fix: stop use int key in local

This commit is contained in:
taDuc
2026-05-13 04:17:22 +07:00
parent 33a866b659
commit 41e43d4974
25 changed files with 289 additions and 807 deletions
@@ -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) {
+47 -14
View File
@@ -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<GeometrySnapshot, "id" | "source" | "operation">),
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<string>();
const deduped: GeometryEntitySnapshot[] = [];
+17
View File
@@ -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;
}
@@ -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,
});
}
+10 -36
View File
@@ -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 },
});
}
@@ -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,
});
}
+9 -36
View File
@@ -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,
});
}
@@ -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,
});
}
+10 -36
View File
@@ -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 },
});
}
@@ -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,
});
}
+9 -36
View File
@@ -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,
});
}
@@ -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,
});
}
@@ -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],
});
}
@@ -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,
});
}
@@ -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,
});
}
@@ -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,
});
}
+10 -36
View File
@@ -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 },
});
}
+9 -64
View File
@@ -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,
});
}
+10 -36
View File
@@ -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],
});
}