123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237 |
- 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';
- 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 - Zoom delta.
- * @param {Object} position - Zoom 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 - Zoom 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 - Zoom delta. Can be positive or negative.
- * @param {Object} position - Zoom position.
- * @param {number} stepSize - Step size.
- */
- 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);
- };
|