ts-maps 0.2.7 → 0.3.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/LICENSE.md +21 -0
- package/README.md +202 -141
- package/dist/core-map/assets/embedded-icons.d.ts +8 -0
- package/dist/core-map/control/AttributionControl.d.ts +12 -0
- package/dist/core-map/control/Control.d.ts +14 -0
- package/dist/core-map/control/LayersControl.d.ts +38 -0
- package/dist/core-map/control/ScaleControl.d.ts +14 -0
- package/dist/core-map/control/ZoomControl.d.ts +14 -0
- package/dist/core-map/control/index.d.ts +5 -0
- package/dist/core-map/core/Browser.d.ts +24 -0
- package/dist/core-map/core/Class.d.ts +12 -0
- package/dist/core-map/core/Events.d.ts +31 -0
- package/dist/core-map/core/Handler.d.ts +12 -0
- package/dist/core-map/core/Util.d.ts +24 -0
- package/dist/core-map/core/index.d.ts +7 -0
- package/dist/core-map/dom/Animation.d.ts +50 -0
- package/dist/core-map/dom/DomEvent.DoubleTap.d.ts +6 -0
- package/dist/core-map/dom/DomEvent.PointerEvents.d.ts +4 -0
- package/dist/core-map/dom/DomEvent.d.ts +15 -0
- package/dist/core-map/dom/DomUtil.d.ts +22 -0
- package/dist/core-map/dom/Draggable.d.ts +26 -0
- package/dist/core-map/dom/PosAnimation.d.ts +19 -0
- package/dist/core-map/dom/easing.d.ts +41 -0
- package/dist/core-map/dom/index.d.ts +8 -0
- package/dist/core-map/geo/LatLng.d.ts +18 -0
- package/dist/core-map/geo/LatLngBounds.d.ts +27 -0
- package/dist/core-map/geo/TerrainSource.d.ts +35 -0
- package/dist/core-map/geo/crs/CRS.d.ts +23 -0
- package/dist/core-map/geo/crs/EPSG3395.d.ts +7 -0
- package/dist/core-map/geo/crs/EPSG3857.d.ts +10 -0
- package/dist/core-map/geo/crs/EPSG4326.d.ts +7 -0
- package/dist/core-map/geo/crs/EarthCRS.d.ts +7 -0
- package/dist/core-map/geo/crs/SimpleCRS.d.ts +11 -0
- package/dist/core-map/geo/crs/index.d.ts +6 -0
- package/dist/core-map/geo/elevation.d.ts +23 -0
- package/dist/core-map/geo/index.d.ts +13 -0
- package/dist/core-map/geo/index.js +1204 -0
- package/dist/core-map/geo/projection/Projection.Globe.d.ts +30 -0
- package/dist/core-map/geo/projection/Projection.LonLat.d.ts +11 -0
- package/dist/core-map/geo/projection/Projection.Mercator.d.ts +6 -0
- package/dist/core-map/geo/projection/Projection.SphericalMercator.d.ts +6 -0
- package/dist/core-map/geo/projection/index.d.ts +5 -0
- package/dist/core-map/geo/terrainMesh.d.ts +21 -0
- package/dist/core-map/geometry/Bounds.d.ts +23 -0
- package/dist/core-map/geometry/LineUtil.d.ts +13 -0
- package/dist/core-map/geometry/Point.d.ts +35 -0
- package/dist/core-map/geometry/PolyUtil.d.ts +6 -0
- package/dist/core-map/geometry/RTree.d.ts +35 -0
- package/dist/core-map/geometry/Transformation.d.ts +12 -0
- package/dist/core-map/geometry/earcut.d.ts +17 -0
- package/dist/core-map/geometry/index.d.ts +10 -0
- package/dist/core-map/geometry/index.js +1586 -0
- package/dist/core-map/index.d.ts +59 -0
- package/dist/core-map/layer/BlanketOverlay.d.ts +24 -0
- package/dist/core-map/layer/DivOverlay.d.ts +40 -0
- package/dist/core-map/layer/FeatureGroup.d.ts +11 -0
- package/dist/core-map/layer/GeoJSON.d.ts +17 -0
- package/dist/core-map/layer/GeoJSONClusterSource.d.ts +54 -0
- package/dist/core-map/layer/HeatmapLayer.d.ts +40 -0
- package/dist/core-map/layer/ImageOverlay.d.ts +27 -0
- package/dist/core-map/layer/Layer.d.ts +18 -0
- package/dist/core-map/layer/LayerGroup.d.ts +16 -0
- package/dist/core-map/layer/Popup.d.ts +18 -0
- package/dist/core-map/layer/SVGOverlay.d.ts +4 -0
- package/dist/core-map/layer/Tooltip.d.ts +15 -0
- package/dist/core-map/layer/VideoOverlay.d.ts +4 -0
- package/dist/core-map/layer/index.d.ts +18 -0
- package/dist/core-map/layer/marker/DefaultIcon.d.ts +7 -0
- package/dist/core-map/layer/marker/DivIcon.d.ts +5 -0
- package/dist/core-map/layer/marker/Icon.d.ts +10 -0
- package/dist/core-map/layer/marker/Marker.Drag.d.ts +17 -0
- package/dist/core-map/layer/marker/Marker.d.ts +37 -0
- package/dist/core-map/layer/marker/index.d.ts +5 -0
- package/dist/core-map/layer/tile/GridLayer.d.ts +88 -0
- package/dist/core-map/layer/tile/RasterDEMLayer.d.ts +46 -0
- package/dist/core-map/layer/tile/TileLayer.d.ts +22 -0
- package/dist/core-map/layer/tile/VectorTileMapLayer.d.ts +145 -0
- package/dist/core-map/layer/tile/WMSTileLayer.d.ts +12 -0
- package/dist/core-map/layer/tile/index.d.ts +15 -0
- package/dist/core-map/layer/tile/urlTemplate.d.ts +17 -0
- package/dist/core-map/layer/vector/Canvas.d.ts +52 -0
- package/dist/core-map/layer/vector/Circle.d.ts +7 -0
- package/dist/core-map/layer/vector/CircleMarker.d.ts +22 -0
- package/dist/core-map/layer/vector/Path.d.ts +20 -0
- package/dist/core-map/layer/vector/Polygon.d.ts +13 -0
- package/dist/core-map/layer/vector/Polyline.d.ts +30 -0
- package/dist/core-map/layer/vector/Rectangle.d.ts +6 -0
- package/dist/core-map/layer/vector/Renderer.d.ts +12 -0
- package/dist/core-map/layer/vector/Renderer.getRenderer.d.ts +1 -0
- package/dist/core-map/layer/vector/SVG.d.ts +21 -0
- package/dist/core-map/layer/vector/index.d.ts +10 -0
- package/dist/core-map/map/Map.d.ts +353 -0
- package/dist/core-map/map/Style.d.ts +29 -0
- package/dist/core-map/map/handler/BoxZoomHandler.d.ts +23 -0
- package/dist/core-map/map/handler/DoubleClickZoomHandler.d.ts +6 -0
- package/dist/core-map/map/handler/DragHandler.d.ts +27 -0
- package/dist/core-map/map/handler/KeyboardHandler.d.ts +18 -0
- package/dist/core-map/map/handler/PinchZoomHandler.d.ts +20 -0
- package/dist/core-map/map/handler/ScrollWheelZoomHandler.d.ts +12 -0
- package/dist/core-map/map/handler/TapHoldHandler.d.ts +15 -0
- package/dist/core-map/map/handler/TwoFingerPitchHandler.d.ts +21 -0
- package/dist/core-map/map/handler/TwoFingerRotateHandler.d.ts +17 -0
- package/dist/core-map/map/index.d.ts +11 -0
- package/dist/core-map/mvt/VectorTile.d.ts +9 -0
- package/dist/core-map/mvt/VectorTileFeature.d.ts +59 -0
- package/dist/core-map/mvt/VectorTileLayer.d.ts +13 -0
- package/dist/core-map/proto/Pbf.d.ts +84 -0
- package/dist/core-map/renderer/webgl/GLContext.d.ts +22 -0
- package/dist/core-map/renderer/webgl/WebGLTileRenderer.d.ts +86 -0
- package/dist/core-map/renderer/webgl/index.d.ts +9 -0
- package/dist/core-map/renderer/webgl/mat4.d.ts +14 -0
- package/dist/core-map/services/index.d.ts +26 -0
- package/dist/core-map/services/index.js +1230 -0
- package/dist/core-map/services/providers/Google.d.ts +16 -0
- package/dist/core-map/services/providers/Mapbox.d.ts +26 -0
- package/dist/core-map/services/providers/Maptiler.d.ts +11 -0
- package/dist/core-map/services/providers/Nominatim.d.ts +11 -0
- package/dist/core-map/services/providers/OSRM.d.ts +20 -0
- package/dist/core-map/services/providers/Photon.d.ts +10 -0
- package/dist/core-map/services/providers/Valhalla.d.ts +20 -0
- package/dist/core-map/services/types.d.ts +84 -0
- package/dist/core-map/storage/TileCache.d.ts +40 -0
- package/dist/core-map/storage/cachedFetch.d.ts +13 -0
- package/dist/core-map/storage/defaultCache.d.ts +3 -0
- package/dist/core-map/storage/index.d.ts +13 -0
- package/dist/core-map/storage/index.js +283 -0
- package/dist/core-map/storage/offlineRegion.d.ts +26 -0
- package/dist/core-map/style-spec/diff.d.ts +17 -0
- package/dist/core-map/style-spec/expressions/Color.d.ts +16 -0
- package/dist/core-map/style-spec/expressions/compile.d.ts +4 -0
- package/dist/core-map/style-spec/expressions/errors.d.ts +8 -0
- package/dist/core-map/style-spec/expressions/index.d.ts +16 -0
- package/dist/core-map/style-spec/expressions/legacyFilter.d.ts +6 -0
- package/dist/core-map/style-spec/expressions/operators/conversion.d.ts +1 -0
- package/dist/core-map/style-spec/expressions/operators/interpolate.d.ts +14 -0
- package/dist/core-map/style-spec/expressions/operators/logical.d.ts +1 -0
- package/dist/core-map/style-spec/expressions/operators/lookup.d.ts +1 -0
- package/dist/core-map/style-spec/expressions/operators/math.d.ts +1 -0
- package/dist/core-map/style-spec/expressions/operators/string.d.ts +1 -0
- package/dist/core-map/style-spec/expressions/registry.d.ts +29 -0
- package/dist/core-map/style-spec/expressions/types.d.ts +48 -0
- package/dist/core-map/style-spec/expressions/validate.d.ts +13 -0
- package/dist/core-map/style-spec/index.d.ts +68 -0
- package/dist/core-map/style-spec/index.js +2529 -0
- package/dist/core-map/style-spec/schema.d.ts +381 -0
- package/dist/core-map/style-spec/types.d.ts +375 -0
- package/dist/core-map/style-spec/validate.d.ts +14 -0
- package/dist/core-map/symbols/CollisionIndex.d.ts +21 -0
- package/dist/core-map/symbols/GlyphAtlas.d.ts +38 -0
- package/dist/core-map/symbols/IconAtlas.d.ts +18 -0
- package/dist/core-map/symbols/index.d.ts +6 -0
- package/dist/core-map/symbols/index.js +501 -0
- package/dist/index.d.ts +2 -4
- package/dist/index.js +18414 -1857
- package/package.json +50 -58
- package/src/core-map/ts-maps.css +725 -0
- package/dist/components/base.d.ts +0 -17
- package/dist/components/concerns/interactable.d.ts +0 -1
- package/dist/components/line.d.ts +0 -29
- package/dist/components/marker.d.ts +0 -50
- package/dist/components/region.d.ts +0 -46
- package/dist/components/tooltip.d.ts +0 -22
- package/dist/core/apply-transform.d.ts +0 -7
- package/dist/core/coords-to-point.d.ts +0 -12
- package/dist/core/create-lines.d.ts +0 -2
- package/dist/core/create-markers.d.ts +0 -2
- package/dist/core/create-regions.d.ts +0 -2
- package/dist/core/create-series.d.ts +0 -3
- package/dist/core/get-inset-for-point.d.ts +0 -13
- package/dist/core/get-marker-position.d.ts +0 -6
- package/dist/core/index.d.ts +0 -1
- package/dist/core/reposition-labels.d.ts +0 -2
- package/dist/core/reposition-lines.d.ts +0 -2
- package/dist/core/reposition-markers.d.ts +0 -2
- package/dist/core/resize.d.ts +0 -3
- package/dist/core/set-focus.d.ts +0 -2
- package/dist/core/set-scale.d.ts +0 -2
- package/dist/core/setup-container-events.d.ts +0 -2
- package/dist/core/setup-container-touch-events.d.ts +0 -2
- package/dist/core/setup-element-events.d.ts +0 -2
- package/dist/core/setup-zoom-buttons.d.ts +0 -2
- package/dist/core/update-size.d.ts +0 -2
- package/dist/data-visualization.d.ts +0 -17
- package/dist/defaults/events.d.ts +0 -1
- package/dist/defaults/options.d.ts +0 -1
- package/dist/event-handler.d.ts +0 -1
- package/dist/legend.d.ts +0 -17
- package/dist/map.d.ts +0 -81
- package/dist/maps/brasil.d.ts +0 -2
- package/dist/maps/brasil.js +0 -7
- package/dist/maps/canada.d.ts +0 -2
- package/dist/maps/canada.js +0 -7
- package/dist/maps/iraq.d.ts +0 -2
- package/dist/maps/iraq.js +0 -84
- package/dist/maps/italy.d.ts +0 -2
- package/dist/maps/italy.js +0 -7
- package/dist/maps/russia.d.ts +0 -2
- package/dist/maps/russia.js +0 -366
- package/dist/maps/spain.d.ts +0 -2
- package/dist/maps/spain.js +0 -7
- package/dist/maps/us-aea-en.d.ts +0 -2
- package/dist/maps/us-aea-en.js +0 -7
- package/dist/maps/us-lcc-en.d.ts +0 -2
- package/dist/maps/us-lcc-en.js +0 -7
- package/dist/maps/us-merc-en.d.ts +0 -2
- package/dist/maps/us-merc-en.js +0 -7
- package/dist/maps/us-mill-en.d.ts +0 -2
- package/dist/maps/us-mill-en.js +0 -7
- package/dist/maps/world-merc.d.ts +0 -2
- package/dist/maps/world-merc.js +0 -7
- package/dist/maps/world.d.ts +0 -2
- package/dist/maps/world.js +0 -7
- package/dist/projection.d.ts +0 -1
- package/dist/scales/ordinal-scale.d.ts +0 -12
- package/dist/series.d.ts +0 -14
- package/dist/svg/base-element.d.ts +0 -19
- package/dist/svg/canvas-element.d.ts +0 -21
- package/dist/svg/image-element.d.ts +0 -12
- package/dist/svg/shape-element.d.ts +0 -19
- package/dist/svg/text-element.d.ts +0 -7
- package/dist/types.d.ts +0 -418
- package/dist/util/deep-merge.d.ts +0 -2
- package/dist/util/index.d.ts +0 -18
- package/dist/utils.d.ts +0 -87
- package/dist/vector-map.d.ts +0 -5
|
@@ -0,0 +1,1230 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
function __accessProp(key) {
|
|
6
|
+
return this[key];
|
|
7
|
+
}
|
|
8
|
+
var __toCommonJS = (from) => {
|
|
9
|
+
var entry = (__moduleCache ??= new WeakMap).get(from), desc;
|
|
10
|
+
if (entry)
|
|
11
|
+
return entry;
|
|
12
|
+
entry = __defProp({}, "__esModule", { value: true });
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (var key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(entry, key))
|
|
16
|
+
__defProp(entry, key, {
|
|
17
|
+
get: __accessProp.bind(from, key),
|
|
18
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
__moduleCache.set(from, entry);
|
|
22
|
+
return entry;
|
|
23
|
+
};
|
|
24
|
+
var __moduleCache;
|
|
25
|
+
var __returnValue = (v) => v;
|
|
26
|
+
function __exportSetter(name, newValue) {
|
|
27
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
28
|
+
}
|
|
29
|
+
var __export = (target, all) => {
|
|
30
|
+
for (var name in all)
|
|
31
|
+
__defProp(target, name, {
|
|
32
|
+
get: all[name],
|
|
33
|
+
enumerable: true,
|
|
34
|
+
configurable: true,
|
|
35
|
+
set: __exportSetter.bind(all, name)
|
|
36
|
+
});
|
|
37
|
+
};
|
|
38
|
+
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
39
|
+
|
|
40
|
+
// src/core-map/core/Util.ts
|
|
41
|
+
var exports_Util = {};
|
|
42
|
+
__export(exports_Util, {
|
|
43
|
+
wrapNum: () => wrapNum,
|
|
44
|
+
throttle: () => throttle,
|
|
45
|
+
template: () => template,
|
|
46
|
+
stamp: () => stamp,
|
|
47
|
+
splitWords: () => splitWords,
|
|
48
|
+
setOptions: () => setOptions,
|
|
49
|
+
setLastId: () => setLastId,
|
|
50
|
+
noop: () => noop,
|
|
51
|
+
lastId: () => lastId,
|
|
52
|
+
formatNum: () => formatNum,
|
|
53
|
+
falseFn: () => falseFn
|
|
54
|
+
});
|
|
55
|
+
function stamp(obj) {
|
|
56
|
+
if (!("_tsmap_id" in obj)) {
|
|
57
|
+
obj._tsmap_id = ++lastId;
|
|
58
|
+
}
|
|
59
|
+
return obj._tsmap_id;
|
|
60
|
+
}
|
|
61
|
+
function setLastId(id) {
|
|
62
|
+
lastId = id;
|
|
63
|
+
}
|
|
64
|
+
function throttle(fn, time, context) {
|
|
65
|
+
let lock = false;
|
|
66
|
+
let queuedArgs = false;
|
|
67
|
+
function later() {
|
|
68
|
+
lock = false;
|
|
69
|
+
if (queuedArgs) {
|
|
70
|
+
wrapperFn.apply(context, queuedArgs);
|
|
71
|
+
queuedArgs = false;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
function wrapperFn(...args) {
|
|
75
|
+
if (lock) {
|
|
76
|
+
queuedArgs = args;
|
|
77
|
+
} else {
|
|
78
|
+
fn.apply(context, args);
|
|
79
|
+
setTimeout(later, time);
|
|
80
|
+
lock = true;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return wrapperFn;
|
|
84
|
+
}
|
|
85
|
+
function wrapNum(x, range, includeMax) {
|
|
86
|
+
const max = range[1];
|
|
87
|
+
const min = range[0];
|
|
88
|
+
const d = max - min;
|
|
89
|
+
return x === max && includeMax ? x : ((x - min) % d + d) % d + min;
|
|
90
|
+
}
|
|
91
|
+
function falseFn(..._args) {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
function formatNum(num, precision) {
|
|
95
|
+
if (precision === false)
|
|
96
|
+
return num;
|
|
97
|
+
const pow = 10 ** (precision === undefined ? 6 : precision);
|
|
98
|
+
return Math.round(num * pow) / pow;
|
|
99
|
+
}
|
|
100
|
+
function splitWords(str) {
|
|
101
|
+
return str.trim().split(/\s+/);
|
|
102
|
+
}
|
|
103
|
+
function setOptions(obj, options) {
|
|
104
|
+
if (!Object.hasOwn(obj, "options")) {
|
|
105
|
+
obj.options = obj.options ? Object.create(obj.options) : {};
|
|
106
|
+
}
|
|
107
|
+
if (options) {
|
|
108
|
+
for (const i in options) {
|
|
109
|
+
if (Object.hasOwn(options, i)) {
|
|
110
|
+
obj.options[i] = options[i];
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return obj.options;
|
|
115
|
+
}
|
|
116
|
+
function template(str, data) {
|
|
117
|
+
return str.replace(templateRe, (match, key) => {
|
|
118
|
+
const k = key.trim();
|
|
119
|
+
let value = data[k];
|
|
120
|
+
if (value === undefined)
|
|
121
|
+
throw new Error(`No value provided for variable ${match}`);
|
|
122
|
+
else if (typeof value === "function")
|
|
123
|
+
value = value(data);
|
|
124
|
+
return value;
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
function noop() {}
|
|
128
|
+
var lastId = 0, templateRe;
|
|
129
|
+
var init_Util = __esm(() => {
|
|
130
|
+
templateRe = /\{([^{}]+)\}/g;
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
// src/core-map/services/index.ts
|
|
134
|
+
var exports_services = {};
|
|
135
|
+
__export(exports_services, {
|
|
136
|
+
valhallaMatrix: () => valhallaMatrix,
|
|
137
|
+
valhallaDirections: () => valhallaDirections,
|
|
138
|
+
defaultMatrix: () => defaultMatrix,
|
|
139
|
+
defaultIsochrone: () => defaultIsochrone,
|
|
140
|
+
defaultGeocoder: () => defaultGeocoder,
|
|
141
|
+
defaultDirections: () => defaultDirections,
|
|
142
|
+
ValhallaMatrix: () => ValhallaMatrix,
|
|
143
|
+
ValhallaIsochrone: () => ValhallaIsochrone,
|
|
144
|
+
ValhallaDirections: () => ValhallaDirections,
|
|
145
|
+
PhotonGeocoder: () => PhotonGeocoder,
|
|
146
|
+
OSRMMatrix: () => OSRMMatrix,
|
|
147
|
+
OSRMDirections: () => OSRMDirections,
|
|
148
|
+
NominatimGeocoder: () => NominatimGeocoder,
|
|
149
|
+
MaptilerGeocoder: () => MaptilerGeocoder,
|
|
150
|
+
MapboxMatrix: () => MapboxMatrix,
|
|
151
|
+
MapboxIsochrone: () => MapboxIsochrone,
|
|
152
|
+
MapboxGeocoder: () => MapboxGeocoder,
|
|
153
|
+
MapboxDirections: () => MapboxDirections,
|
|
154
|
+
GoogleGeocoder: () => GoogleGeocoder,
|
|
155
|
+
GoogleDirections: () => GoogleDirections
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
// src/core-map/services/providers/Google.ts
|
|
159
|
+
var DEFAULT_BASE = "https://maps.googleapis.com/maps/api";
|
|
160
|
+
function requireKey(apiKey) {
|
|
161
|
+
if (!apiKey)
|
|
162
|
+
throw new Error("Google provider requires an apiKey");
|
|
163
|
+
return apiKey;
|
|
164
|
+
}
|
|
165
|
+
var profileMap = {
|
|
166
|
+
driving: "driving",
|
|
167
|
+
walking: "walking",
|
|
168
|
+
cycling: "bicycling"
|
|
169
|
+
};
|
|
170
|
+
function decodePolyline(encoded, precision = 5) {
|
|
171
|
+
const factor = 10 ** precision;
|
|
172
|
+
const len = encoded.length;
|
|
173
|
+
let index = 0;
|
|
174
|
+
let lat = 0;
|
|
175
|
+
let lng = 0;
|
|
176
|
+
const out = [];
|
|
177
|
+
while (index < len) {
|
|
178
|
+
let shift = 0;
|
|
179
|
+
let result = 0;
|
|
180
|
+
let byte;
|
|
181
|
+
do {
|
|
182
|
+
byte = encoded.charCodeAt(index++) - 63;
|
|
183
|
+
result |= (byte & 31) << shift;
|
|
184
|
+
shift += 5;
|
|
185
|
+
} while (byte >= 32);
|
|
186
|
+
const dLat = result & 1 ? ~(result >> 1) : result >> 1;
|
|
187
|
+
lat += dLat;
|
|
188
|
+
shift = 0;
|
|
189
|
+
result = 0;
|
|
190
|
+
do {
|
|
191
|
+
byte = encoded.charCodeAt(index++) - 63;
|
|
192
|
+
result |= (byte & 31) << shift;
|
|
193
|
+
shift += 5;
|
|
194
|
+
} while (byte >= 32);
|
|
195
|
+
const dLng = result & 1 ? ~(result >> 1) : result >> 1;
|
|
196
|
+
lng += dLng;
|
|
197
|
+
out.push({ lat: lat / factor, lng: lng / factor });
|
|
198
|
+
}
|
|
199
|
+
return out;
|
|
200
|
+
}
|
|
201
|
+
async function fetchJson(url, signal) {
|
|
202
|
+
const res = await fetch(url, { signal });
|
|
203
|
+
if (!res.ok)
|
|
204
|
+
throw new Error(`Google request failed: ${res.status} ${res.statusText}`);
|
|
205
|
+
return res.json();
|
|
206
|
+
}
|
|
207
|
+
function mapTypes(types) {
|
|
208
|
+
if (!types)
|
|
209
|
+
return;
|
|
210
|
+
if (types.includes("country"))
|
|
211
|
+
return "country";
|
|
212
|
+
if (types.includes("administrative_area_level_1"))
|
|
213
|
+
return "region";
|
|
214
|
+
if (types.includes("administrative_area_level_2"))
|
|
215
|
+
return "district";
|
|
216
|
+
if (types.includes("postal_code"))
|
|
217
|
+
return "postcode";
|
|
218
|
+
if (types.includes("locality") || types.includes("sublocality"))
|
|
219
|
+
return "place";
|
|
220
|
+
if (types.includes("street_address") || types.includes("route") || types.includes("premise"))
|
|
221
|
+
return "address";
|
|
222
|
+
if (types.includes("point_of_interest") || types.includes("establishment"))
|
|
223
|
+
return "poi";
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
function toResult(r) {
|
|
227
|
+
const out = {
|
|
228
|
+
text: r.formatted_address,
|
|
229
|
+
center: { lat: r.geometry.location.lat, lng: r.geometry.location.lng },
|
|
230
|
+
properties: { place_id: r.place_id, types: r.types, address_components: r.address_components }
|
|
231
|
+
};
|
|
232
|
+
const b = r.geometry.bounds ?? r.geometry.viewport;
|
|
233
|
+
if (b)
|
|
234
|
+
out.bbox = [b.southwest.lng, b.southwest.lat, b.northeast.lng, b.northeast.lat];
|
|
235
|
+
const pt = mapTypes(r.types);
|
|
236
|
+
if (pt)
|
|
237
|
+
out.placeType = pt;
|
|
238
|
+
return out;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
class GoogleGeocoder {
|
|
242
|
+
name = "google";
|
|
243
|
+
apiKey;
|
|
244
|
+
baseUrl;
|
|
245
|
+
constructor(opts) {
|
|
246
|
+
this.apiKey = requireKey(opts.apiKey);
|
|
247
|
+
this.baseUrl = (opts.baseUrl ?? DEFAULT_BASE).replace(/\/$/, "");
|
|
248
|
+
}
|
|
249
|
+
async search(query, opts) {
|
|
250
|
+
const params = new URLSearchParams;
|
|
251
|
+
params.set("address", query);
|
|
252
|
+
params.set("key", this.apiKey);
|
|
253
|
+
if (opts?.language)
|
|
254
|
+
params.set("language", opts.language);
|
|
255
|
+
if (opts?.bbox) {
|
|
256
|
+
const [w, s, e, n] = opts.bbox;
|
|
257
|
+
params.set("bounds", `${s},${w}|${n},${e}`);
|
|
258
|
+
}
|
|
259
|
+
if (opts?.countries && opts.countries.length > 0)
|
|
260
|
+
params.set("components", opts.countries.map((c) => `country:${c}`).join("|"));
|
|
261
|
+
const url = `${this.baseUrl}/geocode/json?${params.toString()}`;
|
|
262
|
+
const raw = await fetchJson(url, opts?.signal);
|
|
263
|
+
if (raw.status !== "OK" && raw.status !== "ZERO_RESULTS")
|
|
264
|
+
throw new Error(`Google geocoding error: ${raw.status}${raw.error_message ? ` — ${raw.error_message}` : ""}`);
|
|
265
|
+
const results = (raw.results ?? []).map(toResult);
|
|
266
|
+
return typeof opts?.limit === "number" ? results.slice(0, opts.limit) : results;
|
|
267
|
+
}
|
|
268
|
+
async reverse(center, opts) {
|
|
269
|
+
const params = new URLSearchParams;
|
|
270
|
+
params.set("latlng", `${center.lat},${center.lng}`);
|
|
271
|
+
params.set("key", this.apiKey);
|
|
272
|
+
if (opts?.language)
|
|
273
|
+
params.set("language", opts.language);
|
|
274
|
+
const url = `${this.baseUrl}/geocode/json?${params.toString()}`;
|
|
275
|
+
const raw = await fetchJson(url, opts?.signal);
|
|
276
|
+
if (raw.status !== "OK" && raw.status !== "ZERO_RESULTS")
|
|
277
|
+
throw new Error(`Google reverse-geocoding error: ${raw.status}${raw.error_message ? ` — ${raw.error_message}` : ""}`);
|
|
278
|
+
const results = (raw.results ?? []).map(toResult);
|
|
279
|
+
return typeof opts?.limit === "number" ? results.slice(0, opts.limit) : results;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
function stripHtml(html) {
|
|
283
|
+
return html ? html.replace(/<[^>]+>/g, "") : "";
|
|
284
|
+
}
|
|
285
|
+
function stepToStep(step) {
|
|
286
|
+
const out = {
|
|
287
|
+
distance: step.distance?.value ?? 0,
|
|
288
|
+
duration: step.duration?.value ?? 0,
|
|
289
|
+
instruction: stripHtml(step.html_instructions),
|
|
290
|
+
geometry: step.polyline ? decodePolyline(step.polyline.points) : []
|
|
291
|
+
};
|
|
292
|
+
if (step.maneuver)
|
|
293
|
+
out.maneuver = step.maneuver;
|
|
294
|
+
return out;
|
|
295
|
+
}
|
|
296
|
+
function routeToRoute(r) {
|
|
297
|
+
const legs = r.legs ?? [];
|
|
298
|
+
const steps = legs.flatMap((l) => (l.steps ?? []).map(stepToStep));
|
|
299
|
+
const distance = legs.reduce((sum, l) => sum + (l.distance?.value ?? 0), 0);
|
|
300
|
+
const duration = legs.reduce((sum, l) => sum + (l.duration?.value ?? 0), 0);
|
|
301
|
+
const geometry = r.overview_polyline ? decodePolyline(r.overview_polyline.points) : steps.flatMap((s) => s.geometry);
|
|
302
|
+
return { distance, duration, geometry, steps };
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
class GoogleDirections {
|
|
306
|
+
name = "google";
|
|
307
|
+
apiKey;
|
|
308
|
+
baseUrl;
|
|
309
|
+
constructor(opts) {
|
|
310
|
+
this.apiKey = requireKey(opts.apiKey);
|
|
311
|
+
this.baseUrl = (opts.baseUrl ?? DEFAULT_BASE).replace(/\/$/, "");
|
|
312
|
+
}
|
|
313
|
+
async getDirections(waypoints, opts) {
|
|
314
|
+
if (waypoints.length < 2)
|
|
315
|
+
throw new Error("Google directions requires at least two waypoints");
|
|
316
|
+
const params = new URLSearchParams;
|
|
317
|
+
params.set("key", this.apiKey);
|
|
318
|
+
params.set("mode", profileMap[opts?.profile ?? "driving"]);
|
|
319
|
+
const origin = waypoints[0];
|
|
320
|
+
const destination = waypoints[waypoints.length - 1];
|
|
321
|
+
params.set("origin", `${origin.lat},${origin.lng}`);
|
|
322
|
+
params.set("destination", `${destination.lat},${destination.lng}`);
|
|
323
|
+
if (waypoints.length > 2) {
|
|
324
|
+
const via = waypoints.slice(1, -1).map((p) => `${p.lat},${p.lng}`).join("|");
|
|
325
|
+
params.set("waypoints", via);
|
|
326
|
+
}
|
|
327
|
+
if (opts?.alternatives)
|
|
328
|
+
params.set("alternatives", "true");
|
|
329
|
+
if (opts?.language)
|
|
330
|
+
params.set("language", opts.language);
|
|
331
|
+
const url = `${this.baseUrl}/directions/json?${params.toString()}`;
|
|
332
|
+
const raw = await fetchJson(url, opts?.signal);
|
|
333
|
+
if (raw.status !== "OK" && raw.status !== "ZERO_RESULTS")
|
|
334
|
+
throw new Error(`Google directions error: ${raw.status}${raw.error_message ? ` — ${raw.error_message}` : ""}`);
|
|
335
|
+
return (raw.routes ?? []).map(routeToRoute);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
// src/core-map/services/providers/Mapbox.ts
|
|
339
|
+
var DEFAULT_BASE2 = "https://api.mapbox.com";
|
|
340
|
+
function requireToken(token) {
|
|
341
|
+
if (!token)
|
|
342
|
+
throw new Error("Mapbox provider requires an accessToken");
|
|
343
|
+
return token;
|
|
344
|
+
}
|
|
345
|
+
var profileMap2 = {
|
|
346
|
+
driving: "mapbox/driving",
|
|
347
|
+
walking: "mapbox/walking",
|
|
348
|
+
cycling: "mapbox/cycling"
|
|
349
|
+
};
|
|
350
|
+
var isochroneProfileMap = {
|
|
351
|
+
driving: "mapbox/driving",
|
|
352
|
+
walking: "mapbox/walking",
|
|
353
|
+
cycling: "mapbox/cycling"
|
|
354
|
+
};
|
|
355
|
+
async function fetchJson2(url, signal) {
|
|
356
|
+
const res = await fetch(url, { signal });
|
|
357
|
+
if (!res.ok)
|
|
358
|
+
throw new Error(`Mapbox request failed: ${res.status} ${res.statusText}`);
|
|
359
|
+
return res.json();
|
|
360
|
+
}
|
|
361
|
+
function mapFeatureType(t) {
|
|
362
|
+
switch (t) {
|
|
363
|
+
case "country":
|
|
364
|
+
case "region":
|
|
365
|
+
case "district":
|
|
366
|
+
case "postcode":
|
|
367
|
+
case "place":
|
|
368
|
+
case "address":
|
|
369
|
+
case "poi":
|
|
370
|
+
return t;
|
|
371
|
+
default:
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
function featureToResult(f) {
|
|
376
|
+
const coords = f.geometry?.coordinates ?? [0, 0];
|
|
377
|
+
const result = {
|
|
378
|
+
text: f.properties?.full_address ?? f.properties?.name ?? "",
|
|
379
|
+
center: { lat: coords[1], lng: coords[0] },
|
|
380
|
+
properties: f.properties
|
|
381
|
+
};
|
|
382
|
+
if (f.properties?.bbox)
|
|
383
|
+
result.bbox = f.properties.bbox;
|
|
384
|
+
const pt = mapFeatureType(f.properties?.feature_type);
|
|
385
|
+
if (pt)
|
|
386
|
+
result.placeType = pt;
|
|
387
|
+
if (typeof f.relevance === "number")
|
|
388
|
+
result.relevance = f.relevance;
|
|
389
|
+
return result;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
class MapboxGeocoder {
|
|
393
|
+
name = "mapbox";
|
|
394
|
+
accessToken;
|
|
395
|
+
baseUrl;
|
|
396
|
+
constructor(opts) {
|
|
397
|
+
this.accessToken = requireToken(opts.accessToken);
|
|
398
|
+
this.baseUrl = (opts.baseUrl ?? DEFAULT_BASE2).replace(/\/$/, "");
|
|
399
|
+
}
|
|
400
|
+
async search(query, opts) {
|
|
401
|
+
const params = new URLSearchParams;
|
|
402
|
+
params.set("q", query);
|
|
403
|
+
params.set("access_token", this.accessToken);
|
|
404
|
+
params.set("limit", String(opts?.limit ?? 5));
|
|
405
|
+
if (opts?.language)
|
|
406
|
+
params.set("language", opts.language);
|
|
407
|
+
if (opts?.proximity)
|
|
408
|
+
params.set("proximity", `${opts.proximity.lng},${opts.proximity.lat}`);
|
|
409
|
+
if (opts?.bbox)
|
|
410
|
+
params.set("bbox", opts.bbox.join(","));
|
|
411
|
+
if (opts?.countries && opts.countries.length > 0)
|
|
412
|
+
params.set("country", opts.countries.join(","));
|
|
413
|
+
const url = `${this.baseUrl}/search/geocode/v6/forward?${params.toString()}`;
|
|
414
|
+
const raw = await fetchJson2(url, opts?.signal);
|
|
415
|
+
return (raw.features ?? []).map(featureToResult);
|
|
416
|
+
}
|
|
417
|
+
async reverse(center, opts) {
|
|
418
|
+
const params = new URLSearchParams;
|
|
419
|
+
params.set("longitude", String(center.lng));
|
|
420
|
+
params.set("latitude", String(center.lat));
|
|
421
|
+
params.set("access_token", this.accessToken);
|
|
422
|
+
params.set("limit", String(opts?.limit ?? 1));
|
|
423
|
+
if (opts?.language)
|
|
424
|
+
params.set("language", opts.language);
|
|
425
|
+
const url = `${this.baseUrl}/search/geocode/v6/reverse?${params.toString()}`;
|
|
426
|
+
const raw = await fetchJson2(url, opts?.signal);
|
|
427
|
+
return (raw.features ?? []).map(featureToResult);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
function coords(arr) {
|
|
431
|
+
return arr.map(([lng, lat]) => ({ lat, lng }));
|
|
432
|
+
}
|
|
433
|
+
function mbStepToStep(s) {
|
|
434
|
+
const out = {
|
|
435
|
+
distance: s.distance,
|
|
436
|
+
duration: s.duration,
|
|
437
|
+
instruction: s.maneuver?.instruction ?? s.name ?? "",
|
|
438
|
+
geometry: coords(s.geometry?.coordinates ?? [])
|
|
439
|
+
};
|
|
440
|
+
if (s.maneuver?.type) {
|
|
441
|
+
out.maneuver = s.maneuver.modifier ? `${s.maneuver.type}-${s.maneuver.modifier}`.replace(/\s+/g, "-") : s.maneuver.type;
|
|
442
|
+
}
|
|
443
|
+
return out;
|
|
444
|
+
}
|
|
445
|
+
function mbRouteToRoute(r) {
|
|
446
|
+
const steps = (r.legs ?? []).flatMap((l) => (l.steps ?? []).map(mbStepToStep));
|
|
447
|
+
return {
|
|
448
|
+
distance: r.distance,
|
|
449
|
+
duration: r.duration,
|
|
450
|
+
geometry: coords(r.geometry?.coordinates ?? []),
|
|
451
|
+
steps
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
class MapboxDirections {
|
|
456
|
+
name = "mapbox";
|
|
457
|
+
accessToken;
|
|
458
|
+
baseUrl;
|
|
459
|
+
constructor(opts) {
|
|
460
|
+
this.accessToken = requireToken(opts.accessToken);
|
|
461
|
+
this.baseUrl = (opts.baseUrl ?? DEFAULT_BASE2).replace(/\/$/, "");
|
|
462
|
+
}
|
|
463
|
+
async getDirections(waypoints, opts) {
|
|
464
|
+
if (waypoints.length < 2)
|
|
465
|
+
throw new Error("Mapbox directions requires at least two waypoints");
|
|
466
|
+
const profile = profileMap2[opts?.profile ?? "driving"];
|
|
467
|
+
const coordStr = waypoints.map((w) => `${w.lng},${w.lat}`).join(";");
|
|
468
|
+
const params = new URLSearchParams;
|
|
469
|
+
params.set("access_token", this.accessToken);
|
|
470
|
+
params.set("geometries", "geojson");
|
|
471
|
+
params.set("overview", "full");
|
|
472
|
+
params.set("steps", "true");
|
|
473
|
+
params.set("alternatives", opts?.alternatives ? "true" : "false");
|
|
474
|
+
if (opts?.language)
|
|
475
|
+
params.set("language", opts.language);
|
|
476
|
+
const url = `${this.baseUrl}/directions/v5/${profile}/${coordStr}?${params.toString()}`;
|
|
477
|
+
const raw = await fetchJson2(url, opts?.signal);
|
|
478
|
+
if (raw.code !== "Ok")
|
|
479
|
+
throw new Error(`Mapbox directions error: ${raw.code}${raw.message ? ` — ${raw.message}` : ""}`);
|
|
480
|
+
return (raw.routes ?? []).map(mbRouteToRoute);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
class MapboxIsochrone {
|
|
485
|
+
name = "mapbox";
|
|
486
|
+
accessToken;
|
|
487
|
+
baseUrl;
|
|
488
|
+
constructor(opts) {
|
|
489
|
+
this.accessToken = requireToken(opts.accessToken);
|
|
490
|
+
this.baseUrl = (opts.baseUrl ?? DEFAULT_BASE2).replace(/\/$/, "");
|
|
491
|
+
}
|
|
492
|
+
async getIsochrones(center, opts) {
|
|
493
|
+
const profile = isochroneProfileMap[opts.profile ?? "driving"];
|
|
494
|
+
const metric = opts.contourMetric ?? "time";
|
|
495
|
+
const params = new URLSearchParams;
|
|
496
|
+
params.set("access_token", this.accessToken);
|
|
497
|
+
if (metric === "distance")
|
|
498
|
+
params.set("contours_meters", opts.contours.join(","));
|
|
499
|
+
else
|
|
500
|
+
params.set("contours_minutes", opts.contours.join(","));
|
|
501
|
+
params.set("polygons", "true");
|
|
502
|
+
if (typeof opts.denoise === "number")
|
|
503
|
+
params.set("denoise", String(opts.denoise));
|
|
504
|
+
if (typeof opts.generalize === "number")
|
|
505
|
+
params.set("generalize", String(opts.generalize));
|
|
506
|
+
const url = `${this.baseUrl}/isochrone/v1/${profile}/${center.lng},${center.lat}?${params.toString()}`;
|
|
507
|
+
const raw = await fetchJson2(url, opts.signal);
|
|
508
|
+
const out = [];
|
|
509
|
+
for (const f of raw.features ?? []) {
|
|
510
|
+
const contour = f.properties?.contour ?? 0;
|
|
511
|
+
if (f.geometry.type === "Polygon") {
|
|
512
|
+
const rings = f.geometry.coordinates;
|
|
513
|
+
if (rings.length === 0)
|
|
514
|
+
continue;
|
|
515
|
+
const p = {
|
|
516
|
+
geometry: coords(rings[0]),
|
|
517
|
+
contour
|
|
518
|
+
};
|
|
519
|
+
if (rings.length > 1)
|
|
520
|
+
p.holes = rings.slice(1).map((r) => coords(r));
|
|
521
|
+
out.push(p);
|
|
522
|
+
} else if (f.geometry.type === "LineString") {
|
|
523
|
+
out.push({
|
|
524
|
+
geometry: coords(f.geometry.coordinates),
|
|
525
|
+
contour
|
|
526
|
+
});
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
return out;
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
class MapboxMatrix {
|
|
534
|
+
name = "mapbox";
|
|
535
|
+
accessToken;
|
|
536
|
+
baseUrl;
|
|
537
|
+
constructor(opts) {
|
|
538
|
+
this.accessToken = requireToken(opts.accessToken);
|
|
539
|
+
this.baseUrl = (opts.baseUrl ?? DEFAULT_BASE2).replace(/\/$/, "");
|
|
540
|
+
}
|
|
541
|
+
async getMatrix(origins, destinations, opts) {
|
|
542
|
+
const profile = profileMap2[opts?.profile ?? "driving"];
|
|
543
|
+
const all = [...origins, ...destinations];
|
|
544
|
+
const coordStr = all.map((w) => `${w.lng},${w.lat}`).join(";");
|
|
545
|
+
const sources = origins.map((_, i) => i).join(";");
|
|
546
|
+
const destinations_ = destinations.map((_, i) => i + origins.length).join(";");
|
|
547
|
+
const params = new URLSearchParams;
|
|
548
|
+
params.set("access_token", this.accessToken);
|
|
549
|
+
params.set("sources", sources);
|
|
550
|
+
params.set("destinations", destinations_);
|
|
551
|
+
const annotations = [];
|
|
552
|
+
const metric = opts?.metric ?? "time";
|
|
553
|
+
if (metric === "distance" || metric === "time") {
|
|
554
|
+
annotations.push("duration", "distance");
|
|
555
|
+
}
|
|
556
|
+
params.set("annotations", annotations.join(","));
|
|
557
|
+
const url = `${this.baseUrl}/directions-matrix/v1/${profile}/${coordStr}?${params.toString()}`;
|
|
558
|
+
const raw = await fetchJson2(url, opts?.signal);
|
|
559
|
+
if (raw.code !== "Ok")
|
|
560
|
+
throw new Error(`Mapbox matrix error: ${raw.code}${raw.message ? ` — ${raw.message}` : ""}`);
|
|
561
|
+
const result = {};
|
|
562
|
+
if (raw.durations)
|
|
563
|
+
result.durations = raw.durations;
|
|
564
|
+
if (raw.distances)
|
|
565
|
+
result.distances = raw.distances;
|
|
566
|
+
return result;
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
// src/core-map/services/providers/Maptiler.ts
|
|
570
|
+
var DEFAULT_BASE3 = "https://api.maptiler.com";
|
|
571
|
+
function mapPlaceType(types) {
|
|
572
|
+
if (!types || types.length === 0)
|
|
573
|
+
return;
|
|
574
|
+
const t = types[0];
|
|
575
|
+
switch (t) {
|
|
576
|
+
case "country":
|
|
577
|
+
case "region":
|
|
578
|
+
case "district":
|
|
579
|
+
case "postcode":
|
|
580
|
+
case "place":
|
|
581
|
+
case "address":
|
|
582
|
+
case "poi":
|
|
583
|
+
return t;
|
|
584
|
+
default:
|
|
585
|
+
return;
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
function toResult2(f) {
|
|
589
|
+
const center = f.center ?? [0, 0];
|
|
590
|
+
const out = {
|
|
591
|
+
text: f.place_name ?? f.text ?? "",
|
|
592
|
+
center: { lat: center[1], lng: center[0] },
|
|
593
|
+
properties: f.properties
|
|
594
|
+
};
|
|
595
|
+
if (f.bbox)
|
|
596
|
+
out.bbox = f.bbox;
|
|
597
|
+
const pt = mapPlaceType(f.place_type);
|
|
598
|
+
if (pt)
|
|
599
|
+
out.placeType = pt;
|
|
600
|
+
if (typeof f.relevance === "number")
|
|
601
|
+
out.relevance = f.relevance;
|
|
602
|
+
return out;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
class MaptilerGeocoder {
|
|
606
|
+
name = "maptiler";
|
|
607
|
+
apiKey;
|
|
608
|
+
baseUrl;
|
|
609
|
+
constructor(opts) {
|
|
610
|
+
if (!opts.apiKey)
|
|
611
|
+
throw new Error("Maptiler provider requires an apiKey");
|
|
612
|
+
this.apiKey = opts.apiKey;
|
|
613
|
+
this.baseUrl = (opts.baseUrl ?? DEFAULT_BASE3).replace(/\/$/, "");
|
|
614
|
+
}
|
|
615
|
+
buildParams(opts) {
|
|
616
|
+
const params = new URLSearchParams;
|
|
617
|
+
params.set("key", this.apiKey);
|
|
618
|
+
if (opts?.limit)
|
|
619
|
+
params.set("limit", String(opts.limit));
|
|
620
|
+
if (opts?.language)
|
|
621
|
+
params.set("language", opts.language);
|
|
622
|
+
if (opts?.proximity)
|
|
623
|
+
params.set("proximity", `${opts.proximity.lng},${opts.proximity.lat}`);
|
|
624
|
+
if (opts?.bbox)
|
|
625
|
+
params.set("bbox", opts.bbox.join(","));
|
|
626
|
+
if (opts?.countries && opts.countries.length > 0)
|
|
627
|
+
params.set("country", opts.countries.join(","));
|
|
628
|
+
return params;
|
|
629
|
+
}
|
|
630
|
+
async fetch(url, signal) {
|
|
631
|
+
const res = await fetch(url, { signal });
|
|
632
|
+
if (!res.ok)
|
|
633
|
+
throw new Error(`Maptiler request failed: ${res.status} ${res.statusText}`);
|
|
634
|
+
return await res.json();
|
|
635
|
+
}
|
|
636
|
+
async search(query, opts) {
|
|
637
|
+
const params = this.buildParams(opts);
|
|
638
|
+
const url = `${this.baseUrl}/geocoding/${encodeURIComponent(query)}.json?${params.toString()}`;
|
|
639
|
+
const raw = await this.fetch(url, opts?.signal);
|
|
640
|
+
return (raw.features ?? []).map(toResult2);
|
|
641
|
+
}
|
|
642
|
+
async reverse(center, opts) {
|
|
643
|
+
const params = this.buildParams(opts);
|
|
644
|
+
const url = `${this.baseUrl}/geocoding/${center.lng},${center.lat}.json?${params.toString()}`;
|
|
645
|
+
const raw = await this.fetch(url, opts?.signal);
|
|
646
|
+
return (raw.features ?? []).map(toResult2);
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
// src/core-map/services/providers/Nominatim.ts
|
|
650
|
+
init_Util();
|
|
651
|
+
function mapPlaceType2(klass, type) {
|
|
652
|
+
if (klass === "boundary" && type === "administrative")
|
|
653
|
+
return "region";
|
|
654
|
+
if (type === "country")
|
|
655
|
+
return "country";
|
|
656
|
+
if (type === "state" || type === "province")
|
|
657
|
+
return "region";
|
|
658
|
+
if (type === "city" || type === "town" || type === "village")
|
|
659
|
+
return "place";
|
|
660
|
+
if (type === "postcode")
|
|
661
|
+
return "postcode";
|
|
662
|
+
if (type === "administrative")
|
|
663
|
+
return "district";
|
|
664
|
+
if (klass === "highway" || klass === "place" && type === "house")
|
|
665
|
+
return "address";
|
|
666
|
+
if (klass === "amenity" || klass === "shop" || klass === "tourism")
|
|
667
|
+
return "poi";
|
|
668
|
+
return;
|
|
669
|
+
}
|
|
670
|
+
function parseRaw(raw) {
|
|
671
|
+
const lat = Number.parseFloat(raw.lat);
|
|
672
|
+
const lng = Number.parseFloat(raw.lon);
|
|
673
|
+
const result = {
|
|
674
|
+
text: raw.display_name,
|
|
675
|
+
center: { lat, lng },
|
|
676
|
+
properties: { ...raw.address, osm_id: raw.osm_id, osm_type: raw.osm_type, class: raw.class, type: raw.type }
|
|
677
|
+
};
|
|
678
|
+
if (raw.boundingbox) {
|
|
679
|
+
const [south, north, west, east] = raw.boundingbox.map(Number.parseFloat);
|
|
680
|
+
result.bbox = [west, south, east, north];
|
|
681
|
+
}
|
|
682
|
+
const placeType = mapPlaceType2(raw.class, raw.type);
|
|
683
|
+
if (placeType)
|
|
684
|
+
result.placeType = placeType;
|
|
685
|
+
if (typeof raw.importance === "number")
|
|
686
|
+
result.relevance = Math.max(0, Math.min(1, raw.importance));
|
|
687
|
+
return result;
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
class NominatimGeocoder {
|
|
691
|
+
name = "nominatim";
|
|
692
|
+
baseUrl;
|
|
693
|
+
userAgent;
|
|
694
|
+
scheduleRequest;
|
|
695
|
+
constructor(opts = {}) {
|
|
696
|
+
this.baseUrl = (opts.baseUrl ?? "https://nominatim.openstreetmap.org").replace(/\/$/, "");
|
|
697
|
+
this.userAgent = opts.userAgent ?? "ts-maps";
|
|
698
|
+
this.scheduleRequest = throttle((run) => run(), 250);
|
|
699
|
+
}
|
|
700
|
+
gate(work) {
|
|
701
|
+
return new Promise((resolve, reject) => {
|
|
702
|
+
this.scheduleRequest(() => {
|
|
703
|
+
work().then(resolve, reject);
|
|
704
|
+
});
|
|
705
|
+
});
|
|
706
|
+
}
|
|
707
|
+
buildSearchUrl(query, opts) {
|
|
708
|
+
const params = new URLSearchParams;
|
|
709
|
+
params.set("q", query);
|
|
710
|
+
params.set("format", "json");
|
|
711
|
+
params.set("addressdetails", "1");
|
|
712
|
+
params.set("limit", String(opts?.limit ?? 5));
|
|
713
|
+
if (opts?.language)
|
|
714
|
+
params.set("accept-language", opts.language);
|
|
715
|
+
if (opts?.countries && opts.countries.length > 0)
|
|
716
|
+
params.set("countrycodes", opts.countries.join(","));
|
|
717
|
+
if (opts?.bbox) {
|
|
718
|
+
const [w, s, e, n] = opts.bbox;
|
|
719
|
+
params.set("viewbox", `${w},${n},${e},${s}`);
|
|
720
|
+
params.set("bounded", "1");
|
|
721
|
+
}
|
|
722
|
+
return `${this.baseUrl}/search?${params.toString()}`;
|
|
723
|
+
}
|
|
724
|
+
buildReverseUrl(center, opts) {
|
|
725
|
+
const params = new URLSearchParams;
|
|
726
|
+
params.set("lat", String(center.lat));
|
|
727
|
+
params.set("lon", String(center.lng));
|
|
728
|
+
params.set("format", "json");
|
|
729
|
+
params.set("addressdetails", "1");
|
|
730
|
+
if (opts?.language)
|
|
731
|
+
params.set("accept-language", opts.language);
|
|
732
|
+
return `${this.baseUrl}/reverse?${params.toString()}`;
|
|
733
|
+
}
|
|
734
|
+
async fetch(url, signal) {
|
|
735
|
+
const res = await fetch(url, {
|
|
736
|
+
headers: { "User-Agent": this.userAgent, Accept: "application/json" },
|
|
737
|
+
signal
|
|
738
|
+
});
|
|
739
|
+
if (!res.ok)
|
|
740
|
+
throw new Error(`Nominatim request failed: ${res.status} ${res.statusText}`);
|
|
741
|
+
return res.json();
|
|
742
|
+
}
|
|
743
|
+
async search(query, opts) {
|
|
744
|
+
if (!query)
|
|
745
|
+
return [];
|
|
746
|
+
const url = this.buildSearchUrl(query, opts);
|
|
747
|
+
return this.gate(async () => {
|
|
748
|
+
const raw = await this.fetch(url, opts?.signal);
|
|
749
|
+
return Array.isArray(raw) ? raw.map(parseRaw) : [];
|
|
750
|
+
});
|
|
751
|
+
}
|
|
752
|
+
async reverse(center, opts) {
|
|
753
|
+
const url = this.buildReverseUrl(center, opts);
|
|
754
|
+
return this.gate(async () => {
|
|
755
|
+
const raw = await this.fetch(url, opts?.signal);
|
|
756
|
+
if (!raw || raw.error)
|
|
757
|
+
return [];
|
|
758
|
+
return [parseRaw(raw)];
|
|
759
|
+
});
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
// src/core-map/services/providers/OSRM.ts
|
|
763
|
+
var profileMap3 = {
|
|
764
|
+
driving: "driving",
|
|
765
|
+
walking: "foot",
|
|
766
|
+
cycling: "bike"
|
|
767
|
+
};
|
|
768
|
+
function coordsToLatLng(coords2) {
|
|
769
|
+
return coords2.map(([lng, lat]) => ({ lat, lng }));
|
|
770
|
+
}
|
|
771
|
+
function stepInstruction(step) {
|
|
772
|
+
if (step.maneuver?.instruction)
|
|
773
|
+
return step.maneuver.instruction;
|
|
774
|
+
const parts = [];
|
|
775
|
+
if (step.maneuver?.type)
|
|
776
|
+
parts.push(step.maneuver.type);
|
|
777
|
+
if (step.maneuver?.modifier)
|
|
778
|
+
parts.push(step.maneuver.modifier);
|
|
779
|
+
if (step.name)
|
|
780
|
+
parts.push(`onto ${step.name}`);
|
|
781
|
+
return parts.join(" ").trim() || "continue";
|
|
782
|
+
}
|
|
783
|
+
function stepManeuver(step) {
|
|
784
|
+
if (!step.maneuver?.type)
|
|
785
|
+
return;
|
|
786
|
+
if (step.maneuver.modifier)
|
|
787
|
+
return `${step.maneuver.type}-${step.maneuver.modifier}`.replace(/\s+/g, "-");
|
|
788
|
+
return step.maneuver.type;
|
|
789
|
+
}
|
|
790
|
+
function parseStep(step) {
|
|
791
|
+
const out = {
|
|
792
|
+
distance: step.distance,
|
|
793
|
+
duration: step.duration,
|
|
794
|
+
instruction: stepInstruction(step),
|
|
795
|
+
geometry: coordsToLatLng(step.geometry?.coordinates ?? [])
|
|
796
|
+
};
|
|
797
|
+
const m = stepManeuver(step);
|
|
798
|
+
if (m)
|
|
799
|
+
out.maneuver = m;
|
|
800
|
+
return out;
|
|
801
|
+
}
|
|
802
|
+
function parseLeg(leg) {
|
|
803
|
+
const steps = (leg.steps ?? []).map(parseStep);
|
|
804
|
+
const geometry = steps.flatMap((s) => s.geometry);
|
|
805
|
+
return {
|
|
806
|
+
distance: leg.distance,
|
|
807
|
+
duration: leg.duration,
|
|
808
|
+
geometry,
|
|
809
|
+
steps
|
|
810
|
+
};
|
|
811
|
+
}
|
|
812
|
+
function parseRoute(route) {
|
|
813
|
+
const steps = (route.legs ?? []).flatMap((leg) => (leg.steps ?? []).map(parseStep));
|
|
814
|
+
return {
|
|
815
|
+
distance: route.distance,
|
|
816
|
+
duration: route.duration,
|
|
817
|
+
geometry: coordsToLatLng(route.geometry?.coordinates ?? []),
|
|
818
|
+
steps,
|
|
819
|
+
legs: (route.legs ?? []).map(parseLeg)
|
|
820
|
+
};
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
class OSRMDirections {
|
|
824
|
+
name = "osrm";
|
|
825
|
+
baseUrl;
|
|
826
|
+
constructor(opts = {}) {
|
|
827
|
+
this.baseUrl = (opts.baseUrl ?? "https://router.project-osrm.org").replace(/\/$/, "");
|
|
828
|
+
}
|
|
829
|
+
async getDirections(waypoints, opts) {
|
|
830
|
+
if (waypoints.length < 2)
|
|
831
|
+
throw new Error("OSRM requires at least two waypoints");
|
|
832
|
+
const profile = profileMap3[opts?.profile ?? "driving"] ?? "driving";
|
|
833
|
+
const coords2 = waypoints.map((w) => `${w.lng},${w.lat}`).join(";");
|
|
834
|
+
const params = new URLSearchParams;
|
|
835
|
+
params.set("overview", "full");
|
|
836
|
+
params.set("geometries", "geojson");
|
|
837
|
+
params.set("steps", "true");
|
|
838
|
+
params.set("alternatives", opts?.alternatives ? "true" : "false");
|
|
839
|
+
const url = `${this.baseUrl}/route/v1/${profile}/${coords2}?${params.toString()}`;
|
|
840
|
+
const res = await fetch(url, { signal: opts?.signal });
|
|
841
|
+
if (!res.ok)
|
|
842
|
+
throw new Error(`OSRM request failed: ${res.status} ${res.statusText}`);
|
|
843
|
+
const body = await res.json();
|
|
844
|
+
if (body.code !== "Ok")
|
|
845
|
+
throw new Error(`OSRM error: ${body.code}${body.message ? ` — ${body.message}` : ""}`);
|
|
846
|
+
return (body.routes ?? []).map(parseRoute);
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
class OSRMMatrix {
|
|
851
|
+
name = "osrm";
|
|
852
|
+
baseUrl;
|
|
853
|
+
constructor(opts = {}) {
|
|
854
|
+
this.baseUrl = (opts.baseUrl ?? "https://router.project-osrm.org").replace(/\/$/, "");
|
|
855
|
+
}
|
|
856
|
+
async getMatrix(origins, destinations, opts) {
|
|
857
|
+
if (origins.length === 0 || destinations.length === 0)
|
|
858
|
+
throw new Error("OSRM matrix requires at least one origin and one destination");
|
|
859
|
+
const profile = profileMap3[opts?.profile ?? "driving"] ?? "driving";
|
|
860
|
+
const all = [...origins, ...destinations];
|
|
861
|
+
const coords2 = all.map((w) => `${w.lng},${w.lat}`).join(";");
|
|
862
|
+
const sources = origins.map((_, i) => i).join(";");
|
|
863
|
+
const destinationsParam = destinations.map((_, i) => origins.length + i).join(";");
|
|
864
|
+
const annotations = opts?.metric === "distance" ? "distance" : "duration";
|
|
865
|
+
const params = new URLSearchParams;
|
|
866
|
+
params.set("sources", sources);
|
|
867
|
+
params.set("destinations", destinationsParam);
|
|
868
|
+
params.set("annotations", annotations);
|
|
869
|
+
const url = `${this.baseUrl}/table/v1/${profile}/${coords2}?${params.toString()}`;
|
|
870
|
+
const res = await fetch(url, { signal: opts?.signal });
|
|
871
|
+
if (!res.ok)
|
|
872
|
+
throw new Error(`OSRM matrix request failed: ${res.status} ${res.statusText}`);
|
|
873
|
+
const body = await res.json();
|
|
874
|
+
if (body.code !== "Ok")
|
|
875
|
+
throw new Error(`OSRM matrix error: ${body.code}${body.message ? ` — ${body.message}` : ""}`);
|
|
876
|
+
const result = {};
|
|
877
|
+
if (body.durations)
|
|
878
|
+
result.durations = body.durations.map((row) => row.map((v) => v ?? Number.POSITIVE_INFINITY));
|
|
879
|
+
if (body.distances)
|
|
880
|
+
result.distances = body.distances.map((row) => row.map((v) => v ?? Number.POSITIVE_INFINITY));
|
|
881
|
+
return result;
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
// src/core-map/services/providers/Photon.ts
|
|
885
|
+
function mapType(props) {
|
|
886
|
+
if (!props)
|
|
887
|
+
return;
|
|
888
|
+
if (props.osm_value === "country" || props.type === "country")
|
|
889
|
+
return "country";
|
|
890
|
+
if (props.osm_value === "state" || props.type === "state")
|
|
891
|
+
return "region";
|
|
892
|
+
if (props.type === "county")
|
|
893
|
+
return "district";
|
|
894
|
+
if (props.osm_key === "place" && (props.osm_value === "city" || props.osm_value === "town" || props.osm_value === "village"))
|
|
895
|
+
return "place";
|
|
896
|
+
if (props.osm_key === "highway" || props.housenumber)
|
|
897
|
+
return "address";
|
|
898
|
+
if (props.postcode && props.type === "postcode")
|
|
899
|
+
return "postcode";
|
|
900
|
+
if (props.osm_key === "amenity" || props.osm_key === "shop" || props.osm_key === "tourism")
|
|
901
|
+
return "poi";
|
|
902
|
+
return;
|
|
903
|
+
}
|
|
904
|
+
function buildLabel(props) {
|
|
905
|
+
if (!props)
|
|
906
|
+
return "";
|
|
907
|
+
const parts = [];
|
|
908
|
+
if (props.name)
|
|
909
|
+
parts.push(props.name);
|
|
910
|
+
if (props.street) {
|
|
911
|
+
const street = props.housenumber ? `${props.street} ${props.housenumber}` : props.street;
|
|
912
|
+
if (!parts.length || parts[0] !== street)
|
|
913
|
+
parts.push(street);
|
|
914
|
+
}
|
|
915
|
+
if (props.postcode || props.city) {
|
|
916
|
+
parts.push([props.postcode, props.city].filter(Boolean).join(" "));
|
|
917
|
+
}
|
|
918
|
+
if (props.country)
|
|
919
|
+
parts.push(props.country);
|
|
920
|
+
return parts.filter(Boolean).join(", ");
|
|
921
|
+
}
|
|
922
|
+
function toResult3(f) {
|
|
923
|
+
const coords2 = f.geometry?.coordinates ?? [0, 0];
|
|
924
|
+
const out = {
|
|
925
|
+
text: buildLabel(f.properties),
|
|
926
|
+
center: { lat: coords2[1], lng: coords2[0] },
|
|
927
|
+
properties: f.properties
|
|
928
|
+
};
|
|
929
|
+
if (f.properties?.extent) {
|
|
930
|
+
const [w, n, e, s] = f.properties.extent;
|
|
931
|
+
out.bbox = [w, s, e, n];
|
|
932
|
+
}
|
|
933
|
+
const pt = mapType(f.properties);
|
|
934
|
+
if (pt)
|
|
935
|
+
out.placeType = pt;
|
|
936
|
+
return out;
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
class PhotonGeocoder {
|
|
940
|
+
name = "photon";
|
|
941
|
+
baseUrl;
|
|
942
|
+
constructor(opts = {}) {
|
|
943
|
+
this.baseUrl = (opts.baseUrl ?? "https://photon.komoot.io").replace(/\/$/, "");
|
|
944
|
+
}
|
|
945
|
+
async search(query, opts) {
|
|
946
|
+
if (!query)
|
|
947
|
+
return [];
|
|
948
|
+
const params = new URLSearchParams;
|
|
949
|
+
params.set("q", query);
|
|
950
|
+
params.set("limit", String(opts?.limit ?? 5));
|
|
951
|
+
if (opts?.language)
|
|
952
|
+
params.set("lang", opts.language);
|
|
953
|
+
if (opts?.proximity) {
|
|
954
|
+
params.set("lat", String(opts.proximity.lat));
|
|
955
|
+
params.set("lon", String(opts.proximity.lng));
|
|
956
|
+
}
|
|
957
|
+
if (opts?.bbox)
|
|
958
|
+
params.set("bbox", opts.bbox.join(","));
|
|
959
|
+
const url = `${this.baseUrl}/api?${params.toString()}`;
|
|
960
|
+
const res = await fetch(url, { signal: opts?.signal });
|
|
961
|
+
if (!res.ok)
|
|
962
|
+
throw new Error(`Photon request failed: ${res.status} ${res.statusText}`);
|
|
963
|
+
const raw = await res.json();
|
|
964
|
+
return (raw.features ?? []).map(toResult3);
|
|
965
|
+
}
|
|
966
|
+
async reverse(center, opts) {
|
|
967
|
+
const params = new URLSearchParams;
|
|
968
|
+
params.set("lat", String(center.lat));
|
|
969
|
+
params.set("lon", String(center.lng));
|
|
970
|
+
if (opts?.limit)
|
|
971
|
+
params.set("limit", String(opts.limit));
|
|
972
|
+
if (opts?.language)
|
|
973
|
+
params.set("lang", opts.language);
|
|
974
|
+
const url = `${this.baseUrl}/reverse?${params.toString()}`;
|
|
975
|
+
const res = await fetch(url, { signal: opts?.signal });
|
|
976
|
+
if (!res.ok)
|
|
977
|
+
throw new Error(`Photon reverse request failed: ${res.status} ${res.statusText}`);
|
|
978
|
+
const raw = await res.json();
|
|
979
|
+
return (raw.features ?? []).map(toResult3);
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
// src/core-map/services/providers/Valhalla.ts
|
|
983
|
+
var DEFAULT_BASE_URL = "https://valhalla1.openstreetmap.de";
|
|
984
|
+
var costingMap = {
|
|
985
|
+
driving: "auto",
|
|
986
|
+
walking: "pedestrian",
|
|
987
|
+
cycling: "bicycle"
|
|
988
|
+
};
|
|
989
|
+
function decodePolyline2(encoded, precision = 6) {
|
|
990
|
+
const factor = 10 ** precision;
|
|
991
|
+
const len = encoded.length;
|
|
992
|
+
let index = 0;
|
|
993
|
+
let lat = 0;
|
|
994
|
+
let lng = 0;
|
|
995
|
+
const out = [];
|
|
996
|
+
while (index < len) {
|
|
997
|
+
let shift = 0;
|
|
998
|
+
let result = 0;
|
|
999
|
+
let byte;
|
|
1000
|
+
do {
|
|
1001
|
+
byte = encoded.charCodeAt(index++) - 63;
|
|
1002
|
+
result |= (byte & 31) << shift;
|
|
1003
|
+
shift += 5;
|
|
1004
|
+
} while (byte >= 32);
|
|
1005
|
+
const dLat = result & 1 ? ~(result >> 1) : result >> 1;
|
|
1006
|
+
lat += dLat;
|
|
1007
|
+
shift = 0;
|
|
1008
|
+
result = 0;
|
|
1009
|
+
do {
|
|
1010
|
+
byte = encoded.charCodeAt(index++) - 63;
|
|
1011
|
+
result |= (byte & 31) << shift;
|
|
1012
|
+
shift += 5;
|
|
1013
|
+
} while (byte >= 32);
|
|
1014
|
+
const dLng = result & 1 ? ~(result >> 1) : result >> 1;
|
|
1015
|
+
lng += dLng;
|
|
1016
|
+
out.push({ lat: lat / factor, lng: lng / factor });
|
|
1017
|
+
}
|
|
1018
|
+
return out;
|
|
1019
|
+
}
|
|
1020
|
+
function legToRoute(leg) {
|
|
1021
|
+
const shape = leg.shape ? decodePolyline2(leg.shape) : [];
|
|
1022
|
+
const steps = (leg.maneuvers ?? []).map((m) => {
|
|
1023
|
+
const start = m.begin_shape_index ?? 0;
|
|
1024
|
+
const end = m.end_shape_index ?? start;
|
|
1025
|
+
return {
|
|
1026
|
+
distance: (m.length ?? 0) * 1000,
|
|
1027
|
+
duration: m.time ?? 0,
|
|
1028
|
+
instruction: m.instruction ?? "",
|
|
1029
|
+
geometry: shape.slice(start, end + 1)
|
|
1030
|
+
};
|
|
1031
|
+
});
|
|
1032
|
+
return {
|
|
1033
|
+
distance: (leg.summary?.length ?? 0) * 1000,
|
|
1034
|
+
duration: leg.summary?.time ?? 0,
|
|
1035
|
+
geometry: shape,
|
|
1036
|
+
steps
|
|
1037
|
+
};
|
|
1038
|
+
}
|
|
1039
|
+
function tripToRoute(trip) {
|
|
1040
|
+
const legs = (trip.legs ?? []).map(legToRoute);
|
|
1041
|
+
const geometry = legs.flatMap((l) => l.geometry);
|
|
1042
|
+
const steps = legs.flatMap((l) => l.steps);
|
|
1043
|
+
return {
|
|
1044
|
+
distance: (trip.summary?.length ?? 0) * 1000,
|
|
1045
|
+
duration: trip.summary?.time ?? 0,
|
|
1046
|
+
geometry,
|
|
1047
|
+
steps,
|
|
1048
|
+
legs
|
|
1049
|
+
};
|
|
1050
|
+
}
|
|
1051
|
+
async function postJson(url, body, signal) {
|
|
1052
|
+
const res = await fetch(url, {
|
|
1053
|
+
method: "POST",
|
|
1054
|
+
headers: { "Content-Type": "application/json", Accept: "application/json" },
|
|
1055
|
+
body: JSON.stringify(body),
|
|
1056
|
+
signal
|
|
1057
|
+
});
|
|
1058
|
+
if (!res.ok)
|
|
1059
|
+
throw new Error(`Valhalla request failed: ${res.status} ${res.statusText}`);
|
|
1060
|
+
return res.json();
|
|
1061
|
+
}
|
|
1062
|
+
function buildUrl(base, path, apiKey) {
|
|
1063
|
+
const root = base.replace(/\/$/, "");
|
|
1064
|
+
const suffix = apiKey ? `?api_key=${encodeURIComponent(apiKey)}` : "";
|
|
1065
|
+
return `${root}${path}${suffix}`;
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
class ValhallaDirections {
|
|
1069
|
+
name = "valhalla";
|
|
1070
|
+
baseUrl;
|
|
1071
|
+
apiKey;
|
|
1072
|
+
constructor(opts = {}) {
|
|
1073
|
+
this.baseUrl = opts.baseUrl ?? DEFAULT_BASE_URL;
|
|
1074
|
+
this.apiKey = opts.apiKey;
|
|
1075
|
+
}
|
|
1076
|
+
async getDirections(waypoints, opts) {
|
|
1077
|
+
if (waypoints.length < 2)
|
|
1078
|
+
throw new Error("Valhalla requires at least two waypoints");
|
|
1079
|
+
const body = {
|
|
1080
|
+
locations: waypoints.map((w) => ({ lat: w.lat, lon: w.lng })),
|
|
1081
|
+
costing: costingMap[opts?.profile ?? "driving"] ?? "auto",
|
|
1082
|
+
directions_options: { language: opts?.language ?? "en-US" }
|
|
1083
|
+
};
|
|
1084
|
+
if (opts?.alternatives)
|
|
1085
|
+
body.alternates = 1;
|
|
1086
|
+
const url = buildUrl(this.baseUrl, "/route", this.apiKey);
|
|
1087
|
+
const raw = await postJson(url, body, opts?.signal);
|
|
1088
|
+
const routes = [];
|
|
1089
|
+
if (raw.trip)
|
|
1090
|
+
routes.push(tripToRoute(raw.trip));
|
|
1091
|
+
if (raw.alternates) {
|
|
1092
|
+
for (const alt of raw.alternates) {
|
|
1093
|
+
if (alt.trip)
|
|
1094
|
+
routes.push(tripToRoute(alt.trip));
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
return routes;
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
function ringToLatLng(ring) {
|
|
1101
|
+
return ring.map(([lng, lat]) => ({ lat, lng }));
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
class ValhallaIsochrone {
|
|
1105
|
+
name = "valhalla";
|
|
1106
|
+
baseUrl;
|
|
1107
|
+
apiKey;
|
|
1108
|
+
constructor(opts = {}) {
|
|
1109
|
+
this.baseUrl = opts.baseUrl ?? DEFAULT_BASE_URL;
|
|
1110
|
+
this.apiKey = opts.apiKey;
|
|
1111
|
+
}
|
|
1112
|
+
async getIsochrones(center, opts) {
|
|
1113
|
+
const metric = opts.contourMetric ?? "time";
|
|
1114
|
+
const body = {
|
|
1115
|
+
locations: [{ lat: center.lat, lon: center.lng }],
|
|
1116
|
+
costing: costingMap[opts.profile ?? "driving"] ?? "auto",
|
|
1117
|
+
contours: opts.contours.map((v) => metric === "distance" ? { distance: v } : { time: v }),
|
|
1118
|
+
polygons: true
|
|
1119
|
+
};
|
|
1120
|
+
if (typeof opts.denoise === "number")
|
|
1121
|
+
body.denoise = opts.denoise;
|
|
1122
|
+
if (typeof opts.generalize === "number")
|
|
1123
|
+
body.generalize = opts.generalize;
|
|
1124
|
+
const url = buildUrl(this.baseUrl, "/isochrone", this.apiKey);
|
|
1125
|
+
const raw = await postJson(url, body, opts.signal);
|
|
1126
|
+
const out = [];
|
|
1127
|
+
for (const feature of raw.features ?? []) {
|
|
1128
|
+
const contour = feature.properties?.contour ?? 0;
|
|
1129
|
+
const { geometry } = feature;
|
|
1130
|
+
if (geometry.type === "Polygon") {
|
|
1131
|
+
const rings = geometry.coordinates;
|
|
1132
|
+
if (rings.length === 0)
|
|
1133
|
+
continue;
|
|
1134
|
+
const polygon = {
|
|
1135
|
+
geometry: ringToLatLng(rings[0]),
|
|
1136
|
+
contour
|
|
1137
|
+
};
|
|
1138
|
+
if (rings.length > 1)
|
|
1139
|
+
polygon.holes = rings.slice(1).map(ringToLatLng);
|
|
1140
|
+
out.push(polygon);
|
|
1141
|
+
} else if (geometry.type === "MultiPolygon") {
|
|
1142
|
+
const polys = geometry.coordinates;
|
|
1143
|
+
for (const rings of polys) {
|
|
1144
|
+
if (rings.length === 0)
|
|
1145
|
+
continue;
|
|
1146
|
+
const polygon = {
|
|
1147
|
+
geometry: ringToLatLng(rings[0]),
|
|
1148
|
+
contour
|
|
1149
|
+
};
|
|
1150
|
+
if (rings.length > 1)
|
|
1151
|
+
polygon.holes = rings.slice(1).map(ringToLatLng);
|
|
1152
|
+
out.push(polygon);
|
|
1153
|
+
}
|
|
1154
|
+
} else if (geometry.type === "LineString") {
|
|
1155
|
+
out.push({
|
|
1156
|
+
geometry: ringToLatLng(geometry.coordinates),
|
|
1157
|
+
contour
|
|
1158
|
+
});
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
return out;
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
class ValhallaMatrix {
|
|
1166
|
+
name = "valhalla";
|
|
1167
|
+
baseUrl;
|
|
1168
|
+
apiKey;
|
|
1169
|
+
constructor(opts = {}) {
|
|
1170
|
+
this.baseUrl = opts.baseUrl ?? DEFAULT_BASE_URL;
|
|
1171
|
+
this.apiKey = opts.apiKey;
|
|
1172
|
+
}
|
|
1173
|
+
async getMatrix(origins, destinations, opts) {
|
|
1174
|
+
const body = {
|
|
1175
|
+
sources: origins.map((o) => ({ lat: o.lat, lon: o.lng })),
|
|
1176
|
+
targets: destinations.map((d) => ({ lat: d.lat, lon: d.lng })),
|
|
1177
|
+
costing: costingMap[opts?.profile ?? "driving"] ?? "auto"
|
|
1178
|
+
};
|
|
1179
|
+
const url = buildUrl(this.baseUrl, "/sources_to_targets", this.apiKey);
|
|
1180
|
+
const raw = await postJson(url, body, opts?.signal);
|
|
1181
|
+
const durations = [];
|
|
1182
|
+
const distances = [];
|
|
1183
|
+
for (const row of raw.sources_to_targets ?? []) {
|
|
1184
|
+
const dRow = [];
|
|
1185
|
+
const distRow = [];
|
|
1186
|
+
for (const cell of row) {
|
|
1187
|
+
dRow.push(cell.time ?? 0);
|
|
1188
|
+
distRow.push((cell.distance ?? 0) * 1000);
|
|
1189
|
+
}
|
|
1190
|
+
durations.push(dRow);
|
|
1191
|
+
distances.push(distRow);
|
|
1192
|
+
}
|
|
1193
|
+
const metric = opts?.metric ?? "time";
|
|
1194
|
+
const result = {};
|
|
1195
|
+
if (metric === "time" || metric === "distance") {
|
|
1196
|
+
result.durations = durations;
|
|
1197
|
+
result.distances = distances;
|
|
1198
|
+
}
|
|
1199
|
+
return result;
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1202
|
+
// src/core-map/services/index.ts
|
|
1203
|
+
var defaultGeocoder = () => new NominatimGeocoder;
|
|
1204
|
+
var defaultDirections = () => new OSRMDirections;
|
|
1205
|
+
var defaultIsochrone = () => new ValhallaIsochrone;
|
|
1206
|
+
var defaultMatrix = () => new OSRMMatrix;
|
|
1207
|
+
var valhallaMatrix = () => new ValhallaMatrix;
|
|
1208
|
+
var valhallaDirections = () => new ValhallaDirections;
|
|
1209
|
+
export {
|
|
1210
|
+
valhallaMatrix,
|
|
1211
|
+
valhallaDirections,
|
|
1212
|
+
defaultMatrix,
|
|
1213
|
+
defaultIsochrone,
|
|
1214
|
+
defaultGeocoder,
|
|
1215
|
+
defaultDirections,
|
|
1216
|
+
ValhallaMatrix,
|
|
1217
|
+
ValhallaIsochrone,
|
|
1218
|
+
ValhallaDirections,
|
|
1219
|
+
PhotonGeocoder,
|
|
1220
|
+
OSRMMatrix,
|
|
1221
|
+
OSRMDirections,
|
|
1222
|
+
NominatimGeocoder,
|
|
1223
|
+
MaptilerGeocoder,
|
|
1224
|
+
MapboxMatrix,
|
|
1225
|
+
MapboxIsochrone,
|
|
1226
|
+
MapboxGeocoder,
|
|
1227
|
+
MapboxDirections,
|
|
1228
|
+
GoogleGeocoder,
|
|
1229
|
+
GoogleDirections
|
|
1230
|
+
};
|