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