├── README.md
├── images
├── mamp_dialog.png
└── mamp_preferences.png
└── js
├── fixBounds.js
├── moveToFront.js
├── processError.js
└── translate.js
/README.md:
--------------------------------------------------------------------------------
1 | ### d3-faq
2 | # FAQs and Frequently Encountered Problems (FEPs) When Learning D3
3 |
4 | **_With contributions from Scott Murray, Sophie Engle, Lynn Cherny_**
5 |
6 | TOC:
7 |
8 | * [Loading Data, CSVs, JSON, etc.](#loading-data)
9 | * [General D3](#general-d3)
10 | * [General Gotchas and FAQs with JS](#gotchas-js)
11 | * [Debugging Help](#debugging-help)
12 | * [Tool Setup and Use](#tool-setup)
13 | * [Useful Code Snippets](#useful-code-snippets)
14 |
15 |
16 | Loading Data, CSVs, JSON, etc.
17 | =========================================================
18 |
19 | There is great material on loading your data, with nice explanations, in [Learn JS Data](http://learnjsdata.com/read_data.html).
20 |
21 |
22 | **CSV Column Headers: Avoid spaces! Keep them Short!**
23 |
24 | It's safest not to use spaces in your header column names, and try to keep them short so you can work with them (but still know what they refer to). So, a column called “Years of Drought” should be named to something like “DroughtYears" or "drought_years".
25 |
26 | Your source data may have very long column headers, but you don't want to be typing them in (and having to use quotes because of spaces) in your code. Abbreviate!
27 |
28 | From Scott Murray:
29 |
30 | I strongly recommend simplifying column titles so they do not include spaces.
31 | Why? JavaScript object notation is simpler without spaces. Let me give you an example.
32 |
33 | Say you define an object like so:
34 |
35 | var object = {
36 | Country: “USA”,
37 | “Number of Bananas per Capita (millions)”: “556”,
38 | ”Total Length of Peels if Laid End to End (kilometers)”: “412415123”
39 | }
40 |
41 | To get at the value “556”, you would need to type:
42 |
43 | object[“Number of Bananas per Capita (millions)”]
44 |
45 | However, if you excluded spaces from your column titles, so your object
46 | looked like this:
47 |
48 | var object = {
49 | country: “USA”,
50 | numBananas: “556”,
51 | peelLength: “412415123”
52 | }
53 |
54 | …well first of all, that is so much easier to read, but also then you can
55 | use simplified object notation:
56 |
57 | object.numBananas //returns “556”
58 |
59 | See, you don’t need the quotation marks or the brackets. So eliminating
60 | spaces just saves you a lot of typing and headache later.
61 |
62 |
63 | **Number format in CSV/data files**
64 |
65 | Remove commas in numeric values - replace a value of “3,050” with “3050.” Javascript knows it’s thousands! Change the number format or type of the cell before saving a spreadsheet as csv, to be sure you fix this.
66 |
67 | Beware international number formats with periods as separators for thousands and commas for decimals (e.g., 234.567,89). JS expects no comma in the thousands position, and decimal for a float.
68 |
69 | **Right separator? (CSV--"comma separated values" or TSV--"tab" etc.)**
70 |
71 | Beware of the separator character and make sure it’s comma if you’re using d3.csv, or tab if you want tab separated and d3.tsv (See [Mike's example](https://gist.github.com/mbostock/3305937)). Check your data file and fix!
72 |
73 |
74 | **Numbers are Read as Strings-Convert Them!**
75 |
76 | Data values read in with d3.csv will be read as strings. You need to convert types to use numeric values.
77 |
78 | Convert input data types from string to numeric for use in functions:
79 |
80 | - `+x` is a “shorthand” for “treat x as a number”.
81 | - use `parseFloat(x)` or `parseInt(x)` otherwise, or
82 | - `Number(x)`
83 |
84 | **Wide vs. long format for data - how do I transform it?**
85 |
86 | The difference: https://en.wikipedia.org/wiki/Wide_and_narrow_data
87 |
88 | In D3's csv read, each row becomes an object with those attributes, hence often wide format is used for the data. If you have long or narrow format, you can use nest to group by some object identified.
89 |
90 | E.g.: http://stackoverflow.com/questions/15533533/multiline-chart-in-d3-with-long-format-data
91 |
92 | In Python (especially with pandas), R (melt or reshape), and Excel (with VBA or by hand), you can transform data prior to import.
93 |
94 | There is some information on reformatting data by nesting, etc., at http://learnjsdata.com/group_data.html.
95 |
96 | TODO: ADD MORE.
97 |
98 |
99 | **Using multiple data files (elegantly) - queue, asynchrony, etc.**
100 |
101 | TODO
102 |
103 | **How do I treat data sources with a [-, NaN, NA, null] for 0?**
104 |
105 | TODO
106 |
107 |
108 | ####JSON File Format
109 |
110 | **Be aware and beware of invalid JSON:**
111 |
112 | JSON format looks like this (from [Wikipedia](http://en.wikipedia.org/wiki/JSON)):
113 |
114 | ````
115 | {
116 | "firstName": "John",
117 | "lastName": "Smith",
118 | "isAlive": true,
119 | "age": 25,
120 | "address": {
121 | "streetAddress": "21 2nd Street",
122 | "city": "New York",
123 | "state": "NY",
124 | "postalCode": "10021-3100"
125 | },
126 | "phoneNumbers": [
127 | {
128 | "type": "home",
129 | "number": "212 555-1234"
130 | },
131 | {
132 | "type": "office",
133 | "number": "646 555-4567"
134 | }
135 | ],
136 | "children": [],
137 | "spouse": null
138 | }
139 | ````
140 |
141 | Notice, the labels are in double quotes. You can check your data’s format in a validator online: http://jsonformat.com/.
142 |
143 |
144 | General D3 Intro Questions
145 | ===================================================
146 |
147 | ####What is or what does it mean to say '+d.someProperty'?**
148 |
149 | A shorthand often seen in Mike Bostock's code (and now everyone else's) to cast a d.value as a number. Sometimes improper use of this causes errors.
150 |
151 | ####How do I add a tooltip?
152 |
153 | The poor and fast way is to use the `title` attribute on an appropriate SVG object. This requires the user to hover over the item for a bit before it appears. Not the most recommended or most flexible.
154 |
155 | Here's a nice lib:
156 |
157 | * http://darkmarmot.github.io/kodama/?utm_content=buffer3ff40
158 |
159 | Otherwise some people use tipsy:
160 |
161 | * http://bl.ocks.org/ilyabo/1373263
162 |
163 | Or here's a simple reusable lib called d3-tip:
164 |
165 | * https://github.com/Caged/d3-tip
166 |
167 | Or roll your own with html/css. Here's an example: https://bl.ocks.org/arnicas/c911d0abfe9819305660
168 |
169 |
170 | ####How do I add a legend?
171 |
172 | Seriously, use this by Susie Lu:
173 |
174 | * https://github.com/susielu/d3-legend
175 | * Code example: http://bl.ocks.org/curran/950cbe78b4c307fa14a1
176 | * Docs for it: http://d3-legend.susielu.com/
177 |
178 |
179 | ####Style vs. Attr for SVG elements
180 |
181 | Use style sheets when you can, because you want to keep the formatting independent of the code as much as possible. This makes it easier to swap in a new look without having to hunt through code for the right variables and when they are applied. This means instead of doing hard-coded
182 |
183 | ````
184 | d3.select(‘rect’).style(‘fill’, ‘red’)
185 | ````
186 | it’s better to add a class or id and put the style attribute there:
187 | ````
188 | d3.select(‘rect’).attr(‘class’, ‘redrect’)
189 | ````
190 | and then in the style sheet:
191 | ````
192 | .redrect { fill: red }
193 | ````
194 |
195 | For dynamic styling, you want to do it inline, of course. From [an excellent article on best practices in D3 coding](https://northlandia.wordpress.com/2014/10/23/ten-best-practices-for-coding-with-d3/):
196 |
197 | ````
198 | .style("fill", function(d) {
199 | return choropleth(d, colorize);
200 | })
201 |
202 | //OVERRIDES
203 |
204 | .attr("fill", function(d) {
205 | return choropleth(d, colorize);
206 | })
207 |
208 | ````
209 |
210 | "Things can get confusing if you assign a style rule as a style in one place and then try to re-assign it as an attribute in another. Thus, it’s best to pick one or the other, and style generally seems more appropriate to me. Note that this does not apply to element x/y positions or path d strings, which are only available as attributes." [Source: [an excellent article on best practices in D3 coding](https://northlandia.wordpress.com/2014/10/23/ten-best-practices-for-coding-with-d3/)]
211 |
212 |
213 | ####Date Formats and Formatting - Reading and Writing!
214 |
215 | A date must be “parse”d to read it in, not just declared in the format string. Example:
216 | TODO
217 |
218 | ####Loading Multiple Files
219 |
220 | * Understanding the pros/cons of loading files asynchronously, chaining `d3.json()` calls to load files synchronously, and using [`Queue.js`](https://github.com/mbostock/queue) instead.
221 |
222 | ####Efficiency
223 |
224 | Save your `d3.selectAll()` selections if you plan to reuse them (just be wary if the selection changes).
225 |
226 | **Okay:**
227 |
228 | ```
229 | var bubbles = d3.selectAll("circle");
230 | bubbles.attr("cx", 5);
231 | bubbles.attr("cy", 10);
232 | ```
233 |
234 | *or*
235 |
236 | ```
237 | d3.selectAll("circle")
238 | .attr("cx", 5)
239 | .attr("cy", 10);
240 | ```
241 |
242 | **Less Efficient:**
243 |
244 | ```
245 | d3.selectAll("circle").attr("cx", 5);
246 | d3.selectAll("circle").attr("cy", 5);
247 | ```
248 |
249 | ####Formatting and Working with SVG Text
250 |
251 | Text in SVG is a pain. There are common issues and solutions.
252 |
253 | **How do I split long lines of SVG text?**
254 |
255 | TODO
256 |
257 | **How do I add an icon or html to SVG text?**
258 |
259 | TODO
260 |
261 | ####Data() vs. Datum()**
262 |
263 | Which to use when?
264 |
265 | TODO
266 |
267 | ####Understanding the difference between chaining and/or naming transitions, versus not.
268 |
269 | TODO
270 |
271 | ####How to put multiple graphs on the page (small multiples)
272 |
273 | TODO
274 |
275 | ####Method chaining and the reusable chart pattern
276 |
277 | TODO
278 |
279 |
280 |
281 | General Gotchas and FAQs with JS
282 | =========================================================
283 |
284 | This site has some nice docs on weird bits of JS: http://bonsaiden.github.io/JavaScript-Garden/
285 |
286 | **Case Sensitivity--Or, lower and upper case letters matter!**
287 |
288 | JS is case-sensitive. You can’t call your variable **d.affluence** if the value is really **d.Affluence**. Also, **d.yearlyAvg** is not the same as **d.yearlyavg**. If you read them in from a CSV file, check your header labels!
289 |
290 | **Invalid Characters in Variable Names**
291 |
292 | To be safe, you should follow these rules: variable names should start with a letter or `_` or `$` and the other characters can be letters or `_` or `$` or numbers. You may not start a variable name with a number. You may not use `-` in your variable name. You can't use spaces in variable names. Some people like to use camelcase in longer variable names, because it avoids spaces and allows you to parse words visually: camelCase. lowerCaseThenUpperCase.
293 |
294 | **Using a CDN for included libraries**
295 |
296 | A CDN is a repository for code online (**content delivery network**). For non-local development, or for bl.ocks.org display, you need paths to CDNs for d3 and tools like jquery, or your bl.ocks won't display correctly.
297 |
298 | * D3: https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.js
299 | * JQuery: https://code.jquery.com/jquery-2.1.4.js, or minified: https://code.jquery.com/jquery-2.1.4.min.js (see their links: https://code.jquery.com/)
300 |
301 |
302 | **How do I round numbers?**
303 |
304 | For integer rounding: `Math.round(num)`.
305 |
306 | For 2-place decimal rounding, use ` num.toFixed(2) `.
307 |
308 | Don't forget to make `num` a real number first if it came in as a string: `parseFloat("123.456").toFixed(2)`. If you want to use the '+' shorthand to make it a number, you will need brackets: `(+"45.534").toFixed(2)`.
309 |
310 |
311 | **Missing or improperly placed } or })**
312 |
313 | TODO
314 |
315 | **Missing semicolons confusing interpretation of JavaScript**
316 |
317 | TODO
318 |
319 | **var scope**
320 |
321 | * Initially, variables in included script files are the same as variables defined in the HTML body script sections.
322 | * global and local
323 |
324 | **What is `this`?**
325 |
326 | TODO
327 |
328 | **Equivalence and "Equivalence" in JS**
329 |
330 | TODO:
331 | Understanding the "equivalent-ish" operator `==` versus the "equivalent" operator `===` and when one is beneficial and when it is not. Especially since `if(something)` is often used in examples to detect if something is not undefined, but will break if your data has 0 values in it.
332 |
333 | **Script file at start in head or at end.**
334 | TODO
335 |
336 |
337 |
338 | Debugging Help
339 | ===========================================
340 |
341 |
342 | Check out the Chrome [tips and tricks](https://developer.chrome.com/devtools/docs/tips-and-tricks) for using the console for debugging.
343 |
344 | *Video on console use for D3: https://egghead.io/lessons/debugging-with-dev-tools
345 |
346 | *Parts of the dev tools in chrome: http://www.html5rocks.com/en/tutorials/developertools/part1/
347 |
348 |
349 | _TODO: How to debug in the console - console.log, breakpoints, inspect elements, d3 at the command line._
350 |
351 |
352 | ###Debugging NaNs: Where is that NaN coming from?
353 |
354 | **NaN and other problems from a d3 scale:**
355 |
356 | Is your scale set for the expected domain and range? You need to give them arrays, which means values in square brackets, or use d3.extent to get an array of the lowest and highest values for you:
357 |
358 | ````
359 | var yearScale = d3.time.scale()
360 | .domain(d3.extent(data, function (d) { return d.year;}))
361 | .range([50, window.innerWidth - 50]);
362 | ````
363 |
364 | You use the scale by calling it as a function on a value, which will be mapped from the domain to the range:
365 |
366 | ````
367 | return yearScale(d.year);
368 |
369 | ````
370 |
371 | Remember that if you assign a function to a variable, it's still a function! Some D3 methods are returning *function* objects, for example with `var x = d3.scale.linear();` the variable `x` is now a function that was created by `d3.scale.linear()`.
372 |
373 | **NaN after reading in a data file**
374 |
375 | Did you parse the value correctly? Is there a value in the cell?
376 |
377 | **Coping with NaNs when charting (bars, lines)**
378 |
379 | TODO
380 |
381 |
382 | **More Debugging Tips**:
383 |
384 | Check the size of your selections first. For example:
385 |
386 | ```console.log(d3.select("#plot").selectAll("circle").size());```
387 |
388 | Then, worry about whether the problem is in the rest of the chain.
389 |
390 | Check the values of your functions using accessors. For example, don't tell me you set the domain and range properly, show me you set it properly:
391 |
392 | ```console.log(x.domain(), x.range());```
393 |
394 | Test what your functions return! You can give them sample input:
395 |
396 | ```console.log(x(5));```
397 |
398 |
399 |
400 | Tool Setup and Use
401 | ===========================================
402 |
403 | ###Running a Server
404 |
405 | You won't be able to use d3 or other javascript files without a web server running on your machine. Plain html and CSS will display fine, but anything computational needs to be done with a server to 'view' your pages.
406 |
407 | On Windows, WAMP is a full-service free server (plus MySQL if you want it in the future.) On Mac, you can use either MAMP or run a server in your directory using Python or node from the command line. Or use an editor that does live previews, like Brackets, but we really recommend learning how to run a server.
408 |
409 | ####Wamp on Windows
410 |
411 | For a windows server, look here: http://www.wampserver.com/en/
412 | There is some guidance on installing it in [this slideshow on configuring WAMP](http://www.slideshare.net/triniwiz/wamp-20949805) - I recommend you don't set Firefox as your default browser, but Chrome instead.
413 |
414 | Your default `www` files directory will be inside the wamp folder on your computer (by default, at `C:\wamp`). You want to move your files into that directory to be able to view them.
415 |
416 | By default, the index.php file will display when you open `http://localhost` in a browser. To see the files you want, you will need to add the directory path to that url: `http://localhost/my_folder/`. *You must type the URL path in your browser.* You can't click on a file in the explorer and have it display with the server. Then any index.html in that directory will display instead, if you're configured right. Or hopefully a list of files, if there's no index.html!
417 |
418 | In Windows 10 (or if you see an orange icon for the WAMP icon), you may have a port conflict with the default port 80. Refer to this [video](https://www.youtube.com/watch?v=bRrCqI9Ig4k).
419 |
420 | ####MAMP Setup on Macs
421 |
422 | The location for MAMP is here: https://www.mamp.info/en/downloads/. You only need MAMP, not MAMP Pro, unless you want to get extra nice features for money.
423 |
424 | If you are struggling with the setup for the web server on a Mac: After downloading MAMP, double click to install and go through the install screens. Then find the app icon for MAMP (not MAMP Pro! that's a free trial) in your Launchpad or Applications directory and start it up.
425 |
426 | You will see a preferences icon on the left:
427 |
428 | 
429 |
430 | Apparently MAMP by default uses a port that is used by other stuff like Skype (8888). You will probably want to change it. If your server never starts (the button never turns green on the dialog), you probably have a port conflict. If you click on the **Preferences**, you can change the port for the localhost server if you want. (I wanted a different one because I have other servers running on the same machine. The default port for web servers is 80, but it may be in use already.) If you change the port, for example to 7777, you will enter the url in your browser as:
431 |
432 | ````
433 | http://localhost:7777
434 | ````
435 |
436 | This will show you the files (or index.html) in the MAMP server directory root. You will only be able to browse to files inside the server home directory folder.
437 |
438 | **To change your Home Directory for MAMP**
439 |
440 | You may want to click on the Preferences and **set a new home directory** for your server. Click on the "Web Server" tab and double click on the document root icon to pick a new directory. I made one called **Knight D3** for this example.
441 |
442 | 
443 |
444 | Put the files you want to view in the browser into the directory you set as your Document Root. Make sure the server is running - on the Start/Stop tab there should be a green server power icon showing.
445 |
446 | Then, in your browser, go to `http://localhost` or `http://localhost:` and you should see the files with links if they are HTML files.
447 |
448 | If you run into an error on Yosemite 10, try this fix: http://stackoverflow.com/questions/25333173/mysql-with-mamp-does-not-work-with-osx-yosemite-10-10/26446158#26446158.
449 |
450 | ###Python SimpleServer from Command Line
451 |
452 | Alternately, from a Terminal program command line on the Mac (google how to find and start one), you can start a web server in the directory with your files:
453 |
454 | ````
455 | >python -m HTTPSimpleServer 5555
456 | ````
457 |
458 | You'll need to run this whenever you want to work on your web files. You'll go to `http://localhost:5555` to see the files in the directory if you use the command above.
459 |
460 | You can stop the webserver by typing ^c (control-c) in that window.
461 |
462 | ###Node Server
463 |
464 | On a Mac, if you have Homebrew, use Homebrew to install Node, and then install http-server. Run it in the directory of your files, with & so you can get your command line back.
465 |
466 | ````
467 | brew install node
468 | npm install -g http-server
469 | http-server
470 | ````
471 | This will make your server at `http://localhost:8080`.
472 |
473 |
474 | ####Brackets Editor Preview Option
475 |
476 | Apparently the Brackets MACOSX editor will run like a server and display your files just fine locally: http://brackets.io/. (I don't have any details about how this works yet.)
477 |
478 | ------------
479 |
480 | ###GitHub
481 |
482 | Intros to GitHub:
483 |
484 | * https://guides.github.com/activities/hello-world/
485 | * http://blog.teamtreehouse.com/git-for-designers-part-1
486 | * http://vallandingham.me/Quick_Git.html
487 |
488 | Command line is an issue on Windows:
489 | * [Command Line github on Windows](http://stackoverflow.com/questions/11000869/command-line-git-on-windows)
490 |
491 | --------------
492 |
493 | ###Bl.ocks.org and Gists
494 |
495 | **Seeing source gist for a bl.ock:**
496 |
497 | To find the source of a bl.ocks.org link, just replace the blocks part with gist.github.com:
498 |
499 | ```
500 | http://bl.ocks.org/AndresClavijo/9706481d505f2553a71a
501 | becomes
502 | https://gist.github.com/AndresClavijo/9706481d505f2553a71a
503 | ```
504 |
505 | Or add the extension to your browser (however, this isn't working for me right now): https://github.com/mbostock/bl.ocks.org (scroll down)
506 |
507 | Note that the bl.ocks.org site takes a few mins to catch up to changes on the gists site.
508 |
509 | **Seeing a Gist as a Bl.ock with Vis Rendered - html page name**:
510 |
511 | Scott Murray:
512 |
513 | ````
514 | When creating your block, make sure your HTML page is named “index.html”. It must be named exactly that, with all lowercase letters. (“Index.html” will not work!) This is a web convention, to name your primary page index.html, and the blocks service expects you to follow it.
515 | ````
516 |
517 | **Path to d3 in a bl.ocks.org file:**
518 |
519 | Your d3 won’t display in the live page in a published gist/bl.ock if you don’t use the path to the online CDN (rather than your local version). Your error in your console will say “File not found.”
520 |
521 | ````
522 |
523 | ````
524 |
525 | **How do I get an image in bl.ocks.org previews?**
526 |
527 | Using git and adding a thumbnail: http://bost.ocks.org/mike/block/#advanced
528 |
529 | **Vis that is too big for bl.ocks**
530 |
531 | From Scott Murray:
532 |
533 | ````
534 | The blocks preview frame is 960 x 500 pixels. If your design exceeds these dimensions, you’ll need to click “Open in a new window” to see the whole thing, or you can insert “/raw/” in the URL following your username. For example, here is a block of mine:
535 | http://bl.ocks.org/alignedleft/9471486
536 | …and here is the URL for the “raw” version:
537 | http://bl.ocks.org/alignedleft/raw/9471486/
538 | ````
539 |
540 | **Security Error with bl.ocks.org Pages**
541 |
542 | From Scott Murray:
543 |
544 | ````
545 | The Gist service supports secure, HTTPS connections, but blocks does not. So, make sure your blocks URL uses only “http://…” not “https://…” or you’ll see a security error. This is confusing, as this secure gist:
546 | https://gist.github.com/alignedleft/9471486
547 | …appears as an insecure block here:
548 | http://bl.ocks.org/alignedleft/9471486
549 | ````
550 |
551 | **Command line gistup tool: https://github.com/mbostock/gistup**
552 |
553 | You might want to look at Mike's Command line tutorial on making a block: http://bost.ocks.org/mike/block/ and his gistup tool.
554 |
555 | ### (Shell) Command Line
556 |
557 | Knowing something about command line usage (Unix/bash/etc) is a good idea. A nice intro tutorial: http://cli.learncodethehardway.org/book/
558 |
559 |
560 | Useful Code Snippets
561 | =======================================================
562 |
563 | I recommend you use/look into lowdash: http://colintoh.com/blog/lodash-10-javascript-utility-functions-stop-rewriting
564 |
565 | These code snippets are in the js directory:
566 |
567 |
568 | * **fixBounds.js**: fixes the size and viewbox of an SVG
569 | to fit an inner group with the specified padding. Both the
570 | svg and group parameters need to be D3 selections.
571 |
572 | * **processError.js**: for handling error during file read.
573 |
574 | * **translate.js**: helper for translating SVG elements.
575 |
576 | * **moveToFront.js**: helper to move the currently selected item to top (in crowded plots)
577 |
578 |
579 | Resources
580 | =================================
581 |
582 | ### Learning JS for free, online
583 |
584 | See https://www.javascript.com/resources.
585 |
586 |
--------------------------------------------------------------------------------
/images/mamp_dialog.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arnicas/d3-faq/fa96c5f017ae2ece89c9a93a220e515799999866/images/mamp_dialog.png
--------------------------------------------------------------------------------
/images/mamp_preferences.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arnicas/d3-faq/fa96c5f017ae2ece89c9a93a220e515799999866/images/mamp_preferences.png
--------------------------------------------------------------------------------
/js/fixBounds.js:
--------------------------------------------------------------------------------
1 | /*
2 | * A magical function that fixes the size and viewbox of an SVG
3 | * to fit an inner group with the specified padding. Both the
4 | * svg and group parameters need to be D3 selections.
5 | *
6 | * Contrib by Sophie Engle.
7 | *
8 | */
9 | function fixBounds(svg, group, padding) {
10 | // svg and group should be d3 selections
11 | if (!(svg instanceof d3.selection) ||
12 | !(group instanceof d3.selection)) {
13 | console.log("Warning: Must have D3 selections to fix bounds.");
14 | return;
15 | }
16 |
17 | // get bounding and view box
18 | var bbox = group.node().getBBox();
19 | var view = [bbox.x, bbox.y, bbox.width, bbox.height];
20 |
21 | var x = -bbox.x + padding;
22 | var y = -bbox.y + padding;
23 |
24 | var w = bbox.width + padding * 2;
25 | var h = bbox.height + padding * 2;
26 |
27 | group.attr("viewBox", view.join(" "));
28 | group.attr("transform", "translate(" + x + ", " + y + ")");
29 |
30 | svg.attr("width", w);
31 | svg.attr("height", h);
32 |
33 | svg.attr("viewBox", [0, 0, w, h].join(" "));
34 | svg.attr("version", "1.1");
35 | svg.attr("xmlns", "http://www.w3.org/2000/svg");
36 | svg.attr("preserveAspectRatio", "xMinYMin meet");
37 | }
38 |
--------------------------------------------------------------------------------
/js/moveToFront.js:
--------------------------------------------------------------------------------
1 | /* move the currently moused over item to the front */
2 |
3 | d3.selection.prototype.moveToFront = function() {
4 | return this.each(function(){
5 | this.parentNode.appendChild(this);
6 | });
7 | };
8 |
9 | // selected_items.moveToFront();
--------------------------------------------------------------------------------
/js/processError.js:
--------------------------------------------------------------------------------
1 | /*
2 | * If there is an error, insert an error message in the HTML
3 | * and log the error to the console.
4 | * Contrib by Sophie Engle.
5 | */
6 |
7 | function processError(error) {
8 | if (error) {
9 | // Use the "statusText" of the error if possible
10 | var errorText = error.hasOwnProperty("statusText") ?
11 | error.statusText : error.toString();
12 |
13 | // Insert the error message before all else
14 | d3.select("body")
15 | .insert("p", ":first-child")
16 | .text("Error: " + errorText)
17 | .style("color", "red");
18 |
19 | // Log the error to the console
20 | console.warn(error);
21 | return true;
22 | }
23 |
24 | return false;
25 | }
--------------------------------------------------------------------------------
/js/translate.js:
--------------------------------------------------------------------------------
1 | // Helper function for translating SVG elements.
2 | // Contrib by Sophie Engle.
3 |
4 | function translate(x, y) {
5 | return "translate(" + x + ", " + y + ")";
6 | };
7 |
--------------------------------------------------------------------------------