问题
There are two containers: the first is a small viewport and the second is huge workspace. So, user scroll the viewport to move within the workspace. I want to implement a zoom in/out feature via CSS property tranform, but during the process I faced one difficulty and could not find a precise solution for it.
The issue is: when user zooms in/out, elements at the workspace are shifted. This happens actually because the workspace is resized, not they. But if I resize each element at the workspace, the distances between them (in terms of top/left CSS values) will be changed, what is not preferred.
I see the following solution: change scrolls values after resizing, but I do not know what ratios or numbers to use. Is there any formulae or another solution to overcome such a problem?
For resizing use Alt + MouseWheel
let workspace = document.getElementsByClassName('workspace')[0];
workspace.onwheel = resize;
let current_scale = 1;
function resize(E) {
E = E || window.event
if (E.altKey) {
E.preventDefault();
let new_scale = Math.max(0.1, current_scale - E.deltaY / 360);
workspace.style.setProperty('transform', 'scale(' + new_scale + ')');
current_scale = new_scale;
}
}
.viewport {
width: 80vw;
height: 80vh;
box-sizing: border-box;
overflow: scroll;
transform: scale(1);
}
.workspace {
position: relative;
width: 1000px;
height: 1000px;
overflow: hidden;
}
.element {
position: absolute;
width: 10px;
height: 10px;
}
<div class="viewport">
<div class="workspace">
<button class="element" style="top: 100px; left: 150px"></button>
<button class="element" style="top 80px; left: 100px"></button>
<button class="element" style="top: 230px; left: 130px"></button>
<button class="element" style="top: 100px; left: 250px"></button>
</div>
</div>
UPD: I attached some photos from the original project for clarification:
So, that's a look of the workspace with scale(1)
Then I resize it and get the following result:
But desirable result looks like this:
UPD2
I inserted <svg> element to show how lines are drawn and why resizing each button seems to me a not viable solution in my case
let workspace = document.getElementsByClassName('workspace')[0];
workspace.onwheel = resize;
let current_scale = 1;
function resize(E) {
E = E || window.event;
if (E.altKey) {
E.preventDefault();
let new_scale = Math.max(0.1, current_scale - E.deltaY / 360);
var btns = workspace.getElementsByClassName('element');
for(var i = 0; i <btns.length; i++) {
btns[i].style.setProperty('transform', 'scale(' + new_scale + ')');
}
current_scale = new_scale;
}
}
.viewport {
width: 80vw;
height: 80vh;
box-sizing: border-box;
overflow: scroll;
transform: scale(1);
transform-origin: 0 0;
}
.workspace {
position: relative;
width: 1000px;
height: 1000px;
overflow: hidden;
}
.element {
position: absolute;
width: 10px;
height: 10px;
}
.line-drawer
{
position:absolute;
height:1000px;
width:1000px;
}
<div class="viewport">
<div class="workspace">
<svg class="line-drawer">
<line x1="100px" x2="130px" y1="80px" y2="230px" style='stroke-width: 4px; stroke: black'></line>
</svg>
<button class="element" style="top: 100px; left: 150px"></button>
<button class="element" style="top: 80px; left: 100px"></button>
<button class="element" style="top: 230px; left: 130px"></button>
<button class="element" style="top: 100px; left: 250px"></button>
</div>
</div>
回答1:
Scaling the individual elements like this will keep them in there position
let workspace = document.getElementsByClassName('workspace')[0];
workspace.onwheel = resize;
let current_scale = 1;
function resize(E) {
E = E || window.event
if (E.altKey) {
E.preventDefault();
let new_scale = Math.max(0.1, current_scale - E.deltaY / 360);
var btns = workspace.getElementsByClassName('element');
for(var i = 0; i <btns.length; i++) {
btns[i].style.setProperty('transform', 'scale(' + new_scale + ')');
}
current_scale = new_scale;
}
}
.viewport {
width: 80vw;
height: 80vh;
box-sizing: border-box;
overflow: scroll;
transform: scale(1);
}
.workspace {
position: relative;
width: 1000px;
height: 1000px;
overflow: hidden;
}
.element {
position: absolute;
width: 10px;
height: 10px;
}
<div class="viewport">
<div class="workspace">
<button class="element" style="top: 100px; left: 150px"></button>
<button class="element" style="top 80px; left: 100px"></button>
<button class="element" style="top: 230px; left: 130px"></button>
<button class="element" style="top: 100px; left: 250px"></button>
</div>
</div>
来源:https://stackoverflow.com/questions/62038601/resizing-and-scrolling-issue-js-html