Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 22 additions & 5 deletions app/components/mode_hints.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ import { useBreakpoint } from 'app/hooks/use_responsive';
import { getIsMac, localizeKeybinding } from 'app/lib/utils';
import clsx from 'clsx';
import { useAtom, useAtomValue } from 'jotai';
import { hideHintsAtom, selectionAtom } from 'state/jotai';
import {
hideHintsAtom,
selectedFeaturesAtom,
selectionAtom
} from 'state/jotai';
import { Mode, modeAtom } from 'state/mode';

function ModeHint({
Expand Down Expand Up @@ -48,17 +52,26 @@ function ModeHint({
export function ModeHints() {
const mode = useAtomValue(modeAtom);
const selection = useAtomValue(selectionAtom);
const selectedFeatures = useAtomValue(selectedFeaturesAtom);
const show = useBreakpoint('lg');
const isMac = getIsMac();

const selectedGeometryType = selectedFeatures[0]?.feature.geometry?.type;
const selectionHasVertices =
selectedGeometryType === 'LineString' ||
selectedGeometryType === 'MultiLineString' ||
selectedGeometryType === 'Polygon' ||
selectedGeometryType === 'MultiPolygon';

if (!show) {
return null;
}

const hold = (shift: boolean = false) => (
<div className="text-xs">
Hold {localizeKeybinding('Option', isMac)} to snap to existing features.
{shift ? 'Hold Shift to snap to right angles.' : null}
Hold {localizeKeybinding('Option', isMac)} to snap to existing features,{' '}
{localizeKeybinding('Option', isMac)}+Shift to snap to vertices.
{shift ? ' Hold Shift to snap to right angles.' : null}
</div>
);

Expand Down Expand Up @@ -107,8 +120,12 @@ export function ModeHints() {
<div>
Hold space bar & drag to move entire features. Hold option &
drag to rotate.
<br />
{hold()}
{selectionHasVertices ? (
<>
<br />
{hold()}
</>
) : null}
</div>
</ModeHint>
);
Expand Down
97 changes: 97 additions & 0 deletions app/lib/__snapshots__/load_and_augment_style.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -585,6 +585,24 @@ exports[`loadAndAugmentStyle 1`] = `
"source": "circle-drawing",
"type": "circle",
},
{
"id": "vertex-snap-circles",
"layout": {},
"paint": {
"circle-color": [
"coalesce",
[
"get",
"stroke",
],
"#312E81",
],
"circle-emissive-strength": 1,
"circle-radius": 3,
},
"source": "vertex-snap",
"type": "circle",
},
],
"name": "Empty",
"sources": {
Expand Down Expand Up @@ -613,6 +631,13 @@ exports[`loadAndAugmentStyle 1`] = `
"tolerance": 0,
"type": "geojson",
},
"vertex-snap": {
"data": {
"features": [],
"type": "FeatureCollection",
},
"type": "geojson",
},
},
"sprite": "mapbox://sprites/mapbox/streets-v8",
"version": 8,
Expand Down Expand Up @@ -1159,6 +1184,24 @@ exports[`makeLayers > categorical 2`] = `
"source": "circle-drawing",
"type": "circle",
},
{
"id": "vertex-snap-circles",
"layout": {},
"paint": {
"circle-color": [
"coalesce",
[
"get",
"stroke",
],
"#312E81",
],
"circle-emissive-strength": 1,
"circle-radius": 3,
},
"source": "vertex-snap",
"type": "circle",
},
]
`;

Expand Down Expand Up @@ -1716,6 +1759,24 @@ exports[`makeLayers > none 1`] = `
"source": "circle-drawing",
"type": "circle",
},
{
"id": "vertex-snap-circles",
"layout": {},
"paint": {
"circle-color": [
"coalesce",
[
"get",
"stroke",
],
"#312E81",
],
"circle-emissive-strength": 1,
"circle-radius": 3,
},
"source": "vertex-snap",
"type": "circle",
},
]
`;

Expand Down Expand Up @@ -2234,6 +2295,24 @@ exports[`makeLayers > ramp 1`] = `
"source": "circle-drawing",
"type": "circle",
},
{
"id": "vertex-snap-circles",
"layout": {},
"paint": {
"circle-color": [
"coalesce",
[
"get",
"stroke",
],
"#312E81",
],
"circle-emissive-strength": 1,
"circle-radius": 3,
},
"source": "vertex-snap",
"type": "circle",
},
]
`;

Expand Down Expand Up @@ -2797,6 +2876,24 @@ exports[`makeLayers > with preview property 1`] = `
"source": "circle-drawing",
"type": "circle",
},
{
"id": "vertex-snap-circles",
"layout": {},
"paint": {
"circle-color": [
"coalesce",
[
"get",
"stroke",
],
"#312E81",
],
"circle-emissive-strength": 1,
"circle-radius": 3,
},
"source": "vertex-snap",
"type": "circle",
},
{
"filter": [
"all",
Expand Down
57 changes: 51 additions & 6 deletions app/lib/handlers/line.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
import { lockDirection, useAltHeld, useShiftHeld } from 'app/hooks/use_held';
import { CURSOR_DEFAULT } from 'app/lib/constants';
import * as utils from 'app/lib/map_component_utils';
import { usePopMoment } from 'app/lib/persistence/shared';
import replaceCoordinates from 'app/lib/replace_coordinates';
import { captureException } from 'integrations/errors';
import { useSetAtom } from 'jotai';
import { useRef } from 'react';
import { USelection } from 'state';
import { cursorStyleAtom, Mode, modeAtom, selectionAtom } from 'state/jotai';
import {
cursorStyleAtom,
ephemeralStateAtom,
Mode,
modeAtom,
selectionAtom
} from 'state/jotai';
import type { HandlerContext, IFeature, LineString, Position } from 'types';
import {
createOrUpdateFeature,
getMapCoord,
getNearbyVertices,
getSnappingCoordinates
} from './utils';

Expand All @@ -28,6 +34,7 @@
const setSelection = useSetAtom(selectionAtom);
const setMode = useSetAtom(modeAtom);
const setCursor = useSetAtom(cursorStyleAtom);
const setEphemeralState = useSetAtom(ephemeralStateAtom);
const transact = rep.useTransact();
const popMoment = usePopMoment();
const usingTouchEvents = useRef<boolean>(false);
Expand All @@ -43,7 +50,21 @@
* Drawing a new line: create the line and set the new
* selection
*/
const lineString = utils.newLineStringFromClickEvent(e);
const verticesOnly = altHeld.current && shiftHeld.current;
const pos = altHeld.current
? (getSnappingCoordinates(

Check warning on line 55 in app/lib/handlers/line.ts

View workflow job for this annotation

GitHub Actions / test

This assertion is unnecessary since it does not change the type of the expression

Check warning on line 55 in app/lib/handlers/line.ts

View workflow job for this annotation

GitHub Actions / test

This assertion is unnecessary since it does not change the type of the expression
e,
featureMap,
pmap,
idMap,
undefined,
verticesOnly
) as Position)
: getMapCoord(e);
const lineString: LineString = {
type: 'LineString',
coordinates: [pos, pos]
};

const putFeature = createOrUpdateFeature({
mode,
Expand Down Expand Up @@ -100,7 +121,17 @@
*/
move: (e) => {
const { modeOptions } = mode;
if (selection.type !== 'single') return;
if (selection.type !== 'single') {
if (altHeld.current) {
setEphemeralState({
type: 'vertex-snap',
vertices: getNearbyVertices(e, featureMap, pmap, idMap)
});
} else {
setEphemeralState({ type: 'none' });
}
return;
}

/**
* Ignore mousemove events produced by the Apple Pencil.
Expand All @@ -116,12 +147,26 @@

let nextCoord = getMapCoord(e) as Position;
const lastCoord = feature.geometry.coordinates.at(-2);
if (shiftHeld.current && lastCoord) {
const verticesOnly = altHeld.current && shiftHeld.current;
if (shiftHeld.current && !altHeld.current && lastCoord) {
nextCoord = lockDirection(lastCoord, nextCoord);
}

if (altHeld.current && lastCoord) {
nextCoord = getSnappingCoordinates(e, featureMap, pmap, idMap);
nextCoord = getSnappingCoordinates(
e,
featureMap,
pmap,
idMap,
selection.id,
verticesOnly
);
setEphemeralState({
type: 'vertex-snap',
vertices: getNearbyVertices(e, featureMap, pmap, idMap, selection.id)
});
} else {
setEphemeralState({ type: 'none' });
}

void transact({
Expand Down
Loading
Loading