blob: b5a60af94593d682293d4219219534a2c71fcdfc [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { each } from 'zrender/src/core/util';
import Group from 'zrender/src/container/Group';
import * as componentUtil from '../util/component';
import * as clazzUtil from '../util/clazz';
import * as modelUtil from '../util/model';
import * as graphicUtil from '../util/graphic';
import { createTask } from '../stream/task';
import createRenderPlanner from '../chart/helper/createRenderPlanner';
var inner = modelUtil.makeInner();
var renderPlanner = createRenderPlanner();
function Chart() {
/**
* @type {module:zrender/container/Group}
* @readOnly
*/
this.group = new Group();
/**
* @type {string}
* @readOnly
*/
this.uid = componentUtil.getUID('viewChart');
this.renderTask = createTask({
plan: renderTaskPlan,
reset: renderTaskReset
});
this.renderTask.context = {
view: this
};
}
Chart.prototype = {
type: 'chart',
/**
* Init the chart.
* @param {module:echarts/model/Global} ecModel
* @param {module:echarts/ExtensionAPI} api
*/
init: function (ecModel, api) {},
/**
* Render the chart.
* @param {module:echarts/model/Series} seriesModel
* @param {module:echarts/model/Global} ecModel
* @param {module:echarts/ExtensionAPI} api
* @param {Object} payload
*/
render: function (seriesModel, ecModel, api, payload) {},
/**
* Highlight series or specified data item.
* @param {module:echarts/model/Series} seriesModel
* @param {module:echarts/model/Global} ecModel
* @param {module:echarts/ExtensionAPI} api
* @param {Object} payload
*/
highlight: function (seriesModel, ecModel, api, payload) {
toggleHighlight(seriesModel.getData(), payload, 'emphasis');
},
/**
* Downplay series or specified data item.
* @param {module:echarts/model/Series} seriesModel
* @param {module:echarts/model/Global} ecModel
* @param {module:echarts/ExtensionAPI} api
* @param {Object} payload
*/
downplay: function (seriesModel, ecModel, api, payload) {
toggleHighlight(seriesModel.getData(), payload, 'normal');
},
/**
* Remove self.
* @param {module:echarts/model/Global} ecModel
* @param {module:echarts/ExtensionAPI} api
*/
remove: function (ecModel, api) {
this.group.removeAll();
},
/**
* Dispose self.
* @param {module:echarts/model/Global} ecModel
* @param {module:echarts/ExtensionAPI} api
*/
dispose: function () {},
/**
* Rendering preparation in progressive mode.
* @param {module:echarts/model/Series} seriesModel
* @param {module:echarts/model/Global} ecModel
* @param {module:echarts/ExtensionAPI} api
* @param {Object} payload
*/
incrementalPrepareRender: null,
/**
* Render in progressive mode.
* @param {Object} params See taskParams in `stream/task.js`
* @param {module:echarts/model/Series} seriesModel
* @param {module:echarts/model/Global} ecModel
* @param {module:echarts/ExtensionAPI} api
* @param {Object} payload
*/
incrementalRender: null,
/**
* Update transform directly.
* @param {module:echarts/model/Series} seriesModel
* @param {module:echarts/model/Global} ecModel
* @param {module:echarts/ExtensionAPI} api
* @param {Object} payload
* @return {Object} {update: true}
*/
updateTransform: null,
/**
* The view contains the given point.
* @interface
* @param {Array.<number>} point
* @return {boolean}
*/
// containPoint: function () {}
/**
* @param {string} eventType
* @param {Object} query
* @param {module:zrender/Element} targetEl
* @param {Object} packedEvent
* @return {boolen} Pass only when return `true`.
*/
filterForExposedEvent: null
};
var chartProto = Chart.prototype;
chartProto.updateView = chartProto.updateLayout = chartProto.updateVisual = function (seriesModel, ecModel, api, payload) {
this.render(seriesModel, ecModel, api, payload);
};
/**
* Set state of single element
* @param {module:zrender/Element} el
* @param {string} state 'normal'|'emphasis'
* @param {number} highlightDigit
*/
function elSetState(el, state, highlightDigit) {
if (el) {
el.trigger(state, highlightDigit);
if (el.isGroup // Simple optimize.
&& !graphicUtil.isHighDownDispatcher(el)) {
for (var i = 0, len = el.childCount(); i < len; i++) {
elSetState(el.childAt(i), state, highlightDigit);
}
}
}
}
/**
* @param {module:echarts/data/List} data
* @param {Object} payload
* @param {string} state 'normal'|'emphasis'
*/
function toggleHighlight(data, payload, state) {
var dataIndex = modelUtil.queryDataIndex(data, payload);
var highlightDigit = payload && payload.highlightKey != null ? graphicUtil.getHighlightDigit(payload.highlightKey) : null;
if (dataIndex != null) {
each(modelUtil.normalizeToArray(dataIndex), function (dataIdx) {
elSetState(data.getItemGraphicEl(dataIdx), state, highlightDigit);
});
} else {
data.eachItemGraphicEl(function (el) {
elSetState(el, state, highlightDigit);
});
}
} // Enable Chart.extend.
clazzUtil.enableClassExtend(Chart, ['dispose']); // Add capability of registerClass, getClass, hasClass, registerSubTypeDefaulter and so on.
clazzUtil.enableClassManagement(Chart, {
registerWhenExtend: true
});
Chart.markUpdateMethod = function (payload, methodName) {
inner(payload).updateMethod = methodName;
};
function renderTaskPlan(context) {
return renderPlanner(context.model);
}
function renderTaskReset(context) {
var seriesModel = context.model;
var ecModel = context.ecModel;
var api = context.api;
var payload = context.payload; // ???! remove updateView updateVisual
var progressiveRender = seriesModel.pipelineContext.progressiveRender;
var view = context.view;
var updateMethod = payload && inner(payload).updateMethod;
var methodName = progressiveRender ? 'incrementalPrepareRender' : updateMethod && view[updateMethod] ? updateMethod // `appendData` is also supported when data amount
// is less than progressive threshold.
: 'render';
if (methodName !== 'render') {
view[methodName](seriesModel, ecModel, api, payload);
}
return progressMethodMap[methodName];
}
var progressMethodMap = {
incrementalPrepareRender: {
progress: function (params, context) {
context.view.incrementalRender(params, context.model, context.ecModel, context.api, context.payload);
}
},
render: {
// Put view.render in `progress` to support appendData. But in this case
// view.render should not be called in reset, otherwise it will be called
// twise. Use `forceFirstProgress` to make sure that view.render is called
// in any cases.
forceFirstProgress: true,
progress: function (params, context) {
context.view.render(context.model, context.ecModel, context.api, context.payload);
}
}
};
export default Chart;