├── 01 nvd3 ├── Readme.md ├── 00 Lines │ ├── pictures │ │ ├── 06_pie.png │ │ ├── 00A_libs.png │ │ ├── 00C_Main1.png │ │ ├── 00C_Main2.png │ │ ├── 00C_Main3.png │ │ ├── 00B_Series1.png │ │ ├── 00B_Series2.png │ │ ├── 00B_Series3.png │ │ ├── 02_vertical.png │ │ ├── 03_twolines.png │ │ ├── 02_Chart_Original.png │ │ └── 02_Chart_Bar_Padding.png │ ├── index.html │ ├── main.js │ └── data.js └── 01 BubbleChart │ ├── data.js │ ├── index.html │ ├── main.js │ └── readme.md ├── 02 d3js-es5 ├── Readme.md ├── 06 Pie │ ├── data.js │ ├── styles.css │ ├── index.html │ └── main.js ├── 04 BarChartRefactor │ ├── data.js │ ├── styles.css │ ├── index.html │ └── main.js ├── 03 BarChartAxis │ ├── styles.css │ ├── index.html │ ├── main.js │ └── readme.md ├── 00 SVG │ ├── styles.css │ ├── index.html │ └── readme.md ├── 05 Lines │ ├── styles.css │ ├── data.js │ ├── index.html │ └── main.js └── 02 BarChart │ ├── index.html │ ├── main.js │ └── readme.md ├── 00 basics ├── .gitignore ├── 04 SVG │ ├── styles.css │ ├── index.html │ └── readme.md ├── 05 SVG 2 │ ├── styles.css │ ├── index.html │ └── readme.md ├── 00 HTML │ ├── index.html │ └── readme.md ├── 02 DOM │ ├── styles.css │ ├── main.js │ ├── index.html │ └── readme.md ├── 03 DOM 2 │ ├── src │ │ ├── styles.css │ │ └── index.ts │ ├── package.json │ ├── index.html │ └── readme.md └── 01 CSS │ ├── index.html │ ├── styles.css │ └── readme.md ├── readme.md ├── 03 d3js-typescript ├── 01 Lines │ ├── .prettierrc │ ├── src │ │ ├── app.ts │ │ ├── index.html │ │ ├── d3 │ │ │ ├── title.d3.ts │ │ │ ├── linechart.data.ts │ │ │ └── linechart.d3.ts │ │ └── app.scss │ ├── .gitignore │ ├── .babelrc │ ├── tsconfig.json │ ├── webpack.prod.js │ ├── webpack.dev.js │ ├── package.json │ ├── webpack.config.js │ └── tslint.json ├── 02 Bars │ ├── .prettierrc │ ├── src │ │ ├── app.ts │ │ ├── index.html │ │ ├── d3 │ │ │ ├── title.d3.ts │ │ │ ├── barchart.data.ts │ │ │ └── barchart.d3.ts │ │ └── app.scss │ ├── .gitignore │ ├── .babelrc │ ├── tsconfig.json │ ├── webpack.prod.js │ ├── webpack.dev.js │ ├── package.json │ ├── webpack.config.js │ ├── tslint.json │ └── Readme.md ├── 00 Playground │ ├── .prettierrc │ ├── src │ │ ├── app.ts │ │ ├── index.html │ │ ├── d3 │ │ │ └── title.d3.ts │ │ └── app.scss │ ├── .gitignore │ ├── .babelrc │ ├── tsconfig.json │ ├── webpack.prod.js │ ├── webpack.dev.js │ ├── package.json │ ├── tslint.json │ └── webpack.config.js ├── 991 Basic Map │ ├── .prettierrc │ ├── src │ │ ├── app.ts │ │ ├── index.html │ │ ├── d3 │ │ │ ├── title.d3.ts │ │ │ ├── world-mercator.d3.ts │ │ │ └── world-platee-carre.d3.ts │ │ └── app.scss │ ├── .gitignore │ ├── .babelrc │ ├── tsconfig.json │ ├── webpack.prod.js │ ├── webpack.dev.js │ ├── package.json │ ├── tslint.json │ └── webpack.config.js ├── 993 Spain Cloropleth │ ├── src │ │ ├── d3 │ │ │ ├── styles.scss │ │ │ ├── title.d3.ts │ │ │ ├── effects.d3.ts │ │ │ └── spain.d3.ts │ │ ├── app.ts │ │ ├── index.html │ │ └── app.scss │ ├── .prettierrc │ ├── .babelrc │ ├── .gitignore │ ├── tsconfig.json │ ├── webpack.prod.js │ ├── webpack.dev.js │ ├── package.json │ ├── tslint.json │ └── webpack.config.js ├── 992 Map Interaction │ ├── .prettierrc │ ├── src │ │ ├── app.ts │ │ ├── index.html │ │ ├── d3 │ │ │ ├── title.d3.ts │ │ │ └── countries.d3.ts │ │ ├── app.scss │ │ └── data │ │ │ └── population.tsv │ ├── .babelrc │ ├── .gitignore │ ├── tsconfig.json │ ├── webpack.prod.js │ ├── webpack.dev.js │ ├── package.json │ ├── tslint.json │ └── webpack.config.js └── 994 World Population │ ├── .prettierrc │ ├── src │ ├── app.ts │ ├── index.html │ ├── d3 │ │ ├── title.d3.ts │ │ ├── net-population.d3.ts │ │ └── birth-rate.d3.ts │ └── app.scss │ ├── .babelrc │ ├── .gitignore │ ├── tsconfig.json │ ├── webpack.prod.js │ ├── webpack.dev.js │ ├── package.json │ ├── tslint.json │ └── webpack.config.js ├── .gitignore └── LICENSE /01 nvd3/Readme.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /02 d3js-es5/Readme.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /00 basics/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .cache -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # D3.js From Scratch 2 | 3 | D3.js course from scratch, based on examples. Designed for UMA Big Data Master classes. -------------------------------------------------------------------------------- /03 d3js-typescript/01 Lines/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 100, 3 | "trailingComma": "es5", 4 | "singleQuote": false 5 | } 6 | -------------------------------------------------------------------------------- /03 d3js-typescript/02 Bars/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 100, 3 | "trailingComma": "es5", 4 | "singleQuote": false 5 | } 6 | -------------------------------------------------------------------------------- /01 nvd3/00 Lines/pictures/06_pie.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lemoncode/d3js-from-scratch/master/01 nvd3/00 Lines/pictures/06_pie.png -------------------------------------------------------------------------------- /03 d3js-typescript/00 Playground/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 100, 3 | "trailingComma": "es5", 4 | "singleQuote": false 5 | } 6 | -------------------------------------------------------------------------------- /03 d3js-typescript/991 Basic Map/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 100, 3 | "trailingComma": "es5", 4 | "singleQuote": false 5 | } 6 | -------------------------------------------------------------------------------- /03 d3js-typescript/993 Spain Cloropleth/src/d3/styles.scss: -------------------------------------------------------------------------------- 1 | .with-shadow { 2 | filter: drop-shadow(12px 12px 7px rbga(0,0,0,0.5)) 3 | } -------------------------------------------------------------------------------- /01 nvd3/00 Lines/pictures/00A_libs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lemoncode/d3js-from-scratch/master/01 nvd3/00 Lines/pictures/00A_libs.png -------------------------------------------------------------------------------- /01 nvd3/00 Lines/pictures/00C_Main1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lemoncode/d3js-from-scratch/master/01 nvd3/00 Lines/pictures/00C_Main1.png -------------------------------------------------------------------------------- /01 nvd3/00 Lines/pictures/00C_Main2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lemoncode/d3js-from-scratch/master/01 nvd3/00 Lines/pictures/00C_Main2.png -------------------------------------------------------------------------------- /01 nvd3/00 Lines/pictures/00C_Main3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lemoncode/d3js-from-scratch/master/01 nvd3/00 Lines/pictures/00C_Main3.png -------------------------------------------------------------------------------- /03 d3js-typescript/01 Lines/src/app.ts: -------------------------------------------------------------------------------- 1 | import "./app.scss"; 2 | 3 | // Import here your D3 visualizations. 4 | import "./d3/linechart.d3"; 5 | -------------------------------------------------------------------------------- /01 nvd3/00 Lines/pictures/00B_Series1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lemoncode/d3js-from-scratch/master/01 nvd3/00 Lines/pictures/00B_Series1.png -------------------------------------------------------------------------------- /01 nvd3/00 Lines/pictures/00B_Series2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lemoncode/d3js-from-scratch/master/01 nvd3/00 Lines/pictures/00B_Series2.png -------------------------------------------------------------------------------- /01 nvd3/00 Lines/pictures/00B_Series3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lemoncode/d3js-from-scratch/master/01 nvd3/00 Lines/pictures/00B_Series3.png -------------------------------------------------------------------------------- /01 nvd3/00 Lines/pictures/02_vertical.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lemoncode/d3js-from-scratch/master/01 nvd3/00 Lines/pictures/02_vertical.png -------------------------------------------------------------------------------- /01 nvd3/00 Lines/pictures/03_twolines.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lemoncode/d3js-from-scratch/master/01 nvd3/00 Lines/pictures/03_twolines.png -------------------------------------------------------------------------------- /03 d3js-typescript/00 Playground/src/app.ts: -------------------------------------------------------------------------------- 1 | import "./app.scss"; 2 | 3 | // Import here your D3 visualizations. 4 | import "./d3/title.d3"; 5 | -------------------------------------------------------------------------------- /03 d3js-typescript/992 Map Interaction/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 100, 3 | "trailingComma": "es5", 4 | "singleQuote": false 5 | } 6 | -------------------------------------------------------------------------------- /03 d3js-typescript/993 Spain Cloropleth/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 100, 3 | "trailingComma": "es5", 4 | "singleQuote": false 5 | } 6 | -------------------------------------------------------------------------------- /03 d3js-typescript/994 World Population/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 100, 3 | "trailingComma": "es5", 4 | "singleQuote": false 5 | } 6 | -------------------------------------------------------------------------------- /01 nvd3/00 Lines/pictures/02_Chart_Original.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lemoncode/d3js-from-scratch/master/01 nvd3/00 Lines/pictures/02_Chart_Original.png -------------------------------------------------------------------------------- /01 nvd3/00 Lines/pictures/02_Chart_Bar_Padding.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lemoncode/d3js-from-scratch/master/01 nvd3/00 Lines/pictures/02_Chart_Bar_Padding.png -------------------------------------------------------------------------------- /02 d3js-es5/06 Pie/data.js: -------------------------------------------------------------------------------- 1 | var totalSales = [ 2 | { product: 'Hoodie', sales: 7 }, 3 | { product: 'Jacket', sales: 6 }, 4 | { product: 'Snuggie', sales: 9 }, 5 | ]; 6 | -------------------------------------------------------------------------------- /03 d3js-typescript/02 Bars/src/app.ts: -------------------------------------------------------------------------------- 1 | import "./app.scss"; 2 | 3 | // Import here your D3 visualizations. 4 | import "./d3/title.d3"; 5 | import "./d3/barchart.d3"; 6 | -------------------------------------------------------------------------------- /02 d3js-es5/04 BarChartRefactor/data.js: -------------------------------------------------------------------------------- 1 | var totalSales = [ 2 | { product: 'Hoodie', sales: 7 }, 3 | { product: 'Jacket', sales: 6 }, 4 | { product: 'Snuggie', sales: 9 }, 5 | ]; 6 | -------------------------------------------------------------------------------- /03 d3js-typescript/992 Map Interaction/src/app.ts: -------------------------------------------------------------------------------- 1 | import "./app.scss"; 2 | 3 | // Import here your D3 visualizations. 4 | import "./d3/title.d3"; 5 | import "./d3/countries.d3"; 6 | -------------------------------------------------------------------------------- /03 d3js-typescript/993 Spain Cloropleth/src/app.ts: -------------------------------------------------------------------------------- 1 | import "./app.scss"; 2 | 3 | // Import here your D3 visualizations. 4 | import "./d3/title.d3"; 5 | import "./d3/spain.d3"; 6 | -------------------------------------------------------------------------------- /02 d3js-es5/06 Pie/styles.css: -------------------------------------------------------------------------------- 1 | .axis text { 2 | font: 10px sans-serif; 3 | } 4 | 5 | .axis path, 6 | .axis line { 7 | fill: none; 8 | stroke: #000; 9 | shape-rendering: crispEdges; 10 | } 11 | -------------------------------------------------------------------------------- /02 d3js-es5/03 BarChartAxis/styles.css: -------------------------------------------------------------------------------- 1 | .axis text { 2 | font: 10px sans-serif; 3 | } 4 | 5 | .axis path, 6 | .axis line { 7 | fill: none; 8 | stroke: #000; 9 | shape-rendering: crispEdges; 10 | } 11 | -------------------------------------------------------------------------------- /03 d3js-typescript/994 World Population/src/app.ts: -------------------------------------------------------------------------------- 1 | import "./app.scss"; 2 | 3 | // Import here your D3 visualizations. 4 | import "./d3/title.d3"; 5 | // import "./d3/world.d3"; 6 | import "./d3/birth-rate.d3"; 7 | -------------------------------------------------------------------------------- /02 d3js-es5/04 BarChartRefactor/styles.css: -------------------------------------------------------------------------------- 1 | .axis text { 2 | font: 10px sans-serif; 3 | } 4 | 5 | .axis path, 6 | .axis line { 7 | fill: none; 8 | stroke: #000; 9 | shape-rendering: crispEdges; 10 | } 11 | -------------------------------------------------------------------------------- /03 d3js-typescript/991 Basic Map/src/app.ts: -------------------------------------------------------------------------------- 1 | import "./app.scss"; 2 | 3 | // Import here your D3 visualizations. 4 | import "./d3/title.d3"; 5 | import "./d3/world-mercator.d3"; 6 | import "./d3/world-platee-carre.d3"; 7 | -------------------------------------------------------------------------------- /00 basics/04 SVG/styles.css: -------------------------------------------------------------------------------- 1 | .red { 2 | fill: red; /* not background-color! */ 3 | } 4 | 5 | .fancy { 6 | fill: none; 7 | stroke: black; /* similar to border-color */ 8 | stroke-width: 3pt; /* similar to border-width */ 9 | stroke-dasharray: 3,5,10; 10 | } 11 | -------------------------------------------------------------------------------- /00 basics/05 SVG 2/styles.css: -------------------------------------------------------------------------------- 1 | .red { 2 | fill: red; /* not background-color! */ 3 | } 4 | 5 | .fancy { 6 | fill: none; 7 | stroke: black; /* similar to border-color */ 8 | stroke-width: 3pt; /* similar to border-width */ 9 | stroke-dasharray: 3,5,10; 10 | } 11 | -------------------------------------------------------------------------------- /02 d3js-es5/00 SVG/styles.css: -------------------------------------------------------------------------------- 1 | .red { 2 | fill: red; /* not background-color! */ 3 | } 4 | 5 | .fancy { 6 | fill: none; 7 | stroke: black; /* similar to border-color */ 8 | stroke-width: 3pt; /* similar to border-width */ 9 | stroke-dasharray: 3,5,10; 10 | } 11 | -------------------------------------------------------------------------------- /02 d3js-es5/05 Lines/styles.css: -------------------------------------------------------------------------------- 1 | .axis text { 2 | font: 10px sans-serif; 3 | } 4 | 5 | .axis path, 6 | .axis line { 7 | fill: none; 8 | stroke: #000; 9 | shape-rendering: crispEdges; 10 | } 11 | 12 | .line { 13 | fill: none; 14 | stroke: steelblue; 15 | stroke-width: 2px; 16 | } 17 | -------------------------------------------------------------------------------- /02 d3js-es5/05 Lines/data.js: -------------------------------------------------------------------------------- 1 | 2 | var totalSales = [ 3 | { month: new Date(2016,10, 01), sales: 6500 }, 4 | { month: new Date(2016,11, 01), sales: 5400 }, 5 | { month: new Date(2016,12, 01), sales: 3500 }, 6 | { month: new Date(2017,1, 01), sales: 9000 }, 7 | { month: new Date(2017,2, 01), sales: 8500 }, 8 | ]; 9 | -------------------------------------------------------------------------------- /03 d3js-typescript/01 Lines/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | D3.js Playground 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | -------------------------------------------------------------------------------- /03 d3js-typescript/02 Bars/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | D3.js Playground 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | -------------------------------------------------------------------------------- /03 d3js-typescript/00 Playground/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | D3.js Playground 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | -------------------------------------------------------------------------------- /03 d3js-typescript/991 Basic Map/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | D3.js Playground 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | -------------------------------------------------------------------------------- /03 d3js-typescript/992 Map Interaction/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | D3.js Playground 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | -------------------------------------------------------------------------------- /03 d3js-typescript/993 Spain Cloropleth/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | D3.js Playground 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | -------------------------------------------------------------------------------- /03 d3js-typescript/994 World Population/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | D3.js Playground 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | -------------------------------------------------------------------------------- /03 d3js-typescript/01 Lines/src/d3/title.d3.ts: -------------------------------------------------------------------------------- 1 | import { select } from "d3-selection"; 2 | 3 | // Lets add a card in our root node. 4 | const card = select("#root") 5 | .append("div") 6 | .attr("class", "card"); 7 | 8 | // This card will contain a title for our visualization. 9 | card 10 | .append("h1") 11 | .text("Basic Map with D3.js"); 12 | 13 | -------------------------------------------------------------------------------- /03 d3js-typescript/02 Bars/src/d3/title.d3.ts: -------------------------------------------------------------------------------- 1 | import { select } from "d3-selection"; 2 | 3 | // Lets add a card in our root node. 4 | const card = select("#root") 5 | .append("div") 6 | .attr("class", "card"); 7 | 8 | // This card will contain a title for our visualization. 9 | card 10 | .append("h1") 11 | .text("Basic Map with D3.js"); 12 | 13 | -------------------------------------------------------------------------------- /00 basics/00 HTML/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | TITLE GOES HERE 6 | 7 | 8 |

9 | MAIN CONTENT GOES HERE 10 |

11 | 12 |

13 | HTML Basics tutorial 14 |

15 | 16 | 17 | -------------------------------------------------------------------------------- /03 d3js-typescript/00 Playground/src/d3/title.d3.ts: -------------------------------------------------------------------------------- 1 | import { select } from "d3-selection"; 2 | 3 | // Lets add a card in our root node. 4 | const card = select("#root") 5 | .append("div") 6 | .attr("class", "card"); 7 | 8 | // This card will contain a title for our visualization. 9 | card 10 | .append("h1") 11 | .text("Basic Map with D3.js"); 12 | 13 | -------------------------------------------------------------------------------- /03 d3js-typescript/991 Basic Map/src/d3/title.d3.ts: -------------------------------------------------------------------------------- 1 | import { select } from "d3-selection"; 2 | 3 | // Lets add a card in our root node. 4 | const card = select("#root") 5 | .append("div") 6 | .attr("class", "card"); 7 | 8 | // This card will contain a title for our visualization. 9 | card 10 | .append("h1") 11 | .text("Basic Map with D3.js"); 12 | 13 | -------------------------------------------------------------------------------- /03 d3js-typescript/01 Lines/.gitignore: -------------------------------------------------------------------------------- 1 | # Common aux folders 2 | .awcache/ 3 | .vscode/ 4 | .idea/ 5 | 6 | # Dependencies & Build 7 | node_modules/ 8 | dist/ 9 | 10 | # Aux files 11 | *.log 12 | */src/**/*.orig 13 | */src/**/*.js.map 14 | 15 | # Win 16 | desktop.ini 17 | 18 | # MacOs 19 | .DS_Store 20 | 21 | # Yarn 22 | yarn.lock 23 | 24 | # NPM 25 | package-lock.json -------------------------------------------------------------------------------- /03 d3js-typescript/02 Bars/.gitignore: -------------------------------------------------------------------------------- 1 | # Common aux folders 2 | .awcache/ 3 | .vscode/ 4 | .idea/ 5 | 6 | # Dependencies & Build 7 | node_modules/ 8 | dist/ 9 | 10 | # Aux files 11 | *.log 12 | */src/**/*.orig 13 | */src/**/*.js.map 14 | 15 | # Win 16 | desktop.ini 17 | 18 | # MacOs 19 | .DS_Store 20 | 21 | # Yarn 22 | yarn.lock 23 | 24 | # NPM 25 | package-lock.json -------------------------------------------------------------------------------- /03 d3js-typescript/00 Playground/.gitignore: -------------------------------------------------------------------------------- 1 | # Common aux folders 2 | .awcache/ 3 | .vscode/ 4 | .idea/ 5 | 6 | # Dependencies & Build 7 | node_modules/ 8 | dist/ 9 | 10 | # Aux files 11 | *.log 12 | */src/**/*.orig 13 | */src/**/*.js.map 14 | 15 | # Win 16 | desktop.ini 17 | 18 | # MacOs 19 | .DS_Store 20 | 21 | # Yarn 22 | yarn.lock 23 | 24 | # NPM 25 | package-lock.json -------------------------------------------------------------------------------- /03 d3js-typescript/01 Lines/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | "modules": false, 7 | "useBuiltIns": "usage" 8 | } 9 | ], 10 | "@babel/preset-typescript" 11 | ], 12 | "plugins": [ 13 | "@babel/proposal-class-properties", 14 | "@babel/proposal-object-rest-spread" 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /03 d3js-typescript/02 Bars/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | "modules": false, 7 | "useBuiltIns": "usage" 8 | } 9 | ], 10 | "@babel/preset-typescript" 11 | ], 12 | "plugins": [ 13 | "@babel/proposal-class-properties", 14 | "@babel/proposal-object-rest-spread" 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /03 d3js-typescript/991 Basic Map/.gitignore: -------------------------------------------------------------------------------- 1 | # Common aux folders 2 | .awcache/ 3 | .vscode/ 4 | .idea/ 5 | 6 | # Dependencies & Build 7 | node_modules/ 8 | dist/ 9 | 10 | # Aux files 11 | *.log 12 | */src/**/*.orig 13 | */src/**/*.js.map 14 | 15 | # Win 16 | desktop.ini 17 | 18 | # MacOs 19 | .DS_Store 20 | 21 | # Yarn 22 | yarn.lock 23 | 24 | # NPM 25 | package-lock.json -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Common aux folders 2 | .awcache/ 3 | .vscode/ 4 | .idea/ 5 | 6 | # Dependencies & Build 7 | */**/node_modules/ 8 | */**/dist/ 9 | 10 | # Aux files 11 | */**/*.log 12 | */src/**/*.orig 13 | */src/**/*.js.map 14 | 15 | # Win 16 | */**/desktop.ini 17 | 18 | # MacOs 19 | */**.DS_Store 20 | 21 | # Yarn 22 | */**/yarn.lock 23 | 24 | # NPM 25 | */**/package-lock.json -------------------------------------------------------------------------------- /03 d3js-typescript/00 Playground/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | "modules": false, 7 | "useBuiltIns": "usage" 8 | } 9 | ], 10 | "@babel/preset-typescript" 11 | ], 12 | "plugins": [ 13 | "@babel/proposal-class-properties", 14 | "@babel/proposal-object-rest-spread" 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /03 d3js-typescript/991 Basic Map/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | "modules": false, 7 | "useBuiltIns": "usage" 8 | } 9 | ], 10 | "@babel/preset-typescript" 11 | ], 12 | "plugins": [ 13 | "@babel/proposal-class-properties", 14 | "@babel/proposal-object-rest-spread" 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /03 d3js-typescript/992 Map Interaction/src/d3/title.d3.ts: -------------------------------------------------------------------------------- 1 | import { select } from "d3-selection"; 2 | 3 | // Lets add a card in our root node. 4 | const card = select("#root") 5 | .append("div") 6 | .attr("class", "card"); 7 | 8 | // This card will contain a title for our visualization. 9 | card 10 | .append("h1") 11 | .text("Map Interaction with D3.js"); 12 | 13 | -------------------------------------------------------------------------------- /03 d3js-typescript/993 Spain Cloropleth/src/d3/title.d3.ts: -------------------------------------------------------------------------------- 1 | import { select } from "d3-selection"; 2 | 3 | // Lets add a card in our root node. 4 | const card = select("#root") 5 | .append("div") 6 | .attr("class", "card"); 7 | 8 | // This card will contain a title for our visualization. 9 | card 10 | .append("h1") 11 | .text("Spain Cloropleth with D3.js"); 12 | 13 | -------------------------------------------------------------------------------- /03 d3js-typescript/994 World Population/src/d3/title.d3.ts: -------------------------------------------------------------------------------- 1 | import { select } from "d3-selection"; 2 | 3 | // Lets add a card in our root node. 4 | const card = select("#root") 5 | .append("div") 6 | .attr("class", "card"); 7 | 8 | // This card will contain a title for our visualization. 9 | card 10 | .append("h1") 11 | .text("World Population with D3.js"); 12 | 13 | -------------------------------------------------------------------------------- /02 d3js-es5/02 BarChart/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /03 d3js-typescript/992 Map Interaction/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | "modules": false, 7 | "useBuiltIns": "usage" 8 | } 9 | ], 10 | "@babel/preset-typescript" 11 | ], 12 | "plugins": [ 13 | "@babel/proposal-class-properties", 14 | "@babel/proposal-object-rest-spread" 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /03 d3js-typescript/992 Map Interaction/.gitignore: -------------------------------------------------------------------------------- 1 | # Common aux folders 2 | .awcache/ 3 | .vscode/ 4 | .idea/ 5 | 6 | # Dependencies & Build 7 | node_modules/ 8 | dist/ 9 | 10 | # Aux files 11 | *.log 12 | */src/**/*.orig 13 | */src/**/*.js.map 14 | 15 | # Win 16 | desktop.ini 17 | 18 | # MacOs 19 | .DS_Store 20 | 21 | # Yarn 22 | yarn.lock 23 | 24 | # NPM 25 | package-lock.json -------------------------------------------------------------------------------- /03 d3js-typescript/993 Spain Cloropleth/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | "modules": false, 7 | "useBuiltIns": "usage" 8 | } 9 | ], 10 | "@babel/preset-typescript" 11 | ], 12 | "plugins": [ 13 | "@babel/proposal-class-properties", 14 | "@babel/proposal-object-rest-spread" 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /03 d3js-typescript/993 Spain Cloropleth/.gitignore: -------------------------------------------------------------------------------- 1 | # Common aux folders 2 | .awcache/ 3 | .vscode/ 4 | .idea/ 5 | 6 | # Dependencies & Build 7 | node_modules/ 8 | dist/ 9 | 10 | # Aux files 11 | *.log 12 | */src/**/*.orig 13 | */src/**/*.js.map 14 | 15 | # Win 16 | desktop.ini 17 | 18 | # MacOs 19 | .DS_Store 20 | 21 | # Yarn 22 | yarn.lock 23 | 24 | # NPM 25 | package-lock.json -------------------------------------------------------------------------------- /03 d3js-typescript/994 World Population/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | "modules": false, 7 | "useBuiltIns": "usage" 8 | } 9 | ], 10 | "@babel/preset-typescript" 11 | ], 12 | "plugins": [ 13 | "@babel/proposal-class-properties", 14 | "@babel/proposal-object-rest-spread" 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /03 d3js-typescript/994 World Population/.gitignore: -------------------------------------------------------------------------------- 1 | # Common aux folders 2 | .awcache/ 3 | .vscode/ 4 | .idea/ 5 | 6 | # Dependencies & Build 7 | node_modules/ 8 | dist/ 9 | 10 | # Aux files 11 | *.log 12 | */src/**/*.orig 13 | */src/**/*.js.map 14 | 15 | # Win 16 | desktop.ini 17 | 18 | # MacOs 19 | .DS_Store 20 | 21 | # Yarn 22 | yarn.lock 23 | 24 | # NPM 25 | package-lock.json -------------------------------------------------------------------------------- /02 d3js-es5/03 BarChartAxis/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /00 basics/02 DOM/styles.css: -------------------------------------------------------------------------------- 1 | /* Applied to all

tags */ 2 | p { 3 | color: blue; 4 | } 5 | 6 | /* Applied to all tags with the class "red" */ 7 | .red { 8 | background: red; 9 | } 10 | 11 | /* Applied to the tag with the id "some-id" */ 12 | #some-id { 13 | font-style: italic; 14 | } 15 | 16 | /* Applied only to

tags that are inside

  • tags */ 17 | li p { 18 | color: #0C0; 19 | } 20 | -------------------------------------------------------------------------------- /00 basics/03 DOM 2/src/styles.css: -------------------------------------------------------------------------------- 1 | /* Applied to all

    tags */ 2 | p { 3 | color: blue; 4 | } 5 | 6 | /* Applied to all tags with the class "red" */ 7 | .red { 8 | background: red; 9 | } 10 | 11 | /* Applied to the tag with the id "some-id" */ 12 | #some-id { 13 | font-style: italic; 14 | } 15 | 16 | /* Applied only to

    tags that are inside

  • tags */ 17 | li p { 18 | color: #0c0; 19 | } 20 | -------------------------------------------------------------------------------- /02 d3js-es5/05 Lines/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /02 d3js-es5/06 Pie/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /02 d3js-es5/04 BarChartRefactor/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /03 d3js-typescript/01 Lines/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "module": "es6", 5 | "moduleResolution": "node", 6 | "declaration": false, 7 | "noImplicitAny": false, 8 | "sourceMap": true, 9 | "jsx": "react", 10 | "noLib": false, 11 | "suppressImplicitAnyIndexErrors": true 12 | }, 13 | "compileOnSave": false, 14 | "exclude": [ 15 | "node_modules" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /03 d3js-typescript/02 Bars/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "module": "es6", 5 | "moduleResolution": "node", 6 | "declaration": false, 7 | "noImplicitAny": false, 8 | "sourceMap": true, 9 | "jsx": "react", 10 | "noLib": false, 11 | "suppressImplicitAnyIndexErrors": true 12 | }, 13 | "compileOnSave": false, 14 | "exclude": [ 15 | "node_modules" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /03 d3js-typescript/00 Playground/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "module": "es6", 5 | "moduleResolution": "node", 6 | "declaration": false, 7 | "noImplicitAny": false, 8 | "sourceMap": true, 9 | "jsx": "react", 10 | "noLib": false, 11 | "suppressImplicitAnyIndexErrors": true 12 | }, 13 | "compileOnSave": false, 14 | "exclude": [ 15 | "node_modules" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /03 d3js-typescript/991 Basic Map/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "module": "es6", 5 | "moduleResolution": "node", 6 | "declaration": false, 7 | "noImplicitAny": false, 8 | "sourceMap": true, 9 | "jsx": "react", 10 | "noLib": false, 11 | "suppressImplicitAnyIndexErrors": true 12 | }, 13 | "compileOnSave": false, 14 | "exclude": [ 15 | "node_modules" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /03 d3js-typescript/992 Map Interaction/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "module": "es6", 5 | "moduleResolution": "node", 6 | "declaration": false, 7 | "noImplicitAny": false, 8 | "sourceMap": true, 9 | "jsx": "react", 10 | "noLib": false, 11 | "suppressImplicitAnyIndexErrors": true 12 | }, 13 | "compileOnSave": false, 14 | "exclude": [ 15 | "node_modules" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /03 d3js-typescript/994 World Population/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "module": "es6", 5 | "moduleResolution": "node", 6 | "declaration": false, 7 | "noImplicitAny": false, 8 | "sourceMap": true, 9 | "jsx": "react", 10 | "noLib": false, 11 | "suppressImplicitAnyIndexErrors": true 12 | }, 13 | "compileOnSave": false, 14 | "exclude": [ 15 | "node_modules" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /03 d3js-typescript/993 Spain Cloropleth/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "module": "es6", 5 | "moduleResolution": "node", 6 | "declaration": false, 7 | "noImplicitAny": false, 8 | "sourceMap": true, 9 | "jsx": "react", 10 | "noLib": false, 11 | "suppressImplicitAnyIndexErrors": true, 12 | "allowSyntheticDefaultImports": true 13 | }, 14 | "compileOnSave": false, 15 | "exclude": [ 16 | "node_modules" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /00 basics/03 DOM 2/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test", 3 | "version": "1.0.0", 4 | "description": "Let's play now with events and javascript.", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "parcel index.html --open", 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "devDependencies": { 13 | "@types/d3": "^5.7.2", 14 | "parcel": "^1.12.4" 15 | }, 16 | "dependencies": { 17 | "d3": "^5.15.0", 18 | "typescript": "^3.8.3" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /00 basics/01 CSS/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
    10 |

    Normal paragraph

    11 | 12 |

    Red paragraph

    13 |
    14 | 15 |
      16 |
    1. Unique element
    2. 17 |
    3. Another list element
    4. 18 |
    5. 19 |

      Paragraph inside list element

      20 |

      Second paragraph

      21 |
    6. 22 |
    23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /00 basics/05 SVG 2/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Howdy! 4 | 5 | 6 | 7 | 10 | 12 | 13 | 14 | 15 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /01 nvd3/00 Lines/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
    9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /03 d3js-typescript/01 Lines/webpack.prod.js: -------------------------------------------------------------------------------- 1 | const webpack = require("webpack"); 2 | const merge = require("webpack-merge"); 3 | const base = require("./webpack.config.js"); 4 | const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin; 5 | 6 | module.exports = merge(base, { 7 | mode: "production", 8 | devtool: "none", 9 | output: { 10 | filename: "[name].js", 11 | }, 12 | plugins: [ 13 | new BundleAnalyzerPlugin({ 14 | analyzerMode: "static", 15 | openAnalyzer: false, 16 | reportFilename: "report/report.html", 17 | }), 18 | ], 19 | }); 20 | -------------------------------------------------------------------------------- /03 d3js-typescript/02 Bars/webpack.prod.js: -------------------------------------------------------------------------------- 1 | const webpack = require("webpack"); 2 | const merge = require("webpack-merge"); 3 | const base = require("./webpack.config.js"); 4 | const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin; 5 | 6 | module.exports = merge(base, { 7 | mode: "production", 8 | devtool: "none", 9 | output: { 10 | filename: "[name].js", 11 | }, 12 | plugins: [ 13 | new BundleAnalyzerPlugin({ 14 | analyzerMode: "static", 15 | openAnalyzer: false, 16 | reportFilename: "report/report.html", 17 | }), 18 | ], 19 | }); 20 | -------------------------------------------------------------------------------- /03 d3js-typescript/00 Playground/webpack.prod.js: -------------------------------------------------------------------------------- 1 | const webpack = require("webpack"); 2 | const merge = require("webpack-merge"); 3 | const base = require("./webpack.config.js"); 4 | const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin; 5 | 6 | module.exports = merge(base, { 7 | mode: "production", 8 | devtool: "none", 9 | output: { 10 | filename: "[name].js", 11 | }, 12 | plugins: [ 13 | new BundleAnalyzerPlugin({ 14 | analyzerMode: "static", 15 | openAnalyzer: false, 16 | reportFilename: "report/report.html", 17 | }), 18 | ], 19 | }); 20 | -------------------------------------------------------------------------------- /03 d3js-typescript/991 Basic Map/webpack.prod.js: -------------------------------------------------------------------------------- 1 | const webpack = require("webpack"); 2 | const merge = require("webpack-merge"); 3 | const base = require("./webpack.config.js"); 4 | const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin; 5 | 6 | module.exports = merge(base, { 7 | mode: "production", 8 | devtool: "none", 9 | output: { 10 | filename: "[name].js", 11 | }, 12 | plugins: [ 13 | new BundleAnalyzerPlugin({ 14 | analyzerMode: "static", 15 | openAnalyzer: false, 16 | reportFilename: "report/report.html", 17 | }), 18 | ], 19 | }); 20 | -------------------------------------------------------------------------------- /03 d3js-typescript/992 Map Interaction/webpack.prod.js: -------------------------------------------------------------------------------- 1 | const webpack = require("webpack"); 2 | const merge = require("webpack-merge"); 3 | const base = require("./webpack.config.js"); 4 | const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin; 5 | 6 | module.exports = merge(base, { 7 | mode: "production", 8 | devtool: "none", 9 | output: { 10 | filename: "[name].js", 11 | }, 12 | plugins: [ 13 | new BundleAnalyzerPlugin({ 14 | analyzerMode: "static", 15 | openAnalyzer: false, 16 | reportFilename: "report/report.html", 17 | }), 18 | ], 19 | }); 20 | -------------------------------------------------------------------------------- /03 d3js-typescript/993 Spain Cloropleth/webpack.prod.js: -------------------------------------------------------------------------------- 1 | const webpack = require("webpack"); 2 | const merge = require("webpack-merge"); 3 | const base = require("./webpack.config.js"); 4 | const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin; 5 | 6 | module.exports = merge(base, { 7 | mode: "production", 8 | devtool: "none", 9 | output: { 10 | filename: "[name].js", 11 | }, 12 | plugins: [ 13 | new BundleAnalyzerPlugin({ 14 | analyzerMode: "static", 15 | openAnalyzer: false, 16 | reportFilename: "report/report.html", 17 | }), 18 | ], 19 | }); 20 | -------------------------------------------------------------------------------- /03 d3js-typescript/994 World Population/webpack.prod.js: -------------------------------------------------------------------------------- 1 | const webpack = require("webpack"); 2 | const merge = require("webpack-merge"); 3 | const base = require("./webpack.config.js"); 4 | const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin; 5 | 6 | module.exports = merge(base, { 7 | mode: "production", 8 | devtool: "none", 9 | output: { 10 | filename: "[name].js", 11 | }, 12 | plugins: [ 13 | new BundleAnalyzerPlugin({ 14 | analyzerMode: "static", 15 | openAnalyzer: false, 16 | reportFilename: "report/report.html", 17 | }), 18 | ], 19 | }); 20 | -------------------------------------------------------------------------------- /00 basics/02 DOM/main.js: -------------------------------------------------------------------------------- 1 | // DOM API 2 | var element = document.getElementById('some-id'); 3 | //
  • Unique element
  • 4 | var plenght = document.getElementsByTagName('p').length; 5 | // 4 6 | var reds = document.getElementsByClassName('red'); 7 | // [

    Red paragraph

    ] 8 | console.log(reds[0].innerText); 9 | // "Red paragraph" 10 | 11 | // D3 Selection API 12 | var one = d3.select('p').size(); // select() only finds one 13 | // 1 14 | var many = d3.selectAll('p').size(); // selectAll() finds all 15 | // 4 16 | var reds = d3.selectAll('.red'); 17 | // [ > Array[1] ] 18 | console.log(reds.text()); 19 | // "Red paragraph" 20 | -------------------------------------------------------------------------------- /00 basics/03 DOM 2/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
    10 |

    Normal paragraph

    11 | 12 |

    Red paragraph

    13 |
    14 | 15 |
      16 |
    1. Unique element
    2. 17 |
    3. Another list element
    4. 18 |
    5. 19 |

      Paragraph inside list element

      20 |

      Second paragraph

      21 |
    6. 22 |
    23 |

    24 | Click on me! 25 |

    26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /00 basics/04 SVG/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 16 | 18 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /00 basics/02 DOM/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
    10 |

    Normal paragraph

    11 | 12 |

    Red paragraph

    13 |
    14 | 15 |
      16 |
    1. Unique element
    2. 17 |
    3. Another list element
    4. 18 |
    5. 19 |

      Paragraph inside list element

      20 |

      Second paragraph

      21 |
    6. 22 |
    23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /03 d3js-typescript/01 Lines/webpack.dev.js: -------------------------------------------------------------------------------- 1 | const webpack = require("webpack"); 2 | const merge = require("webpack-merge"); 3 | const base = require("./webpack.config.js"); 4 | const path = require("path"); 5 | 6 | const basePath = __dirname; 7 | 8 | module.exports = merge(base, { 9 | mode: "development", 10 | devtool: "eval-source-map", 11 | output: { 12 | filename: "[name].[hash].js", 13 | }, 14 | devServer: { 15 | contentBase: path.join(basePath, "dist"), 16 | inline: true, 17 | host: "localhost", 18 | port: 4301, 19 | historyApiFallback: true, 20 | hot: true, 21 | stats: "minimal" 22 | }, 23 | plugins: [ 24 | new webpack.HotModuleReplacementPlugin(), 25 | new webpack.NamedModulesPlugin() 26 | ], 27 | }); 28 | -------------------------------------------------------------------------------- /03 d3js-typescript/02 Bars/webpack.dev.js: -------------------------------------------------------------------------------- 1 | const webpack = require("webpack"); 2 | const merge = require("webpack-merge"); 3 | const base = require("./webpack.config.js"); 4 | const path = require("path"); 5 | 6 | const basePath = __dirname; 7 | 8 | module.exports = merge(base, { 9 | mode: "development", 10 | devtool: "eval-source-map", 11 | output: { 12 | filename: "[name].[hash].js", 13 | }, 14 | devServer: { 15 | contentBase: path.join(basePath, "dist"), 16 | inline: true, 17 | host: "localhost", 18 | port: 4301, 19 | historyApiFallback: true, 20 | hot: true, 21 | stats: "minimal" 22 | }, 23 | plugins: [ 24 | new webpack.HotModuleReplacementPlugin(), 25 | new webpack.NamedModulesPlugin() 26 | ], 27 | }); 28 | -------------------------------------------------------------------------------- /03 d3js-typescript/00 Playground/webpack.dev.js: -------------------------------------------------------------------------------- 1 | const webpack = require("webpack"); 2 | const merge = require("webpack-merge"); 3 | const base = require("./webpack.config.js"); 4 | const path = require("path"); 5 | 6 | const basePath = __dirname; 7 | 8 | module.exports = merge(base, { 9 | mode: "development", 10 | devtool: "eval-source-map", 11 | output: { 12 | filename: "[name].[hash].js", 13 | }, 14 | devServer: { 15 | contentBase: path.join(basePath, "dist"), 16 | inline: true, 17 | host: "localhost", 18 | port: 4301, 19 | historyApiFallback: true, 20 | hot: true, 21 | stats: "minimal" 22 | }, 23 | plugins: [ 24 | new webpack.HotModuleReplacementPlugin(), 25 | new webpack.NamedModulesPlugin() 26 | ], 27 | }); 28 | -------------------------------------------------------------------------------- /03 d3js-typescript/991 Basic Map/webpack.dev.js: -------------------------------------------------------------------------------- 1 | const webpack = require("webpack"); 2 | const merge = require("webpack-merge"); 3 | const base = require("./webpack.config.js"); 4 | const path = require("path"); 5 | 6 | const basePath = __dirname; 7 | 8 | module.exports = merge(base, { 9 | mode: "development", 10 | devtool: "eval-source-map", 11 | output: { 12 | filename: "[name].[hash].js", 13 | }, 14 | devServer: { 15 | contentBase: path.join(basePath, "dist"), 16 | inline: true, 17 | host: "localhost", 18 | port: 4301, 19 | historyApiFallback: true, 20 | hot: true, 21 | stats: "minimal" 22 | }, 23 | plugins: [ 24 | new webpack.HotModuleReplacementPlugin(), 25 | new webpack.NamedModulesPlugin() 26 | ], 27 | }); 28 | -------------------------------------------------------------------------------- /01 nvd3/01 BubbleChart/data.js: -------------------------------------------------------------------------------- 1 | function randomData(groups, points) { //# groups,# points per group 2 | // smiley and thin-x are our custom symbols! 3 | var data = [], 4 | shapes = ['thin-x', 'circle', 'cross', 'triangle-up', 'triangle-down', 'diamond', 'square'], 5 | random = d3.random.normal(); 6 | 7 | for (i = 0; i < groups; i++) { 8 | data.push({ 9 | key: 'Group ' + i, 10 | values: [] 11 | }); 12 | 13 | for (j = 0; j < points; j++) { 14 | data[i].values.push({ 15 | x: random(), 16 | y: random(), 17 | size: Math.round(Math.random() * 100) / 100, 18 | shape: shapes[j % shapes.length] 19 | }); 20 | } 21 | } 22 | 23 | return data; 24 | } 25 | -------------------------------------------------------------------------------- /03 d3js-typescript/992 Map Interaction/webpack.dev.js: -------------------------------------------------------------------------------- 1 | const webpack = require("webpack"); 2 | const merge = require("webpack-merge"); 3 | const base = require("./webpack.config.js"); 4 | const path = require("path"); 5 | 6 | const basePath = __dirname; 7 | 8 | module.exports = merge(base, { 9 | mode: "development", 10 | devtool: "eval-source-map", 11 | output: { 12 | filename: "[name].[hash].js", 13 | }, 14 | devServer: { 15 | contentBase: path.join(basePath, "dist"), 16 | inline: true, 17 | host: "localhost", 18 | port: 4302, 19 | historyApiFallback: true, 20 | hot: true, 21 | stats: "minimal" 22 | }, 23 | plugins: [ 24 | new webpack.HotModuleReplacementPlugin(), 25 | new webpack.NamedModulesPlugin() 26 | ], 27 | }); 28 | -------------------------------------------------------------------------------- /03 d3js-typescript/993 Spain Cloropleth/webpack.dev.js: -------------------------------------------------------------------------------- 1 | const webpack = require("webpack"); 2 | const merge = require("webpack-merge"); 3 | const base = require("./webpack.config.js"); 4 | const path = require("path"); 5 | 6 | const basePath = __dirname; 7 | 8 | module.exports = merge(base, { 9 | mode: "development", 10 | devtool: "eval-source-map", 11 | output: { 12 | filename: "[name].[hash].js", 13 | }, 14 | devServer: { 15 | contentBase: path.join(basePath, "dist"), 16 | inline: true, 17 | host: "localhost", 18 | port: 4303, 19 | historyApiFallback: true, 20 | hot: true, 21 | stats: "minimal" 22 | }, 23 | plugins: [ 24 | new webpack.HotModuleReplacementPlugin(), 25 | new webpack.NamedModulesPlugin() 26 | ], 27 | }); 28 | -------------------------------------------------------------------------------- /03 d3js-typescript/994 World Population/webpack.dev.js: -------------------------------------------------------------------------------- 1 | const webpack = require("webpack"); 2 | const merge = require("webpack-merge"); 3 | const base = require("./webpack.config.js"); 4 | const path = require("path"); 5 | 6 | const basePath = __dirname; 7 | 8 | module.exports = merge(base, { 9 | mode: "development", 10 | devtool: "eval-source-map", 11 | output: { 12 | filename: "[name].[hash].js", 13 | }, 14 | devServer: { 15 | contentBase: path.join(basePath, "dist"), 16 | inline: true, 17 | host: "localhost", 18 | port: 4304, 19 | historyApiFallback: true, 20 | hot: true, 21 | stats: "minimal" 22 | }, 23 | plugins: [ 24 | new webpack.HotModuleReplacementPlugin(), 25 | new webpack.NamedModulesPlugin() 26 | ], 27 | }); 28 | -------------------------------------------------------------------------------- /03 d3js-typescript/02 Bars/src/app.scss: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css?family=Montserrat:300,400,500,600,700'); 2 | 3 | :global{ 4 | body { 5 | font-family: 'Montserrat', sans-serif; 6 | font-weight: 300; 7 | display: flex; 8 | flex-direction: column; 9 | justify-content: flex-start; 10 | align-items: stretch; 11 | margin: 0; 12 | padding: 2rem; 13 | background-color: #e2e1e0; 14 | } 15 | 16 | .card { 17 | display: flex; 18 | flex-direction: column; 19 | justify-content: flex-start; 20 | align-items: center; 21 | min-height: 5rem; 22 | padding: 1rem; 23 | margin-bottom: 2rem; 24 | background-color: #fff; 25 | border-radius: 2px; 26 | box-shadow: 0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /03 d3js-typescript/01 Lines/src/app.scss: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css?family=Montserrat:300,400,500,600,700'); 2 | 3 | :global{ 4 | body { 5 | font-family: 'Montserrat', sans-serif; 6 | font-weight: 300; 7 | display: flex; 8 | flex-direction: column; 9 | justify-content: flex-start; 10 | align-items: stretch; 11 | margin: 0; 12 | padding: 2rem; 13 | background-color: #e2e1e0; 14 | } 15 | 16 | .card { 17 | display: flex; 18 | flex-direction: column; 19 | justify-content: flex-start; 20 | align-items: center; 21 | min-height: 5rem; 22 | padding: 1rem; 23 | margin-bottom: 2rem; 24 | background-color: #fff; 25 | border-radius: 2px; 26 | box-shadow: 0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /03 d3js-typescript/00 Playground/src/app.scss: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css?family=Montserrat:300,400,500,600,700'); 2 | 3 | :global{ 4 | body { 5 | font-family: 'Montserrat', sans-serif; 6 | font-weight: 300; 7 | display: flex; 8 | flex-direction: column; 9 | justify-content: flex-start; 10 | align-items: stretch; 11 | margin: 0; 12 | padding: 2rem; 13 | background-color: #e2e1e0; 14 | } 15 | 16 | .card { 17 | display: flex; 18 | flex-direction: column; 19 | justify-content: flex-start; 20 | align-items: center; 21 | min-height: 5rem; 22 | padding: 1rem; 23 | margin-bottom: 2rem; 24 | background-color: #fff; 25 | border-radius: 2px; 26 | box-shadow: 0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /03 d3js-typescript/991 Basic Map/src/app.scss: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css?family=Montserrat:300,400,500,600,700'); 2 | 3 | :global{ 4 | body { 5 | font-family: 'Montserrat', sans-serif; 6 | font-weight: 300; 7 | display: flex; 8 | flex-direction: column; 9 | justify-content: flex-start; 10 | align-items: stretch; 11 | margin: 0; 12 | padding: 2rem; 13 | background-color: #e2e1e0; 14 | } 15 | 16 | .card { 17 | display: flex; 18 | flex-direction: column; 19 | justify-content: flex-start; 20 | align-items: center; 21 | min-height: 5rem; 22 | padding: 1rem; 23 | margin-bottom: 2rem; 24 | background-color: #fff; 25 | border-radius: 2px; 26 | box-shadow: 0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /03 d3js-typescript/992 Map Interaction/src/app.scss: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css?family=Montserrat:300,400,500,600,700'); 2 | 3 | :global{ 4 | body { 5 | font-family: 'Montserrat', sans-serif; 6 | font-weight: 300; 7 | display: flex; 8 | flex-direction: column; 9 | justify-content: flex-start; 10 | align-items: stretch; 11 | margin: 0; 12 | padding: 2rem; 13 | background-color: #e2e1e0; 14 | } 15 | 16 | .card { 17 | display: flex; 18 | flex-direction: column; 19 | justify-content: flex-start; 20 | align-items: center; 21 | min-height: 5rem; 22 | padding: 1rem; 23 | margin-bottom: 2rem; 24 | background-color: #fff; 25 | border-radius: 2px; 26 | box-shadow: 0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /03 d3js-typescript/993 Spain Cloropleth/src/app.scss: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css?family=Montserrat:300,400,500,600,700'); 2 | 3 | :global{ 4 | body { 5 | font-family: 'Montserrat', sans-serif; 6 | font-weight: 300; 7 | display: flex; 8 | flex-direction: column; 9 | justify-content: flex-start; 10 | align-items: stretch; 11 | margin: 0; 12 | padding: 2rem; 13 | background-color: #e2e1e0; 14 | } 15 | 16 | .card { 17 | display: flex; 18 | flex-direction: column; 19 | justify-content: flex-start; 20 | align-items: center; 21 | min-height: 5rem; 22 | padding: 1rem; 23 | margin-bottom: 2rem; 24 | background-color: #fff; 25 | border-radius: 2px; 26 | box-shadow: 0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /03 d3js-typescript/994 World Population/src/app.scss: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css?family=Montserrat:300,400,500,600,700'); 2 | 3 | :global{ 4 | body { 5 | font-family: 'Montserrat', sans-serif; 6 | font-weight: 300; 7 | display: flex; 8 | flex-direction: column; 9 | justify-content: flex-start; 10 | align-items: stretch; 11 | margin: 0; 12 | padding: 2rem; 13 | background-color: #e2e1e0; 14 | } 15 | 16 | .card { 17 | display: flex; 18 | flex-direction: column; 19 | justify-content: flex-start; 20 | align-items: center; 21 | min-height: 5rem; 22 | padding: 1rem; 23 | margin-bottom: 2rem; 24 | background-color: #fff; 25 | border-radius: 2px; 26 | box-shadow: 0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /03 d3js-typescript/01 Lines/src/d3/linechart.data.ts: -------------------------------------------------------------------------------- 1 | export const avgTemp = [14, 13, 14, 16, 19, 25, 29, 29, 27, 21, 17, 17]; 2 | export const minTemp = [11, 10, 11, 13, 16, 21, 24, 25, 23, 17, 14, 14]; 3 | export const maxTemp = [17, 16, 17, 19, 23, 27, 31, 31, 28, 23, 19, 19]; 4 | 5 | export interface TempStat { 6 | id: string; 7 | name: string; 8 | values: number[]; 9 | } 10 | 11 | export const malagaStats: TempStat[] = [ 12 | { 13 | id: "avg", 14 | name: "Average Temp", 15 | values: [14, 13, 14, 16, 19, 25, 29, 29, 27, 21, 17, 17], 16 | }, 17 | { 18 | id: "min", 19 | name: "Min Temp", 20 | values: [11, 10, 11, 13, 16, 21, 24, 25, 23, 17, 14, 14], 21 | }, 22 | { 23 | id: "max", 24 | name: "Max Temp", 25 | values: [17, 16, 17, 19, 23, 27, 31, 31, 28, 23, 19, 19], 26 | } 27 | ]; -------------------------------------------------------------------------------- /01 nvd3/01 BubbleChart/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 31 | 32 | 33 | 34 | 35 |
    36 | 37 |
    38 | 39 | 40 | -------------------------------------------------------------------------------- /03 d3js-typescript/993 Spain Cloropleth/src/d3/effects.d3.ts: -------------------------------------------------------------------------------- 1 | export const defineGlowEffect = (defsSelection) => { 2 | const id = "glow" 3 | const stdDeviation = 0.55; 4 | const colorMatrix = "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0"; 5 | 6 | const filter = defsSelection.append("filter") 7 | .attr("id", id) 8 | .attr("x", "-50%") 9 | .attr("y", "-50%") 10 | .attr("width", "200%") 11 | .attr("height", "200%") 12 | filter.append("feColorMatrix") 13 | .attr("type", "matrix") 14 | .attr("values", colorMatrix); 15 | filter.append("feGaussianBlur") 16 | // .attr("in", "SourceGraphics") 17 | .attr("stdDeviation", stdDeviation) 18 | .attr("result", "coloredBlur"); 19 | const feMerge = filter.append("feMerge") 20 | feMerge.append("feMergeNode") 21 | .attr("in", "coloredBlur"); 22 | feMerge.append("feMergeNode") 23 | .attr("in", "SourceGraphic"); 24 | 25 | return `url(#${id})`; 26 | } 27 | 28 | 29 | -------------------------------------------------------------------------------- /00 basics/03 DOM 2/src/index.ts: -------------------------------------------------------------------------------- 1 | import * as d3 from "d3"; 2 | 3 | // DOM API 4 | var element = document.getElementById("some-id"); 5 | //
  • Unique element
  • 6 | console.log(element); 7 | 8 | var plength = document.getElementsByTagName("p").length; 9 | // 4 10 | console.log(plength); 11 | 12 | var reds = document.getElementsByClassName("red"); 13 | // [

    Red paragraph

    ] 14 | console.log(reds[0].innerHTML); 15 | // "Red paragraph" 16 | 17 | // D3 Selection API 18 | var one = d3.select("p").size(); // select() only finds one 19 | console.log(one); 20 | 21 | // 1 22 | var many = d3.selectAll("p").size(); // selectAll() finds all 23 | console.log(many); 24 | 25 | // 4 26 | var redElements = d3.selectAll(".red"); 27 | // [ > Array[1] ] 28 | console.log(redElements.text()); 29 | // "Red paragraph" 30 | 31 | var clickMe = document.getElementById("click-me"); 32 | clickMe.onclick = function() { 33 | if (this.style.backgroundColor) { 34 | this.style.backgroundColor = ""; 35 | } else { 36 | this.style.backgroundColor = "red"; 37 | } 38 | }; 39 | -------------------------------------------------------------------------------- /01 nvd3/01 BubbleChart/main.js: -------------------------------------------------------------------------------- 1 | // register our custom symbols to nvd3 2 | // make sure your path is valid given any size because size scales if the chart scales. 3 | nv.utils.symbolMap.set('thin-x', function(size) { 4 | size = Math.sqrt(size); 5 | return 'M' + (-size/2) + ',' + (-size/2) + 6 | 'l' + size + ',' + size + 7 | 'm0,' + -(size) + 8 | 'l' + (-size) + ',' + size; 9 | }); 10 | 11 | // create the chart 12 | var chart; 13 | nv.addGraph(function() { 14 | chart = nv.models.scatterChart() 15 | .showDistX(true) 16 | .showDistY(true) 17 | .useVoronoi(true) 18 | .color(d3.scale.category10().range()) 19 | .duration(300) 20 | ; 21 | 22 | chart.xAxis.tickFormat(d3.format('.02f')); 23 | chart.yAxis.tickFormat(d3.format('.02f')); 24 | 25 | d3.select('#test1 svg') 26 | .datum(randomData(4,40)) 27 | .call(chart); 28 | 29 | nv.utils.windowResize(chart.update); 30 | 31 | return chart; 32 | }); 33 | 34 | -------------------------------------------------------------------------------- /03 d3js-typescript/02 Bars/src/d3/barchart.data.ts: -------------------------------------------------------------------------------- 1 | // Generador de datos aleatorios en formato de array de n posiciones. 2 | const randomArrayGenerator = n => Array.from({length: n}, () => Math.random()); 3 | 4 | // Otra forma podría ser Array(n).fill(0).map(n => Math.random()); 5 | 6 | 7 | // Singleton inicializado con datos aleatorios. Array de 20 posiciones. 8 | export let randomData = randomArrayGenerator(20); 9 | 10 | // Creamos un mecanismo para modifcar estos datos aleatorios cada segundo. 11 | // Simula una fuente de datos 'real-time'. Permitimos la suscripción de un 12 | // callback para informar a la visualización de que hubo modificaciones. 13 | export const startRealTimeDataV1 = (onDataChange: (newData) => void) => { 14 | setInterval(() => { 15 | randomData = randomArrayGenerator(20); 16 | onDataChange && onDataChange(randomData); 17 | }, 1000); 18 | } 19 | 20 | export const startRealTimeDataV2 = (onDataChange: (data: any[]) => void) => { 21 | setInterval(() => { 22 | const n = Math.random() * 10 + 10; // [10, 20] 23 | onDataChange && onDataChange(randomArrayGenerator(n)); 24 | }, 1500); 25 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Lemoncode 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /01 nvd3/00 Lines/main.js: -------------------------------------------------------------------------------- 1 | 2 | // Wrapping in nv.addGraph allows for '0 timeout render', stores rendered charts in nv.graphs, and may do more in the future... it's NOT required 3 | var chart; 4 | var data; 5 | var legendPosition = "top"; 6 | 7 | nv.addGraph(function() { 8 | chart = nv.models.lineChart() 9 | .options({ 10 | duration: 300, 11 | useInteractiveGuideline: true 12 | }) 13 | ; 14 | // chart sub-models (ie. xAxis, yAxis, etc) when accessed directly, return themselves, not the parent chart, so need to chain separately 15 | chart.xAxis 16 | .axisLabel("Time (s)") 17 | .tickFormat(d3.format(',.1f')) 18 | .staggerLabels(true) 19 | ; 20 | chart.yAxis 21 | .axisLabel('Voltage (v)') 22 | .tickFormat(function(d) { 23 | if (d == null) { 24 | return 'N/A'; 25 | } 26 | return d3.format(',.2f')(d); 27 | }) 28 | ; 29 | data = sinAndCos(); 30 | d3.select('#chart1').append('svg') 31 | .datum(data) 32 | .call(chart); 33 | nv.utils.windowResize(chart.update); 34 | return chart; 35 | }); 36 | -------------------------------------------------------------------------------- /02 d3js-es5/00 SVG/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | $10 27 | $80 28 | 29 | 30 | 31 | January 2014 32 | April 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /01 nvd3/00 Lines/data.js: -------------------------------------------------------------------------------- 1 | function sinAndCos() { 2 | var sin = [], 3 | sin2 = [], 4 | cos = [], 5 | rand = [], 6 | rand2 = [] 7 | ; 8 | for (var i = 0; i < 100; i++) { 9 | sin.push({x: i, y: i % 10 == 5 ? null : Math.sin(i/10) }); //the nulls are to show how defined works 10 | sin2.push({x: i, y: Math.sin(i/5) * 0.4 - 0.25}); 11 | cos.push({x: i, y: .5 * Math.cos(i/10)}); 12 | rand.push({x:i, y: Math.random() / 10}); 13 | rand2.push({x: i, y: Math.cos(i/10) + Math.random() / 10 }) 14 | } 15 | return [ 16 | { 17 | area: true, 18 | values: sin, 19 | key: "Sine Wave", 20 | color: "#ff7f0e", 21 | strokeWidth: 4, 22 | classed: 'dashed' 23 | }, 24 | { 25 | values: cos, 26 | key: "Cosine Wave", 27 | color: "#2ca02c" 28 | }, 29 | { 30 | values: rand, 31 | key: "Random Points", 32 | color: "#2222ff" 33 | }, 34 | { 35 | values: rand2, 36 | key: "Random Cosine", 37 | color: "#667711", 38 | strokeWidth: 3.5 39 | }, 40 | { 41 | area: true, 42 | values: sin2, 43 | key: "Fill opacity", 44 | color: "#EF9CFB", 45 | fillOpacity: .1 46 | } 47 | ]; 48 | } 49 | -------------------------------------------------------------------------------- /00 basics/05 SVG 2/readme.md: -------------------------------------------------------------------------------- 1 | # Path and transformations 2 | 3 | Let's play a bit with paths and transformation. 4 | 5 | # Steps 6 | 7 | - Let's define our initial HTML 8 | 9 | ```html 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | ``` 23 | 24 | - In SVG we can create a group of element and apply transformations (translations, rotations...), let' draw some text. 25 | 26 | _index.html_ 27 | 28 | ```diff 29 | 30 | + 31 | + Howdy! 32 | + 33 | 34 | ``` 35 | 36 | - One interesting element is the polygon path: 37 | 38 | ```html 39 | 40 | 43 | 45 | 46 | ``` 47 | 48 | - You can as well close the curve: 49 | 50 | ```html 51 | 52 | 54 | 55 | 56 | ``` 57 | 58 | > Let's play with the transformations, one of the things we can do is to rotate the shape: 59 | 60 | https://developer.mozilla.org/es/docs/Web/SVG/Attribute/transform -------------------------------------------------------------------------------- /03 d3js-typescript/02 Bars/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "d3js-playground", 3 | "version": "1.0.0", 4 | "description": "D3.js playground", 5 | "scripts": { 6 | "start": "webpack-dev-server --config=webpack.dev.js", 7 | "build:dev": "rimraf dist && webpack --config webpack.dev.js", 8 | "build:prod": "rimraf dist && webpack -p --config webpack.prod.js" 9 | }, 10 | "author": "Javier Calzado", 11 | "license": "MIT", 12 | "dependencies": { 13 | "@babel/polyfill": "^7.2.5", 14 | "d3": "^5.7.0" 15 | }, 16 | "devDependencies": { 17 | "@babel/cli": "^7.2.3", 18 | "@babel/core": "^7.2.2", 19 | "@babel/plugin-proposal-class-properties": "^7.2.3", 20 | "@babel/plugin-proposal-object-rest-spread": "^7.2.0", 21 | "@babel/preset-env": "^7.2.3", 22 | "@babel/preset-typescript": "^7.1.0", 23 | "@types/d3": "^5.5.0", 24 | "@types/node": "^10.12.18", 25 | "babel-loader": "^8.0.5", 26 | "css-loader": "^2.1.0", 27 | "file-loader": "^3.0.1", 28 | "html-webpack-plugin": "^3.2.0", 29 | "json-loader": "^0.5.7", 30 | "node-sass": "^4.9.0", 31 | "prettier": "^1.15.3", 32 | "resolve-url-loader": "^2.3.0", 33 | "rimraf": "^2.6.2", 34 | "sass-loader": "^7.0.1", 35 | "style-loader": "^0.23.1", 36 | "ts-lint": "^4.5.1", 37 | "typescript": "^3.1.2", 38 | "url-loader": "^1.1.1", 39 | "webpack": "^4.20.2", 40 | "webpack-bundle-analyzer": "^3.0.2", 41 | "webpack-cli": "^3.1.2", 42 | "webpack-dev-server": "^3.1.14", 43 | "webpack-merge": "^4.1.4" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /03 d3js-typescript/01 Lines/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "d3js-playground", 3 | "version": "1.0.0", 4 | "description": "D3.js playground", 5 | "scripts": { 6 | "start": "webpack-dev-server --config=webpack.dev.js", 7 | "build:dev": "rimraf dist && webpack --config webpack.dev.js", 8 | "build:prod": "rimraf dist && webpack -p --config webpack.prod.js" 9 | }, 10 | "author": "Javier Calzado", 11 | "license": "MIT", 12 | "dependencies": { 13 | "@babel/polyfill": "^7.2.5", 14 | "d3": "^5.7.0" 15 | }, 16 | "devDependencies": { 17 | "@babel/cli": "^7.2.3", 18 | "@babel/core": "^7.2.2", 19 | "@babel/plugin-proposal-class-properties": "^7.2.3", 20 | "@babel/plugin-proposal-object-rest-spread": "^7.2.0", 21 | "@babel/preset-env": "^7.2.3", 22 | "@babel/preset-typescript": "^7.1.0", 23 | "@types/d3": "^5.5.0", 24 | "@types/node": "^10.12.18", 25 | "babel-loader": "^8.0.5", 26 | "css-loader": "^2.1.0", 27 | "file-loader": "^3.0.1", 28 | "html-webpack-plugin": "^3.2.0", 29 | "json-loader": "^0.5.7", 30 | "node-sass": "^4.9.0", 31 | "prettier": "^1.15.3", 32 | "resolve-url-loader": "^2.3.0", 33 | "rimraf": "^2.6.2", 34 | "sass-loader": "^7.0.1", 35 | "style-loader": "^0.23.1", 36 | "ts-lint": "^4.5.1", 37 | "typescript": "^3.1.2", 38 | "url-loader": "^1.1.1", 39 | "webpack": "^4.20.2", 40 | "webpack-bundle-analyzer": "^3.0.2", 41 | "webpack-cli": "^3.1.2", 42 | "webpack-dev-server": "^3.1.14", 43 | "webpack-merge": "^4.1.4" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /03 d3js-typescript/00 Playground/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "d3js-playground", 3 | "version": "1.0.0", 4 | "description": "D3.js playground", 5 | "scripts": { 6 | "start": "webpack-dev-server --config=webpack.dev.js", 7 | "build:dev": "rimraf dist && webpack --config webpack.dev.js", 8 | "build:prod": "rimraf dist && webpack -p --config webpack.prod.js" 9 | }, 10 | "author": "Javier Calzado", 11 | "license": "MIT", 12 | "dependencies": { 13 | "@babel/polyfill": "^7.2.5", 14 | "d3": "^5.7.0" 15 | }, 16 | "devDependencies": { 17 | "@babel/cli": "^7.2.3", 18 | "@babel/core": "^7.2.2", 19 | "@babel/plugin-proposal-class-properties": "^7.2.3", 20 | "@babel/plugin-proposal-object-rest-spread": "^7.2.0", 21 | "@babel/preset-env": "^7.2.3", 22 | "@babel/preset-typescript": "^7.1.0", 23 | "@types/d3": "^5.5.0", 24 | "@types/node": "^10.12.18", 25 | "babel-loader": "^8.0.5", 26 | "css-loader": "^2.1.0", 27 | "file-loader": "^3.0.1", 28 | "html-webpack-plugin": "^3.2.0", 29 | "json-loader": "^0.5.7", 30 | "node-sass": "^4.9.0", 31 | "prettier": "^1.15.3", 32 | "resolve-url-loader": "^2.3.0", 33 | "rimraf": "^2.6.2", 34 | "sass-loader": "^7.0.1", 35 | "style-loader": "^0.23.1", 36 | "ts-lint": "^4.5.1", 37 | "typescript": "^3.1.2", 38 | "url-loader": "^1.1.1", 39 | "webpack": "^4.20.2", 40 | "webpack-bundle-analyzer": "^3.0.2", 41 | "webpack-cli": "^3.1.2", 42 | "webpack-dev-server": "^3.1.14", 43 | "webpack-merge": "^4.1.4" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /03 d3js-typescript/991 Basic Map/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "d3js-basic-map", 3 | "version": "1.0.0", 4 | "description": "D3.js Basic Map Demo", 5 | "scripts": { 6 | "start": "webpack-dev-server --config=webpack.dev.js", 7 | "build:dev": "rimraf dist && webpack --config webpack.dev.js", 8 | "build:prod": "rimraf dist && webpack -p --config webpack.prod.js" 9 | }, 10 | "author": "Javier Calzado", 11 | "license": "MIT", 12 | "dependencies": { 13 | "@babel/polyfill": "^7.2.5", 14 | "d3": "^5.7.0" 15 | }, 16 | "devDependencies": { 17 | "@babel/cli": "^7.2.3", 18 | "@babel/core": "^7.2.2", 19 | "@babel/plugin-proposal-class-properties": "^7.2.3", 20 | "@babel/plugin-proposal-object-rest-spread": "^7.2.0", 21 | "@babel/preset-env": "^7.2.3", 22 | "@babel/preset-typescript": "^7.1.0", 23 | "@types/d3": "^5.5.0", 24 | "@types/node": "^10.12.18", 25 | "babel-loader": "^8.0.5", 26 | "css-loader": "^2.1.0", 27 | "file-loader": "^3.0.1", 28 | "html-webpack-plugin": "^3.2.0", 29 | "json-loader": "^0.5.7", 30 | "node-sass": "^4.9.0", 31 | "prettier": "^1.15.3", 32 | "resolve-url-loader": "^2.3.0", 33 | "rimraf": "^2.6.2", 34 | "sass-loader": "^7.0.1", 35 | "style-loader": "^0.23.1", 36 | "ts-lint": "^4.5.1", 37 | "typescript": "^3.1.2", 38 | "url-loader": "^1.1.1", 39 | "webpack": "^4.20.2", 40 | "webpack-bundle-analyzer": "^3.0.2", 41 | "webpack-cli": "^3.1.2", 42 | "webpack-dev-server": "^3.1.14", 43 | "webpack-merge": "^4.1.4" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /03 d3js-typescript/992 Map Interaction/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "d3js-map-interaction", 3 | "version": "1.0.0", 4 | "description": "D3.js Map Interaction Demo", 5 | "scripts": { 6 | "start": "webpack-dev-server --config=webpack.dev.js", 7 | "build:dev": "rimraf dist && webpack --config webpack.dev.js", 8 | "build:prod": "rimraf dist && webpack -p --config webpack.prod.js" 9 | }, 10 | "author": "Javier Calzado", 11 | "license": "MIT", 12 | "dependencies": { 13 | "@babel/polyfill": "^7.2.5", 14 | "d3": "^5.7.0" 15 | }, 16 | "devDependencies": { 17 | "@babel/cli": "^7.2.3", 18 | "@babel/core": "^7.2.2", 19 | "@babel/plugin-proposal-class-properties": "^7.2.3", 20 | "@babel/plugin-proposal-object-rest-spread": "^7.2.0", 21 | "@babel/preset-env": "^7.2.3", 22 | "@babel/preset-typescript": "^7.1.0", 23 | "@types/d3": "^5.5.0", 24 | "@types/node": "^10.12.18", 25 | "babel-loader": "^8.0.5", 26 | "css-loader": "^2.1.0", 27 | "file-loader": "^3.0.1", 28 | "html-webpack-plugin": "^3.2.0", 29 | "json-loader": "^0.5.7", 30 | "node-sass": "^4.9.0", 31 | "prettier": "^1.15.3", 32 | "resolve-url-loader": "^2.3.0", 33 | "rimraf": "^2.6.2", 34 | "sass-loader": "^7.0.1", 35 | "style-loader": "^0.23.1", 36 | "ts-lint": "^4.5.1", 37 | "typescript": "^3.1.2", 38 | "url-loader": "^1.1.1", 39 | "webpack": "^4.20.2", 40 | "webpack-bundle-analyzer": "^3.0.2", 41 | "webpack-cli": "^3.1.2", 42 | "webpack-dev-server": "^3.1.14", 43 | "webpack-merge": "^4.1.4" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /03 d3js-typescript/994 World Population/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "d3js-world-population", 3 | "version": "1.0.0", 4 | "description": "D3.js World Population Demo", 5 | "scripts": { 6 | "start": "webpack-dev-server --config=webpack.dev.js", 7 | "build:dev": "rimraf dist && webpack --config webpack.dev.js", 8 | "build:prod": "rimraf dist && webpack -p --config webpack.prod.js" 9 | }, 10 | "author": "Javier Calzado", 11 | "license": "MIT", 12 | "dependencies": { 13 | "@babel/polyfill": "^7.2.5", 14 | "d3": "^5.7.0" 15 | }, 16 | "devDependencies": { 17 | "@babel/cli": "^7.2.3", 18 | "@babel/core": "^7.2.2", 19 | "@babel/plugin-proposal-class-properties": "^7.2.3", 20 | "@babel/plugin-proposal-object-rest-spread": "^7.2.0", 21 | "@babel/preset-env": "^7.2.3", 22 | "@babel/preset-typescript": "^7.1.0", 23 | "@types/d3": "^5.5.0", 24 | "@types/node": "^10.12.18", 25 | "babel-loader": "^8.0.5", 26 | "css-loader": "^2.1.0", 27 | "file-loader": "^3.0.1", 28 | "html-webpack-plugin": "^3.2.0", 29 | "json-loader": "^0.5.7", 30 | "node-sass": "^4.9.0", 31 | "prettier": "^1.15.3", 32 | "resolve-url-loader": "^2.3.0", 33 | "rimraf": "^2.6.2", 34 | "sass-loader": "^7.0.1", 35 | "style-loader": "^0.23.1", 36 | "ts-lint": "^4.5.1", 37 | "typescript": "^3.1.2", 38 | "url-loader": "^1.1.1", 39 | "webpack": "^4.20.2", 40 | "webpack-bundle-analyzer": "^3.0.2", 41 | "webpack-cli": "^3.1.2", 42 | "webpack-dev-server": "^3.1.14", 43 | "webpack-merge": "^4.1.4" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /03 d3js-typescript/993 Spain Cloropleth/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "d3js-spain-cloropleth", 3 | "version": "1.0.0", 4 | "description": "D3.js Spain Cloropleth Demo", 5 | "scripts": { 6 | "start": "webpack-dev-server --config=webpack.dev.js", 7 | "build:dev": "rimraf dist && webpack --config webpack.dev.js", 8 | "build:prod": "rimraf dist && webpack -p --config webpack.prod.js" 9 | }, 10 | "author": "Javier Calzado", 11 | "license": "MIT", 12 | "dependencies": { 13 | "@babel/polyfill": "^7.2.5", 14 | "d3": "^5.7.0", 15 | "d3-composite-projections": "^1.2.0", 16 | "topojson": "^3.0.2" 17 | }, 18 | "devDependencies": { 19 | "@babel/cli": "^7.2.3", 20 | "@babel/core": "^7.2.2", 21 | "@babel/plugin-proposal-class-properties": "^7.2.3", 22 | "@babel/plugin-proposal-object-rest-spread": "^7.2.0", 23 | "@babel/preset-env": "^7.2.3", 24 | "@babel/preset-typescript": "^7.1.0", 25 | "@types/d3": "^5.5.0", 26 | "@types/node": "^10.12.18", 27 | "@types/topojson": "^3.2.1", 28 | "babel-loader": "^8.0.5", 29 | "css-loader": "^2.1.0", 30 | "file-loader": "^3.0.1", 31 | "html-webpack-plugin": "^3.2.0", 32 | "json-loader": "^0.5.7", 33 | "node-sass": "^4.9.0", 34 | "prettier": "^1.15.3", 35 | "resolve-url-loader": "^2.3.0", 36 | "rimraf": "^2.6.2", 37 | "sass-loader": "^7.0.1", 38 | "style-loader": "^0.23.1", 39 | "ts-lint": "^4.5.1", 40 | "typescript": "^3.1.2", 41 | "url-loader": "^1.1.1", 42 | "webpack": "^4.20.2", 43 | "webpack-bundle-analyzer": "^3.0.2", 44 | "webpack-cli": "^3.1.2", 45 | "webpack-dev-server": "^3.1.14", 46 | "webpack-merge": "^4.1.4" 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /00 basics/01 CSS/styles.css: -------------------------------------------------------------------------------- 1 | /* Applied to all

    tags */ 2 | p { 3 | color: blue; 4 | } 5 | 6 | /* Applied to all tags with the class "red" */ 7 | .red { 8 | background: red; 9 | } 10 | 11 | /* Applied to the tag with the id "some-id" */ 12 | #some-id { 13 | font-style: italic; 14 | } 15 | 16 | /* Applied only to

    tags that are inside

  • tags */ 17 | li p { 18 | color: #0C0; 19 | } 20 | 21 | body { 22 | font-family: sans-serif; 23 | } 24 | 25 | /* Applied to all

    tags */ 26 | p { 27 | color: blue; 28 | } 29 | 30 | /* Applied to all tags with the class "red" */ 31 | .red { 32 | background: red; 33 | } 34 | 35 | /* Applied to the tag with the id "some-id" */ 36 | #some-id { 37 | font-style: italic; 38 | } 39 | 40 | /* Applied only to

    tags that are inside

  • tags */ 41 | li p { 42 | color: #0c0; 43 | } 44 | 45 | h2 { 46 | font: 400 40px/1.5 Helvetica, Verdana, sans-serif; 47 | margin: 0; 48 | padding: 0; 49 | } 50 | 51 | ul { 52 | list-style-type: none; 53 | margin: 0; 54 | padding: 0; 55 | } 56 | 57 | ul li { 58 | font: 200 20px/1.5 Helvetica, Verdana, sans-serif; 59 | border-bottom: 1px solid #ccc; 60 | } 61 | 62 | ul li:last-child { 63 | border: none; 64 | } 65 | 66 | ul li a { 67 | text-decoration: none; 68 | color: #000; 69 | display: block; 70 | width: 100%; 71 | 72 | -webkit-transition: font-size 0.3s ease, background-color 0.3s ease; 73 | -moz-transition: font-size 0.3s ease, background-color 0.3s ease; 74 | -o-transition: font-size 0.3s ease, background-color 0.3s ease; 75 | -ms-transition: font-size 0.3s ease, background-color 0.3s ease; 76 | transition: font-size 0.3s ease, background-color 0.3s ease; 77 | } 78 | 79 | ul li a:hover { 80 | font-size: 30px; 81 | background: #f6f6f6; 82 | } 83 | -------------------------------------------------------------------------------- /03 d3js-typescript/991 Basic Map/src/d3/world-mercator.d3.ts: -------------------------------------------------------------------------------- 1 | import { select } from "d3-selection"; 2 | import { geoMercator, geoPath } from "d3-geo"; 3 | import { json } from "d3-fetch"; 4 | import { FeatureCollection } from 'geojson'; 5 | 6 | // (*) Lets define a width and height for the SVG user space 7 | // coordinate system (viewBox), also a padding to avoid 8 | // overflows. 9 | const width = 960; 10 | const height = 880; 11 | const padding = 20; 12 | 13 | // (*) Lets add a card for our map. 14 | const card = select("#root") 15 | .append("div") 16 | .attr("class", "card"); 17 | 18 | // (*) Now the SVG canvas with the viewBox. 19 | const svg = card 20 | .append("svg") 21 | .attr("width", "100%") 22 | .attr("height", "100%") 23 | .attr("viewBox", `${-padding} ${-padding} ${width + 2*padding} ${height + 2*padding}`); 24 | 25 | // (*) Lets create a projection, which basically is a math 26 | // function to develop a 3D surface into a flat surface. 27 | // In practice, it transforms geographic coordinates into 28 | // projected coordinates. There are plenty of different 29 | // projections, and depending on our target application, 30 | // we will select one or another. A good general purpose 31 | // projection is spherical mercator (used extensively by 32 | // web map providers such as Google Maps) also known as 33 | // webMercator or pseudoMercator. Another one extended 34 | // is equirectangular AKA Platee-Carree. 35 | const mercatorProjection = geoMercator() 36 | .translate([width/2, height/2]); 37 | 38 | // (*) A path in SVG is described in a very specific manner. 39 | // Lets use a utility provided by d3 to create the proper 40 | // SVG coordinates for a path from user space coordinates. 41 | const pathCreator = geoPath() 42 | .projection(mercatorProjection); 43 | 44 | // (*) Finally, lets paint our path in the svg by loading 45 | // locally the world geojson. 46 | json(require("../data/world.geojson")).then((worldData => 47 | svg.append("path") 48 | .attr("d", pathCreator(worldData)) 49 | )); 50 | 51 | -------------------------------------------------------------------------------- /03 d3js-typescript/991 Basic Map/src/d3/world-platee-carre.d3.ts: -------------------------------------------------------------------------------- 1 | import { select } from "d3-selection"; 2 | import { geoEquirectangular, geoPath } from "d3-geo"; 3 | import { json } from "d3-fetch"; 4 | import { FeatureCollection } from 'geojson'; 5 | 6 | // (*)Lets define a width and height for the SVG user space 7 | // coordinate system (viewBox), also a padding to avoid 8 | // overflows. 9 | const width = 960; 10 | const height = 460; 11 | const padding = 20; 12 | 13 | // (*) Lets add a card for our map. 14 | const card = select("#root") 15 | .append("div") 16 | .attr("class", "card"); 17 | 18 | // (*) Now the SVG canvas with the viewBox. 19 | const svg = card 20 | .append("svg") 21 | .attr("width", "100%") 22 | .attr("height", "100%") 23 | .attr("viewBox", `${-padding} ${-padding} ${width + 2*padding} ${height + 2*padding}`); 24 | 25 | // (*) Lets create a projection, which basically is a math 26 | // function to develop a 3D surface into a flat surface. 27 | // In practice, it transforms geographic coordinates into 28 | // projected coordinates. There are plenty of different 29 | // projections, and depending on our target application, 30 | // we will select one or another. A good general purpose 31 | // projection is spherical mercator (used extensively by 32 | // web map providers such as Google Maps) also known as 33 | // webMercator or pseudoMercator. Another one extended 34 | // is equirectangular AKA Platee-Carree. 35 | const plateeProjection = geoEquirectangular() 36 | .translate([width/2, height/2]); 37 | 38 | // (*) A path in SVG is described in a very specific manner. 39 | // Lets use a utility provided by d3 to create the proper 40 | // SVG coordinates for a path from user space coordinates. 41 | const pathCreator = geoPath() 42 | .projection(plateeProjection); 43 | 44 | // (*) Finally, lets paint our path in the svg by loading 45 | // locally the world geojson. 46 | json(require("../data/world.geojson")).then((worldData => 47 | svg.append("path") 48 | .attr("d", pathCreator(worldData)) 49 | )); -------------------------------------------------------------------------------- /00 basics/04 SVG/readme.md: -------------------------------------------------------------------------------- 1 | # Intro 2 | 3 | Let's start playing with vector graphics, we will use the SVG HTML standard. 4 | 5 | # Steps 6 | 7 | - Let's start by creating an index.html 8 | 9 | _index.html_ 10 | 11 | ```html 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | ``` 23 | 24 | - Now let's create an SVG container 25 | 26 | _index.html_ 27 | 28 | ```diff 29 | 30 | + 31 | + 32 | 33 | ``` 34 | 35 | - Let's draw a circle 36 | 37 | _index.html_ 38 | 39 | ```diff 40 | 41 | + 42 | 43 | ``` 44 | 45 | - SVG elements support CSS styling (altough some class names are different to what we are used): 46 | 47 | _styles.css_ 48 | 49 | ```css 50 | .red { 51 | fill: red; /* not background-color! */ 52 | } 53 | ``` 54 | 55 | _index.html_ 56 | 57 | ```diff 58 | 59 | 60 | + 61 | 62 | 63 | 64 | ``` 65 | 66 | - Let's paint some styles rectangles. 67 | 68 | ```diff 69 | .red { 70 | fill: red; /* not background-color! */ 71 | } 72 | 73 | + .fancy { 74 | + fill: none; 75 | + stroke: black; /* similar to border-color */ 76 | + stroke-width: 3pt; /* similar to border-width */ 77 | + stroke-dasharray: 3,5,10; 78 | + } 79 | ``` 80 | 81 | ```diff 82 | 83 | 84 | 85 | 86 | 87 | + 89 | + 91 | + 93 | 94 | ``` 95 | 96 | -------------------------------------------------------------------------------- /02 d3js-es5/02 BarChart/main.js: -------------------------------------------------------------------------------- 1 | var totalSales = [ 2 | { product: 'Hoodie', sales: 7 }, 3 | { product: 'Jacket', sales: 6 }, 4 | { product: 'Snuggie', sales: 9 }, 5 | ]; 6 | 7 | 8 | // 1. let's start by selecting the SVG Node 9 | var svg = d3.select('svg'); 10 | 11 | // 2. Now let's select all the rectangles inside that svg 12 | // (right now is empty) 13 | var rects = svg.selectAll('rect') 14 | .data(totalSales); 15 | 16 | 17 | // 3. In order to calculate the max width for the X axis 18 | // on the bar chart, we need to know the max sales value we are going 19 | // to show. 20 | 21 | var maxSales = d3.max(totalSales, function(d, i) { 22 | return d.sales; 23 | }); 24 | 25 | // Now on the X axis we want to map totalSales values to 26 | // pixels 27 | // in this case we map the canvas range 0..350, to 0...maxSales 28 | // domain == data (data from 0 to maxSales) boundaries 29 | // ** Tip: let's play with [0, 350] values 30 | var x = d3.scaleLinear() 31 | .range([0, 350]) 32 | .domain([0, maxSales]); 33 | 34 | // Now we don't have a linear range of values, we have a discrete 35 | // range of values (one per product) 36 | // Here we are generating an array of product names 37 | // ** Tip: let's play with [0, 75] values 38 | var y = d3.scaleBand() 39 | .rangeRound([0, 75]) 40 | .domain(totalSales.map(function(d, i) { 41 | return d.product; 42 | })); 43 | 44 | // Now it's time to append to the list of Rectangles we already have 45 | var newRects = rects.enter(); 46 | 47 | // Let's append a new Rectangles 48 | // UpperCorner: 49 | // Starting x position, the start from the axis 50 | // Starting y position, where the product starts on the y scale 51 | // React width and height: 52 | // height: the space assign for each entry (product) on the Y axis 53 | // width: Now that we have the mapping previously done (linear) 54 | // we just pass the sales and use the X axis conversion to 55 | // get the right value 56 | newRects.append('rect') 57 | .attr('x', x(0)) 58 | .attr('y', function(d, i) { 59 | return y(d.product); 60 | }) 61 | .attr('height', y.bandwidth) 62 | .attr('width', function(d, i) { 63 | return x(d.sales); 64 | }); 65 | -------------------------------------------------------------------------------- /00 basics/02 DOM/readme.md: -------------------------------------------------------------------------------- 1 | # Playing with selectors 2 | 3 | d3js implements a powerful set of selectors, they allows us to manipulate the existing DOM. 4 | 5 | # Sample 6 | 7 | In this sample we are going to learn how to play with the chrome debugger and how selectors work. 8 | 9 | Starting from the previous sample (right before we added the cool styled li). 10 | 11 | ```html 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
    21 |

    Normal paragraph

    22 | 23 |

    Red paragraph

    24 |
    25 | 26 |
      27 |
    1. Unique element
    2. 28 |
    3. Another list element
    4. 29 |
    5. 30 |

      Paragraph inside list element

      31 |

      Second paragraph

      32 |
    6. 33 |
    34 | 35 | 36 | 37 | 38 | ``` 39 | 40 | ```css 41 | /* Applied to all

    tags */ 42 | p { 43 | color: blue; 44 | } 45 | 46 | /* Applied to all tags with the class "red" */ 47 | .red { 48 | background: red; 49 | } 50 | 51 | /* Applied to the tag with the id "some-id" */ 52 | #some-id { 53 | font-style: italic; 54 | } 55 | 56 | /* Applied only to

    tags that are inside

  • tags */ 57 | li p { 58 | color: #0C0; 59 | } 60 | ``` 61 | 62 | - Let's crate a _main.js_ file and add the follwing selectors. 63 | 64 | ```javascript 65 | // DOM API 66 | var element = document.getElementById('some-id'); 67 | //
  • Unique element
  • 68 | var plenght = document.getElementsByTagName('p').length; 69 | // 4 70 | var reds = document.getElementsByClassName('red'); 71 | // [

    Red paragraph

    ] 72 | console.log(reds[0].innerText); 73 | // "Red paragraph" 74 | 75 | // D3 Selection API 76 | var one = d3.select('p').size(); // select() only finds one 77 | // 1 78 | var many = d3.selectAll('p').size(); // selectAll() finds all 79 | // 4 80 | var reds = d3.selectAll('.red'); 81 | // [ > Array[1] ] 82 | console.log(reds.text()); 83 | // "Red paragraph" 84 | ``` 85 | 86 | - Now let's click on the index file and press F12, we are going to start debugging the samples. 87 | 88 | -------------------------------------------------------------------------------- /02 d3js-es5/06 Pie/main.js: -------------------------------------------------------------------------------- 1 | 2 | // Let's start using ES6 3 | // And let's organize the code following clean code concepts 4 | // Later one we will complete a version using imports + webpack 5 | 6 | // Isolated data array to a different file 7 | 8 | let margin = null, 9 | width = null, 10 | height = null; 11 | 12 | let svg = null; 13 | let x, y = null; // scales 14 | 15 | // helper that returns a color based on an ID 16 | const color = d3.scaleOrdinal(d3.schemeCategory10); 17 | 18 | 19 | setupCanvasSize(); 20 | appendSvg("body"); 21 | appendPieChart(); 22 | AppendLegend(); 23 | 24 | // 1. let's start by selecting the SVG Node 25 | function setupCanvasSize() { 26 | margin = {top: 0, left: 80, bottom: 20, right: 30}; 27 | width = 960 - margin.left - margin.right; 28 | height = 120 - margin.top - margin.bottom; 29 | } 30 | 31 | function appendSvg(domElement) { 32 | svg = d3.select(domElement).append("svg") 33 | .attr("width", width + margin.left + margin.right) 34 | .attr("height", height + margin.top + margin.bottom) 35 | .append("g") 36 | .attr("transform",`translate(${margin.left}, ${margin.top})`); 37 | 38 | } 39 | 40 | 41 | function appendPieChart() 42 | { 43 | // Where to get the measure data 44 | var pie = d3.pie() 45 | .value(function(d) { return d.sales }) 46 | 47 | // Calculate Arcs 48 | var slices = pie(totalSales); 49 | 50 | // Pie chart size 51 | var arc = d3.arc() 52 | .innerRadius(0) 53 | .outerRadius(50); 54 | 55 | // Draw the pie 56 | svg.selectAll('path.slice') 57 | .data(slices) 58 | .enter() 59 | .append('path') 60 | .attr('class', 'slice') 61 | .attr('d', arc) 62 | .attr('fill', function(d) { 63 | return color(d.data.product); 64 | }) 65 | .attr("transform", `translate(150, 50)`) 66 | ; 67 | } 68 | 69 | function AppendLegend() { 70 | // building a legend is as simple as binding 71 | // more elements to the same data. in this case, 72 | // tags 73 | svg.append('g') 74 | .attr('class', 'legend') 75 | .selectAll('text') 76 | .data(totalSales) 77 | .enter() 78 | .append('text') 79 | .text(function(d) { return '• ' + d.product; }) 80 | .attr('fill', function(d) { return color(d.product); }) 81 | .attr('y', function(d, i) { return 20 * (i + 1); }) 82 | } -------------------------------------------------------------------------------- /03 d3js-typescript/01 Lines/src/d3/linechart.d3.ts: -------------------------------------------------------------------------------- 1 | import { select } from "d3-selection"; 2 | import { scaleLinear, scaleTime, scaleOrdinal } from "d3-scale"; 3 | import { schemeAccent, schemeCategory10 } from "d3-scale-chromatic"; 4 | import { line } from "d3-shape"; 5 | import { malagaStats, TempStat } from "./linechart.data"; 6 | import { axisBottom, axisLeft } from "d3-axis"; 7 | import { extent } from "d3-array"; 8 | import { accessSync } from "fs"; 9 | 10 | const d3 = { 11 | select, 12 | scaleLinear, 13 | scaleTime, 14 | extent, 15 | line, 16 | axisBottom, 17 | axisLeft, 18 | scaleOrdinal, 19 | schemeAccent, 20 | schemeCategory10, 21 | }; 22 | 23 | const width = 500; 24 | const height = 300; 25 | const padding = 50; 26 | 27 | const card = d3 28 | .select("#root") 29 | .append("div") 30 | .attr("class", "card"); 31 | 32 | const svg = card 33 | .append("svg") 34 | .attr("width", "100%") 35 | .attr("height", "100%") 36 | .attr("viewBox", `${-padding} ${-padding} ${width + 2 * padding} ${height + 2 * padding}`); 37 | 38 | const xScale = d3 39 | .scaleTime() 40 | .domain([new Date(2018, 0), new Date(2018, 11)]) // Range Jan to Dec 2019 41 | .range([0, width]); // pixels 42 | 43 | const yScale = d3 44 | .scaleLinear() 45 | .domain(d3.extent(malagaStats.reduce((acc, s) => acc.concat(s.values), []))) 46 | .range([height, 0]); 47 | 48 | const colorScale = d3.scaleOrdinal(d3.schemeCategory10) 49 | .domain(['min', '', 'avg', 'max']); 50 | ; 51 | 52 | const lineCreator = d3 53 | .line() 54 | .x((d, i) => xScale(new Date(2018, i))) // data and array index, x Axis is month 55 | .y(d => yScale(d)); 56 | 57 | // let's paint the line, we are going to add a single array, later 58 | // on we will got for a more ellaborated solution 59 | // We pass data 60 | // path, attribute "d" each point in the path 61 | svg 62 | .selectAll("path") 63 | .data(malagaStats, (d: TempStat) => d.id) 64 | .enter() 65 | .append("path") 66 | .attr("d", d => lineCreator(d.values)) 67 | .attr("fill", "none") 68 | .attr("stroke-width", "3px") 69 | .attr("stroke", d => colorScale(d.id)); 70 | 71 | const axisGroup = svg.append("g"); 72 | 73 | // Y Axis: call axisLeft helper and pass the scale 74 | axisGroup.append("g").call(d3.axisLeft(yScale)); 75 | 76 | // X axis: 77 | axisGroup 78 | .append("g") 79 | .attr("transform", `translate(0, ${height})`) 80 | .call(d3.axisBottom(xScale)); 81 | -------------------------------------------------------------------------------- /00 basics/00 HTML/readme.md: -------------------------------------------------------------------------------- 1 | # Basic HTML 2 | 3 | Let's start creating a very basic HTML file. 4 | 5 | # Steps 6 | 7 | - Let's create a very basic structure 8 | 9 | ```html 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | ``` 18 | 19 | Let's check each tag: 20 | 21 | _DocType_ 22 | 23 | ```html 24 | 25 | ``` 26 | 27 | The declaration must be the very first thing in your HTML document, before the tag. 28 | 29 | The declaration is not an HTML tag; it is an instruction to the web browser about what version of HTML the page is written in. 30 | 31 | More info: https://www.w3schools.com/tags/tag_doctype.asp 32 | 33 | _html_ 34 | 35 | The tag tells the browser that this is an HTML document. 36 | 37 | The tag represents the root of an HTML document. 38 | 39 | The tag is the container for all other HTML elements (except for the tag). 40 | 41 | More info: https://www.w3schools.com/tags/tag_html.asp 42 | 43 | _head_ 44 | 45 | The element is a container for all the head elements. 46 | 47 | The element can include a title for the document, scripts, styles, meta information, and more. 48 | 49 | More info: https://www.w3schools.com/tags/tag_head.asp 50 | 51 | _meta_ 52 | 53 | Metadata is data (information) about data. 54 | 55 | ```html 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | ``` 64 | 65 | The tag provides metadata about the HTML document. Metadata will not be displayed on the page, but will be machine parsable. 66 | 67 | Meta elements are typically used to specify page description, keywords, author of the document, last modified, and other metadata. 68 | 69 | More info: https://www.w3schools.com/tags/tag_meta.asp 70 | 71 | _body_ 72 | 73 | The tag defines the document's body. 74 | 75 | The element contains all the contents of an HTML document, such as text, hyperlinks, images, tables, lists, etc. 76 | 77 | ```html 78 | 79 |

    80 | MAIN CONTENT GOES HERE 81 |

    82 | 83 |

    84 | HTML Basics tutorial 85 |

    86 | 87 | ``` 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /02 d3js-es5/05 Lines/main.js: -------------------------------------------------------------------------------- 1 | 2 | // Let's start using ES6 3 | // And let's organize the code following clean code concepts 4 | // Later one we will complete a version using imports + webpack 5 | 6 | // Isolated data array to a different file 7 | 8 | let margin = null, 9 | width = null, 10 | height = null; 11 | 12 | let svg = null; 13 | let x, y = null; // scales 14 | 15 | setupCanvasSize(); 16 | appendSvg("body"); 17 | setupXScale(); 18 | setupYScale(); 19 | appendXAxis(); 20 | appendYAxis(); 21 | appendLineCharts(); 22 | 23 | 24 | // 1. let's start by selecting the SVG Node 25 | function setupCanvasSize() { 26 | margin = {top: 20, left: 80, bottom: 20, right: 30}; 27 | width = 960 - margin.left - margin.right; 28 | height = 520 - margin.top - margin.bottom; 29 | } 30 | 31 | function appendSvg(domElement) { 32 | svg = d3.select(domElement).append("svg") 33 | .attr("width", width + margin.left + margin.right) 34 | .attr("height", height + margin.top + margin.bottom) 35 | .append("g") 36 | .attr("transform",`translate(${margin.left}, ${margin.top})`); 37 | 38 | } 39 | 40 | // Now on the X axis we want to map totalSales values to 41 | // pixels 42 | // in this case we map the canvas range 0..350, to 0...maxSales 43 | // domain == data (data from 0 to maxSales) boundaries 44 | function setupXScale() 45 | { 46 | 47 | x = d3.scaleTime() 48 | .range([0, width]) 49 | .domain(d3.extent(totalSales, function(d) { return d.month})); 50 | } 51 | 52 | // Now we don't have a linear range of values, we have a discrete 53 | // range of values (one per product) 54 | // Here we are generating an array of product names 55 | function setupYScale() 56 | { 57 | var maxSales = d3.max(totalSales, function(d, i) { 58 | return d.sales; 59 | }); 60 | 61 | y = d3.scaleLinear() 62 | .range([height, 0]) 63 | .domain([0, maxSales]); 64 | 65 | } 66 | 67 | function appendXAxis() { 68 | // Add the X Axis 69 | svg.append("g") 70 | .attr("transform",`translate(0, ${height})`) 71 | .call(d3.axisBottom(x)); 72 | } 73 | 74 | function appendYAxis() { 75 | // Add the Y Axis 76 | svg.append("g") 77 | .call(d3.axisLeft(y)); 78 | } 79 | 80 | function appendLineCharts() 81 | { 82 | // define the line 83 | var valueline = d3.line() 84 | .x(function(d) { return x(d.month); }) 85 | .y(function(d) { return y(d.sales); }); 86 | 87 | // Add the valueline path. 88 | svg.append("path") 89 | .data([totalSales]) 90 | .attr("class", "line") 91 | .attr("d", valueline); 92 | 93 | } 94 | -------------------------------------------------------------------------------- /03 d3js-typescript/02 Bars/src/d3/barchart.d3.ts: -------------------------------------------------------------------------------- 1 | import { select, selectAll } from "d3-selection"; 2 | import 'd3-transition'; 3 | import { scaleBand, scaleLinear } from "d3-scale"; 4 | import { randomData, startRealTimeDataV1 } from "./barchart.data"; 5 | 6 | const d3 = { 7 | select, selectAll, scaleBand, scaleLinear 8 | }; 9 | 10 | const width = 500; 11 | const height = 300; 12 | const padding = 50; 13 | 14 | // Creamos la tarjeta. 15 | const card = select("#root") 16 | .append("div") 17 | .attr("class", "card"); 18 | 19 | // Creamos el 'lienzo' svg. 20 | const svg = card 21 | .append("svg") 22 | .attr("width", "100%") 23 | .attr("height", "100%") 24 | .attr("viewBox", `${-padding} ${-padding} ${width + 2*padding} ${height + 2*padding}`); 25 | 26 | const scaleYPos = d3.scaleLinear() 27 | .domain([0, 1]) 28 | .range([height, 0]); 29 | 30 | // In Domain (bars) we don't have continuous values, we have to identify the bands, like in ordinal scale 31 | // we could return [0,1,2,3...20], we will do that wiht a map 32 | const scaleXPos = d3.scaleBand() 33 | .domain(randomData.map((d,i) => i)) 34 | .range([0, width]) // use RangeRound to get pixel perfect layout 35 | .paddingInner(0.05); // space between bars, wathout! percentages values, range number 0..1 36 | 37 | const barGroup = svg 38 | .append('g'); 39 | 40 | barGroup 41 | .selectAll('rect') 42 | .data(randomData) 43 | .enter() 44 | .append("rect") 45 | .attr("x", (d,i) => scaleXPos(i)) 46 | .attr("y", d => scaleYPos(d)) 47 | .attr("width", scaleXPos.bandwidth()) 48 | .attr("height", d => height - scaleYPos(d)) 49 | .attr("fill", "url(#barGradient)"); 50 | 51 | const dataUpdated = (newData : number[]) => { 52 | // Update pattern 53 | barGroup 54 | .selectAll('rect') 55 | .data(newData) 56 | .transition() 57 | .duration(750) 58 | .attr("y", d => scaleYPos(d)) 59 | .attr("height", d => height - scaleYPos(d)) 60 | } 61 | 62 | startRealTimeDataV1(dataUpdated); 63 | 64 | 65 | // OPTIONAL 66 | // Gradient fill for the bars. 67 | const gradient = svg 68 | .append("defs") 69 | .append("linearGradient") 70 | .attr("id", "barGradient") 71 | .attr("gradientUnits", "userSpaceOnUse") 72 | .attr("x1", "0") 73 | .attr("y1", height) 74 | .attr("x2", "0") 75 | .attr("y2", "0"); 76 | gradient 77 | .append("stop") 78 | .attr("offset", "0") 79 | .attr("stop-color", "#185a9d"); 80 | gradient 81 | .append("stop") 82 | .attr("offset", "80%") 83 | .attr("stop-color", "#43cea2"); 84 | gradient 85 | .append("stop") 86 | .attr("offset", "100%") 87 | .attr("stop-color", "#43cea2"); 88 | 89 | -------------------------------------------------------------------------------- /02 d3js-es5/00 SVG/readme.md: -------------------------------------------------------------------------------- 1 | # Trying to create a chart with no helpers 2 | 3 | Now that we got some basic concepts on SVG, it's a good excercise to try to create 4 | a chart without using any helper, we will notice it's a cumbersome task, and that 5 | it would be greate to have a helper library that covers all the boiler plate (e.g. d3js). 6 | 7 | # Steps 8 | 9 | - Let's first create the HTML 10 | 11 | ```html 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | ``` 25 | 26 | - Now let's move a bit the chart we want to display to add some margins. 27 | 28 | ```diff 29 | 30 | 31 | + 32 | + 33 | 34 | 35 | ``` 36 | 37 | - Now let's draw the dots with the data (we are manually calculating where it should be placed) 38 | 39 | ```diff 40 | 41 | 42 | 43 | + 50 | + 51 | + 52 | + 53 | + 54 | 55 | 56 | ``` 57 | 58 | - And finally let's add X and Y axis. 59 | 60 | ```diff 61 | 62 | 63 | 64 | 65 | 66 | + 67 | + 68 | + $10 69 | + $80 70 | + 71 | + 72 | + 73 | + January 2014 74 | + April 75 | + 76 | 77 | 78 | ``` 79 | 80 | This approach is not ideal, one of the main pain points is when you try to resize the chart, you will have to recalculate all entries. -------------------------------------------------------------------------------- /03 d3js-typescript/02 Bars/webpack.config.js: -------------------------------------------------------------------------------- 1 | const webpack = require("webpack"); 2 | const path = require("path"); 3 | const HtmlWebpackPlugin = require("html-webpack-plugin"); 4 | 5 | const basePath = __dirname; 6 | 7 | module.exports = { 8 | context: path.join(basePath, "src"), 9 | resolve: { 10 | extensions: [".js", ".ts"], 11 | }, 12 | entry: { 13 | app: ["./app.ts"], 14 | }, 15 | output: { 16 | path: path.join(basePath, "dist"), 17 | }, 18 | optimization: { 19 | splitChunks: { 20 | chunks: "all", 21 | cacheGroups: { 22 | vendorGroup: { 23 | test: /[\\/]node_modules[\\/]/, 24 | name: "vendor", 25 | enforce: true, 26 | }, 27 | }, 28 | }, 29 | }, 30 | module: { 31 | rules: [ 32 | { 33 | test: /\.(ts|js)$/, 34 | exclude: /node_modules/, 35 | loader: "babel-loader", 36 | }, 37 | { 38 | test: /\.css$/, 39 | exclude: /node_modules/, 40 | use: [ 41 | { loader: "style-loader" }, 42 | { loader: "css-loader" } 43 | ], 44 | }, 45 | { 46 | test: /\.scss$/, 47 | exclude: /node_modules/, 48 | use: [ 49 | { loader: "style-loader" }, 50 | { 51 | loader: "css-loader", 52 | options: { 53 | modules: true, 54 | camelCase: true, 55 | importLoaders: 1, 56 | localIdentName: "[local]___[hash:base64:5]", 57 | }, 58 | }, 59 | { loader: "resolve-url-loader" }, 60 | { loader: "sass-loader" }, 61 | ], 62 | }, 63 | // Font resources embedded in final bundle with url-loader. 64 | { 65 | test: /\.(woff|woff2)(\?v=\d+\.\d+\.\d+)?$/, 66 | loader: "url-loader", 67 | options: { 68 | mimetype: "application/font-woff" 69 | } 70 | }, 71 | { 72 | test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, 73 | loader: "url-loader", 74 | options: { 75 | mimetype: "application/octet-stream" 76 | } 77 | }, 78 | { 79 | test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, 80 | loader: "url-loader" 81 | }, 82 | // Common files, emitted to the output directory 83 | { 84 | test: /\.(png|jpg|ico|gif|svg|webp)?$/, 85 | loader: "file-loader", 86 | options: { 87 | name: "[name].[ext]" 88 | } 89 | }, 90 | // Same for geo data sources 91 | { 92 | test: /\.(geojson|topojson|json)?$/, 93 | loader: "json-loader" 94 | }, 95 | ], 96 | }, 97 | plugins: [ 98 | new HtmlWebpackPlugin({ 99 | filename: "index.html", 100 | template: "index.html", 101 | hash: true, 102 | chunksSortMode: "manual", 103 | chunks: ["vendor", "app"], 104 | }), 105 | ], 106 | }; 107 | -------------------------------------------------------------------------------- /03 d3js-typescript/01 Lines/webpack.config.js: -------------------------------------------------------------------------------- 1 | const webpack = require("webpack"); 2 | const path = require("path"); 3 | const HtmlWebpackPlugin = require("html-webpack-plugin"); 4 | 5 | const basePath = __dirname; 6 | 7 | module.exports = { 8 | context: path.join(basePath, "src"), 9 | resolve: { 10 | extensions: [".js", ".ts"], 11 | }, 12 | entry: { 13 | app: ["./app.ts"], 14 | }, 15 | output: { 16 | path: path.join(basePath, "dist"), 17 | }, 18 | optimization: { 19 | splitChunks: { 20 | chunks: "all", 21 | cacheGroups: { 22 | vendorGroup: { 23 | test: /[\\/]node_modules[\\/]/, 24 | name: "vendor", 25 | enforce: true, 26 | }, 27 | }, 28 | }, 29 | }, 30 | module: { 31 | rules: [ 32 | { 33 | test: /\.(ts|js)$/, 34 | exclude: /node_modules/, 35 | loader: "babel-loader", 36 | }, 37 | { 38 | test: /\.css$/, 39 | exclude: /node_modules/, 40 | use: [ 41 | { loader: "style-loader" }, 42 | { loader: "css-loader" } 43 | ], 44 | }, 45 | { 46 | test: /\.scss$/, 47 | exclude: /node_modules/, 48 | use: [ 49 | { loader: "style-loader" }, 50 | { 51 | loader: "css-loader", 52 | options: { 53 | modules: true, 54 | camelCase: true, 55 | importLoaders: 1, 56 | localIdentName: "[local]___[hash:base64:5]", 57 | }, 58 | }, 59 | { loader: "resolve-url-loader" }, 60 | { loader: "sass-loader" }, 61 | ], 62 | }, 63 | // Font resources embedded in final bundle with url-loader. 64 | { 65 | test: /\.(woff|woff2)(\?v=\d+\.\d+\.\d+)?$/, 66 | loader: "url-loader", 67 | options: { 68 | mimetype: "application/font-woff" 69 | } 70 | }, 71 | { 72 | test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, 73 | loader: "url-loader", 74 | options: { 75 | mimetype: "application/octet-stream" 76 | } 77 | }, 78 | { 79 | test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, 80 | loader: "url-loader" 81 | }, 82 | // Common files, emitted to the output directory 83 | { 84 | test: /\.(png|jpg|ico|gif|svg|webp)?$/, 85 | loader: "file-loader", 86 | options: { 87 | name: "[name].[ext]" 88 | } 89 | }, 90 | // Same for geo data sources 91 | { 92 | test: /\.(geojson|topojson|json)?$/, 93 | loader: "json-loader" 94 | }, 95 | ], 96 | }, 97 | plugins: [ 98 | new HtmlWebpackPlugin({ 99 | filename: "index.html", 100 | template: "index.html", 101 | hash: true, 102 | chunksSortMode: "manual", 103 | chunks: ["vendor", "app"], 104 | }), 105 | ], 106 | }; 107 | -------------------------------------------------------------------------------- /02 d3js-es5/03 BarChartAxis/main.js: -------------------------------------------------------------------------------- 1 | var totalSales = [ 2 | { product: 'Hoodie', sales: 7 }, 3 | { product: 'Jacket', sales: 6 }, 4 | { product: 'Snuggie', sales: 9 }, 5 | ]; 6 | 7 | 8 | // 1. let's start by selecting the SVG Node 9 | var margin = {top: 0, left: 80, bottom: 20, right: 0}; 10 | var width = 960 - margin.left - margin.right; 11 | var height = 120 - margin.top - margin.bottom; 12 | 13 | var svg = d3.select("body").append("svg") 14 | .attr("width", width + margin.left + margin.right) 15 | .attr("height", height + margin.top + margin.bottom) 16 | .append("g") 17 | .attr("transform", 18 | "translate(" + margin.left + "," + margin.top + ")"); 19 | ; 20 | 21 | var barChartsGroup = svg.append("g"); 22 | 23 | //barChartsGroup.attr("transform", "translate(" + margin.left + ",0)"); 24 | 25 | // 2. Now let's select all the rectangles inside that svg 26 | // (right now is empty) 27 | var rects = barChartsGroup.selectAll('rect') 28 | .data(totalSales); 29 | 30 | 31 | // 3. In order to calculate the max width for the X axis 32 | // on the bar chart, we need to know the max sales value we are going 33 | // to show. 34 | 35 | var maxSales = d3.max(totalSales, function(d, i) { 36 | return d.sales; 37 | }); 38 | 39 | // Now on the X axis we want to map totalSales values to 40 | // pixels 41 | // in this case we map the canvas range 0..350, to 0...maxSales 42 | // domain == data (data from 0 to maxSales) boundaries 43 | // ** Tip: let's play with [0, 350] values 44 | var x = d3.scaleLinear() 45 | .range([0, 350]) 46 | .domain([0, maxSales]); 47 | 48 | // Now we don't have a linear range of values, we have a discrete 49 | // range of values (one per product) 50 | // Here we are generating an array of product names 51 | // ** Tip: let's play with [0, 75] values 52 | var y = d3.scaleBand() 53 | .rangeRound([0, height]) 54 | .domain(totalSales.map(function(d, i) { 55 | return d.product; 56 | })); 57 | 58 | 59 | 60 | // Now it's time to append to the list of Rectangles we already have 61 | var newRects = rects.enter(); 62 | 63 | // Let's append a new Rectangles 64 | // UpperCorner: 65 | // Starting x position, the start from the axis 66 | // Starting y position, where the product starts on the y scale 67 | // React width and height: 68 | // height: the space assign for each entry (product) on the Y axis 69 | // width: Now that we have the mapping previously done (linear) 70 | // we just pass the sales and use the X axis conversion to 71 | // get the right value 72 | newRects.append('rect') 73 | .attr('x', x(0)) 74 | .attr('y', function(d, i) { 75 | return y(d.product); 76 | }) 77 | .attr('height', y.bandwidth) 78 | .attr('width', function(d, i) { 79 | return x(d.sales); 80 | }); 81 | 82 | // Add the X Axis 83 | svg.append("g") 84 | .attr("transform", "translate(0,"+ height +")") 85 | .call(d3.axisBottom(x)); 86 | 87 | // Add the Y Axis 88 | svg.append("g") 89 | .call(d3.axisLeft(y)); 90 | -------------------------------------------------------------------------------- /03 d3js-typescript/02 Bars/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["tslint:recommended"], 3 | "defaultSeverity": "warning", 4 | "rules": { 5 | "align": [true, "parameters", "statements"], 6 | "array-type": false, 7 | "arrow-parens": false, 8 | "class-name": true, 9 | "comment-format": [true, "check-space"], 10 | "curly": false, 11 | "eofline": true, 12 | "forin": false, 13 | "import-spacing": true, 14 | "indent": [true, "spaces"], 15 | "interface-name": [true, "never-prefix"], 16 | "jsdoc-format": true, 17 | "label-position": true, 18 | "max-line-length": [true, 100], 19 | "member-ordering": false, 20 | "member-access": false, 21 | "no-any": false, 22 | "no-arg": true, 23 | "no-bitwise": true, 24 | "no-console": false, 25 | "no-consecutive-blank-lines": [true, 2], 26 | "no-construct": true, 27 | "no-debugger": true, 28 | "no-default-export": true, 29 | "no-duplicate-variable": true, 30 | "no-empty": true, 31 | "no-empty-interface": false, 32 | "no-eval": true, 33 | "no-implicit-dependencies": false, 34 | "no-internal-module": true, 35 | "no-object-literal-type-assertion": false, 36 | "no-shadowed-variable": true, 37 | "no-string-literal": false, 38 | "no-submodule-imports": false, 39 | "no-trailing-whitespace": true, 40 | "no-unsafe-finally": true, 41 | "no-unused-expression": true, 42 | "no-var-keyword": true, 43 | "no-var-requires": false, 44 | "object-literal-key-quotes": [true, "as-needed"], 45 | "object-literal-sort-keys": false, 46 | "one-line": [true, "check-catch", "check-else", "check-open-brace", "check-whitespace"], 47 | "only-arrow-functions": false, 48 | "ordered-imports": false, 49 | "quotemark": [true, "double"], 50 | "radix": false, 51 | "semicolon": [true, "always", "strict-bound-class-methods"], 52 | "trailing-comma": [ 53 | true, 54 | { 55 | "multiline": { 56 | "objects": "always", 57 | "arrays": "always", 58 | "imports": "always", 59 | "exports": "always", 60 | "typeLiterals": "always" 61 | }, 62 | "singleline": "never", 63 | "esSpecCompliant": true 64 | } 65 | ], 66 | "triple-equals": [true, "allow-null-check"], 67 | "typedef": [true, "parameter", "property-declaration"], 68 | "typedef-whitespace": [ 69 | true, 70 | { 71 | "call-signature": "nospace", 72 | "index-signature": "nospace", 73 | "parameter": "nospace", 74 | "property-declaration": "nospace", 75 | "variable-declaration": "nospace" 76 | } 77 | ], 78 | "variable-name": [true, "ban-keywords", "check-format", "allow-leading-underscore", "allow-pascal-case"], 79 | "whitespace": [ 80 | true, 81 | "check-branch", 82 | "check-decl", 83 | "check-module", 84 | "check-operator", 85 | "check-separator", 86 | "check-type", 87 | "check-typecast" 88 | ] 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /03 d3js-typescript/01 Lines/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["tslint:recommended"], 3 | "defaultSeverity": "warning", 4 | "rules": { 5 | "align": [true, "parameters", "statements"], 6 | "array-type": false, 7 | "arrow-parens": false, 8 | "class-name": true, 9 | "comment-format": [true, "check-space"], 10 | "curly": false, 11 | "eofline": true, 12 | "forin": false, 13 | "import-spacing": true, 14 | "indent": [true, "spaces"], 15 | "interface-name": [true, "never-prefix"], 16 | "jsdoc-format": true, 17 | "label-position": true, 18 | "max-line-length": [true, 100], 19 | "member-ordering": false, 20 | "member-access": false, 21 | "no-any": false, 22 | "no-arg": true, 23 | "no-bitwise": true, 24 | "no-console": false, 25 | "no-consecutive-blank-lines": [true, 2], 26 | "no-construct": true, 27 | "no-debugger": true, 28 | "no-default-export": true, 29 | "no-duplicate-variable": true, 30 | "no-empty": true, 31 | "no-empty-interface": false, 32 | "no-eval": true, 33 | "no-implicit-dependencies": false, 34 | "no-internal-module": true, 35 | "no-object-literal-type-assertion": false, 36 | "no-shadowed-variable": true, 37 | "no-string-literal": false, 38 | "no-submodule-imports": false, 39 | "no-trailing-whitespace": true, 40 | "no-unsafe-finally": true, 41 | "no-unused-expression": true, 42 | "no-var-keyword": true, 43 | "no-var-requires": false, 44 | "object-literal-key-quotes": [true, "as-needed"], 45 | "object-literal-sort-keys": false, 46 | "one-line": [true, "check-catch", "check-else", "check-open-brace", "check-whitespace"], 47 | "only-arrow-functions": false, 48 | "ordered-imports": false, 49 | "quotemark": [true, "double"], 50 | "radix": false, 51 | "semicolon": [true, "always", "strict-bound-class-methods"], 52 | "trailing-comma": [ 53 | true, 54 | { 55 | "multiline": { 56 | "objects": "always", 57 | "arrays": "always", 58 | "imports": "always", 59 | "exports": "always", 60 | "typeLiterals": "always" 61 | }, 62 | "singleline": "never", 63 | "esSpecCompliant": true 64 | } 65 | ], 66 | "triple-equals": [true, "allow-null-check"], 67 | "typedef": [true, "parameter", "property-declaration"], 68 | "typedef-whitespace": [ 69 | true, 70 | { 71 | "call-signature": "nospace", 72 | "index-signature": "nospace", 73 | "parameter": "nospace", 74 | "property-declaration": "nospace", 75 | "variable-declaration": "nospace" 76 | } 77 | ], 78 | "variable-name": [true, "ban-keywords", "check-format", "allow-leading-underscore", "allow-pascal-case"], 79 | "whitespace": [ 80 | true, 81 | "check-branch", 82 | "check-decl", 83 | "check-module", 84 | "check-operator", 85 | "check-separator", 86 | "check-type", 87 | "check-typecast" 88 | ] 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /03 d3js-typescript/00 Playground/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["tslint:recommended"], 3 | "defaultSeverity": "warning", 4 | "rules": { 5 | "align": [true, "parameters", "statements"], 6 | "array-type": false, 7 | "arrow-parens": false, 8 | "class-name": true, 9 | "comment-format": [true, "check-space"], 10 | "curly": false, 11 | "eofline": true, 12 | "forin": false, 13 | "import-spacing": true, 14 | "indent": [true, "spaces"], 15 | "interface-name": [true, "never-prefix"], 16 | "jsdoc-format": true, 17 | "label-position": true, 18 | "max-line-length": [true, 100], 19 | "member-ordering": false, 20 | "member-access": false, 21 | "no-any": false, 22 | "no-arg": true, 23 | "no-bitwise": true, 24 | "no-console": false, 25 | "no-consecutive-blank-lines": [true, 2], 26 | "no-construct": true, 27 | "no-debugger": true, 28 | "no-default-export": true, 29 | "no-duplicate-variable": true, 30 | "no-empty": true, 31 | "no-empty-interface": false, 32 | "no-eval": true, 33 | "no-implicit-dependencies": false, 34 | "no-internal-module": true, 35 | "no-object-literal-type-assertion": false, 36 | "no-shadowed-variable": true, 37 | "no-string-literal": false, 38 | "no-submodule-imports": false, 39 | "no-trailing-whitespace": true, 40 | "no-unsafe-finally": true, 41 | "no-unused-expression": true, 42 | "no-var-keyword": true, 43 | "no-var-requires": false, 44 | "object-literal-key-quotes": [true, "as-needed"], 45 | "object-literal-sort-keys": false, 46 | "one-line": [true, "check-catch", "check-else", "check-open-brace", "check-whitespace"], 47 | "only-arrow-functions": false, 48 | "ordered-imports": false, 49 | "quotemark": [true, "double"], 50 | "radix": false, 51 | "semicolon": [true, "always", "strict-bound-class-methods"], 52 | "trailing-comma": [ 53 | true, 54 | { 55 | "multiline": { 56 | "objects": "always", 57 | "arrays": "always", 58 | "imports": "always", 59 | "exports": "always", 60 | "typeLiterals": "always" 61 | }, 62 | "singleline": "never", 63 | "esSpecCompliant": true 64 | } 65 | ], 66 | "triple-equals": [true, "allow-null-check"], 67 | "typedef": [true, "parameter", "property-declaration"], 68 | "typedef-whitespace": [ 69 | true, 70 | { 71 | "call-signature": "nospace", 72 | "index-signature": "nospace", 73 | "parameter": "nospace", 74 | "property-declaration": "nospace", 75 | "variable-declaration": "nospace" 76 | } 77 | ], 78 | "variable-name": [true, "ban-keywords", "check-format", "allow-leading-underscore", "allow-pascal-case"], 79 | "whitespace": [ 80 | true, 81 | "check-branch", 82 | "check-decl", 83 | "check-module", 84 | "check-operator", 85 | "check-separator", 86 | "check-type", 87 | "check-typecast" 88 | ] 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /03 d3js-typescript/991 Basic Map/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["tslint:recommended"], 3 | "defaultSeverity": "warning", 4 | "rules": { 5 | "align": [true, "parameters", "statements"], 6 | "array-type": false, 7 | "arrow-parens": false, 8 | "class-name": true, 9 | "comment-format": [true, "check-space"], 10 | "curly": false, 11 | "eofline": true, 12 | "forin": false, 13 | "import-spacing": true, 14 | "indent": [true, "spaces"], 15 | "interface-name": [true, "never-prefix"], 16 | "jsdoc-format": true, 17 | "label-position": true, 18 | "max-line-length": [true, 100], 19 | "member-ordering": false, 20 | "member-access": false, 21 | "no-any": false, 22 | "no-arg": true, 23 | "no-bitwise": true, 24 | "no-console": false, 25 | "no-consecutive-blank-lines": [true, 2], 26 | "no-construct": true, 27 | "no-debugger": true, 28 | "no-default-export": true, 29 | "no-duplicate-variable": true, 30 | "no-empty": true, 31 | "no-empty-interface": false, 32 | "no-eval": true, 33 | "no-implicit-dependencies": false, 34 | "no-internal-module": true, 35 | "no-object-literal-type-assertion": false, 36 | "no-shadowed-variable": true, 37 | "no-string-literal": false, 38 | "no-submodule-imports": false, 39 | "no-trailing-whitespace": true, 40 | "no-unsafe-finally": true, 41 | "no-unused-expression": true, 42 | "no-var-keyword": true, 43 | "no-var-requires": false, 44 | "object-literal-key-quotes": [true, "as-needed"], 45 | "object-literal-sort-keys": false, 46 | "one-line": [true, "check-catch", "check-else", "check-open-brace", "check-whitespace"], 47 | "only-arrow-functions": false, 48 | "ordered-imports": false, 49 | "quotemark": [true, "double"], 50 | "radix": false, 51 | "semicolon": [true, "always", "strict-bound-class-methods"], 52 | "trailing-comma": [ 53 | true, 54 | { 55 | "multiline": { 56 | "objects": "always", 57 | "arrays": "always", 58 | "imports": "always", 59 | "exports": "always", 60 | "typeLiterals": "always" 61 | }, 62 | "singleline": "never", 63 | "esSpecCompliant": true 64 | } 65 | ], 66 | "triple-equals": [true, "allow-null-check"], 67 | "typedef": [true, "parameter", "property-declaration"], 68 | "typedef-whitespace": [ 69 | true, 70 | { 71 | "call-signature": "nospace", 72 | "index-signature": "nospace", 73 | "parameter": "nospace", 74 | "property-declaration": "nospace", 75 | "variable-declaration": "nospace" 76 | } 77 | ], 78 | "variable-name": [true, "ban-keywords", "check-format", "allow-leading-underscore", "allow-pascal-case"], 79 | "whitespace": [ 80 | true, 81 | "check-branch", 82 | "check-decl", 83 | "check-module", 84 | "check-operator", 85 | "check-separator", 86 | "check-type", 87 | "check-typecast" 88 | ] 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /03 d3js-typescript/992 Map Interaction/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["tslint:recommended"], 3 | "defaultSeverity": "warning", 4 | "rules": { 5 | "align": [true, "parameters", "statements"], 6 | "array-type": false, 7 | "arrow-parens": false, 8 | "class-name": true, 9 | "comment-format": [true, "check-space"], 10 | "curly": false, 11 | "eofline": true, 12 | "forin": false, 13 | "import-spacing": true, 14 | "indent": [true, "spaces"], 15 | "interface-name": [true, "never-prefix"], 16 | "jsdoc-format": true, 17 | "label-position": true, 18 | "max-line-length": [true, 100], 19 | "member-ordering": false, 20 | "member-access": false, 21 | "no-any": false, 22 | "no-arg": true, 23 | "no-bitwise": true, 24 | "no-console": false, 25 | "no-consecutive-blank-lines": [true, 2], 26 | "no-construct": true, 27 | "no-debugger": true, 28 | "no-default-export": true, 29 | "no-duplicate-variable": true, 30 | "no-empty": true, 31 | "no-empty-interface": false, 32 | "no-eval": true, 33 | "no-implicit-dependencies": false, 34 | "no-internal-module": true, 35 | "no-object-literal-type-assertion": false, 36 | "no-shadowed-variable": true, 37 | "no-string-literal": false, 38 | "no-submodule-imports": false, 39 | "no-trailing-whitespace": true, 40 | "no-unsafe-finally": true, 41 | "no-unused-expression": true, 42 | "no-var-keyword": true, 43 | "no-var-requires": false, 44 | "object-literal-key-quotes": [true, "as-needed"], 45 | "object-literal-sort-keys": false, 46 | "one-line": [true, "check-catch", "check-else", "check-open-brace", "check-whitespace"], 47 | "only-arrow-functions": false, 48 | "ordered-imports": false, 49 | "quotemark": [true, "double"], 50 | "radix": false, 51 | "semicolon": [true, "always", "strict-bound-class-methods"], 52 | "trailing-comma": [ 53 | true, 54 | { 55 | "multiline": { 56 | "objects": "always", 57 | "arrays": "always", 58 | "imports": "always", 59 | "exports": "always", 60 | "typeLiterals": "always" 61 | }, 62 | "singleline": "never", 63 | "esSpecCompliant": true 64 | } 65 | ], 66 | "triple-equals": [true, "allow-null-check"], 67 | "typedef": [true, "parameter", "property-declaration"], 68 | "typedef-whitespace": [ 69 | true, 70 | { 71 | "call-signature": "nospace", 72 | "index-signature": "nospace", 73 | "parameter": "nospace", 74 | "property-declaration": "nospace", 75 | "variable-declaration": "nospace" 76 | } 77 | ], 78 | "variable-name": [true, "ban-keywords", "check-format", "allow-leading-underscore", "allow-pascal-case"], 79 | "whitespace": [ 80 | true, 81 | "check-branch", 82 | "check-decl", 83 | "check-module", 84 | "check-operator", 85 | "check-separator", 86 | "check-type", 87 | "check-typecast" 88 | ] 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /03 d3js-typescript/993 Spain Cloropleth/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["tslint:recommended"], 3 | "defaultSeverity": "warning", 4 | "rules": { 5 | "align": [true, "parameters", "statements"], 6 | "array-type": false, 7 | "arrow-parens": false, 8 | "class-name": true, 9 | "comment-format": [true, "check-space"], 10 | "curly": false, 11 | "eofline": true, 12 | "forin": false, 13 | "import-spacing": true, 14 | "indent": [true, "spaces"], 15 | "interface-name": [true, "never-prefix"], 16 | "jsdoc-format": true, 17 | "label-position": true, 18 | "max-line-length": [true, 100], 19 | "member-ordering": false, 20 | "member-access": false, 21 | "no-any": false, 22 | "no-arg": true, 23 | "no-bitwise": true, 24 | "no-console": false, 25 | "no-consecutive-blank-lines": [true, 2], 26 | "no-construct": true, 27 | "no-debugger": true, 28 | "no-default-export": true, 29 | "no-duplicate-variable": true, 30 | "no-empty": true, 31 | "no-empty-interface": false, 32 | "no-eval": true, 33 | "no-implicit-dependencies": false, 34 | "no-internal-module": true, 35 | "no-object-literal-type-assertion": false, 36 | "no-shadowed-variable": true, 37 | "no-string-literal": false, 38 | "no-submodule-imports": false, 39 | "no-trailing-whitespace": true, 40 | "no-unsafe-finally": true, 41 | "no-unused-expression": true, 42 | "no-var-keyword": true, 43 | "no-var-requires": false, 44 | "object-literal-key-quotes": [true, "as-needed"], 45 | "object-literal-sort-keys": false, 46 | "one-line": [true, "check-catch", "check-else", "check-open-brace", "check-whitespace"], 47 | "only-arrow-functions": false, 48 | "ordered-imports": false, 49 | "quotemark": [true, "double"], 50 | "radix": false, 51 | "semicolon": [true, "always", "strict-bound-class-methods"], 52 | "trailing-comma": [ 53 | true, 54 | { 55 | "multiline": { 56 | "objects": "always", 57 | "arrays": "always", 58 | "imports": "always", 59 | "exports": "always", 60 | "typeLiterals": "always" 61 | }, 62 | "singleline": "never", 63 | "esSpecCompliant": true 64 | } 65 | ], 66 | "triple-equals": [true, "allow-null-check"], 67 | "typedef": [true, "parameter", "property-declaration"], 68 | "typedef-whitespace": [ 69 | true, 70 | { 71 | "call-signature": "nospace", 72 | "index-signature": "nospace", 73 | "parameter": "nospace", 74 | "property-declaration": "nospace", 75 | "variable-declaration": "nospace" 76 | } 77 | ], 78 | "variable-name": [true, "ban-keywords", "check-format", "allow-leading-underscore", "allow-pascal-case"], 79 | "whitespace": [ 80 | true, 81 | "check-branch", 82 | "check-decl", 83 | "check-module", 84 | "check-operator", 85 | "check-separator", 86 | "check-type", 87 | "check-typecast" 88 | ] 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /03 d3js-typescript/994 World Population/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["tslint:recommended"], 3 | "defaultSeverity": "warning", 4 | "rules": { 5 | "align": [true, "parameters", "statements"], 6 | "array-type": false, 7 | "arrow-parens": false, 8 | "class-name": true, 9 | "comment-format": [true, "check-space"], 10 | "curly": false, 11 | "eofline": true, 12 | "forin": false, 13 | "import-spacing": true, 14 | "indent": [true, "spaces"], 15 | "interface-name": [true, "never-prefix"], 16 | "jsdoc-format": true, 17 | "label-position": true, 18 | "max-line-length": [true, 100], 19 | "member-ordering": false, 20 | "member-access": false, 21 | "no-any": false, 22 | "no-arg": true, 23 | "no-bitwise": true, 24 | "no-console": false, 25 | "no-consecutive-blank-lines": [true, 2], 26 | "no-construct": true, 27 | "no-debugger": true, 28 | "no-default-export": true, 29 | "no-duplicate-variable": true, 30 | "no-empty": true, 31 | "no-empty-interface": false, 32 | "no-eval": true, 33 | "no-implicit-dependencies": false, 34 | "no-internal-module": true, 35 | "no-object-literal-type-assertion": false, 36 | "no-shadowed-variable": true, 37 | "no-string-literal": false, 38 | "no-submodule-imports": false, 39 | "no-trailing-whitespace": true, 40 | "no-unsafe-finally": true, 41 | "no-unused-expression": true, 42 | "no-var-keyword": true, 43 | "no-var-requires": false, 44 | "object-literal-key-quotes": [true, "as-needed"], 45 | "object-literal-sort-keys": false, 46 | "one-line": [true, "check-catch", "check-else", "check-open-brace", "check-whitespace"], 47 | "only-arrow-functions": false, 48 | "ordered-imports": false, 49 | "quotemark": [true, "double"], 50 | "radix": false, 51 | "semicolon": [true, "always", "strict-bound-class-methods"], 52 | "trailing-comma": [ 53 | true, 54 | { 55 | "multiline": { 56 | "objects": "always", 57 | "arrays": "always", 58 | "imports": "always", 59 | "exports": "always", 60 | "typeLiterals": "always" 61 | }, 62 | "singleline": "never", 63 | "esSpecCompliant": true 64 | } 65 | ], 66 | "triple-equals": [true, "allow-null-check"], 67 | "typedef": [true, "parameter", "property-declaration"], 68 | "typedef-whitespace": [ 69 | true, 70 | { 71 | "call-signature": "nospace", 72 | "index-signature": "nospace", 73 | "parameter": "nospace", 74 | "property-declaration": "nospace", 75 | "variable-declaration": "nospace" 76 | } 77 | ], 78 | "variable-name": [true, "ban-keywords", "check-format", "allow-leading-underscore", "allow-pascal-case"], 79 | "whitespace": [ 80 | true, 81 | "check-branch", 82 | "check-decl", 83 | "check-module", 84 | "check-operator", 85 | "check-separator", 86 | "check-type", 87 | "check-typecast" 88 | ] 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /03 d3js-typescript/00 Playground/webpack.config.js: -------------------------------------------------------------------------------- 1 | const webpack = require("webpack"); 2 | const path = require("path"); 3 | const HtmlWebpackPlugin = require("html-webpack-plugin"); 4 | 5 | const basePath = __dirname; 6 | 7 | module.exports = { 8 | context: path.join(basePath, "src"), 9 | resolve: { 10 | extensions: [".js", ".ts"], 11 | }, 12 | entry: { 13 | app: ["./app.ts"], 14 | }, 15 | output: { 16 | path: path.join(basePath, "dist"), 17 | }, 18 | optimization: { 19 | splitChunks: { 20 | chunks: "all", 21 | cacheGroups: { 22 | vendorGroup: { 23 | test: /[\\/]node_modules[\\/]/, 24 | name: "vendor", 25 | enforce: true, 26 | }, 27 | }, 28 | }, 29 | }, 30 | module: { 31 | rules: [ 32 | { 33 | test: /\.(ts|js)$/, 34 | exclude: /node_modules/, 35 | loader: "babel-loader", 36 | }, 37 | { 38 | test: /\.css$/, 39 | exclude: /node_modules/, 40 | use: [ 41 | { loader: "style-loader" }, 42 | { loader: "css-loader" } 43 | ], 44 | }, 45 | { 46 | test: /\.scss$/, 47 | exclude: /node_modules/, 48 | use: [ 49 | { loader: "style-loader" }, 50 | { 51 | loader: "css-loader", 52 | options: { 53 | modules: true, 54 | camelCase: true, 55 | importLoaders: 1, 56 | localIdentName: "[local]___[hash:base64:5]", 57 | }, 58 | }, 59 | { loader: "resolve-url-loader" }, 60 | { loader: "sass-loader" }, 61 | ], 62 | }, 63 | // Font resources embedded in final bundle with url-loader. 64 | { 65 | test: /\.(woff|woff2)(\?v=\d+\.\d+\.\d+)?$/, 66 | loader: "url-loader", 67 | options: { 68 | mimetype: "application/font-woff" 69 | } 70 | }, 71 | { 72 | test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, 73 | loader: "url-loader", 74 | options: { 75 | mimetype: "application/octet-stream" 76 | } 77 | }, 78 | { 79 | test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, 80 | loader: "url-loader" 81 | }, 82 | // Common files, emitted to the output directory 83 | { 84 | test: /\.(png|jpg|ico|gif|svg|webp)?$/, 85 | loader: "file-loader", 86 | options: { 87 | name: "[name].[ext]" 88 | } 89 | }, 90 | // Possible Data sources as files. 91 | { 92 | type: "javascript/auto", 93 | test: /\.(geojson|topojson|json|tsv)?$/, 94 | include: /data/, 95 | loader: "file-loader", 96 | options: { 97 | name: "[name].[ext]" 98 | } 99 | }, 100 | ], 101 | }, 102 | plugins: [ 103 | new HtmlWebpackPlugin({ 104 | filename: "index.html", 105 | template: "index.html", 106 | hash: true, 107 | chunksSortMode: "manual", 108 | chunks: ["vendor", "app"], 109 | }), 110 | ], 111 | }; 112 | -------------------------------------------------------------------------------- /03 d3js-typescript/991 Basic Map/webpack.config.js: -------------------------------------------------------------------------------- 1 | const webpack = require("webpack"); 2 | const path = require("path"); 3 | const HtmlWebpackPlugin = require("html-webpack-plugin"); 4 | 5 | const basePath = __dirname; 6 | 7 | module.exports = { 8 | context: path.join(basePath, "src"), 9 | resolve: { 10 | extensions: [".js", ".ts"], 11 | }, 12 | entry: { 13 | app: ["./app.ts"], 14 | }, 15 | output: { 16 | path: path.join(basePath, "dist"), 17 | }, 18 | optimization: { 19 | splitChunks: { 20 | chunks: "all", 21 | cacheGroups: { 22 | vendorGroup: { 23 | test: /[\\/]node_modules[\\/]/, 24 | name: "vendor", 25 | enforce: true, 26 | }, 27 | }, 28 | }, 29 | }, 30 | module: { 31 | rules: [ 32 | { 33 | test: /\.(ts|js)$/, 34 | exclude: /node_modules/, 35 | loader: "babel-loader", 36 | }, 37 | { 38 | test: /\.css$/, 39 | exclude: /node_modules/, 40 | use: [ 41 | { loader: "style-loader" }, 42 | { loader: "css-loader" } 43 | ], 44 | }, 45 | { 46 | test: /\.scss$/, 47 | exclude: /node_modules/, 48 | use: [ 49 | { loader: "style-loader" }, 50 | { 51 | loader: "css-loader", 52 | options: { 53 | modules: true, 54 | camelCase: true, 55 | importLoaders: 1, 56 | localIdentName: "[local]___[hash:base64:5]", 57 | }, 58 | }, 59 | { loader: "resolve-url-loader" }, 60 | { loader: "sass-loader" }, 61 | ], 62 | }, 63 | // Font resources embedded in final bundle with url-loader. 64 | { 65 | test: /\.(woff|woff2)(\?v=\d+\.\d+\.\d+)?$/, 66 | loader: "url-loader", 67 | options: { 68 | mimetype: "application/font-woff" 69 | } 70 | }, 71 | { 72 | test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, 73 | loader: "url-loader", 74 | options: { 75 | mimetype: "application/octet-stream" 76 | } 77 | }, 78 | { 79 | test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, 80 | loader: "url-loader" 81 | }, 82 | // Common files, emitted to the output directory 83 | { 84 | test: /\.(png|jpg|ico|gif|svg|webp)?$/, 85 | loader: "file-loader", 86 | options: { 87 | name: "[name].[ext]" 88 | } 89 | }, 90 | // Possible Data sources as files. 91 | { 92 | type: "javascript/auto", 93 | test: /\.(geojson|topojson|json|tsv)?$/, 94 | include: /data/, 95 | loader: "file-loader", 96 | options: { 97 | name: "[name].[ext]" 98 | } 99 | }, 100 | ], 101 | }, 102 | plugins: [ 103 | new HtmlWebpackPlugin({ 104 | filename: "index.html", 105 | template: "index.html", 106 | hash: true, 107 | chunksSortMode: "manual", 108 | chunks: ["vendor", "app"], 109 | }), 110 | ], 111 | }; 112 | -------------------------------------------------------------------------------- /03 d3js-typescript/992 Map Interaction/webpack.config.js: -------------------------------------------------------------------------------- 1 | const webpack = require("webpack"); 2 | const path = require("path"); 3 | const HtmlWebpackPlugin = require("html-webpack-plugin"); 4 | 5 | const basePath = __dirname; 6 | 7 | module.exports = { 8 | context: path.join(basePath, "src"), 9 | resolve: { 10 | extensions: [".js", ".ts"], 11 | }, 12 | entry: { 13 | app: ["./app.ts"], 14 | }, 15 | output: { 16 | path: path.join(basePath, "dist"), 17 | }, 18 | optimization: { 19 | splitChunks: { 20 | chunks: "all", 21 | cacheGroups: { 22 | vendorGroup: { 23 | test: /[\\/]node_modules[\\/]/, 24 | name: "vendor", 25 | enforce: true, 26 | }, 27 | }, 28 | }, 29 | }, 30 | module: { 31 | rules: [ 32 | { 33 | test: /\.(ts|js)$/, 34 | exclude: /node_modules/, 35 | loader: "babel-loader", 36 | }, 37 | { 38 | test: /\.css$/, 39 | exclude: /node_modules/, 40 | use: [ 41 | { loader: "style-loader" }, 42 | { loader: "css-loader" } 43 | ], 44 | }, 45 | { 46 | test: /\.scss$/, 47 | exclude: /node_modules/, 48 | use: [ 49 | { loader: "style-loader" }, 50 | { 51 | loader: "css-loader", 52 | options: { 53 | modules: true, 54 | camelCase: true, 55 | importLoaders: 1, 56 | localIdentName: "[local]___[hash:base64:5]", 57 | }, 58 | }, 59 | { loader: "resolve-url-loader" }, 60 | { loader: "sass-loader" }, 61 | ], 62 | }, 63 | // Font resources embedded in final bundle with url-loader. 64 | { 65 | test: /\.(woff|woff2)(\?v=\d+\.\d+\.\d+)?$/, 66 | loader: "url-loader", 67 | options: { 68 | mimetype: "application/font-woff" 69 | } 70 | }, 71 | { 72 | test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, 73 | loader: "url-loader", 74 | options: { 75 | mimetype: "application/octet-stream" 76 | } 77 | }, 78 | { 79 | test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, 80 | loader: "url-loader" 81 | }, 82 | // Common files, emitted to the output directory 83 | { 84 | test: /\.(png|jpg|ico|gif|svg|webp)?$/, 85 | loader: "file-loader", 86 | options: { 87 | name: "[name].[ext]" 88 | } 89 | }, 90 | // Possible Data sources as files. 91 | { 92 | type: "javascript/auto", 93 | test: /\.(geojson|topojson|json|tsv)?$/, 94 | include: /data/, 95 | loader: "file-loader", 96 | options: { 97 | name: "[name].[ext]" 98 | } 99 | }, 100 | ], 101 | }, 102 | plugins: [ 103 | new HtmlWebpackPlugin({ 104 | filename: "index.html", 105 | template: "index.html", 106 | hash: true, 107 | chunksSortMode: "manual", 108 | chunks: ["vendor", "app"], 109 | }), 110 | ], 111 | }; 112 | -------------------------------------------------------------------------------- /03 d3js-typescript/993 Spain Cloropleth/webpack.config.js: -------------------------------------------------------------------------------- 1 | const webpack = require("webpack"); 2 | const path = require("path"); 3 | const HtmlWebpackPlugin = require("html-webpack-plugin"); 4 | 5 | const basePath = __dirname; 6 | 7 | module.exports = { 8 | context: path.join(basePath, "src"), 9 | resolve: { 10 | extensions: [".js", ".ts"], 11 | }, 12 | entry: { 13 | app: ["./app.ts"], 14 | }, 15 | output: { 16 | path: path.join(basePath, "dist"), 17 | }, 18 | optimization: { 19 | splitChunks: { 20 | chunks: "all", 21 | cacheGroups: { 22 | vendorGroup: { 23 | test: /[\\/]node_modules[\\/]/, 24 | name: "vendor", 25 | enforce: true, 26 | }, 27 | }, 28 | }, 29 | }, 30 | module: { 31 | rules: [ 32 | { 33 | test: /\.(ts|js)$/, 34 | exclude: /node_modules/, 35 | loader: "babel-loader", 36 | }, 37 | { 38 | test: /\.css$/, 39 | exclude: /node_modules/, 40 | use: [ 41 | { loader: "style-loader" }, 42 | { loader: "css-loader" } 43 | ], 44 | }, 45 | { 46 | test: /\.scss$/, 47 | exclude: /node_modules/, 48 | use: [ 49 | { loader: "style-loader" }, 50 | { 51 | loader: "css-loader", 52 | options: { 53 | modules: true, 54 | camelCase: true, 55 | importLoaders: 1, 56 | localIdentName: "[local]___[hash:base64:5]", 57 | }, 58 | }, 59 | { loader: "resolve-url-loader" }, 60 | { loader: "sass-loader" }, 61 | ], 62 | }, 63 | // Font resources embedded in final bundle with url-loader. 64 | { 65 | test: /\.(woff|woff2)(\?v=\d+\.\d+\.\d+)?$/, 66 | loader: "url-loader", 67 | options: { 68 | mimetype: "application/font-woff" 69 | } 70 | }, 71 | { 72 | test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, 73 | loader: "url-loader", 74 | options: { 75 | mimetype: "application/octet-stream" 76 | } 77 | }, 78 | { 79 | test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, 80 | loader: "url-loader" 81 | }, 82 | // Common files, emitted to the output directory 83 | { 84 | test: /\.(png|jpg|ico|gif|svg|webp)?$/, 85 | loader: "file-loader", 86 | options: { 87 | name: "[name].[ext]" 88 | } 89 | }, 90 | // Possible Data sources as files. 91 | { 92 | type: "javascript/auto", 93 | test: /\.(geojson|topojson|json|tsv)?$/, 94 | include: /data/, 95 | loader: "file-loader", 96 | options: { 97 | name: "[name].[ext]" 98 | } 99 | }, 100 | ], 101 | }, 102 | plugins: [ 103 | new HtmlWebpackPlugin({ 104 | filename: "index.html", 105 | template: "index.html", 106 | hash: true, 107 | chunksSortMode: "manual", 108 | chunks: ["vendor", "app"], 109 | }), 110 | ], 111 | }; 112 | -------------------------------------------------------------------------------- /03 d3js-typescript/994 World Population/webpack.config.js: -------------------------------------------------------------------------------- 1 | const webpack = require("webpack"); 2 | const path = require("path"); 3 | const HtmlWebpackPlugin = require("html-webpack-plugin"); 4 | 5 | const basePath = __dirname; 6 | 7 | module.exports = { 8 | context: path.join(basePath, "src"), 9 | resolve: { 10 | extensions: [".js", ".ts"], 11 | }, 12 | entry: { 13 | app: ["./app.ts"], 14 | }, 15 | output: { 16 | path: path.join(basePath, "dist"), 17 | }, 18 | optimization: { 19 | splitChunks: { 20 | chunks: "all", 21 | cacheGroups: { 22 | vendorGroup: { 23 | test: /[\\/]node_modules[\\/]/, 24 | name: "vendor", 25 | enforce: true, 26 | }, 27 | }, 28 | }, 29 | }, 30 | module: { 31 | rules: [ 32 | { 33 | test: /\.(ts|js)$/, 34 | exclude: /node_modules/, 35 | loader: "babel-loader", 36 | }, 37 | { 38 | test: /\.css$/, 39 | exclude: /node_modules/, 40 | use: [ 41 | { loader: "style-loader" }, 42 | { loader: "css-loader" } 43 | ], 44 | }, 45 | { 46 | test: /\.scss$/, 47 | exclude: /node_modules/, 48 | use: [ 49 | { loader: "style-loader" }, 50 | { 51 | loader: "css-loader", 52 | options: { 53 | modules: true, 54 | camelCase: true, 55 | importLoaders: 1, 56 | localIdentName: "[local]___[hash:base64:5]", 57 | }, 58 | }, 59 | { loader: "resolve-url-loader" }, 60 | { loader: "sass-loader" }, 61 | ], 62 | }, 63 | // Font resources embedded in final bundle with url-loader. 64 | { 65 | test: /\.(woff|woff2)(\?v=\d+\.\d+\.\d+)?$/, 66 | loader: "url-loader", 67 | options: { 68 | mimetype: "application/font-woff" 69 | } 70 | }, 71 | { 72 | test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, 73 | loader: "url-loader", 74 | options: { 75 | mimetype: "application/octet-stream" 76 | } 77 | }, 78 | { 79 | test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, 80 | loader: "url-loader" 81 | }, 82 | // Common files, emitted to the output directory 83 | { 84 | test: /\.(png|jpg|ico|gif|svg|webp)?$/, 85 | loader: "file-loader", 86 | options: { 87 | name: "[name].[ext]" 88 | } 89 | }, 90 | // Possible Data sources as files. 91 | { 92 | type: "javascript/auto", 93 | test: /\.(geojson|topojson|json|tsv)?$/, 94 | include: /data/, 95 | loader: "file-loader", 96 | options: { 97 | name: "[name].[ext]" 98 | } 99 | }, 100 | ], 101 | }, 102 | plugins: [ 103 | new HtmlWebpackPlugin({ 104 | filename: "index.html", 105 | template: "index.html", 106 | hash: true, 107 | chunksSortMode: "manual", 108 | chunks: ["vendor", "app"], 109 | }), 110 | ], 111 | }; 112 | -------------------------------------------------------------------------------- /02 d3js-es5/04 BarChartRefactor/main.js: -------------------------------------------------------------------------------- 1 | 2 | // Let's start using ES6 3 | // And let's organize the code following clean code concepts 4 | // Later one we will complete a version using imports + webpack 5 | 6 | // Isolated data array to a different file 7 | 8 | let margin = null, 9 | width = null, 10 | height = null; 11 | 12 | let svg = null; 13 | let x, y = null; // scales 14 | 15 | setupCanvasSize(); 16 | appendSvg("body"); 17 | setupXScale(); 18 | setupYScale(); 19 | appendXAxis(); 20 | appendYAxis(); 21 | appendChartBars(); 22 | 23 | // 1. let's start by selecting the SVG Node 24 | function setupCanvasSize() { 25 | margin = {top: 0, left: 80, bottom: 20, right: 30}; 26 | width = 960 - margin.left - margin.right; 27 | height = 120 - margin.top - margin.bottom; 28 | } 29 | 30 | function appendSvg(domElement) { 31 | svg = d3.select(domElement).append("svg") 32 | .attr("width", width + margin.left + margin.right) 33 | .attr("height", height + margin.top + margin.bottom) 34 | .append("g") 35 | .attr("transform",`translate(${margin.left}, ${margin.top})`); 36 | 37 | } 38 | 39 | // Now on the X axis we want to map totalSales values to 40 | // pixels 41 | // in this case we map the canvas range 0..350, to 0...maxSales 42 | // domain == data (data from 0 to maxSales) boundaries 43 | function setupXScale() 44 | { 45 | var maxSales = d3.max(totalSales, function(d, i) { 46 | return d.sales; 47 | }); 48 | 49 | x = d3.scaleLinear() 50 | .range([0, width]) 51 | .domain([0, maxSales]); 52 | 53 | } 54 | 55 | // Now we don't have a linear range of values, we have a discrete 56 | // range of values (one per product) 57 | // Here we are generating an array of product names 58 | function setupYScale() 59 | { 60 | y = d3.scaleBand() 61 | .rangeRound([0, height]) 62 | .domain(totalSales.map(function(d, i) { 63 | return d.product; 64 | })); 65 | } 66 | 67 | function appendXAxis() { 68 | // Add the X Axis 69 | svg.append("g") 70 | .attr("transform",`translate(0, ${height})`) 71 | .call(d3.axisBottom(x)); 72 | } 73 | 74 | function appendYAxis() { 75 | // Add the Y Axis 76 | svg.append("g") 77 | .call(d3.axisLeft(y)); 78 | } 79 | 80 | function appendChartBars() 81 | { 82 | // 2. Now let's select all the rectangles inside that svg 83 | // (right now is empty) 84 | var rects = svg.selectAll('rect') 85 | .data(totalSales); 86 | 87 | // Now it's time to append to the list of Rectangles we already have 88 | var newRects = rects.enter(); 89 | 90 | // Let's append a new Rectangles 91 | // UpperCorner: 92 | // Starting x position, the start from the axis 93 | // Starting y position, where the product starts on the y scale 94 | // React width and height: 95 | // height: the space assign for each entry (product) on the Y axis 96 | // width: Now that we have the mapping previously done (linear) 97 | // we just pass the sales and use the X axis conversion to 98 | // get the right value 99 | newRects.append('rect') 100 | .attr('x', x(0)) 101 | .attr('y', function(d, i) { 102 | return y(d.product); 103 | }) 104 | .attr('height', y.bandwidth) 105 | .attr('width', function(d, i) { 106 | return x(d.sales); 107 | }); 108 | } 109 | -------------------------------------------------------------------------------- /00 basics/03 DOM 2/readme.md: -------------------------------------------------------------------------------- 1 | # Intro 2 | 3 | Let's play now with events and javascript. 4 | 5 | # Sample 6 | 7 | We will build this time a modern project strucutre, using: 8 | 9 | - parcel. 10 | - npm. 11 | - typescript. 12 | - d3js (selectors) 13 | 14 | - Let's start by initializing our node project: 15 | 16 | ```bash 17 | npm init 18 | ``` 19 | 20 | - Let's install parcel as our bundler. 21 | 22 | ```bash 23 | npm install parcel --save-dev 24 | ``` 25 | 26 | - Let's install _TypeScript_ 27 | 28 | ```bash 29 | npm install typescript --save 30 | ``` 31 | 32 | - Let's install _d3js_ 33 | 34 | ``bash 35 | npm install d3 --save 36 | ```` 37 | 38 | - Let's install _d3js_ typings 39 | 40 | ```bash 41 | npm install @types/d3 --save-dev 42 | ```` 43 | 44 | - Let's add command to run our project: 45 | 46 | _./package.json_ 47 | 48 | ```diff 49 | "scripts": { 50 | + "start": "parcel index.html --open", 51 | ``` 52 | 53 | - Let's add some styles: 54 | 55 | _./src/styles.css_ 56 | 57 | ```css 58 | /* Applied to all

    tags */ 59 | p { 60 | color: blue; 61 | } 62 | 63 | /* Applied to all tags with the class "red" */ 64 | .red { 65 | background: red; 66 | } 67 | 68 | /* Applied to the tag with the id "some-id" */ 69 | #some-id { 70 | font-style: italic; 71 | } 72 | 73 | /* Applied only to

    tags that are inside

  • tags */ 74 | li p { 75 | color: #0c0; 76 | } 77 | ``` 78 | 79 | - Let's add a basic HTML 80 | 81 | _./index.html_ 82 | 83 | ```html 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 |
    93 |

    Normal paragraph

    94 | 95 |

    Red paragraph

    96 |
    97 | 98 |
      99 |
    1. Unique element
    2. 100 |
    3. Another list element
    4. 101 |
    5. 102 |

      Paragraph inside list element

      103 |

      Second paragraph

      104 |
    6. 105 |
    106 | 107 | 108 | 109 | ``` 110 | 111 | - Let's add some standard selectors: 112 | 113 | _./src/index.ts_ 114 | 115 | ```typescript 116 | // DOM API 117 | var element = document.getElementById("some-id"); 118 | //
  • Unique element
  • 119 | console.log(element); 120 | 121 | var plength = document.getElementsByTagName("p").length; 122 | // 4 123 | console.log(plength); 124 | 125 | var reds = document.getElementsByClassName("red"); 126 | // [

    Red paragraph

    ] 127 | console.log(reds[0].innerHTML); 128 | // "Red paragraph" 129 | ``` 130 | 131 | - Let's test this project: 132 | 133 | ```bash 134 | npm start 135 | ``` 136 | 137 | - Let's add some d3js selectors 138 | 139 | _./src/index.ts_ 140 | 141 | ```typescript 142 | import * as d3 from 'd3'; 143 | ``` 144 | 145 | ```typescript 146 | // D3 Selection API 147 | var one = d3.select("p").size(); // select() only finds one 148 | console.log(one); 149 | 150 | // 1 151 | var many = d3.selectAll("p").size(); // selectAll() finds all 152 | console.log(many); 153 | 154 | // 4 155 | var redElements = d3.selectAll(".red"); 156 | // [ > Array[1] ] 157 | console.log(redElements.text()); 158 | // "Red paragraph" 159 | ``` 160 | 161 | - Just to wrap up let's hook to an on click event, we will add one section 162 | in the HTML 163 | 164 | ```diff 165 | 166 | 167 | +

    168 | + Click on me! 169 | +

    170 | ``` 171 | 172 | - On the javascript side: 173 | 174 | _./index.ts_ 175 | 176 | ```typescript 177 | var clickMe = document.getElementById("click-me"); 178 | clickMe.onclick = function() { 179 | if (this.style.backgroundColor) { 180 | this.style.backgroundColor = ""; 181 | } else { 182 | this.style.backgroundColor = "red"; 183 | } 184 | }; 185 | ``` 186 | -------------------------------------------------------------------------------- /02 d3js-es5/03 BarChartAxis/readme.md: -------------------------------------------------------------------------------- 1 | # Setting up chart axis 2 | 3 | In this sample we will set the X and Y axis. 4 | 5 | We will start from scratch adn later on we will refactor the bar chart. 6 | 7 | # Steps 8 | 9 | - This time we will create the HTML with no SVG tag (we will inject it via javascript). 10 | 11 | _./index.html_ 12 | 13 | ```html 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | ``` 27 | 28 | - Let's add the sales data. 29 | 30 | _./main.js_ 31 | 32 | ```javascript 33 | var totalSales = [ 34 | { product: 'Hoodie', sales: 7 }, 35 | { product: 'Jacket', sales: 6 }, 36 | { product: 'Snuggie', sales: 9 }, 37 | ]; 38 | ``` 39 | 40 | - Let's calculate the size of the new chart and add some margins 41 | 42 | _./main.js_ 43 | 44 | ```javascript 45 | var margin = {top: 0, left: 80, bottom: 20, right: 0}; 46 | var width = 960 - margin.left - margin.right; 47 | var height = 120 - margin.top - margin.bottom; 48 | ``` 49 | 50 | - Let's add the SVG element with the given new width and height, and translate the origins applying the margins. 51 | 52 | _./main.js_ 53 | 54 | ```javascript 55 | var svg = d3.select("body").append("svg") 56 | .attr("width", width + margin.left + margin.right) 57 | .attr("height", height + margin.top + margin.bottom) 58 | .append("g") 59 | .attr("transform", 60 | "translate(" + margin.left + "," + margin.top + ")"); 61 | ; 62 | 63 | var barChartsGroup = svg.append("g"); 64 | ``` 65 | 66 | - Now let's select all the rectangles inside that svg 67 | 68 | _./main.js_ 69 | 70 | ```javascript 71 | // 2. Now let's select all the rectangles inside that svg 72 | // (right now is empty) 73 | var rects = barChartsGroup.selectAll('rect') 74 | .data(totalSales); 75 | ``` 76 | 77 | - In order to calculate the max width for the X axis 78 | on the bar chart, we need to know the max sales value we are going 79 | to show. 80 | 81 | _./main.js_ 82 | 83 | ```javascript 84 | var maxSales = d3.max(totalSales, function(d, i) { 85 | return d.sales; 86 | }); 87 | ``` 88 | 89 | - Now on the X axis we want to map totalSales values to pixels 90 | in this case we map the canvas range 0..width, to 0...maxSales 91 | domain == data (data from 0 to maxSales) boundaries 92 | 93 | ```javascript 94 | var x = d3.scaleLinear() 95 | .range([0, width]) 96 | .domain([0, maxSales]); 97 | ``` 98 | 99 | - Now we don't have a linear range of values, we have a discrete 100 | range of values (one per product) Here we are generating an array of product names 101 | 102 | ```javascript 103 | var y = d3.scaleBand() 104 | .rangeRound([0, height]) 105 | .domain(totalSales.map(function(d, i) { 106 | return d.product; 107 | })); 108 | ``` 109 | 110 | - Now it's time to append to the list of Rectangles we already have. 111 | 112 | ```javascript 113 | // Now it's time to append to the list of Rectangles we already have 114 | var newRects = rects.enter(); 115 | 116 | // Let's append a new Rectangles 117 | // UpperCorner: 118 | // Starting x position, the start from the axis 119 | // Starting y position, where the product starts on the y scale 120 | // React width and height: 121 | // height: the space assign for each entry (product) on the Y axis 122 | // width: Now that we have the mapping previously done (linear) 123 | // we just pass the sales and use the X axis conversion to 124 | // get the right value 125 | newRects.append('rect') 126 | .attr('x', x(0)) 127 | .attr('y', function(d, i) { 128 | return y(d.product); 129 | }) 130 | .attr('height', y.bandwidth) 131 | .attr('width', function(d, i) { 132 | return x(d.sales); 133 | }); 134 | ``` 135 | 136 | - Let's add the X and Y axis. 137 | 138 | ```javascript 139 | // Add the X Axis 140 | svg.append("g") 141 | .attr("transform", "translate(0,"+ height +")") 142 | .call(d3.axisBottom(x)); 143 | 144 | // Add the Y Axis 145 | svg.append("g") 146 | .call(d3.axisLeft(y)); 147 | ``` 148 | 149 | 150 | 151 | -------------------------------------------------------------------------------- /02 d3js-es5/02 BarChart/readme.md: -------------------------------------------------------------------------------- 1 | # Barchart starting with d3js 2 | 3 | Creating a chart from scratch it's a painful process let's see what d3js offers to us to simplify 4 | this process. 5 | 6 | # Steps 7 | 8 | - First let's create the basic HTML, in this case we will create just the SVG container. 9 | 10 | _./index.html_ 11 | 12 | ```html 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | ``` 27 | 28 | - Let's define the data we want to display (sales by item): 29 | 30 | _main.js_ 31 | 32 | ```javascript 33 | var totalSales = [ 34 | { product: 'Hoodie', sales: 7 }, 35 | { product: 'Jacket', sales: 6 }, 36 | { product: 'Snuggie', sales: 9 }, 37 | ]; 38 | ``` 39 | 40 | - It's time to use a selector and selct the _svg_ node that we have created in the HTML: 41 | 42 | _main.js_ 43 | 44 | ```javascript 45 | // 1. let's start by selecting the SVG Node 46 | var svg = d3.select('svg'); 47 | ``` 48 | 49 | - Now let's select all the rectangles inside that areas (right now this selection is empty) 50 | 51 | ```javascript 52 | // 2. Now let's select all the rectangles inside that svg 53 | // (right now is empty) 54 | var rects = svg.selectAll('rect') 55 | .data(totalSales); 56 | ``` 57 | 58 | - In order to calculate the max width for the X axis on the bar chart, we need to know the max sales value we are going 59 | to show. 60 | 61 | ```javascript 62 | // 3. In order to calculate the max width for the X axis 63 | // on the bar chart, we need to know the max sales value we are going 64 | // to show. 65 | 66 | var maxSales = d3.max(totalSales, function(d, i) { 67 | return d.sales; 68 | }); 69 | ``` 70 | 71 | - Now on the X axis we want to map totalSales values to pixels 72 | in this case we map the canvas range 0..350, to 0...maxSales 73 | domain == data (data from 0 to maxSales) boundaries 74 | ** Tip: let's play with [0, 350] values 75 | 76 | ```javascript 77 | // Now on the X axis we want to map totalSales values to 78 | // pixels 79 | // in this case we map the canvas range 0..350, to 0...maxSales 80 | // domain == data (data from 0 to maxSales) boundaries 81 | // ** Tip: let's play with [0, 350] values 82 | var x = d3.scaleLinear() 83 | .range([0, 350]) 84 | .domain([0, maxSales]); 85 | ``` 86 | 87 | - Now we don't have a linear range of values, we have a discrete 88 | range of values (one per product), Here we are generating an array of product names 89 | ** Tip: let's play with [0, 75] values 90 | 91 | ```javascript 92 | // Now we don't have a linear range of values, we have a discrete 93 | // range of values (one per product) 94 | // Here we are generating an array of product names 95 | // ** Tip: let's play with [0, 75] values 96 | var y = d3.scaleBand() 97 | .rangeRound([0, 75]) 98 | .domain(totalSales.map(function(d, i) { 99 | return d.product; 100 | })); 101 | ``` 102 | 103 | - Now it's time to append to the list of Rectangles we already have 104 | 105 | ```javascript 106 | // Now it's time to append to the list of Rectangles we already have 107 | var newRects = rects.enter(); 108 | ``` 109 | 110 | - Let's append a new Rectangles 111 | UpperCorner: 112 | Starting x position, the start from the axis 113 | Starting y position, where the product starts on the y scale 114 | React width and height: 115 | height: the space assign for each entry (product) on the Y axis 116 | width: Now that we have the mapping previously done (linear) 117 | we just pass the sales and use the X axis conversion to 118 | get the right value 119 | 120 | 121 | ```javascript 122 | newRects.append('rect') 123 | .attr('x', x(0)) 124 | .attr('y', function(d, i) { 125 | return y(d.product); 126 | }) 127 | .attr('height', y.bandwidth) 128 | .attr('width', function(d, i) { 129 | return x(d.sales); 130 | }); 131 | ``` 132 | 133 | > **Excercise**: Let's try to this dynamic, we dont' want to stick to a given resolution, steps: 134 | 135 | 1. Create a function where you determine the size of the canvas as parameters. 136 | 2. Get the SVG widht and height and maximize size. 137 | 138 | tips 139 | 140 | - Wrap the create chart in a function: 141 | 142 | ```javascript 143 | function drawBarchChart(width, height) { 144 | ``` 145 | 146 | - Get the svg width and height 147 | 148 | ```javascript 149 | var svg = d3.select('svg'); 150 | drawBarcChart(svg._groups[0][0].clientWidth, svg._groups[0][0].clientHeight); 151 | ``` 152 | 153 | 154 | -------------------------------------------------------------------------------- /00 basics/01 CSS/readme.md: -------------------------------------------------------------------------------- 1 | # CSS basics 2 | 3 | Let's create a very basic sample and play a bit with CSS 4 | 5 | # Sample 6 | 7 | - Let's start by creating our basic _index.html_ file 8 | 9 | _index.html_ 10 | 11 | ```html 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | ``` 20 | 21 | - Let's create an empty filed called _styles.css_ 22 | 23 | - Now it's time to define the metadata content in the _head_ section. 24 | 25 | ```diff 26 | 27 | 28 | 29 | + 30 | + 31 | + 32 | 33 | 34 | 35 | 36 | ``` 37 | 38 | We have just set the chartset to UTF8 (to avoid issues with tilde and addition characters), and imported the 39 | _styles.css_ file that we have previously created. 40 | 41 | - Next step we are going to add normal paragraph to the body section. 42 | 43 | ```diff 44 | 45 | +
    46 | +

    Normal paragraph

    47 | +
    48 | 49 | ``` 50 | 51 | - Now let's add a new paragraph that will use a class that will place the background in red. 52 | 53 | _./styles.css_ 54 | 55 | ```css 56 | /* Applied to all tags with the class "red" */ 57 | .red { 58 | background: red; 59 | } 60 | ``` 61 | 62 | _./index.html_ 63 | 64 | ```diff 65 | 66 |
    67 |

    Normal paragraph

    68 | 69 | +

    Red paragraph

    70 |
    71 | ``` 72 | 73 | - Now let's cover a bit more complex scenario: 74 | 75 | ```html 76 |
      77 |
    1. Unique element
    2. 78 |
    3. Another list element
    4. 79 |
    5. 80 |

      Paragraph inside list element

      81 |

      Second paragraph

      82 |
    6. 83 |
    84 | ``` 85 | 86 | Let's say we want to highlight in green all the paragrapsh that are inside an li element. 87 | 88 | _styles.css_ 89 | 90 | ```css 91 | /* Applied only to

    tags that are inside

  • tags */ 92 | li p { 93 | color: #0C0; 94 | } 95 | ``` 96 | 97 | - And now we want to highlight an specific element (italic, by id). 98 | 99 | _styles.css_ 100 | 101 | ```css 102 | /* Applied to the tag with the id "some-id" */ 103 | #some-id { 104 | font-style: italic; 105 | } 106 | ``` 107 | 108 | _index.html_ 109 | 110 | ```html 111 |
      112 |
    1. Unique element
    2. 113 |
    3. Another list element
    4. 114 |
    5. 115 |

      Paragraph inside list element

      116 |

      Second paragraph

      117 |
    6. 118 |
    119 | ``` 120 | 121 | - Ok, we learnt something... but the result was quite ugly, let's add some nice design. 122 | Let's remove the current list, and create a new one 123 | 124 | ```diff 125 | -
      126 | -
    1. Unique element
    2. 127 | -
    3. Another list element
    4. 128 | -
    5. 129 | -

      Paragraph inside list element

      130 | -

      Second paragraph

      131 | -
    6. 132 | -
    133 | + 142 | ``` 143 | 144 | - From the CSS let's remove the styles we have created and add the following 145 | 146 | ```diff 147 | - /* Applied to all tags with the class "red" */ 148 | - .red { 149 | - background: red; 150 | - } 151 | 152 | - /* Applied to the tag with the id "some-id" */ 153 | - #some-id { 154 | - font-style: italic; 155 | - } 156 | 157 | - /* Applied only to

    tags that are inside

  • tags */ 158 | - li p { 159 | - color: #0C0; 160 | - } 161 | 162 | + h2 { 163 | + font: 400 40px/1.5 Helvetica, Verdana, sans-serif; 164 | + margin: 0; 165 | + padding: 0; 166 | + } 167 | + 168 | + ul { 169 | + list-style-type: none; 170 | + margin: 0; 171 | + padding: 0; 172 | + } 173 | + 174 | + ul li { 175 | + font: 200 20px/1.5 Helvetica, Verdana, sans-serif; 176 | + border-bottom: 1px solid #ccc; 177 | + } 178 | + 179 | + ul li:last-child { 180 | + border: none; 181 | + } 182 | + 183 | + ul li a { 184 | + text-decoration: none; 185 | + color: #000; 186 | + display: block; 187 | + width: 100%; 188 | + 189 | + -webkit-transition: font-size 0.3s ease, background-color 0.3s ease; 190 | + -moz-transition: font-size 0.3s ease, background-color 0.3s ease; 191 | + -o-transition: font-size 0.3s ease, background-color 0.3s ease; 192 | + -ms-transition: font-size 0.3s ease, background-color 0.3s ease; 193 | + transition: font-size 0.3s ease, background-color 0.3s ease; 194 | +} 195 | + 196 | + ul li a:hover { 197 | + font-size: 30px; 198 | + background: #f6f6f6; 199 | +} 200 | ``` 201 | 202 | 203 | 204 | 205 | 206 | -------------------------------------------------------------------------------- /03 d3js-typescript/994 World Population/src/d3/net-population.d3.ts: -------------------------------------------------------------------------------- 1 | import { mouse } from "d3"; 2 | import { select } from "d3-selection"; 3 | import { geoNaturalEarth1, geoPath } from "d3-geo"; 4 | import { interpolateBlues } from "d3-scale-chromatic"; 5 | import { scaleSqrt } from "d3-scale"; 6 | import { json } from "d3-fetch"; 7 | import { FeatureCollection, Geometry, Feature } from 'geojson'; 8 | 9 | // (*) Lets define a width and height for the SVG user space 10 | // coordinate system (viewBox), also a padding to avoid 11 | // overflows. 12 | const width = 960; 13 | const height = 460; 14 | const padding = 20; 15 | 16 | // (*) Lets add a card for our map. 17 | const card = select("#root") 18 | .append("div") 19 | .attr("class", "card"); 20 | 21 | // (*) Now the SVG canvas with the viewBox. 22 | const svg = card 23 | .append("svg") 24 | .attr("width", "100%") 25 | .attr("height", "100%") 26 | .attr("viewBox", `${-padding} ${-3*padding} ${width + 2*padding} ${height + 4*padding}`); 27 | 28 | // Main title. 29 | const mainTitle = svg 30 | .append("g") 31 | .attr("transform", `translate(${width / 2}, ${-1.5 * padding})`) 32 | .append("text") 33 | .attr("text-anchor", "middle") 34 | .attr("font-weight", "bold") 35 | .attr("font-size", "2rem") 36 | .text("Historic Population") 37 | 38 | // Also, lets create a group whithin the svg to group 39 | // all the countries inside. 40 | const countriesGroup = svg 41 | .append("g"); 42 | 43 | // (*) Lets create a projection for our map. Since we want 44 | // to represent the whole world, a good choice for small-scale 45 | // maps is natural Earth projection. 46 | const projection = geoNaturalEarth1() 47 | .translate([width/2, height/2]); 48 | 49 | // And then a path creator based on that projection. 50 | const pathCreator = geoPath() 51 | .projection(projection); 52 | 53 | // (*) Lets implement a useful scale to assign color to 54 | // countries based on its population. 55 | const populationLogScale = scaleSqrt().exponent(1/6) 56 | .domain([0, 1500000000]) 57 | .range([0, 1]); 58 | const colorScale = (population: number) => population ? 59 | interpolateBlues(populationLogScale(population)) : "pink"; 60 | 61 | // (*) Let's load the needed data. This time we will use an 62 | // async helper borrowed from Promise. We are requiring local 63 | // files using require() for webpack to provide us with the right 64 | // path. 65 | Promise.all([ 66 | json(require("../data/countries.geojson")), 67 | json(require("../data/population.stats.json")) 68 | ]).then(startChart as (value) => void); 69 | 70 | // (*) And the function callback to handle that loaded data. 71 | // We will need typings here to specify the structure of the 72 | // expected country entities and population records. 73 | interface CountryProps { 74 | name: string; 75 | population: number; 76 | }; 77 | 78 | interface PopulationRecord { 79 | "Country Code": string; 80 | "Country Name": string; 81 | "Value": number; 82 | "Year": number; 83 | } 84 | 85 | // Here is the function. 86 | function startChart([countries, population]: [FeatureCollection, PopulationRecord[]]) { 87 | // Utility function to lookup population by year and country. 88 | const populationLookupFunction = createPopulationLookup(population); 89 | 90 | // First paint, just countries with no population data. 91 | enterPattern(countries); 92 | 93 | // Now, lets simulate population data is changing over time. 94 | // 1 year = 1 second. 95 | const totalYears = 56; 96 | let yearIndex = 0; 97 | setInterval(() => { 98 | const year = 1960 + yearIndex++ % totalYears; 99 | updatePattern(year, countries, populationLookupFunction); 100 | }, 1000); 101 | } 102 | 103 | const createPopulationLookup = (population: PopulationRecord[]) => 104 | (year: number, countryName: string) => { 105 | const record = population.find(record => 106 | record["Country Name"] === countryName && record["Year"] === year); 107 | return record ? record["Value"] : undefined; 108 | } 109 | 110 | const enterPattern = (countries: FeatureCollection) => { 111 | countriesGroup.selectAll("path") 112 | .data(countries.features, (d: Feature) => d.properties.name) 113 | .enter() 114 | .append("path") 115 | .attr("d", pathCreator) 116 | .attr("fill", d => colorScale(d.properties.population)) 117 | .style("stroke", "white") 118 | .style("stroke-width", "0.5px"); 119 | } 120 | 121 | const updatePattern = ( 122 | year: number, 123 | countries: FeatureCollection, 124 | getPopulation: (year: number, countryName: string) => number, 125 | ) => { 126 | mainTitle.text(`Year ${year.toLocaleString()}`); 127 | 128 | countriesGroup.selectAll("path") 129 | .data(countries.features, (d: Feature) => d.properties.name) 130 | .attr("fill", d => colorScale(getPopulation(year, d.properties.name))) 131 | } 132 | -------------------------------------------------------------------------------- /03 d3js-typescript/992 Map Interaction/src/d3/countries.d3.ts: -------------------------------------------------------------------------------- 1 | import { mouse } from "d3"; 2 | import { select } from "d3-selection"; 3 | import { geoNaturalEarth1, geoPath } from "d3-geo"; 4 | import { interpolateBlues } from "d3-scale-chromatic"; 5 | import { scaleSqrt } from "d3-scale"; 6 | import { json, tsv } from "d3-fetch"; 7 | import { FeatureCollection, Geometry, Feature } from 'geojson'; 8 | 9 | // (*) Lets define a width and height for the SVG user space 10 | // coordinate system (viewBox), also a padding to avoid 11 | // overflows. 12 | const width = 960; 13 | const height = 460; 14 | const padding = 20; 15 | 16 | // (*) Lets add a card for our map. 17 | const card = select("#root") 18 | .append("div") 19 | .attr("class", "card"); 20 | 21 | // (*) Also lets add a reserved div for a tooltip. 22 | const tooltip = select("#root") 23 | .append("div") 24 | .style("display", "none") 25 | .style("position", "absolute") 26 | .style("padding", "10px") 27 | .style("border-radius", "3px") 28 | .style("background-color", "black") 29 | .style("color", "white") 30 | .style("opacity", "0.7"); 31 | 32 | // (*) Now the SVG canvas with the viewBox. 33 | const svg = card 34 | .append("svg") 35 | .attr("width", "100%") 36 | .attr("height", "100%") 37 | .attr("viewBox", `${-padding} ${-padding} ${width + 2*padding} ${height + 2*padding}`); 38 | 39 | // Also, lets create a group whithin the svg to group 40 | // all the countries inside. 41 | const countriesGroup = svg 42 | .append("g"); 43 | 44 | // (*) Lets create a projection for our map. Since we want 45 | // to represent the whole world, a good choice for small-scale 46 | // maps is natural Earth projection. 47 | const projection = geoNaturalEarth1() 48 | .translate([width/2, height/2]); 49 | 50 | // And then a path creator based on that projection. 51 | const pathCreator = geoPath() 52 | .projection(projection); 53 | 54 | // (*) Lets implement a useful scale to assign color to 55 | // countries based on its population. 56 | const populationLogScale = scaleSqrt().exponent(1/6) 57 | .domain([0, 1500000000]) 58 | .range([0, 1]); 59 | const colorScale = (population: number) => interpolateBlues(populationLogScale(population)); 60 | 61 | // (*) Let's load the needed data. This time we will use an 62 | // async helper borrowed from Promise. We are requiring local 63 | // files using require() for webpack to provide us with the right 64 | // path. Prior to that we need to do something with webpack config: 65 | // **** WARNING **** Remember to change webpack rule to use 66 | // file-loader for all these data extensions. 67 | 68 | Promise.all([ 69 | json(require("../data/countries.geojson")), 70 | tsv(require("../data/population.tsv")) 71 | ]).then(onDataReady as (value) => void); 72 | 73 | // (*) And the function callback to handle that loaded data. 74 | // We will need typings here to specify the structure of the 75 | // expected country entities and population records. 76 | interface CountryProps { 77 | name: string; 78 | }; 79 | 80 | interface PopulationRecord { 81 | id: string; 82 | name: string; 83 | population: string; 84 | } 85 | 86 | // Here is the function. 87 | function onDataReady([countries, population]: [FeatureCollection, PopulationRecord[]]) { 88 | const populationMap = population.reduce( 89 | (acc, record) => { 90 | acc[record.name] = Number(record.population); 91 | return acc; 92 | }, {} 93 | ); 94 | 95 | // (*) Lets implement the ENTER pattern for each new country to be represented 96 | // with a SVG path, joined to its datum. 97 | countriesGroup.selectAll("path") 98 | .data(countries.features, (d: Feature) => d.properties.name) 99 | .enter() 100 | .append("path") 101 | .attr("d", pathCreator) 102 | .attr("fill", d => colorScale(populationMap[d.properties.name])) 103 | .style("stroke", "white") 104 | .style("stroke-width", "0.5px") 105 | .style("opacity", 0.8) 106 | // Finally, lets bind some mouse events to show a tooltip with info. 107 | .on("mouseenter", onMouseEnter) 108 | .on("mousemove", onMouseMove) 109 | .on("mouseleave", onMouseLeave); 110 | 111 | 112 | // (*) You can find below the event handlers implementation 113 | 114 | // OnMouseEnter we will show the tooltip and hightlight the country. 115 | function onMouseEnter(d: Feature) { 116 | tooltip 117 | .style("display", "block") 118 | .html(` 119 |

    Country: ${d.properties.name}

    120 |

    Population: ${populationMap[d.properties.name].toLocaleString()}

    121 | `); 122 | 123 | select(this) 124 | .raise() // To be able to see the stroke width change. 125 | .transition() 126 | .ease(Math.sqrt) 127 | .duration(400) 128 | .style("opacity", 1) 129 | .style("stroke", "orange") 130 | .style("stroke-width", "1.5px"); 131 | }; 132 | 133 | // OnMouseMove lets update the tooltip position. 134 | function onMouseMove() { 135 | const [mx, my] = mouse(document.body); 136 | 137 | tooltip 138 | .style("left", `${mx + 10}px`) 139 | .style("top", `${my + 10}px`); 140 | }; 141 | 142 | // OnMouseLeave just hide the tooltip. 143 | function onMouseLeave() { 144 | tooltip 145 | .style("display", "none"); 146 | 147 | select(this) 148 | .transition() 149 | .style("opacity", 0.8) 150 | .style("stroke", "white") 151 | .style("stroke-width", "0.5px"); 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /03 d3js-typescript/994 World Population/src/d3/birth-rate.d3.ts: -------------------------------------------------------------------------------- 1 | import "d3-transition"; 2 | import { select } from "d3-selection"; 3 | import { geoNaturalEarth1, geoPath } from "d3-geo"; 4 | import { interpolateGnBu, interpolateOrRd } from "d3-scale-chromatic"; 5 | import { scaleSqrt } from "d3-scale"; 6 | import { json } from "d3-fetch"; 7 | import { FeatureCollection, Geometry, Feature } from 'geojson'; 8 | import { isNumber } from 'util'; 9 | 10 | 11 | // (*) Lets define a width and height for the SVG user space 12 | // coordinate system (viewBox), also a padding to avoid 13 | // overflows. 14 | const width = 960; 15 | const height = 460; 16 | const padding = 20; 17 | 18 | // (*) Lets add a card for our map. 19 | const card = select("#root") 20 | .append("div") 21 | .attr("class", "card"); 22 | 23 | // (*) Now the SVG canvas with the viewBox. 24 | const svg = card 25 | .append("svg") 26 | .attr("width", "100%") 27 | .attr("height", "100%") 28 | .attr("viewBox", `${-padding} ${-3*padding} ${width + 2*padding} ${height + 4*padding}`); 29 | 30 | // Main title. 31 | const mainTitle = svg 32 | .append("g") 33 | .attr("transform", `translate(${width / 2}, ${-1.5 * padding})`) 34 | .append("text") 35 | .attr("text-anchor", "middle") 36 | .attr("font-weight", "bold") 37 | .attr("font-size", "2rem") 38 | .text("Historic Population") 39 | 40 | // Also, lets create a group whithin the svg to group 41 | // all the countries inside. 42 | const countriesGroup = svg 43 | .append("g"); 44 | 45 | // (*) Lets create a projection for our map. Since we want 46 | // to represent the whole world, a good choice for small-scale 47 | // maps is natural Earth projection. 48 | const projection = geoNaturalEarth1() 49 | .translate([width/2, height/2]); 50 | 51 | // And then a path creator based on that projection. 52 | const pathCreator = geoPath() 53 | .projection(projection); 54 | 55 | // (*) Lets implement a useful scale to assign color to 56 | // countries based on its population grow. 57 | const popIncreaseScale = scaleSqrt().exponent(1/2).domain([0, 0.2]).range([0, 1]); 58 | const popDecreaseScale = scaleSqrt().exponent(1/4).domain([-0.1, 0]).range([1, 0]); 59 | const colorScale = (delta: number) => isNumber(delta) ? 60 | delta >= 0 ? 61 | interpolateGnBu(popIncreaseScale(delta)) : 62 | interpolateOrRd(popDecreaseScale(delta)) : 63 | "pink"; 64 | 65 | // (*) Let's load the needed data. This time we will use an 66 | // async helper borrowed from Promise. We are requiring local 67 | // files using require() for webpack to provide us with the right 68 | // path. 69 | Promise.all([ 70 | json(require("../data/countries.geojson")), 71 | json(require("../data/population.stats.json")) 72 | ]).then(startChart as (value) => void); 73 | 74 | // (*) And the function callback to handle that loaded data. 75 | // We will need typings here to specify the structure of the 76 | // expected country entities and population records. 77 | interface CountryProps { 78 | name: string; 79 | population: number; 80 | }; 81 | 82 | interface PopulationRecord { 83 | "Country Code": string; 84 | "Country Name": string; 85 | "Value": number; 86 | "Year": number; 87 | "Delta": number; 88 | } 89 | 90 | // Here is the function. 91 | function startChart([countries, population]: [FeatureCollection, PopulationRecord[]]) { 92 | // Compute delta population as the population grow percentage. 93 | calculateDeltaPopulation(population); 94 | 95 | // Utility function to lookup delta population by year and country. 96 | const populationDeltaLookupFunction = createDeltaPopulationLookup(population); 97 | 98 | // First paint, just countries with no population data. 99 | enterPattern(countries); 100 | 101 | // Now, lets simulate population data is changing over time. 102 | // 1 year = 1 second. 103 | const totalYears = 56; 104 | let yearIndex = 0; 105 | setInterval(() => { 106 | const year = 1960 + yearIndex++ % totalYears; 107 | // And update our visualization accordingly. 108 | updatePattern(year, countries, populationDeltaLookupFunction); 109 | }, 1000); 110 | }; 111 | 112 | const calculateDeltaPopulation = (population: PopulationRecord[]) => { 113 | population.forEach(record => { 114 | const previousRecord = population.find(r => 115 | r["Country Name"] === record["Country Name"] && r["Year"] === record["Year"] - 1); 116 | record["Delta"] = previousRecord ? 117 | (record["Value"] - previousRecord["Value"]) / previousRecord["Value"] 118 | : 0; 119 | }); 120 | }; 121 | 122 | const createDeltaPopulationLookup = (population: PopulationRecord[]) => 123 | (year: number, countryName: string) => { 124 | const record = population.find(record => 125 | record["Country Name"] === countryName && record["Year"] === year); 126 | return record ? record["Delta"] : 0; 127 | }; 128 | 129 | const enterPattern = (countries: FeatureCollection) => { 130 | countriesGroup.selectAll("path") 131 | .data(countries.features, (d: Feature) => d.properties.name) 132 | .enter() 133 | .append("path") 134 | .attr("d", pathCreator) 135 | .attr("fill", d => colorScale(0)) 136 | .style("stroke", "white") 137 | .style("stroke-width", "0.5px"); 138 | } 139 | 140 | const updatePattern = ( 141 | year: number, 142 | countries: FeatureCollection, 143 | getDeltaPopulation: (year: number, countryName: string) => number, 144 | ) => { 145 | mainTitle.text(`Year ${year.toLocaleString()}`); 146 | 147 | countriesGroup.selectAll("path") 148 | .data(countries.features, (d: Feature) => d.properties.name) 149 | .transition() 150 | .duration(900) 151 | .attr("fill", d => colorScale(getDeltaPopulation(year, d.properties.name))) 152 | } -------------------------------------------------------------------------------- /01 nvd3/01 BubbleChart/readme.md: -------------------------------------------------------------------------------- 1 | # nvd3 Bubble Chart 2 | 3 | Let's finish our third parties libraries startup by creating a simple bubble chart (nvd3). 4 | 5 | # Steps to reproduce the sample 6 | 7 | This time we will just create the HTML in one go (you can find a step by step detailed guide in the previous sample). 8 | 9 | > This time we will include directly all the libs, plus data and main js files, we are including as well an SVG shape in 10 | the div container 11 | 12 | _./index.html_ 13 | 14 | ```html 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 45 | 46 | 47 | 48 | 49 |
    50 | 51 |
    52 | 53 | 54 | 55 | ``` 56 | 57 | - Now it's time to go through defining the data: 58 | - We are going to define an array of shapes (one of the shapes will be custom). 59 | - The we are going to add random values + shapes, in a loop following the format: 60 | 61 | ```json 62 | { 63 | x: number, 64 | y: number, 65 | size: number, 66 | shape: string 67 | } 68 | ``` 69 | 70 | _./data.js_ 71 | 72 | ```javascript 73 | function randomData(groups, points) { //# groups,# points per group 74 | // smiley and thin-x are our custom symbols! 75 | var data = [], 76 | shapes = ['thin-x', 'circle', 'cross', 'triangle-up', 'triangle-down', 'diamond', 'square'], 77 | random = d3.random.normal(); 78 | 79 | for (i = 0; i < groups; i++) { 80 | data.push({ 81 | key: 'Group ' + i, 82 | values: [] 83 | }); 84 | 85 | for (j = 0; j < points; j++) { 86 | data[i].values.push({ 87 | x: random(), 88 | y: random(), 89 | size: Math.round(Math.random() * 100) / 100, 90 | shape: shapes[j % shapes.length] 91 | }); 92 | } 93 | } 94 | 95 | return data; 96 | } 97 | ``` 98 | 99 | - Moving into the defining chart section, first let's define a custom shape (svg). 100 | 101 | _./main.js_ 102 | 103 | ```javascript 104 | // register our custom symbols to nvd3 105 | // make sure your path is valid given any size because size scales if the chart scales. 106 | nv.utils.symbolMap.set('thin-x', function(size) { 107 | size = Math.sqrt(size); 108 | return 'M' + (-size/2) + ',' + (-size/2) + 109 | 'l' + size + ',' + size + 110 | 'm0,' + -(size) + 111 | 'l' + (-size) + ',' + size; 112 | }); 113 | ``` 114 | 115 | - Let's add our AddGraph funnction: 116 | 117 | _./main.js_ 118 | 119 | ```javascript 120 | // create the chart 121 | var chart; 122 | nv.addGraph(function() { 123 | }); 124 | ``` 125 | 126 | - Let's define the chart 127 | 128 | _./main.js_ 129 | 130 | ```diff 131 | // create the chart 132 | var chart; 133 | nv.addGraph(function() { 134 | + chart = nv.models.scatterChart() 135 | + .showDistX(true) 136 | + .showDistY(true) 137 | + .useVoronoi(true) 138 | + .color(d3.scale.category10().range()) 139 | + .duration(300) 140 | + ; 141 | }); 142 | ``` 143 | 144 | - Let's provide the tick format to X and Y axis. 145 | 146 | ```diff 147 | var chart; 148 | nv.addGraph(function () { 149 | chart = nv.models.scatterChart() 150 | .showDistX(true) 151 | .showDistY(true) 152 | .useVoronoi(true) 153 | .color(d3.scale.category10().range()) 154 | .duration(300) 155 | ; 156 | 157 | + chart.xAxis.tickFormat(d3.format('.02f')); 158 | + chart.yAxis.tickFormat(d3.format('.02f')); 159 | }); 160 | ``` 161 | 162 | - Now let's instantiate the chart and place it in the svg placeholder that we have previously defined in the html, 163 | we are hooking as well to windowsResize to update the chart layout whenever the browser window changes it's width or height. 164 | 165 | ```diff 166 | // create the chart 167 | var chart; 168 | nv.addGraph(function () { 169 | chart = nv.models.scatterChart() 170 | .showDistX(true) 171 | .showDistY(true) 172 | .useVoronoi(true) 173 | .color(d3.scale.category10().range()) 174 | .duration(300) 175 | ; 176 | 177 | chart.xAxis.tickFormat(d3.format('.02f')); 178 | chart.yAxis.tickFormat(d3.format('.02f')); 179 | 180 | + d3.select('#test1 svg') 181 | + .datum(randomData(4,40)) 182 | + .call(chart); 183 | 184 | + nv.utils.windowResize(chart.update); 185 | 186 | + return chart; 187 | }); 188 | ``` 189 | 190 | > Excercise: Let's customize our scattered chart, entry data (Ice Cream Sales vs Temperature): 191 | 192 | | Temperature | Sales | 193 | | ------------- |:-------:| 194 | | 14.2 C | $215 | 195 | | 16.4 C | $325 | 196 | | 11.9 C | $185 | 197 | | 15.2 C | $332 | 198 | | 18.5 C | $406 | 199 | | 22.1 C | $522 | 200 | | 19.4 C | $412 | 201 | | 25.1 C | $614 | 202 | | 23.4 C | $544 | 203 | | 18.1 C | $421 | 204 | | 22.6 C | $445 | 205 | | 17.2 C | $408 | 206 | 207 | Challenges: 208 | 209 | - Create the right JSON structure. 210 | - Enrich the chart using shapes (e.g. if a given entry is above 400$ use a shape if it's below 200$ another one). 211 | - Display the data 212 | - Adjust X and Y Axis 213 | 214 | 215 | 216 | 217 | 218 | -------------------------------------------------------------------------------- /03 d3js-typescript/02 Bars/Readme.md: -------------------------------------------------------------------------------- 1 | # Intro 2 | 3 | # Steps 4 | 5 | - We are going to start form _00 boilerplate_. 6 | 7 | - Install the packages. 8 | 9 | ```bash 10 | npm install 11 | ``` 12 | 13 | - Let's create a file that will hold the graphic data, we will generate random data and simulta real time updates. 14 | 15 | _./src/d3/barchart.data.ts_ 16 | 17 | ```typescript 18 | // Generador de datos aleatorios en formato de array de n posiciones. 19 | const randomArrayGenerator = n => Array.from({length: n}, () => Math.random()); 20 | 21 | // Otra forma podría ser Array(n).fill(0).map(n => Math.random()); 22 | 23 | 24 | // Singleton inicializado con datos aleatorios. Array de 20 posiciones. 25 | export let randomData = randomArrayGenerator(20); 26 | 27 | // Creamos un mecanismo para modifcar estos datos aleatorios cada segundo. 28 | // Simula una fuente de datos 'real-time'. Permitimos la suscripción de un 29 | // callback para informar a la visualización de que hubo modificaciones. 30 | export const startRealTimeDataV1 = (onDataChange: (newData) => void) => { 31 | setInterval(() => { 32 | randomData = randomArrayGenerator(20); 33 | onDataChange && onDataChange(randomData); 34 | }, 1000); 35 | } 36 | 37 | export const startRealTimeDataV2 = (onDataChange: (data: any[]) => void) => { 38 | setInterval(() => { 39 | const n = Math.random() * 10 + 10; // [10, 20] 40 | onDataChange && onDataChange(randomArrayGenerator(n)); 41 | }, 1500); 42 | } 43 | ``` 44 | 45 | - Let's start with the chart it self: 46 | - We will add the widht and height (like in sample on). 47 | - Let's add a card. 48 | - Let's add the d3 namespace. 49 | - Le't define the viewbox 50 | 51 | _./src/barchart.d3.ts_ 52 | 53 | ```typescript 54 | import { select, selectAll } from "d3-selection"; 55 | import { scaleBand, scaleLinear } from "d3-scale"; 56 | import { randomData, startRealTimeDataV1 } from "./barchart.data"; 57 | 58 | const d3 = { 59 | select, selectAll, scaleBand, scaleLinear 60 | }; 61 | 62 | const width = 500; 63 | const height = 300; 64 | const padding = 50; 65 | 66 | // Creamos la tarjeta. 67 | const card = select("#root") 68 | .append("div") 69 | .attr("class", "card"); 70 | 71 | // Creamos el 'lienzo' svg. 72 | const svg = card 73 | .append("svg") 74 | .attr("width", "100%") 75 | .attr("height", "100%") 76 | .attr("viewBox", `${-padding} ${-padding} ${width + 2*padding} ${height + 2*padding}`); 77 | ``` 78 | 79 | - Let's add the import to the app.ts. 80 | 81 | _./src/app.ts_ 82 | 83 | ```diff 84 | import "./app.scss"; 85 | 86 | // Import here your D3 visualizations. 87 | - import "./d3/title.d3"; 88 | + import "./d3/barchart.d3"; 89 | ``` 90 | 91 | - Now let's paint a bar per random number entry we get (each datum will be associated to each bar, we will make use of enter and update). 92 | We will create first the scales, let's start with the Y scale 93 | 94 | ```typescript 95 | const scaleYPos = scaleLinear() 96 | .domain([0,1]) 97 | .range([height, 0]); 98 | ``` 99 | 100 | - For the scale X we wil make use of _scaleBand_ (https://github.com/d3/d3-scale#band-scales) 101 | 102 | ```typescript 103 | // In Domain (bars) we don't have continuous values, we have to identify the bands, like in ordinal scale 104 | // we could return [0,1,2,3...20], we will do that wiht a map 105 | const scaleXPos = d3.scaleBand() 106 | .domain(randomData.map((d,i) => i)) 107 | .range([0, width]) // use RangeRound to get pixel perfect layout 108 | .paddingInner(0.05); // space between bars, wathout! percentages values, range number 0..1 109 | ``` 110 | 111 | - Let's start creating the bar char it self 112 | 113 | - First we will create a bar group 114 | 115 | ```typescript 116 | const barGroup = svg 117 | .append('g'); 118 | ``` 119 | 120 | - Now let's append the new bars (we are going to pain all the bars just the first time). 121 | 122 | ```typescript 123 | barGroup 124 | .selectAll('rect') 125 | .data(randomData) 126 | .enter() 127 | .append("rect") 128 | .attr("x", (d,i) => scaleXPos(i)) 129 | .attr("y", d => scaleYPos(d)) 130 | .attr("width", scaleXPos.bandwidth()) 131 | .attr("height", d => height - scaleYPos()) // Remember Y coord start top on 0 132 | ``` 133 | 134 | - Let's add a nice gradiente to the bars. 135 | 136 | ```typescript 137 | // OPTIONAL 138 | // Gradient fill for the bars. 139 | const gradient = svg 140 | .append("defs") 141 | .append("linearGradient") 142 | .attr("id", "barGradient") 143 | .attr("gradientUnits", "userSpaceOnUse") 144 | .attr("x1", "0") 145 | .attr("y1", height) 146 | .attr("x2", "0") 147 | .attr("y2", "0"); 148 | gradient 149 | .append("stop") 150 | .attr("offset", "0") 151 | .attr("stop-color", "#185a9d"); 152 | gradient 153 | .append("stop") 154 | .attr("offset", "80%") 155 | .attr("stop-color", "#43cea2"); 156 | gradient 157 | .append("stop") 158 | .attr("offset", "100%") 159 | .attr("stop-color", "#43cea2"); 160 | ``` 161 | 162 | - And use it in our bar chart 163 | 164 | ```diff 165 | barGroup 166 | .selectAll('rect') 167 | .data(randomData) 168 | .enter() 169 | .append("rect") 170 | .attr("x", (d,i) => scaleXPos(i)) 171 | .attr("y", d => scaleYPos(d)) 172 | .attr("width", scaleXPos.bandwidth()) 173 | .attr("height", d => height - scaleYPos(d)) 174 | + .attr("fill", "url(#barGradient)"); 175 | ``` 176 | 177 | - If we refresh the browser we can see that data is changed, now let's go 178 | for real time updates. By default the mode to update is 'update' (enter is insert) 179 | 180 | ```typescript 181 | const dataUpdated = (newData : number[]) => { 182 | // Update pattern 183 | barGroup 184 | .selectAll('rect') 185 | .data(newData) 186 | .attr("y", d => scaleYPos(d)) 187 | .attr("height", d => height - scaleYPos(d)) 188 | } 189 | 190 | startRealTimeDataV1(dataUpdated); 191 | ``` 192 | 193 | - now we got the graphic changing in real time, but... couldn't it be nice to add 194 | a transition for the values? 195 | 196 | ```diff 197 | + import 'd3-transition'; 198 | 199 | // (...) 200 | 201 | const dataUpdated = (newData : number[]) => { 202 | // Update pattern 203 | barGroup 204 | .selectAll('rect') 205 | .data(newData) 206 | + .transition() 207 | + .duration(750) 208 | .attr("y", d => scaleYPos(d)) 209 | .attr("height", d => height - scaleYPos(d)) 210 | } 211 | 212 | startRealTimeDataV1(dataUpdated); 213 | ``` -------------------------------------------------------------------------------- /03 d3js-typescript/992 Map Interaction/src/data/population.tsv: -------------------------------------------------------------------------------- 1 | id name population 2 | CHN China "1330141295" 3 | IND India "1173108018" 4 | USA United States "310232863" 5 | IDN Indonesia "242968342" 6 | BRA Brazil "201103330" 7 | PAK Pakistan "177276594" 8 | BGD Bangladesh "158065841" 9 | NGA Nigeria "152217341" 10 | RUS Russia "139390205" 11 | JPN Japan "126804433" 12 | MEX Mexico "112468855" 13 | PHL Philippines "99900177" 14 | VNM Vietnam "89571130" 15 | ETH Ethiopia "88013491" 16 | DEU Germany "82282988" 17 | EGY Egypt "80471869" 18 | TUR Turkey "77804122" 19 | COD Democratic Republic of the Congo "70916439" 20 | IRN Iran "67037517" 21 | THA Thailand "66404688" 22 | FRA France "64057792" 23 | GBR United Kingdom "61284806" 24 | ITA Italy "58090681" 25 | MMR Myanmar "53414374" 26 | ZAF South Africa "49109107" 27 | KOR South Korea "48636068" 28 | UKR Ukraine "45415596" 29 | COL Colombia "44205293" 30 | SDN Sudan "41980182" 31 | TZA United Republic of Tanzania "41892895" 32 | ARG Argentina "41343201" 33 | ESP Spain "40548753" 34 | KEN Kenya "40046566" 35 | POL Poland "38463689" 36 | DZA Algeria "34586184" 37 | CAN Canada "33759742" 38 | UGA Uganda "33398682" 39 | MAR Morocco "31627428" 40 | PER Peru "29907003" 41 | IRQ Iraq "29671605" 42 | SAU Saudi Arabia "29207277" 43 | AFG Afghanistan "29121286" 44 | NPL Nepal "28951852" 45 | UZB Uzbekistan "27865738" 46 | VEN Venezuela "27223228" 47 | MYS Malaysia "26160256" 48 | GHA Ghana "24339838" 49 | YEM Yemen "23495361" 50 | TWN Taiwan "23024956" 51 | PRK North Korea "22757275" 52 | SYR Syria "22198110" 53 | ROU Romania "22181287" 54 | MOZ Mozambique "22061451" 55 | AUS Australia "21515754" 56 | LKA Sri Lanka "21513990" 57 | MDG Madagascar "21281844" 58 | CIV Ivory Coast "21058798" 59 | CMR Cameroon "19294149" 60 | NLD Netherlands "16783092" 61 | CHL Chile "16746491" 62 | BFA Burkina Faso "16241811" 63 | NER Niger "15878271" 64 | KAZ Kazakhstan "15460484" 65 | MWI Malawi "15447500" 66 | ECU Ecuador "14790608" 67 | KHM Cambodia "14753320" 68 | SEN Senegal "14086103" 69 | MLI Mali "13796354" 70 | GTM Guatemala "13550440" 71 | AGO Angola "13068161" 72 | ZMB Zambia "12056923" 73 | ZWE Zimbabwe "11651858" 74 | CUB Cuba "11477459" 75 | RWA Rwanda "11055976" 76 | GRC Greece "10749943" 77 | PRT Portugal "10735765" 78 | TUN Tunisia "10589025" 79 | TCD Chad "10543464" 80 | BEL Belgium "10423493" 81 | GIN Guinea "10324025" 82 | CZE Czech Republic "10201707" 83 | SOM Somalia "10112453" 84 | BOL Bolivia "9947418" 85 | HUN Hungary "9880059" 86 | BDI Burundi "9863117" 87 | DOM Dominican Republic "9794487" 88 | BLR Belarus "9612632" 89 | HTI Haiti "9203083" 90 | SWE Sweden "9074055" 91 | BEN Benin "9056010" 92 | AZE Azerbaijan "8303512" 93 | AUT Austria "8214160" 94 | HND Honduras "7989415" 95 | CHE Switzerland "7623438" 96 | TJK Tajikistan "7487489" 97 | ISR Israel "7353985" 98 | SRB Republic of Serbia "7344847" 99 | BGR Bulgaria "7148785" 100 | HKG Hong Kong "7089705" 101 | LAO Laos "6993767" 102 | LBY Libya "6461454" 103 | JOR Jordan "6407085" 104 | PRY Paraguay "6375830" 105 | TGO Togo "6199841" 106 | PNG Papua New Guinea "6064515" 107 | SLV El Salvador "6052064" 108 | NIC Nicaragua "5995928" 109 | ERI Eritrea "5792984" 110 | DNK Denmark "5515575" 111 | KGZ Kyrgyzstan "5508626" 112 | SVK Slovakia "5470306" 113 | FIN Finland "5255068" 114 | SLE Sierra Leone "5245695" 115 | ARE United Arab Emirates "4975593" 116 | TKM Turkmenistan "4940916" 117 | CAF Central African Republic "4844927" 118 | SGP Singapore "4701069" 119 | NOR Norway "4676305" 120 | BIH Bosnia and Herzegovina "4621598" 121 | GEO Georgia "4600825" 122 | CRI Costa Rica "4516220" 123 | HRV Croatia "4486881" 124 | MDA Moldova "4317483" 125 | NZL New Zealand "4252277" 126 | IRL Ireland "4250163" 127 | COG Republic of the Congo "4125916" 128 | LBN Lebanon "4125247" 129 | PRI Puerto Rico "3977663" 130 | LBR Liberia "3685076" 131 | ALB Albania "3659616" 132 | LTU Lithuania "3545319" 133 | URY Uruguay "3510386" 134 | PAN Panama "3410676" 135 | MRT Mauritania "3205060" 136 | MNG Mongolia "3086918" 137 | OMN Oman "2967717" 138 | ARM Armenia "2966802" 139 | JAM Jamaica "2847232" 140 | KWT Kuwait "2789132" 141 | PSE West Bank "2514845" 142 | LVA Latvia "2217969" 143 | NAM Namibia "2128471" 144 | MKD Macedonia "2072086" 145 | BWA Botswana "2029307" 146 | SVN Slovenia "2003136" 147 | LSO Lesotho "1919552" 148 | GMB Gambia "1824158" 149 | KWT Kosovo "1815048" 150 | 149 Gaza Strip "1604238" 151 | GNB Guinea Bissau "1565126" 152 | GAB Gabon "1545255" 153 | SWZ Swaziland "1354051" 154 | 153 Mauritius "1294104" 155 | EST Estonia "1291170" 156 | TTO Trinidad and Tobago "1228691" 157 | TLS Timor-Leste "1154625" 158 | CYP Cyprus "1102677" 159 | FJI Fiji "957780" 160 | QAT Qatar "840926" 161 | 160 Comoros "773407" 162 | GUY Guyana "748486" 163 | DJI Djibouti "740528" 164 | 163 Bahrain "738004" 165 | BTN Bhutan "699847" 166 | MNE Montenegro "666730" 167 | GNQ Equatorial Guinea "650702" 168 | SLB Solomon Islands "609794" 169 | 168 Macau "567957" 170 | 169 Cape Verde "508659" 171 | LUX Luxembourg "497538" 172 | ESH Western Sahara "491519" 173 | SUR Suriname "486618" 174 | 173 Malta "406771" 175 | 174 Maldives "395650" 176 | BRN Brunei "395027" 177 | BLZ Belize "314522" 178 | BHS The Bahamas "310426" 179 | ISL Iceland "308910" 180 | 179 French Polynesia "291000" 181 | 180 Barbados "285653" 182 | 181 Mayotte "231139" 183 | NCL New Caledonia "229993" 184 | 183 Netherlands Antilles "228693" 185 | VUT Vanuatu "221552" 186 | 185 Samoa "192001" 187 | 186 Sao Tome and Principe "175808" 188 | 187 Saint Lucia "160922" 189 | 188 Tonga "122580" 190 | 189 Virgin Islands "109775" 191 | 190 Grenada "107818" 192 | 191 Federated States of Micronesia "107154" 193 | 192 Aruba "104589" 194 | 193 Saint Vincent and the Grenadines "104217" 195 | 194 Kiribati "99482" 196 | 195 Jersey "91812" 197 | 196 Seychelles "88340" 198 | 197 Antigua and Barbuda "86754" 199 | 198 Andorra "84525" 200 | 199 Isle of Man "76913" 201 | DOM Dominica "72813" 202 | 201 Bermuda "68268" 203 | 202 American Samoa "66432" 204 | 203 Marshall Islands "65859" 205 | 204 Guernsey "65632" 206 | GRL Greenland "57637" 207 | 206 Cayman Islands "50209" 208 | 207 Saint Kitts and Nevis "49898" 209 | 208 Faroe Islands "49057" 210 | 209 Northern Mariana Islands "48317" 211 | 210 Liechtenstein "35002" 212 | 211 San Marino "31477" 213 | 212 Monaco "30586" 214 | 213 Saint Martin "30235" 215 | 214 Gibraltar "28877" 216 | 215 British Virgin Islands "24939" 217 | 216 Turks and Caicos Islands "23528" 218 | 217 Palau "20879" 219 | 218 Akrotiri "15700" 220 | 219 Dhekelia "15700" 221 | 220 Wallis and Futuna "15343" 222 | 221 Anguilla "14764" 223 | 222 Nauru "14264" 224 | 223 Cook Islands "11488" 225 | 224 Tuvalu "10472" 226 | 225 Saint Helena, Ascension, and Tristan da Cunha "7670" 227 | 226 Saint Barthelemy "7406" 228 | 227 Saint Pierre and Miquelon "6010" 229 | 228 Montserrat "5118" 230 | FLK Falkland Islands "3140" 231 | 230 Norfolk Island "2155" 232 | 231 Svalbard "2067" 233 | 232 Christmas Island "1402" 234 | 233 Tokelau "1400" 235 | 234 Niue "1354" 236 | 235 Holy See (Vatican City) 829 237 | 236 Cocos (Keeling) Islands 596 238 | 237 Pitcairn Islands 48 239 | ATA Antarctica 0 240 | ATF French Southern and Antarctic Lands 0 241 | SDS South Sudan "12152321" 242 | ABV Somaliland "3500000" 243 | OSA Kosovo "1824000" -------------------------------------------------------------------------------- /03 d3js-typescript/993 Spain Cloropleth/src/d3/spain.d3.ts: -------------------------------------------------------------------------------- 1 | import { mouse, extent, event } from "d3"; 2 | import { select } from "d3-selection"; 3 | import { geoConicConformalSpain } from "d3-composite-projections"; 4 | import { geoPath } from "d3-geo"; 5 | import { interpolateReds } from "d3-scale-chromatic"; 6 | import { scaleSqrt } from "d3-scale"; 7 | import { json } from "d3-fetch"; 8 | import { zoom } from "d3-zoom"; 9 | import { range, ticks } from "d3-array"; 10 | import { presimplify, simplify, feature } from "topojson"; 11 | import { Topology, GeometryCollection, Objects } from 'topojson-specification'; 12 | import { Feature, Geometry } from 'geojson'; 13 | import { defineGlowEffect } from './effects.d3'; 14 | const styles = require("./styles.scss"); 15 | 16 | 17 | // (*) Lets define a width and height for the SVG user space 18 | // coordinate system (viewBox), also a padding to avoid 19 | // overflows. 20 | const width = 960; 21 | const height = 460; 22 | const padding = 20; 23 | 24 | // (*) Lets add a card for our map. 25 | const card = select("#root") 26 | .append("div") 27 | .attr("class", "card"); 28 | 29 | // (*) Also lets add a reserved div for a tooltip. 30 | const tooltip = select("#root") 31 | .append("div") 32 | .style("display", "none") 33 | .style("position", "absolute") 34 | .style("padding", "10px") 35 | .style("border-radius", "3px") 36 | .style("background-color", "black") 37 | .style("color", "white") 38 | .style("opacity", "0.7"); 39 | 40 | // (*) Now the SVG canvas with the viewBox. 41 | const svg = card 42 | .append("svg") 43 | .attr("width", "100%") 44 | .attr("height", "100%") 45 | .attr("viewBox", `${-padding} ${-padding} ${width + 2*padding} ${height + 2*padding}`); 46 | 47 | // And we define a special effect: a glow effect 48 | // to highlight regions on hover. 49 | const glowUrl = defineGlowEffect(svg.append("defs")); 50 | 51 | // (*) Lets prepare a group to be zoomable. And a group for a 52 | // legend, out of the zoom. 53 | const zoomGroup = svg 54 | .append("g"); 55 | const legendGroup = svg 56 | .append("g"); 57 | 58 | // Also, lets create a couple of groups whithin the zoom to 59 | // group regions and municipalities in different sections. 60 | const municipalitiesGroup = zoomGroup 61 | .append("g"); 62 | const regionsGroup = zoomGroup 63 | .append("g"); 64 | 65 | // Now the zoom logic binded to the svg. 66 | const zoomCreator = zoom() 67 | .scaleExtent([1, 15]) 68 | .on("zoom", onZoom); 69 | 70 | svg.call(zoomCreator); 71 | 72 | // And de onZoom callback. 73 | function onZoom() { 74 | zoomGroup 75 | .attr("transform", event.transform); 76 | } 77 | 78 | // (*) Lets use a custom projection for Spain that will allow 79 | // us to represent Canary Islands closer to Iberian Peninsula. 80 | // We need the package "npm i d3-composite-projections". 81 | const projection = geoConicConformalSpain() 82 | .translate([width/2, height/2]); 83 | 84 | // And then a path creator based on that projection. 85 | const pathCreator = geoPath() 86 | .projection(projection); 87 | 88 | 89 | // (*) Let's load the needed data with an async helper. 90 | // **** WARNING **** Remember to change webpack rule to use 91 | // file-loader for all these data extensions. 92 | Promise.all([ 93 | json(require("../data/municipalities.topojson")), 94 | json(require("../data/regions.topojson")) 95 | ]).then(onDataReady as (value) => void); 96 | 97 | // (*) Prior to define the onDataReady function callback 98 | // we will need typings here to specify the structure of the 99 | // expected regions and municipalities entities. 100 | interface Municipality { 101 | name: string; 102 | rate: number; 103 | }; 104 | 105 | interface MunicipalityData extends Objects { 106 | municipios: GeometryCollection; 107 | } 108 | 109 | interface Region {}; 110 | 111 | interface RegionData extends Objects { 112 | ccaa: GeometryCollection; 113 | } 114 | 115 | // AndHere is the function. 116 | function onDataReady([mData, rData]: [Topology, Topology]) { 117 | // (*) Data management. 118 | // Presimplify to prepare data structure to simplify. It adds a weight 119 | // to each coordinate. When simplifying, we just drop coordinates by 120 | // filtering with a weight threshold. 121 | presimplify(mData); 122 | simplify(mData, 0.5); 123 | 124 | // (!) I found a 'bug' in topojson-specification typings 125 | // that will prevent TS from infering properties in a 126 | // geometry.properities object. To prevent that: 127 | /* Replace in index.d.ts line 112: 128 | export interface NullObject

    extends GeometryObjectA

    { 129 | type: null; 130 | } 131 | */ 132 | 133 | // (*) Lets implement a scale to assign color to 134 | // each municipality based on its population density. 135 | // This time, instead of manually setting the domain, 136 | // let's compute it dynamically from the data. 137 | const densities = mData.objects.municipios.geometries.map(g => (g.properties.rate)); 138 | const densityExtent = extent(densities); 139 | const densityScale = scaleSqrt().exponent(1/6) 140 | .domain(densityExtent) 141 | .range([0, 1]); 142 | const colorScale = (density: number) => interpolateReds(densityScale(density || 0)); 143 | 144 | // (*) Lets implement the ENTER pattern for each new municipality 145 | // to be represented with a SVG path joined to its datum. 146 | // First, we need to extract the corresponding feature collection. 147 | const municipalities = feature(mData, mData.objects.municipios); 148 | 149 | municipalitiesGroup.selectAll("path") 150 | .data(municipalities.features, (d: Feature) => d.properties.name) 151 | .enter() 152 | .append("path") 153 | .attr("d", pathCreator) 154 | .attr("fill", d => colorScale(d.properties.rate)) 155 | // .style("stroke", "white") // Painting the strokes will hit performance 156 | // .style("stroke-width", "0.5px") 157 | // Finally, lets bind some mouse events to show a tooltip with info. 158 | .on("mouseenter", onMouseEnter) 159 | .on("mousemove", onMouseMove) 160 | .on("mouseleave", onMouseLeave); 161 | 162 | 163 | // (*) You can find below the event handlers implementation 164 | 165 | // OnMouseEnter we will show the tooltip and hightlight the municipality. 166 | function onMouseEnter(d: Feature) { 167 | tooltip 168 | .style("display", "block") 169 | .html(` 170 |

    Municipality: ${d.properties.name}

    171 |

    Pop. Density: ${d.properties.rate ? d.properties.rate.toLocaleString() : "N/D"} per km2

    172 | `); 173 | 174 | select(this) 175 | .raise() 176 | .attr("filter", glowUrl); 177 | }; 178 | 179 | // OnMouseMove lets update the tooltip position. 180 | function onMouseMove() { 181 | const [mx, my] = mouse(document.body); 182 | 183 | tooltip 184 | .style("left", `${mx + 10}px`) 185 | .style("top", `${my + 10}px`); 186 | }; 187 | 188 | // OnMouseLeave just hide the tooltip. 189 | function onMouseLeave() { 190 | tooltip 191 | .style("display", "none"); 192 | 193 | select(this) 194 | .attr("filter", undefined); 195 | } 196 | 197 | // ************************************************************************************ 198 | // (*) OPTIONAL - ¿Exercise? - Add a legend 199 | const numPatches = 10; 200 | const patchesData = Array(numPatches).fill(0).map((p,i) => densityScale.invert(i/(numPatches-1))) 201 | const patchesHeight = 20; 202 | const patchesWidth = 80; 203 | const legendMargin = 20; 204 | 205 | // Setup legend group position to lower right corner by using a transform-translate. 206 | legendGroup 207 | .attr("transform", `translate(${width - patchesWidth - legendMargin}, ${height - (patchesHeight * numPatches) - legendMargin})`) 208 | 209 | // Enter pattern for patches. Each patch will have a group. 210 | const patches = legendGroup.selectAll("rect") 211 | .data(patchesData) 212 | .enter() 213 | .append("g") 214 | .attr("transform", (d, i) => `translate(0, ${patchesHeight * i})`) 215 | patches.append("rect") 216 | .attr("width", patchesWidth) 217 | .attr("height", patchesHeight) 218 | .attr("fill", colorScale) 219 | patches.append("text") 220 | .attr("transform", "translate(15)") 221 | .attr("alignment-baseline", "text-before-edge") 222 | .attr("fill", "white") 223 | .text(d => Math.round(d).toLocaleString()) 224 | 225 | 226 | // ************************************************************************************ 227 | // (*) OPTIONAL - ¿Exercise? - Add CCAA. 228 | // Add Autonomous Communities in the map, just to group the 229 | // municipalities into regions. We have already loaded the file 230 | // regions.topojson and have created a SVG group for that, just 231 | // draw it in the map with D3. 232 | 233 | const regions = feature(rData, rData.objects.ccaa); 234 | console.log(regions) 235 | regionsGroup.selectAll("path") 236 | .data(regions.features) 237 | .enter() 238 | .append("path") 239 | .attr("d", pathCreator) 240 | .attr("fill", "none") 241 | .style("stroke", "white") 242 | .style("stroke-width", "1px"); 243 | } 244 | --------------------------------------------------------------------------------