UNPKG

@visactor/vchart

Version:

charts lib based @visactor/VGrammar

224 lines (210 loc) 13.3 kB
import { BaseTooltipHandler } from "./base"; import { getDomStyle, getTextStyle, setStyleToDom } from "./utils/style"; import { TOOLTIP_CONTAINER_EL_CLASS_NAME, DEFAULT_TOOLTIP_Z_INDEX, TOOLTIP_PREFIX, TOOLTIP_CONTENT_BOX_CLASS_NAME, TOOLTIP_TITLE_CLASS_NAME } from "./constants"; import { isValid } from "@visactor/vutils"; import { domDocument } from "../../../util/env"; import { registerComponentPlugin } from "../register"; import { TooltipHandlerType } from "../../../component/tooltip/constant"; import { getSvgHtml } from "./utils/svg"; import { formatContent } from "./utils/common"; import { token } from "../../../theme/token"; import { calcLayoutNumber } from "../../../util/space"; export class DomTooltipHandler extends BaseTooltipHandler { getVisibility() { return !!this._rootDom && "visible" === this._rootDom.style.visibility; } setVisibility(_value) { _value !== this.getVisibility() && this._rootDom && (this._rootDom.style.visibility = _value ? "visible" : "hidden"); } getRootDom() { return this._rootDom; } constructor() { super(DomTooltipHandler.type), this.type = TooltipHandlerType.dom, this._tooltipContainer = null == domDocument ? void 0 : domDocument.body; } onAdd(service) { super.onAdd(service), this._initStyle(), this.initEl(); } initEl() { const parentElement = this._component.getSpec().parentElement; if (domDocument && parentElement && parentElement.children && parentElement.children.length) { for (let i = 0; i < parentElement.children.length; i++) if (parentElement.children[i].classList.contains(TOOLTIP_CONTAINER_EL_CLASS_NAME)) { this._container = parentElement.children[i]; break; } this._container || (this._container = domDocument.createElement("div"), this._container.style.position = "relative", this._container.style.zIndex = DEFAULT_TOOLTIP_Z_INDEX, this._container.classList.add(TOOLTIP_CONTAINER_EL_CLASS_NAME), parentElement.appendChild(this._container)); } } initRootDom() { var _a; const tooltipSpec = this._component.getSpec(), tooltipElement = document.createElement("div"), themeFontFamily = null === (_a = this._chartOption) || void 0 === _a ? void 0 : _a.getTheme("fontFamily"); setStyleToDom(tooltipElement, Object.assign({ left: "0", top: "0", pointerEvents: "none", padding: "12px", position: "absolute", zIndex: DEFAULT_TOOLTIP_Z_INDEX, fontFamily: null != themeFontFamily ? themeFontFamily : token.fontFamily, fontSize: "11px", borderRadius: "3px", borderStyle: "solid", lineHeight: "initial", background: "#fff", boxShadow: "2px 2px 4px rgba(0, 0, 0, 0.1)", maxWidth: "100wh", maxHeight: "100vh", visibility: "hidden" }, this._domStyle.panel)), tooltipElement.classList.add(tooltipSpec.className), tooltipElement.setAttribute("vchart-tooltip-id", `${this.id}`), this._container.appendChild(tooltipElement), this._rootDom = tooltipElement; } _getTooltipBoxSize(actualTooltip, changePositionOnly) { var _a; this._rootDom || this.initRootDom(), changePositionOnly || this._updateDomStringByCol(actualTooltip), this._updateDomStyle("height", changePositionOnly); const rect = null === (_a = this._rootDom) || void 0 === _a ? void 0 : _a.getBoundingClientRect(); return { width: null == rect ? void 0 : rect.width, height: null == rect ? void 0 : rect.height }; } _removeTooltip() { this._rootDom && this._rootDom.parentNode && (this._rootDom.parentNode.removeChild(this._rootDom), this._rootDom = null), this._container = null; } _updateTooltip(visible, params) { var _a, _b; if (visible && this._rootDom) { const {tooltipSpec: tooltipSpec, activeTooltipSpec: activeTooltipSpec} = params; params.changePositionOnly || (this._tooltipActual = activeTooltipSpec); const el = this._rootDom; if (el) { const {x: x = 0, y: y = 0} = null !== (_a = activeTooltipSpec.position) && void 0 !== _a ? _a : {}; let position = { x: x, y: y }; const currentVisible = this.getVisibility(); tooltipSpec.updateElement && (this._updatePosition(null !== (_b = this._cacheCustomTooltipPosition) && void 0 !== _b ? _b : { x: x, y: y }), tooltipSpec.updateElement(el, activeTooltipSpec, params), position = this._getActualTooltipPosition(activeTooltipSpec, params, { width: el.offsetWidth, height: el.offsetHeight }), this._cacheCustomTooltipPosition = position), !currentVisible && visible && (this._rootDom.style.transition = "none", this._updatePosition(position, !1), this._rootDom.getBoundingClientRect()), this._updatePosition(position); } this.setVisibility(visible); } else this.setVisibility(visible), this._cacheCustomTooltipPosition = void 0; } _initStyle() { const tooltipSpec = this._component.getSpec(); this._domStyle = getDomStyle(tooltipSpec); } _updateDomStringByCol(actualTooltip) { var _a; const {title: title = {}, content: content} = actualTooltip, hasContent = content && content.length, rowStyle = this._domStyle.row, chilren = [ ...this._rootDom.children ]; let titleDom = chilren.find((child => child.className.includes(TOOLTIP_TITLE_CLASS_NAME))), contentDom = chilren.find((child => child.className.includes(TOOLTIP_CONTENT_BOX_CLASS_NAME))); if (!titleDom && !1 !== title.visible) { titleDom = document.createElement("h2"); const span = document.createElement("span"); titleDom.appendChild(span), titleDom.classList.add(TOOLTIP_TITLE_CLASS_NAME), this._rootDom.firstChild ? this._rootDom.insertBefore(titleDom, this._rootDom.firstChild) : this._rootDom.appendChild(titleDom); } titleDom && !1 !== title.visible ? (setStyleToDom(titleDom, Object.assign(Object.assign(Object.assign({}, this._domStyle.title), hasContent ? rowStyle : { marginBottom: "0px" }), { marginTop: "0px" })), titleDom.firstChild.innerHTML = `${null !== (_a = title.value) && void 0 !== _a ? _a : ""}`) : titleDom && !1 === title.visible && titleDom.parentNode.removeChild(titleDom); const columns = [ "shape", "key", "value" ]; if (!contentDom && hasContent && (contentDom = document.createElement("div"), columns.forEach((col => { const colDiv = document.createElement("div"); colDiv.classList.add(`${TOOLTIP_PREFIX}-column`), colDiv.classList.add(`${TOOLTIP_PREFIX}-${col}-column`), colDiv.setAttribute("data-col", col), contentDom.appendChild(colDiv); })), contentDom.classList.add(TOOLTIP_CONTENT_BOX_CLASS_NAME), this._rootDom.appendChild(contentDom)), contentDom && hasContent) { const columnDivs = [ ...contentDom.children ]; setStyleToDom(contentDom, { whiteSpace: "nowrap" }), columnDivs.forEach(((colDiv, index) => { const colName = colDiv.getAttribute("data-col"); if (colName && columns.includes(colName)) { const hideColumn = "shape" === colName && content.every((c => !c.hasShape || !c.shapeType)); setStyleToDom(colDiv, Object.assign(Object.assign({}, this._domStyle[colName]), { display: hideColumn ? "none" : "inline-block", verticalAlign: "top" })); const rows = [ ...colDiv.children ]; rows.slice(content.length).forEach((extraRow => { extraRow.parentNode.removeChild(extraRow); })), content.forEach(((entry, index) => { let row = rows[index]; row || (row = document.createElement("div"), row.classList.add(`${TOOLTIP_PREFIX}-${colName}`), colDiv.appendChild(row)); const styleByRow = Object.assign({}, rowStyle); index === content.length - 1 && (styleByRow.marginBottom = "0px"), styleByRow.display = !1 === entry.visible ? "none" : "block", styleByRow.height = "initial", "key" === colName ? (row.innerHTML = formatContent(entry.key), entry.keyStyle && getTextStyle(entry.keyStyle, styleByRow)) : "value" === colName ? (row.innerHTML = formatContent(entry.value), entry.valueStyle && getTextStyle(entry.valueStyle, styleByRow)) : "shape" === colName && (row.innerHTML = getSvgHtml(entry, `${this.id}_${index}`)), setStyleToDom(row, styleByRow); })); } })); } else contentDom && !hasContent && contentDom.parentNode.removeChild(contentDom); } _updateDomStyle(sizeKey = "width", refreshSize) { var _a, _b, _c, _d, _e; const rootDom = this._rootDom, contentDom = [ ...rootDom.children ].find((child => child.className.includes(TOOLTIP_CONTENT_BOX_CLASS_NAME))), titleDom = [ ...rootDom.children ].find((child => child.className.includes(TOOLTIP_TITLE_CLASS_NAME))); if (contentDom) { const tooltipSpec = this._component.getSpec(), contentStyle = {}, titleLabel = null === (_a = tooltipSpec.style) || void 0 === _a ? void 0 : _a.titleLabel; if (titleLabel && titleLabel.autoWidth && !1 !== titleLabel.multiLine && titleDom) { const maxWidth = [ ...contentDom.children ].reduce(((res, col) => "height" === sizeKey ? res + col.getBoundingClientRect().width : Math.max(res, col.getBoundingClientRect().width)), 0); maxWidth > 0 && (titleDom.style.maxWidth = `${maxWidth}px`, titleDom.style.maxWidth = `${Math.ceil(contentDom.getBoundingClientRect().width)}px`); } if (isValid(null === (_b = null == tooltipSpec ? void 0 : tooltipSpec.style) || void 0 === _b ? void 0 : _b.maxContentHeight)) { const titleHeight = titleDom && titleDom.className.includes(TOOLTIP_TITLE_CLASS_NAME) ? titleDom.getBoundingClientRect().height + (null !== (_c = tooltipSpec.style.spaceRow) && void 0 !== _c ? _c : 0) : 0, viewRect = this._chartOption.getChartViewRect(), maxHeight = calcLayoutNumber(tooltipSpec.style.maxContentHeight, Math.min(viewRect.height, document.body.clientHeight) - titleHeight - (this._domStyle.panelPadding ? this._domStyle.panelPadding[0] + this._domStyle.panelPadding[1] : 0)); maxHeight > 0 && (contentStyle.maxHeight = `${maxHeight}px`, contentStyle.overflowY = "auto", contentStyle.width = `calc(100% + ${this._domStyle.panelPadding ? this._domStyle.panelPadding[1] + "px" : "10px"})`, setStyleToDom(contentDom, contentStyle)); } const rows = contentDom.children, widthByCol = []; if (rows) { for (let i = 0; i < rows.length; i++) { const cols = null !== (_d = rows[i].children) && void 0 !== _d ? _d : []; for (let j = 0; j < cols.length; j++) { refreshSize && (cols[j].style[sizeKey] = "initial"); const width = cols[j].getBoundingClientRect()[sizeKey]; (void 0 === widthByCol[j] || widthByCol[j] < width) && (widthByCol[j] = width); } } for (let i = 0; i < rows.length; i++) { const cols = null !== (_e = rows[i].children) && void 0 !== _e ? _e : []; for (let j = 0; j < cols.length; j++) cols[j].style[sizeKey] = `${widthByCol[j]}px`; } } } } _getParentElement(spec) { var _a; return null !== (_a = this._container) && void 0 !== _a ? _a : super._getParentElement(spec); } isTooltipShown() { return this.getVisibility(); } reInit() { super.reInit(), this._initStyle(), this._rootDom && setStyleToDom(this._rootDom, this._domStyle.panel), this.getVisibility() && (this._updateDomStringByCol(this._tooltipActual), this._updateDomStyle("height", !1)); } _updatePosition({x: x, y: y}, resetTransition = !0) { this._rootDom && (this._rootDom.style.transform = `translate3d(${x}px, ${y}px, 0)`, resetTransition && "" !== this._rootDom.style.transition && (this._rootDom.style.transition = "", Object.assign(this._rootDom.style, this._domStyle.panel))); } } DomTooltipHandler.type = TooltipHandlerType.dom; export const registerDomTooltipHandler = () => { registerComponentPlugin(DomTooltipHandler); }; //# sourceMappingURL=dom-tooltip-handler.js.map