function _createSuper(Derived) { return function () { var Super = _getPrototypeOf(Derived), result; if (_isNativeReflectConstruct()) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
function _possibleConstructorReturn(self, call) { if (call && (typeof call === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }
function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; }
var Util = require('../util');
var DomUtil = Util.DomUtil;
var Component = require('../component');
var positionAdjust = require('./utils/position-adjust');
var spirialAdjust = require('./utils/spiral-adjust');
var bboxAdjust = require('./utils/bbox-adjust');
var LAYOUTS = {
scatter: positionAdjust,
map: spirialAdjust,
treemap: bboxAdjust
};
var Label = /*#__PURE__*/function (_Component) {
_inheritsLoose(Label, _Component);
var _super = _createSuper(Label);
function Label() {
return _Component.apply(this, arguments) || this;
}
var _proto = Label.prototype;
_proto.getDefaultCfg = function getDefaultCfg() {
var cfg = _Component.prototype.getDefaultCfg.call(this);
return Util.mix({}, cfg, {
name: 'label',
/**
* label类型
* @type {(String)}
*/
type: 'default',
/**
* 默认文本样式
* @type {Array}
*/
textStyle: null,
/**
* 文本显示格式化回调函数
* @type {Function}
*/
formatter: null,
/**
* 显示的文本集合
* @type {Array}
*/
items: null,
/**
* 是否使用html渲染label
* @type {String}
*/
useHtml: false,
/**
* html 渲染时用的容器的模板,必须存在 class = "g-labels"
* @type {String}
*/
containerTpl: '
',
/**
* html 渲染时单个 label 的模板,必须存在 class = "g-label"
* @type {String}
*/
itemTpl: '{text}
',
/**
* label牵引线定义
* @type {String || Object}
*/
labelLine: false,
/**
* label牵引线容器
* @type Object
*/
lineGroup: null,
/**
* 需添加label的shape
* @type Object
*/
shapes: null,
/**
* 默认为true。为false时指定直接用items渲染文本,不进行config
* @type Object
*/
config: true,
/**
* 是否进行拾取
* @type Object
*/
capture: true
});
}
/*
* 清空label容器
*/
;
_proto.clear = function clear() {
var group = this.get('group');
var container = this.get('container');
if (group && !group.get('destroyed')) {
group.clear();
}
if (container) {
container.innerHTML = '';
}
_Component.prototype.clear.call(this);
}
/**
* 销毁group
*/
;
_proto.destroy = function destroy() {
var group = this.get('group');
var container = this.get('container');
if (!group.destroy) {
group.destroy();
}
if (container) {
container.parentNode && container.parentNode.removeChild(container);
}
_Component.prototype.destroy.call(this); // 要最后调用 super.destroy 否则 get 属性会无效
}
/**
* label绘制全过程
*/
;
_proto.render = function render() {
this.clear();
this._init();
this.beforeDraw();
this.draw();
this.afterDraw();
};
_proto._dryDraw = function _dryDraw() {
var self = this;
var items = self.get('items');
var children = self.getLabels();
var count = children.length;
Util.each(items, function (item, index) {
if (index < count) {
var label = children[index];
self.changeLabel(label, item);
} else {
var labelShape = self._addLabel(item, index);
if (labelShape) {
labelShape._id = item._id;
labelShape.set('coord', item.coord);
}
}
});
for (var i = count - 1; i >= items.length; i--) {
children[i].remove();
}
self._adjustLabels();
if (self.get('labelLine') || !self.get('config')) {
self.drawLines();
}
}
/**
* 更新label
* 1. 将items与group中的children对比,更新/新增/删除labels
* 2. labels布局优化
* 3. 画label连接线
* 4. 绘制到画布
*/
;
_proto.draw = function draw() {
this._dryDraw();
this.get('canvas').draw();
}
/*
* 更新label
* oldLabel shape或label dom
* newLabel label data
* index items中的下标
*/
;
_proto.changeLabel = function changeLabel(oldLabel, newLabel) {
if (!oldLabel) {
return;
}
if (oldLabel.tagName) {
var node = this._createDom(newLabel);
oldLabel.innerHTML = node.innerHTML;
this._setCustomPosition(newLabel, oldLabel);
} else {
oldLabel._id = newLabel._id;
oldLabel.attr('text', newLabel.text);
if (oldLabel.attr('x') !== newLabel.x || oldLabel.attr('y') !== newLabel.y) {
oldLabel.resetMatrix();
if (newLabel.textStyle.rotate) {
oldLabel.rotateAtStart(newLabel.textStyle.rotate);
delete newLabel.textStyle.rotate;
}
oldLabel.attr(newLabel);
}
}
}
/**
* 显示label
*/
;
_proto.show = function show() {
var group = this.get('group');
var container = this.get('container');
if (group) {
group.show();
}
if (container) {
container.style.opacity = 1;
}
}
/**
* 隐藏label
*/
;
_proto.hide = function hide() {
var group = this.get('group');
var container = this.get('container');
if (group) {
group.hide();
}
if (container) {
container.style.opacity = 0;
}
}
/**
* 画label连接线
*/
;
_proto.drawLines = function drawLines() {
var self = this;
var lineStyle = self.get('labelLine');
if (typeof lineStyle === 'boolean') {
self.set('labelLine', {});
}
var lineGroup = self.get('lineGroup');
if (!lineGroup || lineGroup.get('destroyed')) {
lineGroup = self.get('group').addGroup({
elCls: 'x-line-group'
});
self.set('lineGroup', lineGroup);
} else {
lineGroup.clear();
}
Util.each(self.get('items'), function (label) {
self.lineToLabel(label, lineGroup);
});
};
_proto.lineToLabel = function lineToLabel(label, lineGroup) {
var self = this;
if (!self.get('config') && !label.labelLine) {
return;
}
var lineStyle = label.labelLine || self.get('labelLine');
var capture = typeof label.capture === 'undefined' ? self.get('capture') : label.capture;
var path = lineStyle.path;
if (path && Util.isFunction(lineStyle.path)) {
path = lineStyle.path(label);
}
if (!path) {
var start = label.start || {
x: label.x - label._offset.x,
y: label.y - label._offset.y
};
path = [['M', start.x, start.y], ['L', label.x, label.y]];
}
var stroke = label.color;
if (!stroke) {
if (label.textStyle && label.textStyle.fill) {
stroke = label.textStyle.fill;
} else {
stroke = '#000';
}
}
var lineShape = lineGroup.addShape('path', {
attrs: Util.mix({
path: path,
fill: null,
stroke: stroke
}, lineStyle),
capture: capture
}); // label 对应线的动画关闭
lineShape.name = self.get('name'); // generate labelLine id according to label id
lineShape._id = label._id && label._id.replace('glabel', 'glabelline');
lineShape.set('coord', self.get('coord'));
} // 根据type对label布局
;
_proto._adjustLabels = function _adjustLabels() {
var self = this;
var type = self.get('type');
var labels = self.getLabels();
var shapes = self.get('shapes');
var layout = LAYOUTS[type];
if (type === 'default' || !layout) {
return;
}
layout(labels, shapes);
}
/**
* 获取当前所有label实例
* @return {Array} 当前label实例
*/
;
_proto.getLabels = function getLabels() {
var container = this.get('container');
if (container) {
return Util.toArray(container.childNodes);
}
return this.get('group').get('children');
} // 先计算label的所有配置项,然后生成label实例
;
_proto._addLabel = function _addLabel(item, index) {
var cfg = item;
if (this.get('config')) {
cfg = this._getLabelCfg(item, index);
}
return this._createText(cfg);
};
_proto._getLabelCfg = function _getLabelCfg(item, index) {
var textStyle = this.get('textStyle') || {};
var formatter = this.get('formatter');
var htmlTemplate = this.get('htmlTemplate');
if (!Util.isObject(item)) {
var tmp = item;
item = {};
item.text = tmp;
}
if (Util.isFunction(textStyle)) {
textStyle = textStyle(item.text, item, index);
}
if (formatter) {
item.text = formatter(item.text, item, index);
}
if (htmlTemplate) {
item.useHtml = true;
if (Util.isFunction(htmlTemplate)) {
item.text = htmlTemplate(item.text, item, index);
}
}
if (Util.isNil(item.text)) {
item.text = '';
}
item.text = item.text + ''; // ? 为什么转换为字符串
var cfg = Util.mix({}, item, {
textStyle: textStyle
}, {
x: item.x || 0,
y: item.y || 0
});
return cfg;
}
/**
* label初始化,主要针对html容器
*/
;
_proto._init = function _init() {
if (!this.get('group')) {
var group = this.get('canvas').addGroup({
id: 'label-group'
});
this.set('group', group);
}
};
_proto.initHtmlContainer = function initHtmlContainer() {
var container = this.get('container');
if (!container) {
var containerTpl = this.get('containerTpl');
var wrapper = this.get('canvas').get('el').parentNode;
container = DomUtil.createDom(containerTpl);
wrapper.style.position = 'relative';
wrapper.appendChild(container);
this.set('container', container);
} else if (Util.isString(container)) {
container = document.getElementById(container);
if (container) {
this.set('container', container);
}
}
return container;
} // 分html dom和G shape两种情况生成label实例
;
_proto._createText = function _createText(config) {
// @2018-11-29 by blue.lb 这里由于使用delete导致之后的配置无法获取到point和rotate,出现问题,深拷贝一次比较好
var cfg = Util.deepMix({}, config);
var container = this.get('container');
var capture = typeof cfg.capture === 'undefined' ? this.get('capture') : cfg.capture;
var labelShape;
if (cfg.useHtml || cfg.htmlTemplate) {
if (!container) {
container = this.initHtmlContainer();
}
var node = this._createDom(cfg);
container.appendChild(node);
this._setCustomPosition(cfg, node);
} else {
var name = this.get('name');
var origin = cfg.point;
var group = this.get('group');
delete cfg.point; // 临时解决,否则影响动画
var rotate = cfg.rotate; // textStyle中的rotate虽然可以正常画出,但是在做动画的时候可能会导致动画异常。移出,在定义好shape后通过transform实现效果。
if (cfg.textStyle) {
if (cfg.textStyle.rotate) {
rotate = cfg.textStyle.rotate;
delete cfg.textStyle.rotate;
}
cfg = Util.mix({
x: cfg.x,
y: cfg.y,
textAlign: cfg.textAlign,
text: cfg.text
}, cfg.textStyle);
}
labelShape = group.addShape('text', {
attrs: cfg,
capture: capture
});
if (rotate) {
// rotate是用角度定义的,转换为弧度
if (Math.abs(rotate) > Math.PI * 2) {
rotate = rotate / 180 * Math.PI;
}
labelShape.transform([['t', -cfg.x, -cfg.y], ['r', rotate], ['t', cfg.x, cfg.y]]);
}
labelShape.setSilent('origin', origin || cfg);
labelShape.name = name; // 用于事件标注
this.get('appendInfo') && labelShape.setSilent('appendInfo', this.get('appendInfo'));
return labelShape;
}
};
_proto._createDom = function _createDom(cfg) {
var itemTpl = this.get('itemTpl');
var str = Util.substitute(itemTpl, {
text: cfg.text
});
return DomUtil.createDom(str);
} // 根据文本对齐方式确定dom位置
;
_proto._setCustomPosition = function _setCustomPosition(cfg, htmlDom) {
var textAlign = cfg.textAlign || 'left';
var top = cfg.y;
var left = cfg.x;
var width = DomUtil.getOuterWidth(htmlDom);
var height = DomUtil.getOuterHeight(htmlDom);
top = top - height / 2;
if (textAlign === 'center') {
left = left - width / 2;
} else if (textAlign === 'right') {
left = left - width;
}
htmlDom.style.top = parseInt(top, 10) + 'px';
htmlDom.style.left = parseInt(left, 10) + 'px';
};
return Label;
}(Component);
module.exports = Label;