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 2020/09/24 06:57:49 UTC
[incubator-echarts] branch list-remove-chunk updated: perf:
optimize lttb downsample performance.
This is an automated email from the ASF dual-hosted git repository.
shenyi pushed a commit to branch list-remove-chunk
in repository https://gitbox.apache.org/repos/asf/incubator-echarts.git
The following commit(s) were added to refs/heads/list-remove-chunk by this push:
new 03bf01c perf: optimize lttb downsample performance.
03bf01c is described below
commit 03bf01c9d8f3769b2ace7d38cd130c0b4c213c21
Author: pissang <bm...@gmail.com>
AuthorDate: Thu Sep 24 14:57:15 2020 +0800
perf: optimize lttb downsample performance.
---
src/chart/line/poly.ts | 2 +-
src/data/List.ts | 51 ++++++++++++++++++++-------------------------
src/processor/dataSample.ts | 7 +++----
3 files changed, 27 insertions(+), 33 deletions(-)
diff --git a/src/chart/line/poly.ts b/src/chart/line/poly.ts
index 24a14f6..2f341da 100644
--- a/src/chart/line/poly.ts
+++ b/src/chart/line/poly.ts
@@ -77,7 +77,7 @@ function drawSegment(
const dy = y - prevY;
// Ignore tiny segment.
- if ((dx * dx + dy * dy) < 1) {
+ if ((dx * dx + dy * dy) < 0.5) {
idx += dir;
continue;
}
diff --git a/src/data/List.ts b/src/data/List.ts
index d13ae70..d38e03a 100644
--- a/src/data/List.ts
+++ b/src/data/List.ts
@@ -1625,73 +1625,67 @@ class List<
/**
* Large data down sampling using largest-triangle-three-buckets
- * @param {string} baseDimension
* @param {string} valueDimension
* @param {number} targetCount
*/
lttbDownSample(
- baseDimension: DimensionName,
valueDimension: DimensionName,
- targetCount: number
+ rate: number
) {
const list = cloneListForMapAndSample(this, []);
const targetStorage = list._storage;
- const baseDimStore = targetStorage[baseDimension];
- const valueDimStore = targetStorage[valueDimension];
+ const dimStore = targetStorage[valueDimension];
const len = this.count();
const newIndices = new (getIndicesCtor(this))(len);
let sampledIndex = 0;
- const frameSize = (len - 2) / (targetCount - 2);
+ const frameSize = mathFloor(1 / rate);
let currentRawIndex = this.getRawIndex(0);
let maxArea;
let area;
let nextRawIndex;
+ // First frame use the first data.
newIndices[sampledIndex++] = currentRawIndex;
- for (let i = 0; i < targetCount - 2; i++) {
- let avgX = 0;
- let avgY = 0;
- const avgRangeStart = mathFloor((i + 1) * frameSize) + 1;
- const avgRangeEnd = Math.min(mathFloor((i + 2) * frameSize) + 1, len);
+ for (let i = 1; i < len - 1; i += frameSize) {
+ const nextFrameStart = Math.min(i + frameSize, len - 1);
+ const nextFrameEnd = Math.min(i + frameSize * 2, len);
- const avgRangeLength = avgRangeEnd - avgRangeStart;
+ const avgX = (nextFrameEnd + nextFrameStart) / 2;
+ let avgY = 0;
- for (let idx = avgRangeStart; idx < avgRangeEnd; idx++) {
+ for (let idx = nextFrameStart; idx < nextFrameEnd; idx++) {
const rawIndex = this.getRawIndex(idx);
- const x = baseDimStore[rawIndex] as number;
- const y = valueDimStore[rawIndex] as number;
- if (isNaN(x) || isNaN(y)) {
+ const y = dimStore[rawIndex] as number;
+ if (isNaN(y)) {
continue;
}
- avgX += x as number;
avgY += y as number;
}
- avgX /= avgRangeLength;
- avgY /= avgRangeLength;
+ avgY /= (nextFrameEnd - nextFrameStart);
- const rangeOffs = mathFloor((i) * frameSize) + 1;
- const rangeTo = mathFloor((i + 1) * frameSize) + 1;
+ const frameStart = i;
+ const frameEnd = Math.min(i + frameSize, len);
- const pointAX = baseDimStore[currentRawIndex] as number;
- const pointAY = valueDimStore[currentRawIndex] as number;
+ const pointAX = i - 1;
+ const pointAY = dimStore[currentRawIndex] as number;
maxArea = -1;
+ nextRawIndex = frameStart;
// Find a point from current frame that construct a triangel with largest area with previous selected point
// And the average of next frame.
- for (let idx = rangeOffs; idx < rangeTo; idx++) {
+ for (let idx = frameStart; idx < frameEnd; idx++) {
const rawIndex = this.getRawIndex(idx);
- const x = baseDimStore[rawIndex] as number;
- const y = valueDimStore[rawIndex] as number;
- if (isNaN(x) || isNaN(y)) {
+ const y = dimStore[rawIndex] as number;
+ if (isNaN(y)) {
continue;
}
// Calculate triangle area over three buckets
area = Math.abs((pointAX - avgX) * (y - pointAY)
- - (pointAX - x) * (avgY - pointAY)
+ - (pointAX - idx) * (avgY - pointAY)
);
if (area > maxArea) {
maxArea = area;
@@ -1704,6 +1698,7 @@ class List<
currentRawIndex = nextRawIndex; // This a is the next a (chosen b)
}
+ // First frame use the last data.
newIndices[sampledIndex++] = this.getRawIndex(len - 1);
list._count = sampledIndex;
list._indices = newIndices;
diff --git a/src/processor/dataSample.ts b/src/processor/dataSample.ts
index 485f6df..2e2fc4c 100644
--- a/src/processor/dataSample.ts
+++ b/src/processor/dataSample.ts
@@ -88,15 +88,14 @@ export default function (seriesType: string): StageHandler {
const baseAxis = coordSys.getBaseAxis();
const valueAxis = coordSys.getOtherAxis(baseAxis);
const extent = baseAxis.getExtent();
+ const dpr = api.getDevicePixelRatio();
// Coordinste system has been resized
- const size = Math.abs(extent[1] - extent[0]);
+ const size = Math.abs(extent[1] - extent[0]) * (dpr || 1);
const rate = Math.round(data.count() / size);
if (rate > 1) {
if (sampling === 'lttb') {
- seriesModel.setData(data.lttbDownSample(
- data.mapDimension(baseAxis.dim), data.mapDimension(valueAxis.dim), size
- ));
+ seriesModel.setData(data.lttbDownSample(data.mapDimension(valueAxis.dim), 1 / rate));
}
let sampler;
if (typeof sampling === 'string') {
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@echarts.apache.org
For additional commands, e-mail: commits-help@echarts.apache.org