syntax.us Let the syntax do the talking
Blog Contact Posts Questions Tags Hire Me

Question:
What is 2015_1010 Code Challenge?

The 2015_1010 Code Challenge is a learning exercise for students attending Dan's Linux JavaScript Class at 3pm on 2015-10-10 at Hacker Dojo:

http://www.meetup.com/Dans-Linux-JavaScript-Class/events/225843604/

We start with three tasks: Install Ubuntu, enhance it, and create account named ann: Next, we learn some Emacs:
  • emacs ~ann/.emacs
  • Experiment with the controls at the top of the emacs window
  • Add this syntax to file: ~ann/.emacs
    ;;
    ;; ~ann/.emacs
    ;;
    (global-set-key "\C-xs" 'shell)
    (global-set-key "\em"   'buffer-menu-other-window)
    (global-set-key "\eR"   'rename-buffer)
    ;; end of .emacs
    
  • Figure out how to save and exit
  • Verify your work:
    cat ~ann/.emacs
  • Start 'bare' emacs:
    emacs
  • Start a shell in emacs with ctrl-x then letter 's'.
  • I should see something like this:
  • Rename the shell to SHELL1 with esc-key, then letter 'R'
  • I should see something like this:
  • List all buffers in my emacs with esc-key, then letter 'm'
  • I should see something like this:

I see the buffer-menu as similar to the Mac-Dock, Ubuntu-Launcher or the Windows-Taskbar.

The buffer-menu is my favorite emacs feature; it allows my mind to QUICKLY switch focus among three types of objects:
  • different shells
  • different files
  • different folders

The buffer-menu floats 'hot' shells, files and folders to the top.

This is useful behavior.

I mostly do 4 types of tasks on a laptop:
  • Interact with file
  • Interact with folder
  • Interact with shell
  • Interact with browser

I can do the first three types inside of emacs.

When I coordinate tasks with emacs rather than a Dock, I work much faster (because of the buffer-menu).

That sequence of creating a shell, and renaming it is the most difficult task I need to know.

All other emacs tasks can be done using mouse and arrow keys.

If I am an emacs power-user, I know two ways to use emacs to interact with folders.

The GUI-way is to click on the file-cabinet at the top.

Another way, which is quicker, is to type command ctrl-x then letter 'f'.

I should see something like this:


  • After I learn some Emacs or some other editor, I Install Node.js in this folder: ~ann/node/
  • cd ~ann
    wget https://nodejs.org/dist/v5.0.0/node-v5.0.0-linux-x64.tar.gz
    tar zxf node-v5.0.0-linux-x64.tar.gz
    rm -rf node
    mv node-v5.0.0-linux-x64 node
  • Then, I add Node.js to PATH:
    export       PATH="/home/ann/node/bin:${PATH}"
    echo 'export PATH="/home/ann/node/bin:${PATH}"' >> ~ann/.bashrc
  • Run a test:
    which node
    node -e 'console.log("hello world")'
  • Install CoffeScript to test npm:
    which npm
    npm install -g coffee-script
    ls -la /home/ann/node/lib/node_modules/
    which coffee
    coffee -e 'console.log "hello coffee!"'
  • Start work on an app:
    cd ~ann
    mkdir app20
    cd    ~ann/app20
    mkdir fee haml app
I did the above steps on my laptop.

Next, I used emacs to create a file named ~ann/app20/package.json
{
  "name": "app20",
  "version": "1.0.0",
  "description": "Demo by Dan",
  "main": "node_modules/http-server/bin/http-server",
  "scripts": {
    "test": "echo 'hello world' && exit"
  },
  "author": "Dan",
  "license": "ISC",
  "dependencies": {
    "http-server": "^0.8.5"
  },
  "engines": {
    "node": "4.1.2"
  }
}
Then, I ran a simple shell command:
cd ~ann/app20
npm install
That shell command created a folder named node_modules:
ann@red1:~/app20$
ann@red1:~/app20$ ll node_modules/
total 16
drwxrwxr-x 4 ann ann 4096 Oct  8 23:58 ./
drwxrwxr-x 6 ann ann 4096 Oct  8 23:58 ../
drwxrwxr-x 2 ann ann 4096 Oct  8 23:58 .bin/
drwxrwxr-x 8 ann ann 4096 Oct  8 23:58 http-server/
ann@red1:~/app20$
ann@red1:~/app20$
ann@red1:~/app20$
I wanted git to ignore node_modules:
echo node_modules > ~ann/app20/.gitignore
Next, I created a git repository for the app20 folder:
cd ~ann/app20
git config --global user.email "ann@ann.edu"
git config --global user.name ann
git init
git add .
git commit -am app20IsHereNow
git status
git log -1
Then, I created ~ann/app20/app20env.bash
# ~ann/app20/app20env.bash

# I use this file to set env variables.
# Demo:
# . ~ann/app20/app20env.bash

export PATH="/home/ann/node/bin:${PATH}"
export GEM_HOME=/home/ann/app20/gems
export PATH=${GEM_HOME}/bin:${PATH}
Next, I created a script to start http-server.
#!/bin/bash

# ~ann/app20/http.bash

cd ~ann/app20/
. ~ann/app20/app20env.bash

~ann/node/bin/node node_modules/http-server/bin/http-server
exit
I started a shell in emacs and ran the above script.
ann@red1:~/app20$ 
ann@red1:~/app20$ ll
total 44
drwxrwxr-x  7 ann ann 4096 Oct  9 00:31 ./
drwxr-xr-x 15 ann ann 4096 Oct  9 00:11 ../
drwxrwxr-x  2 ann ann 4096 Oct  8 23:54 app/
-rw-rw-r--  1 ann ann  221 Oct  9 00:31 app20env.bash
drwxrwxr-x  2 ann ann 4096 Oct  8 23:54 fee/
drwxrwxr-x  8 ann ann 4096 Oct  9 00:12 .git/
-rw-rw-r--  1 ann ann   13 Oct  9 00:08 .gitignore
drwxrwxr-x  2 ann ann 4096 Oct  8 23:54 haml/
-rw-rw-r--  1 ann ann  145 Oct  9 00:30 http.bash
drwxrwxr-x  4 ann ann 4096 Oct  8 23:58 node_modules/
-rw-rw-r--  1 ann ann  324 Oct  8 23:55 package.json
ann@red1:~/app20$ 
ann@red1:~/app20$ bash http.bash 
Starting up http-server, serving ./
Available on:
  http:127.0.0.1:8080
  http:192.168.1.77:8080
Hit CTRL-C to stop the server
That shell was locked; I renamed it so I could start another shell.

Next, I installed a Linux utility called HAML.
cd ~ann/app20
mkdir gems
echo  gems >> .gitignore
.  ~ann/app20/app20env.bash
gem install haml
Then, I got a copy of d3.v3.min.js
cd ~ann/app20/app/
curl https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js > d3.v3.min.js
Next, I created ~ann/app20/haml/demo10.haml
!!!
%html(lang="en")
  %head
    %meta(content="text/html; charset=UTF-8" http-equiv="Content-Type")/
    %meta(charset="utf-8")/
    %title demo10
    %script(src="/app/d3.v3.min.js")
  / The body-element below should be affected by D3.js
  %body.d3body
    hello world.
    %br/
    D3.js makes this text unreadable.
    %br/
    Why?
    %br/
    It is unreadable because the text becomes black,
    and the background-color becomes black.
    / The p-elements below should be affected by D3.js
    %p.d3p I am Paragraph 1
    %p.d3p I am Paragraph 2
    %p.d3p
      I am Paragraph 3
      Refer to:
      %a(href='http://d3js.org/#selections' target='x')
        http://d3js.org/#selections
    :javascript
      d3.select("body.d3body").style("background-color", "black");
      d3.selectAll("p.d3p").style("color", "white");
Then, I used the haml shell command to generate ~ann/app20/app/demo10.html
cd ~ann/app20/haml/
.  ~ann/app20/app20env.bash
~ann/app20/gems/bin/haml -eq ~ann/app20/haml/demo10.haml ~ann/app20/app/demo10.html
Next, I checked that http-server was serving demo10.html
curl localhost:8080/app/demo10.html | head
Then, I browsed the URL and saw the page below:


The main idea of the above demo is that when my browser loads d3.v3.min.js, then I get access to an object named 'd3'.

A useful method of d3 is selectAll().

This method transforms HTML elements into JavaScript objects.

Then, I can manipulate the objects with calls to methods like style().

The methods then change HTML and CSS currently rendered in the browser.

This type of API behavior should seem natural and familiar to you if you have worked with jQuery.

I use two ideas when I work with this kind of API.

First, I use comments in the HTML which tell me when an element is affected by D3.

Secondly, I use a descriptive id or class name like "d3body" or "d3p" when I intend to control an element with D3.

Why do I add comments and descriptive attributes to my HTML?

Well, one feature of AngularJS which I like is that when I look at HTML controlled by AngularJS, that control is obvious because of attributes with names like ng-app and ng-controller.

D3 does not have this feature so I manually annotate my HTML.

When I look at my code a year from now, I will easily connect my mind to the connections between the HTML and the D3 JavaScript due to my comments and class naming conventions.

Next, I worked on deploying my current copy of ~ann/app20 to heroku.com which is a popular free hosting service.

Heroku supports the following deployment idea:
  • Create a simple Node.js app (~ann/app20 is a simple Node.js app)
  • Add a one-line-file named Procfile to the app
  • git-init the app so I then have a git repo
  • create an account at heroku.com
  • download/install Heroku client
  • Use heroku-client to "login" my shell
  • Think of a unique app name (newyork212 for example)
  • Use the client to create a blank app named newyork212 at herokuapp.com
  • git-push ~ann/app20 to heroku
  • see ~ann/app20 deployed at newyork212.herokuapp.com

What is the cost?

The cost is $0.00

The steps listed below demonstrate the above deployment idea:
  • I created ~ann/app20 (done already)
  • I created a simple one-line file named: ~ann/app20/Procfile
    echo 'web: node node_modules/http-server/bin/http-server -p $PORT' > ~ann/app20/Procfile
  • git-init the app so I then have a git repo (done already)
  • Create an account at heroku.com (done already)
  • Download/Install Heroku client
    cd ~ann
    wget https://s3.amazonaws.com/assets.heroku.com/heroku-client/heroku-client.tgz
    tar zxf heroku-client.tgz
    echo 'export PATH=/home/ann/heroku-client/bin:${PATH}' >> ~ann/.bashrc
    echo  export PATH=/home/ann/heroku-client/bin:${PATH}
  • I created ssh-key for ann account (assuming ann has none yet):
    ann@dev06:~$ 
    ann@dev06:~$ ssh-keygen -t rsa
    Generating public/private rsa key pair.
    Enter file in which to save the key (/home/ann/.ssh/id_rsa): 
    Created directory '/home/ann/.ssh'.
    Enter passphrase (empty for no passphrase): 
    Enter same passphrase again: 
    Your identification has been saved in /home/ann/.ssh/id_rsa.
    Your public key has been saved in /home/ann/.ssh/id_rsa.pub.
    The key fingerprint is:
    7c:73:e0:26:8b:62:f6:a4:1d:78:22:e5:cd:3a:5c:eb ann@dev06
    The key randomart image is:
    +--[ RSA 2048]----+
    |                 |
    |                 |
    |          .      |
    |       . . .     |
    |    .   S = .    |
    |   o +.. = o     |
    |  ..B.B..        |
    |   +oX..         |
    |    ooE          |
    +-----------------+
    ann@dev06:~$ 
    ann@dev06:~$ 
    ann@dev06:~$ 
    
  • I used heroku-client to "login" my shell. I gave a copy of ann public ssh-key to heroku:
    heroku status
    heroku auth:login
    heroku auth:whoami
    heroku keys:add
  • I used heroku-client to create a blank app named newyork212 at herokuapp.com
    cd ~ann/app20
    heroku create newyork212
  • git-push ~ann/app20 to heroku
    cd ~ann/app20
    git add .
    git commit -am helloNY
    git push heroku master
  • I saw ~ann/app20 deployed at https://newyork212.herokuapp.com/app/demo10.html

Next, using emacs, I started work on ~ann/app20/haml/demo11.haml
!!!
%html(lang="en")
  %head
    %meta(content="text/html; charset=UTF-8" http-equiv="Content-Type")/
    %meta(charset="utf-8")/
    %title demo11
    %script(src="/app/d3.v3.min.js")
  / The body-element below should be affected by D3.js
  %body.d3body
    hello world.
    %br/
    D3.js makes this text unreadable.
    %br/
    Why?
    %br/
    It is unreadable because the text becomes black,
    and the background-color becomes black.
    / The p-elements below should be affected by D3.js
    %p.d3p I am Paragraph 1
    %p.d3p I am Paragraph 2
    %p.d3p
      I am Paragraph 3
      Refer to:
      %a(href='http://d3js.org/#properties' target='x')
        http://d3js.org/#properties
    :javascript
      d3.select("body.d3body").style("background-color", "black");
      d3.selectAll("p.d3p").style("color", function() {
        return "hsl(" + Math.random() * 360 + ",100%,50%)";
      });
demo10 showed us how to serve d3.v3.min.js and then get access to a JavaScript object named 'd3'.

demo11 does that, and then shows how to get realtime programatic control of an HTML p-element using a simple anonymous JavaScript function.

After I wrote demo11.haml, I generated an HTML file from it using the haml shell command:
cd ~ann/app20/haml/
.  ~ann/app20/app20env.bash
~ann/app20/gems/bin/haml -eq ~ann/app20/haml/demo11.haml ~ann/app20/app/demo11.html
I deployed it to heroku.
cd ~ann/app20
git add .
git commit -am demo11Hello
git push heroku  master
I browsed this URL several times in a row:
https://newyork212.herokuapp.com/app/demo11.html
I noticed the p-elements changed color after each reload.
Compare this behavior to the behavior of demo10 which only serves white text.
Next, using emacs, I started work on ~ann/app20/haml/demo12.haml
!!!
%html(lang="en")
  %head
    %meta(content="text/html; charset=UTF-8" http-equiv="Content-Type")/
    %meta(charset="utf-8")/
    %title demo12
    %script(src="/app/d3.v3.min.js")
  %body
    %h1 hello world
    / The p-elements below should be affected by D3.js
    %p.d3p I am Paragraph 1
    %p.d3p I am Paragraph 2
    %p.d3p I am Paragraph 3
    %p.d3p I am Paragraph 4
    %p.d3p I am Paragraph 5
    %p.d3p I am Paragraph 6
    %p.d3p
      Refer to:
      %a(href='http://d3js.org/#properties' target='x')
        http://d3js.org/#properties
    :javascript
      d3.selectAll("p.d3p").style("color", function(d, i) {
        return i % 2 ? "#eee" : "#444";
      });
    :css
      p.d3p {font-size: 24px;}
demo12 enhances the idea behind demo11.

In demo11, all of the information which changes the p-elements comes from JavaScript.

In demo12, some of the information comes from JavaScript and some comes from the HTML.

This is a powerful concept. It means that D3 can look at information in the HTML, and then use that information to change the HTML.

For example, imagine my HTML contains a table-element with x and y values.

I can use D3 to read the x,y values into a JavaScript array.

The next obvious step is to build a chart from that array.

If the table changes every minute, D3 will update the chart automatically.

I demonstrate this table-chart idea at this URL:

http://www.spy611.com/pred_lr

If I browse that URL with JavaScript disabled, I only see a plain table.

If I enable JavaScript, D3 builds a chart from the data in the table, and it decorates the table based on the data in the table.

Anyway, after I wrote ~ann/app20/haml/demo12.haml I used the haml command to generate HTML from it:
cd ~ann/app20/haml/
.  ~ann/app20/app20env.bash
~ann/app20/gems/bin/haml -eq ~ann/app20/haml/demo12.haml ~ann/app20/app/demo12.html
I deployed it to heroku.
cd ~ann/app20
git add .
git commit -am demo12Hello
git push heroku  master
I saw it here:
https://newyork212.herokuapp.com/app/demo12.html


Next, using emacs, I started work on ~ann/app20/haml/demo13.haml
!!!
%html(lang="en")
  %head
    %meta(content="text/html; charset=UTF-8" http-equiv="Content-Type")/
    %meta(charset="utf-8")/
    %title demo13
    %script(src="/app/d3.v3.min.js")
  %body
    %h1 demo13
    / The p-elements below should be affected by D3.js
    %p.d3p I am Paragraph 1
    %p.d3p I am Paragraph 2
    %p.d3p I am Paragraph 3
    %p.d3p I am Paragraph 4
    %p.d3p I am Paragraph 5
    %p.d3p I am Paragraph 6
    %p.d3p I am Paragraph 7
    %p.d3p I am Paragraph 8
    %p.d3p I am Paragraph 9
    %p.d3p
      Refer to:
      %a(href='http://d3js.org/#properties' target='x')
        http://d3js.org/#properties
    :javascript
      d3.selectAll("p.d3p")
        .data([4, 8, 15, 16, 23, 42])
        .style("font-size", function(d) { return d + "px"; });
The above demo shows how to attach a data source (in this case a simple JS array) to a selection of p-elements.

Each member of the data source is matched to a corresponding member of the p-element-selection.

After the match is made, a method is called which allows me to run an anonymous function against the match.

If I did not have D3 and had to do this by hand, I would probably need to write a nested loop which has the outer-loop iterate through the p-elements and an inner loop which selects an array element for each p-element. Then the pair of objects would get fed to the anonymous function.

Anyway, after I wrote ~ann/app20/haml/demo13.haml I used the haml command to generate HTML from it:
cd ~ann/app20/haml/
.  ~ann/app20/app20env.bash
~ann/app20/gems/bin/haml -eq ~ann/app20/haml/demo13.haml ~ann/app20/app/demo13.html
I deployed it to heroku.
cd ~ann/app20
git add .
git commit -am demo13Hello
git push heroku  master
I saw it here:
https://newyork212.herokuapp.com/app/demo13.html


Next, using emacs, I started work on ~ann/app20/haml/demo14.haml
!!!
%html(lang="en")
  %head
    %meta(content="text/html; charset=UTF-8" http-equiv="Content-Type")/
    %meta(charset="utf-8")/
    %title demo14
    %script(src="/app/d3.v3.min.js")
  %body.d3body
    %h1 demo14
    #refer
      Refer to:
      %a(href='http://d3js.org/#enter-exit' target='x')
        http://d3js.org/#enter-exit
    :javascript
      d3.select("body.d3body").selectAll("p.d3p")
          .data([4, 8, 15, 16, 23, 42])
        .enter().append("p").attr("class","d3p")
          .text(function(d) { return "I’m number " + d + "!"; });
The above haml file shows how to create p-elements from data source (a JS-array), and then append them to the body element.

So, demo13.haml updates p-elements from a data source and demo14.haml creates elements from data.

I used the haml command to generate HTML from demo14.haml:
cd ~ann/app20/haml/
.  ~ann/app20/app20env.bash
~ann/app20/gems/bin/haml -eq ~ann/app20/haml/demo14.haml ~ann/app20/app/demo14.html
I deployed it to heroku.
cd ~ann/app20
git add .
git commit -am demo14Hello
git push heroku  master
I saw it here:
https://newyork212.herokuapp.com/app/demo14.html


Next, using emacs, I started work on ~ann/app20/haml/demo15.haml
!!!
%html(lang="en")
  %head
    %meta(content="text/html; charset=UTF-8" http-equiv="Content-Type")/
    %meta(charset="utf-8")/
    %title demo15
    %script(src="/app/d3.v3.min.js")
  %body.d3body
    %h1 demo15
    #refer
      Refer to:
      %a(href='http://d3js.org/#enter-exit' target='x')
        http://d3js.org/#enter-exit
    :javascript
      // Update...
      var p = d3.select("body.d3body").selectAll("p.d3p")
          .data([4, 8, 15, 16, 23, 42]);
      // Enter...
      p.enter().append("p").attr("class","d3p")
          .text(function(d) { return "Hello number " + d + "!"; });
      // Exit.
      p.exit().remove();
The above syntax should do the same thing as demo14.haml.

The point of demo15 is to show how to break a long chain of D3 calls into pieces.

Perhaps when you see the pieces you will then understand the D3 API better?

I used the haml command to generate HTML from demo15.haml:
cd ~ann/app20/haml/
.  ~ann/app20/app20env.bash
~ann/app20/gems/bin/haml -eq ~ann/app20/haml/demo15.haml ~ann/app20/app/demo15.html
I deployed it to heroku.
cd ~ann/app20
git add .
git commit -am demo15Hello
git push heroku  master
I saw it here:
https://newyork212.herokuapp.com/app/demo15.html


Next, using emacs, I started work on ~ann/app20/haml/demo16.haml
!!!
%html(lang="en")
  %head
    %meta(content="text/html; charset=UTF-8" http-equiv="Content-Type")/
    %meta(charset="utf-8")/
    %title demo16
    %script(src="/app/d3.v3.min.js")
  %body.d3body
    %h1 demo16
    %svg(width="550" height="550")
      %circle.d3circle(cx="250" cy="250" r="250" fill="blue")
    #refer
      Refer to:
      %a(href='http://d3js.org/#transitions' target='x')
        http://d3js.org/#transitions
    :javascript
      d3.select("body").transition()
          .style("background-color", "grey");
      d3.selectAll("circle.d3circle").transition()
          .duration(750)
          .delay(function(d, i) { return i * 10; })
          .attr("r", function(d) { return Math.sqrt(d * scale); });
The above haml file introduces some new API concepts:
  • svg element
  • circle element inside svg element
  • transitions
An svg-element is created with help from SVG which has been supported by browsers for over 10 years:

https://en.wikipedia.org/wiki/Scalable_Vector_Graphics

For example in demo16 I use two lines of HAML to create a blue circle.

I assume that D3 intends to wrap the SVG API in a way which makes it easier to use.

The next API-idea in demo16 is called 'transitions'.

I can use a transition when I want to change an element in a way which makes the change more evident to the user.

For example if I change the color or size of an element slowly rather than quickly, the user might notice the change more easily.

I used the haml command to generate HTML from demo16.haml:
cd ~ann/app20/haml/
.  ~ann/app20/app20env.bash
~ann/app20/gems/bin/haml -eq ~ann/app20/haml/demo16.haml ~ann/app20/app/demo16.html
I deployed it to heroku.
cd ~ann/app20
git add .
git commit -am demo16Hello
git push heroku  master
I saw it here:
https://newyork212.herokuapp.com/app/demo16.html


Next, using emacs, I started work on ~ann/app20/haml/demo17.haml
!!!
%html(lang="en")
  %head
    %meta(content="text/html; charset=UTF-8" http-equiv="Content-Type")/
    %meta(charset="utf-8")/
    %title demo17
    :css
      .chart div {
        font: 10px sans-serif;
        background-color: steelblue;
        text-align: right;
        padding: 3px;
        margin: 1px;
        color: white;
      }
  %body
    %h1 demo17
    #refer
      Refer to:
      %a(href='http://bost.ocks.org/mike/bar/#manual' target='x')
        http://bost.ocks.org/mike/bar/#manual
    %hr/
    .chart
      %div(style="width: 40px;") 4
      %div(style="width: 80px;") 8
      %div(style="width: 150px;") 15
      %div(style="width: 160px;") 16
      %div(style="width: 230px;") 23
      %div(style="width: 420px;") 42
The above file is the start of a simple bar chart demo. The file contains only HAML and CSS.

I used the haml command to generate HTML from demo17.haml:
cd ~ann/app20/haml/
.  ~ann/app20/app20env.bash
~ann/app20/gems/bin/haml -eq ~ann/app20/haml/demo17.haml ~ann/app20/app/demo17.html
I deployed it to heroku.
cd ~ann/app20
git add .
git commit -am demo17Hello
git push heroku  master
I saw it here:
https://newyork212.herokuapp.com/app/demo17.html


Next, using emacs, I started work on ~ann/app20/haml/demo18.haml
!!!
%html(lang="en")
  %head
    %meta(content="text/html; charset=UTF-8" http-equiv="Content-Type")/
    %meta(charset="utf-8")/
    %title demo18
    %script(src="/app/d3.v3.min.js")
    :css
      .d3chart div {
        font: 10px sans-serif;
        background-color: steelblue;
        text-align: right;
        padding: 3px;
        margin: 1px;
        color: white;
      }
  %body
    %h1 demo18
    #refer
      Refer to:
      %a(href='http://bost.ocks.org/mike/bar/#automatic' target='x')
        http://bost.ocks.org/mike/bar/#automatic
    %hr/
    / The div.d3chart element is acted upon by D3.js:
    .d3chart
    :javascript
      var data = [4, 8, 15, 16, 23, 42];
      d3.select(".d3chart")
        .selectAll("div")
          .data(data)
        .enter().append("div")
          .style("width", function(d) { return d * 10 + "px"; })
          .text(function(d) { return d; });
The above file uses a JS-array-data to drive two types of objects.

I use the data to create div-elements.

I use the data to fill the new div-elements with text.

I used the haml command to generate HTML from demo18.haml:
cd ~ann/app20/haml/
.  ~ann/app20/app20env.bash
~ann/app20/gems/bin/haml -eq ~ann/app20/haml/demo18.haml ~ann/app20/app/demo18.html
I deployed it to heroku.
cd ~ann/app20
git add .
git commit -am demo18Hello
git push heroku  master
I saw it here:
https://newyork212.herokuapp.com/app/demo18.html


Next, using emacs, I started work on ~ann/app20/haml/demo19.haml
!!!
%html(lang="en")
  %head
    %meta(content="text/html; charset=UTF-8" http-equiv="Content-Type")/
    %meta(charset="utf-8")/
    %title demo19
    %script(src="/app/d3.v3.min.js")
    :css
      .d3chart div {
        font: 10px sans-serif;
        background-color: steelblue;
        text-align: right;
        padding: 3px;
        margin: 1px;
        color: white;
      }
  %body
    %h1 demo19
    #refer
      Refer to:
      %a(href='http://bost.ocks.org/mike/bar/#automatic' target='x')
        http://bost.ocks.org/mike/bar/#automatic
    %hr/
    / The div.d3chart element is acted upon by D3.js:
    .d3chart
    :javascript
      // I create data to drive the chart.
      var data  = [4, 8, 15, 16, 23, 42];
      // I select the chart container.
      var chart = d3.select(".d3chart");
      // I initiate the data join.
      var bar = chart.selectAll("div");
      // I join the data.
      var barUpdate = bar.data(data);
      // I use enter() to create missing elements.
      var barEnter = barUpdate.enter().append("div");
      // I use my data and D3.js to change style of barEnter.
      barEnter.style("width", function(d) { return d * 10 + "px"; });
      // I set the text content of each bar.
      barEnter.text(function(d) { return d; });
The above haml file offers the same behavior as demo18.haml

The point of demo19 is to show how to break a long chain of D3 calls into pieces.

Perhaps when you see the pieces you will then understand the D3 API better?

I used the haml command to generate HTML from demo19.haml:
cd ~ann/app20/haml/
.  ~ann/app20/app20env.bash
~ann/app20/gems/bin/haml -eq ~ann/app20/haml/demo19.haml ~ann/app20/app/demo19.html
I deployed it to heroku.
cd ~ann/app20
git add .
git commit -am demo19Hello
git push heroku  master
I saw it here:
https://newyork212.herokuapp.com/app/demo19.html


Next, using emacs, I started work on ~ann/app20/haml/demo20.haml
!!!
%html(lang="en")
  %head
    %meta(content="text/html; charset=UTF-8" http-equiv="Content-Type")/
    %meta(charset="utf-8")/
    %title demo20
    %script(src="/app/d3.v3.min.js")
    :css
      .d3chart div {
        font: 10px sans-serif;
        background-color: steelblue;
        text-align: right;
        padding: 3px;
        margin: 1px;
        color: white;
      }
  %body
    %h1 demo20
    #refer
      Refer to:
      %a(href='http://bost.ocks.org/mike/bar/#scaling' target='x')
        http://bost.ocks.org/mike/bar/#scaling
    %hr/
    / The div.d3chart element is acted upon by D3.js:
    .d3chart
    :javascript
      var data = [4, 8, 15, 16, 23, 42];
      var x = d3.scale.linear()
          .domain([0, d3.max(data)])
          .range([0, 800]);
      d3.select(".d3chart")
        .selectAll("div")
          .data(data)
        .enter().append("div")
          .style("width", function(d) { return x(d) + "px"; })
          .text(function(d) { return d; });
In demo20.haml I see how to create a function named, 'x()', which scales values in an array called data.

A synonym of the verb: 'scales' is, 'maps'.

The function, x() maps the min-value of data to 0 and maps the max-value of data to 800.

Then later in the file, I see how x() is actually called.

I used the haml command to generate HTML from demo20.haml:
cd ~ann/app20/haml/
.  ~ann/app20/app20env.bash
~ann/app20/gems/bin/haml -eq ~ann/app20/haml/demo20.haml ~ann/app20/app/demo20.html
I deployed it to heroku.
cd ~ann/app20
git add .
git commit -am demo20Hello
git push heroku  master
I saw it here:
https://newyork212.herokuapp.com/app/demo20.html


Next, using emacs, I started work on ~ann/app20/haml/demo21.haml
!!!
%html(lang="en")
  %head
    %meta(content="text/html; charset=UTF-8" http-equiv="Content-Type")/
    %meta(charset="utf-8")/
    %title demo21
    :css
      .chart rect {
        fill: steelblue;
      }
      .chart text {
        fill: white;
        font: 10px sans-serif;
        text-anchor: end;
      }
  %body
    %h1 demo21
    #refer
      Refer to:
      %br/
      %a(href='http://bost.ocks.org/mike/bar/2/#manual' target='x')
        http://bost.ocks.org/mike/bar/2/#manual
      %br/
      %a(href='http://bl.ocks.org/mbostock/7331260' target='x')
        http://bl.ocks.org/mbostock/7331260
    %hr/
    %svg.chart(height="120" width="420")
      %g(transform="translate(0,0)")
        %rect(height="19" width="40")
        %text(dy=".35em" x="37" y="9.5") 4
      %g(transform="translate(0,20)")
        %rect(height="19" width="80")
        %text(dy=".35em" x="77" y="9.5") 8
      %g(transform="translate(0,40)")
        %rect(height="19" width="150")
        %text(dy=".35em" x="147" y="9.5") 15
      %g(transform="translate(0,60)")
        %rect(height="19" width="160")
        %text(dy=".35em" x="157" y="9.5") 16
      %g(transform="translate(0,80)")
        %rect(height="19" width="230")
        %text(dy=".35em" x="227" y="9.5") 23
      %g(transform="translate(0,100)")
        %rect(height="19" width="420")
        %text(dy=".35em" x="417" y="9.5") 42
In demo21.haml I see how to duplicate the behavior of demo17.haml using plain SVG rather than div-elements.

The differences between the two files appear in two places:
  • The CSS is different
  • The element names are different
Another obvious difference is that the syntax in demo21.haml is more verbose than the syntax in demo17.haml

Note, however, that both files contain no JavaScript.

I used the haml command to generate HTML from demo21.haml:
cd ~ann/app20/haml/
.  ~ann/app20/app20env.bash
~ann/app20/gems/bin/haml -eq ~ann/app20/haml/demo21.haml ~ann/app20/app/demo21.html
I deployed it to heroku.
cd ~ann/app20
git add .
git commit -am demo21Hello
git push heroku  master
I saw it here:
https://newyork212.herokuapp.com/app/demo21.html


Next, using emacs, I started work on ~ann/app20/haml/demo22.haml
!!!
%html(lang="en")
  %head
    %meta(content="text/html; charset=UTF-8" http-equiv="Content-Type")/
    %meta(charset="utf-8")/
    %title demo22
    %script(src="/app/d3.v3.min.js")
    :css
      .d3chart rect {
        fill: steelblue;
      }
      .d3chart text {
        fill: white;
        font: 10px sans-serif;
        text-anchor: end;
      }
  %body
    %h1 demo22
    #refer
      Refer to:
      %br/
      %a(href='http://bost.ocks.org/mike/bar/2/#automatic' target='x')
        http://bost.ocks.org/mike/bar/2/#automatic
      %br/
      %a(href='http://bl.ocks.org/mbostock/7331275' target='x')
        http://bl.ocks.org/mbostock/7331275
    %hr/
    %svg.d3chart
    :javascript
      var data = [4, 8, 15, 16, 23, 42];
      var width = 420,
          barHeight = 20;
      var x = d3.scale.linear()
          .domain([0, d3.max(data)])
          .range([0, width]);
      var chart = d3.select(".d3chart")
          .attr("width", width)
          .attr("height", barHeight * data.length);
      var bar = chart.selectAll("g")
          .data(data)
        .enter().append("g")
          .attr("transform", function(d, i) { return "translate(0," + i * barHeight + ")"; });
      bar.append("rect")
          .attr("width", x)
          .attr("height", barHeight - 1);
      bar.append("text")
          .attr("x", function(d) { return x(d) - 3; })
          .attr("y", barHeight / 2)
          .attr("dy", ".35em")
          .text(function(d) { return d; });
The above file enhances demo21.haml by showing how to connect the D3 API to SVG elements.

I used the haml command to generate HTML from demo22.haml:
cd ~ann/app20/haml/
.  ~ann/app20/app20env.bash
~ann/app20/gems/bin/haml -eq ~ann/app20/haml/demo22.haml ~ann/app20/app/demo22.html
I deployed it to heroku.
cd ~ann/app20
git add .
git commit -am demo22Hello
git push heroku  master
I saw it here:
https://newyork212.herokuapp.com/app/demo22.html


Next, using emacs, I started work on ~ann/app20/haml/demo23.haml
!!!
%html(lang="en")
  %head
    %meta(content="text/html; charset=UTF-8" http-equiv="Content-Type")/
    %meta(charset="utf-8")/
    %title demo23
    %script(src="/app/d3.v3.min.js")
    :css
      .d3chart rect {
        fill: steelblue;
      }
      .d3chart text {
        fill: white;
        font: 10px sans-serif;
        text-anchor: end;
      }
  %body
    %h1 demo23
    #refer
      Refer to:
      %br/
      %a(href='http://bost.ocks.org/mike/bar/2/#data' target='x')
        http://bost.ocks.org/mike/bar/2/#data
      %br/
      %a(href='http://bl.ocks.org/mbostock/7341714' target='x')
        http://bl.ocks.org/mbostock/7341714
      %br
      %a(href='/app/demo23data.tsv') /app/demo23data.tsv
    %hr/
    %svg.d3chart
    :javascript
      var width = 420, barHeight = 20;
      
      var x = d3.scale.linear()
          .range([0, width]);
      
      var chart = d3.select(".d3chart")
          .attr("width", width);
      
      d3.tsv("/app/demo23data.tsv", type, function(error, data) {
        x.domain([0, d3.max(data, function(d) { return d.value; })]);
      
        chart.attr("height", barHeight * data.length);
      
        var bar = chart.selectAll("g")
            .data(data)
          .enter().append("g")
            .attr("transform", function(d, i) { return "translate(0," + i * barHeight + ")"; });
      
        bar.append("rect")
            .attr("width", function(d) { return x(d.value); })
            .attr("height", barHeight - 1);
      
        bar.append("text")
            .attr("x", function(d) { return x(d.value) - 3; })
            .attr("y", barHeight / 2)
            .attr("dy", ".35em")
            .text(function(d) { return d.value; });
      });
      
      function type(d) {
        d.value = +d.value; // coerce to number
        return d;
      }
The above file enhances demo22.haml by showing how to replace an internal JS-array with external data file.

I used the haml command to generate HTML from demo23.haml:
cd ~ann/app20/haml/
.  ~ann/app20/app20env.bash
~ann/app20/gems/bin/haml -eq ~ann/app20/haml/demo23.haml ~ann/app20/app/demo23.html
I copied demo23data.tsv into place:
cd ~ann/app20/app
curl https://newyork212.herokuapp.com/app/demo23data.tsv > ~ann/app20/app/demo23data.tsv
I deployed it to heroku.
cd ~ann/app20
git add .
git commit -am demo23Hello
git push heroku  master
I saw it here:
https://newyork212.herokuapp.com/app/demo23.html


Next, using emacs, I started work on ~ann/app20/haml/demo24.haml
!!!
%html(lang='en')
  %head
    %meta(content='text/html; charset=UTF-8' http-equiv='Content-Type')/
    %meta(charset='utf-8')/
    %title demo24
    %script(src='/app/d3.v3.min.js')
    :css
      .d3chart rect {
        fill: steelblue;
      }
      .d3chart text {
        fill: white;
        font: 10px sans-serif;
        text-anchor: end;
      }
  %body
    %h1 demo24
    #refer
      Refer to:
      %br/
      %a(href='http://bost.ocks.org/mike/bar/2/#data' target='x')
        http://bost.ocks.org/mike/bar/2/#data
      %br/
      %a(href='http://bl.ocks.org/mbostock/7341714' target='x')
        http://bl.ocks.org/mbostock/7341714
      %br
      %a(href='/app/demo23data.tsv') /app/demo23data.tsv
      %br
      %a(href='/fee/demo24.coffee') /fee/demo24.coffee
      %br
      %a(href='/app/demo24.js') /app/demo24.js
    %hr/
    %svg.d3chart
    %script(src='/app/demo24.js')
The above file shows that I can move the JavaScript out of the HAML into a separate file called this:
~ann/app20/app/demo24.js

A simple way to do that is a straight copy using emacs.

Another way is to start with a file full of CoffeeScript.

I created a CoffeeScript file at this path:
~ann/app20/fee/demo24.coffee
# ~ann/app20/fee/demo24.coffee

width = 420
barHeight = 20
x = d3.scale.linear().range([
  0
  width
])
chart = d3.select('.d3chart').attr('width', width)

type = (d) ->
  d.value = +d.value
  # coerce to number
  d

d3.tsv '/app/demo23data.tsv', type, (error, data) ->
  x.domain [
    0
    d3.max(data, (d) ->
      d.value
    )
  ]
  chart.attr 'height', barHeight * data.length
  bar = chart.selectAll('g').data(data).enter().append('g').attr('transform', (d, i) ->
    'translate(0,' + i * barHeight + ')'
  )
  bar.append('rect').attr('width', (d) ->
    x d.value
  ).attr 'height', barHeight - 1
  bar.append('text').attr('x', (d) ->
    x(d.value) - 3
  ).attr('y', barHeight / 2).attr('dy', '.35em').text (d) ->
    d.value
  return
Then, I converted the CoffeeScript into JavaScript:
npm install -g coffee-script
coffee -bpc ~ann/app20/fee/demo24.coffee > ~ann/app20/app/demo24.js
I used the haml command to generate HTML from demo24.haml:
cd ~ann/app20/haml/
.  ~ann/app20/app20env.bash
~ann/app20/gems/bin/haml -eq ~ann/app20/haml/demo24.haml ~ann/app20/app/demo24.html
I deployed it to heroku.
cd ~ann/app20
git add .
git commit -am demo24Hello
git push heroku  master
I saw it here:
https://newyork212.herokuapp.com/app/demo24.html


Next, using emacs, I started work on ~ann/app20/haml/demo25.haml
!!!
%html(lang='en')
  %head
    %meta(content='text/html; charset=UTF-8' http-equiv='Content-Type')/
    %meta(charset='utf-8')/
    %title demo25
    %script(src='/app/d3.v3.min.js')
    :css
      .bar {
        fill: steelblue;
      }
      .bar:hover {
        fill: brown;
      }
      .axis {
        font: 10px sans-serif;
      }
      .axis path,
      .axis line {
        fill: none;
        stroke: #000;
        shape-rendering: crispEdges;
      }
      .x.axis path {
        display: none;
      }
  / Note: D3.js acts on body-element
  %body.d3body
    %h1 demo25
    #refer
      Refer to:
      %br/
      %a(href='http://bost.ocks.org/mike/bar/3/' target='x')
        http://bost.ocks.org/mike/bar/3/
      %br/
      %a(href='http://bl.ocks.org/mbostock/3885304/' target='x')
        http://bl.ocks.org/mbostock/3885304/
      %br/
      %a(href='/app/demo25data.tsv') /app/demo25data.tsv
      %br/
      %a(href='/fee/demo25.coffee') /fee/demo25.coffee
      %br/
      %a(href='/app/demo25.js') /app/demo25.js
      %br/
      %a(href='view-source:http://bl.ocks.org/mbostock/raw/3885304/' target='v')
        view-source:http://bl.ocks.org/mbostock/raw/3885304
    %hr/
    %script(src='/app/demo25.js')
Then I wrote CoffeeScript into ~ann/fee/demo25.coffee
# ~ann/app20/fee/demo25.coffee

margin = 
  top: 20
  right: 20
  bottom: 30
  left: 40
width = 960 - (margin.left) - (margin.right)
height = 500 - (margin.top) - (margin.bottom)
x = d3.scale.ordinal().rangeRoundBands([
  0
  width
], .1)
y = d3.scale.linear().range([
  height
  0
])
xAxis = d3.svg.axis().scale(x).orient('bottom')
yAxis = d3.svg.axis().scale(y).orient('left').ticks(10, '%')
svg = d3.select('body.d3body').append('svg').attr('width', width + margin.left + margin.right).attr('height', height + margin.top + margin.bottom).append('g').attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')

type = (d) ->
  d.frequency = +d.frequency
  d

d3.tsv '/app/demo25data.tsv', type, (error, data) ->
  if error
    throw error
  x.domain data.map((d) ->
    d.letter
  )
  y.domain [
    0
    d3.max(data, (d) ->
      d.frequency
    )
  ]
  svg.append('g').attr('class', 'x axis').attr('transform', 'translate(0,' + height + ')').call xAxis
  svg.append('g').attr('class', 'y axis').call(yAxis).append('text').attr('transform', 'rotate(-90)').attr('y', 6).attr('dy', '.71em').style('text-anchor', 'end').text 'Frequency'
  svg.selectAll('.bar').data(data).enter().append('rect').attr('class', 'bar').attr('x', (d) ->
    x d.letter
  ).attr('width', x.rangeBand()).attr('y', (d) ->
    y d.frequency
  ).attr 'height', (d) ->
    height - y(d.frequency)
  return
Next, I converted the CoffeeScript into JavaScript:
coffee -bpc ~ann/app20/fee/demo25.coffee > ~ann/app20/app/demo25.js
I used the haml command to generate HTML from demo25.haml:
cd ~ann/app20/haml/
.  ~ann/app20/app20env.bash
~ann/app20/gems/bin/haml -eq ~ann/app20/haml/demo25.haml ~ann/app20/app/demo25.html
I deployed it to heroku.
cd ~ann/app20
git add .
git commit -am demo25Hello
git push heroku  master
I saw it here:
https://newyork212.herokuapp.com/app/demo25.html

When I compare the syntax in demo25.coffee to the JS-syntax from the original demo, it seems the JS-syntax is actually easier to read:

view-source:http://bl.ocks.org/mbostock/raw/3885304/

For me, CoffeeScript is usually easier to read than JavaScript but that is not true in this demo.

The coding style used by many D3-developers which breaks up long chains of calls, with indented whitespace, works well for me when I read their code.

So, when I write D3 apps, I will rely less on CoffeeScript.


That could be considered an adequate code challenge for a two hour Meetup.

If you have questions, e-me:

bikle101@gmail.com


syntax.us Let the syntax do the talking
Blog Contact Posts Questions Tags Hire Me