Skip to content
Browse files

reworked how the examples work"

  • Loading branch information...
1 parent 46a7b3f commit 2535117ba0202d96e1f34504d26bb731708c636f @vogievetsky committed
Showing with 678 additions and 531 deletions.
  1. +1 −1 deck/deck.css
  2. +2 −0 deck/deck.less
  3. +5 −1 deck/slide_maker.js
  4. +3 −529 index.html
  5. +112 −0 slide_maker.js
  6. +498 −0 slides.coffee
  7. +57 −0 slides.js
View
2 deck/deck.css
@@ -10,7 +10,7 @@ section.title h1{margin-top:310px;font-size:40px;}
section.top_title h1{margin-top:22px;margin-bottom:15px;font-size:36px;}
section.code_title h1{font-family:"Courier New",monospace;margin-top:310px;font-size:42px;}
section.code_slide h1{font-family:"Courier New",monospace;margin-top:22px;font-size:36px;}
-section.code_slide div.codes{position:absolute;left:10px;bottom:10px;right:517px;top:90px;}section.code_slide div.codes textarea{font-family:"Courier New",monospace;text-align:left;width:100%;height:100%;border:1px solid #ccc;font-size:16px;padding:4px 4px;resize:none;}section.code_slide div.codes textarea.init{display:none;}
+section.code_slide div.codes{position:absolute;left:10px;bottom:10px;right:517px;top:90px;}section.code_slide div.codes textarea{font-family:"Courier New",monospace;text-align:left;width:100%;height:100%;border:1px solid #ccc;font-size:16px;padding:4px 4px;resize:none;outline:none;white-space:pre;}section.code_slide div.codes textarea.init{display:none;}
section.code_slide div.codes div.button_bar{position:absolute;right:16px;bottom:4px;}section.code_slide div.codes div.button_bar div.reset,section.code_slide div.codes div.button_bar div.run{margin:3px;}
section.code_slide div.out{position:absolute;right:10px;bottom:10px;left:517px;top:90px;border:1px solid #ccc;}section.code_slide div.out div.error{position:absolute;background:white;top:5px;left:5px;right:5px;color:red;border:2px solid red;z-index:100;padding:10px;font-size:16px;}
section.code_slide div.out pre.log{position:absolute;background:white;top:5px;left:5px;right:5px;border:2px solid black;z-index:99;padding:10px;font-size:16px;text-align:left;}
View
2 deck/deck.less
@@ -151,6 +151,8 @@ section {
font-size: 16px;
padding: 4px 4px;
resize: none;
+ outline: none;
+ white-space: pre;
&.init {
display: none;
View
6 deck/slide_maker.js
@@ -10,6 +10,8 @@
.replace(/\s*}\s*$/, '')
.split('\n');
+ lines = lines.map(function(line) { return line.replace(/ *$/, ''); });
+
// remove common pre-space
var minSpace = d3.min(lines.map(function(line) {
return line ? line.match(/^\s*/)[0].length : Infinity;
@@ -18,6 +20,7 @@
lines = lines.map(function(line) { return line.substr(minSpace); })
}
+ console.log(lines.join('\n'))
return lines.join('\n');
}
@@ -67,7 +70,8 @@
}
codeText = codes.append('textarea')
- .attr('class', 'code')
+ .attr('class', 'code')
+ .attr('placeholder', 'JavaScript goes in here...')
.property('value', fn_to_string(code))
.on('keydown', function() {
// Run if command + enter
View
532 index.html
@@ -5,46 +5,6 @@
<link rel="stylesheet" type="text/css" href="deck/deck.css">
<script src="d3/d3.js"></script>
<script src="deck/slide_maker.js"></script>
- <script>
- var title;
-
- function empty_svg(parent) {
- window.svg = d3.select(parent).append('svg');
- }
-
- function rect1(parent) {
- empty_svg(parent);
-
- svg
- .append('rect')
- .attr('x', 150)
- .attr('y', 100)
- .attr('width', 60)
- .attr('height', 300);
- }
-
- function rect3(parent) {
- empty_svg(parent);
-
- svg.append('rect')
- .attr('x', 200)
- .attr('y', 300)
- .attr('width', 40)
- .attr('height', 50);
-
- svg.append('rect')
- .attr('x', 100)
- .attr('y', 20)
- .attr('width', 30)
- .attr('height', 50);
-
- svg.append('rect')
- .attr('x', 10)
- .attr('y', 200)
- .attr('width', 25)
- .attr('height', 90);
- }
- </script>
</head>
<body>
@@ -56,493 +16,7 @@
<div class="date">Feb 16, 2012</div>
</section>
- <script>
- slide.title('First some JavaScript')
-
- slide.code('JavaScript', empty_svg, function() {
- // In JS functions are first class citizens.
- // This is a very powerful concept!
- var squared = function(x) { return x*x };
- console.log('squared(7) ==', squared(7));
-
- // D3 has many helper methods
- // d3.scale.linear() returns a function that
- // will map the given domain to the given
- // range linearly.
- var w = 640, h = 320;
-
- var x = d3.scale.linear()
- .domain([-1, 1])
- .range([0, w]);
-
- var y = d3.scale.linear()
- .domain([0, 1])
- .range([0, h]);
-
- console.log('x(0) ==', x(0)); // == w/2
- console.log('y(3) ==', y(3)); // == 3*h
- });
-
- slide.title('Core D3')
-
- // -----------------------------------------------
- slide.code_title(title = '.select()');
-
- slide.code(title, rect1, function() {
- // svg = d3.select('svg.that_svg_to_the_right')
- var myRect = svg.select('rect')
- myRect.attr('width', 100)
- myRect.attr('height', 100)
- myRect.style('fill', 'steelblue')
- });
-
- slide.code(title, rect1, function() {
- // svg = d3.select('svg.that_svg_to_the_right')
- svg.select('rect')
- .attr('width', 100)
- .attr('height', 100)
- .style('fill', 'steelblue')
- });
-
-
- // -----------------------------------------------
- slide.code_title(title = '.selectAll()');
-
- slide.code(title, rect3, function() {
- svg.select('rect')
- .attr('width', 100)
- .attr('height', 100)
- .style('fill', 'steelblue')
- });
-
- slide.code(title, rect3, function() {
- svg.selectAll('rect')
- .attr('width', 100)
- .attr('height', 100)
- .style('fill', 'steelblue')
- });
-
- slide.code(title, rect3, function() {
- svg.selectAll('rect')
- .attr('x', 0)
- .attr('y', function(d,i) { return i*90+50 })
- .attr('width', function(d,i) {
- return i*150+100;
- })
- .attr('height', 20)
- .style('fill', 'steelblue')
- });
-
-
- // -----------------------------------------------
- slide.code_title(title = '.data()');
-
- slide.code(title, rect3, function() {
- svg.selectAll('rect')
- .data([64, 128, 256])
- .attr('x', 0)
- .attr('y', function(d,i) { return i*90+50 })
- .attr('width', function(d,i) { return d; })
- .attr('height', 20)
- .style('fill', 'steelblue')
- });
-
- // -----------------------------------------------
- slide.code_title(title = '.enter()');
-
- slide.code(title, rect3, function() {
- var selection = svg.selectAll('rect')
- .data([64, 128, 256, 71])
-
- selection
- .attr('x', 0)
- .attr('y', function(d,i) { return i*90+50 })
- .attr('width', function(d,i) { return d; })
- .attr('height', 20)
- .style('fill', 'steelblue')
- });
-
- slide.code(title, rect3, function() {
- var selection = svg.selectAll('rect')
- .data([64, 128, 256, 71])
-
- selection
- .attr('x', 0)
- .attr('y', function(d,i) { return i*90+50 })
- .attr('width', function(d,i) { return d; })
- .attr('height', 20)
- .style('fill', 'steelblue')
-
- selection.enter().append('rect')
- .attr('x', 10) // let's just put it somewhere
- .attr('y', 10)
- .attr('width', 30)
- .attr('height', 30)
- .style('fill', 'green')
- });
-
- slide.code(title, rect3, function() {
- var selection = svg.selectAll('rect')
- .data([64, 128, 256, 71])
-
- selection
- .attr('x', 0)
- .attr('y', function(d,i) { return i*90+50 })
- .attr('width', function(d,i) { return d; })
- .attr('height', 20)
- .style('fill', 'steelblue')
-
- selection.enter().append('rect')
- .attr('x', 0)
- .attr('y', function(d,i) { return i*90+50 })
- .attr('width', function(d,i) { return d; })
- .attr('height', 20)
- .style('fill', 'steelblue')
- });
-
- slide.code(title, rect3, function() {
- var selection = svg.selectAll('rect')
- .data([64, 128, 256, 71])
-
- // Shorter
- selection.enter().append('rect')
-
- // when updating the regular selection then
- // enter selection is joined in to the update
- // selection for convenience.
- selection
- .attr('x', 0)
- .attr('y', function(d,i) { return i*90+50 })
- .attr('width', function(d,i) { return d; })
- .attr('height', 20)
- .style('fill', 'steelblue')
- });
-
- slide.code(title + ' // a common pattern', empty_svg, function() {
- svg.selectAll('rect')
- .data([64, 128, 256])
- .enter().append('rect')
- .attr('x', 0)
- .attr('y', function(d,i) { return i*90+50 })
- .attr('width', function(d,i) { return d; })
- .attr('height', 20)
- .style('fill', 'steelblue')
- });
-
-
- // -----------------------------------------------
- slide.code_title(title = '.exit()');
-
- slide.code(title, rect3, function() {
- var selection = svg.selectAll('rect')
- .data([64, 128])
-
- selection
- .attr('x', 0)
- .attr('y', function(d,i) { return i*90+50 })
- .attr('width', function(d,i) { return d; })
- .attr('height', 20)
- .style('fill', 'steelblue')
- });
-
- slide.code(title, rect3, function() {
- var selection = svg.selectAll('rect')
- .data([64, 128])
-
- selection
- .attr('x', 0)
- .attr('y', function(d,i) { return i*90+50 })
- .attr('width', function(d,i) { return d; })
- .attr('height', 20)
- .style('fill', 'steelblue')
-
- selection.exit()
- .remove()
- });
-
-
- // -----------------------------------------------
- slide.code_title(title = '.transition()');
-
- slide.code(title, rect3, function() {
- svg.selectAll('rect')
- .data([64, 128, 256])
- .transition()
- .duration(3000) // 3 seconds
- .attr('x', 0)
- .attr('y', function(d,i) { return i*90+50 })
- .attr('width', function(d,i) { return d; })
- .attr('height', 20)
- .style('fill', 'steelblue')
- });
-
- slide.code(title, rect3, function() {
- var selection = svg.selectAll('rect')
- .data([64, 128, 256, 71])
-
- selection.enter().append('rect')
- .attr('x', 200)
- .attr('y', 200)
- .attr('width', 10)
- .attr('height', 10)
- .style('fill', 'red')
-
- selection
- .transition()
- .duration(3000)
- .attr('x', 0)
- .attr('y', function(d,i) { return i*90+50 })
- .attr('width', function(d,i) { return d; })
- .attr('height', 20)
- .style('fill', 'steelblue')
- .transition()
- .duration(3000)
- .delay(3000)
- .style('fill', 'green')
- .attr('width', function(d,i) {
- return d*1.5;
- })
-
- selection.exit()
- .attr('opacity', 1)
- .transition()
- .duration(3000)
- .attr('opacity', 0)
- .remove();
- });
-
- // -----------------------------------------------
- slide.code_title(title = '.data(..., join)');
-
- function init_svg(parent) {
- empty_svg(parent);
- svg.selectAll('rect')
- .data([64, 128, 256])
- .enter().append('rect')
- .attr('x', 0)
- .attr('y', function(d,i) { return i*90+50 })
- .attr('width', function(d,i) { return d; })
- .attr('height', 20)
- .style('fill', 'steelblue')
- }
-
- slide.code(title, init_svg, function() {
- // Let's say we start here:
- /*
- svg.selectAll('rect')
- .data([64, 128, 256])
- .enter().append('rect')
- .attr('x', 0)
- .attr('y', function(d,i) { return i*90+50 })
- .attr('width', function(d,i) { return d; })
- .attr('height', 20)
- .style('fill', 'steelblue')
- */
- // And then we do this:
-
- var selection = svg.selectAll('rect')
- .data([128, 256, 71]) // <- incomplete?
-
- selection.enter().append('rect')
- .attr('x', 0)
- .attr('y', function(d,i) { return i*90+50 })
- .attr('width', function(d,i) { return d; })
- .attr('height', 20)
- .style('fill', 'steelblue')
-
- selection
- .transition()
- .duration(3000)
- .attr('x', 0)
- .attr('y', function(d,i) { return i*90+50 })
- .attr('width', function(d,i) { return d; })
- .attr('height', 20)
- .style('fill', 'steelblue')
-
- selection.exit()
- .remove()
-
- // Note that String(5) === "5"
- });
-
- slide.code(title, init_svg, function() {
- // Start the same as before
-
- var selection = svg.selectAll('rect')
- .data([128, 256, 71], String)
-
- selection.enter().append('rect')
- .attr('x', 0)
- .attr('y', function(d,i) {
- return (i+1)*100+50
- })
- .attr('width', function(d,i) { return d; })
- .attr('height', 20)
- .style('fill', 'steelblue')
- .style('opacity', 0)
-
- selection
- .transition()
- .duration(3000)
- .attr('y', function(d,i) { return i*90+50 })
- .attr('height', 20)
- .style('opacity', 1)
-
- selection.exit()
- .transition()
- .duration(3000)
- .attr('y', function(d,i) {
- return (i-1)*100+50
- })
- .style('opacity', 0)
- .remove()
- });
-
- // -----------------------------------------------
- slide.title('Educational Examples');
-
- slide.code('Shuffle', empty_svg, function() {
- // Global var accessible in subsequent runs
- window.cards = window.cards || (function() {
- var ret = [];
- for (var i = 0; i < 4; i++) {
- for (var j = 0; j < 4; j++) {
- ret.push(
- 'JKQA'[i] +
- '\u2665\u2666\u2663\u2660'[j]);
- }
- }
- return ret;
- })();
-
- cards.sort(function() {return Math.random()-.5})
-
- var selection = svg.selectAll('text')
- .data(cards, String)
-
- selection
- .transition()
- .duration(1000)
- .attr('y', function(d,i) { return i*35+40 })
-
- selection.enter().append('text')
- .attr('x', 30)
- .attr('y', function(d,i) { return i*35+40 })
- .style('fill', function(d) {
- return '\u2665\u2666'.indexOf(d[1]) < 0 ?
- 'black' : 'red';
- })
- .style('font', '20px monospace')
- .text(String)
- });
-
- function init_cards(parent) {
- empty_svg(parent);
- window.cards = window.cards || (function() {
- var ret = [];
- for (var i = 0; i < 4; i++) {
- for (var j = 0; j < 4; j++) {
- ret.push(
- 'JKQA'[i] +
- '\u2665\u2666\u2663\u2660'[j]);
- }
- }
- return ret;
- })();
- }
-
- slide.code('Shuffle (v2)', init_cards, function() {
- // window.cards = ... same as before
-
- cards.sort(function() {return Math.random()-.5})
-
- var selection = svg.selectAll('text')
- .data(cards, String)
-
- selection
- .transition().duration(500)
- .attr('x', function(d,i) {return (i%8)*30+30})
- .transition().duration(500).delay(500)
- .attr('y', function(d,i) { return i*35+40 })
- .transition().duration(500).delay(1000)
- .attr('x', 30)
-
- selection.enter().append('text')
- .attr('x', 30)
- .attr('y', function(d,i) { return i*35+40 })
- .style('fill', function(d) {
- return '\u2665\u2666'.indexOf(d[1]) < 0 ?
- 'black' : 'red';
- })
- .style('font', '20px monospace')
- .text(String)
- });
-
- // -----------------------------------------------
- slide.code('Drawing lines', empty_svg, function() {
- svg.append('path')
- .style('fill', 'none')
- .style('stroke', 'black')
- .style('stroke-width', 2)
- .attr('d', 'M 10 10 L 200 200 '+
- 'L 200 400 L 300 100 L 400 150')
- });
-
- slide.code('Drawing lines', empty_svg, function() {
- var points = [
- { x: 10, y: 10 },
- { x: 200, y: 200 },
- { x: 200, y: 400 },
- { x: 300, y: 100 },
- { x: 400, y: 150 }
- ]
-
- var lineFn = d3.svg.line()
- .x(function(d) { return d.x })
- .y(function(d) { return d.y })
-
- svg.append('path').data([points])
- .style('fill', 'none')
- .style('stroke', 'black')
- .style('stroke-width', 2)
- .attr('d', lineFn)
- });
-
- slide.code('Drawing lines', empty_svg, function() {
- var pointsSin = d3.range(20).map(function(i) {
- return {x: i/19, y: (Math.sin(i/3) + 1) / 2}
- })
- var pointsCos = d3.range(20).map(function(i) {
- return {x: i/19, y: (Math.cos(i/3) + 1) / 2}
- })
-
-
- var w = 480
- var h = 300
- var x = d3.scale.linear()
- .domain([0, 1]).range([0, w])
- var y = d3.scale.linear()
- .domain([0, 1]).range([h, 0])
-
- var lineFn = d3.svg.line()
- .x(function(d) { return x(d.x); })
- .y(function(d) { return y(d.y); })
-
- svg.selectAll('path')
- .data([pointsSin, pointsCos])
- .enter().append("path")
- .style('fill', 'none')
- .style('stroke', 'black')
- .style('stroke-width', 2)
- .attr('d', lineFn)
- });
-
- /*
- ToDo:
- - add MMX logo
- */
-
- </script>
+ <script src="slides.js"></script>
<section class="top_title">
<h1>Where to learn more about SVG?</h1>
@@ -552,9 +26,9 @@
<section class="title">
<h1>Questions?</h1>
- <img class='mmx' src="images/MMX-logo.png">
+ <img class="mmx" src="images/MMX-logo.png">
</section>
+ <script src="deck/deck.js"></script>
</body>
- <script src="deck/deck.js"></script>
</html>
View
112 slide_maker.js
@@ -0,0 +1,112 @@
+(function() {
+ "use strict"
+
+ var slide = {};
+ window.slide = slide;
+
+ function fn_to_string(fn) {
+ var lines = fn.toString()
+ .replace(/^function\s*\([^)]*\)\s*{\s*\n/, '')
+ .replace(/\s*}\s*$/, '')
+ .split('\n');
+
+ // remove common pre-space
+ var minSpace = d3.min(lines.map(function(line) {
+ return line ? line.match(/^\s*/)[0].length : Infinity;
+ }));
+ if (minSpace && isFinite(minSpace)) {
+ lines = lines.map(function(line) { return line.substr(minSpace); })
+ }
+
+ return lines.join('\n');
+ }
+
+ slide.code = function(title, init, code) {
+ var out, codeText;
+
+ function myInit() {
+ out.selectAll('*').remove();
+ init(out.node());
+ }
+
+ var section = d3.select('body')
+ .append('section')
+ .data([myInit])
+ .attr('class', "code_slide")
+
+ section.append('h1')
+ .text(title)
+
+ var codes = section.append('div')
+ .attr('class', 'codes')
+
+ function myConsoleLog() {
+ var str = Array.prototype.slice.call(arguments).join(' ') + '\n';
+ var pre = out.select('pre.log');
+ if (pre.empty()) {
+ out.append('pre')
+ .attr('class', 'log')
+ .text(str)
+ } else {
+ pre.text(pre.text() + str);
+ }
+ }
+
+ function run() {
+ var code = codeText.property('value');
+ code = '(function(console) { \n' + code + '\n})({ log: myConsoleLog })';
+ out.select('div.error').remove();
+ out.select('pre.log').remove();
+ try {
+ eval(code);
+ } catch(err) {
+ out.append('div')
+ .attr('class', 'error')
+ .text('Error: ' + err.message)
+ }
+ }
+
+ codeText = codes.append('textarea')
+ .attr('class', 'code')
+ .property('value', fn_to_string(code))
+ .on('keydown', function() {
+ // Run if command + enter
+ if (d3.event.keyCode === 13 && d3.event.metaKey) run();
+ d3.event.stopPropagation();
+ })
+
+ var buttonBar = codes.append('div')
+ .attr('class', 'button_bar')
+
+ buttonBar.append('div')
+ .attr('class', 'run btn')
+ .text('Run')
+ .on('click', run)
+
+ buttonBar.append('div')
+ .attr('class', 'reset btn')
+ .text('Reset')
+ .on('click', myInit)
+
+ out = section.append('div')
+ .attr('class', "out")
+ }
+
+ slide.code_title = function(title) {
+ d3.select('body')
+ .append('section')
+ .attr('class', "code_title")
+ .append('h1')
+ .text(title);
+ }
+
+ slide.title = function(title) {
+ d3.select('body')
+ .append('section')
+ .attr('class', "title")
+ .append('h1')
+ .text(title);
+ }
+})();
+
+
View
498 slides.coffee
@@ -0,0 +1,498 @@
+empty_svg = (parent) ->
+ window.svg = d3.select(parent).append("svg")
+
+rect1 = (parent) ->
+ empty_svg(parent);
+
+ svg
+ .append("rect")
+ .attr("x", 150)
+ .attr("y", 100)
+ .attr("width", 60)
+ .attr("height", 300)
+
+
+rect3 = (parent) ->
+ empty_svg(parent)
+
+ svg.append("rect")
+ .attr("x", 200)
+ .attr("y", 300)
+ .attr("width", 40)
+ .attr("height", 50);
+
+ svg.append("rect")
+ .attr("x", 100)
+ .attr("y", 20)
+ .attr("width", 30)
+ .attr("height", 50);
+
+ svg.append("rect")
+ .attr("x", 10)
+ .attr("y", 200)
+ .attr("width", 25)
+ .attr("height", 90)
+
+# ----------------------------------------------------
+
+slide.code "JavaScript", empty_svg, """
+ // In JS functions are first class citizens.
+ // This is a very powerful concept!
+ var squared = function(x) { return x*x };
+ console.log("squared(7) ==", squared(7));
+
+
+ // D3 has many helper methods
+ // d3.scale.linear() returns a function that
+ // will map the given domain to the given
+ // range linearly.
+ var w = 640, h = 320;
+
+ var x = d3.scale.linear()
+ .domain([-1, 1])
+ .range([0, w]);
+
+ var y = d3.scale.linear()
+ .domain([0, 1])
+ .range([0, h]);
+
+ console.log("x(0) ==", x(0)); // == w/2
+ console.log("y(3) ==", y(3)); // == 3*h
+"""
+
+slide.title "Core D3"
+
+# -----------------------------------------------
+slide.code_title(title = ".select()");
+
+slide.code title, rect1, """
+ // svg = d3.select("svg.that_svg_to_the_right")
+ var myRect = svg.select("rect")
+ myRect.attr("width", 100)
+ myRect.attr("height", 100)
+ myRect.style("fill", "steelblue")
+"""
+
+slide.code title, rect1, """
+ // svg = d3.select("svg.that_svg_to_the_right")
+ svg.select("rect")
+ .attr("width", 100)
+ .attr("height", 100)
+ .style("fill", "steelblue")
+"""
+
+
+# -----------------------------------------------
+slide.code_title(title = ".selectAll()");
+
+slide.code title, rect3, """
+ svg.select("rect")
+ .attr("width", 100)
+ .attr("height", 100)
+ .style("fill", "steelblue")
+"""
+
+slide.code title, rect3, """
+ svg.selectAll("rect")
+ .attr("width", 100)
+ .attr("height", 100)
+ .style("fill", "steelblue")
+"""
+
+slide.code title, rect3, """
+ svg.selectAll("rect")
+ .attr("x", 0)
+ .attr("y", function(d,i) { return i*90+50 })
+ .attr("width", function(d,i) {
+ return i*150+100;
+ })
+ .attr("height", 20)
+ .style("fill", "steelblue")
+"""
+
+
+# -----------------------------------------------
+slide.code_title(title = ".data()");
+
+slide.code title, rect3, """
+ svg.selectAll("rect")
+ .data([64, 128, 256])
+ .attr("x", 0)
+ .attr("y", function(d,i) { return i*90+50 })
+ .attr("width", function(d,i) { return d; })
+ .attr("height", 20)
+ .style("fill", "steelblue")
+"""
+
+# -----------------------------------------------
+slide.code_title(title = ".enter()");
+
+slide.code title, rect3, """
+ var selection = svg.selectAll("rect")
+ .data([64, 128, 256, 71])
+
+ selection
+ .attr("x", 0)
+ .attr("y", function(d,i) { return i*90+50 })
+ .attr("width", function(d,i) { return d; })
+ .attr("height", 20)
+ .style("fill", "steelblue")
+"""
+
+slide.code title, rect3, """
+ var selection = svg.selectAll("rect")
+ .data([64, 128, 256, 71])
+
+ selection
+ .attr("x", 0)
+ .attr("y", function(d,i) { return i*90+50 })
+ .attr("width", function(d,i) { return d; })
+ .attr("height", 20)
+ .style("fill", "steelblue")
+
+ selection.enter().append("rect")
+ .attr("x", 10) // let"s just put it somewhere
+ .attr("y", 10)
+ .attr("width", 30)
+ .attr("height", 30)
+ .style("fill", "green")
+"""
+
+slide.code title, rect3, """
+ var selection = svg.selectAll("rect")
+ .data([64, 128, 256, 71])
+
+ selection
+ .attr("x", 0)
+ .attr("y", function(d,i) { return i*90+50 })
+ .attr("width", function(d,i) { return d; })
+ .attr("height", 20)
+ .style("fill", "steelblue")
+
+ selection.enter().append("rect")
+ .attr("x", 0)
+ .attr("y", function(d,i) { return i*90+50 })
+ .attr("width", function(d,i) { return d; })
+ .attr("height", 20)
+ .style("fill", "steelblue")
+"""
+
+slide.code title, rect3, """
+ var selection = svg.selectAll("rect")
+ .data([64, 128, 256, 71])
+
+ // Shorter
+ selection.enter().append("rect")
+
+ // when updating the regular selection then
+ // enter selection is joined in to the update
+ // selection for convenience.
+ selection
+ .attr("x", 0)
+ .attr("y", function(d,i) { return i*90+50 })
+ .attr("width", function(d,i) { return d; })
+ .attr("height", 20)
+ .style("fill", "steelblue")
+"""
+
+title += " // a common pattern"
+slide.code title, empty_svg, """
+ svg.selectAll("rect")
+ .data([64, 128, 256])
+ .enter().append("rect")
+ .attr("x", 0)
+ .attr("y", function(d,i) { return i*90+50 })
+ .attr("width", function(d,i) { return d; })
+ .attr("height", 20)
+ .style("fill", "steelblue")
+"""
+
+
+# -----------------------------------------------
+slide.code_title(title = ".exit()");
+
+slide.code title, rect3, """
+ var selection = svg.selectAll("rect")
+ .data([64, 128])
+
+ selection
+ .attr("x", 0)
+ .attr("y", function(d,i) { return i*90+50 })
+ .attr("width", function(d,i) { return d; })
+ .attr("height", 20)
+ .style("fill", "steelblue")
+"""
+
+slide.code title, rect3, """
+ var selection = svg.selectAll("rect")
+ .data([64, 128])
+
+ selection
+ .attr("x", 0)
+ .attr("y", function(d,i) { return i*90+50 })
+ .attr("width", function(d,i) { return d; })
+ .attr("height", 20)
+ .style("fill", "steelblue")
+
+ selection.exit()
+ .remove()
+"""
+
+
+# -----------------------------------------------
+slide.code_title(title = ".transition()");
+
+slide.code title, rect3, """
+ svg.selectAll("rect")
+ .data([64, 128, 256])
+ .transition()
+ .duration(3000) // 3 seconds
+ .attr("x", 0)
+ .attr("y", function(d,i) { return i*90+50 })
+ .attr("width", function(d,i) { return d; })
+ .attr("height", 20)
+ .style("fill", "steelblue")
+"""
+
+slide.code title, rect3, """
+ var selection = svg.selectAll("rect")
+ .data([64, 128, 256, 71])
+
+ selection.enter().append("rect")
+ .attr("x", 200)
+ .attr("y", 200)
+ .attr("width", 10)
+ .attr("height", 10)
+ .style("fill", "red")
+
+ selection
+ .transition()
+ .duration(3000)
+ .attr("x", 0)
+ .attr("y", function(d,i) { return i*90+50 })
+ .attr("width", function(d,i) { return d; })
+ .attr("height", 20)
+ .style("fill", "steelblue")
+ .transition()
+ .duration(3000)
+ .delay(3000)
+ .style("fill", "green")
+ .attr("width", function(d,i) {
+ return d*1.5;
+ })
+
+ selection.exit()
+ .attr("opacity", 1)
+ .transition()
+ .duration(3000)
+ .attr("opacity", 0)
+ .remove();
+"""
+
+# -----------------------------------------------
+slide.code_title(title = ".data(..., join)");
+
+init_svg = (parent) ->
+ empty_svg(parent);
+ svg.selectAll("rect")
+ .data([64, 128, 256])
+ .enter().append("rect")
+ .attr("x", 0)
+ .attr("y", (d,i) -> i*90+50)
+ .attr("width", (d,i) -> d)
+ .attr("height", 20)
+ .style("fill", "steelblue")
+
+slide.code title, init_svg, """
+ // Let"s say we start here:
+ /*
+ svg.selectAll("rect")
+ .data([64, 128, 256])
+ .enter().append("rect")
+ .attr("x", 0)
+ .attr("y", function(d,i) { return i*90+50 })
+ .attr("width", function(d,i) { return d; })
+ .attr("height", 20)
+ .style("fill", "steelblue")
+ */
+ // And then we do this:
+
+ var selection = svg.selectAll("rect")
+ .data([128, 256, 71]) // <- incomplete?
+
+ selection.enter().append("rect")
+ .attr("x", 0)
+ .attr("y", function(d,i) { return i*90+50 })
+ .attr("width", function(d,i) { return d; })
+ .attr("height", 20)
+ .style("fill", "steelblue")
+
+ selection
+ .transition()
+ .duration(3000)
+ .attr("x", 0)
+ .attr("y", function(d,i) { return i*90+50 })
+ .attr("width", function(d,i) { return d; })
+ .attr("height", 20)
+ .style("fill", "steelblue")
+
+ selection.exit()
+ .remove()
+
+ // Note that String(5) === "5"
+"""
+
+slide.code title, init_svg, """
+ // Start the same as before
+
+ var selection = svg.selectAll("rect")
+ .data([128, 256, 71], String)
+
+ selection.enter().append("rect")
+ .attr("x", 0)
+ .attr("y", function(d,i) {
+ return (i+1)*100+50
+ })
+ .attr("width", function(d,i) { return d; })
+ .attr("height", 20)
+ .style("fill", "steelblue")
+ .style("opacity", 0)
+
+ selection
+ .transition()
+ .duration(3000)
+ .attr("y", function(d,i) { return i*90+50 })
+ .attr("height", 20)
+ .style("opacity", 1)
+
+ selection.exit()
+ .transition()
+ .duration(3000)
+ .attr("y", function(d,i) {
+ return (i-1)*100+50
+ })
+ .style("opacity", 0)
+ .remove()
+"""
+
+# -----------------------------------------------
+slide.title("Educational Examples");
+
+slide.code "Shuffle", empty_svg, """
+ var cards = [
+ "J\\u2665", "J\\u2666", "J\\u2663", "J\\u2660",
+ "K\\u2665", "K\\u2666", "K\\u2663", "K\\u2660",
+ "Q\\u2665", "Q\\u2666", "Q\\u2663", "Q\\u2660",
+ "A\\u2665", "A\\u2666", "A\\u2663", "A\\u2660"]
+
+ cards.sort(function() {return Math.random()-.5})
+
+ var selection = svg.selectAll("text")
+ .data(cards, String)
+
+ selection
+ .transition()
+ .duration(1000)
+ .attr("y", function(d,i) { return i*35+40 })
+
+ selection.enter().append("text")
+ .attr("x", 30)
+ .attr("y", function(d,i) { return i*35+40 })
+ .style("fill", function(d) {
+ return "\\u2665\\u2666".indexOf(d[1]) < 0 ?
+ "black" : "red";
+ })
+ .style("font", "20px monospace")
+ .text(String)
+"""
+
+slide.code "Shuffle (v2)", empty_svg, """
+ var cards = [
+ "J\\u2665", "J\\u2666", "J\\u2663", "J\\u2660",
+ "K\\u2665", "K\\u2666", "K\\u2663", "K\\u2660",
+ "Q\\u2665", "Q\\u2666", "Q\\u2663", "Q\\u2660",
+ "A\\u2665", "A\\u2666", "A\\u2663", "A\\u2660"]
+
+ cards.sort(function() {return Math.random()-.5})
+
+ var selection = svg.selectAll("text")
+ .data(cards, String)
+
+ selection
+ .transition().duration(500)
+ .attr("x", function(d,i) {return (i%8)*30+30})
+ .transition().duration(500).delay(500)
+ .attr("y", function(d,i) { return i*35+40 })
+ .transition().duration(500).delay(1000)
+ .attr("x", 30)
+
+ selection.enter().append("text")
+ .attr("x", 30)
+ .attr("y", function(d,i) { return i*35+40 })
+ .style("fill", function(d) {
+ return "\\u2665\\u2666".indexOf(d[1]) < 0 ?
+ "black" : "red";
+ })
+ .style("font", "20px monospace")
+ .text(String)
+"""
+
+# -----------------------------------------------
+slide.code "Drawing lines", empty_svg, """
+ svg.append("path")
+ .style("fill", "none")
+ .style("stroke", "black")
+ .style("stroke-width", 2)
+ .attr("d", "M 10 10 L 200 200 "+
+ "L 200 400 L 300 100 L 400 150")
+"""
+
+slide.code "Drawing lines", empty_svg, """
+ var points = [
+ { x: 10, y: 10 },
+ { x: 200, y: 200 },
+ { x: 200, y: 400 },
+ { x: 300, y: 100 },
+ { x: 400, y: 150 }
+ ]
+
+ var lineFn = d3.svg.line()
+ .x(function(d) { return d.x })
+ .y(function(d) { return d.y })
+
+ svg.append("path").data([points])
+ .style("fill", "none")
+ .style("stroke", "black")
+ .style("stroke-width", 2)
+ .attr("d", lineFn)
+"""
+
+slide.code "Drawing lines", empty_svg, """
+ var pointsSin = d3.range(20).map(function(i) {
+ return {x: i/19, y: (Math.sin(i/3) + 1) / 2}
+ })
+ var pointsCos = d3.range(20).map(function(i) {
+ return {x: i/19, y: (Math.cos(i/3) + 1) / 2}
+ })
+
+
+ var w = 480
+ var h = 300
+ var x = d3.scale.linear()
+ .domain([0, 1]).range([0, w])
+ var y = d3.scale.linear()
+ .domain([0, 1]).range([h, 0])
+
+ var lineFn = d3.svg.line()
+ .x(function(d) { return x(d.x); })
+ .y(function(d) { return y(d.y); })
+
+ svg.selectAll("path")
+ .data([pointsSin, pointsCos])
+ .enter().append("path")
+ .style("fill", "none")
+ .style("stroke", "black")
+ .style("stroke-width", 2)
+ .attr("d", lineFn)
+"""
+
View
57 slides.js
@@ -0,0 +1,57 @@
+(function() {
+ var empty_svg, init_svg, rect1, rect3, title;
+ empty_svg = function(parent) {
+ return window.svg = d3.select(parent).append("svg");
+ };
+ rect1 = function(parent) {
+ empty_svg(parent);
+ return svg.append("rect").attr("x", 150).attr("y", 100).attr("width", 60).attr("height", 300);
+ };
+ rect3 = function(parent) {
+ empty_svg(parent);
+ svg.append("rect").attr("x", 200).attr("y", 300).attr("width", 40).attr("height", 50);
+ svg.append("rect").attr("x", 100).attr("y", 20).attr("width", 30).attr("height", 50);
+ return svg.append("rect").attr("x", 10).attr("y", 200).attr("width", 25).attr("height", 90);
+ };
+ slide.code("JavaScript", empty_svg, "// In JS functions are first class citizens.\n// This is a very powerful concept!\nvar squared = function(x) { return x*x };\nconsole.log(\"squared(7) ==\", squared(7));\n\n\n// D3 has many helper methods\n// d3.scale.linear() returns a function that\n// will map the given domain to the given\n// range linearly.\nvar w = 640, h = 320;\n\nvar x = d3.scale.linear()\n .domain([-1, 1])\n .range([0, w]);\n\nvar y = d3.scale.linear()\n .domain([0, 1])\n .range([0, h]);\n\nconsole.log(\"x(0) ==\", x(0)); // == w/2\nconsole.log(\"y(3) ==\", y(3)); // == 3*h");
+ slide.title("Core D3");
+ slide.code_title(title = ".select()");
+ slide.code(title, rect1, "// svg = d3.select(\"svg.that_svg_to_the_right\")\nvar myRect = svg.select(\"rect\")\nmyRect.attr(\"width\", 100)\nmyRect.attr(\"height\", 100)\nmyRect.style(\"fill\", \"steelblue\")");
+ slide.code(title, rect1, "// svg = d3.select(\"svg.that_svg_to_the_right\")\nsvg.select(\"rect\")\n .attr(\"width\", 100)\n .attr(\"height\", 100)\n .style(\"fill\", \"steelblue\")");
+ slide.code_title(title = ".selectAll()");
+ slide.code(title, rect3, "svg.select(\"rect\")\n .attr(\"width\", 100)\n .attr(\"height\", 100)\n .style(\"fill\", \"steelblue\")");
+ slide.code(title, rect3, "svg.selectAll(\"rect\")\n .attr(\"width\", 100)\n .attr(\"height\", 100)\n .style(\"fill\", \"steelblue\")");
+ slide.code(title, rect3, "svg.selectAll(\"rect\")\n .attr(\"x\", 0)\n .attr(\"y\", function(d,i) { return i*90+50 })\n .attr(\"width\", function(d,i) {\n return i*150+100;\n })\n .attr(\"height\", 20)\n .style(\"fill\", \"steelblue\")");
+ slide.code_title(title = ".data()");
+ slide.code(title, rect3, "svg.selectAll(\"rect\")\n .data([64, 128, 256])\n .attr(\"x\", 0)\n .attr(\"y\", function(d,i) { return i*90+50 })\n .attr(\"width\", function(d,i) { return d; })\n .attr(\"height\", 20)\n .style(\"fill\", \"steelblue\")");
+ slide.code_title(title = ".enter()");
+ slide.code(title, rect3, "var selection = svg.selectAll(\"rect\")\n .data([64, 128, 256, 71])\n\nselection\n .attr(\"x\", 0)\n .attr(\"y\", function(d,i) { return i*90+50 })\n .attr(\"width\", function(d,i) { return d; })\n .attr(\"height\", 20)\n .style(\"fill\", \"steelblue\")");
+ slide.code(title, rect3, "var selection = svg.selectAll(\"rect\")\n .data([64, 128, 256, 71])\n\nselection\n .attr(\"x\", 0)\n .attr(\"y\", function(d,i) { return i*90+50 })\n .attr(\"width\", function(d,i) { return d; })\n .attr(\"height\", 20)\n .style(\"fill\", \"steelblue\")\n\nselection.enter().append(\"rect\")\n .attr(\"x\", 10) // let\"s just put it somewhere\n .attr(\"y\", 10)\n .attr(\"width\", 30)\n .attr(\"height\", 30)\n .style(\"fill\", \"green\")");
+ slide.code(title, rect3, "var selection = svg.selectAll(\"rect\")\n .data([64, 128, 256, 71])\n\nselection\n .attr(\"x\", 0)\n .attr(\"y\", function(d,i) { return i*90+50 })\n .attr(\"width\", function(d,i) { return d; })\n .attr(\"height\", 20)\n .style(\"fill\", \"steelblue\")\n\nselection.enter().append(\"rect\")\n .attr(\"x\", 0)\n .attr(\"y\", function(d,i) { return i*90+50 })\n .attr(\"width\", function(d,i) { return d; })\n .attr(\"height\", 20)\n .style(\"fill\", \"steelblue\")");
+ slide.code(title, rect3, "var selection = svg.selectAll(\"rect\")\n .data([64, 128, 256, 71])\n\n// Shorter\nselection.enter().append(\"rect\")\n\n// when updating the regular selection then\n// enter selection is joined in to the update\n// selection for convenience.\nselection\n .attr(\"x\", 0)\n .attr(\"y\", function(d,i) { return i*90+50 })\n .attr(\"width\", function(d,i) { return d; })\n .attr(\"height\", 20)\n .style(\"fill\", \"steelblue\")");
+ title += " // a common pattern";
+ slide.code(title, empty_svg, "svg.selectAll(\"rect\")\n .data([64, 128, 256])\n .enter().append(\"rect\")\n .attr(\"x\", 0)\n .attr(\"y\", function(d,i) { return i*90+50 })\n .attr(\"width\", function(d,i) { return d; })\n .attr(\"height\", 20)\n .style(\"fill\", \"steelblue\")");
+ slide.code_title(title = ".exit()");
+ slide.code(title, rect3, "var selection = svg.selectAll(\"rect\")\n .data([64, 128])\n\nselection\n .attr(\"x\", 0)\n .attr(\"y\", function(d,i) { return i*90+50 })\n .attr(\"width\", function(d,i) { return d; })\n .attr(\"height\", 20)\n .style(\"fill\", \"steelblue\")");
+ slide.code(title, rect3, "var selection = svg.selectAll(\"rect\")\n .data([64, 128])\n\nselection\n .attr(\"x\", 0)\n .attr(\"y\", function(d,i) { return i*90+50 })\n .attr(\"width\", function(d,i) { return d; })\n .attr(\"height\", 20)\n .style(\"fill\", \"steelblue\")\n\nselection.exit()\n .remove()");
+ slide.code_title(title = ".transition()");
+ slide.code(title, rect3, "svg.selectAll(\"rect\")\n .data([64, 128, 256])\n .transition()\n .duration(3000) // 3 seconds\n .attr(\"x\", 0)\n .attr(\"y\", function(d,i) { return i*90+50 })\n .attr(\"width\", function(d,i) { return d; })\n .attr(\"height\", 20)\n .style(\"fill\", \"steelblue\")");
+ slide.code(title, rect3, "var selection = svg.selectAll(\"rect\")\n .data([64, 128, 256, 71])\n\nselection.enter().append(\"rect\")\n .attr(\"x\", 200)\n .attr(\"y\", 200)\n .attr(\"width\", 10)\n .attr(\"height\", 10)\n .style(\"fill\", \"red\")\n\nselection\n .transition()\n .duration(3000)\n .attr(\"x\", 0)\n .attr(\"y\", function(d,i) { return i*90+50 })\n .attr(\"width\", function(d,i) { return d; })\n .attr(\"height\", 20)\n .style(\"fill\", \"steelblue\")\n .transition()\n .duration(3000)\n .delay(3000)\n .style(\"fill\", \"green\")\n .attr(\"width\", function(d,i) {\n return d*1.5;\n })\n\nselection.exit()\n .attr(\"opacity\", 1)\n .transition()\n .duration(3000)\n .attr(\"opacity\", 0)\n .remove();");
+ slide.code_title(title = ".data(..., join)");
+ init_svg = function(parent) {
+ empty_svg(parent);
+ return svg.selectAll("rect").data([64, 128, 256]).enter().append("rect").attr("x", 0).attr("y", function(d, i) {
+ return i * 90 + 50;
+ }).attr("width", function(d, i) {
+ return d;
+ }).attr("height", 20).style("fill", "steelblue");
+ };
+ slide.code(title, init_svg, "// Let\"s say we start here:\n/*\nsvg.selectAll(\"rect\")\n .data([64, 128, 256])\n .enter().append(\"rect\")\n .attr(\"x\", 0)\n .attr(\"y\", function(d,i) { return i*90+50 })\n .attr(\"width\", function(d,i) { return d; })\n .attr(\"height\", 20)\n .style(\"fill\", \"steelblue\")\n*/\n// And then we do this:\n\nvar selection = svg.selectAll(\"rect\")\n .data([128, 256, 71]) // <- incomplete?\n\nselection.enter().append(\"rect\")\n .attr(\"x\", 0)\n .attr(\"y\", function(d,i) { return i*90+50 })\n .attr(\"width\", function(d,i) { return d; })\n .attr(\"height\", 20)\n .style(\"fill\", \"steelblue\")\n\nselection\n .transition()\n .duration(3000)\n .attr(\"x\", 0)\n .attr(\"y\", function(d,i) { return i*90+50 })\n .attr(\"width\", function(d,i) { return d; })\n .attr(\"height\", 20)\n .style(\"fill\", \"steelblue\")\n\nselection.exit()\n .remove()\n\n// Note that String(5) === \"5\"");
+ slide.code(title, init_svg, "// Start the same as before\n\nvar selection = svg.selectAll(\"rect\")\n .data([128, 256, 71], String)\n\nselection.enter().append(\"rect\")\n .attr(\"x\", 0)\n .attr(\"y\", function(d,i) {\n return (i+1)*100+50\n })\n .attr(\"width\", function(d,i) { return d; })\n .attr(\"height\", 20)\n .style(\"fill\", \"steelblue\")\n .style(\"opacity\", 0)\n\nselection\n .transition()\n .duration(3000)\n .attr(\"y\", function(d,i) { return i*90+50 })\n .attr(\"height\", 20)\n .style(\"opacity\", 1)\n\nselection.exit()\n .transition()\n .duration(3000)\n .attr(\"y\", function(d,i) {\n return (i-1)*100+50\n })\n .style(\"opacity\", 0)\n .remove()");
+ slide.title("Educational Examples");
+ slide.code("Shuffle", empty_svg, "var cards = [\n \"J\\u2665\", \"J\\u2666\", \"J\\u2663\", \"J\\u2660\",\n \"K\\u2665\", \"K\\u2666\", \"K\\u2663\", \"K\\u2660\",\n \"Q\\u2665\", \"Q\\u2666\", \"Q\\u2663\", \"Q\\u2660\",\n \"A\\u2665\", \"A\\u2666\", \"A\\u2663\", \"A\\u2660\"]\n\ncards.sort(function() {return Math.random()-.5})\n\nvar selection = svg.selectAll(\"text\")\n .data(cards, String)\n\nselection\n .transition()\n .duration(1000)\n .attr(\"y\", function(d,i) { return i*35+40 })\n\nselection.enter().append(\"text\")\n .attr(\"x\", 30)\n .attr(\"y\", function(d,i) { return i*35+40 })\n .style(\"fill\", function(d) {\n return \"\\u2665\\u2666\".indexOf(d[1]) < 0 ?\n \"black\" : \"red\";\n })\n .style(\"font\", \"20px monospace\")\n .text(String)");
+ slide.code("Shuffle (v2)", empty_svg, "var cards = [\n \"J\\u2665\", \"J\\u2666\", \"J\\u2663\", \"J\\u2660\",\n \"K\\u2665\", \"K\\u2666\", \"K\\u2663\", \"K\\u2660\",\n \"Q\\u2665\", \"Q\\u2666\", \"Q\\u2663\", \"Q\\u2660\",\n \"A\\u2665\", \"A\\u2666\", \"A\\u2663\", \"A\\u2660\"]\n\ncards.sort(function() {return Math.random()-.5})\n\nvar selection = svg.selectAll(\"text\")\n .data(cards, String)\n\nselection\n .transition().duration(500)\n .attr(\"x\", function(d,i) {return (i%8)*30+30})\n .transition().duration(500).delay(500)\n .attr(\"y\", function(d,i) { return i*35+40 })\n .transition().duration(500).delay(1000)\n .attr(\"x\", 30)\n\nselection.enter().append(\"text\")\n .attr(\"x\", 30)\n .attr(\"y\", function(d,i) { return i*35+40 })\n .style(\"fill\", function(d) {\n return \"\\u2665\\u2666\".indexOf(d[1]) < 0 ?\n \"black\" : \"red\";\n })\n .style(\"font\", \"20px monospace\")\n .text(String)");
+ slide.code("Drawing lines", empty_svg, "svg.append(\"path\")\n .style(\"fill\", \"none\")\n .style(\"stroke\", \"black\")\n .style(\"stroke-width\", 2)\n .attr(\"d\", \"M 10 10 L 200 200 \"+\n \"L 200 400 L 300 100 L 400 150\")");
+ slide.code("Drawing lines", empty_svg, "var points = [\n { x: 10, y: 10 },\n { x: 200, y: 200 },\n { x: 200, y: 400 },\n { x: 300, y: 100 },\n { x: 400, y: 150 }\n]\n\nvar lineFn = d3.svg.line()\n .x(function(d) { return d.x })\n .y(function(d) { return d.y })\n\nsvg.append(\"path\").data([points])\n .style(\"fill\", \"none\")\n .style(\"stroke\", \"black\")\n .style(\"stroke-width\", 2)\n .attr(\"d\", lineFn)");
+ slide.code("Drawing lines", empty_svg, "var pointsSin = d3.range(20).map(function(i) {\n return {x: i/19, y: (Math.sin(i/3) + 1) / 2}\n})\nvar pointsCos = d3.range(20).map(function(i) {\n return {x: i/19, y: (Math.cos(i/3) + 1) / 2}\n})\n\n\nvar w = 480\nvar h = 300\nvar x = d3.scale.linear()\n .domain([0, 1]).range([0, w])\nvar y = d3.scale.linear()\n .domain([0, 1]).range([h, 0])\n\nvar lineFn = d3.svg.line()\n .x(function(d) { return x(d.x); })\n .y(function(d) { return y(d.y); })\n\nsvg.selectAll(\"path\")\n .data([pointsSin, pointsCos])\n .enter().append(\"path\")\n .style(\"fill\", \"none\")\n .style(\"stroke\", \"black\")\n .style(\"stroke-width\", 2)\n .attr(\"d\", lineFn)");
+}).call(this);

0 comments on commit 2535117

Please sign in to comment.
Something went wrong with that request. Please try again.