init: replay mode
This commit is contained in:
@@ -26,6 +26,7 @@ type MapProps = {
|
||||
geometryVisibility?: Record<string, boolean>;
|
||||
selectedFeatureIds: (string | number)[];
|
||||
onSelectFeatureIds: (ids: (string | number)[]) => void;
|
||||
onSetMode?: (mode: EditorMode, featureId?: string | number) => void;
|
||||
labelContextDraft?: FeatureCollection;
|
||||
onCreateFeature?: (feature: FeatureCollection["features"][number]) => void;
|
||||
onDeleteFeature?: (id: string | number) => void;
|
||||
@@ -40,10 +41,13 @@ type MapProps = {
|
||||
focusFeatureCollection?: FeatureCollection | null;
|
||||
focusRequestKey?: string | number | null;
|
||||
focusPadding?: number | import("maplibre-gl").PaddingOptions;
|
||||
hideOutside?: boolean;
|
||||
onToggleHideOutside?: () => void;
|
||||
};
|
||||
|
||||
export default function Map({
|
||||
mode,
|
||||
onSetMode,
|
||||
draft,
|
||||
backgroundVisibility,
|
||||
geometryVisibility,
|
||||
@@ -63,10 +67,13 @@ export default function Map({
|
||||
focusFeatureCollection = null,
|
||||
focusRequestKey = null,
|
||||
focusPadding,
|
||||
hideOutside = false,
|
||||
onToggleHideOutside,
|
||||
}: MapProps) {
|
||||
const modeRef = useRef<MapProps["mode"]>(mode);
|
||||
const draftRef = useRef<FeatureCollection>(draft);
|
||||
const onSelectFeatureIdsRef = useRef(onSelectFeatureIds);
|
||||
const onSetModeRef = useRef(onSetMode);
|
||||
const onHoverFeatureChangeRef = useRef<MapProps["onHoverFeatureChange"]>(onHoverFeatureChange);
|
||||
const onCreateRef = useRef<MapProps["onCreateFeature"]>(onCreateFeature);
|
||||
const onDeleteRef = useRef<MapProps["onDeleteFeature"]>(onDeleteFeature);
|
||||
@@ -75,6 +82,7 @@ export default function Map({
|
||||
useEffect(() => { modeRef.current = mode; }, [mode]);
|
||||
useEffect(() => { draftRef.current = draft; }, [draft]);
|
||||
useEffect(() => { onSelectFeatureIdsRef.current = onSelectFeatureIds; }, [onSelectFeatureIds]);
|
||||
useEffect(() => { onSetModeRef.current = onSetMode; }, [onSetMode]);
|
||||
useEffect(() => { onHoverFeatureChangeRef.current = onHoverFeatureChange; }, [onHoverFeatureChange]);
|
||||
useEffect(() => { onCreateRef.current = onCreateFeature; }, [onCreateFeature]);
|
||||
useEffect(() => { onDeleteRef.current = onDeleteFeature; }, [onDeleteFeature]);
|
||||
@@ -106,6 +114,7 @@ export default function Map({
|
||||
allowGeometryEditing,
|
||||
selectedFeatureIds,
|
||||
onSelectFeatureIdsRef,
|
||||
onSetModeRef,
|
||||
onCreateRef,
|
||||
onDeleteRef,
|
||||
onUpdateRef,
|
||||
@@ -150,6 +159,14 @@ export default function Map({
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [isMapLoaded]);
|
||||
|
||||
useEffect(() => {
|
||||
const map = mapRef.current;
|
||||
if (map && isMapLoaded) {
|
||||
// Trigger resize after a short delay to allow layout to settle
|
||||
setTimeout(() => map.resize(), 100);
|
||||
}
|
||||
}, [mode, isMapLoaded]);
|
||||
|
||||
return (
|
||||
<div style={{ width: "100%", height, position: "relative" }}>
|
||||
<div ref={containerRef} style={{ width: "100%", height: "100%" }} />
|
||||
@@ -198,7 +215,7 @@ export default function Map({
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
maxWidth: "520px",
|
||||
maxWidth: "650px",
|
||||
margin: "0 auto",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
@@ -212,6 +229,72 @@ export default function Map({
|
||||
pointerEvents: "auto",
|
||||
}}
|
||||
>
|
||||
{mode === "replay" && (
|
||||
<>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => onSetMode?.("select")}
|
||||
style={{
|
||||
...zoomButtonStyle,
|
||||
width: "auto",
|
||||
padding: "0 12px",
|
||||
fontSize: "12px",
|
||||
fontWeight: 700,
|
||||
background: "#7f1d1d",
|
||||
color: "white",
|
||||
border: "1px solid #991b1b",
|
||||
borderRadius: "999px",
|
||||
cursor: "pointer",
|
||||
marginRight: "4px",
|
||||
}}
|
||||
>
|
||||
Thoát Replay Edit
|
||||
</button>
|
||||
|
||||
<div
|
||||
onClick={onToggleHideOutside}
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: "8px",
|
||||
cursor: "pointer",
|
||||
marginRight: "8px",
|
||||
userSelect: "none",
|
||||
}}
|
||||
>
|
||||
<span style={{ fontSize: "12px", fontWeight: 700, color: hideOutside ? "#fb7185" : "#94a3b8" }}>
|
||||
Hide Outside
|
||||
</span>
|
||||
<div
|
||||
style={{
|
||||
width: "32px",
|
||||
height: "18px",
|
||||
borderRadius: "10px",
|
||||
background: hideOutside ? "#e11d48" : "#334155",
|
||||
position: "relative",
|
||||
transition: "background 0.2s",
|
||||
border: "1px solid rgba(255,255,255,0.1)",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: "2px",
|
||||
left: hideOutside ? "16px" : "2px",
|
||||
width: "12px",
|
||||
height: "12px",
|
||||
borderRadius: "50%",
|
||||
background: "white",
|
||||
transition: "left 0.2s cubic-bezier(0.4, 0, 0.2, 1)",
|
||||
boxShadow: "0 1px 2px rgba(0,0,0,0.3)",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ width: "1px", height: "20px", background: "rgba(148, 163, 184, 0.3)", marginRight: "4px" }} />
|
||||
</>
|
||||
)}
|
||||
|
||||
<label
|
||||
title={
|
||||
isGlobeProjection
|
||||
|
||||
@@ -36,5 +36,12 @@ export function ModeHint({ mode }: { mode: EditorMode }) {
|
||||
</div>
|
||||
)
|
||||
}
|
||||
if (mode === "replay") {
|
||||
return (
|
||||
<div style={{ marginTop: 6, fontSize: 12, color: "#93c5fd" }}>
|
||||
Đang trong chế độ trình diễn diễn biến kịch bản.
|
||||
</div>
|
||||
)
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -156,8 +156,13 @@ export function filterDraftByGeometryVisibility(
|
||||
return {
|
||||
...fc,
|
||||
features: fc.features.filter((feature) => {
|
||||
const id = String(feature.properties.id);
|
||||
// Kiểm tra ẩn theo ID cụ thể (ưu tiên cao nhất)
|
||||
if (visibility[id] === false) return false;
|
||||
|
||||
const key = getFeatureSemanticType(feature);
|
||||
if (!key) return true;
|
||||
// Kiểm tra ẩn theo loại (semantic type)
|
||||
return visibility[key] !== false;
|
||||
}),
|
||||
};
|
||||
|
||||
@@ -26,6 +26,7 @@ type UseMapInteractionProps = {
|
||||
allowGeometryEditing: boolean;
|
||||
selectedFeatureIds: (string | number)[];
|
||||
onSelectFeatureIdsRef: React.MutableRefObject<(ids: (string | number)[]) => void>;
|
||||
onSetModeRef: React.MutableRefObject<((mode: EditorMode) => void) | undefined>;
|
||||
onCreateRef: React.MutableRefObject<((feature: FeatureCollection["features"][number]) => void) | undefined>;
|
||||
onDeleteRef: React.MutableRefObject<((id: string | number) => void) | undefined>;
|
||||
onUpdateRef: React.MutableRefObject<((id: string | number, geometry: Geometry) => void) | undefined>;
|
||||
@@ -40,6 +41,7 @@ export function useMapInteraction({
|
||||
allowGeometryEditing,
|
||||
selectedFeatureIds,
|
||||
onSelectFeatureIdsRef,
|
||||
onSetModeRef,
|
||||
onCreateRef,
|
||||
onDeleteRef,
|
||||
onUpdateRef,
|
||||
@@ -142,7 +144,8 @@ export function useMapInteraction({
|
||||
editingEngineRef.current?.beginEditing((originalFeature || feature) as any);
|
||||
}
|
||||
: undefined,
|
||||
(ids) => onSelectFeatureIdsRef.current?.(ids)
|
||||
(ids) => onSelectFeatureIdsRef.current?.(ids),
|
||||
(id: string | number) => onSetModeRef.current?.("replay", id)
|
||||
);
|
||||
|
||||
const cleanupPoint = initPoint(
|
||||
@@ -236,6 +239,7 @@ export function useMapInteraction({
|
||||
engineBindingsRef.current = {
|
||||
draw: drawingEngine,
|
||||
select: selectEngine,
|
||||
replay: selectEngine,
|
||||
"add-line": lineEngine,
|
||||
"add-path": pathEngine,
|
||||
"add-circle": circleEngine,
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
} from "@/uhm/lib/map/styles/style";
|
||||
import { EMPTY_FEATURE_COLLECTION } from "@/uhm/lib/map/geo/constants";
|
||||
import { PATH_ARROW_ICON_ID, PATH_ARROW_SOURCE_ID, POLYGON_LABEL_SOURCE_ID } from "@/uhm/lib/map/constants";
|
||||
import { ensurePointGeotypeIcons, getAllGeotypeLabelLayers, getAllGeotypeLayers } from "@/uhm/lib/map/styles/geotypes";
|
||||
import { ensurePointGeotypeIcons, getAllGeotypeLabelLayers, getAllGeotypeLayers } from "@/uhm/lib/map/styles/geotypeLayers";
|
||||
import {
|
||||
applyBackgroundLayerVisibility,
|
||||
buildTypeMatchExpression,
|
||||
|
||||
@@ -7,7 +7,8 @@ export type EditorMode =
|
||||
| "add-point"
|
||||
| "add-line"
|
||||
| "add-path"
|
||||
| "add-circle";
|
||||
| "add-circle"
|
||||
| "replay";
|
||||
|
||||
export type TimelineRange = {
|
||||
min: number;
|
||||
|
||||
@@ -7,7 +7,8 @@ export function initSelect(
|
||||
getMode: ModeGetter,
|
||||
onDelete?: (id: string | number) => void,
|
||||
onEdit?: (feature: maplibregl.MapGeoJSONFeature) => void,
|
||||
onSelectIds?: (ids: (string | number)[]) => void
|
||||
onSelectIds?: (ids: (string | number)[]) => void,
|
||||
onReplayEdit?: (id: string | number) => void
|
||||
) {
|
||||
|
||||
const FEATURE_STATE_SOURCES = [
|
||||
@@ -16,7 +17,7 @@ export function initSelect(
|
||||
"path-arrow-shapes",
|
||||
] as const;
|
||||
const selectedIds = new Set<number | string>();
|
||||
const hasContextActions = Boolean(onDelete || onEdit);
|
||||
const hasContextActions = Boolean(onDelete || onEdit || onReplayEdit);
|
||||
let contextMenu: HTMLDivElement | null = null;
|
||||
let docClickHandler: ((ev: MouseEvent) => void) | null = null;
|
||||
|
||||
@@ -54,7 +55,7 @@ export function initSelect(
|
||||
|
||||
// Chọn feature theo click trái, hỗ trợ additive bằng Alt.
|
||||
function onClick(e: maplibregl.MapLayerMouseEvent) {
|
||||
if (getMode() !== "select") return;
|
||||
if (getMode() !== "select" && getMode() !== "replay") return;
|
||||
const selectableLayers = getSelectableLayers();
|
||||
if (!selectableLayers.length) return;
|
||||
|
||||
@@ -74,11 +75,12 @@ export function initSelect(
|
||||
// Hiển thị menu ngữ cảnh (sửa/xóa) khi click chuột phải.
|
||||
// Mở menu thao tác khi click phải lên feature.
|
||||
function onRightClick(e: maplibregl.MapLayerMouseEvent) {
|
||||
if (getMode() !== "select") return;
|
||||
if (getMode() !== "select" && getMode() !== "replay") return;
|
||||
const selectableLayers = getSelectableLayers();
|
||||
if (!selectableLayers.length) return;
|
||||
|
||||
e.preventDefault(); // block browser menu
|
||||
if (getMode() === "replay") return;
|
||||
|
||||
const features = map.queryRenderedFeatures(e.point, {
|
||||
layers: selectableLayers,
|
||||
@@ -105,7 +107,7 @@ export function initSelect(
|
||||
|
||||
// Đổi cursor pointer khi hover lên đối tượng có thể chọn.
|
||||
function onMove(e: maplibregl.MapLayerMouseEvent) {
|
||||
if (getMode() !== "select") return;
|
||||
if (getMode() !== "select" && getMode() !== "replay") return;
|
||||
const selectableLayers = getSelectableLayers();
|
||||
if (!selectableLayers.length) {
|
||||
map.getCanvas().style.cursor = "";
|
||||
@@ -218,6 +220,17 @@ export function initSelect(
|
||||
hasMenuItems = true;
|
||||
}
|
||||
|
||||
if (
|
||||
selectedCount === 1 &&
|
||||
onReplayEdit
|
||||
) {
|
||||
const featureId = clickedFeature.id ?? clickedFeature.properties?.id;
|
||||
if (featureId) {
|
||||
menu.appendChild(createItem("Replay Edit", () => onReplayEdit(featureId)));
|
||||
hasMenuItems = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (onDelete) {
|
||||
menu.appendChild(
|
||||
createItem(
|
||||
|
||||
+30
-30
@@ -1,36 +1,36 @@
|
||||
import maplibregl from "maplibre-gl";
|
||||
export const TYPE_MATCH_EXPR: maplibregl.ExpressionSpecification = ["coalesce", ["get", "type"], ["get", "entity_type_id"], ""];
|
||||
export { ensurePointGeotypeIcons } from "./pointStyle";
|
||||
export { ensurePointGeotypeIcons } from "./shared/pointStyle";
|
||||
|
||||
import { getDefenseLineLayers } from "./defense_line";
|
||||
import { getAttackRouteLayers } from "./attack_route";
|
||||
import { getRetreatRouteLayers } from "./retreat_route";
|
||||
import { getInvasionRouteLayers } from "./invasion_route";
|
||||
import { getMigrationRouteLayers } from "./migration_route";
|
||||
import { getRefugeeRouteLayers } from "./refugee_route";
|
||||
import { getTradeRouteLayers } from "./trade_route";
|
||||
import { getShippingRouteLayers } from "./shipping_route";
|
||||
import { getCountryLayers } from "./country";
|
||||
import { getStateLayers } from "./state";
|
||||
import { getEmpireLayers } from "./empire";
|
||||
import { getKingdomLayers } from "./kingdom";
|
||||
import { getWarLayers } from "./war";
|
||||
import { getBattleLayers } from "./battle";
|
||||
import { getCivilizationLayers } from "./civilization";
|
||||
import { getRebellionZoneLayers } from "./rebellion_zone";
|
||||
import { getPersonDeathplaceLayers } from "./person_deathplace";
|
||||
import { getPersonBirthplaceLayers } from "./person_birthplace";
|
||||
import { getPersonActivityLayers } from "./person_activity";
|
||||
import { getTempleLayers } from "./temple";
|
||||
import { getCapitalLayers } from "./capital";
|
||||
import { getCityLayers } from "./city";
|
||||
import { getFortressLayers } from "./fortress";
|
||||
import { getCastleLayers } from "./castle";
|
||||
import { getRuinLayers } from "./ruin";
|
||||
import { getPortLayers } from "./port";
|
||||
import { getBridgeLayers } from "./bridge";
|
||||
import { getLineLabelLayers } from "./lineLabels";
|
||||
import { getPolygonLabelLayers } from "./polygonLabels";
|
||||
import { getDefenseLineLayers } from "./geotypes/defense_line";
|
||||
import { getAttackRouteLayers } from "./geotypes/attack_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 { 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 { 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 { getRuinLayers } from "./geotypes/ruin";
|
||||
import { getPortLayers } from "./geotypes/port";
|
||||
import { getBridgeLayers } from "./geotypes/bridge";
|
||||
import { getLineLabelLayers } from "./shared/lineLabels";
|
||||
import { getPolygonLabelLayers } from "./shared/polygonLabels";
|
||||
|
||||
import { LayerSpecification } from "maplibre-gl";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { LayerSpecification } from "maplibre-gl";
|
||||
import { buildLineGeotypeLayers } from "./styleBuilders";
|
||||
import { buildLineGeotypeLayers } from "../shared/styleBuilders";
|
||||
|
||||
export function getAttackRouteLayers(sourceId: string, pathArrowSourceId?: string, pointSourceId?: string): LayerSpecification[] {
|
||||
void pointSourceId;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { LayerSpecification } from "maplibre-gl";
|
||||
import { buildPolygonGeotypeLayers } from "./styleBuilders";
|
||||
import { buildPolygonGeotypeLayers } from "../shared/styleBuilders";
|
||||
|
||||
export function getBattleLayers(sourceId: string, pathArrowSourceId?: string, pointSourceId?: string): LayerSpecification[] {
|
||||
void pathArrowSourceId;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { LayerSpecification } from "maplibre-gl";
|
||||
import { buildPointGeotypeLayers } from "./pointStyle";
|
||||
import { buildPointGeotypeLayers } from "../shared/pointStyle";
|
||||
|
||||
export function getBridgeLayers(sourceId: string, pathArrowSourceId?: string, pointSourceId?: string): LayerSpecification[] {
|
||||
void sourceId;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { LayerSpecification } from "maplibre-gl";
|
||||
import { buildPointGeotypeLayers } from "./pointStyle";
|
||||
import { buildPointGeotypeLayers } from "../shared/pointStyle";
|
||||
|
||||
export function getCapitalLayers(sourceId: string, pathArrowSourceId?: string, pointSourceId?: string): LayerSpecification[] {
|
||||
void sourceId;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { LayerSpecification } from "maplibre-gl";
|
||||
import { buildPointGeotypeLayers } from "./pointStyle";
|
||||
import { buildPointGeotypeLayers } from "../shared/pointStyle";
|
||||
|
||||
export function getCastleLayers(sourceId: string, pathArrowSourceId?: string, pointSourceId?: string): LayerSpecification[] {
|
||||
void sourceId;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { LayerSpecification } from "maplibre-gl";
|
||||
import { buildPointGeotypeLayers } from "./pointStyle";
|
||||
import { buildPointGeotypeLayers } from "../shared/pointStyle";
|
||||
|
||||
export function getCityLayers(sourceId: string, pathArrowSourceId?: string, pointSourceId?: string): LayerSpecification[] {
|
||||
void sourceId;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { LayerSpecification } from "maplibre-gl";
|
||||
import { buildPolygonGeotypeLayers } from "./styleBuilders";
|
||||
import { buildPolygonGeotypeLayers } from "../shared/styleBuilders";
|
||||
|
||||
export function getCivilizationLayers(sourceId: string, pathArrowSourceId?: string, pointSourceId?: string): LayerSpecification[] {
|
||||
void pathArrowSourceId;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { LayerSpecification } from "maplibre-gl";
|
||||
import { buildPolygonGeotypeLayers } from "./styleBuilders";
|
||||
import { buildPolygonGeotypeLayers } from "../shared/styleBuilders";
|
||||
|
||||
export function getCountryLayers(sourceId: string, pathArrowSourceId?: string, pointSourceId?: string): LayerSpecification[] {
|
||||
void pathArrowSourceId;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { LayerSpecification } from "maplibre-gl";
|
||||
import { buildLineGeotypeLayers } from "./styleBuilders";
|
||||
import { buildLineGeotypeLayers } from "../shared/styleBuilders";
|
||||
|
||||
export function getDefenseLineLayers(sourceId: string, pathArrowSourceId?: string, pointSourceId?: string): LayerSpecification[] {
|
||||
void pointSourceId;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { LayerSpecification } from "maplibre-gl";
|
||||
import { buildPolygonGeotypeLayers } from "./styleBuilders";
|
||||
import { buildPolygonGeotypeLayers } from "../shared/styleBuilders";
|
||||
|
||||
export function getEmpireLayers(sourceId: string, pathArrowSourceId?: string, pointSourceId?: string): LayerSpecification[] {
|
||||
void pathArrowSourceId;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { LayerSpecification } from "maplibre-gl";
|
||||
import { buildPointGeotypeLayers } from "./pointStyle";
|
||||
import { buildPointGeotypeLayers } from "../shared/pointStyle";
|
||||
|
||||
export function getFortressLayers(sourceId: string, pathArrowSourceId?: string, pointSourceId?: string): LayerSpecification[] {
|
||||
void sourceId;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { LayerSpecification } from "maplibre-gl";
|
||||
import { buildLineGeotypeLayers } from "./styleBuilders";
|
||||
import { buildLineGeotypeLayers } from "../shared/styleBuilders";
|
||||
|
||||
export function getInvasionRouteLayers(sourceId: string, pathArrowSourceId?: string, pointSourceId?: string): LayerSpecification[] {
|
||||
void pointSourceId;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { LayerSpecification } from "maplibre-gl";
|
||||
import { buildPolygonGeotypeLayers } from "./styleBuilders";
|
||||
import { buildPolygonGeotypeLayers } from "../shared/styleBuilders";
|
||||
|
||||
export function getKingdomLayers(sourceId: string, pathArrowSourceId?: string, pointSourceId?: string): LayerSpecification[] {
|
||||
void pathArrowSourceId;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { LayerSpecification } from "maplibre-gl";
|
||||
import { buildLineGeotypeLayers } from "./styleBuilders";
|
||||
import { buildLineGeotypeLayers } from "../shared/styleBuilders";
|
||||
|
||||
export function getMigrationRouteLayers(sourceId: string, pathArrowSourceId?: string, pointSourceId?: string): LayerSpecification[] {
|
||||
void pointSourceId;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { LayerSpecification } from "maplibre-gl";
|
||||
import { buildPointGeotypeLayers } from "./pointStyle";
|
||||
import { buildPointGeotypeLayers } from "../shared/pointStyle";
|
||||
|
||||
export function getPersonActivityLayers(sourceId: string, pathArrowSourceId?: string, pointSourceId?: string): LayerSpecification[] {
|
||||
void sourceId;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { LayerSpecification } from "maplibre-gl";
|
||||
import { buildPointGeotypeLayers } from "./pointStyle";
|
||||
import { buildPointGeotypeLayers } from "../shared/pointStyle";
|
||||
|
||||
export function getPersonBirthplaceLayers(sourceId: string, pathArrowSourceId?: string, pointSourceId?: string): LayerSpecification[] {
|
||||
void sourceId;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { LayerSpecification } from "maplibre-gl";
|
||||
import { buildPointGeotypeLayers } from "./pointStyle";
|
||||
import { buildPointGeotypeLayers } from "../shared/pointStyle";
|
||||
|
||||
export function getPersonDeathplaceLayers(sourceId: string, pathArrowSourceId?: string, pointSourceId?: string): LayerSpecification[] {
|
||||
void sourceId;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { LayerSpecification } from "maplibre-gl";
|
||||
import { buildPointGeotypeLayers } from "./pointStyle";
|
||||
import { buildPointGeotypeLayers } from "../shared/pointStyle";
|
||||
|
||||
export function getPortLayers(sourceId: string, pathArrowSourceId?: string, pointSourceId?: string): LayerSpecification[] {
|
||||
void sourceId;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { LayerSpecification } from "maplibre-gl";
|
||||
import { buildPolygonGeotypeLayers } from "./styleBuilders";
|
||||
import { buildPolygonGeotypeLayers } from "../shared/styleBuilders";
|
||||
|
||||
export function getRebellionZoneLayers(sourceId: string, pathArrowSourceId?: string, pointSourceId?: string): LayerSpecification[] {
|
||||
void pathArrowSourceId;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { LayerSpecification } from "maplibre-gl";
|
||||
import { buildLineGeotypeLayers } from "./styleBuilders";
|
||||
import { buildLineGeotypeLayers } from "../shared/styleBuilders";
|
||||
|
||||
export function getRefugeeRouteLayers(sourceId: string, pathArrowSourceId?: string, pointSourceId?: string): LayerSpecification[] {
|
||||
void pointSourceId;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { LayerSpecification } from "maplibre-gl";
|
||||
import { buildLineGeotypeLayers } from "./styleBuilders";
|
||||
import { buildLineGeotypeLayers } from "../shared/styleBuilders";
|
||||
|
||||
export function getRetreatRouteLayers(sourceId: string, pathArrowSourceId?: string, pointSourceId?: string): LayerSpecification[] {
|
||||
void pointSourceId;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { LayerSpecification } from "maplibre-gl";
|
||||
import { buildPointGeotypeLayers } from "./pointStyle";
|
||||
import { buildPointGeotypeLayers } from "../shared/pointStyle";
|
||||
|
||||
export function getRuinLayers(sourceId: string, pathArrowSourceId?: string, pointSourceId?: string): LayerSpecification[] {
|
||||
void sourceId;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { LayerSpecification } from "maplibre-gl";
|
||||
import { buildLineGeotypeLayers } from "./styleBuilders";
|
||||
import { buildLineGeotypeLayers } from "../shared/styleBuilders";
|
||||
|
||||
export function getShippingRouteLayers(sourceId: string, pathArrowSourceId?: string, pointSourceId?: string): LayerSpecification[] {
|
||||
void pointSourceId;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { LayerSpecification } from "maplibre-gl";
|
||||
import { buildPolygonGeotypeLayers } from "./styleBuilders";
|
||||
import { buildPolygonGeotypeLayers } from "../shared/styleBuilders";
|
||||
|
||||
export function getStateLayers(sourceId: string, pathArrowSourceId?: string, pointSourceId?: string): LayerSpecification[] {
|
||||
void pathArrowSourceId;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { LayerSpecification } from "maplibre-gl";
|
||||
import { buildPointGeotypeLayers } from "./pointStyle";
|
||||
import { buildPointGeotypeLayers } from "../shared/pointStyle";
|
||||
|
||||
export function getTempleLayers(sourceId: string, pathArrowSourceId?: string, pointSourceId?: string): LayerSpecification[] {
|
||||
void sourceId;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { LayerSpecification } from "maplibre-gl";
|
||||
import { buildLineGeotypeLayers } from "./styleBuilders";
|
||||
import { buildLineGeotypeLayers } from "../shared/styleBuilders";
|
||||
|
||||
export function getTradeRouteLayers(sourceId: string, pathArrowSourceId?: string, pointSourceId?: string): LayerSpecification[] {
|
||||
void pointSourceId;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { LayerSpecification } from "maplibre-gl";
|
||||
import { buildPolygonGeotypeLayers } from "./styleBuilders";
|
||||
import { buildPolygonGeotypeLayers } from "../shared/styleBuilders";
|
||||
|
||||
export function getWarLayers(sourceId: string, pathArrowSourceId?: string, pointSourceId?: string): LayerSpecification[] {
|
||||
void pathArrowSourceId;
|
||||
|
||||
@@ -15,6 +15,54 @@ export type CommitSnapshot = {
|
||||
geometry_entity: GeometryEntitySnapshot[];
|
||||
wikis: WikiSnapshot[];
|
||||
entity_wiki: EntityWikiLinkSnapshot[];
|
||||
replays?: BattleReplay[];
|
||||
};
|
||||
|
||||
// ---- Replay / Scripting System ----
|
||||
|
||||
export type UIFunctionName =
|
||||
| "hide_timeline"
|
||||
| "hide_layer_panel"
|
||||
| "hide_wiki_panel"
|
||||
| "hide_zoom_panel"
|
||||
| "hide_all_UI"
|
||||
| "open_wiki";
|
||||
|
||||
export type MapFunctionName =
|
||||
| "zoom_to_lnglat"
|
||||
| "zoom_scale"
|
||||
| "zoom_geometries"
|
||||
| "change_geometry_color"
|
||||
| "change_geometries_color"
|
||||
| "change_geometry_texture"
|
||||
| "change_geometries_texture"
|
||||
| "hide_geometries";
|
||||
|
||||
export type NarrativeFunctionName = "set_title" | "set_descriptions";
|
||||
|
||||
export type ReplayAction<T> = {
|
||||
function_name: T;
|
||||
params: any[];
|
||||
};
|
||||
|
||||
export type ReplayStep = {
|
||||
duration: number; // Trọng số thời gian của step trong 1 stage
|
||||
use_UI_function: ReplayAction<UIFunctionName>[];
|
||||
use_map_function: ReplayAction<MapFunctionName>[];
|
||||
use_narrow_function: ReplayAction<NarrativeFunctionName>[];
|
||||
};
|
||||
|
||||
export type ReplayStage = {
|
||||
id: number; // số đếm thứ tự từ 0
|
||||
title?: string;
|
||||
detail_time_start: string;
|
||||
detail_time_stop: string;
|
||||
steps: ReplayStep[];
|
||||
};
|
||||
|
||||
export type BattleReplay = {
|
||||
geometry_id: string; // geometry mà khi nhấn vào là có thể replay
|
||||
detail: ReplayStage[];
|
||||
};
|
||||
|
||||
// ---- GeoJSON / FeatureCollection ----
|
||||
|
||||
Reference in New Issue
Block a user