block by ThomasG77 c82aafb197157f2bd666

c82aafb197157f2bd666

Full Screen

Displays earthquake data for past 30 days. Hexes sized according to largest earthquake within. Opacity determined by most recent earthquake within.

index.html

<!DOCTYPE html>
<html>
  <head>
		<meta charset="utf-8" />


		<script src="//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="//d3js.org/d3.v3.min.js"></script>
		<script src="//d3js.org/d3.hexbin.v0.min.js"></script>
		<script src="//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
					"//wms.alaskamapped.org/bdl/",
						{
							layers: 'BestDataAvailableLayer', //layer wms name
						},
						{
							animationEnabled:true,
							isBaseLayer:true,
							wrapDateLine:destProj.wrapDateLine,
							transitionEffect: 'resize',
							attribution: '<a href="//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:'//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.D3.js

    	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;
							}
						},

					}
				}


			});