What I'm trying to do is simple: scale some SVG dots from scale(0) to scale(1) when a sibling element is hovered using vanilla js. They are the red ones in the demo
Here's the basic SVG setup
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
x="0px" y="0px" viewBox="0 0 720 576" style="enable-background:new 0 0 720 576;" xml:space="preserve">
<style type="text/css">
.st3 {
fill:red;
}
* {
-webkit-transition:.3s;
transition:.3s;
}
</style>
<g id="Layer_4">
<!-- Shield -->
<path class="st8" d="M601,304.7c-32.4-15.4-68.6-24-106.8-24c-40.4,0-78.5,9.6-112.3,26.6c4.9,79.7,41.9,146.7,109.5,187.6
C559.8,454.1,597,385.6,601,304.7z" />
<path class="st9" d="M420.1,328.7c2.1-4.7,32.5-23.9,72.5-23.9c39.9,0,73.1,20,75.5,24.3c2.4,4.3,5.7,40-12.7,74.6
c-19.7,36.9-53.5,50.1-61.8,50.4c-6.4,0.2-41.8-14.3-62.5-51.6C411.5,367.4,418,333.4,420.1,328.7z" />
<circle class="st10" cx="494.9" cy="373.3" r="35.5" />
</g>
<g id="Layer_8">
<!-- Dots on shield -->
<circle class="st3" cx="578.8" cy="316.2" r="4.6" />
<circle class="st3" cx="543.4" cy="346.2" r="4.6" />
<circle class="st3" cx="505" cy="375.5" r="4.6" />
</g>
</svg>
The issue is that SVG scales based on the origin location, not the current location, thus when a transform is applied it moves the element in addition to scaling it. I am attempting to fix this situation by translating by the BBox() offset, scaling, then translating back but that only seemed to help and not entirely fix the issue.
var shield = document.getElementById("Layer_4"),
dots = document.querySelectorAll("#Layer_8 .st3");
toggleTransform(false);
shield.onmouseover = function () { toggleTransform(true); }
shield.onmouseout = function () { toggleTransform(false); }
function toggleTransform(bool) {
if (!bool) {
for (var i = 0; i < dots.length; i++) {
var box = dots[i].getBBox(),
cx = box.x + box.width / 10,
cy = box.y + box.height / 10;
//dots[i].setAttribute("transform", "translate(" + cx + " " + cy + ") scale(0) translate(" + cx + " " + cy + ")");
dots[i].style.WebkitTransform = "translate(" + cx + "px, " + cy + "px) scale(0) translate(" + -cx + "px, " + -cy + "px)";
}
} else {
for (var i = 0; i < dots.length; i++) {
var box = dots[i].getBBox(),
cx = box.x + box.width / 2,
cy = box.y + box.height / 2;
//dots[i].setAttribute("transform", "translate(0 0) scale(1) translate(0 0)");
dots[i].style.WebkitTransform = "translate(0, 0) scale(1) translate(0, 0)";
}
}
}
I tried using both setAttribute and CSS's transform (I couldn't get setAttribute to transition, presumably because it's not animatable by CSS) but couldn't get it with either. I've only been testing in Chrome
Anyone have an idea how I can scale, while not moving, red dots?
Here's the demo again if you missed it
Edit
I made a function based on RashFlash's answer to make it quite simple to use and also takes into account offsets and different transform origins
function scaleMe(elem, scaleX, scaleY, newOffsetX, newOffsetY, originX, originY) {
newOffsetX = null ? 0 : newOffsetX;
newOffsetY = null ? 0 : newOffsetY;
originX = null ? "center" : originX;
originY = null ? "center" : originY;
var bbox = elem.getBBox(),
cx = bbox.x + (bbox.width / 2),
cy = bbox.y + (bbox.height / 2),
tx = -cx * (scaleX - 1) + newOffsetX,
ty = -cy * (scaleY - 1) + newOffsetY;
if(originX === "left" || originX === "right") {
tx = newOffsetX;
}
if(originY === "top" || originY === "bottom") {
ty = newOffsetY;
}
var scalestr = scaleX + ',' + scaleY,
translatestr = tx + 'px,' + ty + 'px';
elem.style.WebkitTransformOrigin = originX + " " + originY;
elem.style.MozTransformOrigin = originX + " " + originY;
elem.style.msTransformOrigin = originX + " " + originY;
elem.style.transformOrigin = originX + " " + originY;
elem.style.WebkitTransform = "translate(" + translatestr + ") scale(" + scalestr + ")";
elem.style.MozTransform = "translate(" + translatestr + ") scale(" + scalestr + ")";
elem.style.msTransform = "translate(" + translatestr + ") scale(" + scalestr + ")";
elem.style.transform = "translate(" + translatestr + ") scale(" + scalestr + ")";
}
Updated to work with modern browsers that support transform-box
Previously, this approach worked only in Chrome. But spec changes to how transform-origin works, and the addition of transform-box now means that this works in more browsers (currently Chrome, FF, and Opera).
You can actually achieve this effect without JS.
.st3 {
fill: red;
-webkit-transform: scale(1);
-webkit-transform-origin: 50% 50%;
-webkit-transition:.3s;
transform: scale(1);
transform-origin: 50% 50%;
transition:.3s;
transform-box: fill-box;
}
#Layer_4:hover + g .st3 {
-webkit-transform: scale(2);
-webkit-transform-origin: 50% 50%;
-webkit-transition:.3s;
transform: scale(2);
transform-origin: 50% 50%;
transition:.3s;
}
Demo here
if i am not wrong, you want to scale the dots along their center, dots remain their current position and just gets bigger.
if this you want, then following code will help you
var bbox=elementNode.getBBox();
var cx=bbox.x+(bbox.width/2),
cy=bbox.y+(bbox.height/2); // finding center of element
var scalex=1.5, scaley=1.5; // your desired scale
var saclestr=scalex+','+scaley;
var tx=-cx*(scalex-1);
var ty=-cy*(scaley-1);
var translatestr=tx+','+ty;
elementNode.setAttribute('transform','translate('+translatestr+') scale('+saclestr+')');
So what i did, i first translate the dot and than scale it. i use following formula as described in
Transforming Coordinate system
translate(-centerX*(factor-1), -centerY*(factor-1))
scale(factor)
An easier way to do this that does not involve a bunch of geometry is to put the item to be scaled and translated into a parent group ('g').
Then, you apply the translation to the parent group and the scale to the element itself.
var trasnstr = x + ',' + y;
var scalestr = scaleX + ',' + scaleY;
parentElement.setAttribute('transform', 'translate(' + trasnstr + ')');
element.setAttribute('transform', 'scale(' + scalestr + ')');
This will automatically calculate and set transform-origin for any SVG element.
// mainSvgElement is SVG element itself
// svgChildElement is any path, rect, circle etc. inside SVG element
var setTransformOrigin = function(mainSvgElement, svgChildElement) {
var mainRect = mainSvgElement.getBoundingClientRect();
var childRect = svgChildElement.getBoundingClientRect();
var originX = (((childRect.left - mainRect.left) + (childRect.width * 0.5)) / mainRect.width) * 100;
var originY = (((childRect.top - mainRect.top) + (childRect.height * 0.5)) / mainRect.height) * 100;
svgChildElement.style.transformOrigin = originX + "% " + originY + "%";
};
setTransformOrigin(mainSvgElement, svgChildElement);
// set scale now / or you can set in css too
svgChildElement.style.transform = "scale(1.5)";
(function() {
var mainSvgElement = document.querySelector("svg");
var svgChildElement = mainSvgElement.querySelector("path");
// mainSvgElement is SVG element itself
// svgChildElement is any path, rect, circle etc. inside SVG element
var setTransformOrigin = function(mainSvgElement, svgChildElement) {
var mainRect = mainSvgElement.getBoundingClientRect();
var childRect = svgChildElement.getBoundingClientRect();
var originX = (((childRect.left - mainRect.left) + (childRect.width * 0.5)) / mainRect.width) * 100;
var originY = (((childRect.top - mainRect.top) + (childRect.height * 0.5)) / mainRect.height) * 100;
svgChildElement.style.transformOrigin = originX + "% " + originY + "%";
};
setTransformOrigin(mainSvgElement, svgChildElement);
// set scale now / or you can set in css too
svgChildElement.addEventListener("mouseenter", function() {
svgChildElement.style.transform = "scale(1.5)";
});
svgChildElement.addEventListener("mouseleave", function() {
svgChildElement.style.transform = "scale(1)";
});
})();
svg {
width: 100%;
border: 2px solid red;
}
path {
cursor: pointer;
transition: transform 1s;
}
Bring your mouse over on the shape:
<svg class="tb-graph" viewBox="0 0 1006 684" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M574.618 66.3322C575.377 63.1066 573.378 59.87 570.137 59.1784C512.776 46.9376 452.991 52.4821 398.793 75.1494C344.594 97.8167 298.663 136.486 267.096 185.919C265.312 188.711 266.213 192.407 269.042 194.132L357.225 247.895C360.055 249.62 363.738 248.718 365.56 245.95C384.451 217.254 411.493 194.793 443.273 181.502C475.052 168.211 510.032 164.732 543.728 171.435C546.978 172.082 550.207 170.093 550.966 166.867L574.618 66.3322Z" fill="#005453" stroke="#012020" stroke-width="2" />
https://codepen.io/animatedcreativity/pen/qBKXQKZ
Related
My Objective is:
1) Instead of rect tag my aim is to make the rect object remoldable(as in it can be changed to any polygon when the vertices of the rect shape is clicked twice the side should be added by 1 , so by default it is 4 side , when the user clicks on a vertex then 1 more edge should be added , so it will become pentagon-5sides)
2) The text inside the g tag shape should wrap and be responsive it hsould become bigger wrt to the gtag when g tag becomes bigger and viceversa
ts code
drop(event:any){
event.preventDefault();
let data = event.dataTransfer.getData("text"),
x = (event.clientX - event.srcElement.parentElement.offsetLeft - 80),
y = (event.clientY - event.srcElement.parentElement.offsetTop),
inner = `<g>
<rect
class = "draggable"
fill = "#e24301"
fill-opacity = "0.2"
stroke = "#24301"
stroke-width = "1.5"
style = "pointer-events:inherit"
x= inherit
y= inherit
width='${this.zoneAttribute.minWidth}'
height='${this.zoneAttribute.minHeight}'
id='${data}
stroke-dasharray="none"
onContextMenu="return false;">
</rect>
<text
x= inherit
y= inherit
style='user-select: none'>
${data}
</text>
<text
style='cursor:pointer; user-select: none'
class="close"
x= inherit
y= inherit
>X
</text>
<text
style='user-select: none'
class="temp-display"
x= inherit
y= inherit
>
</text>
</g>`,
close = document.getElementByClassName('close');
(<HTMLDivElement>event.target.parentElement.querySelector
('.from-them')).insertAdjacentHTML('beforeend',inner);
for(let i=0; i<close.length; i++){
close[i].addEventListner('click',(event: Event) => {});
}
if(event.target.getElementById(data)){
this.changeDimension(event.currentTarget.lastElementChild);
}
(<HTMLDivElement>document.getElementById(''+ (data) + '').style.display = 'none';
}
changeDimension(event:any){
interact(event.firstElementChild)
.draggable({
inertia: true,
restrict: {
restriction: '.from-them',
endonly: true,
elementRect: {top:0, left:0, bottom:1, right:1}
},
autoscroll: true,
onmove: this.dragMoveListner,
onend: function(event){
const textEl = event.target.querySelector('.close');
textEl && (textEl.textContent =
'moved a distance of'
+(Math.sqrt(Math.pow(event.pageX - event.x0, 2)+
Math.pow(event.pageY - event.y0, 2) | 0))
.toFixed(2) + 'px');
}
})
.ressizable({
edges: {left: true, right:true, bottom:true, top:true}
})
.on('resizemove',(event:any) =>{
let target = event.target,
x = (parseFloat(target.getAttribute('data-x')) || 0),
y = (parseFloat(target.getAttribute('data-y')) || 0)
target.style.width = event.rect.width < this.zoneAttribute.minWidth ? this.zoneAttribute.minWidth :
event.rect.width + 'px';
target.style.width = event.rect.width < this.zoneAttribute.minHeight ? this.zoneAttribute.minHeight :
event.rect.height + 'px';
x += event.deltaRect.left;
y += event.deltaRect.top;
target.style.webKitTransform = target.style.transform = 'translate('+ x + 'px,' + y + 'px)';
target.nextElementSibling.style.transform = 'translate('+ x + 'px,' + y + 'px)';
target.nextElementSibling.nextElementSibling.style.transform = 'translate('+ x + 'px,' + y + 'px)';
target.nextElementSibling.nextElementSibling.nextElementSibling.style.transform = 'translate('+ x + 'px,' + y + 'px)';
target.setAttribute('data-x', x);
target.setAttribute('data-y', y);
});
}
dragMoveListner(event:any){
const target = event.target,
x = (parseFloat(target.getAttribute('data-x')) || 0) + event.dx,
y = (parseFloat(target.getAttribute('data-y')) || 0) + event.dy;
target.style.webKitTransform = target.style.transform = 'translate('+ x + 'px,' + y + 'px)';
target.setAttribute('data-x', x);
target.setAttribute('data-y', y);
target.nextElementSibling.style.transform = 'translate('+ x + 'px,' + y + 'px)';
target.nextElementSibling.nextElementSibling.style.transform = 'translate('+ x + 'px,' + y + 'px)';
target.nextElementSibling.nextElementSibling.nextElementSibling.style.transform = 'translate('+ x + 'px,' + y + 'px)';
}
html code
<svg xmlns="http://www.w3.org/2000/svg" id="imgpos" viewBox="0 0 80 80"
class="form-them" (dragover)="allowDrop($event)" (drop)="drop($event)"
[innerHTML]= "abcsvg | safeHtml" [ngStyle]="{'background-
image':'url('+url+')', 'background-repeat':'no-repeat', 'background-
position':'center','background-size':'contain'}">
__________________________________
| _______ ______ |
| | | | |--> g tag |----> svg image
| |_______| |______| |
|__________________________________|
For ref the snippet from the above ts code which is for the g tag
inner = `<g>
<rect
class = "draggable"
fill = "#e24301"
fill-opacity = "0.2"
stroke = "#24301"
stroke-width = "1.5"
style = "pointer-events:inherit"
x='${x}'
y='${y}'
width='${this.zoneAttribute.minWidth}'
height='${this.zoneAttribute.minHeight}'
id='${data}
stroke-dasharray="none"
onContextMenu="return false;">
</rect>
<text
x='${x+40}'
y='${y+40}'
style='user-select: none'>
${data}
</text>
<text
style='cursor:pointer; user-select: none'
class="close"
x='${x+80}'
y='${y+20}'
>X
</text>
<text
style='user-select: none'
class="temp-display"
x='${x+40}'
y='${y+25}'
>
</text>
</g>`
I'm trying to scale my SVG with g.animate({ transform: "s2.5,2.5," + bbox.cx + "," + bbox.cy }, 0); and then animate wheelAnimation(bbox.cx, bbox.cy, 1500);
var i = 0;
function wheelAnimation(cx, cy, speed){
i++;
g.animate(
{ transform: "r360," + cx + ',' + cy}, // Basic rotation around a point. No frills.
speed, // Nice slow turning rays
function(){
if(i == 5)
speed = 5000;
g.attr({ transform: 'rotate(0 ' + cx + ' ' + cy}); // Reset the position of the rays.
wheelAnimation(cx,cy, speed); // Repeat this animation so it appears infinite.
}
);
}
But my SVG didn't scaling. It's only rotates. If I remove rotation - SVG scaling. How to combine it to immediately scale and then animate rotation?
Plunker example
I've never used Snap.svg but you might try this:
var i = 0;
function wheelAnimation(cx, cy, speed, scale){
i++;
g.attr({ transform: "r0 " + cx + " " + cy + " s" + scale + "," + scale + "," + cx + "," + cy }); //Reset + Scale setup
g.animate({
transform: "r360," + cx + "," + cy + " s" + scale + "," + scale + "," + cx + "," + cy }, // Basic rotation around a point. No frills.
speed, // Nice slow turning rays
function(){
if(i == 5)
speed = 5000;
wheelAnimation(cx, cy, speed, scale); // Repeat this animation so it appears infinite.
}
);
}
Hope this helps you :)
See Plunkr
I have a SVG shape (which is quite complex, I have made it simple for the sake of understanding) which I need to transform. My requirement is,
When mouseover, The group should be scaled to 2x
When mouseout, group should scale back to 1x
When dragging the group scale should be preseved
So far, I have managed to do all the parts, except one issue. After I drag the element when I try to mouseover the group it reverts to its original location. I cannot understand why it happens. Here is a working fiddle. Can anyone help me out?
index.html
<svg width="400" height="400" style="background-color: red">
<g id="op" class="operator" transform="translate(0,0)">
<circle class="head" cx="50" cy="50" r="20" style="fill: yellow"></circle>
<circle cx="40" cy="40" r="10" style="fill: blue"></circle>
<circle cx="60" cy="40" r="10" style="fill: blue"></circle>
</g>
</svg>
script.js
d3.selectAll('.operator')
.on('mouseenter', function () {
console.log('Mouse Enter');
var c = d3.select(this).select('.head');
var x = c.attr('cx');
var y = c.attr('cy');
var scale = 2;
var scaleX = -1 * x * (scale - 1);
var scaleY = -1 * y * (scale - 1);
d3.select(this).attr('transform', 'translate(' + scaleX + ',' + scaleY + ')' + 'scale(' + scale + ')');
})
.on('mouseleave', function () {
console.log('Mouse Leave');
var c = d3.select(this).select('.head');
var x = c.attr('cx');
var y = c.attr('cy');
var scale = 1;
var scaleX = -1 * x * (scale - 1);
var scaleY = -1 * y * (scale - 1);
d3.select(this).attr('transform', 'translate(' + scaleX + ',' + scaleY + ')' + 'scale(' + scale + ')');
})
.call(d3.behavior.drag()
.origin(function () {
var t = d3.select(this);
return {
x: d3.transform(t.attr("transform")).translate[0],
y: d3.transform(t.attr("transform")).translate[1]
};
})
.on('drag', function () {
var oldScale = d3.transform(d3.select(this).attr('transform')).scale;
d3.select(this).attr('transform', 'translate(' + d3.event.x + ',' + d3.event.y + ')scale(' + oldScale + ')');
}))
As #PhilAnderson said, you shouldn't be mixing translate and cx/cy. In fact, the way you are nesting elements, you should only be translating. Translate your g within the SVG and then translate your circles within the g. Correcting that, things get much simpler:
<!DOCTYPE html>
<html>
<head>
<script data-require="d3#3.5.3" data-semver="3.5.3" src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.3/d3.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body>
<svg width="400" height="400" style="background-color: red">
<g id="op" class="operator" transform="translate(50,50)">
<circle class="head" r="20" style="fill: yellow"></circle>
<circle transform="translate(-10,0)" r="10" style="fill: blue"></circle>
<circle transform="translate(10,0)" r="10" style="fill: blue"></circle>
</g>
</svg>
<script>
d3.select('.operator')
.on('mouseenter', function() {
console.log('Mouse Enter');
var self = d3.select(this),
xy = d3.transform(self.attr('transform')).translate,
scale = 2;
self.attr('transform', 'translate(' + xy[0] + ',' + xy[1] + ')' + 'scale(' + scale + ')');
})
.on('mouseleave', function() {
console.log('Mouse Leave');
var self = d3.select(this),
xy = d3.transform(self.attr('transform')).translate,
scale = 1;
self.attr('transform', 'translate(' + xy[0] + ',' + xy[1] + ')' + 'scale(' + scale + ')');
})
.call(d3.behavior.drag()
.on('drag', function() {
var self = d3.select(this),
oldScale = d3.transform(self.attr('transform')).scale;
self.attr('transform', 'translate(' + d3.event.x + ',' + d3.event.y + ')scale(' + oldScale + ')');
}))
</script>
</body>
</html>
It looks like you're confusing the cx and cy attributes with the translate.
In mouseenter and mouseleave you move the shape according to the values of cx and cy, but in the drag event you simply translate using the x and y values of the event.
One way of fixing this would be to set the cx and cy attributes in your drag event, although tbh it would be better to settle for one approach and stick to it throughout.
What I'm trying to accomplish is when the window is resized, the blurred image is resized as well. For some reason the code is not working. Can someone spot what is wrong and what I need to do to correct the code. Thanks.
CSS -
/* ------- BLUR BEHIND MESSAGE HOLDER CONTAINER SETTINGS ------- */
img.clipphoto {
/*--- CLIP SETTINGS: top, right, bottom, left ---*/
clip: rect(18px,770px,600px,240px);
position: absolute;
-webkit-filter: blur(10px);
-moz-filter: blur(10px);
-o-filter: blur(10px);
-ms-filter: blur(10px);
filter: blur(10px);
}
JS -
window.addEventListener('resize', function(event){
var vInnerHeight= window.innerHeight;
var t = "18";
var r = "770";
var b = vInnerHeight-140;
var l = "240";
var clipString = "rect(" + t + "px " + r + "px " + b + "px " + l + "px)";
document.getElementByClassName(clipphoto).style.clip = clipString;
HTML -
<!-- blurred photo of pix -->
<img src="images/image1.png" width="1200" height="620" alt="" class="clipphoto">
There is no getElementByClassName() function. It's getElementsByClassName() (plural).
And you want the string "clipphoto", not the (non-existant) variable named clipphoto:
var clipString = "rect(" + t + "px, " + r + "px, " + b + "px, " + l + "px)";
document.getElementsByClassName('clipphoto')[0].style.clip = clipString;
Believe the values should be comma separated, not space separated
var clipString = "rect(" + t + "px," + r + "px," + b + "px," + l + "px)";
document.getElementsByClassName('clipphoto')[0].style.clip = clipString;
Edit: incorporated class accessor errror by Paul Roub too
I'm getting absolutely positioned rotated elements position with jQuery .position() method, then setting position-related attributes (top, left) with jQuery .css(pos), where pos is the data returned by .position(). I think it'll leave the element in it's place, but elements position is changing.
How can I use set rotated elements position, so that it'll be placed as expected? Maybe there is a coefficient depended on angle that changes position?
I'm testing in Google Chrome v.9, Windows XP.
HTML
<div id="container">
<div id="element">
<img src="http://t0.gstatic.com/images?q=tbn:ANd9GcS0Fawya9MVMez80ZusMVtk_4-ScKCIy6J_fg84oZ37GzKaJXU74Ma0vENc"/>
</div>
</div>
CSS
#container {
position: relative;
border: 1px solid #999;
padding: 5px;
height: 300px;
width:300px;
}
#element {
position: absolute;
top:50px;
left: 60px;
width: auto;
border: 1px solid #999;
padding: 5px;
-webkit-transform: rotate(45deg);
-moz-transform: rotate(45deg);
}
JS
$(document).ready(function(){
var $el = $('#element'),
// getting position
pos = $el.position();
alert(pos.left + '/' + pos.top);
// alerts 37/11
// setting css position attributes equal to pos
$el.css(pos);
// re-getting position
pos = $el.position();
alert(pos.left + '/' + pos.top);
// alerts 14/-28
});
View it http://jsfiddle.net/Antaranian/2gVL4/
// Needed to read the "real" position
$.fn.adjustedPosition = function() {
var p = $(this).position();
return {
left: p.left - this.data('dx'),
top: p.top - this.data('dy')
}
};
$(function() {
var img = $('img'),
pos;
// Calculate the delta
img.each(function() {
var po = $(this).position(), // original position
pr = $(this).addClass('rot').position(); // rotated position
$(this).data({
dx: pr.left - po.left, // delta X
dy: pr.top - po.top // delta Y
});
});
// Read the position
pos = img.adjustedPosition();
alert(pos.left + '/' + pos.top);
// Write the position
img.css(pos);
// Read the position again
pos = img.adjustedPosition();
alert(pos.left + '/' + pos.top);
});
Live demo: http://jsfiddle.net/2gVL4/4/
So what is going on here:
The CSS code that rotates the image is stored inside a special CSS class. I do this because I want to read the original position of the image (before rotating). Once I read that original position, I apply the .rot class, and then read the position again to calculate the difference (delta), which is stored inside the element's data().
Now, I can read the position via the custom method adjustedPosition (which is defined above). This method will read the position of the element and then subtract the delta values stored inside the data() of the element.
To write the position, just use the css(pos) method like normally.
Had similar problem. There is simple solution (not elegant, but working):
set current angle to 0
read X/Y position
revert angle back to its value
var temp = $(this).position();
temp.angle = getRotationDegrees( $(this) ); // remember current angle
rotateObject($(this), 0); // set angle to 0
temp.left = Math.round($(this).position().left); // proper value
temp.top = Math.round($(this).position().top); // proper value
// revert back the angle
rotateObject($(this), temp.angle);
Used functions:
function rotateObject(obj, angle) {
obj.css({ '-webkit-transform': 'rotate(' + angle + 'deg)'});
obj.css({ '-moz-transform': 'rotate(' + angle + 'deg)'});
obj.css({ '-ms-transform': 'rotate(' + angle + 'deg)'});
obj.css({ 'msTransform': 'rotate(' + angle + 'deg)'});
obj.css({ '-o-transform': 'rotate(' + angle + 'deg)'});
obj.css({ '-sand-transform': 'rotate(' + angle + 'deg)'});
obj.css({ 'transform': 'rotate(' + angle + 'deg)'});
}
function getRotationDegrees(obj) {
var matrix = obj.css("-webkit-transform") ||
obj.css("-moz-transform") ||
obj.css("-ms-transform") ||
obj.css("-o-transform") ||
obj.css("transform");
if(matrix !== 'none') {
var tr;
if (tr = matrix.match('matrix\\((.*)\\)')) {
tr = tr[1].split(',');
if(typeof tr[0] != 'undefined' && typeof tr[1] != 'undefined') {
var angle = Math.round(Math.atan2(tr[1], tr[0]) * (180/Math.PI));
}else{
var angle = 0;
}
}else if(tr = matrix.match('rotate\\((.*)deg\\)')){
var angle = parseInt(tr[1]);
}
} else { var angle = 0; }
return (angle < 0) ? angle + 360 : angle;
}