在d3js线图中展开行

时间:2015-09-25 19:27:37

标签: javascript d3.js

我在d3js中制作了折线图。实施如下。 但是,图表会在屏幕中突然显示(没有过渡)。 如何使图表显示在屏幕上并进行转换,以使图表显示"展开效果"即好像是在用户正在观看一段时间的情况下绘制线条。秒。

This is what I have in mind.



var lineData = [
  [new Date('Mon Aug 17 2015 00:00:00 GMT+0530 (India Standard Time)'), 100],
  [new Date('Tue Aug 18 2015 00:00:00 GMT+0530 (India Standard Time)'), 100],
  [new Date('Thu Aug 20 2015 00:00:00 GMT+0530 (India Standard Time)'), 66.66666666666667],
  [new Date('Fri Aug 21 2015 00:00:00 GMT+0530 (India Standard Time)'), 50],
  [new Date('Sat Aug 22 2015 00:00:00 GMT+0530 (India Standard Time)'), 40]
];

var margin = {
  top: 30,
  right: 30,
  bottom: 30,
  left: 30
};
var height = 200 - margin.top - margin.bottom,
  width = 300 - margin.left - margin.right;

var parseDate = d3.time.format("%Y-%m-%d").parse;
var xScale = d3.time.scale().domain([lineData[0][0], lineData[lineData.length - 1][0]]).range([0, width]);
var yScale = d3.scale.linear().domain([0, 100]).range([0, height]);

var svgContainer = d3.select("#lc-visual").select("svg").attr("width", margin.right + width + margin.left).attr("height", margin.bottom + height + margin.top);

var lineFunction = d3.svg.line().x(function(d, i) {
    return xScale(d[0]);
  })
  .y(function(d, i) {
    return height - yScale(d[1]);
  })
  .interpolate("linear");

var svgGroup = svgContainer.append('g');

var lineGraph = svgGroup.append("path")
  .attr("d", lineFunction(lineData))
  .attr("stroke", '#000')
  .attr("stroke-width", 2)
  .attr("fill", "none");

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

<body>
  <div class="group">
    <!-- </form> -->
    <div id="lc-visual">
      <svg id="#line-svg">
      </svg>
    </div>
  </div>

</body>
&#13;
&#13;
&#13;

1 个答案:

答案 0 :(得分:1)

至少有两种方法可以实现这一目标。

  1. 在点之间插入d属性。这使您可以更好地控制每个线段。

  2. 插值stroke-dashoffset以显示 绘制该行。这提供了更好,更流畅的视觉体验

  3. This codepen演示了两种方法之间的区别。

    方法1:使用d属性

    第一种方法将按顺序添加每一行和点,为您提供选项,以提供涉及点本身的转换。

    您希望首先将数据的第一个点传递到d属性,如下所示:selection.attr('d', lineData[0])。然后,您调用转换并使用attrTween传递lineData并声明补间函数:selection.attrTween('d', tween)

    您的代码如下所示:

    var lineGraph = svgGroup.append("path")
      .transition()
      .duration(2000) // must pass in duration for tween function
      .attrTween('d', tween) // call tween function with attrTween
    
    function tween() {
      var interpolate = d3.scale.quantile()
          .domain([0,1]) // where 0 is start of tween and 1 is end of tween
          .range(d3.range(1, lineData.length + 1)); // return current point and all previous points in data
      return function(t) {
        // render the line in sequence from beginning
        return lineFunction(lineData.slice(0, interpolate(t)));
      };
    }
    

    如您所见,这将在每个点转换渲染,但不会模拟线条的绘制。

    方法2:使用stroke-dasharraystroke-dashoffset属性

    如果您不熟悉这些属性,则可能需要了解stroke-dasharraystroke-dashoffset如何对路径进行操作。关于它们如何工作,这是一个很好的CSS Tricks article,这是我创建的codepen,它说明了这些属性的工作原理(将所有值设置为最大值,然后慢慢减少stroke-dashoffset

    这种方法的要点是我们想要设置这样的初始值:

    selection
      .attr('stroke-dasharray', lineLength + ' ' + lineLength)
      .attr('stroke-dashoffset', lineLength);
    

    您希望补间的 end 的路径选择属性如下:

    selection
      .attr('stroke-dashoffset', 0);
    

    您正在将stroke-dashoffset从路径长度转换为0.以下是在您的情况下如何实现这一目标。

    您的代码如下所示:

    // render path so it's possible to check its length
    lineGraph
      .attr('d', lineFunction(lineData));
    
    // get total length of path
    var lineLength = lineGraph.node().getTotalLength();
    
    lineGraph
      .transition()
      .duration(2000)
      .attr('stroke-dasharray', lineLength + ' ' + lineLength)
      // here we transition the stroke-dashoffset to simulate 'drawing' the line
      .attrTween('stroke-dashoffset', tween);
    
    
    function tween() {
      // get values between lineLength and 0
      var interpolate = d3.interpolate(lineLength, 0);
      return function(t) {
        return interpolate(t);
      };
    }
    

    我已经使用您的示例创建了working codepen来演示这两种方法。我已经评论了第二个例子,以更好地展示第一个的程序优势和使用第二个的视觉优势。