2016-11-10 122 views
1

有人可以幫助我使用d3.js實現類似於這個的螺旋圖嗎? https://en.wikipedia.org/wiki/File:Condegram_Spiral_Plot.pngD3:螺旋圖

到目前爲止,我剛剛得到了基本的螺旋圖(一個簡單的圖),但未能根據圖中所示的時間線將圖形追加到圖上。我正在嘗試一些事情(如果你看到評論的代碼)。

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())); 

這將會是巨大的,有幾個類似的例子(即螺旋時間表圖)。

感謝。

+3

歡迎StackOverflow上。你需要在你的問題上多加一點努力,否則它可能會被關閉。向我們展示您迄今爲止編寫的代碼以及您正在努力的具體內容。 – Mark

+0

@Mark對不起。我已經發布了我的代碼和小提琴鏈接。謝謝。 – Shashank

回答

3

很高興你回來並更新了你的問題,因爲這是一個有趣的問題。這是一個運行最少的實現。我的評論就OK了,所以讓我知道,如果您有任何疑問...

<!DOCTYPE html> 
 
<html> 
 

 
<head> 
 
    <script data-require="[email protected]" 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 the spiral, borrowed from 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 some data, 2 years of data starting today 
 
    var spiralLength = path.node().getTotalLength(), 
 
     N = 730, 
 
     barWidth = (spiralLength/N) - 1; 
 
    var someData = []; 
 
    for (var i = 0; i < 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 the spiral 
 
    var timeScale = d3.scaleTime() 
 
     .domain(d3.extent(someData, function(d){ 
 
     return d.date; 
 
     })) 
 
     .range([0, spiralLength]); 
 
    
 
    // yScale for the 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 are on the spiral 
 
     d.x = posOnLine.x; // x postion on the spiral 
 
     d.y = posOnLine.y; // y position on the spiral 
 
     
 
     d.a = (Math.atan2(angleOnLine.y, angleOnLine.x) * 180/Math.PI) - 90; //angle at the 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 the 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") 
 
     // only add for the 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>

+1

如果將'.range([0,r]);'更改爲'.range([r/4,r]);'會得到更接近鏈接圖的螺旋圖。 –

+0

嘿馬克,它看起來不錯。我會自己添加一些其他功能,如果有任何問題,將會回覆給您。謝謝! – Shashank