@antv/g2plot
Version:
G2 Plot, a market of plots built with the Grammar of Graphics'
509 lines • 19.4 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var g_1 = require("@antv/g");
var G2 = tslib_1.__importStar(require("@antv/g2"));
var _ = tslib_1.__importStar(require("@antv/util"));
var description_1 = tslib_1.__importDefault(require("../components/description"));
var factory_1 = require("../components/factory");
var index_1 = tslib_1.__importDefault(require("../interaction/index"));
var event_1 = require("../util/event");
var padding_1 = tslib_1.__importDefault(require("./controller/padding"));
var state_1 = tslib_1.__importDefault(require("./controller/state"));
var theme_1 = tslib_1.__importDefault(require("./controller/theme"));
var layer_1 = tslib_1.__importDefault(require("./layer"));
var common_1 = require("../util/common");
var ViewLayer = /** @class */ (function (_super) {
tslib_1.__extends(ViewLayer, _super);
function ViewLayer(props) {
var _this = _super.call(this, props) || this;
_this.interactions = [];
_this.options = _this.getOptions(props);
_this.initialOptions = _.deepMix({}, _this.options);
_this.paddingController = new padding_1.default({
plot: _this,
});
_this.stateController = new state_1.default({
plot: _this,
});
_this.themeController = new theme_1.default();
return _this;
}
ViewLayer.getDefaultOptions = function (props) {
return {
title: {
visible: false,
text: '',
},
description: {
visible: false,
text: '',
},
padding: 'auto',
legend: {
visible: true,
position: 'bottom-center',
},
tooltip: {
visible: true,
shared: true,
crosshairs: {
type: 'y',
},
},
xAxis: {
visible: true,
autoHideLabel: false,
autoRotateLabel: false,
autoRotateTitle: false,
grid: {
visible: false,
},
line: {
visible: true,
},
tickLine: {
visible: true,
},
label: {
visible: true,
},
title: {
visible: false,
offset: 12,
},
},
yAxis: {
visible: true,
autoHideLabel: false,
autoRotateLabel: false,
autoRotateTitle: true,
grid: {
visible: true,
},
line: {
visible: false,
},
tickLine: {
visible: false,
},
label: {
visible: true,
},
title: {
visible: false,
offset: 12,
},
},
label: {
visible: false,
},
};
};
ViewLayer.prototype.getOptions = function (props) {
var options = _super.prototype.getOptions.call(this, props);
// @ts-ignore
var defaultOptions = this.constructor.getDefaultOptions(props);
return _.deepMix({}, options, defaultOptions, props);
};
ViewLayer.prototype.beforeInit = function () {
_super.prototype.beforeInit.call(this);
};
ViewLayer.prototype.init = function () {
var _this = this;
_super.prototype.init.call(this);
this.theme = this.themeController.getTheme(this.options, this.type);
this.config = {
scales: {},
legends: {},
tooltip: {
showTitle: true,
triggerOn: 'mousemove',
inPanel: true,
useHtml: true,
},
axes: { fields: {} },
coord: { type: 'cartesian' },
elements: [],
annotations: [],
interactions: {},
theme: this.theme,
panelRange: {},
animate: true,
};
this.paddingController.clear();
this.drawTitle();
this.drawDescription();
this.coord();
this.scale();
this.axis();
this.tooltip();
this.legend();
this.addGeometry();
this.annotation();
this.animation();
this.viewRange = this.getViewRange();
this.paddingController.clearOuterComponents();
this.view = new G2.View({
width: this.width,
height: this.height,
canvas: this.canvas,
container: this.container,
padding: this.paddingController.getPadding(),
data: this.processData(this.options.data),
theme: this.theme,
options: this.config,
start: { x: this.viewRange.minX, y: this.viewRange.minY },
end: { x: this.viewRange.maxX, y: this.viewRange.maxY },
});
this.applyInteractions();
this.view.on('afterrender', function () {
_this.afterRender();
});
};
ViewLayer.prototype.afterInit = function () {
_super.prototype.afterInit.call(this);
if (!this.view || this.view.destroyed) {
return;
}
if (this.options.padding !== 'auto') {
this.parseEvents();
}
};
ViewLayer.prototype.afterRender = function () {
if (!this.view || this.view.destroyed) {
return;
}
var options = this.options;
var padding = options.padding ? options.padding : this.config.theme.padding;
/** defaultState */
if (options.defaultState && padding !== 'auto') {
this.stateController.defaultStates(options.defaultState);
}
this.addGeomCliper();
/** autopadding */
if (padding === 'auto') {
this.paddingController.processAutoPadding();
}
};
/** 完整生命周期渲染 */
ViewLayer.prototype.render = function () {
_super.prototype.render.call(this);
var data = this.options.data;
if (!_.isEmpty(data)) {
this.view.render();
}
};
/** 销毁 */
ViewLayer.prototype.destroy = function () {
this.doDestroy();
_super.prototype.destroy.call(this);
};
/** 更新配置项 */
ViewLayer.prototype.updateConfig = function (cfg) {
this.doDestroy();
if (!cfg.padding && this.initialOptions.padding && this.initialOptions.padding === 'auto') {
cfg.padding = 'auto';
}
this.options = _.deepMix({}, this.options, cfg);
this.processOptions(this.options);
};
ViewLayer.prototype.changeData = function (data) {
this.options.data = this.processData(data);
this.view.changeData(this.options.data);
};
// plot 不断销毁重建,需要一个api获取最新的plot
ViewLayer.prototype.getPlot = function () {
return this.view;
};
// 获取对应的G2 Theme
ViewLayer.prototype.getTheme = function () {
return this.theme;
};
ViewLayer.prototype.getResponsiveTheme = function () {
return this.themeController.getResponsiveTheme(this.type);
};
// 获取对应的Plot Theme
ViewLayer.prototype.getPlotTheme = function () {
return this.themeController.getPlotTheme(this.options, this.type);
};
// 绑定一个外部的stateManager
ViewLayer.prototype.bindStateManager = function (stateManager, cfg) {
this.stateController.bindStateManager(stateManager, cfg);
};
// 响应状态量更新的快捷方法
ViewLayer.prototype.setActive = function (condition, style) {
this.stateController.setState({ type: 'active', condition: condition, style: style });
};
ViewLayer.prototype.setSelected = function (condition, style) {
this.stateController.setState({ type: 'selected', condition: condition, style: style });
};
ViewLayer.prototype.setDisable = function (condition, style) {
this.stateController.setState({ type: 'disable', condition: condition, style: style });
};
ViewLayer.prototype.setNormal = function (condition) {
this.stateController.setState({ type: 'normal', condition: condition, style: {} });
};
// 获取 ViewLayer 的数据项
ViewLayer.prototype.getData = function (start, end) {
return this.processData((this.options.data || []).slice(start, end));
};
ViewLayer.prototype.processData = function (data) {
return data;
};
ViewLayer.prototype.scale = function () {
/** scale meta配置 */
// 1. this.config.scales中已有子图形在处理xAxis/yAxis是写入的xField/yField对应的scale信息,这里再检查用户设置的meta,将meta信息合并到默认的scale中
// 2. 同时xAxis/yAxis中的type优先级更高,覆盖meta中的type配置
var scaleTypes = _.mapValues(this.config.scales, function (scaleConfig) {
var type = scaleConfig.type;
return type ? { type: type } : {};
});
var scales = _.deepMix({}, this.config.scales, this.options.meta || {}, scaleTypes);
this.setConfig('scales', scales);
};
ViewLayer.prototype.axis = function () {
var xAxis_parser = factory_1.getComponent('axis', {
plot: this,
dim: 'x',
});
var yAxis_parser = factory_1.getComponent('axis', {
plot: this,
dim: 'y',
});
var axesConfig = { fields: {} };
axesConfig.fields[this.options.xField] = xAxis_parser;
axesConfig.fields[this.options.yField] = yAxis_parser;
/** 存储坐标轴配置项到config */
this.setConfig('axes', axesConfig);
};
ViewLayer.prototype.tooltip = function () {
if (this.options.tooltip.visible === false) {
this.setConfig('tooltip', false);
return;
}
this.setConfig('tooltip', _.deepMix({}, _.get(this.options, 'tooltip')));
_.deepMix(this.config.theme.tooltip, this.options.tooltip.style);
};
ViewLayer.prototype.legend = function () {
if (this.options.legend.visible === false) {
this.setConfig('legends', false);
return;
}
var flipOption = _.get(this.options, 'legend.flipPage');
var clickable = _.get(this.options, 'legend.clickable');
this.setConfig('legends', {
position: _.get(this.options, 'legend.position'),
formatter: _.get(this.options, 'legend.formatter'),
offsetX: _.get(this.options, 'legend.offsetX'),
offsetY: _.get(this.options, 'legend.offsetY'),
clickable: _.isUndefined(clickable) ? true : clickable,
// wordSpacing: _.get(this.options, 'legend.wordSpacing'),
flipPage: flipOption,
});
};
ViewLayer.prototype.annotation = function () {
var _this = this;
var config = [];
if (this.config.coord.type === 'cartesian' && this.options.guideLine) {
_.each(this.options.guideLine, function (line) {
var guideLine = factory_1.getComponent('guideLine', {
plot: _this,
cfg: line,
});
config.push(guideLine);
});
}
this.setConfig('annotations', config);
};
ViewLayer.prototype.animation = function () {
if (this.options.animation === false || this.options.padding === 'auto') {
this.config.animate = false;
}
};
ViewLayer.prototype.applyInteractions = function () {
var _this = this;
var _a = this.options.interactions, interactions = _a === void 0 ? [] : _a;
if (this.interactions) {
this.interactions.forEach(function (inst) {
inst.destroy();
});
}
this.interactions = [];
interactions.forEach(function (interaction) {
var Ctor = index_1.default.getInteraction(interaction.type, _this.type);
if (Ctor) {
var inst = new Ctor({ view: _this.view }, _this, Ctor.getInteractionRange(_this.layerBBox, interaction.cfg), interaction.cfg);
_this.interactions.push(inst);
}
});
};
/** 设置G2 config,带有类型推导 */
ViewLayer.prototype.setConfig = function (key, config) {
if (key === 'element') {
this.config.elements.push(config);
return;
}
if (config === false) {
this.config[key] = false;
return;
}
_.assign(this.config[key], config);
};
ViewLayer.prototype.parseEvents = function (eventParser) {
var _this = this;
var options = this.options;
if (options.events) {
_super.prototype.parseEvents.call(this, options.events);
var eventmap_1 = eventParser ? eventParser.EVENT_MAP : event_1.EVENT_MAP;
_.each(options.events, function (e, k) {
if (_.isFunction(e)) {
var eventName = eventmap_1[k] || k;
var handler = e;
event_1.onEvent(_this, eventName, handler);
}
});
}
};
ViewLayer.prototype.drawTitle = function () {
var props = this.options;
var range = this.layerBBox;
if (this.title) {
this.title.destroy();
this.title = null;
}
if (common_1.isTextUsable(props.title)) {
var width = this.width;
var theme = this.config.theme;
var title = new description_1.default({
leftMargin: range.minX + theme.title.padding[3],
topMargin: range.minY + theme.title.padding[0],
text: props.title.text,
style: _.mix(theme.title, props.title.style),
wrapperWidth: width - theme.title.padding[3] - theme.title.padding[1],
container: this.container.addGroup(),
theme: theme,
index: common_1.isTextUsable(props.description) ? 0 : 1,
plot: this,
name: 'title',
});
this.title = title;
this.paddingController.registerPadding(title, 'outer');
}
};
ViewLayer.prototype.drawDescription = function () {
var props = this.options;
var range = this.layerBBox;
if (this.description) {
this.description.destroy();
this.description = null;
}
if (common_1.isTextUsable(props.description)) {
var width = this.width;
var theme = this.config.theme;
var topMargin = 0;
if (this.title) {
var titleBBox = this.title.getBBox();
topMargin += titleBBox.minY + titleBBox.height;
topMargin += theme.description.padding[0];
}
else {
// 无title的情况下使用title的上padding
topMargin += range.minY + theme.title.padding[0];
}
var description = new description_1.default({
leftMargin: range.minX + theme.description.padding[3],
topMargin: topMargin,
text: props.description.text,
style: _.mix(theme.description, props.description.style),
wrapperWidth: width - theme.description.padding[3] - theme.description.padding[1],
container: this.container.addGroup(),
theme: theme,
index: 1,
plot: this,
name: 'description',
});
this.description = description;
this.paddingController.registerPadding(description, 'outer');
}
};
/** 抽取destroy和updateConfig共有代码为_destroy方法 */
ViewLayer.prototype.doDestroy = function () {
this.doDestroyInteractions();
/** 销毁g2.view实例 */
if (!this.view.destroyed) {
this.view.destroy();
}
};
ViewLayer.prototype.doDestroyInteractions = function () {
// 移除注册的 interactions
if (this.interactions) {
this.interactions.forEach(function (inst) {
inst.destroy();
});
}
this.interactions = [];
};
ViewLayer.prototype.getViewRange = function () {
var _this = this;
// 有 Range 的 Interaction 参与 ViewMargin 计算
var _a = this.options.interactions, interactions = _a === void 0 ? [] : _a;
var layerBBox = this.layerBBox;
interactions.forEach(function (interaction) {
var Ctor = index_1.default.getInteraction(interaction.type, _this.type);
var range = Ctor && Ctor.getInteractionRange(layerBBox, interaction.cfg);
var position = '';
if (range) {
// 先只考虑 Range 靠边的情况
if (range.bottom === layerBBox.bottom && range.top > layerBBox.top) {
// margin[2] += range.height;
position = 'bottom';
}
else if (range.right === layerBBox.right && range.left > layerBBox.left) {
// margin[1] += range.width;
position = 'right';
}
else if (range.left === layerBBox.left && range.right > layerBBox.right) {
// margin[3] += range.width;
position = 'left';
}
else if (range.top === layerBBox.top && range.bottom > layerBBox.bottom) {
// margin[0] += range.height;
position = 'top';
}
_this.paddingController.registerPadding({
getBBox: function () {
return range;
},
position: position,
}, 'outer');
}
});
var viewRange = this.paddingController.processOuterPadding();
return viewRange;
};
// 临时解决scale min & max的图形截取
ViewLayer.prototype.addGeomCliper = function () {
var panelRange = this.view.get('panelRange');
var cliper = new g_1.Rect({
attrs: {
x: panelRange.minX,
y: panelRange.minY,
width: panelRange.width,
height: panelRange.height,
},
});
var geoms = this.view.get('elements');
_.each(geoms, function (geom) {
var cliperContainer = geom.get('shapeContainer');
var preCliper = cliperContainer.attr('clip');
if (preCliper) {
preCliper.remove();
}
cliperContainer.attr('clip', cliper);
});
};
return ViewLayer;
}(layer_1.default));
exports.default = ViewLayer;
//# sourceMappingURL=view-layer.js.map