|
<!DOCTYPE html> |
|
<html> |
|
|
|
<head> |
|
<meta http-equiv="content-type" content="text/html; charset=UTF8"> |
|
<title>A real time data visualization</title> |
|
|
|
|
|
<script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script> |
|
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.2/jquery.min.js"></script> |
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3-legend/1.10.0/d3-legend.js"></script> |
|
<script src="https://d3js.org/d3-queue.v2.min.js"></script> |
|
<script> |
|
q=d3_queue.queue(); |
|
</script> |
|
|
|
<style> |
|
|
|
|
|
|
|
|
|
#g0 { fill: #eafeea; } |
|
#g1 { fill: #d5fdd5; } |
|
#g2 { fill: #c1fcc1; } |
|
#g3 { fill: #acfbac; } |
|
#g4 { fill: #88e188; } |
|
#g5 { fill: #6aaf6a; } |
|
#g6 { fill: #4c7d4c; } |
|
#g7 { fill: #2d4b2d; } |
|
.g0 { fill: #eafeea; } |
|
.g1 { fill: #d5fdd5; } |
|
.g2 { fill: #c1fcc1; } |
|
.g3 { fill: #acfbac; } |
|
.g4 { fill: #88e188; } |
|
.g5 { fill: #6aaf6a; } |
|
.g6 { fill: #4c7d4c; } |
|
.g7 { fill: #2d4b2d; } |
|
|
|
.zipcode{stroke:black;} |
|
|
|
|
|
|
|
|
|
|
|
</style> |
|
</head> |
|
<body> |
|
|
|
|
|
<script> |
|
|
|
(function(){ |
|
var rectData=[] |
|
var scaleX |
|
var data; |
|
var dataGeo |
|
var dataZipcode={}; |
|
|
|
var dataCalls={}; |
|
|
|
|
|
var h = 600; |
|
var w = 550; |
|
var width=400; |
|
var svg =d3.select("body").append("svg") |
|
.attr("width",w) |
|
.attr("height",h) |
|
.attr("id","svgone"); |
|
|
|
|
|
var projection= d3.geo.albers() |
|
.scale(45000) |
|
.rotate([120.5,.25,0]); |
|
|
|
|
|
var path = d3.geo.path() |
|
.projection(projection); |
|
|
|
|
|
|
|
|
|
var quantize; |
|
|
|
|
|
|
|
var newData; |
|
|
|
var check; |
|
var newDict={}; |
|
var mapDict={}; |
|
//ordinal scale |
|
|
|
|
|
|
|
var ordinal=d3.scale.ordinal().domain(["#g0","#g1","#g2","#g3","#g4","#g5","#g6","#g7"]) |
|
.range(["#eafeea","#d5fdd5","#c1fcc1","#acfbac","#88e188","#6aaf6a","#4c7d4c","#2d4b2d"]) |
|
|
|
|
|
|
|
//mouseover mouseout |
|
|
|
var selecetion; |
|
|
|
var mouseover= function(d){ |
|
var z = this.getAttribute('class') |
|
console.log(z) |
|
if(z.slice(0,1)=="y"){ |
|
|
|
var z = this.getAttribute('class'); |
|
var y = z.slice(1,6); |
|
d3.select("." + this.getAttribute('class')) |
|
.style("fill","orange") |
|
|
|
d3.select('.z'+y) |
|
.style("fill","orange") |
|
|
|
d3.select('#svgone') |
|
.append("text") |
|
.attr("class","text") |
|
.attr({ |
|
x:5, |
|
y:250, |
|
"font-size": "12px", |
|
"font-family":"Sans-Serif" |
|
|
|
|
|
|
|
}) |
|
.text("Name: "+d.properties.PO_NAME) |
|
|
|
d3.select('#svgone') |
|
.append("text") |
|
.attr("class","text") |
|
.attr({ |
|
x:5, |
|
y:260, |
|
"font-size": "12px", |
|
"font-family":"Sans-Serif" |
|
|
|
|
|
|
|
}) |
|
.text("Zipcode: " +d.properties.ZIP5+ ", Calls: " +newDict[d.properties.ZIP5])} |
|
|
|
|
|
|
|
else{ |
|
var z = this.getAttribute('class'); |
|
var y = z.slice(1,6); |
|
d3.select("." + this.getAttribute('class')) |
|
.style("fill","orange"); |
|
|
|
d3.select('.y'+y) |
|
.style("fill","orange") |
|
|
|
d3.select('#svgone') |
|
.append("text") |
|
.attr("class","text") |
|
.attr({ |
|
x:5, |
|
y:250, |
|
"font-size": "12px", |
|
"font-family":"Sans-Serif" |
|
|
|
|
|
|
|
}) |
|
.text("Name: "+mapDict[d.zipcode].name) |
|
|
|
d3.select('#svgone') |
|
.append("text") |
|
.attr("class","text") |
|
.attr({ |
|
x:5, |
|
y:260, |
|
"font-size": "12px", |
|
"font-family":"Sans-Serif" |
|
|
|
|
|
|
|
}) |
|
.text("Zipcode: " +mapDict[d.zipcode].zipcode+ ", Calls: " +mapDict[d.zipcode].calls)} |
|
|
|
|
|
}; |
|
|
|
|
|
var mouseout= function(d){ |
|
|
|
var z = this.getAttribute('class') |
|
|
|
console.log(z.slice(0,1)=="y") |
|
if(z.slice(0,1)=="y"){ |
|
|
|
var z = this.getAttribute('class'); |
|
var y = z.slice(1,6); |
|
var color=ordinal('#'+quantize(newDict[d.properties.ZIP5])) |
|
console.log(color) |
|
d3.select("." + this.getAttribute('class')) |
|
.style("fill",ordinal('#'+quantize(newDict[d.properties.ZIP5]))) |
|
|
|
|
|
|
|
d3.select('.z'+y) |
|
.style("fill",ordinal('#'+quantize(newDict[d.properties.ZIP5]))) |
|
|
|
d3.selectAll(".text").remove() |
|
|
|
}else{ |
|
console.log(d.calls) |
|
console.log('#'+quantize(d.calls)) |
|
console.log(ordinal(quantize(d.calls))) |
|
var z = this.getAttribute('class'); |
|
var y = z.slice(1,6); |
|
d3.select("." + this.getAttribute('class')) |
|
.style("fill",ordinal('#'+quantize(d.calls))); |
|
|
|
d3.select('.y'+y) |
|
.style("fill",ordinal('#'+quantize(d.calls)))} |
|
|
|
d3.selectAll('.text').remove(); |
|
|
|
|
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//defer double request |
|
|
|
q.defer(d3.json,"http://saccounty.cloudapi.junar.com/api/v2/datastreams/311-CASES-BY-ZIPCO-SUMMA/data.json/?auth_key=77bf2351cdb42d68f577b6c54041550cf708b773") |
|
.defer(d3.json,"saczipgeo.json") |
|
.awaitAll(ready) |
|
|
|
|
|
function ready(error,first){ |
|
if(error){alert("You had an error retrieving data");} |
|
//preparing data and everything for first json file |
|
|
|
data=first; |
|
data=data[0]; |
|
data.result.fArray.forEach(function(value,i){ |
|
if(i%2==0){ |
|
dataZipcode[i]=data.result.fArray[i].fStr |
|
} |
|
if(i%2!=0){ |
|
dataCalls[i]=data.result.fArray[i].fStr |
|
} |
|
}); |
|
|
|
data=[]; |
|
for ( i=0;i<=108;i=i+2){ |
|
if(i==0){ |
|
data[i]={"zipcode":dataZipcode[i],"calls":dataCalls[i+1]}; |
|
} |
|
data[i/2]={"zipcode":dataZipcode[i],"calls":dataCalls[i+1]}; |
|
}; |
|
|
|
//scale for data colors |
|
|
|
|
|
var maxD=d3.max(data.slice(1,data.length-1),function(d){return parseInt(d.calls)}); |
|
console.log(maxD); |
|
var minD=d3.min(data.slice(1,data.length-1),function(d){return d.calls}); |
|
|
|
quantize= d3.scale.quantize() |
|
.domain([0,maxD]) |
|
.range(d3.range(8).map(function(i) { return "g"+i; })); |
|
|
|
|
|
data.forEach(function(d){return newDict[d.zipcode]= +d.calls;}); |
|
|
|
|
|
//preparing for the second json |
|
|
|
dataGeo=first[1]; |
|
dataGeo=dataGeo.features |
|
|
|
//checking for zipcodes that had zero calls(will be undefined in the dataMap object |
|
|
|
for(i=0;i<dataGeo.length;i++){ |
|
if (newDict[dataGeo[i].properties.ZIP5] === undefined){ |
|
newDict[dataGeo[i].properties.ZIP5]=0; |
|
}; |
|
|
|
|
|
}; |
|
|
|
svg.selectAll("zipcode") |
|
.data(dataGeo) |
|
.enter().append("path") |
|
.attr("d", path) |
|
.attr("class",function(d){return 'y'+ d.properties.ZIP5}) |
|
.attr("id",function(d){return quantize(newDict[d.properties.ZIP5])}) |
|
.attr("stroke","black") |
|
.on("mouseover",mouseover) |
|
.on("mouseout",mouseout) |
|
|
|
|
|
|
|
var svg2=d3.select("body") |
|
.append("svg") |
|
.attr({ |
|
width: width, |
|
height:h, |
|
id:"svgtwo" |
|
|
|
}); |
|
|
|
scaleX = d3.scale.linear() |
|
.domain([0,maxD]) |
|
.range([0,width]); |
|
|
|
|
|
|
|
for(i=0;i<dataGeo.length;i++){ |
|
|
|
rectData[i] = {"zipcode":dataGeo[i].properties.ZIP5,"calls":newDict[dataGeo[i].properties.ZIP5]} |
|
}; |
|
|
|
|
|
rectData.sort(function(a, b){ |
|
return b.calls-a.calls; |
|
}) |
|
|
|
var barPadding=1; |
|
svg2.selectAll("rect") |
|
.data(rectData) |
|
.enter() |
|
.sort(function(a, b) { |
|
return d3.ascending(a, b); |
|
}) |
|
.append("rect") |
|
.attr("width",function(d){return scaleX(d.calls)}) |
|
.attr("height", function(d,i){return (h/rectData.length)-barPadding;}) |
|
.attr("y",function(d,i){return (h/rectData.length)*i;}) |
|
.attr("id",function(d){return quantize(d.calls)}) |
|
.attr("class",function(d){return 'z'+d.zipcode;}) |
|
.on("mouseover",mouseover) |
|
.on("mouseout",mouseout); |
|
|
|
|
|
|
|
|
|
for(i=0;i<dataGeo.length;i++){ |
|
mapDict[dataGeo[i].properties.ZIP5]={'name':dataGeo[i].properties.PO_NAME,'zipcode':dataGeo[i].properties.ZIP5,'calls':newDict[dataGeo[i].properties.ZIP5]}; |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
d3.select('#svgtwo') |
|
.append('line') |
|
.attr({ |
|
x1:0, |
|
y1:0, |
|
x2:0, |
|
y2:h, |
|
"stroke-width":"1px", |
|
"stroke":"black", |
|
}); |
|
|
|
|
|
//legend |
|
|
|
|
|
|
|
svg.append("g") |
|
.attr("class", "legendQuant") |
|
.attr("transform", "translate(350,450)"); |
|
|
|
var legend = d3.legend.color() |
|
.labelFormat(d3.format(".2f")) |
|
.useClass(true) |
|
.scale(quantize); |
|
|
|
svg.select(".legendQuant") |
|
.call(legend); |
|
|
|
|
|
|
|
};})(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
</script> |
|
for more info or data vist <a href="http://data.saccounty.net/home">http://data.saccounty.net/home</a> |
|
</body> |
|
|
|
|
|
|
|
|
|
<html> |