I am using SnapSVG to display a pretty complex image. Part of the image is a circle that I would like to rotate when the user does a click/drag.
I've been reading all evening about coordinate systems and it just isn't clicking. I read this page and tried to adapt the code to convert the screen location of the click to my SVG coordinates.
Here is the code I'm trying...
function dragStart(x, y, event) {
var inverse = event.srcElement.getScreenCTM().inverse();
var point = svg.createSVGPoint();
point.x = event.clientX;
point.y = event.clientY;
var final = point.matrixTransform(inverse);
console.log('Before: (' + point.x + ', ' + point.y + ')');
console.log('Final: (' + final.x + ', ' + final.y + ')');
}
The odd thing is that the X value is returning exactly what I would expect. But the Y value makes no sense at all.
EDIT: Fiddle added here
I've stripped the SVG down to the bare minimum. The black outer ring is static. The white inner ring will rotate when the user clicks and drags. The SVG was created so that the center of the ring is at (0,0) and the SVG has a width and height of 600. Open your browser's developer tools console and click on the image. As you can see, when you click close to the center of the red circle the x coordinate is near zero as expected. But the Y value is way off.
Related
I have a set of divs which are dynamic, I somehow want them in a different order. So I'm using flex order to control the order of the divs. One of the div contains an image. By clicking on that image it should console the x & y coordinates of the click which is related to the image. I have made everything I want. But the problem is I'm getting the y coordinates in a negative number, I believe it is because of the order I have changed using flex.
Here's what I tried
The expected result: When I click on the border image top left position it should console the exact position of the click which is related to the image.
This is caused by your own calculations.
You can simplify the calculation using this function
GetMousePositionRelativeToTarget(e) {
// Get the target
const target = e.target;
// Get the bounding rectangle of target
const rect = target.getBoundingClientRect();
// Mouse position
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
console.log(x + ':' + y);
return [x, y];
}
I want to make chart, that you can not drag out of its svg element.
I'm doing this at the moment like this jsfiddle
As you can see, you can zoom and drag this freely. What i want is this:
If you drag it for example to the right and the y axis hits the edge of your screen on the left it should stop and not be able to be dragged anymore to the right.
Which also means, that you can't drag it around while not zoomed in, because it already fills its svg area.
I guess i have to somehow restrict my redraw method. At the moment it's just this
function redraw() {
plotChart.attr("transform",
"translate(" + d3.event.translate + ")"
+ " scale(" + d3.event.scale + ")");
};
It probably has to check if for example the left edge of the chart hits coordinate [0][x] and then somehow stop drawing it any further out.
To know the axis point on scaling and on translation you need to get the CTM and then transform to get the real points.
//gets CTM on the first y line that is the group
var ctm = d3.select(".x").select(".tick")[0][0].getCTM();
//the first y line
var k = d3.select("svg")[0][0].createSVGPoint();
//current point without transform
k.x = d3.select(".x").select("line").attr("x2");
k.y = d3.select(".x").select("line").attr("y2")
j = k.matrixTransform(ctm)
//j is the real point of the line post transform.
//your code to zoom or pan depending on the value of j
I wish to set a boundary for two rectangles in my SVG.
I found this example: http://bl.ocks.org/mbostock/1557377
In the example the boundaries get worked out from the position of the object that is dragged. Every circle in the example can only move a certain distance from where it started. What I wish to do is to create one drag function and use it on multiple shapes. This drag function will stop the shapes from going out of a certain area.
For example: I have a rectangle on the left side of the screen and one on the right but I don't want any of them to be able to go off screen. I started working on this but figured out this worked with regards to the position of the object getting dragged. So this works for the left hand rectangle but the right hand rectangle can go offscreen to the right but only so far to the left
.on("drag", function(d) {
g = this;
translate = d3.transform(g.getAttribute("transform")).translate;
x = d3.event.dx + translate[0],
y = d3.event.dy + translate[1];
if(x<-10){x=-10}
if(x>width-10){width-10}
if(y<-10){y=-10}
if(y>height-10){y=height-10}
d3.select(g).attr("transform", "translate(" + x + "," + y + ")");
d3.event.sourceEvent.stopPropagation();
My question is: how do I impose the same boundary on anything that is dragged? i.e I don't want it to go off screen. I have variables width and height which are screen width and screen height respectively
I've been struggling with 3D CSS lately.
I have a cube (made as taught in this tutorial: http://desandro.github.io/3dtransforms/docs/cube.html)
I'm trying to allow the user to rotate it by 90 degrees vertically or horizontally to show another face, so I have two javascript functions:
document.getElementById('rot-x').addEventListener( 'click', function()
{
rotX+=90;
$('#cube').css("transform",
"translateZ(-100px)
rotateX("+rotX+"deg)
rotateY("+rotY+"deg)
rotateZ("+rotZ+"deg)");
console.log("X:" + rotX + "\nY:" + rotY + "\nZ:" + rotZ);
};
and
document.getElementById('rot-x').addEventListener( 'click', function()
{
rotY+=90;
$('#cube').css("transform",
"translateZ(-100px)
rotateX("+rotX+"deg)
rotateY("+rotY+"deg)
rotateZ("+rotZ+"deg)");
console.log("X:" + rotX + "\nY:" + rotY + "\nZ:" + rotZ);
};
The problem is that the rotation is local apparently, which means that the axes rotate together with the object. So if I rotate once on the X axis and once on the Y axis, that second rotation doesn't show another face, as the Y axis is now perpendicular to the screen.
I really need to know how to fix this, or find an alternate way to have the user switch cube faces
I need all of these actions to always be possible:
Show face above the current one
Show face below the current one
Show face to the left of the current one
Show face to the right of the current one
I'm capturing mouse position like this
mouse_move: function(e)
{
mousePos.x = e.pageX - vr.o.context.canvas.offsetLeft;
mousePos.y = e.pageY - vr.o.context.canvas.offsetTop;
},
and it has worked like a dream in all modern browsers while in development, Even tested Wrapping the <canvas/> in a basic dom structure to make sure mouse position adjusted...
obviously now I'm putting it in the actual site it's not working...
You can see here http://jondavidjohn.com/projects/
the mouse position ends up quite a ways south of the actual cursor, anything specifically that could be causing this?
SOLUTION
mouse_move: function(e)
{
mousePos.x = e.offsetX;
mousePos.y = e.offsetY;
},
COPIED FROM: http://simonsarris.com/blog/510-making-html5-canvas-useful
Getting mouse coordinates on Canvas
Getting good mouse coordinates is a little tricky on Canvas. You could use offsetX/Y and LayerX/Y, but LayerX/Y is deprecated in webkit (Chrome and Safari) and Firefox does not have offsetX/Y.
The most bulletproof way to get the correct mouse position is shown below. You have to walk up the tree adding the offsets together. Then you must add any padding or border to the offset. Finally, to fix coordinate problems when you have fixed-position elements on the page (like the wordpress admin bar or a stumbleupon bar) you must add the ’s offsetTop and offsetLeft.
Then you simply subtract that offset from the e.pageX/Y values and you’ll get perfect coordinates in almost every possible situation.
// Creates an object with x and y defined,
// set to the mouse position relative to the state's canvas
// If you wanna be super-correct this can be tricky,
// we have to worry about padding and borders
CanvasState.prototype.getMouse = function(e) {
var element = this.canvas, offsetX = 0, offsetY = 0, mx, my;
// Compute the total offset
if (element.offsetParent !== undefined) {
do {
offsetX += element.offsetLeft;
offsetY += element.offsetTop;
} while ((element = element.offsetParent));
}
// Add padding and border style widths to offset
// Also add the <html> offsets in case there's a position:fixed bar
offsetX += this.stylePaddingLeft + this.styleBorderLeft + this.htmlLeft;
offsetY += this.stylePaddingTop + this.styleBorderTop + this.htmlTop;
mx = e.pageX - offsetX;
my = e.pageY - offsetY;
// We return a simple javascript object (a hash) with x and y defined
return {x: mx, y: my};
}
Use e.offsetX and e.offsetY for now instead.
It actually gets more complicated when you introduce some other things, like margins and padding, but offsetX and offsetY will be much more accurate than what you've got to say the least.
I don't have my new "bulletproof-works-in-every-situation" mouse code on me right now, I can get that later for you if you think you'll need it.
edit: Derp! Thanks chopperdave for finally providing the code I forgot to add!