提交 ddab25f6 编写于 作者: S sushuang

support auto sampling in progressive, which makes the incremental graphic...

support auto sampling in progressive, which makes the incremental graphic elements uniformly distributed.
上级 3ebcdadd
......@@ -60,6 +60,7 @@ var CandlestickSeries = SeriesModel.extend({
progressive: 5e3,
progressiveThreshold: 1e4,
progressiveChunkMode: 'mod',
animationUpdate: false,
animationEasing: 'linear',
......
......@@ -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);
......
......@@ -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);
......
......@@ -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;
......
......@@ -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
});
......
......@@ -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();
......
......@@ -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>
......
......@@ -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) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册