From fe2a16e694e0ed238265a142d6dd17ca88269c6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Prod=27homme?= Date: Mon, 11 Nov 2024 09:15:30 +0100 Subject: [PATCH 1/2] =?UTF-8?q?feat(cms):=20Add=20legend=20type=20?= =?UTF-8?q?=E2=80=9Cscale=E2=80=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/types/generated/strapi.schemas.ts | 9 +++++ .../sync/admin-role.strapi-super-admin.json | 6 +++ ...onfiguration_components##legend.items.json | 38 +++++++++++++++++++ cms/src/components/legend/items.json | 7 ++++ cms/src/components/legend/legend-config.json | 3 +- .../1.0.0/full_documentation.json | 29 ++++++++++++-- cms/types/generated/components.d.ts | 10 ++++- 7 files changed, 96 insertions(+), 6 deletions(-) diff --git a/client/src/types/generated/strapi.schemas.ts b/client/src/types/generated/strapi.schemas.ts index e49b888..cfa4261 100644 --- a/client/src/types/generated/strapi.schemas.ts +++ b/client/src/types/generated/strapi.schemas.ts @@ -1001,12 +1001,15 @@ export const LegendLegendConfigComponentType = { basic: 'basic', choropleth: 'choropleth', gradient: 'gradient', + scale: 'scale', } as const; export type LegendLegendConfigComponentItemsItem = { color?: string; + group?: string; id?: number; pattern?: string; + size?: number; value?: string; }; @@ -1225,12 +1228,15 @@ export const LayerDatasetDataAttributesLayersDataItemAttributesLegendConfigType basic: 'basic', choropleth: 'choropleth', gradient: 'gradient', + scale: 'scale', } as const; export type LayerDatasetDataAttributesLayersDataItemAttributesLegendConfigItemsItem = { color?: string; + group?: string; id?: number; pattern?: string; + size?: number; value?: string; }; @@ -1598,12 +1604,15 @@ export const DatasetLayersDataItemAttributesLegendConfigType = { basic: 'basic', choropleth: 'choropleth', gradient: 'gradient', + scale: 'scale', } as const; export type DatasetLayersDataItemAttributesLegendConfigItemsItem = { color?: string; + group?: string; id?: number; pattern?: string; + size?: number; value?: string; }; diff --git a/cms/config/sync/admin-role.strapi-super-admin.json b/cms/config/sync/admin-role.strapi-super-admin.json index baad72d..52d7c6e 100644 --- a/cms/config/sync/admin-role.strapi-super-admin.json +++ b/cms/config/sync/admin-role.strapi-super-admin.json @@ -69,6 +69,8 @@ "legend_config.items.color", "legend_config.items.value", "legend_config.items.pattern", + "legend_config.items.size", + "legend_config.items.group", "legend_config.unit", "dataset", "download_link" @@ -97,6 +99,8 @@ "legend_config.items.color", "legend_config.items.value", "legend_config.items.pattern", + "legend_config.items.size", + "legend_config.items.group", "legend_config.unit", "dataset", "download_link" @@ -118,6 +122,8 @@ "legend_config.items.color", "legend_config.items.value", "legend_config.items.pattern", + "legend_config.items.size", + "legend_config.items.group", "legend_config.unit", "dataset", "download_link" diff --git a/cms/config/sync/core-store.plugin_content_manager_configuration_components##legend.items.json b/cms/config/sync/core-store.plugin_content_manager_configuration_components##legend.items.json index 3fa2619..00f89af 100644 --- a/cms/config/sync/core-store.plugin_content_manager_configuration_components##legend.items.json +++ b/cms/config/sync/core-store.plugin_content_manager_configuration_components##legend.items.json @@ -60,6 +60,34 @@ "searchable": true, "sortable": true } + }, + "size": { + "edit": { + "label": "size", + "description": "Only for legends of type “scale”", + "placeholder": "", + "visible": true, + "editable": true + }, + "list": { + "label": "size", + "searchable": true, + "sortable": true + } + }, + "group": { + "edit": { + "label": "group", + "description": "Only for legends of type “scale”", + "placeholder": "", + "visible": true, + "editable": true + }, + "list": { + "label": "group", + "searchable": true, + "sortable": true + } } }, "layouts": { @@ -85,6 +113,16 @@ "name": "value", "size": 6 } + ], + [ + { + "name": "size", + "size": 4 + }, + { + "name": "group", + "size": 6 + } ] ] }, diff --git a/cms/src/components/legend/items.json b/cms/src/components/legend/items.json index db60822..b92bc9c 100644 --- a/cms/src/components/legend/items.json +++ b/cms/src/components/legend/items.json @@ -16,6 +16,13 @@ }, "pattern": { "type": "string" + }, + "size": { + "type": "integer", + "min": 0 + }, + "group": { + "type": "string" } } } diff --git a/cms/src/components/legend/legend-config.json b/cms/src/components/legend/legend-config.json index 5d59dd3..7636b96 100644 --- a/cms/src/components/legend/legend-config.json +++ b/cms/src/components/legend/legend-config.json @@ -11,7 +11,8 @@ "enum": [ "basic", "choropleth", - "gradient" + "gradient", + "scale" ], "required": true }, diff --git a/cms/src/extensions/documentation/documentation/1.0.0/full_documentation.json b/cms/src/extensions/documentation/documentation/1.0.0/full_documentation.json index e53f428..25e9008 100644 --- a/cms/src/extensions/documentation/documentation/1.0.0/full_documentation.json +++ b/cms/src/extensions/documentation/documentation/1.0.0/full_documentation.json @@ -14,7 +14,7 @@ "name": "Apache 2.0", "url": "https://www.apache.org/licenses/LICENSE-2.0.html" }, - "x-generation-date": "2024-11-08T08:14:51.291Z" + "x-generation-date": "2024-11-11T08:14:01.299Z" }, "x-strapi-config": { "path": "/documentation", @@ -244,7 +244,8 @@ "enum": [ "basic", "choropleth", - "gradient" + "gradient", + "scale" ] }, "items": { @@ -263,6 +264,12 @@ }, "pattern": { "type": "string" + }, + "size": { + "type": "integer" + }, + "group": { + "type": "string" } } } @@ -1094,7 +1101,8 @@ "enum": [ "basic", "choropleth", - "gradient" + "gradient", + "scale" ] }, "items": { @@ -1113,6 +1121,12 @@ }, "pattern": { "type": "string" + }, + "size": { + "type": "integer" + }, + "group": { + "type": "string" } } } @@ -1717,7 +1731,8 @@ "enum": [ "basic", "choropleth", - "gradient" + "gradient", + "scale" ] }, "items": { @@ -1736,6 +1751,12 @@ }, "pattern": { "type": "string" + }, + "size": { + "type": "integer" + }, + "group": { + "type": "string" } } } diff --git a/cms/types/generated/components.d.ts b/cms/types/generated/components.d.ts index e6ef569..09626ca 100644 --- a/cms/types/generated/components.d.ts +++ b/cms/types/generated/components.d.ts @@ -7,7 +7,7 @@ export interface LegendLegendConfig extends Schema.Component { description: ''; }; attributes: { - type: Attribute.Enumeration<['basic', 'choropleth', 'gradient']> & + type: Attribute.Enumeration<['basic', 'choropleth', 'gradient', 'scale']> & Attribute.Required; items: Attribute.Component<'legend.items', true>; unit: Attribute.String; @@ -24,6 +24,14 @@ export interface LegendItems extends Schema.Component { color: Attribute.String & Attribute.Required; value: Attribute.String; pattern: Attribute.String; + size: Attribute.Integer & + Attribute.SetMinMax< + { + min: 0; + }, + number + >; + group: Attribute.String; }; } From 17fad026660a8237d5d64461c37efd3c0432e15f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Prod=27homme?= Date: Mon, 11 Nov 2024 10:25:52 +0100 Subject: [PATCH 2/2] feat(client): Implement scale legend --- .../src/components/map/legend/item/index.tsx | 2 + .../map/legend/item/scale-legend.tsx | 113 ++++++++++++++++++ 2 files changed, 115 insertions(+) create mode 100644 client/src/components/map/legend/item/scale-legend.tsx diff --git a/client/src/components/map/legend/item/index.tsx b/client/src/components/map/legend/item/index.tsx index e5c5ba9..904d23b 100644 --- a/client/src/components/map/legend/item/index.tsx +++ b/client/src/components/map/legend/item/index.tsx @@ -17,6 +17,7 @@ import { LayerSettings } from "@/types/layer"; import BasicLegend from "./basic-legend"; import ChoroplethLegend from "./choropleth-legend"; import GradientLegend from "./gradient-legend"; +import ScaleLegend from "./scale-legend"; interface LegendItemProps { id: number; @@ -130,6 +131,7 @@ const LegendItem = ({ id, settings, sortableAttributes, sortableListeners }: Leg {data.type === "basic" && } {data.type === "choropleth" && } {data.type === "gradient" && } + {data.type === "scale" && } )} diff --git a/client/src/components/map/legend/item/scale-legend.tsx b/client/src/components/map/legend/item/scale-legend.tsx new file mode 100644 index 0000000..412821c --- /dev/null +++ b/client/src/components/map/legend/item/scale-legend.tsx @@ -0,0 +1,113 @@ +import { useMemo } from "react"; + +import useLayerLegend from "@/hooks/use-layer-legend"; +import { cn } from "@/lib/utils"; +import { LegendLegendConfigComponentItemsItem } from "@/types/generated/strapi.schemas"; + +type ScaleLegendProps = ReturnType["data"]; + +const ScaleLegend = (data: ScaleLegendProps) => { + const itemsByGroup = useMemo(() => { + if (!data.items || data.items.length === 0) { + return undefined; + } + + return data.items.reduce( + (res, item) => ({ + ...res, + [item.group ?? ""]: [...(res[item.group ?? ""] ?? []), item].sort( + (itemA, itemB) => (itemB.size ?? 0) - (itemA.size ?? 0), + ), + }), + {} as Record, + ); + }, [data.items]); + + const minMaxValues = useMemo(() => { + if (!itemsByGroup) { + return undefined; + } + + const minValueItems = Object.values(itemsByGroup).find( + (items) => + items[items.length - 1]?.value !== undefined && items[items.length - 1]?.value !== null, + ); + const minValue = minValueItems?.[minValueItems?.length - 1].value; + + const maxValue = Object.values(itemsByGroup).find( + (items) => items[0]?.value !== undefined && items[0]?.value !== null, + )?.[0].value; + + return [minValue, maxValue] as const; + }, [itemsByGroup]); + + if (!itemsByGroup) { + return null; + } + + return ( +
+ {Object.entries(itemsByGroup).map(([key, items], index) => ( +
+
{key}
+ {minMaxValues?.[0] !== undefined && ( +
0, + })} + style={{ + bottom: `${items[0]?.size ?? 0}px`, + }} + /> + )} + {minMaxValues?.[1] !== undefined && ( +
0, + })} + /> + )} +
+ {items.map((item) => ( +
+ ))} +
+
+ ))} + {!!minMaxValues && ( +
+ {minMaxValues[0] !== undefined && ( +
+ {minMaxValues[1]} +
+ )} + {minMaxValues[1] !== undefined && ( +
+ {minMaxValues[0]} +
+ )} +
+ )} +
+ ); +}; + +export default ScaleLegend;