Skip to content

Commit

Permalink
Merge pull request #1077 from MTES-MCT/fix-map-building-colors
Browse files Browse the repository at this point in the history
Fix building colors on the map
  • Loading branch information
Falinor authored Jan 7, 2025
2 parents 730f02f + db8cae2 commit 21b89ea
Show file tree
Hide file tree
Showing 12 changed files with 701 additions and 35 deletions.
4 changes: 3 additions & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"version": "0.0.1",
"scripts": {
"clean": "rimraf build",
"icons": "only-include-used-icons",
"icons": "only-include-used-icons && tsx src/scripts/generate-building-images.ts",
"build": "yarn clean && yarn icons && tsc -b tsconfig.build.json && DISABLE_ESLINT_PLUGIN=true craco build",
"dev": "yarn icons && DISABLE_ESLINT_PLUGIN=true craco start",
"test": "DISABLE_ESLINT_PLUGIN=true craco test",
Expand Down Expand Up @@ -100,6 +100,8 @@
"react-dev-utils": "^12.0.1",
"rimraf": "^5.0.10",
"sass": "^1.79.4",
"sharp": "^0.33.5",
"tsx": "^4.19.2",
"typescript": "^5.6.2",
"undici": "^6.19.8"
}
Expand Down
1 change: 1 addition & 0 deletions frontend/public/map/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
square-fill-*.png
Empty file added frontend/public/map/.gitkeep
Empty file.
Binary file removed frontend/public/map/square-fill.png
Binary file not shown.
31 changes: 16 additions & 15 deletions frontend/src/components/Map/BuildingPoints.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { FilterSpecification } from '@maplibre/maplibre-gl-style-spec';
import { Layer } from 'react-map-gl/maplibre';

import { BUILDING_DARK } from './Icon';
import statusColors from './status-colors';
import { FilterSpecification } from '@maplibre/maplibre-gl-style-spec';
import { HousingStatus } from '../../models/HousingState';

interface Props {
filter?: FilterSpecification;
Expand All @@ -17,21 +16,23 @@ function BuildingPoints(props: Props) {
filter={props.filter}
layout={{
'icon-allow-overlap': true,
'icon-image': BUILDING_DARK,
'icon-size': 0.75
}}
paint={{
// @ts-expect-error: match expects 4 starting arguments
'icon-color': [
'icon-image': [
'match',
['get', 'status', ['at', 0, ['get', 'housingList']]],
// Apply a text color depending on the housing status
...statusColors.textColors.flat(),
statusColors.defaultBackgroundColor
HousingStatus.Waiting,
`square-fill-${HousingStatus.Waiting}`,
HousingStatus.FirstContact,
`square-fill-${HousingStatus.FirstContact}`,
HousingStatus.InProgress,
`square-fill-${HousingStatus.InProgress}`,
HousingStatus.Completed,
`square-fill-${HousingStatus.Completed}`,
HousingStatus.Blocked,
`square-fill-${HousingStatus.Blocked}`,
// Default value
`square-fill-${HousingStatus.NeverContacted}`
],
'icon-halo-color': statusColors.defaultTextColor,
'icon-halo-width': 4,
'icon-halo-blur': 0
'icon-size': 1
}}
source={props.source}
/>
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/components/Map/HousingPoints.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ function HousingPoints(props: Props) {
['get', 'status', ['at', 0, ['get', 'housingList']]],
// Apply a stroke color to the circle
// depending on the housing status
...statusColors.textColors.flat(),
statusColors.defaultTextColor
...statusColors.borderColors.flat(),
statusColors.defaultBorderColor
]
}}
source={props.source}
Expand Down
3 changes: 1 addition & 2 deletions frontend/src/components/Map/Icon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ export const BUILDING_DARK = 'building-dark';
export async function loadIcon(map: MapRef, path: string, id: string) {
const response = await map.loadImage(path);
map.addImage(id, response.data, {
sdf: true
sdf: false
});

}
31 changes: 25 additions & 6 deletions frontend/src/components/Map/Map.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { GeoPerimeter } from '../../models/GeoPerimeter';
import Perimeters from './Perimeters';
import MapControls from './MapControls';
import Points from './Points';
import { BUILDING_DARK, loadIcon } from './Icon';
import { useMapImage } from '../../hooks/useMapImage';

const STYLE = {
title: 'Carte',
Expand Down Expand Up @@ -86,11 +86,30 @@ function Map(props: MapProps) {
const excludedPerimeters = props.perimetersExcluded ?? [];
const [showPerimeters, setShowPerimeters] = useState(true);

useEffect(() => {
if (map && !map.hasImage(BUILDING_DARK)) {
loadIcon(map, '/map/square-fill.png', BUILDING_DARK).catch(console.error);
}
}, [map]);
useMapImage({
id: 'square-fill-0',
path: '/map/square-fill-0.png'
});
useMapImage({
id: 'square-fill-1',
path: '/map/square-fill-1.png'
});
useMapImage({
id: 'square-fill-2',
path: '/map/square-fill-2.png'
});
useMapImage({
id: 'square-fill-3',
path: '/map/square-fill-3.png'
});
useMapImage({
id: 'square-fill-4',
path: '/map/square-fill-4.png'
});
useMapImage({
id: 'square-fill-5',
path: '/map/square-fill-5.png'
});

useEffect(() => {
if (map && points.length > 0) {
Expand Down
8 changes: 4 additions & 4 deletions frontend/src/components/Map/status-colors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const backgroundColors = fp.zip(statuses, [
hex.decisions.background.contrast.greenBourgeon.default,
hex.decisions.background.contrast.purpleGlycine.default
]) as NonEmptyArray<[HousingStatus, string]>;
const textColors = fp.zip(statuses, [
const borderColors = fp.zip(statuses, [
hex.decisions.text.label.yellowTournesol.default,
hex.decisions.text.label.blueCumulus.default,
hex.decisions.text.label.orangeTerreBattue.default,
Expand All @@ -27,13 +27,13 @@ const textColors = fp.zip(statuses, [
]) as NonEmptyArray<[HousingStatus, string]>;
const defaultBackgroundColor =
hex.decisions.background.actionHigh.blueFrance.default;
const defaultTextColor = hex.decisions.text.inverted.grey.default;
const defaultBorderColor = hex.decisions.text.inverted.grey.default;

const statusColors = {
defaultBackgroundColor,
defaultTextColor,
defaultBorderColor,
backgroundColors,
textColors
borderColors
};

export default statusColors;
24 changes: 24 additions & 0 deletions frontend/src/hooks/useMapImage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { useMap } from 'react-map-gl/maplibre';
import { useEffect } from 'react';

interface UseMapImageOptions {
id: string;
path: string;
}

export function useMapImage(options: UseMapImageOptions) {
const { housingMap: map } = useMap();

useEffect(() => {
if (map && !map.hasImage(options.id)) {
map
.loadImage(options.path)
.then((response) => {
map.addImage(options.id, response.data, {
sdf: false
});
})
.catch(console.error);
}
}, [map, options.id, options.path]);
}
55 changes: 55 additions & 0 deletions frontend/src/scripts/generate-building-images.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import async from 'async';
import * as path from 'node:path';
import sharp, { Color, OutputInfo } from 'sharp';

import { HousingStatus } from '@zerologementvacant/models';
import statusColors from '../components/Map/status-colors';

const SIZE = 15;
const BORDER_SIZE = 1;

interface CreateImageOptions {
border: Color;
background: Color;
filename: string;
}

const directory = path.join(__dirname, '..', '..', 'public', 'map');

async function createImage(options: CreateImageOptions): Promise<OutputInfo> {
return sharp({
create: {
channels: 3,
background: options.background,
width: SIZE,
height: SIZE
}
})
.extend({
top: BORDER_SIZE,
right: BORDER_SIZE,
bottom: BORDER_SIZE,
left: BORDER_SIZE,
background: options.border
})
.png()
.toFile(path.join(directory, options.filename));
}

createImage({
border: statusColors.defaultBorderColor,
background: statusColors.defaultBackgroundColor,
filename: `square-fill-${HousingStatus.NEVER_CONTACTED}.png`
});

async.forEachOf(
statusColors.borderColors,
async ([status, borderColor], index) => {
const [, backgroundColor] = statusColors.backgroundColors[index as number];
return createImage({
border: borderColor,
background: backgroundColor,
filename: `square-fill-${status}.png`
});
}
);
Loading

0 comments on commit 21b89ea

Please sign in to comment.