D3:螺旋图 [英] D3: Spiral plot

查看:74
本文介绍了D3:螺旋图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有人可以帮助我使用d3.js来实现类似于下面的螺旋图吗?

Can someone help me implementing a spiral chart similar to the one below using d3.js?

到目前为止,我已经获得了基本的螺旋图(一个简单的图),但是无法根据时间轴将条形图添加到图中,如图所示.我正在尝试一些操作(如果您看到注释的代码).

I've just got the basic spiral plot (a simple one) as of now but not been able to append bars to the plot based on the timeline as shown in the image. I'm trying out a few things (if you see the commented code).

这是我的小提琴,以及我的代码:

Here's my fiddle, and my code:

      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 be great to have a few similar examples (i.e. spiral timeline plot).

谢谢.

推荐答案

很高兴您回来并更新了您的问题,因为这很有趣.这是一个正在运行的最小实现.我已经评论好了,所以如果您有任何疑问,请告诉我...

Glad you came back and updated your question, because this is an interesting one. Here's a running minimal implementation. I've commented it ok, so let me know if you have any 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 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>

这篇关于D3:螺旋图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆