NuclearDispersionSystem/ant-design-vue-jeecg/node_modules/@antv/g2/lib/chart/chart.js
2023-09-14 14:47:11 +08:00

808 lines
21 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; }
/**
* @fileOverview G2 图表的入口文件
* @author dxq613@gmail.com
*/
var Util = require('../util');
var View = require('./view');
var G = require('../renderer');
var Canvas = G.Canvas;
var DomUtil = Util.DomUtil;
var Global = require('../global');
var Plot = require('../component/plot');
var Controller = require('./controller/index');
var mergeBBox = require('./util/merge-bbox');
var bboxOfBackPlot = require('./util/bbox-of-back-plot');
var plotRange2BBox = require('./util/plot-range2bbox');
var AUTO_STR = 'auto';
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().toString() === compareScaleValues.sort().toString()) {
flag = true;
return;
}
});
return flag;
}
function isEqualArray(arr1, arr2) {
return Util.isEqualWith(arr1, arr2, function (v1, v2) {
return v1 === v2;
});
}
/**
* 图表的入口
* @class Chart
*/
var Chart = /*#__PURE__*/function (_View) {
_inheritsLoose(Chart, _View);
function Chart() {
return _View.apply(this, arguments) || this;
}
var _proto = Chart.prototype;
/**
* 获取默认的配置属性
* @protected
* @return {Object} 默认属性
*/
_proto.getDefaultCfg = function getDefaultCfg() {
var viewCfg = _View.prototype.getDefaultCfg.call(this);
return Util.mix(viewCfg, {
id: null,
forceFit: false,
container: null,
wrapperEl: null,
canvas: null,
width: 500,
height: 500,
pixelRatio: null,
backPlot: null,
frontPlot: null,
plotBackground: null,
padding: Global.plotCfg.padding,
background: null,
autoPaddingAppend: 5,
limitInPlot: false,
renderer: Global.renderer,
// renderer: 'svg',
views: []
});
};
_proto.init = function init() {
var self = this;
var viewTheme = self.get('viewTheme');
self._initCanvas();
self._initPlot();
self._initEvents();
_View.prototype.init.call(this);
var tooltipController = new Controller.Tooltip({
chart: self,
viewTheme: viewTheme,
options: {}
});
self.set('tooltipController', tooltipController);
var legendController = new Controller.Legend({
chart: self,
viewTheme: viewTheme
});
self.set('legendController', legendController);
self.set('_id', 'chart'); // 防止同用户设定的 id 同名
self.emit('afterinit'); // 初始化完毕
};
_proto._isAutoPadding = function _isAutoPadding() {
var padding = this.get('padding');
if (Util.isArray(padding)) {
return padding.includes(AUTO_STR);
}
return padding === AUTO_STR;
};
_proto._getAutoPadding = function _getAutoPadding() {
var padding = this.get('padding'); // 图例在最前面的一层
var frontPlot = this.get('frontPlot');
var frontBBox = frontPlot.getBBox(); // 坐标轴在最后面的一层
var backPlot = this.get('backPlot'); // 这段代码临时处理了title 过长的情况,但是是非常不好的代码
var backBBox = bboxOfBackPlot(backPlot, plotRange2BBox(this.get('plotRange')));
var box = mergeBBox(frontBBox, backBBox);
var outter = [0 - box.minY, // 上面超出的部分
box.maxX - this.get('width'), // 右边超出的部分
box.maxY - this.get('height'), // 下边超出的部分
0 - box.minX]; // 如果原始的 padding 内部存在 'auto' 则替换对应的边
var autoPadding = Util.toAllPadding(padding);
for (var i = 0; i < autoPadding.length; i++) {
if (autoPadding[i] === AUTO_STR) {
var tmp = Math.max(0, outter[i]);
autoPadding[i] = tmp + this.get('autoPaddingAppend');
}
}
return autoPadding;
} // 初始化画布
;
_proto._initCanvas = function _initCanvas() {
var container = this.get('container');
var id = this.get('id'); // 如果未设置 container 使用 ID, 兼容 2.x 版本
if (!container && id) {
container = id;
this.set('container', id);
}
var width = this.get('width');
var height = this.get('height');
if (Util.isString(container)) {
container = document.getElementById(container);
if (!container) {
throw new Error('Please specify the container for the chart!');
}
this.set('container', container);
}
var wrapperEl = DomUtil.createDom('<div style="position:relative;"></div>');
container.appendChild(wrapperEl);
this.set('wrapperEl', wrapperEl);
if (this.get('forceFit')) {
width = DomUtil.getWidth(container, width);
this.set('width', width);
}
var renderer = this.get('renderer');
var canvas = new Canvas({
containerDOM: wrapperEl,
width: width,
height: height,
// NOTICE: 有问题找青湳
pixelRatio: renderer === 'svg' ? 1 : this.get('pixelRatio'),
renderer: renderer
});
this.set('canvas', canvas);
} // 初始化绘图区间
;
_proto._initPlot = function _initPlot() {
var self = this;
self._initPlotBack(); // 最底层的是背景相关的 group
var canvas = self.get('canvas');
var backPlot = canvas.addGroup({
zIndex: 1
}); // 图表最后面的容器
var plotContainer = canvas.addGroup({
zIndex: 0
}); // 图表所在的容器
var frontPlot = canvas.addGroup({
zIndex: 3
}); // 图表前面的容器
self.set('backPlot', backPlot);
self.set('middlePlot', plotContainer);
self.set('frontPlot', frontPlot);
} // 初始化背景
;
_proto._initPlotBack = function _initPlotBack() {
var self = this;
var canvas = self.get('canvas');
var viewTheme = self.get('viewTheme');
var plot = canvas.addGroup(Plot, {
padding: this.get('padding'),
plotBackground: Util.mix({}, viewTheme.plotBackground, self.get('plotBackground')),
background: Util.mix({}, viewTheme.background, self.get('background'))
});
self.set('plot', plot);
self.set('plotRange', plot.get('plotRange'));
};
_proto._initEvents = function _initEvents() {
if (this.get('forceFit')) {
window.addEventListener('resize', Util.wrapBehavior(this, '_initForceFitEvent'));
}
};
_proto._initForceFitEvent = function _initForceFitEvent() {
var timer = setTimeout(Util.wrapBehavior(this, 'forceFit'), 200);
clearTimeout(this.get('resizeTimer'));
this.set('resizeTimer', timer);
} // 绘制图例
;
_proto._renderLegends = function _renderLegends() {
var options = this.get('options');
var legendOptions = options.legends;
if (Util.isNil(legendOptions) || legendOptions !== false) {
// 没有关闭图例
var legendController = this.get('legendController');
legendController.options = legendOptions || {};
legendController.plotRange = this.get('plotRange');
if (legendOptions && legendOptions.custom) {
// 用户自定义图例
legendController.addCustomLegend();
} else {
var geoms = this.getAllGeoms();
var scales = [];
Util.each(geoms, function (geom) {
var view = geom.get('view');
var attrs = geom.getAttrsForLegend();
Util.each(attrs, function (attr) {
var type = attr.type;
var scale = attr.getScale(type);
if (scale.field && scale.type !== 'identity' && !_isScaleExist(scales, scale)) {
scales.push(scale);
var filteredValues = view.getFilteredOutValues(scale.field);
legendController.addLegend(scale, attr, geom, filteredValues);
}
});
}); // 双轴的情况
var yScales = this.getYScales();
if (scales.length === 0 && yScales.length > 1) {
legendController.addMixedLegend(yScales, geoms);
}
}
legendController.alignLegends();
}
} // 绘制 tooltip
;
_proto._renderTooltips = function _renderTooltips() {
var options = this.get('options');
if (Util.isNil(options.tooltip) || options.tooltip !== false) {
// 用户没有关闭 tooltip
var tooltipController = this.get('tooltipController');
tooltipController.options = options.tooltip || {};
tooltipController.renderTooltip();
}
}
/**
* 获取所有的几何标记
* @return {Array} 所有的几何标记
*/
;
_proto.getAllGeoms = function getAllGeoms() {
var geoms = [];
geoms = geoms.concat(this.get('geoms'));
var views = this.get('views');
Util.each(views, function (view) {
geoms = geoms.concat(view.get('geoms'));
});
return geoms;
}
/**
* 自适应宽度
* @chainable
* @return {Chart} 图表对象
*/
;
_proto.forceFit = function forceFit() {
var self = this;
if (!self || self.destroyed) {
return;
}
var container = self.get('container');
var oldWidth = self.get('width');
var width = DomUtil.getWidth(container, oldWidth);
if (width !== 0 && width !== oldWidth) {
var height = self.get('height');
self.changeSize(width, height);
}
return self;
};
_proto.resetPlot = function resetPlot() {
var plot = this.get('plot');
var padding = this.get('padding');
if (!isEqualArray(padding, plot.get('padding'))) {
// 重置 padding仅当padding 发生更改
plot.set('padding', padding);
plot.repaint();
}
}
/**
* 改变大小
* @param {Number} width 图表宽度
* @param {Number} height 图表高度
* @return {Chart} 图表对象
*/
;
_proto.changeSize = function changeSize(width, height) {
var self = this;
var canvas = self.get('canvas');
canvas.changeSize(width, height);
var plot = this.get('plot');
self.set('width', width);
self.set('height', height); // change size 时重新计算边框
plot.repaint(); // 保持边框不变,防止自动 padding 时绘制多遍
this.set('keepPadding', true);
self.repaint();
this.set('keepPadding', false);
this.emit('afterchangesize');
return self;
}
/**
* 改变宽度
* @param {Number} width 图表宽度
* @return {Chart} 图表对象
*/
;
_proto.changeWidth = function changeWidth(width) {
return this.changeSize(width, this.get('height'));
}
/**
* 改变宽度
* @param {Number} height 图表高度
* @return {Chart} 图表对象
*/
;
_proto.changeHeight = function changeHeight(height) {
return this.changeSize(this.get('width'), height);
}
/**
* 创建一个视图
* @param {Object} cfg 视图的配置项
* @return {View} 视图对象
*/
;
_proto.view = function view(cfg) {
cfg = cfg || {};
cfg.theme = this.get('theme');
cfg.parent = this;
cfg.backPlot = this.get('backPlot');
cfg.middlePlot = this.get('middlePlot');
cfg.frontPlot = this.get('frontPlot');
cfg.canvas = this.get('canvas');
if (Util.isNil(cfg.animate)) {
cfg.animate = this.get('animate');
}
cfg.options = Util.mix({}, this._getSharedOptions(), cfg.options);
var view = new View(cfg);
view.set('_id', 'view' + this.get('views').length); // 标识 ID防止同用户设定的 id 重名
this.get('views').push(view);
this.emit('addview', {
view: view
});
return view;
} // isShapeInView() {
// return true;
// }
;
_proto.removeView = function removeView(view) {
var views = this.get('views');
Util.Array.remove(views, view);
view.destroy();
};
_proto._getSharedOptions = function _getSharedOptions() {
var options = this.get('options');
var sharedOptions = {};
Util.each(['scales', 'coord', 'axes'], function (name) {
sharedOptions[name] = Util.cloneDeep(options[name]);
});
return sharedOptions;
}
/**
* @override
* 当前chart 的范围
*/
;
_proto.getViewRegion = function getViewRegion() {
var plotRange = this.get('plotRange');
return {
start: plotRange.bl,
end: plotRange.tr
};
}
/**
* 设置图例配置信息
* @param {String|Object} field 字段名
* @param {Object} [cfg] 图例的配置项
* @return {Chart} 当前的图表对象
*/
;
_proto.legend = function legend(field, cfg) {
var options = this.get('options');
if (!options.legends) {
options.legends = {};
}
var legends = {};
if (field === false) {
options.legends = false;
} else if (Util.isObject(field)) {
legends = field;
} else if (Util.isString(field)) {
legends[field] = cfg;
} else {
legends = cfg;
}
Util.mix(options.legends, legends);
return this;
}
/**
* 设置提示信息
* @param {String|Object} visible 是否可见
* @param {Object} [cfg] 提示信息的配置项
* @return {Chart} 当前的图表对象
*/
;
_proto.tooltip = function tooltip(visible, cfg) {
var options = this.get('options');
if (!options.tooltip) {
options.tooltip = {};
}
if (visible === false) {
options.tooltip = false;
} else if (Util.isObject(visible)) {
Util.mix(options.tooltip, visible);
} else {
Util.mix(options.tooltip, cfg);
}
return this;
}
/**
* 清空图表
* @return {Chart} 当前的图表对象
*/
;
_proto.clear = function clear() {
this.emit('beforeclear');
var views = this.get('views');
while (views.length > 0) {
var view = views.shift();
view.destroy();
}
_View.prototype.clear.call(this);
var canvas = this.get('canvas');
this.resetPlot();
canvas.draw();
this.emit('afterclear');
return this;
};
_proto.clearInner = function clearInner() {
var views = this.get('views');
Util.each(views, function (view) {
view.clearInner();
});
var tooltipController = this.get('tooltipController');
tooltipController && tooltipController.clear();
if (!this.get('keepLegend')) {
var legendController = this.get('legendController');
legendController && legendController.clear();
}
_View.prototype.clearInner.call(this);
} // chart 除了view 上绘制的组件外,还会绘制图例和 tooltip
;
_proto.drawComponents = function drawComponents() {
_View.prototype.drawComponents.call(this); // 一般是点击图例时,仅仅隐藏某些选项,而不销毁图例
if (!this.get('keepLegend')) {
this._renderLegends(); // 渲染图例
}
}
/**
* 绘制图表
* @override
*/
;
_proto.render = function render() {
var self = this; // 需要自动计算边框,则重新设置
if (!self.get('keepPadding') && self._isAutoPadding()) {
self.beforeRender(); // 初始化各个 view 和 绘制
self.drawComponents();
var autoPadding = self._getAutoPadding();
var plot = self.get('plot'); // 在计算出来的边框不一致的情况,重新改变边框
if (!isEqualArray(plot.get('padding'), autoPadding)) {
plot.set('padding', autoPadding);
plot.repaint();
}
}
var middlePlot = self.get('middlePlot');
if (self.get('limitInPlot') && !middlePlot.attr('clip')) {
var clip = Util.getClipByRange(self.get('plotRange')); // TODO Polar coord
middlePlot.attr('clip', clip); // clip.attr('fill', 'grey');
// clip.attr('opacity', 0.5);
// middlePlot.add(clip);
}
_View.prototype.render.call(this);
self._renderTooltips(); // 渲染 tooltip
};
_proto.repaint = function repaint() {
// 重绘时需要判定当前的 padding 是否发生过改变,如果发生过改变进行调整
// 需要判定是否使用了自动 padding
if (!this.get('keepPadding')) {
this.resetPlot();
}
_View.prototype.repaint.call(this);
}
/**
* @override
* 显示或者隐藏
*/
;
_proto.changeVisible = function changeVisible(visible) {
var wrapperEl = this.get('wrapperEl');
var visibleStr = visible ? '' : 'none';
wrapperEl.style.display = visibleStr;
}
/**
* 返回图表的 dataUrl 用于生成图片
* @return {String} dataUrl 路径
*/
;
_proto.toDataURL = function toDataURL() {
var chart = this;
var canvas = chart.get('canvas');
var renderer = chart.get('renderer');
var canvasDom = canvas.get('el');
var dataURL = '';
if (renderer === 'svg') {
var clone = canvasDom.cloneNode(true);
var svgDocType = document.implementation.createDocumentType('svg', '-//W3C//DTD SVG 1.1//EN', 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd');
var svgDoc = document.implementation.createDocument('http://www.w3.org/2000/svg', 'svg', svgDocType);
svgDoc.replaceChild(clone, svgDoc.documentElement);
var svgData = new XMLSerializer().serializeToString(svgDoc);
dataURL = 'data:image/svg+xml;charset=utf8,' + encodeURIComponent(svgData);
} else if (renderer === 'canvas') {
dataURL = canvasDom.toDataURL('image/png');
}
return dataURL;
}
/**
* 图表导出功能
* @param {String} [name] 图片的名称,默认为 chart(.png|.svg)
*/
;
_proto.downloadImage = function downloadImage(name) {
var chart = this;
var link = document.createElement('a');
var renderer = chart.get('renderer');
var filename = (name || 'chart') + (renderer === 'svg' ? '.svg' : '.png');
var canvas = chart.get('canvas');
canvas.get('timeline').stopAllAnimations();
setTimeout(function () {
var dataURL = chart.toDataURL();
if (window.Blob && window.URL && renderer !== 'svg') {
var arr = dataURL.split(',');
var mime = arr[0].match(/:(.*?);/)[1];
var bstr = atob(arr[1]);
var n = bstr.length;
var u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
var blobObj = new Blob([u8arr], {
type: mime
});
if (window.navigator.msSaveBlob) {
window.navigator.msSaveBlob(blobObj, filename);
} else {
link.addEventListener('click', function () {
link.download = filename;
link.href = window.URL.createObjectURL(blobObj);
});
}
} else {
link.addEventListener('click', function () {
link.download = filename;
link.href = dataURL;
});
}
var e = document.createEvent('MouseEvents');
e.initEvent('click', false, false);
link.dispatchEvent(e);
}, 16);
}
/**
* 根据坐标点显示对应的 tooltip
* @param {Object} point 画布上的点
* @return {Chart} 返回 chart 实例
*/
;
_proto.showTooltip = function showTooltip(point) {
var views = this.getViewsByPoint(point);
if (views.length) {
var tooltipController = this.get('tooltipController');
tooltipController.showTooltip(point, views);
}
return this;
}
/**
* 将tooltip 锁定到当前位置不能移动
* @return {Chart} 返回 chart 实例
*/
;
_proto.lockTooltip = function lockTooltip() {
var tooltipController = this.get('tooltipController');
tooltipController.lockTooltip();
return this;
}
/**
* 将tooltip 锁定解除
* @return {Chart} 返回 chart 实例
*/
;
_proto.unlockTooltip = function unlockTooltip() {
var tooltipController = this.get('tooltipController');
tooltipController.unlockTooltip();
return this;
}
/**
* 隐藏 tooltip
* @return {Chart} 返回 chart 实例
*/
;
_proto.hideTooltip = function hideTooltip() {
var tooltipController = this.get('tooltipController');
tooltipController.hideTooltip();
return this;
}
/**
* 根据传入的画布坐标,获取该处的 tooltip 上的记录信息
* @param {Object} point 画布坐标点
* @return {Array} 返回结果
*/
;
_proto.getTooltipItems = function getTooltipItems(point) {
var self = this;
var views = self.getViewsByPoint(point);
var rst = [];
Util.each(views, function (view) {
var geoms = view.get('geoms');
Util.each(geoms, function (geom) {
var dataArray = geom.get('dataArray');
var items = [];
Util.each(dataArray, function (data) {
var tmpPoint = geom.findPoint(point, data);
if (tmpPoint) {
var subItems = geom.getTipItems(tmpPoint);
items = items.concat(subItems);
}
});
rst = rst.concat(items);
});
});
return rst;
}
/**
* @override
* 销毁图表
*/
;
_proto.destroy = function destroy() {
this.emit('beforedestroy');
clearTimeout(this.get('resizeTimer'));
var canvas = this.get('canvas');
var wrapperEl = this.get('wrapperEl');
wrapperEl.parentNode.removeChild(wrapperEl);
_View.prototype.destroy.call(this);
canvas.destroy();
window.removeEventListener('resize', Util.getWrapBehavior(this, '_initForceFitEvent'));
this.emit('afterdestroy');
};
return Chart;
}(View);
module.exports = Chart;