So i am tryingout Snap svg
Right now i have the following code:
var chatSvg = Snap("#chatSvg");
var c = chatSvg.image('assets/figures/naked.jpg', 10, 10);
chatSvg.click(function (event) {
c.x = event.x;
c.y = event.y;
});
However once the properties x and y is changed the image does not move.
Can anyone tell me what im doing wrong?
You change attributes in Snap using the attr() method, which will change the SVG attributes at the lower level for you.
So for example, it would look like
c.attr({ x: event.x, y: event.y })
Its also worth noting that the x, y coords get passed correctly into the click function, so its generally preferred to use this, so you could change the func to...
chatSvg.click( function( event, x, y ) {
c.attr({ x: x, y: y })
});
Related
Why when I click at the beginning or end of a Raphael path element are the coordinates not what I expect? See example (http://jsfiddle.net/gharabed/prh2J/1/)
In the example, I have a path drawn from (10,10) to (100,100). If I click at the very tip of the path near 100,100, I get a click event coordinate of something like (107,108). I can't be more than 4 or 5 pixels away from the end of the line. In fact it looks like I am only 2 (maybe 3 at the most) pixels away. It seems like the coordinates are a little off. Am I not considering something here?
function sendAlert(e) {
alert("Clicked at: " + e.x + "," + e.y + " I would expect it to be near the coordinates in the path defined (10,10) or (100,100)");
}
var paper = Raphael(document.getElementById('myid'),200,200);
var line = paper.path('M10,10L100,100');
line.attr({"stroke":"red","stroke-width":4});
line.click(sendAlert);
alert("Click as close as you can to the end of either end of the line segment.")
i agree what Vasil has said. i have made a small utility function which will gives you exact coordinates. just pass the mousedown event to this function. ( call this function in your sendalert function)
(i am using javascript).
var mainsvg = document.getElementsByTagName('svg')[0];
function getSvgCordinates(event) {
var m = mainsvg.getScreenCTM();
var p = mainsvg.createSVGPoint();
var x, y;
x = event.pageX;
y = event.pageY;
p.x = x;
p.y = y;
p = p.matrixTransform(m.inverse());
x = p.x;
y = p.y;
x = parseFloat(x.toFixed(3));
y = parseFloat(y.toFixed(3));
return {x: x, y: y};
}
I'm trying to hack arbor.js so I can perform on edges hover event and then display any information from it.
So let's say I can move over any edge and detect which edge's been hovered.
This is the drawing edges part of the rendering code:
particleSystem.eachEdge(function(edge, pt1, pt2){
// edge: {source:Node, target:Node, length:#, data:{}}
// pt1: {x:#, y:#} source position in screen coords
// pt2: {x:#, y:#} target position in screen coords
// find the start point
var tail = intersect_line_box(pt1, pt2, nodeBoxes[edge.source.name])
var head = intersect_line_box(tail, pt2, nodeBoxes[edge.target.name])
ctx.save()
ctx.beginPath()
ctx.lineWidth = (!isNaN(weight)) ? parseFloat(weight) : 1
ctx.strokeStyle = (color) ? color : "#cccccc"
ctx.fillStyle = null
//We save edge's line data, "Diego"
var slope = ((head.y)-(tail.y))/((head.x)-(tail.x))
a.push({x1:tail.x, y1:tail.y, x2:head.x, y2:head.y, m:slope})
ctx.moveTo(tail.x, tail.y)
ctx.lineTo(head.x, head.y)
ctx.stroke()
// Why pushing here makes x2 and y2 undefined?, "Diego"
ctx.restore()
})
This is the refered function:
var intersect_line_box = function(p1, p2, boxTuple)
{
var p3 = {x:boxTuple[0], y:boxTuple[1]},
w = boxTuple[2],
h = boxTuple[3]
var tl = {x: p3.x, y: p3.y};
var tr = {x: p3.x + w, y: p3.y};
var bl = {x: p3.x, y: p3.y + h};
var br = {x: p3.x + w, y: p3.y + h};
return intersect_line_line(p1, p2, tl, tr) ||
intersect_line_line(p1, p2, tr, br) ||
intersect_line_line(p1, p2, br, bl) ||
intersect_line_line(p1, p2, bl, tl) ||
false
}
I thought about two approaches:
First approach
First one is adding a 'hover' anonymous function inside var handler = {...}. So when $(canvas).mousemove(handler.hover) all would be managed by hover's function. I thought capturing the mouse's position and comparing it with the previous edges line coordinates.
I have a variable like:
var a = []
And then, before drawing again I clear out saved edges:
a=[]
And save the to be drawed edges:
var slope = ((head.y)-(tail.y))/((head.x)-(tail.x))
a.push({x1:tail.x, y1:tail.y, x2:head.x, y2:head.y, m:slope})
So, hover's event function is:
hover: function(e) {
var pos = $(canvas).offset();
var x = e.pageX-pos.left
var y = e.pageY-pos.top
_mouseP = arbor.Point(e.pageX-pos.left, e.pageY-pos.top)
for (var i = 0; i<a.length; i++) {
if ( (_mouseP.x-a[i].x1)) == (a[i].m* (_mouseP.y-a[i].y1)) )
console.log("This is an edge)
},
Second approach
What about going for jQuery? So something like:
$("anyDrawedOnCanvasStuff").hover(function(){}
would trigger events automatically. However I don't think this as possible, is it?
I quite completed first approach, but something weird is happening with the saved points in a array, they're all double and obtained mouse points happened to be integer. And also, they don't even get close to complete the formula's logic.
In the following fiddle, you can click and drag around the image, and it will not be able to exit the blue border. By clicking the red and green rectangles, you can rotate the image. However when you click and drag a rotated object, the image does not follow the mouse. I would like the image to follow the mouse even if it is rotated.
http://jsfiddle.net/n3Sn5/
I think the issue occurs within my move function
move = function (dx, dy)
{
nowX = Math.min(boundary.attr("x")+boundary.attr("width")-this.attr("width"), this.ox + dx);
nowY = Math.min(boundary.attr("y")+boundary.attr("height")-this.attr("height"), this.oy + dy);
nowX = Math.max(boundary.attr("x"), nowX);
nowY = Math.max(boundary.attr("y"), nowY);
this.attr({x: nowX, y: nowY });
}
One thing to notice is that when you click and drag a rotated object, after you release your mouse click, if you rotate the image, it snaps to where your mouse was when you released the mouse click, even obeying the boundary.
I was able to get the rotated image to drag with the mouse previously, but by adding the boundary rectangle, i had to use a more complex approach.
If anyone has an idea of what I need to change, I would be very grateful!
Thanks!
The required output can be achieved in a bit different way. Please check the fiddle at http://jsfiddle.net/6BbRL/. I have trimmed to code to keep the basic parts for demo.
var paper = Raphael(0, 0, 475, 475),
boxX = 100,
boxY = 100,
boxWidth = 300,
boxHeight = 200,
// EDITED
imgWidth = 50,
imgHeight = 50,
box = paper.rect(boxX, boxY, boxWidth, boxHeight).attr({fill:"#ffffff"}),
// EDITED
html5 = paper.image("http://www.w3.org/html/logo/downloads/HTML5_Badge_512.png",boxX+boxWidth-imgWidth,boxY+boxHeight-imgHeight,imgWidth,imgHeight)
.attr({cursor: "move"}),
elementCounterClockwise = paper.rect(180, 0, 50, 50).attr({fill:"#ff5555", cursor:"pointer"}),
elementClockwise = paper.rect(250, 0, 50, 50).attr({ fill: "#55ff55", cursor: "pointer" }),
boundary = paper.rect(50,50,400,300).attr({stroke: '#3333FF'}),
transform,
// EDITED
xBound = {min: 50 + imgWidth/2, max: 450 - imgWidth/2},
yBound = {min: 50 + imgHeight/2, max: 350 - imgHeight/2};
start = function (x, y) {
// Find min and max values of dx and dy for "html5" element and store them for validating dx and dy in move()
// This is required to impose a rectagular bound on drag movement of "html5" element.
transform = html5.transform();
}
move = function (dx, dy, x, y) {
// To restrict movement of the dragged element, Validate dx and dy before applying below.
// Here, dx and dy are shifts along x and y axes, with respect to drag start position.
// EDITED
var deltaX = x > xBound.max && xBound.max - x || x < xBound.min && xBound.min - x || 0;
deltaY = y > yBound.max && yBound.max - y || y < yBound.min && yBound.min - y || 0;
this.attr({transform: transform + 'T'+ [dx + deltaX, dy + deltaY]});
}
up = function () {
};
html5.drag(move, start, up);
elementClockwise.click(function() {
html5.animate({transform: '...r90'}, 100);
})
elementCounterClockwise.click(function() {
html5.animate({transform: '...r-90'}, 100);
})
Use of '...' to append a transformation to the pre-existing transformation state (Raphael API) is important for the rotational issue. While, for translating the element on drag requires absolute translation, which neglects the rotational state of the element while translating the element.
//EDIT NOTE
Drag bounding is worked on and updated. However, there remains an issue with incorporating the difference between mouse position and image center.
I can help you with your rotation and drag problem, you need to store the rotation and apply it after you have moved the object.
elementClockwise.node.onclick = function()
{
html5.animate({'transform': html5.transform() +'r90'}, 100, onAnimComplete);
}
elementCounterClockwise.node.onclick = function()
{
html5.animate({'transform': html5.transform() +'r-90'}, 100, onAnimComplete);
}
function onAnimComplete(){
default_transform = html5.transform();
}
At present I can't get the boundary to work, but will have a try later.
http://jsfiddle.net/n3Sn5/2/
I have an svg map with a g element container.
inside the g element I have items with x, y positions.
I am trying to implement a mouse wheel zoom that pans the g element so that the object under the mouse is always under the mouse. similar to the way Google maps pans the map when zooming via the mouse wheel so that you zoom to the mouse position.
I have exhausted all searches and tried many different ways to calculate out the mouse position verses the g element position.
I've tried:
var xPan = (mouse.x - (matrix.scale * mouse.x)) - matrix.panX;
var yPan = (mouse.y - (matrix.scale * mouse.y)) - matrix.panY;
pan(xPan, yPan);
I had an similar problem some time ago, with the difference that I am using canvas but because I use svg to save my transform matrix it may help you, if I post the necessary part of my code:
window.transform = svg.createSVGMatrix();
window.pt = svg.createSVGPoint();
transformedPoint = function (x, y) {
window.pt.x = x; window.pt.y = y;
return pt.matrixTransform(window.transform.inverse());
}
translate = function(dx, dy) {
window.transform = window.transform.translate(dx, dy);
}
scale = function (scaleX, scaleY) {
window.transform = window.transform.scaleNonUniform(scaleX, scaleY);
};
zoom = function (scaleX, scaleY, x, y) { //use real x and y i.e. mouseposition on element
var p = transformedPoint(x, y);
translate(x, y);
scale(scaleX, scaleY);
translate(-x, -y);
}
I hope you can use some of this code and get it to work for you
Credits going to Phrogz and his outstanding example here: https://stackoverflow.com/a/5527449/1293849
I have a rect rotated by 45degrees when I try and move it in a straight line using the normal move drag functionality it moves with the 45degree rotation. I've seen a lot of posts regarding this and that this is intended to work like this but I haven't found a simple way to fix this.
I know about the raphael.free_transform.js plugin but I don't need 90% of the script.
From other posts I know I'm supposed to use Math.atan2 but alas my Math skills aren't that great.
My current move function looks like this:
function (dx, dy) {
var att = this.type == "rect" ? {x: this.ox + dx, y: this.oy + dy} : {cx: this.ox + dx, cy: this.oy + dy};
this.attr(att);
for (var i = connections.length; i--;) {
r.connection(connections[i]);
}
r.safari();
}
You have to use "transform" method instead of simply changing x-y attrs.
var data = {};
var R = Raphael('raphael', 500, 500);
var rect = R.rect(100, 100, 100, 50).attr({fill: "#aa5555"}).transform('r45');
var default_transform = rect.transform();
var onmove = function (dx, dy) {
rect.transform(default_transform + 'T' + dx + ',' + dy);
};
var onstart = function () {};
var onend = function () {
default_transform = rect.transform();
};
rect.drag(onmove, onstart, onend);
I have created a live demo for you on JSfiddle: http://jsfiddle.net/pybBq/
Please note that you have to use big T letter in transform string (not small t) to make transformation absolute and not relative. Please read Raphael's docs on transform for more info: http://raphaeljs.com/reference.html#Element.transform