diff --git a/package.json b/package.json index f11d788..3ca6e7b 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "react-dom": "^17.0.2", "react-intersection-observer": "^8.32.0", "react-konva": "^17.0.2-5", + "react-konva-utils": "^0.1.7", "react-markdown": "4", "react-media": "^2.0.0-rc.1", "react-modal": "^3.12.1", diff --git a/src/components/konva/Transformer.tsx b/src/components/konva/Transformer.tsx index 695257b..76ab5ac 100644 --- a/src/components/konva/Transformer.tsx +++ b/src/components/konva/Transformer.tsx @@ -2,6 +2,7 @@ import Konva from "konva"; import { Transform } from "konva/lib/Util"; import { useEffect, useMemo, useRef, useState } from "react"; import { Transformer as KonvaTransformer } from "react-konva"; +import { Portal } from "react-konva-utils"; import { useGridCellPixelSize, @@ -200,80 +201,85 @@ function Transformer({ } return ( - { - let snapBox = { ...newBox }; - const movingAnchor = movingAnchorRef.current; - if (movingAnchor === "middle-left" || movingAnchor === "middle-right") { - // Account for grid snapping - const nearestCellWidth = roundTo( - snapBox.width, - gridCellAbsoluteSize.x - ); - const distanceToSnap = Math.abs(snapBox.width - nearestCellWidth); - let snapping = false; + + { + let snapBox = { ...newBox }; + const movingAnchor = movingAnchorRef.current; if ( - distanceToSnap < - gridCellAbsoluteSize.x * gridSnappingSensitivity + movingAnchor === "middle-left" || + movingAnchor === "middle-right" ) { - snapBox.width = nearestCellWidth; - snapping = true; + // Account for grid snapping + const nearestCellWidth = roundTo( + snapBox.width, + gridCellAbsoluteSize.x + ); + const distanceToSnap = Math.abs(snapBox.width - nearestCellWidth); + let snapping = false; + if ( + distanceToSnap < + gridCellAbsoluteSize.x * gridSnappingSensitivity + ) { + snapBox.width = nearestCellWidth; + snapping = true; + } + + const deltaWidth = snapBox.width - oldBox.width; + // Account for node ratio + const inverseRatio = + Math.round(oldBox.height) / Math.round(oldBox.width); + const deltaHeight = inverseRatio * deltaWidth; + + // Account for node rotation + // Create a transform to unrotate the x,y position of the Box + const rotator = new Transform(); + rotator.rotate(-snapBox.rotation); + + // Unrotate and add the resize amount + let rotatedMin = rotator.point({ x: snapBox.x, y: snapBox.y }); + rotatedMin.y = rotatedMin.y - deltaHeight / 2; + // Snap x position if needed + if (snapping) { + const snapDelta = newBox.width - nearestCellWidth; + rotatedMin.x = rotatedMin.x + snapDelta / 2; + } + + // Rotated back + rotator.invert(); + rotatedMin = rotator.point(rotatedMin); + + snapBox = { + ...snapBox, + height: snapBox.height + deltaHeight, + x: rotatedMin.x, + y: rotatedMin.y, + }; } - const deltaWidth = snapBox.width - oldBox.width; - // Account for node ratio - const inverseRatio = - Math.round(oldBox.height) / Math.round(oldBox.width); - const deltaHeight = inverseRatio * deltaWidth; - - // Account for node rotation - // Create a transform to unrotate the x,y position of the Box - const rotator = new Transform(); - rotator.rotate(-snapBox.rotation); - - // Unrotate and add the resize amount - let rotatedMin = rotator.point({ x: snapBox.x, y: snapBox.y }); - rotatedMin.y = rotatedMin.y - deltaHeight / 2; - // Snap x position if needed - if (snapping) { - const snapDelta = newBox.width - nearestCellWidth; - rotatedMin.x = rotatedMin.x + snapDelta / 2; + if (snapBox.width < 5 || snapBox.height < 5) { + return oldBox; } - - // Rotated back - rotator.invert(); - rotatedMin = rotator.point(rotatedMin); - - snapBox = { - ...snapBox, - height: snapBox.height + deltaHeight, - x: rotatedMin.x, - y: rotatedMin.y, - }; - } - - if (snapBox.width < 5 || snapBox.height < 5) { - return oldBox; - } - return snapBox; - }} - onTransformStart={handleTransformStart} - onTransform={handleTrasform} - onTransformEnd={handleTransformEnd} - centeredScaling={true} - rotationSnaps={[...Array(24).keys()].map((n) => n * 15)} - rotateAnchorOffset={16} - enabledAnchors={["middle-left", "middle-right"]} - flipEnabled={false} - ignoreStroke={true} - borderStroke="invisible" - anchorStroke="invisible" - anchorCornerRadius={24} - borderStrokeWidth={0} - anchorSize={48} - useSingleNodeRotation={true} - /> + return snapBox; + }} + onTransformStart={handleTransformStart} + onTransform={handleTrasform} + onTransformEnd={handleTransformEnd} + centeredScaling={true} + rotationSnaps={[...Array(24).keys()].map((n) => n * 15)} + rotateAnchorOffset={16} + enabledAnchors={["middle-left", "middle-right"]} + flipEnabled={false} + ignoreStroke={true} + borderStroke="invisible" + anchorStroke="invisible" + anchorCornerRadius={24} + borderStrokeWidth={0} + anchorSize={48} + useSingleNodeRotation={true} + /> + ); } diff --git a/src/components/map/MapInteraction.tsx b/src/components/map/MapInteraction.tsx index 8d42e0c..031a761 100644 --- a/src/components/map/MapInteraction.tsx +++ b/src/components/map/MapInteraction.tsx @@ -1,7 +1,7 @@ import React, { useRef, useEffect, useState } from "react"; import { Box } from "theme-ui"; import ReactResizeDetector from "react-resize-detector"; -import { Stage, Layer, Image } from "react-konva"; +import { Stage, Layer, Image, Group } from "react-konva"; import Konva from "konva"; import { EventEmitter } from "events"; @@ -215,8 +215,8 @@ function MapInteraction({ id="mapImage" ref={mapImageRef} /> - {mapLoaded && children} + diff --git a/yarn.lock b/yarn.lock index f686e89..15214bc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11254,7 +11254,15 @@ react-is@^17.0.1: resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.1.tgz#5b3531bd76a645a4c9fb6e693ed36419e3301339" integrity sha512-NAnt2iGDXohE5LI7uBnLnqvLQMtzhkiAOLXTmv+qnF9Ky7xAPcX8Up/xWIhxvLVGJvuLiNc4xQLtuqDRzb4fSA== -react-konva@^17.0.2-5: +react-konva-utils@^0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/react-konva-utils/-/react-konva-utils-0.1.7.tgz#f3feb6c0dd5a930020fd10a0f57d5c7a904166c8" + integrity sha512-wjNq4TsPXaig2Zufg6nBeFQpijR3FJ4iL2YrmtlwQN7Ase158eWHrpHKNySdMo2E4OSls8220sIaTY5TlrzqyA== + dependencies: + react-konva "^17.0.2-4" + use-image "^1.0.7" + +react-konva@^17.0.2-4, react-konva@^17.0.2-5: version "17.0.2-5" resolved "https://registry.yarnpkg.com/react-konva/-/react-konva-17.0.2-5.tgz#e70b0acf323402de0a540f27b300fbe7ed151849" integrity sha512-IyzdfqRDK8r1ulp/jbLPX18AuO+n5yNtL0+4T0QEUsgArRqIl/VRCG1imA5mYJBk0cBNC5+fWDHN+HWEW62ZEQ==