You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@echarts.apache.org by su...@apache.org on 2019/11/25 13:55:45 UTC

[incubator-echarts] branch fix/brush-globalout updated: feature: support `toolbox.dataZoom` `brush component` `dataZoom.slider` `visualMap.continuous` drag outside and release outside.

This is an automated email from the ASF dual-hosted git repository.

sushuang pushed a commit to branch fix/brush-globalout
in repository https://gitbox.apache.org/repos/asf/incubator-echarts.git


The following commit(s) were added to refs/heads/fix/brush-globalout by this push:
     new 93534d6  feature: support `toolbox.dataZoom` `brush component` `dataZoom.slider` `visualMap.continuous` drag outside and release outside.
93534d6 is described below

commit 93534d6a131d6b1b9ba56554fd99d5756734efc3
Author: SHUANG SU <su...@gmail.com>
AuthorDate: Mon Nov 25 21:54:42 2019 +0800

    feature: support `toolbox.dataZoom` `brush component` `dataZoom.slider` `visualMap.continuous` drag outside and release outside.
---
 src/component/dataZoom/SliderZoomView.js |  13 +-
 src/component/helper/BrushController.js  | 125 ++++++++++-------
 test/drag-out.html                       | 227 +++++++++++++++++++++++++++++++
 3 files changed, 305 insertions(+), 60 deletions(-)

diff --git a/src/component/dataZoom/SliderZoomView.js b/src/component/dataZoom/SliderZoomView.js
index 4b875da..abfd922 100644
--- a/src/component/dataZoom/SliderZoomView.js
+++ b/src/component/dataZoom/SliderZoomView.js
@@ -450,10 +450,6 @@ var SliderZoomView = DataZoomView.extend({
             draggable: true,
             cursor: getCursor(this._orient),
             drift: bind(this._onDragMove, this, 'all'),
-            onmousemove: function (e) {
-                // Fot mobile devicem, prevent screen slider on the button.
-                eventTool.stop(e.event);
-            },
             ondragstart: bind(this._showDataInfo, this, true),
             ondragend: bind(this._onDragEnd, this),
             onmouseover: bind(this._showDataInfo, this, true),
@@ -489,10 +485,6 @@ var SliderZoomView = DataZoomView.extend({
                     cursor: getCursor(this._orient),
                     draggable: true,
                     drift: bind(this._onDragMove, this, handleIndex),
-                    onmousemove: function (e) {
-                        // Fot mobile devicem, prevent screen slider on the button.
-                        eventTool.stop(e.event);
-                    },
                     ondragend: bind(this._onDragEnd, this),
                     onmouseover: bind(this._showDataInfo, this, true),
                     onmouseout: bind(this._showDataInfo, this, false)
@@ -714,9 +706,12 @@ var SliderZoomView = DataZoomView.extend({
         handleLabels[1].attr('invisible', !showOrHide);
     },
 
-    _onDragMove: function (handleIndex, dx, dy) {
+    _onDragMove: function (handleIndex, dx, dy, event) {
         this._dragging = true;
 
+        // For mobile device, prevent screen slider on the button.
+        eventTool.stop(event.event);
+
         // Transform dx, dy to bar coordination.
         var barTransform = this._displayables.barGroup.getLocalTransform();
         var vertex = graphic.applyTransform([dx, dy], barTransform, true);
diff --git a/src/component/helper/BrushController.js b/src/component/helper/BrushController.js
index caa753d..901a9f1 100644
--- a/src/component/helper/BrushController.js
+++ b/src/component/helper/BrushController.js
@@ -138,12 +138,6 @@ function BrushController(zr) {
 
     /**
      * @private
-     * @type {Object}
-     */
-    this._lastMouseMovePoint = {};
-
-    /**
-     * @private
      * @type {Array}
      */
     this._covers = [];
@@ -186,8 +180,26 @@ function BrushController(zr) {
      * @type {Object}
      */
     this._handlers = {};
-    each(mouseHandlers, function (handler, eventName) {
-        this._handlers[eventName] = zrUtil.bind(handler, this);
+
+    /**
+     * @private
+     * @type {Object}
+     */
+    this._localHandlers = {};
+
+    /**
+     * @private
+     * @type {Object}
+     */
+    this._pageHandlers = {};
+
+    each(localMouseHandlers, function (handler, eventName) {
+        this._handlers[eventName] =
+            this._localHandlers[eventName] = zrUtil.bind(handler, this);
+    }, this);
+    each(pageMouseHandlers, function (handler, eventName) {
+        this._handlers[eventName] =
+            this._pageHandlers[eventName] = zrUtil.bind(handler, this);
     }, this);
 }
 
@@ -382,9 +394,7 @@ function doEnableBrush(controller, brushOption) {
         interactionMutex.take(zr, MUTEX_RESOURCE_KEY, controller._uid);
     }
 
-    each(controller._handlers, function (handler, eventName) {
-        zr.on(eventName, handler);
-    });
+    mountHandlers(zr, controller._localHandlers);
 
     controller._brushType = brushOption.brushType;
     controller._brushOption = zrUtil.merge(zrUtil.clone(DEFAULT_BRUSH_OPT), brushOption, true);
@@ -395,13 +405,23 @@ function doDisableBrush(controller) {
 
     interactionMutex.release(zr, MUTEX_RESOURCE_KEY, controller._uid);
 
-    each(controller._handlers, function (handler, eventName) {
-        zr.off(eventName, handler);
-    });
+    unmountHandlers(zr, controller._handlers);
 
     controller._brushType = controller._brushOption = null;
 }
 
+function mountHandlers(zr, handlers) {
+    each(handlers, function (handler, eventName) {
+        zr.on(eventName, handler);
+    });
+}
+
+function unmountHandlers(zr, handlers) {
+    each(handlers, function (handler, eventName) {
+        zr.off(eventName, handler);
+    });
+}
+
 function createCover(controller, brushOption) {
     var cover = coverRenderers[brushOption.brushType].createCover(controller, brushOption);
     cover.__brushOption = brushOption;
@@ -744,8 +764,12 @@ function resetCursor(controller, e, localCursorPoint) {
 }
 
 function preventDefault(e) {
-    var rawE = e.event;
-    rawE.preventDefault && rawE.preventDefault();
+    // Just be worried about bring some side effect to the world
+    // out of echarts, we do not `preventDefault` for globalout.
+    if (e.zrIsFromLocal) {
+        var rawE = e.event;
+        rawE.preventDefault && rawE.preventDefault();
+    }
 }
 
 function mainShapeContain(cover, x, y) {
@@ -820,7 +844,7 @@ function determineBrushType(brushType, panel) {
     return brushType;
 }
 
-var mouseHandlers = {
+var localMouseHandlers = {
 
     mousedown: function (e) {
         if (this._dragging) {
@@ -841,60 +865,44 @@ var mouseHandlers = {
                 this._dragging = true;
                 this._track = [localCursorPoint.slice()];
             }
+
+            // Mount page handlers only when needed to minimize unexpected side-effect.
+            mountHandlers(this._zr, this._pageHandlers);
         }
     },
 
     mousemove: function (e) {
-        var lastPoint = this._lastMouseMovePoint;
-        lastPoint.x = e.offsetX;
-        lastPoint.y = e.offsetY;
-
-        var localCursorPoint = this.group.transformCoordToLocal(lastPoint.x, lastPoint.y);
-
+        var localCursorPoint = this.group.transformCoordToLocal(e.offsetX, e.offsetY);
+        // resetCursor should be always called when mouse is in zr area,
+        // but not called when mouse is out of zr area.
         resetCursor(this, e, localCursorPoint);
+    }
+};
 
+var pageMouseHandlers = {
+
+    pagemousemove: function (e) {
         if (this._dragging) {
+            var xy = getLocalMouseXY(e, this._zr);
+            var localCursorPoint = this.group.transformCoordToLocal(xy[0], xy[1]);
 
             preventDefault(e);
-
             var eventParams = updateCoverByMouse(this, e, localCursorPoint, false);
-
             eventParams && trigger(this, eventParams);
         }
     },
 
-    mouseup: function (e) {
+    pagemouseup: function (e) {
         handleDragEnd(this, e);
-    },
-
-    globalout: function (e) {
-        handleDragEnd(this, e, true);
     }
 };
 
-function handleDragEnd(controller, e, isGlobalOut) {
+function handleDragEnd(controller, e) {
     if (controller._dragging) {
+        preventDefault(e);
 
-        // Just be worried about bring some side effect to the world
-        // out of echarts, we do not `preventDefault` for globalout.
-        !isGlobalOut && preventDefault(e);
-
-        var pointerX = e.offsetX;
-        var pointerY = e.offsetY;
-        var lastPoint = controller._lastMouseMovePoint;
-        if (isGlobalOut) {
-            pointerX = lastPoint.x;
-            pointerY = lastPoint.y;
-        }
-
-        var localCursorPoint = controller.group.transformCoordToLocal(pointerX, pointerY);
-        // FIXME
-        // Here `e` is used only in `onIrrelevantElement` finally. And it's OK
-        // that pass the `e` of `globalout` to `onIrrelevantElement`. But it is
-        // not a good design of these interfaces. However, we do not refactor
-        // these code now because the implementation of `onIrrelevantElement`
-        // need to be discussed and probably be changed in future, becuase it
-        // slows down the performance of zrender in some cases.
+        var xy = getLocalMouseXY(e, controller._zr);
+        var localCursorPoint = controller.group.transformCoordToLocal(xy[0], xy[1]);
         var eventParams = updateCoverByMouse(controller, e, localCursorPoint, true);
 
         controller._dragging = false;
@@ -903,9 +911,24 @@ function handleDragEnd(controller, e, isGlobalOut) {
 
         // trigger event shoule be at final, after procedure will be nested.
         eventParams && trigger(controller, eventParams);
+
+        unmountHandlers(controller._zr, controller._pageHandlers);
     }
 }
 
+function getLocalMouseXY(event, zr) {
+    var x = event.offsetX;
+    var y = event.offsetY;
+    var w = zr.getWidth();
+    var h = zr.getHeight();
+    x < 0 && (x = 0);
+    x > w && (x = w);
+    y < 0 && (y = 0);
+    y > h && (y = h);
+
+    return [x, y];
+}
+
 /**
  * key: brushType
  * @type {Object}
diff --git a/test/drag-out.html b/test/drag-out.html
new file mode 100644
index 0000000..deac082
--- /dev/null
+++ b/test/drag-out.html
@@ -0,0 +1,227 @@
+<!DOCTYPE html>
+<!--
+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.
+-->
+
+
+<html>
+    <head>
+        <meta charset="utf-8">
+        <meta name="viewport" content="width=device-width, initial-scale=1" />
+        <script src="lib/esl.js"></script>
+        <script src="lib/config.js"></script>
+        <script src="lib/jquery.min.js"></script>
+        <script src="lib/facePrint.js"></script>
+        <script src="lib/testHelper.js"></script>
+        <!-- <script src="ut/lib/canteen.js"></script> -->
+        <link rel="stylesheet" href="lib/reset.css" />
+    </head>
+    <body>
+        <style>
+            body {
+                background: #000 !important;
+            }
+            .test-chart {
+                margin: 80px auto 80px auto !important;
+                background: #fff !important;
+            }
+            #live-info-panel {
+                position: fixed;
+                right: 5px;
+                top: 5px;
+                width: 120px;
+                height: 120px;
+                box-shadow: 0 0 5px #fff;
+                border: 2px solid green;
+                z-index: 999999;
+                color: #fff;
+                font-size: 10px;
+                background: #000;
+            }
+            #live-info-panel .title {
+                font-size: 10px;
+                color: yellow;
+                text-align: center;
+            }
+            #live-info-panel #live-info-content {
+                padding: 2px 3px;
+            }
+            #parent-of-main0 {
+                overflow: hidden;
+            }
+        </style>
+
+
+        <div id="live-info-panel">
+            <div class="title">Live Info Panel</div>
+            <div id="live-info-content"></div>
+        </div>
+
+        <div id="parent-of-main0">
+            <div id="main0"></div>
+        </div>
+        <div id="main1"></div>
+
+
+
+
+        <script>
+            var _liveInfoPanel = document.getElementById('live-info-panel');
+            var _liveInfoContent = document.getElementById('live-info-content');;
+            function _printLiveInfo(msg) {
+                _liveInfoContent.innerHTML = testHelper.encodeHTML(msg).replace(/\n/g, '<br>');
+            }
+            function _printEvent(event) {
+                _printLiveInfo([
+                    'type: ' + event.type,
+                    'x: ' + event.offsetX,
+                    'y: ' + event.offsetY,
+                    'isFromLocal: ' + !!event.zrIsFromLocal
+                ].join('\n'));
+            }
+        </script>
+
+
+
+
+
+        <script>
+        require(['echarts'/*, 'map/js/china' */], function (echarts) {
+            var option;
+            // $.getJSON('./data/nutrients.json', function (data) {});
+
+            option = {
+                xAxis: {},
+                yAxis: {},
+                brush: {},
+                series: {
+                    type: 'line',
+                    data: [[11, 22]]
+                }
+            };
+
+            var chart = testHelper.create(echarts, 'main0', {
+                title: [
+                    '[ Test this case in **PC** / **Touch device** / **WeApp(no document)** ]',
+                    '(1) Before anything clicked, **mousemove** / **click** on both inside and outside echarts.',
+                    '**Live Info Panel** should have nothing.',
+                    '(2) Click "mount page event listeners"',
+                    '**mousemove** / **click** on both inside and outside echarts.',
+                    '**Live Info Panel** should display mouse **xy** and **isFromLocal** correctly.',
+                    '(3) Click "add stopPropagation on parent"',
+                    'Move outside echarts, **Live Info Panel** should have nothing changed.',
+                    'Move inside echarts, **Live Info Panel** should have page event.'
+                ],
+                option: option,
+                width: 300,
+                height: 200,
+                buttons: [{
+                    text: 'mount page event listeners',
+                    onclick: function () {
+                        if (mounted) {
+                            return;
+                        }
+                        mounted = true;
+                        zr.on('pagemousemove', function (event) {
+                            _printEvent(event)
+                        });
+                        zr.on('pagemouseup', function (event) {
+                            _printEvent(event)
+                        });
+                    }
+                }, {
+                    text: 'add stopPropagation on parent',
+                    onclick: function () {
+                        var parent = document.getElementById('parent-of-main0');
+                        parent.addEventListener('mousemove', function (event) {
+                            event.stopPropagation();
+                        });
+                    }
+                }]
+            });
+
+            var zr;
+            var mounted;
+            if (chart) {
+                zr = chart.getZr();
+            }
+        });
+        </script>
+
+
+
+
+
+
+        <script>
+        require(['echarts'/*, 'map/js/china' */], function (echarts) {
+            var option;
+            // $.getJSON('./data/nutrients.json', function (data) {});
+
+            option = {
+                xAxis: {},
+                yAxis: {},
+                toolbox: {
+                    feature: {
+                        dataZoom: {}
+                    }
+                },
+                grid: {
+                    left: 100
+                },
+                brush: {},
+                dataZoom: [{
+                    type: 'slider'
+                }, {
+                    type: 'inside'
+                }],
+                visualMap: {
+                    type: 'continuous',
+                    calculable: true,
+                    left: 0,
+                    top: 20,
+                    min: 0,
+                    max: 50,
+                    itemHeight: 80
+                },
+                series: {
+                    type: 'line',
+                    data: [[11, 22], [33, 44], [42, 11], [52, 33]]
+                }
+            };
+
+            var chart = testHelper.create(echarts, 'main1', {
+                title: [
+                    'Drag **toolbox.dataZoom** / **dataZoom-slider** / **brush**',
+                    'to the **top** / **right** / **bottom** / **left** of the **black area** (out of echarts)',
+                    'and then mouseup or go back.',
+                    'Should act like listening to document `mousemove` and `mouseup`'
+                ],
+                option: option,
+                width: 350,
+                height: 260,
+                // buttons: [{text: 'btn-txt', onclick: function () {}}],
+                // recordCanvas: true,
+            });
+        });
+        </script>
+
+
+    </body>
+</html>
+


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@echarts.apache.org
For additional commands, e-mail: commits-help@echarts.apache.org