@fusion.dev/helix-map 0.112.0 → 0.114.0
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/dist/connect-map/connect-map.d.ts +7 -3
- package/dist/connect-map/connect-map.js +17 -16
- package/dist/maplibre/index.d.ts +2 -2
- package/dist/maplibre/index.js +1 -1
- package/dist/maplibre/maplibre-driver.d.ts +5 -0
- package/dist/maplibre/maplibre-driver.js +54 -16
- package/dist/style/index.d.ts +2 -2
- package/dist/style/index.js +1 -1
- package/dist/style/map-style.d.ts +19 -0
- package/dist/style/map-style.js +19 -3
- package/package.json +5 -5
|
@@ -33,9 +33,13 @@ export interface MapDriver {
|
|
|
33
33
|
stop(): void;
|
|
34
34
|
};
|
|
35
35
|
/**
|
|
36
|
-
* Calls `done` once the renderer has drawn its view with
|
|
37
|
-
*
|
|
38
|
-
*
|
|
36
|
+
* Calls `done` once the renderer has drawn its view whole, with every tile
|
|
37
|
+
* it needs and the ground where there is terrain, and returns what stops the
|
|
38
|
+
* waiting. Leave the frame's own shapes out, since a route that animates is
|
|
39
|
+
* redrawn every frame and would never count as drawn. What takes a snapshot
|
|
40
|
+
* drawn on the server away and sends the frame's `helix-map-ready`; without
|
|
41
|
+
* it, the snapshot stays under the renderer's drawing and the frame is never
|
|
42
|
+
* `:state(ready)`.
|
|
39
43
|
*/
|
|
40
44
|
ready?(done: () => void): () => void;
|
|
41
45
|
/**
|
|
@@ -726,23 +726,23 @@ export const connectMap = (frame, driver, options = {}) => {
|
|
|
726
726
|
snapshot.style.display = 'none';
|
|
727
727
|
};
|
|
728
728
|
const snapshots = [...frame.querySelectorAll(':scope > [data-helix-map-snapshot]')];
|
|
729
|
-
const stopWaiting =
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
snapshot
|
|
738
|
-
.animate([{ opacity: 1 }, { opacity: 0 }], {
|
|
739
|
-
duration: motion.duration,
|
|
740
|
-
easing: `linear(${Array.from({ length: 13 }, (_, step) => motion.easing(step / 12).toFixed(3)).join(', ')})`,
|
|
741
|
-
})
|
|
742
|
-
.finished.then(() => away(snapshot), () => away(snapshot));
|
|
729
|
+
const stopWaiting = driver.ready?.(() => {
|
|
730
|
+
place();
|
|
731
|
+
frame.drawn?.();
|
|
732
|
+
const motion = motionOf(frame, 'step');
|
|
733
|
+
for (const snapshot of snapshots) {
|
|
734
|
+
if (!motion || typeof snapshot.animate !== 'function') {
|
|
735
|
+
away(snapshot);
|
|
736
|
+
continue;
|
|
743
737
|
}
|
|
744
|
-
|
|
745
|
-
|
|
738
|
+
snapshot
|
|
739
|
+
.animate([{ opacity: 1 }, { opacity: 0 }], {
|
|
740
|
+
duration: motion.duration,
|
|
741
|
+
easing: `linear(${Array.from({ length: 13 }, (_, step) => motion.easing(step / 12).toFixed(3)).join(', ')})`,
|
|
742
|
+
})
|
|
743
|
+
.finished.then(() => away(snapshot), () => away(snapshot));
|
|
744
|
+
}
|
|
745
|
+
});
|
|
746
746
|
let live = true;
|
|
747
747
|
let placing = false;
|
|
748
748
|
let drawing = false;
|
|
@@ -876,6 +876,7 @@ export const connectMap = (frame, driver, options = {}) => {
|
|
|
876
876
|
stopViewing?.();
|
|
877
877
|
clearTimeout(looking);
|
|
878
878
|
stopWaiting?.();
|
|
879
|
+
frame.drawn?.(false);
|
|
879
880
|
stopTheming?.();
|
|
880
881
|
styled.disconnect();
|
|
881
882
|
children.disconnect();
|
package/dist/maplibre/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type { MapLibreStyle, MapStyleOptions } from '../style/index.js';
|
|
2
|
-
export { mapLibreStyle } from '../style/index.js';
|
|
1
|
+
export type { MapLandmark, MapLibreStyle, MapStyleOptions } from '../style/index.js';
|
|
2
|
+
export { MAP_LANDMARKS, mapLibreStyle } from '../style/index.js';
|
|
3
3
|
export type { FollowedTheme, MapLibreMap } from './maplibre-driver.js';
|
|
4
4
|
export { followTheme, mapLibreDriver } from './maplibre-driver.js';
|
package/dist/maplibre/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { mapLibreStyle } from '../style/index.js';
|
|
1
|
+
export { MAP_LANDMARKS, mapLibreStyle } from '../style/index.js';
|
|
2
2
|
export { followTheme, mapLibreDriver } from './maplibre-driver.js';
|
|
@@ -101,6 +101,11 @@ export interface MapLibreMap {
|
|
|
101
101
|
loaded?(): boolean;
|
|
102
102
|
/** Whether the style has loaded: `true`, and anything else is not yet. MapLibre 6 types it loosely. */
|
|
103
103
|
isStyleLoaded?(): unknown;
|
|
104
|
+
/**
|
|
105
|
+
* Whether one source has every tile the view needs, once the view has asked
|
|
106
|
+
* for them; a source no shown layer draws from has nothing to wait for.
|
|
107
|
+
*/
|
|
108
|
+
isSourceLoaded?(id: string): boolean;
|
|
104
109
|
/** The canvas, which MapLibre makes focusable. */
|
|
105
110
|
getCanvas(): HTMLElement;
|
|
106
111
|
/** The middle of the view, which a map-type picture is drawn around. */
|
|
@@ -1056,30 +1056,68 @@ export const mapLibreDriver = (map) => ({
|
|
|
1056
1056
|
return { x, y };
|
|
1057
1057
|
},
|
|
1058
1058
|
ready: (done) => {
|
|
1059
|
-
if (map.
|
|
1060
|
-
|
|
1061
|
-
|
|
1059
|
+
if (!map.isSourceLoaded) {
|
|
1060
|
+
if (map.loaded?.() && map.areTilesLoaded?.()) {
|
|
1061
|
+
done();
|
|
1062
|
+
return () => undefined;
|
|
1063
|
+
}
|
|
1064
|
+
let finished = false;
|
|
1065
|
+
const finish = () => {
|
|
1066
|
+
if (!finished) {
|
|
1067
|
+
finished = true;
|
|
1068
|
+
map.off('load', finish);
|
|
1069
|
+
map.off('render', drawn);
|
|
1070
|
+
done();
|
|
1071
|
+
}
|
|
1072
|
+
};
|
|
1073
|
+
const drawn = () => {
|
|
1074
|
+
if (map.isStyleLoaded?.() === true && map.areTilesLoaded?.() === true) {
|
|
1075
|
+
finish();
|
|
1076
|
+
}
|
|
1077
|
+
};
|
|
1078
|
+
map.on('load', finish);
|
|
1079
|
+
map.on('render', drawn);
|
|
1080
|
+
return () => {
|
|
1081
|
+
map.off('load', finish);
|
|
1082
|
+
map.off('render', drawn);
|
|
1083
|
+
};
|
|
1062
1084
|
}
|
|
1063
|
-
let
|
|
1064
|
-
const
|
|
1065
|
-
|
|
1066
|
-
|
|
1085
|
+
let tiled;
|
|
1086
|
+
const read = () => {
|
|
1087
|
+
const sources = map.getStyle()?.sources;
|
|
1088
|
+
tiled = sources
|
|
1089
|
+
? Object.entries(sources)
|
|
1090
|
+
.filter(([, source]) => source.type !== 'geojson')
|
|
1091
|
+
.map(([id]) => id)
|
|
1092
|
+
: undefined;
|
|
1093
|
+
};
|
|
1094
|
+
const whole = () => {
|
|
1095
|
+
if (tiled === undefined) {
|
|
1096
|
+
read();
|
|
1067
1097
|
}
|
|
1068
|
-
|
|
1069
|
-
|
|
1098
|
+
return tiled?.every((id) => map.isSourceLoaded?.(id) === true) === true;
|
|
1099
|
+
};
|
|
1100
|
+
if (whole()) {
|
|
1070
1101
|
done();
|
|
1102
|
+
return () => undefined;
|
|
1103
|
+
}
|
|
1104
|
+
const restyled = () => {
|
|
1105
|
+
tiled = undefined;
|
|
1071
1106
|
};
|
|
1072
|
-
const
|
|
1073
|
-
if (
|
|
1074
|
-
|
|
1107
|
+
const heard = () => {
|
|
1108
|
+
if (whole()) {
|
|
1109
|
+
stop();
|
|
1110
|
+
done();
|
|
1075
1111
|
}
|
|
1076
1112
|
};
|
|
1077
1113
|
const stop = () => {
|
|
1078
|
-
map.off('
|
|
1079
|
-
map.off('render',
|
|
1114
|
+
map.off('styledata', restyled);
|
|
1115
|
+
map.off('render', heard);
|
|
1116
|
+
map.off('idle', heard);
|
|
1080
1117
|
};
|
|
1081
|
-
map.on('
|
|
1082
|
-
map.on('render',
|
|
1118
|
+
map.on('styledata', restyled);
|
|
1119
|
+
map.on('render', heard);
|
|
1120
|
+
map.on('idle', heard);
|
|
1083
1121
|
return stop;
|
|
1084
1122
|
},
|
|
1085
1123
|
rotate: ({ by, to }, motion) => {
|
package/dist/style/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export type { MapColors } from './map-colors.js';
|
|
2
2
|
export { colorsNow, colorsReady, fontReady, mapColorsFrom, mapFontFrom, PATIENCE, settledColor, } from './map-colors.js';
|
|
3
|
-
export type { MapImage, MapLibreStyle, MapStyleOptions } from './map-style.js';
|
|
4
|
-
export { mapLibreStyle } from './map-style.js';
|
|
3
|
+
export type { MapImage, MapLandmark, MapLibreStyle, MapStyleOptions } from './map-style.js';
|
|
4
|
+
export { MAP_LANDMARKS, mapLibreStyle } from './map-style.js';
|
package/dist/style/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { colorsNow, colorsReady, fontReady, mapColorsFrom, mapFontFrom, PATIENCE, settledColor, } from './map-colors.js';
|
|
2
|
-
export { mapLibreStyle } from './map-style.js';
|
|
2
|
+
export { MAP_LANDMARKS, mapLibreStyle } from './map-style.js';
|
|
@@ -23,6 +23,18 @@ export interface MapStyleOptions {
|
|
|
23
23
|
* every zoom, which MapLibre 4 also needs, since it has no globe.
|
|
24
24
|
*/
|
|
25
25
|
globe?: boolean | undefined;
|
|
26
|
+
/**
|
|
27
|
+
* Which landmarks the map draws, each kind an icon in a hue of its own.
|
|
28
|
+
* `true`, the default, draws every kind in `MAP_LANDMARKS`; `false` draws
|
|
29
|
+
* none, for a map whose own markers are the places a reader is looking for;
|
|
30
|
+
* a list draws those kinds and no others, such as `['nature', 'transit']`.
|
|
31
|
+
*
|
|
32
|
+
* **An option of the style, so it holds through a theme change.**
|
|
33
|
+
* `followTheme` builds the style again from the same options when the mode
|
|
34
|
+
* changes, where a page hiding the layers itself had them back on every
|
|
35
|
+
* rebuild and had to learn their ids from this file to do it.
|
|
36
|
+
*/
|
|
37
|
+
landmarks?: boolean | readonly MapLandmark[] | undefined;
|
|
26
38
|
/**
|
|
27
39
|
* The language labels are written in, where the tiles carry it, falling back
|
|
28
40
|
* to the Latin name and then the local one. `en` by default.
|
|
@@ -78,6 +90,13 @@ export type MapImage = {
|
|
|
78
90
|
ink: string;
|
|
79
91
|
kind: 'sign';
|
|
80
92
|
};
|
|
93
|
+
/**
|
|
94
|
+
* The kinds of landmark the style draws, each an icon in a hue of its own, for
|
|
95
|
+
* `MapStyleOptions.landmarks`.
|
|
96
|
+
*/
|
|
97
|
+
export declare const MAP_LANDMARKS: readonly ['culture', 'food', 'health', 'learning', 'lodging', 'nature', 'shopping', 'sport', 'transit'];
|
|
98
|
+
/** One kind of landmark, such as `nature` for parks and gardens. */
|
|
99
|
+
export type MapLandmark = (typeof MAP_LANDMARKS)[number];
|
|
81
100
|
/**
|
|
82
101
|
* A MapLibre style in the page's theme.
|
|
83
102
|
*
|
package/dist/style/map-style.js
CHANGED
|
@@ -4,6 +4,17 @@ const OPENFREEMAP = {
|
|
|
4
4
|
glyphs: 'https://tiles.openfreemap.org/fonts/{fontstack}/{range}.pbf',
|
|
5
5
|
tiles: 'https://tiles.openfreemap.org/planet',
|
|
6
6
|
};
|
|
7
|
+
export const MAP_LANDMARKS = [
|
|
8
|
+
'culture',
|
|
9
|
+
'food',
|
|
10
|
+
'health',
|
|
11
|
+
'learning',
|
|
12
|
+
'lodging',
|
|
13
|
+
'nature',
|
|
14
|
+
'shopping',
|
|
15
|
+
'sport',
|
|
16
|
+
'transit',
|
|
17
|
+
];
|
|
7
18
|
const LANDMARKS = [
|
|
8
19
|
{
|
|
9
20
|
classes: ['park', 'garden', 'playground', 'campsite', 'golf', 'zoo'],
|
|
@@ -151,7 +162,10 @@ export const mapLibreStyle = (colors, options = {}) => {
|
|
|
151
162
|
const images = {};
|
|
152
163
|
const landmarkImage = ['match', ['get', 'class']];
|
|
153
164
|
const landmarkColor = ['match', ['get', 'class']];
|
|
154
|
-
|
|
165
|
+
const kept = LANDMARKS.filter(({ group }) => options.landmarks === undefined || options.landmarks === true
|
|
166
|
+
? true
|
|
167
|
+
: options.landmarks !== false && options.landmarks.includes(group));
|
|
168
|
+
for (const { classes, group, hue, icon } of kept) {
|
|
155
169
|
const color = cssColor(hued(hue));
|
|
156
170
|
const image = {
|
|
157
171
|
color,
|
|
@@ -166,7 +180,7 @@ export const mapLibreStyle = (colors, options = {}) => {
|
|
|
166
180
|
}
|
|
167
181
|
landmarkImage.push('');
|
|
168
182
|
landmarkColor.push(legible(land, 0.6));
|
|
169
|
-
const classesOf = (everyday) =>
|
|
183
|
+
const classesOf = (everyday) => kept.filter((one) => (one.everyday === true) === everyday).flatMap(({ classes }) => classes);
|
|
170
184
|
const signFont = face ? `"${face}", sans-serif` : 'sans-serif';
|
|
171
185
|
const signs = `helix-sign-${stamp(signFont)}-`;
|
|
172
186
|
images[`${signs}interstate`] = {
|
|
@@ -375,7 +389,9 @@ export const mapLibreStyle = (colors, options = {}) => {
|
|
|
375
389
|
'source-layer': 'transportation_name',
|
|
376
390
|
type: 'symbol',
|
|
377
391
|
},
|
|
378
|
-
...[false, true]
|
|
392
|
+
...[false, true]
|
|
393
|
+
.filter((everyday) => classesOf(everyday).length > 0)
|
|
394
|
+
.map((everyday) => ({
|
|
379
395
|
filter: ['match', ['get', 'class'], classesOf(everyday), true, false],
|
|
380
396
|
id: everyday ? 'label-landmark-everyday' : 'label-landmark',
|
|
381
397
|
layout: {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fusion.dev/helix-map",
|
|
3
3
|
"description": "Connects the Helix Map frame to a map renderer: MapLibre, Leaflet, or a driver of your own.",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.114.0",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Ross Sheppard <ross.sheppard@fusion.dev>",
|
|
7
7
|
"repository": {
|
|
@@ -43,14 +43,14 @@
|
|
|
43
43
|
},
|
|
44
44
|
"bugs": "https://github.com/project-fusion/fusion/issues",
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"@fusion.dev/helix-core": "0.
|
|
47
|
-
"@fusion.dev/helix-icons": "0.
|
|
46
|
+
"@fusion.dev/helix-core": "0.114.0",
|
|
47
|
+
"@fusion.dev/helix-icons": "0.114.0",
|
|
48
48
|
"@mapbox/vector-tile": "^3.0.0",
|
|
49
49
|
"pbf": "^5.1.2"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
|
-
"@fusion.dev/helix-headless": "0.
|
|
53
|
-
"@fusion.dev/helix-testing": "0.
|
|
52
|
+
"@fusion.dev/helix-headless": "0.114.0",
|
|
53
|
+
"@fusion.dev/helix-testing": "0.114.0",
|
|
54
54
|
"@maplibre/maplibre-gl-style-spec": "^26.4.4",
|
|
55
55
|
"@types/bun": "^1.3.0",
|
|
56
56
|
"@types/leaflet": "^1.9.20",
|