You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@echarts.apache.org by sh...@apache.org on 2021/10/12 04:59:51 UTC

[echarts] branch optimize-progressive updated: fix(large): fix event and tooltip on large symbol and lines

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

shenyi pushed a commit to branch optimize-progressive
in repository https://gitbox.apache.org/repos/asf/echarts.git


The following commit(s) were added to refs/heads/optimize-progressive by this push:
     new f76464c  fix(large): fix event and tooltip on large symbol and lines
f76464c is described below

commit f76464c33b68aa37fcbb404b26811d71a6ea2a1a
Author: pissang <bm...@gmail.com>
AuthorDate: Tue Oct 12 12:58:34 2021 +0800

    fix(large): fix event and tooltip on large symbol and lines
---
 src/chart/helper/LargeLineDraw.ts   | 68 +++++++++++++++++++++++++---
 src/chart/helper/LargeSymbolDraw.ts | 88 +++++++++++++++++++++++++++++++++----
 2 files changed, 140 insertions(+), 16 deletions(-)

diff --git a/src/chart/helper/LargeLineDraw.ts b/src/chart/helper/LargeLineDraw.ts
index 0e7c55f..62f5b6d 100644
--- a/src/chart/helper/LargeLineDraw.ts
+++ b/src/chart/helper/LargeLineDraw.ts
@@ -57,11 +57,21 @@ class LargeLinesPath extends graphic.Path {
     shape: LargeLinesPathShape;
 
     __startIndex: number;
+    private _off: number = 0;
+
+    hoverDataIdx: number = -1;
+
+    notClear: boolean;
 
     constructor(opts?: LargeLinesPathProps) {
         super(opts);
     }
 
+    reset() {
+        this.notClear = false;
+        this._off = 0;
+    }
+
     getDefaultStyle() {
         return {
             stroke: '#000',
@@ -76,9 +86,10 @@ class LargeLinesPath extends graphic.Path {
     buildPath(ctx: CanvasRenderingContext2D, shape: LargeLinesPathShape) {
         const segs = shape.segs;
         const curveness = shape.curveness;
+        let i;
 
         if (shape.polyline) {
-            for (let i = 0; i < segs.length;) {
+            for (i = this._off; i < segs.length;) {
                 const count = segs[i++];
                 if (count > 0) {
                     ctx.moveTo(segs[i++], segs[i++]);
@@ -89,7 +100,7 @@ class LargeLinesPath extends graphic.Path {
             }
         }
         else {
-            for (let i = 0; i < segs.length;) {
+            for (i = this._off; i < segs.length;) {
                 const x0 = segs[i++];
                 const y0 = segs[i++];
                 const x1 = segs[i++];
@@ -105,6 +116,10 @@ class LargeLinesPath extends graphic.Path {
                 }
             }
         }
+        if (this.incremental) {
+            this._off = i;
+            this.notClear = true;
+        }
     }
 
     findDataIndex(x: number, y: number) {
@@ -164,6 +179,45 @@ class LargeLinesPath extends graphic.Path {
 
         return -1;
     }
+
+    contain(x: number, y: number): boolean {
+        const localPos = this.transformCoordToLocal(x, y);
+        const rect = this.getBoundingRect();
+        x = localPos[0];
+        y = localPos[1];
+
+        if (rect.contain(x, y)) {
+            // Cache found data index.
+            const dataIdx = this.hoverDataIdx = this.findDataIndex(x, y);
+            return dataIdx >= 0;
+        }
+        this.hoverDataIdx = -1;
+        return false;
+    }
+
+    getBoundingRect() {
+        // Ignore stroke for large symbol draw.
+        let rect = this._rect;
+        if (!rect) {
+            const shape = this.shape;
+            const points = shape.segs;
+            let minX = Infinity;
+            let minY = Infinity;
+            let maxX = -Infinity;
+            let maxY = -Infinity;
+            for (let i = 0; i < points.length;) {
+                const x = points[i++];
+                const y = points[i++];
+                minX = Math.min(x, minX);
+                maxX = Math.max(x, maxX);
+                minY = Math.min(y, minY);
+                maxY = Math.max(y, maxY);
+            }
+
+            rect = this._rect = new graphic.BoundingRect(minX, minY, maxX, maxY);
+        }
+        return rect;
+    }
 }
 
 class LargeLineDraw {
@@ -197,9 +251,6 @@ class LargeLineDraw {
     incrementalUpdate(taskParams: StageHandlerProgressParams, data: LargeLinesData) {
         const lastAdded = this._newAdded[0];
         const linePoints = data.getLayout('linesPoints');
-        // Clear
-        this._newAdded = [];
-
 
         const oldSegs = lastAdded && lastAdded.shape.segs;
 
@@ -216,6 +267,9 @@ class LargeLineDraw {
             });
         }
         else {
+            // Clear
+            this._newAdded = [];
+
             const lineEl = this._create();
             lineEl.incremental = true;
             lineEl.setShape({
@@ -239,7 +293,6 @@ class LargeLineDraw {
 
     private _create() {
         const lineEl = new LargeLinesPath({
-            rectHover: true,
             cursor: 'default'
         });
         this._newAdded.push(lineEl);
@@ -273,7 +326,7 @@ class LargeLineDraw {
         ecData.seriesIndex = hostModel.seriesIndex;
         lineEl.on('mousemove', function (e) {
             ecData.dataIndex = null;
-            const dataIndex = lineEl.findDataIndex(e.offsetX, e.offsetY);
+            const dataIndex = lineEl.hoverDataIdx;
             if (dataIndex > 0) {
                 // Provide dataIndex for tooltip
                 ecData.dataIndex = dataIndex + lineEl.__startIndex;
@@ -282,6 +335,7 @@ class LargeLineDraw {
     };
 
     private _clear() {
+        this._newAdded = [];
         this.group.removeAll();
     };
 
diff --git a/src/chart/helper/LargeSymbolDraw.ts b/src/chart/helper/LargeSymbolDraw.ts
index 788de72..22614b2 100644
--- a/src/chart/helper/LargeSymbolDraw.ts
+++ b/src/chart/helper/LargeSymbolDraw.ts
@@ -59,6 +59,11 @@ class LargeSymbolPath extends graphic.Path<LargeSymbolPathProps> {
     endIndex: number;
 
     private _ctx: CanvasRenderingContext2D;
+    private _off: number = 0;
+
+    hoverDataIdx: number = -1;
+
+    notClear: boolean;
 
     constructor(opts?: LargeSymbolPathProps) {
         super(opts);
@@ -70,6 +75,11 @@ class LargeSymbolPath extends graphic.Path<LargeSymbolPathProps> {
 
     setColor: ECSymbol['setColor'];
 
+    reset() {
+        this.notClear = false;
+        this._off = 0;
+    }
+
     buildPath(path: PathProxy | CanvasRenderingContext2D, shape: LargeSymbolPathShape) {
         const points = shape.points;
         const size = shape.size;
@@ -80,6 +90,8 @@ class LargeSymbolPath extends graphic.Path<LargeSymbolPathProps> {
             ? (path as PathProxy).getContext()
             : path as CanvasRenderingContext2D;
         const canBoost = ctx && size[0] < BOOST_SIZE_THRESHOLD;
+        const softClipShape = this.softClipShape;
+        let i;
 
         // Do draw in afterBrush.
         if (canBoost) {
@@ -89,14 +101,14 @@ class LargeSymbolPath extends graphic.Path<LargeSymbolPathProps> {
 
         this._ctx = null;
 
-        for (let i = 0; i < points.length;) {
+        for (i = this._off; i < points.length;) {
             const x = points[i++];
             const y = points[i++];
 
             if (isNaN(x) || isNaN(y)) {
                 continue;
             }
-            if (this.softClipShape && !this.softClipShape.contain(x, y)) {
+            if (softClipShape && !softClipShape.contain(x, y)) {
                 continue;
             }
 
@@ -107,6 +119,10 @@ class LargeSymbolPath extends graphic.Path<LargeSymbolPathProps> {
 
             symbolProxy.buildPath(path, symbolProxyShape, true);
         }
+        if (this.incremental) {
+            this._off = i;
+            this.notClear = true;
+        }
     }
 
     afterBrush() {
@@ -114,19 +130,21 @@ class LargeSymbolPath extends graphic.Path<LargeSymbolPathProps> {
         const points = shape.points;
         const size = shape.size;
         const ctx = this._ctx;
+        const softClipShape = this.softClipShape;
+        let i;
 
         if (!ctx) {
             return;
         }
 
         // PENDING If style or other canvas status changed?
-        for (let i = 0; i < points.length;) {
+        for (i = this._off; i < points.length;) {
             const x = points[i++];
             const y = points[i++];
             if (isNaN(x) || isNaN(y)) {
                 continue;
             }
-            if (this.softClipShape && !this.softClipShape.contain(x, y)) {
+            if (softClipShape && !softClipShape.contain(x, y)) {
                 continue;
             }
             // fillRect is faster than building a rect path and draw.
@@ -136,6 +154,10 @@ class LargeSymbolPath extends graphic.Path<LargeSymbolPathProps> {
                 size[0], size[1]
             );
         }
+        if (this.incremental) {
+            this._off = i;
+            this.notClear = true;
+        }
     }
 
     findDataIndex(x: number, y: number) {
@@ -163,6 +185,53 @@ class LargeSymbolPath extends graphic.Path<LargeSymbolPathProps> {
 
         return -1;
     }
+
+    contain(x: number, y: number): boolean {
+        const localPos = this.transformCoordToLocal(x, y);
+        const rect = this.getBoundingRect();
+        x = localPos[0];
+        y = localPos[1];
+
+        if (rect.contain(x, y)) {
+            // Cache found data index.
+            const dataIdx = this.hoverDataIdx = this.findDataIndex(x, y);
+            return dataIdx >= 0;
+        }
+        this.hoverDataIdx = -1;
+        return false;
+    }
+
+    getBoundingRect() {
+        // Ignore stroke for large symbol draw.
+        let rect = this._rect;
+        if (!rect) {
+            const shape = this.shape;
+            const points = shape.points;
+            const size = shape.size;
+            const w = size[0];
+            const h = size[1];
+            let minX = Infinity;
+            let minY = Infinity;
+            let maxX = -Infinity;
+            let maxY = -Infinity;
+            for (let i = 0; i < points.length;) {
+                const x = points[i++];
+                const y = points[i++];
+                minX = Math.min(x, minX);
+                maxX = Math.max(x, maxX);
+                minY = Math.min(y, minY);
+                maxY = Math.max(y, maxY);
+            }
+
+            rect = this._rect = new graphic.BoundingRect(
+                minX - w / 2,
+                minY - h / 2,
+                maxX - minX + w,
+                maxY - minY + h
+            );
+        }
+        return rect;
+    }
 }
 
 interface UpdateOpt {
@@ -198,6 +267,8 @@ class LargeSymbolDraw {
                 points = new Float32Array(points.buffer, byteOffset, len);
             }
             child.setShape('points', points);
+            // Reset draw cursor.
+            child.reset();
         });
     }
 
@@ -208,9 +279,6 @@ class LargeSymbolDraw {
     incrementalUpdate(taskParams: StageHandlerProgressParams, data: SeriesData, opt: UpdateOpt) {
         const lastAdded = this._newAdded[0];
         const points = data.getLayout('points');
-        // Clear
-        this._newAdded = [];
-
         const oldPoints = lastAdded && lastAdded.shape.points;
         // Merging the exists. Each element has 1e4 points.
         // Consider the performance balance between too much elements and too much points in one shape(may affect hover optimization)
@@ -225,6 +293,9 @@ class LargeSymbolDraw {
             lastAdded.setShape({ points: newPoints });
         }
         else {
+            // Clear
+            this._newAdded = [];
+
             const symbolEl = this._create();
             symbolEl.startIndex = taskParams.start;
             symbolEl.endIndex = taskParams.end;
@@ -242,7 +313,6 @@ class LargeSymbolDraw {
 
     private _create() {
         const symbolEl = new LargeSymbolPath({
-            rectHover: true,
             cursor: 'default'
         });
         this.group.add(symbolEl);
@@ -290,7 +360,7 @@ class LargeSymbolDraw {
         ecData.seriesIndex = (hostModel as SeriesModel).seriesIndex;
         symbolEl.on('mousemove', function (e) {
             ecData.dataIndex = null;
-            const dataIndex = symbolEl.findDataIndex(e.offsetX, e.offsetY);
+            const dataIndex = symbolEl.hoverDataIdx;
             if (dataIndex >= 0) {
                 // Provide dataIndex for tooltip
                 ecData.dataIndex = dataIndex + (symbolEl.startIndex || 0);

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