suoqiu-f2
Version:
Charts for mobile visualization.
868 lines (849 loc) • 25.4 kB
JavaScript
"use strict";
exports.__esModule = true;
exports["default"] = void 0;
var _const = require("./const");
var _base = _interopRequireDefault(require("../base"));
var _plot = _interopRequireDefault(require("./plot"));
var _common = require("../util/common");
var _index = _interopRequireDefault(require("../coord/index"));
var _base2 = _interopRequireDefault(require("../geom/base"));
var _scale = _interopRequireDefault(require("./controller/scale"));
var _axis = _interopRequireDefault(require("./controller/axis"));
var _global = _interopRequireDefault(require("../global"));
var _index2 = require("../graphic/index");
var _helper = require("../util/helper");
function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
function _inheritsLoose(t, o) { t.prototype = Object.create(o.prototype), t.prototype.constructor = t, _setPrototypeOf(t, o); }
function _setPrototypeOf(t, e) { return _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function (t, e) { return t.__proto__ = e, t; }, _setPrototypeOf(t, e); }
function compare(a, b) {
return a - b;
}
function _isScaleExist(scales, compareScale) {
var flag = false;
(0, _common.each)(scales, function (scale) {
var scaleValues = [].concat(scale.values);
var compareScaleValues = [].concat(compareScale.values);
if (scale.type === compareScale.type && scale.field === compareScale.field && scaleValues.sort(compare).toString() === compareScaleValues.sort(compare).toString()) {
flag = true;
return;
}
});
return flag;
}
var Chart = /*#__PURE__*/function (_Base) {
function Chart(cfg) {
var _this;
_this = _Base.call(this, cfg) || this;
var self = _this;
(0, _common.each)(_base2["default"], function (geomConstructor, className) {
var methodName = (0, _common.lowerFirst)(className);
self[methodName] = function (cfg) {
var geom = new geomConstructor(cfg);
self.addGeom(geom);
return geom;
};
});
self._init();
return _this;
}
_inheritsLoose(Chart, _Base);
Chart.initPlugins = function initPlugins() {
return {
_plugins: [],
_cacheId: 0,
register: function register(plugins) {
var p = this._plugins;
[].concat(plugins).forEach(function (plugin) {
if (p.indexOf(plugin) === -1) {
p.push(plugin);
}
});
this._cacheId++;
},
unregister: function unregister(plugins) {
var p = this._plugins;
[].concat(plugins).forEach(function (plugin) {
var idx = p.indexOf(plugin);
if (idx !== -1) {
p.splice(idx, 1);
}
});
this._cacheId++;
},
clear: function clear() {
this._plugins = [];
this._cacheId++;
},
count: function count() {
return this._plugins.length;
},
getAll: function getAll() {
return this._plugins;
},
notify: function notify(chart, hook, args) {
var descriptors = this.descriptors(chart);
var ilen = descriptors.length;
var i;
var descriptor;
var plugin;
var params;
var method;
for (i = 0; i < ilen; ++i) {
descriptor = descriptors[i];
plugin = descriptor.plugin;
method = plugin[hook];
if (typeof method === 'function') {
params = [chart].concat(args || []);
if (method.apply(plugin, params) === false) {
return false;
}
}
}
return true;
},
descriptors: function descriptors(chart) {
var cache = chart._plugins || (chart._plugins = {});
if (cache.id === this._cacheId) {
return cache.descriptors;
}
var plugins = [];
var descriptors = [];
this._plugins.concat(chart && chart.get('plugins') || []).forEach(function (plugin) {
var idx = plugins.indexOf(plugin);
if (idx !== -1) {
return;
}
plugins.push(plugin);
descriptors.push({
plugin: plugin
});
});
cache.descriptors = descriptors;
cache.id = this._cacheId;
return descriptors;
}
};
};
var _proto = Chart.prototype;
_proto.getDefaultCfg = function getDefaultCfg() {
return {
/**
* the id of canvas
* @type {String}
*/
id: null,
/** 图表渲染引擎 */
renderer: 'canvas',
rendered: false,
/**
* padding
* @type {Array|Number}
*/
padding: _global["default"].padding,
/**
* data
* @type {Array}
*/
data: null,
/**
* scales of chart
* @type {Object}
*/
scales: {},
/**
* @private
* geometry instances
* @type {Array}
*/
geoms: [],
/**
* scale configuration
* @type {Object}
*/
colDefs: null,
pixelRatio: _global["default"].pixelRatio,
/**
* filter options
* @type {Object}
*/
filters: null,
appendPadding: _global["default"].appendPadding
};
};
_proto._syncYScales = function _syncYScales() {
var syncY = this.get('syncY');
if (!syncY) {
return;
}
var geoms = this.get('geoms');
var syncScales = [];
var min = [];
var max = [];
(0, _common.each)(geoms, function (geom) {
var yScale = geom.getYScale();
if (yScale.isLinear) {
syncScales.push(yScale);
min.push(yScale.min);
max.push(yScale.max);
}
});
min = Math.min.apply(null, min);
max = Math.max.apply(null, max);
(0, _common.each)(syncScales, function (scale) {
scale.change({
min: min
});
scale.change({
max: max
});
});
};
_proto._getFieldsForLegend = function _getFieldsForLegend() {
var fields = [];
var geoms = this.get('geoms');
(0, _common.each)(geoms, function (geom) {
var attrOptions = geom.get('attrOptions');
var attrCfg = attrOptions.color;
if (attrCfg && attrCfg.field && (0, _common.isString)(attrCfg.field)) {
var arr = attrCfg.field.split('*');
(0, _common.each)(arr, function (item) {
if (fields.indexOf(item) === -1) {
fields.push(item);
}
});
}
});
return fields;
};
_proto._getScaleData = function _getScaleData(field) {
var data = this.get('data');
var filteredData = this.get('filteredData');
if (filteredData.length) {
var legendFields = this._getFieldsForLegend();
if (legendFields.indexOf(field) === -1) {
data = filteredData;
}
}
return data;
}
// _updateScales() {
// const scaleController = this.get('scaleController');
// scaleController.updateScales();
// this._adjustScale();
// }
;
_proto._adjustScale = function _adjustScale() {
var self = this;
var scaleController = self.get('scaleController');
// 看起来是为了让柱状图最小或最大都默认从0开始
var geoms = this.get('geoms');
for (var i = 0; i < geoms.length; i++) {
var geom = geoms[i];
if (geom.get('type') === 'interval') {
var yScale = geom.getYScale();
scaleController.adjustStartZero(yScale);
}
}
};
_proto._removeGeoms = function _removeGeoms() {
var geoms = this.get('geoms');
while (geoms.length > 0) {
var geom = geoms.shift();
geom.destroy();
}
};
_proto._clearGeoms = function _clearGeoms() {
var geoms = this.get('geoms');
for (var i = 0, length = geoms.length; i < length; i++) {
var geom = geoms[i];
geom.clear();
}
};
_proto._clearInner = function _clearInner() {
this._clearGeoms();
Chart.plugins.notify(this, 'clearInner');
this.emit(_const.EVENT_CLEAR_INNER);
this.get('axisController') && this.get('axisController').clear();
};
_proto._initFilteredData = function _initFilteredData() {
var filters = this.get('filters');
var data = this.get('data') || [];
if (filters) {
data = data.filter(function (obj) {
var rst = true;
(0, _common.each)(filters, function (fn, k) {
if (fn) {
rst = fn(obj[k], obj);
if (!rst) {
return false;
}
}
});
return rst;
});
}
this.set('filteredData', data);
};
_proto._changeGeomsData = function _changeGeomsData() {
var geoms = this.get('geoms');
var data = this.get('filteredData');
for (var i = 0, length = geoms.length; i < length; i++) {
var geom = geoms[i];
geom.changeData(data);
}
};
_proto._initGeom = function _initGeom(geom) {
if (geom.get('isInit')) {
return;
}
var coord = this.get('coord');
var data = this.get('filteredData');
var colDefs = this.get('colDefs');
var middlePlot = this.get('middlePlot');
geom.set('chart', this);
geom.set('container', middlePlot.addGroup());
geom.set('data', data);
geom.set('coord', coord);
geom.set('colDefs', colDefs);
geom.init();
this.emit(_const.EVENT_AFTER_GEOM_INIT, geom);
};
_proto._initGeoms = function _initGeoms() {
var geoms = this.get('geoms');
for (var i = 0, length = geoms.length; i < length; i++) {
this._initGeom(geoms[i]);
}
};
_proto._initCoord = function _initCoord() {
var plot = this.get('plotRange');
var coordCfg = (0, _common.mix)({
type: 'cartesian'
}, this.get('coordCfg'), {
plot: plot
});
var type = coordCfg.type;
var C = _index["default"][(0, _common.upperFirst)(type)];
var coord = new C(coordCfg);
this.set('coord', coord);
};
_proto._initLayout = function _initLayout() {
var padding = this.get('_padding');
if (!padding) {
padding = this.get('margin') || this.get('padding');
padding = (0, _common.parsePadding)(padding);
}
var top = padding[0] === 'auto' ? 0 : padding[0];
var right = padding[1] === 'auto' ? 0 : padding[1];
var bottom = padding[2] === 'auto' ? 0 : padding[2];
var left = padding[3] === 'auto' ? 0 : padding[3];
var width = this.get('width');
var height = this.get('height');
var start = {
x: left,
y: top
};
var end = {
x: width - right,
y: height - bottom
};
var plot = this.get('plot');
if (plot) {
plot.reset(start, end);
return;
}
var newPlot = new _plot["default"]({
start: start,
end: end
});
this.set('plotRange', newPlot);
this.set('plot', newPlot);
};
_proto._initCanvas = function _initCanvas() {
var self = this;
try {
var canvas = (0, _index2.createCanvas)({
renderer: self.get('renderer'),
el: self.get('el') || self.get('id'),
context: self.get('context'),
pixelRatio: self.get('pixelRatio'),
width: self.get('width'),
height: self.get('height'),
fontFamily: _global["default"].fontFamily,
aria: self.get('aria'),
title: self.get('title'),
landscape: self.get('landscape')
});
self.set('canvas', canvas);
self.set('el', canvas.get('el'));
self.set('width', canvas.get('width'));
self.set('height', canvas.get('height'));
} catch (error) {
throw error;
}
Chart.plugins.notify(self, 'afterCanvasInit');
};
_proto._initLayers = function _initLayers() {
var canvas = this.get('canvas');
this.set('backPlot', canvas.addGroup());
this.set('middlePlot', canvas.addGroup({
zIndex: 10
}));
this.set('frontPlot', canvas.addGroup({
zIndex: 20
}));
};
_proto._initEvents = function _initEvents() {
var _this2 = this;
// 数据更新后的一些更新
this.on(_const.EVENT_AFTER_DATA_CHANGE, function () {
// 数据更新后,重新设置filterdata
_this2._initFilteredData();
// 更新geoms里的数据
_this2._changeGeomsData();
});
// 大小变化后的一些更新
this.on(_const.EVENT_AFTER_SIZE_CHANGE, function () {
_this2._initLayout();
// layout变化后,坐标轴也需要做相应的变化
var coord = _this2.get('coord');
if (coord) {
coord.reset(_this2.get('plot'));
}
});
};
_proto._initScaleController = function _initScaleController() {
var scaleController = new _scale["default"]({
chart: this
});
// 让colDefs 和 scaleController.defs 用同一个对象,这样就不用考虑同步的问题
this.set('colDefs', scaleController.defs);
// 已经实例化的scales 也保持统一个对象
this.set('scales', scaleController.scales);
this.set('scaleController', scaleController);
};
_proto._clearScaleController = function _clearScaleController() {
var scaleController = this.get('scaleController');
scaleController.clear();
};
_proto._init = function _init() {
var self = this;
self._initCanvas();
self._initLayout();
self._initLayers();
self._initEvents();
self._initScaleController();
self.set('axisController', new _axis["default"]({
frontPlot: self.get('frontPlot').addGroup({
className: 'axisContainer'
}),
backPlot: self.get('backPlot').addGroup({
className: 'axisContainer'
}),
chart: self
}));
Chart.plugins.notify(self, 'init');
};
_proto.init = function init() {
// 初始filterData
this._initFilteredData();
// initialization coordinate instance
this._initCoord();
Chart.plugins.notify(this, 'beforeGeomInit');
// init all geometry instances
this._initGeoms();
// 多 Y 轴的情况时,统一 Y 轴的数值范围。
this._syncYScales();
// do some adjust for data
this._adjustScale();
this.emit(_const.EVENT_AFTER_INIT);
}
/**
* set data and some scale configuration
* @chainable
* @param {Array} data the dataset to visualize
* @param {Object} colDefs the configuration for scales
* @return {Chart} return the chart instance
*/;
_proto.source = function source(data, colDefs) {
this.set('data', data);
if (colDefs) {
this.scale(colDefs);
}
return this;
};
_proto.scale = function scale(field, cfg) {
var scaleController = this.get('scaleController');
scaleController.setFieldDef(field, cfg);
return this;
}
/**
* configure the axis
* @chainable
* @param {String|Boolean} field the field name of data
* @param {Object} cfg configuration for axis
* @return {Chart} return the chart instance
*/;
_proto.axis = function axis(field, cfg) {
var axisController = this.get('axisController');
if (!field) {
axisController.axisCfg = null;
} else {
axisController.axisCfg = axisController.axisCfg || {};
axisController.axisCfg[field] = cfg;
}
return this;
}
/**
* configure the coordinate
* @chainable
* @param {String} type set the type of coodinate
* @param {Object} cfg configuration for coordinate
* @return {Chart} return the chart instance
*/;
_proto.coord = function coord(type, cfg) {
var coordCfg;
if ((0, _common.isObject)(type)) {
coordCfg = type;
} else {
coordCfg = cfg || {};
coordCfg.type = type || 'cartesian';
}
this.set('coordCfg', coordCfg);
return this;
};
_proto.filter = function filter(field, condition) {
var filters = this.get('filters') || {};
filters[field] = condition;
this.set('filters', filters);
// 如果已经render过,则再重新触发一次change
if (this.get('rendered')) {
this.emit(_const.EVENT_AFTER_DATA_CHANGE, this.get('data'));
}
}
/**
* render the chart
* @chainable
* @return {Chart} return the chart instance
*/;
_proto.render = function render() {
var rendered = this.get('rendered');
var canvas = this.get('canvas');
var geoms = this.get('geoms');
// 已经渲染过
if (rendered) {
this._initGeoms();
this._adjustScale();
} else {
this.init();
this.set('rendered', true);
}
this.emit(_const.EVENT_BEFORE_RENDER);
Chart.plugins.notify(this, 'beforeGeomDraw');
this._renderAxis();
var middlePlot = this.get('middlePlot');
if (this.get('limitInPlot') && !middlePlot.attr('clip')) {
var coord = this.get('coord');
var clip = (0, _helper.getClip)(coord);
clip.set('canvas', middlePlot.get('canvas'));
middlePlot.attr('clip', clip);
}
this.emit(_const.EVENT_BEFORE_GEOM_DRAW);
for (var i = 0, length = geoms.length; i < length; i++) {
var geom = geoms[i];
geom.paint();
}
this.emit(_const.EVENT_AFTER_GEOM_DRAW);
Chart.plugins.notify(this, 'afterGeomDraw');
canvas.sort();
this.get('frontPlot').sort();
Chart.plugins.notify(this, 'beforeCanvasDraw');
canvas.draw();
this.emit(_const.EVENT_AFTER_RENDER);
return this;
}
/**
* clear the chart, include geometris and all the shapes
* @chainable
* @return {Chart} return the chart
*/;
_proto.clear = function clear() {
Chart.plugins.notify(this, 'clear');
this.emit(_const.EVENT_CLEAR);
this._clearInner();
this._removeGeoms();
this._clearScaleController();
this.set('legendItems', null);
this.set('filters', null);
this.set('isUpdate', false);
this.set('_padding', null);
this.set('rendered', false);
var canvas = this.get('canvas');
canvas.draw();
return this;
};
_proto.repaint = function repaint() {
// 如果在没有render之前就repaint的,就直接return退出
var rendered = this.get('rendered');
if (!rendered) {
return;
}
this.set('isUpdate', true);
this.set('legendItems', null);
Chart.plugins.notify(this, 'repaint');
this._clearInner();
this.emit(_const.EVENT_REPAINT);
this.render();
};
_proto.changeData = function changeData(data) {
this.emit(_const.EVENT_BEFORE_DATA_CHANGE, data);
this.set('data', data);
Chart.plugins.notify(this, 'changeData');
this.emit(_const.EVENT_AFTER_DATA_CHANGE, data);
this.set('_padding', null);
this.repaint();
};
_proto.changeSize = function changeSize(width, height) {
if (width) {
this.set('width', width);
} else {
width = this.get('width');
}
if (height) {
this.set('height', height);
} else {
height = this.get('height');
}
var canvas = this.get('canvas');
canvas.changeSize(width, height);
this.emit(_const.EVENT_AFTER_SIZE_CHANGE, {
width: width,
height: height
});
this.repaint();
return this;
};
_proto.destroy = function destroy() {
this.clear();
var canvas = this.get('canvas');
canvas.destroy();
Chart.plugins.notify(this, 'afterCanvasDestroyed');
if (this._interactions) {
(0, _common.each)(this._interactions, function (interaction) {
interaction.destroy();
});
}
_Base.prototype.destroy.call(this);
}
/**
* calculate dataset's position on canvas
* @param {Object} record the dataset
* @return {Object} return the position
*/;
_proto.getPosition = function getPosition(record) {
var self = this;
var coord = self.get('coord');
var xScale = self.getXScale();
var xField = xScale.field;
var yScales = self.getYScales();
// default first
var yScale = yScales[0];
var yField = yScale.field;
for (var i = 0, len = yScales.length; i < len; i++) {
var scale = yScales[i];
var field = scale.field;
if (record[field]) {
yScale = scale;
yField = field;
break;
}
}
var x = xScale.scale(record[xField]);
var y = yScale.scale(record[yField]);
return coord.convertPoint({
x: x,
y: y
});
}
/**
* get the data item of the point
* @param {Object} point canvas position
* @return {Object} return the data item
*/;
_proto.getRecord = function getRecord(point) {
var self = this;
var coord = self.get('coord');
var xScale = self.getXScale();
var yScale = self.getYScales()[0];
var invertPoint = coord.invertPoint(point);
var record = {};
record[xScale.field] = xScale.invert(invertPoint.x);
record[yScale.field] = yScale.invert(invertPoint.y);
return record;
}
/**
* get the dataset of the point
* @param {Object} point canvas position
* @return {Array} return the dataset
**/;
_proto.getSnapRecords = function getSnapRecords(point) {
var geom = this.get('geoms')[0];
var data = [];
if (geom) {
// need to judge
data = geom.getSnapRecords(point);
}
return data;
}
/**
* creat scale instances
* @param {String} field field name of data
* @return {Scale} return the scale
*/;
_proto.createScale = function createScale(field) {
var data = this._getScaleData(field);
var scaleController = this.get('scaleController');
return scaleController.createScale(field, data);
}
/**
* @protected
* add geometry instance to geoms
* @param {Geom} geom geometry instance
*/;
_proto.addGeom = function addGeom(geom) {
var geoms = this.get('geoms');
geoms.push(geom);
}
/**
* get the scale of x axis
* @return {Scale} return the scale
*/;
_proto.getXScale = function getXScale() {
var self = this;
var geoms = self.get('geoms');
var xScale = geoms[0].getXScale();
return xScale;
}
/**
* get the scale of y axis
* @return {Array} return the scale
*/;
_proto.getYScales = function getYScales() {
var geoms = this.get('geoms');
var rst = [];
(0, _common.each)(geoms, function (geom) {
var yScale = geom.getYScale();
if (rst.indexOf(yScale) === -1) {
rst.push(yScale);
}
});
return rst;
};
_proto.getLegendItems = function getLegendItems() {
if (this.get('legendItems')) {
return this.get('legendItems');
}
var legendItems = {};
var scales = [];
var geoms = this.get('geoms');
(0, _common.each)(geoms, function (geom) {
var colorAttr = geom.getAttr('color');
if (colorAttr) {
var scale = colorAttr.getScale('color');
// 只支持分类图例
if (scale.isCategory && !_isScaleExist(scales, scale)) {
scales.push(scale);
var field = scale.field;
var ticks = scale.getTicks();
var items = [];
(0, _common.each)(ticks, function (tick) {
var text = tick.text;
var name = text;
var scaleValue = tick.value;
var value = scale.invert(scaleValue);
var color = colorAttr.mapping(value).join('') || _global["default"].defaultColor;
var marker = {
fill: color,
radius: 3,
symbol: 'circle',
stroke: '#fff'
};
items.push({
name: name,
// for display
dataValue: value,
// the origin value
checked: true,
marker: marker
});
});
legendItems[field] = items;
}
}
});
this.set('legendItems', legendItems);
return legendItems;
}
// register the plugins
;
_proto.registerPlugins = function registerPlugins(plugins) {
var self = this;
var chartPlugins = self.get('plugins') || [];
if (!(0, _common.isArray)(chartPlugins)) {
chartPlugins = [chartPlugins];
}
[].concat(plugins).forEach(function (plugin) {
if (chartPlugins.indexOf(plugin) === -1) {
plugin.init && plugin.init(self); // init
chartPlugins.push(plugin);
}
});
Chart.plugins._cacheId++;
self.set('plugins', chartPlugins);
};
_proto._renderAxis = function _renderAxis() {
var axisController = this.get('axisController');
var xScale = this.getXScale();
var yScales = this.getYScales();
var coord = this.get('coord');
Chart.plugins.notify(this, 'beforeRenderAxis');
axisController.createAxis(coord, xScale, yScales);
};
_proto._isAutoPadding = function _isAutoPadding() {
if (this.get('_padding')) {
return false;
}
var padding = this.get('padding');
if ((0, _common.isArray)(padding)) {
return padding.indexOf('auto') !== -1;
}
return padding === 'auto';
};
_proto._updateLayout = function _updateLayout(padding) {
var width = this.get('width');
var height = this.get('height');
var start = {
x: padding[3],
y: padding[0]
};
var end = {
x: width - padding[1],
y: height - padding[2]
};
var plot = this.get('plot');
var coord = this.get('coord');
plot.reset(start, end);
coord.reset(plot);
}
/**
* 是否为横屏展示
*
* @param {Boolean} landscape 是否为横屏
*/;
_proto.landscape = function landscape(_landscape) {
var canvas = this.get('canvas');
canvas.set('landscape', _landscape);
};
return Chart;
}(_base["default"]);
Chart.plugins = Chart.initPlugins();
var _default = exports["default"] = Chart;