|
| 1 | +import { useLayoutEffect } from "react"; |
| 2 | +import { ElementType } from "@/components/workspace/elements"; |
| 3 | +import { dataAttributes, ids, selectors } from "@/constants"; |
| 4 | +import { default as store } from "@/store"; |
| 5 | +import { clearAndSelectElements } from "@/store/reducers/editor"; |
| 6 | +import { coordsWithTransform, d3Extended } from "@/utils"; |
| 7 | + |
| 8 | +const useSelection = () => { |
| 9 | + useLayoutEffect(() => { |
| 10 | + const svg = d3Extended.selectById(ids.workspace); |
| 11 | + if (svg.node()) { |
| 12 | + const toolbarWidth = document.getElementById(ids.toolbar)?.clientWidth ?? 0; |
| 13 | + const operationBarHeight = document.getElementById(ids.operationBar)?.clientHeight ?? 0; |
| 14 | + const selectionRect = { |
| 15 | + element: null, |
| 16 | + currentY: 0, |
| 17 | + currentX: 0, |
| 18 | + originX: 0, |
| 19 | + originY: 0, |
| 20 | + setElement: function (ele) { |
| 21 | + this.element = ele; |
| 22 | + }, |
| 23 | + getNewAttributes: function () { |
| 24 | + const x = this.currentX < this.originX ? this.currentX : this.originX; |
| 25 | + const y = this.currentY < this.originY ? this.currentY : this.originY; |
| 26 | + const width = Math.abs(this.currentX - this.originX); |
| 27 | + const height = Math.abs(this.currentY - this.originY); |
| 28 | + return { |
| 29 | + x: x, |
| 30 | + y: y, |
| 31 | + width: width, |
| 32 | + height: height |
| 33 | + }; |
| 34 | + }, |
| 35 | + getCurrentAttributes: function () { |
| 36 | + const transform = d3Extended.zoomTransform(document.querySelector(selectors.workspaceGroup)); |
| 37 | + const { x, y } = coordsWithTransform({ x: +this.element.attr("x"), y: +this.element.attr("y") }, transform); |
| 38 | + return { |
| 39 | + x1: x, |
| 40 | + y1: y, |
| 41 | + x2: x + Number(this.element.attr("width")) / transform.k, |
| 42 | + y2: y + Number(this.element.attr("height")) / transform.k |
| 43 | + }; |
| 44 | + }, |
| 45 | + init: function (newX, newY) { |
| 46 | + const rectElement = svg |
| 47 | + .append("rect") |
| 48 | + .attr("id", ids.workspaceSelection) |
| 49 | + .attr("rx", 4) |
| 50 | + .attr("ry", 4) |
| 51 | + .attr("x", 0) |
| 52 | + .attr("y", 0) |
| 53 | + .attr("width", 0) |
| 54 | + .attr("height", 0) |
| 55 | + .classed("workspace-selection", true); |
| 56 | + this.setElement(rectElement); |
| 57 | + this.originX = newX; |
| 58 | + this.originY = newY; |
| 59 | + this.update(newX, newY); |
| 60 | + }, |
| 61 | + update: function (newX: number, newY: number) { |
| 62 | + this.currentX = newX - (+this.element?.attr("width") > 2 ? toolbarWidth : 0); |
| 63 | + this.currentY = newY - (+this.element?.attr("height") > 2 ? operationBarHeight : 0); |
| 64 | + const attributes = this.getNewAttributes(); |
| 65 | + Object.keys(attributes).forEach((key) => { |
| 66 | + this.element.attr(key, attributes[key]); |
| 67 | + }); |
| 68 | + }, |
| 69 | + remove: function () { |
| 70 | + this.element.remove(); |
| 71 | + this.element = null; |
| 72 | + } |
| 73 | + }; |
| 74 | + |
| 75 | + const dragStart = (e) => { |
| 76 | + const p = d3Extended.pointer(e); |
| 77 | + selectionRect.init(p[0], p[1]); |
| 78 | + }; |
| 79 | + |
| 80 | + const dragMove = (e) => { |
| 81 | + const p = d3Extended.pointer(e); |
| 82 | + selectionRect.update(p[0], p[1]); |
| 83 | + }; |
| 84 | + |
| 85 | + const dragEnd = () => { |
| 86 | + const finalAttributes = selectionRect.getCurrentAttributes(); |
| 87 | + selectionRect.remove(); |
| 88 | + const elements = d3Extended.selectAll(`[${dataAttributes.element}]`); |
| 89 | + const idsToSelect = []; |
| 90 | + |
| 91 | + elements.forEach((element) => { |
| 92 | + const isSeat = element.attr(dataAttributes.elementType) === ElementType.Seat; |
| 93 | + const x = isSeat ? +element.attr("cx") : +element.attr("x"); |
| 94 | + const y = isSeat ? +element.attr("cy") : +element.attr("y"); |
| 95 | + if ( |
| 96 | + x >= finalAttributes.x1 && |
| 97 | + x <= finalAttributes.x2 && |
| 98 | + y >= finalAttributes.y1 && |
| 99 | + y <= finalAttributes.y2 |
| 100 | + ) { |
| 101 | + const id = element.attr("id"); |
| 102 | + if (!id?.includes("-label")) idsToSelect.push(id); |
| 103 | + } |
| 104 | + }); |
| 105 | + store.dispatch(clearAndSelectElements(idsToSelect)); |
| 106 | + }; |
| 107 | + |
| 108 | + svg.call(d3Extended.drag().on("drag", dragMove).on("start", dragStart).on("end", dragEnd)); |
| 109 | + } |
| 110 | + }, []); |
| 111 | +}; |
| 112 | + |
| 113 | +export default useSelection; |
0 commit comments