Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?

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