I have tried the solution posted in this github post
Steps to reproduce:
The image zooms in but should actually zoom out
const element = document.querySelector('#scene');
const zoomLevels = [0.1, 0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2, 2.5, 3];
let currentZoomLevel = zoomLevels[4];
const text = document.querySelector('#text');
let panZoomController = panzoom(element, {
beforeWheel: function(e) {
// allow wheel-zoom Disabled
return true;
}
});
const setText = (input) => {
text.innerText = input;
}
const zoom = () => {
const isSmooth = false;
const scale = currentZoomLevel;
if (scale) {
const transform = panZoomController.getTransform();
const deltaX = transform.x;
const deltaY = transform.y;
const offsetX = scale + deltaX;
const offsetY = scale + deltaY;
if (isSmooth) {
panZoomController.smoothZoom(0, 0, scale);
} else {
panZoomController.zoomTo(offsetX, offsetY, scale);
}
}
};
const zoomIn = () => {
const idx = zoomLevels.indexOf(currentZoomLevel);
// If next element exists
if (typeof zoomLevels[idx + 1] !== 'undefined') {
currentZoomLevel = zoomLevels[idx + 1];
}
if (currentZoomLevel === 1) {
panZoomController.moveTo(0, 0);
panZoomController.zoomAbs(0, 0, 1);
} else {
zoom();
}
setText(currentZoomLevel * 100 + '%');
};
const zoomOut = () => {
const idx = zoomLevels.indexOf(currentZoomLevel);
//if previous element exists
if (typeof zoomLevels[idx - 1] !== 'undefined') {
currentZoomLevel = zoomLevels[idx - 1];
}
if (currentZoomLevel === 1) {
panZoomController.moveTo(0, 0);
panZoomController.zoomAbs(0, 0, 1);
} else {
zoom();
}
setText(currentZoomLevel * 100 + '%');
};
div {
overflow: hidden;
border: 3px solid red
}
<script src="https://unpkg.com/panzoom@8.1.0/dist/panzoom.min.js"></script>
<body>
<div>
<img id="scene" src="https://www.probytes.net/wp-content/uploads/2018/01/5-1.png">
</div>
<br/>
<button onclick="zoomOut()">-</button>
<span id="text">100%</span>
<button onclick="zoomIn()">+</button>
</body>
You have mistaken a relative scale for an absolute one here. While zoomAbs()
is using an absolute zoom level, the zoom()
function is using zoomTo()
which takes in a relative zoom level.
Therefore, describing your entire process:
- Initial. Scale: 1
- Zoom in. Scale: 1 * 1.25 = 1.25
- Zoom in. Scale: 1.25 * 1.5 = 1.875
- Zoom out. Scale: 1.875 * 1.25 = 2.344
- Zoom out. Scale: Hard reset to 1
Note: You can also see this happening in reverse if you zoom out more than once, then try to zoom in.
This can be remedied by either using the absolute scale method zoomAbs()
(much simpler) or by calculating the relative zoom using current and required scales.
To do this simply replace this line
panZoomController.zoomTo(offsetX, offsetY, scale);
with
panZoomController.zoomAbs(offsetX, offsetY, scale);
Fixed snippet:
const element = document.querySelector('#scene');
const zoomLevels = [0.1, 0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2, 2.5, 3];
let currentZoomLevel = zoomLevels[4];
const text = document.querySelector('#text');
let panZoomController = panzoom(element, {
beforeWheel: function(e) {
// allow wheel-zoom Disabled
return true;
}
});
const setText = (input) => {
text.innerText = input;
}
const zoom = () => {
const isSmooth = false;
const scale = currentZoomLevel;
if (scale) {
const transform = panZoomController.getTransform();
const deltaX = transform.x;
const deltaY = transform.y;
const offsetX = scale + deltaX;
const offsetY = scale + deltaY;
if (isSmooth) {
panZoomController.smoothZoom(0, 0, scale);
} else {
panZoomController.zoomAbs(offsetX, offsetY, scale);
}
}
};
const zoomIn = () => {
const idx = zoomLevels.indexOf(currentZoomLevel);
// If next element exists
if (typeof zoomLevels[idx + 1] !== 'undefined') {
currentZoomLevel = zoomLevels[idx + 1];
}
if (currentZoomLevel === 1) {
panZoomController.moveTo(0, 0);
panZoomController.zoomAbs(0, 0, 1);
} else {
zoom();
}
setText(currentZoomLevel * 100 + '%');
};
const zoomOut = () => {
const idx = zoomLevels.indexOf(currentZoomLevel);
//if previous element exists
if (typeof zoomLevels[idx - 1] !== 'undefined') {
currentZoomLevel = zoomLevels[idx - 1];
}
if (currentZoomLevel === 1) {
panZoomController.moveTo(0, 0);
panZoomController.zoomAbs(0, 0, 1);
} else {
zoom();
}
setText(currentZoomLevel * 100 + '%');
};
div {
overflow: hidden;
border: 3px solid red
}
<script src="https://unpkg.com/panzoom@8.1.0/dist/panzoom.min.js"></script>
<body>
<div>
<img id="scene" src="https://www.probytes.net/wp-content/uploads/2018/01/5-1.png">
</div>
<br/>
<button onclick="zoomOut()">-</button>
<span id="text">100%</span>
<button onclick="zoomIn()">+</button>
</body>