jstd-web/node_modules/diagram-js/lib/navigation/zoomscroll/ZoomScroll.js

244 lines
5.0 KiB
JavaScript

import {
event as domEvent,
closest as domClosest
} from 'min-dom';
import {
getStepSize,
cap
} from './ZoomUtil';
import {
log10
} from '../../util/Math';
import {
bind
} from 'min-dash';
/**
* @typedef {import('../../core/Canvas').default} Canvas
* @typedef {import('../../core/EventBus').default} EventBus
*/
var sign = Math.sign || function(n) {
return n >= 0 ? 1 : -1;
};
var RANGE = { min: 0.2, max: 4 },
NUM_STEPS = 10;
var DELTA_THRESHOLD = 0.1;
var DEFAULT_SCALE = 0.75;
/**
* An implementation of zooming and scrolling within the
* {@link Canvas} via the mouse wheel.
*
* Mouse wheel zooming / scrolling may be disabled using
* the {@link toggle(enabled)} method.
*
* @param {Object} [config]
* @param {boolean} [config.enabled=true] default enabled state
* @param {number} [config.scale=.75] scroll sensivity
* @param {EventBus} eventBus
* @param {Canvas} canvas
*/
export default function ZoomScroll(config, eventBus, canvas) {
config = config || {};
this._enabled = false;
this._canvas = canvas;
this._container = canvas._container;
this._handleWheel = bind(this._handleWheel, this);
this._totalDelta = 0;
this._scale = config.scale || DEFAULT_SCALE;
var self = this;
eventBus.on('canvas.init', function(e) {
self._init(config.enabled !== false);
});
}
ZoomScroll.$inject = [
'config.zoomScroll',
'eventBus',
'canvas'
];
ZoomScroll.prototype.scroll = function scroll(delta) {
this._canvas.scroll(delta);
};
ZoomScroll.prototype.reset = function reset() {
this._canvas.zoom('fit-viewport');
};
/**
* Zoom depending on delta.
*
* @param {number} delta
* @param {Object} position
*/
ZoomScroll.prototype.zoom = function zoom(delta, position) {
// zoom with half the step size of stepZoom
var stepSize = getStepSize(RANGE, NUM_STEPS * 2);
// add until threshold reached
this._totalDelta += delta;
if (Math.abs(this._totalDelta) > DELTA_THRESHOLD) {
this._zoom(delta, position, stepSize);
// reset
this._totalDelta = 0;
}
};
ZoomScroll.prototype._handleWheel = function handleWheel(event) {
// event is already handled by '.djs-scrollable'
if (domClosest(event.target, '.djs-scrollable', true)) {
return;
}
var element = this._container;
event.preventDefault();
// pinch to zoom is mapped to wheel + ctrlKey = true
// in modern browsers (!)
var isZoom = event.ctrlKey;
var isHorizontalScroll = event.shiftKey;
var factor = -1 * this._scale,
delta;
if (isZoom) {
factor *= event.deltaMode === 0 ? 0.020 : 0.32;
} else {
factor *= event.deltaMode === 0 ? 1.0 : 16.0;
}
if (isZoom) {
var elementRect = element.getBoundingClientRect();
var offset = {
x: event.clientX - elementRect.left,
y: event.clientY - elementRect.top
};
delta = (
Math.sqrt(
Math.pow(event.deltaY, 2) +
Math.pow(event.deltaX, 2)
) * sign(event.deltaY) * factor
);
// zoom in relative to diagram {x,y} coordinates
this.zoom(delta, offset);
} else {
if (isHorizontalScroll) {
delta = {
dx: factor * event.deltaY,
dy: 0
};
} else {
delta = {
dx: factor * event.deltaX,
dy: factor * event.deltaY
};
}
this.scroll(delta);
}
};
/**
* Zoom with fixed step size.
*
* @param {number} delta - Zoom delta (1 for zooming in, -1 for out).
* @param {Object} position
*/
ZoomScroll.prototype.stepZoom = function stepZoom(delta, position) {
var stepSize = getStepSize(RANGE, NUM_STEPS);
this._zoom(delta, position, stepSize);
};
/**
* Zoom in/out given a step size.
*
* @param {number} delta
* @param {Object} position
* @param {number} stepSize
*/
ZoomScroll.prototype._zoom = function(delta, position, stepSize) {
var canvas = this._canvas;
var direction = delta > 0 ? 1 : -1;
var currentLinearZoomLevel = log10(canvas.zoom());
// snap to a proximate zoom step
var newLinearZoomLevel = Math.round(currentLinearZoomLevel / stepSize) * stepSize;
// increase or decrease one zoom step in the given direction
newLinearZoomLevel += stepSize * direction;
// calculate the absolute logarithmic zoom level based on the linear zoom level
// (e.g. 2 for an absolute x2 zoom)
var newLogZoomLevel = Math.pow(10, newLinearZoomLevel);
canvas.zoom(cap(RANGE, newLogZoomLevel), position);
};
/**
* Toggle the zoom scroll ability via mouse wheel.
*
* @param {boolean} [newEnabled] new enabled state
*/
ZoomScroll.prototype.toggle = function toggle(newEnabled) {
var element = this._container;
var handleWheel = this._handleWheel;
var oldEnabled = this._enabled;
if (typeof newEnabled === 'undefined') {
newEnabled = !oldEnabled;
}
// only react on actual changes
if (oldEnabled !== newEnabled) {
// add or remove wheel listener based on
// changed enabled state
domEvent[newEnabled ? 'bind' : 'unbind'](element, 'wheel', handleWheel, false);
}
this._enabled = newEnabled;
return newEnabled;
};
ZoomScroll.prototype._init = function(newEnabled) {
this.toggle(newEnabled);
};