Last active
December 18, 2015 03:39
-
-
Save milkbread/5720205 to your computer and use it in GitHub Desktop.
HTML: Earthquakes with interactive filtering (crossfilter.js) -- PREV: earthquakes_1.0.html
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<h3>D3 + Crossfilter</h3> | |
<h3 class=sub>this is a basic example on the usage of Crossfilter in combination with D3.<br>This exemplary map is a visualistation of the world wide earthquakes between 01.01.2012 & 31.12.2012</h3> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<script src="http://d3js.org/d3.v3.min.js"></script> | |
<script src="http://d3js.org/topojson.v1.min.js"></script> | |
<script src="http://bl.ocks.org/milkbread/raw/5779939/RKMapping_0.4.js"></script> | |
<script src="http://cdn.leafletjs.com/leaflet-0.6.1/leaflet.js"></script> | |
<script src="http://bl.ocks.org/milkbread/raw/5947143/crossfilter.min.js"></script> | |
<script src="RKToolbox.js"></script> | |
<style> | |
@import url(http://cdn.leafletjs.com/leaflet-0.6.1/leaflet.css); | |
@import url(http://bl.ocks.org/milkbread/raw/5957651/simplyArcDemoStyles.css); | |
@import url(RKToolbox_0.1.css); | |
#map { | |
width: 960px; | |
height: 380px; | |
} | |
input{ | |
width: 40px; | |
} | |
#polys:hover{ | |
fill:rgba(200,0,0,0.8); | |
} | |
#polys{ | |
stroke-width:1px; | |
stroke:rgba(255,255,255,1); | |
} | |
.overlay_poly{ | |
fill:rgba(100,100,100,0.3); | |
} | |
.overlay_multipoly{ | |
fill:rgba(0,0,0,0.7); | |
} | |
#delaunay{ | |
fill:none; | |
stroke:rgba(0,0,255,1); | |
stroke-width:1px; | |
} | |
circle{ | |
} | |
</style> | |
</head> | |
<body> | |
<h1>World Wide Earthquakes in 2009</h1> | |
<div id=map></div> | |
<div id=timeline></div> | |
<div id=heading></div> | |
<div id=info></div> | |
<div> | |
</div> | |
<script> | |
var map = L.map('map').setView([40, 11], 2);//.setView([49.5537, 7.7783], 8); | |
var stamen = L.tileLayer('http://{s}.tile.stamen.com/toner/{z}/{x}/{y}.png', {attribution: 'Map data © 2011 OpenStreetMap contributors, Imagery © 2011 <a href="http://maps.stamen.com/#toner/8/51.072/14.584" rel="author" target="_blank"> Stamen</a>, Data-overlay: <a href="http://earthquake.usgs.gov/earthquakes/" rel="author" target="_blank">© USGS</a>'}).addTo(map); | |
var cloudmade = L.tileLayer('http://{s}.tile.cloudmade.com/{key}/{styleId}/256/{z}/{x}/{y}.png', {attribution: 'Map data © 2011 OpenStreetMap contributors, Imagery © 2011 CloudMade, Data-overlay: <a href="http://earthquake.usgs.gov/earthquakes/" rel="author" target="_blank">© USGS</a>',key: 'BC9A493B41014CAABB98F0471D759707',styleId: 22677 }); | |
var baseLayers = {"stamen": stamen, "cloudmade": cloudmade}; | |
L.control.layers(baseLayers).addTo(map); | |
var overLayer = new mapOverlay(map); | |
var infoContainer = d3.select("#info").append("info").text("This will show you some information!") | |
var maximum = 0; | |
var colors = {fill:["#00f", "#f00"], opacity:0.25, stroke:["#f00","#0ff"]} | |
var magniExt = [2,4], step_width = 0.1; | |
var basicInfos = [], maxim, minim; | |
addInteractions(); | |
var indicatorPositions = [new Date(2100, 0, 1),new Date(1800, 0, 1)], | |
timeline = new timeLine(d3.select("#timeline"),960,60); | |
timeline.addClickListener(clickAction); | |
function addInteractions(){ | |
//***Basics | |
basicInfos[0] = d3.select("#heading").append("text").text("Some basic information"); | |
basicInfos[1] = d3.select("#heading").append("text").text("") | |
basicInfos[2] = d3.select("#heading").append("text"); | |
basicInfos[3] = d3.select("#heading").append("text"); | |
} | |
var points, size, color, overlay, earthquakes, minMax, count, magniDimension, timeDimension; | |
d3.json("earthquakes052012.json", function(collection) { | |
var quakes = collection.features | |
/* console.log(Date.now()) | |
var date = new Date(1335745236510); | |
console.log(date.toString().split(" "), date.getDate(), date.getMonth()+1, date.getFullYear()) | |
var x=new Date(2012, 0, 1); | |
var y=new Date(2013, 0, 1); | |
console.log(x<y) | |
*/ | |
earthquakes = crossfilter(quakes); | |
var n = earthquakes.groupAll().reduceCount().value(); | |
basicInfos[0].text("There are "+ n +" eathquakes within that file!") | |
//magniDimension = earthquakes.dimension(function(d){return d.properties.mag;}) | |
//resetMagniFilter(); | |
console.log(earthquakes.groupAll().reduceCount().value()) | |
count = earthquakes.groupAll().reduceCount().value(); | |
//get the time dimension and the min-&max values of them...needed for the timeline | |
timeDimension = earthquakes.dimension(function(d){return d.properties.time;}) | |
timeDimension.top(count).forEach(function(d){ | |
var date = new Date(parseInt(d.properties.time)) | |
//console.log(date) | |
if(date>indicatorPositions[1])indicatorPositions[1]=date; | |
if(date<indicatorPositions[0])indicatorPositions[0]=date; | |
}) | |
timeline.addScalebar(indicatorPositions); | |
//apply an initial filter...as the dataset is very huge | |
//indicatorPositions = [new Date(2012, 0, 1),new Date(2012, 0, 31)] | |
//timeline.replaceIndicators([undefined,indicatorPositions[1]]); | |
//resetTimeFilter(indicatorPositions); | |
// console.log(indicatorPositions) | |
// var mags = earthquakes.groupAll().reduceSum(function(fact) { return fact.properties.mag; }).value() | |
// console.log("The total of all magnitudes is: " + mags) | |
overLayer.addGeometries([],"path"); | |
overlay = overLayer.overlay; | |
reset(); | |
map.on("viewreset", reset);//.on("move",function(){console.log(map.getCenter(),map.getZoom())}) | |
overLayer.features.attr("class",function(d){if(d.type==="Polygon")return "overlay_poly"; else if(d.type==="MultiPolygon") return "overlay_multipoly"}) | |
.attr("id","polys") | |
.on("mouseover",showInfo) | |
.on("mouseup",zoomToObject); | |
function zoomToObject(d){ | |
var local_bounds = d3.geo.bounds(d), | |
center = new L.LatLng(local_bounds[0][1]+((local_bounds[1][1]-local_bounds[0][1])/2),local_bounds[0][0]+((local_bounds[1][0]-local_bounds[0][0])/2)), | |
southWest = new L.LatLng(local_bounds[0][1], local_bounds[0][0]), | |
northEast = new L.LatLng(local_bounds[1][1], local_bounds[1][0]); | |
var local_bounds = new L.LatLngBounds(southWest, northEast); | |
map.setView( center, map.getBoundsZoom( local_bounds)); | |
} | |
}) | |
function clickAction(){ | |
indicatorPositions=timeline.getIndicPosition() | |
//console.log(indicatorPositions) | |
resetTimeFilter(indicatorPositions) | |
reset(); | |
} | |
function resetTimeFilter(data){ | |
timeDimension.filterAll(); | |
timeDimension.filter(function(d){return (d >= data[0] && d <= data[1])}) | |
count = earthquakes.groupAll().reduceCount().value(); | |
basicInfos[1].text("..."+ count +" eathquakes after filtering!") | |
basicInfos[3].text("Current time interval: ["+data[0].getDate()+". "+ (data[0].getMonth()+1) +". "+ data[0].getFullYear() +", "+data[1].getDate() +". "+ (data[1].getMonth()+1) +". "+ data[1].getFullYear() +"]") | |
} | |
function reset(){ | |
var start_time = Date.now(); | |
var geoDimension = earthquakes.dimension(function(d) { return d.geometry.coordinates; }), | |
geoms = geoDimension.top(count); | |
minMax = [100000,0]; | |
geoms.forEach(function(d){ | |
if(d.properties.mag>minMax[1])minMax[1]=d.properties.mag; | |
if(d.properties.mag<minMax[0])minMax[0]=d.properties.mag; | |
//if(d.magnitude<[5])console.log(d); | |
}) | |
size = d3.scale.linear() | |
.domain(minMax) | |
.range([1,6]); | |
color = d3.scale.linear() | |
.domain(minMax) | |
.range(colors.fill); | |
overlay.selectAll("circle").remove(); | |
points = overlay.selectAll("circle").data(geoms).enter().append("circle").attr("id","circles").on("mouseover",transPoint); | |
points.attr("r",function(d){return size(d.properties.mag)}) | |
.attr("cx",function(d) {var data = overLayer.project(d.geometry.coordinates); return data[0]}) | |
.attr("cy",function(d) {var data = overLayer.project(d.geometry.coordinates); return data[1]}) | |
.attr("fill",function(d){return color(d.properties.mag)}).attr("opacity",colors.opacity).attr("stroke",colors.stroke[0]) | |
//console.log(d3.geo.bounds({type:"MultiPoint", coordinates:centroids})) | |
overLayer.resetView([[-180-10, -89], [180+10, 89]]); | |
overLayer.showAll(); | |
basicInfos[2].text("...visualising them took: "+((Date.now() - start_time)/1000).toFixed(4)+"s").append("br") | |
} | |
function transPoint(d){ | |
points.transition().duration(500).ease("linear") | |
.attr("r",function(e){if(e.id==d.id)return size(e.properties.mag)*5; else return size(e.properties.mag)}) | |
.attr("fill",function(e){if(e.id==d.id)return "#fff"; else return color(e.properties.mag)}) | |
.attr("opacity",function(e){if(e.id==d.id)return 0.8; else return colors.opacity}) | |
.attr("stroke",function(e){if(e.id==d.id)return colors.stroke[1]; else return colors.stroke[0]}) | |
showInfo([d.properties.mag, d.geometry.coordinates[2], d.properties.place]); | |
} | |
function showInfo(value){ | |
infoContainer.text("This earthquake had a magnitude of: "+value[0] + " - a depth of: "+ value[1] + " and was located at: "+ value[2]) | |
} | |
function reShow(maxVal){ | |
maximum = maxVal; | |
overLayer.showAllFiltered(maxVal); | |
} | |
</script> | |
</body> | |
</html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//should be able to define: indicWidth, indicSideWidth | |
function timeLine(container,width,height){ | |
//initialize some variables | |
var indicWidth = 8, indicSideWidth = 3, indicatorGroup, indicatorLeftpart, indicatorRightpart, indicatorLeft, indicatorRight; | |
var axisScale = d3.time.scale(); | |
var timelineSVG = container.append("svg") | |
.attr("width", width) | |
.attr("height", height); | |
var timelineGroup = timelineSVG.append("g"); | |
//this is the background of the timeline | |
timelineGroup.append("rect").attr("x", 0).attr("y", 0).attr("width", width).attr("height", height) | |
.attr("id","_background") | |
var xAxisGroup = timelineGroup.append("g"); | |
//this is the interactive area of the timeline | |
var timeline = timelineGroup.append("rect").attr("x", 0).attr("y", 0).attr("width", width).attr("height", height) | |
.attr("id","timelineSVG") | |
.on("mousemove",overAction); | |
defineIndicators(); | |
//add the scalebar...has to be done from 'outside'...returns the 'xAxisGroup' | |
this.addScalebar=addScalebar; | |
function addScalebar(domain_){ | |
//add the text and something like a 'scalebar' | |
axisScale.domain(domain_).range([0,width]); //tutorial for the time scale: http://bl.ocks.org/mbostock/4149176 | |
var xAxis = d3.svg.axis() | |
.scale(axisScale); | |
xAxisGroup.call(xAxis).attr("class", "axis"); | |
xAxisGroup.selectAll("text").attr("transform","rotate(-90, 0, 0)"); | |
xAxisGroup.attr("transform","translate(0,"+(height/2)+")"); | |
return xAxisGroup; | |
} | |
//variables of the functions | |
var indicBools = [false,false], | |
indicPos = [0,width]; | |
//identic for left and right...just call the 'downAction' | |
function leftDownAction(){ | |
var value = (d3.mouse(this)[0]); | |
downAction(value, 'left') | |
} | |
function rightDownAction(){ | |
var value = (d3.mouse(this)[0]); | |
downAction(value, 'right') | |
} | |
//check which side called me and check if indicator is currently static or dynamic | |
function downAction(value, side){ | |
if(side=='left'){ | |
if(indicBools[0]==false)indicBools[0]=true; | |
else {indicPos[0]=value;indicBools[0]=false;indicatorLeftpart.transition().duration(1000).attr("x",value+indicWidth);indicatorLeft.transition().attr("x",value)} | |
} | |
else if(side=='right'){ | |
if(indicBools[1]==false)indicBools[1]=true; | |
else {indicPos[1]=value;indicBools[1]=false;indicatorRightpart.transition().duration(1000).attr("x",value-indicSideWidth);indicatorRight.transition().attr("x",value)} | |
} | |
//execute the user defined function for a click event...when there is one | |
if(clickListenerTest==true && ((indicBools[1]==false && side=='right')|| (indicBools[0]==false && side=='left')))clickListener(); | |
} | |
//check if and which side was clicked and transition its position | |
function overAction(){ | |
var dur = 100; | |
if(indicBools[0]==true){ | |
var value = (d3.mouse(this)[0]); | |
if(indicPos[1]>value){ | |
indicatorLeft.attr("x",value) | |
indicatorLeftpart.attr("x",value-indicSideWidth) | |
} | |
} | |
else if(indicBools[1]==true){ | |
var value = (d3.mouse(this)[0]); | |
if(indicPos[0]<value){ | |
indicatorRight.attr("x",value) | |
indicatorRightpart.attr("x",value+indicWidth) | |
} | |
} | |
} | |
this.getIndicPosition=getIndicPosition; | |
function getIndicPosition(){ | |
return [axisScale.invert(indicPos[0]),axisScale.invert(indicPos[1])]; | |
} | |
var clickListenerTest = false; | |
this.addClickListener=addClickListener; | |
function addClickListener(listener_){ | |
clickListener = listener_; | |
clickListenerTest = true; | |
} | |
this.getClickListener=getClickListener; | |
function getClickListener(){ | |
return clickListener(); | |
} | |
this.replaceIndicators=replaceIndicators; | |
function replaceIndicators(timeArray){ | |
if(timeArray[0]!=undefined){ | |
indicatorLeftpart.attr("x",axisScale(timeArray[0])+indicWidth); | |
indicatorLeft.attr("x",axisScale(timeArray[0]));} | |
if(timeArray[1]!=undefined){ | |
indicatorRightpart.attr("x",axisScale(timeArray[1])-indicSideWidth); | |
indicatorRight.attr("x",axisScale(timeArray[1]));} | |
} | |
this.defineIndicators=defineIndicators; | |
function defineIndicators(){ | |
//add some indicators | |
//short side of the main left indicator | |
indicatorGroup = timelineGroup.append("g") | |
indicatorLeftpart = indicatorGroup.append("rect").attr("x", indicWidth).attr("y", 0).attr("width", indicSideWidth).attr("height", height) | |
.attr("id","indiSide"); | |
//short side of the main right indicator | |
indicatorRightpart = indicatorGroup.append("rect").attr("x", width-indicSideWidth-indicWidth).attr("y", 0).attr("width", indicSideWidth).attr("height", height).attr("id","indiSide"); | |
//left main indicator | |
indicatorLeft = indicatorGroup.append("rect").attr("x", 0).attr("y", 0) .attr("width", indicWidth).attr("height", height) | |
.attr("id","indicatorLeft") | |
.on("mousedown",leftDownAction); | |
//right main indicator | |
indicatorRight = indicatorGroup.append("rect").attr("x", width-indicWidth).attr("y", 0).attr("width", indicWidth).attr("height", height) | |
.attr("id","indicatorLeft") | |
.on("mousedown",rightDownAction); | |
} | |
this.reDefineIndicators=reDefineIndicators; | |
function reDefineIndicators(width, side){ | |
if(side!=undefined)indicSideWidth = side; | |
indicWidth = width; | |
indicatorGroup.selectAll("rect").remove() | |
defineIndicators(); | |
} | |
} | |
function dummyFunction(this_){ | |
console.log("This is the 'mousedown'...add a function to the '.downAction()' for action!") | |
var value = (d3.mouse(this_)[0]); | |
console.log("Currently, I can offer you the mouseposition: ",value) | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#timeline{ | |
fill:rgba(0,0,0,0.4); | |
} | |
#indicatorLeft{ | |
fill:rgba(255,255,255,0.4); | |
} | |
#indiSide{ | |
fill:rgba(255,0,0,0.3); | |
} | |
#_background{ | |
fill:rgba(100,100,100,1); | |
} | |
.axis path, | |
.axis line{ | |
fill: none; | |
stroke: white; | |
stroke-width:4; | |
shape-rendering: crispEdges; | |
opacity:0.2; | |
} | |
.axis text { | |
font-family: sans-serif; | |
font-size: 10px; | |
text-anchor:left; | |
fill:#0f0; | |
opacity:0.8; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment