JQuery SVG plugin: get space cordinate at page position - jquery-svg

I've created an SVG canvas inline in HTML, dynamically using keith-wood jquery plugin.
I've used the viewBox attribute in the SVG element to scale the contents of the SVG canvas.
Inside the SVG canvas, I have a rectangle drawn, with a repeated pattern (tiles), each a 1x1 unit.
An 800x800 board:
var svg = $(containerDiv).svg('get');
svg.configure({viewBox: minX + "" + minY + "" + width + "" + height});
var pat1 = svg.pattern('pat1', 0, 0, 1, 1, {patternUnits: 'userSpaceOnUse'});
var rectTile = svg.rect(pat1, 0, 0, 1, 1);
var rectBoard = svg.rect(0, 0, 800, 800, {fill: 'url(#pat1)'});
When the user hovers over one of the elements inside the SVG, I'd like to convert the mouse event's pageX and pageY pixel coordinates to the coordinates of the tile, given the viewBox scaling. So if the user hovers over the first tile, I'd like {x: 0, y: 0} returned, given e.pageX and e.pageY where e is the mousemove jquery event object.
How do I calculate this?
Thanks

Related

jCanvas method drawRect() position issue

I have a problem with jCanvas which is a framework drawing canvas and jquery.
When I set x = 0 , y = 0 The .drawRect output should be same as the pure javascript result.
I tried the document and google but I did not find anything to solve this.
Screen shoot:
Pure js result
jCanvas result
Please help me.
Many thanks.
// Pure javascript
var canvas = document.getElementsByTagName('canvas')[0];
var ctx = canvas.getContext("2d");
ctx.fillStyle = 'blue';
ctx.fillRect(0, 0, 100, 100);
// jCanvas
$('canvas').drawRect({
fillStyle: '#000',
x: 0, y: 0,
width: 100,
height: 100
});
To run this code, please copy and pass to this sanbox.
https://projects.calebevans.me/jcanvas/sandbox/
From jCanvas documentation:
The [.drawRect's] fromCenter property determines if a rectangle’s x and y properties lie at its center (as opposed to its top-left corner). This property is true by default.
So yeah. Your X and Y with jCanvas, refer to the center of the rectangle, unlike canvas' fillRect X and Y, which refer to the top left corner of the rectangle.

d3.event.x does not get the x cursor's position

I do not understand why d3.event.x == NaN and not the x cursor's position when I use d3.behavior.drag().
I used d3.event.sourceEvent.offsetX instead, but it works only with Chrome (e.g. not with Firefox).
The side effect can be seen here :
http://gloumouth1.free.fr/test/Nature
The user can move the "frequency cursors" only with Chrome.
Any idea ?
G.
From my point of view, d3.js is terrible documented library. Sorry Mike Bostock, but personally for me it's sometimes absolutely impossible to find "why", without debugging the source and examples.
Now, the answer:
THE FIRST
d3 can create and recognize own events like d3.event.x properly in any browser, BUT you should draw draggable interface elements INSIDE <g></g>! You should not place circles, rectangles or whatever you going to drag later precisely in <svg></svg>. This is not documented.
Example:
<svg>
<rect></rect> // you can not use 'd3.event.x' or 'd3.event.y' for this element.
// for this element is possible to use 'd3.event.sourceEvent.x' in Chrome
// and 'd3.event.sourceEvent.offsetX' in Firefox.
// d3.event.x === NaN, d3.event.y === NaN in any browser
<g>
<rect></rect> // 'd3.event.x' and 'd3.event.y' will work for this element
</g>
<svg>
THE SECOND
The <g></g> wrapper should store the data([{x:..., y:...}]) even you not need it. Without the data in <g></g>, the .origin() method will not work properly and element will jump unpredictably under cursor over the window.
FINALLY
Lets combine all knowledge about dragging in one example:
var draggable = d3.behavior.drag()
.origin(Object) // the sequence function(d){return(d);} in not necessary
.on("drag", drg);
var board = d3.select("body").append("svg:svg").attr({width: 500, height: 500});
var wrap = board.append("svg:g")
.data([{x: 100, y: 100}]); // this is the coordinates of draggable element
// they should be stored in <g></g> wrapper as the data
// IMPORTANT! There is no wrap.data().enter() sequence
// You should not call .enter() method for <g></g> data,
// but nested elements will read the data() freely
var handle = wrap.append("svg:circle")
.attr({
cx: function(d){return(d.x);}, // position of circle will be stored in the data property of <g> element
cy: function(d){return(d.x);},
r: 30,
fill: "gray",
stroke: "black"
}).call(draggable);
function drg(d){
// now d3.event returns not a mouse event,
// but Object {type: "drag", x: ..., y: ..., dx: ..., dy: ...}
d3.select(this).attr({
// reposition the circle and
// update of d.x, d.y
cx: d.x = Math.max(0, Math.min(500 - 60, d3.event.x)), // 500 - width of svg, 60 - width of circle
cy: d.y = Math.max(0, Math.min(500 - 60, d3.event.y)) // 500 - height of svg, 60 - height of circle
});
}
DEMO: http://jsfiddle.net/c8e2Lj9d/4/

Rotate image on its own center kineticJS

I'm trying to rotate an image added to my canvas using KineticJS.
I got it almost working.
I know I need to set the offset to 'move' the rotation point, that part is working.
But it is also moving to that location of the offset.
After doing some rotating I can drag my image to another location in the canvas and continue rotating around its own center.
I don't want to rotate the whole canvas, because I have multiple images on a layer.
The relevant code:
function rotateLayer() {
// Rotate bird image
var rotation = 15;
// Set rotation point:
imageDict[1].setOffsetX(imageDict[1].width() / 2);
imageDict[1].setOffsetY(imageDict[1].height() / 2);
// rotation in degrees
imageDict[1].rotate(rotation);
imageDict[1].getLayer().draw();
}
A working demo is on jsfiddle: http://jsfiddle.net/kp61vcfg/1/
So in short I want the rotation but not the movement.
How you want to rotate without movement?
KineticJS rotate objects relative it's "start point" . For example for Kinetic.Rect start points is {0, 0} - top left corner. You may move such "start point" to any position with offset params.
After a lot of trail and error I found the solution.
The trick is to set the offset during load to the half width and height to set the rotation point to the middle of the image AND don't call image.cache:
function initAddImage(imgId, imgwidth, imgheight) {
var imageObj = new Image();
imageObj.src = document.getElementById(imgId).src;
imageObj.onload = function () {
var image = new Kinetic.Image({
image: imageObj,
draggable: true,
shadowColor: '#787878',
shadowOffsetX: 2,
shadowOffsetY: 2,
width: imgwidth,
height: imgheight,
x: 150, // half width of container
y: 150, // half height of container
offset : {x : imgwidth / 2, y : imgheight / 2}, // Rotation point
imgId: imgId
});
layer.add(image);
//image.cache();
layer.draw();
imageDict[currentLayerHandle] = image;
currentLayerHandle++;
};
}
I've updated my demo to a working version:
http://jsfiddle.net/kp61vcfg/2/

How to get the coordinates of the corners of a rotated element?

I am trying to get the corners of a rotated element in kineticjs. I found a similiar thread for fabricjs and would like to know if there is a similar solution for kineticjs.
Find the coordinates of the corners of a rotated object in fabricjs
I have a layer with an image in it, the image has a negative offset so the origin point is in the center. The layer gets the rotation.
var layer = new Kinetic.Layer({rotationDeg: 45});
var image = new Kinetic.Image({width: 100, height: 100, offsetX: -50, offsetY: -50});
layer.add(Image);
Thank you
You can use some trigonometry:
function findRotatedCornerXY(rectX,rectY,rectWidth,rectHeight,degreeAngle,
originalCornerX,originalCornerY){
// calc rotation centerpoint
var cx=rectX+rectWidth/2;
var cy=rectY+rectHeight/2;
// calc length from rect center to any rect corner
var r=Math.sqrt(rectWidth/2*rectWidth/2+rectHeight/2*rectHeight/2);
// calc unrotated angle from center to corner
var dx=originalCornerX-cx;
var dy=originalCornerY-cy;
var originalAngle=Math.atan2(dy,dx);
// calc new angle of rotated corner
var radianAngle=degreeAngle*Math.PI/180;
var newAngle=originalAngle+radianAngle;
// calc XY of rotated corner
var rx = cx + r * Math.cos(newAngle);
var ry = cy + r * Math.sin(newAngle);
// return the results
return({x:rx,y:ry});
}

Raphael playground effect and fill opacity

I've written the following code:
var w = 800;
var h = 600;
var paper = Raphael(0, 0, w, h);
paper.image("http://static.pourfemme.it/pfmoda/fotogallery/625X0/63617/borsa-alviero-martini-rodeo-drive.jpg", 0, 0, w, h);
var c = paper.circle(400, 300, 1);
c.attr({stroke: "#999", "stroke-width": w*2});
anim = Raphael.animation({r: w*2}, 6000);
c.animate(anim.delay(100));
( http://jsfiddle.net/qAgy7/ )
I need to visualize background image when the circle enlarges its radius, however I have the following problems:
I don't understand why the animation run slowly
Chrome render the effect in different way (I see a polygon not a circle like in
Firefox and IE)
Someone can help me?

Resources