UNPKG

@gravity-ui/graph

Version:

Modern graph editor component

110 lines (109 loc) 4.2 kB
import { ESchedulerPriority } from "../../../lib"; import { ECameraScaleLevel } from "../../../services/camera/CameraService"; import { selectBlockAnchor } from "../../../store/block/selectors"; import { debounce, isMetaKeyEvent } from "../../../utils/functions"; import { GraphComponent } from "../GraphComponent"; export class Anchor extends GraphComponent { get zIndex() { // @ts-ignore this.__comp.parent instanceOf Block return this.__comp.parent.zIndex + 1; } constructor(props, parent) { super(props, parent); this.cursor = "pointer"; this.debouncedSetHitBox = debounce(() => { const { x, y } = this.props.getPosition(this.props); this.setHitBox(x - this.shift, y - this.shift, x + this.shift, y + this.shift); }, { priority: ESchedulerPriority.HIGHEST, frameInterval: 4, }); this.state = { size: props.size, raised: false, selected: false }; this.connectedState = selectBlockAnchor(this.context.graph, props.blockId, props.id); this.subscribeSignal(this.connectedState.$selected, (selected) => { this.setState({ selected }); }); this.addEventListener("click", this); this.addEventListener("mouseenter", this); this.addEventListener("mousedown", this); this.addEventListener("mouseleave", this); this.computeRenderSize(this.props.size, this.state.raised); this.shift = this.props.size / 2 + props.lineWidth; } getPosition() { return this.props.getPosition(this.props); } toggleSelected() { this.connectedState.setSelection(!this.state.selected); } isVisible() { const params = this.getHitBox(); return params ? this.context.camera.isRectVisible(...params) : true; } unmount() { super.unmount(); this.debouncedSetHitBox.cancel(); } didIterate() { const { x: poxX, y: posY } = this.props.getPosition(this.props); const hash = `${poxX}/${posY}/${this.shift}`; if (this.hitBoxHash !== hash) { this.hitBoxHash = hash; this.debouncedSetHitBox(); } } handleEvent(event) { event.preventDefault(); event.stopPropagation(); switch (event.type) { case "click": { const { blocksList, connectionsList } = this.context.graph.rootStore; const isAnyBlockSelected = blocksList.$selectedBlocks.value.length !== 0; const isAnyConnectionSelected = connectionsList.$selectedConnections.value.size !== 0; if (!isMetaKeyEvent(event) && isAnyBlockSelected) { blocksList.resetSelection(); } if (!isMetaKeyEvent(event) && isAnyConnectionSelected) { connectionsList.resetSelection(); } this.toggleSelected(); break; } case "mouseenter": { this.setState({ raised: true }); this.computeRenderSize(this.props.size, true); break; } case "mouseleave": { this.setState({ raised: false }); this.computeRenderSize(this.props.size, false); break; } } } computeRenderSize(size, raised) { if (raised) { this.setState({ size: size * 1.8 }); } else { this.setState({ size }); } } render() { if (this.context.camera.getCameraBlockScaleLevel() === ECameraScaleLevel.Detailed) { return; } const { x, y } = this.props.getPosition(this.props); const ctx = this.context.ctx; ctx.fillStyle = this.context.colors.anchor.background; ctx.beginPath(); ctx.arc(x, y, this.state.size * 0.5, 0, 2 * Math.PI); ctx.fill(); if (this.state.selected) { ctx.strokeStyle = this.context.colors.anchor.selectedBorder; ctx.lineWidth = this.props.lineWidth + 3; ctx.stroke(); } ctx.closePath(); } }