├── .gitignore ├── LICENSE ├── README.md ├── d3 ├── LICENSE └── d3.v3.js ├── data └── browsers.js ├── deck ├── deck.css ├── deck.js ├── deck.less └── slide_maker.js ├── example_bar_chart.html ├── example_sort.html ├── images ├── inspect.png └── svgbook.png ├── index.html ├── slide_maker.js ├── slides.coffee ├── slides.js └── template.html /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012, Vadim Ogievetsky 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * The name Vadim Ogievetsky may not be used to endorse or promote products 15 | derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL VADIM OGIEVETSKY BE LIABLE FOR ANY DIRECT, 21 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 22 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 24 | OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 26 | EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | D3 slides in D3 that I put together after becoming frustrated with explaining D3 using PowerPoint. 2 | 3 | Questions, comments, contributions, feedback, etc. 4 | 5 | ```javascript 6 | // base64 email for fun. 7 | sendEmailTo(atob("dmFkaW1Ab2dpZXZldHNreS5jb20=")) 8 | ``` 9 | 10 | ## License 11 | 12 | MIT © [Vadim Ogievetsky](http://vadim.ogievetsky.com) 13 | -------------------------------------------------------------------------------- /d3/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013, Michael Bostock 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * The name Michael Bostock may not be used to endorse or promote products 15 | derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL MICHAEL BOSTOCK BE LIABLE FOR ANY DIRECT, 21 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 22 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 24 | OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 26 | EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | -------------------------------------------------------------------------------- /data/browsers.js: -------------------------------------------------------------------------------- 1 | var colors = { 2 | 'IE10': "#00BBFF", 3 | 'IE9': "#003BFF", 4 | 'IE8': "#003BB2", 5 | 'IE7': "#0062C4", 6 | 'IE6': "#008ED6", 7 | 'IE5': "#00BFE5", 8 | 'IE4': "#00ddff", 9 | 'Firefox': "#E58714", 10 | 'Mozilla': "#C1650F", 11 | 'Chrome': "#FCD610", 12 | 'Safari': "#5384B1", 13 | 'Opera': "#FF3333", 14 | 'Opera 8': "#E52D2D", 15 | 'Opera 7': "#E23F3F", 16 | 'AOL': "#FFD52F", 17 | 'Netscape 7': "#00AFB5", 18 | 'Netscape 5': "#00D5D8", 19 | 'Netscape 4': "#00EFEF", 20 | 'Netscape 3': "#14FFFF", 21 | }; 22 | 23 | var stats = [ 24 | { month: "January 2012", data: { 25 | "IE10": 0.010, 26 | "IE9": 0.053, 27 | "IE8": 0.105, 28 | "IE7": 0.031, 29 | "IE6": 0.011, 30 | "Firefox": 0.371, 31 | "Chrome": 0.353, 32 | "Safari": 0.043, 33 | "Opera": 0.024 34 | }}, 35 | { month: "December 2011", data: { 36 | "IE9": 0.051, 37 | "IE8": 0.107, 38 | "IE7": 0.032, 39 | "IE6": 0.012, 40 | "Firefox": 0.377, 41 | "Chrome": 0.346, 42 | "Safari": 0.042, 43 | "Opera": 0.025 44 | }}, 45 | { month: "November 2011", data: { 46 | "IE9": 0.051, 47 | "IE8": 0.115, 48 | "IE7": 0.034, 49 | "IE6": 0.012, 50 | "Firefox": 0.381, 51 | "Chrome": 0.334, 52 | "Safari": 0.042, 53 | "Opera": 0.024 54 | }}, 55 | { month: "October 2011", data: { 56 | "IE9": 0.051, 57 | "IE8": 0.118, 58 | "IE7": 0.035, 59 | "IE6": 0.013, 60 | "Firefox": 0.387, 61 | "Chrome": 0.323, 62 | "Safari": 0.042, 63 | "Opera": 0.024 64 | }}, 65 | { month: "September 2011", data: { 66 | "IE9": 0.048, 67 | "IE8": 0.124, 68 | "IE7": 0.039, 69 | "IE6": 0.018, 70 | "Firefox": 0.397, 71 | "Chrome": 0.305, 72 | "Safari": 0.040, 73 | "Opera": 0.022, 74 | }}, 75 | { month: "August 2011", data: { 76 | "IE9": 0.042, 77 | "IE8": 0.119, 78 | "IE7": 0.042, 79 | "IE6": 0.020, 80 | "Firefox": 0.406, 81 | "Chrome": 0.303, 82 | "Safari": 0.038, 83 | "Opera": 0.023, 84 | }}, 85 | { month: "July 2011", data: { 86 | "IE9": 0.039, 87 | "IE8": 0.117, 88 | "IE7": 0.041, 89 | "IE6": 0.023, 90 | "Firefox": 0.420, 91 | "Chrome": 0.294, 92 | "Safari": 0.036, 93 | "Opera": 0.024, 94 | }}, 95 | { month: "June 2011", data: { 96 | "IE9": 0.036, 97 | "IE8": 0.129, 98 | "IE7": 0.044, 99 | "IE6": 0.023, 100 | "Firefox": 0.422, 101 | "Chrome": 0.279, 102 | "Safari": 0.037, 103 | "Opera": 0.024, 104 | }}, 105 | { month: "May 2011", data: { 106 | "IE9": 0.031, 107 | "IE8": 0.141, 108 | "IE7": 0.053, 109 | "IE6": 0.024, 110 | "Firefox": 0.424, 111 | "Chrome": 0.259, 112 | "Safari": 0.040, 113 | "Opera": 0.024, 114 | }}, 115 | { month: "April 2011", data: { 116 | "IE9": 0.021, 117 | "IE8": 0.148, 118 | "IE7": 0.049, 119 | "IE6": 0.025, 120 | "Firefox": 0.429, 121 | "Chrome": 0.256, 122 | "Safari": 0.041, 123 | "Opera": 0.026, 124 | }}, 125 | { month: "March 2011", data: { 126 | "IE9": 0.011, 127 | "IE8": 0.163, 128 | "IE7": 0.054, 129 | "IE6": 0.030, 130 | "Firefox": 0.422, 131 | "Chrome": 0.250, 132 | "Safari": 0.040, 133 | "Opera": 0.025, 134 | }}, 135 | { month: "February 2011", data: { 136 | "IE9": 0.006, 137 | "IE8": 0.167, 138 | "IE7": 0.057, 139 | "IE6": 0.035, 140 | "Firefox": 0.424, 141 | "Chrome": 0.241, 142 | "Safari": 0.041, 143 | "Opera": 0.025, 144 | }}, 145 | { month: "January 2011", data: { 146 | "IE9": 0.005, 147 | "IE8": 0.166, 148 | "IE7": 0.057, 149 | "IE6": 0.038, 150 | "Firefox": 0.428, 151 | "Chrome": 0.238, 152 | "Safari": 0.040, 153 | "Opera": 0.025, 154 | }}, 155 | { month: "December 2010", data: { 156 | "IE9": 0.005, 157 | "IE8": 0.165, 158 | "IE7": 0.061, 159 | "IE6": 0.044, 160 | "Firefox": 0.435, 161 | "Chrome": 0.224, 162 | "Safari": 0.038, 163 | "Opera": 0.022, 164 | }}, 165 | { month: "November 2010", data: { 166 | "IE9": 0.004, 167 | "IE8": 0.176, 168 | "IE7": 0.065, 169 | "IE6": 0.041, 170 | "Firefox": 0.440, 171 | "Chrome": 0.205, 172 | "Safari": 0.040, 173 | "Opera": 0.023, 174 | }}, 175 | { month: "October 2010", data: { 176 | "IE9": 0.004, 177 | "IE8": 0.173, 178 | "IE7": 0.072, 179 | "IE6": 0.048, 180 | "Firefox": 0.441, 181 | "Chrome": 0.192, 182 | "Safari": 0.039, 183 | "Opera": 0.022, 184 | }}, 185 | { month: "September 2010", data: { 186 | "IE9": 0.002, 187 | "IE8": 0.173, 188 | "IE7": 0.080, 189 | "IE6": 0.056, 190 | "Firefox": 0.451, 191 | "Chrome": 0.173, 192 | "Safari": 0.037, 193 | "Opera": 0.022, 194 | }}, 195 | { month: "August 2010", data: { 196 | "IE8": 0.162, 197 | "IE7": 0.078, 198 | "IE6": 0.067, 199 | "Firefox": 0.458, 200 | "Chrome": 0.170, 201 | "Safari": 0.035, 202 | "Opera": 0.023, 203 | }}, 204 | { month: "July 2010", data: { 205 | "IE8": 0.156, 206 | "IE7": 0.076, 207 | "IE6": 0.072, 208 | "Firefox": 0.464, 209 | "Chrome": 0.167, 210 | "Safari": 0.034, 211 | "Opera": 0.023, 212 | }}, 213 | { month: "June 2010", data: { 214 | "IE8": 0.157, 215 | "IE7": 0.081, 216 | "IE6": 0.072, 217 | "Firefox": 0.466, 218 | "Chrome": 0.159, 219 | "Safari": 0.036, 220 | "Opera": 0.021, 221 | }}, 222 | { month: "May 2010", data: { 223 | "IE8": 0.160, 224 | "IE7": 0.091, 225 | "IE6": 0.071, 226 | "Firefox": 0.469, 227 | "Chrome": 0.145, 228 | "Safari": 0.035, 229 | "Opera": 0.022, 230 | }}, 231 | { month: "April 2010", data: { 232 | "IE8": 0.162, 233 | "IE7": 0.093, 234 | "IE6": 0.079, 235 | "Firefox": 0.464, 236 | "Chrome": 0.136, 237 | "Safari": 0.037, 238 | "Opera": 0.022, 239 | }}, 240 | { month: "March 2010", data: { 241 | "IE8": 0.153, 242 | "IE7": 0.107, 243 | "IE6": 0.089, 244 | "Firefox": 0.462, 245 | "Chrome": 0.123, 246 | "Safari": 0.037, 247 | "Opera": 0.022, 248 | }}, 249 | { month: "February 2010", data: { 250 | "IE8": 0.147, 251 | "IE7": 0.110, 252 | "IE6": 0.096, 253 | "Firefox": 0.465, 254 | "Chrome": 0.116, 255 | "Safari": 0.038, 256 | "Opera": 0.021, 257 | }}, 258 | { month: "January 2010", data: { 259 | "IE8": 0.143, 260 | "IE7": 0.117, 261 | "IE6": 0.102, 262 | "Firefox": 0.463, 263 | "Chrome": 0.108, 264 | "Safari": 0.037, 265 | "Opera": 0.022, 266 | }}, 267 | { month: "December 2009", data: { 268 | "IE8": 0.135, 269 | "IE7": 0.128, 270 | "IE6": 0.109, 271 | "Firefox": 0.464, 272 | "Chrome": 0.098, 273 | "Safari": 0.036, 274 | "Opera": 0.023, 275 | }}, 276 | { month: "November 2009", data: { 277 | "IE8": 0.133, 278 | "IE7": 0.133, 279 | "IE6": 0.111, 280 | "Firefox": 0.470, 281 | "Chrome": 0.085, 282 | "Safari": 0.038, 283 | "Opera": 0.023, 284 | }}, 285 | { month: "October 2009", data: { 286 | "IE8": 0.128, 287 | "IE7": 0.141, 288 | "IE6": 0.106, 289 | "Firefox": 0.475, 290 | "Chrome": 0.080, 291 | "Safari": 0.038, 292 | "Opera": 0.023, 293 | }}, 294 | { month: "September 2009", data: { 295 | "IE8": 0.122, 296 | "IE7": 0.153, 297 | "IE6": 0.121, 298 | "Firefox": 0.466, 299 | "Chrome": 0.071, 300 | "Safari": 0.036, 301 | "Opera": 0.022, 302 | }}, 303 | { month: "August 2009", data: { 304 | "IE7": 0.151, 305 | "IE6": 0.136, 306 | "IE8": 0.106, 307 | "Firefox": 0.474, 308 | "Chrome": 0.07, 309 | "Safari": 0.033, 310 | "Opera": 0.021, 311 | }}, 312 | { month: "July 2009", data: { 313 | "IE7": 0.159, 314 | "IE6": 0.144, 315 | "IE8": 0.091, 316 | "Firefox": 0.479, 317 | "Chrome": 0.065, 318 | "Safari": 0.033, 319 | "Opera": 0.021, 320 | }}, 321 | { month: "June 2009", data: { 322 | "IE7": 0.187, 323 | "IE6": 0.149, 324 | "IE8": 0.071, 325 | "Firefox": 0.473, 326 | "Chrome": 0.06, 327 | "Safari": 0.031, 328 | "Opera": 0.021, 329 | }}, 330 | { month: "May 2009", data: { 331 | "IE7": 0.213, 332 | "IE6": 0.145, 333 | "IE8": 0.052, 334 | "Firefox": 0.477, 335 | "Chrome": 0.055, 336 | "Safari": 0.03, 337 | "Opera": 0.022, 338 | }}, 339 | { month: "April 2009", data: { 340 | "IE7": 0.232, 341 | "IE6": 0.154, 342 | "IE8": 0.035, 343 | "Firefox": 0.471, 344 | "Chrome": 0.049, 345 | "Safari": 0.03, 346 | "Opera": 0.022, 347 | }}, 348 | { month: "March 2009", data: { 349 | "IE7": 0.249, 350 | "IE6": 0.17, 351 | "IE8": 0.014, 352 | "Firefox": 0.465, 353 | "Chrome": 0.042, 354 | "Safari": 0.031, 355 | "Opera": 0.023, 356 | }}, 357 | { month: "February 2009", data: { 358 | "IE7": 0.254, 359 | "IE6": 0.174, 360 | "IE8": 0.008, 361 | "Firefox": 0.464, 362 | "Chrome": 0.04, 363 | "Safari": 0.03, 364 | "Opera": 0.022, 365 | }}, 366 | { month: "January 2009", data: { 367 | "IE7": 0.257, 368 | "IE6": 0.185, 369 | "IE8": 0.006, 370 | "Firefox": 0.455, 371 | "Chrome": 0.039, 372 | "Safari": 0.03, 373 | "Opera": 0.023, 374 | }}, 375 | { month: "December 2008", data: { 376 | "IE7": 0.261, 377 | "IE6": 0.196, 378 | "IE5": 0, 379 | "Firefox": 0.444, 380 | "Chrome": 0.036, 381 | "Safari": 0.027, 382 | "Opera": 0.024, 383 | }}, 384 | { month: "November 2008", data: { 385 | "IE7": 0.266, 386 | "IE6": 0.2, 387 | "IE5": 0, 388 | "Firefox": 0.442, 389 | "Chrome": 0.031, 390 | "Safari": 0.027, 391 | "Opera": 0.023, 392 | }}, 393 | { month: "October 2008", data: { 394 | "IE7": 0.269, 395 | "IE6": 0.202, 396 | "IE5": 0, 397 | "Firefox": 0.44, 398 | "Chrome": 0.03, 399 | "Safari": 0.028, 400 | "Opera": 0.022, 401 | }}, 402 | { month: "September 2008", data: { 403 | "IE7": 0.263, 404 | "IE6": 0.223, 405 | "IE5": 0, 406 | "Firefox": 0.426, 407 | "Chrome": 0.031, 408 | "Safari": 0.027, 409 | "Opera": 0.02, 410 | }}, 411 | { month: "August 2008", data: { 412 | "IE7": 0.26, 413 | "IE6": 0.245, 414 | "IE5": 0, 415 | "Firefox": 0.437, 416 | "Chrome": 0, 417 | "Safari": 0.026, 418 | "Opera": 0.021, 419 | }}, 420 | { month: "July 2008", data: { 421 | "IE7": 0.264, 422 | "IE6": 0.253, 423 | "IE5": 0, 424 | "Firefox": 0.426, 425 | "Chrome": 0, 426 | "Safari": 0.025, 427 | "Opera": 0.019, 428 | }}, 429 | { month: "June 2008", data: { 430 | "IE7": 0.27, 431 | "IE6": 0.265, 432 | "IE5": 0.005, 433 | "Firefox": 0.41, 434 | "Chrome": 0, 435 | "Safari": 0.026, 436 | "Opera": 0.017, 437 | }}, 438 | { month: "May 2008", data: { 439 | "IE7": 0.265, 440 | "IE6": 0.273, 441 | "IE5": 0.007, 442 | "Firefox": 0.398, 443 | "Chrome": 0, 444 | "Safari": 0.024, 445 | "Opera": 0.015, 446 | }}, 447 | { month: "April 2008", data: { 448 | "IE7": 0.249, 449 | "IE6": 0.289, 450 | "IE5": 0.01, 451 | "Firefox": 0.391, 452 | "Chrome": 0, 453 | "Safari": 0.022, 454 | "Opera": 0.014, 455 | }}, 456 | { month: "March 2008", data: { 457 | "IE7": 0.233, 458 | "IE6": 0.295, 459 | "IE5": 0.011, 460 | "Firefox": 0.37, 461 | "Chrome": 0, 462 | "Safari": 0.021, 463 | "Opera": 0.014, 464 | }}, 465 | { month: "February 2008", data: { 466 | "IE7": 0.227, 467 | "IE6": 0.307, 468 | "IE5": 0.013, 469 | "Firefox": 0.365, 470 | "Chrome": 0, 471 | "Safari": 0.02, 472 | "Opera": 0.014, 473 | }}, 474 | { month: "January 2008", data: { 475 | "IE7": 0.212, 476 | "IE6": 0.32, 477 | "IE5": 0.015, 478 | "Firefox": 0.364, 479 | "Chrome": 0, 480 | "Safari": 0.019, 481 | "Opera": 0.014, 482 | }}, 483 | { month: "November 2007", data: { 484 | "IE7": 0.208, 485 | "IE6": 0.336, 486 | "IE5": 0.016, 487 | "Firefox": 0.363, 488 | "Mozilla": 0.012, 489 | "Safari": 0.018, 490 | "Opera": 0.016, 491 | }}, 492 | { month: "September 2007", data: { 493 | "IE7": 0.208, 494 | "IE6": 0.349, 495 | "IE5": 0.015, 496 | "Firefox": 0.354, 497 | "Mozilla": 0.012, 498 | "Safari": 0.016, 499 | "Opera": 0.015, 500 | }}, 501 | { month: "July 2007", data: { 502 | "IE7": 0.201, 503 | "IE6": 0.369, 504 | "IE5": 0.015, 505 | "Firefox": 0.345, 506 | "Mozilla": 0.014, 507 | "Safari": 0.015, 508 | "Opera": 0.019, 509 | }}, 510 | { month: "May 2007", data: { 511 | "IE7": 0.192, 512 | "IE6": 0.381, 513 | "IE5": 0.016, 514 | "Firefox": 0.337, 515 | "Mozilla": 0.013, 516 | "Safari": 0.015, 517 | "Opera": 0.017, 518 | }}, 519 | { month: "March 2007", data: { 520 | "IE7": 0.18, 521 | "IE6": 0.387, 522 | "IE5": 0.02, 523 | "Firefox": 0.318, 524 | "Mozilla": 0.013, 525 | "Safari": 0.016, 526 | "Opera": 0.016, 527 | }}, 528 | { month: "January 2007", data: { 529 | "IE7": 0.133, 530 | "IE6": 0.423, 531 | "IE5": 0.03, 532 | "Firefox": 0.31, 533 | "Mozilla": 0.015, 534 | "Safari": 0.017, 535 | "Opera": 0.015, 536 | }}, 537 | { month: "November 2006", data: { 538 | "IE7": 0.071, 539 | "IE6": 0.499, 540 | "IE5": 0.036, 541 | "Firefox": 0.299, 542 | "Mozilla": 0.025, 543 | "Opera": 0.015, 544 | }}, 545 | { month: "September 2006", data: { 546 | "IE7": 0.025, 547 | "IE6": 0.556, 548 | "IE5": 0.04, 549 | "Firefox": 0.273, 550 | "Mozilla": 0.023, 551 | "Opera": 0.016, 552 | }}, 553 | { month: "July 2006", data: { 554 | "IE7": 0.019, 555 | "IE6": 0.563, 556 | "IE5": 0.042, 557 | "Firefox": 0.255, 558 | "Mozilla": 0.023, 559 | "Opera": 0.014, 560 | }}, 561 | { month: "May 2006", data: { 562 | "IE7": 0.011, 563 | "IE6": 0.574, 564 | "IE5": 0.045, 565 | "Firefox": 0.257, 566 | "Mozilla": 0.023, 567 | "Opera": 0.015, 568 | }}, 569 | { month: "March 2006", data: { 570 | "IE7": 0.006, 571 | "IE6": 0.588, 572 | "IE5": 0.053, 573 | "Firefox": 0.245, 574 | "Mozilla": 0.024, 575 | "Opera": 0.015, 576 | }}, 577 | { month: "January 2006", data: { 578 | "IE7": 0.002, 579 | "IE6": 0.603, 580 | "IE5": 0.055, 581 | "Firefox": 0.25, 582 | "Mozilla": 0.031, 583 | "Opera": 0.016, 584 | }}, 585 | { month: "November 2005", data: { 586 | "IE6": 0.627, 587 | "IE5": 0.062, 588 | "Firefox": 0.236, 589 | "Mozilla": 0.028, 590 | "Netscape 7": 0.004, 591 | "Opera 8": 0.013, 592 | "Opera 7": 0.002, 593 | }}, 594 | { month: "September 2005", data: { 595 | "IE6": 0.698, 596 | "IE5": 0.057, 597 | "Firefox": 0.18, 598 | "Mozilla": 0.025, 599 | "Netscape 7": 0.004, 600 | "Opera 8": 0.01, 601 | "Opera 7": 0.002, 602 | }}, 603 | { month: "July 2005", data: { 604 | "IE6": 0.679, 605 | "IE5": 0.059, 606 | "Firefox": 0.198, 607 | "Mozilla": 0.026, 608 | "Netscape 7": 0.005, 609 | "Opera 8": 0.008, 610 | "Opera 7": 0.004, 611 | }}, 612 | { month: "May 2005", data: { 613 | "IE6": 0.648, 614 | "IE5": 0.068, 615 | "Firefox": 0.21, 616 | "Mozilla": 0.031, 617 | "Netscape 7": 0.007, 618 | "Opera 8": 0.007, 619 | "Opera 7": 0.006, 620 | }}, 621 | { month: "March 2005", data: { 622 | "IE6": 0.636, 623 | "IE5": 0.089, 624 | "Firefox": 0.189, 625 | "Mozilla": 0.033, 626 | "Netscape 7": 0.01, 627 | "Opera 8": 0.003, 628 | "Opera 7": 0.016, 629 | }}, 630 | { month: "January 2005", data: { 631 | "IE6": 0.648, 632 | "IE5": 0.097, 633 | "Firefox": 0.166, 634 | "Mozilla": 0.034, 635 | "Netscape 7": 0.011, 636 | "Opera 8": 0, 637 | "Opera 7": 0.019, 638 | }}, 639 | { month: "November 2004", data: { 640 | "IE6": 0.66, 641 | "IE5": 0.102, 642 | "Mozilla": 0.165, 643 | "Netscape 3": 0.002, 644 | "Netscape 7": 0.012, 645 | "Netscape 4": 0.003, 646 | "Opera 7": 0.016, 647 | }}, 648 | { month: "September 2004", data: { 649 | "IE6": 0.678, 650 | "IE5": 0.112, 651 | "Mozilla": 0.137, 652 | "Netscape 3": 0.003, 653 | "Netscape 7": 0.014, 654 | "Netscape 4": 0.003, 655 | "Opera 7": 0.017, 656 | }}, 657 | { month: "July 2004", data: { 658 | "IE6": 0.672, 659 | "IE5": 0.132, 660 | "Mozilla": 0.126, 661 | "Netscape 3": 0.004, 662 | "Netscape 7": 0.014, 663 | "Netscape 4": 0.004, 664 | "Opera 7": 0.016, 665 | }}, 666 | { month: "May 2004", data: { 667 | "IE6": 0.681, 668 | "IE5": 0.138, 669 | "Mozilla": 0.095, 670 | "Netscape 3": 0.006, 671 | "Netscape 7": 0.014, 672 | "Netscape 4": 0.004, 673 | "Opera 7": 0.016, 674 | }}, 675 | { month: "March 2004", data: { 676 | "IE6": 0.682, 677 | "IE5": 0.146, 678 | "Mozilla": 0.079, 679 | "Netscape 3": 0.008, 680 | "Netscape 7": 0.014, 681 | "Netscape 4": 0.006, 682 | "Opera 7": 0.014, 683 | }}, 684 | { month: "January 2004", data: { 685 | "IE6": 0.689, 686 | "IE5": 0.158, 687 | "Mozilla": 0.055, 688 | "Netscape 3": 0.004, 689 | "Netscape 7": 0.015, 690 | "Netscape 4": 0.005, 691 | "Opera 7": 0.015, 692 | }}, 693 | { month: "November 2003", data: { 694 | "IE6": 0.712, 695 | "IE5": 0.137, 696 | "Mozilla": 0.072, 697 | "Netscape 3": 0.005, 698 | "Netscape 7": 0.016, 699 | "Netscape 4": 0.005, 700 | "Opera 7": 0.019, 701 | }}, 702 | { month: "September 2003", data: { 703 | "IE6": 0.697, 704 | "IE5": 0.169, 705 | "Mozilla": 0.062, 706 | "Netscape 3": 0.006, 707 | "Netscape 7": 0.015, 708 | "Netscape 4": 0.006, 709 | "Opera 7": 0.018, 710 | }}, 711 | { month: "July 2003", data: { 712 | "IE6": 0.669, 713 | "IE5": 0.203, 714 | "Mozilla": 0.057, 715 | "Netscape 3": 0.006, 716 | "Netscape 7": 0.015, 717 | "Netscape 4": 0.006, 718 | "Opera 7": 0.017, 719 | }}, 720 | { month: "May 2003", data: { 721 | "IE6": 0.65, 722 | "IE5": 0.227, 723 | "Mozilla": 0.046, 724 | "Netscape 3": 0.01, 725 | "Netscape 7": 0.014, 726 | "Netscape 4": 0.009, 727 | "Opera 7": 0.014, 728 | }}, 729 | { month: "March 2003", data: { 730 | "IE6": 0.634, 731 | "IE5": 0.246, 732 | "Mozilla": 0.042, 733 | "Netscape 3": 0.009, 734 | "Netscape 7": 0.014, 735 | "Netscape 4": 0.011, 736 | "Opera 7": 0.012, 737 | }}, 738 | { month: "January 2003", data: { 739 | "IE6": 0.553, 740 | "IE5": 0.293, 741 | "Mozilla": 0.04, 742 | "Netscape 3": 0.012, 743 | "Netscape 7": 0.011, 744 | "Netscape 4": 0.017, 745 | "Opera 7": 0, 746 | }}, 747 | { month: "November 2002", data: { 748 | "IE6": 0.535, 749 | "IE5": 0.299, 750 | "AOL": 0.052, 751 | "Netscape 3": 0.011, 752 | "Netscape 5": 0.049, 753 | "Netscape 4": 0.02, 754 | "IE4": 0, 755 | }}, 756 | { month: "September 2002", data: { 757 | "IE6": 0.491, 758 | "IE5": 0.344, 759 | "AOL": 0.045, 760 | "Netscape 3": 0.013, 761 | "Netscape 5": 0.045, 762 | "Netscape 4": 0.022, 763 | "IE4": 0, 764 | }}, 765 | { month: "July 2002", data: { 766 | "IE6": 0.444, 767 | "IE5": 0.401, 768 | "AOL": 0.035, 769 | "Netscape 3": 0.012, 770 | "Netscape 5": 0.035, 771 | "Netscape 4": 0.026, 772 | "IE4": 0.005, 773 | }}, 774 | { month: "May 2002", data: { 775 | "IE6": 0.407, 776 | "IE5": 0.46, 777 | "AOL": 0.028, 778 | "Netscape 3": 0.012, 779 | "Netscape 5": 0.027, 780 | "Netscape 4": 0.034, 781 | "IE4": 0.007, 782 | }}, 783 | { month: "March 2002", data: { 784 | "IE6": 0.367, 785 | "IE5": 0.494, 786 | "AOL": 0.03, 787 | "Netscape 3": 0.012, 788 | "Netscape 5": 0.024, 789 | "Netscape 4": 0.041, 790 | "IE4": 0.007, 791 | }}, 792 | { month: "January 2002", data: { 793 | "IE6": 0.301, 794 | "IE5": 0.557, 795 | "AOL": 0.028, 796 | "Netscape 3": 0.013, 797 | "Netscape 5": 0.022, 798 | "Netscape 4": 0.044, 799 | "IE4": 0.01, 800 | }}, 801 | ]; -------------------------------------------------------------------------------- /deck/deck.css: -------------------------------------------------------------------------------- 1 | *{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;} 2 | h1{margin:0;} 3 | .btn{display:inline-block;padding:4px 10px 4px;font-size:13px;line-height:18px;color:#333333;text-align:center;text-shadow:0 1px 1px rgba(255, 255, 255, 0.75);background-color:#fafafa;background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), color-stop(25%, #ffffff), to(#e6e6e6));background-image:-webkit-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-image:-moz-linear-gradient(top, #ffffff, #ffffff 25%, #e6e6e6);background-image:-ms-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-image:-o-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-image:linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-repeat:no-repeat;border:1px solid #ccc;border-bottom-color:#bbb;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);cursor:pointer;}.btn:hover{color:#333333;text-decoration:none;background-color:#e6e6e6;background-position:0 -15px;-webkit-transition:background-position 0.1s linear;-moz-transition:background-position 0.1s linear;-ms-transition:background-position 0.1s linear;-o-transition:background-position 0.1s linear;transition:background-position 0.1s linear;} 4 | .btn:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;} 5 | .btn.active,.btn:active{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);background-color:#e6e6e6;background-color:#d9d9d9 \9;color:rgba(0, 0, 0, 0.5);outline:0;} 6 | body{background:#929292;font-family:"Helvetica Neue",Arial,sans-serif;text-align:center;} 7 | section{width:1024px;height:768px;position:absolute;top:50%;left:50%;margin-left:-512px;margin-top:-384px;border-radius:8px;-o-border-radius:8px;-moz-border-radius:8px;-webkit-border-radius:8px;background:white;-moz-box-shadow:0px 0px 2px 2px #ccc;-webkit-box-shadow:0px 0px 2px 2px #ccc;box-shadow:0px 0px 2px 2px #ccc;}section.main_title h1{margin-top:140px;font-size:256px;} 8 | section.main_title h2{margin-top:20px;font-size:56px;} 9 | section.title h1{margin-top:310px;font-size:40px;} 10 | section.top_title h1{margin-top:22px;margin-bottom:15px;font-size:36px;} 11 | section.top_title a{display:block;margin-top:30px;font-size:28px;} 12 | section.code_title h1{font-family:"Courier New",monospace;margin-top:310px;font-size:42px;} 13 | section.code_slide h1{font-family:"Courier New",monospace;margin-top:22px;font-size:36px;} 14 | section.code_slide div.codes{position:absolute;left:10px;bottom:10px;right:517px;top:90px;}section.code_slide div.codes textarea{font-family:"Courier New",monospace;text-align:left;width:100%;height:100%;border:1px solid #ccc;font-size:16px;padding:4px 4px;resize:none;outline:none;white-space:pre;}section.code_slide div.codes textarea.init{display:none;} 15 | section.code_slide div.codes div.button_bar{position:absolute;right:16px;bottom:4px;}section.code_slide div.codes div.button_bar div.reset,section.code_slide div.codes div.button_bar div.run{margin:3px;} 16 | section.code_slide div.out{position:absolute;right:10px;bottom:10px;left:517px;top:90px;border:1px solid #ccc;}section.code_slide div.out div.error{position:absolute;background:white;top:5px;left:5px;right:5px;color:red;border:2px solid red;z-index:100;padding:10px;font-size:16px;} 17 | section.code_slide div.out pre.log{position:absolute;background:white;top:5px;left:5px;right:5px;border:2px solid black;z-index:99;padding:10px;font-size:16px;text-align:left;} 18 | section .name,section .date{position:absolute;bottom:20px;color:#999;} 19 | section .name{left:20px;} 20 | section .date{right:20px;} 21 | section svg{width:100%;height:100%;}section svg rect{fill:#ccc;stroke:gray;stroke-width:2px;} 22 | section svg text{font:16px sans-serif;} 23 | section a{color:steelblue;} 24 | section a:not(:hover){text-decoration:none;} 25 | section .mmx{position:absolute;left:50%;margin-left:-150px;bottom:3px;} 26 | -------------------------------------------------------------------------------- /deck/deck.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | "use strict"; 3 | var m, n, slide; 4 | slide = null; 5 | n = d3.selectAll('section')[0].length; 6 | 7 | function update(newSlide) { 8 | newSlide = Math.min(Math.max(newSlide, 0), n - 1); 9 | if (slide === newSlide) return; 10 | slide = newSlide; 11 | window.location.href = window.location.href.replace(/#.+$/, '') + '#' + String(slide + 1); 12 | d3.selectAll('section').style('display', function(d, i) { 13 | if (i === slide) { 14 | return null; 15 | } else { 16 | return 'none'; 17 | } 18 | }).each(function(d, i) { 19 | if (i === slide && typeof d === 'function') { 20 | d(); 21 | } 22 | }); 23 | }; 24 | 25 | if (m = window.location.href.match(/#(\d+)$/)) { 26 | update(parseInt(m[1], 10) - 1); 27 | } else { 28 | update(0); 29 | } 30 | 31 | d3.select('body').on('keydown', function() { 32 | var newSlide; 33 | switch (d3.event.keyCode) { 34 | case 40: 35 | case 34: 36 | case 39: 37 | newSlide = d3.event.metaKey ? Infinity : slide + 1; 38 | break; 39 | case 38: 40 | case 33: 41 | case 37: 42 | newSlide = d3.event.metaKey ? 0 : slide - 1; 43 | break; 44 | case 32: 45 | newSlide = d3.event.shiftKey ? slide - 1 : slide + 1; 46 | break; 47 | default: 48 | return; 49 | } 50 | update(newSlide); 51 | d3.event.preventDefault(); 52 | }); 53 | })(); 54 | -------------------------------------------------------------------------------- /deck/deck.less: -------------------------------------------------------------------------------- 1 | * { 2 | -webkit-box-sizing: border-box; 3 | -moz-box-sizing: border-box; 4 | box-sizing: border-box; 5 | } 6 | 7 | h1 { 8 | margin: 0; 9 | } 10 | 11 | /* ---------------------------- */ 12 | 13 | .btn { 14 | display: inline-block; 15 | padding: 4px 10px 4px; 16 | font-size: 13px; 17 | line-height: 18px; 18 | color: #333333; 19 | text-align: center; 20 | text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); 21 | background-color: #fafafa; 22 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), color-stop(25%, #ffffff), to(#e6e6e6)); 23 | background-image: -webkit-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6); 24 | background-image: -moz-linear-gradient(top, #ffffff, #ffffff 25%, #e6e6e6); 25 | background-image: -ms-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6); 26 | background-image: -o-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6); 27 | background-image: linear-gradient(#ffffff, #ffffff 25%, #e6e6e6); 28 | background-repeat: no-repeat; 29 | border: 1px solid #ccc; 30 | border-bottom-color: #bbb; 31 | -webkit-border-radius: 4px; 32 | -moz-border-radius: 4px; 33 | border-radius: 4px; 34 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); 35 | -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); 36 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); 37 | cursor: pointer; 38 | 39 | &:hover { 40 | color: #333333; 41 | text-decoration: none; 42 | background-color: #e6e6e6; 43 | background-position: 0 -15px; 44 | -webkit-transition: background-position 0.1s linear; 45 | -moz-transition: background-position 0.1s linear; 46 | -ms-transition: background-position 0.1s linear; 47 | -o-transition: background-position 0.1s linear; 48 | transition: background-position 0.1s linear; 49 | } 50 | &:focus { 51 | outline: thin dotted; 52 | outline: 5px auto -webkit-focus-ring-color; 53 | outline-offset: -2px; 54 | } 55 | &.active, &:active { 56 | background-image: none; 57 | -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); 58 | -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); 59 | box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); 60 | background-color: #e6e6e6; 61 | background-color: #d9d9d9 \9; 62 | color: rgba(0, 0, 0, 0.5); 63 | outline: 0; 64 | } 65 | } 66 | 67 | 68 | /* ---------------------------- */ 69 | 70 | body { 71 | background: #929292; 72 | font-family: "Helvetica Neue", Arial, sans-serif; 73 | text-align: center; 74 | } 75 | 76 | section { 77 | width: 1024px; 78 | height: 768px; 79 | position: absolute; 80 | top: 50%; 81 | left: 50%; 82 | margin-left: -512px; 83 | margin-top: -384px; 84 | 85 | border-radius: 8px; 86 | -o-border-radius: 8px; 87 | -moz-border-radius: 8px; 88 | -webkit-border-radius: 8px; 89 | 90 | background: white; 91 | 92 | -moz-box-shadow: 0px 0px 2px 2px #ccc; 93 | -webkit-box-shadow: 0px 0px 2px 2px #ccc; 94 | box-shadow: 0px 0px 2px 2px #ccc; 95 | 96 | &.main_title { 97 | h1 { 98 | margin-top: 140px; 99 | font-size: 256px; 100 | } 101 | 102 | h2 { 103 | margin-top: 20px; 104 | font-size: 56px; 105 | } 106 | } 107 | 108 | &.title { 109 | h1 { 110 | margin-top: 310px; 111 | font-size: 40px; 112 | } 113 | } 114 | 115 | &.top_title { 116 | h1 { 117 | margin-top: 22px; 118 | margin-bottom: 15px; 119 | font-size: 36px; 120 | } 121 | 122 | a { 123 | display: block; 124 | margin-top: 30px; 125 | font-size: 28px; 126 | } 127 | } 128 | 129 | &.code_title { 130 | h1 { 131 | font-family: "Courier New", monospace; 132 | margin-top: 310px; 133 | font-size: 42px; 134 | } 135 | } 136 | 137 | &.code_slide { 138 | h1 { 139 | font-family: "Courier New", monospace; 140 | margin-top: 22px; 141 | font-size: 36px; 142 | } 143 | 144 | div.codes { 145 | position: absolute; 146 | left: 10px; 147 | bottom: 10px; 148 | right: 512px + 5px; 149 | top: 90px; 150 | 151 | textarea { 152 | font-family: "Courier New", monospace; 153 | text-align: left; 154 | width: 100%; 155 | height: 100%; 156 | border: 1px solid #ccc; 157 | font-size: 16px; 158 | padding: 4px 4px; 159 | resize: none; 160 | outline: none; 161 | white-space: pre; 162 | 163 | &.init { 164 | display: none; 165 | } 166 | } 167 | 168 | div.button_bar { 169 | position: absolute; 170 | right: 16px; 171 | bottom: 4px; 172 | 173 | div.reset, 174 | div.run { 175 | margin: 3px; 176 | } 177 | } 178 | } 179 | 180 | div.out { 181 | position: absolute; 182 | right: 10px; 183 | bottom: 10px; 184 | left: 512px + 5px; 185 | top: 90px; 186 | border: 1px solid #ccc; 187 | 188 | div.error { 189 | position: absolute; 190 | background: white; 191 | top: 5px; 192 | left: 5px; 193 | right: 5px; 194 | color: red; 195 | border: 2px solid red; 196 | z-index: 100; 197 | padding: 10px; 198 | font-size: 16px; 199 | } 200 | 201 | pre.log { 202 | position: absolute; 203 | background: white; 204 | top: 5px; 205 | left: 5px; 206 | right: 5px; 207 | border: 2px solid black; 208 | z-index: 99; 209 | padding: 10px; 210 | font-size: 16px; 211 | text-align: left; 212 | } 213 | } 214 | } 215 | } 216 | 217 | section { 218 | .name, 219 | .date { 220 | position: absolute; 221 | bottom: 20px; 222 | color: #999; 223 | } 224 | 225 | .name { 226 | left: 20px; 227 | } 228 | 229 | .date { 230 | right: 20px; 231 | } 232 | 233 | svg { 234 | width: 100%; 235 | height: 100%; 236 | 237 | rect { 238 | fill: #ccc; 239 | stroke: gray; 240 | stroke-width: 2px; 241 | } 242 | 243 | text { 244 | font: 16px sans-serif; 245 | } 246 | } 247 | 248 | a { 249 | color: steelblue; 250 | } 251 | 252 | a:not(:hover) { 253 | text-decoration: none; 254 | } 255 | 256 | .mmx { 257 | position: absolute; 258 | left: 50%; 259 | margin-left: -300px / 2; 260 | bottom: 3px; 261 | } 262 | } 263 | -------------------------------------------------------------------------------- /deck/slide_maker.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | "use strict" 3 | 4 | var slide = {}; 5 | window.slide = slide; 6 | 7 | slide.code = function(title, init, code) { 8 | var out, codeText; 9 | 10 | function myInit() { 11 | d3.selectAll('div.output').classed('output', false) 12 | out 13 | .classed('output', true) 14 | .selectAll('*').remove(); 15 | if (typeof init === 'function') init(); 16 | } 17 | 18 | var section = d3.select('body') 19 | .append('section') 20 | .data([myInit]) 21 | .attr('class', "code_slide") 22 | 23 | section.append('h1') 24 | .text(title) 25 | 26 | var codes = section.append('div') 27 | .attr('class', 'codes') 28 | 29 | function myConsoleLog() { 30 | var str = Array.prototype.slice.call(arguments).join(' ') + '\n'; 31 | var pre = out.select('pre.log'); 32 | if (pre.empty()) { 33 | out.append('pre') 34 | .attr('class', 'log') 35 | .text(str) 36 | } else { 37 | pre.text(pre.text() + str); 38 | } 39 | } 40 | 41 | function run() { 42 | var code = codeText.property('value'); 43 | code = '(function(console) { "use strict"\n' + code + '\n})({ log: myConsoleLog })'; 44 | out.select('div.error').remove(); 45 | out.select('pre.log').remove(); 46 | try { 47 | eval(code); 48 | } catch(err) { 49 | out.append('div') 50 | .attr('class', 'error') 51 | .text('Error: ' + err.message) 52 | } 53 | } 54 | 55 | codeText = codes.append('textarea') 56 | .attr('class', 'code') 57 | .attr('placeholder', 'JavaScript goes in here...') 58 | .property('value', code) 59 | .on('keydown', function() { 60 | // Run if command + enter 61 | if (d3.event.keyCode === 13 && d3.event.metaKey) run(); 62 | d3.event.stopPropagation(); 63 | }) 64 | 65 | var buttonBar = codes.append('div') 66 | .attr('class', 'button_bar') 67 | 68 | buttonBar.append('div') 69 | .attr('class', 'run btn') 70 | .text('Run') 71 | .on('click', run) 72 | 73 | buttonBar.append('div') 74 | .attr('class', 'reset btn') 75 | .text('Reset') 76 | .on('click', myInit) 77 | 78 | out = section.append('div') 79 | .attr('class', "out") 80 | } 81 | 82 | slide.code_title = function(title) { 83 | d3.select('body') 84 | .append('section') 85 | .attr('class', "code_title") 86 | .append('h1') 87 | .text(title); 88 | } 89 | 90 | slide.title = function(title) { 91 | d3.select('body') 92 | .append('section') 93 | .attr('class', "title") 94 | .append('h1') 95 | .text(title); 96 | } 97 | })(); 98 | 99 | 100 | -------------------------------------------------------------------------------- /example_bar_chart.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Introduction to D3 6 | 7 | 8 | 22 | 23 | 24 | 25 | 26 | 130 | 131 | -------------------------------------------------------------------------------- /example_sort.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Sorting 6 | 7 | 20 | 21 | 22 |
23 | 24 | 54 | 55 | -------------------------------------------------------------------------------- /images/inspect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vogievetsky/IntroD3/07b2415f8df5c3ed3c4f5762b6812afdb84e8f2d/images/inspect.png -------------------------------------------------------------------------------- /images/svgbook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vogievetsky/IntroD3/07b2415f8df5c3ed3c4f5762b6812afdb84e8f2d/images/svgbook.png -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | D3 Intro 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 |

D3

14 |

Data Driven Documents

15 | this = http://vadim.ogievetsky.com/IntroD3 16 |
17 | github = http://github.com/vogievetsky/IntroD3 18 |
Vadim Ogievetsky
19 |
Slides last updated November 18, 2014
20 |
21 | 22 | 23 | 24 |
25 |

Where to learn more about D3?

26 | https://developer.mozilla.org/en-US/docs/JavaScript/Guide 27 | http://d3js.org 28 | https://github.com/mbostock/d3/wiki 29 | http://groups.google.com/group/d3-js 30 | http://www.janwillemtulp.com/category/d3/ 31 |
32 | 33 |
34 |

Where to learn more about SVG?

35 | SVG Book 36 | Chrome Inspect Element 37 |
38 | 39 |
40 |

Questions?

41 |
42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /slide_maker.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | "use strict" 3 | 4 | var slide = {}; 5 | window.slide = slide; 6 | 7 | function fn_to_string(fn) { 8 | var lines = fn.toString() 9 | .replace(/^function\s*\([^)]*\)\s*{\s*\n/, '') 10 | .replace(/\s*}\s*$/, '') 11 | .split('\n'); 12 | 13 | // remove common pre-space 14 | var minSpace = d3.min(lines.map(function(line) { 15 | return line ? line.match(/^\s*/)[0].length : Infinity; 16 | })); 17 | if (minSpace && isFinite(minSpace)) { 18 | lines = lines.map(function(line) { return line.substr(minSpace); }) 19 | } 20 | 21 | return lines.join('\n'); 22 | } 23 | 24 | slide.code = function(title, init, code) { 25 | var out, codeText; 26 | 27 | function myInit() { 28 | out.selectAll('*').remove(); 29 | init(out.node()); 30 | } 31 | 32 | var section = d3.select('body') 33 | .append('section') 34 | .data([myInit]) 35 | .attr('class', "code_slide") 36 | 37 | section.append('h1') 38 | .text(title) 39 | 40 | var codes = section.append('div') 41 | .attr('class', 'codes') 42 | 43 | function myConsoleLog() { 44 | var str = Array.prototype.slice.call(arguments).join(' ') + '\n'; 45 | var pre = out.select('pre.log'); 46 | if (pre.empty()) { 47 | out.append('pre') 48 | .attr('class', 'log') 49 | .text(str) 50 | } else { 51 | pre.text(pre.text() + str); 52 | } 53 | } 54 | 55 | function run() { 56 | var code = codeText.property('value'); 57 | code = '(function(console) { \n' + code + '\n})({ log: myConsoleLog })'; 58 | out.select('div.error').remove(); 59 | out.select('pre.log').remove(); 60 | try { 61 | eval(code); 62 | } catch(err) { 63 | out.append('div') 64 | .attr('class', 'error') 65 | .text('Error: ' + err.message) 66 | } 67 | } 68 | 69 | codeText = codes.append('textarea') 70 | .attr('class', 'code') 71 | .property('value', fn_to_string(code)) 72 | .on('keydown', function() { 73 | // Run if command + enter 74 | if (d3.event.keyCode === 13 && d3.event.metaKey) run(); 75 | d3.event.stopPropagation(); 76 | }) 77 | 78 | var buttonBar = codes.append('div') 79 | .attr('class', 'button_bar') 80 | 81 | buttonBar.append('div') 82 | .attr('class', 'run btn') 83 | .text('Run') 84 | .on('click', run) 85 | 86 | buttonBar.append('div') 87 | .attr('class', 'reset btn') 88 | .text('Reset') 89 | .on('click', myInit) 90 | 91 | out = section.append('div') 92 | .attr('class', "out") 93 | } 94 | 95 | slide.code_title = function(title) { 96 | d3.select('body') 97 | .append('section') 98 | .attr('class', "code_title") 99 | .append('h1') 100 | .text(title); 101 | } 102 | 103 | slide.title = function(title) { 104 | d3.select('body') 105 | .append('section') 106 | .attr('class', "title") 107 | .append('h1') 108 | .text(title); 109 | } 110 | })(); 111 | 112 | 113 | -------------------------------------------------------------------------------- /slides.coffee: -------------------------------------------------------------------------------- 1 | empty_svg = -> 2 | d3.select('div.output') 3 | .append('svg') 4 | 5 | rect1 = -> 6 | svg = d3.select('div.output') 7 | .append('svg') 8 | 9 | svg.append("rect") 10 | .attr("x", 150) 11 | .attr("y", 100) 12 | .attr("width", 60) 13 | .attr("height", 300) 14 | 15 | 16 | rect3 = -> 17 | svg = d3.select('div.output') 18 | .append('svg') 19 | 20 | svg.append("rect") 21 | .attr("x", 200) 22 | .attr("y", 300) 23 | .attr("width", 40) 24 | .attr("height", 50) 25 | 26 | svg.append("rect") 27 | .attr("x", 100) 28 | .attr("y", 20) 29 | .attr("width", 30) 30 | .attr("height", 50) 31 | 32 | svg.append("rect") 33 | .attr("x", 10) 34 | .attr("y", 200) 35 | .attr("width", 25) 36 | .attr("height", 90) 37 | 38 | # ---------------------------------------------------- 39 | 40 | slide.title "First, some JavaScript" 41 | 42 | slide.code "JavaScript", null, """ 43 | // In JS functions are first class citizens. 44 | // This is a very powerful concept! 45 | function sq1(x) { 46 | return x * x 47 | } 48 | 49 | var sq2 = function(x) { 50 | return x * x 51 | } 52 | 53 | console.log("sq1(4) ==", sq1(4)) // == 16 54 | console.log("sq2(4) ==", sq2(4)) // == 16 55 | 56 | sq1.foo = 8 57 | sq2.bar = 3 58 | 59 | console.log("Trippy:", sq1(sq1.foo + sq2.bar)) 60 | """ 61 | 62 | slide.code "JavaScript to the Max", null, """ 63 | // Functions can be used to 'bake in' state 64 | 65 | var formatter = function(prefix, fixed) { 66 | if (prefix == null) { prefix = '' } 67 | if (fixed == null) { fixed = 2 } 68 | return function(number) { 69 | return prefix + number.toFixed(fixed) 70 | } 71 | } 72 | 73 | var currency = formatter('$', 2) 74 | var roughly = formatter('~ ', 1) 75 | 76 | console.log("currency(31/3) ==", currency(31/3)) 77 | 78 | console.log("roughly(31/3) ==", roughly(31/3)) 79 | """ 80 | 81 | slide.code "JavaScript to the Max", null, """ 82 | // D3 has many helper methods 83 | // d3.scale.linear() returns a function that 84 | // will map the given domain to the given 85 | // range linearly. 86 | var w = 640, h = 320 87 | 88 | // x is a function! 89 | var x = d3.scale.linear() 90 | .domain([-1, 1]) 91 | .range([0, w]) 92 | 93 | // y is also a function! 94 | var y = d3.scale.linear() 95 | .domain([0, 1]) 96 | .range([0, h]) 97 | 98 | console.log("x(0) ==", x(0)) // == w/2 99 | console.log("y(3) ==", y(3)) // == 3*h 100 | """ 101 | 102 | slide.title "Core D3" 103 | 104 | # ----------------------------------------------- 105 | slide.code_title title = ".select()" 106 | 107 | slide.code title, rect1, """ 108 | var svg = d3.select("div.output svg") 109 | 110 | 111 | var myRect = svg.select("rect") 112 | myRect.attr("width", 100) 113 | myRect.attr("height", 100) 114 | myRect.style("fill", "steelblue") 115 | """ 116 | 117 | slide.code title, rect1, """ 118 | var svg = d3.select("div.output svg") 119 | 120 | // Chain style 121 | svg.select("rect") 122 | .attr("width", 100) 123 | .attr("height", 100) 124 | .style("fill", "steelblue") 125 | """ 126 | 127 | slide.code title, rect1, """ 128 | var svg = d3.select("div.output svg") 129 | 130 | // Object map style 131 | svg.select("rect") 132 | .attr({ 133 | width: 100, 134 | height: 100 135 | }) 136 | .style("fill", "steelblue") 137 | """ 138 | 139 | # ----------------------------------------------- 140 | slide.code_title title = ".selectAll()" 141 | 142 | slide.code title, rect3, """ 143 | var svg = d3.select("div.output svg") 144 | 145 | svg.select("rect") 146 | .attr("width", 100) 147 | .attr("height", 100) 148 | .style("fill", "steelblue") 149 | """ 150 | 151 | slide.code title, rect3, """ 152 | var svg = d3.select("div.output svg") 153 | 154 | svg.selectAll("rect") 155 | .attr("width", 100) 156 | .attr("height", 100) 157 | .style("fill", "steelblue") 158 | """ 159 | 160 | slide.code title, rect3, """ 161 | var svg = d3.select("div.output svg") 162 | 163 | svg.selectAll("rect") 164 | .attr("x", 0) 165 | .attr("y", function(d,i) { return i*90+50 }) 166 | .attr("width", function(d,i) { 167 | return i*150+100; 168 | }) 169 | .attr("height", 20) 170 | .style("fill", "steelblue") 171 | """ 172 | 173 | 174 | # ----------------------------------------------- 175 | slide.code_title title = ".data()" 176 | 177 | slide.code title, rect3, """ 178 | var svg = d3.select("div.output svg") 179 | 180 | svg.selectAll("rect") 181 | .data([127, 61, 256]) 182 | .attr("x", 0) 183 | .attr("y", function(d,i) { return i*90+50 }) 184 | .attr("width", function(d,i) { return d; }) 185 | .attr("height", 20) 186 | .style("fill", "steelblue") 187 | """ 188 | 189 | # ----------------------------------------------- 190 | slide.code_title title = ".enter()" 191 | 192 | slide.code title, rect3, """ 193 | var svg = d3.select("div.output svg") 194 | 195 | var selection = svg.selectAll("rect") 196 | .data([127, 61, 256, 71]) 197 | 198 | selection 199 | .attr("x", 0) 200 | .attr("y", function(d,i) { return i*90+50 }) 201 | .attr("width", function(d,i) { return d; }) 202 | .attr("height", 20) 203 | .style("fill", "steelblue") 204 | """ 205 | 206 | slide.code title, rect3, """ 207 | var svg = d3.select("div.output svg") 208 | 209 | var selection = svg.selectAll("rect") 210 | .data([127, 61, 256, 71]) 211 | 212 | selection 213 | .attr("x", 0) 214 | .attr("y", function(d,i) { return i*90+50 }) 215 | .attr("width", function(d,i) { return d; }) 216 | .attr("height", 20) 217 | .style("fill", "steelblue") 218 | 219 | selection.enter().append("rect") 220 | .attr("x", 10) // let's just put it somewhere 221 | .attr("y", 10) 222 | .attr("width", 30) 223 | .attr("height", 30) 224 | .style("fill", "green") 225 | """ 226 | 227 | slide.code title, rect3, """ 228 | var svg = d3.select("div.output svg") 229 | 230 | var selection = svg.selectAll("rect") 231 | .data([127, 61, 256, 71]) 232 | 233 | selection 234 | .attr("x", 0) 235 | .attr("y", function(d,i) { return i*90+50 }) 236 | .attr("width", function(d,i) { return d; }) 237 | .attr("height", 20) 238 | .style("fill", "steelblue") 239 | 240 | selection.enter().append("rect") 241 | .attr("x", 0) 242 | .attr("y", function(d,i) { return i*90+50 }) 243 | .attr("width", function(d,i) { return d; }) 244 | .attr("height", 20) 245 | .style("fill", "steelblue") 246 | """ 247 | 248 | slide.code title, rect3, """ 249 | var svg = d3.select("div.output svg") 250 | 251 | var selection = svg.selectAll("rect") 252 | .data([127, 61, 256, 71]) 253 | 254 | // Shorter 255 | selection.enter().append("rect") 256 | 257 | // when updating the regular selection then 258 | // enter selection is joined in to the update 259 | // selection for convenience. 260 | selection 261 | .attr("x", 0) 262 | .attr("y", function(d,i) { return i*90+50 }) 263 | .attr("width", function(d,i) { return d; }) 264 | .attr("height", 20) 265 | .style("fill", "steelblue") 266 | """ 267 | 268 | title += " // a common pattern" 269 | slide.code title, empty_svg, """ 270 | var svg = d3.select("div.output svg") 271 | 272 | svg.selectAll("rect") 273 | .data([127, 61, 256]) 274 | .enter().append("rect") 275 | .attr("x", 0) 276 | .attr("y", function(d,i) { return i*90+50 }) 277 | .attr("width", function(d,i) { return d; }) 278 | .attr("height", 20) 279 | .style("fill", "steelblue") 280 | """ 281 | 282 | 283 | # ----------------------------------------------- 284 | slide.code_title title = ".exit()" 285 | 286 | slide.code title, rect3, """ 287 | var svg = d3.select("div.output svg") 288 | 289 | var selection = svg.selectAll("rect") 290 | .data([127, 61]) 291 | 292 | selection 293 | .attr("x", 0) 294 | .attr("y", function(d,i) { return i*90+50 }) 295 | .attr("width", function(d,i) { return d; }) 296 | .attr("height", 20) 297 | .style("fill", "steelblue") 298 | """ 299 | 300 | slide.code title, rect3, """ 301 | var svg = d3.select("div.output svg") 302 | 303 | var selection = svg.selectAll("rect") 304 | .data([127, 61]) 305 | 306 | selection 307 | .attr("x", 0) 308 | .attr("y", function(d,i) { return i*90+50 }) 309 | .attr("width", function(d,i) { return d; }) 310 | .attr("height", 20) 311 | .style("fill", "steelblue") 312 | 313 | selection.exit() 314 | .remove() 315 | """ 316 | 317 | 318 | # ----------------------------------------------- 319 | slide.code_title title = ".transition()" 320 | 321 | slide.code title, rect3, """ 322 | var svg = d3.select("div.output svg") 323 | 324 | svg.selectAll("rect") 325 | .data([127, 61, 256]) 326 | .transition() 327 | .duration(3000) // 3 seconds 328 | .attr("x", 0) 329 | .attr("y", function(d,i) { return i*90+50 }) 330 | .attr("width", function(d,i) { return d; }) 331 | .attr("height", 20) 332 | .style("fill", "steelblue") 333 | """ 334 | 335 | slide.code title, rect3, """ 336 | var svg = d3.select("div.output svg") 337 | 338 | var selection = svg.selectAll("rect") 339 | .data([127, 61, 256, 71]) 340 | 341 | selection.enter().append("rect") 342 | .attr("x", 200) 343 | .attr("y", 200) 344 | .attr("width", 10) 345 | .attr("height", 10) 346 | .style("fill", "red") 347 | 348 | selection 349 | .transition() 350 | .duration(3000) 351 | .attr("x", 0) 352 | .attr("y", function(d,i) { return i*90+50 }) 353 | .attr("width", function(d,i) { return d; }) 354 | .attr("height", 20) 355 | .style("fill", "steelblue") 356 | .transition() 357 | .duration(3000) 358 | .delay(3000) 359 | .style("fill", "green") 360 | .attr("width", function(d,i) { 361 | return d*1.5; 362 | }) 363 | 364 | selection.exit() 365 | .attr("opacity", 1) 366 | .transition() 367 | .duration(3000) 368 | .attr("opacity", 0) 369 | .remove() 370 | """ 371 | 372 | # ----------------------------------------------- 373 | slide.code_title title = ".data(..., join)" 374 | 375 | init_svg = -> 376 | svg = d3.select("div.output").append("svg") 377 | 378 | svg.selectAll("rect") 379 | .data([127, 61, 256]) 380 | .enter().append("rect") 381 | .attr("x", 0) 382 | .attr("y", (d,i) -> i*90+50) 383 | .attr("width", (d,i) -> d) 384 | .attr("height", 20) 385 | .style("fill", "steelblue") 386 | 387 | slide.code title, init_svg, """ 388 | var svg = d3.select("div.output svg") 389 | 390 | // Let's say we start here: 391 | /* 392 | svg.selectAll("rect") 393 | .data([127, 61, 256]) 394 | .enter().append("rect") 395 | .attr("x", 0) 396 | .attr("y", function(d,i) { return i*90+50 }) 397 | .attr("width", function(d,i) { return d; }) 398 | .attr("height", 20) 399 | .style("fill", "steelblue") 400 | */ 401 | 402 | // And then we do this: 403 | var selection = svg.selectAll("rect") 404 | .data([61, 256, 71]) // <- incomplete? 405 | 406 | selection.enter().append("rect") 407 | .attr("x", 0) 408 | .attr("y", function(d,i) { return i*90+50 }) 409 | .attr("width", function(d,i) { return d; }) 410 | .attr("height", 20) 411 | .style("fill", "steelblue") 412 | 413 | selection 414 | .transition() 415 | .duration(3000) 416 | .attr("x", 0) 417 | .attr("y", function(d,i) { return i*90+50 }) 418 | .attr("width", function(d,i) { return d; }) 419 | .attr("height", 20) 420 | .style("fill", "steelblue") 421 | 422 | selection.exit() 423 | .remove() 424 | """ 425 | 426 | slide.code title, init_svg, """ 427 | // Start the same as before 428 | 429 | var svg = d3.select("div.output svg") 430 | 431 | var selection = svg.selectAll("rect") 432 | .data([61, 256, 71], String) 433 | 434 | selection.enter().append("rect") 435 | .attr("x", 0) 436 | .attr("y", function(d,i) { 437 | return (i+1)*90+50 438 | }) 439 | .attr("width", function(d,i) { return d; }) 440 | .attr("height", 20) 441 | .style("fill", "steelblue") 442 | .style("opacity", 0) 443 | 444 | selection 445 | .transition() 446 | .duration(3000) 447 | .attr("y", function(d,i) { return i*90+50 }) 448 | .attr("height", 20) 449 | .style("opacity", 1) 450 | 451 | selection.exit() 452 | .transition() 453 | .duration(3000) 454 | .attr("y", function(d,i) { 455 | return (i-1)*90+50 456 | }) 457 | .style("opacity", 0) 458 | .remove() 459 | """ 460 | 461 | # ----------------------------------------------- 462 | slide.title title = "Nested Selections" 463 | 464 | slide.code title, empty_svg, """ 465 | var myData = [ 466 | [15, 20], 467 | [40, 10], 468 | [30, 17] 469 | ] 470 | 471 | var svg = d3.select("div.output svg") 472 | 473 | // First selection (within svg) 474 | 475 | var selA = svg.selectAll("g").data(myData) 476 | selA.enter().append("g") 477 | selA.attr("transform", function(d,i) { 478 | return 'translate(70,' + (i*100+50) + ')' 479 | }) 480 | selA.exit().remove() 481 | 482 | // Second selection (within first selection) 483 | 484 | var selB = selA.selectAll('circle') 485 | .data(function(d) { return d }) 486 | selB.enter().append('circle') 487 | selB 488 | .attr("cx", function(d,i) { return i*80 }) 489 | .attr("r", function(d,i) { return d }) 490 | selB.exit().remove() 491 | """ 492 | 493 | # ----------------------------------------------- 494 | slide.title "Useful Examples" 495 | 496 | slide.code "Shuffle", empty_svg, """ 497 | var cards = [ 498 | "J\\u2665", "J\\u2666", "J\\u2663", "J\\u2660", 499 | "K\\u2665", "K\\u2666", "K\\u2663", "K\\u2660", 500 | "Q\\u2665", "Q\\u2666", "Q\\u2663", "Q\\u2660", 501 | "A\\u2665", "A\\u2666", "A\\u2663", "A\\u2660"] 502 | 503 | cards.sort(function() {return Math.random()-.5}) 504 | 505 | var svg = d3.select("div.output svg") 506 | 507 | var selection = svg.selectAll("text") 508 | .data(cards, String) 509 | 510 | selection 511 | .transition() 512 | .duration(1000) 513 | .attr("y", function(d,i) { return i*35+40 }) 514 | 515 | selection.enter().append("text") 516 | .attr("x", 30) 517 | .attr("y", function(d,i) { return i*35+40 }) 518 | .style("fill", function(d) { 519 | return "\\u2665\\u2666".indexOf(d[1]) < 0 ? 520 | "black" : "red"; 521 | }) 522 | .style("font", "20px monospace") 523 | .text(String) 524 | """ 525 | 526 | slide.code "Shuffle (v2)", empty_svg, """ 527 | var cards = [ 528 | "J\\u2665", "J\\u2666", "J\\u2663", "J\\u2660", 529 | "K\\u2665", "K\\u2666", "K\\u2663", "K\\u2660", 530 | "Q\\u2665", "Q\\u2666", "Q\\u2663", "Q\\u2660", 531 | "A\\u2665", "A\\u2666", "A\\u2663", "A\\u2660"] 532 | 533 | cards.sort(function() {return Math.random()-.5}) 534 | 535 | var svg = d3.select("div.output svg") 536 | 537 | var selection = svg.selectAll("text") 538 | .data(cards, String) 539 | 540 | selection 541 | .transition().duration(500) 542 | .attr("x", function(d,i) {return (i%8)*30+30}) 543 | .transition().duration(500).delay(500) 544 | .attr("y", function(d,i) { return i*35+40 }) 545 | .transition().duration(500).delay(1000) 546 | .attr("x", 30) 547 | 548 | selection.enter().append("text") 549 | .attr("x", 30) 550 | .attr("y", function(d,i) { return i*35+40 }) 551 | .style("fill", function(d) { 552 | return "\\u2665\\u2666".indexOf(d[1]) < 0 ? 553 | "black" : "red"; 554 | }) 555 | .style("font", "20px monospace") 556 | .text(String) 557 | """ 558 | 559 | # ----------------------------------------------- 560 | slide.code "Drawing lines", empty_svg, """ 561 | var svg = d3.select("div.output svg") 562 | 563 | svg.append("path") 564 | .style("fill", "none") 565 | .style("stroke", "black") 566 | .style("stroke-width", 2) 567 | .attr("d", "M 10 10 L 200 200 "+ 568 | "L 200 400 L 300 100 L 400 150") 569 | """ 570 | 571 | slide.code "Drawing lines", empty_svg, """ 572 | var points = [ 573 | { x: 10, y: 10 }, 574 | { x: 200, y: 200 }, 575 | { x: 200, y: 400 }, 576 | { x: 300, y: 100 }, 577 | { x: 400, y: 150 } 578 | ] 579 | 580 | var lineFn = d3.svg.line() 581 | .x(function(d) { return d.x }) 582 | .y(function(d) { return d.y }) 583 | //.interpolate("cardinal") 584 | 585 | var svg = d3.select("div.output svg") 586 | 587 | svg.append("path") 588 | .style("fill", "none") 589 | .style("stroke", "black") 590 | .style("stroke-width", 2) 591 | .attr("d", lineFn(points)) 592 | """ 593 | 594 | slide.code "Drawing lines", empty_svg, """ 595 | var pointsSin = d3.range(21).map(function(i) { 596 | return {x: i, y: Math.sin(i/3) } 597 | }) 598 | var pointsCos = d3.range(21).map(function(i) { 599 | return {x: i, y: Math.cos(i/3) } 600 | }) 601 | 602 | 603 | var w = 480 604 | var h = 300 605 | var x = d3.scale.linear() 606 | .domain([0, 20]).range([0, w]) 607 | var y = d3.scale.linear() 608 | .domain([-1, 1]).range([h, 0]) 609 | 610 | var lineFn = d3.svg.line() 611 | .x(function(d) { return x(d.x) }) 612 | .y(function(d) { return y(d.y) }) 613 | 614 | var svg = d3.select("div.output svg") 615 | 616 | svg.selectAll("path") 617 | .data([pointsSin, pointsCos]) 618 | .enter().append("path") 619 | .style("fill", "none") 620 | .style("stroke", "black") 621 | .style("stroke-width", 2) 622 | .attr("d", lineFn) 623 | """ 624 | 625 | -------------------------------------------------------------------------------- /slides.js: -------------------------------------------------------------------------------- 1 | // Generated by CoffeeScript 1.3.1 2 | (function() { 3 | var empty_svg, init_svg, rect1, rect3, title; 4 | 5 | empty_svg = function() { 6 | return d3.select('div.output').append('svg'); 7 | }; 8 | 9 | rect1 = function() { 10 | var svg; 11 | svg = d3.select('div.output').append('svg'); 12 | return svg.append("rect").attr("x", 150).attr("y", 100).attr("width", 60).attr("height", 300); 13 | }; 14 | 15 | rect3 = function() { 16 | var svg; 17 | svg = d3.select('div.output').append('svg'); 18 | svg.append("rect").attr("x", 200).attr("y", 300).attr("width", 40).attr("height", 50); 19 | svg.append("rect").attr("x", 100).attr("y", 20).attr("width", 30).attr("height", 50); 20 | return svg.append("rect").attr("x", 10).attr("y", 200).attr("width", 25).attr("height", 90); 21 | }; 22 | 23 | slide.title("First, some JavaScript"); 24 | 25 | slide.code("JavaScript", null, "// In JS functions are first class citizens.\n// This is a very powerful concept!\nfunction sq1(x) {\n return x * x\n}\n\nvar sq2 = function(x) {\n return x * x\n}\n\nconsole.log(\"sq1(4) ==\", sq1(4)) // == 16\nconsole.log(\"sq2(4) ==\", sq2(4)) // == 16\n\nsq1.foo = 8\nsq2.bar = 3\n\nconsole.log(\"Trippy:\", sq1(sq1.foo + sq2.bar))"); 26 | 27 | slide.code("JavaScript to the Max", null, "// Functions can be used to 'bake in' state\n\nvar formatter = function(prefix, fixed) {\n if (prefix == null) { prefix = '' }\n if (fixed == null) { fixed = 2 }\n return function(number) {\n return prefix + number.toFixed(fixed)\n }\n}\n\nvar currency = formatter('$', 2)\nvar roughly = formatter('~ ', 1)\n\nconsole.log(\"currency(31/3) ==\", currency(31/3))\n\nconsole.log(\"roughly(31/3) ==\", roughly(31/3))"); 28 | 29 | slide.code("JavaScript to the Max", null, "// D3 has many helper methods\n// d3.scale.linear() returns a function that\n// will map the given domain to the given\n// range linearly.\nvar w = 640, h = 320\n\n// x is a function!\nvar x = d3.scale.linear()\n .domain([-1, 1])\n .range([0, w])\n\n// y is also a function!\nvar y = d3.scale.linear()\n .domain([0, 1])\n .range([0, h])\n\nconsole.log(\"x(0) ==\", x(0)) // == w/2\nconsole.log(\"y(3) ==\", y(3)) // == 3*h"); 30 | 31 | slide.title("Core D3"); 32 | 33 | slide.code_title(title = ".select()"); 34 | 35 | slide.code(title, rect1, "var svg = d3.select(\"div.output svg\")\n\n\nvar myRect = svg.select(\"rect\")\nmyRect.attr(\"width\", 100)\nmyRect.attr(\"height\", 100)\nmyRect.style(\"fill\", \"steelblue\")"); 36 | 37 | slide.code(title, rect1, "var svg = d3.select(\"div.output svg\")\n\n// Chain style\nsvg.select(\"rect\")\n .attr(\"width\", 100)\n .attr(\"height\", 100)\n .style(\"fill\", \"steelblue\")"); 38 | 39 | slide.code(title, rect1, "var svg = d3.select(\"div.output svg\")\n\n// Object map style\nsvg.select(\"rect\")\n .attr({\n width: 100,\n height: 100\n })\n .style(\"fill\", \"steelblue\")"); 40 | 41 | slide.code_title(title = ".selectAll()"); 42 | 43 | slide.code(title, rect3, "var svg = d3.select(\"div.output svg\")\n\nsvg.select(\"rect\")\n .attr(\"width\", 100)\n .attr(\"height\", 100)\n .style(\"fill\", \"steelblue\")"); 44 | 45 | slide.code(title, rect3, "var svg = d3.select(\"div.output svg\")\n\nsvg.selectAll(\"rect\")\n .attr(\"width\", 100)\n .attr(\"height\", 100)\n .style(\"fill\", \"steelblue\")"); 46 | 47 | slide.code(title, rect3, "var svg = d3.select(\"div.output svg\")\n\nsvg.selectAll(\"rect\")\n .attr(\"x\", 0)\n .attr(\"y\", function(d,i) { return i*90+50 })\n .attr(\"width\", function(d,i) {\n return i*150+100;\n })\n .attr(\"height\", 20)\n .style(\"fill\", \"steelblue\")"); 48 | 49 | slide.code_title(title = ".data()"); 50 | 51 | slide.code(title, rect3, "var svg = d3.select(\"div.output svg\")\n\nsvg.selectAll(\"rect\")\n .data([127, 61, 256])\n .attr(\"x\", 0)\n .attr(\"y\", function(d,i) { return i*90+50 })\n .attr(\"width\", function(d,i) { return d; })\n .attr(\"height\", 20)\n .style(\"fill\", \"steelblue\")"); 52 | 53 | slide.code_title(title = ".enter()"); 54 | 55 | slide.code(title, rect3, "var svg = d3.select(\"div.output svg\")\n\nvar selection = svg.selectAll(\"rect\")\n .data([127, 61, 256, 71])\n\nselection\n .attr(\"x\", 0)\n .attr(\"y\", function(d,i) { return i*90+50 })\n .attr(\"width\", function(d,i) { return d; })\n .attr(\"height\", 20)\n .style(\"fill\", \"steelblue\")"); 56 | 57 | slide.code(title, rect3, "var svg = d3.select(\"div.output svg\")\n\nvar selection = svg.selectAll(\"rect\")\n .data([127, 61, 256, 71])\n\nselection\n .attr(\"x\", 0)\n .attr(\"y\", function(d,i) { return i*90+50 })\n .attr(\"width\", function(d,i) { return d; })\n .attr(\"height\", 20)\n .style(\"fill\", \"steelblue\")\n\nselection.enter().append(\"rect\")\n .attr(\"x\", 10) // let's just put it somewhere\n .attr(\"y\", 10)\n .attr(\"width\", 30)\n .attr(\"height\", 30)\n .style(\"fill\", \"green\")"); 58 | 59 | slide.code(title, rect3, "var svg = d3.select(\"div.output svg\")\n\nvar selection = svg.selectAll(\"rect\")\n .data([127, 61, 256, 71])\n\nselection\n .attr(\"x\", 0)\n .attr(\"y\", function(d,i) { return i*90+50 })\n .attr(\"width\", function(d,i) { return d; })\n .attr(\"height\", 20)\n .style(\"fill\", \"steelblue\")\n\nselection.enter().append(\"rect\")\n .attr(\"x\", 0)\n .attr(\"y\", function(d,i) { return i*90+50 })\n .attr(\"width\", function(d,i) { return d; })\n .attr(\"height\", 20)\n .style(\"fill\", \"steelblue\")"); 60 | 61 | slide.code(title, rect3, "var svg = d3.select(\"div.output svg\")\n\nvar selection = svg.selectAll(\"rect\")\n .data([127, 61, 256, 71])\n\n// Shorter\nselection.enter().append(\"rect\")\n\n// when updating the regular selection then\n// enter selection is joined in to the update\n// selection for convenience.\nselection\n .attr(\"x\", 0)\n .attr(\"y\", function(d,i) { return i*90+50 })\n .attr(\"width\", function(d,i) { return d; })\n .attr(\"height\", 20)\n .style(\"fill\", \"steelblue\")"); 62 | 63 | title += " // a common pattern"; 64 | 65 | slide.code(title, empty_svg, "var svg = d3.select(\"div.output svg\")\n\nsvg.selectAll(\"rect\")\n .data([127, 61, 256])\n .enter().append(\"rect\")\n .attr(\"x\", 0)\n .attr(\"y\", function(d,i) { return i*90+50 })\n .attr(\"width\", function(d,i) { return d; })\n .attr(\"height\", 20)\n .style(\"fill\", \"steelblue\")"); 66 | 67 | slide.code_title(title = ".exit()"); 68 | 69 | slide.code(title, rect3, "var svg = d3.select(\"div.output svg\")\n\nvar selection = svg.selectAll(\"rect\")\n .data([127, 61])\n\nselection\n .attr(\"x\", 0)\n .attr(\"y\", function(d,i) { return i*90+50 })\n .attr(\"width\", function(d,i) { return d; })\n .attr(\"height\", 20)\n .style(\"fill\", \"steelblue\")"); 70 | 71 | slide.code(title, rect3, "var svg = d3.select(\"div.output svg\")\n\nvar selection = svg.selectAll(\"rect\")\n .data([127, 61])\n\nselection\n .attr(\"x\", 0)\n .attr(\"y\", function(d,i) { return i*90+50 })\n .attr(\"width\", function(d,i) { return d; })\n .attr(\"height\", 20)\n .style(\"fill\", \"steelblue\")\n\nselection.exit()\n .remove()"); 72 | 73 | slide.code_title(title = ".transition()"); 74 | 75 | slide.code(title, rect3, "var svg = d3.select(\"div.output svg\")\n\nsvg.selectAll(\"rect\")\n .data([127, 61, 256])\n .transition()\n .duration(3000) // 3 seconds\n .attr(\"x\", 0)\n .attr(\"y\", function(d,i) { return i*90+50 })\n .attr(\"width\", function(d,i) { return d; })\n .attr(\"height\", 20)\n .style(\"fill\", \"steelblue\")"); 76 | 77 | slide.code(title, rect3, "var svg = d3.select(\"div.output svg\")\n\nvar selection = svg.selectAll(\"rect\")\n .data([127, 61, 256, 71])\n\nselection.enter().append(\"rect\")\n .attr(\"x\", 200)\n .attr(\"y\", 200)\n .attr(\"width\", 10)\n .attr(\"height\", 10)\n .style(\"fill\", \"red\")\n\nselection\n .transition()\n .duration(3000)\n .attr(\"x\", 0)\n .attr(\"y\", function(d,i) { return i*90+50 })\n .attr(\"width\", function(d,i) { return d; })\n .attr(\"height\", 20)\n .style(\"fill\", \"steelblue\")\n .transition()\n .duration(3000)\n .delay(3000)\n .style(\"fill\", \"green\")\n .attr(\"width\", function(d,i) {\n return d*1.5;\n })\n\nselection.exit()\n .attr(\"opacity\", 1)\n .transition()\n .duration(3000)\n .attr(\"opacity\", 0)\n .remove()"); 78 | 79 | slide.code_title(title = ".data(..., join)"); 80 | 81 | init_svg = function() { 82 | var svg; 83 | svg = d3.select("div.output").append("svg"); 84 | return svg.selectAll("rect").data([127, 61, 256]).enter().append("rect").attr("x", 0).attr("y", function(d, i) { 85 | return i * 90 + 50; 86 | }).attr("width", function(d, i) { 87 | return d; 88 | }).attr("height", 20).style("fill", "steelblue"); 89 | }; 90 | 91 | slide.code(title, init_svg, "var svg = d3.select(\"div.output svg\")\n\n// Let's say we start here:\n/*\nsvg.selectAll(\"rect\")\n .data([127, 61, 256])\n .enter().append(\"rect\")\n .attr(\"x\", 0)\n .attr(\"y\", function(d,i) { return i*90+50 })\n .attr(\"width\", function(d,i) { return d; })\n .attr(\"height\", 20)\n .style(\"fill\", \"steelblue\")\n*/\n\n// And then we do this:\nvar selection = svg.selectAll(\"rect\")\n .data([61, 256, 71]) // <- incomplete?\n\nselection.enter().append(\"rect\")\n .attr(\"x\", 0)\n .attr(\"y\", function(d,i) { return i*90+50 })\n .attr(\"width\", function(d,i) { return d; })\n .attr(\"height\", 20)\n .style(\"fill\", \"steelblue\")\n\nselection\n .transition()\n .duration(3000)\n .attr(\"x\", 0)\n .attr(\"y\", function(d,i) { return i*90+50 })\n .attr(\"width\", function(d,i) { return d; })\n .attr(\"height\", 20)\n .style(\"fill\", \"steelblue\")\n\nselection.exit()\n .remove()"); 92 | 93 | slide.code(title, init_svg, "// Start the same as before\n\nvar svg = d3.select(\"div.output svg\")\n\nvar selection = svg.selectAll(\"rect\")\n .data([61, 256, 71], String)\n\nselection.enter().append(\"rect\")\n .attr(\"x\", 0)\n .attr(\"y\", function(d,i) {\n return (i+1)*90+50\n })\n .attr(\"width\", function(d,i) { return d; })\n .attr(\"height\", 20)\n .style(\"fill\", \"steelblue\")\n .style(\"opacity\", 0)\n\nselection\n .transition()\n .duration(3000)\n .attr(\"y\", function(d,i) { return i*90+50 })\n .attr(\"height\", 20)\n .style(\"opacity\", 1)\n\nselection.exit()\n .transition()\n .duration(3000)\n .attr(\"y\", function(d,i) {\n return (i-1)*90+50\n })\n .style(\"opacity\", 0)\n .remove()"); 94 | 95 | slide.title(title = "Nested Selections"); 96 | 97 | slide.code(title, empty_svg, "var myData = [\n [15, 20],\n [40, 10],\n [30, 17]\n]\n\nvar svg = d3.select(\"div.output svg\")\n\n// First selection (within svg)\n\nvar selA = svg.selectAll(\"g\").data(myData)\nselA.enter().append(\"g\")\nselA.attr(\"transform\", function(d,i) {\n return 'translate(70,' + (i*100+50) + ')'\n})\nselA.exit().remove()\n\n// Second selection (within first selection)\n\nvar selB = selA.selectAll('circle')\n .data(function(d) { return d })\nselB.enter().append('circle')\nselB\n .attr(\"cx\", function(d,i) { return i*80 })\n .attr(\"r\", function(d,i) { return d })\nselB.exit().remove()"); 98 | 99 | slide.title("Useful Examples"); 100 | 101 | slide.code("Shuffle", empty_svg, "var cards = [\n \"J\\u2665\", \"J\\u2666\", \"J\\u2663\", \"J\\u2660\",\n \"K\\u2665\", \"K\\u2666\", \"K\\u2663\", \"K\\u2660\",\n \"Q\\u2665\", \"Q\\u2666\", \"Q\\u2663\", \"Q\\u2660\",\n \"A\\u2665\", \"A\\u2666\", \"A\\u2663\", \"A\\u2660\"]\n\ncards.sort(function() {return Math.random()-.5})\n\nvar svg = d3.select(\"div.output svg\")\n\nvar selection = svg.selectAll(\"text\")\n .data(cards, String)\n\nselection\n .transition()\n .duration(1000)\n .attr(\"y\", function(d,i) { return i*35+40 })\n\nselection.enter().append(\"text\")\n .attr(\"x\", 30)\n .attr(\"y\", function(d,i) { return i*35+40 })\n .style(\"fill\", function(d) {\n return \"\\u2665\\u2666\".indexOf(d[1]) < 0 ?\n \"black\" : \"red\";\n })\n .style(\"font\", \"20px monospace\")\n .text(String)"); 102 | 103 | slide.code("Shuffle (v2)", empty_svg, "var cards = [\n \"J\\u2665\", \"J\\u2666\", \"J\\u2663\", \"J\\u2660\",\n \"K\\u2665\", \"K\\u2666\", \"K\\u2663\", \"K\\u2660\",\n \"Q\\u2665\", \"Q\\u2666\", \"Q\\u2663\", \"Q\\u2660\",\n \"A\\u2665\", \"A\\u2666\", \"A\\u2663\", \"A\\u2660\"]\n\ncards.sort(function() {return Math.random()-.5})\n\nvar svg = d3.select(\"div.output svg\")\n\nvar selection = svg.selectAll(\"text\")\n .data(cards, String)\n\nselection\n .transition().duration(500)\n .attr(\"x\", function(d,i) {return (i%8)*30+30})\n .transition().duration(500).delay(500)\n .attr(\"y\", function(d,i) { return i*35+40 })\n .transition().duration(500).delay(1000)\n .attr(\"x\", 30)\n\nselection.enter().append(\"text\")\n .attr(\"x\", 30)\n .attr(\"y\", function(d,i) { return i*35+40 })\n .style(\"fill\", function(d) {\n return \"\\u2665\\u2666\".indexOf(d[1]) < 0 ?\n \"black\" : \"red\";\n })\n .style(\"font\", \"20px monospace\")\n .text(String)"); 104 | 105 | slide.code("Drawing lines", empty_svg, "var svg = d3.select(\"div.output svg\")\n\nsvg.append(\"path\")\n .style(\"fill\", \"none\")\n .style(\"stroke\", \"black\")\n .style(\"stroke-width\", 2)\n .attr(\"d\", \"M 10 10 L 200 200 \"+\n \"L 200 400 L 300 100 L 400 150\")"); 106 | 107 | slide.code("Drawing lines", empty_svg, "var points = [\n { x: 10, y: 10 },\n { x: 200, y: 200 },\n { x: 200, y: 400 },\n { x: 300, y: 100 },\n { x: 400, y: 150 }\n]\n\nvar lineFn = d3.svg.line()\n .x(function(d) { return d.x })\n .y(function(d) { return d.y })\n //.interpolate(\"cardinal\")\n\nvar svg = d3.select(\"div.output svg\")\n\nsvg.append(\"path\")\n .style(\"fill\", \"none\")\n .style(\"stroke\", \"black\")\n .style(\"stroke-width\", 2)\n .attr(\"d\", lineFn(points))"); 108 | 109 | slide.code("Drawing lines", empty_svg, "var pointsSin = d3.range(21).map(function(i) {\n return {x: i, y: Math.sin(i/3) }\n})\nvar pointsCos = d3.range(21).map(function(i) {\n return {x: i, y: Math.cos(i/3) }\n})\n\n\nvar w = 480\nvar h = 300\nvar x = d3.scale.linear()\n .domain([0, 20]).range([0, w])\nvar y = d3.scale.linear()\n .domain([-1, 1]).range([h, 0])\n\nvar lineFn = d3.svg.line()\n .x(function(d) { return x(d.x) })\n .y(function(d) { return y(d.y) })\n\nvar svg = d3.select(\"div.output svg\")\n\nsvg.selectAll(\"path\")\n .data([pointsSin, pointsCos])\n .enter().append(\"path\")\n .style(\"fill\", \"none\")\n .style(\"stroke\", \"black\")\n .style(\"stroke-width\", 2)\n .attr(\"d\", lineFn)"); 110 | 111 | }).call(this); 112 | -------------------------------------------------------------------------------- /template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | D3 Template 6 | 7 | 8 | 22 | 23 | 24 | 25 | 38 | 39 | --------------------------------------------------------------------------------