Use heatmap.js to see the Spanish gas stations that serve gasolina95 over 1.3€/litre.
Gas station price list last updated on 7-mars 2015.
Data from geoportalgasolineras.es.
Use heatmap.js to see the Spanish gas stations that serve gasolina95 over 1.3€/litre.
Gas station price list last updated on 7-mars 2015.
Data from geoportalgasolineras.es.
/* | |
* heatmap.js v2.0.0 | JavaScript Heatmap Library | |
* | |
* Copyright 2008-2014 Patrick Wied <heatmapjs@patrick-wied.at> - All rights reserved. | |
* Dual licensed under MIT and Beerware license | |
* | |
* :: 2014-10-31 21:16 | |
*/ | |
(function(a,b,c){if(typeof module!=="undefined"&&module.exports){module.exports=c()}else if(typeof define==="function"&&define.amd){define(c)}else{b[a]=c()}})("h337",this,function(){var a={defaultRadius:40,defaultRenderer:"canvas2d",defaultGradient:{.25:"rgb(0,0,255)",.55:"rgb(0,255,0)",.85:"yellow",1:"rgb(255,0,0)"},defaultMaxOpacity:1,defaultMinOpacity:0,defaultBlur:.85,defaultXField:"x",defaultYField:"y",defaultValueField:"value",plugins:{}};var b=function h(){var b=function d(a){this._coordinator={};this._data=[];this._radi=[];this._min=0;this._max=1;this._xField=a["xField"]||a.defaultXField;this._yField=a["yField"]||a.defaultYField;this._valueField=a["valueField"]||a.defaultValueField;if(a["radius"]){this._cfgRadius=a["radius"]}};var c=a.defaultRadius;b.prototype={_organiseData:function(a,b){var d=a[this._xField];var e=a[this._yField];var f=this._radi;var g=this._data;var h=this._max;var i=this._min;var j=a[this._valueField]||1;var k=a.radius||this._cfgRadius||c;if(!g[d]){g[d]=[];f[d]=[]}if(!g[d][e]){g[d][e]=j;f[d][e]=k}else{g[d][e]+=j}if(g[d][e]>h){if(!b){this._max=g[d][e]}else{this.setDataMax(g[d][e])}return false}else{return{x:d,y:e,value:j,radius:k,min:i,max:h}}},_unOrganizeData:function(){var a=[];var b=this._data;var c=this._radi;for(var d in b){for(var e in b[d]){a.push({x:d,y:e,radius:c[d][e],value:b[d][e]})}}return{min:this._min,max:this._max,data:a}},_onExtremaChange:function(){this._coordinator.emit("extremachange",{min:this._min,max:this._max})},addData:function(){if(arguments[0].length>0){var a=arguments[0];var b=a.length;while(b--){this.addData.call(this,a[b])}}else{var c=this._organiseData(arguments[0],true);if(c){this._coordinator.emit("renderpartial",{min:this._min,max:this._max,data:[c]})}}return this},setData:function(a){var b=a.data;var c=b.length;this._data=[];this._radi=[];for(var d=0;d<c;d++){this._organiseData(b[d],false)}this._max=a.max;this._min=a.min||0;this._onExtremaChange();this._coordinator.emit("renderall",this._getInternalData());return this},removeData:function(){},setDataMax:function(a){this._max=a;this._onExtremaChange();this._coordinator.emit("renderall",this._getInternalData());return this},setDataMin:function(a){this._min=a;this._onExtremaChange();this._coordinator.emit("renderall",this._getInternalData());return this},setCoordinator:function(a){this._coordinator=a},_getInternalData:function(){return{max:this._max,min:this._min,data:this._data,radi:this._radi}},getData:function(){return this._unOrganizeData()}};return b}();var c=function i(){var a=function(a){var b=a.gradient||a.defaultGradient;var c=document.createElement("canvas");var d=c.getContext("2d");c.width=256;c.height=1;var e=d.createLinearGradient(0,0,256,1);for(var f in b){e.addColorStop(f,b[f])}d.fillStyle=e;d.fillRect(0,0,256,1);return d.getImageData(0,0,256,1).data};var b=function(a,b){var c=document.createElement("canvas");var d=c.getContext("2d");var e=a;var f=a;c.width=c.height=a*2;if(b==1){d.beginPath();d.arc(e,f,a,0,2*Math.PI,false);d.fillStyle="rgba(0,0,0,1)";d.fill()}else{var g=d.createRadialGradient(e,f,a*b,e,f,a);g.addColorStop(0,"rgba(0,0,0,1)");g.addColorStop(1,"rgba(0,0,0,0)");d.fillStyle=g;d.fillRect(0,0,2*a,2*a)}return c};var c=function(a){var b=[];var c=a.min;var d=a.max;var e=a.radi;var a=a.data;var f=Object.keys(a);var g=f.length;while(g--){var h=f[g];var i=Object.keys(a[h]);var j=i.length;while(j--){var k=i[j];var l=a[h][k];var m=e[h][k];b.push({x:h,y:k,value:l,radius:m})}}return{min:c,max:d,data:b}};function d(b){var c=b.container;var d=this.shadowCanvas=document.createElement("canvas");var e=this.canvas=b.canvas||document.createElement("canvas");var f=this._renderBoundaries=[1e4,1e4,0,0];var g=getComputedStyle(b.container)||{};e.className="heatmap-canvas";this._width=e.width=d.width=+g.width.replace(/px/,"");this._height=e.height=d.height=+g.height.replace(/px/,"");this.shadowCtx=d.getContext("2d");this.ctx=e.getContext("2d");e.style.cssText=d.style.cssText="position:absolute;left:0;top:0;";c.style.position="relative";c.appendChild(e);this._palette=a(b);this._templates={};this._setStyles(b)}d.prototype={renderPartial:function(a){this._drawAlpha(a);this._colorize()},renderAll:function(a){this._clear();this._drawAlpha(c(a));this._colorize()},_updateGradient:function(b){this._palette=a(b)},updateConfig:function(a){if(a["gradient"]){this._updateGradient(a)}this._setStyles(a)},setDimensions:function(a,b){this._width=a;this._height=b;this.canvas.width=this.shadowCanvas.width=a;this.canvas.height=this.shadowCanvas.height=b},_clear:function(){this.shadowCtx.clearRect(0,0,this._width,this._height);this.ctx.clearRect(0,0,this._width,this._height)},_setStyles:function(a){this._blur=a.blur==0?0:a.blur||a.defaultBlur;if(a.backgroundColor){this.canvas.style.backgroundColor=a.backgroundColor}this._opacity=(a.opacity||0)*255;this._maxOpacity=(a.maxOpacity||a.defaultMaxOpacity)*255;this._minOpacity=(a.minOpacity||a.defaultMinOpacity)*255;this._useGradientOpacity=!!a.useGradientOpacity},_drawAlpha:function(a){var c=this._min=a.min;var d=this._max=a.max;var a=a.data||[];var e=a.length;var f=1-this._blur;while(e--){var g=a[e];var h=g.x;var i=g.y;var j=g.radius;var k=Math.min(g.value,d);var l=h-j;var m=i-j;var n=this.shadowCtx;var o;if(!this._templates[j]){this._templates[j]=o=b(j,f)}else{o=this._templates[j]}n.globalAlpha=(k-c)/(d-c);n.drawImage(o,l,m);if(l<this._renderBoundaries[0]){this._renderBoundaries[0]=l}if(m<this._renderBoundaries[1]){this._renderBoundaries[1]=m}if(l+2*j>this._renderBoundaries[2]){this._renderBoundaries[2]=l+2*j}if(m+2*j>this._renderBoundaries[3]){this._renderBoundaries[3]=m+2*j}}},_colorize:function(){var a=this._renderBoundaries[0];var b=this._renderBoundaries[1];var c=this._renderBoundaries[2]-a;var d=this._renderBoundaries[3]-b;var e=this._width;var f=this._height;var g=this._opacity;var h=this._maxOpacity;var i=this._minOpacity;var j=this._useGradientOpacity;if(a<0){a=0}if(b<0){b=0}if(a+c>e){c=e-a}if(b+d>f){d=f-b}var k=this.shadowCtx.getImageData(a,b,c,d);var l=k.data;var m=l.length;var n=this._palette;for(var o=3;o<m;o+=4){var p=l[o];var q=p*4;if(!q){continue}var r;if(g>0){r=g}else{if(p<h){if(p<i){r=i}else{r=p}}else{r=h}}l[o-3]=n[q];l[o-2]=n[q+1];l[o-1]=n[q+2];l[o]=j?n[q+3]:r}k.data=l;this.ctx.putImageData(k,a,b);this._renderBoundaries=[1e3,1e3,0,0]},getValueAt:function(a){var b;var c=this.shadowCtx;var d=c.getImageData(a.x,a.y,1,1);var e=d.data[3];var f=this._max;var g=this._min;b=Math.abs(f-g)*(e/255)>>0;return b},getDataURL:function(){return this.canvas.toDataURL()}};return d}();var d=function j(){var b=false;if(a["defaultRenderer"]==="canvas2d"){b=c}return b}();var e={merge:function(){var a={};var b=arguments.length;for(var c=0;c<b;c++){var d=arguments[c];for(var e in d){a[e]=d[e]}}return a}};var f=function k(){var c=function h(){function a(){this.cStore={}}a.prototype={on:function(a,b,c){var d=this.cStore;if(!d[a]){d[a]=[]}d[a].push(function(a){return b.call(c,a)})},emit:function(a,b){var c=this.cStore;if(c[a]){var d=c[a].length;for(var e=0;e<d;e++){var f=c[a][e];f(b)}}}};return a}();var f=function(a){var b=a._renderer;var c=a._coordinator;var d=a._store;c.on("renderpartial",b.renderPartial,b);c.on("renderall",b.renderAll,b);c.on("extremachange",function(b){a._config.onExtremaChange&&a._config.onExtremaChange({min:b.min,max:b.max,gradient:a._config["gradient"]||a._config["defaultGradient"]})});d.setCoordinator(c)};function g(){var g=this._config=e.merge(a,arguments[0]||{});this._coordinator=new c;if(g["plugin"]){var h=g["plugin"];if(!a.plugins[h]){throw new Error("Plugin '"+h+"' not found. Maybe it was not registered.")}else{var i=a.plugins[h];this._renderer=new i.renderer(g);this._store=new i.store(g)}}else{this._renderer=new d(g);this._store=new b(g)}f(this)}g.prototype={addData:function(){this._store.addData.apply(this._store,arguments);return this},removeData:function(){this._store.removeData&&this._store.removeData.apply(this._store,arguments);return this},setData:function(){this._store.setData.apply(this._store,arguments);return this},setDataMax:function(){this._store.setDataMax.apply(this._store,arguments);return this},setDataMin:function(){this._store.setDataMin.apply(this._store,arguments);return this},configure:function(a){this._config=e.merge(this._config,a);this._renderer.updateConfig(this._config);this._coordinator.emit("renderall",this._store._getInternalData());return this},repaint:function(){this._coordinator.emit("renderall",this._store._getInternalData());return this},getData:function(){return this._store.getData()},getDataURL:function(){return this._renderer.getDataURL()},getValueAt:function(a){if(this._store.getValueAt){return this._store.getValueAt(a)}else if(this._renderer.getValueAt){return this._renderer.getValueAt(a)}else{return null}}};return g}();var g={create:function(a){return new f(a)},register:function(b,c){a.plugins[b]=c}};return g}); |
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> | |
<title>price heatmap, Spain's gas stations </title> | |
<style> | |
body, html { margin:0; padding:0; height:100%;} | |
body { font-family:sans-serif; } | |
body * { font-weight:200;} | |
h1 { position:absolute; background:white; padding:10px;} | |
#map { height:100%; } | |
.leaflet-container { | |
background: rgba(0,0,0,.8) !important; | |
} | |
.fill-gray, .fill-grey {background: #EEE;} | |
.pin-top {top: 0;right: 0;left: 0;position: absolute;} | |
.pad1 {padding: 10px 10px 10px 50px;} | |
</style> | |
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.css" /> | |
<script src="http://code.jquery.com/jquery-2.1.0.min.js"></script> | |
<script src="http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.js"></script> | |
<script src="lib/heatmap.min.js"></script> | |
<script src="lib/leaflet-heatmap.js"></script> | |
</head> | |
<body> | |
<h1>Leaflet Heatmap Layer Example</h1> | |
<div id="map"></div> | |
<div id='stationsNum' class="number">Number of gas stations: 0<div> | |
<div class="pin-top fill-gray pad1"> | |
Gas station // gasolina95 price > | |
<input type = "number" id = "price" max = "1.6" min = "0.9" class="clean short small-input" value="1.30" step="0.01"> €/litre | |
<p id="numStations"><p> | |
<p>Price updated on 7 mar 2015</p> | |
</div> | |
<script> | |
window.onload = function() { | |
var baseLayer = L.tileLayer( | |
'http://services.arcgisonline.com/arcgis/rest/services/Canvas/World_Dark_Gray_Base/MapServer/tile/{z}/{y}/{x}.png',{ | |
attribution: 'Basemap: Esri, HERE, MapmyIndia, © OpenStreetMap contributors, and the GIS user community. Data:http://geoportalgasolineras.es', | |
maxZoom: 18 | |
} | |
); | |
var cfg = { | |
// radius should be small ONLY if scaleRadius is true (or small radius is intended) | |
"radius": 0.1,//The radius each datapoint will have (if not specified on the datapoint itself) | |
"maxOpacity": .8, | |
// scales the radius based on map zoom | |
"scaleRadius": true, | |
// if set to false the heatmap uses the global maximum for colorization | |
// if activated: uses the data maximum within the current map boundaries | |
// (there will always be a red spot with useLocalExtremas true) | |
"useLocalExtrema": true, | |
// which field name in your data represents the latitude - default "lat" | |
latField: 'lat', | |
// which field name in your data represents the longitude - default "lng" | |
lngField: 'lng', | |
// which field name in your data represents the data value - default "value" | |
valueField: 'PrecioGasolina95Proteccion' | |
} | |
var heatmapLayer = new HeatmapOverlay(cfg); | |
var heatmapData | |
var map = new L.Map('map', { | |
center: new L.LatLng(40.6586, -1.3568), | |
zoom: 6, | |
layers: [baseLayer, heatmapLayer] | |
}); | |
var geojsonURL = "http://mappingandco.github.io/geojsonDB/gas_stations_spain/estacionesDeServicio.geojson" | |
$.getJSON(geojsonURL, function(response) { | |
var features = response.features | |
heatmapData = {max:1.4, min:0.9, data:[]}; | |
for (var i = 0; i < features.length; i++) { | |
var lat = features[i].geometry.coordinates[1]; | |
var lng = features[i].geometry.coordinates[0]; | |
var pGasolina95 = features[i].properties.PrecioGasolina95Proteccion; | |
if (pGasolina95 != null) | |
heatmapData.data.push({'lat':lat, 'lng': lng, 'PrecioGasolina95Proteccion': pGasolina95}) | |
} | |
run(1.30) | |
}); | |
function run(min){ | |
var filteredHeatmapData= {max:1.4, min:0.9, data:[]}; | |
var data = heatmapData.data; | |
for (var i = 0; i < heatmapData.data.length; i++) { | |
if (heatmapData.data[i].PrecioGasolina95Proteccion > min) { | |
filteredHeatmapData.data.push({'lat':heatmapData.data[i].lat, 'lng': heatmapData.data[i].lng, 'PrecioGasolina95Proteccion': heatmapData.data[i].PrecioGasolina95Proteccion}) | |
} | |
} | |
heatmapLayer.setData(filteredHeatmapData); | |
document.getElementById('numStations').innerHTML = "Number of stations : "+ filteredHeatmapData.data.length; | |
} | |
$( "#price" ).change(function() { | |
var newMin = $( "#price" ).val(); | |
console.log(newMin) | |
run(newMin) | |
}) | |
// make accessible for debugging | |
layer = heatmapLayer; | |
}; | |
</script> | |
</body> | |
</html> |
/* | |
* Leaflet Heatmap Overlay | |
* | |
* Copyright (c) 2014, Patrick Wied (http://www.patrick-wied.at) | |
* Dual-licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) | |
* and the Beerware (http://en.wikipedia.org/wiki/Beerware) license. | |
*/ | |
// Leaflet < 0.8 compatibility | |
if (typeof L.Layer === 'undefined') { | |
L.Layer = L.Class; | |
} | |
var HeatmapOverlay = L.Layer.extend({ | |
initialize: function (config) { | |
this.cfg = config; | |
this._el = L.DomUtil.create('div', 'leaflet-zoom-hide'); | |
this._data = []; | |
this._max = 1; | |
this._min = 0; | |
this.cfg.container = this._el; | |
}, | |
onAdd: function (map) { | |
var size = map.getSize(); | |
this._map = map; | |
this._width = size.x; | |
this._height = size.y; | |
this._el.style.width = size.x + 'px'; | |
this._el.style.height = size.y + 'px'; | |
this._resetOrigin(); | |
map.getPanes().overlayPane.appendChild(this._el); | |
if (!this._heatmap) { | |
this._heatmap = h337.create(this.cfg); | |
} | |
// on zoom, reset origin | |
map.on('viewreset', this._resetOrigin, this); | |
// redraw whenever dragend | |
map.on('dragend', this._draw, this); | |
this._draw(); | |
}, | |
onRemove: function (map) { | |
// remove layer's DOM elements and listeners | |
map.getPanes().overlayPane.removeChild(this._el); | |
map.off('viewreset', this._resetOrigin, this); | |
map.off('dragend', this._draw, this); | |
}, | |
_draw: function() { | |
if (!this._map) { return; } | |
var point = this._map.latLngToContainerPoint(this._origin); | |
// reposition the layer | |
this._el.style[HeatmapOverlay.CSS_TRANSFORM] = 'translate(' + | |
-Math.round(point.x) + 'px,' + | |
-Math.round(point.y) + 'px)'; | |
this._update(); | |
}, | |
_update: function() { | |
var bounds, zoom, scale; | |
bounds = this._map.getBounds(); | |
zoom = this._map.getZoom(); | |
scale = Math.pow(2, zoom); | |
if (this._data.length == 0) { | |
return; | |
} | |
var generatedData = { max: this._max, min: this._min }; | |
var latLngPoints = []; | |
var radiusMultiplier = this.cfg.scaleRadius ? scale : 1; | |
var localMax = 0; | |
var localMin = 0; | |
var valueField = this.cfg.valueField; | |
var len = this._data.length; | |
while (len--) { | |
var entry = this._data[len]; | |
var value = entry[valueField]; | |
var latlng = entry.latlng; | |
// we don't wanna render points that are not even on the map ;-) | |
if (!bounds.contains(latlng)) { | |
continue; | |
} | |
// local max is the maximum within current bounds | |
localMax = Math.max(value, localMax); | |
localMin = Math.min(value, localMin); | |
var point = this._map.latLngToContainerPoint(latlng); | |
var latlngPoint = { x: Math.round(point.x), y: Math.round(point.y) }; | |
latlngPoint[valueField] = value; | |
var radius; | |
if (entry.radius) { | |
radius = entry.radius * radiusMultiplier; | |
} else { | |
radius = (this.cfg.radius || 2) * radiusMultiplier; | |
} | |
latlngPoint.radius = radius; | |
latLngPoints.push(latlngPoint); | |
} | |
if (this.cfg.useLocalExtrema) { | |
generatedData.max = localMax; | |
generatedData.min = localMin; | |
} | |
generatedData.data = latLngPoints; | |
this._heatmap.setData(generatedData); | |
}, | |
setData: function(data) { | |
this._max = data.max || this._max; | |
this._min = data.min || this._min; | |
var latField = this.cfg.latField || 'lat'; | |
var lngField = this.cfg.lngField || 'lng'; | |
var valueField = this.cfg.valueField || 'value'; | |
// transform data to latlngs | |
var data = data.data; | |
var len = data.length; | |
var d = []; | |
while (len--) { | |
var entry = data[len]; | |
var latlng = new L.LatLng(entry[latField], entry[lngField]); | |
var dataObj = { latlng: latlng }; | |
dataObj[valueField] = entry[valueField]; | |
if (entry.radius) { | |
dataObj.radius = entry.radius; | |
} | |
d.push(dataObj); | |
} | |
this._data = d; | |
this._draw(); | |
}, | |
// experimential... not ready. | |
addData: function(pointOrArray) { | |
if (pointOrArray.length > 0) { | |
var len = pointOrArray.length; | |
while(len--) { | |
this.addData(pointOrArray[len]); | |
} | |
} else { | |
var latField = this.cfg.latField || 'lat'; | |
var lngField = this.cfg.lngField || 'lng'; | |
var valueField = this.cfg.valueField || 'value'; | |
var entry = pointOrArray; | |
var latlng = new L.LatLng(entry[latField], entry[lngField]); | |
var dataObj = { latlng: latlng }; | |
dataObj[valueField] = entry[valueField]; | |
this._max = Math.max(this._max, dataObj[valueField]); | |
this._min = Math.min(this._min, dataObj[valueField]); | |
if (entry.radius) { | |
dataObj.radius = entry.radius; | |
} | |
this._data.push(dataObj); | |
this._draw(); | |
} | |
}, | |
_resetOrigin: function () { | |
this._origin = this._map.layerPointToLatLng(new L.Point(0, 0)); | |
this._draw(); | |
} | |
}); | |
HeatmapOverlay.CSS_TRANSFORM = (function() { | |
var div = document.createElement('div'); | |
var props = [ | |
'transform', | |
'WebkitTransform', | |
'MozTransform', | |
'OTransform', | |
'msTransform' | |
]; | |
for (var i = 0; i < props.length; i++) { | |
var prop = props[i]; | |
if (div.style[prop] !== undefined) { | |
return prop; | |
} | |
} | |
return props[0]; | |
})(); |