Skip to content

Commit

Permalink
Merge branch 'main' into shattering
Browse files Browse the repository at this point in the history
  • Loading branch information
nofurtherinformation committed Oct 9, 2024
2 parents a0832d4 + 23c1869 commit 746955e
Show file tree
Hide file tree
Showing 14 changed files with 137 additions and 104 deletions.
26 changes: 22 additions & 4 deletions app/src/app/components/sidebar/BrushSizeSelector.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
import { Slider, Flex } from "@radix-ui/themes";
import { Slider, Flex, Heading, Text } from "@radix-ui/themes";
import { useMapStore } from "../../store/mapStore";

/**
* BrushSizeSelector
* Note: right now the brush size is an arbitrary value between
* 1 and 100. This is slightly arbitrary. Should we communicate brush size
* differently or not display the brush size?
*
* @description A slider to select the brush size
* @returns {JSX.Element} The component
*/
export function BrushSizeSelector() {
const brushSize = useMapStore((state) => state.brushSize);
const setBrushSize = useMapStore((state) => state.setBrushSize);
Expand All @@ -11,16 +20,25 @@ export function BrushSizeSelector() {
};

return (
<Flex direction="row" gap="4" maxWidth="300px" style={{alignItems:'center'}}>
<h4>Brush Size</h4>
<Flex direction="row" gap="4" maxWidth="300px" mb="3" align="center">
<Heading
as="h4"
size="2"
weight="regular"
style={{ whiteSpace: "nowrap" }}
>
Brush Size
</Heading>
<Slider
defaultValue={[brushSize]}
size="2"
onValueChange={handleChangeEnd}
min={1}
max={100}
/>
{brushSize}
<Text size="2" as="span" color="gray">
{brushSize}
</Text>
</Flex>
);
}
6 changes: 2 additions & 4 deletions app/src/app/components/sidebar/ColorPicker.jsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
import React, { useState } from "react";
import { palette, color10 } from "../../constants/colors";
import { _colorScheme, colorScheme } from "../../constants/colors";
import { Button } from "@radix-ui/themes";
import { styled } from "@stitches/react";
import * as RadioGroup from "@radix-ui/react-radio-group";
import { blackA } from "@radix-ui/colors";
import { useMapStore } from "../../store/mapStore";

export function ColorPicker() {
const [color, setColor] = useState(null);
const [open, setOpen] = useState(false);
const selectedZone = useMapStore((state) => state.selectedZone);
const setSelectedZone = useMapStore((state) => state.setSelectedZone);
const setZoneAssignments = useMapStore((state) => state.setZoneAssignments);
const accumulatedGeoids = useMapStore((state) => state.accumulatedGeoids);
const resetAccumulatedBlockPopulations = useMapStore((state) => state.resetAccumulatedBlockPopulations);

const colorArray = color10;
const colorArray = colorScheme;
if (!colorArray) return null;
const handleRadioChange = (value) => {
console.log(
Expand Down
2 changes: 1 addition & 1 deletion app/src/app/components/sidebar/MapModeSelector.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export function MapModeSelector() {
const activeTools = [
{ mode: "pan", disabled: false, label: "Pan", icon: <HandIcon /> },
{ mode: "brush", disabled: false, label: "Brush", icon: <Pencil2Icon /> },
{ mode: "erase", disabled: true, label: "Erase", icon: <EraserIcon /> },
{ mode: "eraser", disabled: false, label: "Erase", icon: <EraserIcon /> },
];

const handleRadioChange = (value) => {
Expand Down
8 changes: 6 additions & 2 deletions app/src/app/components/sidebar/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,17 @@ export default function SidebarComponent() {
</Heading>
<GerryDBViewSelector />
<MapModeSelector />
{activeTool === "brush" ? (
{activeTool === "brush" || activeTool === "eraser" ? (
<div>
<ColorPicker />
<BrushSizeSelector />
<PaintByCounty />{" "}
</div>
) : null}
{activeTool === "brush" ? (
<div>
<ColorPicker />
</div>
) : null}
<ResetMapButton />
<Tabs.Root defaultValue="layers">
<Tabs.List>
Expand Down
10 changes: 7 additions & 3 deletions app/src/app/components/sidebar/charts/HorizontalBarChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
YAxis,
Cell,
} from "recharts";
import { color10 } from "@/app/constants/colors";
import { colorScheme } from "@/app/constants/colors";

type TooltipInput = {
active?: boolean;
Expand Down Expand Up @@ -56,7 +56,8 @@ export const HorizontalBar = () => {
</Heading>
<ResponsiveContainer
width="100%"
height={color10.length * 18}
// should this instead be set based on the target number of zones? see https://github.com/districtr/districtr-v2/issues/92
height={colorScheme.length * 18}
minHeight="200px"
>
<BarChart
Expand All @@ -78,7 +79,10 @@ export const HorizontalBar = () => {
{mapMetrics.data
.sort((a, b) => a.zone - b.zone)
.map((entry, index) => (
<Cell key={`cell-${index}`} fill={color10[entry.zone - 1]} />
<Cell
key={`cell-${index}`}
fill={colorScheme[entry.zone - 1]}
/>
))}
</Bar>
</BarChart>
Expand Down
102 changes: 43 additions & 59 deletions app/src/app/constants/colors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,63 +27,47 @@ import {
sky,
} from "@radix-ui/colors";

export const palette = {
colors: {
...(tomato as object),
...(red as object),
...(ruby as object),
...(crimson as object),
...(pink as object),
...(plum as object),
...(purple as object),
...(violet as object),
...(iris as object),
...(indigo as object),
...(blue as object),
...(cyan as object),
...(teal as object),
...(jade as object),
...(green as object),
...(grass as object),
...(orange as object),
...(amber as object),
...(yellow as object),
...(gold as object),
...(brown as object),
...(bronze as object),
...(gray as object),
...(mint as object),
...(lime as object),
...(sky as object),
} as { [key: string]: { [key: string]: string } },
};

// bright colors!
export const color10 = [
tomato.tomato10,
red.red10,
ruby.ruby10,
crimson.crimson10,
pink.pink10,
plum.plum10,
purple.purple10,
violet.violet10,
iris.iris10,
indigo.indigo10,
blue.blue10,
cyan.cyan10,
teal.teal10,
jade.jade10,
green.green10,
grass.grass10,
orange.orange10,
amber.amber10,
yellow.yellow10,
gold.gold10,
brown.brown10,
bronze.bronze10,
gray.gray10,
mint.mint10,
lime.lime10,
sky.sky10,
export const colorScheme = [
"#0099cd",
"#ffca5d",
"#00cd99",
"#99cd00",
"#cd0099",
"#aa44ef", // lighter, req from San Diego
// Color brewer:
"#8dd3c7",
"#bebada",
"#fb8072",
"#80b1d3",
"#fdb462",
"#b3de69",
"#fccde5",
"#bc80bd",
"#ccebc5",
"#ffed6f",
"#ffffb3",
// other color brewer scheme:
"#a6cee3",
"#1f78b4",
"#b2df8a",
"#33a02c",
"#fb9a99",
"#e31a1c",
"#fdbf6f",
"#ff7f00",
"#cab2d6",
"#6a3d9a",
"#b15928",
// random material design colors:
"#64ffda",
"#00B8D4",
"#A1887F",
"#76FF03",
"#DCE775",
"#B388FF",
"#FF80AB",
"#D81B60",
"#26A69A",
"#FFEA00",
"#6200EA",
];
14 changes: 9 additions & 5 deletions app/src/app/constants/layers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import { MutableRefObject } from "react";
import { Map } from "maplibre-gl";
import { getBlocksSource } from "./sources";
import { DocumentObject } from "../utils/api/apiHandlers";
import { color10 } from "./colors";
import { MapStore, useMapStore } from "../store/mapStore";
import { colorScheme } from "./colors";

export const BLOCK_SOURCE_ID = "blocks";
export const BLOCK_LAYER_ID = "blocks";
Expand Down Expand Up @@ -46,10 +46,14 @@ export const COUNTY_LAYER_IDS: string[] = [
export const LABELS_BREAK_LAYER_ID = "places_subplace";

const colorStyleBaseline: any[] = ["case"];
export const ZONE_ASSIGNMENT_STYLE_DYNAMIC = color10.reduce((val, color, i) => {
val.push(["==", ["feature-state", "zone"], i + 1], color); // 1-indexed per mapStore.ts
return val;
}, colorStyleBaseline);

export const ZONE_ASSIGNMENT_STYLE_DYNAMIC = colorScheme.reduce(
(val, color, i) => {
val.push(["==", ["feature-state", "zone"], i + 1], color); // 1-indexed per mapStore.ts
return val;
},
colorStyleBaseline
);
ZONE_ASSIGNMENT_STYLE_DYNAMIC.push("#cecece");

// cast the above as an ExpressionSpecification
Expand Down
2 changes: 1 addition & 1 deletion app/src/app/constants/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { MapOptions, MapLibreEvent } from "maplibre-gl";

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

export type GEOID = string;

Expand Down
4 changes: 1 addition & 3 deletions app/src/app/store/mapStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,7 @@ export interface MapStore {
setSelectedZone: (zone: Zone) => void;
accumulatedBlockPopulations: Map<string, number>;
resetAccumulatedBlockPopulations: () => void;
// TODO: Add parent/child status to zoneAssignments
// Probably, something like Map<string, { zone: number, child?: boolean }>
zoneAssignments: Map<string, number>; // geoid -> zone
zoneAssignments: Map<string, Zone>; // geoid -> zone
setZoneAssignments: (zone: Zone, gdbPaths: Set<GDBPath>) => void;
loadZoneAssignments: (assigments: Assignment[]) => void;
resetZoneAssignments: () => void;
Expand Down
21 changes: 16 additions & 5 deletions app/src/app/utils/events/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { BLOCK_SOURCE_ID } from "@/app/constants/layers";
import { MutableRefObject } from "react";
import { Map, MapGeoJSONFeature } from "maplibre-gl";
import { debounce } from "lodash";
import { Zone } from "@/app/constants/types";
import { MapStore } from "@/app/store/mapStore";

/**
Expand All @@ -11,7 +12,7 @@ import { MapStore } from "@/app/store/mapStore";
* @returns void - but updates the zoneAssignments and zonePopulations in the store
*/
const debouncedSetZoneAssignments = debounce(
(mapStoreRef: MapStore, selectedZone: number, geoids: Set<string>) => {
(mapStoreRef: MapStore, selectedZone: Zone, geoids: Set<string>) => {
mapStoreRef.setZoneAssignments(selectedZone, geoids);

const accumulatedBlockPopulations = mapStoreRef.accumulatedBlockPopulations;
Expand Down Expand Up @@ -41,21 +42,31 @@ export const SelectMapFeatures = (
map: MutableRefObject<Map | null>,
mapStoreRef: MapStore,
) => {
let {
accumulatedGeoids,
accumulatedBlockPopulations,
activeTool,
selectedZone,
} = mapStoreRef;
if (activeTool === "eraser") {
selectedZone = null;
}

features?.forEach((feature) => {
map.current?.setFeatureState(
{
source: BLOCK_SOURCE_ID,
id: feature?.id ?? undefined,
sourceLayer: feature.sourceLayer,
},
{ selected: true, zone: mapStoreRef.selectedZone },
{ selected: true, zone: selectedZone },
);
});
if (features?.length) {
features.forEach((feature) => {
mapStoreRef.accumulatedGeoids.add(feature.properties?.path);
accumulatedGeoids.add(feature.properties?.path);

mapStoreRef.accumulatedBlockPopulations.set(
accumulatedBlockPopulations.set(
feature.properties?.path,
feature.properties?.total_pop,
);
Expand All @@ -80,7 +91,7 @@ export const SelectZoneAssignmentFeatures = (mapStoreRef: MapStore) => {
if (accumulatedGeoids?.size) {
debouncedSetZoneAssignments(
mapStoreRef,
mapStoreRef.selectedZone,
mapStoreRef.activeTool === "brush" ? mapStoreRef.selectedZone : null,
mapStoreRef.accumulatedGeoids,
);
}
Expand Down
14 changes: 3 additions & 11 deletions app/src/app/utils/events/mapEvents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,11 @@ export const handleMapClick = (
if (activeTool === "brush" || activeTool === "eraser") {
const selectedFeatures = mapStore.paintFunction(map, e, mapStore.brushSize);

if (activeTool === "brush" && sourceLayer) {
if (sourceLayer) {
// select on both the map object and the store
SelectMapFeatures(selectedFeatures, map, mapStore).then(() => {
SelectZoneAssignmentFeatures(mapStore);
});
} else if (activeTool === "eraser") {
// erase features
// TODO: implement eraser
}
} else {
// tbd, for pan mode - is there an info mode on click?
Expand All @@ -55,7 +52,7 @@ export const handleMapMouseUp = (
const activeTool = mapStore.activeTool;
const isPainting = mapStore.isPainting;

if (activeTool === "brush" && isPainting) {
if ((activeTool === "brush" || activeTool === "eraser") && isPainting) {
// set isPainting to false
mapStore.setIsPainting(false);
SelectZoneAssignmentFeatures(mapStore);
Expand All @@ -75,12 +72,7 @@ export const handleMapMouseDown = (
} else if (activeTool === "brush" || activeTool === "eraser") {
// disable drag pan
map.current?.dragPan.disable();
if (activeTool === "brush") {
mapStore.setIsPainting(true);
return;
} else if (activeTool === "eraser") {
// erase features tbd
}
mapStore.setIsPainting(true);
}
};

Expand Down
Loading

0 comments on commit 746955e

Please sign in to comment.