Skip to content

Instantly share code, notes, and snippets.

@stevage
Last active April 21, 2017 04:18
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 stevage/e89f350b06d8c5a9390ca24c5b625e83 to your computer and use it in GitHub Desktop.
Save stevage/e89f350b06d8c5a9390ca24c5b625e83 to your computer and use it in GitHub Desktop.
MKW map
license: mit
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8' />
<title></title>
<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
<!-- Need these! -->
<script src="https://d3js.org/d3-collection.v1.min.js"></script>
<script src="https://d3js.org/d3-dispatch.v1.min.js"></script>
<script src="https://d3js.org/d3-dsv.v1.min.js"></script>
<script src="https://d3js.org/d3-request.v1.min.js"></script>
<script src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.36.0/mapbox-gl.js'></script>
<link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.36.0/mapbox-gl.css' rel='stylesheet' />
<!-- -->
<style>
/* This should probably go */
body { margin:0; padding:0; }
/* This one needs to be changed as appropriate for responsiveness */
#map { position:absolute; top:0; bottom:0; width:100%; }
/* From here downwards should be tweaked for MKW branding */
.mapboxgl-popup-content {
max-width: 400px;
}
.mapboxgl-popup-content img {
max-width: 80%;
}
.mapboxgl-popup-content .moreinfo {
display: block;
height:30px;
background:#00aecb;
color:white;
}
</style>
</head>
<body>
<div id='map'></div>
<script>
//http://mkw.melbourne.vic.gov.au/wp-json/wp/v2/posts?categories=1&per_page=100
//http://mkw.melbourne.vic.gov.au/wp-json/acf/v3/posts?categories=1&per_page=100
/*
TODO:
- how the hell do I geocode?
-- one off process?
-- convert json to csv, save to disk
-- load into google sheets
-- geocode
-- re-export
-- somehow import??
- tweak style so it's just big pins, no invisible titles [text titles that use a non-present text attribute]
*/
/* The main MKW site needs to call this hook whenever the filter changes
Sample values (each can be undefined for no filter)
dayFilter: "06/05/2017"
themeFilter: "Startups"
typeFilter: "Talk"
accessibilityFilter: "Wheelchair accessible"
*/
var filters = {
day: undefined,
theme: undefined,
type: undefined,
accessibility: undefined
};
function updateFilter(dayFilter, themeFilter, typeFilter, accessibilityFilter) {
//**** Replace from here...
// maintain state from previous filter updates
if (dayFilter) {
filters.day = dayFilter === 'all days' ? undefined : dayFilter;
}
if (themeFilter) {
filters.theme = themeFilter === 'all themes' ? undefined : themeFilter;
}
if (typeFilter) {
filters.type = typeFilter === 'all types' ? undefined : typeFilter;
}
if (accessibilityFilter) {
filters.accessibility = accessibilityFilter === 'all venues' ? undefined : accessibilityFilter;
}
var mapFilters = ['all'];
// now use the current state of filters to generate map filter
if (filters.day) {
mapFilters.push(['==', 'program_date',filters.day]);
}
if (filters.theme) {
mapFilters.push(['has','theme:' + filters.theme]);
}
if (filters.type) {
mapFilters.push(['has','type:' + filters.type]);
}
if (filters.accessibility) {
mapFilters.push(['has', 'accessibility:' + filters.accessibility]);
}
if (mapFilters.length === 1) {
map.setFilter('mkw-event-pins', undefined);
} else {
map.setFilter('mkw-event-pins', mapFilters);
}
// **** To here
}
function def(a, b) {
return a !== undefined ? a : b;
}
var mkwEvents = {};
function eventsToGeoJson(events) {
var mapData = {
type:'FeatureCollection',
features: []
};
Object.keys(mkwEvents).forEach(function(id) {
mapData.features.push({
type: 'Feature',
properties: mkwEvents[id],
geometry: {
type: 'Point',
// ### TODO: use actual coordinates
coordinates: [
144.85 + Math.random() * 0.2,
-37.9 + Math.random() * 0.2
]
}
});
});
console.log(mapData);
return mapData;
}
function dumpAddressesCsv(acfs) {
var rows=[];
acfs.forEach(function(acf) {
var e = acf.acf;
rows.push({
id: acf.id,
address: [e.location_address.street1, e.location_address.street2, e.location_address.city, e.location_address.state, e.location_address.zip, 'Australia'].join(' ')
});
});
console.log(d3.csvFormat(rows));
}
var metadataCount = 0;
function metadataLoaded() {
if (++metadataCount < 2)
return; // keep waiting until we have both main metadata and advanced custom fields. (Because we're not using a Promises library)
// Now we have all the metadata for every event, let's create a GeoJSON object with all of it:
var mapData = eventsToGeoJson(mkwEvents);
whenMapLoaded(function() {
// add the map data so we can style it
map.addSource('mkw-events', {
type: 'geojson',
data: mapData
});
// now add a style layer that depends on it.
map.addLayer({
id: 'mkw-event-pins',
source: 'mkw-events',
'type': 'symbol',
layout: {
'icon-image': 'marker-15',
'icon-allow-overlap': true,
'icon-size': 1
/*'text-optional': true,
'text-size': 18,
'text-font': ['CoM Regular', 'Arial Unicode MS Regular'],
'text-offset': [0,0.5],
'text-anchor': 'top',
'text-field': '{Organisation}'*/
}, paint: {
'icon-opacity': 0.72,
//'text-color': '#00aecb'
}
});
// When we click on a pin, show a popup.
map.on('click', 'mkw-event-pins', function (e) {
var event = e.features[0];
new mapboxgl.Popup()
.setLngLat(event.geometry.coordinates)
.setHTML(
'<img src="' + event.properties.hero_image + '">' +
'<h2>' + event.properties.title + '</h2>' +
event.properties.excerpt +
'<label class="dates">' + event.properties.program_date + ', ' + event.properties.event_dates_start + ' - ' + event.properties.event_dates_end + '</label>' +
'<a class="moreinfo" href="' + event.properties.link + '">More information</a>'
).addTo(map);
});
map.on('mouseenter', 'mkw-event-pins', function () {
map.getCanvas().style.cursor = 'pointer';
});
map.on('mouseleave', 'mkw-event-pins', function () {
map.getCanvas().style.cursor = '';
});
});
}
function whenMapLoaded(f) {
return map.loaded() ? f() : map.once('load', f);
}
function onLoad() {
var postsUrl = 'http://mkw.melbourne.vic.gov.au/wp-json/wp/v2/posts?categories=1&per_page=100';
var acfUrl = 'http://mkw.melbourne.vic.gov.au/wp-json/acf/v3/posts?categories=1&per_page=100';
// ### for dev/testing as the above URLs don't support CORS
postsUrl = 'https://gist.githubusercontent.com/stevage/29faffd252d62f56b71319f9281f21ce/raw/fdf485a2850bb85ce80cf2f92f9be22b20daea91/posts.json';
acfUrl = 'https://gist.githubusercontent.com/stevage/ca8d8f0b41f10882ec0fd1de04240410/raw/d39c4fd4dd7ec4bc1db63a38ec615528a144664c/posts.json';
// get JSON with main metadata about each event
d3.json(postsUrl, function(j) {
j.forEach(function(event) {
mkwEvents[event.id] = def(mkwEvents[event.id], {});
mkwEvents[event.id].id = event.id;
mkwEvents[event.id].link = event.link;
mkwEvents[event.id].title = event.title.rendered;
mkwEvents[event.id].excerpt = event.excerpt.rendered;
});
metadataLoaded();
});
// get info with advanced custom fields metadata about each event
d3.json(acfUrl, function(j) {
dumpAddressesCsv(j);
j.forEach(function(acf) {
var event = acf.acf;
mkwEvents[acf.id] = def(mkwEvents[acf.id], {});
mkwEvents[acf.id].hero_image = event.hero_image;
mkwEvents[acf.id].location = event.location;
mkwEvents[acf.id].event_dates_start = event.event_dates_start;
mkwEvents[acf.id].event_dates_end = event.event_dates_end;
mkwEvents[acf.id].program_date = event.program_date;
// We create properties like "theme:Startups", so we can filter on them with Mapbox.
def(event.theme, []).forEach(function(theme) {
mkwEvents[acf.id]['theme:' + theme] = true;
});
if (event.access !== "") {
def(event.access, []).forEach(function(accessibility) {
// "Wheelchair accessible". No auslan?
mkwEvents[acf.id]['accessibility:' + accessibility] = true;
});
}
// *** This next line had a bug.
def(event.type, []).forEach(function(type) {
mkwEvents[acf.id]['type:' + type] = true;
});
});
metadataLoaded();
});
}
mapboxgl.accessToken = 'pk.eyJ1IjoiY2l0eW9mbWVsYm91cm5lIiwiYSI6ImNpejdob2J0czAwOWQzM21ubGt6MDVqaHoifQ.55YbqeTHWMK_b6CEAmoUlA';
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/cityofmelbourne/cj1pz0q5d00382rp7zylkhxp1?update=1',
center: [144.9, -37.8],
zoom: 12
});
onLoad();
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment