@tileflow/dom 0.1.0-alpha.0 → 0.1.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/REFERENCE.md +11 -0
- package/dist/index.js +564 -381
- package/package.json +3 -3
package/REFERENCE.md
CHANGED
|
@@ -73,6 +73,17 @@ with no renderer keeps the default view.
|
|
|
73
73
|
| `getInteractionState()`, `getRenderTargets()` | The open popup; the view elements the map handed out. |
|
|
74
74
|
| `destroy()` | Takes the map down, removes the capture attributes and stops every listener. Later calls do nothing. |
|
|
75
75
|
|
|
76
|
+
Use `getMap()` or the map passed to `onLoad` for application-owned MapLibre sources, layers,
|
|
77
|
+
controls and events. Tileflow owns the style; theme changes may replace it, so reinstall your
|
|
78
|
+
own layers on `style.load`, or use `dataSources` and `dataOverlays`. Calling the MapLibre map's
|
|
79
|
+
`remove()` also stops the Tileflow controller. Prefer `destroy()` for normal application cleanup.
|
|
80
|
+
Destroying during loading rejects `ready` and prevents a late response from mounting a map.
|
|
81
|
+
|
|
82
|
+
If optional interactions cannot start, the map remains mounted and reports an interaction
|
|
83
|
+
diagnostic. Changing their inputs retries initialization. A failed theme change keeps the
|
|
84
|
+
applied theme and its system-colour-scheme following; an unknown name does not cancel a valid
|
|
85
|
+
pending change. `getStatus()` reports the failure until the requested selection changes.
|
|
86
|
+
|
|
76
87
|
## `getTileflowMapInitialStatus(options, controlledInteractionState?)`
|
|
77
88
|
|
|
78
89
|
The status a map with these options has before it mounts: its declarative diagnostics, `error` or
|
package/dist/index.js
CHANGED
|
@@ -181,6 +181,8 @@ function imageModeMapInteractionDiagnostic(annotationCount, bindingCount, hasAdd
|
|
|
181
181
|
|
|
182
182
|
// src/maplibre.ts
|
|
183
183
|
var bundlerWorkerUrlKey = /* @__PURE__ */ Symbol.for("tileflow.maplibre.workerUrl");
|
|
184
|
+
var importMapLibre = () => import("maplibre-gl");
|
|
185
|
+
var loadMapLibreModule = importMapLibre;
|
|
184
186
|
var mapLibrePromise;
|
|
185
187
|
var mapLibre;
|
|
186
188
|
var workerUrl;
|
|
@@ -202,7 +204,7 @@ function configureTileflowMapLibre(configuration) {
|
|
|
202
204
|
if (mapLibre) applyWorkerUrl(mapLibre);
|
|
203
205
|
}
|
|
204
206
|
function loadTileflowMapLibre() {
|
|
205
|
-
mapLibrePromise ??=
|
|
207
|
+
mapLibrePromise ??= loadMapLibreModule().then(resolveMapLibreModule).then(configureTileflowMapLibreModule).catch((error) => {
|
|
206
208
|
mapLibrePromise = void 0;
|
|
207
209
|
throw error;
|
|
208
210
|
});
|
|
@@ -337,6 +339,32 @@ function throwCollected(errors, message) {
|
|
|
337
339
|
if (errors.length > 1) throw new AggregateError(errors, message);
|
|
338
340
|
}
|
|
339
341
|
|
|
342
|
+
// src/scope.ts
|
|
343
|
+
function createTileflowResourceScope() {
|
|
344
|
+
const cleanups = [];
|
|
345
|
+
let disposed = false;
|
|
346
|
+
const scope = {
|
|
347
|
+
add(cleanup) {
|
|
348
|
+
if (disposed) runTileflowCleanups([cleanup]);
|
|
349
|
+
else cleanups.push(cleanup);
|
|
350
|
+
},
|
|
351
|
+
child() {
|
|
352
|
+
const child = createTileflowResourceScope();
|
|
353
|
+
scope.add(() => child.dispose());
|
|
354
|
+
return child;
|
|
355
|
+
},
|
|
356
|
+
dispose() {
|
|
357
|
+
if (disposed) return;
|
|
358
|
+
disposed = true;
|
|
359
|
+
runTileflowCleanups(cleanups.splice(0).reverse());
|
|
360
|
+
},
|
|
361
|
+
get disposed() {
|
|
362
|
+
return disposed;
|
|
363
|
+
}
|
|
364
|
+
};
|
|
365
|
+
return scope;
|
|
366
|
+
}
|
|
367
|
+
|
|
340
368
|
// src/views.ts
|
|
341
369
|
function tileflowAnnotationViewContext(target, state) {
|
|
342
370
|
const { annotation } = target;
|
|
@@ -547,13 +575,20 @@ function createTileflowMap(container, initialOptions, createOptions = {}) {
|
|
|
547
575
|
let stateBridgeDiagnostic;
|
|
548
576
|
let rendererBridgeDiagnostic;
|
|
549
577
|
let viewBridgeDiagnostic;
|
|
578
|
+
let dataBridgeDiagnostic;
|
|
579
|
+
let interactionStartDiagnostic;
|
|
550
580
|
let annotationDiagnostics = [];
|
|
551
581
|
let semanticDiagnostics = [];
|
|
552
582
|
let reportedDeclarativeDiagnosticKeys = /* @__PURE__ */ new Set();
|
|
553
583
|
let imageSize = null;
|
|
554
584
|
let managedImage = null;
|
|
555
585
|
let imageReadinessRun = 0;
|
|
586
|
+
let themeMapIdentity;
|
|
587
|
+
let appliedTheme;
|
|
588
|
+
let failedTheme;
|
|
589
|
+
let validThemeSelection;
|
|
556
590
|
let map = null;
|
|
591
|
+
let mounted;
|
|
557
592
|
let scene;
|
|
558
593
|
let themeController;
|
|
559
594
|
let appearanceBinding;
|
|
@@ -644,6 +679,13 @@ function createTileflowMap(container, initialOptions, createOptions = {}) {
|
|
|
644
679
|
}));
|
|
645
680
|
const mapName = runtimeSource.map;
|
|
646
681
|
const manifestUrl = runtimeSource.manifestUrl ?? defaultTileflowManifestUrl;
|
|
682
|
+
const runtimeMapIdentity = `${manifestUrl}\0${mapName}`;
|
|
683
|
+
if (themeMapIdentity !== runtimeMapIdentity) {
|
|
684
|
+
themeMapIdentity = runtimeMapIdentity;
|
|
685
|
+
appliedTheme = void 0;
|
|
686
|
+
failedTheme = void 0;
|
|
687
|
+
validThemeSelection = void 0;
|
|
688
|
+
}
|
|
647
689
|
const preparedAnnotations = memo(
|
|
648
690
|
"annotations",
|
|
649
691
|
[annotations],
|
|
@@ -679,37 +721,75 @@ function createTileflowMap(container, initialOptions, createOptions = {}) {
|
|
|
679
721
|
const manifestMap = currentManifest.state === "ready" ? currentManifest.map : null;
|
|
680
722
|
const themeBlendKey = themeBlend ? JSON.stringify(themeBlend.themes) : void 0;
|
|
681
723
|
const blendThemeName = themeBlend ? nearestTileflowBlendTheme(themeBlend) : void 0;
|
|
724
|
+
const resolveSelection = (selection) => {
|
|
725
|
+
if (!manifestMap) {
|
|
726
|
+
return {
|
|
727
|
+
error: false,
|
|
728
|
+
name: selection && selection !== "system" ? selection : void 0
|
|
729
|
+
};
|
|
730
|
+
}
|
|
731
|
+
try {
|
|
732
|
+
if (themeBlendKey) {
|
|
733
|
+
for (const name of JSON.parse(themeBlendKey)) {
|
|
734
|
+
resolveTileflowRuntimeTheme(manifestMap, name);
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
return {
|
|
738
|
+
error: false,
|
|
739
|
+
name: resolveTileflowRuntimeTheme(
|
|
740
|
+
manifestMap,
|
|
741
|
+
selection,
|
|
742
|
+
systemColorScheme,
|
|
743
|
+
themeBlendKey ? void 0 : timeOfDay
|
|
744
|
+
).name
|
|
745
|
+
};
|
|
746
|
+
} catch (cause) {
|
|
747
|
+
return { cause, error: true, name: void 0 };
|
|
748
|
+
}
|
|
749
|
+
};
|
|
682
750
|
const themeResolution = memo(
|
|
683
751
|
"themeResolution",
|
|
684
|
-
[
|
|
752
|
+
[
|
|
753
|
+
blendThemeName,
|
|
754
|
+
manifestMap,
|
|
755
|
+
(blendThemeName ?? theme) === "system" ? systemColorScheme : void 0,
|
|
756
|
+
theme,
|
|
757
|
+
themeBlendKey,
|
|
758
|
+
timeOfDay
|
|
759
|
+
],
|
|
760
|
+
() => resolveSelection(blendThemeName ?? theme)
|
|
761
|
+
);
|
|
762
|
+
const themeRequestFailed = failedTheme !== void 0 && failedTheme.selection === theme && failedTheme.theme === themeResolution.name;
|
|
763
|
+
const themeChoice = memo(
|
|
764
|
+
"themeChoice",
|
|
765
|
+
[
|
|
766
|
+
failedTheme,
|
|
767
|
+
manifestMap,
|
|
768
|
+
systemColorScheme,
|
|
769
|
+
themeBlendKey,
|
|
770
|
+
themeRequestFailed,
|
|
771
|
+
themeResolution,
|
|
772
|
+
timeOfDay,
|
|
773
|
+
validThemeSelection
|
|
774
|
+
],
|
|
685
775
|
() => {
|
|
686
|
-
|
|
687
|
-
if (
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
};
|
|
776
|
+
if (blendThemeName) return { resolution: themeResolution, selection: theme };
|
|
777
|
+
if (themeRequestFailed && failedTheme) {
|
|
778
|
+
const { fallback } = failedTheme;
|
|
779
|
+
const resolution = resolveSelection(fallback.selection);
|
|
780
|
+
return resolution.error || resolution.name === failedTheme.theme ? { resolution: { error: false, name: fallback.theme }, selection: fallback.theme } : { resolution, selection: fallback.selection };
|
|
692
781
|
}
|
|
693
|
-
|
|
694
|
-
if (themeBlendKey) {
|
|
695
|
-
for (const name of JSON.parse(themeBlendKey)) {
|
|
696
|
-
resolveTileflowRuntimeTheme(manifestMap, name);
|
|
697
|
-
}
|
|
698
|
-
}
|
|
782
|
+
if (themeResolution.error) {
|
|
699
783
|
return {
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
manifestMap,
|
|
703
|
-
selection,
|
|
704
|
-
systemColorScheme,
|
|
705
|
-
themeBlendKey ? void 0 : timeOfDay
|
|
706
|
-
).name
|
|
784
|
+
resolution: resolveSelection(validThemeSelection),
|
|
785
|
+
selection: validThemeSelection
|
|
707
786
|
};
|
|
708
|
-
} catch (cause) {
|
|
709
|
-
return { cause, error: true, name: void 0 };
|
|
710
787
|
}
|
|
788
|
+
return { resolution: themeResolution, selection: theme };
|
|
711
789
|
}
|
|
712
790
|
);
|
|
791
|
+
const themeSelection = themeChoice.selection;
|
|
792
|
+
const shownThemeResolution = themeChoice.resolution;
|
|
713
793
|
const manifestView = resolveTileflowRuntimeView({ manifestMap });
|
|
714
794
|
const manifestCenter = stable(
|
|
715
795
|
"manifestCenter",
|
|
@@ -750,15 +830,18 @@ function createTileflowMap(container, initialOptions, createOptions = {}) {
|
|
|
750
830
|
preparedInteractionState
|
|
751
831
|
})
|
|
752
832
|
);
|
|
753
|
-
const runtimeStyle =
|
|
833
|
+
const runtimeStyle = stable(
|
|
754
834
|
"runtimeStyle",
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
835
|
+
memo(
|
|
836
|
+
"runtimeStyle",
|
|
837
|
+
[isImageMode, manifestMap, runtimeSource, systemColorScheme, shownThemeResolution],
|
|
838
|
+
() => isImageMode || shownThemeResolution.error ? null : resolveTileflowRuntimeStyle({
|
|
839
|
+
colorScheme: systemColorScheme,
|
|
840
|
+
manifestMap,
|
|
841
|
+
source: runtimeSource,
|
|
842
|
+
theme: shownThemeResolution.name
|
|
843
|
+
})
|
|
844
|
+
)
|
|
762
845
|
);
|
|
763
846
|
const blendResolution = memo(
|
|
764
847
|
"blendResolution",
|
|
@@ -808,7 +891,7 @@ function createTileflowMap(container, initialOptions, createOptions = {}) {
|
|
|
808
891
|
zoom: resolvedZoom
|
|
809
892
|
}) : void 0)
|
|
810
893
|
);
|
|
811
|
-
const runtimeResolutionState = currentManifest.state !== "ready" ? currentManifest.state === "error" ? "error" : "loading" : themeResolution.error ? "error" : isImageMode ? runtimeImageUrl ? "idle" : options.imageUrl === void 0 && imageSize === null ? "loading" : "error" : runtimeStyle ? "idle" : "error";
|
|
894
|
+
const runtimeResolutionState = currentManifest.state !== "ready" ? currentManifest.state === "error" ? "error" : "loading" : themeResolution.error || themeRequestFailed ? "error" : isImageMode ? runtimeImageUrl ? "idle" : options.imageUrl === void 0 && imageSize === null ? "loading" : "error" : runtimeStyle ? "idle" : "error";
|
|
812
895
|
return {
|
|
813
896
|
annotationClusters,
|
|
814
897
|
blendResolution,
|
|
@@ -834,10 +917,14 @@ function createTileflowMap(container, initialOptions, createOptions = {}) {
|
|
|
834
917
|
resolvedInteractive,
|
|
835
918
|
resolvedPitch,
|
|
836
919
|
resolvedZoom,
|
|
837
|
-
runtimeMapIdentity
|
|
920
|
+
runtimeMapIdentity,
|
|
838
921
|
runtimeResolutionState,
|
|
839
922
|
runtimeSource,
|
|
923
|
+
manifestReady: manifestMap !== null,
|
|
840
924
|
runtimeStyle,
|
|
925
|
+
shownThemeResolution,
|
|
926
|
+
themeRequestFailed,
|
|
927
|
+
themeSelection,
|
|
841
928
|
themeBlendHold: themeBlend?.hold === true,
|
|
842
929
|
themeBlendKey,
|
|
843
930
|
themeBlendPosition: themeBlend?.position,
|
|
@@ -964,8 +1051,14 @@ function createTileflowMap(container, initialOptions, createOptions = {}) {
|
|
|
964
1051
|
image.removeEventListener("error", fail);
|
|
965
1052
|
};
|
|
966
1053
|
});
|
|
967
|
-
|
|
968
|
-
|
|
1054
|
+
if (d.manifestReady && !d.themeResolution.error && !d.themeRequestFailed) {
|
|
1055
|
+
validThemeSelection = options.theme;
|
|
1056
|
+
}
|
|
1057
|
+
if (failedTheme && (failedTheme.selection !== options.theme || failedTheme.theme !== d.themeResolution.name)) {
|
|
1058
|
+
failedTheme = void 0;
|
|
1059
|
+
}
|
|
1060
|
+
effect("systemColorScheme", [d.themeSelection], () => {
|
|
1061
|
+
if (d.themeSelection !== "system") return;
|
|
969
1062
|
systemColorScheme = getTileflowSystemColorScheme();
|
|
970
1063
|
invalidate();
|
|
971
1064
|
return subscribeTileflowSystemColorScheme((scheme) => {
|
|
@@ -1040,7 +1133,25 @@ function createTileflowMap(container, initialOptions, createOptions = {}) {
|
|
|
1040
1133
|
"reconcileData",
|
|
1041
1134
|
[d.annotationClusters, d.dataOverlays, d.dataSources, d.preparedAnnotations],
|
|
1042
1135
|
() => {
|
|
1043
|
-
dataRuntime
|
|
1136
|
+
if (dataRuntime) reconcileData(dataRuntime);
|
|
1137
|
+
}
|
|
1138
|
+
);
|
|
1139
|
+
effect(
|
|
1140
|
+
"restartInteractions",
|
|
1141
|
+
[
|
|
1142
|
+
d.annotationClusters,
|
|
1143
|
+
d.dataOverlays,
|
|
1144
|
+
d.dataSources,
|
|
1145
|
+
d.hasMarkerRenderer,
|
|
1146
|
+
d.hasPopupRenderer,
|
|
1147
|
+
d.hasTooltipRenderer,
|
|
1148
|
+
d.preparedAnnotations,
|
|
1149
|
+
d.preparedInteractions
|
|
1150
|
+
],
|
|
1151
|
+
() => {
|
|
1152
|
+
if (interactionStartDiagnostic && mounted && !mounted.scope.disposed) {
|
|
1153
|
+
attachInteractions(mounted);
|
|
1154
|
+
}
|
|
1044
1155
|
}
|
|
1045
1156
|
);
|
|
1046
1157
|
effect("reconcileInteractions", [d.preparedInteractions], () => {
|
|
@@ -1100,23 +1211,13 @@ function createTileflowMap(container, initialOptions, createOptions = {}) {
|
|
|
1100
1211
|
],
|
|
1101
1212
|
() => d.isImageMode ? void 0 : mountMap()
|
|
1102
1213
|
);
|
|
1103
|
-
effect("theme", [d.runtimeStyle, d.themeBlendKey
|
|
1214
|
+
effect("theme", [d.runtimeStyle, d.themeBlendKey], () => {
|
|
1104
1215
|
const controller = themeController;
|
|
1105
1216
|
if (!controller || d.themeBlendKey) return;
|
|
1106
|
-
if (d.themeResolution.error) {
|
|
1107
|
-
void controller.setTheme(controller.getCurrent());
|
|
1108
|
-
return;
|
|
1109
|
-
}
|
|
1110
1217
|
if (!d.runtimeStyle || controller.getCurrent() === d.runtimeStyle && !controller.getBlend()) {
|
|
1111
1218
|
return;
|
|
1112
1219
|
}
|
|
1113
|
-
|
|
1114
|
-
invalidate();
|
|
1115
|
-
void controller.setTheme(d.runtimeStyle, { transition: options.themeTransition }).then((result) => {
|
|
1116
|
-
if (result.status === "failed") {
|
|
1117
|
-
reportError("theme", result.error ?? new Error("The map theme could not be changed."));
|
|
1118
|
-
}
|
|
1119
|
-
});
|
|
1220
|
+
requestTheme(controller, d.runtimeStyle, d.themeSelection);
|
|
1120
1221
|
});
|
|
1121
1222
|
const themeResolutionCause = d.themeResolution.error ? d.themeResolution.cause : void 0;
|
|
1122
1223
|
effect("themeError", [d.themeResolution.error, themeResolutionCause], () => {
|
|
@@ -1172,6 +1273,19 @@ function createTileflowMap(container, initialOptions, createOptions = {}) {
|
|
|
1172
1273
|
}
|
|
1173
1274
|
invalidate();
|
|
1174
1275
|
}
|
|
1276
|
+
function reconcileData(runtime) {
|
|
1277
|
+
try {
|
|
1278
|
+
dataBridgeDiagnostic = void 0;
|
|
1279
|
+
runtime.reconcile(dataInput);
|
|
1280
|
+
} catch (error) {
|
|
1281
|
+
console.error("Failed to reconcile Tileflow data layers", error);
|
|
1282
|
+
dataBridgeDiagnostic = createOverlayFailureDiagnostic(
|
|
1283
|
+
"Tileflow data layers could not be reconciled."
|
|
1284
|
+
);
|
|
1285
|
+
reportDiagnostic(dataBridgeDiagnostic);
|
|
1286
|
+
}
|
|
1287
|
+
invalidate();
|
|
1288
|
+
}
|
|
1175
1289
|
function reconcileInteractions(runtime, bindings) {
|
|
1176
1290
|
try {
|
|
1177
1291
|
semanticBridgeDiagnostic = void 0;
|
|
@@ -1203,10 +1317,10 @@ function createTileflowMap(container, initialOptions, createOptions = {}) {
|
|
|
1203
1317
|
if (!initialRuntimeStyle) return void 0;
|
|
1204
1318
|
activeRuntimeResource = initialRuntimeStyle;
|
|
1205
1319
|
captureState = "loading";
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
const { mapOptions, resolvedInteractive } = current;
|
|
1320
|
+
const scope = createTileflowResourceScope();
|
|
1321
|
+
const { mapOptions } = current;
|
|
1209
1322
|
const resourceLifetime = new AbortController();
|
|
1323
|
+
scope.add(() => resourceLifetime.abort());
|
|
1210
1324
|
const session = createTileflowSessionController({ source: sessionSource });
|
|
1211
1325
|
const resourceTransform = createTileflowTransformRequest({
|
|
1212
1326
|
getAnalytics: () => current.resolvedAnalytics,
|
|
@@ -1228,337 +1342,400 @@ function createTileflowMap(container, initialOptions, createOptions = {}) {
|
|
|
1228
1342
|
return prepared;
|
|
1229
1343
|
})
|
|
1230
1344
|
]).then(([maplibregl, prepared]) => {
|
|
1231
|
-
if (
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
const
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
runTileflowCleanups([...setupCleanups].reverse());
|
|
1240
|
-
} finally {
|
|
1241
|
-
map = null;
|
|
1242
|
-
interactionRuntime = void 0;
|
|
1243
|
-
semanticRuntime = void 0;
|
|
1244
|
-
interactionCoordinator = void 0;
|
|
1245
|
-
annotationDiagnostics = [];
|
|
1246
|
-
annotationRenderTargets = [];
|
|
1247
|
-
annotationBridgeDiagnostic = void 0;
|
|
1248
|
-
semanticDiagnostics = [];
|
|
1249
|
-
semanticRenderTargets = [];
|
|
1250
|
-
semanticBridgeDiagnostic = void 0;
|
|
1251
|
-
stateBridgeDiagnostic = void 0;
|
|
1252
|
-
rendererBridgeDiagnostic = void 0;
|
|
1253
|
-
invalidate();
|
|
1254
|
-
}
|
|
1255
|
-
};
|
|
1256
|
-
const sessionStarter = createTileflowSessionStarter({
|
|
1257
|
-
getSessionId: () => session.sessionId,
|
|
1258
|
-
sessionId: session.sessionId,
|
|
1259
|
-
source: sessionSource
|
|
1260
|
-
});
|
|
1261
|
-
const fairUseNotice = attachTileflowFairUseNotice(container);
|
|
1262
|
-
registerCleanup(() => fairUseNotice.dispose());
|
|
1263
|
-
registerTileflowContourProtocol({ addProtocol: maplibregl.addProtocol });
|
|
1264
|
-
registerTileflowPathGroundProtocol({ addProtocol: maplibregl.addProtocol });
|
|
1265
|
-
registerTileflowPmtilesProtocol({ addProtocol: maplibregl.addProtocol });
|
|
1266
|
-
const worldRequestBridge = registerTileflowWorldRequestBridge({
|
|
1267
|
-
addProtocol: maplibregl.addProtocol,
|
|
1268
|
-
onNotice: fairUseNotice.update
|
|
1269
|
-
});
|
|
1270
|
-
registerCleanup(() => worldRequestBridge.dispose());
|
|
1271
|
-
const contourRequestScope = createTileflowContourRequestScope({
|
|
1272
|
-
transformRequest: (url, resourceType) => transformRequest(
|
|
1273
|
-
url,
|
|
1274
|
-
resourceType
|
|
1275
|
-
)
|
|
1276
|
-
});
|
|
1277
|
-
registerCleanup(() => contourRequestScope.dispose());
|
|
1278
|
-
const transformRequest = createTileflowTransformRequest({
|
|
1279
|
-
contourRequestScope,
|
|
1280
|
-
getAnalytics: () => current.resolvedAnalytics,
|
|
1281
|
-
sessionController: session,
|
|
1282
|
-
sessionId: session.sessionId,
|
|
1283
|
-
transformRequest: mapOptions?.transformRequest ?? void 0,
|
|
1284
|
-
worldRequestBridge
|
|
1285
|
-
});
|
|
1286
|
-
const mapLibreMap = new maplibregl.Map({
|
|
1287
|
-
...mapOptions,
|
|
1288
|
-
canvasContextAttributes: tileflowCanvasContextAttributes(
|
|
1289
|
-
mapOptions?.canvasContextAttributes
|
|
1290
|
-
),
|
|
1291
|
-
container,
|
|
1292
|
-
style: prepared.style,
|
|
1293
|
-
bearing: current.resolvedBearing,
|
|
1294
|
-
center: current.resolvedCenter,
|
|
1295
|
-
pitch: current.resolvedPitch,
|
|
1296
|
-
zoom: current.resolvedZoom,
|
|
1297
|
-
interactive: resolvedInteractive,
|
|
1298
|
-
attributionControl: mapOptions?.attributionControl ?? { compact: true },
|
|
1299
|
-
// Tileflow's compiled styles are validated when they are built.
|
|
1300
|
-
validateStyle: mapOptions?.validateStyle ?? false,
|
|
1301
|
-
maxPitch: mapOptions?.maxPitch ?? tileflowMaxPitch,
|
|
1302
|
-
transformRequest
|
|
1303
|
-
});
|
|
1304
|
-
map = mapLibreMap;
|
|
1305
|
-
registerCleanup(() => mapLibreMap.remove());
|
|
1306
|
-
registerCleanup(attachTileflowAtmosphere(mapLibreMap));
|
|
1307
|
-
registerCleanup(attachTileflowBranding(mapLibreMap));
|
|
1308
|
-
registerCleanup(attachTileflowNotices(mapLibreMap));
|
|
1309
|
-
registerCleanup(attachTileflowNauticalLights(mapLibreMap));
|
|
1310
|
-
registerCleanup(attachTileflowLabelPlacement(mapLibreMap));
|
|
1311
|
-
registerCleanup(attachTileflowHorizonQueries(mapLibreMap));
|
|
1312
|
-
const controller = initialRuntimeStyle.theme === void 0 ? void 0 : createTileflowThemeController({
|
|
1313
|
-
initial: prepared.family ? prepared : initialRuntimeStyle,
|
|
1314
|
-
initialStyle: prepared.style,
|
|
1315
|
-
styleLoadOptions,
|
|
1316
|
-
map: mapLibreMap,
|
|
1317
|
-
onTransition(transition) {
|
|
1318
|
-
options.onThemeChange?.(transition);
|
|
1319
|
-
themeTransitionState = transition.phase === "preloading" || transition.phase === "applying" ? "loading" : transition.phase === "error" ? "error" : "idle";
|
|
1320
|
-
invalidate();
|
|
1321
|
-
}
|
|
1322
|
-
});
|
|
1323
|
-
if (controller) {
|
|
1324
|
-
themeController = controller;
|
|
1325
|
-
registerCleanup(() => {
|
|
1326
|
-
controller.dispose();
|
|
1327
|
-
if (themeController === controller) themeController = void 0;
|
|
1328
|
-
});
|
|
1329
|
-
const appearance = createTileflowAppearanceBinding({
|
|
1330
|
-
controller,
|
|
1331
|
-
// CSS variables in `colors` are read where the map sits.
|
|
1332
|
-
element: container,
|
|
1333
|
-
map: mapLibreMap,
|
|
1334
|
-
onError: (error, part) => reportError(part, error)
|
|
1335
|
-
});
|
|
1336
|
-
appearanceBinding = appearance;
|
|
1337
|
-
registerCleanup(() => {
|
|
1338
|
-
appearance.dispose();
|
|
1339
|
-
if (appearanceBinding === appearance) appearanceBinding = void 0;
|
|
1340
|
-
});
|
|
1341
|
-
appearance.update(
|
|
1342
|
-
{ colors: options.colors, emphasis: options.emphasis },
|
|
1343
|
-
{ transition: { duration: 0 } }
|
|
1344
|
-
);
|
|
1345
|
+
if (scope.disposed || destroyed) return;
|
|
1346
|
+
createMap(scope, maplibregl, prepared, { initialRuntimeStyle, session, styleLoadOptions });
|
|
1347
|
+
}).catch((error) => {
|
|
1348
|
+
const cancelled = scope.disposed || destroyed;
|
|
1349
|
+
try {
|
|
1350
|
+
scope.dispose();
|
|
1351
|
+
} catch (cleanupError) {
|
|
1352
|
+
console.error("Failed to release a Tileflow map that could not start", cleanupError);
|
|
1345
1353
|
}
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1354
|
+
if (cancelled) return;
|
|
1355
|
+
reportError("runtime", error);
|
|
1356
|
+
captureState = "error";
|
|
1357
|
+
invalidate();
|
|
1358
|
+
});
|
|
1359
|
+
return () => scope.dispose();
|
|
1360
|
+
}
|
|
1361
|
+
function createMap(scope, maplibregl, prepared, context) {
|
|
1362
|
+
const { initialRuntimeStyle, session, styleLoadOptions } = context;
|
|
1363
|
+
const { mapOptions, resolvedInteractive } = current;
|
|
1364
|
+
scope.add(() => {
|
|
1365
|
+
map = null;
|
|
1366
|
+
mounted = void 0;
|
|
1367
|
+
appliedTheme = void 0;
|
|
1368
|
+
invalidate();
|
|
1369
|
+
});
|
|
1370
|
+
const sessionStarter = createTileflowSessionStarter({
|
|
1371
|
+
getSessionId: () => session.sessionId,
|
|
1372
|
+
sessionId: session.sessionId,
|
|
1373
|
+
source: sessionSource
|
|
1374
|
+
});
|
|
1375
|
+
const fairUseNotice = attachTileflowFairUseNotice(container);
|
|
1376
|
+
scope.add(() => fairUseNotice.dispose());
|
|
1377
|
+
registerTileflowContourProtocol({ addProtocol: maplibregl.addProtocol });
|
|
1378
|
+
registerTileflowPathGroundProtocol({ addProtocol: maplibregl.addProtocol });
|
|
1379
|
+
registerTileflowPmtilesProtocol({ addProtocol: maplibregl.addProtocol });
|
|
1380
|
+
const worldRequestBridge = registerTileflowWorldRequestBridge({
|
|
1381
|
+
addProtocol: maplibregl.addProtocol,
|
|
1382
|
+
onNotice: fairUseNotice.update
|
|
1383
|
+
});
|
|
1384
|
+
scope.add(() => worldRequestBridge.dispose());
|
|
1385
|
+
const contourRequestScope = createTileflowContourRequestScope({
|
|
1386
|
+
transformRequest: (url, resourceType) => transformRequest(
|
|
1387
|
+
url,
|
|
1388
|
+
resourceType
|
|
1389
|
+
)
|
|
1390
|
+
});
|
|
1391
|
+
scope.add(() => contourRequestScope.dispose());
|
|
1392
|
+
const transformRequest = createTileflowTransformRequest({
|
|
1393
|
+
contourRequestScope,
|
|
1394
|
+
getAnalytics: () => current.resolvedAnalytics,
|
|
1395
|
+
sessionController: session,
|
|
1396
|
+
sessionId: session.sessionId,
|
|
1397
|
+
transformRequest: mapOptions?.transformRequest ?? void 0,
|
|
1398
|
+
worldRequestBridge
|
|
1399
|
+
});
|
|
1400
|
+
const mapLibreMap = new maplibregl.Map({
|
|
1401
|
+
...mapOptions,
|
|
1402
|
+
canvasContextAttributes: tileflowCanvasContextAttributes(mapOptions?.canvasContextAttributes),
|
|
1403
|
+
container,
|
|
1404
|
+
style: prepared.style,
|
|
1405
|
+
bearing: current.resolvedBearing,
|
|
1406
|
+
center: current.resolvedCenter,
|
|
1407
|
+
pitch: current.resolvedPitch,
|
|
1408
|
+
zoom: current.resolvedZoom,
|
|
1409
|
+
interactive: resolvedInteractive,
|
|
1410
|
+
attributionControl: mapOptions?.attributionControl ?? { compact: true },
|
|
1411
|
+
// Tileflow's compiled styles are validated when they are built.
|
|
1412
|
+
validateStyle: mapOptions?.validateStyle ?? false,
|
|
1413
|
+
maxPitch: mapOptions?.maxPitch ?? tileflowMaxPitch,
|
|
1414
|
+
transformRequest
|
|
1415
|
+
});
|
|
1416
|
+
map = mapLibreMap;
|
|
1417
|
+
let removedByMapLibre = false;
|
|
1418
|
+
scope.add(() => {
|
|
1419
|
+
if (!removedByMapLibre) mapLibreMap.remove();
|
|
1420
|
+
});
|
|
1421
|
+
const handleRemove = () => {
|
|
1422
|
+
removedByMapLibre = true;
|
|
1423
|
+
if (map !== mapLibreMap) return;
|
|
1424
|
+
map = null;
|
|
1425
|
+
queueMicrotask(teardown);
|
|
1426
|
+
};
|
|
1427
|
+
mapLibreMap.on("remove", handleRemove);
|
|
1428
|
+
scope.add(() => mapLibreMap.off("remove", handleRemove));
|
|
1429
|
+
scope.add(attachTileflowAtmosphere(mapLibreMap));
|
|
1430
|
+
scope.add(attachTileflowBranding(mapLibreMap));
|
|
1431
|
+
scope.add(attachTileflowNotices(mapLibreMap));
|
|
1432
|
+
scope.add(attachTileflowNauticalLights(mapLibreMap));
|
|
1433
|
+
scope.add(attachTileflowLabelPlacement(mapLibreMap));
|
|
1434
|
+
scope.add(attachTileflowHorizonQueries(mapLibreMap));
|
|
1435
|
+
let lifecycle;
|
|
1436
|
+
const controller = initialRuntimeStyle.theme === void 0 ? void 0 : createTileflowThemeController({
|
|
1437
|
+
initial: prepared.family ? prepared : initialRuntimeStyle,
|
|
1438
|
+
initialStyle: prepared.style,
|
|
1439
|
+
styleLoadOptions,
|
|
1440
|
+
map: mapLibreMap,
|
|
1441
|
+
onTransition(transition) {
|
|
1442
|
+
if (themeController !== controller) return;
|
|
1443
|
+
if (transition.phase === "ready") {
|
|
1444
|
+
lifecycle?.invalidate("loading");
|
|
1445
|
+
mapLibreMap.triggerRepaint();
|
|
1374
1446
|
}
|
|
1447
|
+
options.onThemeChange?.(transition);
|
|
1448
|
+
themeTransitionState = transition.phase === "preloading" || transition.phase === "applying" ? "loading" : transition.phase === "error" ? "error" : "idle";
|
|
1449
|
+
invalidate();
|
|
1450
|
+
}
|
|
1451
|
+
});
|
|
1452
|
+
if (controller) {
|
|
1453
|
+
themeController = controller;
|
|
1454
|
+
scope.add(() => {
|
|
1455
|
+
controller.dispose();
|
|
1456
|
+
if (themeController === controller) themeController = void 0;
|
|
1375
1457
|
});
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
}) => wrapMapLibrePositioned(
|
|
1382
|
-
new maplibregl.Popup({
|
|
1383
|
-
closeButton: false,
|
|
1384
|
-
closeOnClick: false,
|
|
1385
|
-
closeOnMove: false,
|
|
1386
|
-
focusAfterOpen: false,
|
|
1387
|
-
offset: kind === "popup" ? 24 : 18
|
|
1388
|
-
}).setDOMContent(overlayContainer)
|
|
1389
|
-
);
|
|
1390
|
-
const annotationRuntime = createTileflowMapLibreDomRuntime({
|
|
1391
|
-
createMarker({ annotation, element }) {
|
|
1392
|
-
const marker = new maplibregl.Marker({ element });
|
|
1393
|
-
element.title = annotationTitles.get(annotation.id) ?? annotation.ariaLabel;
|
|
1394
|
-
return wrapMapLibrePositioned(marker);
|
|
1395
|
-
},
|
|
1396
|
-
createOverlay,
|
|
1397
|
-
customMarker: current.hasMarkerRenderer,
|
|
1398
|
-
customPopup: current.hasPopupRenderer,
|
|
1399
|
-
customTooltip: current.hasTooltipRenderer,
|
|
1400
|
-
document: container.ownerDocument,
|
|
1401
|
-
interactionState: coordinator.getInteractionState(),
|
|
1458
|
+
appliedTheme = { selection: current.themeSelection, theme: initialRuntimeStyle.theme };
|
|
1459
|
+
const appearance = createTileflowAppearanceBinding({
|
|
1460
|
+
controller,
|
|
1461
|
+
// CSS variables in `colors` are read where the map sits.
|
|
1462
|
+
element: container,
|
|
1402
1463
|
map: mapLibreMap,
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
updateMarker(_marker, { annotation, element }) {
|
|
1406
|
-
element.title = annotationTitles.get(annotation.id) ?? annotation.ariaLabel;
|
|
1464
|
+
onError: (error, part) => {
|
|
1465
|
+
if (appearanceBinding === appearance) reportError(part, error);
|
|
1407
1466
|
}
|
|
1408
1467
|
});
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
document: container.ownerDocument,
|
|
1414
|
-
map: mapLibreMap,
|
|
1415
|
-
onDiagnostic: reportDiagnostic,
|
|
1416
|
-
onInteractionEvent(event) {
|
|
1417
|
-
options.onInteractionEvent?.(event);
|
|
1418
|
-
},
|
|
1419
|
-
setHiddenAnnotations: annotationRuntime.setHiddenAnnotations
|
|
1468
|
+
appearanceBinding = appearance;
|
|
1469
|
+
scope.add(() => {
|
|
1470
|
+
appearance.dispose();
|
|
1471
|
+
if (appearanceBinding === appearance) appearanceBinding = void 0;
|
|
1420
1472
|
});
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
if (dataRuntime === mapDataRuntime) dataRuntime = void 0;
|
|
1425
|
-
});
|
|
1426
|
-
const featureRuntime = createTileflowMapLibreSemanticDomRuntime({
|
|
1427
|
-
cancelFrame: (frame) => browserWindow.cancelAnimationFrame(frame),
|
|
1428
|
-
createOverlay,
|
|
1429
|
-
customPopup: current.hasPopupRenderer,
|
|
1430
|
-
customTooltip: current.hasTooltipRenderer,
|
|
1431
|
-
document: container.ownerDocument,
|
|
1432
|
-
interactionState: coordinator.getInteractionState(),
|
|
1433
|
-
map: mapLibreMap,
|
|
1434
|
-
onDiagnostic: reportDiagnostic,
|
|
1435
|
-
onInteractionStateChange: coordinator.requestInteractionState,
|
|
1436
|
-
poiMap: createTileflowMapLibrePoiMap(mapLibreMap),
|
|
1437
|
-
requestFrame: (callback) => browserWindow.requestAnimationFrame(() => callback())
|
|
1438
|
-
});
|
|
1439
|
-
semanticRuntime = featureRuntime;
|
|
1440
|
-
registerCleanup(() => featureRuntime.dispose());
|
|
1441
|
-
registerCleanup(coordinator.attach("annotation", annotationRuntime));
|
|
1442
|
-
registerCleanup(coordinator.attach("semantic", featureRuntime));
|
|
1443
|
-
registerCleanup(
|
|
1444
|
-
annotationRuntime.subscribeEvents((event) => options.onInteractionEvent?.(event))
|
|
1445
|
-
);
|
|
1446
|
-
registerCleanup(
|
|
1447
|
-
annotationRuntime.subscribeDiagnostics((diagnostics) => {
|
|
1448
|
-
annotationDiagnostics = diagnostics;
|
|
1449
|
-
invalidate();
|
|
1450
|
-
})
|
|
1451
|
-
);
|
|
1452
|
-
registerCleanup(
|
|
1453
|
-
annotationRuntime.subscribeRenderTargets((targets) => {
|
|
1454
|
-
annotationRenderTargets = targets;
|
|
1455
|
-
invalidate();
|
|
1456
|
-
})
|
|
1457
|
-
);
|
|
1458
|
-
registerCleanup(
|
|
1459
|
-
featureRuntime.subscribeEvents((event) => {
|
|
1460
|
-
if (event.target.kind === "annotation") return;
|
|
1461
|
-
options.onInteractionEvent?.({ ...event, target: event.target });
|
|
1462
|
-
})
|
|
1463
|
-
);
|
|
1464
|
-
registerCleanup(
|
|
1465
|
-
featureRuntime.subscribeDiagnostics((diagnostics) => {
|
|
1466
|
-
semanticDiagnostics = diagnostics;
|
|
1467
|
-
invalidate();
|
|
1468
|
-
})
|
|
1469
|
-
);
|
|
1470
|
-
registerCleanup(
|
|
1471
|
-
featureRuntime.subscribeRenderTargets((targets) => {
|
|
1472
|
-
semanticRenderTargets = targets;
|
|
1473
|
-
invalidate();
|
|
1474
|
-
})
|
|
1473
|
+
appearance.update(
|
|
1474
|
+
{ colors: options.colors, emphasis: options.emphasis },
|
|
1475
|
+
{ transition: { duration: 0 } }
|
|
1475
1476
|
);
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
}
|
|
1528
|
-
}
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1477
|
+
}
|
|
1478
|
+
const mapScene = attachTileflowMap3D({
|
|
1479
|
+
map: mapLibreMap,
|
|
1480
|
+
...controller ? { controller } : {},
|
|
1481
|
+
vegetation: options.vegetation,
|
|
1482
|
+
viewMode: options.viewMode ?? "3d",
|
|
1483
|
+
load: () => import("@tileflow/core/3d"),
|
|
1484
|
+
onError: (error) => {
|
|
1485
|
+
if (scene === mapScene) reportError("scene", error);
|
|
1486
|
+
},
|
|
1487
|
+
// Direct tile readers use HTTP, not MapLibre's custom World protocol.
|
|
1488
|
+
transformRequest: createTileflowTransformRequest({
|
|
1489
|
+
getAnalytics: () => current.resolvedAnalytics,
|
|
1490
|
+
sessionController: session,
|
|
1491
|
+
sessionId: session.sessionId,
|
|
1492
|
+
transformRequest: (url) => mapOptions?.transformRequest?.(
|
|
1493
|
+
url,
|
|
1494
|
+
"Tile"
|
|
1495
|
+
)
|
|
1496
|
+
})
|
|
1497
|
+
});
|
|
1498
|
+
scene = mapScene;
|
|
1499
|
+
scope.add(() => {
|
|
1500
|
+
mapScene.dispose();
|
|
1501
|
+
if (scene === mapScene) scene = void 0;
|
|
1502
|
+
});
|
|
1503
|
+
mounted = { map: mapLibreMap, maplibregl, scope };
|
|
1504
|
+
attachInteractions(mounted);
|
|
1505
|
+
const navigation = createTileflowNavigationControlBinding({
|
|
1506
|
+
createControl: (controlOptions) => new maplibregl.NavigationControl(controlOptions),
|
|
1507
|
+
map: mapLibreMap
|
|
1508
|
+
});
|
|
1509
|
+
navigationBinding = navigation;
|
|
1510
|
+
scope.add(() => {
|
|
1511
|
+
navigation.dispose();
|
|
1512
|
+
if (navigationBinding === navigation) navigationBinding = void 0;
|
|
1513
|
+
});
|
|
1514
|
+
navigation.update(current.resolvedInteractive ? options.navigationControl : false);
|
|
1515
|
+
const initialFit = current.cameraFit;
|
|
1516
|
+
appliedCameraFitKey = initialFit.key;
|
|
1517
|
+
if (initialFit.error) reportError("camera", new Error(initialFit.error));
|
|
1518
|
+
if (initialFit.fit) fitCameraTo(mapLibreMap, initialFit.fit, 0);
|
|
1519
|
+
const resizeObserver = new ResizeObserver(() => mapLibreMap.resize());
|
|
1520
|
+
scope.add(() => resizeObserver.disconnect());
|
|
1521
|
+
resizeObserver.observe(container);
|
|
1522
|
+
const mapLifecycle = attachTileflowMapLifecycle({
|
|
1523
|
+
getSession: () => {
|
|
1524
|
+
const analyticsForLoad = current.resolvedAnalytics;
|
|
1525
|
+
return {
|
|
1526
|
+
analytics: analyticsForLoad,
|
|
1527
|
+
styleId: analyticsForLoad?.styleId ?? (typeof initialRuntimeStyle.style === "string" ? initialRuntimeStyle.style : current.mapName)
|
|
1528
|
+
};
|
|
1529
|
+
},
|
|
1530
|
+
map: mapLibreMap,
|
|
1531
|
+
onLoad: (loadedMap) => {
|
|
1532
|
+
settleReady({ map: loadedMap });
|
|
1533
|
+
options.onLoad?.(loadedMap);
|
|
1534
|
+
},
|
|
1535
|
+
scheduler: {
|
|
1536
|
+
cancelFrame: (frame) => browserWindow.cancelAnimationFrame(frame),
|
|
1537
|
+
requestFrame: (callback) => browserWindow.requestAnimationFrame(callback)
|
|
1538
|
+
},
|
|
1539
|
+
sessionStarter,
|
|
1540
|
+
setState: (state) => {
|
|
1541
|
+
if (map !== mapLibreMap) return;
|
|
1542
|
+
captureState = state;
|
|
1543
|
+
invalidate();
|
|
1544
|
+
},
|
|
1545
|
+
subscribe: (subscribedMap, event, listener) => {
|
|
1546
|
+
const subscription = subscribedMap.on(event, listener);
|
|
1547
|
+
return () => subscription.unsubscribe();
|
|
1542
1548
|
}
|
|
1549
|
+
});
|
|
1550
|
+
lifecycle = mapLifecycle;
|
|
1551
|
+
scope.add(() => {
|
|
1552
|
+
lifecycle = void 0;
|
|
1553
|
+
mapLifecycle.dispose();
|
|
1554
|
+
});
|
|
1555
|
+
const latestRuntimeStyle = current.runtimeStyle;
|
|
1556
|
+
const latestBlend = current.blendResolution.styles && current.themeBlendPosition !== void 0 ? {
|
|
1557
|
+
hold: current.themeBlendHold,
|
|
1558
|
+
position: current.themeBlendPosition,
|
|
1559
|
+
themes: current.blendResolution.styles
|
|
1560
|
+
} : null;
|
|
1561
|
+
if (controller && latestBlend) {
|
|
1562
|
+
if (latestRuntimeStyle) activeRuntimeResource = latestRuntimeStyle;
|
|
1563
|
+
void controller.setBlend(latestBlend, { transition: options.themeTransition });
|
|
1564
|
+
} else if (controller && latestRuntimeStyle && latestRuntimeStyle !== initialRuntimeStyle) {
|
|
1565
|
+
requestTheme(controller, latestRuntimeStyle, current.themeSelection);
|
|
1566
|
+
}
|
|
1567
|
+
invalidate();
|
|
1568
|
+
}
|
|
1569
|
+
function attachInteractions(target) {
|
|
1570
|
+
const { map: mapLibreMap, maplibregl } = target;
|
|
1571
|
+
const scope = target.scope.child();
|
|
1572
|
+
scope.add(() => {
|
|
1573
|
+
interactionRuntime = void 0;
|
|
1574
|
+
semanticRuntime = void 0;
|
|
1575
|
+
interactionCoordinator = void 0;
|
|
1576
|
+
dataRuntime = void 0;
|
|
1577
|
+
annotationDiagnostics = [];
|
|
1578
|
+
annotationRenderTargets = [];
|
|
1579
|
+
annotationBridgeDiagnostic = void 0;
|
|
1580
|
+
semanticDiagnostics = [];
|
|
1581
|
+
semanticRenderTargets = [];
|
|
1582
|
+
semanticBridgeDiagnostic = void 0;
|
|
1583
|
+
stateBridgeDiagnostic = void 0;
|
|
1584
|
+
rendererBridgeDiagnostic = void 0;
|
|
1585
|
+
dataBridgeDiagnostic = void 0;
|
|
1543
1586
|
invalidate();
|
|
1544
|
-
})
|
|
1545
|
-
|
|
1587
|
+
});
|
|
1588
|
+
try {
|
|
1589
|
+
startInteractions(scope, mapLibreMap, maplibregl);
|
|
1590
|
+
interactionStartDiagnostic = void 0;
|
|
1591
|
+
} catch (error) {
|
|
1592
|
+
console.error("Failed to start Tileflow map interactions", error);
|
|
1546
1593
|
try {
|
|
1547
|
-
|
|
1594
|
+
scope.dispose();
|
|
1548
1595
|
} catch (cleanupError) {
|
|
1549
|
-
|
|
1596
|
+
console.error("Failed to release Tileflow map interactions", cleanupError);
|
|
1550
1597
|
}
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1598
|
+
interactionStartDiagnostic = createOverlayFailureDiagnostic(
|
|
1599
|
+
"Tileflow map interactions could not start."
|
|
1600
|
+
);
|
|
1601
|
+
reportDiagnostic(interactionStartDiagnostic);
|
|
1602
|
+
}
|
|
1603
|
+
invalidate();
|
|
1604
|
+
}
|
|
1605
|
+
function startInteractions(scope, mapLibreMap, maplibregl) {
|
|
1606
|
+
const coordinator = createTileflowMapLibreInteractionCoordinator({
|
|
1607
|
+
...controlledInteractionOwnership ? { interactionState: coordinatedInteractionState } : { defaultInteractionState: coordinatedInteractionState },
|
|
1608
|
+
onInteractionStateChange(state) {
|
|
1609
|
+
if (interactionCoordinator !== coordinator) return;
|
|
1610
|
+
if (!controlledInteractionOwnership) coordinatedInteractionState = state;
|
|
1611
|
+
options.onInteractionStateChange?.(state);
|
|
1612
|
+
}
|
|
1613
|
+
});
|
|
1614
|
+
interactionCoordinator = coordinator;
|
|
1615
|
+
scope.add(() => coordinator.dispose());
|
|
1616
|
+
const createOverlay = ({
|
|
1617
|
+
container: overlayContainer,
|
|
1618
|
+
kind
|
|
1619
|
+
}) => wrapMapLibrePositioned(
|
|
1620
|
+
new maplibregl.Popup({
|
|
1621
|
+
closeButton: false,
|
|
1622
|
+
closeOnClick: false,
|
|
1623
|
+
closeOnMove: false,
|
|
1624
|
+
focusAfterOpen: false,
|
|
1625
|
+
offset: kind === "popup" ? 24 : 18
|
|
1626
|
+
}).setDOMContent(overlayContainer)
|
|
1627
|
+
);
|
|
1628
|
+
const annotationRuntime = createTileflowMapLibreDomRuntime({
|
|
1629
|
+
createMarker({ annotation, element }) {
|
|
1630
|
+
const marker = new maplibregl.Marker({ element });
|
|
1631
|
+
element.title = annotationTitles.get(annotation.id) ?? annotation.ariaLabel;
|
|
1632
|
+
return wrapMapLibrePositioned(marker);
|
|
1633
|
+
},
|
|
1634
|
+
createOverlay,
|
|
1635
|
+
customMarker: current.hasMarkerRenderer,
|
|
1636
|
+
customPopup: current.hasPopupRenderer,
|
|
1637
|
+
customTooltip: current.hasTooltipRenderer,
|
|
1638
|
+
document: container.ownerDocument,
|
|
1639
|
+
interactionState: coordinator.getInteractionState(),
|
|
1640
|
+
map: mapLibreMap,
|
|
1641
|
+
onInteractionStateChange: coordinator.requestInteractionState,
|
|
1642
|
+
onDiagnostic: reportDiagnostic,
|
|
1643
|
+
updateMarker(_marker, { annotation, element }) {
|
|
1644
|
+
element.title = annotationTitles.get(annotation.id) ?? annotation.ariaLabel;
|
|
1645
|
+
}
|
|
1646
|
+
});
|
|
1647
|
+
interactionRuntime = annotationRuntime;
|
|
1648
|
+
scope.add(() => annotationRuntime.dispose());
|
|
1649
|
+
const mapDataRuntime = createTileflowMapLibreDataRuntime({
|
|
1650
|
+
createMarker: ({ element }) => wrapMapLibrePositioned(new maplibregl.Marker({ element })),
|
|
1651
|
+
document: container.ownerDocument,
|
|
1652
|
+
map: mapLibreMap,
|
|
1653
|
+
onDiagnostic: reportDiagnostic,
|
|
1654
|
+
onInteractionEvent(event) {
|
|
1655
|
+
options.onInteractionEvent?.(event);
|
|
1656
|
+
},
|
|
1657
|
+
setHiddenAnnotations: annotationRuntime.setHiddenAnnotations
|
|
1658
|
+
});
|
|
1659
|
+
dataRuntime = mapDataRuntime;
|
|
1660
|
+
scope.add(() => mapDataRuntime.dispose());
|
|
1661
|
+
const featureRuntime = createTileflowMapLibreSemanticDomRuntime({
|
|
1662
|
+
cancelFrame: (frame) => browserWindow.cancelAnimationFrame(frame),
|
|
1663
|
+
createOverlay,
|
|
1664
|
+
customPopup: current.hasPopupRenderer,
|
|
1665
|
+
customTooltip: current.hasTooltipRenderer,
|
|
1666
|
+
document: container.ownerDocument,
|
|
1667
|
+
interactionState: coordinator.getInteractionState(),
|
|
1668
|
+
map: mapLibreMap,
|
|
1669
|
+
onDiagnostic: reportDiagnostic,
|
|
1670
|
+
onInteractionStateChange: coordinator.requestInteractionState,
|
|
1671
|
+
poiMap: createTileflowMapLibrePoiMap(mapLibreMap),
|
|
1672
|
+
requestFrame: (callback) => browserWindow.requestAnimationFrame(() => callback())
|
|
1673
|
+
});
|
|
1674
|
+
semanticRuntime = featureRuntime;
|
|
1675
|
+
scope.add(() => featureRuntime.dispose());
|
|
1676
|
+
scope.add(coordinator.attach("annotation", annotationRuntime));
|
|
1677
|
+
scope.add(coordinator.attach("semantic", featureRuntime));
|
|
1678
|
+
scope.add(annotationRuntime.subscribeEvents((event) => options.onInteractionEvent?.(event)));
|
|
1679
|
+
scope.add(
|
|
1680
|
+
annotationRuntime.subscribeDiagnostics((diagnostics) => {
|
|
1681
|
+
annotationDiagnostics = diagnostics;
|
|
1682
|
+
invalidate();
|
|
1683
|
+
})
|
|
1684
|
+
);
|
|
1685
|
+
scope.add(
|
|
1686
|
+
annotationRuntime.subscribeRenderTargets((targets) => {
|
|
1687
|
+
annotationRenderTargets = targets;
|
|
1554
1688
|
invalidate();
|
|
1689
|
+
})
|
|
1690
|
+
);
|
|
1691
|
+
scope.add(
|
|
1692
|
+
featureRuntime.subscribeEvents((event) => {
|
|
1693
|
+
if (event.target.kind === "annotation") return;
|
|
1694
|
+
options.onInteractionEvent?.({ ...event, target: event.target });
|
|
1695
|
+
})
|
|
1696
|
+
);
|
|
1697
|
+
scope.add(
|
|
1698
|
+
featureRuntime.subscribeDiagnostics((diagnostics) => {
|
|
1699
|
+
semanticDiagnostics = diagnostics;
|
|
1700
|
+
invalidate();
|
|
1701
|
+
})
|
|
1702
|
+
);
|
|
1703
|
+
scope.add(
|
|
1704
|
+
featureRuntime.subscribeRenderTargets((targets) => {
|
|
1705
|
+
semanticRenderTargets = targets;
|
|
1706
|
+
invalidate();
|
|
1707
|
+
})
|
|
1708
|
+
);
|
|
1709
|
+
annotationDiagnostics = annotationRuntime.getDiagnostics();
|
|
1710
|
+
annotationRenderTargets = annotationRuntime.getRenderTargets();
|
|
1711
|
+
semanticDiagnostics = featureRuntime.getDiagnostics();
|
|
1712
|
+
semanticRenderTargets = featureRuntime.getRenderTargets();
|
|
1713
|
+
reconcileAnnotations(annotationRuntime, annotationsForRuntime);
|
|
1714
|
+
reconcileData(mapDataRuntime);
|
|
1715
|
+
const initialInteractions = current.preparedInteractions;
|
|
1716
|
+
if (initialInteractions.ok) reconcileInteractions(featureRuntime, initialInteractions.bindings);
|
|
1717
|
+
}
|
|
1718
|
+
function requestTheme(controller, style, selection) {
|
|
1719
|
+
const requested = { selection: options.theme, theme: current.themeResolution.name };
|
|
1720
|
+
const standingIn = current.themeRequestFailed || current.themeResolution.error;
|
|
1721
|
+
activeRuntimeResource = style;
|
|
1722
|
+
invalidate();
|
|
1723
|
+
void controller.setTheme(style, { transition: options.themeTransition }).then((result) => {
|
|
1724
|
+
if (destroyed || themeController !== controller) return;
|
|
1725
|
+
if (result.status === "applied") {
|
|
1726
|
+
appliedTheme = { selection, theme: result.theme };
|
|
1727
|
+
if (!standingIn) failedTheme = void 0;
|
|
1728
|
+
} else if (result.status === "failed") {
|
|
1729
|
+
const shown = controller.getCurrent().theme;
|
|
1730
|
+
const applied = appliedTheme ?? { selection: shown, theme: shown };
|
|
1731
|
+
failedTheme = {
|
|
1732
|
+
...requested,
|
|
1733
|
+
fallback: standingIn ? { selection: applied.theme, theme: applied.theme } : applied
|
|
1734
|
+
};
|
|
1735
|
+
reportError("theme", result.error ?? new Error("The map theme could not be changed."));
|
|
1555
1736
|
}
|
|
1737
|
+
invalidate();
|
|
1556
1738
|
});
|
|
1557
|
-
return () => {
|
|
1558
|
-
cancelled = true;
|
|
1559
|
-
resourceLifetime.abort();
|
|
1560
|
-
disposeMap?.();
|
|
1561
|
-
};
|
|
1562
1739
|
}
|
|
1563
1740
|
function computeStatus() {
|
|
1564
1741
|
const d = current;
|
|
@@ -1569,6 +1746,8 @@ function createTileflowMap(container, initialOptions, createOptions = {}) {
|
|
|
1569
1746
|
...stateBridgeDiagnostic ? [stateBridgeDiagnostic] : [],
|
|
1570
1747
|
...rendererBridgeDiagnostic ? [rendererBridgeDiagnostic] : [],
|
|
1571
1748
|
...viewBridgeDiagnostic ? [viewBridgeDiagnostic] : [],
|
|
1749
|
+
...dataBridgeDiagnostic ? [dataBridgeDiagnostic] : [],
|
|
1750
|
+
...interactionStartDiagnostic ? [interactionStartDiagnostic] : [],
|
|
1572
1751
|
...annotationDiagnostics,
|
|
1573
1752
|
...semanticDiagnostics
|
|
1574
1753
|
];
|
|
@@ -1585,7 +1764,7 @@ function createTileflowMap(container, initialOptions, createOptions = {}) {
|
|
|
1585
1764
|
return {
|
|
1586
1765
|
diagnostics,
|
|
1587
1766
|
readiness: parts.includes("error") ? "error" : parts.every((part) => part === "idle") ? "idle" : "loading",
|
|
1588
|
-
theme: d.
|
|
1767
|
+
theme: d.shownThemeResolution.name,
|
|
1589
1768
|
imageUrl: d.isImageMode ? d.runtimeImageUrl : void 0
|
|
1590
1769
|
};
|
|
1591
1770
|
}
|
|
@@ -1619,27 +1798,31 @@ function createTileflowMap(container, initialOptions, createOptions = {}) {
|
|
|
1619
1798
|
}
|
|
1620
1799
|
reconcile();
|
|
1621
1800
|
}
|
|
1801
|
+
function teardown() {
|
|
1802
|
+
if (destroyed) return;
|
|
1803
|
+
destroyed = true;
|
|
1804
|
+
settleReady({ error: new DOMException("The Tileflow map was destroyed.", "AbortError") });
|
|
1805
|
+
try {
|
|
1806
|
+
runTileflowCleanups([() => viewHost.dispose(), () => reconciler.dispose()]);
|
|
1807
|
+
} catch (error) {
|
|
1808
|
+
console.error("Failed to release a Tileflow map", error);
|
|
1809
|
+
} finally {
|
|
1810
|
+
map = null;
|
|
1811
|
+
mounted = void 0;
|
|
1812
|
+
if (statusElement) {
|
|
1813
|
+
for (const attribute of statusAttributes) statusElement.removeAttribute(attribute);
|
|
1814
|
+
}
|
|
1815
|
+
}
|
|
1816
|
+
}
|
|
1622
1817
|
reconcile();
|
|
1623
1818
|
return {
|
|
1624
1819
|
container,
|
|
1625
|
-
destroy
|
|
1626
|
-
if (destroyed) return;
|
|
1627
|
-
destroyed = true;
|
|
1628
|
-
settleReady({ error: new DOMException("The Tileflow map was destroyed.", "AbortError") });
|
|
1629
|
-
try {
|
|
1630
|
-
viewHost.dispose();
|
|
1631
|
-
reconciler.dispose();
|
|
1632
|
-
} finally {
|
|
1633
|
-
if (statusElement) {
|
|
1634
|
-
for (const attribute of statusAttributes) statusElement.removeAttribute(attribute);
|
|
1635
|
-
}
|
|
1636
|
-
}
|
|
1637
|
-
},
|
|
1820
|
+
destroy: teardown,
|
|
1638
1821
|
getInteractionState: () => interactionCoordinator?.getInteractionState() ?? coordinatedInteractionState,
|
|
1639
1822
|
getMap: () => map,
|
|
1640
1823
|
getRenderTargets: () => lastRenderTargets,
|
|
1641
1824
|
getStatus: () => lastStatus ?? computeStatus(),
|
|
1642
|
-
getThemeController: () => themeController ?? null,
|
|
1825
|
+
getThemeController: () => map ? themeController ?? null : null,
|
|
1643
1826
|
ready,
|
|
1644
1827
|
setAnnotations: (annotations) => update({ annotations }),
|
|
1645
1828
|
setBounds: (bounds, fitBoundsOptions) => update(fitBoundsOptions === void 0 ? { bounds } : { bounds, fitBoundsOptions }),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tileflow/dom",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.1",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"description": "Mount a Tileflow map in any DOM element, without a framework.",
|
|
6
6
|
"type": "module",
|
|
@@ -40,8 +40,8 @@
|
|
|
40
40
|
"access": "public"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@tileflow/core": ">=0.1.0-alpha.
|
|
44
|
-
"@tileflow/interactions": ">=0.1.0-alpha.
|
|
43
|
+
"@tileflow/core": ">=0.1.0-alpha.51 <0.1.0-beta.0",
|
|
44
|
+
"@tileflow/interactions": ">=0.1.0-alpha.10 <0.1.0-beta.0"
|
|
45
45
|
},
|
|
46
46
|
"peerDependencies": {
|
|
47
47
|
"maplibre-gl": ">=6.4.1 <7"
|