Skip to content

Instantly share code, notes, and snippets.

@dimaslanjaka
Created May 14, 2021 06:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dimaslanjaka/df43624980171c0979fea59443890844 to your computer and use it in GitHub Desktop.
Save dimaslanjaka/df43624980171c0979fea59443890844 to your computer and use it in GitHub Desktop.
MapBox Example
body { margin:0; padding:0; }
#map { position:absolute; top:0; bottom:0; width:100%; }
#map {
position:absolute;
left:25%;
top:0;
bottom:0;
width: 75%;
}
.map-overlay {
position: absolute;
width: 25%;
top: 0;
bottom: 0;
left: 0;
font: 12px/20px 'Helvetica Neue', Arial, Helvetica, sans-serif;
background-color: #fff;
max-height: 100%;
overflow: hidden;
}
.map-overlay fieldset {
display: none;
background: #ddd;
border: none;
padding: 10px;
margin: 0;
}
.map-overlay input {
display: block;
border: none;
width: 100%;
border-radius: 3px;
padding: 10px;
margin: 0;
}
.map-overlay .listing {
overflow: auto;
max-height: 100%;
}
.map-overlay .listing > * {
display: block;
padding: 5px 10px;
margin: 0;
}
.map-overlay .listing a {
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
color: #404;
text-decoration: none;
}
.map-overlay .listing a:last-child {
border: none;
}
.map-overlay .listing a:hover {
background: #f0f0f0;
}
<script src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.35.1/mapbox-gl.js'></script>
<link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.35.1/mapbox-gl.css' rel='stylesheet' />
<link href='main.css' rel='stylesheet' />
<script src='main.js' async></script>
<div id='map'></div>
<div class='map-overlay'>
<fieldset>
<input id='feature-filter' type='text' placeholder='Filter results by name' />
</fieldset>
<div id='feature-listing' class='listing'></div>
</div>
mapboxgl.accessToken = 'pk.eyJ1IjoiZGltYXNsYW5qYWthIiwiYSI6ImNrb254eDM4MzAxejgyd3F4bDF1aWhycGkifQ.lWod7dsXeO47iINNB05iew';
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/streets-v9',
center: [-98, 38.88],
maxZoom: 5,
minZoom: 1,
zoom: 3
});
// Holds visible airport features for filtering
var airports = [];
// Create a popup, but don't add it to the map yet.
var popup = new mapboxgl.Popup({
closeButton: false
});
var filterEl = document.getElementById('feature-filter');
var listingEl = document.getElementById('feature-listing');
function renderListings(features) {
// Clear any existing listings
listingEl.innerHTML = '';
if (features.length) {
features.forEach(function(feature) {
var prop = feature.properties;
var item = document.createElement('a');
item.href = prop.wikipedia;
item.target = '_blank';
item.textContent = prop.name + ' (' + prop.abbrev + ')';
item.addEventListener('mouseover', function() {
// Highlight corresponding feature on the map
popup.setLngLat(feature.geometry.coordinates)
.setText(feature.properties.name + ' (' + feature.properties.abbrev + ')')
.addTo(map);
});
listingEl.appendChild(item);
});
// Show the filter input
filterEl.parentNode.style.display = 'block';
} else {
var empty = document.createElement('p');
empty.textContent = 'Drag the map to populate results';
listingEl.appendChild(empty);
// Hide the filter input
filterEl.parentNode.style.display = 'none';
// remove features filter
map.setFilter('airport', ['has', 'abbrev']);
}
}
function normalize(string) {
return string.trim().toLowerCase();
}
function getUniqueFeatures(array, comparatorProperty) {
var existingFeatureKeys = {};
// Because features come from tiled vector data, feature geometries may be split
// or duplicated across tile boundaries and, as a result, features may appear
// multiple times in query results.
var uniqueFeatures = array.filter(function(el) {
if (existingFeatureKeys[el.properties[comparatorProperty]]) {
return false;
} else {
existingFeatureKeys[el.properties[comparatorProperty]] = true;
return true;
}
});
return uniqueFeatures;
}
map.on('load', function() {
map.addLayer({
"id": "airport",
"source": {
"type": "vector",
"url": "mapbox://mapbox.04w69w5j"
},
"source-layer": "ne_10m_airports",
"type": "symbol",
"layout": {
"icon-image": "airport-15",
"icon-padding": 0,
"icon-allow-overlap":true
}
});
map.on('moveend', function() {
var features = map.queryRenderedFeatures({layers:['airport']});
if (features) {
var uniqueFeatures = getUniqueFeatures(features, "iata_code");
// Populate features for the listing overlay.
renderListings(uniqueFeatures);
// Clear the input container
filterEl.value = '';
// Store the current features in sn `airports` variable to
// later use for filtering on `keyup`.
airports = uniqueFeatures;
}
});
map.on('mousemove', 'airport', function(e) {
// Change the cursor style as a UI indicator.
map.getCanvas().style.cursor = 'pointer';
// Populate the popup and set its coordinates based on the feature.
var feature = e.features[0];
popup.setLngLat(feature.geometry.coordinates)
.setText(feature.properties.name + ' (' + feature.properties.abbrev + ')')
.addTo(map);
});
map.on('mouseleave', 'airport', function() {
map.getCanvas().style.cursor = '';
popup.remove();
});
filterEl.addEventListener('keyup', function(e) {
var value = normalize(e.target.value);
// Filter visible features that don't match the input value.
var filtered = airports.filter(function(feature) {
var name = normalize(feature.properties.name);
var code = normalize(feature.properties.abbrev);
return name.indexOf(value) > -1 || code.indexOf(value) > -1;
});
// Populate the sidebar with filtered results
renderListings(filtered);
// Set the filter to populate features into the layer.
map.setFilter('airport', ['in', 'abbrev'].concat(filtered.map(function(feature) {
return feature.properties.abbrev;
})));
});
// Call this function on initialization
// passing an empty array to render an empty state
renderListings([]);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment