mirror of
https://github.com/drawdb-io/drawdb.git
synced 2025-09-01 18:35:24 +00:00
fix: rewrite coordinate management
After some initial smaller fixes, it turned out that I had broken the red line used when linking fields. Fixing this was not trivial as I found myself battling a lot of small bugs relating to scale and translation in the existing code. This was made extra difficult as a lot of coordinates were calculated when necessary in Canvas.jsx. This commit attempts to simplify the coordinate management in a few different ways: * There are now two distinct coordinate systems in use, typically referred to as "spaces". Screen space and diagram space. * Diagram space is no longer measured in pixels (though the dimension-less measure used instead still maps to pixels at 100% zoom). * The canvas now exposes helper methods for transforming between spaces. * Zoom and translation is now managed via the svg viewBox property. * This makes moving items in diagram space much easier as the coordinates remain constant regardless of zoom level. * The canvas now wraps the current mouse position in a context object, making mouse movement much easier to work with. * The transform.pan property now refers to the center of the screen. A new feature in this commit is that scroll wheel zoom is now based on the current cursor location, making the diagram more convenient to move around in. I have tried to focus on Canvas.jsx and avoid changes that might be desctructive on existing save files. I also believe more refactors and abstractions could be introduced based on these changes to make the diagram even easier to work with. However, I deem that out of scope for now.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { useState } from "react";
|
||||
import { useContext, useRef, useState } from "react";
|
||||
import { Button, Popover, Input } from "@douyinfe/semi-ui";
|
||||
import { IconEdit, IconDeleteStroked } from "@douyinfe/semi-icons";
|
||||
import {
|
||||
@@ -15,16 +15,27 @@ import {
|
||||
useSelect,
|
||||
useAreas,
|
||||
useSaveState,
|
||||
useTransform,
|
||||
} from "../../hooks";
|
||||
import ColorPalette from "../ColorPicker";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useHover } from "usehooks-ts";
|
||||
import { CanvasContext } from "../../context/CanvasContext";
|
||||
|
||||
export default function Area({ data, onPointerDown, setResize, setInitCoords }) {
|
||||
const [hovered, setHovered] = useState(false);
|
||||
export default function Area({
|
||||
data,
|
||||
onPointerDown,
|
||||
setResize,
|
||||
setInitCoords,
|
||||
}) {
|
||||
const ref = useRef(null);
|
||||
const isHovered = useHover(ref);
|
||||
const {
|
||||
pointer: {
|
||||
spaces: { diagram: pointer },
|
||||
},
|
||||
} = useContext(CanvasContext);
|
||||
const { layout } = useLayout();
|
||||
const { settings } = useSettings();
|
||||
const { transform } = useTransform();
|
||||
const { setSaveState } = useSaveState();
|
||||
const { selectedElement, setSelectedElement } = useSelect();
|
||||
|
||||
@@ -35,8 +46,8 @@ export default function Area({ data, onPointerDown, setResize, setInitCoords })
|
||||
y: data.y,
|
||||
width: data.width,
|
||||
height: data.height,
|
||||
pointerX: e.clientX / transform.zoom,
|
||||
pointerY: e.clientY / transform.zoom,
|
||||
pointerX: pointer.x,
|
||||
pointerY: pointer.y,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -84,10 +95,7 @@ export default function Area({ data, onPointerDown, setResize, setInitCoords })
|
||||
selectedElement.open;
|
||||
|
||||
return (
|
||||
<g
|
||||
onPointerEnter={(e) => e.isPrimary && setHovered(true)}
|
||||
onPointerLeave={(e) => e.isPrimary &&setHovered(false)}
|
||||
>
|
||||
<g ref={ref}>
|
||||
<foreignObject
|
||||
key={data.id}
|
||||
x={data.x}
|
||||
@@ -98,7 +106,7 @@ export default function Area({ data, onPointerDown, setResize, setInitCoords })
|
||||
>
|
||||
<div
|
||||
className={`border-2 ${
|
||||
hovered
|
||||
isHovered
|
||||
? "border-dashed border-blue-500"
|
||||
: selectedElement.element === ObjectType.AREA &&
|
||||
selectedElement.id === data.id
|
||||
@@ -114,7 +122,7 @@ export default function Area({ data, onPointerDown, setResize, setInitCoords })
|
||||
<div className="text-color select-none overflow-hidden text-ellipsis">
|
||||
{data.name}
|
||||
</div>
|
||||
{(hovered || (areaIsSelected() && !layout.sidebar)) && (
|
||||
{(isHovered || (areaIsSelected() && !layout.sidebar)) && (
|
||||
<Popover
|
||||
visible={areaIsSelected() && !layout.sidebar}
|
||||
onClickOutSide={onClickOutSide}
|
||||
@@ -139,7 +147,7 @@ export default function Area({ data, onPointerDown, setResize, setInitCoords })
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
{hovered && (
|
||||
{isHovered && (
|
||||
<>
|
||||
<circle
|
||||
cx={data.x}
|
||||
|
Reference in New Issue
Block a user