NuclearDispersionSystem/ant-design-vue-jeecg/node_modules/@antv/g2/lib/chart/chart.js

808 lines
21 KiB
Java
Raw Normal View History

2023-09-14 14:47:11 +08:00
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;