Public
Edited
Aug 17, 2024
Importers
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
_EMCdata.RouteData.SydneySuburban
Insert cell
Insert cell
Insert cell
_MapLibre = {
return class {
attach = null;
map = null;
resized = false;
id = DOM.uid("map");

opts = {
height: 500, // anything under 200 is kinda weird
theme: "light", // light, dark, black, white, grayscale, debug
center: [151.21645331382751, -33.85481594764607], // centered on sydney
zoom: 12 // default zoom
};

tileconfig = {
glyphs: "https://cdn.protomaps.com/fonts/pbf/{fontstack}/{range}.pbf",
tiles:
"https://api.protomaps.com/tiles/v2/{z}/{x}/{y}.pbf?key=f5d904b825555256",
attribution: htl.html`
<a>Zoom: <span id="${this.id.id}">0</span></a> |
<a href="https://protomaps.com/">Protomaps</a> |
<a href="https://www.openstreetmap.org/copyright/">OpenStreetMap</a> |
<a href="https://electronicmobilityco.dev/"><strong>Electronic Mobility Co</strong> ↗</a>`
};
ids = {
ctx: DOM.uid("MapLibre-ctx")
};
constructor(optsIn) {
this.opts = Object.assign(this.opts, optsIn);
const MapDom = this.DomInitMapElements();
this.map = new _Imports.Mapping.MapLibreGL.Map({
container: MapDom,
style: this.ProtomapsStyle(),
center: this.opts.center,
zoom: this.opts.zoom
});
this.map.on("render", () => {
document.querySelector(`#${this.id.id}`).innerText =
Math.round(this.map.getZoom() * 100) / 100;
if (this.resized == false) {
this.map.resize();
this.resized = true;
}
});
this.map.on("zoom", () => {
document.querySelector(`#${this.id.id}`).innerText =
Math.round(this.map.getZoom() * 100) / 100;
});
}
ProtomapsStyle() {
return {
version: 8,
glyphs: this.tileconfig.glyphs,
sources: {
protomaps: {
type: "vector",
tiles: [this.tileconfig.tiles],
attribution: "",
minzoom: 0,
maxzoom: 14
}
},
layers: _Imports.Mapping.ProtomapsLayers.default(
"protomaps",
this.opts.theme
)
};
}
DomInitMapElements() {
const styles = {
".w": `height:${this.opts.height}px;max-width:${width}px;width:${width}px;border-radius:5px;overflow:hidden;position:relative;`,
".c": `height:${
this.opts.height - 10
}px;max-width:${width}px;width:${width}px;border-radius:5px;overflow:hidden;background:#80deea;`,
".t": `position:absolute;bottom:15px;right:5px;height:max-content;display:flex;flex-flow:row;max-width:calc(100% - 20px);align-items:center;background-color:#ffffff;padding:2px 5px;border-radius:2.5px;font-variant-numeric:tabular-nums;`
};
const StyleBlock = () => {
const blocks = [];
for (const sel in styles) {
const selstr = sel
.split(",")
.map(
(s) =>
`[data-ctx="${this.ids.ctx.id}"] ${s},[data-ctx="${this.ids.ctx.id}"]${s}`
)
.join(",");
blocks.push(`${selstr} {${styles[sel]}}`);
}
return htl.html`<style>${blocks.join(" ")}</style>`;
};
const MapContainer = htl.html`<div class="c r p">`;
const MapAttribution = htl.html`<figcaption class="t">${this.tileconfig.attribution}</figcaption>`;
const ElementWrapper = htl.html`
<figure class="w" data-ctx="${this.ids.ctx.id}">
${MapContainer}${MapAttribution}${StyleBlock()}
</figure>`;
this.attach = ElementWrapper;
return MapContainer;
}
AddDataSource(id, data) {
const af = () => {
this.map.addSource(id, {
type: "geojson",
data: data
});
};
if (this.map.loaded()) af();
else this.map.on("load", af);
}
AddMapPolygon(id, source, color, opacity) {
const af = () => {
this.map.addLayer({
id: id,
type: "fill",
source: source,
layout: {},
paint: {
"fill-color": color,
"fill-opacity": opacity || 1
}
});
};
if (this.map.loaded()) af();
else this.map.on("load", af);
}
AddMapLine(id, source, color, width, opacity) {
const af = () => {
this.map.addLayer({
id: id,
type: "line",
source: source,
layout: {},
paint: {
"line-color": color,
"line-opacity": opacity || 1,
"line-width": width || 2
}
});
};
if (this.map.loaded()) af();
else this.map.on("load", af);
}
AddMapPoint(id, source, color, width, opacity) {
const af = () => {
this.map.addLayer({
id: id,
type: "circle",
source: source,
layout: {},
paint: {
"circle-color": color,
"circle-opacity": opacity || 1,
"circle-radius": width || 2
}
});
};
if (this.map.loaded()) af();
else this.map.on("load", af);
}
kill() {
try {
this.map.remove();
} catch (e) {}
}
};
}
Insert cell
Insert cell
Insert cell
viewof MapLibre_Demo = {
const map = new _MapLibre({
height: MapLibre_DemoControls.height,
theme: MapLibre_DemoControls.theme,
zoom: MapLibre_DemoControls.zoom
});
yield map.attach;
invalidation.then(() => map.kill());
}
Insert cell
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more