CONTEXT :
- My requirement is to do image transformations like scale, rotate and translate with user actions on an image.
- Rotation and translation of image is done in its center using transform origin 50% 50% ( default ).
- For scaling the image on mouse point using mouse wheel, i was able to make it work with transform origin 0 0
- Just to accomodate the scale behaviour if i change the origin, i am required to recalculate other transformations relative to the new origin.
PROBLEM :
- How to scale the image on mouse point if the transform origin is defaulted to 50% 50% by default ?
- The following fiddle works with transform origin 0 0 for reference. I needhelp in optimizing this calculations using transform origin 50% 50%.
Can someone assist in optimizing this calculation further so that it works with default transform origin ?
<!DOCTYPE html>
<html lang="en">
<head>
<style>
.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;
}
</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">
</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();
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)`;
img.style.transform = steps;
}
</script>
</body>
</html>