RoamController.ts 8.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/

20 21
// @ts-nocheck

S
sushuang 已提交
22
import * as zrUtil from 'zrender/src/core/util';
23
import Eventful from 'zrender/src/core/Eventful';
S
sushuang 已提交
24
import * as eventTool from 'zrender/src/core/event';
S
sushuang 已提交
25
import * as interactionMutex from './interactionMutex';
S
sushuang 已提交
26 27 28 29 30 31 32 33 34

/**
 * @alias module:echarts/component/helper/RoamController
 * @constructor
 * @mixin {module:zrender/mixin/Eventful}
 *
 * @param {module:zrender/zrender~ZRender} zr
 */
function RoamController(zr) {
L
lang 已提交
35 36

    /**
S
sushuang 已提交
37
     * @type {Function}
L
lang 已提交
38
     */
S
sushuang 已提交
39
    this.pointerChecker;
L
lang 已提交
40

S
sushuang 已提交
41 42 43 44
    /**
     * @type {module:zrender}
     */
    this._zr = zr;
L
lang 已提交
45

S
sushuang 已提交
46 47 48 49
    /**
     * @type {Object}
     */
    this._opt = {};
P
pah100 已提交
50

S
sushuang 已提交
51 52 53 54 55 56 57
    // Avoid two roamController bind the same handler
    var bind = zrUtil.bind;
    var mousedownHandler = bind(mousedown, this);
    var mousemoveHandler = bind(mousemove, this);
    var mouseupHandler = bind(mouseup, this);
    var mousewheelHandler = bind(mousewheel, this);
    var pinchHandler = bind(pinch, this);
P
pah100 已提交
58

S
sushuang 已提交
59
    Eventful.call(this);
P
pah100 已提交
60

S
sushuang 已提交
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
    /**
     * @param {Function} pointerChecker
     *                   input: x, y
     *                   output: boolean
     */
    this.setPointerChecker = function (pointerChecker) {
        this.pointerChecker = pointerChecker;
    };

    /**
     * Notice: only enable needed types. For example, if 'zoom'
     * is not needed, 'zoom' should not be enabled, otherwise
     * default mousewheel behaviour (scroll page) will be disabled.
     *
     * @param  {boolean|string} [controlType=true] Specify the control type,
     *                          which can be null/undefined or true/false
     *                          or 'pan/move' or 'zoom'/'scale'
     * @param {Object} [opt]
S
sushuang 已提交
79 80 81
     * @param {Object} [opt.zoomOnMouseWheel=true] The value can be: true / false / 'shift' / 'ctrl' / 'alt'.
     * @param {Object} [opt.moveOnMouseMove=true] The value can be: true / false / 'shift' / 'ctrl' / 'alt'.
     * @param {Object} [opt.moveOnMouseWheel=false] The value can be: true / false / 'shift' / 'ctrl' / 'alt'.
S
sushuang 已提交
82 83 84 85 86 87 88 89 90 91
     * @param {Object} [opt.preventDefaultMouseMove=true] When pan.
     */
    this.enable = function (controlType, opt) {

        // Disable previous first
        this.disable();

        this._opt = zrUtil.defaults(zrUtil.clone(opt) || {}, {
            zoomOnMouseWheel: true,
            moveOnMouseMove: true,
S
sushuang 已提交
92
            // By default, wheel do not trigger move.
93
            moveOnMouseWheel: false,
S
sushuang 已提交
94 95 96 97 98
            preventDefaultMouseMove: true
        });

        if (controlType == null) {
            controlType = true;
P
pah100 已提交
99 100
        }

S
sushuang 已提交
101 102 103 104
        if (controlType === true || (controlType === 'move' || controlType === 'pan')) {
            zr.on('mousedown', mousedownHandler);
            zr.on('mousemove', mousemoveHandler);
            zr.on('mouseup', mouseupHandler);
105
        }
S
sushuang 已提交
106 107 108 109 110
        if (controlType === true || (controlType === 'scale' || controlType === 'zoom')) {
            zr.on('mousewheel', mousewheelHandler);
            zr.on('pinch', pinchHandler);
        }
    };
P
pah100 已提交
111

S
sushuang 已提交
112 113 114 115 116 117 118
    this.disable = function () {
        zr.off('mousedown', mousedownHandler);
        zr.off('mousemove', mousemoveHandler);
        zr.off('mouseup', mouseupHandler);
        zr.off('mousewheel', mousewheelHandler);
        zr.off('pinch', pinchHandler);
    };
P
pah100 已提交
119

S
sushuang 已提交
120
    this.dispose = this.disable;
P
pah100 已提交
121

S
sushuang 已提交
122 123 124
    this.isDragging = function () {
        return this._dragging;
    };
P
pah100 已提交
125

S
sushuang 已提交
126 127 128 129
    this.isPinching = function () {
        return this._pinching;
    };
}
P
pah100 已提交
130

S
sushuang 已提交
131
zrUtil.mixin(RoamController, Eventful);
P
pah100 已提交
132

S
sushuang 已提交
133 134

function mousedown(e) {
S
sushuang 已提交
135
    if (eventTool.isMiddleOrRightButtonOnMouseUpDown(e)
S
sushuang 已提交
136 137 138
        || (e.target && e.target.draggable)
    ) {
        return;
P
pah100 已提交
139 140
    }

S
sushuang 已提交
141 142 143 144 145 146 147 148 149 150 151 152 153
    var x = e.offsetX;
    var y = e.offsetY;

    // Only check on mosedown, but not mousemove.
    // Mouse can be out of target when mouse moving.
    if (this.pointerChecker && this.pointerChecker(e, x, y)) {
        this._x = x;
        this._y = y;
        this._dragging = true;
    }
}

function mousemove(e) {
S
sushuang 已提交
154
    if (!this._dragging
S
sushuang 已提交
155
        || !isAvailableBehavior('moveOnMouseMove', e, this._opt)
S
sushuang 已提交
156 157 158 159
        || e.gestureEvent === 'pinch'
        || interactionMutex.isTaken(this._zr, 'globalPan')
    ) {
        return;
P
pah100 已提交
160 161
    }

S
sushuang 已提交
162 163
    var x = e.offsetX;
    var y = e.offsetY;
P
pah100 已提交
164

S
sushuang 已提交
165 166 167 168 169 170 171 172 173 174 175
    var oldX = this._x;
    var oldY = this._y;

    var dx = x - oldX;
    var dy = y - oldY;

    this._x = x;
    this._y = y;

    this._opt.preventDefaultMouseMove && eventTool.stop(e.event);

S
sushuang 已提交
176 177 178
    trigger(this, 'pan', 'moveOnMouseMove', e, {
        dx: dx, dy: dy, oldX: oldX, oldY: oldY, newX: x, newY: y
    });
S
sushuang 已提交
179 180 181
}

function mouseup(e) {
S
sushuang 已提交
182
    if (!eventTool.isMiddleOrRightButtonOnMouseUpDown(e)) {
S
sushuang 已提交
183
        this._dragging = false;
P
pah100 已提交
184
    }
S
sushuang 已提交
185
}
P
pah100 已提交
186

S
sushuang 已提交
187
function mousewheel(e) {
S
sushuang 已提交
188 189
    var shouldZoom = isAvailableBehavior('zoomOnMouseWheel', e, this._opt);
    var shouldMove = isAvailableBehavior('moveOnMouseWheel', e, this._opt);
190 191
    var wheelDelta = e.wheelDelta;
    var absWheelDeltaDelta = Math.abs(wheelDelta);
S
sushuang 已提交
192 193
    var originX = e.offsetX;
    var originY = e.offsetY;
194

S
sushuang 已提交
195
    // wheelDelta maybe -0 in chrome mac.
196
    if (wheelDelta === 0 || (!shouldZoom && !shouldMove)) {
S
sushuang 已提交
197
        return;
P
pah100 已提交
198
    }
S
sushuang 已提交
199 200 201 202 203

    // If both `shouldZoom` and `shouldMove` is true, trigger
    // their event both, and the final behavior is determined
    // by event listener themselves.

204 205 206 207 208 209 210 211 212 213 214 215
    if (shouldZoom) {
        // Convenience:
        // Mac and VM Windows on Mac: scroll up: zoom out.
        // Windows: scroll up: zoom in.

        // FIXME: Should do more test in different environment.
        // wheelDelta is too complicated in difference nvironment
        // (https://developer.mozilla.org/en-US/docs/Web/Events/mousewheel),
        // although it has been normallized by zrender.
        // wheelDelta of mouse wheel is bigger than touch pad.
        var factor = absWheelDeltaDelta > 3 ? 1.4 : absWheelDeltaDelta > 1 ? 1.2 : 1.1;
        var scale = wheelDelta > 0 ? factor : 1 / factor;
S
sushuang 已提交
216 217 218
        checkPointerAndTrigger(this, 'zoom', 'zoomOnMouseWheel', e, {
            scale: scale, originX: originX, originY: originY
        });
219
    }
S
sushuang 已提交
220

221 222 223 224
    if (shouldMove) {
        // FIXME: Should do more test in different environment.
        var absDelta = Math.abs(wheelDelta);
        // wheelDelta of mouse wheel is bigger than touch pad.
S
sushuang 已提交
225
        var scrollDelta = (wheelDelta > 0 ? 1 : -1) * (absDelta > 3 ? 0.4 : absDelta > 1 ? 0.15 : 0.05);
S
sushuang 已提交
226 227 228
        checkPointerAndTrigger(this, 'scrollMove', 'moveOnMouseWheel', e, {
            scrollDelta: scrollDelta, originX: originX, originY: originY
        });
229
    }
S
sushuang 已提交
230
}
P
pah100 已提交
231

S
sushuang 已提交
232 233 234
function pinch(e) {
    if (interactionMutex.isTaken(this._zr, 'globalPan')) {
        return;
P
pah100 已提交
235
    }
236
    var scale = e.pinchScale > 1 ? 1.1 : 1 / 1.1;
S
sushuang 已提交
237 238 239
    checkPointerAndTrigger(this, 'zoom', null, e, {
        scale: scale, originX: e.pinchX, originY: e.pinchY
    });
S
sushuang 已提交
240 241
}

S
sushuang 已提交
242
function checkPointerAndTrigger(controller, eventName, behaviorToCheck, e, contollerEvent) {
S
sushuang 已提交
243 244 245
    if (controller.pointerChecker
        && controller.pointerChecker(e, contollerEvent.originX, contollerEvent.originY)
    ) {
S
sushuang 已提交
246 247 248 249 250
        // When mouse is out of roamController rect,
        // default befavoius should not be be disabled, otherwise
        // page sliding is disabled, contrary to expectation.
        eventTool.stop(e.event);

S
sushuang 已提交
251
        trigger(controller, eventName, behaviorToCheck, e, contollerEvent);
P
pah100 已提交
252
    }
S
sushuang 已提交
253 254
}

S
sushuang 已提交
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272
function trigger(controller, eventName, behaviorToCheck, e, contollerEvent) {
    // Also provide behavior checker for event listener, for some case that
    // multiple components share one listener.
    contollerEvent.isAvailableBehavior = zrUtil.bind(isAvailableBehavior, null, behaviorToCheck, e);
    controller.trigger(eventName, contollerEvent);
}

// settings: {
//     zoomOnMouseWheel
//     moveOnMouseMove
//     moveOnMouseWheel
// }
// The value can be: true / false / 'shift' / 'ctrl' / 'alt'.
function isAvailableBehavior(behaviorToCheck, e, settings) {
    var setting = settings[behaviorToCheck];
    return !behaviorToCheck || (
        setting && (!zrUtil.isString(setting) || e.event[setting + 'Key'])
    );
S
sushuang 已提交
273
}
P
pah100 已提交
274

S
sushuang 已提交
275
export default RoamController;