diff --git a/src/app/editor/[id]/page.tsx b/src/app/editor/[id]/page.tsx
index 37e4497..9e0ce6e 100644
--- a/src/app/editor/[id]/page.tsx
+++ b/src/app/editor/[id]/page.tsx
@@ -495,7 +495,7 @@ function EditorPageContent() {
initialMapViewState: previewSession?.mapViewState ?? null,
selectedStageId: previewSession?.selectedStageId ?? replaySelection.stageId,
selectedStepIndex: previewSession?.selectedStepIndex ?? replaySelection.stepIndex,
- onSelectStep: () => {},
+ onSelectStep: () => { },
});
const {
hiddenGeometryIds: replayPreviewHiddenGeometryIds,
@@ -788,7 +788,7 @@ function EditorPageContent() {
// QUY TẮC: Geo chọn đầu tiên là geo main.
const finalSelectedIds = Array.from(new Set([...selectedFeatureIds, featureId]));
const triggerId = selectedFeatureIds.length > 0 ? selectedFeatureIds[0] : featureId;
-
+
setReplayFeatureId(triggerId);
setReplaySelection({ stageId: null, stepIndex: null });
editor.switchReplayContext(triggerId, finalSelectedIds);
@@ -997,7 +997,7 @@ function EditorPageContent() {
if (isReplayEditMode && hideOutside) {
// Trong mode replay, ta chỉ hiển thị những gì có trong draft của replay đó
const currentReplayFeatureIds = new Set(editor.draft.features.map(f => String(f.properties.id)));
-
+
// Ẩn tất cả các geo KHÔNG nằm trong draft replay hiện tại
Object.keys(visibility).forEach(fid => {
if (fid === String(replayFeatureId)) {
@@ -1062,7 +1062,7 @@ function EditorPageContent() {
// Xóa pending submission để backend cho phép mở editor lại.
const unlockByDeletingPendingSubmission = useCallback(async () => {
if (!blockedPendingSubmissionId) return;
- const confirmed = window.confirm("Xoa submission PENDING de unlock editor? Hanh dong nay khong the hoan tac.");
+ const confirmed = window.confirm("Bạn chắc chắn muốn xóa Submition? - việc này không làm hỏng project của bạn");
if (!confirmed) return;
try {
setIsOpeningSection(true);
@@ -1599,7 +1599,7 @@ function EditorPageContent() {
}
const prevBindingIds = normalizeFeatureBindingIds(targetFeature);
-
+
// Merge prevBindingIds with sourceIds (which are strings of selected features)
// filter out targetId itself (we can't bind a geometry to itself)
const newSources = sourceIds.map(String).filter((x) => x !== idStr);
@@ -1966,6 +1966,127 @@ function EditorPageContent() {
[entities, labelContextBaseDraft]
);
+ if (blockedPendingSubmissionId) {
+ return (
+
+
+
+
+
+
+
Editor đang bị khóa
+
+
+ Project này đang có submission ở trạng thái PENDING (id: {blockedPendingSubmissionId}). Theo quy trình làm việc, khi submission đang pending thì không được tạo submission/commit mới và không được vào editor.
+
+
+ { if (!isOpeningSection) e.currentTarget.style.background = "#dc2626"; }}
+ onMouseLeave={(e) => { if (!isOpeningSection) e.currentTarget.style.background = "#ef4444"; }}
+ >
+ Xóa submission pending để unlock
+
+ router.push("/user/projects")}
+ style={{
+ padding: "10px 16px",
+ borderRadius: 6,
+ border: "1px solid #334155",
+ background: "#1e293b",
+ color: "#f1f5f9",
+ fontWeight: 600,
+ fontSize: 14,
+ cursor: "pointer",
+ transition: "background 0.2s",
+ }}
+ onMouseEnter={(e) => e.currentTarget.style.background = "#334155"}
+ onMouseLeave={(e) => e.currentTarget.style.background = "#1e293b"}
+ >
+ Quay lại danh sách projects
+
+
+
+
+ );
+ }
+
+ if (isOpeningSection || !activeSection) {
+ return (
+
+ {!activeSection && !isOpeningSection ? (
+
+
Lỗi tải Project
+
+ {entityStatus || "Không thể tải thông tin dự án. Vui lòng thử lại hoặc quay lại danh sách."}
+
+
+
+ Thử lại
+
+ router.push("/user/projects")}
+ style={{
+ padding: "8px 16px",
+ borderRadius: 6,
+ background: "#1e293b",
+ color: "#f1f5f9",
+ border: "1px solid #334155",
+ fontWeight: "600",
+ cursor: "pointer"
+ }}
+ >
+ Quay lại
+
+
+
+ ) : (
+ <>
+
+
+
+ Đang tải dữ liệu bản đồ...
+
+ >
+ )}
+
+ );
+ }
+
return (
{!isReplayEditMode && !isReplayPreviewMode ? (
@@ -1980,7 +2101,7 @@ function EditorPageContent() {
onRestoreCommit={restoreCommit}
isSaving={isSaving}
isSubmitting={isSubmitting}
- sectionTitle={activeSection?.title || "Đang tải project"}
+ sectionTitle={activeSection.title || "Đang tải project"}
projectStatus={projectState?.status || "editing"}
commitTitle={commitTitle}
onCommitTitleChange={setCommitTitle}
@@ -2019,8 +2140,8 @@ function EditorPageContent() {
previewPlaybackSpeed={1}
onPlayPreviewFromStart={() => openReplayPreview("start")}
onPlayPreviewFromSelection={() => openReplayPreview("selection")}
- onStopPreview={() => {}}
- onResetPreview={() => {}}
+ onStopPreview={() => { }}
+ onResetPreview={() => { }}
/>
) : null}
- {blockedPendingSubmissionId ? (
-
-
-
Editor dang bi khoa
-
- Project nay dang co submission o trang thai PENDING (id:{" "}
- {blockedPendingSubmissionId}). Theo BE moi, khi
- submission dang pending thi khong duoc tao submission/commit moi va khong duoc vao editor.
-
-
-
- Xoa submission pending de unlock
-
- router.push("/user/projects")}
- style={{
- padding: "10px 12px",
- borderRadius: 6,
- border: "1px solid #334155",
- background: "#111827",
- color: "white",
- cursor: "pointer",
- }}
- >
- Quay lai danh sach projects
-
-
-
-
- ) : null}
-
- {!blockedPendingSubmissionId ? (
-
- {isBackgroundVisibilityReady ? (
-
{
- if (Array.isArray(id)) {
- editor.deleteFeatures(id);
- } else {
- editor.deleteFeature(id);
- }
- }}
- onHideFeature={handleHideGeometryLocal}
- onUpdateFeature={editor.updateFeature}
- backgroundVisibility={backgroundVisibility}
- geometryVisibility={effectiveGeometryVisibility}
- applyGeometryBindingFilter={isReplayEditMode || isReplayPreviewMode ? false : geometryBindingFilterEnabled}
- highlightFeatures={null}
- focusFeatureCollection={geometryFocusRequest?.collection || null}
- focusRequestKey={geometryFocusRequest?.key ?? null}
- focusPadding={96}
- imageOverlay={imageOverlay}
- onImageOverlayChange={setImageOverlay}
- onBindGeometries={handleBindGeometries}
- />
- ) : (
-
- )}
- {isReplayPreviewMode ? (
-
- ) : null}
- {isReplayPreviewMode && replayPreview.sidebarOpen ? (
-
- {
- setPreviewWikiError(null);
- replayPreview.closeWikiPanel();
- }}
- onWikiLinkRequest={handleReplayPreviewWikiLinkRequest}
- />
-
- ) : null}
- {!isReplayPreviewMode || replayPreview.timelineVisible ? (
-
+ {isBackgroundVisibilityReady ? (
+ {
+ if (Array.isArray(id)) {
+ editor.deleteFeatures(id);
+ } else {
+ editor.deleteFeature(id);
}
+ }}
+ onHideFeature={handleHideGeometryLocal}
+ onUpdateFeature={editor.updateFeature}
+ backgroundVisibility={backgroundVisibility}
+ geometryVisibility={effectiveGeometryVisibility}
+ applyGeometryBindingFilter={isReplayEditMode || isReplayPreviewMode ? false : geometryBindingFilterEnabled}
+ highlightFeatures={null}
+ focusFeatureCollection={geometryFocusRequest?.collection || null}
+ focusRequestKey={geometryFocusRequest?.key ?? null}
+ focusPadding={96}
+ imageOverlay={imageOverlay}
+ onImageOverlayChange={setImageOverlay}
+ onBindGeometries={handleBindGeometries}
+ />
+ ) : (
+
+ )}
+ {isReplayPreviewMode ? (
+
+ ) : null}
+ {isReplayPreviewMode && replayPreview.sidebarOpen ? (
+
+ {
+ setPreviewWikiError(null);
+ replayPreview.closeWikiPanel();
+ }}
+ onWikiLinkRequest={handleReplayPreviewWikiLinkRequest}
/>
- ) : null}
-
- ) : null}
+
+ ) : null}
+ {!isReplayPreviewMode || replayPreview.timelineVisible ? (
+
+ ) : null}
+
{!isReplayEditMode && !isReplayPreviewMode ? (
<>
{
- // dragging handle (between map and right panel): moving right increases right panel width
setRightPanelWidth((prev) => clampNumber(prev - deltaX, 260, 720));
}}
/>
diff --git a/src/uhm/doc/map_styling.md b/src/uhm/doc/map_styling.md
index aa32829..d868fb3 100644
--- a/src/uhm/doc/map_styling.md
+++ b/src/uhm/doc/map_styling.md
@@ -48,33 +48,22 @@ Geotype render hiện được tập trung ở `getAllGeotypeLayers(...)` trong
Các type đang được register:
- `defense_line`
-- `attack_route`
+- `military_route`
- `retreat_route`
-- `invasion_route`
- `migration_route`
-- `refugee_route`
- `trade_route`
-- `shipping_route`
- `country`
- `state`
-- `empire`
-- `kingdom`
- `faction`
-- `war`
- `battle`
-- `civilization`
- `rebellion_zone`
-- `person_deathplace`
-- `person_birthplace`
-- `person_activity`
+- `person_event`
- `temple`
- `capital`
- `city`
-- `fortress`
-- `castle`
+- `fortification`
- `ruin`
- `port`
-- `bridge`
`GEOMETRY_TYPE_OPTIONS` trong `src/uhm/lib/map/geo/geometryTypeOptions.ts` phải khớp với tập geotype này nếu muốn user chọn được từ UI.
diff --git a/src/uhm/lib/editor/project/useProjectCommands.ts b/src/uhm/lib/editor/project/useProjectCommands.ts
index ece490e..cde3376 100644
--- a/src/uhm/lib/editor/project/useProjectCommands.ts
+++ b/src/uhm/lib/editor/project/useProjectCommands.ts
@@ -74,14 +74,7 @@ export function useProjectCommands(options: Options) {
return;
}
- const orphanGeometries = findOrphanGeometries(options.editor.mainDraft);
- if (orphanGeometries.length > 0) {
- const firstOrphan = orphanGeometries[0];
- state.setSelectedFeatureIds([firstOrphan.id]);
- state.setEntityFormStatus("Geometry này chưa bind entity.");
- state.setEntityStatus(formatOrphanGeometryMessage("Commit", orphanGeometries));
- return;
- }
+
const geometryChanges = options.editor.buildPayload();
state.setIsSaving(true);
@@ -221,14 +214,7 @@ export function useProjectCommands(options: Options) {
return;
}
- const orphanGeometries = findOrphanGeometries(options.editor.mainDraft);
- if (orphanGeometries.length > 0) {
- const firstOrphan = orphanGeometries[0];
- state.setSelectedFeatureIds([firstOrphan.id]);
- state.setEntityFormStatus("Geometry này chưa bind entity.");
- state.setEntityStatus(formatOrphanGeometryMessage("Submit", orphanGeometries));
- return;
- }
+
state.setIsSubmitting(true);
state.setEntityStatus(null);
@@ -305,33 +291,7 @@ export function useProjectCommands(options: Options) {
};
}
-type OrphanGeometry = {
- id: Feature["properties"]["id"];
- label: string;
-};
-function findOrphanGeometries(draft: FeatureCollection): OrphanGeometry[] {
- const rows: OrphanGeometry[] = [];
-
- for (const feature of draft.features || []) {
- const entityIds = normalizeFeatureEntityIds(feature);
- if (entityIds.length > 0) continue;
-
- const id = feature.properties.id;
- rows.push({
- id,
- label: String(id),
- });
- }
-
- return rows;
-}
-
-function formatOrphanGeometryMessage(action: "Commit" | "Submit", rows: OrphanGeometry[]): string {
- const sample = rows.slice(0, 8).map((row) => row.label).join(", ");
- const more = rows.length > 8 ? `, ... (+${rows.length - 8})` : "";
- return `Không thể ${action}: còn ${rows.length} geometry chưa bind entity. Hãy bind entity cho: ${sample}${more}.`;
-}
function toEditorSessionSnapshot(snapshot: EditorSnapshot): EditorSnapshot {
return {
diff --git a/src/uhm/lib/map/engines/circleEngine.ts b/src/uhm/lib/map/engines/circleEngine.ts
index 944ce65..58d9299 100644
--- a/src/uhm/lib/map/engines/circleEngine.ts
+++ b/src/uhm/lib/map/engines/circleEngine.ts
@@ -23,6 +23,7 @@ export function initCircle(
// Xóa dữ liệu preview circle trên map.
const clearPreview = () => {
+ if (!map.isStyleLoaded()) return;
(map.getSource("draw-circle-preview") as maplibregl.GeoJSONSource | undefined)?.setData(
EMPTY_PREVIEW
);
@@ -32,7 +33,7 @@ export function initCircle(
const releaseDragPan = () => {
if (!dragPanDisabledByCircle) return;
dragPanDisabledByCircle = false;
- if (!map.dragPan.isEnabled()) {
+ if (map.isStyleLoaded() && !map.dragPan.isEnabled()) {
map.dragPan.enable();
}
};
@@ -53,6 +54,7 @@ export function initCircle(
return;
}
+ if (!map.isStyleLoaded()) return;
const ring = buildCircleRing(center, radiusMeters, CIRCLE_SEGMENTS);
(map.getSource("draw-circle-preview") as maplibregl.GeoJSONSource | undefined)?.setData({
type: "FeatureCollection",
@@ -91,7 +93,7 @@ export function initCircle(
const onMouseMove = (e: maplibregl.MapMouseEvent) => {
const canvas = map.getCanvas();
if (getMode() !== "add-circle") {
- if (canvas.style.cursor === "crosshair") {
+ if (canvas && canvas.style.cursor === "crosshair") {
canvas.style.cursor = "";
}
if (isDragging) {
@@ -100,7 +102,9 @@ export function initCircle(
return;
}
- canvas.style.cursor = "crosshair";
+ if (canvas) {
+ canvas.style.cursor = "crosshair";
+ }
if (!isDragging || !center) return;
radiusMeters = distanceMeters(center, [e.lngLat.lng, e.lngLat.lat]);
@@ -150,13 +154,20 @@ export function initCircle(
document.addEventListener("keydown", onKeyDown);
const cleanup = () => {
- map.off("mousedown", onMouseDown);
- map.off("mousemove", onMouseMove);
- map.off("mouseup", onMouseUp);
- document.removeEventListener("keydown", onKeyDown);
- resetDrawingState();
- if (map.getCanvas().style.cursor === "crosshair") {
- map.getCanvas().style.cursor = "";
+ try {
+ map.off("mousedown", onMouseDown);
+ map.off("mousemove", onMouseMove);
+ map.off("mouseup", onMouseUp);
+ document.removeEventListener("keydown", onKeyDown);
+ resetDrawingState();
+ if (map.isStyleLoaded()) {
+ const canvas = map.getCanvas();
+ if (canvas && canvas.style.cursor === "crosshair") {
+ canvas.style.cursor = "";
+ }
+ }
+ } catch {
+ // ignore
}
};
diff --git a/src/uhm/lib/map/engines/drawingEngine.ts b/src/uhm/lib/map/engines/drawingEngine.ts
index ed5c6ef..d0ea3c7 100644
--- a/src/uhm/lib/map/engines/drawingEngine.ts
+++ b/src/uhm/lib/map/engines/drawingEngine.ts
@@ -12,6 +12,7 @@ export function initDrawing(
let coords: [number, number][] = [];
const clearPreview = () => {
+ if (!map.isStyleLoaded()) return;
(map.getSource("draw-preview") as maplibregl.GeoJSONSource | undefined)?.setData({
type: "FeatureCollection",
features: [],
@@ -39,6 +40,7 @@ export function initDrawing(
function update(c: [number, number][]) {
const closed = closePolygon(c);
+ if (!map.isStyleLoaded()) return;
(map.getSource("draw-preview") as maplibregl.GeoJSONSource)?.setData({
type: "FeatureCollection",
features: [
@@ -130,12 +132,18 @@ export function initDrawing(
document.addEventListener("keydown", onKeyDown);
const cleanup = () => {
- map.boxZoom.enable();
- map.doubleClickZoom.enable();
- map.off("click", onClick);
- map.off("mousemove", onMove);
- document.removeEventListener("keydown", onKeyDown);
- cancelDrawing();
+ try {
+ if (map.isStyleLoaded()) {
+ map.boxZoom.enable();
+ map.doubleClickZoom.enable();
+ }
+ map.off("click", onClick);
+ map.off("mousemove", onMove);
+ document.removeEventListener("keydown", onKeyDown);
+ cancelDrawing();
+ } catch {
+ // ignore
+ }
};
return {
diff --git a/src/uhm/lib/map/engines/editingEngine.ts b/src/uhm/lib/map/engines/editingEngine.ts
index 95f29d2..753b36a 100644
--- a/src/uhm/lib/map/engines/editingEngine.ts
+++ b/src/uhm/lib/map/engines/editingEngine.ts
@@ -37,7 +37,7 @@ export function createEditingEngine(options: {
setDeleteVertexMode(false);
hideContextMenu();
const map = mapRef.current;
- if (!map) return;
+ if (!map || !map.isStyleLoaded()) return;
const empty: GeoJSON.FeatureCollection = { type: "FeatureCollection", features: [] };
(map.getSource("edit-shape") as maplibregl.GeoJSONSource | undefined)?.setData(empty);
(map.getSource("edit-handles") as maplibregl.GeoJSONSource | undefined)?.setData(empty);
@@ -47,7 +47,7 @@ export function createEditingEngine(options: {
const updateEditSources = () => {
const editing = editingRef.current;
const map = mapRef.current;
- if (!editing || !map) return;
+ if (!editing || !map || !map.isStyleLoaded()) return;
let shape: GeoJSON.FeatureCollection;
let handles: GeoJSON.FeatureCollection;
@@ -143,7 +143,7 @@ export function createEditingEngine(options: {
const setDeleteVertexMode = (enabled: boolean) => {
deleteVertexModeRef.current = enabled;
const map = mapRef.current;
- if (!map?.getLayer("edit-handles-circle")) return;
+ if (!map || !map.isStyleLoaded() || !map.getLayer("edit-handles-circle")) return;
map.setPaintProperty("edit-handles-circle", "circle-color", enabled ? "#ef4444" : "#f97316");
map.setPaintProperty("edit-handles-circle", "circle-stroke-color", enabled ? "#7f1d1d" : "#0f172a");
};
diff --git a/src/uhm/lib/map/engines/lineEngine.ts b/src/uhm/lib/map/engines/lineEngine.ts
index 99150cd..201e759 100644
--- a/src/uhm/lib/map/engines/lineEngine.ts
+++ b/src/uhm/lib/map/engines/lineEngine.ts
@@ -18,6 +18,7 @@ export function initLine(
// Xóa dữ liệu preview line.
const clearPreview = () => {
+ if (!map.isStyleLoaded()) return;
(map.getSource("draw-line-preview") as maplibregl.GeoJSONSource | undefined)?.setData(
EMPTY_PREVIEW
);
@@ -36,6 +37,7 @@ export function initLine(
return;
}
+ if (!map.isStyleLoaded()) return;
(map.getSource("draw-line-preview") as maplibregl.GeoJSONSource | undefined)?.setData({
type: "FeatureCollection",
features: [
@@ -91,13 +93,15 @@ export function initLine(
if (coords.length) {
cancelLine();
}
- if (canvas.style.cursor === "crosshair") {
+ if (canvas && canvas.style.cursor === "crosshair") {
canvas.style.cursor = "";
}
return;
}
- canvas.style.cursor = "crosshair";
+ if (canvas) {
+ canvas.style.cursor = "crosshair";
+ }
if (coords.length === 0) return;
const lngLat = e.originalEvent.shiftKey || e.originalEvent.altKey
@@ -133,12 +137,19 @@ export function initLine(
document.addEventListener("keydown", onKeyDown);
const cleanup = () => {
- map.off("click", onClick);
- map.off("mousemove", onMove);
- document.removeEventListener("keydown", onKeyDown);
- cancelLine();
- if (map.getCanvas().style.cursor === "crosshair") {
- map.getCanvas().style.cursor = "";
+ try {
+ map.off("click", onClick);
+ map.off("mousemove", onMove);
+ document.removeEventListener("keydown", onKeyDown);
+ cancelLine();
+ if (map.isStyleLoaded()) {
+ const canvas = map.getCanvas();
+ if (canvas && canvas.style.cursor === "crosshair") {
+ canvas.style.cursor = "";
+ }
+ }
+ } catch {
+ // ignore
}
};
diff --git a/src/uhm/lib/map/engines/pathEngine.ts b/src/uhm/lib/map/engines/pathEngine.ts
index dbc4a68..601c27d 100644
--- a/src/uhm/lib/map/engines/pathEngine.ts
+++ b/src/uhm/lib/map/engines/pathEngine.ts
@@ -18,6 +18,7 @@ export function initPath(
// Xóa dữ liệu preview path.
const clearPreview = () => {
+ if (!map.isStyleLoaded()) return;
(map.getSource("draw-path-preview") as maplibregl.GeoJSONSource | undefined)?.setData(
EMPTY_PREVIEW
);
@@ -30,6 +31,7 @@ export function initPath(
return;
}
+ if (!map.isStyleLoaded()) return;
(map.getSource("draw-path-preview") as maplibregl.GeoJSONSource | undefined)?.setData({
type: "FeatureCollection",
features: [
@@ -92,13 +94,15 @@ export function initPath(
if (coords.length) {
cancelPath();
}
- if (canvas.style.cursor === "crosshair") {
+ if (canvas && canvas.style.cursor === "crosshair") {
canvas.style.cursor = "";
}
return;
}
- canvas.style.cursor = "crosshair";
+ if (canvas) {
+ canvas.style.cursor = "crosshair";
+ }
if (coords.length === 0) return;
const lngLat = e.originalEvent.shiftKey || e.originalEvent.altKey
@@ -134,12 +138,19 @@ export function initPath(
document.addEventListener("keydown", onKeyDown);
const cleanup = () => {
- map.off("click", onClick);
- map.off("mousemove", onMove);
- document.removeEventListener("keydown", onKeyDown);
- cancelPath();
- if (map.getCanvas().style.cursor === "crosshair") {
- map.getCanvas().style.cursor = "";
+ try {
+ map.off("click", onClick);
+ map.off("mousemove", onMove);
+ document.removeEventListener("keydown", onKeyDown);
+ cancelPath();
+ if (map.isStyleLoaded()) {
+ const canvas = map.getCanvas();
+ if (canvas && canvas.style.cursor === "crosshair") {
+ canvas.style.cursor = "";
+ }
+ }
+ } catch {
+ // ignore
}
};
diff --git a/src/uhm/lib/map/engines/pointEngine.ts b/src/uhm/lib/map/engines/pointEngine.ts
index f8ef9f8..ed0799b 100644
--- a/src/uhm/lib/map/engines/pointEngine.ts
+++ b/src/uhm/lib/map/engines/pointEngine.ts
@@ -41,10 +41,17 @@ export function initPoint(
map.on("mousemove", onMove);
return () => {
- map.off("click", onClick);
- map.off("mousemove", onMove);
- if (map.getCanvas().style.cursor === "crosshair") {
- map.getCanvas().style.cursor = "";
+ try {
+ map.off("click", onClick);
+ map.off("mousemove", onMove);
+ if (map.isStyleLoaded()) {
+ const canvas = map.getCanvas();
+ if (canvas && canvas.style.cursor === "crosshair") {
+ canvas.style.cursor = "";
+ }
+ }
+ } catch {
+ // ignore
}
};
}
diff --git a/src/uhm/lib/map/engines/selectingEngine.ts b/src/uhm/lib/map/engines/selectingEngine.ts
index 4fdbfb2..597bc8b 100644
--- a/src/uhm/lib/map/engines/selectingEngine.ts
+++ b/src/uhm/lib/map/engines/selectingEngine.ts
@@ -150,6 +150,7 @@ export function initSelect(
}
function setSelectionStateForId(id: string | number, selected: boolean) {
+ if (!map.isStyleLoaded()) return;
for (const source of FEATURE_STATE_SOURCES) {
if (!map.getSource(source)) continue;
map.setFeatureState({ source, id }, { selected });
@@ -194,13 +195,19 @@ export function initSelect(
}
const cleanup = () => {
- map.off("click", onClick);
- map.off("mousemove", onMove);
- if (hasContextActions) {
- map.off("contextmenu", onRightClick);
+ try {
+ map.off("click", onClick);
+ map.off("mousemove", onMove);
+ if (hasContextActions) {
+ map.off("contextmenu", onRightClick);
+ }
+ if (map.isStyleLoaded()) {
+ clearSelection(false);
+ }
+ hideContextMenu();
+ } catch {
+ // ignore
}
- clearSelection(false);
- hideContextMenu();
};
return {
diff --git a/src/uhm/lib/map/geo/geoTypeMap.json b/src/uhm/lib/map/geo/geoTypeMap.json
index 0bd5164..0c27ce3 100644
--- a/src/uhm/lib/map/geo/geoTypeMap.json
+++ b/src/uhm/lib/map/geo/geoTypeMap.json
@@ -1,33 +1,28 @@
[
{ "type_key": "defense_line", "geo_type_code": 1 },
- { "type_key": "attack_route", "geo_type_code": 2 },
+ { "type_key": "military_route", "geo_type_code": 2 },
{ "type_key": "retreat_route", "geo_type_code": 3 },
- { "type_key": "invasion_route", "geo_type_code": 4 },
{ "type_key": "migration_route", "geo_type_code": 5 },
- { "type_key": "refugee_route", "geo_type_code": 6 },
{ "type_key": "trade_route", "geo_type_code": 7 },
- { "type_key": "shipping_route", "geo_type_code": 8 },
{ "type_key": "country", "geo_type_code": 9, "fixed": true },
{ "type_key": "state", "geo_type_code": 10 },
- { "type_key": "empire", "geo_type_code": 11 },
- { "type_key": "kingdom", "geo_type_code": 12 },
{ "type_key": "faction", "geo_type_code": 28 },
- { "type_key": "war", "geo_type_code": 13 },
{ "type_key": "battle", "geo_type_code": 14 },
- { "type_key": "civilization", "geo_type_code": 15 },
{ "type_key": "rebellion_zone", "geo_type_code": 16 },
- { "type_key": "person_deathplace", "geo_type_code": 17 },
- { "type_key": "person_birthplace", "geo_type_code": 18 },
- { "type_key": "person_activity", "geo_type_code": 19 },
+ { "type_key": "person_event", "geo_type_code": 17 },
+ { "type_key": "person_event", "geo_type_code": 18 },
+ { "type_key": "person_event", "geo_type_code": 19 },
+
{ "type_key": "temple", "geo_type_code": 20 },
{ "type_key": "capital", "geo_type_code": 21 },
{ "type_key": "city", "geo_type_code": 22 },
- { "type_key": "fortress", "geo_type_code": 23 },
- { "type_key": "castle", "geo_type_code": 24 },
+
+ { "type_key": "fortification", "geo_type_code": 23 },
+ { "type_key": "fortification", "geo_type_code": 24 },
+
{ "type_key": "ruin", "geo_type_code": 25 },
- { "type_key": "port", "geo_type_code": 26 },
- { "type_key": "bridge", "geo_type_code": 27 }
+ { "type_key": "port", "geo_type_code": 26 }
]
diff --git a/src/uhm/lib/map/geo/geoTypeMap.ts b/src/uhm/lib/map/geo/geoTypeMap.ts
index da849e7..5c22b1f 100644
--- a/src/uhm/lib/map/geo/geoTypeMap.ts
+++ b/src/uhm/lib/map/geo/geoTypeMap.ts
@@ -40,6 +40,15 @@ export function geoTypeCodeToTypeKey(code: number | null | undefined): string |
return KEY_BY_CODE.get(Math.trunc(code)) ?? null;
}
+const DEPRECATED_MAPPING: Record = {
+ attack_route: "military_route",
+ person_birthplace: "person_event",
+ person_deathplace: "person_event",
+ person_activity: "person_event",
+ fortress: "fortification",
+ castle: "fortification",
+};
+
export function normalizeGeoTypeKey(value: unknown): string | null {
if (typeof value === "number") {
return geoTypeCodeToTypeKey(value);
@@ -54,5 +63,14 @@ export function normalizeGeoTypeKey(value: unknown): string | null {
return geoTypeCodeToTypeKey(Number(normalized));
}
+ if (normalized in DEPRECATED_MAPPING) {
+ return DEPRECATED_MAPPING[normalized];
+ }
+
+ const code = CODE_BY_KEY.get(normalized);
+ if (code !== undefined) {
+ return KEY_BY_CODE.get(code) ?? normalized;
+ }
+
return normalized;
}
diff --git a/src/uhm/lib/map/geo/geometryTypeOptions.ts b/src/uhm/lib/map/geo/geometryTypeOptions.ts
index 0e555c4..d0a56c1 100644
--- a/src/uhm/lib/map/geo/geometryTypeOptions.ts
+++ b/src/uhm/lib/map/geo/geometryTypeOptions.ts
@@ -62,37 +62,25 @@ const RAW_GEOMETRY_TYPE_OPTIONS: Array<{
geometryPreset: GeometryPreset;
}> = [
{ value: "defense_line", label: "Defense Line", groupId: "line", geometryPreset: "line" },
-
- { value: "attack_route", label: "Attack Route", groupId: "line", geometryPreset: "line" },
+ { value: "military_route", label: "Military Route", groupId: "line", geometryPreset: "line" },
{ value: "retreat_route", label: "Retreat Route", groupId: "line", geometryPreset: "line" },
- { value: "invasion_route", label: "Invasion Route", groupId: "line", geometryPreset: "line" },
{ value: "migration_route", label: "Migration Route", groupId: "line", geometryPreset: "line" },
- { value: "refugee_route", label: "Refugee Route", groupId: "line", geometryPreset: "line" },
{ value: "trade_route", label: "Trade Route", groupId: "line", geometryPreset: "line" },
- { value: "shipping_route", label: "Shipping Route", groupId: "line", geometryPreset: "line" },
{ value: "country", label: "Country", groupId: "polygon", geometryPreset: "polygon" },
{ value: "state", label: "State", groupId: "polygon", geometryPreset: "polygon" },
- { value: "empire", label: "Empire", groupId: "polygon", geometryPreset: "polygon" },
- { value: "kingdom", label: "Kingdom", groupId: "polygon", geometryPreset: "polygon" },
{ value: "faction", label: "Faction", groupId: "polygon", geometryPreset: "polygon" },
- { value: "war", label: "War", groupId: "circle", geometryPreset: "circle-area" },
{ value: "battle", label: "Battle", groupId: "circle", geometryPreset: "circle-area" },
- { value: "civilization", label: "Civilization", groupId: "circle", geometryPreset: "circle-area" },
{ value: "rebellion_zone", label: "Rebellion Zone", groupId: "circle", geometryPreset: "circle-area" },
- { value: "person_deathplace", label: "Person Deathplace", groupId: "point", geometryPreset: "point" },
- { value: "person_birthplace", label: "Person Birthplace", groupId: "point", geometryPreset: "point" },
- { value: "person_activity", label: "Person Activity", groupId: "point", geometryPreset: "point" },
+ { value: "person_event", label: "Person Event", groupId: "point", geometryPreset: "point" },
{ value: "temple", label: "Temple", groupId: "point", geometryPreset: "point" },
{ value: "capital", label: "Capital", groupId: "point", geometryPreset: "point" },
{ value: "city", label: "City", groupId: "point", geometryPreset: "point" },
- { value: "fortress", label: "Fortress", groupId: "point", geometryPreset: "point" },
- { value: "castle", label: "Castle", groupId: "point", geometryPreset: "point" },
+ { value: "fortification", label: "Fortification", groupId: "point", geometryPreset: "point" },
{ value: "ruin", label: "Ruin", groupId: "point", geometryPreset: "point" },
{ value: "port", label: "Port", groupId: "point", geometryPreset: "point" },
- { value: "bridge", label: "Bridge", groupId: "point", geometryPreset: "point" },
];
export const GEOMETRY_TYPE_OPTIONS: GeometryTypeOption[] = RAW_GEOMETRY_TYPE_OPTIONS.map((item) => ({
diff --git a/src/uhm/lib/map/styles/geotypeLayers.ts b/src/uhm/lib/map/styles/geotypeLayers.ts
index f854b91..0dba6a5 100644
--- a/src/uhm/lib/map/styles/geotypeLayers.ts
+++ b/src/uhm/lib/map/styles/geotypeLayers.ts
@@ -3,33 +3,22 @@ export const TYPE_MATCH_EXPR: maplibregl.ExpressionSpecification = ["coalesce",
export { ensurePointGeotypeIcons } from "./shared/pointStyle";
import { getDefenseLineLayers } from "./geotypes/defense_line";
-import { getAttackRouteLayers } from "./geotypes/attack_route";
+import { getMilitaryRouteLayers } from "./geotypes/military_route";
import { getRetreatRouteLayers } from "./geotypes/retreat_route";
-import { getInvasionRouteLayers } from "./geotypes/invasion_route";
import { getMigrationRouteLayers } from "./geotypes/migration_route";
-import { getRefugeeRouteLayers } from "./geotypes/refugee_route";
import { getTradeRouteLayers } from "./geotypes/trade_route";
-import { getShippingRouteLayers } from "./geotypes/shipping_route";
import { getCountryLayers } from "./geotypes/country";
import { getStateLayers } from "./geotypes/state";
-import { getEmpireLayers } from "./geotypes/empire";
-import { getKingdomLayers } from "./geotypes/kingdom";
import { getFactionLayers } from "./geotypes/faction";
-import { getWarLayers } from "./geotypes/war";
import { getBattleLayers } from "./geotypes/battle";
-import { getCivilizationLayers } from "./geotypes/civilization";
import { getRebellionZoneLayers } from "./geotypes/rebellion_zone";
-import { getPersonDeathplaceLayers } from "./geotypes/person_deathplace";
-import { getPersonBirthplaceLayers } from "./geotypes/person_birthplace";
-import { getPersonActivityLayers } from "./geotypes/person_activity";
+import { getPersonEventLayers } from "./geotypes/person_event";
import { getTempleLayers } from "./geotypes/temple";
import { getCapitalLayers } from "./geotypes/capital";
import { getCityLayers } from "./geotypes/city";
-import { getFortressLayers } from "./geotypes/fortress";
-import { getCastleLayers } from "./geotypes/castle";
+import { getFortificationLayers } from "./geotypes/fortification";
import { getRuinLayers } from "./geotypes/ruin";
import { getPortLayers } from "./geotypes/port";
-import { getBridgeLayers } from "./geotypes/bridge";
import { getLineLabelLayers } from "./shared/lineLabels";
import { getPolygonLabelLayers } from "./shared/polygonLabels";
@@ -39,32 +28,21 @@ export function getAllGeotypeLayers(sourceId: string, pathArrowSourceId?: string
return [
...getCountryLayers(sourceId, pathArrowSourceId, pointSourceId),
...getStateLayers(sourceId, pathArrowSourceId, pointSourceId),
- ...getEmpireLayers(sourceId, pathArrowSourceId, pointSourceId),
- ...getKingdomLayers(sourceId, pathArrowSourceId, pointSourceId),
...getFactionLayers(sourceId, pathArrowSourceId, pointSourceId),
- ...getWarLayers(sourceId, pathArrowSourceId, pointSourceId),
...getBattleLayers(sourceId, pathArrowSourceId, pointSourceId),
- ...getCivilizationLayers(sourceId, pathArrowSourceId, pointSourceId),
...getRebellionZoneLayers(sourceId, pathArrowSourceId, pointSourceId),
...getDefenseLineLayers(sourceId, pathArrowSourceId, pointSourceId),
- ...getAttackRouteLayers(sourceId, pathArrowSourceId, pointSourceId),
+ ...getMilitaryRouteLayers(sourceId, pathArrowSourceId, pointSourceId),
...getRetreatRouteLayers(sourceId, pathArrowSourceId, pointSourceId),
- ...getInvasionRouteLayers(sourceId, pathArrowSourceId, pointSourceId),
...getMigrationRouteLayers(sourceId, pathArrowSourceId, pointSourceId),
- ...getRefugeeRouteLayers(sourceId, pathArrowSourceId, pointSourceId),
...getTradeRouteLayers(sourceId, pathArrowSourceId, pointSourceId),
- ...getShippingRouteLayers(sourceId, pathArrowSourceId, pointSourceId),
- ...getPersonDeathplaceLayers(sourceId, pathArrowSourceId, pointSourceId),
- ...getPersonBirthplaceLayers(sourceId, pathArrowSourceId, pointSourceId),
- ...getPersonActivityLayers(sourceId, pathArrowSourceId, pointSourceId),
+ ...getPersonEventLayers(sourceId, pathArrowSourceId, pointSourceId),
...getTempleLayers(sourceId, pathArrowSourceId, pointSourceId),
...getCapitalLayers(sourceId, pathArrowSourceId, pointSourceId),
...getCityLayers(sourceId, pathArrowSourceId, pointSourceId),
- ...getFortressLayers(sourceId, pathArrowSourceId, pointSourceId),
- ...getCastleLayers(sourceId, pathArrowSourceId, pointSourceId),
+ ...getFortificationLayers(sourceId, pathArrowSourceId, pointSourceId),
...getRuinLayers(sourceId, pathArrowSourceId, pointSourceId),
- ...getPortLayers(sourceId, pathArrowSourceId, pointSourceId),
- ...getBridgeLayers(sourceId, pathArrowSourceId, pointSourceId)
+ ...getPortLayers(sourceId, pathArrowSourceId, pointSourceId)
];
}
diff --git a/src/uhm/lib/map/styles/geotypes/bridge.ts b/src/uhm/lib/map/styles/geotypes/bridge.ts
deleted file mode 100644
index fac2bae..0000000
--- a/src/uhm/lib/map/styles/geotypes/bridge.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import { LayerSpecification } from "maplibre-gl";
-import { buildPointGeotypeLayers } from "../shared/pointStyle";
-
-export function getBridgeLayers(sourceId: string, pathArrowSourceId?: string, pointSourceId?: string): LayerSpecification[] {
- void sourceId;
- void pathArrowSourceId;
- return buildPointGeotypeLayers("bridge", pointSourceId!);
-}
diff --git a/src/uhm/lib/map/styles/geotypes/castle.ts b/src/uhm/lib/map/styles/geotypes/castle.ts
deleted file mode 100644
index eb8fb89..0000000
--- a/src/uhm/lib/map/styles/geotypes/castle.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import { LayerSpecification } from "maplibre-gl";
-import { buildPointGeotypeLayers } from "../shared/pointStyle";
-
-export function getCastleLayers(sourceId: string, pathArrowSourceId?: string, pointSourceId?: string): LayerSpecification[] {
- void sourceId;
- void pathArrowSourceId;
- return buildPointGeotypeLayers("castle", pointSourceId!);
-}
diff --git a/src/uhm/lib/map/styles/geotypes/civilization.ts b/src/uhm/lib/map/styles/geotypes/civilization.ts
deleted file mode 100644
index b88267e..0000000
--- a/src/uhm/lib/map/styles/geotypes/civilization.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import { LayerSpecification } from "maplibre-gl";
-import { buildPolygonGeotypeLayers } from "../shared/styleBuilders";
-
-export function getCivilizationLayers(sourceId: string, pathArrowSourceId?: string, pointSourceId?: string): LayerSpecification[] {
- 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/empire.ts b/src/uhm/lib/map/styles/geotypes/empire.ts
deleted file mode 100644
index 755558b..0000000
--- a/src/uhm/lib/map/styles/geotypes/empire.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-import { LayerSpecification } from "maplibre-gl";
-import { buildPolygonGeotypeLayers } from "../shared/styleBuilders";
-
-export function getEmpireLayers(sourceId: string, pathArrowSourceId?: string, pointSourceId?: string): LayerSpecification[] {
- 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/fortification.ts b/src/uhm/lib/map/styles/geotypes/fortification.ts
new file mode 100644
index 0000000..c15b223
--- /dev/null
+++ b/src/uhm/lib/map/styles/geotypes/fortification.ts
@@ -0,0 +1,8 @@
+import { LayerSpecification } from "maplibre-gl";
+import { buildPointGeotypeLayers } from "../shared/pointStyle";
+
+export function getFortificationLayers(sourceId: string, pathArrowSourceId?: string, pointSourceId?: string): LayerSpecification[] {
+ void sourceId;
+ void pathArrowSourceId;
+ return buildPointGeotypeLayers("fortification", pointSourceId!);
+}
diff --git a/src/uhm/lib/map/styles/geotypes/fortress.ts b/src/uhm/lib/map/styles/geotypes/fortress.ts
deleted file mode 100644
index 1811456..0000000
--- a/src/uhm/lib/map/styles/geotypes/fortress.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import { LayerSpecification } from "maplibre-gl";
-import { buildPointGeotypeLayers } from "../shared/pointStyle";
-
-export function getFortressLayers(sourceId: string, pathArrowSourceId?: string, pointSourceId?: string): LayerSpecification[] {
- void sourceId;
- void pathArrowSourceId;
- return buildPointGeotypeLayers("fortress", pointSourceId!);
-}
diff --git a/src/uhm/lib/map/styles/geotypes/invasion_route.ts b/src/uhm/lib/map/styles/geotypes/invasion_route.ts
deleted file mode 100644
index c846f75..0000000
--- a/src/uhm/lib/map/styles/geotypes/invasion_route.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import { LayerSpecification } from "maplibre-gl";
-import { buildLineGeotypeLayers } from "../shared/styleBuilders";
-
-export function getInvasionRouteLayers(sourceId: string, pathArrowSourceId?: string, pointSourceId?: string): LayerSpecification[] {
- 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
deleted file mode 100644
index 5c56e05..0000000
--- a/src/uhm/lib/map/styles/geotypes/kingdom.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import { LayerSpecification } from "maplibre-gl";
-import { buildPolygonGeotypeLayers } from "../shared/styleBuilders";
-
-export function getKingdomLayers(sourceId: string, pathArrowSourceId?: string, pointSourceId?: string): LayerSpecification[] {
- 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/attack_route.ts b/src/uhm/lib/map/styles/geotypes/military_route.ts
similarity index 67%
rename from src/uhm/lib/map/styles/geotypes/attack_route.ts
rename to src/uhm/lib/map/styles/geotypes/military_route.ts
index 0ae1cff..5eb8431 100644
--- a/src/uhm/lib/map/styles/geotypes/attack_route.ts
+++ b/src/uhm/lib/map/styles/geotypes/military_route.ts
@@ -1,10 +1,10 @@
import { LayerSpecification } from "maplibre-gl";
import { buildLineGeotypeLayers } from "../shared/styleBuilders";
-export function getAttackRouteLayers(sourceId: string, pathArrowSourceId?: string, pointSourceId?: string): LayerSpecification[] {
+export function getMilitaryRouteLayers(sourceId: string, pathArrowSourceId?: string, pointSourceId?: string): LayerSpecification[] {
void pointSourceId;
return buildLineGeotypeLayers(sourceId, pathArrowSourceId, {
- typeId: "attack_route",
+ typeId: "military_route",
color: "#ef4444",
strokeColor: "#7f1d1d",
width: { z1: 2.6, z4: 3.8, z6: 5 },
diff --git a/src/uhm/lib/map/styles/geotypes/person_activity.ts b/src/uhm/lib/map/styles/geotypes/person_activity.ts
deleted file mode 100644
index 1a0c150..0000000
--- a/src/uhm/lib/map/styles/geotypes/person_activity.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import { LayerSpecification } from "maplibre-gl";
-import { buildPointGeotypeLayers } from "../shared/pointStyle";
-
-export function getPersonActivityLayers(sourceId: string, pathArrowSourceId?: string, pointSourceId?: string): LayerSpecification[] {
- void sourceId;
- void pathArrowSourceId;
- return buildPointGeotypeLayers("person_activity", pointSourceId!);
-}
diff --git a/src/uhm/lib/map/styles/geotypes/person_birthplace.ts b/src/uhm/lib/map/styles/geotypes/person_birthplace.ts
deleted file mode 100644
index 75f09be..0000000
--- a/src/uhm/lib/map/styles/geotypes/person_birthplace.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import { LayerSpecification } from "maplibre-gl";
-import { buildPointGeotypeLayers } from "../shared/pointStyle";
-
-export function getPersonBirthplaceLayers(sourceId: string, pathArrowSourceId?: string, pointSourceId?: string): LayerSpecification[] {
- void sourceId;
- void pathArrowSourceId;
- return buildPointGeotypeLayers("person_birthplace", pointSourceId!);
-}
diff --git a/src/uhm/lib/map/styles/geotypes/person_deathplace.ts b/src/uhm/lib/map/styles/geotypes/person_deathplace.ts
deleted file mode 100644
index 3fd5e15..0000000
--- a/src/uhm/lib/map/styles/geotypes/person_deathplace.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import { LayerSpecification } from "maplibre-gl";
-import { buildPointGeotypeLayers } from "../shared/pointStyle";
-
-export function getPersonDeathplaceLayers(sourceId: string, pathArrowSourceId?: string, pointSourceId?: string): LayerSpecification[] {
- void sourceId;
- void pathArrowSourceId;
- return buildPointGeotypeLayers("person_deathplace", pointSourceId!);
-}
diff --git a/src/uhm/lib/map/styles/geotypes/person_event.ts b/src/uhm/lib/map/styles/geotypes/person_event.ts
new file mode 100644
index 0000000..ea7ab06
--- /dev/null
+++ b/src/uhm/lib/map/styles/geotypes/person_event.ts
@@ -0,0 +1,8 @@
+import { LayerSpecification } from "maplibre-gl";
+import { buildPointGeotypeLayers } from "../shared/pointStyle";
+
+export function getPersonEventLayers(sourceId: string, pathArrowSourceId?: string, pointSourceId?: string): LayerSpecification[] {
+ void sourceId;
+ void pathArrowSourceId;
+ return buildPointGeotypeLayers("person_event", pointSourceId!);
+}
diff --git a/src/uhm/lib/map/styles/geotypes/refugee_route.ts b/src/uhm/lib/map/styles/geotypes/refugee_route.ts
deleted file mode 100644
index a72e8e8..0000000
--- a/src/uhm/lib/map/styles/geotypes/refugee_route.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-import { LayerSpecification } from "maplibre-gl";
-import { buildLineGeotypeLayers } from "../shared/styleBuilders";
-
-export function getRefugeeRouteLayers(sourceId: string, pathArrowSourceId?: string, pointSourceId?: string): LayerSpecification[] {
- 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/shipping_route.ts b/src/uhm/lib/map/styles/geotypes/shipping_route.ts
deleted file mode 100644
index 49a283d..0000000
--- a/src/uhm/lib/map/styles/geotypes/shipping_route.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-import { LayerSpecification } from "maplibre-gl";
-import { buildLineGeotypeLayers } from "../shared/styleBuilders";
-
-export function getShippingRouteLayers(sourceId: string, pathArrowSourceId?: string, pointSourceId?: string): LayerSpecification[] {
- 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/war.ts b/src/uhm/lib/map/styles/geotypes/war.ts
deleted file mode 100644
index 36ef630..0000000
--- a/src/uhm/lib/map/styles/geotypes/war.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-import { LayerSpecification } from "maplibre-gl";
-import { buildPolygonGeotypeLayers } from "../shared/styleBuilders";
-
-export function getWarLayers(sourceId: string, pathArrowSourceId?: string, pointSourceId?: string): LayerSpecification[] {
- void pathArrowSourceId;
- void pointSourceId;
- return buildPolygonGeotypeLayers(sourceId, {
- typeId: "war",
- fillColor: "#dc2626",
- strokeColor: "#7f1d1d",
- fillOpacity: 0.26,
- dasharray: [5, 2],
- });
-}
diff --git a/src/uhm/lib/map/styles/shared/pointStyle.ts b/src/uhm/lib/map/styles/shared/pointStyle.ts
index 3748d80..99d304a 100644
--- a/src/uhm/lib/map/styles/shared/pointStyle.ts
+++ b/src/uhm/lib/map/styles/shared/pointStyle.ts
@@ -2,30 +2,23 @@ import maplibregl, { LayerSpecification } from "maplibre-gl";
import { MAP_EMPHASIS_TEXT_FONT_STACK } from "./textFonts";
export const POINT_GEOTYPE_IDS = [
- "person_birthplace",
- "person_deathplace",
- "person_activity",
+ "person_event",
"temple",
"capital",
"city",
- "fortress",
- "castle",
+ "fortification",
"ruin",
"port",
- "bridge",
] as const;
export type PointGeotypeId = (typeof POINT_GEOTYPE_IDS)[number];
export const POINT_GEOTYPE_ICON_PATHS: Partial> = {
- person_birthplace: "/images/mapIcon/point/house.png",
- person_deathplace: "/images/mapIcon/point/tombstone.png",
- person_activity: "/images/mapIcon/point/flag.png",
+ person_event: "/images/mapIcon/point/flag.png",
temple: "/images/mapIcon/point/temple.png",
capital: "/images/mapIcon/point/capital.png",
city: "/images/mapIcon/point/city.png",
- fortress: "/images/mapIcon/point/fortress.png",
- castle: "/images/mapIcon/point/castle.png",
+ fortification: "/images/mapIcon/point/castle.png",
ruin: "/images/mapIcon/point/ruin.png",
};
@@ -57,21 +50,7 @@ const POINT_GEOMETRY_FILTER: maplibregl.ExpressionSpecification = [
];
const POINT_STYLE_CONFIG: Record = {
- person_birthplace: {
- fill: "#22c55e",
- rim: "#166534",
- iconScale: 1,
- haloRadius: 15,
- drawGlyph: drawHouseGlyph,
- },
- person_deathplace: {
- fill: "#b91c1c",
- rim: "#450a0a",
- iconScale: 1,
- haloRadius: 15,
- drawGlyph: drawMemorialGlyph,
- },
- person_activity: {
+ person_event: {
fill: "#f97316",
rim: "#9a3412",
iconScale: 0.98,
@@ -99,14 +78,7 @@ const POINT_STYLE_CONFIG: Record = {
haloRadius: 15,
drawGlyph: drawCityGlyph,
},
- fortress: {
- fill: "#64748b",
- rim: "#334155",
- iconScale: 1.04,
- haloRadius: 16,
- drawGlyph: drawShieldGlyph,
- },
- castle: {
+ fortification: {
fill: "#7c3aed",
rim: "#4c1d95",
iconScale: 1.04,
@@ -127,13 +99,6 @@ const POINT_STYLE_CONFIG: Record = {
haloRadius: 15,
drawGlyph: drawAnchorGlyph,
},
- bridge: {
- fill: "#b45309",
- rim: "#7c2d12",
- iconScale: 1,
- haloRadius: 14,
- drawGlyph: drawBridgeGlyph,
- },
};
export function buildPointGeotypeLayers(
@@ -320,53 +285,9 @@ function drawGlyphWithOutline(
ctx.restore();
}
-function drawHouseGlyph(ctx: CanvasRenderingContext2D) {
- const img = preloadedImages["person_birthplace"];
- if (img && loadedImageKeys.has("person_birthplace")) {
- ctx.drawImage(img, 0, 0, ICON_CANVAS_SIZE, ICON_CANVAS_SIZE);
- } else {
- ctx.lineWidth = 3.5;
- ctx.beginPath();
- ctx.moveTo(22, 34);
- ctx.lineTo(32, 24);
- ctx.lineTo(42, 34);
- ctx.stroke();
-
- ctx.beginPath();
- ctx.rect(25.5, 34, 13, 9);
- ctx.stroke();
-
- ctx.beginPath();
- ctx.moveTo(32, 43);
- ctx.lineTo(32, 36.5);
- ctx.stroke();
- }
-}
-
-function drawMemorialGlyph(ctx: CanvasRenderingContext2D) {
- const img = preloadedImages["person_deathplace"];
- if (img && loadedImageKeys.has("person_deathplace")) {
- ctx.drawImage(img, 0, 0, ICON_CANVAS_SIZE, ICON_CANVAS_SIZE);
- } else {
- ctx.lineWidth = 3.6;
- ctx.beginPath();
- ctx.moveTo(32, 22);
- ctx.lineTo(32, 43);
- ctx.moveTo(25, 28.5);
- ctx.lineTo(39, 28.5);
- ctx.stroke();
-
- ctx.lineWidth = 2.4;
- ctx.beginPath();
- ctx.moveTo(24, 45);
- ctx.lineTo(40, 45);
- ctx.stroke();
- }
-}
-
function drawFlagGlyph(ctx: CanvasRenderingContext2D) {
- const img = preloadedImages["person_activity"];
- if (img && loadedImageKeys.has("person_activity")) {
+ const img = preloadedImages["person_event"];
+ if (img && loadedImageKeys.has("person_event")) {
ctx.drawImage(img, 0, 0, ICON_CANVAS_SIZE, ICON_CANVAS_SIZE);
} else {
ctx.lineWidth = 3.2;
@@ -462,32 +383,9 @@ function drawCityGlyph(ctx: CanvasRenderingContext2D) {
}
}
-function drawShieldGlyph(ctx: CanvasRenderingContext2D) {
- const img = preloadedImages["fortress"];
- if (img && loadedImageKeys.has("fortress")) {
- ctx.drawImage(img, 0, 0, ICON_CANVAS_SIZE, ICON_CANVAS_SIZE);
- } else {
- ctx.lineWidth = 3.2;
- ctx.beginPath();
- ctx.moveTo(32, 22.5);
- ctx.lineTo(41, 26.5);
- ctx.lineTo(39, 37.5);
- ctx.lineTo(32, 43);
- ctx.lineTo(25, 37.5);
- ctx.lineTo(23, 26.5);
- ctx.closePath();
- ctx.stroke();
-
- ctx.beginPath();
- ctx.moveTo(32, 25);
- ctx.lineTo(32, 39);
- ctx.stroke();
- }
-}
-
function drawCastleGlyph(ctx: CanvasRenderingContext2D) {
- const img = preloadedImages["castle"];
- if (img && loadedImageKeys.has("castle")) {
+ const img = preloadedImages["fortification"];
+ if (img && loadedImageKeys.has("fortification")) {
ctx.drawImage(img, 0, 0, ICON_CANVAS_SIZE, ICON_CANVAS_SIZE);
} else {
ctx.lineWidth = 3;
diff --git a/src/uhm/lib/map/styles/style.ts b/src/uhm/lib/map/styles/style.ts
index 31b420c..f27ccb4 100644
--- a/src/uhm/lib/map/styles/style.ts
+++ b/src/uhm/lib/map/styles/style.ts
@@ -27,50 +27,34 @@ export const COUNTRY_FILL_COLOR_EXPRESSION: maplibregl.ExpressionSpecification =
export const POLYGON_FILL_BY_TYPE: Record = {
country: "#2563eb",
state: "#0ea5e9",
- empire: "#f59e0b",
- kingdom: "#d97706",
- war: "#dc2626",
battle: "#f43f5e",
- civilization: "#14b8a6",
rebellion_zone: "#7c3aed",
};
export const POLYGON_STROKE_BY_TYPE: Record = {
country: "#1e3a8a",
state: "#0c4a6e",
- empire: "#7c2d12",
- kingdom: "#9a3412",
- war: "#7f1d1d",
battle: "#9f1239",
- civilization: "#134e4a",
rebellion_zone: "#4c1d95",
};
export const POLYGON_OPACITY_BY_TYPE: Record = {
- war: 0.3,
battle: 0.34,
- civilization: 0.38,
rebellion_zone: 0.32,
};
export const LINE_COLOR_BY_TYPE: Record = {
defense_line: "#f97316",
- attack_route: "#ef4444",
+ military_route: "#ef4444",
retreat_route: "#94a3b8",
- invasion_route: "#b91c1c",
migration_route: "#0ea5e9",
- refugee_route: "#06b6d4",
trade_route: "#eab308",
- shipping_route: "#2563eb",
};
export const PATH_RENDER_BY_TYPE: Record = {
- attack_route: true,
+ military_route: true,
retreat_route: true,
- invasion_route: true,
migration_route: true,
- refugee_route: true,
trade_route: true,
- shipping_route: true,
};