Skip to content

Commit

Permalink
fix: cadastre superposition parcelles (#973)
Browse files Browse the repository at this point in the history
  • Loading branch information
fufeck authored Jan 7, 2025
1 parent c4b5663 commit 3c7a870
Show file tree
Hide file tree
Showing 4 changed files with 131 additions and 78 deletions.
19 changes: 10 additions & 9 deletions components/bal/numero-editor/select-parcelles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ function SelectParcelles({
highlightedParcelles,
setHighlightedParcelles,
setIsParcelleSelectionEnabled,
hoveredParcelle,
handleHoveredParcelle,
handleParcelle,
hoveredParcelles,
handleHoveredParcelles,
handleParcelles,
} = useContext(ParcellesContext);
const addressType = isToponyme ? "toponyme" : "numéro";

Expand All @@ -53,17 +53,18 @@ function SelectParcelles({
{highlightedParcelles.length > 0 ? (
<Pane display="grid" gridTemplateColumns="1fr 1fr 1fr">
{highlightedParcelles.map((parcelle) => {
const isHovered = parcelle === hoveredParcelle?.id;

const isHovered = hoveredParcelles.some(
({ id }) => id === parcelle
);
return (
<Badge
key={parcelle}
isInteractive
color={parcelle === hoveredParcelle?.id ? "red" : "green"}
color={isHovered ? "red" : "green"}
margin={4}
onClick={() => handleParcelle(parcelle)}
onMouseEnter={() => handleHoveredParcelle({ id: parcelle })}
onMouseLeave={() => handleHoveredParcelle(null)}
onClick={() => handleParcelles([parcelle])}
onMouseEnter={() => handleHoveredParcelles([parcelle])}
onMouseLeave={() => handleHoveredParcelles([])}
>
{parcelle}
{isHovered && (
Expand Down
21 changes: 15 additions & 6 deletions components/map/hooks/hovered.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { LAYERS_SOURCE } from "@/components/map/layers/tiles";

function useHovered(map) {
const hovered = useRef<{ id; source; sourceLayer }>();
const { handleHoveredParcelle } = useContext(ParcellesContext);
const { handleHoveredParcelles } = useContext(ParcellesContext);
const [featureHovered, setFeatureHovered] = useState(null);

const handleRelatedNumerosPoints = (map, idVoie, isHovered) => {
Expand Down Expand Up @@ -61,10 +61,19 @@ function useHovered(map) {
(event) => {
const feature = event && event.features && event.features[0];
if (feature) {
const { source, id, sourceLayer, properties } = feature;
const { source, id, sourceLayer } = feature;

const parcelles = event.features.filter(
({ source, sourceLayer, layer }) =>
source === "cadastre" &&
sourceLayer === "parcelles" &&
layer?.id === "parcelles-fill"
);

if (source === "cadastre") {
handleHoveredParcelle({ featureId: id, id: properties.id });
handleHoveredParcelles(
parcelles.map(({ properties }) => properties.id)
);
}

if (hovered.current) {
Expand Down Expand Up @@ -94,7 +103,7 @@ function useHovered(map) {
}
}
},
[map, handleHoveredParcelle]
[map, handleHoveredParcelles]

Check warning on line 106 in components/map/hooks/hovered.ts

View workflow job for this annotation

GitHub Actions / build (22.x)

React Hook useCallback has a missing dependency: 'handleRelatedFeatures'. Either include it or remove the dependency array
);

const handleMouseLeave = useCallback(() => {
Expand All @@ -105,12 +114,12 @@ function useHovered(map) {
setFeatureHovered(null);

if (source === "cadastre") {
handleHoveredParcelle(null);
handleHoveredParcelles([]);
}
}

hovered.current = null;
}, [map, handleHoveredParcelle]);
}, [map, handleHoveredParcelles]);

Check warning on line 122 in components/map/hooks/hovered.ts

View workflow job for this annotation

GitHub Actions / build (22.x)

React Hook useCallback has a missing dependency: 'handleRelatedFeatures'. Either include it or remove the dependency array

return [handleHover, handleMouseLeave, featureHovered];
}
Expand Down
15 changes: 11 additions & 4 deletions components/map/map.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ function Map({ commune, isAddressFormOpen, handleAddressForm }: MapProps) {
isMapLoaded,
showToponymes,
} = useContext(MapContext);
const { isParcelleSelectionEnabled, handleParcelle } =
const { isParcelleSelectionEnabled, handleParcelles } =
useContext(ParcellesContext);
const { isMobile } = useContext(LayoutContext);

Expand Down Expand Up @@ -211,8 +211,15 @@ function Map({ commune, isAddressFormOpen, handleAddressForm }: MapProps) {
});
const feature = features && features[0];

if (feature?.source === "cadastre") {
handleParcelle(feature.properties.id);
const parcelles = features.filter(
({ source, sourceLayer, layer }) =>
source === "cadastre" &&
sourceLayer === "parcelles" &&
layer?.id === "parcelles-fill"
);

if (parcelles.length > 0) {
handleParcelles(parcelles.map(({ properties }) => properties.id));
} else if (
feature &&
!isEditing &&
Expand All @@ -231,7 +238,7 @@ function Map({ commune, isAddressFormOpen, handleAddressForm }: MapProps) {

setIsContextMenuDisplayed(null);
},
[router, balId, setEditingId, isEditing, voie, handleParcelle]
[router, balId, setEditingId, isEditing, voie, handleParcelles]

Check warning on line 241 in components/map/map.tsx

View workflow job for this annotation

GitHub Actions / build (22.x)

React Hook useCallback has a missing dependency: 'map'. Either include it or remove the dependency array
);

useEffect(() => {
Expand Down
154 changes: 95 additions & 59 deletions contexts/parcelles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import React, {
useMemo,
useRef,
} from "react";
import { xor } from "lodash";
import type { Map as MaplibreMap, ExpressionSpecification } from "maplibre-gl";

import {
Expand All @@ -23,11 +24,9 @@ interface ParcellesContextType {
setHighlightedParcelles: React.Dispatch<React.SetStateAction<string[]>>;
isParcelleSelectionEnabled: boolean;
setIsParcelleSelectionEnabled: React.Dispatch<React.SetStateAction<boolean>>;
hoveredParcelle: { id: string; featureId?: string } | null;
handleHoveredParcelle: (
value: { id: string; featureId?: string } | null
) => void;
handleParcelle: (value: string) => void;
hoveredParcelles: { id: string; featureId?: string }[];
handleHoveredParcelles: (parcelleHoveredIds: string[]) => void;
handleParcelles: (parcellesToggle: string[]) => void;
setShowSelectedParcelles?: React.Dispatch<React.SetStateAction<boolean>>;
handleSetFeatureState: (
parcelleId: string,
Expand Down Expand Up @@ -55,55 +54,71 @@ export function ParcellesContextProvider(props: ChildrenProps) {
const [showSelectedParcelles, setShowSelectedParcelles] =
useState<boolean>(true);
const [isDiffMode, setIsDiffMode] = useState<boolean>(false);
const [hoveredParcelle, setHoveredParcelle] = useState<{
id: string;
featureId?: string;
} | null>(null);
const [hoveredParcelles, setHoveredParcelles] = useState<
{
id: string;
featureId?: string;
}[]
>([]);
const [isParcelleSelectionEnabled, setIsParcelleSelectionEnabled] =
useState<boolean>(false);
const [highlightedParcelles, setHighlightedParcelles] = useState<string[]>(
[]
);

const prevHoveredParcelle = useRef<string | undefined>();
const prevHoveredParcelle = useRef<string[]>([]);

const handleHoveredParcelle = useCallback(
(hovered: { id: string; featureId?: string } | null) => {
if (map && hovered) {
const featureId: string | undefined =
hovered.featureId || getFeatureId(map, hovered.id);
const setHoverFeature = useCallback(
(featureId: string, hover: boolean) => {
map.setFeatureState(
{
source: CADASTRE_SOURCE,
sourceLayer: CADASTRE_SOURCE_LAYER.PARCELLES,
id: featureId,
},
{ hover }
);
},
[map]
);

if (!hovered.featureId && isCadastreDisplayed) {
// Handle parcelle from side menu
map.setFeatureState(
{
source: CADASTRE_SOURCE,
sourceLayer: CADASTRE_SOURCE_LAYER.PARCELLES,
id: featureId,
},
{ hover: true }
);
prevHoveredParcelle.current = featureId;
const handleHoveredParcelles = useCallback(
(parcelleHoveredIds: string[]) => {
if (map) {
// // ON ENLEVE LES HOVERED QUI NE LE SONT PLUS
const oldHovereds: string[] = prevHoveredParcelle.current.filter(
(id) => !parcelleHoveredIds.includes(id)
);
for (const oldHovered of oldHovereds) {
const featureId: string = getFeatureId(map, oldHovered);
setHoverFeature(featureId, false);
}

setHoveredParcelle({ id: hovered.id, featureId });
} else {
if (prevHoveredParcelle?.current && isCadastreDisplayed) {
map.setFeatureState(
{
source: CADASTRE_SOURCE,
sourceLayer: CADASTRE_SOURCE_LAYER.PARCELLES,
id: prevHoveredParcelle.current,
},
{ hover: false }
);
prevHoveredParcelle.current = null;
// ON AJOUTE ENSUITE LES NOUVEAU HOVERED
const newHovereds: string[] = parcelleHoveredIds.filter(
(id) => !prevHoveredParcelle.current.includes(id)
);
for (const newHovered of newHovereds) {
const featureId: string = getFeatureId(map, newHovered);
setHoverFeature(featureId, true);
}

setHoveredParcelle(null);
prevHoveredParcelle.current = parcelleHoveredIds;
const newoveredParcelles = parcelleHoveredIds.map((id) => ({
id,
featureId: getFeatureId(map, id),
}));
setHoveredParcelles(newoveredParcelles);
} else if (
prevHoveredParcelle?.current?.length > 0 &&
isCadastreDisplayed
) {
for (const featureId of prevHoveredParcelle.current) {
setHoverFeature(featureId, false);
}
prevHoveredParcelle.current = [];
setHoveredParcelles([]);
}
},
[map, isCadastreDisplayed]
[map, isCadastreDisplayed, setHoverFeature]
);

const handleSetFeatureState = useCallback(
Expand All @@ -127,20 +142,41 @@ export function ParcellesContextProvider(props: ChildrenProps) {
[map]
);

const handleParcelle = useCallback(
(parcelle: string) => {
if (isParcelleSelectionEnabled) {
setHighlightedParcelles((parcelles: string[]) => {
if (parcelles.includes(parcelle)) {
return parcelles.filter((id) => id !== parcelle);
}
const filterHighlightedWithParcelles = useCallback(
(selectedParcelles) => {
if (selectedParcelles.length > 0) {
const exps: ExpressionSpecification[] = selectedParcelles.map((id) => [
"==",
["get", "id"],
id,
]);
map.setFilter(CADASTRE_LAYER.PARCELLE_HIGHLIGHTED, ["any", ...exps]);
} else {
map.setFilter(CADASTRE_LAYER.PARCELLE_HIGHLIGHTED, [
"==",
["get", "id"],
"",
]);
}
},
[map]
);

return [...parcelles, parcelle];
});
handleHoveredParcelle(null);
const handleParcelles = useCallback(
(parcellesToggle: string[]) => {
if (isParcelleSelectionEnabled) {
const highlightParcelles = xor(parcellesToggle, highlightedParcelles);
setHighlightedParcelles(highlightParcelles);
filterHighlightedWithParcelles(highlightParcelles);
handleHoveredParcelles([]);
}
},
[isParcelleSelectionEnabled, handleHoveredParcelle]
[
isParcelleSelectionEnabled,
highlightedParcelles,
filterHighlightedWithParcelles,
handleHoveredParcelles,
]
);

const toggleCadastreVisibility = useCallback(() => {
Expand Down Expand Up @@ -271,9 +307,9 @@ export function ParcellesContextProvider(props: ChildrenProps) {
setHighlightedParcelles,
isParcelleSelectionEnabled,
setIsParcelleSelectionEnabled,
handleParcelle,
hoveredParcelle,
handleHoveredParcelle,
handleParcelles,
hoveredParcelles,
handleHoveredParcelles,
setShowSelectedParcelles,
handleSetFeatureState,
isDiffMode,
Expand All @@ -283,9 +319,9 @@ export function ParcellesContextProvider(props: ChildrenProps) {
highlightedParcelles,
setHighlightedParcelles,
isParcelleSelectionEnabled,
handleParcelle,
hoveredParcelle,
handleHoveredParcelle,
handleParcelles,
hoveredParcelles,
handleHoveredParcelles,
setShowSelectedParcelles,
handleSetFeatureState,
isDiffMode,
Expand Down

0 comments on commit 3c7a870

Please sign in to comment.