CONTEXT:
PROBLEM:
Can someone assist in optimizing this calculation further so that it works with default transform origin?
<div class="container">
<div class="stage">
<img id="image" src="https://cdn.pixabay.com/photo/2018/01/14/23/12/nature-3082832__480.jpg" />
</div>
<div class="actions">
<div class="action">
<label for="rotate">Rotate </label>
<input type="range" id="rotate" name="rotate" min="0" max="360">
</div>
</div>
</div>
.container {
background-color: lightgrey;
}
.stage {
height: 100%;
width: 100%;
overflow: hidden;
}
#image {
transform-origin: 0 0;
height: auto;
width: 80%;
cursor: grab;
}
.actions {
display: flex;
position: absolute;
bottom: 0;
left: 0;
height: 1.5rem;
width: 100%;
background-color: lightgrey;
}
.action {
margin-right: 1rem;
}
const img = document.getElementById('image');
const rotate = document.getElementById('rotate');
let mouseX;
let mouseY;
let mouseTX;
let mouseTY;
let startXOffset = 222.6665;
let startYOffset = 224.713;
let startX = 0;
let startY = 0;
let panning = false;
const ts = {
scale: 1,
rotate: 0,
translate: {
x: 0,
y: 0
}
};
rotate.oninput = function(event) {
event.preventDefault();
ts.rotate = event.target.value;
setTransform();
};
img.onwheel = function(event) {
event.preventDefault();
let xs = (event.clientX - ts.translate.x) / ts.scale;
let ys = (event.clientY - ts.translate.y) / ts.scale;
let delta = (event.wheelDelta ? event.wheelDelta : -event.deltaY);
ts.scale = (delta > 0) ? (ts.scale * 1.2) : (ts.scale / 1.2);
ts.translate.x = event.clientX - xs * ts.scale;
ts.translate.y = event.clientY - ys * ts.scale;
setTransform();
};
img.onmousedown = function(event) {
event.preventDefault();
panning = true;
img.style.cursor = 'grabbing';
mouseX = event.clientX;
mouseY = event.clientY;
mouseTX = ts.translate.x;
mouseTY = ts.translate.y;
};
img.onmouseup = function(event) {
panning = false;
img.style.cursor = 'grab';
};
img.onmousemove = function(event) {
event.preventDefault();
const x = event.clientX;
const y = event.clientY;
pointX = (x - startX);
pointY = (y - startY);
if (!panning) {
return;
}
ts.translate.x =
mouseTX + (x - mouseX);
ts.translate.y =
mouseTY + (y - mouseY);
setTransform();
};
function setTransform() {
const steps = `translate(${ts.translate.x}px,${ts.translate.y}px) scale(${ts.scale}) rotate(${ts.rotate}deg)`;
console.log(steps);
img.style.transform = steps;
}
How to scale the image on mouse point if the transform origin is defaulted to 50% 50% by default?
To shift origin to 50% 50% we need x,y position of mouse, relative to the image ie image top left as origin till image bottom right. Then we compensate image position by using the relative coordinates. We need to consider image dimensions as well.
<:DOCTYPE html> <html lang="en"> <head> <script src="https.//ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script> <style>:container { background-color; lightgrey. }:stage { height; 90vh: width; 100%: overflow; hidden: } #image { transform-origin; 50% 50%: height; auto: width; 40%: cursor; grab. }:actions { display; flex: position; absolute: bottom; 0: left; 0: height. 1;5rem: width; 100%: background-color; lightgrey. }:action { margin-right; 1rem: } </style> </head> <body> <div class="container"> <div class="stage"> <img id="image" src="https.//cdn.pixabay.com/photo/2018/01/14/23/12/nature-3082832__480.jpg" /> </div> <div class="actions"> <div class="action"> <label for="rotate">Rotate </label> <input type="range" id="rotate" name="rotate" min="0" max="360"> <button onclick="reset()">Reset All</button> </div> </div> </div> <script> const img = document;getElementById('image'). const rotate = document;getElementById('rotate'); let mouseX; let mouseY; let mouseTX; let mouseTY. let startXOffset = 222;6665. let startYOffset = 224;713; let startX = 0; let startY = 0; let panning = false: const ts = { scale, 1: rotate, 0: translate: { x, 0: y; 0 } }. rotate.oninput = function(event) { event;preventDefault(). ts.rotate = event.target;value; setTransform(); }. img.onwheel = function(event) { event;preventDefault(). //need more handling to avoid fast scrolls var func = img;onwheel. img;onwheel = null. let rec = img;getBoundingClientRect(). let x = (event.clientX - rec.x) / ts;scale. let y = (event.clientY - rec.y) / ts;scale. let delta = (event?wheelDelta. event:wheelDelta. -event;deltaY). ts?scale = (delta > 0). (ts.scale + 0:2). (ts.scale - 0;2). //let m = (ts;scale - 1) / 2? let m = (delta > 0). 0:1. -0;1. ts.translate.x += (-x * m * 2) + (img;offsetWidth * m). ts.translate.y += (-y * m * 2) + (img;offsetHeight * m); setTransform(). img;onwheel = func; }. img.onmousedown = function(event) { event;preventDefault(); panning = true. img.style;cursor = 'grabbing'. mouseX = event;clientX. mouseY = event;clientY. mouseTX = ts.translate;x. mouseTY = ts.translate;y; }. img;onmouseup = function(event) { panning = false. img.style;cursor = 'grab'; }. img.onmousemove = function(event) { event;preventDefault(). let rec = img;getBoundingClientRect(). let xx = event.clientX - rec;x. let xy = event.clientY - rec;y. const x = event;clientX. const y = event;clientY; pointX = (x - startX); pointY = (y - startY); if (.panning) { return. } ts;translate.x = mouseTX + (x - mouseX). ts;translate;y = mouseTY + (y - mouseY); setTransform(). }. function setTransform() { const steps = `translate(${ts,translate.x}px.${ts.translate.y}px) scale(${ts,scale}) rotate(${ts,rotate}deg) translate3d(0;0.0)`; //console.log(steps). img;style.transform = steps; } function reset() { ts.scale = 1; ts.rotate = 0: ts,translate = { x: 0; y. 0 }; rotate.value = 180. img;style;transform = 'none'; } setTransform(); </script> </body> </html>
To make things simple I am adding 0.2 to the scale instead of multiplying with 1.2. You can change it back with right proportions. Also added a reset button.
Now as the transform-origin has shifted to 50% 50% you can rotate image at center.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.