├── 01-basic-d3-demo ├── README.md ├── css │ └── styles.css ├── data │ ├── .Rhistory │ ├── midwest.csv │ └── prep_data.R ├── index.html └── js │ └── ScatterPlot.js ├── 02-class-demo ├── README.md ├── css │ └── styles.css ├── index.html └── js │ └── main.js ├── 03-component-demo ├── README.md ├── css │ └── styles.css ├── img │ └── complete.png ├── index.html └── js │ └── main.js ├── 04-react-intro-exercise ├── README.md ├── css │ └── styles.css ├── img │ └── complete.png ├── index.html └── js │ ├── main.js │ └── solution.js ├── 05-state-demo ├── README.md ├── css │ └── styles.css ├── img │ └── complete.png ├── index.html └── js │ └── main.js ├── 06-state-exercise ├── README.md ├── css │ └── styles.css ├── data │ ├── .Rhistory │ ├── midwest.csv │ └── prep_data.R ├── img │ └── complete.png ├── index.html └── js │ ├── App.js │ └── solution.js ├── 07-d3-demo ├── README.md ├── css │ └── styles.css ├── data │ ├── .Rhistory │ ├── midwest.csv │ └── prep_data.R ├── img │ └── complete.png ├── index.html └── js │ └── App.js ├── 08-scatter-exercise ├── README.md ├── css │ └── styles.css ├── data │ ├── .Rhistory │ ├── midwest.csv │ └── prep_data.R ├── img │ └── complete.png ├── index.html └── js │ ├── App.js │ ├── App_solution.js │ ├── ScatterPlot.js │ └── ScatterPlot_solution.js ├── 09-small-multiples-exercise ├── README.md ├── css │ └── styles.css ├── data │ ├── .Rhistory │ ├── midwest.csv │ └── prep_data.R ├── img │ └── complete.png ├── index.html └── js │ ├── App.js │ ├── App_solution.js │ └── ScatterPlot.js ├── 10-lifting-up-state-exercise ├── README.md ├── css │ └── styles.css ├── data │ ├── .Rhistory │ ├── midwest.csv │ └── prep_data.R ├── img │ └── complete.png ├── index.html └── js │ ├── App.js │ ├── App_solution.js │ ├── BarChart.js │ ├── BarChart_solution.js │ ├── ScatterPlot.js │ └── ScatterPlot_solution.js ├── LICENSE ├── README.md ├── css └── style.css ├── data └── demos.csv ├── index.html ├── lib ├── babel.min.js ├── bootstrap.min.css ├── d3-tip.js ├── d3.min.js ├── example-styles.css ├── jquery.min.js ├── materialize.css ├── materialize.js ├── react-dom.js └── react.js └── main.js /01-basic-d3-demo/README.md: -------------------------------------------------------------------------------- 1 | # 01-basic-d3-demo 2 | This demo contains a simple D3 scatterplot -- participants should be comfortable with this use of D3 _before_ the workshop. -------------------------------------------------------------------------------- /01-basic-d3-demo/css/styles.css: -------------------------------------------------------------------------------- 1 | /* Bootstrap CSS */ 2 | /* @import url("https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css"); */ 3 | @import url("../../lib/bootstrap.min.css"); 4 | 5 | .lead { 6 | margin-bottom:0px; 7 | } 8 | 9 | 10 | .jumbotron { 11 | padding:1rem 1rem; 12 | margin-bottom:20px; 13 | } 14 | 15 | /* Scatter plot */ 16 | circle { 17 | cursor:pointer; 18 | } 19 | .axis-label { 20 | text-anchor:middle; 21 | font-size:10px; 22 | } 23 | 24 | #root { 25 | padding-top:30px; 26 | text-align: center; 27 | } -------------------------------------------------------------------------------- /01-basic-d3-demo/data/.Rhistory: -------------------------------------------------------------------------------- 1 | library(dplyr) 2 | library(ggplot2) 3 | View(midwest) 4 | dim(midwest) 5 | ?midwest 6 | levels(midwest$state) 7 | unique(midwest$state) 8 | styler:::style_active_file() 9 | prepped <- midwest %>% 10 | mutate( 11 | state = replace(state, state == "IL", "Illinois"), 12 | state = replace(state, state == "IN", "Indiana"), 13 | state = replace(state, state == "MI", "Michigan"), 14 | state = replace(state, state == "OH", "Ohio"), 15 | state = replace(state, state == "WI", "Wisconsin") 16 | ) 17 | View(prepped) 18 | library(tools) 19 | prepped <- midwest %>% 20 | mutate( 21 | state = replace(state, state == "IL", "Illinois"), 22 | state = replace(state, state == "IN", "Indiana"), 23 | state = replace(state, state == "MI", "Michigan"), 24 | state = replace(state, state == "OH", "Ohio"), 25 | state = replace(state, state == "WI", "Wisconsin"), 26 | county = toTitleCase(county) 27 | ) %>% 28 | select(county, state, %in% "pop") 29 | prepped <- midwest %>% 30 | mutate( 31 | state = replace(state, state == "IL", "Illinois"), 32 | state = replace(state, state == "IN", "Indiana"), 33 | state = replace(state, state == "MI", "Michigan"), 34 | state = replace(state, state == "OH", "Ohio"), 35 | state = replace(state, state == "WI", "Wisconsin"), 36 | county = toTitleCase(county) 37 | ) %>% 38 | select(county, state, inmetro, contains("per")) 39 | View(prepped) 40 | ?perchsd 41 | ?midwest 42 | prepped <- midwest %>% 43 | mutate( 44 | state = replace(state, state == "IL", "Illinois"), 45 | state = replace(state, state == "IN", "Indiana"), 46 | state = replace(state, state == "MI", "Michigan"), 47 | state = replace(state, state == "OH", "Ohio"), 48 | state = replace(state, state == "WI", "Wisconsin"), 49 | county = toTitleCase(county) 50 | ) %>% 51 | select(county, state, inmetro, contains("per"), -perchsd) 52 | midwest %>% 53 | mutate( 54 | state = replace(state, state == "IL", "Illinois"), 55 | state = replace(state, state == "IN", "Indiana"), 56 | state = replace(state, state == "MI", "Michigan"), 57 | state = replace(state, state == "OH", "Ohio"), 58 | state = replace(state, state == "WI", "Wisconsin"), 59 | county = toTitleCase(county) 60 | ) 61 | toTitleCase(midwest$county) 62 | library(stringr) 63 | prepped <- midwest %>% 64 | mutate( 65 | state = replace(state, state == "IL", "Illinois"), 66 | state = replace(state, state == "IN", "Indiana"), 67 | state = replace(state, state == "MI", "Michigan"), 68 | state = replace(state, state == "OH", "Ohio"), 69 | state = replace(state, state == "WI", "Wisconsin"), 70 | county = str_to_title(county) 71 | ) %>% 72 | select(county, state, inmetro, contains("per"), -perchsd) 73 | setwd("~/Documents/react-d3/demo/data") 74 | # Data prep 75 | # Use built in `midwest` data from the `ggplot2` package 76 | library(ggplot2) 77 | library(dplyr) 78 | library(stringr) 79 | # Replace values with full state names 80 | prepped <- midwest %>% 81 | mutate( 82 | state = replace(state, state == "IL", "Illinois"), 83 | state = replace(state, state == "IN", "Indiana"), 84 | state = replace(state, state == "MI", "Michigan"), 85 | state = replace(state, state == "OH", "Ohio"), 86 | state = replace(state, state == "WI", "Wisconsin"), 87 | county = str_to_title(county) 88 | ) %>% 89 | select(county, state, inmetro, contains("per"), -perchsd) 90 | # Write data 91 | write.csv("midwest.csv") 92 | # Data prep 93 | # Use built in `midwest` data from the `ggplot2` package 94 | library(ggplot2) 95 | library(dplyr) 96 | library(stringr) 97 | # Replace values with full state names 98 | prepped <- midwest %>% 99 | mutate( 100 | state = replace(state, state == "IL", "Illinois"), 101 | state = replace(state, state == "IN", "Indiana"), 102 | state = replace(state, state == "MI", "Michigan"), 103 | state = replace(state, state == "OH", "Ohio"), 104 | state = replace(state, state == "WI", "Wisconsin"), 105 | county = str_to_title(county) 106 | ) %>% 107 | select(county, state, inmetro, contains("per"), -perchsd) 108 | # Write data 109 | write.csv(prepped, "midwest.csv", row.names = F) 110 | -------------------------------------------------------------------------------- /01-basic-d3-demo/data/prep_data.R: -------------------------------------------------------------------------------- 1 | # Data prep 2 | 3 | # Use built in `midwest` data from the `ggplot2` package 4 | library(ggplot2) 5 | library(dplyr) 6 | library(stringr) 7 | 8 | # Replace values with full state names 9 | prepped <- midwest %>% 10 | mutate( 11 | state = replace(state, state == "IL", "Illinois"), 12 | state = replace(state, state == "IN", "Indiana"), 13 | state = replace(state, state == "MI", "Michigan"), 14 | state = replace(state, state == "OH", "Ohio"), 15 | state = replace(state, state == "WI", "Wisconsin"), 16 | county = str_to_title(county) 17 | ) %>% 18 | select(county, state, inmetro, contains("per"), -perchsd) 19 | 20 | # Write data 21 | write.csv(prepped, "midwest.csv", row.names = F) -------------------------------------------------------------------------------- /01-basic-d3-demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 01-basic-d3-demo 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 |

01-basic-d3-demo

29 |

A mutual starting point for using D3 and React (i.e., what you should already be able to do)

30 | (all exercises) 31 |
32 |
33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /01-basic-d3-demo/js/ScatterPlot.js: -------------------------------------------------------------------------------- 1 | // A simple d3 scatter plot 2 | "use strict"; 3 | 4 | /* ************************************* Set up: set global variables ******************************** */ 5 | 6 | const width = 500; 7 | const height = 500; 8 | 9 | const margin = { 10 | top: 20, 11 | right: 10, 12 | bottom: 50, 13 | left: 60 14 | }; 15 | 16 | const radius = 5; 17 | const color = "blue"; 18 | 19 | // Chart width and height - accounting for margins 20 | let drawWidth = width - margin.left - margin.right; 21 | let drawHeight = height - margin.top - margin.bottom; 22 | 23 | // Variables to display (i.e., which columns to select in the dataset) 24 | const xVar = "percbelowpoverty"; 25 | const yVar = "percollege"; 26 | 27 | /* ************************************* Create chart wrappers ************************************** */ 28 | 29 | // Create an `svg` element to hold the chart (including axes and labels) 30 | let svg = d3.select('#root') 31 | .append('svg') 32 | .attr('width', width) 33 | .attr('height', height); 34 | 35 | // Create a `g` element in which to render points 36 | let chartG = svg.append('g') 37 | .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')') 38 | .attr('height', drawHeight) 39 | .attr('width', drawWidth); 40 | 41 | 42 | /* ************************************* Load + prepare data ************************************** */ 43 | d3.csv("data/midwest.csv", (err, rawData) => { 44 | // Store data in a more generalized format for reusability 45 | let data = rawData.map((d) => { 46 | return { 47 | x: +d[xVar], 48 | y: +d[yVar], 49 | label: d.county + ',' + d.state 50 | }; 51 | }); 52 | /* ************************************* Defining scales ************************************** */ 53 | 54 | // Find the maximum x value for the x Scale, and multiply it by 1.05 (to add space) 55 | let xMax = d3.max(data, (d) => +d.x) * 1.05; 56 | 57 | // Find the minimum x value for the x Scale, and multiply it by .9 (to add space) 58 | let xMin = d3.min(data, (d) => +d.x) * 0.9; 59 | 60 | // Use `d3.scaleLinear` to define an `xScale` with the appropriate domain and range 61 | let xScale = d3.scaleLinear() 62 | .range([0, drawWidth]) 63 | .domain([xMin, xMax]); 64 | 65 | // Find the maximum y value for the x Scale, and multiply it by 1.05 (to add space) 66 | let yMax = d3.max(data, (d) => +d.y) * 1.05; 67 | 68 | // Find the minimum y value for the x Scale, and multiply it by .9 (to add space) 69 | let yMin = d3.min(data, (d) => +d.y) * 0.9; 70 | 71 | // Use `d3.scaleLinear` to define a `yScale` with the appropriate domain and range 72 | let yScale = d3.scaleLinear() 73 | .range([0, drawHeight]) 74 | .domain([yMax, yMin]); 75 | 76 | /* ************************************* Defining axes ************************************** */ 77 | 78 | // Define xAxis using d3.axisBottom, assigning the scale as `xScale` 79 | let xAxis = d3.axisBottom(xScale); 80 | 81 | // Define yAxis using d3.axisLeft(), assigning the scale as `yScale` 82 | let yAxis = d3.axisLeft(yScale); 83 | 84 | 85 | /* ************************************* Rendering axes and labels ************************************** */ 86 | 87 | // Append a `g` to the `svg` as an x axis label, specifying the 'transform' attribute to position it 88 | // Use the `.call` method to render the axis in the `g` 89 | let xAxisLabel = svg.append('g') 90 | .attr('transform', 'translate(' + margin.left + ',' + (drawHeight + margin.top) + ')') 91 | .attr('class', 'axis') 92 | .call(xAxis); 93 | 94 | // Append a `g` to the `svg` as a y axis label, specifying the 'transform' attribute to position it 95 | // Use the `.call` method to render the axis in the `g` 96 | let yAxisLabel = svg.append('g') 97 | .attr('transform', 'translate(' + margin.left + ',' + (margin.top) + ')') 98 | .attr('class', 'axis') 99 | .call(yAxis); 100 | 101 | // Add a title to the chart 102 | let title = svg.append('text') 103 | .attr('transform', `translate(${margin.left},15)`) 104 | .text("Midwest Counties"); 105 | 106 | // Append a text element to the svg to label the x axis 107 | let xAxisText = svg.append('text') 108 | .attr('transform', `translate(${(margin.left + drawWidth / 2)}, ${(height - margin.bottom + 30)})`) 109 | .attr('class', 'axis-label') 110 | .text(xVar); 111 | 112 | // Append a text element to the svg to label the y axis 113 | svg.append('text') 114 | .attr('transform', `translate( ${(margin.left - 30)},${(margin.top + drawHeight / 2)}) rotate(-90)`) 115 | .attr('class', 'axis-label') 116 | .text(yVar); 117 | 118 | 119 | /* ************************************* Define Tooltip ************************************** */ 120 | let tip = d3.tip().attr('class', 'd3-tip').html(function (d) { 121 | return d.label; 122 | }); 123 | 124 | /* ************************************* Data Join ************************************** */ 125 | // Select all circles and bind data to the selection 126 | let circles = chartG.selectAll('circle').data(data); 127 | 128 | // Use the `.enter()` method to identify the entering elements, and assign their positions 129 | // Then, merge on any updating circles and set all the properties 130 | circles.enter().append('circle') 131 | .on('mouseover', tip.show) 132 | .on('mouseout', tip.hide) 133 | .attr('r', (d) => radius) 134 | .attr('fill', (d) => color) 135 | .attr('label', (d) => d.label) 136 | .style('fill-opacity', 0.3) 137 | .merge(circles) 138 | .transition().duration(500) 139 | .attr('cx', (d) => xScale(d.x)) 140 | .attr('cy', (d) => yScale(d.y)); 141 | 142 | 143 | // Use the .exit() and .remove() methods to remove elements that are no longer in the data 144 | circles.exit().remove(); 145 | 146 | // Add hovers using the d3-tip library 147 | chartG.call(tip); 148 | }); 149 | -------------------------------------------------------------------------------- /02-class-demo/README.md: -------------------------------------------------------------------------------- 1 | # 02-class-demo 2 | This project demonstrates a simple use of JavaScript _classes_. Because using React depends on leveraging a class structure in JavaScript, this is an important prerequisite to using React. 3 | 4 | When you open the page, make sure to **inspect the page** to see the of of classes on the console. -------------------------------------------------------------------------------- /02-class-demo/css/styles.css: -------------------------------------------------------------------------------- 1 | /* Bootstrap CSS */ 2 | /* @import url("https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css"); */ 3 | @import url("../../lib/bootstrap.min.css"); 4 | 5 | .lead { 6 | margin-bottom:0px; 7 | } 8 | 9 | .jumbotron { 10 | padding:1rem 1rem; 11 | margin-bottom:20px; 12 | } -------------------------------------------------------------------------------- /02-class-demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 02-class-demo 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 |
29 |

02-class-demo

30 |

A quick demonstration of using classes (inspect the element and see the console)

31 | (all exercises) 32 |
33 | 34 |
35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /02-class-demo/js/main.js: -------------------------------------------------------------------------------- 1 | // A simple d3 scatter plot 2 | "use strict"; 3 | 4 | // Create a new class `Pet` 5 | class Pet { 6 | // Constructor function is called when the class is instantiated 7 | constructor(name) { 8 | this.name = name; 9 | } 10 | } 11 | 12 | // Create an instance of your pet 13 | let myPet = new Pet("Magnet"); 14 | console.log(myPet.name); 15 | 16 | // Create a new class `Dog` by extending the class `Pet` 17 | class Dog extends Pet { 18 | constructor(name, sound) { 19 | super(name); // call parent class constructor function 20 | this.sound = sound; 21 | } 22 | 23 | // Add a new method `bark` to the class 24 | bark() { 25 | console.log(`${this.sound}! My name is ${this.name}`); 26 | } 27 | } 28 | 29 | // Create an instance of a dog 30 | let myDog = new Dog("Mocha", "Woof Woof!"); 31 | 32 | // Have the dog bark 33 | myDog.bark(); -------------------------------------------------------------------------------- /03-component-demo/README.md: -------------------------------------------------------------------------------- 1 | # 03-component-demo 2 | This project demonstrates the basic using of creating and rendering a React component. It uses properties (_props_) to pass data into a very simple component: 3 | 4 | ![a paragraph rendered with props](img/complete.png) -------------------------------------------------------------------------------- /03-component-demo/css/styles.css: -------------------------------------------------------------------------------- 1 | /* Bootstrap CSS */ 2 | /* @import url("https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css"); */ 3 | @import url("../../lib/bootstrap.min.css"); 4 | 5 | .lead { 6 | margin-bottom:0px; 7 | } 8 | 9 | 10 | .jumbotron { 11 | padding:1rem 1rem; 12 | margin-bottom:20px; 13 | } -------------------------------------------------------------------------------- /03-component-demo/img/complete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mkfreeman/react-d3/47f9cfbd783c059ff752b0e3cd2bce90cccf816a/03-component-demo/img/complete.png -------------------------------------------------------------------------------- /03-component-demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 03-component-demo 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 |
29 |

03-component-demo

30 |

A quick demonstration of rendering a React component

31 | (all exercises) 32 |
33 |
34 |
35 | 36 | 37 | -------------------------------------------------------------------------------- /03-component-demo/js/main.js: -------------------------------------------------------------------------------- 1 | // A simple react component 2 | "use strict"; 3 | 4 | // Create a component that represents someone's biography 5 | class Bio extends React.Component { 6 | // React components have a render method to describe how to draw them on the DOM 7 | render() { 8 | // Figure out the proper article 9 | let article = "a"; 10 | ["a", "e", "i", "o", "u"].forEach((d) => { 11 | if(this.props.description.startsWith(d)) { 12 | article = "an"; 13 | } 14 | }); 15 | return ( 16 |
17 |

{this.props.name}

18 |

Hello, my name is {this.props.name} and I am {article} {this.props.description}.

19 |
20 | ) 21 | } 22 | } 23 | 24 | // Render the Bio component in the `root` element 25 | ReactDOM.render( 26 | , 27 | document.getElementById('root') 28 | ); -------------------------------------------------------------------------------- /04-react-intro-exercise/README.md: -------------------------------------------------------------------------------- 1 | # 04-react-intro-exercise 2 | In this exercise, you'll follow the instructions below to build a simple _todo list_ that looks like this: 3 | 4 | ![Complete todo list](img/complete.png) 5 | In doing so, you'll create and render two react components. See the solution in the `solution.js` file. 6 | 7 | ## Instructions 8 | The necessary CSS and HTML code are already written for you in this exercise. You'll also notice that there is an array of objects storing the _todo_ items that you'll render. In your `main.js` file, complete the following steps: 9 | 10 | ### `Todo` Component 11 | Define a new component called `Todo` by _extending_ the `React.Component` class. The component should accept the following information as _props_: 12 | 13 | - `description`: A _description_ of the task 14 | - `status`: The _status_ of the task (_complete_, or _incomplete_) 15 | - `priority`: The _priority_ of the task (_low_, _medium_, or _high_) 16 | 17 | In the components `render()` method, **return** the following (note: in React, you have to specify the `className` property of an HTML element, because `class` is a protected word): 18 | 19 | - A `
` that has two classes: "todo", and whatever the _priority_ is (which is passed in via _props_) 20 | - Inside the `
`, return a paragraph (`

`) who class name is equal to the _status_. The text of the paragraph should be the _description_ passed in via props 21 | 22 | Rather than rendering an item directly to the DOM, you will use this component _inside_ the `TodoList` component, described below. 23 | 24 | ### `TodoList` Component 25 | Define another new component called `TodoList` by _extending_ the `React.Component` class. The component should accept the following information as _props_: 26 | 27 | - `list`: A _list_ of todo items (i.e., the ones stored in the `todos` constant) 28 | 29 | You will iterate through this list of items, which you can do using the following syntax (assigning a `key` so that React can easily track new/old elements on the DOM): 30 | 31 | ``` 32 |

33 | {someArray.map((d, i) => { 34 | return
Some element
35 | })} 36 |
37 | ``` 38 | 39 | In the components `render()` method, return the following: 40 | 41 | - A `
` that will contain other elements (remenber: you can only return **one element** in the `render()` method!) 42 | - Inside the `
`, iterae through the _list_ that was passed in via _props_. For each element in the array, render a `` component, making sure to pass in the appropriate properties. 43 | 44 | 45 | ### Rendering the list 46 | To render your `` component, use the `ReactDOM.render()` method. Make sure to specify the `list` property of the `` component, and render the list inside the DOM element with id `root`. -------------------------------------------------------------------------------- /04-react-intro-exercise/css/styles.css: -------------------------------------------------------------------------------- 1 | /* Bootstrap CSS */ 2 | /* @import url("https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css"); */ 3 | @import url("../../lib/bootstrap.min.css"); 4 | 5 | 6 | .jumbotron { 7 | padding:1rem 1rem; 8 | margin-bottom:20px; 9 | } 10 | 11 | .complete { 12 | text-decoration: line-through; 13 | } 14 | 15 | p { 16 | margin-bottom:0px; 17 | } 18 | 19 | .todo { 20 | padding:10px; 21 | margin:2px; 22 | border-radius: 5px; 23 | } 24 | .high { 25 | background:#c125084f; 26 | } 27 | 28 | .low { 29 | background:#0080004f; 30 | } 31 | 32 | .medium { 33 | background:#e8e6074f; 34 | } -------------------------------------------------------------------------------- /04-react-intro-exercise/img/complete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mkfreeman/react-d3/47f9cfbd783c059ff752b0e3cd2bce90cccf816a/04-react-intro-exercise/img/complete.png -------------------------------------------------------------------------------- /04-react-intro-exercise/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 04-react-intro-exercise 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 |
29 |

04-react-intro-exercise

30 |

An exercise on creating components and passing them properties. See the 31 | README.md file for instructions.

32 | (all exercises) 33 |
34 |
35 |
36 | 37 | 38 | -------------------------------------------------------------------------------- /04-react-intro-exercise/js/main.js: -------------------------------------------------------------------------------- 1 | // Making a todo list 2 | "use strict"; 3 | 4 | // A set of items to render in your todolist 5 | const todos = [ 6 | { 7 | description: "Learn how to use React and D3", 8 | priority: "high", 9 | status: "incomplete" 10 | 11 | }, 12 | { 13 | description: "Explore Paris", 14 | priority: "medium", 15 | status: "complete" 16 | }, 17 | { 18 | description: "Catch up on work", 19 | priority: "low", 20 | status: "incomplete" 21 | } 22 | ]; 23 | 24 | 25 | // Create a component Todo that represents an item in a to do list (see README.md for instructions) 26 | 27 | 28 | // Create a class TodoList (see README.md for instructions) 29 | 30 | 31 | // Render the TodoList component in the `root` element -------------------------------------------------------------------------------- /04-react-intro-exercise/js/solution.js: -------------------------------------------------------------------------------- 1 | // Solution: making a todo list 2 | "use strict"; 3 | 4 | // A set of items to render in your todolist 5 | const todos = [ 6 | { 7 | description: "Learn how to use React and D3", 8 | priority: "high", 9 | status: "incomplete" 10 | 11 | }, 12 | { 13 | description: "Explore Paris", 14 | priority: "medium", 15 | status: "complete" 16 | }, 17 | { 18 | description: "Catch up on work", 19 | priority: "low", 20 | status: "incomplete" 21 | } 22 | ]; 23 | 24 | // Create a component Todo that represents an item in a to do list (see README.md for instructions) 25 | class Todo extends React.Component { 26 | // Render the Todo item 27 | render() { 28 | return ( 29 |
30 |

{this.props.description}

31 |
32 | ) 33 | } 34 | } 35 | 36 | // Create a class TodoList (see README.md for instructions) 37 | class TodoList extends React.Component { 38 | // Render a Todo component for each element in the `list` props 39 | render() { 40 | return ( 41 |
42 | {this.props.list.map((d, i) => { 43 | return 44 | }) 45 | } 46 |
47 | ) 48 | } 49 | } 50 | 51 | // Render the TodoList component in the `root` element 52 | ReactDOM.render( 53 | , 54 | document.getElementById('root') 55 | ); -------------------------------------------------------------------------------- /05-state-demo/README.md: -------------------------------------------------------------------------------- 1 | # 05-state-demo 2 | This project builds a searchable todo list to demonstrate a React component that keeps track of state: 3 | 4 | ![searchable table](img/complete.png) -------------------------------------------------------------------------------- /05-state-demo/css/styles.css: -------------------------------------------------------------------------------- 1 | /* Bootstrap CSS */ 2 | /* @import url("https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css"); */ 3 | @import url("../../lib/bootstrap.min.css"); 4 | 5 | .complete { 6 | text-decoration: line-through; 7 | } 8 | 9 | .lead { 10 | margin-bottom:0px; 11 | } 12 | 13 | p { 14 | margin-bottom:0px; 15 | } 16 | 17 | 18 | .jumbotron { 19 | padding:1rem 1rem; 20 | margin-bottom:20px; 21 | } 22 | 23 | .todo { 24 | padding:10px; 25 | margin:2px; 26 | border-radius: 5px; 27 | } 28 | .high { 29 | background:#c125084f; 30 | } 31 | 32 | .low { 33 | background:#0080004f; 34 | } 35 | 36 | .medium { 37 | background:#e8e6074f; 38 | } -------------------------------------------------------------------------------- /05-state-demo/img/complete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mkfreeman/react-d3/47f9cfbd783c059ff752b0e3cd2bce90cccf816a/05-state-demo/img/complete.png -------------------------------------------------------------------------------- /05-state-demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 05-state-demo 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 |
29 |

05-state-demo

30 |

A demo of how to use state to re-render a component.

31 | (all exercises) 32 |
33 |
34 |
35 | 36 | 37 | -------------------------------------------------------------------------------- /05-state-demo/js/main.js: -------------------------------------------------------------------------------- 1 | // Solution: making a todo list 2 | "use strict"; 3 | 4 | // A set of items to render in your todolist 5 | const todos = [ 6 | { 7 | description: "Learn how to use React and D3", 8 | priority: "high", 9 | status: "incomplete" 10 | 11 | }, 12 | { 13 | description: "Explore Paris", 14 | priority: "medium", 15 | status: "complete" 16 | }, 17 | { 18 | description: "Catch up on work", 19 | priority: "low", 20 | status: "incomplete" 21 | } 22 | ]; 23 | 24 | // Create a component ToDo that represents an item in a to do list (see README.md for instructions) 25 | class Todo extends React.Component { 26 | // Render the Todo item 27 | render() { 28 | return ( 29 |
30 |

{this.props.description}

31 |
32 | ) 33 | } 34 | } 35 | 36 | // Create a class TodoList (see README.md for instructions) 37 | class TodoList extends React.Component { 38 | // Add a constructor method to set the state 39 | constructor(props) { 40 | super(props); 41 | this.state = { 42 | search: "" 43 | } 44 | } 45 | 46 | // Render a Todo component for each element in the `list` props 47 | render() { 48 | // Filter down the list of todos to the state 49 | let currentList = this.props.list.filter((d) => { 50 | return d.description.match(this.state.search); 51 | }) 52 | return ( 53 |
54 | {/* An input element to search through the todo items*/} 55 | this.setState({ search: event.target.value })} /> 56 | {currentList.map((d, i) => { 57 | return 58 | }) 59 | } 60 |
61 | ) 62 | } 63 | } 64 | 65 | // Render the TodoList component in the `root` element 66 | ReactDOM.render( 67 | , 68 | document.getElementById('root') 69 | ); -------------------------------------------------------------------------------- /06-state-exercise/README.md: -------------------------------------------------------------------------------- 1 | # 06-state-exercise 2 | In this exercise, you'll follow the instructions below to build a data exploration tool in React: 3 | 4 | ![Complete todo list](img/complete.png) 5 | 6 | In doing so, you'll **manage the state** of a React component that you create. See the solution in the `solution.js` file. 7 | 8 | ## Instructions 9 | The necessary CSS and HTML code are already written for you in this exercise, as is _some of_ the JavaScript code. In your `App.js` file, complete the following steps: 10 | 11 | ### `componentDidMount()` Method 12 | When the component mounts, use the `d3.csv()` method to load the `.csv` file stored in `"data/midwest.csv"`. In the callback function for the method (i.e., once you load the data), **update the state** such that the `data` property (i.e., `this.state.data`) is equal to the data loaded by `d3.csv()`. Make sure to use the `this.setState()` method (don't try to set the value of the state directly). This will trigger a re-rendering of your `App` component. To see if it worked, you can add a `console.log()` statement to the `render()` method to see the state of your component. 13 | 14 | 15 | ### `render()` Method 16 | In the `render()` method, you will first compute some values of interest that you want to display, then you will _return_ an HTML element that contains the information you wish to render on the DOM. 17 | 18 | #### Computing values in your `render()` method 19 | It's fairly common to use the state of your component to determine what you wish to render. One challenge to note is that, when the component first renders (but _before_ the data is loaded), your data will be an empty array. This makes it difficult to compute values of interest. Luckily, it's easy to use a **ternary operator** to conditionally capture information of interest: 20 | 21 | ```javascript 22 | // Use a ternary operator to capture information of interest 23 | // If the data hasn't loaded, return an empty array. 24 | // Otherwise, get the keys of the first data element 25 | let options = this.state.data.length === 0 ? [] : Object.keys(this.state.data[0]); 26 | ``` 27 | 28 | You'll need to store the following information in variables (you can obviously call them whatever you want, but these are the variable names in the `solution.js` file): 29 | 30 | - `options`: Create a variable `options` storing the list of possible variables to display in the table (these are the columns in your `.csv` file). These should be the **object keys** from the first element in your data (see above), excluding "county" and "state". 31 | - `allData`: Create a variable `allData` in which you store the current values of interest (based on `this.state.variable`), as well as the state and county. In other words, this should be an **array of objects** with three keys: `value` (the _value_ of whatever is stored in the `this.state.variable` key), `state`, and `county`. 32 | - `mean`: Store the _mean_ of the `value` key in your `allData` array in a variable `mean`. I suggest using `d3.mean()` to do this. 33 | - `topData`: Store the top N values (based on `this.state.nShow`) from the `allData` array in a variable. Observations should be sorted by the current variable being displayed (`this.state.variable`) in either ascending or descending order (based on `this.state.sort`). You can do this using the array methods `.sort()` and `.filter()` (in that order). 34 | 35 | #### Returning elements in your `render()` method 36 | There is already a DOM element returned by the `render()` method. Inside that node, you'll create the following elements. Note, because the `ReactDOM.render()` method is being called, you should be able to see your changes appear as you make them. 37 | 38 | ___Controls___ 39 | - **Select Menu**: Create a Select Menu (i.e., `` element. Assign an `onChange()` method to the ``) to control how many rows are shown in the table. The _value_ of the slider should be `this.state.nShow`. When the slider updates (i.e., `onChange()`), you should use the `this.setState()` method to change the state of the `nShow` value. This will change the number of values stored in `topData`, updating the table you will render (described below). 41 | - **Button Group**: Create a Button Group (i.e., a `
` with two `