UNPKG

@visactor/vgrammar-core

Version:

VGrammar is a visual grammar library

278 lines (252 loc) 15.2 kB
import { clampRadian, getAngleByPoint, isString, merge } from "@visactor/vutils"; import { CircleCrosshair, LineCrosshair, PolygonCrosshair, RectCrosshair, SectorCrosshair } from "@visactor/vrender-components"; import { BaseInteraction } from "./base"; import { CrosshairEnum } from "../graph/enums"; import { isContinuous, isDiscrete } from "@visactor/vscale"; import { invokeFunctionType } from "../parse/util"; const computeCrosshairStartEnd = (point, scale, type, groupSize, config, offset = 0) => { var _a, _b; const start = { x: 0, y: 0 }, end = { x: 0, y: 0 }, radius = "angle" === type ? null !== (_a = null == config ? void 0 : config.radius) && void 0 !== _a ? _a : Math.min(groupSize.width, groupSize.height) / 2 : null, center = "angle" === type ? null !== (_b = null == config ? void 0 : config.center) && void 0 !== _b ? _b : { x: groupSize.width / 2, y: groupSize.height / 2 } : null; let current = 0; if (isDiscrete(scale.type)) { if ("x" === type) current = scale.scale(scale.invert(point.x)); else if ("y" === type) current = scale.scale(scale.invert(point.y)); else if ("angle" === type) { const angle = clampRadian(getAngleByPoint(center, point) + 2 * Math.PI); current = scale.scale(scale.invert(angle)); } } else isContinuous(scale.type) && ("x" === type ? current = point.x : "y" === type ? current = point.y : "angle" === type && (current = getAngleByPoint(center, point))); switch (current += offset, type) { case "x": start.x = current, start.y = 0, end.x = current, end.y = groupSize.height; break; case "y": start.x = 0, start.y = current, end.x = groupSize.width, end.y = current; break; case "angle": start.x = center.x, start.y = center.y, end.x = center.x + radius * Math.cos(current), end.y = center.y + radius * Math.sin(current); } return { start: start, end: end }; }, computeRadiusOfTangential = (point, scale, type, groupSize, config, addition) => { var _a, _b, _c; const center = null !== (_b = null !== (_a = null == addition ? void 0 : addition.center) && void 0 !== _a ? _a : null == config ? void 0 : config.center) && void 0 !== _b ? _b : { x: groupSize.width / 2, y: groupSize.height / 2 }; let currentRadius = 0; if (isDiscrete(scale.type)) { const offset = "band" === scale.type ? scale.bandwidth() / 2 : 0, radius = Math.sqrt((point.x - center.x) ** 2 + (point.y - center.y) ** 2); currentRadius = scale.scale(scale.invert(radius)) + offset; } else if (isContinuous(scale.type)) { const maxRadius = null !== (_c = null == config ? void 0 : config.radius) && void 0 !== _c ? _c : Math.min(groupSize.width, groupSize.height) / 2; currentRadius = Math.min(maxRadius, Math.sqrt((point.x - center.x) ** 2 + (point.y - center.y) ** 2)); } return { radius: currentRadius, center: center }; }; export const generateLineCrosshairAttributes = (point, scale, type, groupSize, config, theme, addition) => { var _a, _b, _c; const crosshairTheme = null === (_a = null == theme ? void 0 : theme.components) || void 0 === _a ? void 0 : _a.lineCrosshair, offset = "band" === scale.type ? scale.bandwidth() / 2 : 0, points = computeCrosshairStartEnd(point, scale, type, groupSize, { radius: null !== (_b = null == addition ? void 0 : addition.radius) && void 0 !== _b ? _b : null == config ? void 0 : config.radius, center: null !== (_c = null == addition ? void 0 : addition.center) && void 0 !== _c ? _c : null == config ? void 0 : config.center }, offset); return merge({}, crosshairTheme, points, null != addition ? addition : {}); }; export const generateRectCrosshairAttributes = (point, scale, type, groupSize, config, theme, addition) => { var _a, _b, _c; const crosshairTheme = null === (_a = null == theme ? void 0 : theme.components) || void 0 === _a ? void 0 : _a.rectCrosshair, defaultSize = "band" === scale.type || "point" === scale.type ? scale.step() : void 0, customRectStyle = null == addition ? void 0 : addition.rectStyle, size = null != defaultSize ? defaultSize : "y" === type ? null !== (_b = null == customRectStyle ? void 0 : customRectStyle.width) && void 0 !== _b ? _b : crosshairTheme.rectStyle.width : null !== (_c = null == customRectStyle ? void 0 : customRectStyle.height) && void 0 !== _c ? _c : crosshairTheme.rectStyle.height, points = computeCrosshairStartEnd(point, scale, type, groupSize, config, "band" === scale.type ? 0 : -size / 2), rectStyle = {}; "x" === type ? rectStyle.width = size : rectStyle.height = size; const attribute = merge({}, crosshairTheme, { start: points.start, end: points.end, rectStyle: rectStyle }, null != addition ? addition : {}); return "x" === type ? attribute.rectStyle.height = attribute.end.y - attribute.start.y : attribute.rectStyle.width = attribute.end.x - attribute.start.x, attribute; }; export const generateRingCrosshairAttributes = (point, scale, type, groupSize, config, theme, addition) => { var _a; const crosshairTheme = null === (_a = null == theme ? void 0 : theme.components) || void 0 === _a ? void 0 : _a.circleCrosshair, {center: center, radius: radius} = computeRadiusOfTangential(point, scale, 0, groupSize, config, addition), startAngle = crosshairTheme.startAngle, endAngle = crosshairTheme.endAngle, deltaRadius = "band" === scale.type || "point" === scale.type ? scale.step() : 0; return merge({}, crosshairTheme, { center: center, innerRadius: radius - deltaRadius / 2, radius: radius + deltaRadius / 2, startAngle: startAngle, endAngle: endAngle }, null != addition ? addition : {}); }; export const generateSectorCrosshairAttributes = (point, scale, type, groupSize, config, theme, addition) => { var _a, _b, _c, _d, _e; const crosshairTheme = null === (_a = null == theme ? void 0 : theme.components) || void 0 === _a ? void 0 : _a.sectorCrosshair, radius = null !== (_c = null !== (_b = null == addition ? void 0 : addition.radius) && void 0 !== _b ? _b : null == config ? void 0 : config.radius) && void 0 !== _c ? _c : Math.min(groupSize.width, groupSize.height) / 2, center = null !== (_e = null !== (_d = null == addition ? void 0 : addition.center) && void 0 !== _d ? _d : null == config ? void 0 : config.center) && void 0 !== _e ? _e : { x: groupSize.width / 2, y: groupSize.height / 2 }, defaultAngle = crosshairTheme.endAngle - crosshairTheme.startAngle, angle = "band" === scale.type || "point" === scale.type ? scale.step() : defaultAngle; let currentAngle = 0; if (isDiscrete(scale.type)) { const angle = clampRadian(getAngleByPoint(center, point) + 2 * Math.PI); currentAngle = scale.scale(scale.invert(angle)) + ("band" === scale.type ? scale.bandwidth() / 2 : 0); } else isContinuous(scale.type) && (currentAngle = getAngleByPoint(center, point)); return merge({}, crosshairTheme, { center: center, radius: radius, startAngle: currentAngle - angle / 2, endAngle: currentAngle + angle / 2 }, null != addition ? addition : {}); }; export const generateCircleCrosshairAttributes = (point, scale, type, groupSize, config, theme, addition) => { var _a; const crosshairTheme = null === (_a = null == theme ? void 0 : theme.components) || void 0 === _a ? void 0 : _a.circleCrosshair, {center: center, radius: radius} = computeRadiusOfTangential(point, scale, 0, groupSize, config, addition), startAngle = crosshairTheme.startAngle, endAngle = crosshairTheme.endAngle; return merge({}, crosshairTheme, { center: center, radius: radius, startAngle: startAngle, endAngle: endAngle }, null != addition ? addition : {}); }; export const generatePolygonCrosshairAttributes = (point, scale, type, groupSize, config, theme, addition) => { var _a; const crosshairTheme = null === (_a = null == theme ? void 0 : theme.components) || void 0 === _a ? void 0 : _a.circleCrosshair, {center: center, radius: radius} = computeRadiusOfTangential(point, scale, 0, groupSize, config, addition), startAngle = crosshairTheme.startAngle, endAngle = crosshairTheme.endAngle; return merge({}, crosshairTheme, { center: center, radius: radius, startAngle: startAngle, endAngle: endAngle }, null != addition ? addition : {}); }; export class Crosshair extends BaseInteraction { constructor(view, options) { var _a, _b; super(view, options), this.type = Crosshair.type, this.handleCrosshairShow = event => { var _a; if (!this._crosshairComponent) return; const groupGraphicItem = this._container.getGroupGraphicItem(), point = { x: 0, y: 0 }, globalTransMatrix = groupGraphicItem.globalTransMatrix, containerPoint = { x: globalTransMatrix.e, y: globalTransMatrix.f }; if (globalTransMatrix.transformPoint(event.canvas, point), point.x < 0 || point.x > groupGraphicItem.attribute.width || point.y < 0 || point.y > groupGraphicItem.attribute.height) return void this._crosshairComponent.hideAll(); const crosshairType = null !== (_a = this.options.crosshairType) && void 0 !== _a ? _a : "x", groupSize = { width: groupGraphicItem.attribute.width, height: groupGraphicItem.attribute.height }, scale = (isString(this.options.scale) ? this.view.getScaleById(this.options.scale) : this.options.scale).getScale(), config = { center: this.options.center, radius: this.options.radius }, theme = this.view.getCurrentTheme(), addition = invokeFunctionType(this.options.attributes, this.parameters(), {}, {}); let attributes = {}; switch (this.getCrosshairComponentType()) { case CrosshairEnum.lineCrosshair: attributes = generateLineCrosshairAttributes(point, scale, crosshairType, groupSize, config, theme, addition); break; case CrosshairEnum.rectCrosshair: attributes = generateRectCrosshairAttributes(point, scale, crosshairType, groupSize, config, theme, addition); break; case CrosshairEnum.sectorCrosshair: attributes = generateSectorCrosshairAttributes(point, scale, 0, groupSize, config, theme, addition); break; case CrosshairEnum.circleCrosshair: attributes = generateCircleCrosshairAttributes(point, scale, 0, groupSize, config, theme, addition); break; case CrosshairEnum.polygonCrosshair: attributes = generatePolygonCrosshairAttributes(point, scale, 0, groupSize, config, theme, addition); break; case CrosshairEnum.ringCrosshair: attributes = generateRingCrosshairAttributes(point, scale, 0, groupSize, config, theme, addition); } this.getCrosshairComponentType() !== CrosshairEnum.circleCrosshair && (attributes.x = containerPoint.x, attributes.y = containerPoint.y), this._crosshairComponent.showAll(), this._crosshairComponent.setAttributes(attributes); }, this.handleCrosshairHide = () => { this._crosshairComponent && this._crosshairComponent.hideAll(); }, this.options = Object.assign({}, Crosshair.defaultOptions, options), this._container = null !== (_b = null === (_a = view.getMarksBySelector(this.options.container)) || void 0 === _a ? void 0 : _a[0]) && void 0 !== _b ? _b : view.rootMark; } getEvents() { return [ { type: this.options.trigger, handler: this.handleCrosshairShow }, { type: this.options.triggerOff, handler: this.handleCrosshairHide } ]; } getCrosshairComponentType() { var _a, _b; if (this._crosshairComponentType) return this._crosshairComponentType; const shape = null !== (_a = this.options.crosshairShape) && void 0 !== _a ? _a : "line", type = null !== (_b = this.options.crosshairType) && void 0 !== _b ? _b : "x"; return this._crosshairComponentType = "rect" === shape ? "angle" === type ? CrosshairEnum.sectorCrosshair : "radius" === type ? CrosshairEnum.ringCrosshair : "radius-polygon" === type ? CrosshairEnum.polygonCrosshair : CrosshairEnum.rectCrosshair : "radius" === type ? CrosshairEnum.circleCrosshair : "radius-polygon" === type ? CrosshairEnum.polygonCrosshair : CrosshairEnum.lineCrosshair, this._crosshairComponentType; } getDefaultCrosshairAttribute() { var _a; const type = null !== (_a = this.options.crosshairType) && void 0 !== _a ? _a : "x"; return "radius" === type || "radius-polygon" === type ? { center: { x: 0, y: 0 }, zIndex: -1 } : { start: { x: 0, y: 0 }, end: { x: 0, y: 0 }, zIndex: -1 }; } bind() { super.bind(); const stage = this.view.renderer.stage(); if (!this._crosshairComponent && stage) { switch (this.getCrosshairComponentType()) { case CrosshairEnum.lineCrosshair: this._crosshairComponent = new LineCrosshair(this.getDefaultCrosshairAttribute()); break; case CrosshairEnum.rectCrosshair: this._crosshairComponent = new RectCrosshair(this.getDefaultCrosshairAttribute()); break; case CrosshairEnum.sectorCrosshair: this._crosshairComponent = new SectorCrosshair(this.getDefaultCrosshairAttribute()); break; case CrosshairEnum.circleCrosshair: this._crosshairComponent = new CircleCrosshair(this.getDefaultCrosshairAttribute()); break; case CrosshairEnum.polygonCrosshair: this._crosshairComponent = new PolygonCrosshair(this.getDefaultCrosshairAttribute()); break; case CrosshairEnum.ringCrosshair: this._crosshairComponent = new SectorCrosshair(this.getDefaultCrosshairAttribute()); } stage.defaultLayer.appendChild(this._crosshairComponent); } } unbind() { super.unbind(); const stage = this.view.renderer.stage(); this._crosshairComponent && stage && (stage.defaultLayer.removeChild(this._crosshairComponent), this._crosshairComponent.release(), this._crosshairComponent = null); } } Crosshair.type = "crosshair", Crosshair.defaultOptions = { trigger: "pointermove", triggerOff: "pointerleave", crosshairType: "x", crosshairShape: "line" }; //# sourceMappingURL=crosshair.js.map