Skip to content

Commit

Permalink
Rect selection added
Browse files Browse the repository at this point in the history
  • Loading branch information
ilyabo committed Sep 2, 2024
1 parent bfd5c73 commit 799a502
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 32 deletions.
13 changes: 10 additions & 3 deletions assets/js/drawing/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
GeoJsonEditMode,
} from "@deck.gl-community/editable-layers";
import {
BoxSelectIcon,
LucideIcon,
MousePointerIcon,
MoveIcon,
Expand All @@ -15,6 +16,7 @@ import {

export const DrawingMode = {
SELECT: "select",
SELECT_RECT: "select:rect",
MOVE: "move",
DRAW_HEXAGON: "draw:hexagon",
DRAW_POLYGON: "draw:polygon",
Expand All @@ -23,6 +25,7 @@ export type DrawingMode = (typeof DrawingMode)[keyof typeof DrawingMode];

export const DRAWING_MODE_LABELS = {
[DrawingMode.SELECT]: "Select",
[DrawingMode.SELECT_RECT]: "Select by Rectangle",
[DrawingMode.MOVE]: "Move Objects",
[DrawingMode.DRAW_HEXAGON]: "Drawing with Hexagons",
[DrawingMode.DRAW_POLYGON]: "Drawing Polygons",
Expand All @@ -34,9 +37,10 @@ export function getDrawingModeLabel(mode: DrawingMode): string {

export const DRAWING_MODE_KEYSTROKES = {
[DrawingMode.SELECT]: "1",
[DrawingMode.MOVE]: "2",
[DrawingMode.DRAW_HEXAGON]: "3",
[DrawingMode.DRAW_POLYGON]: "4",
[DrawingMode.SELECT_RECT]: "2",
[DrawingMode.MOVE]: "3",
[DrawingMode.DRAW_HEXAGON]: "4",
[DrawingMode.DRAW_POLYGON]: "5",
} as const satisfies Record<DrawingMode, string>;

export function getDrawingModeKeystroke(mode: DrawingMode): string {
Expand All @@ -45,6 +49,7 @@ export function getDrawingModeKeystroke(mode: DrawingMode): string {

export const DRAWING_MODE_ICONS = {
[DrawingMode.SELECT]: MousePointerIcon,
[DrawingMode.SELECT_RECT]: BoxSelectIcon,
[DrawingMode.MOVE]: MoveIcon,
[DrawingMode.DRAW_HEXAGON]: PencilIcon,
[DrawingMode.DRAW_POLYGON]: PentagonIcon,
Expand All @@ -63,8 +68,10 @@ export type DrawHandlers = {
onDrag: DeckProps["onDrag"];
onDragStart: DeckProps["onDragStart"];
onDragEnd: DeckProps["onDragEnd"];
onSelect: (info: any) => any;
onEdit: Parameters<EditableGeoJsonLayer["getModeProps"]>[0]["onEdit"]; // EditableGeojsonLayerProps is not exported
cursor: string;
editMode: typeof GeoJsonEditMode;
enableDragPan: boolean;
selectionTool: "rectangle" | "polygon" | undefined;
};
62 changes: 38 additions & 24 deletions assets/js/drawing/use-draw-handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import {DrawHandlerContext, DrawHandlers, DrawingMode} from "./types";
import {
DrawPolygonMode,
ModifyMode,
RotateMode,
TransformMode,
TranslateMode,
ViewMode,
} from "@deck.gl-community/editable-layers";
Expand All @@ -13,19 +15,39 @@ import {useEffect, useState} from "react";

const NOOP = () => {};
const defaultHandlers = {
selectionTool: undefined,
onClick: NOOP,
onDrag: NOOP,
onDragStart: NOOP,
onDragEnd: NOOP,
onEdit: NOOP,
};
onEdit: ({updatedData, editType, editContext}) => {
const {featureIndexes} = editContext;
if (featureIndexes && featureIndexes.length > 0) {
useAppStore
.getState()
.addOrUpdateFeatures(
featureIndexes.map((index) => updatedData.features[index])
);
}
},
onSelect: ({pickingInfos}) => {
const appState = useAppStore.getState();
const features = appState.features;
const selectedFeatures = pickingInfos
.map((pi) => features[pi.index]?.id)
.filter(Boolean);
console.log({pickingInfos, selectedFeatures});
appState.setSelectedIds(selectedFeatures);
},
} satisfies Partial<DrawHandlers>;

export function useDrawHandler(context: DrawHandlerContext): DrawHandlers {
const drawingMode = useAppStore((state) => state.mode);
const isPanning = useAppStore((state) => state.isPanning);
const setDrawingMode = useAppStore((state) => state.setDrawingMode);
const drawHandlers = {
[DrawingMode.SELECT]: useSelectHandlers(context),
[DrawingMode.SELECT_RECT]: useSelectRectHandlers(context),
[DrawingMode.MOVE]: useMoveHandlers(context),
[DrawingMode.DRAW_POLYGON]: usePolygonHandlers(context),
[DrawingMode.DRAW_HEXAGON]: useHexagonHandlers(context),
Expand All @@ -48,6 +70,7 @@ export function useDrawHandler(context: DrawHandlerContext): DrawHandlers {
cursor: "grabbing",
editMode: ViewMode,
enableDragPan: true,
selectionTool: undefined,
};
}
return drawHandlers[drawingMode];
Expand Down Expand Up @@ -81,23 +104,25 @@ function useSelectHandlers(context: DrawHandlerContext): DrawHandlers {
setSelectedIds(undefined);
}
},
onEdit: ({updatedData, editType, editContext}) => {
const {featureIndexes} = editContext;
if (featureIndexes && featureIndexes.length > 0) {
addOrUpdateFeatures(
featureIndexes.map((index) => updatedData.features[index])
);
}
},
cursor: "pointer",
editMode: selectedIds ? ModifyMode : ViewMode,
enableDragPan: selectedIds ? false : true,
};
}

function useSelectRectHandlers(context: DrawHandlerContext): DrawHandlers {
const setSelectedIds = useAppStore((state) => state.setSelectedIds);
return {
...defaultHandlers,
cursor: "crosshair",
editMode: ViewMode,
enableDragPan: false,
selectionTool: "rectangle",
};
}

function useMoveHandlers(context: DrawHandlerContext): DrawHandlers {
const setSelectedIds = useAppStore((state) => state.setSelectedIds);
const addOrUpdateFeatures = useAppStore((state) => state.addOrUpdateFeatures);
return {
...defaultHandlers,
onClick: (evt) => {
Expand All @@ -108,16 +133,8 @@ function useMoveHandlers(context: DrawHandlerContext): DrawHandlers {
setSelectedIds(undefined);
}
},
onEdit: ({updatedData, editContext}) => {
const {featureIndexes} = editContext;
if (featureIndexes && featureIndexes.length > 0) {
addOrUpdateFeatures(
featureIndexes.map((index) => updatedData.features[index])
);
}
},
cursor: "move",
editMode: TranslateMode,
editMode: TransformMode,
enableDragPan: false,
};
}
Expand Down Expand Up @@ -167,10 +184,7 @@ function useHexagonHandlers(context: DrawHandlerContext): DrawHandlers {
{
id: h3,
type: "Feature",
geometry: {
type: "Polygon",
coordinates: [boundary],
},
geometry: {type: "Polygon", coordinates: [boundary]},
properties: {color},
},
]);
Expand Down
32 changes: 28 additions & 4 deletions assets/js/map/map-view.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import {
Color,
EditableGeoJsonLayer,
FeatureCollection,
SelectionLayer,
} from "@deck.gl-community/editable-layers";
import {Layer} from "@deck.gl/core";
import {
MapboxOverlay as DeckOverlay,
MapboxOverlayProps,
Expand Down Expand Up @@ -38,6 +41,12 @@ const INITIAL_VIEW_STATE = {
minZoom: 1.5,
};

const EDITABLE_FEATURES_LAYER_ID = "editable-geojson-layer";
const SELECTION_LAYER_ID = "selection";
const SELECTION_LINE_WIDTH = 3;
const SELECTION_STROKE_COLOR: Color = [255, 100, 0, 255];
const SELECTION_FILL_COLOR: Color = [255, 100, 0, 50];

function DeckGLOverlay(props: MapboxOverlayProps): null {
const overlay = useControl(({map}) => {
const mapInstance = map.getMap() as Map;
Expand Down Expand Up @@ -95,9 +104,9 @@ export const MapView: FC = () => {
[features, selectedIds]
);

const layers = [
const layers: Layer[] = [
new EditableGeoJsonLayer({
id: "editable-geojson-layer",
id: EDITABLE_FEATURES_LAYER_ID,
data: featureCollection,
mode: drawHandlers.editMode,
selectedFeatureIndexes,
Expand All @@ -111,15 +120,30 @@ export const MapView: FC = () => {
stroked: true,
filled: true,
lineWidthUnits: "pixels",
getLineWidth: (f) => (selectedIds?.includes(f.id) ? 5 : 1),
getLineWidth: (f) =>
selectedIds?.includes(f.id) ? SELECTION_LINE_WIDTH : 1,
getLineColor: (f) =>
selectedIds?.includes(f.id)
? [255, 100, 0, 255]
? SELECTION_STROKE_COLOR
: f.properties.color
? colorToRGBA(f.properties.color, {darker: 0.25})
: defaultColor,
}),
];
if (drawHandlers.selectionTool) {
layers.push(
new SelectionLayer({
id: SELECTION_LAYER_ID,
selectionType: drawHandlers.selectionTool,
onSelect: drawHandlers.onSelect,
layerIds: [EDITABLE_FEATURES_LAYER_ID],
getTentativeFillColor: () => SELECTION_FILL_COLOR,
getTentativeLineColor: () => SELECTION_STROKE_COLOR,
lineWidth: SELECTION_LINE_WIDTH,
lineWidthUnits: "pixels",
})
);
}

return (
<ReactMapGl
Expand Down
11 changes: 10 additions & 1 deletion assets/js/store/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,16 @@ export const useAppStore = create<DrawingState>((set, get) => {
redo: () => yfeaturesUndo?.redo(),

setHexResolution: (resolution) => set({hexResolution: resolution}),
setDrawingMode: (mode) => set({mode}),
setDrawingMode: (mode) => {
set({mode});
if (
[DrawingMode.DRAW_HEXAGON, DrawingMode.DRAW_POLYGON].includes(
DrawingMode[mode]
)
) {
set({selectedIds: undefined});
}
},
setPanning: (isPanning) => set({isPanning}),
setSelectedIds: (ids) => set({selectedIds: ids}),
clear: () => yfeatures.clear(),
Expand Down

0 comments on commit 799a502

Please sign in to comment.