d3绘制动画线图基本示例

时间:2015-03-30 11:10:29

标签: javascript d3.js

我已经看到了如何绘制折线图here的示例。我试图从“修复任意数据集”部分复制他们的例子,但我无法让它工作。

希望有人可以向我解释我做错了什么。

以下是我使用的代码:

<!DOCTYPE html>

<head>
    <meta charset="utf-8">

    <script src="js/d3.min.js" charset="utf-8"></script>
    <script src="js/jquery-1.11.2.min.js" charset="utf-8"></script>

    <style>

        .axis text {
          font: 10px sans-serif;
        }

        .axis path,
        .axis line {
          fill: none;
          stroke: #000;
          shape-rendering: crispEdges;
        }

        .line {
            fill: none;
            stroke: steelblue;
            stroke-width: 1.5px;
        }

    </style>

</head>

<body>

    <table class="small-chart">
        <tr>
            <td id="chart_str"></td>
        </tr>
    </table>

</body>

<script>

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

    var data = [{"x":100, "y":0}, {"x":110, "y":10}, {"x":120, "y":20}, {"x":130, "y":30}]

    var x = d3.scale.linear()
        .domain(d3.extent(data, function (d) { return d.x; }))
        .range([0, width]);

    var y = d3.scale.linear()
        .domain(d3.extent(data, function (d) { return d.y; }))
        .range([height, 0]);

    var lineFunction = d3.svg.line()
      .x(x, function (d) { return d.x; })
      .y(y, function (d) { return d.y; });

    var svg = d3.select('#chart_str').append('svg')

    svg.append('path')
        .attr('class', 'line')
        .transition()
        .duration(3000)
        .attrTween('d', getSmoothInterpolation(data));


    function getSmoothInterpolation(iData) {
        return function (d, i, a) {
            var interpolate = d3.scale.linear()
                .domain([0, 1])
                .range([1, iData.length + 1]);

            return function(t) {
                var flooredX = Math.floor(interpolate(t));
                var weight = interpolate(t) - flooredX;
                var interpolatedLine = iData.slice(0, flooredX);

                    if(flooredX > 0 && flooredX < 31) {
                        var weightedLineAverage = iData[flooredX].y * weight + iData[flooredX-1].y * (1-weight);
                        interpolatedLine.push({"x":interpolate(t)-1, "y":weightedLineAverage});
                    }

                return lineFunction(interpolatedLine);
            }
        }
    }

</script>

我在控制台中一直收到以下错误:

Error: Problem parsing d="MNaN,NaNLNaN,NaN" test_line.html:1

Error: Problem parsing d="MNaN,NaNLNaN,NaNLNaN,NaN" test_line.html:1

Error: Problem parsing d="MNaN,NaNLNaN,NaNLNaN,NaNLNaN,NaN" test_line.html:1

Uncaught TypeError: Cannot read property 'y' of undefined test_line.html:91

1 个答案:

答案 0 :(得分:0)

这是一个小提琴:http://jsfiddle.net/henbox/t3fam08j/1/。请注意,我添加了一些额外的数据点,以便更容易看到发生了什么。

根据@ user1614080的评论,首先要绘制基本折线图,然后再转换到过渡\插值位。

为此,您需要确保将xy比例应用于lineFunction中的点,因此请更改:

var lineFunction = d3.svg.line()
  .x(x, function (d) { return d.x; })
  .y(y, function (d) { return d.y; });

var lineFunction = d3.svg.line()
  .x(function (d) { return x(d.x); })
  .y(function (d) { return y(d.y); });

还要定义svg的宽度和高度,以确保该线适合:

.append('svg')
    .attr("width", width)
    .attr("height", height)
    ...

错误:“Uncaught TypeError:无法读取未定义的属性'y'来自于flooredX可能大于iData + 1中元素数的事实,因此iData[flooredX]不存在且{{ 1}}是iData[flooredX].y

插值函数有这个奇怪的“undefined”行,其中if (flooredX > 0 && flooredX < 31)是硬编码的(我不能确切地说为什么,我认为exanple中的数据恰好有30个点)。如果您将31替换为31,您将处理案例:

iData.length

您需要进行的最后一项更改是将点数推送到if (flooredX > 0 && flooredX < iData.length) { ... } 数组。在您当前的代码中,您有:

interpolatedLine

这会将interpolatedLine.push({ "x": interpolate(t) - 1, ... 值推到0和x之间(即数据中x / y值对的数量),而不是实际想要传递的值(iData.length 100和160)

我认为,对于您链接的示例,假设原始数据中的x值将从0开始并运行到30:对您的示例不是很有帮助。一个 hacky方式 来解决这个问题,就是要对从xx1, 2, 3...所需的转换进行硬编码},所以改变:

110, 120, 130...

"x": interpolate(t) - 1,

这不是一种很好的做事方式,因为它硬编码了关于x值的假设。我确信有更好的方法