Last active
October 1, 2015 16:09
-
-
Save artzub/2021642 to your computer and use it in GitHub Desktop.
Global Water Experiment
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
#ignore thumbnails created by windows | |
Thumbs.db | |
#Ignore files build by Visual Studio | |
*.obj | |
*.exe | |
*.pdb | |
*.user | |
*.aps | |
*.pch | |
*.vspscc | |
*_i.c | |
*_p.c | |
*.ncb | |
*.suo | |
*.tlb | |
*.tlh | |
*.bak | |
*.cache | |
*.ilk | |
*.log | |
[Bb]in | |
[Dd]ebug*/ | |
*.lib | |
*.sbr | |
obj/ | |
[Rr]elease*/ | |
_ReSharper*/ | |
[Tt]est[Rr]esult* | |
#Ignore files | |
.idea/ |
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
<script type='text/javascript' | |
src='http://www.visualizing.org/sites/all/modules/custom/seedge_sprint/libs/d3/d3.v2.min.js'></script> | |
<!--<script type='text/javascript' src='../../D3/d3.v2.js'></script>--> | |
<style type="text/css"> | |
body { | |
font-family: Verdana, Arial, Helvetica, sans-serif; | |
font-size: 10px; | |
} | |
a { | |
text-decoration: none; | |
} | |
.feature { | |
stroke-width: 1px; | |
} | |
circle.node { | |
stroke-width: .3px; | |
} | |
line, .tikkies { | |
stroke-width: .6px; | |
} | |
.grid { | |
stroke-width: .3px; | |
} | |
.astxt, .bartxt { | |
font-size: 80%; | |
} | |
.stat { | |
font-weight: bold; | |
} | |
#header, #subheader, a:hover, #bijbakje, | |
#chooseI, #chooseII, #chooseIII, #chooseAxisX, #chooseAxisY, | |
#histolabel_x, #histolabel_y, .stat, .statlabel { | |
text-shadow: .5px .5px 1px #000; | |
} | |
#header { | |
position: absolute; | |
top: 498px; | |
left: 390px; | |
padding: 0px; | |
margin: 0px; | |
font: 36px 'Arial Black', Impact; | |
z-index: 10; | |
} | |
#subheader { | |
position: absolute; | |
top: 25px; | |
left: 498px; | |
padding: 0px; | |
margin: 0px; | |
font: italic 24px 'Times New Roman'; | |
z-index: 11; | |
} | |
#detailscont, #experiments, #watertypes, #watersources, #schaalbakje, div.tooltip { | |
border: 1px solid #5D5D5D; | |
border-radius: 3px; | |
-moz-border-radius: 3px; | |
-webkit-border-radius: 3px; | |
box-shadow: 0px 0px 8px rgba(255, 255, 255, 0.5); | |
-moz-box-shadow: 0px 0px 8px rgba(255, 255, 255, 0.5); | |
-webkit-box-shadow: 0px 0px 8px rgba(255, 255, 255, 0.5); | |
} | |
#map { | |
position: absolute; | |
top: 0px; | |
left: 0px; | |
} | |
#choosers { | |
position: absolute; | |
top: 15px; | |
left: 248px; | |
z-index: 100; | |
opacity: 0; | |
} | |
#chooseI, #chooseII, #chooseIII, | |
#chooseAxisX, #chooseAxisY { | |
position: absolute; | |
width: 240px; | |
height: 20px; | |
} | |
#chooseII { | |
left: 0px; | |
} | |
#chooseII { | |
left: 200px; | |
} | |
#chooseIII { | |
left: 340px; | |
} | |
#chooseAxisX, #chooseAxisY { | |
left: 8px; | |
top: 264px; | |
display: none; | |
z-index: 9006; | |
} | |
#chooseAxisY { | |
top: 289px; | |
} | |
#experiments, #watertypes, #watersources { | |
height: 18px; | |
padding: 0px; | |
font-size: 90%; | |
} | |
#bijbakje { | |
position: absolute; | |
top: 18px; | |
left: 15px; | |
width: 100px; | |
text-align: right; | |
opacity: 0; | |
} | |
#schaalbakje { | |
position: absolute; | |
top: 15px; | |
left: 119px; | |
opacity: 0; | |
} | |
#theNumbers { | |
position: absolute; | |
left: 8px; | |
top: 92px; | |
width: 220px; | |
text-align: right; | |
z-index: 10; | |
} | |
#pieHole { | |
position: absolute; | |
top: 26px; | |
left: 457px; | |
width: 200px; | |
opacity: 0; | |
z-index: 10000; | |
} | |
#pieI, #pieII { | |
position: absolute; | |
top: 20px; | |
} | |
#pieII { | |
left: 145px; | |
} | |
#histo { | |
position: absolute; | |
left: 8px; | |
top: 315px; | |
} | |
#histolabel_x, #histolabel_y { | |
position: absolute; | |
opacity: 0; | |
} | |
#histolabel_y { | |
top: 16px; | |
left: 20px; | |
} | |
#histolabel_x { | |
top: 205px; | |
left: 170px; | |
} | |
#source { | |
position: absolute; | |
bottom: 6px; | |
left: 390px; | |
} | |
div.tooltip { | |
position: absolute; | |
width: 200px; | |
height: auto; | |
padding: 6px 2px 6px 2px; | |
text-shadow: .5px .5px 1px dimgrey; | |
border: solid 1px dimgrey; | |
border-radius: 4px; | |
-webkit-border-radius: 4px; | |
-mozilla-border-radius: 4px; | |
text-align: center; | |
z-index: -100; | |
opacity: 0; | |
} | |
#detailscont { | |
background: rgb(255,255,255); /* Old browsers */ | |
background: -moz-linear-gradient(top, rgba(255,255,255,1) 0%, rgba(203, 203, 203,1) 100%); /* FF3.6+ */ | |
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(255,255,255,1)), color-stop(100%,rgba(203, 203, 203,1))); /* Chrome,Safari4+ */ | |
background: -webkit-linear-gradient(top, rgba(255,255,255,1) 0%,rgba(203, 203, 203,1) 100%); /* Chrome10+,Safari5.1+ */ | |
background: -o-linear-gradient(top, rgba(255,255,255,1) 0%,rgba(203, 203, 203,1) 100%); /* Opera 11.10+ */ | |
background: -ms-linear-gradient(top, rgba(255,255,255,1) 0%,rgba(203, 203, 203,1) 100%); /* IE10+ */ | |
background: linear-gradient(top, rgba(255,255,255,1) 0%,rgba(203, 203, 203,1) 100%); /* W3C */ | |
filter: progid:DXImageTransform.Microsoft.gradient( | |
startColorstr='#ffffff', | |
endColorstr='#CBCBCB', | |
GradientType=0 | |
); /* IE6-9 */ | |
display: none; | |
z-index: 9000; | |
opacity: 1; | |
position: absolute; | |
top: 40px; | |
left: 243px; | |
} | |
#details { | |
border: 1px solid #fff; | |
border-radius: 3px; | |
-moz-border-radius: 3px; | |
-webkit-border-radius: 3px; | |
} | |
#details line, #details .tikkies { | |
stroke-width: 1px; | |
} | |
#details .grid { | |
stroke-width: .3px; | |
} | |
#details .astxt, #details .bartxt { | |
font-size: 10px; | |
font-weight: bold; | |
} | |
#close { | |
position: absolute; | |
right: 5px; | |
top: 5px; | |
z-index: 9002; | |
font-size: 10px; | |
font-weight: bold; | |
border: 1px solid black; | |
padding: 1px 2px; | |
border-radius: 8px; | |
-moz-border-radius: 8px; | |
-webkit-border-radius: 8px; | |
} | |
#close:hover { | |
cursor: pointer; | |
} | |
#checkBoxList { | |
position: absolute; | |
top: 158px; | |
left: 8px; | |
z-index: 9005; | |
display: none; | |
border: 1px dotted #888; | |
background : rgba(68, 68, 68, 0.8); | |
padding: 5px; | |
} | |
#checkBoxList label { | |
text-shadow: .5px .5px 1px #000; | |
padding: 2px; | |
} | |
/** | |
* color theme | |
*/ | |
body { | |
color: #bbb; | |
} | |
a:active { | |
color: #bbb; | |
} | |
a:visited { | |
color: #090; | |
} | |
.feature { | |
fill: #222; | |
stroke: #555; | |
} | |
circle.node { | |
stroke: black; | |
} | |
rect { | |
fill: steelblue; | |
stroke: grey; | |
} | |
line, .tikkies { | |
fill: none; | |
stroke: #000; | |
} | |
.grid { | |
fill: none; | |
stroke: #000; | |
} | |
.astxt, .bartxt { | |
fill: #999; | |
} | |
.stat { | |
color: white; | |
} | |
#header { | |
color: azure; | |
} | |
#subheader { | |
color: #009DDC; /*colors used on http://water.chemistry2011.org/web/iyc: #B5F0FF; #009DDC */ | |
} | |
#detailscont, #experiments, #watertypes, #watersources, #schaalbakje, div.tooltip { | |
border-color: #5D5D5D; | |
} | |
#map { | |
background: #444; | |
} | |
#chooseAxisX, #chooseAxisY { | |
color: #fff; | |
} | |
#source { | |
color: #999; | |
} | |
div.tooltip { | |
background: red; | |
color: black; | |
border-color: dimgrey; | |
} | |
#details line, #details .tikkies { | |
fill: none; | |
stroke: #000; | |
} | |
#details .grid { | |
fill: none; | |
stroke: #000; | |
} | |
#details .astxt, #details .bartxt { | |
fill: #000; | |
} | |
#close { | |
color: black; | |
border-color: black; | |
} | |
#close:hover { | |
color: red; | |
border-color: red; | |
} | |
#checkBoxList { | |
border-color: #888; | |
} | |
#checkBoxList label { | |
color: #fff; | |
} | |
</style> | |
<div id="header">World Wide Water Quality | |
<div id="subheader">2011</div> | |
</div> | |
<div id="map"> | |
<div id="source">source: <a href="http://water.chemistry2011.org/web/iyc" target="_blank">The Global Experiment of | |
the International Year of Chemistry</a></div> | |
</div> | |
<div id="choosers"> | |
<div id="chooseI"> | |
<label for="experiments">experiment #</label> | |
<select id="experiments"> | |
<option value="gwe_experiment1_v1">1: pH</option> | |
<option value="gwe_experiment2_v1">2: salinity</option> | |
<option value="gwe_experiment3_v1">3: dirt</option> | |
<!-- <option value="gwe_experiment4_v1">4: still</option> --> | |
</select> | |
</div> | |
<div id="chooseII"> | |
<label for="watertypes">water types</label> | |
<select id="watertypes"> | |
<option value="">all</option> | |
<option value="fresh">fresh</option> | |
<option value="salt">salt</option> | |
<option value="unknown">unknown</option> | |
</select> | |
</div> | |
<div id="chooseIII"> | |
<label for="watersources">water sources</label> | |
<select id="watersources"> | |
<option value="">all</option> | |
<option value="tap">tap</option> | |
<option value="drinking supply">drinking supply</option> | |
<option value="ground">ground</option> | |
<option value="rain">rain</option> | |
<option value="stream, river, canal">stream, river, canal</option> | |
<option value="pond, lake, pool">pond, lake, pool</option> | |
<option value="ocean">ocean</option> | |
<option value="waste water">waste water</option> | |
<option value="unknown">unknown</option> | |
</select> | |
</div> | |
</div> | |
<div id="pieHole"> | |
<div id="pieI"></div> | |
<div id="pieII"></div> | |
</div> | |
<div id="bijbakje"></div> | |
<div id="schaalbakje"></div> | |
<div id="theNumbers"></div> | |
<div id="histo"> | |
<div id="histolabel_x">result</div> | |
<div id="histolabel_y">frequency</div> | |
</div> | |
<div id="detailscont"> | |
<div id="details"> | |
<span id="close">×</span> | |
</div> | |
</div> | |
<div id="checkBoxList"> | |
<span class="stat">Options:</span><br /> | |
<input type="checkbox" checked="checked" id="axisxbar"/> | |
<label for="axisxbar">Names of axis X</label> | |
<br /> | |
<input type="checkbox" checked="checked" id="axisxbarline"/> | |
<label for="axisxbarline">Lines of axis X</label> | |
<br /> | |
<input type="checkbox" checked="checked" id="axisybar"/> | |
<label for="axisybar">Names of axis Y</label> | |
<br /> | |
<input type="checkbox" checked="checked" id="axisybarline"/> | |
<label for="axisybarline">Lines of axis Y</label> | |
</div> | |
<div id="chooseAxisX"> | |
<label for="axisx">Axis X:</label> | |
<select id="axisx"><option value="tap">tap</option></select> | |
</div> | |
<div id="chooseAxisY"> | |
<label for="axisy">Axis Y:</label> | |
<select id="axisy"><option value="tap">tap</option></select> | |
</div> | |
<script> | |
/** | |
*Variables and settings | |
**/ | |
var activeDataset; | |
//needed for radius consistency during zooms and for updates | |
var reeks, globalData, globalfirstVar, globalsecondVar, globalfirstVarlabel, globalsecondVarlabel; | |
var measurementCircles, detailsCircles = null; | |
var margin = {top:0, right:0, bottom:0, left:0}, | |
width = 1048 - margin.left - margin.right, | |
height = 560 - margin.top - margin.bottom; | |
var projection = d3.geo.mercator() | |
.scale(width) | |
.translate([width / 2.26, height / 1.6]) | |
; | |
var path = d3.geo.path() | |
.projection(projection); | |
var q = projection.scale(); | |
var zoom = d3.behavior.zoom() | |
.translate(projection.translate()) | |
.scale(projection.scale()) | |
.scaleExtent([height, 64 * height]) | |
.on("zoom", move) | |
; | |
/** | |
* Color scheme. used for theming design | |
*/ | |
var cs = { | |
map : { | |
background : "#444", | |
feature : { | |
fill : "#222", | |
stroke : "#555", | |
high : "#666" | |
} | |
}, | |
expI : { | |
low : "red", | |
mid : "green", | |
high : "blue" | |
}, | |
expII : { | |
low : "green", | |
mid : "greenyellow", | |
high : "white" | |
}, | |
expIII : { | |
low : "green", | |
mid : "orange", | |
high : "red" | |
} | |
}; | |
//prelimenary scaling stuff | |
var lowColor, | |
midColor, | |
highColor; | |
var r = d3.scale.linear(); | |
var c = d3.scale.linear(); | |
var highlightTimer = null; // timer to keep interaction responsive while highlighting measurement dots | |
var showhideTimer = null; // timer to keep interaction responsive while highlighting details dots | |
d3.select("#experiments") | |
.property("value", "gwe_experiment1_v1"); | |
d3.selectAll("#watertypes, #watersources") | |
.property("value", ""); | |
/** | |
*Draw map | |
**/ | |
var svg = d3.select("#map").style("background", cs.map.background) | |
.append("svg") | |
.attr("width", width + margin.left + margin.right) | |
.attr("height", height + margin.top + margin.bottom) | |
.append("g") | |
.attr("transform", "translate(" + margin.left + "," + margin.top + ")") | |
.call(zoom) | |
; | |
var g = svg.append("g"), | |
feature = g.selectAll(".feature"); | |
svg.append("g").attr("id", "datapoints"); | |
/** | |
* setup color key holder and gradient | |
**/ | |
var w = 100, | |
h = 17; | |
var bakje = d3.select("#schaalbakje") | |
.append("svg") | |
.attr("width", w) | |
.attr("height", h) | |
.append("svg:g") | |
; | |
var gradient = bakje.append("svg:defs") | |
.append("svg:linearGradient") | |
.attr("id", "gradient") | |
.attr("x1", "0%") | |
.attr("y1", "0%") | |
.attr("x2", "100%") | |
.attr("y2", "0%") | |
.attr("spreadMethod", "pad") | |
; | |
//pie scales and sizes | |
var wpie = 50, | |
hpie = 50, | |
rpie = Math.min(wpie, hpie) / 2, | |
typecolor = d3.scale.ordinal().range(["deepskyblue", "aquamarine", "lightgrey"]), | |
sourcecolor = d3.scale.ordinal().range(["#7B86EF", "#6371ED", "#4E5EEA", "#283BE6", "#1A2DDA", "#1729C5", "#13219F", "#0D176D", "lightgrey"]); | |
/** | |
* setup histogram | |
**/ | |
var histw = 160, | |
histh = 160, | |
histpad = 60; | |
var his = d3.select("#histo") | |
.append("svg") | |
.attr("width", histw + histpad) | |
.attr("height", histh + histpad) | |
.append("svg:g") | |
.attr("transform", "translate(40,40)") | |
; | |
his.append("line") | |
.attr("x1", 0) | |
.attr("x2", histw) | |
.attr("y1", histh) | |
.attr("y2", histh) | |
.style("opacity", 1e-6) | |
.transition() | |
.delay(4000) | |
.duration(250) | |
.style("opacity", 1) | |
; | |
his.append("line") | |
.attr("x1", 0) | |
.attr("x2", 0) | |
.attr("y1", 0) | |
.attr("y2", histh) | |
.style("opacity", 1e-6) | |
.transition() | |
.delay(4000) | |
.duration(250) | |
.style("opacity", 1) | |
; | |
d3.selectAll("#histolabel_y, #histolabel_x") | |
.transition() | |
.delay(4300) | |
.duration(250) | |
.style("opacity", 1) | |
; | |
/** | |
* setup country details | |
*/ | |
var cropw = 50, | |
croph = 40, | |
detw = width - 360 - cropw / 2, | |
deth = height - 100 - croph; | |
var details = d3.select("#details") | |
.append("svg") | |
.attr("width", width - 360) | |
.attr("height", height - 100) | |
; | |
details.append("line") | |
.attr("x1", cropw) | |
.attr("x2", detw) | |
.attr("y1", deth) | |
.attr("y2", deth) | |
.style("opacity", 1) | |
; | |
details.append("line") | |
.attr("x1", cropw) | |
.attr("x2", cropw) | |
.attr("y1", croph) | |
.attr("y2", deth) | |
.style("opacity", 1) | |
; | |
/** | |
* Details | |
*/ | |
var lastData = null; | |
var workArr = null; | |
var selectedPath = null; | |
var axisNames = {}; | |
function isExists(obj) { | |
return typeof(obj) != 'undefined' && obj != null | |
} | |
var replaceCountry = { | |
"Russian Federation":"Russia", | |
"Tuninsia":"Tunisia", | |
"United State of America":"United States of America", | |
"United States":"United States of America", | |
"USA":"United States of America", | |
"US":"United States of America", | |
/*"Georgia":"United States of America" // ???!!!,*/ | |
"Hong Kong":"China", | |
"UK":"United Kingdom", | |
"uk":"United Kingdom", | |
"España":"Spain", | |
"SLOVAKIA":"Slovakia", | |
"Slovákia":"Slovakia", | |
"Slovensko":"Slovakia", | |
"Türkiye":"Turkey", | |
"turkey":"Turkey", | |
"Serbia":"Republic of Serbia", | |
"Bosna i Hercegovina":"Bosnia and Herzegovina", | |
"Scotland":"United Kingdom" | |
} | |
/* If only the UNESCO had used the official UN abreviations... ;) */ | |
function initDataCountries(data) { | |
lastData = {}; | |
for (var i = 0; i < data.length; i++) { | |
var d = data[i]; | |
var ccn = replaceCountry[d.country] || d.country; | |
if (!isExists(lastData[ccn])) | |
lastData[ccn] = []; | |
if (globalfirstVar == "sanity"&& | |
d[globalsecondVar] >= 24) | |
continue; | |
if (globalfirstVar == "dropsofbleach" && | |
d[globalfirstVar] >= 799) | |
continue; | |
lastData[ccn].push(d); | |
} | |
initSelecters(); | |
} | |
function getCountryTempr(coll, name) { | |
var watertype = d3.select("#watertypes").property("value"); | |
var watersource = d3.select("#watersources").property("value"); | |
var arr = []; | |
if (isExists(coll[name])) { | |
var arr = coll[name].filter(function (d) { | |
return (watertype == "" || d.waterType == watertype) && watersource == "" || d.waterSource == watersource; | |
}); | |
} | |
return arr; | |
} | |
function overpath(d) { | |
var cn = d.properties.name; | |
if (getCountryTempr(lastData, cn).length < 1) | |
return; | |
var item = d3.select(this); | |
item.transition() | |
.duration(250) | |
.style('fill', cs.map.feature.high) | |
; | |
item.style("cursor", "pointer"); | |
tooltipdiv | |
.html("<span class=\"statlabel\">" + cn + "</span>") | |
.style("background", "#ddd") | |
.style("height", "auto") | |
.style("z-index", 100) | |
.transition() | |
.duration(250) | |
.style("opacity", 1) | |
; | |
} | |
function moverpath() { | |
tooltipdiv | |
.style("top", d3.event.pageY > height / 2 ? (d3.event.pageY - 32) + "px" : (d3.event.pageY + 12) + "px") | |
.style("left", d3.event.pageX > width / 2 ? (d3.event.pageX - 60) + "px" : (d3.event.pageX + 12) + "px") | |
; | |
} | |
function outpath(d) { | |
var item = d3.select(this); | |
item.style("cursor", "default"); | |
tooltipdiv.transition() | |
.duration(250) | |
.style("opacity", 1e-6) | |
.style("z-index", -100) | |
.style("width", "200px") | |
.style("height", "90px") | |
; | |
item.transition() | |
.duration(250) | |
.style('fill', cs.map.feature.fill) | |
; | |
} | |
function clover(d) { | |
var item = d3.select(this); | |
var city = item.attr("city"); | |
var school = item.attr("school"); | |
var ph = item.attr("ph"); | |
var tph = item.attr("tph"); | |
item.transition() | |
.duration(250) | |
.style("fill", d3.rgb(c(ph)).brighter()) | |
; | |
tooltipdiv | |
.html('<span class="statlabel">School: </span><span class="stat">' + school + '</span>' + | |
'<br /><span class="statlabel">City: </span><span class="stat">' + city + '</span>' + | |
'<br /><span class="statlabel">' + globalfirstVarlabel + '</span><span class="stat">' + ph + '</span>' + | |
'<br /><span class="statlabel">' + globalsecondVarlabel + '</span><span class="stat">' + tph + '</span>' ) | |
.style("background", function () { | |
return c(ph); | |
}) | |
.style("height", "auto") | |
.style("z-index", 9999) | |
.transition() | |
.duration(250) | |
.style("opacity", 1) | |
; | |
} | |
function clmove() { | |
tooltipdiv | |
.style("top", d3.event.pageY + 16 + "px") | |
.style("left", d3.event.pageX - 100 + "px") | |
; | |
} | |
function clout(d) { | |
var item = d3.select(this); | |
item.transition() | |
.duration(250) | |
.style("fill", c(item.attr("ph"))) | |
; | |
tooltipdiv | |
.transition() | |
.duration(250) | |
.style("opacity", 1e-6) | |
.style("z-index", -100) | |
.style("width", "200px") | |
.style("height", "90px") | |
; | |
} | |
function changeAxis() { | |
updateDetails(workArr, | |
d3.select("#axisx").property("value"), | |
d3.select("#axisy").property("value")); | |
} | |
function initSelecters() { | |
axisNames = { | |
"city" : "city", | |
"school" : "school", | |
"teacher" : "teacher", | |
"numberofstudents" : "number of students", | |
"natureofthewater" : "nature of the water", | |
"waterType" : "water type", | |
"waterSource" : "water source", | |
"sourceofwater" : "source of water" | |
}; | |
axisNames[globalsecondVar] = globalsecondVarlabel; | |
axisNames[globalfirstVar] = globalfirstVarlabel; | |
d3.selectAll("#axisx, #axisy") | |
.selectAll("option") | |
.remove() | |
; | |
d3.selectAll("#axisx, #axisy") | |
.on("change", null) | |
.selectAll("option") | |
.data(d3.keys(axisNames).reverse()) | |
.enter() | |
.append("option") | |
.attr("value", function(d) { return d; }) | |
.text(function(d) { return axisNames[d]; }) | |
; | |
d3.select("#axisy").property("value", globalfirstVar); | |
d3.select("#axisx").property("value", "city"); | |
d3.selectAll("#axisx, #axisy").on("change", changeAxis); | |
d3.selectAll("#axisxbarline, #axisxbar, #axisybarline, #axisybar").on("change", showHideBars); | |
} | |
function clickPath(d) { | |
var cn = d.properties.name; | |
workArr = getCountryTempr(lastData, cn); | |
if (workArr.length < 1) | |
return; | |
var item = d3.select(this); | |
selectedPath = item; | |
item.style('fill', '#FFFCCC'); | |
d3.select("#histo") | |
.style("background", "#444") | |
.style("z-index", 9001) | |
; | |
d3.selectAll("#detailscont, #checkBoxList, #chooseAxisX, #chooseAxisY") | |
.style('display', 'block'); | |
d3.select("#close").on("click", function () { | |
if(showhideTimer != null) { | |
clearTimeout(showhideTimer); | |
} | |
detailsCircles = null; | |
d3.selectAll("#detailscont, #checkBoxList, #chooseAxisX, #chooseAxisY") | |
.style('display', 'none'); | |
d3.select("#histo") | |
.style("background", "none"); | |
//this is a lot of html within the code | |
d3.select("#theNumbers") | |
.html("<span class=\"statlabel\">number of measurements: </span><span class=\"stat\">" + | |
reeks.length + "</span><br/><br/><span class=\"statlabel\">average " + | |
globalfirstVarlabel + " </span><span class=\"stat\">" + | |
gemfirstVar + "</span><br/><span class=\"statlabel\">average " + | |
globalsecondVarlabel + ": </span><span class=\"stat\">" + | |
gemsecondVar + "</span>") | |
.style("z-index", 10) | |
; | |
doHistogram(reeks); | |
if (!isExists(selectedPath)) | |
return; | |
selectedPath.style("fill", cs.map.feature.fill); | |
selectedPath = null; | |
}); | |
updateData(); | |
} | |
function updateDetails(arr, axisX, axisY) { | |
details.selectAll("g") | |
.transition() | |
.duration(150) | |
.remove() | |
; | |
if (!isExists(arr) || arr.length < 1) { | |
return; | |
} | |
var cn = arr[0].country; | |
if (!isExists(axisX)) | |
axisX = "city"; | |
if (!isExists(axisY)) | |
axisY = globalfirstVar; | |
var mf = d3.round(d3.mean(arr, function (d) { | |
return d[globalfirstVar]; | |
}), 2), | |
mt = d3.round(d3.mean(arr, function (d) { | |
return d[globalsecondVar]; | |
}), 2), | |
mn = d3.round(d3.mean(arr, function (d) { | |
return d["numberofstudents"]; | |
}), 2); | |
var axisXBar = axisX != globalfirstVar | |
&& axisX != globalsecondVar | |
&& axisX != "numberofstudents" | |
; | |
var axisYBar = axisY != globalfirstVar | |
&& axisY != globalsecondVar | |
&& axisY != "numberofstudents" | |
; | |
var minAxisX = !axisXBar | |
? d3.min(arr, function (d) { | |
return d[axisX]; | |
}) | |
: 0 | |
; | |
var maxAxisX = !axisXBar | |
? d3.max(arr, function (d) { | |
return d[axisX]; | |
}) | |
: 0 | |
; | |
var medAxisX = axisX == globalfirstVar | |
? mf | |
: axisX == globalsecondVar | |
? mt | |
: axisX == "numberofstudents" | |
? mn | |
: 0 | |
; | |
var minAxisY = !axisYBar | |
? d3.min(arr, function (d) { | |
return d[axisY]; | |
}) | |
: 0 | |
; | |
var maxAxisY = !axisYBar | |
? d3.max(arr, function (d) { | |
return d[axisY]; | |
}) | |
: 0 | |
; | |
var medAxisY = axisY == globalfirstVar | |
? mf | |
: axisY == globalsecondVar | |
? mt | |
: axisY == "numberofstudents" | |
? mn | |
: 0 | |
; | |
var x = !axisXBar | |
? d3.scale.linear() | |
.domain([minAxisX - medAxisX / 4, maxAxisX + medAxisX / 4]) | |
.range([cropw + 20, detw - 20]) | |
: d3.scale.ordinal() | |
.domain(arr.map(function (d) { | |
return d[axisX]; | |
})) | |
.rangeBands([cropw + 20, detw - 20]) | |
; | |
var y = !axisYBar | |
? d3.scale.linear() | |
.domain([minAxisY - medAxisY / 4, maxAxisY + medAxisY / 4]) | |
.range([20, deth - croph - 20]) | |
: d3.scale.ordinal() | |
.domain(arr.map(function (d) { | |
return d[axisY]; | |
})) | |
.rangeBands([20, deth - croph - 20]) | |
; | |
//this is a lot of html within the code | |
d3.select("#theNumbers") | |
.html("<span class=\"statlabel\">Country: </span><span class=\"stat\">" + | |
cn + "</span><br /><span class=\"statlabel\">number of measurements: </span><span class=\"stat\">" + | |
arr.length + "</span><br/><br/><span class=\"statlabel\">average " + | |
globalfirstVarlabel + " </span><span class=\"stat\">" + | |
mf + "</span><br/><span class=\"statlabel\">average " + | |
globalsecondVarlabel + ": </span><span class=\"stat\">" + | |
mt + "</span>") | |
.style("z-index", 9003) | |
; | |
details.append("svg:g") | |
.style("opacity", 1) | |
.attr("transform", "translate(0," + (croph - 20) + ")") | |
.append("text") | |
.attr("class", "astxt") | |
.attr("x", cropw - 30) | |
.attr("dy", ".71em") | |
.attr("text-anchor", "left") | |
.text(axisNames[axisY]) | |
.style("fill", d3.rgb("#5D5DE9").darker()) | |
; | |
details.append("svg:g") | |
.style("opacity", 1) | |
.attr("transform", "translate(" + (detw - cropw) + "," + (deth + 20) + ")") | |
.append("text") | |
.attr("class", "astxt") | |
.attr("dy", ".71em") | |
.attr("text-anchor", "right") | |
.text(axisNames[axisX] || axisX) | |
.style("fill", d3.rgb("#5D5DE9").darker()) | |
; | |
var deltay = 0; | |
if (!axisYBar) { | |
var rules = details.selectAll("g.rule") | |
.data(y.ticks(10)) | |
.enter() | |
.append("svg:g") | |
.style("opacity", 1) | |
.attr("transform", function (d) { | |
return "translate(0," + (deth - y(d)) + ")"; | |
}) | |
; | |
rules.append("line") | |
.attr("class", "tikkies") | |
.attr("x1", cropw - 1) | |
.attr("x2", cropw - 5) | |
; | |
rules.append("line") | |
.attr("class", "grid") | |
.attr("x1", cropw + 1) | |
.attr("x2", detw) | |
; | |
rules.append("text") | |
.attr("class", "astxt") | |
.attr("x", cropw - 15) | |
.attr("dy", ".71em") | |
.attr("text-anchor", "middle") | |
.text(y.tickFormat(10)) | |
; | |
} | |
else { | |
deltay = y.rangeBand() / 2; | |
} | |
var delta = 0; | |
if (!axisXBar) { | |
rules = details.selectAll("g.rule") | |
.data(x.ticks(10)) | |
.enter() | |
.append("svg:g") | |
.style("opacity", 1) | |
.attr("transform", function (d) { | |
return "translate(" + x(d) + "," + (0) + ")"; | |
}) | |
; | |
rules.append("line") | |
.attr("class", "tikkies") | |
.attr("y1", deth + 1) | |
.attr("y2", deth + 5) | |
; | |
rules.append("line") | |
.attr("class", "grid") | |
.attr("y1", deth - 1) | |
.attr("y2", croph) | |
; | |
rules.append("text") | |
.attr("class", "astxt") | |
.attr("y", deth + 15) | |
.attr("dx", ".71em") | |
.attr("text-anchor", "middle") | |
.text(x.tickFormat(10)) | |
; | |
} | |
else { | |
delta = x.rangeBand() / 2; | |
} | |
var qt = deth * 2; | |
var rtvar = (axisY == globalsecondVar && axisX == globalfirstVar) | |
|| (axisX == globalsecondVar && axisY == globalfirstVar) | |
? function (d) { | |
return 0; | |
} | |
: axisY == globalsecondVar | |
? function (d) { | |
return d[globalfirstVar]; | |
} | |
: function (d) { | |
return d[globalsecondVar] | |
} | |
; | |
var ypos = function(d) { | |
return (deth - y(d[axisY]) - deltay); | |
} | |
var rt = d3.scale.linear() | |
.domain(d3.extent(arr.map(rtvar))) | |
.range([3 * (qt / deth), 9 * (qt / deth)]) | |
; | |
var bars = details.selectAll("g.bars") | |
.data(arr) | |
.enter() | |
.append("svg:g") | |
.attr("class", "cldetails") | |
.attr("transform", function (d) { | |
return "translate(" + (x(d[axisX]) + delta ) + ", 0" + /*(deth - y(d[globalfirstVar])) + */")"; | |
}) | |
; | |
bars.append("circle") | |
.attr("city", function (d) { return d.city; }) | |
.attr("school", function (d) { return d.school; }) | |
.attr("ph", function(d) { return d[globalfirstVar]; }) | |
.attr("tph", function(d) { return d[globalsecondVar]; }) | |
.attr("r", 5) | |
.style("fill", function (d) { | |
return c(d[globalfirstVar]); | |
}) | |
.style("stroke", function (d) { | |
return d3.rgb(c(d[globalfirstVar])).darker(); | |
}) | |
.attr("transform", function (d) { | |
return "translate(0," + (deth) + ")"; | |
}) | |
.on("mouseover", clover) | |
.on("mousemove", clmove) | |
.on("mouseout", clout) | |
.transition() | |
.delay(100) | |
.duration(800) | |
.attr("transform", function (d) { | |
return "translate(0," + ypos(d) + ")"; | |
}) | |
.transition() | |
.delay(100) | |
.duration(250) | |
.attr("r", function (d) { | |
return rt(rtvar(d)); | |
}) | |
; | |
bars.append("circle") | |
.attr("r", 2) | |
.style("fill", function (d) { | |
return d3.rgb(c(d[globalfirstVar])).darker(); | |
}) | |
.style("stroke", "none") | |
.attr("transform", function (d) { | |
return "translate(0," + ypos(d) + ")"; | |
}) | |
; | |
if (axisYBar) { | |
bars.append("line") | |
.attr("class", "axisYBarLine") | |
.style("stroke", function (d) { | |
return d3.rgb(c(d[globalfirstVar])).darker(); | |
}) | |
.attr("x2", function(d) { | |
return cropw - (x(d[axisX]) + delta - 1); | |
}) | |
.attr("y1", function (d) { | |
return ypos(d); | |
}) | |
.attr("y2", function (d) { | |
return ypos(d); | |
}) | |
.style('visibility', function (d) { | |
return aybl ? null : 'hidden'; | |
}) | |
.style("opacity", 0.4) | |
; | |
bars.append("text") | |
.attr("class", "axisYBar") | |
.style("fill", function (d) { | |
return "#5D5DE9"; | |
}) | |
.attr("y", function(d) { | |
return ypos(d) - 5; | |
}) | |
.attr("x", function(d) { | |
return cropw - (x(d[axisX]) + delta - 1); | |
}) | |
.text(function (d) { | |
return d[axisY]; | |
}) | |
.style('visibility', function (d) { | |
return ayb ? null : 'hidden'; | |
}) | |
.style("font-size", "11px") | |
; | |
} | |
if (axisXBar) { | |
bars.append("line") | |
.attr("class", "axisXBarLine") | |
.style("stroke", function (d) { | |
return d3.rgb(c(d[globalfirstVar])).darker(); | |
}) | |
.attr("y1", deth) | |
.attr("y2", function (d) { | |
return ypos(d); | |
}) | |
.style('visibility', function (d) { | |
return axbl ? null : 'hidden'; | |
}) | |
.style("opacity", 0.4) | |
; | |
bars.append("text") | |
.attr("class", "axisXBar") | |
.style("fill", function (d) { | |
return "#5D5DE9"; | |
}) | |
.style("writing-mode", "tb-rl") | |
.attr("y", function (d) { | |
return deth - ((d[axisX].length) * 11 / 2); | |
}) | |
.attr("x", 5) | |
.style("text-align", "right") | |
.text(function (d) { | |
return d[axisX]; | |
}) | |
.style('visibility', function (d) { | |
return axb ? null : 'hidden'; | |
}) | |
.style("font-size", "11px") | |
; | |
} | |
detailsCircles = details.selectAll(".cldetails"); | |
} | |
var axbl = true; | |
var axb = true; | |
var aybl = true; | |
var ayb = true; | |
function showHideBars() { | |
if (showhideTimer != null) { | |
clearTimeout(showhideTimer); | |
} | |
showhideTimer = setTimeout(function () { | |
if (d3.select("#axisxbarline").property("checked") != axbl) { | |
axbl = d3.select("#axisxbarline").property("checked"); | |
detailsCircles.selectAll(".axisXBarLine") | |
.style('visibility', function (d, i) { | |
return axbl ? null : 'hidden'; | |
}); | |
} | |
if (d3.select("#axisxbar").property("checked") != axb) { | |
axb = d3.select("#axisxbar").property("checked"); | |
detailsCircles.selectAll(".axisXBar") | |
.style('visibility', function (d, i) { | |
return axb ? null : 'hidden'; | |
}); | |
} | |
if (d3.select("#axisybarline").property("checked") != aybl) { | |
aybl = d3.select("#axisybarline").property("checked"); | |
detailsCircles.selectAll(".axisYBarLine") | |
.style('visibility', function (d, i) { | |
return aybl ? null : 'hidden'; | |
}); | |
} | |
if (d3.select("#axisybar").property("checked") != ayb) { | |
ayb = d3.select("#axisybar").property("checked"); | |
detailsCircles.selectAll(".axisYBar") | |
.style('visibility', function (d, i) { | |
return ayb ? null : 'hidden'; | |
}); | |
} | |
}, 350); | |
} | |
tooltipdiv = d3.select("body") | |
.append("div") | |
.attr("class", "tooltip") | |
; | |
function tooltipper(d) { | |
tooltipdiv | |
.html("<span class=\"statlabel\">" + | |
globalfirstVarlabel + " </span><span class=\"stat\">" + | |
d[firstVar] + "</span><br/><span class=\"statlabel\">" + | |
globalsecondVarlabel + ": </span><span class=\"stat\">" + | |
d[secondVar] + "</span><br/><span class=\"stat\">" + | |
d.waterType + "</span><span class=\"statlabel\"> water</span><br/><span class=\"statlabel\">source: </span><span class=\"stat\">" + | |
d.waterSource + "</span><br/><br/><span class=\"schoollabel\">(" + | |
d.school + ", " + | |
d.country + ")</span>") | |
.style("background", c(d[firstVar])) | |
.style("z-index", 100) | |
.transition() | |
.duration(250) | |
.style("opacity", 1) | |
; | |
} | |
function toolmover() { | |
tooltipdiv | |
.style("top", d3.event.pageY > height / 2 ? (d3.event.pageY - 102) + "px" : (d3.event.pageY + 12) + "px") | |
.style("left", d3.event.pageX > width / 2 ? (d3.event.pageX - 212) + "px" : (d3.event.pageX + 12) + "px") | |
; | |
} | |
function tooltapper() { | |
tooltipdiv | |
.transition() | |
.duration(250) | |
.style("opacity", 1e-6) | |
.style("z-index", -100) | |
; | |
} | |
/** | |
*Draw map | |
**/ | |
//d3.json("world-countries.json", function(collection) { | |
d3.json("/sites/default/files/sprint/data/world-countries.json", function (collection) { | |
feature = feature.data(collection.features) | |
.enter().append("path") | |
.attr("class", "feature") | |
.attr("d", path) | |
.style('fill', cs.map.feature.fill) | |
.style('stroke', cs.map.feature.stroke) | |
.on("mouseover", overpath) | |
.on("mousemove", moverpath) | |
.on("click", clickPath) | |
.on("mouseout", outpath) | |
; | |
activeDataset = "gwe_experiment1_v1"; | |
swap_to_Exp(cs.expI.low, cs.expI.mid, cs.expI.high, | |
"pH ", "ph", "temperature (in \u00b0C): ", "temperature"); | |
}); | |
function updateDataset() { | |
var picker = d3.select("#experiments").property("value"); | |
if (activeDataset == picker) | |
return; | |
else | |
activeDataset = picker; | |
switch(picker) { | |
case "gwe_experiment1_v1" : | |
swap_to_Exp(cs.expI.low, cs.expI.mid, cs.expI.high, | |
"pH", "ph", "temperature (in \u00b0C)", "temperature"); | |
break; | |
case "gwe_experiment2_v1" : | |
swap_to_Exp(cs.expII.low, cs.expII.mid, cs.expII.high, | |
"salinity ", "sanity", "salinity by weight", "sanitybyweight"); | |
//please note: the dataset still speaks of sanity instead of salinity - this should be corrected! | |
//this school: | |
//{"city":"Milano","coordinates":[9.18103,45.468945],"country":"Italy","natureofthewater":"fresh","numberofstudents":19,"sanity":0.24,"sanitybyweight":24,"school":"Facoltà di Agraria-Università degli studi di Milano","sourceofwater":"Casalmaiocco (LO), tapwater","teacher":"Gigliola","waterType":"fresh","waterSource":"tap"}, | |
//{"city":"Milano","coordinates":[9.18103,45.468945],"country":"Italy","natureofthewater":"fresh","numberofstudents":19,"salinity":0.62,"salinitybyweight":62,"school":"Facoltà di Agraria-Università degli Studi di Milano","sourceofwater":"Milano, tap water","teacher":"Leonardo","waterType":"fresh","waterSource":"tap"} | |
//seems to have accidentally swapped salinity and salinity by weight - I changed it around, but this has to be checked though!!! | |
break; | |
case "gwe_experiment3_v1" : | |
swap_to_Exp(cs.expIII.low, cs.expIII.mid, cs.expIII.high, | |
"drops of bleach", "dropsofbleach", "temperature (in \u00b0C)", "temperature"); | |
//what is up with this school? 799 dropsofbleach?! | |
//{"city":"Tumon","coordinates":[144.799072,13.50454],"country":"United States","dropsofbleach":799,"natureofthewater":"Fresh","numberofstudents":7,"school":"St. Johns School of Guam","sourceofwater":"Tap","teacher":"Hieter","temperature":26,"waterType":"fresh","waterSource":"tap"}, that mentiones 799 drops of bleach?! This seems unrealistically high. | |
//the still efficiency dataset only has one variable that has to be plotted - how can this be made to fit the experiment changer routine? | |
// else | |
// if (picker == "gwe_experiment4_v1") { swap_to_Exp(); } | |
break; | |
} | |
} | |
function swap_to_Exp(lowColor, midColor, highColor, firstVarlabel, firstVar, secondVarlabel, secondVar) { | |
globalfirstVar = firstVar; | |
globalsecondVar = secondVar; | |
globalfirstVarlabel = firstVarlabel; | |
globalsecondVarlabel = secondVarlabel; | |
/** | |
* Load data from JSON and draw visualization | |
**/ | |
//d3.json(activeDataset + ".json", function(data) { | |
d3.json("/sites/default/files/sprint/data/" + activeDataset + ".json", function (data) { | |
if (firstVar == "sanity") { | |
//filter out two specific data entry errors | |
data = data.filter(function (d) { | |
return d[secondVar] < 24; | |
}); | |
} | |
if (firstVar == "dropsofbleach") { | |
//filter out one unlikely outlier | |
data = data.filter(function (d) { | |
return d[firstVar] < 799; | |
}); | |
} | |
globalData = data; | |
gemfirstVar = d3.round(d3.mean(data, function (d) { | |
return d[firstVar]; | |
}), 2); | |
gemsecondVar = d3.round(d3.mean(data, function (d) { | |
return d[secondVar]; | |
}), 2); | |
reeks = data.map(function (d) { | |
return d[firstVar]; | |
}); | |
initDataCountries(data); | |
// scale for temperature to radius | |
r.domain(d3.extent(data.map(function (d) { | |
return d[secondVar]; | |
}))) | |
.range([1 * (q / width), 6 * (q / width)]); | |
// scale for ph to color | |
// using a manually-set low value because an extreme sample is distorting the range | |
c.domain([ | |
d3.min(data, function (d) { | |
return d[firstVar]; | |
}), | |
gemfirstVar, | |
d3.max(data, function (d) { | |
return d[firstVar]; | |
}) | |
]).range([lowColor, midColor, highColor]); | |
//gather data for pies | |
//this can also be done with d3.nest to extract the variables and their lenghts, but that messes up the order of the watertypes and sources | |
types = []; | |
sources = []; | |
types.push({ "type":"fresh", "size":data.filter( | |
function (d) { | |
return d.waterType == "fresh"; | |
}).length }); | |
types.push({ "type":"salt", "size":data.filter( | |
function (d) { | |
return d.waterType == "salt"; | |
}).length }); | |
types.push({ "type":"unknown", "size":data.filter( | |
function (d) { | |
return d.waterType == "unknown"; | |
}).length }); | |
sources.push({ "source":"tap", "size":data.filter( | |
function (d) { | |
return d.waterSource == "tap"; | |
}).length }); | |
sources.push({ "source":"drinking supply", "size":data.filter( | |
function (d) { | |
return d.waterSource == "drinking supply"; | |
}).length }); | |
sources.push({ "source":"ground", "size":data.filter( | |
function (d) { | |
return d.waterSource == "ground"; | |
}).length }); | |
sources.push({ "source":"rain", "size":data.filter( | |
function (d) { | |
return d.waterSource == "rain"; | |
}).length }); | |
sources.push({ "source":"stream, river, canal", "size":data.filter( | |
function (d) { | |
return d.waterSource == "stream, river, canal"; | |
}).length }); | |
sources.push({ "source":"pond, lake, pool", "size":data.filter( | |
function (d) { | |
return d.waterSource == "pond, lake, pool"; | |
}).length }); | |
sources.push({ "source":"ocean", "size":data.filter( | |
function (d) { | |
return d.waterSource == "ocean"; | |
}).length }); | |
sources.push({ "source":"waste water", "size":data.filter( | |
function (d) { | |
return d.waterSource == "waste water"; | |
}).length }); | |
sources.push({ "source":"unknown", "size":data.filter( | |
function (d) { | |
return d.waterSource == "unknown"; | |
}).length }); | |
donut = d3.layout.pie().sort(null).value(function (d) { | |
return d.size; | |
}); | |
arc = d3.svg.arc().outerRadius(rpie); | |
d3.selectAll("#watertypes , #watersources") | |
.on("change", null); | |
/** | |
*Gradient legend for pH values / needs tickmarks | |
**/ | |
gradient.selectAll("stop").remove(); | |
gradient.append("svg:stop") | |
.attr("offset", "0%") | |
.attr("stop-color", lowColor) | |
.attr("stop-opacity", 1) | |
; | |
gradient.append("svg:stop") | |
.attr("offset", "50%") | |
.attr("stop-color", midColor) | |
.attr("stop-opacity", 1) | |
; | |
gradient.append("svg:stop") | |
.attr("offset", "100%") | |
.attr("stop-color", highColor) | |
.attr("stop-opacity", 1) | |
; | |
bakje.append("rect") | |
.attr("width", w) | |
.attr("height", h) | |
.attr("rx", "4px") | |
.attr("ry", "4px") | |
.style("fill", "url(#gradient)") | |
; | |
d3.select("#bijbakje").text(firstVarlabel); | |
d3.selectAll("#choosers, #schaalbakje, #bijbakje, #pieHole") | |
.transition() | |
.delay(50) | |
.duration(250) | |
.style("opacity", 1) | |
; | |
//the pies could me made a lot slicker by using proper updates (with tweens) instead of remove/appends | |
//the pies could replace the current drop downs for waterType and waterSource | |
d3.selectAll("#pieI, #pieII").select("svg").remove(); | |
var visI = d3.select("#pieI") | |
.append("svg") | |
.data([types]) | |
.attr("width", wpie) | |
.attr("height", hpie) | |
; | |
var arcsI = visI.selectAll("g.arc") | |
.data(donut) | |
.enter().append("svg:g") | |
.attr("class", "arc") | |
.attr("transform", "translate(" + rpie + "," + rpie + ")") | |
; | |
arcsI.append("path") | |
.attr("fill", function (d, i) { | |
return typecolor(i); | |
}) | |
.attr("d", arc) | |
; | |
arcsI.append("title") | |
.text(function (d) { | |
return d.data.type + ": " + d.data.size; | |
}); | |
var visII = d3.select("#pieII") | |
.append("svg") | |
.data([sources]) | |
.attr("width", wpie) | |
.attr("height", hpie) | |
; | |
var arcsII = visII.selectAll("g.arc") | |
.data(donut) | |
.enter().append("svg:g") | |
.attr("class", "arc") | |
.attr("transform", "translate(" + rpie + "," + rpie + ")") | |
; | |
arcsII.append("path") | |
.attr("fill", function (d, i) { | |
return sourcecolor(i); | |
}) | |
.attr("stroke", function (d, i) { | |
return d3.rgb(sourcecolor(i)).darker; | |
}) | |
.attr("d", arc) | |
; | |
arcsII.append("title") | |
.text(function (d) { | |
return d.data.source + ": " + d.data.size; | |
}); | |
// refill circles | |
svg.select("#datapoints") | |
.selectAll("circle") | |
.transition() | |
.duration(1000) | |
.remove() | |
; | |
svg.select("#datapoints") | |
.selectAll("circle.node") | |
.data(data) | |
.enter() | |
.append("circle") | |
.attr('class', 'measurementCircle') | |
.attr("transform", function (d) { | |
return "translate(" + projection(d.coordinates) + ")"; | |
}) | |
.attr("r", 0) | |
.attr("fill", "#aaa") | |
.on("mouseover", tooltipper) | |
.on("mousemove", toolmover) | |
.on("mouseout", tooltapper) | |
.on("click", ripple) | |
.attr("visibility", function(d) { | |
var watertype = d3.select("#watertypes").property("value"); | |
var watersource = d3.select("#watersources").property("value"); | |
return (watertype == "" || watertype == d.waterType) | |
&& (watersource == "" || watersource == d.waterSource) | |
? "visible" | |
: "hidden" | |
; | |
}) | |
.transition() | |
.delay(100) | |
.duration(1000) | |
.attr("r", function (d) { | |
return r(d[secondVar]); | |
}) | |
.transition() | |
.delay(1200) | |
.duration(1250) | |
.attr("fill", function (d) { | |
return c(d[firstVar]); | |
}) | |
.attr("stroke", function (d) { | |
return d3.rgb(c(d[firstVar])).darker(); | |
}); | |
measurementCircles = svg.select('#datapoints').selectAll('.measurementCircle'); | |
//this is a lot of html within the code | |
d3.select("#theNumbers") | |
.html("<span class=\"statlabel\">number of measurements: </span><span class=\"stat\">" + | |
reeks.length + "</span><br/><br/><span class=\"statlabel\">average " + | |
firstVarlabel + " </span><span class=\"stat\">" + | |
gemfirstVar + "</span><br/><span class=\"statlabel\">average " + | |
secondVarlabel + ": </span><span class=\"stat\">" + | |
gemsecondVar + "</span>"); | |
//This is quite a lot of html code inside the d3 code - isn't there a better way to do this? | |
//The school names vary considerably in length. So sometimes they leave a lot of white space in the div, and at other times they stick out at the bottom - resolved for now because by means of a small fontsize | |
//Is it possible to have the tooltip divs automatically size according to their contents? | |
d3.selectAll("#watertypes , #watersources") | |
.property("value", ""); | |
updateData(); | |
d3.selectAll("#watertypes, #watersources").on("change", updateVisibility); | |
}); | |
} | |
function updateData() { | |
if (selectedPath != null) { | |
workArr = getCountryTempr(lastData, selectedPath.datum().properties.name); | |
doHistogram(workArr.map(function (d) { | |
return d[globalfirstVar]; | |
})); | |
changeAxis(); | |
} | |
else | |
doHistogram(); | |
} | |
function doHistogram(reeks) { | |
//histogramcode | |
if (!isExists(reeks)) | |
reeks = window.reeks; | |
d3.selectAll(".grid, .tikkies, .hisrect, text") | |
.transition() | |
.duration(500) | |
.style("opacity", 1e-6) | |
.remove() | |
; | |
var histogram = d3.layout.histogram()(reeks); | |
var x = d3.scale.ordinal() | |
.domain(histogram.map(function (d) { | |
return d.x; | |
})) | |
.rangeBands([0, histw]) | |
; | |
var y = d3.scale.linear() | |
.domain([0, d3.max(histogram, function (d) { | |
return d.y; | |
})]) | |
.range([0, histh]) | |
; | |
var rules = his.selectAll("g.rule") | |
.data(y.ticks(10)) | |
.enter() | |
.append("svg:g") | |
.attr("transform", function (d) { | |
return "translate(0," + (histh - y(d)) + ")"; | |
}) | |
.style("opacity", 1e-6) | |
; | |
rules.append("line") | |
.attr("class", "tikkies") | |
.attr("x1", -1) | |
.attr("x2", -5) | |
; | |
rules.append("line") | |
.attr("class", "grid") | |
.attr("x1", 1) | |
.attr("x2", histw) | |
; | |
rules.append("text") | |
.attr("class", "astxt") | |
.attr("x", -15) | |
.attr("dy", ".71em") | |
.attr("text-anchor", "middle") | |
.style("display", function (d) { | |
return d == 0 ? "none" : null | |
}) | |
.text(y.tickFormat(10)) | |
; | |
rules.transition() | |
.delay(4000) | |
.duration(250) | |
.style("opacity", 1) | |
; | |
var bars = his.selectAll("g.bars") | |
.data(histogram) | |
.enter().append("svg:g") | |
.attr('class', 'histoBar') | |
.attr('id', function (d, i) { | |
return 'histoBar-' + i; | |
}) | |
.attr("transform", function (d) { | |
return "translate(" + x(d.x) + "," + (histh - y(d.y)) + ")"; | |
}) | |
.on('mouseover', markHistogramBar) | |
.on('mouseout', unmarkHistogramBar) | |
; | |
bars.append("rect") | |
.attr("class", "hisrect") | |
.attr("width", x.rangeBand()) | |
.attr("y", function (d) { | |
return y(d.y); | |
}) | |
.attr("height", 0) | |
.style("fill", function (d) { | |
return c(d.x); | |
}) | |
.style("stroke", function (d) { | |
return d3.rgb(c(d.x)).darker(); | |
}) | |
.transition() | |
.delay(2450) | |
.duration(750) | |
.attr("height", function (d) { | |
return y(d.y); | |
}) | |
.attr("y", 0) | |
; | |
bars.append("text") | |
.attr("class", "bartxt") | |
.attr("x", x.rangeBand() / 2) | |
.attr("y", 0) | |
.attr("dy", "-.35em") | |
.attr("text-anchor", "middle") | |
.text(function (d) { | |
return d3.round(d.x, 1) | |
}) | |
.style("opacity", 1e-6) | |
.transition() | |
.delay(3250) | |
.duration(750) | |
.style("opacity", 1) | |
; | |
} | |
function markHistogramBar(d, i) { | |
// make all bars, except the hovered bar, semi transparent | |
var selectedBarId = 'histoBar-' + i; | |
his.selectAll('.histoBar') | |
.transition() | |
.duration(300) | |
.style('opacity', function (d, i) { | |
return ( d3.select(this).attr('id') != selectedBarId ) ? 0.3 : 1 | |
}); | |
highlightMeasurements(globalfirstVar, d.x, d.x + d.dx); | |
} | |
function unmarkHistogramBar(d, i) { | |
// remove transparency from all bars | |
his.selectAll('.histoBar').transition() | |
.duration(300) | |
.style('opacity', 1); | |
highlightMeasurements(null); | |
} | |
function highlightMeasurements(metric, lowerBound, upperBound) { | |
if (highlightTimer != null) { | |
clearTimeout(highlightTimer); | |
} | |
var watertype = d3.select("#watertypes").property("value"); | |
var watersource = d3.select("#watersources").property("value"); | |
highlightTimer = setTimeout(function () { | |
var needObj = measurementCircles; | |
if (isExists(detailsCircles)) | |
needObj = detailsCircles; | |
needObj.style('visibility', function (d, i) { | |
if (( ( metric == null ) || ( d[ metric ] >= lowerBound && d[ metric ] <= upperBound ) ) && | |
(watertype == "" || watertype == d.waterType) && (watersource == "" || watersource == d.waterSource)) { | |
return null; | |
} | |
else { | |
return 'hidden'; | |
} | |
}); | |
}, 350); | |
} | |
/** | |
* Update visibility settings based on selections | |
**/ | |
//to add: recalculate averages and number of measurements / done, i think | |
function updateVisibility() { | |
// kill pending visibility change set by function highlightMeasurements() | |
if (highlightTimer != null) { | |
clearTimeout(highlightTimer); | |
} | |
var watertype = d3.select("#watertypes").property("value"); | |
var watersource = d3.select("#watersources").property("value"); | |
d3.selectAll("circle") | |
.attr("visibility", function (d) { | |
return (watertype == "" || watertype == d.waterType) | |
&& (watersource == "" || watersource == d.waterSource) | |
? null | |
: "hidden"; | |
}); | |
// This bit updates the field containing the averages and other stats | |
filteredData = globalData.filter(function (d) { | |
return (watertype == "" || d.waterType == watertype) && watersource == "" || d.waterSource == watersource; | |
}); | |
gemfirstVar = d3.round(d3.mean(filteredData, function (d) { | |
return d[globalfirstVar]; | |
}), 2); | |
gemsecondVar = d3.round(d3.mean(filteredData, function (d) { | |
return d[globalsecondVar]; | |
}), 2); | |
//for histogram & stats | |
reeks = filteredData.map(function (d) { | |
return d[globalfirstVar]; | |
}); | |
//for reporting correct averages | |
if (reeks.length == 0) { | |
gemfirstVar = 0; | |
gemsecondVar = 0; | |
} | |
d3.select("#theNumbers") | |
.html("<span class=\"statlabel\">number of measurements: </span><span class=\"stat\">" + reeks.length + "</span><br/><br/><span class=\"statlabel\">average " + globalfirstVarlabel + " </span><span class=\"stat\">" + gemfirstVar + "</span><br/><span class=\"statlabel\">average " + globalsecondVarlabel + ": </span><span class=\"stat\">" + gemsecondVar + "</span>"); | |
updateData(); | |
} | |
/** | |
* Re-orient visualization when moved | |
**/ | |
function move() { | |
projection.translate(d3.event.translate).scale(d3.event.scale); | |
feature.attr("d", path); | |
d3.selectAll("circle") | |
.attr("transform", function (d) { | |
return "translate(" + projection(d.coordinates) + ")" | |
}); | |
//Adapt the size of the circles to de scale of the map so they don't get too small | |
q = projection.scale() / 3; | |
r.range([1 * (q / width), 6 * (q / width)]); | |
d3.select("#datapoints").selectAll("circle") | |
.attr("r", function (d) { | |
return r(d[globalsecondVar]); | |
}); | |
} | |
//rippler - makes rings around the circles; nicked from Jerome Cukier's version 14 | |
function ripple(d) { | |
svg.append("circle") | |
.attr("transform", function () { | |
return ("translate(" + projection(d.coordinates) + ")"); | |
}) | |
.attr("r", 200) | |
.style("stroke", "deepskyblue") | |
.style("stroke-opacity", .7) | |
.style("stroke-width", 2) | |
.style("fill", "none") | |
.transition() | |
.delay(250) | |
.duration(250) | |
.attr("r", 100) | |
.transition() | |
.delay(500) | |
.duration(250) | |
.attr("r", 50) | |
.transition() | |
.delay(750) | |
.duration(250) | |
.attr("r", 25) | |
.transition() | |
.delay(1000) | |
.duration(250) | |
.attr("r", 12) | |
.each("end", function () { | |
d3.select(this).remove(); | |
}); | |
} | |
d3.select("#experiments").on("change", updateDataset); | |
</script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment