Published
Edited
Apr 9, 2022
Fork of Map
1 fork
Importers
2 stars
Insert cell
Insert cell
Insert cell
map({
type: "FeatureCollection",
features: [
{
type: "Feature",
properties: { style: { color: "#ff0000", fillOpacity: 0.2 } },
geometry: {
type: "Polygon",
coordinates: [
[
[-104.05, 48.99],
[-97.22, 48.98],
[-96.58, 45.94],
[-104.03, 45.94],
[-104.05, 48.99]
]
]
}
},
{
type: "Feature",
properties: { style: { color: "#0000ff", dashArray: "5,3,2" } },
geometry: {
type: "Polygon",
coordinates: [
[
[-109.05, 41.0],
[-102.06, 40.99],
[-102.03, 36.99],
[-109.04, 36.99],
[-109.05, 41.0]
]
]
}
}
]
})
Insert cell
Insert cell
map(
{
type: "Feature",
geometry: { type: "Point", coordinates: [7.0858402, 50.72769] },
properties: { hi: "There" }
},
{
height: 400,
tileURL: "https://stamen-tiles.a.ssl.fastly.net/toner/{z}/{x}/{y}.png",
attribution:
'Map tiles by <a href="http://stamen.com">Stamen Design</a>, under <a href="http://creativecommons.org/licenses/by/3.0">CC BY 3.0</a>. Data by <a href="http://openstreetmap.org">OpenStreetMap</a>, under <a href="http://www.openstreetmap.org/copyright">ODbL</a>.'
}
)
Insert cell
map(undefined, {
center: [40.086, 13.447],
zoom: 5,
width: 600,
tileURL: 'https://stamen-tiles.a.ssl.fastly.net/watercolor/{z}/{x}/{y}.png',
attribution:
'Map tiles by <a href="http://stamen.com">Stamen Design</a>, under <a href="http://creativecommons.org/licenses/by/3.0">CC BY 3.0</a>. Data by <a href="http://openstreetmap.org">OpenStreetMap</a>, under <a href="http://creativecommons.org/licenses/by-sa/3.0">CC BY SA</a>.'
})
Insert cell
Insert cell
function* map(geojson, options = {}) {
if (!options.tileURL)
options.tileURL = "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png";
document.head.appendChild(
html`<link id=leaflet-sheet href='${resolve(
"leaflet@1.7.1/dist/leaflet.css"
)}' rel='stylesheet' />`
);
// You'll often see Leaflet examples initializing a map like L.map('map'),
// which tells the library to look for a div with the id 'map' on the page.
// In Observable, we instead create a div from scratch in this cell, so it's
// completely self-contained.
const displayWidth = options.width || width;
const displayHeight = options.height || displayWidth / 1.6;

let container = html`<div style='width:${displayWidth}px;height:${displayHeight}px'></div>`;

// Note that I'm yielding the container pretty early here: this allows the
// div to be placed on the page. This is important, because Leaflet uses
// the div's .offsetWidth and .offsetHeight to size the map. If I were
// to only return the container at the end of this method, Leaflet might
// get the wrong idea about the map's size.
yield container;

let map = L.map(container);
// Now we create a map object and add a layer to it.
if (geojson) {
// In case an array of featuers was passed, we convert it to a GeoJSON
// feature collection first
if (Array.isArray(geojson)) {
geojson = { type: "FeatureCollection", features: geojson };
}

function onEachFeature(feature, layer) {
// by default, we try to beautify the properties object
// this may be switched off by passing stringifyProps: true in the
// options
if (feature.properties) {
if (options.stringifyProps) {
layer.bindPopup(
html`<pre style='max-width:200px;max-height:300px;overflow:auto'>${JSON.stringify(
feature.properties,
null,
2
)}</pre>`
);
} else {
const popupString = Object.keys(feature.properties).reduce(
(str, prop) => {
let value = feature.properties[prop];
if (typeof feature.properties[prop] === "object") {
value = JSON.stringify(feature.properties[prop], null, 2);
}
return (str += `${prop}: ${value}\n`);
},
""
);
layer.bindPopup(
html`<pre style='max-width:200px;max-height:300px;overflow:auto'>${popupString}</pre>`
);
}
}
}

function style(feature) {
if (feature.properties) {
return feature.properties.style;
}
}

let gj = L.geoJson(geojson, {
onEachFeature,
style
}).addTo(map);
// gj.eachLayer;
map.fitBounds(gj.getBounds());

if (
!geojson.features ||
(geojson.features && geojson.features.length === 1)
) {
map.eachLayer(function (layer) {
layer.openPopup();
});
}
} else {
const center = options.center || [0, 0];
const zoom = options.zoom || 3;
map.setView(center, zoom);
}
container.value = map;
let osmLayer = L.tileLayer(options.tileURL, {
attribution:
options.attribution ||
'&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);
}
Insert cell
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