Displays earthquake data for past 30 days. Hexes sized according to largest earthquake within. Opacity determined by most recent earthquake within.
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8" /> | |
<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script> | |
<script src="//cdnjs.cloudflare.com/ajax/libs/openlayers/2.12/OpenLayers.debug.js"></script> | |
<script src="//cdnjs.cloudflare.com/ajax/libs/proj4js/1.1.0/proj4js-compressed.js"></script> | |
<script src="http://d3js.org/d3.v3.min.js"></script> | |
<script src="http://d3js.org/d3.hexbin.v0.min.js"></script> | |
<script src="http://d3js.org/topojson.v1.min.js"></script> | |
<script src="OpenLayers.D3.js"></script> | |
<script type="text/javascript"> | |
load = function(){ | |
var sourceProj = new OpenLayers.Projection("EPSG:4326"); | |
var destProj; | |
var lae_extent = [-9036842.762,-9036842.762,9036842.762,9036842.762]; | |
var projections = { | |
'EPSG:3857':{ | |
label:'Web Mercator', | |
def:"+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs", | |
//extent:[], | |
center:[-170,60], | |
zoom:3, | |
extent:[-20037508.34,-20037508.34,20037508.34,20037508.34], | |
wrapDateLine:true | |
}, | |
'EPSG:3574':{ | |
label:'Azimuthal Equal Area: Atlantic', | |
def:"+proj=laea +lat_0=90 +lon_0=-40 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs", | |
extent:lae_extent, | |
center:[-40,90], | |
zoom:1, | |
wrapDateLine:false | |
}, | |
'EPSG:3572':{ | |
label:'Azimuthal Equal Area: Alaska', | |
def:"+proj=laea +lat_0=90 +lon_0=-150 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs", | |
extent:lae_extent, | |
center:[-150,90], | |
selected:true, | |
zoom:1 | |
}, | |
'EPSG:3031':{ | |
label:'Antarctic Stereographic', | |
def:"+proj=stere +lat_0=-90 +lon_0=0 +lat_ts=-71 +ellps=WGS84 +datum=WGS84 +units=m", | |
extent:[-12400000,-12400000, 12400000, 12400000], | |
center:[0,-90], | |
zoom:2, | |
wrapDateLine:false | |
} | |
}; | |
var tools = $('<div>').attr('id','tools'); | |
$('body').append(tools); | |
var projectionSwitcher = $('<select>').attr('id','projection_switcher'); | |
for(var k in projections){ | |
var p = projections[k]; | |
var sel = p.selected === true ? ' selected="selected"' : ''; | |
projectionSwitcher.append('<option value="' + k + '"'+ sel +'>' + p.label + '</option>'); | |
} | |
projectionSwitcher.on('change',function(e){ | |
setProjection(this.value); | |
}); | |
tools.append(projectionSwitcher); | |
var map,baseLayer,features; | |
initMap = function(){ | |
if(map){ | |
map.destroy(); | |
} | |
baseLayer = new OpenLayers.Layer.WMS( | |
"GINA WMS",//layer label | |
"http://wms.alaskamapped.org/bdl/", | |
{ | |
layers: 'BestDataAvailableLayer', //layer wms name | |
}, | |
{ | |
animationEnabled:true, | |
isBaseLayer:true, | |
wrapDateLine:destProj.wrapDateLine, | |
transitionEffect: 'resize', | |
attribution: '<a href="http://www.gina.alaska.edu">GINA</a>' | |
} | |
); | |
var mapOps = {projection:destProj.olProjection}; | |
mapOps.wrapDateLine = destProj.wrapDateLine; | |
if(destProj.extent){ | |
mapOps.maxExtent = destProj.extent; | |
if(!mapOps.wrapDateLine){ | |
mapOps.restrictedExtent = destProj.extent | |
} | |
} | |
map = new OpenLayers.Map('map',mapOps); | |
map.addLayer(baseLayer); | |
var d3Layer = new OpenLayers.Layer.D3Hex('d3Hexes',{ | |
//wrapDateLine:true, | |
d3XAccessor:function(f){ | |
return f.geometry.coordinates[0]; | |
}, | |
d3YAccessor:function(f){ | |
return f.geometry.coordinates[1]; | |
}, | |
d3HexRadius:10, | |
d3HexOpacity:function(d){ | |
console.log('getting op..') | |
return this.getTimeOp(d3.max(d,function(f){return f[2].properties.time})); | |
}, | |
d3PointOpacity:function(f){ | |
return this.getTimeOp(f.properties.time); | |
}, | |
d3VisibleHexRadius:function(d){ | |
return this.getMagRadius(d3.max(d,function(f){return f[2].properties.mag})); | |
}, | |
d3PointRadius:function(f){ | |
return this.getMagRadius(f.properties.mag) | |
}, | |
d3PointStroke:"#999", | |
getMagRadius:function(mag){ | |
var self = this; | |
var max = this.d3HexRadius - 1; | |
var min = 2; | |
var diff = max - min; | |
var s = min; | |
if(!isNaN(this.minMag) && !isNaN(this.maxMag)){ | |
s = min + ((mag - this.minMag )/ (this.maxMag - this.minMag)) * diff; | |
} | |
return s; | |
}, | |
getTimeOp:function(time){ | |
var self = this; | |
var max = 1; | |
var min = .3; | |
var diff = max - min; | |
var s = min; | |
if(!isNaN(this.minTime) && !isNaN(this.maxTime)){ | |
s = min + ((time - this.minTime )/ (this.maxTime - this.minTime)) * diff; | |
} | |
return s; | |
} | |
}); | |
map.addLayer(d3Layer); | |
map.setCenter(new OpenLayers.LonLat(destProj.center).transform(sourceProj,destProj.olProjection),destProj.zoom); | |
reprojectFeatures = function(features){ | |
var feats = []; | |
var nofeats = []; | |
var ext = map.getMaxExtent(); | |
features.forEach(function(f){ | |
if(!f.geometry.coordinates.source){ | |
f.geometry.coordinates.source = [f.geometry.coordinates[0],f.geometry.coordinates[1]]; | |
} | |
var lat = f.geometry.coordinates.source[1]; | |
var ll = new OpenLayers.LonLat(f.geometry.coordinates.source[0],f.geometry.coordinates.source[1]).transform(sourceProj,destProj.olProjection); | |
f.geometry.coordinates[0] = ll.lon; | |
f.geometry.coordinates[1] = ll.lat; | |
if(map.options.wrapDateLine || ext.containsLonLat(ll)){ | |
//console.log('+ ' + lat) | |
feats.push(f); | |
}else{ | |
//console.log('- ' + lat) | |
//nofeats.push(f) | |
} | |
}); | |
d3Layer.minMag = d3.min(feats,function(f){ | |
return f.properties.mag; | |
}); | |
d3Layer.maxMag = d3.max(feats,function(f){ | |
return f.properties.mag; | |
}); | |
d3Layer.minTime = d3.min(feats,function(f){ | |
return f.properties.time; | |
}); | |
d3Layer.maxTime = d3.max(feats,function(f){ | |
return f.properties.time; | |
}); | |
//console.log('NOFE') | |
//console.log(nofeats) | |
d3Layer.d3LoadFeatures(feats); | |
} | |
if(!features){ | |
$.ajax({ | |
type:'GET', | |
dataType:'jsonp', | |
url:'http://earthquake.usgs.gov/fdsnws/event/1/query?format=geojson&starttime=2014-01-01&endtime=2014-01-02', | |
jsonpCallback:'eqfeed_callback', | |
cache:true, | |
success:function(resp){ | |
features = resp.features; | |
reprojectFeatures(features); | |
} | |
}); | |
}else{ | |
reprojectFeatures(features) | |
} | |
} | |
setProjection = function(proj){ | |
if(projections.hasOwnProperty(proj)){ | |
if(!Proj4js.defs[proj] && projections[proj].def){ | |
Proj4js.defs[proj] = projections[proj].def; | |
} | |
if(!projections[proj].olProjection){ | |
projections[proj].olProjection = new OpenLayers.Projection(proj); | |
} | |
destProj = projections[proj]; | |
initMap(); | |
} | |
} | |
console.log(projectionSwitcher.value) | |
setProjection(projectionSwitcher[0].value); | |
} | |
</script> | |
<style type="text/css"> | |
html,body,#map{ | |
margin:0px; | |
padding:0px; | |
width:100%; | |
height:100%; | |
background:black; | |
} | |
#map .olControlAttribution { | |
right: 10px; | |
bottom:10px; | |
} | |
.olControlAttribution a{ | |
color:#FFF; | |
} | |
#tools{ | |
position: absolute; | |
top:20px; | |
right:20px; | |
z-index:1500; | |
width:220px; | |
padding:10px; | |
background:rgba(255,255,255,.5); | |
border-radius: 5px; | |
border:0px solid #ccc; | |
text-align:center; | |
} | |
</style> | |
</head> | |
<body onload="load();"> | |
<div id="map"></div> | |
</body> |
OpenLayers.Layer.D3 = OpenLayers.Class(OpenLayers.Layer.Vector, { | |
d3FeaturesNodeClass:'d3features', | |
d3Features:[], | |
afterAdd:function(){ | |
var self = this; | |
if(this.renderer.CLASS_NAME.match(/SVG$/)){ | |
this.d3InitSVG(); | |
this.events.register('moveend',this,this.onMoveEnd); | |
}else{ | |
} | |
}, | |
onMoveEnd:function(e){ | |
this.onPan(); | |
this.d3RenderFeatures(); | |
}, | |
onPan:function(){ | |
if(this.d3FeaturesNode){ | |
this.d3ClearRoot(); | |
var ext = this.map.getExtent(); | |
var res = this.map.getResolution(); | |
var l = -ext.left/res; | |
var t = ext.top/res; | |
var _l = this.renderer.left; | |
var _t = this.renderer.top; | |
var _xOffset = this.renderer.xOffset; | |
var _x = l - _l + _xOffset; | |
var _y = t - _t; | |
this.d3FeaturesNode.attr("transform", "translate(" + _x + "," + _y + ")"); | |
} | |
}, | |
getFeaturesInView:function(){ | |
var self = this; | |
var feats = []; | |
var boundsArr = this.getViewportBoundsArr(); | |
if(this.d3Features){ | |
this.d3Features.forEach(function(f){ | |
if(self.inViewPort(new OpenLayers.LonLat(self.d3XAccessor(f),self.d3YAccessor(f)),boundsArr)){ | |
feats.push(f) | |
} | |
}) | |
} | |
return feats; | |
}, | |
//accepts lonlat and array of bnds obj | |
//for finding features within viewport | |
//bndsArr accounts for dateline | |
inViewPort: function(ll,bndsArr){ | |
var inView = false; | |
if(bndsArr && bndsArr.length > 0){ | |
//var _oll = {lon:ll[0],lat:ll[1]}; | |
inView = bndsArr[0].containsLonLat(ll); | |
if(!inView && bndsArr.length > 1){ | |
inView = bndsArr[1].containsLonLat(ll); | |
} | |
} | |
return inView; | |
}, | |
getViewportBoundsArr:function(){ | |
var destProj = this.map.projection; | |
var llProj = new OpenLayers.Projection("EPSG:4326"); | |
var isMercator = destProj.projCode.match('3857') || destProj.projCode.match('900913') ? true : false; | |
var bnds = this.map.getExtent(); | |
var bndsArr; | |
if(!isMercator){ | |
bndsArr = [bnds]; | |
}else{ | |
var nBnds = bnds.clone().transform(destProj,llProj); | |
var nBnds1 = nBnds.clone(); | |
//var nBnds1 = [[nBnds.left,n],[]] | |
bndsArr = [nBnds1]; | |
if( | |
((nBnds.left > 0 && nBnds.right < 0) || | |
(nBnds.left > 0 && nBnds.left > nBnds.right) || | |
(nBnds.left < 0 && nBnds.left > nBnds.right)) | |
){ | |
//small hack! | |
var smallNum = .0000000001; | |
bndsArr = [ | |
new OpenLayers.Bounds(nBnds.left,nBnds.bottom,180-smallNum,nBnds.top), | |
new OpenLayers.Bounds(-180 + smallNum,nBnds.bottom,nBnds.right,nBnds.top) | |
] | |
} | |
bndsArr.forEach(function(b){ | |
b.transform(llProj,destProj); | |
}); | |
} | |
return bndsArr; | |
}, | |
d3InitSVG:function(){ | |
this.d3Div = d3.select(this.div); | |
var size = this.map.getSize(); | |
this.olRoot = this.d3Div.selectAll("svg"); | |
this.olRoot.remove(); | |
this.d3Root = this.d3Div.append("svg") | |
.attr('width',size.w) | |
.attr('height',size.h); | |
this.d3ClearRoot(); | |
}, | |
d3LoadFeatures:function(features){ | |
this.d3Features = features; | |
this.d3ClearRoot(); | |
this.d3RenderFeatures(); | |
}, | |
d3ClearRoot:function(){ | |
if(this.d3Root){ | |
this.d3Root.select('.' + this.d3FeaturesNodeClass).remove(); | |
} | |
this.d3FeaturesNode = this.d3Root.append('g') | |
.attr('class',this.d3FeaturesNodeClass); | |
}, | |
d3RenderFeatures:function(){ | |
}, | |
d3FeatureXAccessor:function(f){ | |
return f[0]; | |
}, | |
d3FeatureYAccessor:function(f){ | |
return f[1]; | |
}, | |
d3Project:function(f){ | |
var p = [this.d3XAccessor(f),this.d3YAccessor(f)]; | |
this.renderer.calculateFeatureDx({left:p[0],right:p[0]},this.map.getMaxExtent()); | |
var featureDx = this.renderer.featureDx; | |
var geometry = {x:p[0],y:p[1]}; | |
var resolution = this.renderer.getResolution(); | |
var x = ((geometry.x - featureDx) / resolution + this.renderer.left); | |
var y = (this.renderer.top - geometry.y / resolution); | |
return [x,y]; | |
} | |
}); | |
OpenLayers.Layer.D3Hex = OpenLayers.Class(OpenLayers.Layer.D3, { | |
//used for calculating hexes | |
d3HexRadius:10, | |
//used for drawing hexes | |
d3VisibleHexRadius:function(d){ | |
return this.d3HexRadius - 1; | |
}, | |
//limit, above which, points are drawn rather than hexes | |
d3HexZoomLimit:6, | |
d3RenderFeatures:function(){ | |
if(this.d3HexZoomLimit && this.map.getZoom() > this.d3HexZoomLimit){ | |
this.d3DrawPoints(); | |
}else{ | |
this.d3UpdateHexData(); | |
this.d3DrawHexes(); | |
} | |
}, | |
d3MakeHexBin:function(){ | |
var size = this.map.getSize(); | |
this.hexbin = d3.hexbin() | |
.size([size.w,size.h]) | |
.radius(this.d3HexRadius); | |
}, | |
d3DrawPoints:function(){ | |
//console.log('Make points..') | |
var feats = this.getFeaturesInView(); | |
this.d3FeaturesNode.selectAll("circle") | |
.data(feats) | |
.enter().append("circle") | |
.attr(this.d3GetPointAttr()) | |
.style(this.d3GetPointStyle()) | |
}, | |
d3DrawHexes:function(){ | |
var self = this; | |
this.d3FeaturesNode.selectAll("path") | |
.data(this.hexData) | |
.enter().append("path") | |
.attr(this.d3GetHexAttr()) | |
.style(this.d3GetHexStyle()) | |
}, | |
d3UpdateHexData:function(){ | |
if(!this.hexbin){ | |
this.d3MakeHexBin(); | |
} | |
var points = []; | |
var self = this; | |
this.d3Features.forEach(function(f){ | |
var p = self.d3Project(f); | |
p.push(f); | |
points.push(p); | |
}); | |
this.hexData = this.hexbin(points); | |
this.d3AfterHexDataUpdate(); | |
}, | |
//this makes is a place to set up variables used for styling based on how the hexes were distributed out | |
d3AfterHexDataUpdate:function(){ | |
this.d3MaxHexBinSize = d3.max(this.hexData,function(h){ | |
return h.length | |
}) | |
this.d3MinHexBinSize = d3.min(this.hexData,function(h){ | |
return h.length | |
}); | |
}, | |
d3HexFill:"#FFF", | |
d3PointFill:"#FFF", | |
d3GetHexStyle:function(){ | |
var self = this; | |
return { | |
'fill':function(d){ | |
if(typeof self.d3HexFill == 'function'){ | |
self.d3HexFill(d,this); | |
}else{ | |
return self.d3HexFill; | |
} | |
}, | |
'opacity':function(d){ | |
if(typeof self.d3HexOpacity == 'function'){ | |
return self.d3HexOpacity(d,this); | |
}else{ | |
return self.d3HexOpacity; | |
} | |
}, | |
'stroke':function(d){ | |
if(typeof self.d3HexStroke == 'function'){ | |
return self.d3HexStroke(d,this); | |
}else{ | |
return self.d3HexStroke; | |
} | |
}, | |
} | |
}, | |
d3GetHexAttr:function(){ | |
var self = this; | |
return { | |
"d":function(d) { | |
return self.hexbin.hexagon(self.d3VisibleHexRadius(d)); | |
}, | |
"transform":function(d) { | |
return "translate(" + d.x + "," + d.y + ")"; | |
} | |
}; | |
}, | |
d3PointRadius:function(d){ | |
return 5; | |
}, | |
d3GetPointAttr:function(){ | |
var self = this; | |
return { | |
"r":function(d) { | |
return self.d3PointRadius(d); | |
}, | |
"transform":function(d) { | |
var p = self.d3Project(d); | |
return "translate(" + p[0] + "," + p[1] + ")"; | |
} | |
} | |
}, | |
d3GetPointStyle:function(){ | |
var self = this; | |
return { | |
'fill':function(d){ | |
if(typeof self.d3PointFill == 'function'){ | |
self.d3PointFill(d,this); | |
}else{ | |
return self.d3PointFill; | |
} | |
}, | |
'opacity':function(d){ | |
if(typeof self.d3PointOpacity == 'function'){ | |
return self.d3PointOpacity(d,this); | |
}else{ | |
return self.d3PointOpacity; | |
} | |
}, | |
'stroke':function(d){ | |
if(typeof self.d3PointStroke == 'function'){ | |
return self.d3PointStroke(d,this); | |
}else{ | |
return self.d3PointStroke; | |
} | |
}, | |
} | |
} | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment