/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
/** * DragZoom is a constructor that contains the state of the current dragging and * zooming behavior. It sets the scrolling and zooming behaviors. * * @param {HTMLElement} container description * The container for the canvases
*/ function DragZoom(container, debounceRate, requestAnimationFrame) {
EventEmitter.decorate(this);
this.isDragging = false;
// The current mouse position this.mouseX = container.offsetWidth / 2; this.mouseY = container.offsetHeight / 2;
// The total size of the visualization after being zoomed, in pixels this.zoomedWidth = container.offsetWidth; this.zoomedHeight = container.offsetHeight;
// How much the visualization has been zoomed in this.zoom = 0;
// The offset of visualization from the container. This is applied after // the zoom, and the visualization by default is centered this.translateX = 0; this.translateY = 0;
// The size of the offset between the top/left of the container, and the // top/left of the containing element. This value takes into account // the device pixel ratio for canvas draws. this.offsetX = 0; this.offsetY = 0;
// The smoothed values that are animated and eventually match the target // values. The values are updated by the update loop this.smoothZoom = 0; this.smoothTranslateX = 0; this.smoothTranslateY = 0;
// Add the constant values for testing purposes this.ZOOM_SPEED = ZOOM_SPEED; this.ZOOM_EPSILON = ZOOM_EPSILON;
/** * Returns an update loop. This loop smoothly updates the visualization when * actions are performed. Once the animations have reached their target values * the animation loop is stopped. * * Any value in the `dragZoom` object that starts with "smooth" is the * smoothed version of a value that is interpolating toward the target value. * For instance `dragZoom.smoothZoom` approaches `dragZoom.zoom` on each * iteration of the update loop until it's sufficiently close as defined by * the epsilon values. * * Only these smoothed values and the container CSS are updated by the loop. * * @param {HTMLDivElement} container * @param {Object} dragZoom * The values that represent the current dragZoom state * @param {Function} requestAnimationFrame
*/ function createUpdateLoop(container, dragZoom, requestAnimationFrame) {
let isLooping = false;
const zoom = 1 + dragZoom.smoothZoom; const x = dragZoom.smoothTranslateX; const y = dragZoom.smoothTranslateY;
container.style.transform = `translate(${x}px, ${y}px) scale(${zoom})`;
if (isLooping) {
requestAnimationFrame(update);
}
}
// Go ahead and start the update loop
update();
returnfunction restartLoopingIfStopped() { if (!isLooping) {
update();
}
};
}
/** * Set the various event listeners and return a function to remove them * * @param {Object} dragZoom * @param {HTMLElement} container * @param {Function} update * @return {Function} The function to remove the handlers
*/ function setHandlers(dragZoom, container, update, debounceRate) { const emitChanged = debounce(() => dragZoom.emit("change"), debounceRate);
/** * Sets handlers for when the user drags on the canvas. It will update dragZoom * object with new translate and offset values. * * @param {HTMLElement} container * @param {Object} dragZoom * @param {Function} changed * @param {Function} update
*/ function setDragHandlers(container, dragZoom, emitChanged, update) { const parentEl = container.parentElement;
function startDrag() {
dragZoom.isDragging = true;
container.style.cursor = "grabbing";
}
function stopDrag() {
dragZoom.isDragging = false;
container.style.cursor = "grab";
}
/** * Sets the handlers for when the user scrolls. It updates the dragZoom object * and keeps the canvases all within the view. After changing values update * loop is called, and the changed event is emitted. * * @param {HTMLDivElement} container * @param {Object} dragZoom * @param {Function} changed * @param {Function} update
*/ function setScrollHandlers(container, dragZoom, emitChanged, update) { const window = container.ownerDocument.defaultView;
function handleWheel(event) {
event.preventDefault();
// The ratio of where the center of the mouse is in regards to the total // zoomed width/height const ratioZoomX =
(prevZoomedWidth / 2 + mouseOffsetX - dragZoom.translateX) /
prevZoomedWidth; const ratioZoomY =
(prevZoomedHeight / 2 + mouseOffsetY - dragZoom.translateY) /
prevZoomedHeight;
// Distribute the change in width and height based on the above ratio
dragZoom.translateX -= lerp(-deltaWidth / 2, deltaWidth / 2, ratioZoomX);
dragZoom.translateY -= lerp(-deltaHeight / 2, deltaHeight / 2, ratioZoomY);
// Keep the canvas in range of the container
keepInView(container, dragZoom);
emitChanged();
update();
}
/** * Account for the various mouse wheel event types, per pixel or per line * * @param {WheelEvent} event * @return {Number} The scroll size in pixels
*/ function getScrollDelta(event) { if (event.deltaMode === LINE_SCROLL_MODE) { // Update by a fixed arbitrary value to normalize scroll types return event.deltaY * SCROLL_LINE_SIZE;
} return event.deltaY;
}
/** * Keep the dragging and zooming within the view by updating the values in the * `dragZoom` object. * * @param {HTMLDivElement} container * @param {Object} dragZoom
*/ function keepInView(container, dragZoom) { const { devicePixelRatio } = container.ownerDocument.defaultView; const overdrawX = (dragZoom.zoomedWidth - container.offsetWidth) / 2; const overdrawY = (dragZoom.zoomedHeight - container.offsetHeight) / 2;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.