block by syntagmatic c157cd20973d7f92e913fac28cfa8a56

D3 and Canvas

Full Screen

index.html

<!DOCTYPE html>
<html>
  <head>
    <title>d3 and canvas</title>
    <meta charset="utf-8">
    <style>
      body {
        font-family: 'Futura';
        font-weight: normal;
        color: #080808;
        font-size: 16px;
      }
      h1, h2, h3, h4 {
        font-family: 'Futura';
        font-weight: normal;
      }
      .bottom h2 {
        margin-bottom: 0px;
      }
      .remark-code, .remark-code-line {
        font-family: 'Ubuntu Mono', Monaco, Menlo, monospace;
      }
      .remark-slide-content {
        background-size: cover
      }
      .inverse {
        background-color: #1c1e19;
        color: #f4f3f2;
      }
      .inverse h1 {
        text-shadow: 0 0 8px #555;
      }
      .inverse h1, .inverse h2 {
        color: #f4f3f2;
      }
      a {
        color: #762a83;
        text-decoration: none;
      }
      code {
        padding: 1.6em !important;
        background: rgba(255,255,255,0.9) !important;
        border-radius: 3px;
      }
      blockquote {
        font-size: 1.6em;
        margin: 1em 0;
      }
      .hljs-attr {
        color: #e6550d !important;
      }
      .remark-slide-number {
        font-size: 13px;
      }
      .nobg {
        background: transparent;
      }
    </style>
  </head>
  <body>
    <textarea id="source">

class: center, middle

# d3 and canvas

Kai Chang<br/>
<a href="//bl.ocks.org/syntagmatic">bl.ocks.org/syntagmatic</a><br/>

---

class: right

<img src="pixels-1.png" width=480 style="float:left"/>
<img src="pixels-2.png" width=300 style="float:left;margin-top: 1px;margin-left: 98px;"/>

# Pixels<br/>and</br/>Subpixels

---

background-image: url(monitor-small.jpg)

---

background-image: url(monitor-big.png)

---

background-image: url(eye-cells.jpg)

---

class: bottom, right

background-image: url(eye-brain.jpg)

<a href="//open.lib.umn.edu/intropsyc/">open.lib.umn.edu/intropsyc</a>

---

class: middle, inverse

<blockquote>A programming language is like a natural, human language in that it favors certain metaphors, images, and ways of thinking.</blockquote>
Seymour Papert

---

## Canvas

* Used for drawing graphics
* Pixel-based (bitmap of rgba image data)
* Procedural
* Immediate Mode

## JavaScript Core Skills

* Number, String, Boolean
* Array [❤️,❤️,❤️]
* Object
* Function
* map, filter, forEach

---

class: middle, inverse

<blockquote>I really really like array<br/>
I like mapping them<br/>
I like reducing them<br/>&nbsp;<br/>
But I like to do that on a physical scale so i like mapping and reducing the array that's on the needle opening<br/>&nbsp;<br/>
I have a whole bunch of research about how knitting is coding</blockquote>

Mariko Kosaka

---

# A Blank Canvas

We need a canvas element to draw on:

```html
<canvas id='painting' width=960 height=500></canvas>
```

And a canvas context to render to:

```html
<script type='text/javascript'>

  var canvas = document.getElementById('painting')
  var context = canvas.getContext('2d')

  // make art with pixels here

</script>
```

---

background-image: url(rects.png)

# Filling Rects

```html
<script type='text/javascript'>

  var canvas = document.getElementById('painting')
  var context = canvas.getContext('2d')

  context.fillStyle = "mediumseagreen"
  context.fillRect(500,20,200,600)   // x, y, width, height

  context.fillStyle = "darkorchid"
  context.fillRect(200,200,600,60)

  context.fillStyle = "deepskyblue"
  context.fillRect(400,180,60,300)

</script>
```

---

background-image: url(circs.png)

# Filling Circles

```javascript
context.fillStyle = "crimson"
context.beginPath()
context.arc(800,250,450,0,2*Math.PI)
context.fill()

context.fillStyle = "steelblue"
context.beginPath()
context.arc(50,250,50,0,2*Math.PI)
context.fill()

```

---

# Creating words

```javascript
function circle(x,y,radius,color) {
  context.fillStyle = color
  context.beginPath()
  context.arc(x,y,radius,0,2*Math.PI)
  context.fill()
}
```

---

background-image: url(circs.png)

# Filling Circles

```javascript
circle(800,250,450,"crimson")
circle(800,250,450,"steelblue")

```

---
class: inverse

background-image: url(lab-color-space.png)

# Exploring Lab Color Space

---

class: inverse

background-image: url(lab-color-point.png)

# Exploring Lab Color Space

Pick a color in Lab space

```javascript
var l = 65
var a = -30 
var b = 0

ctx.fillStyle = d3.lab(l,a,b)
ctx.fillRect(0, 0, canvas.width, canvas.height)
```
---

class: inverse

background-image: url(lab-color-gradient.png)

# Exploring Lab Color Space

1-d Gradient

```javascript
d3.range(0, canvas.width).forEach(function(x) {
  var l = 65
  var a = -100+200*x/canvas.width
  var b = 0

  ctx.fillStyle = d3.lab(l,a,b)
  ctx.fillRect(x, 0, 1, canvas.height)
})
```

---

class: inverse

background-image: url(lab-color-space.png)

# Exploring Lab Color Space

2-d Section

```javascript
d3.range(0, canvas.width).forEach(function(x) {
  d3.range(0, canvas.height).forEach(function(y) {

    var l = 65
    var a = -100+200*x/canvas.width
    var b = -100+200*y/canvas.height

    ctx.fillStyle = d3.lab(l,a,b)
    ctx.fillRect(x, y, 1, 1)
  })
})
```

---

background-image: url(lab-color-animation.gif)

class: inverse

# Exploring Lab Color Space

Trip out with **d3.timer**

```javascript
d3.timer(function(elapsed) {
  d3.range(0, canvas.width).forEach(function(x) {
    var l = 65;
    var a = -100+200*x/canvas.width
    var b = 100*Math.sin(elapsed/400)

    ctx.fillStyle = d3.lab(l,a,b)
    ctx.fillRect(x, 0, 1, canvas.height)
  })
})
```

---

background-image: url(science-sats-2.gif)

# Science Satellites

```javascript
d3.timer(function(elapsed) {
  // run time at 151x speed
  var time = new Date(now.getTime() + 150*elapsed)

  data.forEach(function(d) {
    plotSatellite(d, time)
  })
})


function plotSatellite(d, time) {
  var position = satellite.propagate(sat, time).position
  var groundPosition = satellite.geodetic(position, time)

  drawSat(sat, groundPosition)
}

```

---

## Exoplanets Parallel Coordinates

<img src="exoplanets.png"/ width="120%" style="margin-left: -10%">

---

# Progressive Rendering

Once you put something down, it doesn't cost anything to keep it around.

There is no memory cost for rendering to canvas.

Render chunks of data incrementally to keep interactions snappy.

---

background-image: url(boids.gif)

# Particle Trails

Clearing the canvas by filling a transparent rect can be used to create a whimsical trail effect

```javascript
d3.timer(function() {
  context.fillStyle = 'rgba(255,255,255,0.3)';
  context.fillRect(0, 0, canvas.width, canvas.height);

  // redraw all the things!
})
```

---

<img src="front-end.png" width=60%/>

Source: <a href="https://github.com/kamranahmedse/developer-roadmap">Developer Roadmap</a>

---

# SVG Challenges to Learning

* Inconsistences between SVG/HTML
* Confusion between attributes, styles and CSS
* Path strings have their own little language
* Managing a DOM hierarchy
* D3 General Update pattern involves complex method chaining
  * Type of returned object shifts during pattern
  * **.selectAll()** &rarr; **.data()** &rarr; **enter()** &rarr; **append()** &rarr; **merge()**
  * Selections saved to variables may be stale
* Slow with large number of elements (1000+)


... but there are a *ton* of tutorials and examples!

---

<blockquote>If we have a setback or a problem, or if we behave in a way that we determine is inappropriate or immoral, we may feel stupid, embarrassed, or unlovable.
  
  In these cases self-awareness may become burdensome. And even if nothing particularly bad is happening at the moment, self-awareness may still feel unpleasant because we have fears about what might happen to us or about mistakes that we might make in the future.</blockquote>
//open.lib.umn.edu/intropsyc/chapter/5-3-altering-consciousness-without-drugs/

---

# Canvas Challenges

* Drawn objects are not retained
* Interactions with visual marks don't come for free
* Canvas usually needs to be entirely re-rendered, even for minor changes
* Lack of beginner examples and tutorials with D3
* No accessibility fallback for visually impaired users
* Looks fuzzy by default on high-density displays

... but it's an easy-to-use API that's all JavaScript!

---

<img src="nyt-choros.png" width=110% style="margin-left: -5%"/>

---

# CDC WONDER

<img src="cdc.png" width=95% />

---

background-image: url(choro.png)

# Choropleths

```javascript
var path = d3.geoPath()
	.projection(d3.geoAlbersUsa())
	.context(context);

context.strokeStyle = "#fff";
context.lineWidth = 0.3;
countGeojson.forEach(function(d) {
	context.fillStyle = color(d["Crude Rate"]);
	context.beginPath();
	path(d);
	context.fill();
	context.stroke();
});
```


---

# Retina Support

```javascript
var devicePixelRatio = window.devicePixelRatio || 1

var canvas = d3.select("body").append("canvas")
    .attr("width", width * devicePixelRatio)
    .attr("height", height * devicePixelRatio)
    .style("width", width + "px")
    .style("height", height + "px").node()

var context = canvas.getContext("2d")
context.scale(devicePixelRatio, devicePixelRatio)
```

---

# Hidden Canvas Lookups

Using getImageData to lookup data using rgb values off a second canvas.<br/>
See [Yannick's blog post](https://bocoup.com/blog/2d-picking-in-canvas)

<img src="hidden-canvas-method.gif" style="margin-left: -8%; width: 120%;"/>

---

background-image: url(voronoi-quadtree.gif)

# Quadtree

* Subdivides data in two spatial dimensions
* Commonly used to find closest point
* Can create the same interaction surface as Voronoi

---

# d3.forceSimulation

Get the closest graph node to a position (such as the cursor):

**simulation.find(d3.event.x, d3.event.y)**

<img src="facebook-egonet-simulation-find.gif" width=80% style="margin-top: -15px;margin-left: -30px"/>

---

# d3.path 

Makes available the following canvas methods and can generate SVG path strings.

* moveTo
* lineTo
* closePath
* quadraticCurveTo
* BezierCurveTo
* arcTo
* arc
* rect
* toString

---

# Shapes

With V4, these are built on d3.path. So they support both Canvas and SVG.

* Arcs
* Pies
* Lines
* Areas
* Curves
* Symbols
* Stacks

---

class: middle, inverse

<blockquote>At age 5 children are learning to read and learning to write. They can input code and read it off the screen. And they can reason. They have the faculty of reasoning.
</blockquote>
Mary Rose Cook

---

background-image: url(stamen.png)

---

background-image: url(sideways-laptop.jpg)

---

background-image: url(hans-rosling.gif)


    </textarea>
    <script src="remark-latest.min.js">
    </script>
    <script>
      var slideshow = remark.create({
        highlightStyle: 'color-brewer'
      });
    </script>
    <script src="https://d3js.org/d3.v4.js"></script>
  </body>
</html>