Skip to content

Instantly share code, notes, and snippets.

@liesislukas
Created May 26, 2021 11:08
Show Gist options
  • Save liesislukas/ecb4cba35631cd0c8e8c06896422d96a to your computer and use it in GitHub Desktop.
Save liesislukas/ecb4cba35631cd0c8e8c06896422d96a to your computer and use it in GitHub Desktop.
retejs zoom nodes with animation utility function
const min = (arr) => (arr.length === 0 ? 0 : Math.min(...arr));
const max = (arr) => (arr.length === 0 ? 0 : Math.max(...arr));
export function nodesBBox({editor, nodes}) {
const left = min(nodes.map((node) => node.position[0]));
const top = min(nodes.map((node) => node.position[1]));
const right = max(nodes.map((node) => node.position[0] + editor.view.nodes.get(node).el.clientWidth));
const bottom = max(nodes.map((node) => node.position[1] + editor.view.nodes.get(node).el.clientHeight));
return {
left,
right,
top,
bottom,
width: Math.abs(left - right),
height: Math.abs(top - bottom),
getCenter: () => {
return [
(left + right) / 2,
(top + bottom) / 2,
];
},
};
}
const stepIntervalMs = 15;
export default function zoomAt({editor, nodes, doReturnNewPosition, transitionTimeMs}) {
nodes = nodes || editor.nodes;
const bbox = nodesBBox({editor, nodes});
const [x, y] = bbox.getCenter();
const [w, h] = [editor.view.container.clientWidth, editor.view.container.clientHeight];
const {area} = editor.view;
const [kw, kh] = [w / bbox.width, h / bbox.height];
const newZoom = Math.min(kh * 0.9, kw * 0.9, 1);
const newX = area.container.clientWidth / 2 - x * newZoom;
const newY = area.container.clientHeight / 2 - y * newZoom;
if (doReturnNewPosition === true) {
return {
x: newX,
y: newY,
zoom: newZoom,
};
}
if (transitionTimeMs && transitionTimeMs > 0) {
let currentZoom = area.transform.k;
let currentX = area.transform.x;
let currentY = area.transform.y;
const stepZoom = ((newZoom - currentZoom) / transitionTimeMs) * stepIntervalMs;
const stepX = ((newX - currentX) / transitionTimeMs) * stepIntervalMs;
const stepY = ((newY - currentY) / transitionTimeMs) * stepIntervalMs;
let zoomInterval = setInterval(() => {
currentZoom = currentZoom + stepZoom;
currentX = currentX + stepX;
currentY = currentY + stepY;
// don't overshoot zoom value
if (stepZoom < 0) {
if (currentZoom < newZoom) {
currentZoom = newZoom;
}
}
if (stepZoom > 0) {
if (currentZoom > newZoom) {
currentZoom = newZoom;
}
}
// don't overshoot x
if (stepX < 0) {
if (currentX < newX) {
currentX = newX;
}
}
if (stepX > 0) {
if (currentX > newX) {
currentX = newX;
}
}
// don't overshoot y
if (stepY < 0) {
if (currentY < newY) {
currentY = newY;
}
}
if (stepY > 0) {
if (currentY > newY) {
currentY = newY;
}
}
const doStopZoom = currentZoom === newZoom
|| (stepZoom < 0 && currentZoom < newZoom)
|| (stepZoom > 0 && currentZoom > newZoom);
const doStopX =
currentX === newX
|| (stepX < 0 && currentX < newX)
|| (stepX > 0 && currentX > newX);
const doStopY =
currentY === newY
|| (stepY < 0 && currentY < newY)
|| (stepY > 0 && currentY > newY);
area.transform.x = currentX;
area.transform.y = currentY;
area.zoom(currentZoom, 0, 0);
area.update();
if (doStopZoom && doStopX && doStopY) {
clearInterval(zoomInterval);
}
}, stepIntervalMs);
} else {
area.transform.x = newX;
area.transform.y = newY;
area.zoom(newZoom, 0, 0);
area.update();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment