UNPKG

@visactor/vrender-components

Version:

components library for dp visualization

234 lines (221 loc) 16.3 kB
import { builtinSymbolsMap, calculateLineHeight } from "@visactor/vrender-core"; import { merge, isValid, normalizePadding, isNil } from "@visactor/vutils"; import { AbstractComponent } from "../core/base"; import { alignTextInLine, initTextMeasure } from "../util/text"; import { isVisible } from "../util"; import { getRichTextAttribute, mergeRowAttrs } from "./util"; import { defaultAttributes, TOOLTIP_POSITION_ATTRIBUTES } from "./config"; import { DEFAULT_HTML_TEXT_SPEC } from "../constant"; import { loadTooltipComponent } from "./register"; const TOOLTIP_BACKGROUND_NAME = "tooltip-background", TOOLTIP_TITLE_NAME = "tooltip-title", TOOLTIP_CONTENT_NAME = "tooltip-content", TOOLTIP_SHAPE_NAME_SUFFIX = "shape", TOOLTIP_KEY_NAME_SUFFIX = "key", TOOLTIP_VALUE_NAME_SUFFIX = "value"; loadTooltipComponent(); export class Tooltip extends AbstractComponent { constructor(attributes, options) { super((null == options ? void 0 : options.skipDefault) ? attributes : merge({}, Tooltip.defaultAttributes, attributes), options), this.name = "tooltip"; } render() { var _a; const {visible: visible, content: content, panel: panel, keyWidth: keyWidth, valueWidth: valueWidth, hasContentShape: hasContentShape, autoCalculatePosition: autoCalculatePosition, autoMeasure: autoMeasure, align: align} = this.attribute; if (!visible) return void this.hideAll(); autoMeasure && Tooltip.measureTooltip(this.attribute), autoCalculatePosition && Tooltip.calculateTooltipPosition(this.attribute); const padding = normalizePadding(this.attribute.padding); this._tooltipPanel = this.createOrUpdateChild("tooltip-background", Object.assign({ visible: !0 }, panel), "rect"), this._tooltipTitleContainer = this.createOrUpdateChild("tooltip-title", { visible: !0, x: padding[3], y: padding[0] }, "group"); const titleAttr = Tooltip.getTitleAttr(this.attribute); this._tooltipTitleSymbol = this._tooltipTitleContainer.createOrUpdateChild("tooltip-title-shape", merge({ symbolType: "circle" }, titleAttr.shape, { visible: isVisible(titleAttr) && isVisible(titleAttr.shape) }), "symbol"), "object" != typeof titleAttr.value.text || null === titleAttr.value.text || "rich" !== titleAttr.value.text.type && "html" !== titleAttr.value.text.type ? titleAttr.value.multiLine ? this._tooltipTitle = this._tooltipTitleContainer.createOrUpdateChild("tooltip-title-value", Object.assign({ visible: isVisible(titleAttr) && isVisible(titleAttr.value) }, getRichTextAttribute(titleAttr.value)), "richtext") : this._tooltipTitle = this._tooltipTitleContainer.createOrUpdateChild("tooltip-title-value", Object.assign({ text: null !== (_a = titleAttr.value.text) && void 0 !== _a ? _a : "", visible: isVisible(titleAttr) && isVisible(titleAttr.value) }, titleAttr.value), "text") : "rich" === titleAttr.value.text.type ? this._tooltipTitle = this._tooltipTitleContainer.createOrUpdateChild("tooltip-title-value", Object.assign({ visible: isVisible(titleAttr) && isVisible(titleAttr.value) }, getRichTextAttribute(titleAttr.value)), "richtext") : "html" === titleAttr.value.text.type && (this._tooltipTitle = this._tooltipTitleContainer.createOrUpdateChild("tooltip-title-value", Object.assign({ html: Object.assign(Object.assign({ dom: titleAttr.value.text.text }, DEFAULT_HTML_TEXT_SPEC), titleAttr.value), visible: isVisible(titleAttr) && isVisible(titleAttr.value), width: titleAttr.value.width, height: titleAttr.value.height, wordBreak: titleAttr.value.wordBreak, textAlign: titleAttr.value.textAlign, textBaseline: titleAttr.value.textBaseline, singleLine: !1, textConfig: [] }, titleAttr.value), "richtext")); const titlePaddingLeft = isVisible(titleAttr.shape) ? titleAttr.shape.size + titleAttr.shape.spacing : 0, {textAlign: textAlign, textBaseline: textBaseline} = titleAttr.value, contentWidth = panel.width - padding[3] - padding[0] - titlePaddingLeft; "center" === textAlign ? this._tooltipTitle.setAttribute("x", titlePaddingLeft + contentWidth / 2) : "right" === textAlign || "end" === textAlign ? this._tooltipTitle.setAttribute("x", titlePaddingLeft + contentWidth) : this._tooltipTitle.setAttribute("x", titlePaddingLeft), "bottom" === textBaseline ? this._tooltipTitle.setAttribute("y", titleAttr.height) : "middle" === textBaseline ? this._tooltipTitle.setAttribute("y", titleAttr.height / 2) : this._tooltipTitle.setAttribute("y", 0); const titleHeight = isVisible(titleAttr) ? titleAttr.height + titleAttr.spaceRow : 0; if (this._tooltipContent = this.createOrUpdateChild("tooltip-content", { visible: !0 }, "group"), this._tooltipContent.removeAllChild(!0), content && content.length) { this._tooltipContent.setAttribute("x", padding[3]), this._tooltipContent.setAttribute("y", padding[0] + titleHeight); let lastYPos = 0; content.forEach(((item, i) => { const itemAttr = Tooltip.getContentAttr(this.attribute, i); if (!isVisible(itemAttr)) return; const itemGroupName = `tooltip-content-${i}`, itemGroup = this._tooltipContent.createOrUpdateChild(itemGroupName, { visible: !0, x: 0, y: lastYPos }, "group"), shapeOffsetWidth = itemAttr.shape.size + itemAttr.shape.spacing; let x = "right" === align ? (hasContentShape ? shapeOffsetWidth : 0) + (isVisible(itemAttr.key) ? keyWidth + itemAttr.key.spacing : 0) + (isVisible(itemAttr.value) ? valueWidth : 0) : 0; this._createShape("right" === align ? x - itemAttr.shape.size / 2 : x + itemAttr.shape.size / 2, itemAttr, itemGroup, itemGroupName), hasContentShape && ("right" === align ? x -= shapeOffsetWidth : x += shapeOffsetWidth); const keyGraphic = this._createKey(itemAttr, itemGroup, itemGroupName); keyGraphic && (alignTextInLine(align, keyGraphic, itemAttr.key.textAlign, x, keyWidth), keyGraphic.setAttribute("y", 0), "right" === align ? x -= keyWidth + itemAttr.key.spacing : x += keyWidth + itemAttr.key.spacing); const valueGraphic = this._createValue(itemAttr, itemGroup, itemGroupName); if (valueGraphic) { let textAlign = "right"; isValid(itemAttr.value.textAlign) ? textAlign = itemAttr.value.textAlign : isVisible(itemAttr.key) || "right" === align || (textAlign = "left"), valueGraphic.setAttribute("textAlign", textAlign), alignTextInLine(align, valueGraphic, textAlign, x, valueWidth), valueGraphic.setAttribute("y", 0); } lastYPos += itemAttr.height + itemAttr.spaceRow; })); } } _createShape(x, itemAttr, itemGroup, itemGroupName) { var _a; if (isVisible(itemAttr.shape)) return itemGroup.createOrUpdateChild(`${itemGroupName}-shape`, Object.assign({ visible: !0, x: x, y: itemAttr.shape.size / 2 + ((null !== (_a = calculateLineHeight(itemAttr.key.lineHeight, itemAttr.key.fontSize)) && void 0 !== _a ? _a : itemAttr.key.fontSize) - itemAttr.shape.size) / 2 }, itemAttr.shape), "symbol"); } _createKey(itemAttr, itemGroup, itemGroupName) { var _a; if (isVisible(itemAttr.key)) { let element; return element = itemAttr.key.multiLine ? itemGroup.createOrUpdateChild(`${itemGroupName}-key`, Object.assign(Object.assign({ visible: !0 }, getRichTextAttribute(itemAttr.key)), { textBaseline: "top" }), "richtext") : "object" != typeof itemAttr.key.text || null === itemAttr.key.text || "rich" !== itemAttr.key.text.type && "html" !== itemAttr.key.text.type ? itemGroup.createOrUpdateChild(`${itemGroupName}-key`, Object.assign(Object.assign({ visible: !0, text: null !== (_a = itemAttr.key.text) && void 0 !== _a ? _a : "" }, itemAttr.key), { textBaseline: "top" }), "text") : "rich" === itemAttr.key.text.type ? itemGroup.createOrUpdateChild(`${itemGroupName}-value`, Object.assign(Object.assign({ visible: !0 }, getRichTextAttribute(itemAttr.key)), { textBaseline: "top" }), "richtext") : itemGroup.createOrUpdateChild(`${itemGroupName}-value`, { html: Object.assign(Object.assign({ dom: itemAttr.key.text.text }, DEFAULT_HTML_TEXT_SPEC), itemAttr.key) }, "richtext"), element; } } _createValue(itemAttr, itemGroup, itemGroupName) { var _a; if (isVisible(itemAttr.value)) { let element; return element = itemAttr.value.multiLine ? itemGroup.createOrUpdateChild(`${itemGroupName}-value`, Object.assign(Object.assign({ visible: !0 }, getRichTextAttribute(itemAttr.value)), { textBaseline: "top" }), "richtext") : "object" != typeof itemAttr.value.text || null === itemAttr.value.text || "rich" !== itemAttr.value.text.type && "html" !== itemAttr.value.text.type ? itemGroup.createOrUpdateChild(`${itemGroupName}-value`, Object.assign(Object.assign({ visible: !0, text: null !== (_a = itemAttr.value.text) && void 0 !== _a ? _a : "" }, itemAttr.value), { textBaseline: "top" }), "text") : "rich" === itemAttr.value.text.type ? itemGroup.createOrUpdateChild(`${itemGroupName}-value`, Object.assign(Object.assign({ visible: !0 }, getRichTextAttribute(itemAttr.value)), { textBaseline: "top" }), "richtext") : itemGroup.createOrUpdateChild(`${itemGroupName}-value`, { html: Object.assign({ dom: itemAttr.value.text.text, container: "", width: 30, height: 30, style: {} }, itemAttr.value) }, "richtext"), element; } } setAttributes(params, forceUpdateTag) { const keys = Object.keys(params); this.attribute.autoCalculatePosition && keys.every((key => TOOLTIP_POSITION_ATTRIBUTES.includes(key))) ? (this._mergeAttributes(params, keys), isNil(this.attribute.panel.width) && this.attribute.autoMeasure && Tooltip.measureTooltip(this.attribute), Tooltip.calculateTooltipPosition(this.attribute), super.setAttributes({ x: this.attribute.x, y: this.attribute.y }, forceUpdateTag)) : super.setAttributes(params, forceUpdateTag); } static calculateTooltipPosition(attribute) { const {width: tooltipBoxWidth = 0, height: tooltipBoxHeight = 0} = attribute.panel, {offsetX: offsetX, offsetY: offsetY, pointerX: pointerX, pointerY: pointerY, positionX: positionX, positionY: positionY, parentBounds: parentBounds} = attribute; let x = pointerX, y = pointerY; return "left" === positionX ? x -= tooltipBoxWidth + offsetX : "center" === positionX ? x -= tooltipBoxWidth / 2 : x += offsetX, "top" === positionY ? y -= tooltipBoxHeight + offsetY : "middle" === positionY ? y -= tooltipBoxHeight / 2 : y += offsetY, x + tooltipBoxWidth > parentBounds.x2 && (x -= tooltipBoxWidth + offsetX), y + tooltipBoxHeight > parentBounds.y2 && (y -= tooltipBoxHeight + offsetY), x < parentBounds.x1 && (x = parentBounds.x1), y < parentBounds.y1 && (y = parentBounds.y1), attribute.x = x, attribute.y = y, attribute; } static measureTooltip(attribute) { const {content: content, contentStyle: contentStyle} = attribute, padding = normalizePadding(attribute.padding), titleAttr = Tooltip.getTitleAttr(attribute); let maxWidth = 0, containerHeight = padding[0] + padding[2], titleMaxHeight = 0; const {value: titleValue, shape: titleShape} = titleAttr, {visible: titleHasShape = !1, symbolType: titleShapeType = ""} = null != titleShape ? titleShape : {}; if (isValid(titleValue) && "object" != typeof titleAttr.value.text) { const {width: width, height: height} = initTextMeasure(titleValue).quickMeasure(titleValue.text); maxWidth = width, titleMaxHeight = height; } if (titleHasShape && builtinSymbolsMap[titleShapeType] && (maxWidth += titleShape.size + titleShape.spacing, titleMaxHeight = Math.max(titleShape.size, titleMaxHeight)), attribute.title && (attribute.title.width = maxWidth, attribute.title.height = titleMaxHeight), isVisible(titleAttr) && (containerHeight += titleMaxHeight + titleAttr.spaceRow), content && content.length) { const filteredContent = []; if (content.forEach(((item, i) => { const itemAttr = Tooltip.getContentAttr(attribute, i); (item.key || item.value) && isVisible(itemAttr) && filteredContent.push([ item, itemAttr ]); })), filteredContent.length) { let hasContentShape = !1; const shapeWidths = [], keyWidths = [], valueWidths = []; filteredContent.forEach((([item, itemAttr], i) => { var _a; const {key: key, value: value, shape: shape, spaceRow: spaceRow} = itemAttr, itemHasShape = isVisible(shape), itemShapeType = null !== (_a = null == shape ? void 0 : shape.symbolType) && void 0 !== _a ? _a : "", keyTextMeasure = initTextMeasure(key), valueTextMeasure = initTextMeasure(value); let itemHeight = 0; if (isVisible(key)) { const {width: width, height: height} = keyTextMeasure.quickMeasure(key.text); keyWidths.push(width), itemHeight = Math.max(itemHeight, height); } if (isVisible(value)) { const {width: width, height: height} = valueTextMeasure.quickMeasure(value.text); valueWidths.push(width), itemHeight = Math.max(itemHeight, height); } itemHasShape && builtinSymbolsMap[itemShapeType] && (hasContentShape = !0, shapeWidths.push(shape.size), itemHeight = Math.max(shape.size, itemHeight)), item.height = itemHeight, containerHeight += itemHeight, i < filteredContent.length - 1 && (containerHeight += null != spaceRow ? spaceRow : contentStyle.spaceRow); })); const maxShapeWidth = shapeWidths.length ? Math.max(...shapeWidths) : 0, maxKeyWidth = keyWidths.length ? Math.max(...keyWidths) : 0, maxValueWidth = valueWidths.length ? Math.max(...valueWidths) : 0; maxWidth = Math.max(maxKeyWidth + maxValueWidth + contentStyle.key.spacing + contentStyle.value.spacing + (hasContentShape ? maxShapeWidth + contentStyle.shape.spacing : 0), maxWidth), content.forEach((item => { item.width = maxWidth; })), attribute.hasContentShape = hasContentShape, attribute.keyWidth = maxKeyWidth, attribute.valueWidth = maxValueWidth; } } return attribute.panel.width = maxWidth + padding[1] + padding[3], attribute.panel.height = containerHeight, attribute; } static getTitleAttr(attribute) { return mergeRowAttrs({}, Tooltip.defaultAttributes.titleStyle, Tooltip.defaultAttributes.title, attribute.titleStyle, attribute.title); } static getContentAttr(attribute, index) { return mergeRowAttrs({}, Tooltip.defaultAttributes.contentStyle, attribute.contentStyle, attribute.content[index]); } } Tooltip.defaultAttributes = defaultAttributes; //# sourceMappingURL=tooltip.js.map