function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; } function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } var Base = require('../base'); var Plot = require('./plot'); var Util = require('../util/common'); var Coord = require('../coord/index'); var Geom = require('../geom/base'); var ScaleController = require('./controller/scale'); var AxisController = require('./controller/axis'); var Global = require('../global'); var _require = require('../graphic/index'), Canvas = _require.Canvas; var Helper = require('../util/helper'); function isFullCircle(coord) { var startAngle = coord.startAngle; var endAngle = coord.endAngle; if (!Util.isNil(startAngle) && !Util.isNil(endAngle) && endAngle - startAngle < Math.PI * 2) { return false; } return true; } function compare(a, b) { return a - b; } function _isScaleExist(scales, compareScale) { var flag = false; Util.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) { _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, /** * padding * @type {Array|Number} */ padding: Global.padding, /** * data * @type {Array} */ data: null, /** * scales of chart * @type {Object} */ scales: {}, /** * @private * geometry instances * @type {Array} */ geoms: null, /** * scale configuration * @type {Object} */ colDefs: null, pixelRatio: Global.pixelRatio, /** * filter options * @type {Object} */ filters: null, appendPadding: Global.appendPadding }; }; _proto._syncYScales = function _syncYScales() { var geoms = this.get('geoms'); var syncScales = []; var min = []; var max = []; Util.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); Util.each(syncScales, function (scale) { scale.change({ min: min }); scale.change({ max: max }); }); }; _proto._getFieldsForLegend = function _getFieldsForLegend() { var fields = []; var geoms = this.get('geoms'); Util.each(geoms, function (geom) { var attrOptions = geom.get('attrOptions'); var attrCfg = attrOptions.color; if (attrCfg && attrCfg.field && Util.isString(attrCfg.field)) { var arr = attrCfg.field.split('*'); Util.each(arr, function (item) { if (fields.indexOf(item) === -1) { fields.push(item); } }); } }); return fields; }; _proto._createScale = function _createScale(field, data) { var scaleController = this.get('scaleController'); return scaleController.createScale(field, data); }; _proto._adjustScale = function _adjustScale() { var self = this; var coord = self.get('coord'); var xScale = self.getXScale(); var yScales = self.getYScales(); var scales = []; xScale && scales.push(xScale); scales = scales.concat(yScales); var inFullCircle = coord.isPolar && isFullCircle(coord); var scaleController = self.get('scaleController'); var colDefs = scaleController.defs; Util.each(scales, function (scale) { if ((scale.isCategory || scale.isIdentity) && scale.values && !(colDefs[scale.field] && colDefs[scale.field].range)) { var count = scale.values.length; var range; if (count === 1) { range = [0.5, 1]; } else { var widthRatio = 1; var offset = 0; if (inFullCircle) { if (!coord.transposed) { range = [0, 1 - 1 / count]; } else { widthRatio = Global.widthRatio.multiplePie; offset = 1 / count * widthRatio; range = [offset / 2, 1 - offset / 2]; } } else { offset = 1 / count * 1 / 2; range = [offset, 1 - offset]; } } scale.range = range; } }); 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(); var field = yScale.field, min = yScale.min, max = yScale.max, type = yScale.type; if (!(colDefs[field] && colDefs[field].min) && type !== 'time') { if (min > 0) { yScale.change({ min: 0 }); } else if (max <= 0) { yScale.change({ max: 0 }); } } } } }; _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.set('scales', {}); this.set('legendItems', null); this._clearGeoms(); Chart.plugins.notify(this, 'clearInner'); this.get('axisController') && this.get('axisController').clear(); }; _proto._execFilter = function _execFilter(data) { var filters = this.get('filters'); if (filters) { data = data.filter(function (obj) { var rst = true; Util.each(filters, function (fn, k) { if (fn) { rst = fn(obj[k], obj); if (!rst) { return false; } } }); return rst; }); } return data; }; _proto._initGeoms = function _initGeoms(geoms) { var coord = this.get('coord'); var data = this.get('filteredData'); var colDefs = this.get('colDefs'); for (var i = 0, length = geoms.length; i < length; i++) { var geom = geoms[i]; geom.set('data', data); geom.set('coord', coord); geom.set('colDefs', colDefs); geom.init(); } }; _proto._initCoord = function _initCoord() { var plot = this.get('plotRange'); var coordCfg = Util.mix({ type: 'cartesian' }, this.get('coordCfg'), { plot: plot }); var type = coordCfg.type; var C = Coord[Util.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 = Util.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 plot = new Plot({ start: { x: left, y: top }, end: { x: width - right, y: height - bottom } }); this.set('plotRange', plot); this.set('plot', plot); }; _proto._initCanvas = function _initCanvas() { var self = this; try { var canvas = new Canvas({ 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.fontFamily }); self.set('canvas', canvas); self.set('width', canvas.get('width')); self.set('height', canvas.get('height')); } catch (error) { throw error; } Chart.plugins.notify(self, 'afterCanvasInit'); self._initLayout(); }; _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._init = function _init() { var self = this; self._initCanvas(); self._initLayers(); self.set('geoms', []); self.set('scaleController', new ScaleController()); self.set('axisController', new AxisController({ frontPlot: self.get('frontPlot').addGroup({ className: 'axisContainer' }), backPlot: self.get('backPlot').addGroup({ className: 'axisContainer' }), chart: self })); Chart.plugins.notify(self, 'init'); }; function Chart(cfg) { var _this; _this = _Base.call(this, cfg) || this; var self = _assertThisInitialized(_assertThisInitialized(_this)); Util.each(Geom, function (geomConstructor, className) { var methodName = Util.lowerFirst(className); self[methodName] = function (cfg) { var geom = new geomConstructor(cfg); self.addGeom(geom); return geom; }; }); self._init(); return _this; } /** * 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 colDefs = this.get('colDefs') || {}; if (Util.isObject(field)) { Util.mix(colDefs, field); } else { colDefs[field] = cfg; } this.set('colDefs', colDefs); var scaleController = this.get('scaleController'); scaleController.defs = colDefs; 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 (Util.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 the chart * @chainable * @return {Chart} return the chart instance */ _proto.render = function render() { var canvas = this.get('canvas'); var geoms = this.get('geoms'); var data = this.get('data') || []; var filteredData = this._execFilter(data); // filter data this.set('filteredData', filteredData); this._initCoord(); // initialization coordinate instance Chart.plugins.notify(this, 'beforeGeomInit'); this._initGeoms(geoms); // init all geometry instances this.get('syncY') && this._syncYScales(); this._adjustScale(); // do some adjust for data 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 = Helper.getClip(coord); clip.set('canvas', middlePlot.get('canvas')); middlePlot.attr('clip', clip); } for (var i = 0, length = geoms.length; i < length; i++) { var geom = geoms[i]; geom.paint(); } Chart.plugins.notify(this, 'afterGeomDraw'); canvas.sort(); this.get('frontPlot').sort(); Chart.plugins.notify(this, 'beforeCanvasDraw'); canvas.draw(); 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._removeGeoms(); this._clearInner(); this.set('filters', null); this.set('isUpdate', false); this.set('_padding', null); var canvas = this.get('canvas'); canvas.draw(); return this; }; _proto.repaint = function repaint() { this.set('isUpdate', true); Chart.plugins.notify(this, 'repaint'); this._clearInner(); this.render(); }; _proto.changeData = function changeData(data) { this.set('data', data); Chart.plugins.notify(this, 'changeData'); 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._initLayout(); 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) { Util.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 yScale = self.getYScales()[0]; var xField = xScale.field; var x = xScale.scale(record[xField]); var yField = yScale.field; 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.get('data'); var filteredData = this.get('filteredData'); if (filteredData.length) { var legendFields = this._getFieldsForLegend(); if (legendFields.indexOf(field) === -1) { data = filteredData; } } var scales = this.get('scales'); if (!scales[field]) { scales[field] = this._createScale(field, data); } return scales[field]; }; /** * @protected * add geometry instance to geoms * @param {Geom} geom geometry instance */ _proto.addGeom = function addGeom(geom) { var geoms = this.get('geoms'); var middlePlot = this.get('middlePlot'); geoms.push(geom); geom.set('chart', this); geom.set('container', middlePlot.addGroup()); }; /** * 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 = []; Util.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'); Util.each(geoms, function (geom) { var colorAttr = geom.getAttr('color'); if (colorAttr) { var scale = colorAttr.getScale('color'); if (scale.type !== 'identity' && !_isScaleExist(scales, scale)) { scales.push(scale); var field = scale.field; var ticks = scale.getTicks(); var items = []; Util.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.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 (!Util.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 (Util.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); }; return Chart; }(Base); Chart.plugins = Chart.initPlugins(); module.exports = Chart;