├── .eslintrc.json ├── .gitignore ├── LICENSE ├── README.md ├── demo ├── amcharts.html ├── amcharts.js ├── echarts.html ├── echarts.js ├── g2.html ├── g2.js ├── highcharts.html ├── highcharts.js ├── xcharts.html └── xcharts.js ├── dist ├── sketchify.js └── sketchify.min.js ├── docs └── highcharts_demo.png ├── package-lock.json ├── package.json ├── src ├── highcharts.js ├── index.js ├── style.css └── xcharts.js └── webpack.config.js /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "es6": true 5 | }, 6 | "extends": [ 7 | "airbnb-base" 8 | ], 9 | "globals": { 10 | "Atomics": "readonly", 11 | "SharedArrayBuffer": "readonly" 12 | }, 13 | "parserOptions": { 14 | "ecmaVersion": 2018, 15 | "sourceType": "module" 16 | }, 17 | "rules": { 18 | "no-undef": "off", 19 | "import/extensions": "off" 20 | } 21 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | yarn.lock -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Gang Tao 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | 4 | 5 |

6 | 7 |

8 | turns svg graph into sketchy 9 |

10 | 11 | # Sketchify 12 | Sketchify is a js tool that turns svg graph into sketchy visualization. It is based on [Rough.js](https://github.com/pshihn/rough) 13 | 14 | ### Build 15 | ```sh 16 | npm install 17 | npm run build 18 | ``` 19 | 20 | ### Usage 21 | To turn an existing graph that composed by svg into sketch mode. 22 | 23 | Add dependencies to your html: 24 | ```html 25 | 26 | 27 | 28 | ``` 29 | Run following js code: 30 | ```javascript 31 | const option = { 32 | fillStyle: 'hachure', 33 | roughness: 1, 34 | bowing: 1, 35 | chartType: 'highcharts', 36 | }; 37 | // container is the root dom element that contains related graph svg 38 | const handler = Sketchifier(container, option); 39 | handler.handify(); 40 | 41 | // call restore will turn the graph back to original one 42 | handler.restore(); 43 | ``` 44 | Refer to [roughjs api document](https://github.com/pshihn/rough/wiki) for options of `fillStyle`, `roughness` and `bowing`. 45 | 46 | ### demo 47 | 48 | ![](./docs/highcharts_demo.png) 49 | 50 | There are 5 demo charts types: 51 | - [ECharts](https://echarts.apache.org/zh/index.html) 52 | - [AntV G2](https://antv.alipay.com/zh-cn/g2/3.x/index.html) 53 | - [highcharts](https://www.highcharts.com/) 54 | - [amcharts](https://www.amcharts.com/) 55 | - [xCharts](http://xgfe.github.io/xCharts/) 56 | 57 | After `npm run build-dev`, open related html file in `demo` folder will show you the demo. 58 | 59 | Or you can refer to following codepen pages: 60 | - [ECharts](https://codepen.io/gangtao/full/ZEEVzpw) 61 | - [AntV G2](https://codepen.io/gangtao/full/wvvRwzp) 62 | - [highcharts](https://codepen.io/gangtao/full/eYYrpBX) 63 | - [amcharts](https://codepen.io/gangtao/full/PooxBpV) 64 | - [xCharts](https://codepen.io/gangtao/full/PooxBWV) 65 | 66 | 67 | ### new chart type support 68 | Sketchify is high generalized, now I have tried to support most chart types in highcharts and xCharts, the customization is to filter some svg element that does not need to sketchify. Adding a blacklist of related element class. In case you want to do something similar, refer to [highcharts.js](./src/highcharts.js) 69 | -------------------------------------------------------------------------------- /demo/amcharts.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | sketchify 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 |
20 |
21 | 22 |
23 | 24 | 34 | 35 | 36 | 37 | 38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 | 50 | -------------------------------------------------------------------------------- /demo/amcharts.js: -------------------------------------------------------------------------------- 1 | function drawBarChart() { 2 | // Create chart instance 3 | var chart = am4core.create("container_bar", am4charts.XYChart); 4 | // Add data 5 | chart.data = [{ 6 | "country": "USA", 7 | "visits": 2025 8 | }, { 9 | "country": "China", 10 | "visits": 1882 11 | }, { 12 | "country": "Japan", 13 | "visits": 1809 14 | }, { 15 | "country": "Germany", 16 | "visits": 1322 17 | }, { 18 | "country": "UK", 19 | "visits": 1122 20 | }, { 21 | "country": "France", 22 | "visits": 1114 23 | }, { 24 | "country": "India", 25 | "visits": 984 26 | }, { 27 | "country": "Spain", 28 | "visits": 711 29 | }, { 30 | "country": "Netherlands", 31 | "visits": 665 32 | }, { 33 | "country": "Russia", 34 | "visits": 580 35 | }, { 36 | "country": "South Korea", 37 | "visits": 443 38 | }, { 39 | "country": "Canada", 40 | "visits": 441 41 | }, { 42 | "country": "Brazil", 43 | "visits": 395 44 | }]; 45 | 46 | // Create axes 47 | var categoryAxis = chart.xAxes.push(new am4charts.CategoryAxis()); 48 | categoryAxis.dataFields.category = "country"; 49 | categoryAxis.renderer.grid.template.location = 0; 50 | categoryAxis.renderer.minGridDistance = 30; 51 | 52 | categoryAxis.renderer.labels.template.adapter.add("dy", function(dy, target) { 53 | if (target.dataItem && target.dataItem.index & 2 == 2) { 54 | return dy + 25; 55 | } 56 | return dy; 57 | }); 58 | 59 | var valueAxis = chart.yAxes.push(new am4charts.ValueAxis()); 60 | 61 | // Create series 62 | var series = chart.series.push(new am4charts.ColumnSeries()); 63 | series.dataFields.valueY = "visits"; 64 | series.dataFields.categoryX = "country"; 65 | series.name = "Visits"; 66 | series.columns.template.tooltipText = "{categoryX}: [bold]{valueY}[/]"; 67 | series.columns.template.fillOpacity = .8; 68 | 69 | var columnTemplate = series.columns.template; 70 | columnTemplate.strokeWidth = 2; 71 | columnTemplate.strokeOpacity = 1; 72 | } 73 | 74 | function drawScatterChart() { 75 | var chart = am4core.create("container_scatter", am4charts.XYChart); 76 | 77 | var valueAxisX = chart.xAxes.push(new am4charts.ValueAxis()); 78 | valueAxisX.renderer.ticks.template.disabled = true; 79 | valueAxisX.renderer.axisFills.template.disabled = true; 80 | 81 | var valueAxisY = chart.yAxes.push(new am4charts.ValueAxis()); 82 | valueAxisY.renderer.ticks.template.disabled = true; 83 | valueAxisY.renderer.axisFills.template.disabled = true; 84 | 85 | var series = chart.series.push(new am4charts.LineSeries()); 86 | series.dataFields.valueX = "x"; 87 | series.dataFields.valueY = "y"; 88 | series.dataFields.value = "value"; 89 | series.strokeOpacity = 0; 90 | series.sequencedInterpolation = true; 91 | series.tooltip.pointerOrientation = "vertical"; 92 | 93 | var bullet = series.bullets.push(new am4core.Circle()); 94 | bullet.fill = am4core.color("#ff0000"); 95 | bullet.propertyFields.fill = "color"; 96 | bullet.strokeOpacity = 0; 97 | bullet.strokeWidth = 2; 98 | bullet.fillOpacity = 0.5; 99 | bullet.stroke = am4core.color("#ffffff"); 100 | bullet.hiddenState.properties.opacity = 0; 101 | bullet.tooltipText = "[bold]{title}:[/]\nPopulation: {value.value}\nIncome: {valueX.value}\nLife expectancy:{valueY.value}"; 102 | 103 | var outline = chart.plotContainer.createChild(am4core.Circle); 104 | outline.fillOpacity = 0; 105 | outline.strokeOpacity = 0.8; 106 | outline.stroke = am4core.color("#ff0000"); 107 | outline.strokeWidth = 2; 108 | outline.hide(0); 109 | 110 | var blurFilter = new am4core.BlurFilter(); 111 | outline.filters.push(blurFilter); 112 | 113 | series.heatRules.push({ 114 | target: bullet, 115 | min: 2, 116 | max: 60, 117 | property: "radius" 118 | }); 119 | 120 | 121 | chart.cursor = new am4charts.XYCursor(); 122 | chart.cursor.behavior = "zoomXY"; 123 | chart.cursor.snapToSeries = series; 124 | 125 | chart.data = [{ 126 | "title": "Afghanistan", 127 | "id": "AF", 128 | "color": "#eea638", 129 | "continent": "asia", 130 | "x": 1349.69694102398, 131 | "y": 60.524, 132 | "value": 33397058 133 | }, { 134 | "title": "Albania", 135 | "id": "AL", 136 | "color": "#d8854f", 137 | "continent": "europe", 138 | "x": 6969.30628256456, 139 | "y": 77.185, 140 | "value": 3227373 141 | }, { 142 | "title": "Algeria", 143 | "id": "DZ", 144 | "color": "#de4c4f", 145 | "continent": "africa", 146 | "x": 6419.12782939372, 147 | "y": 70.874, 148 | "value": 36485828 149 | }, { 150 | "title": "Angola", 151 | "id": "AO", 152 | "color": "#de4c4f", 153 | "continent": "africa", 154 | "x": 5838.15537582502, 155 | "y": 51.498, 156 | "value": 20162517 157 | }, { 158 | "title": "Argentina", 159 | "id": "AR", 160 | "color": "#86a965", 161 | "continent": "south_america", 162 | "x": 15714.1031814398, 163 | "y": 76.128, 164 | "value": 41118986 165 | }, { 166 | "title": "Armenia", 167 | "id": "AM", 168 | "color": "#d8854f", 169 | "continent": "europe", 170 | "x": 5059.0879636443, 171 | "y": 74.469, 172 | "value": 3108972 173 | }, { 174 | "title": "Australia", 175 | "id": "AU", 176 | "color": "#8aabb0", 177 | "continent": "australia", 178 | "x": 36064.7372768548, 179 | "y": 82.364, 180 | "value": 22918688 181 | }, { 182 | "title": "Austria", 183 | "id": "AT", 184 | "color": "#d8854f", 185 | "continent": "europe", 186 | "x": 36731.6287741081, 187 | "y": 80.965, 188 | "value": 8428915 189 | }, { 190 | "title": "Azerbaijan", 191 | "id": "AZ", 192 | "color": "#d8854f", 193 | "continent": "europe", 194 | "x": 9291.02626998762, 195 | "y": 70.686, 196 | "value": 9421233 197 | }, { 198 | "title": "Bahrain", 199 | "id": "BH", 200 | "color": "#eea638", 201 | "continent": "asia", 202 | "x": 24472.896235865, 203 | "y": 76.474, 204 | "value": 1359485 205 | }, { 206 | "title": "Bangladesh", 207 | "id": "BD", 208 | "color": "#eea638", 209 | "continent": "asia", 210 | "x": 1792.55023464123, 211 | "y": 70.258, 212 | "value": 152408774 213 | }, { 214 | "title": "Belarus", 215 | "id": "BY", 216 | "color": "#d8854f", 217 | "continent": "europe", 218 | "x": 13515.1610255056, 219 | "y": 69.829, 220 | "value": 9527498 221 | }, { 222 | "title": "Belgium", 223 | "id": "BE", 224 | "color": "#d8854f", 225 | "continent": "europe", 226 | "x": 32585.0119650436, 227 | "y": 80.373, 228 | "value": 10787788 229 | }, { 230 | "title": "Benin", 231 | "id": "BJ", 232 | "color": "#de4c4f", 233 | "continent": "africa", 234 | "x": 1464.13825459126, 235 | "y": 59.165, 236 | "value": 9351838 237 | }, { 238 | "title": "Bhutan", 239 | "id": "BT", 240 | "color": "#eea638", 241 | "continent": "asia", 242 | "x": 6130.86235464324, 243 | "y": 67.888, 244 | "value": 750443 245 | }, { 246 | "title": "Bolivia", 247 | "id": "BO", 248 | "color": "#86a965", 249 | "continent": "south_america", 250 | "x": 4363.43264453337, 251 | "y": 66.969, 252 | "value": 10248042 253 | }, { 254 | "title": "Bosnia and Herzegovina", 255 | "id": "BA", 256 | "color": "#d8854f", 257 | "continent": "europe", 258 | "x": 7664.15281166303, 259 | "y": 76.211, 260 | "value": 3744235 261 | }, { 262 | "title": "Botswana", 263 | "id": "BW", 264 | "color": "#de4c4f", 265 | "continent": "africa", 266 | "x": 14045.9403255843, 267 | "y": 47.152, 268 | "value": 2053237 269 | }, { 270 | "title": "Brazil", 271 | "id": "BR", 272 | "color": "#86a965", 273 | "continent": "south_america", 274 | "x": 10383.5405937283, 275 | "y": 73.667, 276 | "value": 198360943 277 | }, { 278 | "title": "Brunei", 279 | "id": "BN", 280 | "color": "#eea638", 281 | "continent": "asia", 282 | "x": 45658.2532642054, 283 | "y": 78.35, 284 | "value": 412892 285 | }, { 286 | "title": "Bulgaria", 287 | "id": "BG", 288 | "color": "#d8854f", 289 | "continent": "europe", 290 | "x": 11669.7223127119, 291 | "y": 73.448, 292 | "value": 7397873 293 | }, { 294 | "title": "Burkina Faso", 295 | "id": "BF", 296 | "color": "#de4c4f", 297 | "continent": "africa", 298 | "x": 1363.77981282077, 299 | "y": 55.932, 300 | "value": 17481984 301 | }, { 302 | "title": "Burundi", 303 | "id": "BI", 304 | "color": "#de4c4f", 305 | "continent": "africa", 306 | "x": 484.090924612833, 307 | "y": 53.637, 308 | "value": 8749387 309 | }, { 310 | "title": "Cambodia", 311 | "id": "KH", 312 | "color": "#eea638", 313 | "continent": "asia", 314 | "x": 2076.68958647462, 315 | "y": 71.577, 316 | "value": 14478320 317 | }, { 318 | "title": "Cameroon", 319 | "id": "CM", 320 | "color": "#de4c4f", 321 | "continent": "africa", 322 | "x": 2094.09541317011, 323 | "y": 54.61, 324 | "value": 20468943 325 | }, { 326 | "title": "Canada", 327 | "id": "CA", 328 | "color": "#a7a737", 329 | "continent": "north_america", 330 | "x": 35992.8327204722, 331 | "y": 81.323, 332 | "value": 34674708 333 | }, { 334 | "title": "Cape Verde", 335 | "id": "CV", 336 | "color": "#de4c4f", 337 | "continent": "africa", 338 | "x": 3896.04113919638, 339 | "y": 74.771, 340 | "value": 505335 341 | }, { 342 | "title": "Central African Rep.", 343 | "id": "CF", 344 | "color": "#de4c4f", 345 | "continent": "africa", 346 | "x": 718.264633200085, 347 | "y": 49.517, 348 | "value": 4575586 349 | }, { 350 | "title": "Chad", 351 | "id": "TD", 352 | "color": "#de4c4f", 353 | "continent": "africa", 354 | "x": 1768.88201756553, 355 | "y": 50.724, 356 | "value": 11830573 357 | }, { 358 | "title": "Chile", 359 | "id": "CL", 360 | "color": "#86a965", 361 | "continent": "south_america", 362 | "x": 15403.7608144625, 363 | "y": 79.691, 364 | "value": 17423214 365 | }, { 366 | "title": "China", 367 | "id": "CN", 368 | "color": "#eea638", 369 | "continent": "asia", 370 | "x": 9501.57424554247, 371 | "y": 75.178, 372 | "value": 1353600687 373 | }, { 374 | "title": "Colombia", 375 | "id": "CO", 376 | "color": "#86a965", 377 | "continent": "south_america", 378 | "x": 8035.65638212719, 379 | "y": 73.835, 380 | "value": 47550708 381 | }, { 382 | "title": "Comoros", 383 | "id": "KM", 384 | "color": "#de4c4f", 385 | "continent": "africa", 386 | "x": 1027.40854349726, 387 | "y": 60.661, 388 | "value": 773344 389 | }, { 390 | "title": "Congo, Dem. Rep.", 391 | "id": "CD", 392 | "color": "#de4c4f", 393 | "continent": "africa", 394 | "x": 403.164594003407, 395 | "y": 49.643, 396 | "value": 69575394 397 | }, { 398 | "title": "Congo, Rep.", 399 | "id": "CG", 400 | "color": "#de4c4f", 401 | "continent": "africa", 402 | "x": 4106.51173855966, 403 | "y": 58.32, 404 | "value": 4233063 405 | }, { 406 | "title": "Costa Rica", 407 | "id": "CR", 408 | "color": "#a7a737", 409 | "continent": "north_america", 410 | "x": 10827.6787293035, 411 | "y": 79.712, 412 | "value": 4793725 413 | }, { 414 | "title": "Cote d'Ivoire", 415 | "id": "CI", 416 | "color": "#de4c4f", 417 | "continent": "africa", 418 | "x": 1491.51631215108, 419 | "y": 50.367, 420 | "value": 20594615 421 | }, { 422 | "title": "Croatia", 423 | "id": "HR", 424 | "color": "#d8854f", 425 | "continent": "europe", 426 | "x": 13388.9902780816, 427 | "y": 76.881, 428 | "value": 4387376 429 | }, { 430 | "title": "Cuba", 431 | "id": "CU", 432 | "color": "#a7a737", 433 | "continent": "north_america", 434 | "x": 10197.4191892126, 435 | "y": 79.088, 436 | "value": 11249266 437 | }, { 438 | "title": "Cyprus", 439 | "id": "CY", 440 | "color": "#d8854f", 441 | "continent": "europe", 442 | "x": 23092.089792339, 443 | "y": 79.674, 444 | "value": 1129166 445 | }, { 446 | "title": "Czech Rep.", 447 | "id": "CZ", 448 | "color": "#d8854f", 449 | "continent": "europe", 450 | "x": 22565.2975367042, 451 | "y": 77.552, 452 | "value": 10565678 453 | }, { 454 | "title": "Denmark", 455 | "id": "DK", 456 | "color": "#d8854f", 457 | "continent": "europe", 458 | "x": 32731.2903910132, 459 | "y": 79.251, 460 | "value": 5592738 461 | }, { 462 | "title": "Djibouti", 463 | "id": "DJ", 464 | "color": "#de4c4f", 465 | "continent": "africa", 466 | "x": 2244.60241376688, 467 | "y": 61.319, 468 | "value": 922708 469 | }, { 470 | "title": "Dominican Rep.", 471 | "id": "DO", 472 | "color": "#a7a737", 473 | "continent": "north_america", 474 | "x": 6978.89657264408, 475 | "y": 73.181, 476 | "value": 10183339 477 | }, { 478 | "title": "Ecuador", 479 | "id": "EC", 480 | "color": "#86a965", 481 | "continent": "south_america", 482 | "x": 7903.09487034651, 483 | "y": 76.195, 484 | "value": 14864987 485 | }, { 486 | "title": "Egypt", 487 | "id": "EG", 488 | "color": "#de4c4f", 489 | "continent": "africa", 490 | "x": 6013.821462967, 491 | "y": 70.933, 492 | "value": 83958369 493 | }, { 494 | "title": "El Salvador", 495 | "id": "SV", 496 | "color": "#a7a737", 497 | "continent": "north_america", 498 | "x": 5833.63022804714, 499 | "y": 72.361, 500 | "value": 6264129 501 | }, { 502 | "title": "Equatorial Guinea", 503 | "id": "GQ", 504 | "color": "#de4c4f", 505 | "continent": "africa", 506 | "x": 13499.2115504397, 507 | "y": 52.562, 508 | "value": 740471 509 | }, { 510 | "title": "Eritrea", 511 | "id": "ER", 512 | "color": "#de4c4f", 513 | "continent": "africa", 514 | "x": 613.716963797415, 515 | "y": 62.329, 516 | "value": 5580862 517 | }, { 518 | "title": "Estonia", 519 | "id": "EE", 520 | "color": "#d8854f", 521 | "continent": "europe", 522 | "x": 18858.0538247661, 523 | "y": 74.335, 524 | "value": 1339762 525 | }, { 526 | "title": "Ethiopia", 527 | "id": "ET", 528 | "color": "#de4c4f", 529 | "continent": "africa", 530 | "x": 958.694705985043, 531 | "y": 62.983, 532 | "value": 86538534 533 | }, { 534 | "title": "Fiji", 535 | "id": "FJ", 536 | "color": "#8aabb0", 537 | "continent": "australia", 538 | "x": 4195.03497178682, 539 | "y": 69.626, 540 | "value": 875822 541 | }, { 542 | "title": "Finland", 543 | "id": "FI", 544 | "color": "#d8854f", 545 | "continent": "europe", 546 | "x": 31551.9534459533, 547 | "y": 80.362, 548 | "value": 5402627 549 | }, { 550 | "title": "France", 551 | "id": "FR", 552 | "color": "#d8854f", 553 | "continent": "europe", 554 | "x": 29896.4182238854, 555 | "y": 81.663, 556 | "value": 63457777 557 | }, { 558 | "title": "Gabon", 559 | "id": "GA", 560 | "color": "#de4c4f", 561 | "continent": "africa", 562 | "x": 13853.4616556007, 563 | "y": 63.115, 564 | "value": 1563873 565 | }, { 566 | "title": "Gambia", 567 | "id": "GM", 568 | "color": "#de4c4f", 569 | "continent": "africa", 570 | "x": 747.68096900917, 571 | "y": 58.59, 572 | "value": 1824777 573 | }, { 574 | "title": "Georgia", 575 | "id": "GE", 576 | "color": "#d8854f", 577 | "continent": "europe", 578 | "x": 4943.23814339098, 579 | "y": 74.162, 580 | "value": 4304363 581 | }, { 582 | "title": "Germany", 583 | "id": "DE", 584 | "color": "#d8854f", 585 | "continent": "europe", 586 | "x": 34131.8745974324, 587 | "y": 80.578, 588 | "value": 81990837 589 | }, { 590 | "title": "Ghana", 591 | "id": "GH", 592 | "color": "#de4c4f", 593 | "continent": "africa", 594 | "x": 1728.47847396661, 595 | "y": 60.979, 596 | "value": 25545939 597 | }, { 598 | "title": "Greece", 599 | "id": "GR", 600 | "color": "#d8854f", 601 | "continent": "europe", 602 | "x": 21811.3302462212, 603 | "y": 80.593, 604 | "value": 11418878 605 | }, { 606 | "title": "Guatemala", 607 | "id": "GT", 608 | "color": "#a7a737", 609 | "continent": "north_america", 610 | "x": 5290.75202738533, 611 | "y": 71.77, 612 | "value": 15137569 613 | }, { 614 | "title": "Guinea", 615 | "id": "GN", 616 | "color": "#de4c4f", 617 | "continent": "africa", 618 | "x": 965.699260160386, 619 | "y": 55.865, 620 | "value": 10480710 621 | }, { 622 | "title": "Guinea-Bissau", 623 | "id": "GW", 624 | "color": "#de4c4f", 625 | "continent": "africa", 626 | "x": 593.074251034428, 627 | "y": 54.054, 628 | "value": 1579632 629 | }, { 630 | "title": "Guyana", 631 | "id": "GY", 632 | "color": "#86a965", 633 | "continent": "south_america", 634 | "x": 4265.10644905906, 635 | "y": 66.134, 636 | "value": 757623 637 | }, { 638 | "title": "Haiti", 639 | "id": "HT", 640 | "color": "#a7a737", 641 | "continent": "north_america", 642 | "x": 1180.36719611488, 643 | "y": 62.746, 644 | "value": 10255644 645 | }, { 646 | "title": "Honduras", 647 | "id": "HN", 648 | "color": "#a7a737", 649 | "continent": "north_america", 650 | "x": 3615.1565803195, 651 | "y": 73.503, 652 | "value": 7912032 653 | }, { 654 | "title": "Hong Kong, China", 655 | "id": "HK", 656 | "color": "#eea638", 657 | "continent": "asia", 658 | "x": 43854.4129062733, 659 | "y": 83.199, 660 | "value": 7196450 661 | }, { 662 | "title": "Hungary", 663 | "id": "HU", 664 | "color": "#d8854f", 665 | "continent": "europe", 666 | "x": 17065.6047342876, 667 | "y": 74.491, 668 | "value": 9949589 669 | }, { 670 | "title": "Iceland", 671 | "id": "IS", 672 | "color": "#d8854f", 673 | "continent": "europe", 674 | "x": 34371.1793657215, 675 | "y": 81.96, 676 | "value": 328290 677 | }, { 678 | "title": "India", 679 | "id": "IN", 680 | "color": "#eea638", 681 | "continent": "asia", 682 | "x": 3229.14788745778, 683 | "y": 66.168, 684 | "value": 1258350971 685 | }, { 686 | "title": "Indonesia", 687 | "id": "ID", 688 | "color": "#eea638", 689 | "continent": "asia", 690 | "x": 4379.69981934714, 691 | "y": 70.624, 692 | "value": 244769110 693 | }, { 694 | "title": "Iran", 695 | "id": "IR", 696 | "color": "#eea638", 697 | "continent": "asia", 698 | "x": 12325.1280322371, 699 | "y": 73.736, 700 | "value": 75611798 701 | }, { 702 | "title": "Iraq", 703 | "id": "IQ", 704 | "color": "#eea638", 705 | "continent": "asia", 706 | "x": 4160.84708826172, 707 | "y": 69.181, 708 | "value": 33703068 709 | }, { 710 | "title": "Ireland", 711 | "id": "IE", 712 | "color": "#d8854f", 713 | "continent": "europe", 714 | "x": 35856.1099094562, 715 | "y": 80.531, 716 | "value": 4579498 717 | }, { 718 | "title": "Israel", 719 | "id": "IL", 720 | "color": "#eea638", 721 | "continent": "asia", 722 | "x": 27321.205182135, 723 | "y": 81.641, 724 | "value": 7694670 725 | }, { 726 | "title": "Italy", 727 | "id": "IT", 728 | "color": "#d8854f", 729 | "continent": "europe", 730 | "x": 25811.7393303661, 731 | "y": 82.235, 732 | "value": 60964145 733 | }, { 734 | "title": "Jamaica", 735 | "id": "JM", 736 | "color": "#a7a737", 737 | "continent": "north_america", 738 | "x": 6945.70274711582, 739 | "y": 73.338, 740 | "value": 2761331 741 | }, { 742 | "title": "Japan", 743 | "id": "JP", 744 | "color": "#eea638", 745 | "continent": "asia", 746 | "x": 31273.9932002261, 747 | "y": 83.418, 748 | "value": 126434653 749 | }, { 750 | "title": "Jordan", 751 | "id": "JO", 752 | "color": "#eea638", 753 | "continent": "asia", 754 | "x": 5242.51826246118, 755 | "y": 73.7, 756 | "value": 6457260 757 | }, { 758 | "title": "Kazakhstan", 759 | "id": "KZ", 760 | "color": "#eea638", 761 | "continent": "asia", 762 | "x": 11982.6526657273, 763 | "y": 66.394, 764 | "value": 16381297 765 | }, { 766 | "title": "Kenya", 767 | "id": "KE", 768 | "color": "#de4c4f", 769 | "continent": "africa", 770 | "x": 1517.69754383602, 771 | "y": 61.115, 772 | "value": 42749418 773 | }, { 774 | "title": "Korea, Dem. Rep.", 775 | "id": "KP", 776 | "color": "#eea638", 777 | "continent": "asia", 778 | "x": 1540.44018783769, 779 | "y": 69.701, 780 | "value": 24553672 781 | }, { 782 | "title": "Korea, Rep.", 783 | "id": "KR", 784 | "color": "#eea638", 785 | "continent": "asia", 786 | "x": 26199.4035642374, 787 | "y": 81.294, 788 | "value": 48588326 789 | }, { 790 | "title": "Kuwait", 791 | "id": "KW", 792 | "color": "#eea638", 793 | "continent": "asia", 794 | "x": 42045.05923634, 795 | "y": 74.186, 796 | "value": 2891553 797 | }, { 798 | "title": "Kyrgyzstan", 799 | "id": "KG", 800 | "color": "#eea638", 801 | "continent": "asia", 802 | "x": 2078.20824171434, 803 | "y": 67.37, 804 | "value": 5448085 805 | }, { 806 | "title": "Laos", 807 | "id": "LA", 808 | "color": "#eea638", 809 | "continent": "asia", 810 | "x": 2807.04752629832, 811 | "y": 67.865, 812 | "value": 6373934 813 | }, { 814 | "title": "Latvia", 815 | "id": "LV", 816 | "color": "#d8854f", 817 | "continent": "europe", 818 | "x": 15575.2762808015, 819 | "y": 72.045, 820 | "value": 2234572 821 | }, { 822 | "title": "Lebanon", 823 | "id": "LB", 824 | "color": "#eea638", 825 | "continent": "asia", 826 | "x": 13711.975683994, 827 | "y": 79.716, 828 | "value": 4291719 829 | }, { 830 | "title": "Lesotho", 831 | "id": "LS", 832 | "color": "#de4c4f", 833 | "continent": "africa", 834 | "x": 1970.47114938861, 835 | "y": 48.947, 836 | "value": 2216850 837 | }, { 838 | "title": "Liberia", 839 | "id": "LR", 840 | "color": "#de4c4f", 841 | "continent": "africa", 842 | "x": 499.809082037359, 843 | "y": 60.23, 844 | "value": 4244684 845 | }, { 846 | "title": "Libya", 847 | "id": "LY", 848 | "color": "#de4c4f", 849 | "continent": "africa", 850 | "x": 9136.34462458268, 851 | "y": 75.13, 852 | "value": 6469497 853 | }, { 854 | "title": "Lithuania", 855 | "id": "LT", 856 | "color": "#d8854f", 857 | "continent": "europe", 858 | "x": 18469.9748244583, 859 | "y": 71.942, 860 | "value": 3292454 861 | }, { 862 | "title": "Macedonia, FYR", 863 | "id": "MK", 864 | "color": "#d8854f", 865 | "continent": "europe", 866 | "x": 8918.81131421927, 867 | "y": 75.041, 868 | "value": 2066785 869 | }, { 870 | "title": "Madagascar", 871 | "id": "MG", 872 | "color": "#de4c4f", 873 | "continent": "africa", 874 | "x": 981.478674981018, 875 | "y": 64.28, 876 | "value": 21928518 877 | }, { 878 | "title": "Malawi", 879 | "id": "MW", 880 | "color": "#de4c4f", 881 | "continent": "africa", 882 | "x": 848.191013907702, 883 | "y": 54.798, 884 | "value": 15882815 885 | }, { 886 | "title": "Malaysia", 887 | "id": "MY", 888 | "color": "#eea638", 889 | "continent": "asia", 890 | "x": 14202.2119391177, 891 | "y": 74.836, 892 | "value": 29321798 893 | }, { 894 | "title": "Mali", 895 | "id": "ML", 896 | "color": "#de4c4f", 897 | "continent": "africa", 898 | "x": 1070.55152828447, 899 | "y": 54.622, 900 | "value": 16318897 901 | }, { 902 | "title": "Mauritania", 903 | "id": "MR", 904 | "color": "#de4c4f", 905 | "continent": "africa", 906 | "x": 1898.35192059663, 907 | "y": 61.39, 908 | "value": 3622961 909 | }, { 910 | "title": "Mauritius", 911 | "id": "MU", 912 | "color": "#de4c4f", 913 | "continent": "africa", 914 | "x": 13082.7750766535, 915 | "y": 73.453, 916 | "value": 1313803 917 | }, { 918 | "title": "Mexico", 919 | "id": "MX", 920 | "color": "#a7a737", 921 | "continent": "north_america", 922 | "x": 12030.3862129571, 923 | "y": 77.281, 924 | "value": 116146768 925 | }, { 926 | "title": "Moldova", 927 | "id": "MD", 928 | "color": "#d8854f", 929 | "continent": "europe", 930 | "x": 2963.99305976246, 931 | "y": 68.779, 932 | "value": 3519266 933 | }, { 934 | "title": "Mongolia", 935 | "id": "MN", 936 | "color": "#eea638", 937 | "continent": "asia", 938 | "x": 4300.13326887206, 939 | "y": 67.286, 940 | "value": 2844081 941 | }, { 942 | "title": "Montenegro", 943 | "id": "ME", 944 | "color": "#d8854f", 945 | "continent": "europe", 946 | "x": 10064.1609429569, 947 | "y": 74.715, 948 | "value": 632796 949 | }, { 950 | "title": "Morocco", 951 | "id": "MA", 952 | "color": "#de4c4f", 953 | "continent": "africa", 954 | "x": 4514.51993561297, 955 | "y": 70.714, 956 | "value": 32598536 957 | }, { 958 | "title": "Mozambique", 959 | "id": "MZ", 960 | "color": "#de4c4f", 961 | "continent": "africa", 962 | "x": 1058.44192915498, 963 | "y": 49.91, 964 | "value": 24475186 965 | }, { 966 | "title": "Myanmar", 967 | "id": "MM", 968 | "color": "#eea638", 969 | "continent": "asia", 970 | "x": 1657.04593430092, 971 | "y": 65.009, 972 | "value": 48724387 973 | }, { 974 | "title": "Namibia", 975 | "id": "NA", 976 | "color": "#de4c4f", 977 | "continent": "africa", 978 | "x": 5535.83674233219, 979 | "y": 64.014, 980 | "value": 2364433 981 | }, { 982 | "title": "Nepal", 983 | "id": "NP", 984 | "color": "#eea638", 985 | "continent": "asia", 986 | "x": 1264.49264527071, 987 | "y": 67.989, 988 | "value": 31011137 989 | }, { 990 | "title": "Netherlands", 991 | "id": "NL", 992 | "color": "#d8854f", 993 | "continent": "europe", 994 | "x": 36257.0874018501, 995 | "y": 80.906, 996 | "value": 16714228 997 | }, { 998 | "title": "New Zealand", 999 | "id": "NZ", 1000 | "color": "#8aabb0", 1001 | "continent": "australia", 1002 | "x": 25223.5351395532, 1003 | "y": 80.982, 1004 | "value": 4461257 1005 | }, { 1006 | "title": "Nicaragua", 1007 | "id": "NI", 1008 | "color": "#a7a737", 1009 | "continent": "north_america", 1010 | "x": 3098.48351674394, 1011 | "y": 74.515, 1012 | "value": 5954898 1013 | }, { 1014 | "title": "Niger", 1015 | "id": "NE", 1016 | "color": "#de4c4f", 1017 | "continent": "africa", 1018 | "x": 706.79424834157, 1019 | "y": 57.934, 1020 | "value": 16644339 1021 | }, { 1022 | "title": "Nigeria", 1023 | "id": "NG", 1024 | "color": "#de4c4f", 1025 | "continent": "africa", 1026 | "x": 2483.98940927953, 1027 | "y": 52.116, 1028 | "value": 166629383 1029 | }, { 1030 | "title": "Norway", 1031 | "id": "NO", 1032 | "color": "#d8854f", 1033 | "continent": "europe", 1034 | "x": 47383.6245293861, 1035 | "y": 81.367, 1036 | "value": 4960482 1037 | }, { 1038 | "title": "Oman", 1039 | "id": "OM", 1040 | "color": "#eea638", 1041 | "continent": "asia", 1042 | "x": 26292.8480723207, 1043 | "y": 76.287, 1044 | "value": 2904037 1045 | }, { 1046 | "title": "Pakistan", 1047 | "id": "PK", 1048 | "color": "#eea638", 1049 | "continent": "asia", 1050 | "x": 2681.12078190231, 1051 | "y": 66.42, 1052 | "value": 179951140 1053 | }, { 1054 | "title": "Panama", 1055 | "id": "PA", 1056 | "color": "#a7a737", 1057 | "continent": "north_america", 1058 | "x": 13607.1433621853, 1059 | "y": 77.342, 1060 | "value": 3624991 1061 | }, { 1062 | "title": "Papua New Guinea", 1063 | "id": "PG", 1064 | "color": "#8aabb0", 1065 | "continent": "australia", 1066 | "x": 2391.5795121997, 1067 | "y": 62.288, 1068 | "value": 7170112 1069 | }, { 1070 | "title": "Paraguay", 1071 | "id": "PY", 1072 | "color": "#86a965", 1073 | "continent": "south_america", 1074 | "x": 4467.15872465943, 1075 | "y": 72.181, 1076 | "value": 6682943 1077 | }, { 1078 | "title": "Peru", 1079 | "id": "PE", 1080 | "color": "#86a965", 1081 | "continent": "south_america", 1082 | "x": 9277.57076044381, 1083 | "y": 74.525, 1084 | "value": 29733829 1085 | }, { 1086 | "title": "Philippines", 1087 | "id": "PH", 1088 | "color": "#eea638", 1089 | "continent": "asia", 1090 | "x": 3677.10197520058, 1091 | "y": 68.538, 1092 | "value": 96471461 1093 | }, { 1094 | "title": "Poland", 1095 | "id": "PL", 1096 | "color": "#d8854f", 1097 | "continent": "europe", 1098 | "x": 17851.9477668397, 1099 | "y": 76.239, 1100 | "value": 38317090 1101 | }, { 1102 | "title": "Portugal", 1103 | "id": "PT", 1104 | "color": "#d8854f", 1105 | "continent": "europe", 1106 | "x": 19576.4108427574, 1107 | "y": 79.732, 1108 | "value": 10699333 1109 | }, { 1110 | "title": "Romania", 1111 | "id": "RO", 1112 | "color": "#d8854f", 1113 | "continent": "europe", 1114 | "x": 11058.1809744544, 1115 | "y": 73.718, 1116 | "value": 21387517 1117 | }, { 1118 | "title": "Russia", 1119 | "id": "RU", 1120 | "color": "#d8854f", 1121 | "continent": "europe", 1122 | "x": 15427.6167470064, 1123 | "y": 67.874, 1124 | "value": 142703181 1125 | }, { 1126 | "title": "Rwanda", 1127 | "id": "RW", 1128 | "color": "#de4c4f", 1129 | "continent": "africa", 1130 | "x": 1223.52570881561, 1131 | "y": 63.563, 1132 | "value": 11271786 1133 | }, { 1134 | "title": "Saudi Arabia", 1135 | "id": "SA", 1136 | "color": "#eea638", 1137 | "continent": "asia", 1138 | "x": 26259.6213479005, 1139 | "y": 75.264, 1140 | "value": 28705133 1141 | }, { 1142 | "title": "Senegal", 1143 | "id": "SN", 1144 | "color": "#de4c4f", 1145 | "continent": "africa", 1146 | "x": 1753.48800936096, 1147 | "y": 63.3, 1148 | "value": 13107945 1149 | }, { 1150 | "title": "Serbia", 1151 | "id": "RS", 1152 | "color": "#d8854f", 1153 | "continent": "europe", 1154 | "x": 9335.95911484282, 1155 | "y": 73.934, 1156 | "value": 9846582 1157 | }, { 1158 | "title": "Sierra Leone", 1159 | "id": "SL", 1160 | "color": "#de4c4f", 1161 | "continent": "africa", 1162 | "x": 1072.95787930719, 1163 | "y": 45.338, 1164 | "value": 6126450 1165 | }, { 1166 | "title": "Singapore", 1167 | "id": "SG", 1168 | "color": "#eea638", 1169 | "continent": "asia", 1170 | "x": 49381.9560054179, 1171 | "y": 82.155, 1172 | "value": 5256278 1173 | }, { 1174 | "title": "Slovak Republic", 1175 | "id": "SK", 1176 | "color": "#d8854f", 1177 | "continent": "europe", 1178 | "x": 20780.9857840812, 1179 | "y": 75.272, 1180 | "value": 5480332 1181 | }, { 1182 | "title": "Slovenia", 1183 | "id": "SI", 1184 | "color": "#d8854f", 1185 | "continent": "europe", 1186 | "x": 23986.8506836646, 1187 | "y": 79.444, 1188 | "value": 2040057 1189 | }, { 1190 | "title": "Solomon Islands", 1191 | "id": "SB", 1192 | "color": "#8aabb0", 1193 | "continent": "australia", 1194 | "x": 2024.23067334134, 1195 | "y": 67.465, 1196 | "value": 566481 1197 | }, { 1198 | "title": "Somalia", 1199 | "id": "SO", 1200 | "color": "#de4c4f", 1201 | "continent": "africa", 1202 | "x": 953.275713662563, 1203 | "y": 54, 1204 | "value": 9797445 1205 | }, { 1206 | "title": "South Africa", 1207 | "id": "ZA", 1208 | "color": "#de4c4f", 1209 | "continent": "africa", 1210 | "x": 9657.25275417241, 1211 | "y": 56.271, 1212 | "value": 50738255 1213 | }, { 1214 | "title": "South Sudan", 1215 | "id": "SS", 1216 | "color": "#de4c4f", 1217 | "continent": "africa", 1218 | "x": 1433.03720057714, 1219 | "y": 54.666, 1220 | "value": 10386101 1221 | }, { 1222 | "title": "Spain", 1223 | "id": "ES", 1224 | "color": "#d8854f", 1225 | "continent": "europe", 1226 | "x": 26457.7572559653, 1227 | "y": 81.958, 1228 | "value": 46771596 1229 | }, { 1230 | "title": "Sri Lanka", 1231 | "id": "LK", 1232 | "color": "#eea638", 1233 | "continent": "asia", 1234 | "x": 5182.66658831813, 1235 | "y": 74.116, 1236 | "value": 21223550 1237 | }, { 1238 | "title": "Sudan", 1239 | "id": "SD", 1240 | "color": "#de4c4f", 1241 | "continent": "africa", 1242 | "x": 2917.61641581811, 1243 | "y": 61.875, 1244 | "value": 35335982 1245 | }, { 1246 | "title": "Suriname", 1247 | "id": "SR", 1248 | "color": "#86a965", 1249 | "continent": "south_america", 1250 | "x": 8979.80549248675, 1251 | "y": 70.794, 1252 | "value": 534175 1253 | }, { 1254 | "title": "Swaziland", 1255 | "id": "SZ", 1256 | "color": "#de4c4f", 1257 | "continent": "africa", 1258 | "x": 4979.704126513, 1259 | "y": 48.91, 1260 | "value": 1220408 1261 | }, { 1262 | "title": "Sweden", 1263 | "id": "SE", 1264 | "color": "#d8854f", 1265 | "continent": "europe", 1266 | "x": 34530.2628238397, 1267 | "y": 81.69, 1268 | "value": 9495392 1269 | }, { 1270 | "title": "Switzerland", 1271 | "id": "CH", 1272 | "color": "#d8854f", 1273 | "continent": "europe", 1274 | "x": 37678.3928108684, 1275 | "y": 82.471, 1276 | "value": 7733709 1277 | }, { 1278 | "title": "Syria", 1279 | "id": "SY", 1280 | "color": "#eea638", 1281 | "continent": "asia", 1282 | "x": 4432.01553897559, 1283 | "y": 71, 1284 | "value": 21117690 1285 | }, { 1286 | "title": "Taiwan", 1287 | "id": "TW", 1288 | "color": "#eea638", 1289 | "continent": "asia", 1290 | "x": 32840.8623523232, 1291 | "y": 79.45, 1292 | "value": 23114000 1293 | }, { 1294 | "title": "Tajikistan", 1295 | "id": "TJ", 1296 | "color": "#eea638", 1297 | "continent": "asia", 1298 | "x": 1952.10042735043, 1299 | "y": 67.118, 1300 | "value": 7078755 1301 | }, { 1302 | "title": "Tanzania", 1303 | "id": "TZ", 1304 | "color": "#de4c4f", 1305 | "continent": "africa", 1306 | "x": 1330.05614548839, 1307 | "y": 60.885, 1308 | "value": 47656367 1309 | }, { 1310 | "title": "Thailand", 1311 | "id": "TH", 1312 | "color": "#eea638", 1313 | "continent": "asia", 1314 | "x": 8451.15964058768, 1315 | "y": 74.225, 1316 | "value": 69892142 1317 | }, { 1318 | "title": "Timor-Leste", 1319 | "id": "TL", 1320 | "color": "#eea638", 1321 | "continent": "asia", 1322 | "x": 3466.08281224683, 1323 | "y": 67.033, 1324 | "value": 1187194 1325 | }, { 1326 | "title": "Togo", 1327 | "id": "TG", 1328 | "color": "#de4c4f", 1329 | "continent": "africa", 1330 | "x": 975.396852535221, 1331 | "y": 56.198, 1332 | "value": 6283092 1333 | }, { 1334 | "title": "Trinidad and Tobago", 1335 | "id": "TT", 1336 | "color": "#a7a737", 1337 | "continent": "north_america", 1338 | "x": 17182.0954558471, 1339 | "y": 69.761, 1340 | "value": 1350999 1341 | }, { 1342 | "title": "Tunisia", 1343 | "id": "TN", 1344 | "color": "#de4c4f", 1345 | "continent": "africa", 1346 | "x": 7620.47056462131, 1347 | "y": 75.632, 1348 | "value": 10704948 1349 | }, { 1350 | "title": "Turkey", 1351 | "id": "TR", 1352 | "color": "#d8854f", 1353 | "continent": "europe", 1354 | "x": 9287.29312549815, 1355 | "y": 74.938, 1356 | "value": 74508771 1357 | }, { 1358 | "title": "Turkmenistan", 1359 | "id": "TM", 1360 | "color": "#eea638", 1361 | "continent": "asia", 1362 | "x": 7921.2740619558, 1363 | "y": 65.299, 1364 | "value": 5169660 1365 | }, { 1366 | "title": "Uganda", 1367 | "id": "UG", 1368 | "color": "#de4c4f", 1369 | "continent": "africa", 1370 | "x": 1251.09807015907, 1371 | "y": 58.668, 1372 | "value": 35620977 1373 | }, { 1374 | "title": "Ukraine", 1375 | "id": "UA", 1376 | "color": "#d8854f", 1377 | "continent": "europe", 1378 | "x": 6389.58597273257, 1379 | "y": 68.414, 1380 | "value": 44940268 1381 | }, { 1382 | "title": "United Arab Emirates", 1383 | "id": "AE", 1384 | "color": "#eea638", 1385 | "continent": "asia", 1386 | "x": 31980.24143802, 1387 | "y": 76.671, 1388 | "value": 8105873 1389 | }, { 1390 | "title": "United Kingdom", 1391 | "id": "GB", 1392 | "color": "#d8854f", 1393 | "continent": "europe", 1394 | "x": 31295.1431522074, 1395 | "y": 80.396, 1396 | "value": 62798099 1397 | }, { 1398 | "title": "United States", 1399 | "id": "US", 1400 | "color": "#a7a737", 1401 | "continent": "north_america", 1402 | "x": 42296.2316492477, 1403 | "y": 78.797, 1404 | "value": 315791284 1405 | }, { 1406 | "title": "Uruguay", 1407 | "id": "UY", 1408 | "color": "#86a965", 1409 | "continent": "south_america", 1410 | "x": 13179.2310803465, 1411 | "y": 77.084, 1412 | "value": 3391428 1413 | }, { 1414 | "title": "Uzbekistan", 1415 | "id": "UZ", 1416 | "color": "#eea638", 1417 | "continent": "asia", 1418 | "x": 3117.27386553102, 1419 | "y": 68.117, 1420 | "value": 28077486 1421 | }, { 1422 | "title": "Venezuela", 1423 | "id": "VE", 1424 | "color": "#86a965", 1425 | "continent": "south_america", 1426 | "x": 11685.1771941737, 1427 | "y": 74.477, 1428 | "value": 29890694 1429 | }, { 1430 | "title": "West Bank and Gaza", 1431 | "id": "PS", 1432 | "color": "#eea638", 1433 | "continent": "asia", 1434 | "x": 4328.39115760087, 1435 | "y": 73.018, 1436 | "value": 4270791 1437 | }, { 1438 | "title": "Vietnam", 1439 | "id": "VN", 1440 | "color": "#eea638", 1441 | "continent": "asia", 1442 | "x": 3073.64961158389, 1443 | "y": 75.793, 1444 | "value": 89730274 1445 | }, { 1446 | "title": "Yemen, Rep.", 1447 | "id": "YE", 1448 | "color": "#eea638", 1449 | "continent": "asia", 1450 | "x": 2043.7877761328, 1451 | "y": 62.923, 1452 | "value": 25569263 1453 | }, { 1454 | "title": "Zambia", 1455 | "id": "ZM", 1456 | "color": "#de4c4f", 1457 | "continent": "africa", 1458 | "x": 1550.92385858124, 1459 | "y": 57.037, 1460 | "value": 13883577 1461 | }, { 1462 | "title": "Zimbabwe", 1463 | "id": "ZW", 1464 | "color": "#de4c4f", 1465 | "continent": "africa", 1466 | "x": 545.344601005788, 1467 | "y": 58.142, 1468 | "value": 13013678 1469 | }]; 1470 | } 1471 | 1472 | function drawPieChart() { 1473 | // Create chart instance 1474 | var chart = am4core.create("container_pie", am4charts.PieChart); 1475 | 1476 | // Add and configure Series 1477 | var pieSeries = chart.series.push(new am4charts.PieSeries()); 1478 | pieSeries.dataFields.value = "litres"; 1479 | pieSeries.dataFields.category = "country"; 1480 | 1481 | // Let's cut a hole in our Pie chart the size of 30% the radius 1482 | chart.innerRadius = am4core.percent(30); 1483 | 1484 | // Put a thick white border around each Slice 1485 | pieSeries.slices.template.stroke = am4core.color("#fff"); 1486 | pieSeries.slices.template.strokeWidth = 2; 1487 | pieSeries.slices.template.strokeOpacity = 1; 1488 | pieSeries.slices.template 1489 | // change the cursor on hover to make it apparent the object can be interacted with 1490 | .cursorOverStyle = [{ 1491 | "property": "cursor", 1492 | "value": "pointer" 1493 | }]; 1494 | 1495 | pieSeries.alignLabels = false; 1496 | pieSeries.labels.template.bent = true; 1497 | pieSeries.labels.template.radius = 3; 1498 | pieSeries.labels.template.padding(0, 0, 0, 0); 1499 | 1500 | pieSeries.ticks.template.disabled = true; 1501 | 1502 | // Create a base filter effect (as if it's not there) for the hover to return to 1503 | var shadow = pieSeries.slices.template.filters.push(new am4core.DropShadowFilter); 1504 | shadow.opacity = 0; 1505 | 1506 | // Create hover state 1507 | var hoverState = pieSeries.slices.template.states.getKey("hover"); // normally we have to create the hover state, in this case it already exists 1508 | 1509 | // Slightly shift the shadow and make it more prominent on hover 1510 | var hoverShadow = hoverState.filters.push(new am4core.DropShadowFilter); 1511 | hoverShadow.opacity = 0.7; 1512 | hoverShadow.blur = 5; 1513 | 1514 | // Add a legend 1515 | chart.legend = new am4charts.Legend(); 1516 | 1517 | chart.data = [{ 1518 | "country": "Lithuania", 1519 | "litres": 501.9 1520 | }, { 1521 | "country": "Germany", 1522 | "litres": 165.8 1523 | }, { 1524 | "country": "Australia", 1525 | "litres": 139.9 1526 | }, { 1527 | "country": "Austria", 1528 | "litres": 128.3 1529 | }, { 1530 | "country": "UK", 1531 | "litres": 99 1532 | }, { 1533 | "country": "Belgium", 1534 | "litres": 60 1535 | }]; 1536 | } 1537 | 1538 | function drawLineChart() { 1539 | // Create chart instance 1540 | var chart = am4core.create("container_line", am4charts.XYChart); 1541 | 1542 | chart.colors.step = 2; 1543 | chart.maskBullets = false; 1544 | 1545 | // Add data 1546 | chart.data = [{ 1547 | "date": "2012-01-01", 1548 | "distance": 227, 1549 | "townName": "New York", 1550 | "townName2": "New York", 1551 | "townSize": 12, 1552 | "latitude": 40.71, 1553 | "duration": 408 1554 | }, { 1555 | "date": "2012-01-02", 1556 | "distance": 371, 1557 | "townName": "Washington", 1558 | "townSize": 7, 1559 | "latitude": 38.89, 1560 | "duration": 482 1561 | }, { 1562 | "date": "2012-01-03", 1563 | "distance": 433, 1564 | "townName": "Wilmington", 1565 | "townSize": 3, 1566 | "latitude": 34.22, 1567 | "duration": 562 1568 | }, { 1569 | "date": "2012-01-04", 1570 | "distance": 345, 1571 | "townName": "Jacksonville", 1572 | "townSize": 3.5, 1573 | "latitude": 30.35, 1574 | "duration": 379 1575 | }, { 1576 | "date": "2012-01-05", 1577 | "distance": 480, 1578 | "townName": "Miami", 1579 | "townName2": "Miami", 1580 | "townSize": 5, 1581 | "latitude": 25.83, 1582 | "duration": 501 1583 | }, { 1584 | "date": "2012-01-06", 1585 | "distance": 386, 1586 | "townName": "Tallahassee", 1587 | "townSize": 3.5, 1588 | "latitude": 30.46, 1589 | "duration": 443 1590 | }, { 1591 | "date": "2012-01-07", 1592 | "distance": 348, 1593 | "townName": "New Orleans", 1594 | "townSize": 5, 1595 | "latitude": 29.94, 1596 | "duration": 405 1597 | }, { 1598 | "date": "2012-01-08", 1599 | "distance": 238, 1600 | "townName": "Houston", 1601 | "townName2": "Houston", 1602 | "townSize": 8, 1603 | "latitude": 29.76, 1604 | "duration": 309 1605 | }, { 1606 | "date": "2012-01-09", 1607 | "distance": 218, 1608 | "townName": "Dalas", 1609 | "townSize": 8, 1610 | "latitude": 32.8, 1611 | "duration": 287 1612 | }, { 1613 | "date": "2012-01-10", 1614 | "distance": 349, 1615 | "townName": "Oklahoma City", 1616 | "townSize": 5, 1617 | "latitude": 35.49, 1618 | "duration": 485 1619 | }, { 1620 | "date": "2012-01-11", 1621 | "distance": 603, 1622 | "townName": "Kansas City", 1623 | "townSize": 5, 1624 | "latitude": 39.1, 1625 | "duration": 890 1626 | }, { 1627 | "date": "2012-01-12", 1628 | "distance": 534, 1629 | "townName": "Denver", 1630 | "townName2": "Denver", 1631 | "townSize": 9, 1632 | "latitude": 39.74, 1633 | "duration": 810 1634 | }, { 1635 | "date": "2012-01-13", 1636 | "townName": "Salt Lake City", 1637 | "townSize": 6, 1638 | "distance": 425, 1639 | "duration": 670, 1640 | "latitude": 40.75, 1641 | "dashLength": 8, 1642 | "alpha": 0.4 1643 | }, { 1644 | "date": "2012-01-14", 1645 | "latitude": 36.1, 1646 | "duration": 470, 1647 | "townName": "Las Vegas", 1648 | "townName2": "Las Vegas" 1649 | }, { 1650 | "date": "2012-01-15" 1651 | }, { 1652 | "date": "2012-01-16" 1653 | }, { 1654 | "date": "2012-01-17" 1655 | }]; 1656 | 1657 | // Create axes 1658 | var dateAxis = chart.xAxes.push(new am4charts.DateAxis()); 1659 | dateAxis.renderer.grid.template.location = 0; 1660 | dateAxis.renderer.minGridDistance = 50; 1661 | dateAxis.renderer.grid.template.disabled = true; 1662 | dateAxis.renderer.fullWidthTooltip = true; 1663 | 1664 | var distanceAxis = chart.yAxes.push(new am4charts.ValueAxis()); 1665 | distanceAxis.title.text = "Distance"; 1666 | distanceAxis.renderer.grid.template.disabled = true; 1667 | 1668 | var durationAxis = chart.yAxes.push(new am4charts.DurationAxis()); 1669 | durationAxis.title.text = "Duration"; 1670 | durationAxis.baseUnit = "minute"; 1671 | durationAxis.renderer.grid.template.disabled = true; 1672 | durationAxis.renderer.opposite = true; 1673 | 1674 | durationAxis.durationFormatter.durationFormat = "hh'h' mm'min'"; 1675 | 1676 | var latitudeAxis = chart.yAxes.push(new am4charts.ValueAxis()); 1677 | latitudeAxis.renderer.grid.template.disabled = true; 1678 | latitudeAxis.renderer.labels.template.disabled = true; 1679 | 1680 | // Create series 1681 | var distanceSeries = chart.series.push(new am4charts.ColumnSeries()); 1682 | distanceSeries.dataFields.valueY = "distance"; 1683 | distanceSeries.dataFields.dateX = "date"; 1684 | distanceSeries.yAxis = distanceAxis; 1685 | distanceSeries.tooltipText = "{valueY} miles"; 1686 | distanceSeries.name = "Distance"; 1687 | distanceSeries.columns.template.fillOpacity = 0.7; 1688 | distanceSeries.columns.template.propertyFields.strokeDasharray = "dashLength"; 1689 | distanceSeries.columns.template.propertyFields.fillOpacity = "alpha"; 1690 | 1691 | var disatnceState = distanceSeries.columns.template.states.create("hover"); 1692 | disatnceState.properties.fillOpacity = 0.9; 1693 | 1694 | var durationSeries = chart.series.push(new am4charts.LineSeries()); 1695 | durationSeries.dataFields.valueY = "duration"; 1696 | durationSeries.dataFields.dateX = "date"; 1697 | durationSeries.yAxis = durationAxis; 1698 | durationSeries.name = "Duration"; 1699 | durationSeries.strokeWidth = 2; 1700 | durationSeries.propertyFields.strokeDasharray = "dashLength"; 1701 | durationSeries.tooltipText = "{valueY.formatDuration()}"; 1702 | 1703 | var durationBullet = durationSeries.bullets.push(new am4charts.Bullet()); 1704 | var durationRectangle = durationBullet.createChild(am4core.Rectangle); 1705 | durationBullet.horizontalCenter = "middle"; 1706 | durationBullet.verticalCenter = "middle"; 1707 | durationBullet.width = 7; 1708 | durationBullet.height = 7; 1709 | durationRectangle.width = 7; 1710 | durationRectangle.height = 7; 1711 | 1712 | var durationState = durationBullet.states.create("hover"); 1713 | durationState.properties.scale = 1.2; 1714 | 1715 | var latitudeSeries = chart.series.push(new am4charts.LineSeries()); 1716 | latitudeSeries.dataFields.valueY = "latitude"; 1717 | latitudeSeries.dataFields.dateX = "date"; 1718 | latitudeSeries.yAxis = latitudeAxis; 1719 | latitudeSeries.name = "Duration"; 1720 | latitudeSeries.strokeWidth = 2; 1721 | latitudeSeries.propertyFields.strokeDasharray = "dashLength"; 1722 | latitudeSeries.tooltipText = "Latitude: {valueY} ({townName})"; 1723 | 1724 | var latitudeBullet = latitudeSeries.bullets.push(new am4charts.CircleBullet()); 1725 | latitudeBullet.circle.fill = am4core.color("#fff"); 1726 | latitudeBullet.circle.strokeWidth = 2; 1727 | latitudeBullet.circle.propertyFields.radius = "townSize"; 1728 | 1729 | var latitudeState = latitudeBullet.states.create("hover"); 1730 | latitudeState.properties.scale = 1.2; 1731 | 1732 | var latitudeLabel = latitudeSeries.bullets.push(new am4charts.LabelBullet()); 1733 | latitudeLabel.label.text = "{townName2}"; 1734 | latitudeLabel.label.horizontalCenter = "left"; 1735 | latitudeLabel.label.dx = 14; 1736 | 1737 | // Add legend 1738 | chart.legend = new am4charts.Legend(); 1739 | 1740 | // Add cursor 1741 | chart.cursor = new am4charts.XYCursor(); 1742 | chart.cursor.fullWidthLineX = true; 1743 | chart.cursor.xAxis = dateAxis; 1744 | chart.cursor.lineX.strokeOpacity = 0; 1745 | chart.cursor.lineX.fill = am4core.color("#000"); 1746 | chart.cursor.lineX.fillOpacity = 0.1; 1747 | } 1748 | 1749 | function drawRadarChart() { 1750 | /* Create chart instance */ 1751 | var chart = am4core.create("container_radar", am4charts.RadarChart); 1752 | 1753 | /* Add data */ 1754 | chart.data = [{ 1755 | "country": "Lithuania", 1756 | "litres": 501 1757 | }, { 1758 | "country": "Czechia", 1759 | "litres": 301 1760 | }, { 1761 | "country": "Ireland", 1762 | "litres": 266 1763 | }, { 1764 | "country": "Germany", 1765 | "litres": 165 1766 | }, { 1767 | "country": "Australia", 1768 | "litres": 139 1769 | }, { 1770 | "country": "Austria", 1771 | "litres": 336 1772 | }, { 1773 | "country": "UK", 1774 | "litres": 290 1775 | }, { 1776 | "country": "Belgium", 1777 | "litres": 325 1778 | }, { 1779 | "country": "The Netherlands", 1780 | "litres": 40 1781 | }]; 1782 | 1783 | /* Create axes */ 1784 | var categoryAxis = chart.xAxes.push(new am4charts.CategoryAxis()); 1785 | categoryAxis.dataFields.category = "country"; 1786 | 1787 | var valueAxis = chart.yAxes.push(new am4charts.ValueAxis()); 1788 | valueAxis.renderer.axisFills.template.fill = chart.colors.getIndex(2); 1789 | valueAxis.renderer.axisFills.template.fillOpacity = 0.05; 1790 | 1791 | /* Create and configure series */ 1792 | var series = chart.series.push(new am4charts.RadarSeries()); 1793 | series.dataFields.valueY = "litres"; 1794 | series.dataFields.categoryX = "country"; 1795 | series.name = "Sales"; 1796 | series.strokeWidth = 3; 1797 | } 1798 | 1799 | function drawFunnelChart() { 1800 | var chart = am4core.create("container_funnel", am4charts.SlicedChart); 1801 | chart.hiddenState.properties.opacity = 0; 1802 | // this makes initial fade in effect 1803 | 1804 | chart.data = [{ 1805 | "name": "The first", 1806 | "value": 600 1807 | }, { 1808 | "name": "The second", 1809 | "value": 300 1810 | }, { 1811 | "name": "The third", 1812 | "value": 200 1813 | }, { 1814 | "name": "The fourth", 1815 | "value": 180 1816 | }, { 1817 | "name": "The fifth", 1818 | "value": 50 1819 | }, { 1820 | "name": "The sixth", 1821 | "value": 20 1822 | }, { 1823 | "name": "The seventh", 1824 | "value": 10 1825 | }]; 1826 | 1827 | var series = chart.series.push(new am4charts.FunnelSeries()); 1828 | series.colors.step = 2; 1829 | series.dataFields.value = "value"; 1830 | series.dataFields.category = "name"; 1831 | series.alignLabels = true; 1832 | series.orientation = "horizontal"; 1833 | series.bottomRatio = 1; 1834 | } 1835 | 1836 | function drawChart() { 1837 | am4core.ready(function() { 1838 | drawBarChart(); 1839 | drawScatterChart(); 1840 | drawPieChart(); 1841 | drawLineChart(); 1842 | drawRadarChart(); 1843 | drawFunnelChart(); 1844 | }); 1845 | } 1846 | 1847 | function getHandler() { 1848 | const option = { 1849 | fillStyle: $('#fillStyleSelector').children('option:selected').val(), 1850 | bowing: $('#bowingRange').val(), 1851 | roughness: $('#roughnessRange').val() 1852 | }; 1853 | 1854 | const container = $('#charts')[0]; 1855 | return handler = Sketchifier(container, option); 1856 | } 1857 | 1858 | $(function() { 1859 | drawChart(); 1860 | var handler = getHandler(); 1861 | 1862 | function updateHandler() { 1863 | handler.restore(); 1864 | handler = getHandler(); 1865 | if ($('#handifyChecker').prop('checked')) { 1866 | handler.handify(); 1867 | } 1868 | } 1869 | 1870 | $('#fillStyleSelector').change(function() { 1871 | updateHandler(); 1872 | }) 1873 | 1874 | $('#bowingRange').change(function() { 1875 | updateHandler(); 1876 | }) 1877 | 1878 | $('#roughnessRange').change(function() { 1879 | updateHandler(); 1880 | }) 1881 | 1882 | $('#handifyChecker').change(function() { 1883 | if (this.checked) { 1884 | handler.handify(); 1885 | } else { 1886 | handler.restore(); 1887 | } 1888 | }); 1889 | }); -------------------------------------------------------------------------------- /demo/echarts.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | sketchify 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |
19 | 20 |
21 | 22 | 32 | 33 | 34 | 35 | 36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | 48 | -------------------------------------------------------------------------------- /demo/echarts.js: -------------------------------------------------------------------------------- 1 | function drawBarChart() { 2 | const myChart = echarts.init(document.getElementById('container_bar'), null, { 3 | renderer: 'svg' 4 | }); 5 | const option = { 6 | xAxis: { 7 | type: 'category', 8 | data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun中午'] 9 | }, 10 | yAxis: { 11 | type: 'value' 12 | }, 13 | series: [{ 14 | data: [120, 200, 150, 80, 70, 110, 130], 15 | type: 'bar' 16 | }] 17 | }; 18 | myChart.setOption(option); 19 | } 20 | 21 | function drawScatterChart() { 22 | const myChart = echarts.init(document.getElementById('container_scatter'), null, { 23 | renderer: 'svg' 24 | }); 25 | 26 | const option = { 27 | xAxis: {}, 28 | yAxis: {}, 29 | series: [{ 30 | symbolSize: 50, 31 | data: [ 32 | [10.0, 8.04], 33 | [8.0, 6.95], 34 | [13.0, 7.58], 35 | [9.0, 8.81], 36 | [11.0, 8.33], 37 | [14.0, 9.96], 38 | [6.0, 7.24], 39 | [4.0, 4.26], 40 | [12.0, 10.84], 41 | [7.0, 4.82], 42 | [5.0, 5.68] 43 | ], 44 | type: 'scatter' 45 | }] 46 | }; 47 | 48 | myChart.setOption(option); 49 | } 50 | 51 | function drawPieChart() { 52 | const myChart = echarts.init(document.getElementById('container_pie'), null, { 53 | renderer: 'svg' 54 | }); 55 | const option = { 56 | tooltip: { 57 | trigger: 'item', 58 | formatter: "{a}
{b}: {c} ({d}%)" 59 | }, 60 | legend: { 61 | orient: 'vertical', 62 | x: 'left', 63 | data: ['A', 'B', 'C', 'D', 'E'] 64 | }, 65 | series: [{ 66 | name: 'F', 67 | type: 'pie', 68 | radius: ['50%', '70%'], 69 | avoidLabelOverlap: false, 70 | label: { 71 | normal: { 72 | show: false, 73 | position: 'center' 74 | }, 75 | emphasis: { 76 | show: true, 77 | textStyle: { 78 | fontSize: '30', 79 | fontWeight: 'bold' 80 | } 81 | } 82 | }, 83 | labelLine: { 84 | normal: { 85 | show: false 86 | } 87 | }, 88 | data: [{ 89 | value: 335, 90 | name: 'A' 91 | }, { 92 | value: 310, 93 | name: 'B' 94 | }, { 95 | value: 234, 96 | name: 'C' 97 | }, { 98 | value: 135, 99 | name: 'D' 100 | }, { 101 | value: 1548, 102 | name: 'E' 103 | }] 104 | }] 105 | }; 106 | 107 | myChart.setOption(option); 108 | } 109 | 110 | function drawLineChart() { 111 | const myChart = echarts.init(document.getElementById('container_line'), null, { 112 | renderer: 'svg' 113 | }); 114 | const option = { 115 | title: { 116 | text: 'Step Line' 117 | }, 118 | tooltip: { 119 | trigger: 'axis' 120 | }, 121 | legend: { 122 | data: ['Step Start', 'Step Middle', 'Step End'] 123 | }, 124 | grid: { 125 | left: '3%', 126 | right: '4%', 127 | bottom: '3%', 128 | containLabel: true 129 | }, 130 | toolbox: { 131 | feature: { 132 | saveAsImage: {} 133 | } 134 | }, 135 | xAxis: { 136 | type: 'category', 137 | data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] 138 | }, 139 | yAxis: { 140 | type: 'value' 141 | }, 142 | series: [{ 143 | name: 'Step Start', 144 | type: 'line', 145 | step: 'start', 146 | data: [120, 132, 101, 134, 90, 230, 210] 147 | }, { 148 | name: 'Step Middle', 149 | type: 'line', 150 | step: 'middle', 151 | data: [220, 282, 201, 234, 290, 430, 410] 152 | }, { 153 | name: 'Step End', 154 | type: 'line', 155 | step: 'end', 156 | data: [450, 432, 401, 454, 590, 530, 510] 157 | }] 158 | }; 159 | myChart.setOption(option); 160 | } 161 | 162 | function drawRadarChart() { 163 | const myChart = echarts.init(document.getElementById('container_radar'), null, { 164 | renderer: 'svg' 165 | }); 166 | const option = { 167 | title: { 168 | text: 'radar' 169 | }, 170 | tooltip: {}, 171 | legend: { 172 | data: ['Allocated Budget', 'Actual Spending'] 173 | }, 174 | radar: { 175 | // shape: 'circle', 176 | name: { 177 | textStyle: { 178 | color: '#fff', 179 | backgroundColor: '#999', 180 | borderRadius: 3, 181 | padding: [3, 5] 182 | } 183 | }, 184 | indicator: [{ 185 | name: 'sales', 186 | max: 6500 187 | }, { 188 | name: 'Administration', 189 | max: 16000 190 | }, { 191 | name: 'Information Techology', 192 | max: 30000 193 | }, { 194 | name: 'Customer Support', 195 | max: 38000 196 | }, { 197 | name: 'Development', 198 | max: 52000 199 | }, { 200 | name: 'Marketing', 201 | max: 25000 202 | }] 203 | }, 204 | series: [{ 205 | name: 'Budget vs spending', 206 | type: 'radar', 207 | // areaStyle: {normal: {}}, 208 | data: [{ 209 | value: [4300, 10000, 28000, 35000, 50000, 19000], 210 | name: '(Allocated Budget)' 211 | }, { 212 | value: [5000, 14000, 28000, 31000, 42000, 21000], 213 | name: '(Actual Spending)' 214 | }] 215 | }] 216 | }; 217 | myChart.setOption(option); 218 | } 219 | 220 | function drawFunnelChart() { 221 | const myChart = echarts.init(document.getElementById('container_funnel'), null, { 222 | renderer: 'svg' 223 | }); 224 | const option = { 225 | title: { 226 | text: '漏斗图', 227 | subtext: '纯属虚构', 228 | left: 'left', 229 | top: 'bottom' 230 | }, 231 | tooltip: { 232 | trigger: 'item', 233 | formatter: "{a}
{b} : {c}%" 234 | }, 235 | toolbox: { 236 | orient: 'vertical', 237 | top: 'center', 238 | feature: { 239 | dataView: { 240 | readOnly: false 241 | }, 242 | restore: {}, 243 | saveAsImage: {} 244 | } 245 | }, 246 | legend: { 247 | orient: 'vertical', 248 | left: 'left', 249 | data: ['A', 'B', 'C', 'D', 'E'] 250 | }, 251 | calculable: true, 252 | series: [{ 253 | name: '漏斗图', 254 | type: 'funnel', 255 | width: '40%', 256 | height: '45%', 257 | left: '5%', 258 | top: '50%', 259 | data: [{ 260 | value: 60, 261 | name: 'C' 262 | }, { 263 | value: 30, 264 | name: 'D' 265 | }, { 266 | value: 10, 267 | name: 'E' 268 | }, { 269 | value: 80, 270 | name: 'B' 271 | }, { 272 | value: 100, 273 | name: 'A' 274 | }] 275 | }, { 276 | name: '金字塔', 277 | type: 'funnel', 278 | width: '40%', 279 | height: '45%', 280 | left: '5%', 281 | top: '5%', 282 | sort: 'ascending', 283 | data: [{ 284 | value: 60, 285 | name: 'C' 286 | }, { 287 | value: 30, 288 | name: 'D' 289 | }, { 290 | value: 10, 291 | name: 'E' 292 | }, { 293 | value: 80, 294 | name: 'B' 295 | }, { 296 | value: 100, 297 | name: 'A' 298 | }] 299 | }, { 300 | name: '漏斗图', 301 | type: 'funnel', 302 | width: '40%', 303 | height: '45%', 304 | left: '55%', 305 | top: '5%', 306 | label: { 307 | normal: { 308 | position: 'left' 309 | } 310 | }, 311 | data: [{ 312 | value: 60, 313 | name: 'C' 314 | }, { 315 | value: 30, 316 | name: 'D' 317 | }, { 318 | value: 10, 319 | name: 'E' 320 | }, { 321 | value: 80, 322 | name: 'B' 323 | }, { 324 | value: 100, 325 | name: 'A' 326 | }] 327 | }, { 328 | name: '金字塔', 329 | type: 'funnel', 330 | width: '40%', 331 | height: '45%', 332 | left: '55%', 333 | top: '50%', 334 | sort: 'ascending', 335 | label: { 336 | normal: { 337 | position: 'left' 338 | } 339 | }, 340 | data: [{ 341 | value: 60, 342 | name: 'C' 343 | }, { 344 | value: 30, 345 | name: 'D' 346 | }, { 347 | value: 10, 348 | name: 'E' 349 | }, { 350 | value: 80, 351 | name: 'B' 352 | }, { 353 | value: 100, 354 | name: 'A' 355 | }] 356 | }] 357 | }; 358 | myChart.setOption(option); 359 | } 360 | 361 | function drawChart() { 362 | drawBarChart(); 363 | drawScatterChart(); 364 | drawPieChart(); 365 | drawLineChart(); 366 | drawRadarChart(); 367 | drawFunnelChart(); 368 | } 369 | 370 | function getHandler() { 371 | const option = { 372 | fillStyle: $('#fillStyleSelector').children('option:selected').val(), 373 | bowing: $('#bowingRange').val(), 374 | roughness: $('#roughnessRange').val() 375 | }; 376 | 377 | const container = $('#charts')[0]; 378 | return handler = Sketchifier(container, option); 379 | } 380 | 381 | $(function() { 382 | drawChart(); 383 | var handler = getHandler(); 384 | 385 | function updateHandler() { 386 | handler.restore(); 387 | handler = getHandler(); 388 | if ($('#handifyChecker').prop('checked')) { 389 | handler.handify(); 390 | } 391 | } 392 | 393 | $('#fillStyleSelector').change(function() { 394 | updateHandler(); 395 | }) 396 | 397 | $('#bowingRange').change(function() { 398 | updateHandler(); 399 | }) 400 | 401 | $('#roughnessRange').change(function() { 402 | updateHandler(); 403 | }) 404 | 405 | $('#handifyChecker').change(function() { 406 | if (this.checked) { 407 | handler.handify(); 408 | } else { 409 | handler.restore(); 410 | } 411 | }); 412 | }); -------------------------------------------------------------------------------- /demo/g2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | sketchify 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 |
19 |
20 | 21 |
22 | 23 | 33 | 34 | 35 | 36 | 37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 | 49 | -------------------------------------------------------------------------------- /demo/g2.js: -------------------------------------------------------------------------------- 1 | function drawBarChart() { 2 | var data = [{ 3 | year: '1951 年', 4 | sales: 38 5 | }, { 6 | year: '1952 年', 7 | sales: 52 8 | }, { 9 | year: '1956 年', 10 | sales: 61 11 | }, { 12 | year: '1957 年', 13 | sales: 145 14 | }, { 15 | year: '1958 年', 16 | sales: 48 17 | }, { 18 | year: '1959 年', 19 | sales: 38 20 | }, { 21 | year: '1960 年', 22 | sales: 38 23 | }, { 24 | year: '1962 年', 25 | sales: 38 26 | }]; 27 | var chart = new G2.Chart({ 28 | container: 'container_bar', 29 | forceFit: true, 30 | height: 300, 31 | renderer: 'svg' 32 | }); 33 | chart.source(data); 34 | chart.scale('sales', { 35 | tickInterval: 20 36 | }); 37 | chart.interval().position('year*sales'); 38 | chart.render(); 39 | } 40 | 41 | function drawScatterChart() { 42 | var data = [{ 43 | x: 95, 44 | y: 95, 45 | z: 13.8, 46 | name: 'BE', 47 | country: 'Belgium' 48 | }, { 49 | x: 86.5, 50 | y: 102.9, 51 | z: 14.7, 52 | name: 'DE', 53 | country: 'Germany' 54 | }, { 55 | x: 80.8, 56 | y: 91.5, 57 | z: 15.8, 58 | name: 'FI', 59 | country: 'Finland' 60 | }, { 61 | x: 80.4, 62 | y: 102.5, 63 | z: 12, 64 | name: 'NL', 65 | country: 'Netherlands' 66 | }, { 67 | x: 80.3, 68 | y: 86.1, 69 | z: 11.8, 70 | name: 'SE', 71 | country: 'Sweden' 72 | }, { 73 | x: 78.4, 74 | y: 70.1, 75 | z: 16.6, 76 | name: 'ES', 77 | country: 'Spain' 78 | }, { 79 | x: 74.2, 80 | y: 68.5, 81 | z: 14.5, 82 | name: 'FR', 83 | country: 'France' 84 | }, { 85 | x: 73.5, 86 | y: 83.1, 87 | z: 10, 88 | name: 'NO', 89 | country: 'Norway' 90 | }, { 91 | x: 71, 92 | y: 93.2, 93 | z: 24.7, 94 | name: 'UK', 95 | country: 'United Kingdom' 96 | }, { 97 | x: 69.2, 98 | y: 57.6, 99 | z: 10.4, 100 | name: 'IT', 101 | country: 'Italy' 102 | }, { 103 | x: 68.6, 104 | y: 20, 105 | z: 16, 106 | name: 'RU', 107 | country: 'Russia' 108 | }, { 109 | x: 65.5, 110 | y: 126.4, 111 | z: 35.3, 112 | name: 'US', 113 | country: 'United States' 114 | }, { 115 | x: 65.4, 116 | y: 50.8, 117 | z: 28.5, 118 | name: 'HU', 119 | country: 'Hungary' 120 | }, { 121 | x: 63.4, 122 | y: 51.8, 123 | z: 15.4, 124 | name: 'PT', 125 | country: 'Portugal' 126 | }, { 127 | x: 64, 128 | y: 82.9, 129 | z: 31.3, 130 | name: 'NZ', 131 | country: 'New Zealand' 132 | }]; 133 | var chart = new G2.Chart({ 134 | container: 'container_scatter', 135 | forceFit: true, 136 | padding: [20, 20, 50, 80], 137 | height: 300, 138 | renderer: 'svg', 139 | plotBackground: { 140 | stroke: '#ccc', // 边颜色 141 | lineWidth: 1 // 边框粗细 142 | } // 绘图区域背景设置 143 | }); 144 | chart.source(data, { 145 | x: { 146 | alias: 'Daily fat intake', // 定义别名 147 | tickInterval: 5, // 自定义刻度间距 148 | nice: false, // 不对最大最小值优化 149 | max: 96, // 自定义最大值 150 | min: 62 // 自定义最小是 151 | }, 152 | y: { 153 | alias: 'Daily sugar intake', 154 | tickInterval: 50, 155 | nice: false, 156 | max: 165, 157 | min: 0 158 | }, 159 | z: { 160 | alias: 'Obesity(adults) %' 161 | } 162 | }); 163 | // 开始配置坐标轴 164 | chart.axis('x', { 165 | label: { 166 | formatter: function formatter(val) { 167 | return val + ' gr'; // 格式化坐标轴显示文本 168 | } 169 | }, 170 | grid: { 171 | lineStyle: { 172 | stroke: '#d9d9d9', 173 | lineWidth: 1, 174 | lineDash: [2, 2] 175 | } 176 | } 177 | }); 178 | chart.axis('y', { 179 | title: { 180 | offset: 64 181 | }, 182 | label: { 183 | formatter: function formatter(val) { 184 | if (val > 0) { 185 | return val + ' gr'; 186 | } 187 | } 188 | } 189 | }); 190 | chart.legend(false); 191 | chart.tooltip({ 192 | title: 'country' 193 | }); 194 | chart.point().position('x*y').color('#1890ff').size('z', [10, 40]).label('name*country', { 195 | offset: 0, // 文本距离图形的距离 196 | textStyle: { 197 | fill: '#1890FF' 198 | } 199 | }).opacity(0.3).shape('circle').tooltip('x*y*z').style({ 200 | lineWidth: 1, 201 | stroke: '#1890ff' 202 | }); 203 | chart.guide().line({ 204 | top: true, 205 | start: [65, 'min'], 206 | end: [65, 'max'], 207 | text: { 208 | content: 'Safe fat intake 65g/day', 209 | position: 'end', 210 | autoRotate: false, 211 | style: { 212 | textAlign: 'start' 213 | } 214 | } 215 | }); 216 | chart.guide().line({ 217 | top: true, 218 | start: ['min', 50], 219 | end: ['max', 50], 220 | text: { 221 | content: 'Safe sugar intake 50g/day', 222 | position: 'end', 223 | style: { 224 | textAlign: 'end' 225 | } 226 | } 227 | }); 228 | chart.render(); 229 | } 230 | 231 | function drawPieChart() { 232 | var data = [{ 233 | year: '2001', 234 | population: 41.8 235 | }, { 236 | year: '2002', 237 | population: 38 238 | }, { 239 | year: '2003', 240 | population: 33.7 241 | }, { 242 | year: '2004', 243 | population: 30.7 244 | }, { 245 | year: '2005', 246 | population: 25.8 247 | }, { 248 | year: '2006', 249 | population: 31.7 250 | }, { 251 | year: '2007', 252 | population: 33 253 | }, { 254 | year: '2008', 255 | population: 46 256 | }, { 257 | year: '2009', 258 | population: 38.3 259 | }, { 260 | year: '2010', 261 | population: 28 262 | }, { 263 | year: '2011', 264 | population: 42.5 265 | }, { 266 | year: '2012', 267 | population: 30.3 268 | }]; 269 | 270 | var chart = new G2.Chart({ 271 | container: 'container_pie', 272 | forceFit: true, 273 | height: 300, 274 | renderer: 'svg', 275 | }); 276 | chart.source(data); 277 | chart.coord('polar'); 278 | chart.legend({ 279 | position: 'right', 280 | offsetY: -window.innerHeight / 2 + 280, 281 | offsetX: -140 282 | }); 283 | chart.axis(false); 284 | chart.interval().position('year*population').color('year', G2.Global.colors_pie_16).style({ 285 | lineWidth: 1, 286 | stroke: '#fff' 287 | }); 288 | chart.render(); 289 | } 290 | 291 | function drawLineChart() { 292 | var data = [{ 293 | month: 'Jan', 294 | Tokyo: 7.0, 295 | London: 3.9 296 | }, { 297 | month: 'Feb', 298 | Tokyo: 6.9, 299 | London: 4.2 300 | }, { 301 | month: 'Mar', 302 | Tokyo: 9.5, 303 | London: 5.7 304 | }, { 305 | month: 'Apr', 306 | Tokyo: 14.5, 307 | London: 8.5 308 | }, { 309 | month: 'May', 310 | Tokyo: 18.4, 311 | London: 11.9 312 | }, { 313 | month: 'Jun', 314 | Tokyo: 21.5, 315 | London: 15.2 316 | }, { 317 | month: 'Jul', 318 | Tokyo: 25.2, 319 | London: 17.0 320 | }, { 321 | month: 'Aug', 322 | Tokyo: 26.5, 323 | London: 16.6 324 | }, { 325 | month: 'Sep', 326 | Tokyo: 23.3, 327 | London: 14.2 328 | }, { 329 | month: 'Oct', 330 | Tokyo: 18.3, 331 | London: 10.3 332 | }, { 333 | month: 'Nov', 334 | Tokyo: 13.9, 335 | London: 6.6 336 | }, { 337 | month: 'Dec', 338 | Tokyo: 9.6, 339 | London: 4.8 340 | }]; 341 | var ds = new DataSet(); 342 | var dv = ds.createView().source(data); 343 | // fold 方式完成了行列转换,如果不想使用 DataSet 直接手工转换数据即可 344 | dv.transform({ 345 | type: 'fold', 346 | fields: ['Tokyo', 'London'], // 展开字段集 347 | key: 'city', // key字段 348 | value: 'temperature' // value字段 349 | }); 350 | var chart = new G2.Chart({ 351 | container: 'container_line', 352 | forceFit: true, 353 | height: 300, 354 | renderer: 'svg', 355 | }); 356 | chart.source(dv, { 357 | month: { 358 | range: [0, 1] 359 | } 360 | }); 361 | chart.tooltip({ 362 | crosshairs: { 363 | type: 'line' 364 | } 365 | }); 366 | chart.axis('temperature', { 367 | label: { 368 | formatter: function formatter(val) { 369 | return val + '°C'; 370 | } 371 | } 372 | }); 373 | chart.line().position('month*temperature').color('city').shape('smooth'); 374 | chart.point().position('month*temperature').color('city').size(4).shape('circle').style({ 375 | stroke: '#fff', 376 | lineWidth: 1 377 | }); 378 | chart.render(); 379 | } 380 | 381 | function drawRadarChart() { 382 | var _DataSet = DataSet, 383 | DataView = _DataSet.DataView; 384 | 385 | var data = [{ 386 | item: 'Design', 387 | a: 70, 388 | b: 30 389 | }, { 390 | item: 'Development', 391 | a: 60, 392 | b: 70 393 | }, { 394 | item: 'Marketing', 395 | a: 50, 396 | b: 60 397 | }, { 398 | item: 'Users', 399 | a: 40, 400 | b: 50 401 | }, { 402 | item: 'Test', 403 | a: 60, 404 | b: 70 405 | }, { 406 | item: 'Language', 407 | a: 70, 408 | b: 50 409 | }, { 410 | item: 'Technology', 411 | a: 50, 412 | b: 40 413 | }, { 414 | item: 'Support', 415 | a: 30, 416 | b: 40 417 | }, { 418 | item: 'Sales', 419 | a: 60, 420 | b: 40 421 | }, { 422 | item: 'UX', 423 | a: 50, 424 | b: 60 425 | }]; 426 | var dv = new DataView().source(data); 427 | dv.transform({ 428 | type: 'fold', 429 | fields: ['a', 'b'], // 展开字段集 430 | key: 'user', // key字段 431 | value: 'score' // value字段 432 | }); 433 | var chart = new G2.Chart({ 434 | container: 'container_radar', 435 | forceFit: true, 436 | height: 300, 437 | renderer: 'svg', 438 | padding: [20, 20, 95, 20] 439 | }); 440 | chart.source(dv, { 441 | score: { 442 | min: 0, 443 | max: 80 444 | } 445 | }); 446 | chart.coord('polar', { 447 | radius: 0.8 448 | }); 449 | chart.axis('item', { 450 | line: null, 451 | tickLine: null, 452 | grid: { 453 | lineStyle: { 454 | lineDash: null 455 | }, 456 | hideFirstLine: false 457 | } 458 | }); 459 | chart.axis('score', { 460 | line: null, 461 | tickLine: null, 462 | grid: { 463 | type: 'polygon', 464 | lineStyle: { 465 | lineDash: null 466 | } 467 | } 468 | }); 469 | chart.legend('user', { 470 | marker: 'circle', 471 | offset: 30 472 | }); 473 | chart.line().position('item*score').color('user').size(2); 474 | chart.point().position('item*score').color('user').shape('circle').size(4).style({ 475 | stroke: '#fff', 476 | lineWidth: 1, 477 | fillOpacity: 1 478 | }); 479 | chart.area().position('item*score').color('user'); 480 | chart.render(); 481 | } 482 | 483 | function drawFunnelChart() { 484 | var _DataSet = DataSet, 485 | DataView = _DataSet.DataView; 486 | 487 | var data = [{ 488 | action: 'A', 489 | pv: 50000 490 | }, { 491 | action: 'B', 492 | pv: 35000 493 | }, { 494 | action: 'C', 495 | pv: 25000 496 | }, { 497 | action: 'D', 498 | pv: 15000 499 | }, { 500 | action: 'E', 501 | pv: 8000 502 | }]; 503 | var dv = new DataView().source(data); 504 | dv.transform({ 505 | type: 'map', 506 | callback: function callback(row) { 507 | row.percent = row.pv / 50000; 508 | return row; 509 | } 510 | }); 511 | data = dv.rows; 512 | var chart = new G2.Chart({ 513 | container: 'container_funnel', 514 | forceFit: true, 515 | height: 300, 516 | renderer: 'svg', 517 | padding: [20, 120, 95] 518 | }); 519 | chart.source(data, { 520 | percent: { 521 | nice: false 522 | } 523 | }); 524 | chart.axis(false); 525 | chart.tooltip({ 526 | showTitle: false, 527 | itemTpl: '
  • ' + '' + '{name}
    ' + '浏览人数:{pv}
    ' + '占比:{percent}
    ' + '
  • ' 528 | }); 529 | chart.coord('rect').transpose().scale(1, -1); 530 | chart.intervalSymmetric().position('action*percent').shape('funnel').color('action', ['#0050B3', '#1890FF', '#40A9FF', '#69C0FF', '#BAE7FF']).label('action*pv', function(action, pv) { 531 | return action + ' ' + pv; 532 | }, { 533 | offset: 35, 534 | labelLine: { 535 | lineWidth: 1, 536 | stroke: 'rgba(0, 0, 0, 0.15)' 537 | } 538 | }).tooltip('action*pv*percent', function(action, pv, percent) { 539 | return { 540 | name: action, 541 | percent: parseInt(percent * 100) + '%', 542 | pv: pv 543 | }; 544 | }); 545 | data.forEach(function(obj) { 546 | // 中间标签文本 547 | chart.guide().text({ 548 | top: true, 549 | position: { 550 | action: obj.action, 551 | percent: 'median' 552 | }, 553 | content: parseInt(obj.percent * 100) + '%', // 显示的文本内容 554 | style: { 555 | fill: '#fff', 556 | fontSize: '12', 557 | textAlign: 'center', 558 | shadowBlur: 2, 559 | shadowColor: 'rgba(0, 0, 0, .45)' 560 | } 561 | }); 562 | }); 563 | chart.render(); 564 | } 565 | 566 | function drawChart() { 567 | drawBarChart(); 568 | drawScatterChart(); 569 | drawPieChart(); 570 | drawLineChart(); 571 | drawRadarChart(); 572 | drawFunnelChart(); 573 | } 574 | 575 | function getHandler() { 576 | const option = { 577 | fillStyle: $('#fillStyleSelector').children('option:selected').val(), 578 | bowing: $('#bowingRange').val(), 579 | roughness: $('#roughnessRange').val() 580 | }; 581 | 582 | const container = $('#charts')[0]; 583 | return handler = Sketchifier(container, option); 584 | } 585 | 586 | $(function() { 587 | drawChart(); 588 | var handler = getHandler(); 589 | 590 | function updateHandler() { 591 | handler.restore(); 592 | handler = getHandler(); 593 | if ($('#handifyChecker').prop('checked')) { 594 | handler.handify(); 595 | } 596 | } 597 | 598 | $('#fillStyleSelector').change(function() { 599 | updateHandler(); 600 | }) 601 | 602 | $('#bowingRange').change(function() { 603 | updateHandler(); 604 | }) 605 | 606 | $('#roughnessRange').change(function() { 607 | updateHandler(); 608 | }) 609 | 610 | $('#handifyChecker').change(function() { 611 | if (this.checked) { 612 | handler.handify(); 613 | } else { 614 | handler.restore(); 615 | } 616 | }); 617 | }); -------------------------------------------------------------------------------- /demo/highcharts.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | sketchify 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
    19 |
    20 |
    21 | 22 |
    23 | 24 | 34 | 35 | 36 | 37 | 38 |
    39 |
    40 |
    41 |
    42 |
    43 |
    44 |
    45 |
    46 |
    47 |
    48 |
    49 | 50 | -------------------------------------------------------------------------------- /demo/highcharts.js: -------------------------------------------------------------------------------- 1 | function drawBarChart() { 2 | Highcharts.chart('container_bar', { 3 | 4 | chart: { 5 | type: 'column' 6 | }, 7 | 8 | title: { 9 | text: 'Total fruit consumtion, grouped by gender' 10 | }, 11 | 12 | xAxis: { 13 | categories: ['Apples', 'Oranges', 'Pears', 'Grapes', 'Bananas'] 14 | }, 15 | 16 | yAxis: { 17 | allowDecimals: false, 18 | min: 0, 19 | title: { 20 | text: 'Number of fruits' 21 | } 22 | }, 23 | 24 | tooltip: { 25 | formatter: function() { 26 | return '' + this.x + '
    ' + 27 | this.series.name + ': ' + this.y + '
    ' + 28 | 'Total: ' + this.point.stackTotal; 29 | } 30 | }, 31 | 32 | plotOptions: { 33 | column: { 34 | stacking: 'normal' 35 | } 36 | }, 37 | 38 | series: [{ 39 | name: 'John', 40 | data: [5, 3, 4, 7, 2], 41 | stack: 'male' 42 | }, { 43 | name: 'Joe', 44 | data: [3, 4, 4, 2, 5], 45 | stack: 'male' 46 | }, { 47 | name: 'Jane', 48 | data: [2, 5, 6, 2, 1], 49 | stack: 'female' 50 | }, { 51 | name: 'Janet', 52 | data: [3, 0, 4, 4, 3], 53 | stack: 'female' 54 | }] 55 | }); 56 | } 57 | 58 | function drawScatterChart() { 59 | Highcharts.chart('container_scatter', { 60 | 61 | chart: { 62 | type: 'bubble', 63 | plotBorderWidth: 1, 64 | zoomType: 'xy' 65 | }, 66 | 67 | legend: { 68 | enabled: false 69 | }, 70 | 71 | title: { 72 | text: 'Sugar and fat intake per country' 73 | }, 74 | 75 | subtitle: { 76 | text: 'Source: Euromonitor and OECD' 77 | }, 78 | 79 | xAxis: { 80 | gridLineWidth: 1, 81 | title: { 82 | text: 'Daily fat intake' 83 | }, 84 | labels: { 85 | format: '{value} gr' 86 | }, 87 | plotLines: [{ 88 | color: 'black', 89 | dashStyle: 'dot', 90 | width: 2, 91 | value: 65, 92 | label: { 93 | rotation: 0, 94 | y: 15, 95 | style: { 96 | fontStyle: 'italic' 97 | }, 98 | text: 'Safe fat intake 65g/day' 99 | }, 100 | zIndex: 3 101 | }] 102 | }, 103 | 104 | yAxis: { 105 | startOnTick: false, 106 | endOnTick: false, 107 | title: { 108 | text: 'Daily sugar intake' 109 | }, 110 | labels: { 111 | format: '{value} gr' 112 | }, 113 | maxPadding: 0.2, 114 | plotLines: [{ 115 | color: 'black', 116 | dashStyle: 'dot', 117 | width: 2, 118 | value: 50, 119 | label: { 120 | align: 'right', 121 | style: { 122 | fontStyle: 'italic' 123 | }, 124 | text: 'Safe sugar intake 50g/day', 125 | x: -10 126 | }, 127 | zIndex: 3 128 | }] 129 | }, 130 | 131 | tooltip: { 132 | useHTML: true, 133 | headerFormat: '', 134 | pointFormat: '' + 135 | '' + 136 | '' + 137 | '', 138 | footerFormat: '

    {point.country}

    Fat intake:{point.x}g
    Sugar intake:{point.y}g
    Obesity (adults):{point.z}%
    ', 139 | followPointer: true 140 | }, 141 | 142 | plotOptions: { 143 | series: { 144 | dataLabels: { 145 | enabled: true, 146 | format: '{point.name}' 147 | } 148 | } 149 | }, 150 | 151 | series: [{ 152 | data: [{ 153 | x: 95, 154 | y: 95, 155 | z: 13.8, 156 | name: 'BE', 157 | country: 'Belgium' 158 | }, { 159 | x: 86.5, 160 | y: 102.9, 161 | z: 14.7, 162 | name: 'DE', 163 | country: 'Germany' 164 | }, { 165 | x: 80.8, 166 | y: 91.5, 167 | z: 15.8, 168 | name: 'FI', 169 | country: 'Finland' 170 | }, { 171 | x: 80.4, 172 | y: 102.5, 173 | z: 12, 174 | name: 'NL', 175 | country: 'Netherlands' 176 | }, { 177 | x: 80.3, 178 | y: 86.1, 179 | z: 11.8, 180 | name: 'SE', 181 | country: 'Sweden' 182 | }, { 183 | x: 78.4, 184 | y: 70.1, 185 | z: 16.6, 186 | name: 'ES', 187 | country: 'Spain' 188 | }, { 189 | x: 74.2, 190 | y: 68.5, 191 | z: 14.5, 192 | name: 'FR', 193 | country: 'France' 194 | }, { 195 | x: 73.5, 196 | y: 83.1, 197 | z: 10, 198 | name: 'NO', 199 | country: 'Norway' 200 | }, { 201 | x: 71, 202 | y: 93.2, 203 | z: 24.7, 204 | name: 'UK', 205 | country: 'United Kingdom' 206 | }, { 207 | x: 69.2, 208 | y: 57.6, 209 | z: 10.4, 210 | name: 'IT', 211 | country: 'Italy' 212 | }, { 213 | x: 68.6, 214 | y: 20, 215 | z: 16, 216 | name: 'RU', 217 | country: 'Russia' 218 | }, { 219 | x: 65.5, 220 | y: 126.4, 221 | z: 35.3, 222 | name: 'US', 223 | country: 'United States' 224 | }, { 225 | x: 65.4, 226 | y: 50.8, 227 | z: 28.5, 228 | name: 'HU', 229 | country: 'Hungary' 230 | }, { 231 | x: 63.4, 232 | y: 51.8, 233 | z: 15.4, 234 | name: 'PT', 235 | country: 'Portugal' 236 | }, { 237 | x: 64, 238 | y: 82.9, 239 | z: 31.3, 240 | name: 'NZ', 241 | country: 'New Zealand' 242 | }] 243 | }] 244 | 245 | }); 246 | } 247 | 248 | function drawPieChart() { 249 | Highcharts.chart('container_pie', { 250 | chart: { 251 | plotBackgroundColor: null, 252 | plotBorderWidth: null, 253 | plotShadow: false, 254 | type: 'pie' 255 | }, 256 | title: { 257 | text: 'Browser market shares in January, 2018' 258 | }, 259 | tooltip: { 260 | pointFormat: '{series.name}: {point.percentage:.1f}%' 261 | }, 262 | plotOptions: { 263 | pie: { 264 | allowPointSelect: true, 265 | cursor: 'pointer', 266 | dataLabels: { 267 | enabled: true, 268 | format: '{point.name}: {point.percentage:.1f} %' 269 | } 270 | } 271 | }, 272 | series: [{ 273 | name: 'Brands', 274 | colorByPoint: true, 275 | data: [{ 276 | name: 'Chrome', 277 | y: 61.41, 278 | sliced: true, 279 | selected: true 280 | }, { 281 | name: 'Internet Explorer', 282 | y: 11.84 283 | }, { 284 | name: 'Firefox', 285 | y: 10.85 286 | }, { 287 | name: 'Edge', 288 | y: 4.67 289 | }, { 290 | name: 'Safari', 291 | y: 4.18 292 | }, { 293 | name: 'Sogou Explorer', 294 | y: 1.64 295 | }, { 296 | name: 'Opera', 297 | y: 1.6 298 | }, { 299 | name: 'QQ', 300 | y: 1.2 301 | }, { 302 | name: 'Other', 303 | y: 2.61 304 | }] 305 | }] 306 | }); 307 | } 308 | 309 | function drawLineChart() { 310 | Highcharts.chart('container_line', { 311 | 312 | title: { 313 | text: 'Solar Employment Growth by Sector, 2010-2016' 314 | }, 315 | 316 | subtitle: { 317 | text: 'Source: thesolarfoundation.com' 318 | }, 319 | 320 | yAxis: { 321 | title: { 322 | text: 'Number of Employees' 323 | } 324 | }, 325 | legend: { 326 | layout: 'vertical', 327 | align: 'right', 328 | verticalAlign: 'middle' 329 | }, 330 | 331 | plotOptions: { 332 | series: { 333 | label: { 334 | connectorAllowed: false 335 | }, 336 | pointStart: 2010 337 | } 338 | }, 339 | 340 | series: [{ 341 | name: 'Installation', 342 | data: [43934, 52503, 57177, 69658, 97031, 119931, 137133, 154175] 343 | }, { 344 | name: 'Manufacturing', 345 | data: [24916, 24064, 29742, 29851, 32490, 30282, 38121, 40434] 346 | }, { 347 | name: 'Sales & Distribution', 348 | data: [11744, 17722, 16005, 19771, 20185, 24377, 32147, 39387] 349 | }, { 350 | name: 'Project Development', 351 | data: [null, null, 7988, 12169, 15112, 22452, 34400, 34227] 352 | }, { 353 | name: 'Other', 354 | data: [12908, 5948, 8105, 11248, 8989, 11816, 18274, 18111] 355 | }], 356 | 357 | responsive: { 358 | rules: [{ 359 | condition: { 360 | maxWidth: 500 361 | }, 362 | chartOptions: { 363 | legend: { 364 | layout: 'horizontal', 365 | align: 'center', 366 | verticalAlign: 'bottom' 367 | } 368 | } 369 | }] 370 | } 371 | 372 | }); 373 | } 374 | 375 | function drawRadarChart() { 376 | Highcharts.chart('container_radar', { 377 | 378 | chart: { 379 | polar: true, 380 | type: 'line' 381 | }, 382 | 383 | accessibility: { 384 | description: 'A spiderweb chart compares the allocated budget against actual spending within an organization. The spider chart has six spokes. Each spoke represents one of the 6 departments within the organization: sales, marketing, development, customer support, information technology and administration. The chart is interactive, and each data point is displayed upon hovering. The chart clearly shows that 4 of the 6 departments have overspent their budget with Marketing responsible for the greatest overspend of $20,000. The allocated budget and actual spending data points for each department are as follows: Sales. Budget equals $43,000; spending equals $50,000. Marketing. Budget equals $19,000; spending equals $39,000. Development. Budget equals $60,000; spending equals $42,000. Customer support. Budget equals $35,000; spending equals $31,000. Information technology. Budget equals $17,000; spending equals $26,000. Administration. Budget equals $10,000; spending equals $14,000.' 385 | }, 386 | 387 | title: { 388 | text: 'Budget vs spending', 389 | x: -80 390 | }, 391 | 392 | pane: { 393 | size: '80%' 394 | }, 395 | 396 | xAxis: { 397 | categories: ['Sales', 'Marketing', 'Development', 'Customer Support', 398 | 'Information Technology', 'Administration' 399 | ], 400 | tickmarkPlacement: 'on', 401 | lineWidth: 0 402 | }, 403 | 404 | yAxis: { 405 | gridLineInterpolation: 'polygon', 406 | lineWidth: 0, 407 | min: 0 408 | }, 409 | 410 | tooltip: { 411 | shared: true, 412 | pointFormat: '{series.name}: ${point.y:,.0f}
    ' 413 | }, 414 | 415 | legend: { 416 | align: 'right', 417 | verticalAlign: 'middle' 418 | }, 419 | 420 | series: [{ 421 | name: 'Allocated Budget', 422 | data: [43000, 19000, 60000, 35000, 17000, 10000], 423 | pointPlacement: 'on' 424 | }, { 425 | name: 'Actual Spending', 426 | data: [50000, 39000, 42000, 31000, 26000, 14000], 427 | pointPlacement: 'on' 428 | }], 429 | 430 | responsive: { 431 | rules: [{ 432 | condition: { 433 | maxWidth: 500 434 | }, 435 | chartOptions: { 436 | legend: { 437 | align: 'center', 438 | verticalAlign: 'bottom' 439 | }, 440 | pane: { 441 | size: '70%' 442 | } 443 | } 444 | }] 445 | } 446 | 447 | }); 448 | } 449 | 450 | function drawFunnelChart() { 451 | Highcharts.chart('container_funnel', { 452 | chart: { 453 | type: 'funnel' 454 | }, 455 | title: { 456 | text: 'Sales funnel' 457 | }, 458 | plotOptions: { 459 | series: { 460 | dataLabels: { 461 | enabled: true, 462 | format: '{point.name} ({point.y:,.0f})', 463 | softConnector: true 464 | }, 465 | center: ['40%', '50%'], 466 | neckWidth: '30%', 467 | neckHeight: '25%', 468 | width: '80%' 469 | } 470 | }, 471 | legend: { 472 | enabled: false 473 | }, 474 | series: [{ 475 | name: 'Unique users', 476 | data: [ 477 | ['Website visits', 15654], 478 | ['Downloads', 4064], 479 | ['Requested price list', 1987], 480 | ['Invoice sent', 976], 481 | ['Finalized', 846] 482 | ] 483 | }], 484 | 485 | responsive: { 486 | rules: [{ 487 | condition: { 488 | maxWidth: 500 489 | }, 490 | chartOptions: { 491 | plotOptions: { 492 | series: { 493 | dataLabels: { 494 | inside: true 495 | }, 496 | center: ['50%', '50%'], 497 | width: '100%' 498 | } 499 | } 500 | } 501 | }] 502 | } 503 | }); 504 | } 505 | 506 | function drawChart() { 507 | drawBarChart(); 508 | drawScatterChart(); 509 | drawPieChart(); 510 | drawLineChart(); 511 | drawRadarChart(); 512 | drawFunnelChart(); 513 | } 514 | 515 | function getHandler() { 516 | const option = { 517 | chartType: 'highcharts', 518 | fillStyle: $('#fillStyleSelector').children('option:selected').val(), 519 | bowing: $('#bowingRange').val(), 520 | roughness: $('#roughnessRange').val() 521 | }; 522 | 523 | const container = $('#charts')[0]; 524 | return handler = Sketchifier(container, option); 525 | } 526 | 527 | $(function() { 528 | drawChart(); 529 | var handler = getHandler(); 530 | 531 | function updateHandler() { 532 | handler.restore(); 533 | handler = getHandler(); 534 | if ($('#handifyChecker').prop('checked')) { 535 | handler.handify(); 536 | } 537 | } 538 | 539 | $('#fillStyleSelector').change(function() { 540 | updateHandler(); 541 | }) 542 | 543 | $('#bowingRange').change(function() { 544 | updateHandler(); 545 | }) 546 | 547 | $('#roughnessRange').change(function() { 548 | updateHandler(); 549 | }) 550 | 551 | $('#handifyChecker').change(function() { 552 | if (this.checked) { 553 | handler.handify(); 554 | } else { 555 | handler.restore(); 556 | } 557 | }); 558 | }); -------------------------------------------------------------------------------- /demo/xcharts.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | sketchify 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
    19 |
    20 |
    21 | 22 |
    23 | 24 | 34 | 35 | 36 | 37 | 38 |
    39 |
    40 |
    41 |
    42 |
    43 |
    44 |
    45 |
    46 |
    47 |
    48 |
    49 | 50 | -------------------------------------------------------------------------------- /demo/xcharts.js: -------------------------------------------------------------------------------- 1 | function drawBarChart() { 2 | const chart = xCharts(document.querySelector('#container_bar')); 3 | option = { 4 | title: { 5 | text: 'Barchart' 6 | }, 7 | tooltip: { 8 | show: true, 9 | trigger: 'axis' 10 | }, 11 | legend: { 12 | x: 'center', 13 | y: 'bottom', 14 | show: true, 15 | data: ['Li', 'Han'] 16 | }, 17 | xAxis: [{ 18 | type: 'category', 19 | data: ['A', 'B', 'C', 'D', 'E', 'F'] 20 | }], 21 | yAxis: [{ 22 | type: 'value', 23 | maxValue: 100, 24 | minValue: 0 25 | }], 26 | resize: { 27 | enable: true 28 | }, 29 | animation: { 30 | enable: true 31 | }, 32 | series: [{ 33 | name: 'Li', 34 | type: 'bar', 35 | data: [10, 20, 30, 40, 50, 60] 36 | }, { 37 | name: 'Han', 38 | type: 'bar', 39 | data: [60, 50, 40, 30, 20, 10], 40 | formatter: function(name, value) { 41 | var htmlStr = ''; 42 | htmlStr += '
    ' + name + ':' + value + 'Score
    '; 43 | return htmlStr; 44 | } 45 | }] 46 | }; 47 | chart.loadConfig(option); 48 | } 49 | 50 | function drawScatterChart() { 51 | const chart = xCharts(document.querySelector('#container_scatter')); 52 | option = { 53 | title: { 54 | text: 'Scatter' 55 | }, 56 | legend: { 57 | data: ['Female', 'Male'], 58 | x: 'center' 59 | }, 60 | tooltip: { 61 | trigger: 'axis' 62 | }, 63 | xAxis: [{ 64 | type: 'value', 65 | tickFormat: function(data) { 66 | return data + ' cm'; 67 | } 68 | }], 69 | yAxis: [{ 70 | type: 'value', 71 | tickFormat: function(data) { 72 | return data + ' kg'; 73 | } 74 | }], 75 | resize: { 76 | enable: true 77 | }, 78 | animation: { 79 | enable: true 80 | }, 81 | series: [{ 82 | name: 'Female', 83 | type: 'scatter', 84 | size: 30, 85 | data: [ 86 | [161.2, 51.6], 87 | [167.5, 59.0], 88 | [159.5, 49.2], 89 | [157.0, 63.0], 90 | [155.8, 53.6], 91 | [170.0, 59.0], 92 | [159.1, 47.6], 93 | [166.0, 69.8], 94 | [176.2, 66.8], 95 | [160.2, 75.2] 96 | ] 97 | }, { 98 | name: 'Male', 99 | type: 'scatter', 100 | size: 30, 101 | data: [ 102 | [174.0, 65.6], 103 | [175.3, 71.8], 104 | [193.5, 80.7], 105 | [186.5, 72.6], 106 | [187.2, 78.8], 107 | [181.5, 74.8], 108 | [184.0, 86.4], 109 | [184.5, 78.4], 110 | [175.0, 62.0], 111 | [184.0, 81.6] 112 | ] 113 | }] 114 | }; 115 | chart.loadConfig(option); 116 | } 117 | 118 | function drawPieChart() { 119 | const chart = xCharts(document.querySelector('#container_pie')); 120 | option = { 121 | title: { 122 | text: 'Pie' 123 | }, 124 | tooltip: { 125 | show: true 126 | }, 127 | legend: { 128 | orient: 'vertical', 129 | x: 'right', 130 | show: true, 131 | data: ['section1', 'section2', 'section3', 'section4', 'section5', 'section6'] 132 | }, 133 | resize: { 134 | enable: true 135 | }, 136 | animation: { 137 | enable: true 138 | }, 139 | series: [{ 140 | type: 'pie', 141 | center: ['50%', '50%'], 142 | radius: { 143 | outerRadius: '30%', 144 | innerRadius: 0 145 | }, 146 | data: [{ 147 | name: 'section1', 148 | value: 10 149 | }, { 150 | name: 'section2', 151 | value: 20 152 | }, { 153 | name: 'section3', 154 | value: 30 155 | }, { 156 | name: 'section4', 157 | value: 40 158 | }, { 159 | name: 'section5', 160 | value: 50 161 | }, { 162 | name: 'section6', 163 | value: 60 164 | }] 165 | }] 166 | }; 167 | chart.loadConfig(option); 168 | } 169 | 170 | function drawLineChart() { 171 | const chart = xCharts(document.querySelector('#container_line')); 172 | option = { 173 | title: { 174 | text: 'Area' 175 | }, 176 | legend: { 177 | data: ['Apple', 'Orange'], 178 | x: 'center' 179 | }, 180 | tooltip: { 181 | trigger: 'axis' 182 | }, 183 | xAxis: [{ 184 | type: 'category', 185 | data: ['1', '2', '3', '4', '5', '6', '7'], 186 | tickFormat: function(data) { 187 | return 'week' + data; 188 | } 189 | }], 190 | yAxis: [{ 191 | type: 'value' 192 | }], 193 | resize: { 194 | enable: true 195 | }, 196 | animation: { 197 | enable: true 198 | }, 199 | series: [{ 200 | type: 'line', 201 | name: 'Apple', 202 | data: [100, 200, 300, 300, 350, 400, 450], 203 | areaStyle: { 204 | show: true 205 | }, 206 | stack: 'sales' 207 | }, { 208 | type: 'line', 209 | name: 'Orange', 210 | data: [500, 400, 200, 200, 150, 200, 250], 211 | areaStyle: { 212 | show: true 213 | }, 214 | stack: 'sales' 215 | }] 216 | }; 217 | chart.loadConfig(option); 218 | } 219 | 220 | function drawRadarChart() { 221 | const chart = xCharts(document.querySelector('#container_radar')); 222 | option = { 223 | title: { 224 | text: 'Radar' 225 | }, 226 | tooltip: { 227 | show: true 228 | }, 229 | legend: { 230 | orient: 'vertical', 231 | x: 'right', 232 | show: true, 233 | data: ['Li', 'Han'] 234 | }, 235 | resize: { 236 | enable: true 237 | }, 238 | animation: { 239 | enable: true 240 | }, 241 | series: [{ 242 | type: 'radar', 243 | levels: 4, 244 | radius: '25%', 245 | fill: false, 246 | center: ['50%', '50%'], 247 | indicator: [{ 248 | text: 'A', 249 | max: 100, 250 | min: 0 251 | }, { 252 | text: 'B', 253 | max: 100, 254 | min: 0 255 | }, { 256 | text: 'C', 257 | max: 100, 258 | min: 0 259 | }, { 260 | text: 'D', 261 | max: 100, 262 | min: 0 263 | }, { 264 | text: 'E', 265 | max: 100, 266 | min: 0 267 | }, { 268 | text: 'F', 269 | max: 100, 270 | min: 0 271 | }], 272 | data: [{ 273 | name: 'Li', 274 | value: [10, 20, 30, 40, 50, 60] 275 | }, { 276 | name: 'Han', 277 | value: [80, 70, 60, 50, 40, 30] 278 | }] 279 | }] 280 | }; 281 | chart.loadConfig(option); 282 | } 283 | 284 | function drawFunnelChart() { 285 | const chart = xCharts(document.querySelector('#container_funnel')); 286 | option = { 287 | tooltip: { 288 | trigger: 'item' 289 | }, 290 | legend: { 291 | show: true, 292 | data: ['A', 'B', 'C', 'D', 'E'], 293 | x: 'center' 294 | }, 295 | title: { 296 | text: 'Funnel' 297 | }, 298 | resize: { 299 | enable: true 300 | }, 301 | animation: { 302 | enable: true 303 | }, 304 | series: [{ 305 | name: 'sample', 306 | size: ['50%', '70%'], 307 | type: 'funnel', 308 | data: [{ 309 | name: 'A', 310 | value: '80' 311 | }, { 312 | name: 'B', 313 | value: '100' 314 | }, { 315 | name: 'C', 316 | value: '60' 317 | }, { 318 | name: 'D', 319 | value: '40' 320 | }, { 321 | name: 'E', 322 | value: '20' 323 | }, ] 324 | }] 325 | }; 326 | chart.loadConfig(option); 327 | } 328 | 329 | function drawChart() { 330 | drawBarChart(); 331 | drawScatterChart(); 332 | drawPieChart(); 333 | drawLineChart(); 334 | drawRadarChart(); 335 | drawFunnelChart(); 336 | } 337 | 338 | function getHandler() { 339 | const option = { 340 | chartType: 'xcharts', 341 | fillStyle: $('#fillStyleSelector').children('option:selected').val(), 342 | bowing: $('#bowingRange').val(), 343 | roughness: $('#roughnessRange').val() 344 | }; 345 | 346 | const container = $('#charts')[0]; 347 | return handler = Sketchifier(container, option); 348 | } 349 | 350 | $(function() { 351 | drawChart(); 352 | var handler = getHandler(); 353 | 354 | function updateHandler() { 355 | handler.restore(); 356 | handler = getHandler(); 357 | if ($('#handifyChecker').prop('checked')) { 358 | handler.handify(); 359 | } 360 | } 361 | 362 | $('#fillStyleSelector').change(function() { 363 | updateHandler(); 364 | }) 365 | 366 | $('#bowingRange').change(function() { 367 | updateHandler(); 368 | }) 369 | 370 | $('#roughnessRange').change(function() { 371 | updateHandler(); 372 | }) 373 | 374 | $('#handifyChecker').change(function() { 375 | if (this.checked) { 376 | handler.handify(); 377 | } else { 378 | handler.restore(); 379 | } 380 | }); 381 | }); -------------------------------------------------------------------------------- /dist/sketchify.js: -------------------------------------------------------------------------------- 1 | /******/ (function(modules) { // webpackBootstrap 2 | /******/ // The module cache 3 | /******/ var installedModules = {}; 4 | /******/ 5 | /******/ // The require function 6 | /******/ function __webpack_require__(moduleId) { 7 | /******/ 8 | /******/ // Check if module is in cache 9 | /******/ if(installedModules[moduleId]) { 10 | /******/ return installedModules[moduleId].exports; 11 | /******/ } 12 | /******/ // Create a new module (and put it into the cache) 13 | /******/ var module = installedModules[moduleId] = { 14 | /******/ i: moduleId, 15 | /******/ l: false, 16 | /******/ exports: {} 17 | /******/ }; 18 | /******/ 19 | /******/ // Execute the module function 20 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 21 | /******/ 22 | /******/ // Flag the module as loaded 23 | /******/ module.l = true; 24 | /******/ 25 | /******/ // Return the exports of the module 26 | /******/ return module.exports; 27 | /******/ } 28 | /******/ 29 | /******/ 30 | /******/ // expose the modules object (__webpack_modules__) 31 | /******/ __webpack_require__.m = modules; 32 | /******/ 33 | /******/ // expose the module cache 34 | /******/ __webpack_require__.c = installedModules; 35 | /******/ 36 | /******/ // define getter function for harmony exports 37 | /******/ __webpack_require__.d = function(exports, name, getter) { 38 | /******/ if(!__webpack_require__.o(exports, name)) { 39 | /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); 40 | /******/ } 41 | /******/ }; 42 | /******/ 43 | /******/ // define __esModule on exports 44 | /******/ __webpack_require__.r = function(exports) { 45 | /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { 46 | /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); 47 | /******/ } 48 | /******/ Object.defineProperty(exports, '__esModule', { value: true }); 49 | /******/ }; 50 | /******/ 51 | /******/ // create a fake namespace object 52 | /******/ // mode & 1: value is a module id, require it 53 | /******/ // mode & 2: merge all properties of value into the ns 54 | /******/ // mode & 4: return value when already ns object 55 | /******/ // mode & 8|1: behave like require 56 | /******/ __webpack_require__.t = function(value, mode) { 57 | /******/ if(mode & 1) value = __webpack_require__(value); 58 | /******/ if(mode & 8) return value; 59 | /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; 60 | /******/ var ns = Object.create(null); 61 | /******/ __webpack_require__.r(ns); 62 | /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); 63 | /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); 64 | /******/ return ns; 65 | /******/ }; 66 | /******/ 67 | /******/ // getDefaultExport function for compatibility with non-harmony modules 68 | /******/ __webpack_require__.n = function(module) { 69 | /******/ var getter = module && module.__esModule ? 70 | /******/ function getDefault() { return module['default']; } : 71 | /******/ function getModuleExports() { return module; }; 72 | /******/ __webpack_require__.d(getter, 'a', getter); 73 | /******/ return getter; 74 | /******/ }; 75 | /******/ 76 | /******/ // Object.prototype.hasOwnProperty.call 77 | /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; 78 | /******/ 79 | /******/ // __webpack_public_path__ 80 | /******/ __webpack_require__.p = ""; 81 | /******/ 82 | /******/ 83 | /******/ // Load entry module and return exports 84 | /******/ return __webpack_require__(__webpack_require__.s = "./src/index.js"); 85 | /******/ }) 86 | /************************************************************************/ 87 | /******/ ({ 88 | 89 | /***/ "./node_modules/css-loader/dist/cjs.js!./src/style.css": 90 | /*!*************************************************************!*\ 91 | !*** ./node_modules/css-loader/dist/cjs.js!./src/style.css ***! 92 | \*************************************************************/ 93 | /*! no static exports found */ 94 | /***/ (function(module, exports, __webpack_require__) { 95 | 96 | eval("exports = module.exports = __webpack_require__(/*! ../node_modules/css-loader/dist/runtime/api.js */ \"./node_modules/css-loader/dist/runtime/api.js\")(false);\n// Module\nexports.push([module.i, \".sk-text {\\n font-family: 'Indie Flower', Helvetica, sans-serif, SimSun;\\n}\\n\\n/* latin */\\n@font-face {\\n font-family: 'Shadows Into Light';\\n font-style: normal;\\n font-weight: 400;\\n font-display: swap;\\n src: local('Shadows Into Light'), local('ShadowsIntoLight'), url(https://fonts.gstatic.com/s/shadowsintolight/v9/UqyNK9UOIntux_czAvDQx_ZcHqZXBNQzdcD55TecYQ.woff2) format('woff2');\\n unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;\\n}\\n\\n/* latin */\\n@font-face {\\n font-family: 'Indie Flower';\\n font-style: normal;\\n font-weight: 400;\\n font-display: swap;\\n src: local('Indie Flower'), local('IndieFlower'), url(https://fonts.gstatic.com/s/indieflower/v11/m8JVjfNVeKWVnh3QMuKkFcZVaUuH99GUDg.woff2) format('woff2');\\n unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;\\n}\", \"\"]);\n\n\n//# sourceURL=webpack:///./src/style.css?./node_modules/css-loader/dist/cjs.js"); 97 | 98 | /***/ }), 99 | 100 | /***/ "./node_modules/css-loader/dist/runtime/api.js": 101 | /*!*****************************************************!*\ 102 | !*** ./node_modules/css-loader/dist/runtime/api.js ***! 103 | \*****************************************************/ 104 | /*! no static exports found */ 105 | /***/ (function(module, exports, __webpack_require__) { 106 | 107 | "use strict"; 108 | eval("\n\n/*\n MIT License http://www.opensource.org/licenses/mit-license.php\n Author Tobias Koppers @sokra\n*/\n// css base code, injected by the css-loader\n// eslint-disable-next-line func-names\nmodule.exports = function (useSourceMap) {\n var list = []; // return the list of modules as css string\n\n list.toString = function toString() {\n return this.map(function (item) {\n var content = cssWithMappingToString(item, useSourceMap);\n\n if (item[2]) {\n return \"@media \".concat(item[2], \"{\").concat(content, \"}\");\n }\n\n return content;\n }).join('');\n }; // import a list of modules into the list\n // eslint-disable-next-line func-names\n\n\n list.i = function (modules, mediaQuery) {\n if (typeof modules === 'string') {\n // eslint-disable-next-line no-param-reassign\n modules = [[null, modules, '']];\n }\n\n var alreadyImportedModules = {};\n\n for (var i = 0; i < this.length; i++) {\n // eslint-disable-next-line prefer-destructuring\n var id = this[i][0];\n\n if (id != null) {\n alreadyImportedModules[id] = true;\n }\n }\n\n for (var _i = 0; _i < modules.length; _i++) {\n var item = modules[_i]; // skip already imported module\n // this implementation is not 100% perfect for weird media query combinations\n // when a module is imported multiple times with different media queries.\n // I hope this will never occur (Hey this way we have smaller bundles)\n\n if (item[0] == null || !alreadyImportedModules[item[0]]) {\n if (mediaQuery && !item[2]) {\n item[2] = mediaQuery;\n } else if (mediaQuery) {\n item[2] = \"(\".concat(item[2], \") and (\").concat(mediaQuery, \")\");\n }\n\n list.push(item);\n }\n }\n };\n\n return list;\n};\n\nfunction cssWithMappingToString(item, useSourceMap) {\n var content = item[1] || ''; // eslint-disable-next-line prefer-destructuring\n\n var cssMapping = item[3];\n\n if (!cssMapping) {\n return content;\n }\n\n if (useSourceMap && typeof btoa === 'function') {\n var sourceMapping = toComment(cssMapping);\n var sourceURLs = cssMapping.sources.map(function (source) {\n return \"/*# sourceURL=\".concat(cssMapping.sourceRoot).concat(source, \" */\");\n });\n return [content].concat(sourceURLs).concat([sourceMapping]).join('\\n');\n }\n\n return [content].join('\\n');\n} // Adapted from convert-source-map (MIT)\n\n\nfunction toComment(sourceMap) {\n // eslint-disable-next-line no-undef\n var base64 = btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap))));\n var data = \"sourceMappingURL=data:application/json;charset=utf-8;base64,\".concat(base64);\n return \"/*# \".concat(data, \" */\");\n}\n\n//# sourceURL=webpack:///./node_modules/css-loader/dist/runtime/api.js?"); 109 | 110 | /***/ }), 111 | 112 | /***/ "./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js": 113 | /*!****************************************************************************!*\ 114 | !*** ./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js ***! 115 | \****************************************************************************/ 116 | /*! no static exports found */ 117 | /***/ (function(module, exports, __webpack_require__) { 118 | 119 | "use strict"; 120 | eval("\n\nvar stylesInDom = {};\n\nvar isOldIE = function isOldIE() {\n var memo;\n return function memorize() {\n if (typeof memo === 'undefined') {\n // Test for IE <= 9 as proposed by Browserhacks\n // @see http://browserhacks.com/#hack-e71d8692f65334173fee715c222cb805\n // Tests for existence of standard globals is to allow style-loader\n // to operate correctly into non-standard environments\n // @see https://github.com/webpack-contrib/style-loader/issues/177\n memo = Boolean(window && document && document.all && !window.atob);\n }\n\n return memo;\n };\n}();\n\nvar getTarget = function getTarget() {\n var memo = {};\n return function memorize(target) {\n if (typeof memo[target] === 'undefined') {\n var styleTarget = document.querySelector(target); // Special case to return head of iframe instead of iframe itself\n\n if (window.HTMLIFrameElement && styleTarget instanceof window.HTMLIFrameElement) {\n try {\n // This will throw an exception if access to iframe is blocked\n // due to cross-origin restrictions\n styleTarget = styleTarget.contentDocument.head;\n } catch (e) {\n // istanbul ignore next\n styleTarget = null;\n }\n }\n\n memo[target] = styleTarget;\n }\n\n return memo[target];\n };\n}();\n\nfunction listToStyles(list, options) {\n var styles = [];\n var newStyles = {};\n\n for (var i = 0; i < list.length; i++) {\n var item = list[i];\n var id = options.base ? item[0] + options.base : item[0];\n var css = item[1];\n var media = item[2];\n var sourceMap = item[3];\n var part = {\n css: css,\n media: media,\n sourceMap: sourceMap\n };\n\n if (!newStyles[id]) {\n styles.push(newStyles[id] = {\n id: id,\n parts: [part]\n });\n } else {\n newStyles[id].parts.push(part);\n }\n }\n\n return styles;\n}\n\nfunction addStylesToDom(styles, options) {\n for (var i = 0; i < styles.length; i++) {\n var item = styles[i];\n var domStyle = stylesInDom[item.id];\n var j = 0;\n\n if (domStyle) {\n domStyle.refs++;\n\n for (; j < domStyle.parts.length; j++) {\n domStyle.parts[j](item.parts[j]);\n }\n\n for (; j < item.parts.length; j++) {\n domStyle.parts.push(addStyle(item.parts[j], options));\n }\n } else {\n var parts = [];\n\n for (; j < item.parts.length; j++) {\n parts.push(addStyle(item.parts[j], options));\n }\n\n stylesInDom[item.id] = {\n id: item.id,\n refs: 1,\n parts: parts\n };\n }\n }\n}\n\nfunction insertStyleElement(options) {\n var style = document.createElement('style');\n\n if (typeof options.attributes.nonce === 'undefined') {\n var nonce = true ? __webpack_require__.nc : undefined;\n\n if (nonce) {\n options.attributes.nonce = nonce;\n }\n }\n\n Object.keys(options.attributes).forEach(function (key) {\n style.setAttribute(key, options.attributes[key]);\n });\n\n if (typeof options.insert === 'function') {\n options.insert(style);\n } else {\n var target = getTarget(options.insert || 'head');\n\n if (!target) {\n throw new Error(\"Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.\");\n }\n\n target.appendChild(style);\n }\n\n return style;\n}\n\nfunction removeStyleElement(style) {\n // istanbul ignore if\n if (style.parentNode === null) {\n return false;\n }\n\n style.parentNode.removeChild(style);\n}\n/* istanbul ignore next */\n\n\nvar replaceText = function replaceText() {\n var textStore = [];\n return function replace(index, replacement) {\n textStore[index] = replacement;\n return textStore.filter(Boolean).join('\\n');\n };\n}();\n\nfunction applyToSingletonTag(style, index, remove, obj) {\n var css = remove ? '' : obj.css; // For old IE\n\n /* istanbul ignore if */\n\n if (style.styleSheet) {\n style.styleSheet.cssText = replaceText(index, css);\n } else {\n var cssNode = document.createTextNode(css);\n var childNodes = style.childNodes;\n\n if (childNodes[index]) {\n style.removeChild(childNodes[index]);\n }\n\n if (childNodes.length) {\n style.insertBefore(cssNode, childNodes[index]);\n } else {\n style.appendChild(cssNode);\n }\n }\n}\n\nfunction applyToTag(style, options, obj) {\n var css = obj.css;\n var media = obj.media;\n var sourceMap = obj.sourceMap;\n\n if (media) {\n style.setAttribute('media', media);\n }\n\n if (sourceMap && btoa) {\n css += \"\\n/*# sourceMappingURL=data:application/json;base64,\".concat(btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))), \" */\");\n } // For old IE\n\n /* istanbul ignore if */\n\n\n if (style.styleSheet) {\n style.styleSheet.cssText = css;\n } else {\n while (style.firstChild) {\n style.removeChild(style.firstChild);\n }\n\n style.appendChild(document.createTextNode(css));\n }\n}\n\nvar singleton = null;\nvar singletonCounter = 0;\n\nfunction addStyle(obj, options) {\n var style;\n var update;\n var remove;\n\n if (options.singleton) {\n var styleIndex = singletonCounter++;\n style = singleton || (singleton = insertStyleElement(options));\n update = applyToSingletonTag.bind(null, style, styleIndex, false);\n remove = applyToSingletonTag.bind(null, style, styleIndex, true);\n } else {\n style = insertStyleElement(options);\n update = applyToTag.bind(null, style, options);\n\n remove = function remove() {\n removeStyleElement(style);\n };\n }\n\n update(obj);\n return function updateStyle(newObj) {\n if (newObj) {\n if (newObj.css === obj.css && newObj.media === obj.media && newObj.sourceMap === obj.sourceMap) {\n return;\n }\n\n update(obj = newObj);\n } else {\n remove();\n }\n };\n}\n\nmodule.exports = function (list, options) {\n options = options || {};\n options.attributes = typeof options.attributes === 'object' ? options.attributes : {}; // Force single-tag solution on IE6-9, which has a hard limit on the # of