所以,我试图复制这个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。我提供的代码实际上是一个函数,数据和$元素都在变量中传递。我已经改变了他们在小提琴中传递的方式,但数据与我正在使用的数据相同。
答案 0 :(得分:1)
要使用d3.bisector
,您必须先对数据数组进行排序。
关于这一点,API并不是很明确,但你可以在那里阅读:
返回数组中x的插入点以维护排序顺序[...]返回值适合用作拼接的第一个参数,假设该数组已经排序。 (强调我的)
因此,在您使用d3.bisector
:
data.sort(function(a, b) {
return d3.ascending(a.date, b.date)
});
这是你的工作小提琴:https://jsfiddle.net/7154p8uv/