UNPKG

@gravity-ui/graph

Version:

Modern graph editor component

104 lines (103 loc) 3.09 kB
import debounce from "lodash/debounce"; import RBush from "rbush"; import { Emitter } from "../utils/Emitter"; export class HitTest extends Emitter { constructor() { super(...arguments); this.tree = new RBush(16); this.empty = true; this.scheduledItems = new Set(); this.scheduleLoad = debounce(() => { this.tree.load(Array.from(this.scheduledItems)); this.scheduledItems.clear(); this.emitUpdate(); }, 50); this.emitUpdate = debounce(() => { this.emit("update", this); }, 50); } load(items) { this.tree.load(items); } clear() { this.scheduledItems.clear(); this.tree.clear(); } add(item, force = false) { this.scheduledItems.add(item); this.scheduleLoad(); if (force) { this.scheduleLoad.flush(); } } remove(item, silent = false) { this.scheduledItems.delete(item); this.tree.remove(item); if (!silent) { this.emitUpdate(); } } testPoint(point, pixelRatio) { return this.testHitBox({ minX: point.x - 1, minY: point.y - 1, maxX: point.x + 1, maxY: point.y + 1, x: point.origPoint?.x * pixelRatio, y: point.origPoint?.y * pixelRatio, }); } testBox(item) { return this.tree.search(item).map((hitBox) => hitBox.item); } testHitBox(item) { const hitBoxes = this.tree.search(item); const result = []; for (let i = 0; i < hitBoxes.length; i++) { if (hitBoxes[i].item.onHitBox(item)) { result.push(hitBoxes[i].item); } } const res = result.sort((a, b) => { const aZIndex = typeof a.zIndex === "number" ? a.zIndex : -1; const bZIndex = typeof b.zIndex === "number" ? b.zIndex : -1; if (aZIndex !== bZIndex) { return bZIndex - aZIndex; } return 0; }); return res; } } export class HitBox { constructor(item, hitTest) { this.item = item; this.hitTest = hitTest; this.destroyed = false; this.update = (minX, minY, maxX, maxY, force) => { if (this.destroyed) return; if (minX === this.minX && minY === this.minY && maxX === this.maxX && maxY === this.maxY && !force) return; if (this.minX !== undefined) { this.hitTest.remove(this, true); } this.minX = minX; this.minY = minY; this.maxX = maxX; this.maxY = maxY; this.rect = [this.minX, this.minY, this.maxX - this.minX, this.maxY - this.minY]; this.hitTest.add(this, Boolean(force)); }; } getRect() { return this.rect; } remove() { this.hitTest.remove(this); } destroy() { this.destroyed = true; this.hitTest.remove(this); } }