我想显示位于鼠标位置的数据。我知道网上有很多例子,但没有一个真正适用于我拥有的数据,因为我有三条线没有相同的x间隔。
以下是我用来尝试mousemove
功能的代码。
mb = focus.append("rect")
.attr("width", width)
.attr("height", height)
.attr("opacity", 0)
.on("mousemove", function(){
mouse_dt = x.invert(d3.mouse(mb.node())[0]);
tooltip.style("display", "block")
.style("left", (d3.mouse(mb.node())[0] + margin.left + 20) + "px")
.style("top", (d3.mouse(mb.node())[1] + margin.top) + "px")
.selectAll()
.data(grouped_data)
.enter().append("div")
.html(d => d.key);
})
.on("mouseout", function(){if (tooltip) tooltip.style("display", "none");})
我的问题是当我将鼠标悬停在焦点rect
周围时,该函数允许我在第一个鼠标点获取数据,但是当我指向第二个位置时,它不会删除旧数据。 (如下图所示)
grouped_data
如下所示;
half-hourly_interval_data hourly-interval_data
感谢任何帮助。
PS。如果您对完整代码感兴趣
<style> /* set the CSS */
.svg-container {
display: inline-block;
position: relative;
width: 100%;
padding-bottom: 100%;
vertical-align: top;
overflow: hidden;
}
.svg-content-responsive {
display: inline-block;
position: absolute;
top: 0;
left: 0;
}
body { font: 12px Arial;}
path {
stroke: #ccc;
stroke-width: 2;
fill: none;
}
.axis path,
.axis line {
fill: none;
stroke: grey;
stroke-width: 1;
shape-rendering: crispEdges;
}
#showAll{
position:absolute;
top:750px;
left:880px;
}
#clearAll{
position:absolute;
top:750px;
left:950px;
}
input{
border-radius:5px;
padding:5px 10px;
background:#999;
border:0;
color:#fff;
}
.brush .extent {
stroke: #fff;
fill-opacity: .125;
shape-rendering: crispEdges;
}
.line {
fill: none;
}
.zoom {
cursor: move;
fill: none;
pointer-events: all;
}
#legendContainer{
position:absolute;
top:200px;
left:20px;
overflow: auto;
height:490px;
width:90px;
}
#legend{
width:75px;
height:150px;
}
.legend {
font-size: 12px;
font-weight: normal;
text-anchor: left;
}
.legendcheckbox{
cursor: pointer;
}
</style>
<body>
<!-- load d3 v4 and jquery libraries -->
<script src="http://d3js.org/d3.v4.min.js"></script>
<div id="station_name"></div>
<div id="weather_type"></div>
<div id="container" class="svg-container" >
<div id="legendContainer" class="legendContainer">
<svg id="legend"></svg>
</div>
<div id="tooltip" style="position:absolute;background-color:lightgray;padding:5px"></div>
<script>
function filter_station_type(data, station, type) {
return data.filter(function(d) {
if(d['station_name']==station & d['metric']==type) {return d;} }) }
// Set the dimensions of the canvas / graph
var margin = {top: 10, right: 10, bottom: 100, left: 140},
margin2 = {top: 480, right: 10, bottom: 20, left: 140},
width = 1000 - margin.left - margin.right,
height = 550 - margin.top - margin.bottom,
height2 = 550 - margin2.top - margin2.bottom;
// Parse the date / time
var parseDate = d3.utcParse("%Y-%m-%dT%H:%M:%S%Z"),
bisectDate = d3.bisector(function(d){return d.dt;}).left;
// Set the ranges
var x = d3.scaleTime().range([0, width]);
var x2 = d3.scaleTime().range([0, width]);
var y = d3.scaleLinear().range([height, 0]);
var y2 = d3.scaleLinear().range([height2, 0]);
// Define the axes
var xAxis = d3.axisBottom(x).ticks(5)
.tickFormat(d3.timeFormat("%Y-%m-%d %H:%M"))
var xAxis2 = d3.axisBottom(x2).ticks(5)
.tickFormat(d3.timeFormat("%Y-%m-%d"))
var yAxis = d3.axisLeft(y)
.ticks(5);
var brush = d3.brushX()
.extent([[0, 0], [width, height2]])
.on("brush", brushed);
// Define the line
var stateline = d3.line()
.x(function(d) { return x(d.dt); })
.y(function(d) { return y(d.value); });
var stateline2 = d3.line()
.x(function(d) { return x2(d.dt); })
.y(function(d) { return y2(d.value); });
// Adds main graph svg canvas
var svg = d3.select("div#container")
// .append("div")
// .classed("svg-container", true)
.append("svg")
// .attr("preserveAspectRatio", "xMinYMin meet")
// .attr("viewBox", "0 0 600 400")
// .attr("svg-content-responsive", true)
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom);
// This line makes sure the main plot doesn't go beyond its assigned canvas
svg.append("defs").append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width)
.attr("height", height);
var focus = svg.append("g")
.attr("class", "focus")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var tooltip = d3.select("#tooltip")
.style("display", "none");
var context = svg.append("g")
.attr("class", "context")
.attr("transform", "translate(" + margin2.left + "," + margin2.top + ")");
var color = d3.scaleOrdinal(["#48A36D", "#0096ff", "#ff007e"]);
// Get the data
temp ="/basic_app/api/WF/"
d3.json(temp, function(error, json){
json.forEach(function(d) {
d.dt = parseDate(String(d.dt));
d.value = +d.value; });
var station_list = d3.map(json, function(d){return d.station_name;}).keys().sort(),
weather_type_list = d3.map(json, function(d){return d.metric;}).keys().sort(),
station_menu = d3.select("#station_name"),
weather_type_menu = d3.select("#weather_type");
station_menu.append('select')
.selectAll('option')
.data(station_list)
.enter().append('option')
.attr('value', function(d) {return d;})
.text(function(d) {return d;});
weather_type_menu.append('select')
.selectAll('option')
.data(weather_type_list)
.enter().append('option')
.attr('value', function(d) {return d;})
.text(function(d) {return d;});
update_plot(json, station_menu, weather_type_menu);
station_menu.on("change", function() {
update_plot(json, station_menu, weather_type_menu) });
weather_type_menu.on("change", function() {
update_plot(json, station_menu, weather_type_menu) });
});
function update_plot(data, menu1, menu2) {
var station = menu1.select("select").property("value")
type = menu2.select("select").property("value")
subset = filter_station_type(data, station, type)
plot(subset)
};
function plot(data) {
// Scale the range of the data
x.domain(d3.extent(data, function(d) { return d.dt; }));
y.domain([d3.min(data, function(d) { return d.value; }), d3.max(data, function(d) { return d.value; })]);
x2.domain(x.domain());
y2.domain(y.domain());
// Nest the entries by state
grouped_data = d3.nest()
.key(function(d) {return d.provider;})
.entries(data);
focus.selectAll('.line').remove();
focus.selectAll('.line')
.data(grouped_data)
.enter().append('path')
.attr('class', 'line')
.attr("clip-path", "url(#clip)") // makes sure the main plot doesn't go out of its boundary. Required for brush functionality
.attr("id", function(d) {return 'tag'+d.key.replace(/\s+/g, '')}) // assign ID. Required for interactive legend functionality
.style('stroke', function(d) {return color(d.key);})
.attr('d', function(d) {return stateline(d.values);})
focus.selectAll('.axis').remove();
focus.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
focus.append("g")
.attr("class", "axis axis--y")
.call(yAxis);
context.selectAll('.line').remove();
context.selectAll('.line')
.data(grouped_data)
.enter().append('path')
.attr('class', 'line')
.style('stroke', function(d) {return color(d.key);})
.attr('d', function(d) {return stateline2(d.values);});
context.selectAll('.axis').remove();
context.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height2 + ")")
.call(xAxis2);
context.selectAll('.brush').remove();
context.append("g")
.attr("class", "brush")
.call(brush)
.call(brush.move, x.range());
mb = focus.append("rect")
.attr("width", width)
.attr("height", height)
.attr("opacity", 0)
.on("mousemove", function(){
mouse_dt = x.invert(d3.mouse(mb.node())[0]);
tooltip.style("display", "block")
.style("left", (d3.mouse(mb.node())[0] + margin.left + 20) + "px")
.style("top", (d3.mouse(mb.node())[1] + margin.top) + "px")
.selectAll()
.data(grouped_data)
.enter().append("div")
.html(d => d.key);
})
.on("mouseout", function(){if (tooltip) tooltip.style("display", "none");})
svg.selectAll('.legend').remove();
var legend = d3.select("#legend")
.selectAll("text")
.data(grouped_data);
legend.enter().append("text")
.attr("x", 0)
.attr("y", function(d, i) {return 10 + i*15})
.attr("class", "legend")
.style("fill", function(d) {return color(d.key);})
.text(function(d) {return d.key;})
.on("click", function(d) {
if(this.style.fill == "rgb(204, 204, 204)") {
this.style.fill = color(d.key);}
else {
this.style.fill = "rgb(204, 204, 204)";}
var active = d.active ? false : true,
new_opacity = active ? 0 : 1;
d3.selectAll("#tag"+d.key.replace(/\s+/g, ''))
.transition().duration(100)
.style("opacity", new_opacity);
d.active = active;
})
};
function brushed() {
var selection = d3.event.selection;
x.domain(selection.map(x2.invert, x2));
focus.selectAll(".line").attr("d", function(d) {return stateline(d.values)});
focus.select('.axis--x').call(xAxis);
};
</script>
</div>
</body>