Rotate a rectangle during drag D3 - javascript

I am new on D3 v4 and D3 in general. I created a rectangle and I can drag it on the canvas. Now I want to dynamically rotate the rectangle basing on the circle's radius.
You can check my code here:
https://jsfiddle.net/n4m1r8nb/208/
I also tried to add rotate attribute on drag function, but if I add it, the rectangle move following the mouse as per x and y definition in the snippet you can see here below, without rotating, and an error appear ".rotate is not a function".
var drag = d3.drag().on("drag", function () {
d3.select(this)
.rotate(d3.event.x)
.attr("x", d3.event.x)
.attr("y", d3.event.y);
console.log("X: ", d3.event.x)
console.log("Y: ", d3.event.y)
})
You can see what I mean in this pic (http://imgur.com/a/APbu9). I wanna rotate the black rectangle as per the screenshot in that url.
Thanks in advance.

I have created a fiddle to demonstrate this: https://jsfiddle.net/hsspve49/
Relevant part of the code are in the drag handler:
var drag = d3.drag().on("drag", function () {
var rect = d3.select(this);
var theta = Math.atan2(d3.event.y - height / 2, d3.event.x - width / 2) * 180 / Math.PI
rect
.attr("x", d3.event.x)
.attr("y", d3.event.y)
.attr('transform', `rotate(${theta + 90}, ${d3.event.x}, ${d3.event.y})`)
})

Related

Rotate a rectangle on dragging event D3

Hi everybody I am trying to rotate a rectangle while the user drag it with mouse. The rectangle follow a circular curve.
Below I attach my solution that is perfect, but the mouse is always on top left corner of the rectangle. I want that the mouse would be always in the center of the rectangle during dragging. How can I control it ?
Solution:
var drag = d3.drag().on("drag", function () {
var rect = d3.select(this);
var theta = Math.atan2(d3.event.y - height/2, d3.event.x - width/2) * 180 / Math.PI
rect
.attr("x", d3.event.x)
.attr("y", d3.event.y)
.attr('transform', `rotate(${theta + 90}, ${d3.event.x}, ${d3.event.y})`)
})
Full code of my solution you can see here: https://jsfiddle.net/hsspve49/
Offset the x and y attribute in the drag handler by the size of your rectangle, e.g.:
...
.attr("x", d3.event.x - 15) // half the width
.attr("y", d3.event.y - 35) // half the height
...

d3: svg image in zoom circle packing

UPDATE: New JSFIDDLE Scaling now working, ditched the defs and rect altogether and just appended the image. But still stuck on translate.
The translating is still not working on zoom. I can set the translate to say -100 for both x and y to get the non-zoomed placement correct. But, when zooming, it's of course still translating it -100 and not the larger value it would need to be to keep it in place.
Appears to need something in the code in the zoom section toward the bottom. Been messing with the part currently commented out, but no luck so far.
// .attr("transform", function(d) { return "translate(" + (d.x - v[0]) * k + "," + (d.y - v[1]) * k + ")"; })
// .attr("x", function(d) { return d.r * k; })
// .attr("y", function(d) { return d.r * k; })
.attr("width", function(d) { return d.r * k; })
.attr("height", function(d) { return d.r * k; })
Here's JSFIDDLE. I have a d3 circle packing with a raster image inside an svg rect within each node. How do you make the image scale when zooming? The container scales, but the image stays small and repeats when zoomed. Been trying to set the defs correctly, but no luck.
var defs = svg.append("defs")
// .data(nodes)
// .enter()
.append("pattern")
.attr("id", "bg")
.attr('patternUnits', 'userSpaceOnUse')
.attr('width', imageWidthHeight)
.attr('height', imageWidthHeight)
// .attr("transform", "translate(40,80)")
.append("image")
// .html("xlink:href", "img/" + function(d) { return d.image; })
.attr("xlink:href", "http://www.public-domain-photos.com/free-stock-photos-4/travel/yosemite/yosemite-meadows.jpg")
.attr('width', imageWidthHeight)
.attr('height', imageWidthHeight)
// .attr("transform", "translate(40,80)");
Also, can't get the container/image to translate into the center of the circle. I've commented those bits out for now because it screws everything up.
Have tried to apply info from these discussions, but still stuck. Thanks.
http://bl.ocks.org/mbostock/950642#graph.json
https://groups.google.com/forum/#!topic/d3-js/fL8_1BLrCyo
How to fill D3 SVG with image instead of colour with fill?
Adding elements to a D3 circle pack nodes
Answer JSFIDDLE
Got it. The trick was changing this bit of horrible:
(d.x - v[0]) * k
to this even worse bit of horrible:
(((d.x - v[0]) * (k)) - ((d.r / 2) * k))
Then the same for y.
Don't get me wrong, I'm grateful for the zoom circle pack template and the genius(es) who put it together. Thank you. It's just for someone at my noob level, the code above looks like a punishment of some kind. :)

Disable SVG drag

I would like to disable drag and drop on this SVG element, but failed with several tries,
/// Define drag beavior
var drag = d3.behavior.drag()
.on("drag", dragmove);
function dragmove(d) {
// if the event.x goes over a boundry, trigger "dragend"
if(d3.event.x > 200){
//drag.dragend();
drag.trigger("dragend");
}
var x = d3.event.x;
var y = d3.event.y;
d3.select(this).attr("transform", "translate(" + x + "," + y + ")");
}
svgContainer.call(drag);
JSFiddle - http://jsfiddle.net/nhe613kt/76/
I want disable drag on my chart or matrix you can say, I want it fixed and zoom able.
I am following this jsfiddle - http://jsfiddle.net/typeofgraphic/Ne8h2/4/ but it doesn't has any method
drag.dragend();
//drag.trigger("dragend");
Exception here as it throws - Uncaught TypeError: undefined is not a function
I've fixed you drag capability. You had two zoom variables, the first one called zoomed which was also a variable but wasn't declared until after it was called which wouldn't work. Also called your zoom variable as soon as you made your SVG. Yours was jittery as you appended a 'g' element after you made the SVG and then called your zoom so your zoom was being put on the 'g' element inside your SVG not on your actual SVG.
JSFiddle update : http://jsfiddle.net/nhe613kt/90/
var svgContainer = d3.select("body").append("svg")
.call(zoom) //called earlier
.attr("width", width)
.attr("height", height)
.style("background-color", "black")
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.right + ")");
Like mentioned in the comments, whats your end goal ? How come you want to disable your drag ? Do you wish to drag each rectangle individually ? If so you'll have to call the drag on each individual rectangle :) Tell me what else you want it to do and ill give it a go :)

How can I get the value at the corresponding place while mouseover in d3.js?

I need to show value at corresponding place while mouseover a line/bar chart using d3.js
var toolTip = svg.selectAll("path")
.append("svg:title")
.text(getmouseoverdata(data)
);
function getmouseoverdata(d) {
return d;
}
Here i get all the data in the array while mouseover at any place in the graph.
But I want to show the value at corresponding place. How can I achieve it?
You can use d3js mouse event handler like this
var coordinates = [0, 0];
coordinates = d3.mouse(this);
var x = coordinates[0];
var y = coordinates[1];
It will provide you the current mouse coordinates.
If you're only looking to display the data elements when you mouseover the path/rect elements, you could try to add the titles directly onto those elements while they are being created?
For example:
var data = [0, 1, 2, 3, 4, 5],
size = 300;
var canvas = d3.select("body")
.append("svg:svg")
.attr("width", size)
.attr("height", size);
var pixels = size / data.length;
canvas.selectAll("rect").data(data).enter().append("svg:rect")
.attr("fill", "red")
.attr("height", function(d){return d * pixels})
.attr("width", pixels/2)
.attr("x", function(d,i){return i * pixels})
.attr("y", 0)
.append("title") //Adding the title element to the rectangles.
.text(function(d){return d});
This code should create five rectangles with their data element present in a tooltip if you mouseover the rectangle.
Hope this helps.
Edit based on comment:
For a bottom to top graph, you can change the y attribute like so:
.attr("y", function(d){return size - d * pixels})
This addition will cause the bar to start at the difference between the maxHeight of your graph and the size of the bar, effectively turning a top-to-bottom graph into a bottom-to-top graph.

How to apply drag behavior to a d3.svg.arc?

How do I apply d3.behavior.drag() to the following arc?
var arc = d3.svg.arc()
.innerRadius(50)
.outerRadius(70)
.startAngle(45 * (pi/180)) //converting from degs to radians
.endAngle(3) //just radians
vis.append("path")
.attr("d", arc)
.attr("transform", "translate(200,200)")
I want to be able to drag the arc around. I have not been able to see anything that uses the drag behavior on any SVG path based object (only for basic elements like circle, rectangle, etc.)
The closest thing I can find related to dragging is this:
http://bl.ocks.org/mbostock/1557377
Though it appears that if you try to ".on("drag", dragmove) for the appended path (.append("path")) "d" comes out as undefined. And if you attach ".on("drag", dragmove)" to the arc itself, the event doesn't appear to fire...)
Drag is a behaviour that you create and then apply to the elements you want to execute that behaviour. There should be no issue applying it to an arc.
So with your arc (minor modification to make the translation accessible):
var position = [200,200];
var arc = vis.append("path")
.attr("d", arc)
.attr("transform", "translate(" + position + ")");
Start by creating the behavior you want. Our drag will update the translation of the arc:
var drag = d3.behavior.drag()
.on("drag", function(d,i) {
position[0] += d3.event.dx;
position[1] += d3.event.dy;
d3.select(this)
.attr("transform", function(d,i){
return "translate(" + position + ")"
})
});
Now we attach the behaviour to the arc:
arc.call(drag);
You can try it yourself here.

Categories