admin管理员组文章数量:1315782
I have a 9x6 grid with 80 px squares.
<div class = "grid" style="width: 720px; height:480px; margin: auto; background-color: white;">
<style>
.grid {
background-image:
repeating-linear-gradient(#ccc 0 1px, transparent 1px 100%),
repeating-linear-gradient(90deg, #ccc 0 1px, transparent 1px 100%);
background-size: 80px 80px;
outline: 10px solid black;
}
</style>
I have an image that is 160px wide and 80px tall.
<img class="movable" src="stick.png" id="Stick" style="left: 256.5px; top: 168px;">
The user can drag the image and drop it onto the grid. It snaps into place perfectly, accounting for the position of the grid.
If the image is rotated using CSS, the snap is 40px off for both dimensions. I tried adding a parent div as a container and noticed that the origin of the image remains in the same place, no matter how it is rotated. Because of this, targ.style.left and targ.getBoundingClientRect().left are totally different values. I also tried rotating the image but moving the parent div - this results in the same behavior. Furthermore, the snap is off even more for larger images.
160px x 80px image is off by (40, -40)
80px x 240px image is off by (-80, 40)
80px x 400px image is off by (-160, 160)
function startDrag(e) {
// determine event object
if (!e) {
var e = window.event;
}
if(e.preventDefault) e.preventDefault();
// IE uses srcElement, others use target
targ = e.target ? e.target : e.srcElement;
if (targ.className != 'movable') {return};
// calculate event X, Y coordinates
offsetX = e.clientX;
offsetY = e.clientY;
// assign default values for top and left properties
if(!targ.style.left) { targ.style.left=offsetX-(e.target.getBoundingClientRect().width/2)};
if (!targ.style.top) { targ.style.top=offsetY-(e.target.getBoundingClientRect().height/2)};
// calculate integer values for top and left
// properties
coordX = parseInt(targ.style.left);
coordY = parseInt(targ.style.top);
drag = true;
// move div element
document.onmousemove=dragDiv;
return false;
}
function dragDiv(e) {
if (!drag) {return};
if (!e) { var e= window.event};
// var targ=e.target?e.target:e.srcElement;
// move div element
targ.style.left=coordX+e.clientX-offsetX+'px';
targ.style.top=coordY+e.clientY-offsetY+'px';
return false;
}
function stopDrag() {
drag=false;
let grid_offset = grid.getBoundingClientRect();
let item_offset = targ.getBoundingClientRect();
let xa = Math.abs(grid_offset.left - (80*Math.floor(parseInt(grid_offset.left)/80)));
let ya = Math.abs(grid_offset.top - (80*Math.floor(parseInt(grid_offset.top)/80)));
let snap = {
x: 80*Math.round((item_offset.left - xa)/80),
y: 80*Math.round((item_offset.top - ya)/80)
}
targ.style.left = snap.x + xa;
targ.style.top = snap.y + ya;
}
function rotate_item (e) {
e.preventDefault();
if (!e.target.classList.contains("movable")) return;
if (!e.target.style.rotate) e.target.style.rotate = "0deg";
let deg = e.target.style.rotate.slice(0,-3);
if (e.deltaY < 0) {
deg = parseInt(deg) + 90;
e.target.style.rotate = deg + "deg";
} else {
deg = parseInt(deg) - 90;
e.target.style.rotate = deg + "deg";
}
}
I suppose I could write a lengthy switch to account for all possible image sizes and orientations, or maybe add the difference between targ.style.left and targ.getBoundingClientRect().left, but I'm looking for a more elegant method and want to understand what's going on. What am I doing wrong here? What is the "proper" way to achieve this?
I have a 9x6 grid with 80 px squares.
<div class = "grid" style="width: 720px; height:480px; margin: auto; background-color: white;">
<style>
.grid {
background-image:
repeating-linear-gradient(#ccc 0 1px, transparent 1px 100%),
repeating-linear-gradient(90deg, #ccc 0 1px, transparent 1px 100%);
background-size: 80px 80px;
outline: 10px solid black;
}
</style>
I have an image that is 160px wide and 80px tall.
<img class="movable" src="stick.png" id="Stick" style="left: 256.5px; top: 168px;">
The user can drag the image and drop it onto the grid. It snaps into place perfectly, accounting for the position of the grid.
If the image is rotated using CSS, the snap is 40px off for both dimensions. I tried adding a parent div as a container and noticed that the origin of the image remains in the same place, no matter how it is rotated. Because of this, targ.style.left and targ.getBoundingClientRect().left are totally different values. I also tried rotating the image but moving the parent div - this results in the same behavior. Furthermore, the snap is off even more for larger images.
160px x 80px image is off by (40, -40)
80px x 240px image is off by (-80, 40)
80px x 400px image is off by (-160, 160)
function startDrag(e) {
// determine event object
if (!e) {
var e = window.event;
}
if(e.preventDefault) e.preventDefault();
// IE uses srcElement, others use target
targ = e.target ? e.target : e.srcElement;
if (targ.className != 'movable') {return};
// calculate event X, Y coordinates
offsetX = e.clientX;
offsetY = e.clientY;
// assign default values for top and left properties
if(!targ.style.left) { targ.style.left=offsetX-(e.target.getBoundingClientRect().width/2)};
if (!targ.style.top) { targ.style.top=offsetY-(e.target.getBoundingClientRect().height/2)};
// calculate integer values for top and left
// properties
coordX = parseInt(targ.style.left);
coordY = parseInt(targ.style.top);
drag = true;
// move div element
document.onmousemove=dragDiv;
return false;
}
function dragDiv(e) {
if (!drag) {return};
if (!e) { var e= window.event};
// var targ=e.target?e.target:e.srcElement;
// move div element
targ.style.left=coordX+e.clientX-offsetX+'px';
targ.style.top=coordY+e.clientY-offsetY+'px';
return false;
}
function stopDrag() {
drag=false;
let grid_offset = grid.getBoundingClientRect();
let item_offset = targ.getBoundingClientRect();
let xa = Math.abs(grid_offset.left - (80*Math.floor(parseInt(grid_offset.left)/80)));
let ya = Math.abs(grid_offset.top - (80*Math.floor(parseInt(grid_offset.top)/80)));
let snap = {
x: 80*Math.round((item_offset.left - xa)/80),
y: 80*Math.round((item_offset.top - ya)/80)
}
targ.style.left = snap.x + xa;
targ.style.top = snap.y + ya;
}
function rotate_item (e) {
e.preventDefault();
if (!e.target.classList.contains("movable")) return;
if (!e.target.style.rotate) e.target.style.rotate = "0deg";
let deg = e.target.style.rotate.slice(0,-3);
if (e.deltaY < 0) {
deg = parseInt(deg) + 90;
e.target.style.rotate = deg + "deg";
} else {
deg = parseInt(deg) - 90;
e.target.style.rotate = deg + "deg";
}
}
I suppose I could write a lengthy switch to account for all possible image sizes and orientations, or maybe add the difference between targ.style.left and targ.getBoundingClientRect().left, but I'm looking for a more elegant method and want to understand what's going on. What am I doing wrong here? What is the "proper" way to achieve this?
Share Improve this question asked Jan 30 at 0:27 Joseph MassaroJoseph Massaro 1434 bronze badges 1 |2 Answers
Reset to default 1If you want it to rotate around the top left corner you should set the transform-origin: 0 0
. This way it will keep being snapped to the grid if it was snapped before the rotation.
Basically just:
.movable {
transform-origin: 0 0;
}
I decided to just compute the difference of the position like so:
let difference = {
x: parseInt(targ.style.left) - targ.getBoundingClientRect().left,
y: parseInt(targ.style.top) - targ.getBoundingClientRect().top
}
targ.style.left = snap.x + xa + difference.x;
targ.style.top = snap.y + ya + difference.y
I learned a few interesting things along the way.
- Transformations in CSS do not affect the size or origin of the element, nor their parent.
- Despite this, getBoundingclientRect() always has the actual .left and .top of a rotated element.
- Background images set via CSS cannot be manipulated.
- There is no way to reposition the origin point of an element, and the element remembers its original position at all times.
- 1 and 3 may end up as CSS functions in the future.
版权声明:本文标题:html - How should you snap an image to a grid via Javascript after it has been rotated with CSS? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741991266a2409153.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
el.style.rotate
may work butel.style.transform
withrotate(xdeg)
is probably what you want. The default value fortransform-origin
is 50% 50% I believe so it shouldn't be rotating about the top left. – NickSlash Commented Jan 30 at 1:33