javascript - D3: Spiral plot -
can me implementing spiral chart similar 1 using d3.js? https://en.wikipedia.org/wiki/file:condegram_spiral_plot.png
i've got basic spiral plot (a simple one) of not been able append bars plot based on timeline shown in image. i'm trying out few things (if see commented code).
https://jsfiddle.net/6bhdqqrf/1/
var width = 400, height = 430, axes = 12, tick_axis = 9, start = 0, end = 2.25; var theta = function(r) { return 2 * math.pi * r; }; var angle = d3.scale.linear() .domain([0, axes]).range([0, 360]) var r = d3.min([width, height]) / 2 - 40; var r2 = r; var radius = d3.scale.linear() .domain([start, end]) .range([0, r]); var svg = d3.select("#chart").append("svg") .attr("width", width) .attr("height", height) .append("g") .attr("transform", "translate(" + width / 2 + "," + (height / 2 + 8) + ")"); var points = d3.range(start, end + 0.001, (end - start) / 1000); var spiral = d3.svg.line.radial() .interpolate("cardinal") .angle(theta) .radius(radius); var path = svg.selectall(".spiral") .data([points]) .enter().append("path") .attr("class", "spiral") .attr("d", spiral) var z = d3.scale.category20(); var circles = svg.selectall('.circle') .data(points); /* circles.enter().append('circle') .attr('r', 5) .attr('transform', function(d) { return 'translate(' + d + ')'}) .style('fill', function(d) { return z(d); }); */ var circle = svg.append("circle") .attr("r", 13) .attr("transform", "translate(" + points[0] + ")"); var movingcircle = circle.transition().duration(4000) .attrtween('transform', translatealongpath(path.node())) // .attr('cx', function(d) { return radius(d) * math.cos(theta(d))}) // .attr('cy', function(d) { return radius(d) * math.sin(theta(d))}) function translatealongpath(path) { var l = path.gettotallength(); return function(d, i, a) { return function(t) { var p = path.getpointatlength(t * l); //console.log(p) return "translate(" + p.x + "," + p.y + ")"; }; }; } function pathxy(path) { var l = path.gettotallength(); var start = 0; /* for(i=start; i<l; i++) { var point = path.getpointatlength(i); svg.append('rect').transition().duration(400).attr('transform', 'translate(' + point.x +','+point.y+')') .attr('width', 10).attr('height', 30).style('fill', z); }*/ } pathxy(path.node()); /*var test = translatealongpath(path.node())()(); //console.log(test) var bars = svg.selectall('.bar') .data(points).enter().append('rect').transition().duration(2000) // .attrtween('transform', translatealongpath(path.node())) .attr('class', 'bar') .attr('width', 10) .attr('height', 20) .style('fill', function(d) { return z(d)}); */ var rect = svg.append('rect').attr('width', 10).attr('height', 10); rect.transition().duration(3400) .attrtween('transform', translatealongpath(path.node()));
it'd great have few similar examples (i.e. spiral timeline plot).
thanks.
glad came , updated question, because interesting one. here's running minimal implementation. i've commented ok, let me know if have questions...
<!doctype html> <html> <head> <script data-require="d3@4.0.0" data-semver="4.0.0" src="https://d3js.org/d3.v4.js"></script> </head> <body> <div id="chart"></div> <script> var width = 500, height = 500, start = 0, end = 2.25, numspirals = 4; var theta = function(r) { return numspirals * math.pi * r; }; var r = d3.min([width, height]) / 2 - 40; var radius = d3.scalelinear() .domain([start, end]) .range([40, r]); var svg = d3.select("#chart").append("svg") .attr("width", width) .attr("height", height) .append("g") .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")"); // create spiral, borrowed http://bl.ocks.org/syntagmatic/3543186 var points = d3.range(start, end + 0.001, (end - start) / 1000); var spiral = d3.radialline() .curve(d3.curvecardinal) .angle(theta) .radius(radius); var path = svg.append("path") .datum(points) .attr("id", "spiral") .attr("d", spiral) .style("fill", "none") .style("stroke", "steelblue"); // fudge data, 2 years of data starting today var spirallength = path.node().gettotallength(), n = 730, barwidth = (spirallength / n) - 1; var somedata = []; (var = 0; < n; i++) { var currentdate = new date(); currentdate.setdate(currentdate.getdate() + i); somedata.push({ date: currentdate, value: math.random() }); } // here's our time scale that'll run along spiral var timescale = d3.scaletime() .domain(d3.extent(somedata, function(d){ return d.date; })) .range([0, spirallength]); // yscale bar height var yscale = d3.scalelinear() .domain([0, d3.max(somedata, function(d){ return d.value; })]) .range([0, (r / numspirals) - 30]); // append our rects svg.selectall("rect") .data(somedata) .enter() .append("rect") .attr("x", function(d,i){ // placement calculations var lineper = timescale(d.date), posonline = path.node().getpointatlength(lineper), angleonline = path.node().getpointatlength(lineper - barwidth); d.lineper = lineper; // % distance on spiral d.x = posonline.x; // x postion on spiral d.y = posonline.y; // y position on spiral d.a = (math.atan2(angleonline.y, angleonline.x) * 180 / math.pi) - 90; //angle @ spiral position return d.x; }) .attr("y", function(d){ return d.y; }) .attr("width", function(d){ return barwidth; }) .attr("height", function(d){ return yscale(d.value); }) .style("fill", "steelblue") .style("stroke", "none") .attr("transform", function(d){ return "rotate(" + d.a + "," + d.x + "," + d.y + ")"; // rotate bar }); // add date labels var tf = d3.timeformat("%b %y"), firstinmonth = {}; svg.selectall("text") .data(somedata) .enter() .append("text") .attr("dy", 10) .style("text-anchor", "start") .style("font", "10px arial") .append("textpath") // add first of each month .filter(function(d){ var sd = tf(d.date); if (!firstinmonth[sd]){ firstinmonth[sd] = 1; return true; } return false; }) .text(function(d){ return tf(d.date); }) // place text along spiral .attr("xlink:href", "#spiral") .style("fill", "grey") .attr("startoffset", function(d){ return ((d.lineper / spirallength) * 100) + "%"; }) </script> </body> </html>
Comments
Post a Comment