Skip to content

Commit

Permalink
climbing: fix positioning while zoom (zbycz#411)
Browse files Browse the repository at this point in the history
  • Loading branch information
zbycz authored Jul 14, 2024
1 parent 853b7f2 commit 40654c6
Show file tree
Hide file tree
Showing 9 changed files with 116 additions and 123 deletions.
17 changes: 6 additions & 11 deletions src/components/FeaturePanel/Climbing/Editor/MouseTrackingLine.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,33 +10,28 @@ export const MouseTrackingLine = ({ routeNumber }) => {
getPercentagePosition,
routes,
findCloserPoint,
addOffsets,
getPathForRoute,
} = useClimbingContext();

const route = routes[routeNumber];
const path = getPathForRoute(route);
const lastPoint = path[path.length - 1];
const lastPointPositionInPx = getPixelPosition(lastPoint);
const mousePositionWithEditorPosition = addOffsets(
['editorPosition', 'imageContainer'],
mousePosition,
);

const closerMousePositionPoint = mousePositionWithEditorPosition
? findCloserPoint(getPercentagePosition(mousePositionWithEditorPosition))
const closerMousePositionPoint = mousePosition
? findCloserPoint(getPercentagePosition(mousePosition))
: null;
const mousePosition2 = closerMousePositionPoint
const mousePositionSticked = closerMousePositionPoint
? getPixelPosition(closerMousePositionPoint)
: mousePositionWithEditorPosition;
: mousePosition;

const isSelected = isRouteSelected(routeNumber);

return (
mousePosition2 &&
mousePositionSticked &&
isSelected && (
<PathWithBorder
d={`M ${lastPointPositionInPx.x} ${lastPointPositionInPx.y} L ${mousePosition2.x} ${mousePosition2.y}`}
d={`M ${lastPointPositionInPx.x} ${lastPointPositionInPx.y} L ${mousePositionSticked.x} ${mousePositionSticked.y}`}
isSelected={isSelected}
pointerEvents="none"
opacity={0.7}
Expand Down
43 changes: 21 additions & 22 deletions src/components/FeaturePanel/Climbing/Editor/RoutePath.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { useClimbingContext } from '../contexts/ClimbingContext';
import { PositionPx } from '../types';
import { PathWithBorder } from './PathWithBorder';
import { MouseTrackingLine } from './MouseTrackingLine';
import { getPositionInImageFromMouse } from '../utils/mousePositionUtils';

const InteractiveArea = styled.line`
pointer-events: all;
Expand All @@ -16,17 +17,20 @@ const AddNewPoint = styled.circle`

export const RoutePath = ({ route, routeNumber }) => {
const [tempPointPosition, setTempPointPosition] =
useState<(PositionPx & { lineIndex: number }) | null>(null);
useState<PositionPx | null>(null);
const [tempPointSegmentIndex, setTempPointSegmentIndex] =
useState<number | null>(null);
const {
isPointMoving,
isRouteSelected,
getPixelPosition,
getMachine,
isEditMode,
addOffsets,
routeIndexHovered,
setRouteIndexHovered,
getPathForRoute,
photoRef,
photoZoom,
} = useClimbingContext();
const isSelected = isRouteSelected(routeNumber);
const machine = getMachine();
Expand All @@ -38,23 +42,26 @@ export const RoutePath = ({ route, routeNumber }) => {
return `${index === 0 ? 'M' : 'L'}${position.x} ${position.y} `;
});

const onMouseMove = (e, lineIndex: number) => {
const onMouseMove = (e, segmentIndex: number) => {
if (
machine.currentStateName === 'editRoute' ||
machine.currentStateName === 'extendRoute'
) {
if (!routeIndexHovered) setRouteIndexHovered(routeNumber);

const position = addOffsets(['editorPosition', 'imageContainer'], {
const mousePosition: PositionPx = {
x: e.clientX,
y: e.clientY,
units: 'px',
});

setTempPointPosition({
...position,
lineIndex,
});
};
const positionInImage = getPositionInImageFromMouse(
photoRef,
mousePosition,
photoZoom,
);

setTempPointPosition(positionInImage);
setTempPointSegmentIndex(segmentIndex);
}
};

Expand All @@ -66,19 +73,11 @@ export const RoutePath = ({ route, routeNumber }) => {
setRouteIndexHovered(null);
};

const hoveredPosition = tempPointPosition
? addOffsets(['scrollOffset'], {
x: tempPointPosition.x,
y: tempPointPosition.y,
units: 'px',
})
: null;

const onPointAdd = () => {
if (tempPointPosition) {
machine.execute('addPointInBetween', {
hoveredPosition,
tempPointPosition,
hoveredPosition: tempPointPosition,
hoveredSegmentIndex: tempPointSegmentIndex,
});
}
};
Expand Down Expand Up @@ -155,8 +154,8 @@ export const RoutePath = ({ route, routeNumber }) => {
})}
{isEditableSelectedRouteHovered && tempPointPosition && (
<AddNewPoint
cx={hoveredPosition.x}
cy={hoveredPosition.y}
cx={tempPointPosition.x}
cy={tempPointPosition.y}
fill="white"
stroke="rgba(0,0,0,0.3)"
r={5}
Expand Down
25 changes: 14 additions & 11 deletions src/components/FeaturePanel/Climbing/Editor/RoutesEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { RoutesLayer } from './RoutesLayer';
import { useClimbingContext } from '../contexts/ClimbingContext';
import { updateElementOnIndex } from '../utils/array';
import { PositionPx } from '../types';
import { getPositionInImageFromMouse } from '../utils/mousePositionUtils';

const EditorContainer = styled.div<{ imageHeight: number }>`
display: flex;
Expand Down Expand Up @@ -44,7 +45,6 @@ export const RoutesEditor = ({
const {
imageSize,
getMachine,
addOffsets,
setMousePosition,
setIsPointMoving,
getPercentagePosition,
Expand All @@ -59,6 +59,7 @@ export const RoutesEditor = ({
photoRef,
photoPath,
setLoadedPhotos,
photoZoom,
} = useClimbingContext();
const machine = getMachine();
const [transformOrigin] = useState({ x: 0, y: 0 }); // @TODO remove ?
Expand All @@ -83,12 +84,9 @@ export const RoutesEditor = ({
if (isPointClicked) {
setMousePosition(null);
machine.execute('dragPoint', { position });

setIsPointMoving(true);
const newCoordinate = getPercentagePosition(
addOffsets(['editorPosition', 'imageContainer'], position),
);

const newCoordinate = getPercentagePosition(position);
const closestPoint = findCloserPoint(newCoordinate);

const updatedPoint = closestPoint ?? newCoordinate;
Expand All @@ -112,13 +110,18 @@ export const RoutesEditor = ({
};

const onMouseMove = (e) => {
onMove(
addOffsets(['scrollOffset'], {
x: e.clientX,
y: e.clientY,
units: 'px',
}),
const mousePosition: PositionPx = {
x: e.clientX,
y: e.clientY,
units: 'px',
};
const positionInImage = getPositionInImageFromMouse(
photoRef,
mousePosition,
photoZoom,
);

onMove(positionInImage);
};

const onPhotoLoad = () => {
Expand Down
29 changes: 18 additions & 11 deletions src/components/FeaturePanel/Climbing/Editor/RoutesLayer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import { useClimbingContext } from '../contexts/ClimbingContext';
import { RouteWithLabel } from './RouteWithLabel';
import { RouteFloatingMenu } from './RouteFloatingMenu';
import { RouteMarks } from './RouteMarks';
import { getMouseFromPositionInImage } from '../utils/mousePositionUtils';

const DIALOG_TOP_BAR_HEIGHT = 56;
type RouteRenders = { route: React.ReactNode; marks: React.ReactNode };

const Svg = styled.svg<{
Expand Down Expand Up @@ -63,14 +65,14 @@ export const RoutesLayer = ({
isRouteSelected,
isRouteHovered,
getPixelPosition,
editorPosition,
scrollOffset,
isPointMoving,
setIsPointClicked,
setIsPointMoving,
setPointSelectedIndex,
getCurrentPath,
routes,
photoRef,
photoZoom,
} = useClimbingContext();

const machine = getMachine();
Expand Down Expand Up @@ -103,7 +105,7 @@ export const RoutesLayer = ({
hovered: Array<RouteRenders>;
}>(
(acc, route, index) => {
const RenderRoute = () => (
const RouteInner = () => (
<RouteWithLabel
route={route}
routeNumber={index}
Expand All @@ -123,7 +125,7 @@ export const RoutesLayer = ({
...acc,
selected: [
...acc.selected,
{ route: <RenderRoute />, marks: <RenderRouteMarks /> },
{ route: <RouteInner />, marks: <RenderRouteMarks /> },
],
};
}
Expand All @@ -132,15 +134,15 @@ export const RoutesLayer = ({
...acc,
hovered: [
...acc.hovered,
{ route: <RenderRoute />, marks: <RenderRouteMarks /> },
{ route: <RouteInner />, marks: <RenderRouteMarks /> },
],
};
}
return {
...acc,
rest: [
...acc.rest,
{ route: <RenderRoute />, marks: <RenderRouteMarks /> },
{ route: <RouteInner />, marks: <RenderRouteMarks /> },
],
};
},
Expand All @@ -165,6 +167,13 @@ export const RoutesLayer = ({
? selectedPointOfSelectedRoute
: lastPointOfSelectedRoute;

// TODO this position doesnt work well when zoomed
const absolutePositionFromScreen = getMouseFromPositionInImage(
photoRef,
routeFloatingMenuPosition,
photoZoom,
);

return (
<>
<Svg
Expand All @@ -188,12 +197,10 @@ export const RoutesLayer = ({
{sortedRoutes.hovered.map((item) => item.marks)}
</Svg>

{routeFloatingMenuPosition && (
{absolutePositionFromScreen && (
<RouteFloatingMenuContainer
$x={
routeFloatingMenuPosition.x + editorPosition.x + scrollOffset.x + 30
}
$y={routeFloatingMenuPosition.y + scrollOffset.y - 15}
$x={absolutePositionFromScreen.x + 20}
$y={absolutePositionFromScreen.y - DIALOG_TOP_BAR_HEIGHT - 15}
>
<RouteFloatingMenu />
</RouteFloatingMenuContainer>
Expand Down
10 changes: 2 additions & 8 deletions src/components/FeaturePanel/Climbing/TransformWrapper.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react';
import { TransformWrapper as Wrapper } from 'react-zoom-pan-pinch';
import { useClimbingContext } from './contexts/ClimbingContext';
import { ZoomState } from './types';

export const TransformWrapper = ({ children }) => {
const { setArePointerEventsDisabled, setPhotoZoom } = useClimbingContext();
Expand Down Expand Up @@ -28,14 +29,7 @@ export const TransformWrapper = ({ children }) => {
disablePadding
wheel={{ step: 100 }}
centerOnInit
onTransformed={(
_ref,
state: {
scale: number;
positionX: number;
positionY: number;
},
) => {
onTransformed={(_ref, state: ZoomState) => {
setPhotoZoom(state);
}}
>
Expand Down
17 changes: 4 additions & 13 deletions src/components/FeaturePanel/Climbing/contexts/ClimbingContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,7 @@ import {
State,
StateAction,
} from '../utils/getMachineFactory';
import {
CountPositionEntity,
positionUtilsFactory,
} from '../utils/positionUtilsFactory';
import { positionUtilsFactory } from '../utils/positionUtilsFactory';
import { Feature } from '../../../../services/types';
import { osmToClimbingRoutes } from './osmToClimbingRoutes';
import { publishDbgObject } from '../../../../utils';
Expand Down Expand Up @@ -82,10 +79,6 @@ type ClimbingContextType = {
getPathForRoute: (route: ClimbingRoute) => PathPoints;
getCurrentPath: () => PathPoints;
getPercentagePosition: (position: PositionPx) => Position;
addOffsets: (
entities: Array<CountPositionEntity>,
position: PositionPx,
) => PositionPx;
addZoom: (position: PositionPx) => PositionPx;
getMachine: () => {
currentState: Partial<Record<StateAction, ActionWithCallback>>;
Expand Down Expand Up @@ -249,12 +242,10 @@ export const ClimbingContextProvider = ({ children, feature }: Props) => {
getPathForRoute,
});

const { getPixelPosition, getPercentagePosition, addOffsets, addZoom } =
const { getPixelPosition, getPercentagePosition, addZoom } =
positionUtilsFactory({
editorPosition,
scrollOffset,
imageSize,
imageContainerSize,
photoZoom,
});

Expand All @@ -271,8 +262,9 @@ export const ClimbingContextProvider = ({ children, feature }: Props) => {
routes,
updateRouteOnIndex,
getPercentagePosition,
addOffsets,
findCloserPoint,
photoRef,
photoZoom,
});

const isRouteSelected = (index: number) => routeSelectedIndex === index;
Expand Down Expand Up @@ -383,7 +375,6 @@ export const ClimbingContextProvider = ({ children, feature }: Props) => {
pointElement,
setPointElement,
moveRoute,
addOffsets,
isEditMode,
setIsEditMode,
viewportSize,
Expand Down
Loading

0 comments on commit 40654c6

Please sign in to comment.