Published
Edited
May 2, 2021
1 star
Insert cell
Insert cell
{
let container = html`<div style='height:600px;' />`;

let check = html`<div id='menu'>
<label class='switch-container'>
Monsters
<input id='monsters' type = 'checkbox' name='viz-toggle'>
</label>
<label class = 'switch-container'>
UFOs
<input id='ufos' type = 'checkbox' name='viz-toggle'>
</label><label class = 'switch-container'>
Ghosts
<input id='ghosts' type = 'checkbox' name='viz-toggle'>
</label>
</div>`
let content = html `<div class='map-wrapper'>
${container}
${check}
</div>`
// Give the container dimensions.
yield content;
var popup = new mapboxgl.Popup({
closeButton: false,
closeOnClick: false
});
// Create the \`map\` object with the mapboxgl.Map constructor, referencing
// the container div
let map = new mapboxgl.Map({
container,
center: [-96, 62],
zoom: 2,
style: "mapbox://styles/mapbox/dark-v10",
scrollZoom: true
});
map.on("mouseenter", "monsters", function(e) {
// Change the cursor style as a UI indicator.
map.getCanvas().style.cursor = "pointer";

var coordinates = e.features[0].geometry.coordinates.slice();
var description = e.features[0].properties.Location + " - " + e.features[0].properties.Monster;

// Ensure that if the map is zoomed out such that multiple
// copies of the feature are visible, the popup appears
// over the copy being pointed to.
while (Math.abs(e.lngLat.lng - coordinates[0]) > 180) {
coordinates[0] += e.lngLat.lng > coordinates[0] ? 360 : -360;
}

// Populate the popup and set its coordinates
// based on the feature found.
popup
.setLngLat(coordinates)
.setHTML(description)
.addTo(map);
});
map.on("mouseenter", "ghosts", function(e) {
// Change the cursor style as a UI indicator.
map.getCanvas().style.cursor = "pointer";

var coordinates = e.features[0].geometry.coordinates.slice();
var description = e.features[0].properties.Location + " - " + e.features[0].properties.City;

// Ensure that if the map is zoomed out such that multiple
// copies of the feature are visible, the popup appears
// over the copy being pointed to.
while (Math.abs(e.lngLat.lng - coordinates[0]) > 180) {
coordinates[0] += e.lngLat.lng > coordinates[0] ? 360 : -360;
}

// Populate the popup and set its coordinates
// based on the feature found.
popup
.setLngLat(coordinates)
.setHTML(description)
.addTo(map);
});
map.on("mouseenter", "ufos", function(e) {
// Change the cursor style as a UI indicator.
map.getCanvas().style.cursor = "pointer";

var coordinates = e.features[0].geometry.coordinates.slice();
var description = e.features[0].properties.Location + " - " + e.features[0].properties.Year;

// Ensure that if the map is zoomed out such that multiple
// copies of the feature are visible, the popup appears
// over the copy being pointed to.
while (Math.abs(e.lngLat.lng - coordinates[0]) > 180) {
coordinates[0] += e.lngLat.lng > coordinates[0] ? 360 : -360;
}
popup
.setLngLat(coordinates)
.setHTML(description)
.addTo(map);
});
map.on("mouseleave", "monsters", function() {
map.getCanvas().style.cursor = "";
popup.remove();
});
map.on("mouseleave", "ufos", function() {
map.getCanvas().style.cursor = "";
popup.remove();
});
map.on("mouseleave", "ghosts", function() {
map.getCanvas().style.cursor = "";
popup.remove();
});

map.on('load',function(){
map.addLayer({
id: 'ufos',
type: 'circle',
source: {
type: 'geojson',
data: ufos
},
layout:{
visibility: "none"
},
paint:{
'circle-radius':5,
'circle-color':'#AA0000'
}
});
map.addLayer({
id: 'monsters',
type: 'circle',
source: {
type: 'geojson',
data: monsters
},
layout:{
visibility: "none"
},
paint:{
'circle-radius':5,
'circle-color':'#00AA00'
}
});
map.addLayer({
id: 'ghosts',
type: 'circle',
source: {
type: 'geojson',
data: ghosts
},
layout:{
visibility: "none"
},
paint:{
'circle-radius':5,
'circle-color':'#FFFFFF'
}
});
function switchLayer(layer) {
var clickedLayer = layer.target.id; // get the label of the layer
var visibility = map.getLayoutProperty(clickedLayer, "visibility"); // check whether the layer is visible
if (visibility === "visible") {
hideLayer(clickedLayer);
} else {
showLayer(clickedLayer);
}
}

function hideLayer(clickedLayer) {
map.setLayoutProperty(clickedLayer, "visibility", "none");
}

function showLayer(clickedLayer) {
map.setLayoutProperty(clickedLayer, "visibility", "visible");
}
// attach listener to all checkboxes
var layerList = document.getElementById("menu");
var checkboxes = layerList.getElementsByTagName("input");
for (var i = 0; i < checkboxes.length; i++) {
checkboxes[i].onclick = switchLayer;
}
// Be careful to clean up the map's resources using map.remove() whenever
// this cell is re-evaluated.
invalidation.then(() => map.remove());
})
map.addControl(new mapboxgl.NavigationControl(), "top-right");
}
Insert cell
html`<style>
.labeled::after {
margin-left: 2em;
white-space: nowrap;
content: attr(aria-label);
}

body {
margin: 0;
padding: 0;
}

.map-wrapper {
position: relative;
width: 100%;
height: 100%;
}

#map {
position: absolute;
top: 0;
bottom: 0;
width: 100%;
height: 100%;
}

.filter-ctrl {
position: absolute;
top: 10px;
right: 100px;
z-index: 1;
width: 180px;
}

.filter-ctrl input[type="text"] {
font: 12px/20px "Helvetica Neue", Arial, Helvetica, sans-serif;
width: 100%;
border: 0;
background-color: #fff;
height: 30px;
margin: 0;
color: rgba(0, 0, 0, 0.5);
padding: 10px;
box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.1);
border-radius: 3px;
}

#menu {
font: 12px/20px "Helvetica Neue", Arial, Helvetica, sans-serif;
position: absolute;
top: 10px;
right: 50px;
display: flex;
border-radius: 3px;
background-color: rgb(255, 255, 255);
padding: 10px;
z-index: 10;
display: flex;
flex-flow: column;
justify-content: space-between;
}

.switch-container {
display: flex;
flex-flow: row;
justify-content: space-between;
}

.switch {
margin-left: 30px;
}
</style>`
Insert cell
mapboxgl = {
const gl = await require("mapbox-gl@1.1.0");
if (!gl.accessToken) {
gl.accessToken = "pk.eyJ1IjoicDQyc3lzdGVtcyIsImEiOiJja28wb3RueWcwMmhhMnFvaWluaG42YmUwIn0.WhzHen_b1czWG-uC5d88cQ";
const href = await require.resolve("mapbox-gl@1.0.0/dist/mapbox-gl.css");
document.head.appendChild(html`<link href=${href} rel=stylesheet>`);
}
return gl;
}
Insert cell
monsters = FileAttachment("monsters@1.json").json()
Insert cell
Insert cell
ghosts = FileAttachment("ghosts.geo@1.json").json()
Insert cell

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more