d3.js Animation Follow Circles on Mouse Move - javascript

I'm using d3.js library and I'm having a problem implementing what the client needs.
Here's client request they want to "black circles to "follow" the mouse when you hover over it.
I don't know if d3.js library has this kind feature I can only see, on mouse drag.
I've added my sample code in JSFiddle see below:
node.on("mousemove", function(){
var coords = d3.mouse(this);
//node.attr('transform', 'translate(' + coords[0] + ',' + coords[1] + ')';
nodes.call(force.drag);
});
jsFiddle : https://jsfiddle.net/glenmongaya/4pjaeko3/5/
Thanks for you help.

You want a mouse-over to behave like a drag?
node.on("mousemove", function(d){
d3.event.stopPropagation(); // stop the default event handling
d.fixed = true; // fix the moused over node
var coords = d3.mouse(this.parentNode); // get mouse position
d.px = coords[0]; d.py = coords[1]; // set position
force.resume(); // resume layout
});
Updated fiddle.

Related

Dragging element with d3.mouse(this) causes flickering of element

I have an absolutely positioned leading line within a relatively positioned div. I need to move the leading line horizonatally as the mouse moves using d3. Since d3.event requires the elements to be positioned within g elements, I am trying to use d3.mouse to move the leading line. However, the dragging behaviour is very erratic and flickers too much. I cannot seem to figure out what is causing this.
var drag = d3.behavior
.drag()
.on('drag', function(event) {
dragMoveNew(this);
})
d3.select(".grid").call(drag);
function dragMoveNew(elem) {
var x = d3.mouse(elem)[0];
$(elem).css('left', x);
}
Here is the jsfiddle link
https://jsfiddle.net/u4koenra/
Use d3.event.x
function dragMoveNew(elem) {
//var x = d3.mouse(elem)[0];
var x = d3.event.x;
$(elem).css('left', x);
}

D3 zoom event firing on drag in Angular

Tldr; dragging the SVG causes it to rotate as well as translate.
I am trying to implement dragging and zooming events on an SVG group using D3 (v.4) as part of an Angular service.
this.unitGroup = this.svg.append('g')
.attr('id', 'unitGroup')
.call(this.drag)
.call(this.zoom);
Dragging translates the SVG.
drag = d3.drag()
.on('start', () => {
console.log('drag start');
this.setClickOrigin(d3.event);
})
.on('drag', (d, i, n) => {
const target = d3.select(n[i]).node() as any;
const m = target.getCTM();
const x = d3.event.x - this.clickOrigin.x;
const y = d3.event.y - this.clickOrigin.y;
this.setClickOrigin(d3.event);
this.translate(target, x, y);
});
While zooming rotates the SVG.
zoom = d3.zoom()
.on('zoom', (d, i, n) => {
const target = d3.select(n[i]).node() as any;
const m = target.getCTM();
const b = target.getBBox();
const dir = (d3.event.sourceEvent.deltaY > 0) ? 1 : -1;
this.rotate(target, dir);
});
My original code worked fine. However, integrating it into Angular has thrown up some problems.
The current problem is that when you drag the unitGroup it triggers the zoom event along with the drag event.
The expected behaviour is that:
'click-and-drag' translates the small, dark-grey box in the x and y dimensions.
'mouse-wheel-scroll' rotates the small, dark-grey box around its center.
Here is a Plunker: https://embed.plnkr.co/0GrGG7T79ubpjYa2ChYp/
Actually, what you are seeing here is the expected behaviour.
In D3, d3.zoom() handles not only the zoom but the panning as well. So, the mousemove is being handled by d3.drag() and by the zoom function as well.
As Bostock (D3 creator) once said:
combining these two behaviors* means that gesture interpretation is ambiguous and highly sensitive to position. (*zoom and drag)
Off the top of my head the simplest solution is just checking if you had a "real" zoom (mouse wheel) in the zoom function and, if you didn't (no mouse wheel), return:
if(!d3.event.sourceEvent.deltaY) return;
Here is your plunker with that change only: https://plnkr.co/edit/jz5X4Vm9wIzbKmTQLBAT?p=preview

Running functions after a drag occurs?

I'm trying to run a block of code after a drag occurs in my program. I had thought that the following would work:
//behavior for a dragged point
var drag = d3.behavior.drag()
.origin(function (d) {
return d;
})
.on("drag", dragmove);
function dragmove(d) {
d3.select(this).attr("transform", "translate(" + (d.x = d3.event.x) + "," + (d.y = d3.event.y) + ")");
//events to update line to fit dots
updateXs();
updateLineData();
//update line
d3.select(".myLine").transition()
.attr("d", lineFunc(lineData));
}
But after seeing it run I think that the block is running while the drag is occurring and the object is moving, which may be causing it to not work correctly. What I want to find is the correct method for handling code that should run after a drag completely occurs. If there's a way to make the line update while the point is being dragged, that would be really cool and preferred, but I don't mind having it execute after the drag finishes, either.
Here's the full code:
https://jsfiddle.net/cuhwvj8t/4/
To execute some code once the drag has completed you should use the dragend event. So you'd use:
var drag = d3.behavior.drag()
.on("dragend", function(d) {
// Update lines
});
However you should be able to update the lines during the drag using the drag event which you're already wired up to:
var drag = d3.behavior.drag()
.on("drag", function(d) {
// Update lines
});

How to stop d3.drag triggering mouseover/mouseout events in chrome

I have the following d3 visualisation. The darker colour at the top indicates that a node has been selected. When I mouseover a non selected node it changes opacity so a user can see which node would be selected if I click.
This is achieved via a CSS style sheet and the following js/d3:
nodeSelection.select("circle").on('mouseover', function(e) {
d3.select(this).classed("hover", true);
_this.fireDataEvent("mouseOverNode", this);
});
nodeSelection.select("circle").on('mouseout', function(e) {
d3.select(this).classed("hover", false);
_this.fireDataEvent("mouseOutNode", this);
});
So, far, so good. However, when I drag, the drag function seems to randomly trigger mouse over and mouse out events on the nodes that I am not dragging. This causes the node opacity to flicker. If I watch on the development tools in chrome I can see that this is because it is causing nodes to gain the class "hover". The code above to add this CSS class appears nowhere else, and by use of the console logging, I have confirmed that mouseover and mouseout events are being fired. These nodes are often far from the cursor.
This issue does not occur in Firefox.
UPDATE: I actually managed to fix this almost immediately after posting this. I just explicitly de-register the listeners inside drag start, and re register in drag end. It might still be interesting to some people if they are having similar issues.
My drag function now looks like:
var drag = d3.behavior.drag()
.on("dragstart", function(d) {
console.log("dragstart");
d.dragstart = d3.mouse(this); // store this
d.fixedbeforedrag = d.fixed;
d.fixed=true;
// deregister listeners
nodeSelection.select("circle").on("mouseover", null).on("mouseout", null);
})
.on("drag", function(d) {
d.px = d.x; // previous x
d.py = d.y;
var m = d3.mouse(this);
d.x += m[0] - d.dragstart[0];
d.y += m[1] - d.dragstart[1];
nodeSelection.attr("transform", "translate(" + [d.x, d.y] + ")");
_this.getForce().start();
})
.on("dragend", function(d) {
console.log("dragend");
delete d.dragstart;
d.fixed = d.fixedbeforedrag;
//reregisters listeners
_this.updateSVG();
});

mouseOver in Highcharts

I have a chart. There is no mouseOver event in chart options, but I need to get mouse coordinates when I move cursor. For example, I want to show coordinates on xAxis and yAxis. Is it possible?
You can catch mousevent on the div which contain highcharts.
http://jsfiddle.net/5KHaj/2/
$('#highcharts-0').mouseover(function(e){
$('#report').html(e.clientX + ' ' + e.clientY);
});
Get the normal mouse coordinates then calculate the relative position.
document.body.onmousemove = function (event) {
var x = event.target.x - <your_chart_element>.getBoundingClientRect().left
var y = event.target.y - <your_chart_element>.getBoundingClientRect().top
}

Categories