UNPKG

@visactor/vchart

Version:

charts lib based @visactor/VGrammar

303 lines (285 loc) 18.1 kB
import { ComponentTypeEnum } from "../interface/type"; import { BaseComponent } from "../base/base-component"; import { isMobileLikeMode, isTrueBrowser, isMiniAppLikeMode } from "../../util/env"; import { showTooltip } from "./utils/show-tooltip"; import { isEmptyPos } from "./utils/common"; import { isSameDimensionInfo } from "../../event/events/dimension/util/common"; import { ChartEvent, Event_Source_Type } from "../../constant/event"; import { isDimensionInfo, isMarkInfo } from "./processor/util"; import { isValid, isNil, array, isNumber, throttle, isObject } from "@visactor/vutils"; import { VChart } from "../../core/vchart"; import { Factory } from "../../core/factory"; import { TooltipSpecTransformer } from "./tooltip-transformer"; import { error } from "../../util"; import { DEFAULT_SHOW_DELAY, TooltipHandlerType } from "./constant"; import { tooltip } from "../../theme/builtin/common/component/tooltip"; export class Tooltip extends BaseComponent { constructor() { super(...arguments), this.layoutZIndex = 1, this.type = ComponentTypeEnum.tooltip, this.name = ComponentTypeEnum.tooltip, this.transformerConstructor = TooltipSpecTransformer, this.specKey = "tooltip", this.layoutType = "none", this._isReleased = !1, this._alwaysShow = !1, this._eventList = [], this._isTooltipShown = !1, this._clickLock = !1, this._mountEvent = (eType, query, callback) => { this.event.on(eType, query, callback), this._eventList.push({ eventType: eType, handler: callback }); }, this._handleClickToLock = params => { var _a, _b; if (this._clickLock) this._handleChartMouseOut(params), this._clickLock = !1; else { if (!this._isTooltipShown && !(null === (_b = null === (_a = this.tooltipHandler) || void 0 === _a ? void 0 : _a.isTooltipShown) || void 0 === _b ? void 0 : _b.call(_a))) return; this._clickLock = !0; } }, this._getMouseOutHandler = needPointerDetection => params => { var _a, _b, _c, _d, _e; if (this._isReleased) return; if (this._alwaysShow || this._clickLock) return; if (!this._isTooltipShown && !(null === (_b = null === (_a = this.tooltipHandler) || void 0 === _a ? void 0 : _a.isTooltipShown) || void 0 === _b ? void 0 : _b.call(_a))) return; const browserEnv = isTrueBrowser(null === (_c = this._option) || void 0 === _c ? void 0 : _c.mode), {clientX: clientX, clientY: clientY} = params.event; browserEnv && needPointerDetection && this._isPointerInChart({ x: clientX, y: clientY }) || (this._enterable ? this._outTimer = setTimeout((() => { this._handleChartMouseOut(params); }), null !== (_e = null === (_d = this._spec) || void 0 === _d ? void 0 : _d.showDelay) && void 0 !== _e ? _e : DEFAULT_SHOW_DELAY) : this._handleChartMouseOut(params)); }, this._handleChartMouseOut = params => { this._alwaysShow || this._isReleased || this._isEnterTooltip || "none" !== this._spec.triggerOff && (this._hideTooltipByHandler(Object.assign(Object.assign({}, params), { tooltip: this })), this._handleMouseMove && this._handleMouseMove.cancel && this._handleMouseMove.cancel(), this._cacheEnterableRect = null, this._cacheInfo = void 0, this._cacheParams = void 0, this._cacheActiveType = void 0); }, this._getMouseMoveHandler = isClick => params => { var _a, _b, _c, _d; this._isReleased || this._isEnterTooltip || (this._outTimer && (clearTimeout(this._outTimer), this._outTimer = null), this.tooltipHandler || this._initHandler(), this.processor || this._initProcessor(), this._alwaysShow || (this._clickLock ? isClick && (this._handleChartMouseOut(params), this._clickLock = !1) : !isClick && this._enterable && (null === (_b = null === (_a = this.tooltipHandler) || void 0 === _a ? void 0 : _a.isTooltipShown) || void 0 === _b ? void 0 : _b.call(_a)) ? (this._showTimer && clearTimeout(this._showTimer), this._showTimer = setTimeout((() => { this._handleChartMouseMove(params, isClick); }), null !== (_d = null === (_c = this._spec) || void 0 === _c ? void 0 : _c.showDelay) && void 0 !== _d ? _d : DEFAULT_SHOW_DELAY)) : this._handleChartMouseMove(params, isClick))); }, this._handleChartMouseMove = (params, isClick) => { if (this._isReleased) return; const mouseEventData = this._getMouseEventData(params), {tooltipInfo: {dimension: dimensionInfo}, ignore: {mark: ignoreMark}} = mouseEventData, success = { mark: !1, dimension: !1, group: !1 }, supportedTooltip = [ "group", "mark", "dimension" ]; for (let i = 0, len = supportedTooltip.length; i < len; i++) { const type = supportedTooltip[i]; if (!!this.processor[type] && this._showTooltipByMouseEvent(type, mouseEventData, params, isClick)) { success[type] = !0; break; } } Object.values(success).every((val => !val)) && !isEmptyPos(params) && (ignoreMark && isMarkInfo(this._cacheInfo) ? success.mark = this._showTooltipByMouseEvent("mark", mouseEventData, params, isClick, !0) : isValid(dimensionInfo) && (success.dimension = this._showTooltipByMouseEvent("dimension", mouseEventData, params, isClick))), success.mark || success.group || success.dimension && !isNil(dimensionInfo) ? this._initEventOfTooltipContent() : this._handleChartMouseOut(params); }, this._showTooltipByMouseEvent = (activeType, mouseEventData, params, isClick, useCache) => { var _a; const processor = this.processor[activeType]; if (!processor.shouldHandleTooltip(params, mouseEventData.tooltipInfo[activeType])) return !1; let success; if (this._hideTimer && clearTimeout(this._hideTimer), useCache) success = !processor.showTooltip(this._cacheInfo, params, !0); else { const tooltipInfo = mouseEventData.tooltipInfo[activeType], isSameAsCache = this._isSameAsCache(tooltipInfo, params, activeType); success = !processor.showTooltip(tooltipInfo, params, isSameAsCache), success && (this._cacheInfo = tooltipInfo, this._cacheParams = params, this._cacheActiveType = activeType); } success && (this._isTooltipShown = !0, isClick && this._spec.lockAfterClick && !this._clickLock ? this._clickLock = !0 : Number.isFinite(this._spec.hideTimer) && (this._hideTimer = setTimeout((() => { this._handleChartMouseOut(); }), this._spec.hideTimer))); const vchart = null === (_a = this._option) || void 0 === _a ? void 0 : _a.globalInstance; return success && VChart.globalConfig.uniqueTooltip && vchart && VChart.hideTooltip(vchart.id), success; }, this._getMouseEventData = params => { const result = { tooltipInfo: {}, ignore: {} }; return Object.keys(this.processor).forEach((activeType => { const {tooltipInfo: tooltipInfo, ignore: ignore} = this.processor[activeType].getMouseEventData(params); result.tooltipInfo[activeType] = tooltipInfo, result.ignore[activeType] = ignore; })), result; }, this._hideTooltipByHandler = params => { var _a, _b, _c; if (!this._isTooltipShown && !(null === (_b = null === (_a = this.tooltipHandler) || void 0 === _a ? void 0 : _a.isTooltipShown) || void 0 === _b ? void 0 : _b.call(_a))) return 0; this.event.emit(ChartEvent.tooltipHide, Object.assign(Object.assign({}, params), { source: Event_Source_Type.chart, tooltip: this })), Object.values(this.processor).forEach((processor => { processor.clearCache(); })); const handler = null !== (_c = this._spec.handler) && void 0 !== _c ? _c : this.tooltipHandler; if (handler.hideTooltip) { const result = handler.hideTooltip.call(handler, params); return result || (this._isTooltipShown = !1), result; } return 1; }, this.hideTooltip = () => { if (this._isReleased) return !1; const params = { changePositionOnly: !1, tooltip: this, item: void 0, datum: void 0, source: Event_Source_Type.chart }; return this._alwaysShow = !1, !this._hideTooltipByHandler(params); }; } isTooltipShown() { return this._isTooltipShown; } _registerEvent() {} _releaseEvent() {} onLayoutEnd() {} created() { super.created(), this._regions = this._option.getAllRegions(), this._initEvent(); } release() { var _a, _b; super.release(), this._isReleased = !0, this._hideTimer && clearTimeout(this._hideTimer), this._eventList.forEach((({eventType: eventType, handler: handler}) => { this.event.off(eventType, handler); })), this._eventList = [], null === (_b = null === (_a = this.tooltipHandler) || void 0 === _a ? void 0 : _a.release) || void 0 === _b || _b.call(_a), this._isTooltipShown = !1; } beforeRelease() { this.event.emit(ChartEvent.tooltipHide, { tooltip: this, chart: this.getChart() }), this.event.emit(ChartEvent.tooltipRelease, { tooltip: this, chart: this.getChart() }); } _initHandler() { var _a, _b, _c; const renderMode = null !== (_a = this._spec.renderMode) && void 0 !== _a ? _a : "html", userTooltipHandler = this._option.globalInstance.getTooltipHandlerByUser(); if (userTooltipHandler) this.tooltipHandler = userTooltipHandler, this._enterable = !1; else { const type = "canvas" === renderMode ? TooltipHandlerType.canvas : TooltipHandlerType.dom, handlerConstructor = Factory.getComponentPluginInType(type); handlerConstructor || error("Can not find tooltip handler: " + type); const handler = new handlerConstructor; handler.name = `${this._spec.className}-${null !== (_b = this._option.globalInstance.id) && void 0 !== _b ? _b : 0}-${this.getSpecIndex()}`, null === (_c = this.pluginService) || void 0 === _c || _c.load([ handler ]), this.tooltipHandler = handler, this._spec.enterable && "html" === renderMode && this.tooltipHandler ? (this._enterable = !0, this._needInitEventOfTooltip = !0) : this._enterable = !1; } } _initEventOfTooltipContent() { var _a, _b; if (!this._needInitEventOfTooltip) return; const container = null === (_b = (_a = this.tooltipHandler).getRootDom) || void 0 === _b ? void 0 : _b.call(_a); container && (container.addEventListener("pointerenter", (() => { var _a; if (!this._enterable) return; this._isEnterTooltip = !0; const rect = null === (_a = container.getBoundingClientRect) || void 0 === _a ? void 0 : _a.call(container); rect && (this._cacheEnterableRect = { width: rect.width, height: rect.height }), this._outTimer && (clearTimeout(this._outTimer), this._outTimer = null), this._showTimer && (clearTimeout(this._showTimer), this._showTimer = null); })), container.addEventListener("pointerleave", (() => { var _a, _b, _c; if (this._enterable && (this._isEnterTooltip = !1, "none" !== this._spec.triggerOff && this._cacheEnterableRect)) { const newRect = null === (_a = container.getBoundingClientRect) || void 0 === _a ? void 0 : _a.call(container); newRect && Object.keys(this._cacheEnterableRect).every((k => this._cacheEnterableRect[k] === newRect[k])) && (this._cacheEnterableRect = null, this._outTimer = setTimeout(this.hideTooltip, null !== (_c = null === (_b = this._spec) || void 0 === _b ? void 0 : _b.showDelay) && void 0 !== _c ? _c : DEFAULT_SHOW_DELAY)); } })), this._needInitEventOfTooltip = !1); } _initProcessor() { const activeType = this._spec.activeType; this.processor = {}, activeType.forEach((type => { const instance = Factory.createTooltipProcessor(type, this); instance && (this.processor[type] = instance); })); } _initEvent() { var _a; if (this._option.disableTriggerEvent) return; const trigger = array(null !== (_a = this._spec.trigger) && void 0 !== _a ? _a : "hover"), triggerOff = array(this._spec.triggerOff), mode = this._option.mode; trigger.forEach((triggerType => { var _a; "hover" === triggerType ? (this._handleMouseMove = this._throttle(this._getMouseMoveHandler(!1)), this._mountEvent("pointermove", { source: "chart" }, this._handleMouseMove), (isMobileLikeMode(mode) || isMiniAppLikeMode(mode)) && (this._mountEvent("pointerdown", { source: "chart" }, this._getMouseMoveHandler(!1)), this._mountEvent("pointerup", { source: "window" }, this._getMouseOutHandler(!0))), this._mountEvent("pointerleave", { source: "chart" }, this._getMouseOutHandler(!1))) : "click" === triggerType ? (this._mountEvent("pointertap", { source: "chart" }, this._getMouseMoveHandler(!0)), this._mountEvent("pointerup", { source: "window" }, this._getMouseOutHandler(!0))) : isObject(triggerType) && this._mountEvent(triggerType.eventType, { source: null !== (_a = triggerType.source) && void 0 !== _a ? _a : "chart", consume: triggerType.consume }, this._getMouseMoveHandler(!0)); })); triggerOff.filter((entry => isObject(entry))).forEach((entry => { var _a, _b; this._mountEvent(entry.eventType, { source: null !== (_a = entry.source) && void 0 !== _a ? _a : "chart", consume: entry.consume }, this._getMouseOutHandler(null !== (_b = entry.checkOutside) && void 0 !== _b && _b)); })), !trigger.includes("click") && this._spec.lockAfterClick && this._mountEvent("pointertap", { source: "chart" }, this._handleClickToLock); } _throttle(callback) { let wait; return wait = isNumber(this._spec.throttleInterval) ? this._spec.throttleInterval : "html" === this._spec.renderMode && this._spec.transitionDuration ? 50 : 10, throttle(callback, wait); } reInit(spec) { var _a, _b, _c; if (super.reInit(spec), this.tooltipHandler) { const renderMode = null !== (_a = this._spec.renderMode) && void 0 !== _a ? _a : "html", newEnterable = this._spec.enterable && "html" === renderMode; newEnterable && !this._enterable && (this._needInitEventOfTooltip = !0), this._enterable = newEnterable, null === (_c = (_b = this.tooltipHandler).reInit) || void 0 === _c || _c.call(_b); } else this._initHandler(); } showTooltip(datum, options) { var _a; if (this.tooltipHandler || this._initHandler(), this.processor || this._initProcessor(), !(null === (_a = this.tooltipHandler) || void 0 === _a ? void 0 : _a.showTooltip)) return !1; const result = showTooltip(datum, options, this); return "none" !== result && (this._alwaysShow = !!(null == options ? void 0 : options.alwaysShow)), result; } _isSameAsCache(nextInfo, nextParams, nextActiveType) { if (nextActiveType !== this._cacheActiveType) return !1; if (nextInfo === this._cacheInfo) return !0; if (isNil(this._cacheInfo) || isNil(nextInfo)) return !1; if (isDimensionInfo(nextInfo)) { if (isMarkInfo(this._cacheInfo)) return !1; const prevInfo = this._cacheInfo; return prevInfo.length === nextInfo.length && nextInfo.every(((info, i) => isSameDimensionInfo(info, prevInfo[i]))); } if (isDimensionInfo(this._cacheInfo)) return !1; const prevInfo = this._cacheInfo; if (!((null == nextInfo ? void 0 : nextInfo.datum) === prevInfo.datum && (null == nextInfo ? void 0 : nextInfo.mark) === prevInfo.mark && (null == nextInfo ? void 0 : nextInfo.series) === prevInfo.series)) return !1; const prevParams = this._cacheParams; return !isNil(prevParams) && !isNil(nextParams) && (prevParams.mark === nextParams.mark && prevParams.model === nextParams.model && prevParams.datum === nextParams.datum); } _isPointerInChart(point) { var _a; const globalInstance = null === (_a = this._option) || void 0 === _a ? void 0 : _a.globalInstance; if (!globalInstance) return !1; if (!globalInstance.getChart()) return !1; const {x: x, y: y} = point, canvas = globalInstance.getCanvas(), {x: chartX, y: chartY, width: chartWidth, height: chartHeight} = canvas.getBoundingClientRect(); return x >= chartX && x <= chartX + chartWidth && y >= chartY && y <= chartY + chartHeight; } getVisible() { return !1 !== this._spec.visible; } } Tooltip.type = ComponentTypeEnum.tooltip, Tooltip.transformerConstructor = TooltipSpecTransformer, Tooltip.builtInTheme = { tooltip: tooltip }, Tooltip.specKey = "tooltip"; export const registerTooltip = () => { Factory.registerComponent(Tooltip.type, Tooltip); }; //# sourceMappingURL=tooltip.js.map