我正在尝试创建一个折线图,用户可以将鼠标悬停在点上以显示一个圆圈(并且还会在页面上发生其他事情,但我首先会显示一个圆圈)。
我已经尝试了几个教程,所有这些教程都有相同的结果:圆圈出现在线上方或侧面,几乎没有出现在图表上。
如何让圆圈出现在与之对应的坐标位置。这是问题的Fiddle和下面的d3代码。 JS Fiddle中还包括我的其他失败尝试。
基本图表:
var data=[{
"date":"January 1, 2008","total":'73'},
{"date":"February 1, 2008","total":'40'},
{"date":"March 1, 2008","total":'43'},
{"date":"April 1, 2008","total":'28'},
{"date":"May 1, 2008","total":'35'},
{"date":"June 1, 2008","total":'20'},
{"date":"July 1, 2008","total":'48'}
];
var chartWidth =650;
var chartHeight=375;
var chartMargins ={
top:20,
right: 20,
bottom: 20,
left: 50};
var yScaleDomain=[1, 100];
var chart = d3.select('#chartCanvas'),
WIDTH=chartWidth,
HEIGHT=chartHeight,
MARGINS= chartMargins;
//SET AXIS SCALES
xScale = d3.time.scale().range([MARGINS.left, WIDTH - MARGINS.right]).domain(d3.extent(data, function(d) { return new Date(d.date); }));
var x = d3.time.scale()
.range([0, WIDTH]);
var y = d3.scale.linear()
.range([HEIGHT, 0]);
bisectDate = d3.bisector(function(d) { return d.date; }).left,
yScale = d3.scale.linear().range([HEIGHT - MARGINS.top, MARGINS.bottom]).domain(yScaleDomain);
//DRAW AXES
xAxis = d3.svg.axis()
.scale(xScale),
yAxis = d3.svg.axis()
.scale(yScale)
.orient("left");
chart.append("svg:g")
.attr("transform", "translate(0," + (HEIGHT - MARGINS.bottom) + ")")
.call(xAxis);
chart.append("svg:g")
.attr("transform", "translate(" + (MARGINS.left) + ",0)")
.call(yAxis);
//DRAW LINES/ PLOT DATA
var lineGen = d3.svg.line()
.x(function(d) {
//Date() turns string date to numerical value
return xScale(new Date(d.date));
})
.y(function(d) {
return yScale(d.total);
})
//tell d3 what type of lines to draw (straight/linear ones)
.interpolate('linear');
chart.append("path")
.datum(data)
.attr("class", "line")
.attr("d", lineGen);
MouseOver尝试1(其他尝试在小提琴中注释掉):
var Y_value;
var curve1 = chart.select("path.line").data([data]);
x = d3.time.scale().range([MARGINS.left, WIDTH - MARGINS.right]);
y = d3.scale.linear().range([HEIGHT - MARGINS.top, MARGINS.bottom]);
var circle = chart.append("circle")
.attr("r", 8)
.attr("cx", 0)
.attr("cy", 0)
.style({fill: '#fff', 'fill-opacity': .2, stroke: '#000', "stroke-width": '1px'})
.attr("opacity", 0);
var tooltip = circle.append("chart:title");
chart.on("mouseover", function() {
var X_pixel = d3.mouse(this)[0],
X_date = x.invert(X_pixel);
var Y_pixel = y(Y_value);
var pathData = curve1.data()[0]; // recupere donnée de la courbe
pathData.forEach(function(element, index, array) {
if ((index+1 < array.length) && (array[index].date <= X_date) && (array[index+1].date >= X_date)) {
if (X_date-array[index].date < array[index+1].date-X_date) Y_value = array[index].val;
else Y_value = array[index+1].val;
}
});
circle.attr("opacity", 1)
.attr("cx", X_pixel)
.attr("cy", Math.round(y(Y_value)));
tooltip.text("X = " + (X_date) + "\nY = " + (Y_value));
});
chart.append('svg:path')
.attr('d', lineGen(data))
.attr('stroke', 'green')
.attr('stroke-width', 2)
.attr('fill', 'none');
stickyChart.append('svg:path')
.attr('d', lineGen2(data))
.attr('stroke', 'green')
.attr('stroke-width', 2)
.attr('fill', 'none');
答案 0 :(得分:0)
这位先生有很好的实现:
https://bl.ocks.org/mbostock/3902569
如果它消失了,我在这里创建了它的独立版本:
var margin = {
top: 20,
right: 50,
bottom: 30,
left: 50
},
width = 400,
height = 150;
var parseDate = d3.time.format("%d-%b-%y").parse,
bisectDate = d3.bisector(function(d) {
return d.date;
}).left,
formatValue = d3.format(",.2f"),
formatCurrency = function(d) {
return "$" + formatValue(d);
};
var x = d3.time.scale()
.range([0, width]);
var y = d3.scale.linear()
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var line = d3.svg.line()
.x(function(d) {
return x(d.date);
})
.y(function(d) {
return y(d.close);
});
var svg = d3.select("body").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 + ")");
function process(data) {
data.sort(function(a, b) {
return a.date - b.date;
});
x.domain([data[0].date, data[data.length - 1].date]);
y.domain(d3.extent(data, function(d) {
return d.close;
}));
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Price ($)");
svg.append("path")
.datum(data)
.attr("class", "line")
.attr("d", line);
var focus = svg.append("g")
.attr("class", "focus")
.style("display", "none");
focus.append("circle")
.attr("r", 4.5);
focus.append("text")
.attr("x", 9)
.attr("dy", ".35em");
svg.append("rect")
.attr("class", "overlay")
.attr("width", width)
.attr("height", height)
.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.attr("transform", "translate(" + x(d.date) + "," + y(d.close) + ")");
focus.select("text").text(formatCurrency(d.close));
}
}
var data = [];
var close = 95;
for (var i = 0; i < 100; i++) {
var date = new Date();
var dateValue = date.getDate() + i;
date.setDate(dateValue);
close = close - 1 + 2 * Math.random();
data[i] = {
date: date,
close: close
};
}
process(data);
&#13;
body {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.x.axis path {
display: none;
}
.line {
fill: none;
stroke: steelblue;
stroke-width: 1.5px;
}
.overlay {
fill: none;
pointer-events: all;
}
.focus circle {
fill: none;
stroke: steelblue;
}
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
&#13;