Skip to content

Instantly share code, notes, and snippets.

@dshook
Last active August 29, 2015 14:06
Show Gist options
  • Save dshook/5abcc10d330a2b6f6caf to your computer and use it in GitHub Desktop.
Save dshook/5abcc10d330a2b6f6caf to your computer and use it in GitHub Desktop.
Leaflet map javascript
var map = null;
var zipLayer = null;
var resultStats = {
min: 0,
max: 0,
mean: 0,
variance: 0,
deviation: 0
};
var colorFunc = null; //the current function based on the dropdown
var apiResults = null; //last results we received
//load in the map if not already loaded, center the map on a selected point
//and set up the events/layers
initMap = function () {
clearError();
//get the center point of the map based on external parameters
$.ajax({
url: '/api/GetMapCenter'
}).done(function (results) {
if (map === null) {
map = L.map('map');
//add drag event that only happens every so often
var throttledDrag = _.throttle(dragEnd, 1500, { leading: false });
map.on('dragend', throttledDrag);
map.on('zoomend', throttledDrag);
L.tileLayer(
//'http://{s}.tile.osm.org/{z}/{x}/{y}.png', //another b&w tile server that stopped working for a bit
'http://{s}.tile.stamen.com/toner/{z}/{x}/{y}.png',
{
attribution: '&copy; <a href="http://openstreetmap.org">OpenStreetMap</a> Contributors',
maxZoom: 18,
minZoom: 8
}
).addTo(map);
}
map.setView([results.latitude, results.longitude], 11);
//add center marker
L.marker([results.latitude, results.longitude], { title: 'Tunnel' })
.addTo(map);
fetchData();
}).fail(function (jqXHR, textStatus) {
tunnelData.errorLoading(jqXHR, textStatus);
});
}
var loading = false;
function showLoader() {
var html = '<h5>Loading</h5>'
+ '<div class="control-group span12 pagination-centered" style="font-weight:300; padding:1em 0 1em 0;">'
+ '<i class="icon-spinner icon-spin orange"></i> Loading Lots of Zip Data, please be patient...'
+ '</div>';
$('#map-loader').html(html);
loading = true;
}
function killLoader() {
$('#map-loader').empty();
loading = false;
}
//create the popup loaded with info on hover over a zip
function popup(feature, layer) {
if (feature.properties && feature.properties.zip) {
(function (layer, feature) {
var properties = feature.properties;
// Create a mouseover event
layer.on("mouseover", function (e) {
// Change the style to the highlighted version
layer.setStyle(zipHighlightStyle(feature));
// Create a popup with a unique ID linked to this record
var popup = $("<div></div>", {
id: "popup-" + properties.zip,
class: 'map-popup',
css: {
position: "absolute",
bottom: "10px",
left: "10px",
zIndex: 1002,
backgroundColor: "white",
padding: "8px",
border: "1px solid #ccc"
}
});
var content = '<div>';
content += '<h5><b>' + properties.zip + '</b></h5>';
content += '<p>Revenue ' + numeral(properties.rev).format('$0,0') + '</p>';
content += '<p>Quantity ' + numeral(properties.qty).format('0') + '</p>';
content += '<p>Population ' + numeral(properties.pop).format('0,0') + '</p>';
content += '<p>' + numeral(properties.home_pct_own / 100).format('0.0%') + ' own, ' +
numeral(properties.home_pct_rent / 100).format('0.0%') + ' rent </p>';
content += '<p>Median Age ' + properties.mAge + '</p>';
content += '<p>Median Income ' + numeral(properties.mInc).format('$0,0') + '</p>';
content += '<p>Color Function ' + numeral(colorFunc(properties)).format('0,0.00') + '</p>';
content += '<p>Age Breakdown</p>';
//histogram
content += '<div id="age-graph"><ul>';
content += '<li>' + properties.age_pct_0_19 + ':0-19</li>';
content += '<li>' + properties.age_pct_20_39 + ':20-39</li>';
content += '<li>' + properties.age_pct_40_59 + ':40-59</li>';
content += '<li>' + properties.age_pct_60_79 + ':60-79</li>';
content += '<li>' + properties.age_pct_80_over + ':>=80</li>';
content += '</ul></div>';
content += '</div><div id="age-labels"></div>';
var hed = $(content, { css: { fontSize: "16px", marginBottom: "3px" } })
.appendTo(popup);
popup.appendTo("#map");
makeGraph();
});
// Create a mouseout event that undoes the mouseover changes
layer.on("mouseout", function (e) {
layer.setStyle(zipStyle(feature));
$(".map-popup").remove();
});
})(layer, feature);
}
}
function makeGraph() {
var container = document.getElementById("age-graph");
var labels = document.getElementById("age-labels");
var dnl = container.getElementsByTagName("li");
for (var i = 0; i < dnl.length; i++) {
var item = dnl.item(i);
var innerHtml = item.innerHTML;
var content = innerHtml.split(":");
var value = content[0];
var label = content[1];
item.style.height = value + "%";
var leftOffset = (i * 40 + 20) + "px";
labels.innerHTML = labels.innerHTML +
'<span style="position:absolute;top:-16px;left:' + leftOffset + '">' + label + '</span>';
item.style.left = leftOffset;
item.innerHTML = value;
item.style.visibility = "visible";
}
}
function dragEnd(distance) {
fetchData();
}
var colorFunctions = {
rev: function (properties) {
return properties.rev;
},
revPerPop: function (properties) {
return properties.pop == 0 ?
0 :
properties.rev / properties.pop;
},
popPerRev: function (properties) {
return properties.rev == 0 ?
0 :
properties.pop / properties.rev;
},
medInc: function (properties) {
return properties.mInc;
},
medIncPerRev: function (properties) {
return properties.rev == 0 ?
0 :
properties.mInc / properties.rev;
},
qty: function (properties) {
return properties.qty;
},
totMoney: function (properties) {
return properties.mInc * properties.pop;
}
};
//determine the right color for a feature given its properties
function zipStyle(feature) {
var colorArray = [
'#5D16DA',
'#2F14D9',
'#1325D8',
'#1250D7',
'#117CD6',
'#0FA7D5',
'#0ED3D4',
'#0DD3A6',
'#0CD278',
'#0BD14A',
'#09D01C',
'#22CF08',
'#4ECE07',
'#7ACD06',
'#A6CC05',
'#CBC304',
'#CA9503',
'#C96702',
'#C83901',
'#C70A00',
];
//color values that want it
var colorRange = [];
for (var i = 1; i <= colorArray.length; i++) {
colorRange.push(i);
}
var colorFunc = colorFunctions[$('#map-color').val()];
var val = colorFunc(feature.properties);
var domainStart = Math.max(resultStats.mean - (2 * resultStats.deviation), 0);
var domainEnd = resultStats.mean + (2 * resultStats.deviation);
var bucketFunc = d3.scale.quantize().domain([domainStart, domainEnd]).range(colorRange);
//no color for you 0's
if (val == 0) {
return {
'color': '#888888',
'weight': 2,
'opacity': 0.8
};
}
var assignedBucket = bucketFunc(val);
return {
'color': colorArray[assignedBucket - 1],
'weight': 2,
'opacity': 0.8
};
}
function zipHighlightStyle(feature) {
var defStyle = zipStyle(feature);
defStyle.opacity = 1;
defStyle.weight = 5;
return defStyle;
}
//get the zip geoJSON data from the server
function fetchData() {
//don't load data with an outstanding request
if (loading) {
return;
}
clearError();
showLoader();
var mapCenter = map.getCenter();
var mapBounds = map.getBounds();
var params = {
latitude: mapCenter.lat,
longitude: mapCenter.lng,
NELat: mapBounds._northEast.lat,
NELng: mapBounds._northEast.lng,
SWLat: mapBounds._southWest.lat,
SWLng: mapBounds._southWest.lng,
extraFilterParametersYouShoulPass: null
};
$.ajax({
url: '/api/Map?' + $.param(params)
}).done(function (results) {
killLoader();
apiResults = results;
displayResults(apiResults);
}).fail(function (jqXHR, textStatus) {
errorLoading(jqXHR, textStatus);
killLoader();
});
}
//update the map once we have geoJSON data
function displayResults(results) {
//remove last zips
if (zipLayer !== null) {
map.removeLayer(zipLayer);
}
colorFuncChange();
calcMinMax(results.geoData.features);
zipLayer = L.geoJson(results.geoData, {
onEachFeature: popup,
style: zipStyle
});
zipLayer.addTo(map);
}
//calculate statistics about the data given our coloring function
function calcMinMax(features) {
var colorFuncVals = _.map(features, function (feature) {
return colorFunc(feature.properties);
});
var stats = calcStats(colorFuncVals);
stats.min = _.min(colorFuncVals);
stats.max = _.max(colorFuncVals);
resultStats = stats;
}
function calcStats(a) {
var r = { mean: 0, variance: 0, deviation: 0 }, t = a.length;
for (var m, s = 0, l = t; l--; s += a[l]);
for (m = r.mean = s / t, l = t, s = 0; l--; s += Math.pow(a[l] - m, 2));
return r.deviation = Math.sqrt(r.variance = s / t), r;
}
function colorFuncChange() {
colorFunc = colorFunctions[$('#map-color').val()];
}
$(function () {
$('#map-color').on('change', function (el) {
displayResults(apiResults);
});
initMap();
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment