Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Shatter tool #142

Merged
merged 12 commits into from
Oct 25, 2024
6 changes: 3 additions & 3 deletions .github/workflows/fly-deploy-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ jobs:
echo "::set-output name=name::${{ github.event.repository.name }}-${{ github.event.number }}-db"

# manually launch and deploy the api app
- name: launch api app
- name: Launch API
if: github.event.action != 'closed'
run: |
app="${{ github.event.repository.name }}-${{ github.event.number }}-api"
Expand All @@ -94,7 +94,7 @@ jobs:
echo "api_app_name=$app" >> $GITHUB_ENV
working-directory: backend

- name: deploy api app
- name: Deploy API
if: github.event.action != 'closed'
run: |
flyctl secrets set \
Expand Down Expand Up @@ -138,7 +138,7 @@ jobs:
echo "frontend_app_name=$app" >> $GITHUB_ENV
working-directory: app

- name: Deploy Frontend App
- name: Deploy frontend
if: github.event.action != 'closed'
run: |
app_name="${{ github.event.repository.name }}-${{ github.event.number }}-app"
Expand Down
4 changes: 2 additions & 2 deletions app/fly.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ primary_region = 'ewr'
[http_service]
internal_port = 3000
force_https = true
auto_stop_machines = true
auto_stop_machines = "stop"
auto_start_machines = true
min_machines_running = 1
min_machines_running = 0
processes = ['app']

[[vm]]
Expand Down
2 changes: 0 additions & 2 deletions app/src/app/components/sidebar/GerryDBViewSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { useState } from "react";
import { Flex, Select } from "@radix-ui/themes";
import { useMapStore } from "../../store/mapStore";
import { document } from "@/app/utils/api/mutations";
import { RecentMapsModal } from "./RecentMapsModal";

export function GerryDBViewSelector() {
const [limit, setLimit] = useState<number>(30);
Expand Down Expand Up @@ -57,7 +56,6 @@ export function GerryDBViewSelector() {
</Select.Group>
</Select.Content>
</Select.Root>
<RecentMapsModal />
</Flex>
);
}
21 changes: 16 additions & 5 deletions app/src/app/components/sidebar/MapModeSelector.jsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,31 @@
import React from "react";
import * as RadioGroup from "@radix-ui/react-radio-group";
import { styled } from "@stitches/react";
import { blackA } from "@radix-ui/colors";
import { useMapStore } from "../../store/mapStore";
import { useMapStore } from "@store/mapStore";
import { RadioCards, Box } from "@radix-ui/themes";
import { EraserIcon, Pencil2Icon, HandIcon } from "@radix-ui/react-icons";
import {
EraserIcon,
Pencil2Icon,
HandIcon,
BorderSplitIcon,
} from "@radix-ui/react-icons";
import { RecentMapsModal } from "@components/sidebar/RecentMapsModal";

export function MapModeSelector() {
const mapStore = useMapStore.getState();
const activeTool = useMapStore((state) => state.activeTool);
const setActiveTool = useMapStore((state) => state.setActiveTool);

if (!activeTool) return null;
const activeTools = [
{ mode: "pan", disabled: false, label: "Pan", icon: <HandIcon /> },
{ mode: "brush", disabled: false, label: "Brush", icon: <Pencil2Icon /> },
{ mode: "eraser", disabled: false, label: "Erase", icon: <EraserIcon /> },
{
mode: "shatter",
disabled: false,
label: "Shatter",
icon: <BorderSplitIcon />,
},
];

const handleRadioChange = (value) => {
Expand All @@ -42,6 +52,7 @@ export function MapModeSelector() {
</RadioCards.Item>
</Flex>
))}
<RecentMapsModal />
</RadioCards.Root>
</Box>
);
Expand Down
15 changes: 6 additions & 9 deletions app/src/app/components/sidebar/RecentMapsModal.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useMapStore } from "@/app/store/mapStore";
import React from "react";
import { Cross2Icon } from "@radix-ui/react-icons";
import { Cross2Icon, CounterClockwiseClockIcon } from "@radix-ui/react-icons";
import {
Button,
Flex,
Expand All @@ -10,6 +10,7 @@ import {
Box,
TextField,
IconButton,
RadioCards,
} from "@radix-ui/themes";
import { usePathname, useSearchParams, useRouter } from "next/navigation";
import { DocumentObject } from "../../utils/api/apiHandlers";
Expand Down Expand Up @@ -40,14 +41,10 @@ export const RecentMapsModal = () => {
return (
<Dialog.Root open={dialogOpen} onOpenChange={setDialogOpen}>
<Dialog.Trigger>
<Button
variant="ghost"
size="3"
// weird negative margin happening.
style={{ margin: 0 }}
>
Recent
</Button>
<RadioCards.Item value="recents">
<CounterClockwiseClockIcon />
Recents
</RadioCards.Item>
</Dialog.Trigger>
<Dialog.Content className="max-w-[75vw]">
<Flex align="center" className="mb-4">
Expand Down
4 changes: 2 additions & 2 deletions app/src/app/constants/types.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import type { MapOptions, MapLibreEvent } from "maplibre-gl";

export type Zone = number;
export type NullableZone = Zone | null
export type NullableZone = Zone | null;

export type GEOID = string;

export type GDBPath = string;

export type ZoneDict = Map<GEOID, Zone>;

export type ActiveTool = "pan" | "brush" | "eraser"; // others?
export type ActiveTool = "pan" | "brush" | "eraser" | "shatter"; // others?

export type SpatialUnit =
| "county"
Expand Down
44 changes: 39 additions & 5 deletions app/src/app/store/mapRenderSubs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@ import {
PARENT_LAYERS,
CHILD_LAYERS,
getLayerFilter,
} from "../constants/layers";
} from "@constants/layers";
import {
ColorZoneAssignmentsState,
colorZoneAssignments,
shallowCompareArray,
} from "../utils/helpers";
import { useMapStore as _useMapStore, MapStore } from "./mapStore";
import { useMapStore as _useMapStore, MapStore } from "@store/mapStore";
import { getFeatureUnderCursor } from "@utils/helpers";

export const getRenderSubscriptions = (useMapStore: typeof _useMapStore) => {
const addLayerSubMapDocument = useMapStore.subscribe<
Expand All @@ -20,7 +21,7 @@ export const getRenderSubscriptions = (useMapStore: typeof _useMapStore) => {
(state) => [state.mapDocument, state.getMapRef],
([mapDocument, getMapRef]) => {
const mapStore = useMapStore.getState();
const mapRef = getMapRef()
const mapRef = getMapRef();
if (mapRef && mapDocument) {
addBlockLayers(mapRef, mapDocument);
mapStore.addVisibleLayerIds([BLOCK_LAYER_ID, BLOCK_HOVER_LAYER_ID]);
Expand All @@ -30,12 +31,16 @@ export const getRenderSubscriptions = (useMapStore: typeof _useMapStore) => {
);

const _shatterMapSideEffectRender = useMapStore.subscribe<
[MapStore["shatterIds"], MapStore["getMapRef"], MapStore["mapRenderingState"]]
[
MapStore["shatterIds"],
MapStore["getMapRef"],
MapStore["mapRenderingState"],
]
>(
(state) => [state.shatterIds, state.getMapRef, state.mapRenderingState],
([shatterIds, getMapRef, mapRenderingState]) => {
const state = useMapStore.getState();
const mapRef = getMapRef()
const mapRef = getMapRef();
const setMapLock = state.setMapLock;

if (!mapRef || mapRenderingState !== "loaded") {
Expand Down Expand Up @@ -91,10 +96,39 @@ export const getRenderSubscriptions = (useMapStore: typeof _useMapStore) => {
{ equalityFn: shallowCompareArray },
);

const _updateMapCursor = useMapStore.subscribe<MapStore["activeTool"]>(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PP: This could also be in the map component and use tailwind cursor-x properties

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this suggestions but I'm sort of in a hurry so created new issue #145 so we can do this later

(state) => state.activeTool,
(activeTool) => {
const mapRef = useMapStore.getState().getMapRef();
if (!mapRef) return;

let cursor;
switch (activeTool) {
case "pan":
cursor = "";
break;
case "brush":
cursor = "pointer";
break;
case "eraser":
cursor = "pointer";
break;
case "shatter":
cursor = "crosshair";
useMapStore.getState().setPaintFunction(getFeatureUnderCursor);
break;
default:
cursor = "";
}
mapRef.getCanvas().style.cursor = cursor;
},
);

return [
addLayerSubMapDocument,
_shatterMapSideEffectRender,
_hoverMapSideEffectRender,
_zoneAssignmentMapSideEffectRender,
_updateMapCursor,
];
};
38 changes: 33 additions & 5 deletions app/src/app/utils/events/mapEvents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,30 @@ import {
BLOCK_HOVER_LAYER_ID,
BLOCK_HOVER_LAYER_ID_CHILD,
} from "@constants/layers";
import { ActiveTool } from "@/app/constants/types";

/*
MapEvent handling; these functions are called by the event listeners in the MapComponent
*/

/**
* Get the layer IDs to paint based on whether we have
* a shatterable map (based on whether a child layer is
* present) and the active tool. If the active tool is
* shatter, we only want to paint the shatterable layer.
*
* @param child_layer - string | undefined | null, the child layer
* @param activeTool - ActiveTool, the active tool
* @returns string[], the layer IDs to paint
*/
function getLayerIdsToPaint(
child_layer: string | undefined | null,
activeTool: ActiveTool,
) {
if (activeTool === "shatter") {
return [BLOCK_HOVER_LAYER_ID];
}

*/
function getLayerIdsToPaint(child_layer: string | undefined | null) {
return child_layer
? [BLOCK_HOVER_LAYER_ID, BLOCK_HOVER_LAYER_ID_CHILD]
: [BLOCK_HOVER_LAYER_ID];
Expand All @@ -41,9 +56,13 @@ export const handleMapClick = (
const mapStore = useMapStore.getState();
const activeTool = mapStore.activeTool;
const sourceLayer = mapStore.mapDocument?.parent_layer;
const handleShatter = mapStore.handleShatter;

if (activeTool === "brush" || activeTool === "eraser") {
const paintLayers = getLayerIdsToPaint(mapStore.mapDocument?.child_layer);
const paintLayers = getLayerIdsToPaint(
mapStore.mapDocument?.child_layer,
activeTool,
);
const selectedFeatures = mapStore.paintFunction(
map,
e,
Expand All @@ -57,6 +76,12 @@ export const handleMapClick = (
SelectZoneAssignmentFeatures(mapStore);
});
}
} else if (activeTool === "shatter") {
const documentId = mapStore.mapDocument?.document_id;
const featureId = e.features?.[0].id?.toString();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PP: Highlight on mouse move? Eg. Select features, mapStore.setHoveredFeatures(features[0])

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added

if (documentId && featureId) {
handleShatter(documentId, [featureId]);
}
} else {
// tbd, for pan mode - is there an info mode on click?
}
Expand Down Expand Up @@ -129,15 +154,18 @@ export const handleMapMouseMove = (
const setHoverFeatures = mapStore.setHoverFeatures;
const isPainting = mapStore.isPainting;
const sourceLayer = mapStore.mapDocument?.parent_layer;
const paintLayers = getLayerIdsToPaint(mapStore.mapDocument?.child_layer);
const paintLayers = getLayerIdsToPaint(
mapStore.mapDocument?.child_layer,
activeTool,
);
const selectedFeatures = mapStore.paintFunction(
map,
e,
mapStore.brushSize,
paintLayers,
);
const isBrushingTool =
sourceLayer && ["brush", "eraser"].includes(activeTool);
sourceLayer && ["brush", "eraser", "shatter"].includes(activeTool);
if (isBrushingTool) {
setHoverFeatures(selectedFeatures);
}
Expand Down
Loading
Loading