diff --git a/doc/changelog.md b/doc/changelog.md index fabb8de44..1bb5c7f16 100644 --- a/doc/changelog.md +++ b/doc/changelog.md @@ -75,6 +75,8 @@ Syntax: `- short text describing the change _(Your Name)_` ## 0.4.0 - 12.4.2024 +- Display lines at y=0 and x=0 on the grid. _(Moritz)_ +- Fix a bug that caused the yard stick to jump around while zooming the map _(Moritz)_ - needs new migrations - needs new scraper data (integer for plant spread and height) - pin python package versions for e2e tests #1200 _(4ydan)_ diff --git a/doc/usecases/done/grid.md b/doc/usecases/done/grid.md index 35392e517..51f5a8670 100644 --- a/doc/usecases/done/grid.md +++ b/doc/usecases/done/grid.md @@ -5,17 +5,19 @@ - **Scope:** Grid - **Level:** User Goal - **Actors:** App User -- **Brief:** The app will display a fixed scale coordinate grid. +- **Brief:** The app will display a variable scale coordinate grid. - **Status:** Done - **Assignee:** Moritz -- **Protocol:** ## Scenarios - **Precondition:** - User has opened the map. - **Main success scenario:** - - The user sees a fixed scale coordinate grid with 1 meter spacing. + - The user sees a variable scale coordinate grid with 1 meter, 10 meter and 10 centimeter spacings depending on the current map scale. + - A yard stick displays the current scale of the coordinate grid. + - The origin point is marked on the map. + - The grid can be toggled on and of using a button in the top right toolbar. - **Non-functional Constraints:** - Support for changing viewport (zoom, position, etc.) - The functionality is only available in the frontend. diff --git a/frontend/src/features/map_planning/components/BaseStage.tsx b/frontend/src/features/map_planning/components/BaseStage.tsx index dd99e8012..24cb86191 100644 --- a/frontend/src/features/map_planning/components/BaseStage.tsx +++ b/frontend/src/features/map_planning/components/BaseStage.tsx @@ -92,17 +92,14 @@ export const BaseStage = ({ const { isSelectedLayerVisible } = useSelectedLayerVisibility(); - const updateViewRect = useMapStore((store) => store.updateViewRect); - const viewRect = useMapStore((store) => store.untrackedState.editorViewRect); useEffect(() => { - if (viewRect.width !== 0 || viewRect.height !== 0) return; - updateViewRect({ - x: 0, - y: 0, + useMapStore.getState().updateViewRect({ + x: Math.floor(stage.x / stage.scale), + y: Math.floor(stage.y / stage.scale), width: Math.floor(window.innerWidth / stage.scale), height: Math.floor(window.innerHeight / stage.scale), }); - }); + }, [stage.scale, stage.x, stage.y]); const onStageWheel = (e: KonvaEventObject) => { e.evt.preventDefault(); @@ -124,18 +121,9 @@ export const BaseStage = ({ } } else { if (scrollable) { - handleScroll(e.evt.deltaX, e.evt.deltaY, targetStage); + handleScroll(e.evt.deltaX, e.evt.deltaY, targetStage, setStage); } } - - if (stageRef.current === null) return; - - updateViewRect({ - x: Math.floor(stageRef.current.getAbsolutePosition().x / stage.scale), - y: Math.floor(stageRef.current.getAbsolutePosition().y / stage.scale), - width: Math.floor(window.innerWidth / stage.scale), - height: Math.floor(window.innerHeight / stage.scale), - }); }; // Event listener responsible for allowing stage-dragging only via middle mouse button @@ -155,13 +143,6 @@ export const BaseStage = ({ const onStageDragEnd = (e: KonvaEventObject) => { listeners?.stageDragEndListeners.forEach((listener) => listener(e)); if (stageRef.current === null) return; - - updateViewRect({ - x: Math.floor(stageRef.current.getAbsolutePosition().x / stage.scale), - y: Math.floor(stageRef.current.getAbsolutePosition().y / stage.scale), - width: Math.floor(window.innerWidth / stage.scale), - height: Math.floor(window.innerHeight / stage.scale), - }); }; // Event listener responsible for updating the selection rectangle's size diff --git a/frontend/src/features/map_planning/layers/_frontend_only/grid/groups/Grid.tsx b/frontend/src/features/map_planning/layers/_frontend_only/grid/groups/Grid.tsx index 124a08b37..ba2fa815e 100644 --- a/frontend/src/features/map_planning/layers/_frontend_only/grid/groups/Grid.tsx +++ b/frontend/src/features/map_planning/layers/_frontend_only/grid/groups/Grid.tsx @@ -23,10 +23,22 @@ export const Grid = (rect: ViewRect) => { strokeWidth={gridDotSize} stroke={colors.secondary[500]} points={[startX, y, endX, y]} - dash={[gridDotSize, gridStep - gridDotSize]} + dash={y !== 0 ? [gridDotSize / 2, gridStep - gridDotSize, gridDotSize / 2, 0] : []} + key={`grid-line-y-${y}`} >, ); } - return {lines}; + return ( + + {lines} + {/* Forms a cross with the solid line at y = 0 to indicate where the origin is. */} + + + ); }; diff --git a/frontend/src/features/map_planning/layers/_frontend_only/grid/util/Calculations.ts b/frontend/src/features/map_planning/layers/_frontend_only/grid/util/Calculations.ts index 1a4083389..28eb3aece 100644 --- a/frontend/src/features/map_planning/layers/_frontend_only/grid/util/Calculations.ts +++ b/frontend/src/features/map_planning/layers/_frontend_only/grid/util/Calculations.ts @@ -5,11 +5,11 @@ import { ONE_METER, TEN_CENTIMETERS } from '@/features/map_planning/utils/Consta * @param screenWidth current screen width */ export function calculateGridStep(screenWidth: number): number { - if (screenWidth > 50 * ONE_METER) { + if (screenWidth > 70 * ONE_METER) { return 10 * ONE_METER; } - if (screenWidth > 10 * ONE_METER) { + if (screenWidth > 5 * ONE_METER) { return ONE_METER; } diff --git a/frontend/src/features/map_planning/utils/StageTransform.ts b/frontend/src/features/map_planning/utils/StageTransform.ts index 3f06322e8..17ee48494 100644 --- a/frontend/src/features/map_planning/utils/StageTransform.ts +++ b/frontend/src/features/map_planning/utils/StageTransform.ts @@ -35,7 +35,18 @@ export const handleZoom = ( }); }; -export const handleScroll = (dx: number, dy: number, stage: Stage) => { +export const handleScroll = ( + dx: number, + dy: number, + stage: Stage, + setStage: React.Dispatch< + React.SetStateAction<{ + scale: number; + x: number; + y: number; + }> + >, +) => { const x = stage.position().x; const y = stage.position().y; const scrollingScalePx = 15; @@ -51,13 +62,22 @@ export const handleScroll = (dx: number, dy: number, stage: Stage) => { // how do we determine a scroll has finished? ideas: debounce or timeout. if (dx !== 0 && dy !== 0) { - stage.setPosition({ + setStage({ x: x - (dx / diagonalScalingFactor) * decayFactor, y: y - (dy / diagonalScalingFactor) * decayFactor, + scale: stage.scaleX(), }); } else if (dx !== 0) { - stage.setPosition({ x: x - (dx / scrollingScalePx) * decayFactor, y }); + setStage({ + x: x - (dx / scrollingScalePx) * decayFactor, + y, + scale: stage.scaleX(), + }); } else if (dy !== 0) { - stage.setPosition({ x, y: y - (dy / scrollingScalePx) * decayFactor }); + setStage({ + x, + y: y - (dy / scrollingScalePx) * decayFactor, + scale: stage.scaleX(), + }); } }; diff --git a/frontend/src/svg/icons/grid.svg b/frontend/src/svg/icons/grid.svg deleted file mode 100644 index 55caa82db..000000000 --- a/frontend/src/svg/icons/grid.svg +++ /dev/null @@ -1,13 +0,0 @@ - - - - -