// set up constants and containers var diameter = 850, format = d3.format(",d"); var pack = d3.layout.pack() .size([diameter - 30, diameter - 30]) .value(function(d) { return d.size; }) .padding(5); var svg = d3.select(".container").append("svg") .attr("width", diameter) .attr("height", diameter) .append("g") .attr("transform", "translate(20,10)"); var tip = d3.select("body").append("div") .attr("class", "tooltip") .style("opacity", 0); // get data var currentJson; var dataSet; var getNewData1 = function() { currentUrl = "dataPreModel.json"; d3.json(currentUrl, function(error, data) { currentJson = data; dataSet = 1; refresh(); }); } var getNewData2 = function() { currentUrl = "dataPostModel.json"; d3.json(currentUrl, function(error, data) { currentJson = data; dataSet = 2; refresh(); }); } // draw function var refresh = function() { var dur = 4000; var colorScaleTest = d3.scale.ordinal() .domain([d3.map(currentJson.children)]) .range(["#fc8d62","#66c2a5","#8da0cb","#feb24c"]); // 1 Market 2 Brand 3 Content 4 Demo var node = svg.selectAll(".node") .data(pack.nodes(currentJson), function(d) { return d.key; }); // data_importance data joined with all g elements // including a key function (using the identity function (d)) makes sure the same circles get transitioned var enter = node.enter().append("g") .attr("class", function(d) { return d.children ? "node" : "leaf node"; }) .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; }) d3.select("#button1").on("click", getNewData1); d3.select("#button2").on("click", getNewData2); var circles = enter.append("circle") .attr("r", 0) .transition() // trans.-attributes set by below upd.-sel .attr("r", function(d) { return d.r; }); // entered and transition circles r // set delay for staggered object constancy only for transition from constant to importance dataset (too slow for the other direction) if(dataSet == 2) { node.transition() .delay( function(d,i) { return i * 20; }) .duration(dur / 3) .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; }); // update circles x/y positions } else { node.transition() .duration(dur / 3) .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; }); // update circles x/y positions } node.select("circle") .transition() .duration(dur) .attr("fill", function(d) { return !d.children ? colorScaleTest(d.category) : "#BFBFBF"; }) .attr("stroke-width", function(d) { return !d.children ? 0 : 2; }) .attr("stroke", "#999") .attr("opacity", function(d) { return !d.children ? 1 : 0.25; }) .attr("r", function(d) { return d.r; }); // update circles radius var labels = enter.filter(function(d) { return !d.children; }).append("text") .attr("dy", ".3em") .style("text-anchor", "middle") .text(function(d) { return d.name.substring(0, d.r / 3); }); // enter labels node.selectAll("text").style("font-size", 0); node.filter(function(d) { return !d.children; }).select("text") .transition() .delay(dur) .attr("dy", ".3em") .style("text-anchor", "middle") .style("font-size", 10) // required alongside the ugly hack above .text(function(d) { return d.name.substring(0, d.r / 3); }); // update labels // tooltip and circle size on hover node.on("mouseover", function(d){ tip.style("opacity", .9); tip.html(d.name) .style("left", (d3.event.pageX) + "px") .style("top", (d3.event.pageY - 28) + "px"); if(!d.children){ d3.select(this.firstChild) .transition() .duration(dur/10) .ease("cubic") .attr("r", function(d) { return d.r * 1.2; }) .style("opacity", 0.9); } }); node.on("mouseout", function(d){ tip.style("opacity", 0); if(!d.children){ d3.select(this.firstChild) .transition() .duration(dur/10) .attr("r", function(d) { return d.r; }) .style("opacity", 1);; } }); // bars if(dataSet == 2){ node.filter(function(d) { return !d.children; }).on("click", function(d){ d3.select(".svgRightWrapper") .style("border-left-color","#BFBFBF") .style("border-left-width", "1px"); var svgRight = d3.select(".svgRightWrapper").append("svg") .classed("svgRight", true) .attr("width", 230) .attr("height", 100); var headline = svgRight.append("text") .text(d.name) .style("font-size", 10) .style("fill","#6C7A89") .style("font-weight", "bold") .attr("x", 0 ) .attr("y", 10); var barPotential = svgRight.append("rect") .attr("width", d.potential) .attr("height", 20) .attr("x", 0) .attr("y", 20) .style("fill","#6C7A89"); var barNonPotential = svgRight.append("rect") .attr("width", d.nonPotential) .attr("height", 20) .attr("x", 0) .attr("y", 41) .style("fill","#999"); var textPotential = svgRight.append("text") .text(d.potential + "% Potentials") .style("font-size", 10) .style("fill","#6C7A89") .attr("x", d.potential + 4 ) .attr("y", 20 + 20 / 2 + 10 / 4); // convoluted hack but works w. width / 2 + font-size / 4 var textNonPotential = svgRight.append("text") .text(d.nonPotential + "% Non-Potentials") .style("font-size", 10) .style("fill","#999") .attr("x", d.nonPotential + 4 ) .attr("y", 41 + 20 / 2 + 10 / 4); // convoluted hack but works w. width / 2 + font-size / 4 // exceptions if (d.name == "Age"){ textPotential.text(d.potential + " years Potentials"); textNonPotential.text(d.nonPotential + " years Non-Potentials"); } else if (d.name == "Children") { headline.text("No. of children (" + d.category + ")"); textPotential.text(d.potential + " Potentials") .attr("x", (d.potential * 10) + 4 ); textNonPotential.text(d.nonPotential + " Non-Potentials") .attr("x", (d.nonPotential * 10) + 4 ); barPotential.attr("width", d.potential * 10); barNonPotential.attr("width", d.nonPotential * 10); } else if (d.name == "Residence") { headline.text("Live in a flat (" + d.category + ")"); } else if (d.name == "Income") { textPotential.text("£" + d3.round((d.potential / 1000),0) + "k Potentials") .attr("x", (d.potential / 1000) + 4 ); textNonPotential.text("£" + d3.round((d.nonPotential / 1000),0) + "k Non-Potentials") .attr("x", (d.nonPotential / 1000) + 4 ); barPotential.attr("width", d.potential / 1000); barNonPotential.attr("width", d.nonPotential / 1000); } d3.select(".svgRightWrapper").on("dblclick", function(){ d3.select(this).remove(); }); }); } // exit node.exit() .transition() .duration(dur / 2) .style("opacity", 0) .remove(); // exit the node objects (= g elements incl. circle and text) } d3.select(self.frameElement).style("height", diameter + "px"); getNewData1();