@visactor/vchart
Version:
charts lib based @visactor/VGrammar
371 lines (365 loc) • 19.1 kB
JavaScript
"use strict";
var __rest = this && this.__rest || function(s, e) {
var t = {};
for (var p in s) Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0 && (t[p] = s[p]);
if (null != s && "function" == typeof Object.getOwnPropertySymbols) {
var i = 0;
for (p = Object.getOwnPropertySymbols(s); i < p.length; i++) e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]) && (t[p[i]] = s[p[i]]);
}
return t;
};
Object.defineProperty(exports, "__esModule", {
value: !0
}), exports.BaseCrossHair = void 0;
const vrender_components_1 = require("@visactor/vrender-components"), vutils_1 = require("@visactor/vutils"), common_1 = require("../../typings/spec/common"), base_component_1 = require("../base/base-component"), math_1 = require("../../util/math"), event_1 = require("../../constant/event"), layout_1 = require("../../constant/layout"), config_1 = require("./config"), common_2 = require("./utils/common"), vscale_1 = require("@visactor/vscale"), ORIENT_MAP = {
x: [ "top", "bottom" ],
y: [ "left", "right" ],
category: [ "angle" ],
value: [ "radius" ]
};
class BaseCrossHair extends base_component_1.BaseComponent {
get enableRemain() {
return "none" === this.triggerOff;
}
constructor(spec, options) {
super(spec, options), this.specKey = "crosshair", this.layoutType = "none", this.gridZIndex = layout_1.LayoutZIndex.CrossHair_Grid,
this.labelZIndex = layout_1.LayoutZIndex.CrossHair, this.trigger = "hover", this._handleIn = params => {
if (!this._option) return;
const {x: x, y: y} = this.calculateTriggerPoint(params);
this.showDefault = !1, this._layoutCrosshair(x, y);
const components = this._getNeedClearVRenderComponents();
this._hasActive = components.some((comp => comp && !1 !== comp.attribute.visible));
}, this._handleClickInEvent = params => {
if (!this._hasActive || !this._spec.lockAfterClick || this._clickLock) return this._clickLock ? (this._clickLock = !1,
void this._handleOutEvent()) : void (this._onlyLockClick || (this._handleIn(params),
(0, vutils_1.isNumber)(this.triggerOff) && (this._timer && clearTimeout(this._timer),
this._timer = setTimeout((() => {
this._handleOutEvent();
}), this.triggerOff))));
this._clickLock = !0;
}, this._handleHoverInEvent = (0, vutils_1.throttle)((params => {
this._clickLock || this._handleIn(params);
}), 10), this._handleOutEvent = () => {
this.enableRemain || this._clickLock || !this._hasActive || (this.clearOutEvent(),
this.hide());
}, this._handleTooltipShow = params => {
const tooltipData = params.tooltipData;
if (params.isEmptyTooltip || !tooltipData || !tooltipData.length) return void this._handleTooltipHideOrRelease();
if ((0, vutils_1.isObject)(this._spec.followTooltip) && !1 === this._spec.followTooltip[params.activeType]) return void this._handleTooltipHideOrRelease();
const {x: x, y: y} = this.calculateTriggerPoint(params);
this.showDefault = !1, this._layoutCrosshair(x, y, tooltipData, params.activeType);
const components = this._getNeedClearVRenderComponents();
this._hasActive = components.some((comp => comp && !1 !== comp.attribute.visible));
}, this._handleTooltipHideOrRelease = () => {
this.clearOutEvent(), this.hide();
}, this.enable = !0, this.showDefault = !0;
}
_setAllAxisValues(axisMap, point, field) {
let discrete = !1;
if (axisMap.forEach((item => {
(0, vscale_1.isDiscrete)(item.axis.getScale().type) && (discrete ? this.enable = !1 : discrete = !0);
})), !this.enable) return !1;
const {currentValue: currentValue} = this._stateByField[field];
return axisMap.forEach(((item, id) => {
const axis = item.axis;
currentValue.set(id, {
datum: this._getDatumAtPoint(axis, point),
axis: axis
});
})), !0;
}
clearAxisValue() {
Object.keys(this._stateByField).forEach((field => {
this._stateByField[field].currentValue.clear();
}));
}
hideCrosshair() {
this.clearAxisValue(), this.hide();
}
showCrosshair(dimInfo) {
dimInfo && dimInfo.length && (this.showDefault = !1, this.clearAxisValue(), dimInfo.forEach((d => {
const {axis: axis, value: value} = d;
this.setAxisValue(value, axis);
})), this.layoutByValue(!1));
}
_getLimitBounds() {
var _a, _b;
if (!this._limitBounds) {
const {width: width, height: height} = null !== (_b = null === (_a = this._option.globalInstance.getChart()) || void 0 === _a ? void 0 : _a.getViewRect()) && void 0 !== _b ? _b : {
width: 0,
height: 0
};
this._limitBounds = {
x1: 0,
y1: 0,
x2: width,
y2: height
};
}
return this._limitBounds;
}
_showDefaultCrosshairBySpec() {
Object.keys(this._stateByField).forEach((field => {
const fieldSpec = this._spec[field];
if (fieldSpec && fieldSpec.visible && fieldSpec.defaultSelect) {
const {axisIndex: axisIndex = 0, datum: datum} = fieldSpec.defaultSelect, axis = this._option.getComponentsByKey("axes").find((c => c.getSpecIndex() === axisIndex));
axis && (this._stateByField[field].currentValue.clear(), this._stateByField[field].currentValue.set(axisIndex, {
axis: axis,
datum: datum
}));
}
}));
}
_updateVisibleCrosshair() {
let hasVisible = !1;
Object.keys(this._stateByField).forEach((field => {
const fieldSpec = this._spec[field];
fieldSpec && fieldSpec.visible && this._stateByField[field].currentValue.size ? hasVisible = !0 : this._hideByField(field);
})), hasVisible && this.layoutByValue(!1);
}
_showDefaultCrosshair() {
this.showDefault ? (this._showDefaultCrosshairBySpec(), this.layoutByValue(!1)) : this._updateVisibleCrosshair();
}
setAttrFromSpec() {
super.setAttrFromSpec(), this._parseCrosshairSpec();
}
created() {
super.created(), this._initEvent();
}
_compareSpec(spec, prevSpec) {
const result = super._compareSpec(spec, prevSpec);
return result.reMake || (0, vutils_1.isEqual)(prevSpec, spec) || (result.reRender = !0,
result.reMake = !0), result;
}
_initEvent() {
if (!this._option.disableTriggerEvent) if (this._spec.followTooltip) this._registerTooltipEvent(); else {
const triggerConfig = this._getTriggerEvent();
triggerConfig && triggerConfig.forEach((cfg => {
this._registerEvent(cfg.in, !1, cfg.click), cfg.out && this._registerEvent(cfg.out, !0);
}));
}
}
_registerEvent(eventName, isOut, click) {
const handler = isOut ? this._handleOutEvent : click ? this._handleClickInEvent : this._handleHoverInEvent, cfg = isOut ? {
level: event_1.Event_Bubble_Level.chart
} : {
source: event_1.Event_Source_Type.chart
};
(0, vutils_1.isArray)(eventName) ? eventName.forEach((evt => {
this.event.on(evt, cfg, handler);
})) : this.event.on(eventName, cfg, handler);
}
_eventOff(eventName, isOut, click) {
const handler = isOut ? this._handleOutEvent : click ? this._handleClickInEvent : this._handleHoverInEvent;
(0, vutils_1.isArray)(eventName) ? eventName.forEach((evt => {
this.event.off(evt, handler);
})) : this.event.off(eventName, handler);
}
updateLayoutAttribute() {
this._limitBounds = null, this._showDefaultCrosshair();
}
calculateTriggerPoint(params) {
const {event: event} = params, layer = this._option.getCompiler().getStage().getLayer(void 0), point = {
x: event.viewX,
y: event.viewY
};
return layer.globalTransMatrix.transformPoint({
x: event.viewX,
y: event.viewY
}, point), {
x: point.x - this.getLayoutStartPoint().x,
y: point.y - this.getLayoutStartPoint().y
};
}
_getTriggerEvent() {
const {mode: mode = common_1.RenderModeEnum["desktop-browser"]} = this._option, triggerConfig = (0,
config_1.getDefaultCrosshairTriggerEventByMode)(mode);
if (triggerConfig) {
const trigger = (0, vutils_1.array)(this.trigger || "hover"), outTrigger = inTrigger => "click" === inTrigger ? "none" === this.triggerOff ? null : triggerConfig.clickOut : triggerConfig.hoverOut;
this._spec.lockAfterClick && !trigger.includes("click") ? (trigger.push("click"),
this._onlyLockClick = !0) : this._onlyLockClick = !1;
const res = [];
return trigger.forEach((item => {
res.push({
click: "click" === item,
in: triggerConfig[item],
out: outTrigger(item)
});
})), res;
}
return null;
}
_registerTooltipEvent() {
this.event.on(event_1.ChartEvent.tooltipHide, {
source: event_1.Event_Source_Type.chart
}, this._handleTooltipHideOrRelease), this.event.on(event_1.ChartEvent.tooltipShow, {
source: event_1.Event_Source_Type.chart
}, this._handleTooltipShow), this.event.on(event_1.ChartEvent.tooltipRelease, {
source: event_1.Event_Source_Type.chart
}, this._handleTooltipHideOrRelease);
}
_getAxisInfoByField(field) {
var _a, _b;
const axesComponents = null === (_b = (_a = this._option).getComponentsByKey) || void 0 === _b ? void 0 : _b.call(_a, "axes");
if (!(null == axesComponents ? void 0 : axesComponents.length)) return null;
let bindingAxesIndex = (0, vutils_1.get)(this._spec, `${field}Field.bindingAxesIndex`);
if (bindingAxesIndex || (bindingAxesIndex = [], axesComponents.forEach(((item, index) => {
ORIENT_MAP[field].includes(item.getOrient()) && bindingAxesIndex.push(index);
}))), !bindingAxesIndex.length) return null;
const map = new Map;
let x1 = 1 / 0, y1 = 1 / 0, x2 = -1 / 0, y2 = -1 / 0;
const {x: sx, y: sy} = this.getLayoutStartPoint();
return bindingAxesIndex.forEach((idx => {
x1 = 1 / 0, y1 = 1 / 0, x2 = -1 / 0, y2 = -1 / 0;
const axis = axesComponents.find((axis => axis.getSpecIndex() === idx));
if (!axis) return;
axis.getRegions().forEach((r => {
const {x: regionStartX, y: regionStartY} = r.getLayoutStartPoint();
x1 = Math.min(x1, regionStartX - sx), y1 = Math.min(y1, regionStartY - sy), x2 = Math.max(x2, regionStartX + r.getLayoutRect().width - sx),
y2 = Math.max(y2, regionStartY + r.getLayoutRect().height - sy);
})), map.set(idx, {
x1: x1,
y1: y1,
x2: x2,
y2: y2,
axis: axis
});
})), map;
}
onLayoutEnd() {
const region = this._regions[0];
this.setLayoutRect(region.getLayoutRect()), this.setLayoutStartPosition(region.getLayoutStartPoint()),
super.onLayoutEnd();
}
_releaseEvent() {
this.clearOutEvent();
const triggerConfig = this._getTriggerEvent();
triggerConfig && triggerConfig.forEach((cfg => {
this._eventOff(cfg.in, !1, cfg.click), cfg.out && this._eventOff(cfg.out, !0);
}));
}
_parseFieldInfo() {
Object.keys(this._stateByField).forEach((field => {
const fieldSpec = this._spec[field], {crosshairComp: crosshairComp} = this._stateByField[field];
if (fieldSpec && fieldSpec.visible) {
if (this._stateByField[field].attributes = this._parseField(fieldSpec, field), crosshairComp) {
const {style: style, type: type} = this._stateByField[field].attributes, styleKey = "rect" === type ? "rectStyle" : "lineStyle";
crosshairComp.setAttributes({
[styleKey]: style
});
}
} else crosshairComp && crosshairComp.parent && crosshairComp.parent.removeChild(crosshairComp);
}));
}
_parseCrosshairSpec() {
this._parseFieldInfo();
const {trigger: trigger, triggerOff: triggerOff, labelZIndex: labelZIndex, gridZIndex: gridZIndex} = this._spec;
trigger && (this.trigger = trigger), ("none" === triggerOff || (0, vutils_1.isNumber)(triggerOff) && triggerOff > 0) && (this.triggerOff = triggerOff),
void 0 !== labelZIndex && (this.labelZIndex = labelZIndex), void 0 !== gridZIndex && (this.gridZIndex = gridZIndex);
}
_parseField(field, fieldName) {
var _a, _b, _c;
const hair = {}, {line: line = {}, label: label = {}, visible: visible} = field;
if (hair.visible = visible, hair.type = line.type || "line", !1 === line.visible) hair.style = {
visible: !1
}; else {
const style = line.style || {}, {stroke: stroke, fill: fill, lineWidth: lineWidth} = style, _d = style, {strokeOpacity: strokeOpacity, fillOpacity: fillOpacity, opacity: opacity} = _d, restStyle = __rest(_d, [ "strokeOpacity", "fillOpacity", "opacity" ]), isLineType = "line" === hair.type;
let finalOpacity = isLineType ? strokeOpacity : fillOpacity;
if ((0, vutils_1.isNumber)(opacity) && (finalOpacity = (null != finalOpacity ? finalOpacity : 1) * opacity),
hair.style = Object.assign({
opacity: finalOpacity,
pickable: !1,
visible: !0
}, restStyle), isLineType) hair.style.stroke = stroke || fill, hair.style.lineWidth = (0,
vutils_1.get)(line, "width", lineWidth || 2); else {
hair.style.fill = fill || stroke, (null === (_b = null === (_a = null == field ? void 0 : field.line) || void 0 === _a ? void 0 : _a.style) || void 0 === _b ? void 0 : _b.stroke) && (hair.style.stroke = field.line.style.stroke);
const rectSize = (0, vutils_1.get)(line, "width");
if ("string" == typeof rectSize) {
const percent = parseInt(rectSize.substring(0, rectSize.length - 1), 10) / 100;
hair.style.sizePercent = percent;
} else "number" != typeof rectSize && "function" != typeof rectSize || (hair.style.size = rectSize);
}
}
if (label.visible) {
const labelBackground = label.labelBackground || {}, syncAxisLabelAngle = null !== (_c = label.syncAxisLabelAngle) && void 0 !== _c && _c, labelStyle = label.style || {}, _e = labelBackground.style || {}, {fill: rectFill = "rgba(47, 59, 82, 0.9)", stroke: rectStroke, outerBorder: outerBorder} = _e, rectStyle = __rest(_e, [ "fill", "stroke", "outerBorder" ]);
hair.label = {
visible: !0,
formatMethod: label.formatMethod,
formatter: label.formatter,
minWidth: labelBackground.minWidth,
maxWidth: labelBackground.maxWidth,
padding: labelBackground.padding,
syncAxisLabelAngle: syncAxisLabelAngle,
textStyle: Object.assign(Object.assign({
fontSize: 14,
pickable: !1
}, labelStyle), {
fill: labelStyle.fill || "#fff",
stroke: (0, vutils_1.get)(labelStyle, "stroke")
}),
panel: ((0, vutils_1.isBoolean)(labelBackground.visible) ? labelBackground.visible : labelBackground) ? Object.assign({
visible: !0,
pickable: !1,
fill: rectFill,
stroke: rectStroke,
outerBorder: Object.assign({
stroke: rectFill,
distance: 0,
lineWidth: 3
}, outerBorder)
}, rectStyle) : {
visible: !1
},
zIndex: this.labelZIndex,
childrenPickable: !1,
pickable: !1
};
} else hair.label = {
visible: !1
};
return hair;
}
_filterAxisByPoint(axisMap, relativeX, relativeY) {
return axisMap && axisMap.forEach((item => {
const axis = item.axis;
if ((0, math_1.outOfBounds)(item, relativeX, relativeY) && axisMap.delete(axis.getSpecIndex()),
axis.type.startsWith("polarAxis")) {
const center = axis.getCenter(), innerRadius = axis.getInnerRadius(), outerRadius = axis.getOuterRadius(), distance = vutils_1.PointService.distancePP({
x: relativeX,
y: relativeY
}, center);
(distance > outerRadius || distance < innerRadius) && axisMap.delete(axis.getSpecIndex());
}
})), axisMap;
}
_updateCrosshairLabel(label, labelAttrs, callback) {
const container = this.getContainer();
label ? label.setAttributes(labelAttrs) : (label = new vrender_components_1.Tag(labelAttrs),
null == container || container.add(label), callback(label)), (0, common_2.limitTagInBounds)(label, this._getLimitBounds());
}
clearOutEvent() {
this._timer && (clearTimeout(this._timer), this._timer = null), this._clickLock && (this._clickLock = null),
this._hasActive && (this._hasActive = null);
}
_hideByField(field) {
const {crosshairComp: crosshairComp, labelsComp: labelsComp} = this._stateByField[field];
crosshairComp && crosshairComp.hideAll(), labelsComp && Object.keys(labelsComp).forEach((key => {
labelsComp[key] && labelsComp[key].hideAll();
}));
}
hide() {
Object.keys(this._stateByField).forEach((field => {
this._hideByField(field);
}));
}
_getNeedClearVRenderComponents() {
return Object.keys(this._stateByField).reduce(((res, field) => {
const {crosshairComp: crosshairComp, labelsComp: labelsComp} = this._stateByField[field];
return crosshairComp && res.push(crosshairComp), labelsComp && Object.keys(labelsComp).forEach((key => {
labelsComp[key] && res.push(labelsComp[key]);
})), res;
}), []);
}
}
exports.BaseCrossHair = BaseCrossHair, BaseCrossHair.specKey = "crosshair";
//# sourceMappingURL=base.js.map