Table of Contents for
Learning D3.js 4 Mapping - Second Edition

Version ebook / Retour

Cover image for bash Cookbook, 2nd Edition Learning D3.js 4 Mapping - Second Edition by Lars Verspohl Published by Packt Publishing, 2017
  1. Learning D3.js 4 Mapping, Second Edition
  2. Title Page
  3. Second Edition
  4. Copyright
  5. Learning D3.js 4 Mapping
  6. Second Edition
  7. Credits
  8. About the Authors
  9. About the Reviewers
  10. www.PacktPub.com
  11. Why subscribe?
  12. Customer Feedback
  13. Table of Contents
  14. Preface
  15. What this book covers
  16. What you need for this book
  17. Who this book is for
  18. Conventions
  19. Reader feedback
  20. Customer support
  21. Downloading the example code
  22. Downloading the color images of this book 
  23. Errata
  24. Piracy
  25. Questions
  26. Gathering Your Cartography Toolbox
  27. Quick bootstrap
  28. Step-by-step bootstrap
  29. A lightweight web server
  30. Using the web browser as a development tool
  31. Installing the sample code
  32. Working with the developer tools
  33. Summary
  34. Creating Images from Simple Text
  35. The SVG coordinate system
  36. Line
  37. Rectangle
  38. Circle
  39. Polygon
  40. Path
  41. Experiment
  42. Paths with curves
  43. Transform
  44. Translate
  45. Scale
  46. Grouping
  47. Text
  48. Summary
  49. Producing Graphics from Data - the Foundations of D3
  50. Creating basic SVG elements
  51. The enter() function
  52. The update function
  53. The exit() function
  54. AJAX
  55. Summary
  56. Creating a Map
  57. Foundation - creating your basic map
  58. Including the dataset
  59. Experiment 1 – adjusting the bounding box
  60. Experiment 2 – creating choropleths
  61. Experiment 3 – adding click events to our visualization
  62. Experiment 4 – using updates and transitions to enhance our visualization
  63. Experiment 5 – adding points of interest
  64. Experiment 6 – adding visualizations as a point of interest
  65. Summary
  66. Click-Click Boom! Applying Interactivity to Your Map
  67. Events and how they occur
  68. Experiment 1 – hover events and tooltips
  69. Experiment 2 – tooltips with visualizations
  70. Experiment 3 – panning and zooming
  71. Experiment 4 – orthographic projections
  72. Experiment 5 – rotating orthographic projections
  73. Experiment 6 – dragging orthographic projections
  74. Summary
  75. Finding and Working with Geographic Data
  76. Geodata file types
  77. What are shapefiles and how do I get them?
  78. Acquiring shapefiles for a specific country
  79. GeoJSON
  80. A quick map in D3 with only GeoJSON
  81. TopoJSON basics
  82. TopoJSON command-line tips
  83. Preserving specific attributes
  84. Simplification
  85. Merging files
  86. Summary
  87. Testing
  88. Code organization and reusable assets
  89. Project structure
  90. Exploring the code directory
  91. Other administrative files
  92. Writing testable code
  93. Keeping methods/functions small
  94. Preventing side effects
  95. An example with viz.js
  96. Unit testing
  97. Creating resilient visualization code
  98. Adding a new test case
  99. Summary
  100. Drawing with Canvas and D3
  101. Introducing Canvas
  102. Drawing with Canvas
  103. The three drawing steps of every Canvas visual
  104. Drawing various shapes with Canvas
  105. Animating the Canvas
  106. Animating the Canvas way
  107. Getting a general overview
  108. Preparing the rain data
  109. Updating each drop
  110. Drawing frame by frame
  111. Canvas and D3
  112. Getting an overview of our experiment
  113. The data
  114. Updating each drop
  115. Binding the data
  116. Drawing the data
  117. Running the app
  118. Summary
  119. Mapping with Canvas and D3
  120. Choosing Canvas or SVG
  121. Reasons to choose SVG
  122. Reasons to choose Canvas
  123. Visualizing flight paths with Canvas and D3
  124. The data
  125. Building the flight path map in SVG
  126. Measuring the performance
  127. Building the flight path map in Canvas
  128. Setting up the map
  129. Drawing the map and listening for user input
  130. Preparing and drawing with Canvas
  131. Drawing the background scene
  132. Defining the planes
  133. Calculating the plane's positions
  134. Animating the plane
  135. Measuring the performance
  136. Optimizing performance
  137. Continuing with measuring performance
  138. Summary
  139. Adding Interactivity to Your Canvas Map
  140. Why Canvas interaction is different
  141. Drawing the world on a Canvas
  142. Setting up
  143. Drawing the world
  144. Making the world move
  145. Setting up the behavior
  146. Handling zoom and rotation
  147. Finding the Canvas object under the mouse - Picking
  148. Picking, the theory
  149. Creating all things hidden
  150. Drawing the hidden Canvas
  151. Picking the values
  152. Storing more data and using a lookup array
  153. Highlighting the country on mouse over
  154. Visualizing data per country and adding a tooltip
  155. Adding new data to our old globe
  156. Coloring the globe
  157. Adding a tooltip
  158. The HTML
  159. Building the static parts of the tooltip
  160. Showing and hiding the tooltip
  161. Summary
  162. Shaping Maps with Data - Hexbin Maps
  163. Reviewing map visualization techniques
  164. Choropleth maps
  165. Cartograms
  166. Dot density maps
  167. Value and use of the hexagon
  168. Making a hexbin map
  169. Reviewing the hexbin algorithm
  170. Setting it up
  171. Drawing the map
  172. Drawing a point grid for our hexagons
  173. Keeping only the points within the map
  174. Making the hex tile
  175. Retrieving the hexagon center points
  176. Drawing the hex tiles
  177. Joining data points to the layout points
  178. Dressing our data for the final act
  179. Turning our visual into an interactive app
  180. Adding additional information on hover and click
  181. Changing the hexagon size
  182. Changing the color scale interpolator
  183. Browsing different datasets
  184. Encoding data as hexagon size
  185. Summary
  186. Publishing Your Visualization with Github Pages
  187. What we will publish
  188. Understanding the type of content you can publish
  189. Hosting your code on GitHub
  190. Making sense of some key terms and concepts
  191. Tracking historic changes of your files
  192. Collaborating on a project
  193. Working on project branches
  194. Setting up a GitHub account
  195. Creating a repository
  196. Editing a file on GitHub
  197. Uploading files to the repository
  198. Publishing your project on GitHub Pages
  199. Preparing the files for publishing
  200. Keeping your paths absolute
  201. Changing the main HTML filename to index.html
  202. Publishing your project
  203. Summary

Drawing various shapes with Canvas

Let's add some other basic geometric shapes or graphical primitives to our canvas. As they are the building blocks of all the visuals you draw, some exercise will do us good. Here's what we will draw:

A house and a tree. Or three rectangles under a triangle next to a path and a circle. 
View this step in the browser: https://larsvers.github.io/learning-d3-mapping-8-2. Code example 08_02.html.

You can see the code to the right in the JavaScript console, and before we step through it, let's note some general observations. First, every line starts with context. The Canvas context is really where our drawing comes to life. Second, Canvas code is written in a procedural style. This can be a benefit for beginners, as it is linear. No callbacks, no nested element structure, just a straight line of execution. This linearity will also extend to time, once you start animating the canvas. You write the first frame first, then you change the scene, then you write the second frame. Flip-book simple. Let's step through the code and see how to create these elements in detail. The first thing I suggest is giving the canvas a border. As the canvas element is an HTML element, you can style it with CSS, but we use JavaScript here to show off two properties of the canvas itself: width and height:

context.strokeStyle = '#CCCCCC';
context.strokeRect(0, 0, canvas.width, canvas.height);

The width and height are the only properties the canvas element has. We use them here to read the values of the element, however, they are readable and writable. This is nice, as you can change the canvas size programmatically when you want to resize your canvas during animation for example. Next, we build our flat-roofed blue house:

context.fillStyle = 'royalblue';
context.fillRect(50, 150, 200, 100);

Not much to see here, we've done that previously. The door won't make you sweat either, as it's the same as the house with a different color:

context.fillStyle = 'rgba(255, 255, 255, 0.9)';
context.fillRect(60, 190, 40, 60);

However, we use a different method to describe the color. You can use all CSS color concepts like named color values and hex color values, as well as the rgb(), rgba(), hsl() and hsla() color methods. The window is placed a little differently with context.translate():

context.save();
context.translate(140, 190);
context.fillRect(0, 0, 60, 30);
context.restore();

In this case, we don't move the rectangle, we move the entire coordinate system! The translate() method takes two arguments: the x and the y position you want to move the coordinate system by. You know this concept already from the use of transform, translate(x,y) which is often used to move svg:g elements in D3 and create their own coordinate systems. However, when applied to an svg:g element the transformed coordinate system applies to all objects nested within the g element. As said above, the g element, as well as its children, is retained as a scene-graph representation in the DOM, including its coordinate system. In Canvas, we can't move this information off to a representation of our drawing – there is no such thing. It's up to you to make sure only elements you want to manifest on a different coordinate system will do so. Remember above when we talked about the procedural style of writing Canvas code? This is exactly what we have to keep in mind here. When we change something in the context it will persist through our code until we change it again. To change the coordinate system back we could alternatively move it to our desired position and move it back afterwards like:

context.translate(140, 190);
context.fillRect(0, 0, 60, 30);
context.translate(-140, -190);

But we rather use the generally applicable context.save() and context.restore() methods. The context.save() saves the state at this point of the code and pushes it onto a stack, and  context.restore() pops the last saved state off the stack and restores the previous state of the context.  If you haven't come across stacks so far, here's an image explaining what it does: 

The stacked tower of data.

In short, a stack is a datatype like an array or an object. However, a stack is limited to two operations: adding elements on top of the stack (push) and removing elements from the top of the stack (pop). It's like a brick tower. This care-taking of our application's state is a defining aspect of Canvas and a key difference to SVG.

Next, we give the house a triangular roof. There's no triangle() function in Canvas, so you draw a path:

context.beginPath();
context.moveTo(50, 150);
context.lineTo(250, 150);
context.lineTo(50+200/2, 100); // you can use calculations as inputs!
context.closePath();
context.fillStyle = '#A52A2A';
context.fill();

Finally, we draw the tree. A tree has a brown stem, which you implement as a straight path, and a green treetop, which you draw as a green circle:

context.beginPath();
context.lineWidth = 10;
context.strokeStyle = 'brown'
context.moveTo(300, 250);
context.lineTo(300, 200);
context.stroke();

context.beginPath();
context.fillStyle = 'green';
context.arc(300, 175, 25, 0, Math.PI * 2);
context.fill();

There are two things to note here. First, all path code blocks are bracketed by beginPath() and either stroke() (the stem) or fill() (the roof and treetop):

context.beginPath();
// configure your path here
context.stroke();

context.beginPath();
// configure your path here
context.fill();

beginPath() signifies the intent to draw a new path and removes all current path (or sub-path) implementations. stroke() and fill() signify the end of the path and will produce the path on the screen. fill() will fill the path body with the set fillStyle color, and stroke() will only draw the path contour in with the set strokeStyle() method. Whenever you draw a path, you will need these start and end methods. In fact, whenever you draw anything you will need them. fillRect() or strokeRect(), as used previously, are just wrappers for beginning a path, drawing a path, and filling or stroking a path. You might have noticed that we only drew two sides of the triangular roof and then used closePath() which connects the current endpoint of the path with the starting point. The fill() method will also close the path for you, but making this explicit is more thorough, more performant and a service to the reader of your code (including yourself). The second thing to note is that even a circle is a path. In fact, the only primitive shape beyond a path offered by the Canvas API is the rectangle. SVG facilitates the use of <rect>, <circle>, <ellipse>, <line>, <polyline>, <polygon>, and <path>, while Canvas only offers paths and rectangles. However, drawing shapes with paths quickly becomes routine. While there is no pre-defined circle, there's the arc() and arcTo() methods, which pretty much do the circle drawing for you. You just need to add color to it and wrap it into the path start and end methods. arc() takes five arguments, the x and the y position, the radius, the start and the end angle of our arc. Both angles are being measured in radians.

A radian? One radian equals 57.3 degrees. Radians are an alternative unit of measurement for angles. They are beloved by mathematicians as they make a lot of sense in geometric calculations. To get a radian, you take the radius of a circle and wrap it around that circle – if you can imagine that the radius line is bendable:

How to get a radian

Their mathematical advantage is that they can be derived directly from the radius of a circle. The further beauty is that half a circle (as in 180 degrees) is exactly one PI radians. Hence, a full circle equals 2 * PI radians.

Degrees probably make more sense to you. That's fine. They also make more sense if you want to move objects around on the screen. You can easily convert between radians and degrees by using the following formula: (PI / 180) * degrees. PI is half a circle in radians and 180 is half a circle in degrees. By dividing one by the other, you express one degree in radians, which equals 0.0175. Multiply any degree number you desire with 0.0175 and use the result as radians.

OK! We've drawn a landscape with a house – that's great. There is certainly more to Canvas, but by following these simple steps you have learned a lot. You have learned about the concept of drawing with Canvas and what it means to write your code procedurally. You have seen how to draw individual shapes with Canvas, how you can move individual objects around with a translate transformation, and how the atomic unit of each Canvas shape is the path. Now, let's step it up and animate our landscape the Canvas way before we do it the D3 way.