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;