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 2018/04/16 15:43:33 UTC
[incubator-echarts] 04/04: support auto sampling in progressive,
which makes the incremental graphic elements uniformly distributed.
This is an automated email from the ASF dual-hosted git repository.
sushuang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-echarts.git
commit ddab25f623950f31de61d12186939cb7d77e2f2a
Author: sushuang <su...@gmail.com>
AuthorDate: Mon Apr 16 23:43:05 2018 +0800
support auto sampling in progressive, which makes the incremental graphic elements uniformly distributed.
---
src/chart/candlestick/CandlestickSeries.js | 1 +
src/chart/candlestick/CandlestickView.js | 4 +-
src/chart/candlestick/candlestickLayout.js | 20 +++----
src/chart/candlestick/candlestickVisual.js | 3 +-
src/stream/Scheduler.js | 13 ++++-
src/stream/task.js | 71 +++++++++++++++++++++++--
test/candlestick-large2.html | 50 +++++++-----------
test/candlestick-large3.html | 84 ++++++++++++++++++++++--------
8 files changed, 175 insertions(+), 71 deletions(-)
diff --git a/src/chart/candlestick/CandlestickSeries.js b/src/chart/candlestick/CandlestickSeries.js
index 682cb7e..0d2d352 100644
--- a/src/chart/candlestick/CandlestickSeries.js
+++ b/src/chart/candlestick/CandlestickSeries.js
@@ -60,6 +60,7 @@ var CandlestickSeries = SeriesModel.extend({
progressive: 5e3,
progressiveThreshold: 1e4,
+ progressiveChunkMode: 'mod',
animationUpdate: false,
animationEasing: 'linear',
diff --git a/src/chart/candlestick/CandlestickView.js b/src/chart/candlestick/CandlestickView.js
index 527f62a..4200c1c 100644
--- a/src/chart/candlestick/CandlestickView.js
+++ b/src/chart/candlestick/CandlestickView.js
@@ -45,7 +45,6 @@ var CandlestickView = ChartView.extend({
},
_renderNormal: function (seriesModel) {
- // var largePoints = data.getLayout('largePoints');
var data = seriesModel.getData();
var oldData = this._data;
var group = this.group;
@@ -115,7 +114,8 @@ var CandlestickView = ChartView.extend({
var data = seriesModel.getData();
var isSimpleBox = data.getLayout('isSimpleBox');
- for (var dataIndex = params.start; dataIndex < params.end; dataIndex++) {
+ var dataIndex;
+ while ((dataIndex = params.next()) != null) {
var el;
var itemLayout = data.getItemLayout(dataIndex);
diff --git a/src/chart/candlestick/candlestickLayout.js b/src/chart/candlestick/candlestickLayout.js
index 3aa8d5c..40f6712 100644
--- a/src/chart/candlestick/candlestickLayout.js
+++ b/src/chart/candlestick/candlestickLayout.js
@@ -42,8 +42,8 @@ export default {
};
function normalProgress(params, data) {
-
- for (var dataIndex = params.start; dataIndex < params.end; dataIndex++) {
+ var dataIndex;
+ while ((dataIndex = params.next()) != null) {
var axisDimVal = data.get(cDim, dataIndex);
var openVal = data.get(openDim, dataIndex);
@@ -126,15 +126,15 @@ export default {
}
function largeProgress(params, data) {
- var segCount = params.end - params.start;
// Structure: [sign, x, yhigh, ylow, sign, x, yhigh, ylow, ...]
- var points = new LargeArr(segCount * 5);
-
- for (
- var dataIndex = params.start, offset = 0, point, tmpIn = [], tmpOut = [];
- dataIndex < params.end;
- dataIndex++
- ) {
+ var points = new LargeArr(params.count * 5);
+ var offset = 0;
+ var point;
+ var tmpIn = [];
+ var tmpOut = [];
+ var dataIndex;
+
+ while ((dataIndex = params.next()) != null) {
var axisDimVal = data.get(cDim, dataIndex);
var openVal = data.get(openDim, dataIndex);
var closeVal = data.get(closeDim, dataIndex);
diff --git a/src/chart/candlestick/candlestickVisual.js b/src/chart/candlestick/candlestickVisual.js
index 9273480..abca11e 100644
--- a/src/chart/candlestick/candlestickVisual.js
+++ b/src/chart/candlestick/candlestickVisual.js
@@ -36,7 +36,8 @@ export default {
function progress(params, data) {
- for (var dataIndex = params.start; dataIndex < params.end; dataIndex++) {
+ var dataIndex;
+ while ((dataIndex = params.next()) != null) {
var itemModel = data.getItemModel(dataIndex);
var sign = data.getItemLayout(dataIndex).sign;
diff --git a/src/stream/Scheduler.js b/src/stream/Scheduler.js
index 4dfcf80..beb5d88 100644
--- a/src/stream/Scheduler.js
+++ b/src/stream/Scheduler.js
@@ -93,7 +93,11 @@ proto.getPerformArgs = function (task, isBlock) {
&& (!pCtx || pCtx.progressiveRender)
&& task.__idxInPipeline > pipeline.bockIndex;
- return {step: incremental ? pipeline.step : null};
+ var step = incremental ? pipeline.step : null;
+ var modDataCount = pCtx && pCtx.modDataCount;
+ var modBy = modDataCount != null ? Math.ceil(modDataCount / step): null;
+
+ return {step: step, modBy: modBy, modDataCount: modDataCount};
};
proto.getPipeline = function (pipelineId) {
@@ -123,8 +127,13 @@ proto.updateStreamModes = function (seriesModel, view) {
var large = seriesModel.get('large') && dataLen >= seriesModel.get('largeThreshold');
+ // TODO: modDataCount should not updated if `appendData`, otherwise cause whole repaint.
+ // see `test/candlestick-large3.html`
+ var modDataCount = seriesModel.get('progressiveChunkMode') === 'mod' ? dataLen : null;
+
seriesModel.pipelineContext = pipeline.context = {
progressiveRender: progressiveRender,
+ modDataCount: modDataCount,
large: large
};
};
@@ -145,7 +154,7 @@ proto.restorePipelines = function (ecModel) {
progressiveEnabled: progressive
&& !(seriesModel.preventIncremental && seriesModel.preventIncremental()),
bockIndex: -1,
- step: progressive || 700, // ??? Temporarily number
+ step: Math.round(progressive || 700),
count: 0
});
diff --git a/src/stream/task.js b/src/stream/task.js
index e55b8dd..e1d19bc 100644
--- a/src/stream/task.js
+++ b/src/stream/task.js
@@ -38,6 +38,8 @@ var taskProto = Task.prototype;
* @param {Object} performArgs
* @param {number} [performArgs.step] Specified step.
* @param {number} [performArgs.skip] Skip customer perform call.
+ * @param {number} [performArgs.modBy] Sampling window size.
+ * @param {number} [performArgs.modDataCount] Sampling count.
*/
taskProto.perform = function (performArgs) {
var upTask = this._upstream;
@@ -60,12 +62,30 @@ taskProto.perform = function (performArgs) {
planResult = this._plan(this.context);
}
+ // Support sharding by mod, which changes the render sequence and makes the rendered graphic
+ // elements uniformed distributed when progress, especially when moving or zooming.
+ var lastModBy = normalizeModBy(this._modBy);
+ var lastModDataCount = this._modDataCount || 0;
+ var modBy = normalizeModBy(performArgs && performArgs.modBy);
+ var modDataCount = performArgs && performArgs.modDataCount || 0;
+ if (lastModBy !== modBy || lastModDataCount !== modDataCount) {
+ planResult = 'reset';
+ }
+
+ function normalizeModBy(val) {
+ !(val >= 1) && (val = 1); // jshint ignore:line
+ return val;
+ }
+
var forceFirstProgress;
if (this._dirty || planResult === 'reset') {
this._dirty = false;
forceFirstProgress = reset(this, skip);
}
+ this._modBy = modBy;
+ this._modDataCount = modDataCount;
+
var step = performArgs && performArgs.step;
if (upTask) {
@@ -92,9 +112,12 @@ taskProto.perform = function (performArgs) {
this._dueEnd
);
- !skip && (forceFirstProgress || start < end) && (
- this._progress({start: start, end: end}, this.context)
- );
+ if (!skip && (forceFirstProgress || start < end)) {
+ iterator.reset(start, end, modBy, modDataCount);
+ this._progress({
+ start: start, end: end, step: 1, count: end - start, next: iterator.next
+ }, this.context);
+ }
this._dueIndex = end;
// If no `outputDueEnd`, assume that output data and
@@ -120,6 +143,47 @@ taskProto.perform = function (performArgs) {
return this.unfinished();
};
+var iterator = (function () {
+
+ var end;
+ var current;
+ var modBy;
+ var modDataCount;
+ var winCount;
+
+ var it = {
+ reset: function (s, e, sStep, sCount) {
+ current = s;
+ end = e;
+
+ modBy = sStep;
+ modDataCount = sCount;
+ winCount = Math.ceil(modDataCount / modBy);
+
+ it.next = (modBy > 1 && modDataCount > 0) ? modNext : sequentialNext;
+ }
+ };
+
+ return it;
+
+ function sequentialNext() {
+ return current < end ? current++ : null;
+ }
+
+ function modNext() {
+ var dataIndex = (current % winCount) * modBy + Math.ceil(current / winCount);
+ var result = current >= end
+ ? null
+ : dataIndex < modDataCount
+ ? dataIndex
+ // If modDataCount is smaller than data.count() (consider `appendData` case),
+ // Use normal linear rendering mode.
+ : current;
+ current++;
+ return result;
+ }
+})();
+
taskProto.dirty = function () {
this._dirty = true;
this._onDirty && this._onDirty(this.context);
@@ -144,6 +208,7 @@ function reset(taskIns, skip) {
}
taskIns._progress = progress;
+ taskIns._modBy = taskIns._modDataCount = null;
var downstream = taskIns._downstream;
downstream && downstream.dirty();
diff --git a/test/candlestick-large2.html b/test/candlestick-large2.html
index ec99971..9c4019b 100644
--- a/test/candlestick-large2.html
+++ b/test/candlestick-large2.html
@@ -3,11 +3,12 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1" />
- <script src="../dist/echarts.js"></script>
+ <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="lib/frameInsight.js"></script>
<link rel="stylesheet" href="lib/reset.css" />
</head>
<body>
@@ -21,6 +22,7 @@
<div id="main0"></div>
<div id="panel0"></div>
+ <div id="duration"></div>
@@ -28,14 +30,15 @@
<script>
+ require(['echarts'], function (echarts) {
+
// The data count is from a real requirement.
var rawDataCount = 2e5;
- var progressive = 4e3;
function run() {
var data = generateOHLC(rawDataCount);
- var result = reorder(data);
- init(result.data, result.categoryData);
+ // var result = reorder(data);
+ init(data);
}
function generateOHLC(count) {
@@ -76,27 +79,6 @@
return data;
}
- function reorder(data) {
- var categoryData = new Array(data.length);
- var categoryMap = {};
- for (var i = 0; i < data.length; i++) {
- categoryData[i] = data[i][0];
- categoryMap[categoryData[i]] = i;
- }
-
- var newData = new Array(data.length);
- var step = Math.round(data.length / progressive);
- var newOffset = 0;
- for (var offset = 0; offset < step; offset++) {
- for (var i = offset; i < data.length; i += step) {
- var item = data[i].slice();
- newData[newOffset++] = item;
- item[0] = categoryMap[item[0]];
- }
- }
- return {data: newData, categoryData: categoryData};
- }
-
function calculateMA(dayCount, data) {
var result = [];
for (var i = 0, len = data.length; i < len; i++) {
@@ -113,7 +95,9 @@
return result;
}
- function init(rawData, categoryData) {
+ function init(rawData) {
+
+ frameInsight.init(echarts, 'duration');
var option = {
dataset: {
@@ -165,12 +149,12 @@
type: 'category',
scale: true,
boundaryGap : false,
+ // inverse: true,
axisLine: {onZero: false},
splitLine: {show: false},
splitNumber: 20,
min: 'dataMin',
- max: 'dataMax',
- data: categoryData
+ max: 'dataMax'
},
// {
// type: 'category',
@@ -222,14 +206,16 @@
],
series: [
{
- name: 'Fake index',
+ name: 'Data Amount: ' + echarts.format.addCommas(rawDataCount),
type: 'candlestick',
+ // progressiveMode: 'linear',
// data: data,
encode: {
x: 0,
y: [1, 4, 3, 2]
},
- progressive: progressive
+ // progressive: false
+ // progressive: progressive
// tooltip: {
// formatter: function (param) {
// var param = param[0];
@@ -291,7 +277,7 @@
var panel = document.getElementById('panel0');
var chart = testHelper.create(echarts, 'main0', {
- title: 'Fake OHLC data',
+ title: 'Progressive by mod',
option: option,
height: 550
});
@@ -337,6 +323,8 @@
run();
+ });
+
</script>
diff --git a/test/candlestick-large3.html b/test/candlestick-large3.html
index ca595ae..6361201 100644
--- a/test/candlestick-large3.html
+++ b/test/candlestick-large3.html
@@ -33,20 +33,54 @@
require(['echarts'], function (echarts) {
// The data count is from a real requirement.
- var rawDataCount = 2e5;
+ var rawDataChunkSize = 1e4;
+ var chunkCount = 20;
+
+ var minute = 60 * 1000;
+ var xValue = +new Date(2011, 0, 1);
+ var baseValue = Math.random() * 12000;
+ var xValueMin = 0;
+ var xValueMax = rawDataChunkSize * chunkCount;
+ var yValueMin = Infinity;
+ var yValueMax = -Infinity;
+
+ var rawData = [];
+ for (var i = 0; i < chunkCount; i++) {
+ rawData.push(generateOHLC(rawDataChunkSize));
+ }
+ yValueMax = Math.ceil(yValueMax);
+ yValueMin = Math.floor(yValueMin);
function run() {
- var data = generateOHLC(rawDataCount);
- // var result = reorder(data);
- init(data);
+
+ frameInsight.init(echarts, 'duration');
+
+ // var data = generateOHLC(rawDataChunkSize);
+ var chart = window.chart = init();
+
+ var loadedChunkIndex = 0;
+
+ appendData();
+
+ function appendData() {
+ if (loadedChunkIndex >= chunkCount) {
+ return;
+ }
+
+ setTimeout(function () {
+
+ chart.appendData({seriesIndex: 0, data: rawData[loadedChunkIndex]});
+
+ loadedChunkIndex++;
+
+ appendData();
+ }, 300);
+ }
}
function generateOHLC(count) {
var data = [];
- var xValue = +new Date(2011, 0, 1);
- var minute = 60 * 1000;
- var baseValue = Math.random() * 12000;
var tmpVals = new Array(4);
var dayRange = 12;
@@ -55,6 +89,12 @@
for (var j = 0; j < 4; j++) {
tmpVals[j] = (Math.random() - 0.5) * dayRange + baseValue;
+ if (tmpVals[j] < yValueMin) {
+ yValueMin = tmpVals[j];
+ }
+ if (tmpVals[j] > yValueMax) {
+ yValueMax = tmpVals[j];
+ }
}
tmpVals.sort();
@@ -95,14 +135,9 @@
return result;
}
- function init(rawData) {
-
- frameInsight.init(echarts, 'duration');
+ function init() {
var option = {
- dataset: {
- source: rawData
- },
backgroundColor: '#eee',
// animation: false,
legend: {
@@ -153,8 +188,8 @@
axisLine: {onZero: false},
splitLine: {show: false},
splitNumber: 20,
- min: 'dataMin',
- max: 'dataMax'
+ min: xValueMin,
+ max: xValueMax
},
// {
// type: 'category',
@@ -176,7 +211,9 @@
scale: true,
splitArea: {
show: true
- }
+ },
+ min: yValueMin,
+ max: yValueMax
},
// {
// scale: true,
@@ -192,27 +229,28 @@
{
type: 'inside',
// xAxisIndex: [0, 1],
- start: 10,
- end: 100
+ // start: 10,
+ // end: 100
},
{
show: true,
// xAxisIndex: [0, 1],
type: 'slider',
bottom: 10,
- start: 10,
- end: 100
+ // start: 10,
+ // end: 100
}
],
series: [
{
- name: 'Fake index',
type: 'candlestick',
+ // progressiveMode: 'linear',
// data: data,
encode: {
x: 0,
y: [1, 4, 3, 2]
},
+ // progressiveChunkMode: 'sequential'
// progressive: false
// progressive: progressive
// tooltip: {
@@ -276,11 +314,13 @@
var panel = document.getElementById('panel0');
var chart = testHelper.create(echarts, 'main0', {
- title: 'Fake OHLC data',
+ title: 'Append data and progressive by mod',
option: option,
height: 550
});
+ return chart;
+
// chart && chart.on('brushSelected', renderBrushed);
// function renderBrushed(params) {
--
To stop receiving notification emails like this one, please contact
sushuang@apache.org.
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@echarts.apache.org
For additional commands, e-mail: commits-help@echarts.apache.org