无法使用圆形工具提示创建折线图

时间:2016-12-20 00:40:21

标签: d3.js

所以,我试图复制这个tutorial。最终的目标是使用一个圆形线条图,该圆形线条遵循鼠标的x位置并保持在线条上,工具提示显示有关该线条上该位置的相关数据。以下是我的代码,我对样式进行了一些小改动,并在线下添加了一个填充区域,但我不相信这会对它的工作方式产生影响:

var margin = {
            top: 20,
            left: 50,
            right: 50,
            bottom: 50
        },
        width = $element.innerWidth() - margin.left - margin.right,
        height = 0.2 * width;

        var parseTime = d3.timeParse('%m/%d/%Y');
        data.forEach(function(d) {
            d.date = parseTime(d.date);
            d.price = +d.price;
        });

        var bisectDate = d3.bisector(function(d) { return d.date; }).left;

        var x = d3.scaleTime()
            .domain(d3.extent(data, function(d, i) {
                return d.date;
            }))
            .range([0, width]);
        var y = d3.scaleLinear()
            .domain(d3.extent(data, function(d, i) {
                return d.price;
            }))
            .range([height, 0]);

        var xAxis = d3.axisBottom(x)
            .tickSizeOuter(0);
        var yAxis = d3.axisLeft(y)
            .ticks(5)
            .tickSizeOuter(0);

        var area = d3.area()
            .x(function(d) { return x(d.date); })
            .y0(height)
            .y1(function(d) { return y(d.price); });

        var line = d3.line()
            .x(function(d) { return x(d.date); })
            .y(function(d) { return y(d.price); });

        var svg = d3.select('#priceChart')
            .append('svg')
                .attr('width', width + margin.left + margin.right)
                .attr('height', height + margin.top + margin.bottom)
            .append('g')
                .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');

        svg.append('g')
            .attr('class', 'x axis')
            .attr('transform', 'translate(0,' + height + ')')
            .call(xAxis);

        svg.append('g')
            .attr('class', 'y axis')
            .call(yAxis);

        var areaSvg = svg.append('g');
        areaSvg.append('path')
            .attr('class', 'area')
            .attr('d', area(data))
            .style('opacity', 0.3);

        var lineSvg = svg.append('g');
        lineSvg.append('path')
            .attr('class', 'line')
            .attr('d', line(data));

        var focus = svg.append('g')
            .style('display', 'none');

        focus.append('circle')
            .attr('class', 'y')
            .style('fill', 'steelblue')
            .attr('r', 3);

        svg.append('rect')
            .attr('width', width)
            .attr('height', height)
            .style('fill', 'none')
            .style('pointer-events', 'all')
            .on('mouseover', function() { focus.style('display', null); })
            .on('mouseout', function() { focus.style('display', 'none'); })
            .on('mousemove', mousemove);

        function mousemove() {
            var x0 = x.invert(d3.mouse(this)[0]),
                i = bisectDate(data, x0, 1),
                d0 = data[i - 1],
                d1 = data[i],
                d = x0 - d0.date > d1.date - x0 ? d1 : d0;

            focus.select('circle.y')
                .attr('transform', 'translate(' + x(d.date) + ',' + y(d.price) + ')');
        }

我无法说出我做错了什么。但基本上当我将鼠标移动到屏幕的左半部分时,绝对没有任何反应。圆圈出现在图表中的最后一个数据点上,从不移动。如果我将鼠标移动到图表的右侧,我会在控制台Uncaught TypeError: Cannot read property 'date' of undefined中收到错误。

更新 这是表示问题的jsFiddle。我提供的代码实际上是一个函数,数据和$元素都在变量中传递。我已经改变了他们在小提琴中传递的方式,但数据与我正在使用的数据相同。

1 个答案:

答案 0 :(得分:1)

要使用d3.bisector,您必须先对数据数组进行排序。

关于这一点,API并不是很明确,但你可以在那里阅读:

  

返回数组中x的插入点以维护排序顺序[...]返回值适合用作拼接的第一个参数,假设该数组已经排序。 (强调我的)

因此,在您使用d3.bisector

之前,这是对数据进行排序的功能
data.sort(function(a, b) {
    return d3.ascending(a.date, b.date)
});

这是你的工作小提琴:https://jsfiddle.net/7154p8uv/