Skip to content

Instantly share code, notes, and snippets.

@pjahoorkar
Created July 14, 2017 16:14
Show Gist options
  • Select an option

  • Save pjahoorkar/83be6c484f90de79e60c90321c8fdc63 to your computer and use it in GitHub Desktop.

Select an option

Save pjahoorkar/83be6c484f90de79e60c90321c8fdc63 to your computer and use it in GitHub Desktop.
fresh block
license: mit
/*//////////////////////////////////////////////////////////
////////////////// Set up the Data /////////////////////////
//////////////////////////////////////////////////////////*/
var NameProvider = ["Apple","HTC","Huawei","LG","Nokia","Samsung","Sony","Other"];
var matrix = [
[9.6899,0.8859,0.0554,0.443,2.5471,2.4363,0.5537,2.5471], /*Apple 19.1584*/
[0.1107,1.8272,0,0.4983,1.1074,1.052,0.2215,0.4983], /*HTC 5.3154*/
[0.0554,0.2769,0.2215,0.2215,0.3876,0.8306,0.0554,0.3322], /*Huawei 2.3811*/
[0.0554,0.1107,0.0554,1.2182,1.1628,0.6645,0.4983,1.052], /*LG 4.8173*/
[0.2215,0.443,0,0.2769,10.4097,1.2182,0.4983,2.8239], /*Nokia 15.8915*/
[1.1628,2.6024,0,1.3843,8.7486,16.8328,1.7165,5.5925], /*Samsung 38.0399*/
[0.0554,0.4983,0,0.3322,0.443,0.8859,1.7719,0.443], /*Sony 4.4297*/
[0.2215,0.7198,0,0.3322,1.6611,1.495,0.1107,5.4264] /*Other 9.9667*/
];
/*Sums up to exactly 100*/
var colors = ["#C4C4C4","#69B40F","#EC1D25","#C8125C","#008FC8","#10218B","#134B24","#737373"];
/*Initiate the color scale*/
var fill = d3.scale.ordinal()
.domain(d3.range(NameProvider.length))
.range(colors);
/*//////////////////////////////////////////////////////////
/////////////// Initiate Chord Diagram /////////////////////
//////////////////////////////////////////////////////////*/
var margin = {top: 30, right: 25, bottom: 20, left: 25},
width = 650 - margin.left - margin.right,
height = 600 - margin.top - margin.bottom,
innerRadius = Math.min(width, height) * .39,
outerRadius = innerRadius * 1.04;
/*Initiate the SVG*/
var svg = d3.select("#chart").append("svg:svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("svg:g")
.attr("transform", "translate(" + (margin.left + width/2) + "," + (margin.top + height/2) + ")");
var chord = d3.layout.chord()
.padding(.04)
.sortSubgroups(d3.descending) /*sort the chords inside an arc from high to low*/
.sortChords(d3.descending) /*which chord should be shown on top when chords cross. Now the biggest chord is at the bottom*/
.matrix(matrix);
/*//////////////////////////////////////////////////////////
////////////////// Draw outer Arcs /////////////////////////
//////////////////////////////////////////////////////////*/
var arc = d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius);
var g = svg.selectAll("g.group")
.data(chord.groups)
.enter().append("svg:g")
.attr("class", function(d) {return "group " + NameProvider[d.index];});
g.append("svg:path")
.attr("class", "arc")
.style("stroke", function(d) { return fill(d.index); })
.style("fill", function(d) { return fill(d.index); })
.attr("d", arc)
.style("opacity", 0)
.transition().duration(1000)
.style("opacity", 0.4);
/*//////////////////////////////////////////////////////////
////////////////// Initiate Ticks //////////////////////////
//////////////////////////////////////////////////////////*/
var ticks = svg.selectAll("g.group").append("svg:g")
.attr("class", function(d) {return "ticks " + NameProvider[d.index];})
.selectAll("g.ticks")
.attr("class", "ticks")
.data(groupTicks)
.enter().append("svg:g")
.attr("transform", function(d) {
return "rotate(" + (d.angle * 180 / Math.PI - 90) + ")"
+ "translate(" + outerRadius+40 + ",0)";
});
/*Append the tick around the arcs*/
ticks.append("svg:line")
.attr("x1", 1)
.attr("y1", 0)
.attr("x2", 5)
.attr("y2", 0)
.attr("class", "ticks")
.style("stroke", "#FFF");
/*Add the labels for the %'s*/
ticks.append("svg:text")
.attr("x", 8)
.attr("dy", ".35em")
.attr("class", "tickLabels")
.attr("transform", function(d) { return d.angle > Math.PI ? "rotate(180)translate(-16)" : null; })
.style("text-anchor", function(d) { return d.angle > Math.PI ? "end" : null; })
.text(function(d) { return d.label; })
.attr('opacity', 0);
/*//////////////////////////////////////////////////////////
////////////////// Initiate Names //////////////////////////
//////////////////////////////////////////////////////////*/
g.append("svg:text")
.each(function(d) { d.angle = (d.startAngle + d.endAngle) / 2; })
.attr("dy", ".35em")
.attr("class", "titles")
.attr("text-anchor", function(d) { return d.angle > Math.PI ? "end" : null; })
.attr("transform", function(d) {
return "rotate(" + (d.angle * 180 / Math.PI - 90) + ")"
+ "translate(" + (innerRadius + 55) + ")"
+ (d.angle > Math.PI ? "rotate(180)" : "");
})
.attr('opacity', 0)
.text(function(d,i) { return NameProvider[i]; });
/*//////////////////////////////////////////////////////////
//////////////// Initiate inner chords /////////////////////
//////////////////////////////////////////////////////////*/
var chords = svg.selectAll("path.chord")
.data(chord.chords)
.enter().append("svg:path")
.attr("class", "chord")
.style("stroke", function(d) { return d3.rgb(fill(d.source.index)).darker(); })
.style("fill", function(d) { return fill(d.source.index); })
.attr("d", d3.svg.chord().radius(innerRadius))
.attr('opacity', 0);
/*//////////////////////////////////////////////////////////
///////////// Initiate Progress Bar ////////////////////////
//////////////////////////////////////////////////////////*/
/*Initiate variables for bar*/
var progressColor = ["#D1D1D1","#949494"],
progressClass = ["prgsBehind","prgsFront"],
prgsWidth = 0.4*650,
prgsHeight = 3;
/*Create SVG to visualize bar in*/
var progressBar = d3.select("#progress").append("svg")
.attr("width", prgsWidth)
.attr("height", 3*prgsHeight);
/*Create two bars of which one has a width of zero*/
progressBar.selectAll("rect")
.data([prgsWidth, 0])
.enter()
.append("rect")
.attr("class", function(d,i) {return progressClass[i];})
.attr("x", 0)
.attr("y", 0)
.attr("width", function (d) {return d;})
.attr("height", prgsHeight)
.attr("fill", function(d,i) {return progressColor[i];});
/*//////////////////////////////////////////////////////////
/////////// Initiate the Center Texts //////////////////////
//////////////////////////////////////////////////////////*/
/*Create wrapper for center text*/
var textCenter = svg.append("g")
.attr("class", "explanationWrapper");
/*Starting text middle top*/
var middleTextTop = textCenter.append("text")
.attr("class", "explanation")
.attr("text-anchor", "middle")
.attr("x", 0 + "px")
.attr("y", -24*10/2 + "px")
.attr("dy", "1em")
.attr("opacity", 1)
.text("For the Dutch version of the Deloitte Global Mobile Consumer Survey, Deloitte asked 2000 residents of the Netherlands about their mobile phone behavior")
.call(wrap, 350);
/*Starting text middle bottom*/
var middleTextBottom = textCenter.append("text")
.attr("class", "explanation")
.attr("text-anchor", "middle")
.attr("x", 0 + "px")
.attr("y", 24*3/2 + "px")
.attr("dy", "1em")
.attr('opacity', 1)
.text("The respondents gave us information about the brand of their current main phone, and the brand of their previous main phone")
.call(wrap, 350);
/*//////////////////////////////////////////////////////////
//////////////// Storyboarding Steps ///////////////////////
//////////////////////////////////////////////////////////*/
var counter = 1,
buttonTexts = ["Ok","Go on","Continue","Okay","Go on","Continue","Okay","Continue",
"Continue","Continue","Continue","Continue","Continue","Finish"],
opacityValueBase = 0.8,
opacityValue = 0.4;
/*Reload page*/
d3.select("#reset")
.on("click", function(e) {location.reload();});
/*Skip to final visual right away*/
d3.select("#skip")
.on("click", finalChord);
/*Order of steps when clicking button*/
d3.select("#clicker")
.on("click", function(e){
if(counter == 1) Draw1();
else if(counter == 2) Draw2();
else if(counter == 3) Draw3();
else if(counter == 4) Draw4();
else if(counter == 5) Draw5();
else if(counter == 6) Draw6();
else if(counter == 7) Draw7();
else if(counter == 8) Draw8();
else if(counter == 9) Draw9();
else if(counter == 10) Draw10();
else if(counter == 11) Draw11();
else if(counter == 12) Draw12();
else if(counter == 13) Draw13();
else if(counter == 14) Draw14();
else if(counter == 15) finalChord();
counter = counter + 1;
});
/*//////////////////////////////////////////////////////////
//Introduction
///////////////////////////////////////////////////////////*/
function Draw1(){
/*First disable click event on clicker button*/
stopClicker();
/*Show and run the progressBar*/
runProgressBar(time=700*11);
changeTopText(newText = "These days most people switch phones every few years. " +
"Some people stay loyal, but many also switch to a different phone brand...",
loc = 4/2, delayDisappear = 0, delayAppear = 1);
changeTopText(newText = "In the next few steps I would like to introduce you to the flows of people between the phone brands ",
loc = 8/2, delayDisappear = 9, delayAppear = 10, finalText = true);
changeBottomText(newText = "Let's start by drawing out the division of the 1846 respondents, that have had at least 2 phones, among the biggest 7 brands ",
loc = 1/2, delayDisappear = 0, delayAppear = 10);
//Remove arcs again
d3.selectAll(".arc")
.transition().delay(9*700).duration(2100)
.style("opacity", 0)
.each("end", function() {d3.selectAll(".arc").remove();});
};/*Draw1*/
/*//////////////////////////////////////////////////////////
//Show Arc of Apple
//////////////////////////////////////////////////////////*/
function Draw2(){
/*First disable click event on clicker button*/
stopClicker();
/*Show and run the progressBar*/
runProgressBar(time=700*2);
/*Initiate all arcs but only show the Apple arc (d.index = 0)*/
g.append("svg:path")
.style("stroke", function(d) { return fill(d.index); })
.style("fill", function(d) { return fill(d.index); })
.transition().duration(700)
.attr("d", arc)
.attrTween("d", function(d) {
if(d.index == 0) {
var i = d3.interpolate(d.startAngle, d.endAngle);
return function(t) {
d.endAngle = i(t);
return arc(d);
}
}
});
/*Show the tick around the Apple arc*/
d3.selectAll("g.group").selectAll("line")
.transition().delay(700).duration(1000)
.style("stroke", function(d, i, j) {return j ? 0 : "#000"; });
/*Add the labels for the %'s at Apple*/
d3.selectAll("g.group").selectAll(".tickLabels")
.transition().delay(700).duration(2000)
.attr("opacity", function(d, i, j) {return j ? 0 : 1; });
/*Show the Apple name*/
d3.selectAll(".titles")
.transition().duration(2000)
.attr("opacity", function(d, i) {return d.index ? 0 : 1; });
/*Switch text*/
changeTopText(newText = "According to the survey 19% owns an iPhone as their main phone",
loc = 1/2, delayDisappear = 0, delayAppear = 1, finalText = true);
changeBottomText(newText = "",
loc = 0/2, delayDisappear = 0, delayAppear = 1) ;
};/*Draw2*/
/*///////////////////////////////////////////////////////////
//Draw the other arcs as well
//////////////////////////////////////////////////////////*/
function Draw3(){
/*First disable click event on clicker button*/
stopClicker();
var arcDelay = [0,1,2,12,13,23,33,34,35,40,47];
/*Show and run the progressBar*/
runProgressBar(time=700*(arcDelay[(arcDelay.length-1)]+1));
/*Fill in the other arcs*/
svg.selectAll("g.group").select("path")
.transition().delay(function(d, i) { return 700*arcDelay[i];}).duration(1000)
.attrTween("d", function(d) {
if(d.index != 0) {
var i = d3.interpolate(d.startAngle, d.endAngle);
return function(t) {
d.endAngle = i(t);
return arc(d);
}
}
});
/*Make the other strokes black as well*/
svg.selectAll("g.group")
.transition().delay(function(d,i) { return 700*arcDelay[i]; }).duration(700)
.selectAll("g").selectAll("line").style("stroke", "#000");
/*Same for the %'s*/
svg.selectAll("g.group")
.transition().delay(function(d,i) { return 700*arcDelay[i]; }).duration(700)
.selectAll("g").selectAll("text").style("opacity", 1);
/*And the Names of each Arc*/
svg.selectAll("g.group")
.transition().delay(function(d,i) { return 700*arcDelay[i]; }).duration(700)
.selectAll("text").style("opacity", 1);
/*Change the text of the top section inside the circle accordingly*/
/*HTC*/
changeTopText(newText = "HTC has 5% of the market share",
loc = 6/2, delayDisappear = 0, delayAppear = arcDelay[2]);
/*LG*/
changeTopText(newText = "LG has almost 5% of the market",
loc = 6/2, delayDisappear = arcDelay[3], delayAppear = arcDelay[4]);
/*Samsung*/
changeTopText(newText = "Samsung has the biggest share by far, with 38% of respondents using a Samsung as their main phone",
loc = 3/2, delayDisappear = (arcDelay[5]-1), delayAppear = arcDelay[5]);
/*Sony*/
changeTopText(newText = "Sony has slightly more than 4% share",
loc = 4/2, delayDisappear = arcDelay[6], delayAppear = (arcDelay[8]-1));
/*100%*/
changeTopText(newText = "Together that sums up to 100%",
loc = 1/2, delayDisappear = (arcDelay[9]-1), delayAppear = arcDelay[9]);
/*Chord intro*/
changeTopText(newText = "This circle shows how the respondents are currently divided between the brands",
loc = 8/2, delayDisappear = (arcDelay[10]-1), delayAppear = arcDelay[10], finalText = true);
/*Change the text of the bottom section inside the circle accordingly*/
/*Huawei*/
changeBottomText(newText = "Huawei came from practically no share in 2013 to 2.4% in 2014 thereby taking its place in the biggest 7 brands in the Netherlands",
loc = -2/2, delayDisappear = 0, delayAppear = arcDelay[2]);
/*Nokia*/
changeBottomText(newText = "Nokia is still owned by 15% of the respondents. However practically all of these phones are ordinary phones, not smartphones",
loc = -1/2, delayDisappear = arcDelay[3], delayAppear = arcDelay[4]);
/*Other*/
changeBottomText(newText = "Brands combined in \"Other\" are Blackberry, Motorola, Google Nexus and Operator branded",
loc = -1/2, delayDisappear = (arcDelay[5]-1), delayAppear = (arcDelay[8]-1));
/*Chord intro*/
changeBottomText(newText = "Now we're going to look at how these respondents flowed from their previous phone to their present one",
loc = 1/2, delayDisappear = (arcDelay[9]-1), delayAppear = arcDelay[10]);
};/*Draw3*/
/*///////////////////////////////////////////////////////////
//Show the chord between Samsung and Nokia
//////////////////////////////////////////////////////////*/
function Draw4(){
/*First disable click event on clicker button*/
stopClicker();
/*Show and run the progressBar*/
runProgressBar(time=700*2);
/*Samsung and Nokia intro text*/
changeTopText(newText = "First, let's only look at the respondents that now own a Samsung, but whose previous phone was a Nokia and vice versa",
loc = 5, delayDisappear = 0, delayAppear = 1, finalText = true);
/*Bottom text disappear*/
changeBottomText(newText = "",
loc = 0, delayDisappear = 0, delayAppear = 1);
/*Make the non Samsung & Nokia arcs less visible*/
svg.selectAll("g.group").select("path")
.transition().duration(1000)
.style("opacity", function(d) {
if(d.index != 4 && d.index != 5) {return opacityValue;}
});
/*Make the other strokes less visible*/
d3.selectAll("g.group").selectAll("line")
.transition().duration(700)
.style("stroke",function(d,i,j) {if (j == 5 || j == 4) {return "#000";} else {return "#DBDBDB";}});
/*Same for the %'s*/
svg.selectAll("g.group")
.transition().duration(700)
.selectAll(".tickLabels").style("opacity",function(d,i,j) {if (j == 5 || j == 4) {return 1;} else {return opacityValue;}});
/*And the Names of each Arc*/
svg.selectAll("g.group")
.transition().duration(700)
.selectAll(".titles").style("opacity", function(d) { if(d.index == 4 || d.index == 5) {return 1;} else {return opacityValue;}});
/*Show only the Samsung Nokia chord*/
chords.transition().duration(2000)
.attr("opacity", function(d, i) {
if(d.source.index == 5 && d.target.index == 4)
{return opacityValueBase;}
else {return 0;}
});
};/*Draw4*/
/*//////////////////////////////////////////////////////////////////////////*/
function Draw5(){
/*First disable click event on clicker button*/
stopClicker();
/*Show and run the progressBar*/
runProgressBar(time=700*2);
/*Samsung and Nokia text*/
changeTopText(newText = "On the left, touching the arc of Samsung, we can see that the chord runs from 17% to almost 26%. Which is a thickness spanning 9%",
loc = 5, delayDisappear = 0, delayAppear = 1, finalText = true);
/*Make the non Samsung & Nokia arcs less visible*/
svg.selectAll("g.group").select("path")
.transition().duration(1000)
.style("opacity", opacityValue);
/*Show only the Samsung Nokia part at Samsung*/
var arcSamsung = d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius)
.startAngle(4.040082626337902)
.endAngle(4.561777856121815);
svg.append("path")
.attr("class","SamsungToNokiaArc")
.attr("d", arcSamsung)
.attr("fill", colors[5])
.style('stroke', colors[5]);
repeat();
/*Repeatedly let an arc change colour*/
function repeat() {
d3.selectAll(".SamsungToNokiaArc")
.transition().duration(700)
.attr("fill", "#9FA6D0")
.style('stroke', "#9FA6D0")
.transition().duration(700)
.attr("fill", colors[5])
.style('stroke', colors[5])
.each("end", repeat)
;
};
};/*Draw5*/
/*//////////////////////////////////////////////////////////////////////////*/
function Draw6(){
/*First disable click event on clicker button*/
stopClicker();
/*Show and run the progressBar*/
runProgressBar(time=700*2);
/*Samsung and Nokia text*/
changeTopText(newText = "These 9% of the respondents now own a Samsung and by following the chord we can see what brand they used to own, which in this case, is Nokia",
loc = 5, delayDisappear = 0, delayAppear = 1, finalText = true);
/*Show only the Samsung Nokia part at Nokia*/
var arcNokia = d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius)
.startAngle(2.837816067671451)
.endAngle(2.9104595910835127);
svg.append("path")
.attr("class","NokiaToSamsungArc")
.attr("d", arcNokia)
.attr("opacity", 0)
.attr("fill", colors[4])
.transition().duration(700)
.attr("opacity", 1)
.attr("stroke", colors[4]);
};/*Draw6*/
/*//////////////////////////////////////////////////////////////////////////*/
function Draw7(){
/*First disable click event on clicker button*/
stopClicker();
/*Show and run the progressBar*/
runProgressBar(time=700*11);
/*Samsung and Nokia text*/
changeTopText(newText = "At the Nokia side, the arc is much thinner, only spanning 1.2% (of respondents)",
loc = 4, delayDisappear = 0, delayAppear = 1);
changeTopText(newText = "These 1.2% now own a Nokia, but by following the chord we can see that they had a Samsung before",
loc = 4, delayDisappear = 9, delayAppear = 10, finalText = true);
/*Stop the color changing on the Samsung side*/
d3.selectAll(".SamsungToNokiaArc")
.transition().duration(700)
.attr("fill", colors[5])
.style("stroke", colors[5]);
/*Repeatedly let an arc change colour*/
repeat();
function repeat() {
d3.selectAll(".NokiaToSamsungArc")
.transition().duration(700)
.attr("fill", "#99D2E9")
.style('stroke', "#99D2E9")
.transition().duration(700)
.attr("fill", colors[4])
.style("stroke", colors[4])
.each("end", repeat)
;
};
};/*Draw7*/
/*//////////////////////////////////////////////////////////////////////////*/
function Draw8(){
/*First disable click event on clicker button*/
stopClicker();
/*Show and run the progressBar*/
runProgressBar(time=700*11);
/*Samsung and Nokia text*/
changeTopText(newText = "Since the chord is much wider at the Samsung side, Samsung has taken a lot more clients from Nokia than Nokia managed to take from Samsung",
loc = 5, delayDisappear = 0, delayAppear = 1);
changeTopText(newText = "Therefore, the chord is the color of Samsung blue, since Samsung has the net gain from the exchange of people between Nokia and Samsung",
loc = 5, delayDisappear = 9, delayAppear = 10, finalText = true);
/*Stop the colour changing on the Nokia side*/
d3.selectAll(".NokiaToSamsungArc")
.transition().duration(700)
.attr("fill", colors[4])
.style("stroke", colors[4]);
};/*Draw8*/
/*///////////////////////////////////////////////////////////
//Show Loyalty hills
//////////////////////////////////////////////////////////*/
function Draw9(){
/*First disable click event on clicker button*/
stopClicker();
/*Show and run the progressBar*/
runProgressBar(time=700*20);
/*Samsung Loyal text*/
changeTopText(newText = "There are also people that stay loyal and did not switch brands between their previous and current phone",
loc = 4/2, delayDisappear = 0, delayAppear = 1, finalText = false, xloc=-50, w=300);
changeTopText(newText = "These loyal respondents are represented by the hills at each brand",
loc = 3/2, delayDisappear = 9, delayAppear = 10, finalText = false, xloc=-50, w=300);
changeTopText(newText = "You can also envision this as a chord beginning and ending on itself",
loc = 2/2, delayDisappear = 18, delayAppear = 19, finalText = true, xloc=-50, w=300);
/*Remove the arcs*/
d3.selectAll(".NokiaToSamsungArc")
.transition().duration(2000)
.attr("opacity", 0)
.each("end", function() {d3.selectAll(".NokiaToSamsungArc").remove();});
d3.selectAll(".SamsungToNokiaArc")
.transition().duration(2000)
.attr("opacity", 0)
.each("end", function() {d3.selectAll(".SamsungToNokiaArc").remove();});
/*Show only the loyal chords*/
chords.transition().duration(2000)
.attr("opacity", function(d, i) {
if(d.source.index == 0 && d.target.index == 0) {return opacityValueBase;}
else if(d.source.index == 1 && d.target.index == 1) {return opacityValueBase;}
else if(d.source.index == 2 && d.target.index == 2) {return opacityValueBase;}
else if(d.source.index == 3 && d.target.index == 3) {return opacityValueBase;}
else if(d.source.index == 4 && d.target.index == 4) {return opacityValueBase;}
else if(d.source.index == 5 && d.target.index == 5) {return opacityValueBase;}
else if(d.source.index == 6 && d.target.index == 6) {return opacityValueBase;}
else if(d.source.index == 7 && d.target.index == 7) {return opacityValueBase;}
else {return 0;}
});
/*Show all ticks and texts again*/
/*Ticks*/
d3.selectAll("g.group").selectAll("line")
.transition().duration(700)
.style("stroke", "#000");
/*Same for the %'s*/
svg.selectAll("g.group")
.transition().duration(700)
.selectAll(".tickLabels").style("opacity", 1);
/*And the Names of each Arc*/
svg.selectAll("g.group")
.transition().duration(700)
.selectAll(".titles").style("opacity", 1);
};/*Draw9*/
/*//////////////////////////////////////////////////////////////////////////*/
function Draw10(){
/*First disable click event on clicker button*/
stopClicker();
/*Show and run the progressBar*/
runProgressBar(time=700*11);
changeTopText(newText = "10% of respondents have a Nokia right now, but also used to own a Nokia before that",
loc = 7/2, delayDisappear = 0, delayAppear = 1);
changeTopText(newText = "Seeing that currently Nokia is owned by almost 16% of respondents, this means "+
"that about 2/3 of current Nokia owners are people who stayed loyal",
loc = 7/2, delayDisappear = 9, delayAppear = 10, finalText = true);
/*Show only the Nokia Loyal arc*/
var arcNokia = d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius)
.startAngle(2.048671976860533)
.endAngle(2.6694216777820063);
svg.append("path")
.attr("class","NokiaLoyalArc")
.attr("d", arcNokia)
.attr("opacity", 1)
.attr("stroke", colors[4])
.attr("fill", colors[4]);
/*Repeatedly let an arc change colour*/
repeat();
function repeat() {
d3.selectAll(".NokiaLoyalArc")
.transition().duration(700)
.attr("fill", "#99D2E9")
.style('stroke', "#99D2E9")
.transition().duration(700)
.attr("fill", colors[4])
.style("stroke", colors[4])
.each("end", repeat);
};
/*Show only the Nokia loyal chord*/
chords.transition().duration(2000)
.attr("opacity", function(d, i) {
if(d.source.index == 4 && d.target.index == 4) {return opacityValueBase;}
else {return 0;}
});
/*Make the other strokes less visible*/
d3.selectAll("g.group").selectAll("line")
.transition().duration(700)
.style("stroke",function(d,i,j) {if (j == 4) {return "#000";} else {return "#DBDBDB";}});
/*Same for the %'s*/
svg.selectAll("g.group")
.transition().duration(700)
.selectAll(".tickLabels").style("opacity",function(d,i,j) {if (j == 4) {return 1;} else {return opacityValue;}});
/*And the Names of each Arc*/
svg.selectAll("g.group")
.transition().duration(700)
.selectAll(".titles").style("opacity", function(d) { if(d.index == 4) {return 1;} else {return opacityValue;}});
};/*Draw10*/
/*//////////////////////////////////////////////////////////
//Show all chords that are connected to Apple
//////////////////////////////////////////////////////////*/
function Draw11(){
/*First disable click event on clicker button*/
stopClicker();
/*Show and run the progressBar*/
runProgressBar(time=700*2);
changeTopText(newText = "Here are all the chords for those respondents that currently own "+
"an iPhone or that used to own an iPhone",
loc = 3/2, delayDisappear = 0, delayAppear = 1, finalText = true, xloc=-80, w=200);
/*Remove the Nokia arc*/
d3.selectAll(".NokiaLoyalArc")
.transition().duration(1000)
.attr("opacity", 0)
.each("end", function() {d3.selectAll(".NokiaLoyalArc").remove();});
/*Only show the chords of Apple*/
chords.transition().duration(2000)
.attr("opacity", function(d, i) {
if(d.source.index == 0 || d.target.index == 0) {return opacityValueBase;}
else {return 0;}
});
/*Highlight arc of Apple*/
svg.selectAll("g.group").select("path")
.transition().duration(2000)
.style("opacity", function(d) {
if(d.index != 0) {return opacityValue;}
});
/*Show only the ticks and text at Apple*/
/*Make the other strokes less visible*/
d3.selectAll("g.group").selectAll("line")
.transition().duration(700)
.style("stroke",function(d,i,j) {if (j == 0) {return "#000";} else {return "#DBDBDB";}});
/*Same for the %'s*/
svg.selectAll("g.group")
.transition().duration(700)
.selectAll(".tickLabels").style("opacity",function(d,i,j) {if (j == 0) {return 1;} else {return opacityValue;}});
/*And the Names of each Arc*/
svg.selectAll("g.group")
.transition().duration(700)
.selectAll(".titles").style("opacity", function(d) { if(d.index == 0) {return 1;} else {return opacityValue;}});
};/*Draw11*/
function Draw12(){
/*First disable click event on clicker button*/
stopClicker();
/*Show and run the progressBar*/
runProgressBar(time=700*11);
changeTopText(newText = "One thing that stands out for Apple is that all chords connected to " +
"Apple are the color of the Apple arc: grey",
loc = 3/2, delayDisappear = 0, delayAppear = 1, finalText = false, xloc=-80, w=210);
changeTopText(newText = "This means that Apple has always had the net gain. " +
"They received more customers from other brands than they lost to them",
loc = 3/2, delayDisappear = 9, delayAppear = 10, finalText = true, xloc=-80, w=210);
};/*Draw12*/
function Draw13(){
/*First disable click event on clicker button*/
stopClicker();
/*Show and run the progressBar*/
runProgressBar(time=700*11);
changeTopText(newText = "Even more so, apart from the chord to Samsung, all other chords are extremely narrow at the other end from Apple",
loc = 3/2, delayDisappear = 0, delayAppear = 1, finalText = false, xloc=-80, w=200);
changeTopText(newText = "This means that Apple has lost virtually nobody to any other brand",
loc = 3/2, delayDisappear = 9, delayAppear = 10, finalText = true, xloc=-80, w=200);
/*Repeatedly let specific chords change colour*/
repeat();
function repeat() {
chords
.transition().duration(1000)
.style("opacity",function (d){
if(d.source.index == 0) {
if(d.target.index == 0 || d.target.index == 5) {return opacityValueBase;}
else {return 0.2;}
} else {return 0;}
})
.transition().duration(1000)
.style("opacity",function (d){
if(d.source.index == 0) {return opacityValueBase;}
else {return 0;}
})
.each("end", repeat);
};
};/*Draw13*/
function Draw14(){
/*First disable click event on clicker button*/
stopClicker();
/*Show and run the progressBar*/
/*runProgressBar(time=700*2);*/
changeTopText(newText = "Thank you for staying with me so far! After these examples I think you're absolutely " +
"ready to face the full impact of all chords simultaneously",
loc = 8/2, delayDisappear = 0, delayAppear = 1, finalText = true);
changeBottomText(newText = "I'm looking forward to hearing about the insights that you have discovered on your own",
loc = 3/2, delayDisappear = 0, delayAppear = 1);
/*Only show the chords of Apple*/
chords.transition().duration(1000)
.style("opacity", 0.1);
/*Hide all the text*/
d3.selectAll("g.group").selectAll("line")
.transition().duration(700)
.style("stroke","#DBDBDB");
/*Same for the %'s*/
svg.selectAll("g.group")
.transition().duration(700)
.selectAll(".tickLabels").style("opacity",0.4);
/*And the Names of each Arc*/
svg.selectAll("g.group")
.transition().duration(700)
.selectAll(".titles").style("opacity",0.4);
};/*Draw14*/
/*///////////////////////////////////////////////////////////
//Draw the original Chord diagram
///////////////////////////////////////////////////////////*/
/*Go to the final bit*/
function finalChord() {
/*Remove button*/
d3.select("#clicker")
.style("visibility", "hidden");
d3.select("#skip")
.style("visibility", "hidden");
d3.select("#progress")
.style("visibility", "hidden");
/*Remove texts*/
changeTopText(newText = "",
loc = 0, delayDisappear = 0, delayAppear = 1);
changeBottomText(newText = "",
loc = 0, delayDisappear = 0, delayAppear = 1);
/*Create arcs or show them, depending on the point in the visual*/
if (counter <= 4 ) {
g.append("svg:path")
.style("stroke", function(d) { return fill(d.index); })
.style("fill", function(d) { return fill(d.index); })
.attr("d", arc)
.style("opacity", 0)
.transition().duration(1000)
.style("opacity", 1);
} else {
/*Make all arc visible*/
svg.selectAll("g.group").select("path")
.transition().duration(1000)
.style("opacity", 1);
};
/*Make mouse over and out possible*/
d3.selectAll(".group")
.on("mouseover", fade(.02))
.on("mouseout", fade(.80));
/*Show all chords*/
chords.transition().duration(1000)
.style("opacity", opacityValueBase);
/*Show all the text*/
d3.selectAll("g.group").selectAll("line")
.transition().duration(100)
.style("stroke","#000");
/*Same for the %'s*/
svg.selectAll("g.group")
.transition().duration(100)
.selectAll(".tickLabels").style("opacity",1);
/*And the Names of each Arc*/
svg.selectAll("g.group")
.transition().duration(100)
.selectAll(".titles").style("opacity",1);
};/*finalChord*/
/*//////////////////////////////////////////////////////////
////////////////// Extra Functions /////////////////////////
//////////////////////////////////////////////////////////*/
/*Returns an event handler for fading a given chord group*/
function fade(opacity) {
return function(d, i) {
svg.selectAll("path.chord")
.filter(function(d) { return d.source.index != i && d.target.index != i; })
.transition()
.style("stroke-opacity", opacity)
.style("fill-opacity", opacity);
};
};/*fade*/
/*Returns an array of tick angles and labels, given a group*/
function groupTicks(d) {
var k = (d.endAngle - d.startAngle) / d.value;
return d3.range(0, d.value, 1).map(function(v, i) {
return {
angle: v * k + d.startAngle,
label: i % 5 ? null : v + "%"
};
});
};/*groupTicks*/
/*Taken from https://groups.google.com/forum/#!msg/d3-js/WC_7Xi6VV50/j1HK0vIWI-EJ
//Calls a function only after the total transition ends*/
function endall(transition, callback) {
var n = 0;
transition
.each(function() { ++n; })
.each("end", function() { if (!--n) callback.apply(this, arguments); });
};/*endall*/
/*Taken from http://bl.ocks.org/mbostock/7555321
//Wraps SVG text*/
function wrap(text, width) {
var text = d3.select(this)[0][0],
words = text.text().split(/\s+/).reverse(),
word,
line = [],
lineNumber = 0,
lineHeight = 1.4,
y = text.attr("y"),
x = text.attr("x"),
dy = parseFloat(text.attr("dy")),
tspan = text.text(null).append("tspan").attr("x", x).attr("y", y).attr("dy", dy + "em");
while (word = words.pop()) {
line.push(word);
tspan.text(line.join(" "));
if (tspan.node().getComputedTextLength() > width) {
line.pop();
tspan.text(line.join(" "));
line = [word];
tspan = text.append("tspan").attr("x", x).attr("y", y).attr("dy", ++lineNumber * lineHeight + dy + "em").text(word);
};
};
};
/*Transition the top circle text*/
function changeTopText (newText, loc, delayDisappear, delayAppear, finalText, xloc, w) {
/*If finalText is not provided, it is not the last text of the Draw step*/
if(typeof(finalText)==='undefined') finalText = false;
if(typeof(xloc)==='undefined') xloc = 0;
if(typeof(w)==='undefined') w = 350;
middleTextTop
/*Current text disappear*/
.transition().delay(700 * delayDisappear).duration(700)
.attr('opacity', 0)
/*New text appear*/
.call(endall, function() {
middleTextTop.text(newText)
.attr("y", -24*loc + "px")
.attr("x", xloc + "px")
.call(wrap, w);
})
.transition().delay(700 * delayAppear).duration(700)
.attr('opacity', 1)
.call(endall, function() {
if (finalText == true) {
d3.select("#clicker")
.text(buttonTexts[counter-2])
.style("pointer-events", "auto")
.transition().duration(400)
.style("border-color", "#363636")
.style("color", "#363636");
};
});
};/*changeTopText */
/*Transition the bottom circle text*/
function changeBottomText (newText, loc, delayDisappear, delayAppear) {
middleTextBottom
/*Current text disappear*/
.transition().delay(700 * delayDisappear).duration(700)
.attr('opacity', 0)
/*New text appear*/
.call(endall, function() {
middleTextBottom.text(newText)
.attr("y", 24*loc + "px")
.call(wrap, 350);
})
.transition().delay(700 * delayAppear).duration(700)
.attr('opacity', 1);
;}/*changeTopText*/
/*Stop clicker from working*/
function stopClicker() {
d3.select("#clicker")
.style("pointer-events", "none")
.transition().duration(400)
.style("border-color", "#D3D3D3")
.style("color", "#D3D3D3");
};/*stopClicker*/
/*Run the progress bar during an animation*/
function runProgressBar(time) {
/*Make the progress div visible*/
d3.selectAll("#progress")
.style("visibility", "visible");
/*Linearly increase the width of the bar
//After it is done, hide div again*/
d3.selectAll(".prgsFront")
.transition().duration(time).ease("linear")
.attr("width", prgsWidth)
.call(endall, function() {
d3.selectAll("#progress")
.style("visibility", "hidden");
});
/*Reset to zero width*/
d3.selectAll(".prgsFront")
.attr("width", 0);
};/*runProgressBar*/
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<title>Storytelling with a Chord Diagram - Switching between Phone Brands</title>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<link href='http://fonts.googleapis.com/css?family=Oswald:400,300,700' rel='stylesheet' type='text/css'>
<link href='http://fonts.googleapis.com/css?family=Raleway' rel='stylesheet' type='text/css'>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div id="body">
<div id="chart"></div>
<div id="clickerWrapper">
<div id="progress"></div>
<div id="clicker">Let's Start</div>
</div>
<div id="buttonWrapper">
<div id="buttonWrapperInner">
<div id="skip" class="sideButton">SKIP INTRO</div>
<div id="reset" class="sideButton">RESET</div>
<div id="link" class="sideButton"><a href="http://bl.ocks.org/nbremer/raw/94db779237655907b907/" target="_blank">GO TO SOURCE</a></div>
</div>
</div>
</div>
<script src="chords.js"></script>
</body>
</html>
body {
overflow: hidden;
margin: 0;
font-size: 14px;
font-family: 'Raleway', sans-serif;
text-align: center;
/*font-family: Oswald;*/
/*font-family: "Helvetica Neue", Helvetica;*/
}
#clickerWrapper {
top: 0;
z-index: 1;
display: block;
position: relative;
width: 640px;
/*padding-top: 5px;*/
visibility: auto;
text-align: center;
margin: 0 auto;
}
#clicker {
z-index: 1;
display: block;
font-family: Oswald;
font-size: 36px;
font-weight: 300;
color: #363636;
position: relative;
/*width: 80px;*/
text-align: center;
width: 30%;
margin: 0 auto;
border: 1px solid;
border-color: #363636;
cursor: pointer;
}
#progress {
z-index: 1;
display: block;
position: relative;
width: 40%;
height: 6px;
margin: 10px auto;
visibility: hidden;
}
#buttonWrapper{
z-index: 1;
display: block;
font-family: Oswald;
font-size: 14px;
font-weight: 300;
color: #6B6B6B;
position: relative;
width: 640px;
text-align: center;
overflow: hidden;
text-align: center;
margin: 0 auto;
margin-top: 30px;
}
#buttonWrapperInner{
position: relative;
width: 300px;
height: 30px;
margin: 0 auto;
}
#skip{
width: 90px;
cursor: pointer;
float: left;
text-align: left;
}
#reset{
width: 110px;
cursor: pointer;
float: left;
}
#link{
width: 100px;
cursor: pointer;
float: left;
text-align: right;
}
line {
stroke: #000;
stroke-width: 1.px;
}
text {
font-size: 10px;
}
.titles{
font-size: 14px;
}
.explanation{
font-size: 20px;
font-weight: 300;
text-align: center;
}
path.chord {
fill-opacity: .80;
}
a {
text-decoration: none;
color: #6B6B6B;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment