I'm trying to find the problem with the drag behavior setup that I have in my program, because it seems like the drag won't even activate. I'm using http://jsfiddle.net/da37B/317/ as the reference code for my program.
Here's the relevant code:
vis.selectAll(".nodes")
.data(nodes)
.enter().append("circle")
.attr("class", "nodes")
.attr("cx", function (d) {
return xRange(d.x);
})
.attr("cy", function (d) {
return yRange(d.y);
})
.attr("r", "10px")
.attr("fill", "black")
.attr("transform", "translate(" + p.x + "," + p.y + ")")
.call(drag); <------
// Define drag beavior
var drag = d3.behavior.drag()
.on("drag", dragmove);
function dragmove(d) {
var x = d3.event.x;
var y = d3.event.y;
d3.select(this).attr("transform", "translate(" + x + "," + y + ")");
}
And here's the full code: https://jsfiddle.net/4o5pch1q/1/
The reason you don't see any effect is that you have an error in your jsfiddle. Please check the console for such obvious things in the future.
Once the obvious error is fixed (including moving the definition of drag up so that it's defined before it's being used), the only thing that remains is to tell D3 how to get the origin of the element being dragged (otherwise the circle "jumps" on drag):
var drag = d3.behavior.drag()
.origin(function(d) { return d; })
.on("drag", dragmove);
Complete demo here.
Related
Trying to drag groups. Why doesn't origin work here? Notice how it jumps when you first click on it? JSFIDDLE Based on this: http://bl.ocks.org/mbostock/1557377
var drag = d3.behavior.drag() // construct drag behavior
.origin(function() {
var t = d3.select(this);
return {x: t.attr("x"), y: t.attr("y")};
})
.on("drag", function(d,i) {
d.x += d3.event.dx
d.y += d3.event.dy
d3.select(this).attr("transform", function(d,i){
return "translate(" + [ d.x,d.y ] + ")"
})
});
You're mixing different ways of setting positions -- you're setting transform and cx and cyon the circles, but not on thegelements that you want to drag. While it can be made to work by computing the various offsets, it's much easier if you set the position for the things you're interested in (i.e. theg` elements) and that the drag behaviour is called on.
var svgG = svg.append("g")
.attr("transform", function(d) { return "translate(" + [ d.x,d.y ] + ")"; })
.call(drag);
Complete example here.
I am not sure what's going on, but I have 2 very simple examples set up to show what I am asking.
Both examples have a 'g' that contains a 'rect' and 'text'.
In the 1st example, I am setting up drag on the 'g' itself, i.e., if you mousedown anywhere in that group and drag, it will drag the entire thing (both 'rect' and 'text') around the viewpoint.
http://jsfiddle.net/wup4d0nx/
var chart = d3.select("body").append("svg")
.attr("height", 500)
.attr("width", 500)
.style("background", "lightgrey");
var group = chart.selectAll("g")
.data(["Hello"])
.enter()
.append("g")
.attr("id", function (d) { return d;});
var rect = group.append("rect")
.attr("stroke", "red")
.attr("fill", "blue")
.attr("width", 200)
.attr("height", 200)
.attr("x", 10)
.attr("y", 10);
var label = group.append("text")
.attr("x", 40)
.attr("y", 40)
.attr("font-size", "22px")
.attr("text-anchor", "start")
.text(function (d) { return d;});
// Set up dragging for the entire group
var dragMove = function (d) {
var x = d3.event.x;
var y = d3.event.y;
d3.select(this).attr("transform", "translate(" + x + "," + y + ")");
};
var drag = d3.behavior.drag()
.origin(function (data) {
var element = d3.select("#" + data);
return {
x: d3.transform(element.attr("transform")).translate[0],
y: d3.transform(element.attr("transform")).translate[1]
};
})
.on("drag", dragMove);
group.call(drag);
In the 2nd example, which doesn't work and is what I am interested in, I want ONLY THE TEXT to be something the user can grab to drag the entire group around.
I tried many attempts. Some don't work at all, some work but flicker like the example I provide here:
http://jsfiddle.net/9xeo7ehf/
var chart = d3.select("body").append("svg")
.attr("height", 500)
.attr("width", 500)
.style("background", "lightgrey");
var group = chart.selectAll("g")
.data(["Hello"])
.enter()
.append("g")
.attr("id", function (d) { return d;});
var rect = group.append("rect")
.attr("stroke", "red")
.attr("fill", "blue")
.attr("width", 200)
.attr("height", 200)
.attr("x", 10)
.attr("y", 10);
var label = group.append("text")
.attr("x", 40)
.attr("y", 40)
.attr("font-size", "22px")
.attr("text-anchor", "start")
.text(function (d) { return d;});
// Set up dragging for the entire group USING THE LABEL ONLY TO DRAG
var dragMove = function (d) {
var x = d3.event.x;
var y = d3.event.y;
d3.select(this.parentNode).attr("transform", "translate(" + x + "," + y + ")");
};
var drag = d3.behavior.drag()
.origin(function (data) {
var element = d3.select("#" + data);
return {
x: d3.transform(element.attr("transform")).translate[0],
y: d3.transform(element.attr("transform")).translate[1]
};
})
.on("drag", dragMove);
label.call(drag);
What's going on with this that it flickers and what am I doing wrong?
Any help would be greatly appreciated!
Thanks!
I'm not sure exactly why it is flickering (as I am not too familiar with D3), but one way to get it to stop is to use the source event for D3:
// 50 is the offset x/y position you set for your text
var x = d3.event.sourceEvent.pageX - 50;
var y = d3.event.sourceEvent.pageY - 50;
Edit: While the above code works, it causes the box to initially "jump" to the coordinates of the text, A better fix would be to take your first example and just filter our events that aren't executed on the text element. Try putting the following at the top of the dragMove method:
if(d3.event.sourceEvent.target.nodeName !== 'text') {
return;
}
Try d3.event.sourceEvent.stopPropagation(); inside on-drag function
I have been trying to modify the examples provided by D3.js to create a step plot where I can hover over each step to get details of the value.
Currently I am looking at:
http://bl.ocks.org/mbostock/3902569
and my plot looks like:
http://jsfiddle.net/q47r3pyk/
after hours of playing with the JavaScript. It is close to my final result but if you try to hover over the points, you only get a value on the left handle side of the screen.
How do you get the hover effect to appear over where you place your mouse?
Any advice would be appreciated on what I am doing incorrectly.
My mouse over section looks like:
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(formatted_data, x0, 1),
d0 = formatted_data[i - 1],
d1 = formatted_data[i],
d = x0 - d0.x > d1.x - x0 ? d1 : d0;
focus.attr("transform", "translate(" + x(d.x) + "," + y(d.y) + ")");
focus.select("text").text(d.y);
I think you want to adjust your bisectDate function (as can be seen in the jsfiddle you linked).
If you use:
bisectDate = d3.bisector(function(d) { return d.x; }).left;
(using d.x instead of d.date), it's working for me.
This is due to the fact that you are storing the x coords in x (in formatted_data), whereas Mike Bostock's example uses .date. Thus, d3.bisect can't find the proper value.
var nodeEnter = node.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; })
.on("click", click)
.on("mouseover",function (d){
if(d.name=="Purchased"){
jQuery.getJSON("RequestHandler?usercommand=jsoncompany&subcommand=propCount&useraction=d3Tree_frm&mgmtId="+d.id+"&type="+d.name, function(json){
var count=JSON.stringify(json.prop_purchased_count);
result="Purchased Property :"+count;
});
}
var g = d3.select(this);
var info = g.append("text")
.classed('info', true)
.attr('x', 30)
.attr('y', 30)
.text(result);
})
.on("mouseout", function() {
d3.select(this).select('text.info').remove();
});
i am using above code to display basic tooltip on mouse over of a node. The problem is that when i move from one node to another tooltip value is not updated quickely it show me previous value .if i move my cursor little bit and move again to that node then only it shows me correct value of that node.
How to resolve that issue?
I'm using the function d3.svg.symbol() to plot symbols on a scatterplot. I'd like to have some tooltip show up on mouseover on the symbols. To place them accordingly, I need to get the center of the symbols, but don't really know how to do this. The code I use to generate the symbols is:
var symbols = svg.append("g")
.attr("id", "circles")
.selectAll("path")
.data(dataset)
.enter()
.append("path")
.attr("transform", function (d) { return "translate(" + x(d[SelX]) + "," + y(d[SelY]) + ")"; })
.attr("d", d3.svg.symbol()
.size(50)
.type(function (d) { if (d.Spaziatura == "Proportional") { return "circle";} else { return "diamond"; }; }))
.attr("fill", function (d) {
if (d.Grazie == "Sans") { return colore(parseFloat(d[SelCol])); }
else { return colore2(parseFloat(d[SelCol])); };
})
.attr("id", function (d) { return d.FamilyName;})
.attr("opacity", 1)
.attr("visibility", "visible")
Then the mouseover event:
.on("mouseover", function (d) {
//Get this symbbol's x/y values, then augment for the tooltip
var centroid = symbols.centroid(d);
var xPosition = centroid[0];
var yPosition = centroid[1];
//Update the tooltip position and value
svg .append("text")
.attr("class", "tooltip")
.attr("x", xPosition)
.attr("y", yPosition - (height/20))
//and then other stuff happens
I tried to reuse the centroid function I used for a map, but it doesn't work. I just need to get the center of the symbol's path to get this working, so any help on this is really appreciated, thanks!
You can get the center of the symbol like this (in the mouse handler):
var bibox = this.getBBox(),
t = d3.transform(d3.select(this).attr("transform")),
centroidX = t.translate[0] + (bibox.x + bibox.width)/2,
centroidY = t.translate[1] + (bibox.y + bibox.height)/2;
Demo here.