I have simple d3 code binding data with circles. An event is fired when mouse hover over the circles. The mouseOver function is also very simple. It just makes tooltip div visible.
It's a client work so I cannot share the full code. But it has the simple structure like below:
function mouseOver() {
tooltip.style("visibility", "visible")
.style("top", d3.event.pageY + "px")
.style("left", d3.event.pageX +"px")
.html('<p>'+'</p>')
}
var circles = g
.selectAll('.circles')
.data(data)
.join('circle')
.attr('class', 'circles')
.attr('cx', d => x(d))
.attr('cy', d => y(d))
.attr('r', r)
.attr('fill', d => colour(d.type))
.attr('fill-opacity', 0.6)
.on('mouseover', mouseOver)
.on('mouseleave', mouseLeave)
circles.exit().remove()
It works well on desktop. But for some reasons, the tooltip doesn't show up on mobile.
I changed the 'mouseover' into 'touchstart' in case it's the reason. To capture if the window ontouchstart, I made like this.
var hover = ('ontouchstart' in window) ?
'touchstart click' : 'mouseover';
Then, in the selection, I changed as below:
.on(hover, mouseOver)
But it still doesn't trigger the event on mobile.
On a side note, I also have bars(rect) with the same setting as circles above but the mouseover event is trigerred on mobile as well as desktop.
I really have no idea why one event works well on mobile although it's fired by 'mouseover' event handler while the other doesn't work at all despite the same setting as the other.
Does anyone have ideas??
Related
I'm a freshman wordpress guy who tried to display my small d3.js portofolio collection at my new site built using wordpress. Upon doing so i encountered a small problem : i display my works in a specific blog page, which is accessed by clicking the 'Visual Blog' top navigation menu.
Among the articles is one titled 'Growth Domestic Products of Nations : Bubble Force Chart' which has d3.js visualization embed-ed in it. If you hover on a bubble, there suppose to be a tooltip appear which displays various info, which works fine until yesterday, after i added new articles titled 'British Monarch Family Tree : Force Directed Graph' on top of it, the bubble tooltip suddenly not displaying anymore on mouse hover event.
The tooltip still works fine if you access the article directly, however it doesn't when accessed in the blog page from top navigation menu, as described above.
Here is the relevant code snippet :
bubbles
.on("mouseover", function(d){
tooltip_div.style("display", "inline");
/*.....*/
})
.on("mousemove", function(d){
var r = this.getBBox().width/2, myX = this.getBBox().x, myY = this.getBBox().y;
tooltip_div
.style("left", function(){
return ((d3.event.pageX - 250)+ r) + "px";
})
.style("top", function(){
return (d3.event.pageY - 470) + "px";
});
})
.on("mouseout", function(d){
tooltip_div.style("display", "none");
/*.....*/
});
It is quite confusing, since i used the same technique to display and determine tooltip position at my other articles, such as the various 'Barchart' articles, they're all works fine, except for this bubble chart alone...
Note 1 : i tested this on Opera.
Note 2 : i tried to delete the 'British Monarch Family Tree : Force Directed Graph' article from the blog page, the tooltip back to normal. I posted it again, the tooltip not appearing again...
It seems imposible to rely on absolute tooltip positioning since a wordpress blog is always growing with new articles, messing with the d3.event.pageX and d3.event.pageY variables. Not to mention as a wordpress newbie, my knowledge about how wordpress system works is still lacking..
Instead of positioning the tooltip relative to the entire dynamic page itself (by means of d3.event.pageX and d3.event.pageY), i just append the tooltip directly onto the SVG on every mouse over, adjust the position using d3.mouse(this) as opposed to d3.event earlier, and delete the tooltip SVG element on mouse out event..
var countryText;
bubbles
.on("mouseover", function(d){
countryText = bubbleGroup.append("text")
.attr("class", "countryText")
.attr("font-size", 13)
.attr("font-weight", "bold")
.text(d.country)
.style("pointer-events", "none")
.attr("x", d3.mouse(this)[0] - 60)
.attr("y", (d3.mouse(this)[1] - 20));
})
.on("mousemove", function(d){
countryText
.attr("x", d3.mouse(this)[0] - 60)
.attr("y", (d3.mouse(this)[1] - 20));
})
.on("mouseout", function(d){
d3.select(".countryText").remove();
})
As you can see, this gives stable tooltip positioning wether if you see the article in the blog page, or if you access the article directly.
I'm using d3-tip for tooltips on my graph. And am trying to work out if there's an easy way to keep the tooltips open for a brief period of time?
Once I mouseout on the node, it fires the .hide() method, I can never actually hover over the tooltip.
I think I need a way to mouseover the tooltip element so I can fire the .show() method, like so:
tip.on('mouseover', function(d) {
tip.show(d);
}
But I'm not sure how to do this...
I've set up a JSFiddle here.
Any ideas if this is possible?
Thanks in advance!
Here's the result: http://jsfiddle.net/hx8pjwdu/9/
.on('mouseover', function(d) {
d3.select(".d3-tip").transition().style("opacity", "1");
tip.show(d);
})
.on('mouseout', function(d) {
d3.select(".d3-tip").transition().duration(1000).style("opacity", "0").each("end", tip.hide);
});
d3.select(".d3-tip").on('mouseover', function(d) {
d3.select(".d3-tip").transition().style("opacity", "1");
}).on('mouseout', function(d) {
d3.select(".d3-tip").transition().duration(1000).style("opacity", "0").each("end", tip.hide);
});
I added a mouseover event for your d3-tip and made its hide event a fadeout.
I wrote a D3 widget a while back based on the sunburst example on the D3 site - http://bl.ocks.org/kerryrodden/7090426.
The widget was fine and I even submitted it to an open source project (several other people viewed it and tested it). However now, when I try to view the same widget with a different computer (same browser version), I am experiencing an inconsistent behavior with mouseover and mouseenter. When I hover over items, only the first item I hovered over has the opacity set, when I move the mouse within the widget, opacity is not updated.
Here is the broken version:
http://jsfiddle.net/wrdrvr/f5tvsv5v/
var path = svg.datum(data).selectAll("path")
.data(partition.nodes)
.enter().append("path")
.attr("display", function(d) { return d.depth ? null : "none"; }) // hide inner ring
.attr("d", arc)
.attr('id',function(d) {
return d.name+"-"+d.value;
})
.style("stroke", "#fff")
.style("fill", function(d) {
if (d.depth > 0) {
return color(d.name);
}
}) .each(stash)
.on("mouseover", mouseover)
//.on("mouseenter",mouseover)
.on("mouseleave", mouseleave)
I was able to get it to work as it was supposed to by including a mouseenter, however I did not use it previously and it was not used in the example and I am not sure why I need it here. Can someone please help clarify this?
Updated http://jsfiddle.net/f5tvsv5v/2/
.on("mouseleave", mouseleave)
//.on("mouseover", mouseover)
.on("mouseenter",mouseover)
You should use mouseenter instead of mouseover since mouseover does not buble (http://www.quirksmode.org/dom/events/mouseover.html)
I need some help with my d3.js. Could someone help me in implementing a feature that on mouse over your cursor turns into the "click" cursor form? For example when you click hover over a button on stack overflow the cursor changes.
.on("mouseover", function() {
d3.select(this)
.style("fill", "#3b6887");
})
See the different cursors available you can use cursor CSS | MDN
Try the following
.on('mouseover', function() {
d3.select(this)
.style('fill', '#3b6887')
.style('cursor', 'pointer');
});
I'm trying to implement both dragging and zooming event handlers for a circle item using d3js. I've added behaviors for both events as given below
var circle = svg.append("circle")
.attr("fill", "green")
.attr("opacity", 0.6)
.attr("cx", 100)
.attr("cy", 100)
.attr("r", 13)
.call(d3.behavior.drag().on("drag", drag))
.call(d3.behavior.zoom().on("zoom", zoom));
without zooming the object, dragging works fine. after zooming in/out of the object, dragging does not work, yet all events containing a mousedown is caught as "zoom" event.
For full source please see http://jsfiddle.net/xTaDC/
Seems that i did not understand the "d3.behavior". https://github.com/mbostock/d3/blob/master/examples/mercator/mercator-zoom-constrained.html provides only zoom handler and handles both dragging and zooming.
What am i doing wrong here?
As far as I know, d3's zoom behavior already handles dragging, so the drag thing is redundant. Try making use of the zoom's d3.event.translate (which is a 2 element array, so if you want to get the x value only, you can go d3.event.translate[0]) to replicate the functionality in your Drag into your Zoom.
Additional tip: To make things easier on yourself, make sure that you apply your call(zoom) on the parent of whatever it is that you're trying to drag. This will prevent jittery and shaky behavior.
Source is of course, the d3 wiki.
"This behavior automatically creates event listeners to handle zooming and panning gestures on a container element. Both mouse and touch events are supported."
https://github.com/mbostock/d3/wiki/Zoom-Behavior
I faced similar problem and solved it by overriding other sub events of zoom.
Add below code after zoom and drag event listeners
.on("mousedown.zoom", null)
.on("touchstart.zoom", null)
.on("touchmove.zoom", null)
.on("touchend.zoom", null);
So the full code will look like
var circle = svg.append("circle")
.attr("fill", "green")
.attr("opacity", 0.6)
.attr("cx", 100)
.attr("cy", 100)
.attr("r", 13)
.call(d3.behavior.drag().on("drag", drag))
.call(d3.behavior.zoom().on("zoom", zoom))
.on("mousedown.zoom", null)
.on("touchstart.zoom", null)
.on("touchmove.zoom", null)
.on("touchend.zoom", null);
Append your graph with sensitive event area (must be the last append) :
var rect = svg.append("svg:rect")
.attr("class", "pane")
.attr("width", w)
.attr("height", h);
AFTER (not include) add event management on this area
rect.call(d3.behavior.zoom().x(x).scaleExtent([0.5, 4]).on("zoom", draw));
and the draw function is
function draw() {
svg.select("g.x.axis").call(xAxis);
svg.select("g.y.axis").call(yAxis);
svg.select("path.area").attr("d", area);
svg.select("path.line").attr("d", line);
}
see this exemple : https://groups.google.com/forum/?fromgroups=#!topic/d3-js/6p7Lbnz-jRQ%5B1-25-false%5D
In 2020, use d3.zoom to enable zooming and panning: https://observablehq.com/#d3/zoom
If you want to enable panning for the background, while allowing to drag the circle, see the official example where d3.drag and d3.zoom are used on different elements: https://observablehq.com/#d3/drag-zoom