maplibre-gl-indoor
Version:
A MapLibre plugin to visualize multi-level buildings
1,467 lines (1,466 loc) • 39.9 kB
JavaScript
var $ = Object.defineProperty;
var j = (o, e, t) => e in o ? $(o, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : o[e] = t;
var n = (o, e, t) => j(o, typeof e != "symbol" ? e + "" : e, t);
var p = 63710088e-1, R = {
centimeters: p * 100,
centimetres: p * 100,
degrees: 360 / (2 * Math.PI),
feet: p * 3.28084,
inches: p * 39.37,
kilometers: p / 1e3,
kilometres: p / 1e3,
meters: p,
metres: p,
miles: p / 1609.344,
millimeters: p * 1e3,
millimetres: p * 1e3,
nauticalmiles: p / 1852,
radians: 1,
yards: p * 1.0936
};
function q(o, e, t = {}) {
const i = { type: "Feature" };
return (t.id === 0 || t.id) && (i.id = t.id), t.bbox && (i.bbox = t.bbox), i.properties = e || {}, i.geometry = o, i;
}
function Y(o, e, t = {}) {
if (!o)
throw new Error("coordinates is required");
if (!Array.isArray(o))
throw new Error("coordinates must be an Array");
if (o.length < 2)
throw new Error("coordinates must be at least 2 numbers long");
if (!S(o[0]) || !S(o[1]))
throw new Error("coordinates must contain numbers");
return q({
type: "Point",
coordinates: o
}, e, t);
}
function Z(o, e = "kilometers") {
const t = R[e];
if (!t)
throw new Error(e + " units is invalid");
return o * t;
}
function V(o, e = "kilometers") {
const t = R[e];
if (!t)
throw new Error(e + " units is invalid");
return o / t;
}
function E(o) {
return o % (2 * Math.PI) * 180 / Math.PI;
}
function g(o) {
return o % 360 * Math.PI / 180;
}
function S(o) {
return !isNaN(o) && o !== null && !Array.isArray(o);
}
function b(o) {
if (!o)
throw new Error("coord is required");
if (!Array.isArray(o)) {
if (o.type === "Feature" && o.geometry !== null && o.geometry.type === "Point")
return [...o.geometry.coordinates];
if (o.type === "Point")
return [...o.coordinates];
}
if (Array.isArray(o) && o.length >= 2 && !Array.isArray(o[0]) && !Array.isArray(o[1]))
return [...o];
throw new Error("coord must be GeoJSON Point or an Array of numbers");
}
function X(o, e, t = {}) {
var i = b(o), r = b(e), s = g(r[1] - i[1]), a = g(r[0] - i[0]), d = g(i[1]), l = g(r[1]), c = Math.pow(Math.sin(s / 2), 2) + Math.pow(Math.sin(a / 2), 2) * Math.cos(d) * Math.cos(l);
return Z(
2 * Math.atan2(Math.sqrt(c), Math.sqrt(1 - c)),
t.units
);
}
var L = X;
function k(o) {
const [e, t, i, r] = o;
return [(e + i) / 2, (t + r) / 2];
}
function P(o, e) {
const [t, i, r, s] = o, [a, d] = e, l = i <= d && d <= s;
let c = t <= a && a <= r;
return t > r && (c = t >= a && a >= r), l && c;
}
function J(o, e) {
return o[0] > e[2] || e[0] > o[2] ? !1 : !(o[3] < e[1] || e[3] < o[1]);
}
function K(o, e, t = !1) {
return t ? [
"all",
o,
["any", ["!", ["has", "level"]], B(e)]
] : ["all", o, B(e)];
}
function B(o) {
return [
"all",
[
// level=MIN~... => if LEVEL <= current_level, we can display
"<=",
[
"to-number",
["slice", ["get", "level"], 0, ["index-of", "~", ["get", "level"]]]
],
o
],
[
// level=...~MAX => if LEVEL >= current_level, we can display
">=",
[
"to-number",
[
"slice",
["get", "level"],
["+", ["index-of", "~", ["get", "level"]], 1]
]
],
o
]
];
}
const C = "indoor";
class Q {
constructor(e) {
n(this, "_indoorMaps");
n(this, "_level");
n(this, "_map");
n(this, "_mapLoadedPromise");
n(this, "_previousSelectedLevel");
n(this, "_previousSelectedMap");
n(this, "_savedFilters");
n(this, "_selectedMap");
n(this, "_updateMapPromise");
this._map = e, this._level = null, this._indoorMaps = [], this._savedFilters = [], this._selectedMap = null, this._previousSelectedMap = null, this._previousSelectedLevel = null, this._updateMapPromise = Promise.resolve(), this._map.loaded() ? this._mapLoadedPromise = Promise.resolve() : this._mapLoadedPromise = new Promise(
(t) => this._map.on("load", t)
), this._map.on("moveend", () => this._updateSelectedMapIfNeeded());
}
_addLayerForFiltering(e, t) {
this._map.addLayer(e, t), this._savedFilters.push({
filter: this._map.getFilter(e.id) || [
"all"
],
layerId: e.id
});
}
_closestMap() {
if (this._map.getZoom() < 16.5)
return null;
const e = this._map.getBounds(), t = [
e.getWest(),
e.getSouth(),
e.getEast(),
e.getNorth()
], i = this._indoorMaps.filter(
(a) => J(a.bounds, t)
);
if (i.length === 0)
return null;
if (i.length === 1)
return i[0];
let r = Number.POSITIVE_INFINITY, s = i[0];
for (const a of i) {
const d = L(
k(a.bounds),
k(t)
);
d < r && (s = a, r = d);
}
return s;
}
_removeLayerForFiltering(e) {
this._savedFilters = this._savedFilters.filter(
({ layerId: t }) => e !== t
), this._map.removeLayer(e);
}
/**
* ***********************
* Handle level change
* ***********************
*/
_updateFiltering() {
const e = this._level;
let t;
if (e !== null) {
const i = this._selectedMap ? this._selectedMap.showFeaturesWithEmptyLevel : !1;
t = (r) => K(r, e, i);
} else
t = (i) => i;
this._savedFilters.forEach(({ filter: i, layerId: r }) => {
this._map.setFilter(r, t(i));
});
}
_updateSelectedMap(e) {
const t = this._selectedMap;
if (t !== null && (t.layersToHide.forEach(
(l) => this._map.setLayoutProperty(l, "visibility", "visible")
), t.layers.forEach(({ id: l }) => this._removeLayerForFiltering(l)), this._map.removeSource(C), e || (this._previousSelectedLevel = this._level, this._previousSelectedMap = t), this.setLevel(null, !1), this._map.fire("indoor.map.unloaded", { indoorMap: t })), this._selectedMap = e, !e)
return;
const { beforeLayerId: i, geojson: r, layers: s, levelsRange: a } = e;
this._map.addSource(C, {
data: r,
lineMetrics: !0,
type: "geojson"
}), s.forEach((l) => this._addLayerForFiltering(l, i)), e.layersToHide.forEach(
(l) => this._map.setLayoutProperty(l, "visibility", "none")
);
const d = this._previousSelectedMap === e ? this._previousSelectedLevel : Math.max(
Math.min(e.defaultLevel, a.max),
a.min
);
this.setLevel(d, !1), this._map.fire("indoor.map.loaded", { indoorMap: e });
}
async _updateSelectedMapIfNeeded() {
await this._mapLoadedPromise, await this._updateMapPromise, this._updateMapPromise = (async () => {
const e = this._closestMap();
e !== this._selectedMap && this._updateSelectedMap(e);
})(), await this._updateMapPromise;
}
addLayerForFiltering(e, t) {
this._addLayerForFiltering(e, t), this._updateFiltering();
}
async addMap(e) {
this._indoorMaps.push(e), await this._updateSelectedMapIfNeeded();
}
/**
* **************
* Handle maps
* **************
*/
getLevel() {
return this._level;
}
getSelectedMap() {
return this._selectedMap;
}
removeLayerForFiltering(e) {
this._removeLayerForFiltering(e), this._updateFiltering();
}
async removeMap(e) {
this._indoorMaps = this._indoorMaps.filter(
(t) => t !== e
), await this._updateSelectedMapIfNeeded();
}
setLevel(e, t = !0) {
if (this._selectedMap === null)
throw new Error("Cannot set level, no map has been selected");
this._level = e, this._updateFiltering(), t && this._map.fire("indoor.level.changed", { level: e });
}
}
function ee(o) {
return Object.defineProperty(o, "indoor", {
get: function() {
return this._indoor || (this._indoor = new Q(this)), this._indoor;
}
}), o;
}
class me {
constructor() {
n(this, "_container");
n(this, "_indoor");
n(this, "_indoorMap");
n(this, "_levelsButtons");
n(this, "_map");
n(this, "_selectedButton");
n(this, "_onLevelChanged", ({ level: e }) => this._setSelected(e));
n(this, "_onMapLoaded", ({ indoorMap: e }) => {
this._indoorMap = e, this._updateNavigationBar(), this._setSelected(this._indoor.getLevel());
});
n(this, "_onMapUnLoaded", () => {
this._indoorMap = null, this._updateNavigationBar();
});
this._levelsButtons = [], this._selectedButton = null, this._indoorMap = null;
}
_createLevelButton(e, t) {
const i = document.createElement("button");
return i.innerHTML = t.toString(), i.classList.add("maplibregl-ctrl-icon"), e.appendChild(i), i.addEventListener("click", () => {
var r;
(r = this._map) == null || r.fire("indoor.control.clicked", { level: t }), this._indoor.getLevel() !== t && this._indoor.setLevel(t);
}), i;
}
_onContextMenu(e) {
e.preventDefault();
}
_setSelected(e) {
this._levelsButtons.length !== 0 && (this._selectedButton && (this._selectedButton.style.fontWeight = "normal"), e !== null && this._levelsButtons[e] && (this._levelsButtons[e].style.fontWeight = "bold", this._selectedButton = this._levelsButtons[e]));
}
_updateNavigationBar() {
if (!this._container)
return;
if (this._indoorMap === null) {
this._container.style.display = "none";
return;
}
for (this._container.style.display = "block", this._levelsButtons = []; this._container.firstChild; )
this._container.removeChild(this._container.firstChild);
const e = this._indoorMap.levelsRange;
for (let t = e.max; t >= e.min; t--)
this._levelsButtons[t] = this._createLevelButton(this._container, t);
}
onAdd(e) {
if (e.indoor === void 0)
throw Error("call addIndoorTo(map) before creating the IndoorControl");
this._map = e, this._indoor = this._map.indoor;
const t = this._container = document.createElement("div");
return t.classList.add("maplibregl-ctrl"), t.classList.add("maplibregl-ctrl-group"), t.style.display = "none", t.addEventListener("contextmenu", this._onContextMenu), this._indoorMap = this._indoor.getSelectedMap(), this._indoor.getSelectedMap() !== null && (this._updateNavigationBar(), this._setSelected(this._indoor.getLevel())), this._map.on("indoor.map.loaded", this._onMapLoaded), this._map.on("indoor.map.unloaded", this._onMapUnLoaded), this._map.on("indoor.level.changed", this._onLevelChanged), t;
}
onRemove() {
var e, t, i, r, s;
(e = this._container) == null || e.removeEventListener("contextmenu", this._onContextMenu), (t = this._container) == null || t.remove(), delete this._container, (i = this._map) == null || i.off("indoor.map.loaded", this._onMapLoaded), (r = this._map) == null || r.off("indoor.map.unloaded", this._onMapUnLoaded), (s = this._map) == null || s.off("indoor.level.changed", this._onLevelChanged), delete this._map;
}
}
function D(o, e, t) {
if (o !== null)
for (var i, r, s, a, d, l, c, u = 0, h = 0, v, x = o.type, F = x === "FeatureCollection", H = x === "Feature", U = F ? o.features.length : 1, f = 0; f < U; f++) {
c = F ? o.features[f].geometry : H ? o.geometry : o, v = c ? c.type === "GeometryCollection" : !1, d = v ? c.geometries.length : 1;
for (var w = 0; w < d; w++) {
var m = 0, y = 0;
if (a = v ? c.geometries[w] : c, a !== null) {
l = a.coordinates;
var _ = a.type;
switch (u = 0, _) {
case null:
break;
case "Point":
if (e(
l,
h,
f,
m,
y
) === !1)
return !1;
h++, m++;
break;
case "LineString":
case "MultiPoint":
for (i = 0; i < l.length; i++) {
if (e(
l[i],
h,
f,
m,
y
) === !1)
return !1;
h++, _ === "MultiPoint" && m++;
}
_ === "LineString" && m++;
break;
case "Polygon":
case "MultiLineString":
for (i = 0; i < l.length; i++) {
for (r = 0; r < l[i].length - u; r++) {
if (e(
l[i][r],
h,
f,
m,
y
) === !1)
return !1;
h++;
}
_ === "MultiLineString" && m++, _ === "Polygon" && y++;
}
_ === "Polygon" && m++;
break;
case "MultiPolygon":
for (i = 0; i < l.length; i++) {
for (y = 0, r = 0; r < l[i].length; r++) {
for (s = 0; s < l[i][r].length - u; s++) {
if (e(
l[i][r][s],
h,
f,
m,
y
) === !1)
return !1;
h++;
}
y++;
}
m++;
}
break;
case "GeometryCollection":
for (i = 0; i < a.geometries.length; i++)
if (D(a.geometries[i], e) === !1)
return !1;
break;
default:
throw new Error("Unknown Geometry Type");
}
}
}
}
}
function te(o, e = {}) {
if (o.bbox != null && e.recompute !== !0)
return o.bbox;
const t = [1 / 0, 1 / 0, -1 / 0, -1 / 0];
return D(o, (i) => {
t[0] > i[0] && (t[0] = i[0]), t[1] > i[1] && (t[1] = i[1]), t[2] < i[0] && (t[2] = i[0]), t[3] < i[1] && (t[3] = i[1]);
}), t;
}
var oe = te;
function ie(o) {
const e = o.split(";").map(ae).filter((t) => t !== null);
return e.length ? {
max: Math.max(...e.map((t) => t.max)),
min: Math.min(...e.map((t) => t.min))
} : null;
}
function re(o) {
if (o.type !== "FeatureCollection")
throw new Error(
o.type + " is not allowed as a top level collection, please use FeatureCollection instead."
);
const e = o.features.filter(
(t) => !!t.properties && typeof t.properties.level == "string"
).map((t) => {
var i;
return ie(((i = t.properties) == null ? void 0 : i.level) ?? "");
}).filter((t) => t !== null);
if (e.length == 0)
throw console.debug(o), new Error(
"the FeatureCollection does not contain a single level. Cannot compute the range of levels to display"
);
return {
bounds: oe(o),
levelsRange: {
max: Math.max(...e.map((t) => t.max)),
min: Math.min(...e.map((t) => t.min))
}
};
}
function ae(o) {
const e = o.split("~"), t = {
max: parseFloat(e[1]),
min: parseFloat(e[0])
};
return isNaN(t.min) || isNaN(t.max) ? null : t;
}
const I = [
{
filter: ["any", ["has", "building"], ["has", "building:part"]],
id: "buildings-background",
minzoom: 16.5,
paint: {
"fill-color": "#FFFFFF",
"fill-opacity": ["interpolate", ["linear"], ["zoom"], 16.5, 0, 18, 1]
},
source: "indoor",
type: "fill"
},
// unsure if the level is not better displayed :shrug: ..
// {
// filter: ["==", ["get", "indoor"], "level"],
// id: "indoor-level",
// minzoom: 16.5,
// paint: {
// "fill-color": "#b9e1ff",
// "fill-opacity": ["interpolate", ["linear"], ["zoom"], 16.5, 0, 18, 1],
// },
// source: "indoor",
// type: "fill",
// },
{
filter: ["==", ["get", "leisure"], "garden"],
id: "indoor-gardens",
minzoom: 16.5,
paint: {
"fill-color": "#D8E5A4",
"fill-opacity": ["interpolate", ["linear"], ["zoom"], 16.5, 0, 18, 1]
},
source: "indoor",
type: "fill"
},
{
filter: ["==", ["get", "amenity"], "parking"],
id: "indoor-parkings",
minzoom: 16.5,
paint: {
"fill-color": "#fbeada",
"fill-opacity": ["interpolate", ["linear"], ["zoom"], 16.5, 0, 18, 1],
"fill-outline-color": "#000000"
},
source: "indoor",
type: "fill"
},
{
filter: ["==", ["get", "amenity"], "parking"],
id: "indoor-parkings-patterns",
minzoom: 16.5,
paint: {
"fill-opacity": ["interpolate", ["linear"], ["zoom"], 16.5, 0, 18, 0.1],
"fill-pattern": "si-main-3",
"fill-translate-anchor": "viewport"
},
source: "indoor",
type: "fill"
},
{
filter: [
"any",
["==", ["get", "indoor"], "room"],
["==", ["get", "indoor"], "area"],
["==", ["get", "railway"], "platform"]
],
id: "indoor-rooms",
minzoom: 16.5,
paint: {
"fill-color": "#e0e0e0",
"fill-opacity": ["interpolate", ["linear"], ["zoom"], 16.5, 0, 18, 1]
},
source: "indoor",
type: "fill"
},
{
filter: [
"all",
[
"any",
["==", ["get", "indoor"], "room"],
["==", ["get", "indoor"], "area"],
["==", ["get", "railway"], "platform"]
],
["==", ["get", "access"], "no"]
],
id: "indoor-rooms-no-access",
minzoom: 16.5,
paint: {
"fill-color": "#878787",
"fill-opacity": ["interpolate", ["linear"], ["zoom"], 16.5, 0, 18, 1]
},
source: "indoor",
type: "fill"
},
{
filter: [
"any",
["==", ["get", "indoor"], "room"],
["==", ["get", "indoor"], "area"],
["==", ["get", "railway"], "platform"]
],
id: "indoor-rooms-walls",
minzoom: 16.5,
paint: {
"line-color": "#000",
"line-offset": 1,
"line-opacity": ["interpolate", ["linear"], ["zoom"], 16.5, 0, 18, 1]
},
source: "indoor",
type: "line"
},
{
filter: ["==", ["get", "indoor"], "room"],
id: "indoor-rooms-borders",
minzoom: 16.5,
paint: {
"line-color": "#000",
"line-opacity": ["interpolate", ["linear"], ["zoom"], 16.5, 0, 18, 1]
},
source: "indoor",
type: "line"
},
{
filter: [
"all",
["any", ["==", ["get", "indoor"], "door"], ["has", "door"]],
["!", ["has", "entrance"]],
["!=", ["get", "access"], "no"]
],
id: "indoor-doors",
minzoom: 16.5,
paint: {
"circle-color": "#e0e0e0",
"circle-opacity": ["interpolate", ["linear"], ["zoom"], 16.5, 0, 18, 1],
"circle-radius": [
"interpolate",
["exponential", 2],
["zoom"],
10,
["*", ["*", 0.5, ["number", ["get", "width"], 1.6]], ["^", 2, -6]],
24,
["*", ["*", 0.5, ["number", ["get", "width"], 1.6]], ["^", 2, 8]]
]
},
source: "indoor",
type: "circle"
},
{
filter: ["==", ["get", "highway"], "pedestrian"],
id: "indoor-highways-area",
paint: {
"fill-color": [
"interpolate",
["linear"],
["zoom"],
16,
"hsl(230, 16%, 94%)",
16.25,
"hsl(230, 50%, 98%)"
],
"fill-opacity": 1,
"fill-outline-color": "hsl(230, 26%, 88%)"
},
source: "indoor",
type: "fill"
},
{
filter: ["==", ["get", "highway"], "pedestrian"],
id: "indoor-highways-area-pattern",
minzoom: 16.5,
paint: {
"fill-color": "hsl(0, 0%, 100%)",
"fill-opacity": ["interpolate", ["linear"], ["zoom"], 16.5, 0, 18, 1],
"fill-outline-color": "hsl(35, 10%, 83%)",
"fill-pattern": "pedestrian-polygon"
},
source: "indoor",
type: "fill"
},
{
filter: [
"any",
["==", ["get", "indoor"], "corridor"],
["==", ["get", "room"], "stairs"]
],
id: "indoor-corridors",
minzoom: 16.5,
paint: {
"fill-color": "#b9e1ff",
"fill-opacity": ["interpolate", ["linear"], ["zoom"], 16.5, 0, 18, 1]
},
source: "indoor",
type: "fill"
},
{
filter: ["==", ["get", "indoor"], "area"],
id: "indoor-area",
minzoom: 16.5,
paint: {
"fill-antialias": !0,
// otherwise the outline is invisible sometimes..,
"fill-color": "#8dd1fc",
"fill-opacity": ["interpolate", ["linear"], ["zoom"], 16.5, 0, 18, 1],
"fill-outline-color": "#000"
},
source: "indoor",
type: "fill"
},
{
filter: [
"all",
["==", ["get", "indoor"], "area"],
["==", ["get", "balcony"], "yes"]
],
id: "indoor-balcony",
minzoom: 16.5,
paint: {
"fill-color": "#BDBDBD",
"fill-opacity": ["interpolate", ["linear"], ["zoom"], 16.5, 0, 18, 1]
},
source: "indoor",
type: "fill"
},
{
filter: [
"any",
["==", ["get", "elevator"], "yes"],
["==", ["get", "highway"], "elevator"]
],
id: "indoor-elevators-below",
minzoom: 16.5,
paint: {
"fill-antialias": !0,
"fill-color": "#b9e1ff",
"fill-opacity": ["interpolate", ["linear"], ["zoom"], 16.5, 0, 18, 1],
"fill-outline-color": "#000000"
},
source: "indoor",
type: "fill"
},
{
filter: [
"all",
["==", ["get", "door"], "sliding"],
["==", ["get", "automatic_door"], "button"],
["!=", ["get", "access"], "no"]
],
id: "indoor-elevator-doors",
metadata: {
"maputnik:comment": `Overlaying with the base color makes a ~~door~~ *glory-wall*
:scream:`
},
paint: {
"circle-color": "#b9e1ff",
"circle-radius": [
"interpolate",
["exponential", 2],
["zoom"],
10,
["*", ["*", 0.5, ["number", ["get", "width"], 1.6]], ["^", 2, -6]],
24,
["*", ["*", 0.5, ["number", ["get", "width"], 1.6]], ["^", 2, 8]]
]
},
source: "indoor",
type: "circle"
},
{
filter: [
"any",
["==", ["get", "elevator"], "yes"],
["==", ["get", "highway"], "elevator"]
],
id: "indoor-elevators-logo",
layout: {
"icon-allow-overlap": !0,
"icon-image": "elevator",
"icon-size": [
"interpolate",
["exponential", 1.8],
["zoom"],
17,
["*", 2, ["^", 2, -2]],
24,
["*", 2, ["^", 2, 3]]
]
},
paint: {
"icon-opacity": ["interpolate", ["linear"], ["zoom"], 16.5, 0, 18, 1]
},
source: "indoor",
type: "symbol"
},
{
filter: ["==", ["get", "indoor"], "wall"],
id: "indoor-walls",
paint: {
"line-color": "#000000",
"line-opacity": ["interpolate", ["linear"], ["zoom"], 17, 0, 18, 1],
"line-width": 2
},
source: "indoor",
type: "line"
},
{
filter: ["has", "barrier"],
id: "indoor-barriers",
paint: {
"line-color": "#000000",
"line-opacity": ["interpolate", ["linear"], ["zoom"], 17, 0, 18, 1]
},
source: "indoor",
type: "line"
},
{
filter: ["==", ["get", "indoor"], "block"],
id: "indoor-blocks",
paint: {
"fill-color": "#000000",
"fill-opacity": ["interpolate", ["linear"], ["zoom"], 17, 0, 18, 1]
},
source: "indoor",
type: "fill"
},
{
filter: [
"all",
["==", ["get", "handrail"], "yes"],
["!=", ["get", "highway"], "steps"]
],
id: "indoor-handrail",
paint: {
"line-color": "#000000",
"line-opacity": ["interpolate", ["linear"], ["zoom"], 17, 0, 19, 1]
},
source: "indoor",
type: "line"
},
{
filter: ["==", ["get", "railway"], "rail"],
id: "indoor-rails",
paint: {
"line-color": "hsl(230, 10%, 74%)",
"line-opacity": ["interpolate", ["linear"], ["zoom"], 17, 0, 19, 1]
},
source: "indoor",
type: "line"
},
{
filter: ["==", ["get", "railway"], "rail"],
id: "indoor-rails-tracks",
paint: {
"line-color": "hsl(230,10%,74%)",
"line-dasharray": [0.1, 15],
"line-opacity": ["interpolate", ["linear"], ["zoom"], 17, 0, 19, 1],
"line-width": [
"interpolate",
["exponential", 1.5],
["zoom"],
14,
4,
20,
8
]
},
source: "indoor",
type: "line"
},
{
filter: [
"any",
[
"in",
["get", "indoor"],
[
"literal",
[
"table",
"cupboard",
"chair",
"kitchen",
"sofa",
"tv",
"shelf",
"furniture-item"
]
]
],
["==", ["get", "trashcan"], "yes"],
["==", ["get", "copier"], "yes"],
["==", ["get", "amenity"], "vending_machine"]
],
id: "indoor-furniture",
minzoom: 18,
paint: {
"fill-color": "#000",
"fill-opacity": ["interpolate", ["linear"], ["zoom"], 18, 0, 19, 0.2],
"fill-outline-color": "#000"
},
source: "indoor",
type: "fill"
},
{
filter: [
"all",
["==", ["get", "highway"], "steps"],
["!", ["has", "conveying"]]
],
id: "indoor-steps-white-base",
layout: {
"line-join": "round"
},
minzoom: 17,
paint: {
"line-gradient": [
"interpolate",
["linear"],
["line-progress"],
0,
"rgba(255, 252, 252, 0)",
1,
"rgba(255, 252, 252, 0.8)"
],
"line-opacity": ["interpolate", ["linear"], ["zoom"], 17, 0, 17.25, 1],
"line-width": [
"interpolate",
["exponential", 2],
["zoom"],
10,
["*", 1, ["^", 2, -6]],
24,
["*", 1, ["^", 2, 8]]
]
},
source: "indoor",
type: "line"
},
{
filter: [
"all",
["==", ["get", "highway"], "steps"],
["!", ["has", "conveying"]]
],
id: "indoor-steps-base",
layout: {
"line-join": "round"
},
minzoom: 17,
paint: {
"line-gap-width": [
"interpolate",
["exponential", 2],
["zoom"],
10,
["*", 1, ["^", 2, -6]],
24,
["*", 1, ["^", 2, 8]]
],
"line-gradient": [
"interpolate",
["linear"],
["line-progress"],
0,
"rgba(0,0,0,0)",
1,
"rgba(0,0,0,1)"
],
"line-opacity": ["interpolate", ["linear"], ["zoom"], 17, 0, 17.25, 1],
"line-width": [
"interpolate",
["exponential", 2],
["zoom"],
10,
["*", 0.1, ["^", 2, -6]],
24,
["*", 0.1, ["^", 2, 8]]
]
},
source: "indoor",
type: "line"
},
{
filter: [
"all",
["all", ["==", ["get", "highway"], "steps"], ["!", ["has", "conveying"]]]
],
id: "indoor-steps-middle",
layout: {
"line-cap": "round",
"line-join": "round"
},
minzoom: 17,
paint: {
"line-gradient": [
"interpolate",
["linear"],
["line-progress"],
0,
"rgba(0,0,0,0)",
1,
"rgba(22, 93, 177, 0.4)"
],
"line-opacity": ["interpolate", ["linear"], ["zoom"], 17, 0, 17.25, 1],
"line-width": [
"interpolate",
["exponential", 1.8],
["zoom"],
17,
["*", 1, ["^", 2, -2]],
24,
["*", 1, ["^", 2, 6]]
]
},
source: "indoor",
type: "line"
},
{
filter: ["==", ["get", "highway"], "steps"],
id: "indoor-steps-arrow",
layout: {
"icon-allow-overlap": !0,
"icon-ignore-placement": !1,
"icon-image": "triangle",
"icon-keep-upright": !1,
"icon-rotate": 90,
"icon-size": [
"interpolate",
["exponential", 1.8],
["zoom"],
17,
["*", 1, ["^", 2, -2]],
24,
["*", 1, ["^", 2, 3]]
],
"symbol-avoid-edges": !0,
"symbol-placement": "line"
},
minzoom: 18,
paint: {
"icon-color": "rgba(22, 93, 177, 0.4)",
"icon-opacity": [
"interpolate",
["linear"],
["zoom"],
17,
0,
17.5,
0.5,
19,
1
]
},
source: "indoor",
type: "symbol"
},
{
filter: ["all", ["==", ["get", "highway"], "steps"], ["has", "conveying"]],
id: "indoor-conveying",
layout: {
"line-join": "round"
},
paint: {
"line-color": "#FF0000",
"line-dasharray": [
"step",
["zoom"],
["literal", [1, 0]],
17.5,
["literal", [1.75, 1]],
18,
["literal", [1, 0.75]],
19,
["literal", [0.3, 0.3]]
],
"line-opacity": ["interpolate", ["linear"], ["zoom"], 17, 0, 17.25, 1],
"line-width": [
"interpolate",
["exponential", 1.5],
["zoom"],
17,
1,
18,
1.6,
19,
6
]
},
source: "indoor",
type: "line"
},
{
filter: [
"all",
[
"!",
[
"in",
["get", "amenity"],
["literal", ["toilet", "toilets", "shower", "showers"]]
]
],
["==", ["get", "indoor"], "room"]
],
id: "poi-indoor-text-ref",
layout: {
"text-allow-overlap": !1,
"text-anchor": "center",
"text-field": [
"case",
["all", ["has", "name"], ["has", "name"]],
[
"format",
["get", "name"],
{},
`
`,
{},
["get", "ref"],
{ "font-scale": 0.8 }
],
["has", "name"],
["get", "name"],
["get", "ref"]
],
"text-font": ["Roboto Regular"],
"text-ignore-placement": !1,
"text-justify": "auto",
"text-padding": 5,
"text-rotation-alignment": "auto",
"text-size": [
"interpolate",
["exponential", 1.5],
["zoom"],
16.5,
12,
24,
18
]
},
minzoom: 16.5,
paint: {
"text-color": "#072140",
"text-opacity": [
"interpolate",
["linear"],
["zoom"],
17.5,
0,
18,
0.5,
19,
1
]
},
source: "indoor",
type: "symbol"
},
{
filter: [
"all",
[
"any",
["==", ["get", "entrance"], "exit"],
["==", ["get", "entrance"], "emergency"]
]
],
id: "poi-exterior-exit-bg",
minzoom: 18,
paint: {
"circle-color": "rgba(255, 255, 255, 1)",
"circle-opacity": ["interpolate", ["linear"], ["zoom"], 18, 0, 18.5, 0.8],
"circle-radius": 10
},
source: "indoor",
type: "circle"
},
{
filter: [
"all",
[
"any",
["==", ["get", "entrance"], "exit"],
["==", ["get", "entrance"], "emergency"]
]
],
id: "poi-exterior-exit",
layout: {
"icon-image": "exit-alt1"
},
minzoom: 18,
paint: {
"icon-opacity": ["interpolate", ["linear"], ["zoom"], 18, 0, 18.5, 1]
},
source: "indoor",
type: "symbol"
},
{
filter: [
"all",
["has", "entrance"],
["!=", ["get", "entrance"], "exit"],
["!=", ["get", "entrance"], "emergency"]
],
id: "poi-exterior-entrance-bg",
minzoom: 16,
paint: {
"circle-color": "rgba(255, 255, 255, 1)",
"circle-opacity": ["interpolate", ["linear"], ["zoom"], 16, 0, 16.5, 1],
"circle-radius": 10
},
source: "indoor",
type: "circle"
},
{
filter: ["has", "building"],
id: "buildings-walls",
minzoom: 16.5,
paint: {
"line-color": "#FFFFFF",
"line-opacity": ["interpolate", ["linear"], ["zoom"], 16.5, 0, 18, 1],
"line-width": 2
},
source: "indoor",
type: "line"
},
{
filter: [
"all",
["has", "entrance"],
["!=", ["get", "entrance"], "exit"],
["!=", ["get", "entrance"], "emergency"]
],
id: "poi-exterior-entrance",
layout: {
"icon-allow-overlap": !0,
"icon-ignore-placement": !0,
"icon-image": "entrance-alt1",
"icon-optional": !1,
"text-font": []
},
minzoom: 16,
paint: {
"icon-opacity": ["interpolate", ["linear"], ["zoom"], 16, 0, 16.5, 1]
},
source: "indoor",
type: "symbol"
},
{
filter: [
"in",
["get", "amenity"],
["literal", ["toilets", "shower", "showers"]]
],
id: "poi-indoor-bathrooms",
layout: {
"icon-allow-overlap": !0,
"icon-anchor": "center",
"icon-image": [
"case",
["in", ["get", "amenity"], ["literal", ["shower", "showers"]]],
["literal", "noun-shower-51"],
["==", ["get", "wheelchair"], "yes"],
["literal", "wheelchair"],
[
"all",
["==", ["get", "female"], "yes"],
["!=", ["get", "male"], "yes"]
],
["literal", "toilet_female"],
[
"all",
["!=", ["get", "female"], "yes"],
["==", ["get", "male"], "yes"]
],
["literal", "toilet_male"],
["literal", "toilet"]
],
"icon-size": ["interpolate", ["linear"], ["zoom"], 17, 0.5, 20, 1]
},
minzoom: 18,
paint: {
"icon-opacity": [
"interpolate",
["linear"],
["zoom"],
18,
0,
18.5,
0.5,
19,
1
]
},
source: "indoor",
type: "symbol"
},
{
filter: ["boolean", !1],
// changed in the poi-logic
id: "poi-indoor",
layout: {
"icon-allow-overlap": !0,
"icon-anchor": "center",
"icon-image": ["get", "maki"],
// changed in the poi-logic
"icon-optional": !1,
"icon-size": ["interpolate", ["linear"], ["zoom"], 17, 0.5, 20, 1],
"symbol-placement": "point",
"symbol-spacing": 250,
"text-allow-overlap": !1,
"text-anchor": "top",
"text-field": [
"case",
["all", ["has", "name"], ["has", "name"]],
[
"format",
["get", "name"],
{},
`
`,
{},
["get", "ref"],
{ "font-scale": 0.8 }
],
["has", "name"],
["get", "name"],
["get", "ref"]
],
"text-font": ["Roboto Regular"],
"text-ignore-placement": !1,
"text-line-height": 1.2,
"text-max-angle": 38,
"text-max-width": 8,
"text-offset": [0, 1],
"text-padding": 2,
"text-rotation-alignment": "viewport",
"text-size": ["interpolate", ["linear"], ["zoom"], 17, 11, 20, 13]
},
minzoom: 17,
paint: {
"icon-opacity": [
"interpolate",
["linear"],
["zoom"],
18,
0,
18.5,
0.5,
19,
1
],
"text-color": "#072140",
"text-halo-color": "rgb(194, 215, 239, 0.3)",
"text-halo-width": 1,
"text-opacity": [
"interpolate",
["linear"],
["zoom"],
17,
0,
17.5,
0.5,
19,
1
]
},
source: "indoor",
type: "symbol"
}
];
let M = I;
const T = "poi-indoor", W = [
{ maki: "suitcase", shop: "travel_agency" },
{ maki: "grocery", shop: "convenience" },
{ maki: "bakery", shop: "bakery" },
{ maki: "pharmacy", shop: "chemist" },
{ maki: "clothing-store", shop: "clothes" }
], N = [
{ filter: ["==", ["get", "amenity"], "fast_food"], maki: "fast-food" },
{ filter: ["==", ["get", "amenity"], "restaurant"], maki: "restaurant" },
{ filter: ["==", ["get", "amenity"], "cafe"], maki: "cafe" },
{
filter: [
"in",
["get", "amenity"],
["literal", ["bank", "vending_machine"]]
],
maki: "bank"
},
{ filter: ["==", ["get", "natural"], "tree"], maki: "park" },
...W.map(
({ maki: o, shop: e }) => ({ filter: ["==", ["get", "shop"], e], maki: o })
)
];
function ne(o) {
const e = W.map((t) => t.shop);
return N.push({
filter: ["in", ["get", "shop"], ["literal", e]],
maki: "shop"
}), N.map((t) => {
const i = Object.assign({}, o);
return i.id += `-${t.maki}`, i.filter = t.filter, i.layout = Object.assign({}, o.layout), i.layout["icon-image"] = t.maki, i;
});
}
const A = M.find((o) => o.id === T);
A && (ne(A).forEach(
(o) => M.push(o)
), M = M.filter((o) => o.id !== T));
const le = M, se = { DefaultLayers: le, defaultLayers: I };
class z {
constructor(e, t, i, r, s, a, d, l) {
n(this, "beforeLayerId");
n(this, "bounds");
n(this, "defaultLevel");
n(this, "geojson");
n(this, "layers");
n(this, "layersToHide");
n(this, "levelsRange");
n(this, "showFeaturesWithEmptyLevel");
this.bounds = e, this.geojson = t, this.layers = i, this.levelsRange = r, this.layersToHide = s, this.defaultLevel = a, this.showFeaturesWithEmptyLevel = d, this.beforeLayerId = l;
}
static fromGeojson(e, t = {}) {
const { bounds: i, levelsRange: r } = re(e);
return new z(
i,
e,
t.layers ? t.layers : se.DefaultLayers,
r,
t.layersToHide ? t.layersToHide : [],
t.defaultLevel ? t.defaultLevel : 0,
t.showFeaturesWithEmptyLevel ? t.showFeaturesWithEmptyLevel : !1,
t.beforeLayerId
);
}
}
function de(o, e, t, i = {}) {
const r = b(o), s = g(r[0]), a = g(r[1]), d = g(t), l = V(e, i.units), c = Math.asin(
Math.sin(a) * Math.cos(l) + Math.cos(a) * Math.sin(l) * Math.cos(d)
), u = s + Math.atan2(
Math.sin(d) * Math.sin(l) * Math.cos(a),
Math.cos(l) - Math.sin(a) * Math.sin(c)
), h = E(u), v = E(c);
return Y([h, v], i.properties);
}
var O = de;
const ce = 16.25, pe = 200;
class G {
constructor(e, t, i) {
n(this, "downloadedBounds");
n(this, "indoorMapOptions");
n(this, "loadMapsPromise", Promise.resolve());
n(this, "map");
n(this, "remoteMapsDownloaded");
n(this, "serverUrl");
this.serverUrl = e, this.map = t, this.indoorMapOptions = i, this.remoteMapsDownloaded = [], this.downloadedBounds = null, t.loaded() ? this.loadMapsIfNecessary() : t.on("load", () => this.loadMapsIfNecessary()), t.on("move", () => this.loadMapsIfNecessary());
}
static manage(e, t, i) {
return new G(e, ee(t), i);
}
async addCustomMap(e) {
const t = await (await fetch(e.url)).json();
e.indoorMap = z.fromGeojson(t, this.indoorMapOptions), await this.map.indoor.addMap(e.indoorMap), this.remoteMapsDownloaded.push(e);
}
async loadMapsIfNecessary() {
if (this.map.getZoom() < ce)
return;
const e = this.map.getBounds();
if (this.downloadedBounds !== null && P(
this.downloadedBounds,
e.getNorthEast().toArray()
) && P(this.downloadedBounds, e.getSouthWest().toArray()))
return;
const t = L(
e.getNorthEast().toArray(),
e.getNorthWest().toArray(),
{ units: "meters" }
), i = L(
e.getNorthEast().toArray(),
e.getSouthEast().toArray(),
{ units: "meters" }
), r = Math.max(t, i) / 2, s = Math.max(
pe,
r * 2
), a = this.map.getCenter().toArray();
console.debug(
`requested indoor maps for a bbox ${s}m vertically/horizontally around ${a}`
);
const d = s * Math.sqrt(2), l = O(a, d, 50, {
units: "meters"
}), u = [
...O(a, d, -130, {
units: "meters"
}).geometry.coordinates.reverse(),
...l.geometry.coordinates.reverse()
];
this.downloadedBounds = u, await this.loadMapsPromise, this.loadMapsPromise = this.loadMapsInBounds(u);
}
async loadMapsInBounds(e) {
const t = `${this.serverUrl}?bbox=${e[0]},${e[1]},${e[2]},${e[3]}`, i = await (await fetch(t)).json(), r = [], s = [];
for (const a of i)
i.find((d) => d.url === a.url) ? this.remoteMapsDownloaded.find((d) => d.url === a.url) || s.push(a) : r.push(a);
s.forEach(this.addCustomMap.bind(this)), r.forEach(this.removeCustomMap.bind(this));
}
async removeCustomMap(e) {
await this.map.indoor.removeMap(e.indoorMap), this.remoteMapsDownloaded.splice(this.remoteMapsDownloaded.indexOf(e), 1);
}
}
export {
se as DefaultStyle,
me as IndoorControl,
Q as IndoorLayer,
z as IndoorMap,
G as MapServerHandler,
ee as addIndoorTo
};
//# sourceMappingURL=maplibre-gl-indoor.es.js.map