D3 curve explorer.
From D3 in Depth book by Peter Cook.
forked from d3indepth's block: D3 curve explorer
| license: gpl-3.0 | |
| height: 860 | |
| border: no |
D3 curve explorer.
From D3 in Depth book by Peter Cook.
forked from d3indepth's block: D3 curve explorer
| <!DOCTYPE html> | |
| <meta charset="utf-8"> | |
| <head> | |
| <title>D3 Curve Explorer</title> | |
| </head> | |
| <style> | |
| body { | |
| font-family: "Helvetica Neue", Helvetica, sans-serif; | |
| font-size: 12px; | |
| user-select: none; | |
| } | |
| svg { | |
| box-shadow: 0px 0px 40px -5px rgba(0,0,0,0.3); | |
| border-radius: 5px; | |
| margin: 20px; | |
| } | |
| svg path { | |
| fill: none; | |
| } | |
| svg circle { | |
| fill: white; | |
| stroke: #aaa; | |
| cursor: move; | |
| } | |
| svg .points-menu g { | |
| opacity: 0.2; | |
| } | |
| svg .points-menu g.active { | |
| cursor: pointer; | |
| opacity: 1; | |
| } | |
| svg .points-menu line { | |
| stroke: #777; | |
| stroke-width: 3; | |
| } | |
| svg .points-menu rect { | |
| fill: white; | |
| } | |
| .sidebar { | |
| display: inline-block; | |
| position: relative; | |
| vertical-align: top; | |
| margin-top: 20px; | |
| width: 530px; | |
| color: #444; | |
| } | |
| .sidebar .header { | |
| font-size: 14px; | |
| font-weight: bold; | |
| text-align: right; | |
| color: #aaa; | |
| width: 100%; | |
| } | |
| .menu .item { | |
| padding: 5px; | |
| border: 1px solid #ddd; | |
| margin: 4px 2px; | |
| float: left; | |
| cursor: pointer; | |
| border-radius: 8px; | |
| width: 160px; | |
| text-align: center; | |
| } | |
| .sidebar .info { | |
| float: left; | |
| margin-top: 20px; | |
| line-height: 1.5em; | |
| } | |
| </style> | |
| <body> | |
| <svg width="700" height="400"> | |
| <g> | |
| <path></path> | |
| <g class="points-menu" transform="translate(660, 380)"> | |
| <g class="remove-point"> | |
| <rect x="-6" y="-6" width="12" height="12"></rect> | |
| <line x1="-6" x2="6"></line> | |
| </g> | |
| <g class="add-point" transform="translate(20,0)"> | |
| <rect x="-6" y="-6" width="12" height="12"></rect> | |
| <line x1="-6" x2="6"></line><line y1="-6" y2="6"></line> | |
| </g> | |
| </g> | |
| </g> | |
| </svg> | |
| <div class="sidebar"> | |
| <div class="header">D3 CURVE EXPLORER</div> | |
| <div class="menu"></div> | |
| <div class="info"> | |
| <span class="default">The JavaScript library <a href="http://d3js.org">D3</a> provides a number of <a href="https://github.com/d3/d3-shape#curves">curve types</a> to interpolate (or approximate) a set of points. Toggle each of the curve types using the buttons above. You can also add/remove/drag the points to change the shape of the curve.</span> | |
| <span class="text"></span> | |
| </div> | |
| </div> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.2.2/d3.min.js"></script> | |
| <script> | |
| var curveTypes = [ | |
| {name: 'curveLinear', curve: d3.curveLinear, active: true, lineString: '', clear: false, info: 'Interpolates the points using linear segments.'}, | |
| {name: 'curveBasis', curve: d3.curveBasis, active: true, lineString: '', clear: true, info: 'Interpolates the start and end points and approximates the inner points using a B-spline.'}, | |
| {name: 'curveBasisClosed', curve: d3.curveBasisClosed, active: false, lineString: '', clear: false, info: 'Uses a closed B-Spline to approximate the points.'}, | |
| {name: 'curveBundle (ß=0)', curve: d3.curveBundle.beta(0), active: false, lineString: '', clear: true, info: 'Same as curveBasis with the addition of a paramter ß which determines how close to a straight line the curve is. If ß=0 the curve is straight.'}, | |
| {name: 'curveBundle (ß=0.5)', curve: d3.curveBundle.beta(0.5), active: false, lineString: '', clear: false, info: 'Same as curveBasis with the addition of a paramter ß which determines how close to a straight line the curve is.'}, | |
| {name: 'curveBundle (ß=1)', curve: d3.curveBundle.beta(1), active: false, lineString: '', clear: false, info: 'Same as curveBasis with the addition of a paramter ß which determines how close to a straight line the curve is. If ß=1 the curve is the same as curveBasis.'}, | |
| {name: 'curveCardinal (tension=0)', curve: d3.curveCardinal.tension(0), active: false, lineString: '', clear: true, info: "Interpolates the points using a cubic B-spline. A tension parameter determines how 'taut' the curve is. As tension approaches 1 the segments become linear."}, | |
| {name: 'curveCardinal (tension=0.5)', curve: d3.curveCardinal.tension(0.5), active: false, lineString: '', clear: false, info: "Interpolates the points using a cubic B-spline. A tension parameter determines how 'taut' the curve is. As tension approaches 1 the segments become linear."}, | |
| {name: 'curveCardinal (tension=1)', curve: d3.curveCardinal.tension(1), active: false, lineString: '', clear: false, info: "Interpolates the points using a cubic B-spline. A tension parameter determines how 'taut' the curve is. As tension approaches 1 the segments become linear."}, | |
| {name: 'curveCatmullRom (α=0)', curve: d3.curveCatmullRom.alpha(0), active: false, lineString: '', clear: true, info: 'Similar to curveCardinal (tension=0) but with a parameter α that determines the parameterisation used to interpolate the points. If α=0 the parameterisation is uniform.'}, | |
| {name: 'curveCatmullRom (α=0.5)', curve: d3.curveCatmullRom.alpha(0.5), active: false, lineString: '', clear: false, info: 'Similar to curveCardinal (tension=0) but with a parameter α that determines the parameterisation used to interpolate the points. If α=0.5 the parameterisation is centripetal and self intersecting loops are avoided.'}, | |
| {name: 'curveCatmullRom (α=1)', curve: d3.curveCatmullRom.alpha(1), active: false, lineString: '', clear: false, info: 'Similar to curveCardinal (tension=0) but with a parameter α that determines the parameterisation used to interpolate the points. If α=1 the parameterisation is chordal.'}, | |
| {name: 'curveMonotoneX', curve: d3.curveMonotoneX, active: false, lineString: '', clear: true, info: 'Interpolates the points with a cubic spline which are monotonic (i.e. always increasing or always decreasing) in y.'}, | |
| {name: 'curveMonotoneY', curve: d3.curveMonotoneY, active: false, lineString: '', clear: false, info: 'Interpolates the points with a cubic spline which are monotonic (i.e. always increasing or always decreasing) in x.'}, | |
| {name: 'curveNatural', curve: d3.curveNatural, active: false, lineString: '', clear: true, info: 'Interpolates the points with a cubic spline with zero 2nd derivatives at the endpoints.'}, | |
| {name: 'curveStep', curve: d3.curveStep, active: false, lineString: '', clear: true, info: 'Interpolates the points with alternating horizontal and vertical linear segments. The vertical segments lie midway between points.'}, | |
| {name: 'curveStepAfter', curve: d3.curveStepAfter, active: false, lineString: '', clear: false, info: 'Interpolates the points with alternating horizontal and vertical linear segments. The y value changes after the x value.'}, | |
| {name: 'curveStepBefore', curve: d3.curveStepBefore, active: false, lineString: '', clear: false, info: 'Interpolates the points with alternating horizontal and vertical linear segments. The y value changes before the x value.'} | |
| ]; | |
| var lineGenerator = d3.line(); | |
| var categoryScale = d3.scaleOrdinal(d3.schemeCategory10); | |
| function colorScale(d) {return d === 0 ? '#777' : categoryScale(d);} | |
| var points = [ [50, 330], [75, 200], [280, 75], [300, 75], [475, 300], [600, 200] ]; | |
| var numActivePoints = points.length; | |
| var drag = d3.drag() | |
| .on('drag', function(d, i) { | |
| points[i][0] = d3.event.x; | |
| points[i][1] = d3.event.y; | |
| update(); | |
| }); | |
| function updateInfo(info) { | |
| d3.select('.info .default').style('display', info ? 'none' : 'inline'); | |
| d3.select('.info .text').text(info); | |
| } | |
| function updateMenu() { | |
| var u = d3.select('.menu') | |
| .selectAll('div.item') | |
| .data(curveTypes); | |
| u.enter() | |
| .append('div') | |
| .classed('item', true) | |
| .style('clear', function(d) { return d.clear ? 'left' : 'none'; }) | |
| .text(function(d) { return d.name; }) | |
| .on('click', function(d) { | |
| d.active = !d.active; | |
| update(); | |
| }) | |
| .on('mouseover', function(d) { updateInfo(d.info); }) | |
| .on('mouseout', function() { updateInfo(''); }) | |
| .merge(u) | |
| .style('background-color', function(d, i) { return d.active ? colorScale(i) : '#fff'; }) | |
| .style('color', function(d, i) { return d.active ? 'white' : '#444'; }); | |
| } | |
| function updatePointsMenu() { | |
| d3.select('.remove-point') | |
| .classed('active', numActivePoints > 2) | |
| .on('click', function() { | |
| if(numActivePoints <= 2) return; | |
| numActivePoints--; | |
| update(); | |
| }); | |
| d3.select('.add-point') | |
| .classed('active', numActivePoints < points.length) | |
| .on('click', function() { | |
| if(numActivePoints >= points.length) return; | |
| numActivePoints++; | |
| update(); | |
| }); | |
| } | |
| function updateLines() { | |
| curveTypes.forEach(function(d) { | |
| if(!d.active) return; | |
| lineGenerator.curve(d.curve); | |
| d.lineString = lineGenerator(points.slice(0, numActivePoints)); | |
| }); | |
| var u = d3.select('svg g') | |
| .selectAll('path') | |
| .data(curveTypes); | |
| u.enter() | |
| .append('path') | |
| .merge(u) | |
| .style('stroke', function(d, i) { return colorScale(i); }) | |
| .attr('d', function(d) { return d.lineString; }) | |
| .style('display', function(d) { return d.active ? 'inline' : 'none'; }); | |
| } | |
| function updatePoints() { | |
| var u = d3.select('g') | |
| .selectAll('circle') | |
| .data(points.slice(0, numActivePoints)); | |
| u.enter() | |
| .append('circle') | |
| .attr('r', 4) | |
| .call(drag) | |
| .merge(u) | |
| .attr('cx', function(d) { return d[0];}) | |
| .attr('cy', function(d) { return d[1];}); | |
| u.exit().remove(); | |
| } | |
| function update() { | |
| updateMenu(); | |
| updatePointsMenu(); | |
| updateLines(); | |
| updatePoints(); | |
| } | |
| update(); | |
| </script> | |
| </body> | |
| </html> |
| �PNG | |