I have a vertical guideline across my svg that follows the mouse pointer, but right now it's kind of slow to update its position, something that's especially noticeable with rapid mouse movements. Is there a way to reduce this lag?
Current code:
svg.on("mousemove", function(d) {
svg.select(".guideline")
.attr("x1", d3.mouse(this)[0]-1)
.attr("x2", d3.mouse(this)[0]-1);
});
svg.on("mouseover", function(d) {
svg.append("line")
.attr("class", "guideline")
.attr("y1", margin[0])
.attr("y2", height+margin[0])
.attr("opacity", originOpacity)
.attr("stroke", "#333")
.attr("pointer-events", "none");
});
svg.on("mouseout", function(d) {
svg.select(".guideline").remove();
});
You are selecting the line on every mousemove, keep the line in a variable instead:
var line = svg.append("line")
.attr("class", "guideline")
.attr("y1", margin[0])
.attr("y2", height+margin[0])
.attr("opacity", 0)
.attr("stroke", "#333")
.attr("pointer-events", "none");
svg.on("mousemove", function(d) {
line
.attr("x1", d3.event.pageX-1)
.attr("x2", d3.event.pageY-1);
});
svg.on("mouseover", function(d) {
line.attr("opacity", originOpacity);
});
svg.on("mouseout", function(d) {
line.attr("opacity", 0);
});
I am having the same problem, but I noticed two things:
If you look at High Charts, they have implemented (in their JS library) a similar vertical guideline, which doesn't lag behind so much. So it is possible to do it. See for example: here
I use a container element, to which I added an SVG element, to which I added a group (g) element with a coordinate translation/transformation, like so:
HTML:
<div id="d3-container"></div>
JS:
var svg = d3.select("#d3-container")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.attr("id","d3-svg")
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.attr("id","d3-canvas");
The interesting thing is, when I bind mouse events (using the code above in the first answer) to the various elements, I get very different performance: when I bind it to the "d3-canvas" group my guided line is very slow and lags behind, when I bind it to its parent svg element ("d3-svg") it is already faster, and if I bind it to the div ("d3-container") I get the fastest performance (although it is still not as quick as High Stock though). So I am thinking the coordinate transformation adds a lot of overhead to mouse events, but somehow either D3 or SVG is also not optimized for mouse events.
Rather than updating the attributes on every mousemove
, you could add a couple millisecond delay:
var lastMove, elapsed;
svg.on("mousemove", function(d) {
elapsed = Date.now() - lastMove;
if ( elapsed < 40 ) return;
svg.select(".guideline")
.attr("x1", d3.mouse(this)[0]-1)
.attr("x2", d3.mouse(this)[0]-1);
lastMove = Date.now();
});
This will certainly improve performance, but at the cost of making the movements more choppy. Play around with the number of milliseconds you check for. 40
may be too long.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With