提交 bfc138af 编写于 作者: S sushuang

tweak

上级 696293d9
......@@ -62,14 +62,9 @@ symbolDrawProto.resetData = function (seriesModel, isIgnore) {
});
group.enableStream();
group.renderTask.reset();
dataEachTask.pipe(group.renderTask);
// ??? better way?
dataEachTask.pipelineId = seriesModel.uid;
dataEachTask.updateLayoutBase = true;
return dataEachTask;
seriesModel.pipeTask(dataEachTask, 'render', 'updateLayoutBase');
};
symbolDrawProto.updateLayout = function () {
......@@ -82,8 +77,8 @@ symbolDrawProto.updateLayout = function () {
var data = seriesModel.getData();
var task = createTask({
list: data,
var dataEachTask = createTask({
input: data,
progress: function (params, notify) {
var dueIndex = params.dueIndex;
for (; dueIndex < params.dueEnd; dueIndex++) {
......@@ -97,14 +92,9 @@ symbolDrawProto.updateLayout = function () {
});
group.enableStream();
// group.renderTask.reset({reuseData: true});
group.renderTask.reset();
task.pipe(group.renderTask);
// ??? better way?
task.pipelineId = group.renderTask.pipelineId = seriesModel.uid;
return task;
dataEachTask.pipe(group.renderTask);
seriesModel.pipeTask(dataEachTask, 'render');
};
symbolDrawProto.remove = function (enableAnimation) {
......
......@@ -266,6 +266,7 @@ listProto.initData = function (data, nameList, dimValueGetter) {
var dimensionInfoMap = this._dimensionInfos;
var size = data.count();
var storeSize = data.getMaxSize ? data.getMaxSize() : size;
var idList = [];
var nameRepeatCount = this._nameRepeatCount = {};
......@@ -278,7 +279,7 @@ listProto.initData = function (data, nameList, dimValueGetter) {
var dimInfo = dimensionInfoMap[dimensions[i]];
dimInfo.otherDims.itemName === 0 && (nameDimIdx = i);
var DataCtor = dataCtors[dimInfo.type];
storage[dimensions[i]] = new DataCtor(size);
storage[dimensions[i]] = new DataCtor(storeSize);
}
var self = this;
......@@ -353,67 +354,125 @@ listProto.initData = function (data, nameList, dimValueGetter) {
this._idList = idList;
};
listProto.addData = function (moreData, moreNameList) {
moreNameList = moreNameList || [];
var originalCount = data.count();
var data = this._rawData;
// ?????????
data._data.push(moreData);
listProto.getInitTask = function () {
if (!this._initTask) {
this._initTask = createTask({
input: this._rawData,
progress: zrUtil.bind(initProgress, this)
});
}
return this._initTask;
};
function initProgress(params, notify) {
var data = this._rawData;
var storage = this._storage;
var indices = this.indices;
var dimensions = this.dimensions;
var size = data.count();
var nameDimIdx;
var nameRepeatCount = this._nameRepeatCount;
var nameList = this._nameList;
var idList = this._idList;
var nameDimIdx;
// ??? nameReplaceCount is not supported!!!
// var nameRepeatCount = this._nameRepeatCount = {};
// extract ????????????
for (var i = 0; i < size; i++) {
var dataIndex = originalCount + i;
var dataItem = data.getItem(dataIndex);
// ??? duplicated code
var dueIndex = params.dueIndex;
var dueEnd = params.dueEnd;
if (__DEV__) {
dimensions.length && zrUtil.assert(storage[dimensions[0]].length >= dueEnd);
}
for (; dueIndex < params.dueEnd; dueIndex++) {
var dataItem = data.getItem(dueIndex);
// Store the data by dimensions
for (var k = 0; k < dimensions.length; k++) {
var dim = dimensions[k];
var dimStorage = storage[dim];
// PENDING NULL is empty or zero
dimStorage[dataIndex] = this._dimValueGetter(dataItem, dim, dataIndex, k);
// ??? enlarge TypedArray
dimStorage[dueIndex] = this._dimValueGetter(dataItem, dim, dueIndex, k);
}
indices.push(dataIndex);
}
// extract ??????????
// Use the name in option and create id
for (var i = 0; i < size; i++) {
var dataIndex = originalCount + i;
var dataItem = data.getItem(dataIndex);
if (!moreNameList[i] && dataItem) {
indices.push(dueIndex);
// Use the name in option and create id
if (!nameList[dueIndex] && dataItem) {
if (dataItem.name != null) {
moreNameList[i] = dataItem.name;
nameList[dueIndex] = dataItem.name;
}
else if (nameDimIdx != null) {
moreNameList[i] = storage[dimensions[nameDimIdx]][dataIndex];
}
}
var name = moreNameList[i];
// Try using the id in option
var id = dataItem && dataItem.id;
if (id == null && name) {
// Use name as id and add counter to avoid same name
nameRepeatCount[name] = nameRepeatCount[name] || 0;
id = name;
if (nameRepeatCount[name] > 0) {
id += '__ec__' + nameRepeatCount[name];
nameList[dueIndex] = storage[dimensions[nameDimIdx]][dueIndex];
}
nameRepeatCount[name]++;
}
id != null && (idList[dataIndex] = id);
nameList[dataIndex] = moreNameList[i];
// ??? do not fill idList and do not checked by nameRepeatCount.
}
};
notify(dueIndex);
}
// listProto.addData = function (moreData, moreNameList) {
// moreNameList = moreNameList || [];
// var originalCount = data.count();
// var data = this._rawData;
// // ?????????
// data._data.push(moreData);
// var storage = this._storage;
// var indices = this.indices;
// var dimensions = this.dimensions;
// var size = data.count();
// var nameDimIdx;
// var nameRepeatCount = this._nameRepeatCount;
// var nameList = this._nameList;
// var idList = this._idList;
// // extract ????????????
// for (var i = 0; i < size; i++) {
// var dataIndex = originalCount + i;
// var dataItem = data.getItem(dataIndex);
// for (var k = 0; k < dimensions.length; k++) {
// var dim = dimensions[k];
// var dimStorage = storage[dim];
// // PENDING NULL is empty or zero
// dimStorage[dataIndex] = this._dimValueGetter(dataItem, dim, dataIndex, k);
// }
// indices.push(dataIndex);
// }
// // extract ??????????
// // Use the name in option and create id
// for (var i = 0; i < size; i++) {
// var dataIndex = originalCount + i;
// var dataItem = data.getItem(dataIndex);
// if (!moreNameList[i] && dataItem) {
// if (dataItem.name != null) {
// moreNameList[i] = dataItem.name;
// }
// else if (nameDimIdx != null) {
// moreNameList[i] = storage[dimensions[nameDimIdx]][dataIndex];
// }
// }
// var name = moreNameList[i];
// // Try using the id in option
// var id = dataItem && dataItem.id;
// if (id == null && name) {
// // Use name as id and add counter to avoid same name
// nameRepeatCount[name] = nameRepeatCount[name] || 0;
// id = name;
// if (nameRepeatCount[name] > 0) {
// id += '__ec__' + nameRepeatCount[name];
// }
// nameRepeatCount[name]++;
// }
// id != null && (idList[dataIndex] = id);
// nameList[dataIndex] = moreNameList[i];
// }
// };
/**
* @return {number}
......@@ -814,7 +873,7 @@ listProto.createEachTask = function (dims, cb, stack) {
return createTask({
list: list,
input: list,
progress: function (params, notify) {
var dimSize = dims.length;
......@@ -1303,6 +1362,21 @@ listProto.cloneShallow = function () {
return list;
};
// ??? duplicate with cloneShallow?
listProto.createCloneShallowTask = function () {
return createTask({
input: this,
output: this.cloneShallow(),
progress: function (params, notify) {
var dueIndex = params.dueIndex;
for (; dueIndex < params.dueEnd; dueIndex++) {
this.output.indices[dueIndex] = this.input.indices[dueIndex];
}
notify(dueIndex);
}
});
};
// ???
listProto.getFrameDataIndex = function () {
return this._frameDataIndex;
......
......@@ -43,7 +43,6 @@ export var dependencies = {
// ??? frame remain time in UI thread: 20ms? 16ms?
var TEST_FRAME_REMAIN_TIME = 1;
var TEST_PROGRESS_STEP = 300;
var PRIORITY_PROCESSOR_FILTER = 1000;
var PRIORITY_PROCESSOR_STATISTIC = 5000;
......@@ -80,11 +79,9 @@ var HAS_GRADIENT_OR_PATTERN_BG = '__hasGradientOrPatternBg';
var OPTION_UPDATED = '__optionUpdated';
var ACTION_REG = /^[a-zA-Z0-9_]+$/;
var UNFINISHED_INDEX_DATA = 0;
var UNFINISHED_INDEX_PROCESSOR = 1;
var UNFINISHED_INDEX_VISUAL = 2;
var UNFINISHED_INDEX_RENDER = 3;
// ??? defined in scheduler?
var STAGE_DATA_INIT = 'dataInit';
var STAGE_DATA_CLONE = 'dataClone';
var STAGE_PROCESSOR = 'processor';
var STAGE_VISUAL = 'visual';
var STAGE_RENDER = 'render';
......@@ -206,13 +203,6 @@ function ECharts(dom, theme, opts) {
*/
this._api = createExtensionAPI(this);
// ??? reset when setOption(not merge)?
/**
* @type {Array.<boolean>}
*/
this._unfinished = [];
// ??? reset when setOption(not merge)?
/**
* @type {module:echarts/stream/Scheduler}
*/
......@@ -252,8 +242,7 @@ function ECharts(dom, theme, opts) {
var echartsProto = ECharts.prototype;
echartsProto._onframe = function () {
// ???
if (this.isDisposed()) {
if (this._disposed) {
return;
}
......@@ -263,6 +252,7 @@ echartsProto._onframe = function () {
this[IN_MAIN_PROCESS] = true;
// ??? conflict?
updateMethods.prepareAndUpdate.call(this);
this[IN_MAIN_PROCESS] = false;
......@@ -274,46 +264,32 @@ echartsProto._onframe = function () {
triggerUpdatedEvent.call(this, silent);
}
progressInFrame(this);
};
function progressInFrame(ecIns) {
// Stream progress.
var remainTime = TEST_FRAME_REMAIN_TIME;
var unfinished = ecIns._unfinished;
var b;
do {
var startTime = +new Date();
if (unfinished[UNFINISHED_INDEX_PROCESSOR]) {
b = 1;
updateUnfinished(unfinished, progressStage(ecIns, STAGE_PROCESSOR), UNFINISHED_INDEX_PROCESSOR);
}
var scheduler = this._scheduler;
// ???
// coordSys update
if (scheduler.unfinished) {
scheduler.unfinished = false;
do {
var startTime = +new Date();
scheduler.progressStage(STAGE_DATA_INIT);
scheduler.progressStage(STAGE_DATA_CLONE);
scheduler.progressStage(STAGE_PROCESSOR);
// ???
// coordSys update
if (unfinished[UNFINISHED_INDEX_VISUAL]) {
// console.log('------------- ec frame visual -------------', remainTime);
b = 1;
updateUnfinished(unfinished, progressStage(ecIns, STAGE_VISUAL), UNFINISHED_INDEX_VISUAL);
}
if (unfinished[UNFINISHED_INDEX_RENDER]) {
b = 1;
updateUnfinished(unfinished, progressRender(ecIns, ecIns._model), UNFINISHED_INDEX_RENDER);
}
scheduler.progressStage(STAGE_VISUAL);
remainTime -= (+new Date() - startTime);
}
while (remainTime > 0 && (
unfinished[UNFINISHED_INDEX_PROCESSOR]
|| unfinished[UNFINISHED_INDEX_VISUAL]
|| unfinished[UNFINISHED_INDEX_RENDER]
));
progressRender(this, this._model);
if (b) {
console.log(ecIns._scheduler._pipelines);
}
}
remainTime -= (+new Date() - startTime);
}
while (remainTime > 0 && scheduler.unfinished);
}
};
/**
......@@ -362,6 +338,7 @@ echartsProto.setOption = function (option, notMerge, lazyUpdate) {
var optionManager = new OptionManager(this._api);
var theme = this._theme;
var ecModel = this._model = new GlobalModel(null, null, theme, optionManager);
ecModel.scheduler = this._scheduler;
ecModel.init(null, null, theme, optionManager);
}
......@@ -770,20 +747,18 @@ var updateMethods = {
var api = this._api;
var zr = this._zr;
var coordSysMgr = this._coordSysMgr;
var scheduler = this._scheduler;
// update before setOption
if (!ecModel) {
return;
}
scheduler.clearTemps();
// Fixme First time update ?
ecModel.restoreData();
// Reset pipeline.
this._scheduler.clear();
each(ecModel.getSeries(), function (series) {
this._scheduler.addPipeline(series.uid);
}, this);
// TODO
// Save total ecModel here for undo/redo (after restoring data and before processing data).
// Undo (restoration of total ecModel) can be carried out in 'action' or outside API call.
......@@ -804,6 +779,8 @@ var updateMethods = {
startRender(this, ecModel, api, payload);
scheduler.flushTemps('updateBase');
// Set background
var backgroundColor = ecModel.get('backgroundColor') || 'transparent';
......@@ -864,14 +841,18 @@ var updateMethods = {
return;
}
this._scheduler.clearTemps();
ecModel.eachSeries(function (seriesModel) {
seriesModel.getData().clearAllVisual();
});
// Keep pipe to the exist pipeline because it depends on the render task of the full pipeline.
startVisualEncoding(this, ecModel, this._api, payload, null, 'updateViewBase');
startVisualEncoding(this, ecModel, this._api, payload, null);
invokeUpdateMethod.call(this, 'updateView', ecModel, payload);
this._scheduler.flushTemps('updateViewBase');
},
/**
......@@ -886,14 +867,18 @@ var updateMethods = {
return;
}
this._scheduler.clearTemps();
ecModel.eachSeries(function (seriesModel) {
seriesModel.getData().clearAllVisual();
});
// Keep pipe to the exist pipeline because it depends on the render task of the full pipeline.
startVisualEncoding(this, ecModel, this._api, payload, false, 'updateVisualBase');
startVisualEncoding(this, ecModel, this._api, payload, false);
invokeUpdateMethod.call(this, 'updateVisual', ecModel, payload);
this._scheduler.flushTemps('updateVisualBase');
},
/**
......@@ -908,10 +893,14 @@ var updateMethods = {
return;
}
this._scheduler.clearTemps();
// Keep pipe to the exist pipeline because it depends on the render task of the full pipeline.
startVisualEncoding(this, ecModel, this._api, payload, true, 'updateLayoutBase');
startVisualEncoding(this, ecModel, this._api, payload, true);
invokeUpdateMethod.call(this, 'updateLayout', ecModel, payload);
this._scheduler.flushTemps('updateLayoutBase');
},
/**
......@@ -1179,32 +1168,19 @@ function triggerUpdatedEvent(silent) {
!silent && this.trigger('updated');
}
// ??????
// echartsProto.addData = function (params) {
// var seriesIndex = params.seriesIndex;
// var moreData = params.data;
// var ecModel = this.getModel();
// var seriesModel = ecModel.getSeries(seriesIndex);
// var rawData = seriesModel.getRawData();
// rawData.addData(moreData);
// // ?????
// ???
echartsProto.addData = function (params) {
var seriesIndex = params.seriesIndex;
var ecModel = this.getModel();
var seriesModel = ecModel.getSeries(seriesIndex);
// // ??? addData 应该是继续渲染而不是重启全部渲染?
// // 什么场景下需要重启全部渲染?
// updateMethods.update();
// // ??????
// if (rawData.count() > rawData.getChunkSize()) {
// requestAnimationFrame(step);
// }
if (__DEV__) {
zrUtil.assert(params.data && seriesModel);
}
// function step() {
// // if (rawData.
// }
// };
var rawData = seriesModel.getRawData();
rawData.addData(params.data);
};
/**
* Register event
......@@ -1232,11 +1208,9 @@ function invokeUpdateMethod(methodName, ecModel, payload) {
// ??? duplicate code with `startRender`?
// Upate all charts
var scheduler = this._scheduler;
ecModel.eachSeries(function (seriesModel, idx) {
var chart = this._chartsMap[seriesModel.__viewId];
var task = chart[methodName](seriesModel, ecModel, api, payload);
task && scheduler.pipeTasks([task], STAGE_RENDER);
chart[methodName](seriesModel, ecModel, api, payload);
// ??? updateZ(seriesModel, chart);
......@@ -1346,10 +1320,8 @@ function stackSeriesData(ecModel) {
*/
function startProcessors(ecIns, ecModel, api) {
each(dataProcessorFuncs, function (processor, index) {
var tasks = processor.func(ecModel, api);
ecIns._scheduler.pipeTasks(tasks, STAGE_PROCESSOR);
processor.func(ecModel, api);
});
updateUnfinished(ecIns._unfinished, true, UNFINISHED_INDEX_PROCESSOR);
}
/**
......@@ -1360,10 +1332,10 @@ function startProcessors(ecIns, ecModel, api) {
* @param {boolean} [layoutFilter] `true`: only layout,
* `false`: only not layout,
* `null`/`undefined`: all.
* @param {string} partialBase
* @param {string} taskBaseTag
* @private
*/
function startVisualEncoding(ecIns, ecModel, api, payload, layoutFilter, partialBase) {
function startVisualEncoding(ecIns, ecModel, api, payload, layoutFilter) {
if (layoutFilter !== true) {
ecModel.clearColorPalette();
ecModel.eachSeries(function (seriesModel) {
......@@ -1377,12 +1349,9 @@ function startVisualEncoding(ecIns, ecModel, api, payload, layoutFilter, partial
|| (layoutFilter === false && !isLayout)
|| (layoutFilter === true && isLayout)
) {
var tasks = visual.func(ecModel, api, payload);
ecIns._scheduler.pipeTasks(tasks, STAGE_VISUAL, partialBase);
visual.func(ecModel, api, payload);
}
});
updateUnfinished(ecIns._unfinished, true, UNFINISHED_INDEX_VISUAL);
}
/**
......@@ -1402,16 +1371,13 @@ function startRender(ecIns, ecModel, api, payload) {
chart.__alive = false;
});
var scheduler = ecIns._scheduler;
// ??? The key should be `__viewId` but not index. consider view change !!!
// Render all charts
ecModel.eachSeries(function (seriesModel) {
var chartView = ecIns._chartsMap[seriesModel.__viewId];
chartView.__alive = true;
var task = chartView.render(seriesModel, ecModel, api, payload);
task && scheduler.pipeTasks([task], STAGE_RENDER);
chartView.render(seriesModel, ecModel, api, payload);
// ??? chartView.group.silent = !!seriesModel.get('silent');
......@@ -1430,15 +1396,11 @@ function startRender(ecIns, ecModel, api, payload) {
chart.remove(ecModel, api);
}
});
// ??? add upateUnfinished to other partial update render!
updateUnfinished(ecIns._unfinished, true, UNFINISHED_INDEX_RENDER);
}
function progressRender(ecIns, ecModel) {
var unfinished;
unfinished |= progressStage(ecIns, STAGE_RENDER);
ecIns._scheduler.progressStage(STAGE_RENDER);
// ???
// ecModel.eachSeries(function (seriesModel, idx) {
......@@ -1450,23 +1412,8 @@ function progressRender(ecIns, ecModel) {
// ??? updateProgressiveAndBlend(seriesModel, chartView);
// });
return unfinished;
}
function progressStage(ecIns, stage) {
var unfinished;
var tasks = ecIns._scheduler.getTasksByStage(stage);
each(tasks, function (task) {
task.progress({
step: TEST_PROGRESS_STEP
});
unfinished |= task.unfinished();
});
return unfinished;
}
var MOUSE_EVENT_NAMES = [
'click', 'dblclick', 'mouseover', 'mouseout', 'mousemove',
'mousedown', 'mouseup', 'globalout', 'contextmenu'
......@@ -1616,15 +1563,6 @@ function updateProgressiveAndBlend(seriesModel, chartView) {
});
}
function updateUnfinished(undefinedRecord, unfi, stageIndex) {
var count = Math.max(undefinedRecord.length, stageIndex + 1);
undefinedRecord[stageIndex] = unfi;
for (++stageIndex; stageIndex < count; stageIndex++) {
// update process should clear consequent visual stage using xor.
undefinedRecord[stageIndex] |= unfi;
}
}
/**
* @param {module:echarts/model/Series|module:echarts/model/Component} model
* @param {module:echarts/view/Component|module:echarts/view/Chart} view
......
export default function (seriesType, ecModel) {
var tasks = [];
ecModel.eachSeriesByType(seriesType, function (seriesModel) {
var task = createTask(seriesType, seriesModel);
if (task) {
// ??? better way?
task.pipelineId = seriesModel.uid;
tasks.push(task);
}
seriesModel.pipeTask(
createTask(seriesType, seriesModel),
'visual'
);
});
return tasks;
}
function createTask(seriesType, seriesModel) {
......
......@@ -126,6 +126,7 @@ var GlobalModel = Model.extend({
var option = this.option;
var componentsMap = this._componentsMap;
var newCptTypes = [];
var scheduler = this.scheduler;
// 如果不存在对应的 component model 则直接 merge
each(newOption, function (componentOption, mainType) {
......@@ -151,6 +152,7 @@ var GlobalModel = Model.extend({
this._seriesIndices = this._seriesIndices || [];
function visitComponent(mainType, dependencies) {
var newCptOptionList = modelUtil.normalizeToArray(newOption[mainType]);
var mapResult = modelUtil.mappingToExists(
......@@ -213,6 +215,9 @@ var GlobalModel = Model.extend({
componentModel = new ComponentModelClass(
newCptOption, this, this, extraOpt
);
if (mainType === 'series') {
this.scheduler.initPipeline(componentModel);
}
zrUtil.extend(componentModel, extraOpt);
componentModel.init(newCptOption, this, this, extraOpt);
// Call optionUpdated after init.
......@@ -229,7 +234,11 @@ var GlobalModel = Model.extend({
// Backup series for filtering.
if (mainType === 'series') {
this._seriesIndices = createSeriesIndices(componentsMap.get('series'));
var seriesModels = componentsMap.get('series');
this._seriesIndices = createSeriesIndices(seriesModels);
// Reset pipeline, should be after `restoreData`.
scheduler.clearUnusedPipelines(seriesModels);
scheduler.flushTemps('start', seriesModels);
}
}
},
......
......@@ -139,6 +139,14 @@ OptionManager.prototype = {
* @return {Object} Init option
*/
setOption: function (rawOption, optionPreprocessorFuncs) {
// ??? not a good way?
if (rawOption) {
// axis.data?
zrUtil.each(modelUtil.normalizeToArray(rawOption.series), function (series) {
series && series.data && zrUtil.setAsPrimitive(series.data);
});
}
rawOption = clone(rawOption, true);
// FIXME
......
......@@ -82,18 +82,14 @@ var SeriesModel = ComponentModel.extend({
*/
set(this, 'dataBeforeProcessed', data);
/**
* @type {Array}
* @private
*/
set(this, 'tasks', []);
// If we reverse the order (make data firstly, and then make
// dataBeforeProcessed by cloneShallow), cloneShallow will
// cause data.graph.data !== data when using
// module:echarts/data/Graph or module:echarts/data/Tree.
// See module:echarts/data/helper/linkList
this.restoreData();
// ??? should not restoreData here? but called by echart?
// this.restoreData();
},
/**
......@@ -140,10 +136,11 @@ var SeriesModel = ComponentModel.extend({
}
var data = this.getInitialData(newSeriesOption, ecModel);
// TODO Merge data?
if (data) {
set(this, 'data', data);
set(this, 'dataBeforeProcessed', data.cloneShallow());
// ??? progress data?
set(this, 'dataBeforeProcessed', data);
// ??? should not restoreData here? but called by echart?
// this.restoreData();
}
},
......@@ -324,7 +321,14 @@ var SeriesModel = ComponentModel.extend({
},
restoreData: function () {
set(this, 'data', get(this, 'dataBeforeProcessed').cloneShallow());
var dataBeforeProcessed = get(this, 'dataBeforeProcessed');
var dataCloneTask = dataBeforeProcessed.createCloneShallowTask();
set(this, 'data', dataCloneTask.output);
var dataInitTask = dataBeforeProcessed.getInitTask();
this.pipeTask(dataInitTask, 'dataInit');
this.pipeTask(dataCloneTask, 'dataClone', 'updateBase');
},
getColorFromPalette: function (name, scope) {
......@@ -355,30 +359,10 @@ var SeriesModel = ComponentModel.extend({
*/
getTooltipPosition: null,
// clearPipedTasks: function () {
// get(this, 'tasks').length = 0;
// },
// pipe: function (task) {
// var tasks = get(this, 'tasks');
// var lastTask = tasks[tasks.length - 1];
// lastTask && lastTask.pipe(task);
// tasks.push(task);
// // ??? parallel task? multi-dependency?
// // ??? A bad practice?
// var originalRemove = task.leave;
// task.leave = function () {
// var i = 0;
// for (; i < tasks.length; i++) {
// if (tasks[i] === task) {
// break;
// }
// }
// tasks.length = i;
// originalRemove.call(this);
// };
// }
/**
* @see {module:echarts/stream/Scheduler}
*/
pipeTask: null
// /**
// * @public
......
......@@ -3,63 +3,135 @@
*/
import {__DEV__} from '../config';
import {assert, each} from 'zrender/src/core/util';
import {assert, each, createHashMap, makeInner} from 'zrender/src/core/util';
import {normalizeToArray} from '../util/model';
var inner = makeInner();
/**
* @const
*/
var STAGE = {
dataInit: 0,
dataClone: 1,
processor: 2,
visual: 3,
render: 4
};
var TAG = {
updateBase: 1,
updateLayoutBase: 1,
updateVisualBase: 1,
updateViewBase: 1
};
var TEST_PROGRESS_STEP = 300;
/**
* @constructor
*/
function Scheduler() {
this.clear();
this._pipelineMap = createHashMap();
var stageMap = this._stageMap = createHashMap();
each(STAGE, function (value, name) {
stageMap.set(name, []);
});
// this._stageUnfinished = [];
this.unfinished;
}
var proto = Scheduler.prototype;
/**
* Clear all tasks.
*/
proto.clear = function () {
this._pipelines = {};
this._stage = {
processor: [],
visual: [],
render: []
};
};
proto.progressStage = function (stage) {
// if (!this._stageUnfinished[STAGE[stage]]) {
// return;
// }
proto.addPipeline = function (pipelineId) {
this._pipelines[pipelineId] = [];
var unfinished;
var tasks = this.getTasksByStage(stage);
each(tasks, function (task) {
task.progress({
step: TEST_PROGRESS_STEP
});
unfinished |= task.unfinished();
});
this.unfinished |= unfinished;
};
/**
* @param {Array} tasks Can be `null`/`undefined`. Should has `task.pipelineId`. // ???
* @param {string} stage 'processor', 'visual', 'render'
* @param {string} [partialBase] 'updateLayoutBase', 'updateVisualBase' or 'updateViewBase'
* @param {Object} host Should has uid.
*/
proto.pipeTasks = function (tasks, stage, partialBase) {
var pipelines = this._pipelines;
each(tasks, function (task) {
var pipeline = pipelines[task.pipelineId];
proto.initPipeline = function (host) {
var pipelineId = host.uid;
if (__DEV__) {
assert(!this._pipelineMap.get(pipelineId) && !host.pipeTask);
}
var pipeline = {tasks: [], temps: []};
this._pipelineMap.set(pipelineId, pipeline);
if (__DEV__) {
assert(pipeline);
each(pipeline, function (taskInPipeline) {
assert(taskInPipeline != task);
});
}
// Inject method pipeTask
host.pipeTask = hostPipeTask;
inner(host).temps = pipeline.temps;
};
var baseTask = partialBase
? findAddClearPartialBase(pipeline, partialBase)
: pipeline[pipeline.length - 1];
function hostPipeTask(task, stage, tags) {
task && inner(this).temps.push({task: task, stage: stage, tags: tags});
}
baseTask && baseTask.pipe(task);
/**
* @param {Array.<Object>} allHosts Should has uid.
*/
proto.clearUnusedPipelines = function (allHosts) {
var pipelineMap = this._pipelineMap;
var idMap = createHashMap();
var stageMap = this._stageMap;
each(allHosts, function (host) {
idMap.set(host.uid, 1);
});
pipelineMap.each(function (pipeline, id) {
if (!idMap.get(id)) {
clearPipeline(stageMap, pipeline, -1);
pipelineMap.set(id, null);
}
});
};
pipeline.push(task);
proto.clearTemps = function () {
this._pipelineMap.each(clearPipelineTemp);
};
// ??? Should keep the original register order of tasks
// within single stage. Especially visual and layout.
stage && this._stage[stage].push(task);
function clearPipelineTemp(pipeline) {
pipeline.temps.length = 0;
}
}, this);
/**
* @param {string} tag
* @param {Array.<Object>} [hosts]
*/
proto.flushTemps = function (tag, hosts) {
var pipelineMap = this._pipelineMap;
var stageMap = this._stageMap;
var self = this;
hosts
? each(hosts, function (host) {
flushPipelineTemps(pipelineMap.get(host.uid));
})
: pipelineMap.each(flushPipelineTemps);
function flushPipelineTemps(pipeline) {
clearPipelineDownstreams(stageMap, pipeline, tag);
each(pipeline.temps, function (tmp) {
self.unfinished = true;
pipeTask(stageMap, pipeline.tasks, tmp.task, tmp.stage, tmp.tags);
}, this);
clearPipelineTemp(pipeline);
}
};
/**
......@@ -68,56 +140,82 @@ proto.pipeTasks = function (tasks, stage, partialBase) {
* who are partial streams, depending on the render task of the full stream,
* and should be cleared if another partial stream is started.
*/
function findAddClearPartialBase(pipeline, partialBase) {
function clearPipelineDownstreams(stageMap, pipeline, tag) {
var tasks = pipeline.tasks;
var baseIndex;
for (var i = 0; i < pipeline.length; i++) {
if (pipeline[i][partialBase]) {
baseIndex = i;
break;
if (tag === 'start') {
baseIndex = -1;
}
else {
for (var i = 0; i < tasks.length; i++) {
if (inner(tasks[i])[tag]) {
baseIndex = i;
break;
}
}
}
clearPipeline(stageMap, pipeline, baseIndex);
}
function pipeTask(stageMap, pipelineTasks, task, stage, tags) {
if (__DEV__) {
// In case the developer do not mark a task by partailBase.
assert(baseIndex != null);
// In case typo.
stage && assert(STAGE[stage] != null);
each(pipelineTasks, function (taskInPipeline) {
assert(taskInPipeline != task);
});
}
// Clear from baseTask
var baseTask = pipeline[baseIndex];
baseTask.clearDownstreams();
pipeline.length = baseIndex + 1;
each(normalizeToArray(tags), function (tag) {
if (__DEV__) {
assert(TAG[tag]);
}
inner(task)[tag] = true;
});
pipelineTasks.length && pipelineTasks[pipelineTasks.length - 1].pipe(task);
pipelineTasks.push(task);
return baseTask;
// ??? Should keep the original register order of tasks
// within single stage. Especially visual and layout.
stage && stageMap.get(stage).push(task);
}
// keyInfo: {stage, tag}
proto.getTasksByStage = function (stage) {
return this._stage[stage].slice();
return this._stageMap.get(stage).slice();
};
// ???
// // keyInfo: {stage, tag}
// proto.getTasksByTag = function (pipelineId, tag) {
// var tasks = [];
// each(this._pipelines[pipelineId], function (wrap) {
// wrap.tag === tag && tasks.push(wrap.task);
// });
// return tasks;
// };
// ???
// proto.unpipeTaskByKey = function (key) {
// each(this._pipelines, function (pipeline) {
// var index = 0;
// for (; index < pipeline.length; index++) {
// if (pipeline[index].key === key) {
// break;
// }
// }
// if (index > 0 && index < pipeline.length) {
// pipeline[index - 1].unpipe(pipeline[index]);
// }
// pipeline.length = index;
// });
// };
// taskBaseIndex can be -1;
function clearPipeline(stageMap, pipeline, taskBaseIndex) {
var tasks = pipeline.tasks;
if (!tasks.length) {
return;
}
if (taskBaseIndex === -1) {
var taskBase = tasks[0];
taskBase.clearDownstreams();
taskBase.reset();
}
else {
tasks[taskBaseIndex].clearDownstreams();
}
for (var i = taskBaseIndex + 1; i < tasks.length; i++) {
inner(tasks[i]).cleared = 1;
}
tasks.length = taskBaseIndex + 1;
stageMap.each(function (stageTasks) {
for (var i = stageTasks.length - 1; i >= 0; i--) {
if (inner(stageTasks[i]).cleared) {
stageTasks.splice(i, 1);
}
}
});
i = 10;
}
export default Scheduler;
export default function (seriesType, defaultSymbolType, legendSymbol, ecModel) {
var tasks = [];
// Encoding visual for all series include which is filtered for legend drawing
ecModel.eachRawSeriesByType(seriesType, function (seriesModel) {
var task = createTask(seriesModel, defaultSymbolType, legendSymbol, ecModel);
if (task) {
// ??? better way?
task.pipelineId = seriesModel.uid;
tasks.push(task);
}
seriesModel.pipeTask(
createTask(seriesModel, defaultSymbolType, legendSymbol, ecModel),
'visual'
);
});
return tasks;
}
function createTask(seriesModel, defaultSymbolType, legendSymbol, ecModel) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册