D3
OG
Old school D3 from simpler times
All examples
By author
By category
About
amerval
Full window
Github gist
Income Distribution in New Zealand
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Treasury</title> <script type="text/javascript" src="https://d3js.org/d3.v3.js"></script> <style> text.txt { font-family: tahoma; } rect.backlistener { fill: none; pointer-events: all; } rect.background { fill: none; pointer-events: all; } rect.current { pointer-events: all; stroke: #222222; stroke-width: 2; } .axis path, .axis line { fill: none; stroke: black; shape-rendering: crispEdges; } .axis text { font-family: tahoma; font-size: 12px; } #tooltip { text-align: center; position: absolute; width: 200px; height: auto; padding: 10px; background-color: white; -webkit-border-radius: 10px; -moz-border-radius: 10px; border-radius: 10px; -webkit-box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4); -moz-box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4); box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4); pointer-events: none; } #tooltip.hidden { display: none; } #tooltip p { margin: 0; font-family: tahoma; font-size: 16px; line-height: 20px; } #basettip { text-align: center; position: absolute; width: 200px; height: auto; padding: 10px; background-color: white; -webkit-border-radius: 10px; -moz-border-radius: 10px; border-radius: 10px; -webkit-box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4); -moz-box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4); box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4); pointer-events: none; } #basettip.hidden { display: none; } #basettip p { margin: 0; font-family: tahoma; font-size: 16px; line-height: 20px; } #source { text-align: center; position: absolute; width: 200px; height: auto; padding: 10px; background-color: white; -webkit-border-radius: 10px; -moz-border-radius: 10px; border-radius: 10px; -webkit-box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4); -moz-box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4); box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4); pointer-events: none; } #source.hidden { display: none; } #source p { margin: 0; font-family: tahoma; font-size: 16px; line-height: 20px; } </style> </head> <body> <button id="byGender">View by Gender</button> <button id="byEthni">View by Ethnicity</button> <button id="byAge">View by Age group</button> <div id="tooltip" class="hidden"> <p><span id="people"> . </span></p> <p>That is <span id="percent"> 100.0 </span>% of this income tier.</p> </div> <div id="basettip" class="hidden"> <p><span id="people"> . </span></p> <p>That is <span id="percent"> 100.0 </span>% of the NZ population.</p> </div> <div id="source" class="hidden"> <p>*source: 2006 census</p> </div> <script type="text/javascript" src="../d3/d3.v3.js"></script> <script type="text/javascript"> var h=700, w=1200, margin=5, padding=20, wside = 300; var maxw = 600, maxwcur; var maxVal; var data, dnest, nodes; var NbLines; var caseDisplay; var xScale = d3.scale.linear(), spreadScale = d3.scale.ordinal(), yScale = d3.scale.linear().domain([0,50000,130000]).range([0,2*h/3,h]), yScaleAx = d3.scale.linear().domain([0,50000,130000]).range([h,h/3,0]), wScale = d3.scale.linear(), oScale = d3.scale.linear().domain([0,1]).range([0.2,0.9]) areaScale = d3.scale.linear(), cScale = d3.scale.linear().range(["#0033FF","#CC0000"]) toUnit = d3.scale.ordinal().rangeBands([0,1]) //cScale = d3.scale.category10(); var commasFormatter = d3.format(",.0f"); var yAxis = d3.svg.axis() .scale(yScaleAx) // scale to be used .orient("right") // position of the text (values) .tickValues([0,5000,10000,20000,50000,70000,100000]) .tickFormat(function(d) { return "$" + commasFormatter(d); }); var entier = d3.format(",.0f"), perc = d3.format(".1f"); var base, current, curlist; var listGender=["male","female"], listEthni = ["European","Maori","Pacific","Asian","Other"], listAge = ["15-19","20-29","30-39","40-49","50-59","60-69","70-79","80+"], nodesw = []; var hierarchy = d3.layout.partition().sort(null); var svg = d3.select("body").append("svg") .attr("width", w+200+wside+padding) .attr("height", h+2*padding) ; var gmain = svg.append("g") .attr("transform", "translate(" +(100+padding)+ "," +padding+ ")" ); var gside = svg.append("g") .attr("transform", "translate(" +(100+padding+w)+ "," +padding+ ")" ); gmain.append("rect") // background rectangle to listen to click events .attr("class", "background") .attr("width", w) .attr("height", h) .attr("transform", "translate(" +padding/2+ "," +padding/2+ ")" ) // .attr("stroke","#DDDDDD").attr("stroke-width",2).attr("stroke-opacity",0.5) .attr("fill","green").attr("opacity",0.3) .on("click", back); // "back" function will return to higher level d3.csv("incDistr.csv", function(dd){ data = dd; NbLines = data.length; for (ii=0;ii<NbLines;ii++){ data[ii].value = parseFloat(data[ii].value); data[ii].tierh = parseFloat(data[ii].tierh); data[ii].tierPos = parseFloat(data[ii].tierPos); } dnest = d3.nest() .key(function(d) { return d.tier; }) .entries(dd); nodes = {name: "totpop", children:[],tierh:0, tierPos:0}; for (ii=0;ii<dnest.length;ii++){ var tmp = [], add; tmp = {name: dnest[ii].key, children:[], tierh:dnest[ii].values[0].tierh, tierPos:dnest[ii].values[0].tierPos} for (jj=0;jj<dnest[ii].values.length;jj++){ tmp.children.push(dnest[ii].values[jj]) } nodes.children.push(tmp) } nodes = hierarchy(nodes); NbLines = nodes.length; maxVal = 0; var htmp; for (ii=1;ii<NbLines;ii++){if(nodes[ii].value>maxVal){maxVal=nodes[ii].value;}} areaScale.domain([0,maxVal]).range([0,(maxw*yScale(5000))]); for (ii=1;ii<NbLines;ii++){ if (nodes[ii].tierPos>50000) { nodes[ii].h = (yScale(50000+nodes[ii].tierh)-yScale(50000)-margin) nodes[ii].w = (areaScale(nodes[ii].value)/(yScale(50000+nodes[ii].tierh)-yScale(50000))); } else { nodes[ii].w = (areaScale(nodes[ii].value)/yScale(nodes[ii].tierh)) nodes[ii].h = (yScale(nodes[ii].tierh)-margin)} } nodesw[0] = 0; // display scale var aa = Math.sqrt(areaScale(10000)); scale = gside.append("rect") .attr("rx",6).attr("ry",6) .attr("y",100).attr("x",5) .attr("height",aa) .attr("width",aa) .attr("fill","none") .attr("stroke","#BBBBBB").style("stroke-dasharray",("3,2")).attr("stroke-width",2); gside.append("text").attr("class","txt") .attr("y", 100+aa/2).attr("x",aa+15) .attr("font-size","14px").attr("fill","#BBBBBB") .attr("text-anchor","left") .text("10,000 people"); // first display: level 0 caseDisplay = 0; base = gmain.selectAll(".base") .data(nodes).enter() .append("rect").attr("class","base") .attr("rx",6).attr("ry",6) .attr("y",function(d){return (h-yScale(d.tierPos));}) .attr("height",function(d,i){return (d.depth==1)?d.h:0}) .attr("width",function(d,i){return (d.depth==1)?d.w:0}) .attr("x",function(d,i){return (d.depth==1)?(w/2-d.w/2):0}) .attr("fill","#BBBBBB").attr("opacity",0.7); base.on("mouseover", basemov) .on("mouseout", basemout) svg.append("g") .attr("class","axis") .attr("transform", "translate("+(2*padding)+","+(padding/2)+")") .call(yAxis) ; d3.select("#byGender").on("click", function () { caseDisplay = 1; maxwcur = 0; // Re-organise nodes dnest = d3.nest() .key(function(d) { return d.tier; }) .key(function(d) { return d.gender; }) .entries(data); nodes = {name: "totpop", children:[],tierh:0, tierPos:0}; for (ii=0;ii<dnest.length;ii++){ var tmp = [], add; tmp = {name: dnest[ii].key, children:[], tierh:dnest[ii].values[0].values[0].tierh, tierPos:dnest[ii].values[0].values[0].tierPos} for (jj=0;jj<dnest[ii].values.length;jj++){ add = {name: dnest[ii].values[jj].key, children:[], tierh:dnest[ii].values[jj].values[0].tierh, tierPos:dnest[ii].values[jj].values[0].tierPos} for (kk=0;kk<dnest[ii].values[jj].values.length;kk++){ add.children.push(dnest[ii].values[jj].values[kk]) } tmp.children.push(add) } nodes.children.push(tmp) } nodes = hierarchy(nodes); toUnit.domain(listGender) cScale.domain([0,(1-toUnit.rangeBand())]) spreadScale.domain(listGender) curlist = listGender; createLayer(); }) d3.select("#byAge").on("click", function () { caseDisplay = 2; maxwcur = 0; // Re-organise nodes dnest = d3.nest() .key(function(d) { return d.tier; }) .key(function(d) { return d.agetier; }) .entries(data); nodes = {name: "totpop", children:[],tierh:0, tierPos:0}; for (ii=0;ii<dnest.length;ii++){ var tmp = [], add; tmp = {name: dnest[ii].key, children:[], tierh:dnest[ii].values[0].values[0].tierh, tierPos:dnest[ii].values[0].values[0].tierPos} for (jj=0;jj<dnest[ii].values.length;jj++){ add = {name: dnest[ii].values[jj].key, children:[], tierh:dnest[ii].values[jj].values[0].tierh, tierPos:dnest[ii].values[jj].values[0].tierPos} for (kk=0;kk<dnest[ii].values[jj].values.length;kk++){ add.children.push(dnest[ii].values[jj].values[kk]) } tmp.children.push(add) } nodes.children.push(tmp) } nodes = hierarchy(nodes); toUnit.domain(listAge) cScale.domain([0,(1-toUnit.rangeBand())]) spreadScale.domain(listAge) curlist = listAge; createLayer(); }) d3.select("#byEthni").on("click", function () { caseDisplay = 3; maxwcur = 0; // Re-organise nodes dnest = d3.nest() .key(function(d) { return d.tier; }) .key(function(d) { return d.ethnicity; }) .entries(data); nodes = {name: "totpop", children:[],tierh:0, tierPos:0}; for (ii=0;ii<dnest.length;ii++){ var tmp = [], add; tmp = {name: dnest[ii].key, children:[], tierh:dnest[ii].values[0].values[0].tierh, tierPos:dnest[ii].values[0].values[0].tierPos} for (jj=0;jj<dnest[ii].values.length;jj++){ add = {name: dnest[ii].values[jj].key, children:[], tierh:dnest[ii].values[jj].values[0].tierh, tierPos:dnest[ii].values[jj].values[0].tierPos} for (kk=0;kk<dnest[ii].values[jj].values.length;kk++){ add.children.push(dnest[ii].values[jj].values[kk]) } tmp.children.push(add) } nodes.children.push(tmp) } nodes = hierarchy(nodes); toUnit.domain(listEthni) cScale.domain([0,(1-toUnit.rangeBand())]) spreadScale.domain(listEthni); curlist = listEthni; createLayer(); }) }) function back(){ caseDisplay = 0; gmain.selectAll(".current").transition().duration(500) .attr("x",function(d){ return (d.depth==2)?(w/2+d.xx):0;}) base.on("mouseover", basemov) .on("mouseout", basemout) // gmain.selectAll(".base").transition().duration(1000).delay(500).attr("opacity",1); gmain.selectAll(".base").transition().duration(1000).delay(750).attr("opacity",1); gmain.selectAll(".current").transition().duration(1000).delay(750).attr("opacity",1e-6); gmain.selectAll(".current").transition().delay(1750).remove(); svg.selectAll(".backlistener").remove(); gmain.selectAll(".legend").remove(); } function createLayer() { maxwcur = 0; NbLines = nodes.length; for (ii=1;ii<NbLines;ii++){ if (nodes[ii].tierPos>50000) { nodes[ii].h = (yScale(50000+nodes[ii].tierh)-yScale(50000)-margin) nodes[ii].w = (areaScale(nodes[ii].value)/(yScale(50000+nodes[ii].tierh)-yScale(50000))); } else { nodes[ii].w = (areaScale(nodes[ii].value)/yScale(nodes[ii].tierh)) nodes[ii].h = (yScale(nodes[ii].tierh)-margin)} if (nodes[ii].depth==2) { wScale.domain([0,1]).range([0,nodes[ii].parent.w]); nodes[ii].w = wScale(nodes[ii].dx/nodes[ii].parent.dx); nodes[ii].xx = wScale((nodes[ii].x-nodes[ii].parent.x)/nodes[ii].parent.dx)-nodes[ii].parent.w/2; if (nodes[ii].w > maxwcur){maxwcur = nodes[ii].w;} } } nodesw[0] = 0; current = gmain.selectAll(".current") .data(nodes).enter() .append("rect").attr("class","current") .attr("rx",6).attr("ry",6) .attr("y",function(d){return (h-yScale(d.tierPos));}) .attr("height",function(d,i){return (d.depth==0)?0:d.h}) .attr("width",function(d){return (d.depth==2)?d.w:0}) .attr("x",function(d,i){ var wpar, xtmp; if (d.depth==2){ console.log(i+", "+d.xx) xtmp = d.xx; if (d.parent.maxdx>0){if (xtmp>d.parent.maxdx){d.parent.maxdx=xtmp; d.parent.wmaxdx=d.w}} else {d.parent.maxdx=xtmp; d.parent.wmaxdx=d.w} } else{xtmp=0} return w/2+xtmp;}) .attr("fill","#BBBBBB").attr("opacity",1e-6) .attr("stroke-opacity",1e-6) .on("click",Spread); spreadScale.rangeBands([maxwcur/2,w+maxwcur/2]); gmain.selectAll(".current").transition().duration(500) .attr("opacity",function(d){ return (d.depth>0)?(oScale(d.dx/d.parent.dx)):(1e-6)}) .attr("fill",function(d) {return cScale(toUnit(d.name))}); gmain.selectAll(".base").on("mouseover",null).on("mouseout",null).on("click",back) gmain.selectAll(".base").transition().duration(500).attr("opacity",1e-6); } function Spread() { gmain.selectAll(".current").transition().duration(500) .attr("x",function(d){var wtmp, xtmp; if (d.depth==2){ wtmp = d3.select(this).attr("width") xtmp = spreadScale(d.name)-wtmp/2; } else{xtmp=0} return xtmp;}) current.on("mouseover", function(d){ var txtmp, txtinc; var xPos = parseFloat(d3.select(this).attr("x")); var yPos = parseFloat(d3.select(this).attr("y")); d3.select(this).attr("stroke-opacity",1); if (d.depth==2){ var aa = d3.select("#tooltip") // .style("left", (xPos+200) + "px") .style("left", (w+100) + "px") // .style("top", (yPos+50) + "px"); .style("top", (h/2) + "px"); var nb = entier(d.value); var percent = perc((d.value/d.parent.value)*100); txtinc = extrTxtInc(d); switch (caseDisplay) { case 1: var bb; (d.name == "male")?(bb="* men "):(bb="* women "); txtmp = nb + bb + txtinc; break; case 3: txtmp = nb + "* people of "+d.name+" ethnicity" + txtinc; break; case 2: txtmp = nb + "* people aged " +d.name+ txtinc; break; } aa.select("#people").text(txtmp) aa.select("#percent").text(percent) d3.select("#tooltip").classed("hidden",false); d3.select("#source") .style("left", (w+100) + "px") .style("top", (h-100) + "px") .classed("hidden",false); } }) .on("mouseout", function(d){ d3.select(this).attr("stroke-opacity",1e-6); d3.select("#tooltip").classed("hidden",true); d3.select("#source").classed("hidden",true); }) // svg.append("svg:rect") // background rectangle to listen to click events // .attr("class", "backlistener") // .attr("width", w) // .attr("height", h) // .attr("transform", "translate(" +padding/2+ "," +padding/2+ ")" ) // .on("click", back); gmain.selectAll(".legend") .data(curlist).enter() .append("g").attr("class","legend") .attr("transform", function(d) { return "translate(" +spreadScale(d)+ "," +(h-20)+ ")" }) .append("text").attr("class","txt") .attr("y", 0) .attr("x",0) .attr("font-size","14px") .attr("text-anchor","middle") .attr("opacity",1e-6) .text(function (d){return d}); gmain.selectAll(".txt").transition().duration(500).delay(500) .attr("opacity",1) } function extrTxtInc(d) { var txtmp, t0 =" earn ", t1, t2=" yearly"; switch (d.parent.name) { case "No Income": t0 = " have " t1 = "no income"; t2 = ""; break; case "<5000": t1 = "between $1 and $5,000"; break; case "<10000": t1 = "between $5,000 and $10,000"; break; case "<15000": t1 = "between $10,000 and $15,000"; break;; case "<20000": t1 = "between $15,000 and $20,000"; break; case "<25000": t1 = "between $20,000 and $25,000"; break; case "<30000": t1 = "between $25,000 and $30,000"; break; case "<40000": t1 = "between $30,000 and $40,000"; break; case "<50000": t1 = "between $40,000 and $50,000"; break; case "<70000": t1 = "between $50,000 and $70,000"; break; case "<100000": t1 = "between $70,000 and $100,000"; break; case ">100000": t1 = "over $100,000"; break; } txtmp = t0+t1+t2; return txtmp; } function basemov(d) { var txtmp, txtinc; d3.select(this).attr("opacity",0.95); if (d.depth==1){ var aa = d3.select("#basettip") .style("left", (w+100) + "px") .style("top", (h/2) + "px"); var nb = entier(d.value); var percent = perc((d.value/d.parent.value)*100); var t0 =" earn ", t1, t2=" yearly"; switch (d.name) { case "No Income": t0 = " have " t1 = "no income"; t2 = ""; break; case "<5000": t1 = "between $1 and $5,000"; break; case "<10000": t1 = "between $5,000 and $10,000"; break; case "<15000": t1 = "between $10,000 and $15,000"; break;; case "<20000": t1 = "between $15,000 and $20,000"; break; case "<25000": t1 = "between $20,000 and $25,000"; break; case "<30000": t1 = "between $25,000 and $30,000"; break; case "<40000": t1 = "between $30,000 and $40,000"; break; case "<50000": t1 = "between $40,000 and $50,000"; break; case "<70000": t1 = "between $50,000 and $70,000"; break; case "<100000": t1 = "between $70,000 and $100,000"; break; case ">100000": t1 = "over $100,000"; break; } txtmp = nb +"* NZ residents"+t0+t1+" annually"; aa.select("#people").text(txtmp) aa.select("#percent").text(percent) d3.select("#basettip").classed("hidden",false); d3.select("#source") .style("left", (w+100) + "px") .style("top", (h-100) + "px") .classed("hidden",false); } } function basemout(d){ d3.select(this).attr("opacity",0.7); d3.select("#basettip").classed("hidden",true); d3.select("#source").classed("hidden",true); } </script> </body> </html>
Modified
http://d3js.org/d3.v3.js
to a secure url
https://d3js.org/d3.v3.js