Skip to content

Instantly share code, notes, and snippets.

@evanwill
Last active January 11, 2024 17:38
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save evanwill/c70a1ee888082b85f0808bb8c82d6228 to your computer and use it in GitHub Desktop.
Save evanwill/c70a1ee888082b85f0808bb8c82d6228 to your computer and use it in GitHub Desktop.
collectionbuilder map-js.html customization
{%- if site.data.theme.icons -%}{% assign icons = site.data.theme.icons %}{% else %}
{% assign cb_icons = site.pages | where: "name","cb-icons.svg" | first %}
{% assign icons = cb_icons.icons %}{%- endif -%}
{% if site.data.theme.map-child-objects == true %}
{%- assign items = site.data[site.metadata] | where_exp: 'item','item.objectid' -%}
{% else %}
{%- assign items = site.data[site.metadata] | where_exp: 'item','item.objectid' | where_exp: 'item','item.parentid == nil' -%}
{% endif %}
{% if page.location %}
{%- assign items = items | where_exp: 'item', 'item.location == page.location' -%}
{% endif %}
{%- assign items = items | where_exp: 'item', 'item.objectid != nil' | where_exp: 'item','item.latitude' -%}
{%- assign fields = site.data.config-map -%}
<!-- load leaflet dependencies -->
<script src="{{ '/assets/lib/leaflet/leaflet.js' | relative_url }}"></script>
<script src="{{ '/assets/lib/leaflet/Leaflet.fullscreen.min.js' | relative_url }}"></script>
{% if site.data.theme.map-search == true %}<script src="{{ '/assets/lib/leaflet/fuse.min.js' | relative_url }}"></script>
<script src="{{ '/assets/lib/leaflet/leaflet.fusesearch.js' | relative_url }}"></script>{% endif %}
{% if site.data.theme.map-cluster == true %}<script src="{{ '/assets/lib/leaflet/leaflet.markercluster.js' | relative_url }}"></script>{% endif %}
{% if site.data.theme.map-search == true and site.data.theme.map-cluster == true %}<script src="{{ '/assets/lib/leaflet/leaflet.markercluster.freezable.js' | relative_url }}"></script>{% endif %}
<script>
(function(){
/* add collection map data */
var geodata = { "type": "FeatureCollection", "features": [
{% for item in items %}
{ "type":"Feature", "geometry":{ "type":"Point", "coordinates":[{{ item.longitude | strip }},{{ item.latitude | strip }}] }, "properties":
{ "title": {{ item.title | jsonify }},
{% for f in fields %}{{ f.field | jsonify }}: {{ item[f.field] | jsonify }},{% endfor %}{% if item.youtubeid %} "youtube": {{ item.youtubeid | jsonify }}, {% endif %}
"format": {{ item.format | jsonify }}, {% if item.filename contains '/' %}"filename": "{{ item.filename }}" {% else %}"filename":{{ '/objects/' | relative_url | append: item.filename | jsonify }}{% endif %}, "link": "{% if item.parentid %}{{ item.parentid }}#{{ item.objectid }}{% else %}{{ item.objectid }}{% endif %}", "id": {{ item.objectid | jsonify }} } }{% unless forloop.last %}, {% endunless %}{% endfor %}
]};
/* check for url parameters and set initial view options */
let url = new URL(window.location);
var mapCenter = url.searchParams.get('location') ? url.searchParams.get('location').split(',') : [{{ page.latitude | default: site.data.theme.latitude | default: 46.727485 }}, {{ page.longitude | default: site.data.theme.longitude | default: -117.014185 }}];
var mapZoom = url.searchParams.get('location') ? 16 : {{ page.zoom | default: site.data.theme.zoom-level | default: 5 }};
var markerFilter = url.searchParams.get('marker') ? url.searchParams.get('marker') : "";
/* init map, set center and zoom */
var map = L.map('map').setView(mapCenter, mapZoom);
/* add map layer options */
var Esri_WorldStreetMap = L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer/tile/{z}/{y}/{x}', {
attribution: 'Tiles &copy; Esri &mdash; Source: Esri, DeLorme, NAVTEQ, USGS, Intermap, iPC, NRCAN, Esri Japan, METI, Esri China (Hong Kong), Esri (Thailand), TomTom, 2012'
});
var Esri_NatGeoWorldMap = L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/NatGeo_World_Map/MapServer/tile/{z}/{y}/{x}', {
attribution: 'Tiles &copy; Esri &mdash; National Geographic, Esri, DeLorme, NAVTEQ, UNEP-WCMC, USGS, NASA, ESA, METI, NRCAN, GEBCO, NOAA, iPC',
maxZoom: 16
});
var Esri_WorldImagery = L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', {
attribution: 'Tiles &copy; Esri &mdash; Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community'
});
var OpenStreetMap_Mapnik = L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
});
/* add base map switcher */
var baseMaps = {
"Esri World StreetMap": Esri_WorldStreetMap,
"Esri National Geo": Esri_NatGeoWorldMap,
"Esri Imagery": Esri_WorldImagery,
"Open Street Map": OpenStreetMap_Mapnik
};
L.control.layers(baseMaps).addTo(map);
/* load base map */
{{ site.data.theme.map-base | default: 'Esri_WorldStreetMap' }}.addTo(map);
{% if site.data.theme.map-search == true %}
/* add leaflet-fusesearch */
var options = {
title: 'Search Map Items',
locationholder: 'Search map items...',
threshold: {{ site.data.theme.map-search-fuzziness | default: 0.35 }},
showResultFct: function(feature, container) {
var result = `<strong>${feature.properties.title}</strong><br>`;
{% for f in fields %}
if(feature.properties[{{ f.field | jsonify }}]) { result += feature.properties[{{ f.field | jsonify }}] + `<br>`; }
{% endfor %}
container.innerHTML = result;
}
};
var searchCtrl = L.control.fuseSearch(options);
searchCtrl.addTo(map);
searchCtrl.indexFeatures(geodata.features, {{ fields | where: 'search','true' | map: 'field' | unshift: 'title' | jsonify }});{% endif %}
/* add fullscreen control */
map.addControl(new L.Control.Fullscreen());
{% if site.data.theme.map-cluster == true %}
/* create cluster group */
var markers = L.markerClusterGroup({
maxClusterRadius: {{ site.data.theme.map-cluster-radius | default: 15 }},
singleMarkerMode: true,
iconCreateFunction: function(cluster) {
/* custom icon function, tweak default to add more alt text */
var childCount = cluster.getChildCount();
var csize;
if (childCount < 10) {
csize = 'small';
} else if (childCount < 100) {
csize = 'medium';
} else {
csize = 'large';
}
var c = ' marker-cluster-' + csize;
return new L.DivIcon({ html: '<div><span class="visually-hidden">' + csize +' cluster of </span><span>' + childCount + '</span><span class="visually-hidden"> items</span></div>', className: 'marker-cluster' + c, iconSize: new L.Point(40, 40) });
}
{% if site.data.theme.map-search == true %}, removeOutsideVisibleBounds: false{% endif %}
});{% endif %}
/* function to create object popups */
function objectPopups(feature, layer) {
{% if site.data.theme.map-search == true %}
/* bind feature for search */
feature.layer = layer;{% endif %}
/* calculate item link */
var itemHref = '{{ "/item.html?id=" | relative_url }}' + feature.properties.link;
/* find object thumb based on format */
var thumbSrc;
if (feature.properties.youtube) {
thumbSrc = 'https://img.youtube.com/vi/' + feature.properties.youtube + '/default.jpg';
} else if (feature.properties.format && feature.properties.format.includes("image")) {
thumbSrc = feature.properties.filename;
} else if (feature.properties.format && feature.properties.format.includes("audio")) {
thumbSrc = '{{ "/assets/lib/icons/" | relative_url }}{{ icons.icon-audio }}.svg';
} else if (feature.properties.format && feature.properties.format.includes("video")) {
thumbSrc = '{{ "/assets/lib/icons/" | relative_url }}{{ icons.icon-video }}.svg';
} else if (feature.properties.format && feature.properties.format.includes("pdf")) {
thumbSrc = '{{ "/assets/lib/icons/" | relative_url }}{{ icons.icon-pdf }}.svg';
} else if (feature.properties.format && feature.properties.format.includes("compound")) {
thumbSrc = '{{ "/assets/lib/icons/" | relative_url }}{{ icons.icon-compound-object }}.svg';
} else if (feature.properties.format && feature.properties.format.includes("multiple")) {
thumbSrc = '{{ "/assets/lib/icons/" | relative_url }}{{ icons.icon-multiple }}.svg';
} else {
thumbSrc = '{{ "/assets/lib/icons/" | relative_url }}{{ icons.icon-default }}.svg';
}
/* create popup content */
var popupTemplate = '<h2 class="h4"><a class="text-dark" href="' + itemHref + '">' +
feature.properties.title + '</a></h2><div class="text-center"><a href="' + itemHref +
'" ><img class="mapthumb img-thumb" src="' + thumbSrc + '" alt="item thumbnail"></a></div><p>';
/* add metadata fields */
{% for f in fields %}{% if f.display_name %}
if (feature.properties[{{ f.field | jsonify }}]) {
popupTemplate += '<strong>{{ f.display_name }}:</strong> ' + feature.properties[{{ f.field | jsonify }}] + '<br>';
}
{% endif %}{% endfor %}
/* add object link button to popup */
popupTemplate += '</p><div class="text-center"><a class="btn btn-light" href="' + itemHref + '" >View Item</a></div>';
/* add object popup to map layer */
layer.bindPopup(popupTemplate);
}
/* function to add objects to map */
function objectMarkers(feature,latlng) {
var marker = L.marker(latlng, {alt: feature.properties.title});
{% if site.data.theme.map-cluster == true %}markers.addLayer(marker);{% endif %}
return marker;
}
/* use geoJson features to add objects to map */
var mapFeatures = L.geoJson(geodata, {
onEachFeature: objectPopups,
pointToLayer: objectMarkers
}){% if site.data.theme.map-cluster != true %}.addTo(map);{% else %};
map.addLayer(markers);{% endif %}
{% if site.data.theme.map-cluster == true and site.data.theme.map-search == true %}
/* uncluster when search is clicked */
document.querySelector('a.button').addEventListener("click", function() {
markers.disableClustering();
});
/* recluster when search is closed */
document.querySelector('a.close').addEventListener("click", function() {
markers.enableClustering();
document.querySelector('input.search-input').value = "";
});{% endif %}
/* show popup if id in URL query */
if (markerFilter != "") {
{% if site.data.theme.map-cluster == true %}
markers.eachLayer(layer => {
if (layer.feature.properties.id === markerFilter) {
/* uncluster clusters, then show */
if (markers.getVisibleParent(layer)["_childCount"]) {
markers.getVisibleParent(layer).spiderfy();
}
layer.openPopup();
}
});
{% else %}
mapFeatures.eachLayer(layer => {
if (layer.feature.properties.id === markerFilter) {
layer.openPopup();
}
});
{% endif %}
}
})();
</script>
@evanwill
Copy link
Author

a quick tweak to map-js.html to support configuration via page front matter

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment