From 41e43d49740e082577d70e79fee178b04c7fe55f Mon Sep 17 00:00:00 2001 From: taDuc Date: Wed, 13 May 2026 04:17:22 +0700 Subject: [PATCH] fix: stop use int key in local --- src/app/editor/[id]/page.tsx | 6 +- src/uhm/api/geometries.ts | 33 ++++++++- src/uhm/api/projects.ts | 4 +- .../editor/SelectedGeometryPanel.tsx | 5 +- src/uhm/components/map/mapUtils.ts | 35 +++++---- src/uhm/components/map/useMapLayers.ts | 12 ++- .../lib/editor/project/useProjectCommands.ts | 4 +- src/uhm/lib/editor/snapshot/editorSnapshot.ts | 61 +++++++++++---- src/uhm/lib/map/geo/geoTypeMap.ts | 17 +++++ .../lib/map/styles/geotypes/attack_route.ts | 73 +++--------------- src/uhm/lib/map/styles/geotypes/battle.ts | 46 +++--------- .../lib/map/styles/geotypes/civilization.ts | 45 +++-------- src/uhm/lib/map/styles/geotypes/country.ts | 45 +++-------- .../lib/map/styles/geotypes/defense_line.ts | 40 +++------- src/uhm/lib/map/styles/geotypes/empire.ts | 46 +++--------- .../lib/map/styles/geotypes/invasion_route.ts | 73 +++--------------- src/uhm/lib/map/styles/geotypes/kingdom.ts | 45 +++-------- .../map/styles/geotypes/migration_route.ts | 73 +++--------------- .../lib/map/styles/geotypes/rebellion_zone.ts | 46 +++--------- .../lib/map/styles/geotypes/refugee_route.ts | 74 +++---------------- .../lib/map/styles/geotypes/retreat_route.ts | 74 +++---------------- .../lib/map/styles/geotypes/shipping_route.ts | 74 +++---------------- src/uhm/lib/map/styles/geotypes/state.ts | 46 +++--------- .../lib/map/styles/geotypes/trade_route.ts | 73 +++--------------- src/uhm/lib/map/styles/geotypes/war.ts | 46 +++--------- 25 files changed, 289 insertions(+), 807 deletions(-) diff --git a/src/app/editor/[id]/page.tsx b/src/app/editor/[id]/page.tsx index 9683aa1..6c28e29 100644 --- a/src/app/editor/[id]/page.tsx +++ b/src/app/editor/[id]/page.tsx @@ -24,7 +24,7 @@ import { Geometry, useEditorState, } from "@/uhm/lib/editor/state/useEditorState"; -import { GEO_TYPE_KEYS, geoTypeCodeToTypeKey } from "@/uhm/lib/map/geo/geoTypeMap"; +import { GEO_TYPE_KEYS } from "@/uhm/lib/map/geo/geoTypeMap"; import { BackgroundLayerId, BackgroundLayerVisibility, @@ -1080,7 +1080,7 @@ export default function Page() { } const bindingIds = normalizeGeoSearchBindingIds(geo.binding); - const typeKey = geoTypeCodeToTypeKey(Number(geo.geo_type)) || null; + const typeKey = geo.type || null; const feature: Feature = { type: "Feature", @@ -1537,7 +1537,7 @@ export default function Page() { #{geo.id}
- type: {String(geo.geo_type)}{" "} + type: {geo.type || "unknown"}{" "} {geo.time_start != null || geo.time_end != null ? `| time: ${geo.time_start ?? "?"} → ${geo.time_end ?? "?"}` : ""} diff --git a/src/uhm/api/geometries.ts b/src/uhm/api/geometries.ts index 0ba7621..cdca56f 100644 --- a/src/uhm/api/geometries.ts +++ b/src/uhm/api/geometries.ts @@ -8,7 +8,7 @@ export type { GeometriesBBoxQuery } from "@/uhm/types/api"; export type EntityGeometrySearchGeo = { id: string; - geo_type: number; + type: string | null; draw_geometry: unknown; binding?: unknown; time_start?: number | null; @@ -27,6 +27,18 @@ export type SearchGeometriesByEntityNameResponse = { next_cursor?: string; }; +type EntityGeometrySearchGeoRow = Omit & { + geo_type: number; +}; + +type EntityGeometriesSearchItemRow = Omit & { + geometries: EntityGeometrySearchGeoRow[]; +}; + +type SearchGeometriesByEntityNameApiResponse = Omit & { + items: EntityGeometriesSearchItemRow[]; +}; + function buildBBoxQueryString(params: GeometriesBBoxQuery): string { const query = new URLSearchParams({ // API mới dùng snake_case @@ -71,7 +83,24 @@ export async function searchGeometriesByEntityName( params.set("limit", String(Math.trunc(options.limit))); } - return requestJson(`${API_ENDPOINTS.geometries}/entity?${params.toString()}`); + const response = await requestJson( + `${API_ENDPOINTS.geometries}/entity?${params.toString()}` + ); + + return { + ...response, + items: (response.items || []).map((item) => ({ + ...item, + geometries: (item.geometries || []).map((geometry) => ({ + id: geometry.id, + type: geoTypeCodeToTypeKey(geometry.geo_type) || null, + draw_geometry: geometry.draw_geometry, + binding: geometry.binding, + time_start: geometry.time_start ?? null, + time_end: geometry.time_end ?? null, + })), + })), + }; } type GeometryRow = { diff --git a/src/uhm/api/projects.ts b/src/uhm/api/projects.ts index a56585f..19ebe33 100644 --- a/src/uhm/api/projects.ts +++ b/src/uhm/api/projects.ts @@ -1,5 +1,6 @@ import { API_BASE_URL, API_ENDPOINTS } from "@/uhm/api/config"; import { ApiError, jsonRequestInit, requestJson } from "@/uhm/api/http"; +import { toApiEditorSnapshot } from "@/uhm/lib/editor/snapshot/editorSnapshot"; import type { CreateCommitInput, CreateProjectInput, @@ -76,10 +77,11 @@ export async function createProjectCommit( input: CreateCommitInput ): Promise<{ commit: ProjectCommit; state: ProjectState }> { // POST /projects/{id}/commits + const snapshot = toApiEditorSnapshot(input.snapshot); const commit = await requestJson( `${API_ENDPOINTS.projects}/${encodeURIComponent(projectId)}/commits`, jsonRequestInit("POST", { - snapshot_json: input.snapshot, + snapshot_json: snapshot, edit_summary: input.edit_summary, }) ); diff --git a/src/uhm/components/editor/SelectedGeometryPanel.tsx b/src/uhm/components/editor/SelectedGeometryPanel.tsx index 93c3395..3e3cc68 100644 --- a/src/uhm/components/editor/SelectedGeometryPanel.tsx +++ b/src/uhm/components/editor/SelectedGeometryPanel.tsx @@ -9,6 +9,7 @@ import { findGeometryTypeOption, groupGeometryTypeOptions, } from "@/uhm/lib/map/geo/geometryTypeOptions"; +import { normalizeGeoTypeKey } from "@/uhm/lib/map/geo/geoTypeMap"; import type { GeometryMetaFormState } from "@/uhm/lib/editor/session/sessionTypes"; type Props = { @@ -288,9 +289,7 @@ function normalizeGeometryPreset(value: unknown): GeometryPreset | null { } function normalizeTypeId(value: unknown): string | null { - if (typeof value !== "string") return null; - const normalized = value.trim().toLowerCase(); - return normalized.length ? normalized : null; + return normalizeGeoTypeKey(value); } function mapGeometryTypeToPreset( diff --git a/src/uhm/components/map/mapUtils.ts b/src/uhm/components/map/mapUtils.ts index f61ae67..b272455 100644 --- a/src/uhm/components/map/mapUtils.ts +++ b/src/uhm/components/map/mapUtils.ts @@ -13,6 +13,7 @@ import { import { PATH_RENDER_BY_TYPE } from "@/uhm/lib/map/styles/style"; import { getRasterTileTemplateUrl } from "@/uhm/api/tiles"; import { newId } from "@/uhm/lib/utils/id"; +import { normalizeGeoTypeKey } from "@/uhm/lib/map/geo/geoTypeMap"; type Coordinate = [number, number]; type PolygonCoordinates = Coordinate[][]; @@ -342,18 +343,22 @@ export function collectCoordinatePairs(value: unknown): Array<[number, number]> } export function buildPathArrowFeatureCollection(fc: FeatureCollection): FeatureCollection { - const features = fc.features - .map((feature) => { - if (!isPathFeature(feature) || feature.geometry.type !== "LineString") return null; - const geometry = buildPathArrowGeometry(feature.geometry.coordinates); - if (!geometry) return null; - return { - type: "Feature" as const, + const features: Feature[] = []; + + for (const feature of fc.features) { + if (!isPathFeature(feature)) continue; + + const coordinateGroups = getLineCoordinateGroups(feature.geometry); + for (const coordinates of coordinateGroups) { + const geometry = buildPathArrowGeometry(coordinates); + if (!geometry) continue; + features.push({ + type: "Feature", properties: { ...feature.properties }, geometry, - }; - }) - .filter((feature): feature is Feature => feature !== null); + }); + } + } return { type: "FeatureCollection", @@ -368,9 +373,7 @@ export function isPathFeature(feature: Feature): boolean { export function getFeatureSemanticType(feature: Feature): string | null { const value = feature.properties.type || feature.properties.entity_type_id || null; - if (!value) return null; - const normalized = String(value).trim().toLowerCase(); - return normalized.length ? normalized : null; + return normalizeGeoTypeKey(value); } export function buildPathArrowGeometry(coords: [number, number][]): Geometry | null { @@ -719,6 +722,12 @@ function isLineGeometry(geometry: Geometry): boolean { return geometry.type === "LineString" || geometry.type === "MultiLineString"; } +function getLineCoordinateGroups(geometry: Geometry): Coordinate[][] { + if (geometry.type === "LineString") return [geometry.coordinates]; + if (geometry.type === "MultiLineString") return geometry.coordinates; + return []; +} + function getPolygonLabelPoint(geometry: Geometry): Coordinate | null { if (geometry.type === "Polygon") { return getPolygonLabelCandidate(geometry.coordinates)?.point || null; diff --git a/src/uhm/components/map/useMapLayers.ts b/src/uhm/components/map/useMapLayers.ts index 16bdede..82f4652 100644 --- a/src/uhm/components/map/useMapLayers.ts +++ b/src/uhm/components/map/useMapLayers.ts @@ -384,7 +384,11 @@ export function setupMapLayers( id: "entity-focus-fill", type: "fill", source: "entity-focus", - filter: ["==", ["geometry-type"], "Polygon"], + filter: [ + "any", + ["==", ["geometry-type"], "Polygon"], + ["==", ["geometry-type"], "MultiPolygon"], + ], paint: { "fill-color": "#fde047", "fill-opacity": 0.2, @@ -413,7 +417,11 @@ export function setupMapLayers( id: "entity-focus-points", type: "circle", source: "entity-focus", - filter: ["==", ["geometry-type"], "Point"], + filter: [ + "any", + ["==", ["geometry-type"], "Point"], + ["==", ["geometry-type"], "MultiPoint"], + ], paint: { "circle-color": "#f8fafc", "circle-radius": 8, diff --git a/src/uhm/lib/editor/project/useProjectCommands.ts b/src/uhm/lib/editor/project/useProjectCommands.ts index 3d03f47..d0b3dda 100644 --- a/src/uhm/lib/editor/project/useProjectCommands.ts +++ b/src/uhm/lib/editor/project/useProjectCommands.ts @@ -9,7 +9,7 @@ import { openSectionEditor, submitSection, } from "@/uhm/api/projects"; -import { buildEditorSnapshot, normalizeEditorSnapshot } from "@/uhm/lib/editor/snapshot/editorSnapshot"; +import { buildEditorSnapshot, normalizeEditorSnapshot, toApiEditorSnapshot } from "@/uhm/lib/editor/snapshot/editorSnapshot"; import type { Change } from "@/uhm/lib/editor/draft/editorTypes"; import type { Feature, FeatureCollection, FeatureId, GeometryEntitySnapshot, GeometrySnapshot } from "@/uhm/types/geo"; import type { EditorSnapshot, Project, ProjectCommit, ProjectState, EntityWikiLinkSnapshot } from "@/uhm/types/projects"; @@ -110,7 +110,7 @@ export function useProjectCommands(options: Options) { // Guardrail: commit payload can get large and some deployments reject/close connections for big bodies. // When that happens, browsers often surface it as "TypeError: Failed to fetch". try { - const payloadText = JSON.stringify({ snapshot_json: snapshot, edit_summary: editSummary }); + const payloadText = JSON.stringify({ snapshot_json: toApiEditorSnapshot(snapshot), edit_summary: editSummary }); const bytes = typeof Blob !== "undefined" ? new Blob([payloadText]).size : payloadText.length; const limitBytes = 3_500_000; // ~3.5MB (conservative vs common default body limits) if (bytes > limitBytes) { diff --git a/src/uhm/lib/editor/snapshot/editorSnapshot.ts b/src/uhm/lib/editor/snapshot/editorSnapshot.ts index a6db1d7..d142388 100644 --- a/src/uhm/lib/editor/snapshot/editorSnapshot.ts +++ b/src/uhm/lib/editor/snapshot/editorSnapshot.ts @@ -1,5 +1,5 @@ import { DEFAULT_GEOMETRY_TYPE_ID } from "@/uhm/lib/map/geo/geometryTypeOptions"; -import { geoTypeCodeToTypeKey, typeKeyToGeoTypeCode } from "@/uhm/lib/map/geo/geoTypeMap"; +import { normalizeGeoTypeKey, typeKeyToGeoTypeCode } from "@/uhm/lib/map/geo/geoTypeMap"; import type { Change } from "@/uhm/lib/editor/draft/editorTypes"; import type { EntitySnapshot } from "@/uhm/types/entities"; import type { EntitySnapshotOperation } from "@/uhm/types/entities"; @@ -86,12 +86,15 @@ export function normalizeEditorSnapshot(raw: unknown): EditorSnapshot | null { const source: "inline" | "ref" = existingSource || (refId || !hasInlineGeometry ? "ref" : "inline"); const rest: UnknownRecord = { ...g }; delete rest.ref; + const typeKey = normalizeGeoTypeKey(rest.type) || normalizeGeoTypeKey(rest.geo_type); + delete rest.geo_type; return { ...(rest as unknown as Omit), id, source, operation, + type: typeKey, }; }) : undefined; @@ -210,30 +213,39 @@ export function normalizeEditorSnapshot(raw: unknown): EditorSnapshot | null { for (const feature of cloned.features) { const gid = String(feature.properties.id); const entity_ids = byGeom.get(gid) || []; + const p = feature.properties as unknown as UnknownRecord; + + const existingTypeKey = normalizeGeoTypeKey(p.type) || normalizeGeoTypeKey(p.entity_type_id); + const fallbackTypeKey = getDefaultTypeIdForFeature(feature); + if (existingTypeKey) p.type = existingTypeKey; + if (entity_ids.length || hasLinks) { - const props = feature.properties as unknown as UnknownRecord; - props.entity_ids = entity_ids; - props.entity_id = entity_ids[0] || null; + p.entity_ids = entity_ids; + p.entity_id = entity_ids[0] || null; // Generate denormalized names for UI/map usage. const primaryId = entity_ids[0] || null; const primaryName = primaryId ? (entityNameById.get(primaryId) || "") : ""; const names = entity_ids.map((id) => entityNameById.get(id) || "").filter((n) => n.length > 0); - props.entity_name = primaryName || null; - props.entity_names = names; + p.entity_name = primaryName || null; + p.entity_names = names; } // Generate geometry metadata onto feature properties (optional in persisted snapshot). const geo = geometryById.get(gid) || null; if (geo) { - const p = feature.properties as unknown as UnknownRecord; - // type (semantic key) is derived from geometries[].type (numeric code in string form). - const typeCode = typeof geo.type === "string" && geo.type.trim().length ? Number(geo.type) : NaN; - const typeKey = geoTypeCodeToTypeKey(Number.isFinite(typeCode) ? typeCode : null); + const geoRecord = geo as unknown as UnknownRecord; + // type can arrive as numeric geo_type, numeric string, or semantic key depending on backend version. + const typeKey = normalizeGeoTypeKey(geoRecord.type) + || normalizeGeoTypeKey(geoRecord.geo_type) + || existingTypeKey + || fallbackTypeKey; if (typeKey) p.type = typeKey; if (Array.isArray(geo.binding) && geo.binding.length) p.binding = geo.binding; if (typeof geo.time_start === "number") p.time_start = geo.time_start; if (typeof geo.time_end === "number") p.time_end = geo.time_end; + } else if (!existingTypeKey) { + p.type = fallbackTypeKey; } } return cloned; @@ -375,14 +387,12 @@ export function buildEditorSnapshot(options: { ? "update" : "reference"; const bbox = getFeatureBBox(feature); - const typeKey = feature.properties.type || getDefaultTypeIdForFeature(feature); - const typeCode = typeKeyToGeoTypeCode(typeKey); + const typeKey = normalizeGeoTypeKey(feature.properties.type) || getDefaultTypeIdForFeature(feature); return { id, operation, source: "inline", - // BE currently expects geometries[].type as a string. We send the geo_type SMALLINT code as a string. - type: String(typeCode ?? 0), + type: typeKey, draw_geometry: feature.geometry, binding: normalizeFeatureBindingIds(feature), time_start: feature.properties.time_start ?? null, @@ -600,6 +610,29 @@ export function buildEditorSnapshot(options: { }; } +export function toApiEditorSnapshot(snapshot: EditorSnapshot): EditorSnapshot { + const cloned = JSON.parse(JSON.stringify(snapshot)) as EditorSnapshot; + + if (Array.isArray(cloned.geometries)) { + cloned.geometries = cloned.geometries.map((geometry) => { + const row = { ...(geometry as unknown as UnknownRecord) }; + const typeKey = normalizeGeoTypeKey(row.type) || normalizeGeoTypeKey(row.geo_type); + delete row.geo_type; + + if (typeKey) { + const typeCode = typeKeyToGeoTypeCode(typeKey); + row.type = typeCode == null ? null : String(typeCode); + } else if ("type" in row) { + row.type = null; + } + + return row as unknown as GeometrySnapshot; + }); + } + + return cloned; +} + function dedupeAndSortGeometryEntity(rows: GeometryEntitySnapshot[]): GeometryEntitySnapshot[] { const seen = new Set(); const deduped: GeometryEntitySnapshot[] = []; diff --git a/src/uhm/lib/map/geo/geoTypeMap.ts b/src/uhm/lib/map/geo/geoTypeMap.ts index e6f2c42..da849e7 100644 --- a/src/uhm/lib/map/geo/geoTypeMap.ts +++ b/src/uhm/lib/map/geo/geoTypeMap.ts @@ -39,3 +39,20 @@ export function geoTypeCodeToTypeKey(code: number | null | undefined): string | if (!Number.isFinite(code)) return null; return KEY_BY_CODE.get(Math.trunc(code)) ?? null; } + +export function normalizeGeoTypeKey(value: unknown): string | null { + if (typeof value === "number") { + return geoTypeCodeToTypeKey(value); + } + + if (typeof value !== "string") return null; + + const normalized = value.trim().toLowerCase(); + if (!normalized.length) return null; + + if (/^-?\d+$/.test(normalized)) { + return geoTypeCodeToTypeKey(Number(normalized)); + } + + return normalized; +} diff --git a/src/uhm/lib/map/styles/geotypes/attack_route.ts b/src/uhm/lib/map/styles/geotypes/attack_route.ts index a62c02b..0afb1ba 100644 --- a/src/uhm/lib/map/styles/geotypes/attack_route.ts +++ b/src/uhm/lib/map/styles/geotypes/attack_route.ts @@ -1,68 +1,13 @@ import { LayerSpecification } from "maplibre-gl"; -import { TYPE_MATCH_EXPR } from "./index"; +import { buildLineGeotypeLayers } from "./styleBuilders"; export function getAttackRouteLayers(sourceId: string, pathArrowSourceId?: string, pointSourceId?: string): LayerSpecification[] { - return [ - { - id: "attack_route-line", - type: "line", - source: sourceId, - filter: ["all", ["==", ["geometry-type"], "LineString"], ["==", TYPE_MATCH_EXPR, "attack_route"]], - paint: { - "line-color": [ - "case", - ["boolean", ["feature-state", "selected"], false], "#22c55e", - ["==", ["coalesce", ["get", "entity_id"], ""], ""], "#ef4444", - "#ef4444" - ], - "line-width": ["interpolate", ["linear"], ["zoom"], 1, 2.2, 4, 3.2, 6, 4.2], - "line-opacity": 0.9 - } - }, - { - id: "attack_route-hit", - type: "line", - source: sourceId, - filter: ["all", ["==", ["geometry-type"], "LineString"], ["==", TYPE_MATCH_EXPR, "attack_route"]], - paint: { - "line-color": "#ffffff", - "line-width": ["interpolate", ["linear"], ["zoom"], 1, 12, 4, 18, 6, 24], - "line-opacity": 0 - } - }, - { - id: "attack_route-path-arrow-fill", - type: "fill", - source: pathArrowSourceId!, - filter: ["==", TYPE_MATCH_EXPR, "attack_route"], - paint: { - "fill-color": [ - "case", - ["boolean", ["feature-state", "selected"], false], "#22c55e", - ["==", ["coalesce", ["get", "entity_id"], ""], ""], "#ef4444", - "#ef4444" - ], - "fill-opacity": [ - "case", - ["boolean", ["feature-state", "selected"], false], 0.92, - 0.82 - ] - } - }, - { - id: "attack_route-path-arrow-line", - type: "line", - source: pathArrowSourceId!, - filter: ["==", TYPE_MATCH_EXPR, "attack_route"], - paint: { - "line-color": [ - "case", - ["boolean", ["feature-state", "selected"], false], "#14532d", - "#0f172a" - ], - "line-width": ["interpolate", ["linear"], ["zoom"], 1, 0.45, 4, 0.8, 6, 1.2], - "line-opacity": 0.9 - } - } - ]; + void pointSourceId; + return buildLineGeotypeLayers(sourceId, pathArrowSourceId, { + typeId: "attack_route", + color: "#ef4444", + strokeColor: "#7f1d1d", + width: { z1: 2.6, z4: 3.8, z6: 5 }, + arrowOpacity: 0.9, + }); } diff --git a/src/uhm/lib/map/styles/geotypes/battle.ts b/src/uhm/lib/map/styles/geotypes/battle.ts index 121e9ff..4eaf64a 100644 --- a/src/uhm/lib/map/styles/geotypes/battle.ts +++ b/src/uhm/lib/map/styles/geotypes/battle.ts @@ -1,40 +1,14 @@ import { LayerSpecification } from "maplibre-gl"; -import { TYPE_MATCH_EXPR } from "./index"; +import { buildPolygonGeotypeLayers } from "./styleBuilders"; export function getBattleLayers(sourceId: string, pathArrowSourceId?: string, pointSourceId?: string): LayerSpecification[] { - return [ - { - id: "battle-fill", - type: "fill", - source: sourceId, - filter: ["all", ["==", ["geometry-type"], "Polygon"], ["==", TYPE_MATCH_EXPR, "battle"]], - paint: { - "fill-color": [ - "case", - ["boolean", ["feature-state", "selected"], false], "#22c55e", - ["==", ["coalesce", ["get", "entity_id"], ""], ""], "#ef4444", - "#f43f5e" - ], - "fill-opacity": [ - "case", - ["boolean", ["feature-state", "selected"], false], 0.6, - 0.34 - ] - } - }, - { - id: "battle-line", - type: "line", - source: sourceId, - filter: ["all", ["==", ["geometry-type"], "Polygon"], ["==", TYPE_MATCH_EXPR, "battle"]], - paint: { - "line-color": [ - "case", - ["boolean", ["feature-state", "selected"], false], "#14532d", - "#9f1239" - ], - "line-width": 2 - } - } - ]; + void pathArrowSourceId; + void pointSourceId; + return buildPolygonGeotypeLayers(sourceId, { + typeId: "battle", + fillColor: "#f43f5e", + strokeColor: "#9f1239", + fillOpacity: 0.3, + strokeWidth: { z1: 1.5, z4: 2.2, z6: 3 }, + }); } diff --git a/src/uhm/lib/map/styles/geotypes/civilization.ts b/src/uhm/lib/map/styles/geotypes/civilization.ts index beda40b..8eca272 100644 --- a/src/uhm/lib/map/styles/geotypes/civilization.ts +++ b/src/uhm/lib/map/styles/geotypes/civilization.ts @@ -1,40 +1,13 @@ import { LayerSpecification } from "maplibre-gl"; -import { TYPE_MATCH_EXPR } from "./index"; +import { buildPolygonGeotypeLayers } from "./styleBuilders"; export function getCivilizationLayers(sourceId: string, pathArrowSourceId?: string, pointSourceId?: string): LayerSpecification[] { - return [ - { - id: "civilization-fill", - type: "fill", - source: sourceId, - filter: ["all", ["==", ["geometry-type"], "Polygon"], ["==", TYPE_MATCH_EXPR, "civilization"]], - paint: { - "fill-color": [ - "case", - ["boolean", ["feature-state", "selected"], false], "#22c55e", - ["==", ["coalesce", ["get", "entity_id"], ""], ""], "#ef4444", - "#14b8a6" - ], - "fill-opacity": [ - "case", - ["boolean", ["feature-state", "selected"], false], 0.6, - 0.38 - ] - } - }, - { - id: "civilization-line", - type: "line", - source: sourceId, - filter: ["all", ["==", ["geometry-type"], "Polygon"], ["==", TYPE_MATCH_EXPR, "civilization"]], - paint: { - "line-color": [ - "case", - ["boolean", ["feature-state", "selected"], false], "#14532d", - "#134e4a" - ], - "line-width": 2 - } - } - ]; + void pathArrowSourceId; + void pointSourceId; + return buildPolygonGeotypeLayers(sourceId, { + typeId: "civilization", + fillColor: "#14b8a6", + strokeColor: "#134e4a", + fillOpacity: 0.34, + }); } diff --git a/src/uhm/lib/map/styles/geotypes/country.ts b/src/uhm/lib/map/styles/geotypes/country.ts index ca3ad34..11de408 100644 --- a/src/uhm/lib/map/styles/geotypes/country.ts +++ b/src/uhm/lib/map/styles/geotypes/country.ts @@ -1,40 +1,13 @@ import { LayerSpecification } from "maplibre-gl"; -import { TYPE_MATCH_EXPR } from "./index"; +import { buildPolygonGeotypeLayers } from "./styleBuilders"; export function getCountryLayers(sourceId: string, pathArrowSourceId?: string, pointSourceId?: string): LayerSpecification[] { - return [ - { - id: "country-fill", - type: "fill", - source: sourceId, - filter: ["all", ["==", ["geometry-type"], "Polygon"], ["==", TYPE_MATCH_EXPR, "country"]], - paint: { - "fill-color": [ - "case", - ["boolean", ["feature-state", "selected"], false], "#22c55e", - ["==", ["coalesce", ["get", "entity_id"], ""], ""], "#ef4444", - "#2563eb" - ], - "fill-opacity": [ - "case", - ["boolean", ["feature-state", "selected"], false], 0.6, - 0.5 - ] - } - }, - { - id: "country-line", - type: "line", - source: sourceId, - filter: ["all", ["==", ["geometry-type"], "Polygon"], ["==", TYPE_MATCH_EXPR, "country"]], - paint: { - "line-color": [ - "case", - ["boolean", ["feature-state", "selected"], false], "#14532d", - "#1e3a8a" - ], - "line-width": 2 - } - } - ]; + void pathArrowSourceId; + void pointSourceId; + return buildPolygonGeotypeLayers(sourceId, { + typeId: "country", + fillColor: "#2563eb", + strokeColor: "#1e40af", + fillOpacity: 0.34, + }); } diff --git a/src/uhm/lib/map/styles/geotypes/defense_line.ts b/src/uhm/lib/map/styles/geotypes/defense_line.ts index c8e9068..cb8e7b9 100644 --- a/src/uhm/lib/map/styles/geotypes/defense_line.ts +++ b/src/uhm/lib/map/styles/geotypes/defense_line.ts @@ -1,35 +1,13 @@ import { LayerSpecification } from "maplibre-gl"; -import { TYPE_MATCH_EXPR } from "./index"; +import { buildLineGeotypeLayers } from "./styleBuilders"; export function getDefenseLineLayers(sourceId: string, pathArrowSourceId?: string, pointSourceId?: string): LayerSpecification[] { - return [ - { - id: "defense_line-line", - type: "line", - source: sourceId, - filter: ["all", ["==", ["geometry-type"], "LineString"], ["==", TYPE_MATCH_EXPR, "defense_line"]], - paint: { - "line-color": [ - "case", - ["boolean", ["feature-state", "selected"], false], "#22c55e", - ["==", ["coalesce", ["get", "entity_id"], ""], ""], "#ef4444", - "#f97316" - ], - "line-width": ["interpolate", ["linear"], ["zoom"], 1, 2.2, 4, 3.2, 6, 4.2], - "line-dasharray": [3, 2], - "line-opacity": 0.9 - } - }, - { - id: "defense_line-hit", - type: "line", - source: sourceId, - filter: ["all", ["==", ["geometry-type"], "LineString"], ["==", TYPE_MATCH_EXPR, "defense_line"]], - paint: { - "line-color": "#ffffff", - "line-width": ["interpolate", ["linear"], ["zoom"], 1, 12, 4, 18, 6, 24], - "line-opacity": 0 - } - } - ]; + void pointSourceId; + return buildLineGeotypeLayers(sourceId, pathArrowSourceId, { + typeId: "defense_line", + color: "#38bdf8", + strokeColor: "#075985", + dasharray: [3, 2], + arrow: false, + }); } diff --git a/src/uhm/lib/map/styles/geotypes/empire.ts b/src/uhm/lib/map/styles/geotypes/empire.ts index 4870683..3379345 100644 --- a/src/uhm/lib/map/styles/geotypes/empire.ts +++ b/src/uhm/lib/map/styles/geotypes/empire.ts @@ -1,40 +1,14 @@ import { LayerSpecification } from "maplibre-gl"; -import { TYPE_MATCH_EXPR } from "./index"; +import { buildPolygonGeotypeLayers } from "./styleBuilders"; export function getEmpireLayers(sourceId: string, pathArrowSourceId?: string, pointSourceId?: string): LayerSpecification[] { - return [ - { - id: "empire-fill", - type: "fill", - source: sourceId, - filter: ["all", ["==", ["geometry-type"], "Polygon"], ["==", TYPE_MATCH_EXPR, "empire"]], - paint: { - "fill-color": [ - "case", - ["boolean", ["feature-state", "selected"], false], "#22c55e", - ["==", ["coalesce", ["get", "entity_id"], ""], ""], "#ef4444", - "#f59e0b" - ], - "fill-opacity": [ - "case", - ["boolean", ["feature-state", "selected"], false], 0.6, - 0.5 - ] - } - }, - { - id: "empire-line", - type: "line", - source: sourceId, - filter: ["all", ["==", ["geometry-type"], "Polygon"], ["==", TYPE_MATCH_EXPR, "empire"]], - paint: { - "line-color": [ - "case", - ["boolean", ["feature-state", "selected"], false], "#14532d", - "#7c2d12" - ], - "line-width": 2 - } - } - ]; + void pathArrowSourceId; + void pointSourceId; + return buildPolygonGeotypeLayers(sourceId, { + typeId: "empire", + fillColor: "#f59e0b", + strokeColor: "#92400e", + fillOpacity: 0.36, + strokeWidth: { z1: 1.8, z4: 2.6, z6: 3.4 }, + }); } diff --git a/src/uhm/lib/map/styles/geotypes/invasion_route.ts b/src/uhm/lib/map/styles/geotypes/invasion_route.ts index 50c996b..985446f 100644 --- a/src/uhm/lib/map/styles/geotypes/invasion_route.ts +++ b/src/uhm/lib/map/styles/geotypes/invasion_route.ts @@ -1,68 +1,13 @@ import { LayerSpecification } from "maplibre-gl"; -import { TYPE_MATCH_EXPR } from "./index"; +import { buildLineGeotypeLayers } from "./styleBuilders"; export function getInvasionRouteLayers(sourceId: string, pathArrowSourceId?: string, pointSourceId?: string): LayerSpecification[] { - return [ - { - id: "invasion_route-line", - type: "line", - source: sourceId, - filter: ["all", ["==", ["geometry-type"], "LineString"], ["==", TYPE_MATCH_EXPR, "invasion_route"]], - paint: { - "line-color": [ - "case", - ["boolean", ["feature-state", "selected"], false], "#22c55e", - ["==", ["coalesce", ["get", "entity_id"], ""], ""], "#ef4444", - "#b91c1c" - ], - "line-width": ["interpolate", ["linear"], ["zoom"], 1, 2.2, 4, 3.2, 6, 4.2], - "line-opacity": 0.9 - } - }, - { - id: "invasion_route-hit", - type: "line", - source: sourceId, - filter: ["all", ["==", ["geometry-type"], "LineString"], ["==", TYPE_MATCH_EXPR, "invasion_route"]], - paint: { - "line-color": "#ffffff", - "line-width": ["interpolate", ["linear"], ["zoom"], 1, 12, 4, 18, 6, 24], - "line-opacity": 0 - } - }, - { - id: "invasion_route-path-arrow-fill", - type: "fill", - source: pathArrowSourceId!, - filter: ["==", TYPE_MATCH_EXPR, "invasion_route"], - paint: { - "fill-color": [ - "case", - ["boolean", ["feature-state", "selected"], false], "#22c55e", - ["==", ["coalesce", ["get", "entity_id"], ""], ""], "#ef4444", - "#b91c1c" - ], - "fill-opacity": [ - "case", - ["boolean", ["feature-state", "selected"], false], 0.92, - 0.82 - ] - } - }, - { - id: "invasion_route-path-arrow-line", - type: "line", - source: pathArrowSourceId!, - filter: ["==", TYPE_MATCH_EXPR, "invasion_route"], - paint: { - "line-color": [ - "case", - ["boolean", ["feature-state", "selected"], false], "#14532d", - "#0f172a" - ], - "line-width": ["interpolate", ["linear"], ["zoom"], 1, 0.45, 4, 0.8, 6, 1.2], - "line-opacity": 0.9 - } - } - ]; + void pointSourceId; + return buildLineGeotypeLayers(sourceId, pathArrowSourceId, { + typeId: "invasion_route", + color: "#be123c", + strokeColor: "#4c0519", + width: { z1: 2.8, z4: 4.1, z6: 5.4 }, + arrowOpacity: 0.9, + }); } diff --git a/src/uhm/lib/map/styles/geotypes/kingdom.ts b/src/uhm/lib/map/styles/geotypes/kingdom.ts index f6bae6f..01fd523 100644 --- a/src/uhm/lib/map/styles/geotypes/kingdom.ts +++ b/src/uhm/lib/map/styles/geotypes/kingdom.ts @@ -1,40 +1,13 @@ import { LayerSpecification } from "maplibre-gl"; -import { TYPE_MATCH_EXPR } from "./index"; +import { buildPolygonGeotypeLayers } from "./styleBuilders"; export function getKingdomLayers(sourceId: string, pathArrowSourceId?: string, pointSourceId?: string): LayerSpecification[] { - return [ - { - id: "kingdom-fill", - type: "fill", - source: sourceId, - filter: ["all", ["==", ["geometry-type"], "Polygon"], ["==", TYPE_MATCH_EXPR, "kingdom"]], - paint: { - "fill-color": [ - "case", - ["boolean", ["feature-state", "selected"], false], "#22c55e", - ["==", ["coalesce", ["get", "entity_id"], ""], ""], "#ef4444", - "#d97706" - ], - "fill-opacity": [ - "case", - ["boolean", ["feature-state", "selected"], false], 0.6, - 0.5 - ] - } - }, - { - id: "kingdom-line", - type: "line", - source: sourceId, - filter: ["all", ["==", ["geometry-type"], "Polygon"], ["==", TYPE_MATCH_EXPR, "kingdom"]], - paint: { - "line-color": [ - "case", - ["boolean", ["feature-state", "selected"], false], "#14532d", - "#9a3412" - ], - "line-width": 2 - } - } - ]; + void pathArrowSourceId; + void pointSourceId; + return buildPolygonGeotypeLayers(sourceId, { + typeId: "kingdom", + fillColor: "#8b5cf6", + strokeColor: "#6d28d9", + fillOpacity: 0.34, + }); } diff --git a/src/uhm/lib/map/styles/geotypes/migration_route.ts b/src/uhm/lib/map/styles/geotypes/migration_route.ts index 113b3f7..85eef60 100644 --- a/src/uhm/lib/map/styles/geotypes/migration_route.ts +++ b/src/uhm/lib/map/styles/geotypes/migration_route.ts @@ -1,68 +1,13 @@ import { LayerSpecification } from "maplibre-gl"; -import { TYPE_MATCH_EXPR } from "./index"; +import { buildLineGeotypeLayers } from "./styleBuilders"; export function getMigrationRouteLayers(sourceId: string, pathArrowSourceId?: string, pointSourceId?: string): LayerSpecification[] { - return [ - { - id: "migration_route-line", - type: "line", - source: sourceId, - filter: ["all", ["==", ["geometry-type"], "LineString"], ["==", TYPE_MATCH_EXPR, "migration_route"]], - paint: { - "line-color": [ - "case", - ["boolean", ["feature-state", "selected"], false], "#22c55e", - ["==", ["coalesce", ["get", "entity_id"], ""], ""], "#ef4444", - "#0ea5e9" - ], - "line-width": ["interpolate", ["linear"], ["zoom"], 1, 2.2, 4, 3.2, 6, 4.2], - "line-opacity": 0.9 - } - }, - { - id: "migration_route-hit", - type: "line", - source: sourceId, - filter: ["all", ["==", ["geometry-type"], "LineString"], ["==", TYPE_MATCH_EXPR, "migration_route"]], - paint: { - "line-color": "#ffffff", - "line-width": ["interpolate", ["linear"], ["zoom"], 1, 12, 4, 18, 6, 24], - "line-opacity": 0 - } - }, - { - id: "migration_route-path-arrow-fill", - type: "fill", - source: pathArrowSourceId!, - filter: ["==", TYPE_MATCH_EXPR, "migration_route"], - paint: { - "fill-color": [ - "case", - ["boolean", ["feature-state", "selected"], false], "#22c55e", - ["==", ["coalesce", ["get", "entity_id"], ""], ""], "#ef4444", - "#0ea5e9" - ], - "fill-opacity": [ - "case", - ["boolean", ["feature-state", "selected"], false], 0.92, - 0.82 - ] - } - }, - { - id: "migration_route-path-arrow-line", - type: "line", - source: pathArrowSourceId!, - filter: ["==", TYPE_MATCH_EXPR, "migration_route"], - paint: { - "line-color": [ - "case", - ["boolean", ["feature-state", "selected"], false], "#14532d", - "#0f172a" - ], - "line-width": ["interpolate", ["linear"], ["zoom"], 1, 0.45, 4, 0.8, 6, 1.2], - "line-opacity": 0.9 - } - } - ]; + void pointSourceId; + return buildLineGeotypeLayers(sourceId, pathArrowSourceId, { + typeId: "migration_route", + color: "#10b981", + strokeColor: "#065f46", + dasharray: [4, 3], + arrowOpacity: 0.76, + }); } diff --git a/src/uhm/lib/map/styles/geotypes/rebellion_zone.ts b/src/uhm/lib/map/styles/geotypes/rebellion_zone.ts index 590f669..9e29e15 100644 --- a/src/uhm/lib/map/styles/geotypes/rebellion_zone.ts +++ b/src/uhm/lib/map/styles/geotypes/rebellion_zone.ts @@ -1,40 +1,14 @@ import { LayerSpecification } from "maplibre-gl"; -import { TYPE_MATCH_EXPR } from "./index"; +import { buildPolygonGeotypeLayers } from "./styleBuilders"; export function getRebellionZoneLayers(sourceId: string, pathArrowSourceId?: string, pointSourceId?: string): LayerSpecification[] { - return [ - { - id: "rebellion_zone-fill", - type: "fill", - source: sourceId, - filter: ["all", ["==", ["geometry-type"], "Polygon"], ["==", TYPE_MATCH_EXPR, "rebellion_zone"]], - paint: { - "fill-color": [ - "case", - ["boolean", ["feature-state", "selected"], false], "#22c55e", - ["==", ["coalesce", ["get", "entity_id"], ""], ""], "#ef4444", - "#7c3aed" - ], - "fill-opacity": [ - "case", - ["boolean", ["feature-state", "selected"], false], 0.6, - 0.32 - ] - } - }, - { - id: "rebellion_zone-line", - type: "line", - source: sourceId, - filter: ["all", ["==", ["geometry-type"], "Polygon"], ["==", TYPE_MATCH_EXPR, "rebellion_zone"]], - paint: { - "line-color": [ - "case", - ["boolean", ["feature-state", "selected"], false], "#14532d", - "#4c1d95" - ], - "line-width": 2 - } - } - ]; + void pathArrowSourceId; + void pointSourceId; + return buildPolygonGeotypeLayers(sourceId, { + typeId: "rebellion_zone", + fillColor: "#a21caf", + strokeColor: "#701a75", + fillOpacity: 0.26, + dasharray: [3, 2], + }); } diff --git a/src/uhm/lib/map/styles/geotypes/refugee_route.ts b/src/uhm/lib/map/styles/geotypes/refugee_route.ts index 668c164..5a023f8 100644 --- a/src/uhm/lib/map/styles/geotypes/refugee_route.ts +++ b/src/uhm/lib/map/styles/geotypes/refugee_route.ts @@ -1,68 +1,14 @@ import { LayerSpecification } from "maplibre-gl"; -import { TYPE_MATCH_EXPR } from "./index"; +import { buildLineGeotypeLayers } from "./styleBuilders"; export function getRefugeeRouteLayers(sourceId: string, pathArrowSourceId?: string, pointSourceId?: string): LayerSpecification[] { - return [ - { - id: "refugee_route-line", - type: "line", - source: sourceId, - filter: ["all", ["==", ["geometry-type"], "LineString"], ["==", TYPE_MATCH_EXPR, "refugee_route"]], - paint: { - "line-color": [ - "case", - ["boolean", ["feature-state", "selected"], false], "#22c55e", - ["==", ["coalesce", ["get", "entity_id"], ""], ""], "#ef4444", - "#06b6d4" - ], - "line-width": ["interpolate", ["linear"], ["zoom"], 1, 2.2, 4, 3.2, 6, 4.2], - "line-opacity": 0.9 - } - }, - { - id: "refugee_route-hit", - type: "line", - source: sourceId, - filter: ["all", ["==", ["geometry-type"], "LineString"], ["==", TYPE_MATCH_EXPR, "refugee_route"]], - paint: { - "line-color": "#ffffff", - "line-width": ["interpolate", ["linear"], ["zoom"], 1, 12, 4, 18, 6, 24], - "line-opacity": 0 - } - }, - { - id: "refugee_route-path-arrow-fill", - type: "fill", - source: pathArrowSourceId!, - filter: ["==", TYPE_MATCH_EXPR, "refugee_route"], - paint: { - "fill-color": [ - "case", - ["boolean", ["feature-state", "selected"], false], "#22c55e", - ["==", ["coalesce", ["get", "entity_id"], ""], ""], "#ef4444", - "#06b6d4" - ], - "fill-opacity": [ - "case", - ["boolean", ["feature-state", "selected"], false], 0.92, - 0.82 - ] - } - }, - { - id: "refugee_route-path-arrow-line", - type: "line", - source: pathArrowSourceId!, - filter: ["==", TYPE_MATCH_EXPR, "refugee_route"], - paint: { - "line-color": [ - "case", - ["boolean", ["feature-state", "selected"], false], "#14532d", - "#0f172a" - ], - "line-width": ["interpolate", ["linear"], ["zoom"], 1, 0.45, 4, 0.8, 6, 1.2], - "line-opacity": 0.9 - } - } - ]; + void pointSourceId; + return buildLineGeotypeLayers(sourceId, pathArrowSourceId, { + typeId: "refugee_route", + color: "#f97316", + strokeColor: "#9a3412", + dasharray: [1, 2], + opacity: 0.84, + arrowOpacity: 0.72, + }); } diff --git a/src/uhm/lib/map/styles/geotypes/retreat_route.ts b/src/uhm/lib/map/styles/geotypes/retreat_route.ts index 55f697e..1701538 100644 --- a/src/uhm/lib/map/styles/geotypes/retreat_route.ts +++ b/src/uhm/lib/map/styles/geotypes/retreat_route.ts @@ -1,68 +1,14 @@ import { LayerSpecification } from "maplibre-gl"; -import { TYPE_MATCH_EXPR } from "./index"; +import { buildLineGeotypeLayers } from "./styleBuilders"; export function getRetreatRouteLayers(sourceId: string, pathArrowSourceId?: string, pointSourceId?: string): LayerSpecification[] { - return [ - { - id: "retreat_route-line", - type: "line", - source: sourceId, - filter: ["all", ["==", ["geometry-type"], "LineString"], ["==", TYPE_MATCH_EXPR, "retreat_route"]], - paint: { - "line-color": [ - "case", - ["boolean", ["feature-state", "selected"], false], "#22c55e", - ["==", ["coalesce", ["get", "entity_id"], ""], ""], "#ef4444", - "#94a3b8" - ], - "line-width": ["interpolate", ["linear"], ["zoom"], 1, 2.2, 4, 3.2, 6, 4.2], - "line-opacity": 0.9 - } - }, - { - id: "retreat_route-hit", - type: "line", - source: sourceId, - filter: ["all", ["==", ["geometry-type"], "LineString"], ["==", TYPE_MATCH_EXPR, "retreat_route"]], - paint: { - "line-color": "#ffffff", - "line-width": ["interpolate", ["linear"], ["zoom"], 1, 12, 4, 18, 6, 24], - "line-opacity": 0 - } - }, - { - id: "retreat_route-path-arrow-fill", - type: "fill", - source: pathArrowSourceId!, - filter: ["==", TYPE_MATCH_EXPR, "retreat_route"], - paint: { - "fill-color": [ - "case", - ["boolean", ["feature-state", "selected"], false], "#22c55e", - ["==", ["coalesce", ["get", "entity_id"], ""], ""], "#ef4444", - "#94a3b8" - ], - "fill-opacity": [ - "case", - ["boolean", ["feature-state", "selected"], false], 0.92, - 0.82 - ] - } - }, - { - id: "retreat_route-path-arrow-line", - type: "line", - source: pathArrowSourceId!, - filter: ["==", TYPE_MATCH_EXPR, "retreat_route"], - paint: { - "line-color": [ - "case", - ["boolean", ["feature-state", "selected"], false], "#14532d", - "#0f172a" - ], - "line-width": ["interpolate", ["linear"], ["zoom"], 1, 0.45, 4, 0.8, 6, 1.2], - "line-opacity": 0.9 - } - } - ]; + void pointSourceId; + return buildLineGeotypeLayers(sourceId, pathArrowSourceId, { + typeId: "retreat_route", + color: "#94a3b8", + strokeColor: "#475569", + dasharray: [6, 3], + opacity: 0.82, + arrowOpacity: 0.68, + }); } diff --git a/src/uhm/lib/map/styles/geotypes/shipping_route.ts b/src/uhm/lib/map/styles/geotypes/shipping_route.ts index 3b8ebc7..2c1b246 100644 --- a/src/uhm/lib/map/styles/geotypes/shipping_route.ts +++ b/src/uhm/lib/map/styles/geotypes/shipping_route.ts @@ -1,68 +1,14 @@ import { LayerSpecification } from "maplibre-gl"; -import { TYPE_MATCH_EXPR } from "./index"; +import { buildLineGeotypeLayers } from "./styleBuilders"; export function getShippingRouteLayers(sourceId: string, pathArrowSourceId?: string, pointSourceId?: string): LayerSpecification[] { - return [ - { - id: "shipping_route-line", - type: "line", - source: sourceId, - filter: ["all", ["==", ["geometry-type"], "LineString"], ["==", TYPE_MATCH_EXPR, "shipping_route"]], - paint: { - "line-color": [ - "case", - ["boolean", ["feature-state", "selected"], false], "#22c55e", - ["==", ["coalesce", ["get", "entity_id"], ""], ""], "#ef4444", - "#2563eb" - ], - "line-width": ["interpolate", ["linear"], ["zoom"], 1, 2.2, 4, 3.2, 6, 4.2], - "line-opacity": 0.9 - } - }, - { - id: "shipping_route-hit", - type: "line", - source: sourceId, - filter: ["all", ["==", ["geometry-type"], "LineString"], ["==", TYPE_MATCH_EXPR, "shipping_route"]], - paint: { - "line-color": "#ffffff", - "line-width": ["interpolate", ["linear"], ["zoom"], 1, 12, 4, 18, 6, 24], - "line-opacity": 0 - } - }, - { - id: "shipping_route-path-arrow-fill", - type: "fill", - source: pathArrowSourceId!, - filter: ["==", TYPE_MATCH_EXPR, "shipping_route"], - paint: { - "fill-color": [ - "case", - ["boolean", ["feature-state", "selected"], false], "#22c55e", - ["==", ["coalesce", ["get", "entity_id"], ""], ""], "#ef4444", - "#2563eb" - ], - "fill-opacity": [ - "case", - ["boolean", ["feature-state", "selected"], false], 0.92, - 0.82 - ] - } - }, - { - id: "shipping_route-path-arrow-line", - type: "line", - source: pathArrowSourceId!, - filter: ["==", TYPE_MATCH_EXPR, "shipping_route"], - paint: { - "line-color": [ - "case", - ["boolean", ["feature-state", "selected"], false], "#14532d", - "#0f172a" - ], - "line-width": ["interpolate", ["linear"], ["zoom"], 1, 0.45, 4, 0.8, 6, 1.2], - "line-opacity": 0.9 - } - } - ]; + void pointSourceId; + return buildLineGeotypeLayers(sourceId, pathArrowSourceId, { + typeId: "shipping_route", + color: "#0ea5e9", + strokeColor: "#075985", + width: { z1: 2.4, z4: 3.5, z6: 4.7 }, + dasharray: [7, 4], + arrowOpacity: 0.8, + }); } diff --git a/src/uhm/lib/map/styles/geotypes/state.ts b/src/uhm/lib/map/styles/geotypes/state.ts index 1989cd7..7981db7 100644 --- a/src/uhm/lib/map/styles/geotypes/state.ts +++ b/src/uhm/lib/map/styles/geotypes/state.ts @@ -1,40 +1,14 @@ import { LayerSpecification } from "maplibre-gl"; -import { TYPE_MATCH_EXPR } from "./index"; +import { buildPolygonGeotypeLayers } from "./styleBuilders"; export function getStateLayers(sourceId: string, pathArrowSourceId?: string, pointSourceId?: string): LayerSpecification[] { - return [ - { - id: "state-fill", - type: "fill", - source: sourceId, - filter: ["all", ["==", ["geometry-type"], "Polygon"], ["==", TYPE_MATCH_EXPR, "state"]], - paint: { - "fill-color": [ - "case", - ["boolean", ["feature-state", "selected"], false], "#22c55e", - ["==", ["coalesce", ["get", "entity_id"], ""], ""], "#ef4444", - "#0ea5e9" - ], - "fill-opacity": [ - "case", - ["boolean", ["feature-state", "selected"], false], 0.6, - 0.5 - ] - } - }, - { - id: "state-line", - type: "line", - source: sourceId, - filter: ["all", ["==", ["geometry-type"], "Polygon"], ["==", TYPE_MATCH_EXPR, "state"]], - paint: { - "line-color": [ - "case", - ["boolean", ["feature-state", "selected"], false], "#14532d", - "#0c4a6e" - ], - "line-width": 2 - } - } - ]; + void pathArrowSourceId; + void pointSourceId; + return buildPolygonGeotypeLayers(sourceId, { + typeId: "state", + fillColor: "#0891b2", + strokeColor: "#0e7490", + fillOpacity: 0.28, + strokeWidth: { z1: 1.1, z4: 1.7, z6: 2.4 }, + }); } diff --git a/src/uhm/lib/map/styles/geotypes/trade_route.ts b/src/uhm/lib/map/styles/geotypes/trade_route.ts index 77bd73d..983ced0 100644 --- a/src/uhm/lib/map/styles/geotypes/trade_route.ts +++ b/src/uhm/lib/map/styles/geotypes/trade_route.ts @@ -1,68 +1,13 @@ import { LayerSpecification } from "maplibre-gl"; -import { TYPE_MATCH_EXPR } from "./index"; +import { buildLineGeotypeLayers } from "./styleBuilders"; export function getTradeRouteLayers(sourceId: string, pathArrowSourceId?: string, pointSourceId?: string): LayerSpecification[] { - return [ - { - id: "trade_route-line", - type: "line", - source: sourceId, - filter: ["all", ["==", ["geometry-type"], "LineString"], ["==", TYPE_MATCH_EXPR, "trade_route"]], - paint: { - "line-color": [ - "case", - ["boolean", ["feature-state", "selected"], false], "#22c55e", - ["==", ["coalesce", ["get", "entity_id"], ""], ""], "#ef4444", - "#eab308" - ], - "line-width": ["interpolate", ["linear"], ["zoom"], 1, 2.2, 4, 3.2, 6, 4.2], - "line-opacity": 0.9 - } - }, - { - id: "trade_route-hit", - type: "line", - source: sourceId, - filter: ["all", ["==", ["geometry-type"], "LineString"], ["==", TYPE_MATCH_EXPR, "trade_route"]], - paint: { - "line-color": "#ffffff", - "line-width": ["interpolate", ["linear"], ["zoom"], 1, 12, 4, 18, 6, 24], - "line-opacity": 0 - } - }, - { - id: "trade_route-path-arrow-fill", - type: "fill", - source: pathArrowSourceId!, - filter: ["==", TYPE_MATCH_EXPR, "trade_route"], - paint: { - "fill-color": [ - "case", - ["boolean", ["feature-state", "selected"], false], "#22c55e", - ["==", ["coalesce", ["get", "entity_id"], ""], ""], "#ef4444", - "#eab308" - ], - "fill-opacity": [ - "case", - ["boolean", ["feature-state", "selected"], false], 0.92, - 0.82 - ] - } - }, - { - id: "trade_route-path-arrow-line", - type: "line", - source: pathArrowSourceId!, - filter: ["==", TYPE_MATCH_EXPR, "trade_route"], - paint: { - "line-color": [ - "case", - ["boolean", ["feature-state", "selected"], false], "#14532d", - "#0f172a" - ], - "line-width": ["interpolate", ["linear"], ["zoom"], 1, 0.45, 4, 0.8, 6, 1.2], - "line-opacity": 0.9 - } - } - ]; + void pointSourceId; + return buildLineGeotypeLayers(sourceId, pathArrowSourceId, { + typeId: "trade_route", + color: "#eab308", + strokeColor: "#854d0e", + dasharray: [5, 3], + arrowOpacity: 0.78, + }); } diff --git a/src/uhm/lib/map/styles/geotypes/war.ts b/src/uhm/lib/map/styles/geotypes/war.ts index a261e5f..1e2f0fc 100644 --- a/src/uhm/lib/map/styles/geotypes/war.ts +++ b/src/uhm/lib/map/styles/geotypes/war.ts @@ -1,40 +1,14 @@ import { LayerSpecification } from "maplibre-gl"; -import { TYPE_MATCH_EXPR } from "./index"; +import { buildPolygonGeotypeLayers } from "./styleBuilders"; export function getWarLayers(sourceId: string, pathArrowSourceId?: string, pointSourceId?: string): LayerSpecification[] { - return [ - { - id: "war-fill", - type: "fill", - source: sourceId, - filter: ["all", ["==", ["geometry-type"], "Polygon"], ["==", TYPE_MATCH_EXPR, "war"]], - paint: { - "fill-color": [ - "case", - ["boolean", ["feature-state", "selected"], false], "#22c55e", - ["==", ["coalesce", ["get", "entity_id"], ""], ""], "#ef4444", - "#dc2626" - ], - "fill-opacity": [ - "case", - ["boolean", ["feature-state", "selected"], false], 0.6, - 0.3 - ] - } - }, - { - id: "war-line", - type: "line", - source: sourceId, - filter: ["all", ["==", ["geometry-type"], "Polygon"], ["==", TYPE_MATCH_EXPR, "war"]], - paint: { - "line-color": [ - "case", - ["boolean", ["feature-state", "selected"], false], "#14532d", - "#7f1d1d" - ], - "line-width": 2 - } - } - ]; + void pathArrowSourceId; + void pointSourceId; + return buildPolygonGeotypeLayers(sourceId, { + typeId: "war", + fillColor: "#dc2626", + strokeColor: "#7f1d1d", + fillOpacity: 0.26, + dasharray: [5, 2], + }); }