Created
May 26, 2021 11:08
-
-
Save liesislukas/ecb4cba35631cd0c8e8c06896422d96a to your computer and use it in GitHub Desktop.
retejs zoom nodes with animation utility function
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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