d3.js title above responsive chart with fixed aspect ratio - d3.js

I am very new to programming in d3.js, and I was wondering if someone could help me out with the following:
I have modified a donut chart that I found on the web. I modified it to become responsive while still maintaining an aspect ratio of 1 for the circular donut chart. I was wondering what the best way would be to place a title above or below it. I have tried various approaches but I am unable to create one that works consistently.
Simplified JSFiddle here:
JSFiddle
code also attached here:
var width = 400;
var height = 400;
var x = {
value: 80.43,
color1: "#007EA7",
color2: "#d9d9d9"
};
var margin = {
left: 10,
top: 10,
right: 10,
bottom: 10
};
width = Math.min(width - margin.left - margin.right,
height - margin.top - margin.bottom);
height = width * 1; // Should be a perfect circle.
svg = d3.select("body")
.append("div")
.classed("svg-container", true)
.append("svg")
.attr("preserveAspectRatio", "xMidYMin meet")
.attr("viewBox", "0 0 " + (width) + " " + (height))
.classed("svg-content-responsive", true);
// Below is code to create the actual donut chart. It used the width and height attributes calculated above.
var outerRadius = Math.min(width, height) / 2,
innerRadius = (outerRadius / 5) * 4;
τ = 2 * Math.PI;
fontSize = (Math.min(width, height) / 5);
arc = d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius)
.startAngle(0);
var background = svg.append("path")
.datum({
endAngle: τ
})
.style("fill", x.color2)
.attr("d", arc)
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var text = svg.append("text")
.text(Math.round(x.value * 10) / 10 + '%')
.attr("text-anchor", "middle")
.style("font-size", fontSize + 'px')
.attr("dy", height / 2 + fontSize / 2.5)
.attr("dx", width / 2);
foreground = svg.append("path")
.datum({
endAngle: x.value / 100 * τ
})
.style("fill", x.color1)
.attr("d", arc)
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
.svg-container {
position: relative;
width: 100%;
height: 100%;
overflow: hidden;
}
.svg-content-responsive {
width: 100%;
height: 100%;
}
<script src="https://d3js.org/d3.v3.min.js"></script>
Any comments, advise, references or code snippets that might help me are greatly appreciated.
Thanks,
Florian

Is there something wrong with adding something like this:
var title = svg.append("text")
.text('This is the title')
.attr("text-anchor", "middle")
.style("font-size", '12px')
.attr("dy", 10)
.attr("dx", width / 2);
exactly like the text?
PS: adding your approaches that failed would help people answer the question

If anyone stumbles on this question in the future: I decided to place my title below the chart and managed to solve it by slightly cheating.
I used the following CSS:
.svg-container {
height:100%;
width:100%;
min-height: 100%;
position:relative;
}
.svg-content-responsive {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
height:100%;
width: 100%;
position: relative;
padding-bottom: 50px;
}
.svg-gauge-title-container {
width: 100%;
height: 50px;
position:relative;
margin-top:-50px;
}
.svg-gauge-title {
position: relative;
width: 100%;
}
i.e. I added 50px of padding-bottom to the chart, and also added a title container with 50px of margin above. Might not be the cleanest way, but it works.

Related

d3 v4 - can't scroll vertically on svg containing bar chart

EDIT - added a code snippet (bottom)
The amount of rows are dynamic, so I don't know what the total height needed is. I have initiated the height as 800px, but the list can grow longer. I have a container div with an overflow-y:scroll value, but that did not solve the issue. D3 code and css below.
There is a scroll bar, but if I scroll down no more rows show.
The chart itself only measures about 644px (in Photoshop), so I'm not sure why it is cutting off where it does, or if that is a separate issue.
$(document).ready(function() {
let randProb = () => {
let min = 0;
let max = 1;
return (Math.random() * (max - min) + min).toFixed(4)
};
var data = [];
let initData = () => {
for (let i=0; i<86; ++i) {
data.push({
"attribute":`ATTRIBUTE_${i}`,
"probabilityOfMastery":randProb()
});
}
// console.log('data initialized', data);
};
initData();
// set the dimensions and margins of the graph
var margin = {top: 0, right: 20, bottom: 0, left: 160},
width = 1220 - margin.left - margin.right,
height = 800 - margin.top - margin.bottom;
// set the ranges
var y = d3.scaleBand()
.range([height, 0])
.padding(0.1);
var x = d3.scaleLinear()
.range([0, width]);
// append the svg object to the body of the page
// append a 'group' element to 'svg'
// moves the 'group' element to the top left margin
var svg = d3.select(".analyticsContainer").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 + ")");
// format the data
data.forEach(function(d) {
d.probabilityOfMastery = +d.probabilityOfMastery;
});
// Scale the range of the data in the domains
x.domain([0, 1])
y.domain(data.map(function(d) { return d.attribute; }));
//y.domain([0, d3.max(data, function(d) { return d.probabilityOfMastery; })]);
// append the rectangles for the bar chart
svg.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("width", 0 )
.attr("y", function(d) { return y(d.attribute); })
.transition()
.duration(1000)
//- .delay(function(d, i) {
//- return i * 60
//- })
.attr("height", y.bandwidth())
.attr("width", function(d) {return x(d.probabilityOfMastery); } )
;
// add the x Axis
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
// add the y Axis
svg.append("g")
.call(d3.axisLeft(y));
});
.analyticsWrapper {
height:calc(100vh - 120px);
max-height:100%;
width:100vw;
max-width: 100%;
display:flex;
flex-direction: column;
justify-content: center;
align-items: center;
border:1px solid red
}
.analyticsContainer {
font-size: 40px;
width:100%;
height:100%;
justify-content: center;
overflow-y: scroll;
padding:3.5vw;
height:800px;
}
svg {
width:90vw;
max-height: 100%;
max-width: 100%;
overflow: scroll;
}
.bar {
fill: #11b9b9;
}
.yAxis text {
font-weight: 700;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://d3js.org/d3.v4.min.js"></script>
<body>
<div class="analyticsWrapper">
<div class="analyticsContainer">
</div>
</div>
</body>

sortable bar chart in d3.js

I'm a newbie in d3.js and I'm trying to create a sortable bar chart. I'm following the example but I'm unable to get the same result. The bars move but the labels do not. I'm not sure what I'm doing wrong. Any guidance is hugely appreciated. Thanks
<label><input id="sort" type="checkbox"> Sort values</label>
<div id="check"></div>
<script src="~/Scripts/d3-tip.js"></script>
<script>
debugger;
var data=#Html.Raw(#JsonConvert.SerializeObject(Model));
var margin = {
top: 20,
right: 20,
bottom: 50,
left: 40
},
width = 250 - margin.left - margin.right,
height = 250 - margin.top - margin.bottom;
var x=d3.scaleBand()
.rangeRound([0, width])
.padding(0.1);
var y=d3.scaleLinear().range([height,0]);
var chart = d3.select("#check")
.append("svg:svg")
.attr("class", "chart")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var tip=d3.tip()
.attr("class","d3-tip")
.offset([-10,0])
.html(function(d){
return "<strong>Rec Items:</strong> <span style='color:red'>" + d.TotalRecItemsSum + "</span>"
})
chart.call(tip)
x.domain(data.map(function(d){
return d.AppClientName;
})) //x domain is a map of all client names
y.domain([0,d3.max(data,function(d){return d.TotalRecItemsSum;})])
//y is range from maximum(count) value in array until 0
chart.selectAll(".bar").data(data).enter().append("svg:rect")
.attr("x",function(d){
return x(d.AppClientName);
})
.attr("class", "bar")
.attr("width",x.bandwidth())
.attr("y",function (d){
return y(d.TotalRecItemsSum);})
.attr("height",function(d){
return height-y(d.TotalRecItemsSum);})
.on('mouseover', tip.show)
.on('mouseout', tip.hide)
var xAxis=d3.axisBottom().scale(x);
var yAxis=d3.axisLeft().scale(y);
chart.append("g")
.attr("class","y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("TotalRecItemSum");
chart.append("g").attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text")
.attr("transform","rotate(90)")//In some cases the labels will overlap
//so I want to rotate the label's so they are vertical
.attr("x", 0) //After that some finetuning to align everything the right way:
.attr("y", -6)
.attr("dx", ".6em")
.attr("class","x axis")
.attr("class","text")
.style("text-anchor", "start")
d3.select("#sort").on("change", change);
var sortTimeout = setTimeout(function() {
d3.select("#sort").property("checked", true).each(change);
}, 2000);
function change() {
clearTimeout(sortTimeout);
// Copy-on-write since tweens are evaluated after a delay.
var x0 = x.domain(data.sort(this.checked
? function(a, b) { return b.TotalRecItemsSum - a.TotalRecItemsSum; }
: function(a, b) { return d3.ascending(a.AppClientName, b.AppClientName); })
.map(function(d) { return d.AppClientName; }))
.copy();
chart.selectAll(".bar")
.sort(function(a, b) { return x0(a.AppClientName) - x0(b.AppClientName); });
var transition = chart.transition().duration(750),
delay = function(d, i) { return i * 100; };
transition.selectAll(".bar")
.delay(delay)
.attr("x", function(d) { return x0(d.AppClientName); });
transition.select(".x.axis")
.call(xAxis)
.selectAll("g")
.delay(delay);
}
<style>
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.chart rect {
stroke: white;
fill: orange;
}
.bar:hover {
fill: orangered;
}
.d3-tip {
line-height: 1;
font-weight: bold;
padding: 12px;
background: rgba(0, 0, 0, 0.8);
color: #fff;
border-radius: 2px;
}
/* Creates a small triangle extender for the tooltip */
.d3-tip:after {
box-sizing: border-box;
display: inline;
font-size: 10px;
width: 100%;
line-height: 1;
color: rgba(0, 0, 0, 0.8);
content: "\25BC";
position: absolute;
text-align: center;
}
.d3-tip.n:after {
margin: -1px 0 0 0;
top: 100%;
left: 0;
}
.x.axis path {
display: none;
}
I'm using d3 version 4. And in the above code, my x-axis has the client names and y-axis is a numerical value. So the bars are arranged in ascending order on checking the checkbox, only the labels do not move. Also, another issue is the checkbox gets checked automatically after a couple of seconds, that's happening because of var timeout, so should I be putting timeout inside function change?
Pls ask me any questions if my explanation is unclear, I always have trouble articulating. Thanks.

Why is my graph not getting displayed?

I am working on this fiddle but the graph is not showing up,what am i missing here?
Working fiddle
I am making a vertical bar graph and need to show tooltips on the bar.
I am using this to add tooltip on mouseover
d3.select('#tooltip')
.style('left', xPos + 'px')
.style('top', yPos + 'px')
.style('display','block')
.select('#value')
.text(d.global);
There are several issues here:
You are not defining/appending any div with id="tooltip"
The mouseover/mouseout event need to be part of svg.selectAll(".set")
Your xScale and yScale will always give undefined values
You should be able to continue from here:
var div = d3.select("body").append("div")
.attr("id", "tooltip")
.style("opacity", 0);
var margin = {
top: 25,
right: 40,
bottom: 35,
left: 85
},
w = 500 - margin.left - margin.right,
h = 220 - margin.top - margin.bottom;
var padding = 10;
var formatPercent = d3.format(".0%");
var color = d3.scale.ordinal().range(['#3cbcbd', '#4abc81', '#dcd048', '#4dcc37']);
var dataset = [{
"keyword": "Descriptive",
'global': 70
}, {
"keyword": "Inquisitive",
'global': 60
}, {
"keyword": "Predictive",
'global': 47
}, {
"keyword": "Prescriptive",
'global': 44
}];
var total = 0;
dataset.forEach(function(d) {
total += d.global;
});
var xScale = d3.scale.ordinal()
.domain(d3.range(dataset.length))
.rangeRoundBands([0, w], 0.05);
var yScale = d3.scale.linear()
.domain([0, 100])
.range([h, 0]);
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom")
.tickFormat(function(d) {
return dataset[d].keyword;
});
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("left")
.ticks(10);
var global = function(d) {
return d.global;
};
var commaFormat = d3.format(".0%");
//SVG element
d3.select('svg#dippSVG').remove();
var svg = d3.select("#vertical_bar_chart_container")
.append("svg")
.attr('width', "80%")
.attr('height', "80%")
.attr("viewBox", "0 0 500 250")
.attr("class", "vert_bar_chart_graph")
.attr("id", "dippSVG")
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// Graph Bars
var sets = svg.selectAll(".set")
.data(dataset)
.enter()
.append("g")
.attr("class", "set")
.attr("transform", function(d, i) {
return "translate(" + xScale(i) + ",0)";
})
.on('mouseover', function(d) {
var xPos = xScale(dataset.indexOf(d));
var yPos = yScale(d.global);
var div = d3.select('#tooltip')
.style("left", xPos + "px")
.style("top", yPos + "px")
.style("opacity", 1)
.html('<span>' + d.global + '</span>')
})
.on('mouseout', function() {
var div = d3.select('#tooltip')
.style("opacity", 0);
});
sets.append("rect")
.attr("class", "global")
.attr("width", xScale.rangeBand() / 2)
.attr('y', function(d) {
return yScale((d.global / total) * 100);
})
.attr("height", function(d) {
return h - yScale((d.global / total) * 100);
})
.attr('fill', function(d, i) {
return color(d.global);
})
.append("text")
.text(function(d) {
return commaFormat((d.global / total) * 100);
})
.attr("font-family", "sans-serif")
.attr("font-size", "11px")
.on('mouseover', function(d) {
var xPos = 70 + parseFloat(d3.select(this).attr('w'));
var yPos = parseFloat(d3.select(this).attr('y')) + yScale.rangeBand() + 30;
d3.select('#tooltip')
.style('left', xPos + 'px')
.style('top', yPos + 'px')
.style('display', 'block')
.select('#value')
.text(d.global);
d3.select('#tooltip').classed('hidden', false);
})
.on('mouseout', function() {
d3.select('#tooltip').classed('hidden', true);
})
function make_y_axis() { //function to make grid lines
return d3.svg.axis()
.scale(yScale)
.orient("left")
.ticks(10)
}
//append text
sets.append("text")
.attr("class", "global")
.attr("y", function(d) {
return yScale((d.global / total) * 100) - (margin.top / 4);
})
.attr("dy", 5)
.attr("dx", (xScale.rangeBand() / 8))
.attr("font-family", "sans-serif")
.attr("font-size", "14px")
.attr("fill", "black")
.text(function(d) {
return (d.global > 0) ? commaFormat(d.global / total) : "";
});
// xAxis
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + (h) + ")")
.call(xAxis);
// yAxis
svg.append("g")
.attr("class", "y axis")
.attr("transform", "translate(0 ,0)")
.call(yAxis);
svg.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 0 - margin.left + margin.top)
.attr("x", 0 - (h / 2))
.attr("dy", "1em")
.style("text-anchor", "middle")
.text("Percentage of Tests");
//y axis grid line functions
svg.append("g")
.attr("class", "grid")
.call(make_y_axis()
.tickSize(-w, 0, 0)
.tickFormat("")
)
#tooltip {
position: absolute;
width: 50px;
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: sans-serif;
font-size: 12px;
line-height: 16px;
}
.indent {
padding-left: 5px;
}
rect {
-moz-transition: all 0.3s;
-webkit-transition: all 0.3s;
-o-transition: all 0.3s;
transition: all 0.3s;
}
rect:hover {
fill: orange;
}
.axis path,
.axis line {
fill: none;
stroke: black;
shape-rendering: crispEdges;
}
.axis text {
font-family: sans-serif;
font-size: 11px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.3.13/d3.min.js"></script>
<div id="vertical_bar_chart_container"></div>

Legend not aligned properly in d3 responsive chart

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<title>Testing Pie Chart</title>
<script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
<style type="text/css">
#container {
margin: 20px;
}
#chart {
position: absolute;
background-color: #eee;
}
#chart legend{
position: absolute;
margin: 100px;
}
.tooltip {
background: #eee;
box-shadow: 0 0 5px #999999;
color: #900C3F;
display: inline-block;
font-size: 12px;
left: 600px;
padding: 10px;
position: absolute;
text-align: center;
top: 95px;
width: 150px;
z-index: 10;
opacity: 1;
}
rect {
stroke-width: 2;
}
path {
stroke: #ffffff;
stroke-width: 0.5;
}
div.tooltip {
position: absolute;
z-index: 999;
padding: 10px;
background: #f4f4f4;
border: 0px;
border-radius: 3px;
pointer-events: none;
font-size: 11px;
color: #080808;
line-height: 16px;
border: 1px solid #d4d4d4;
}
</style>
</head>
<body>
<div id="container">
<svg id="chart" width="600" height="300" viewBox="0 0 600 300" perserveAspectRatio="xMinYMid">
<div id="toolTip" class="tooltip" style="opacity: 0;"></div>
<script type="text/javascript">
var div = d3.select("#toolTip");
var data = [
{"IP":"192.168.12.1", "count":20},
{"IP":"76.09.45.34", "count":40},
{"IP":"34.91.23.76", "count":80},
{"IP":"192.168.19.32", "count":16},
{"IP":"192.168.10.89", "count":50},
{"IP":"192.178.34.07", "count":18},
{"IP":"192.168.12.98", "count":30}];
var width = 300,
height = 300;
var margin = {top: 15, right: 15, bottom: 20, left: 40},
radius = Math.min(width, height) / 2 - 10;
var legendRectSize = 18,
legendSpacing = 4;
var color = d3.scale.category20b();
var arc = d3.svg.arc()
.outerRadius(radius);
var arcOver = d3.svg.arc()
.outerRadius(radius + 5);
var pie = d3.layout.pie()
.sort(null)
.value(function(d) { return d.count; });
var labelArc = d3.svg.arc()
.outerRadius(radius - 40)
.innerRadius(radius - 40);
var svg = d3.select("#chart").append("svg")
.datum(data)
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var arcs = svg.selectAll(".arc")
.data(pie)
.enter().append("g")
.attr("class", "arc");
var arcs2 = svg.selectAll(".arc2")
.data(pie)
.enter().append("g")
.attr("class", "arc2");
arcs.append("path")
.attr("fill", function(d, i) { return color(i); })
.on("mouseover", function(d) {
var htmlMsg="";
div.transition()
.style("opacity",0.9);
var total = d3.sum(data.map(function(d) {
return d.count;
}));
var percent = Math.round(1000 * d.data.count / total) / 10;
div.html(
"IP :"+ d.data.IP +""+"<br/>"+
"Count : " + d.data.count +"<br/>" +
"Percent: " + percent + '%'+ htmlMsg)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY) + "px");
svg.selectAll("path").sort(function (a, b) {
if (a != d) return -1;
else return 1;
});
var endAngle = d.endAngle + 0.1;
var startAngle = d.startAngle - 0.1;
var arcOver = d3.svg.arc()
.outerRadius(radius + 10).endAngle(endAngle).startAngle(startAngle);
d3.select(this)
.attr("stroke","white")
.transition()
.ease("bounce")
.duration(1000)
.attr("d", arcOver)
.attr("stroke-width",6);
})
.on("mouseout", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
d3.select(this).transition()
.attr("d", arc)
.attr("stroke","none");
})
.transition()
.ease("bounce")
.duration(2000)
.attrTween("d", tweenPie);
function tweenPie(b) {
b.innerRadius = 0;
var i = d3.interpolate({startAngle: 0, endAngle: 0}, b);
return function(t) { return arc(i(t)); };
}
var k=0;
arcs2.append("text")
.transition()
.ease("elastic")
.duration(2000)
.delay(function (d, i) {
return i * 250;
})
.attr("x","6")
.attr("dy", ".35em")
.text(function(d) { if(d.data.count >0){ k = k+1; return d.data.count;} })
.attr("transform", function(d) { if (k >1){return "translate(" + labelArc.centroid(d) + ") rotate(" + angle(d) + ")";} else{return "rotate(-360)";} })
.attr("font-size", "10px");
function type(d) {
d.count = +d.count;
return d;
}
function angle(d) {
var a = (d.startAngle + d.endAngle) * 90 / Math.PI - 90;
return a > 90 ? a - 180 : a;
}
var legend = d3.select("#chart")
.append("svg")
.attr("class", "legend")
.attr("width", radius+50)
.attr("height", radius * 2)
.selectAll("g")
.data(color.domain())
.enter()
.append("g")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append('rect')
.attr('width', legendRectSize)
.attr('height', legendRectSize)
.style('fill', color)
.style('stroke', color);
legend.append('text')
.attr('x', legendRectSize + legendSpacing)
.attr('y', legendRectSize - legendSpacing)
.data(data)
.text(function(d,i) { return d.IP; });
</script>
</svg>
</div>
<script type="text/javascript">
var chart = $("#chart"),
aspect = chart.width() / chart.height(),
container = chart.parent();
$(window).on("resize", function() {
var targetWidth = container.width();
chart.attr("width", targetWidth);
chart.attr("height", Math.round(targetWidth / aspect));
}).trigger("resize");
</script>
</script>
</body>
</html>
Hello, I am new to D3.js. I am facing issues when building a responsive pie chart. The chart is responsive with tooltips also attached to it. But when I try to attach the legend to the chart the legend is overlapping the chart. Please help me. I am stuck. How can I place the legend beside my pie chart. Here are my codes that I have tried so far.
Thank for any help in advance.
This could be resolved in 3 ways:
Width of chart:
Here, the pie chart is too big for the given dimensions. Hence, the legends overlap. You could try changing the width: 300 to width: 700
Radius of circle:
If you can't change the width, you could reduce the radius of the pie chart. Currently, it selects minimum of the width/height and divides by two subtracting 10 for margin. radius = Math.min(width, height) / 2 You could additionally specify radius = Math.min(width, height) / 2 - 50 to further reduce the radius by pixels.
Transform of the center:
Or you can also move the center of the pie chart further right. Currently, it is located halfway of the dimensions. .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")"). You could make it say to be at 3/4 of the width and 40% of height .attr("transform", "translate(" + width * 3 / 4 + "," + height * 2 / 5 + ")")
I have utilised all three of the ways in your snippet:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<title>Testing Pie Chart</title>
<script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
<style type="text/css">
#container {
margin: 20px;
}
#chart {
position: absolute;
background-color: #eee;
}
#chart legend{
position: absolute;
margin: 100px;
}
.tooltip {
background: #eee;
box-shadow: 0 0 5px #999999;
color: #900C3F;
display: inline-block;
font-size: 12px;
left: 600px;
padding: 10px;
position: absolute;
text-align: center;
top: 95px;
width: 150px;
z-index: 10;
opacity: 1;
}
rect {
stroke-width: 2;
}
path {
stroke: #ffffff;
stroke-width: 0.5;
}
div.tooltip {
position: absolute;
z-index: 999;
padding: 10px;
background: #f4f4f4;
border: 0px;
border-radius: 3px;
pointer-events: none;
font-size: 11px;
color: #080808;
line-height: 16px;
border: 1px solid #d4d4d4;
}
</style>
</head>
<body>
<div id="container">
<svg id="chart" width="600" height="300" viewBox="0 0 600 300" perserveAspectRatio="xMinYMid">
<div id="toolTip" class="tooltip" style="opacity: 0;"></div>
<script type="text/javascript">
var div = d3.select("#toolTip");
var data = [
{"IP":"192.168.12.1", "count":20},
{"IP":"76.09.45.34", "count":40},
{"IP":"34.91.23.76", "count":80},
{"IP":"192.168.19.32", "count":16},
{"IP":"192.168.10.89", "count":50},
{"IP":"192.178.34.07", "count":18},
{"IP":"192.168.12.98", "count":30}];
var width = 400,
height = 300;
var margin = {top: 15, right: 15, bottom: 20, left: 40},
radius = Math.min(width, height) / 2 - 50;
var legendRectSize = 18,
legendSpacing = 4;
var color = d3.scale.category20b();
var arc = d3.svg.arc()
.outerRadius(radius);
var arcOver = d3.svg.arc()
.outerRadius(radius + 5);
var pie = d3.layout.pie()
.sort(null)
.value(function(d) { return d.count; });
var labelArc = d3.svg.arc()
.outerRadius(radius - 40)
.innerRadius(radius - 40);
var svg = d3.select("#chart").append("svg")
.datum(data)
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width * 3 / 4 + "," + height * 2/ 5 + ")");
var arcs = svg.selectAll(".arc")
.data(pie)
.enter().append("g")
.attr("class", "arc");
var arcs2 = svg.selectAll(".arc2")
.data(pie)
.enter().append("g")
.attr("class", "arc2");
arcs.append("path")
.attr("fill", function(d, i) { return color(i); })
.on("mouseover", function(d) {
var htmlMsg="";
div.transition()
.style("opacity",0.9);
var total = d3.sum(data.map(function(d) {
return d.count;
}));
var percent = Math.round(1000 * d.data.count / total) / 10;
div.html(
"IP :"+ d.data.IP +""+"<br/>"+
"Count : " + d.data.count +"<br/>" +
"Percent: " + percent + '%'+ htmlMsg)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY) + "px");
svg.selectAll("path").sort(function (a, b) {
if (a != d) return -1;
else return 1;
});
var endAngle = d.endAngle + 0.1;
var startAngle = d.startAngle - 0.1;
var arcOver = d3.svg.arc()
.outerRadius(radius + 10).endAngle(endAngle).startAngle(startAngle);
d3.select(this)
.attr("stroke","white")
.transition()
.ease("bounce")
.duration(1000)
.attr("d", arcOver)
.attr("stroke-width",6);
})
.on("mouseout", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
d3.select(this).transition()
.attr("d", arc)
.attr("stroke","none");
})
.transition()
.ease("bounce")
.duration(2000)
.attrTween("d", tweenPie);
function tweenPie(b) {
b.innerRadius = 0;
var i = d3.interpolate({startAngle: 0, endAngle: 0}, b);
return function(t) { return arc(i(t)); };
}
var k=0;
arcs2.append("text")
.transition()
.ease("elastic")
.duration(2000)
.delay(function (d, i) {
return i * 250;
})
.attr("x","6")
.attr("dy", ".35em")
.text(function(d) { if(d.data.count >0){ k = k+1; return d.data.count;} })
.attr("transform", function(d) { if (k >1){return "translate(" + labelArc.centroid(d) + ") rotate(" + angle(d) + ")";} else{return "rotate(-360)";} })
.attr("font-size", "10px");
function type(d) {
d.count = +d.count;
return d;
}
function angle(d) {
var a = (d.startAngle + d.endAngle) * 90 / Math.PI - 90;
return a > 90 ? a - 180 : a;
}
var legend = d3.select("#chart")
.append("svg")
.attr("class", "legend")
.attr("width", radius+50)
.attr("height", radius * 2)
.selectAll("g")
.data(color.domain())
.enter()
.append("g")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append('rect')
.attr('width', legendRectSize)
.attr('height', legendRectSize)
.style('fill', color)
.style('stroke', color);
legend.append('text')
.attr('x', legendRectSize + legendSpacing)
.attr('y', legendRectSize - legendSpacing)
.data(data)
.text(function(d,i) { return d.IP; });
</script>
</svg>
</div>
<script type="text/javascript">
var chart = $("#chart"),
aspect = chart.width() / chart.height(),
container = chart.parent();
$(window).on("resize", function() {
var targetWidth = container.width();
chart.attr("width", targetWidth);
chart.attr("height", Math.round(targetWidth / aspect));
}).trigger("resize");
</script>
</script>
</body>
</html>

Add links and hover effects to multi series donut chart in d3.js

I have a multi series donut chart created with the help of this question D3.js - Donut charts with multiple rings in d3.js, see fiddle below.
I'd like to be able to add hover effects, and also make each part clickable in the sense I'd like to assign a certin href to each slice of the chart. I have looked around quite a bit, but can't get my head around it - d3.js is quite complex for me I guess.
The code I have now: http://jsfiddle.net/mephisto73/o6shxw0d/
(function(){
var $container = $('.chart-container'),
τ = 2 * Math.PI,
width = $container.width(),
height = $container.height(),
outerRadius = Math.min(width,height)/2.5,
innerRadius = (outerRadius/5)*4,
fontSize = (Math.min(width,height)/4);
var dataset = {
weeks: [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
months: [1,1,1,1,1,1,1,1,1],
trimester: [1,1,1]
};
var color = d3.scale.ordinal() .range(['rgba(141,211,199,0.8)','rgb(255,255,179)','rgb(190,186,218)','rgb(251,128,114)','rgb(128,177,211)','rgb(253,180,98)','rgb(179,222,105)','rgb(252,205,229)','rgb(217,217,217)','rgb(188,128,189)','rgb(204,235,197)','rgb(255,237,111)']);
var pie = d3.layout.pie()
.sort(null);
var arc = d3.svg.arc();
var svg = d3.select('.chart-container').append("svg")
.attr("width", '100%')
.attr("height", '100%')
.attr('viewBox','0 0 '+Math.min(width,height) +' '+Math.min(width,height) )
.attr('preserveAspectRatio','xMinYMin')
.append("g")
.attr("transform", "translate(" + Math.min(width,height) / 2 + "," + Math.min(width,height) / 2 + ")");
var gs = svg.selectAll("g").data(d3.values(dataset)).enter().append("g").attr("class", "arc");
var path = gs.selectAll("path")
.data(function(d) { return pie(d); })
.enter().append("path")
.attr("fill", function(d, i) { return color(i); })
.attr("d", function(d, i, j) { return arc.innerRadius(innerRadius+(40*j)).outerRadius(innerRadius+(5*(j+5)))(d); });
});
$(function(){
var tooltip = d3.select(".tooltip");
var $container = $('.chart-container'),
τ = 2 * Math.PI,
width = $container.width(),
height = $container.height(),
outerRadius = Math.min(width,height)/2.5,
innerRadius = (outerRadius/5)*4,
fontSize = (Math.min(width,height)/4);
var dataset = {
weeks: [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
months: [1,1,1,1,1,1,1,1,1],
trimester: [1,1,1]
};
var color = d3.scale.ordinal() .range(['rgba(141,211,199,0.8)','rgb(255,255,179)','rgb(190,186,218)','rgb(251,128,114)','rgb(128,177,211)','rgb(253,180,98)','rgb(179,222,105)','rgb(252,205,229)','rgb(217,217,217)','rgb(188,128,189)','rgb(204,235,197)','rgb(255,237,111)']);
var pie = d3.layout.pie()
.sort(null);
var arc = d3.svg.arc();
var svg = d3.select('.chart-container').append("svg")
.attr("width", '100%')
.attr("height", '100%')
.attr('viewBox','0 0 '+Math.min(width,height) +' '+Math.min(width,height) )
.attr('preserveAspectRatio','xMinYMin')
.append("g")
.attr("transform", "translate(" + Math.min(width,height) / 2 + "," + Math.min(width,height) / 2 + ")");
var gs = svg.selectAll("g").data(d3.values(dataset)).enter().append("g").attr("class", "arc");
var path = gs.selectAll("path")
.data(function(d) { return pie(d); })
.enter().append("path")
.attr("fill", function(d, i) { return color(i); })
.attr("d", function(d, i, j) { return arc.innerRadius(innerRadius+(40*j)).outerRadius(innerRadius+(5*(j+5)))(d); })
.on("mousemove", function(d){
tooltip.style("left", d3.event.pageX+10+"px");
tooltip.style("top", d3.event.pageY-25+"px");
tooltip.style("display", "inline-block");
tooltip.select("span").text("Value: "+d.value);
}).on("mouseout",function(){
tooltip.style("display","none");
}).on("click",function(){
//write code to open
});
});
html,body {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
margin:0;
padding:0;
width:100%;
height:100%;
}
text {
font: 10px sans-serif;
}
form {
position: absolute;
right: 10px;
top: 10px;
}
.arc path {
stroke: #fff;
width:5px;
}
.arc path:hover {
background-color:#ccc;
}
.chart-container {
width:70%;
height:70%;
border: 1px dotted silver;
}
svg text{
font-size: 1em;
font-family: sans-serif;
}
.tooltip{
position: absolute;
display: none;
width: auto;
height: auto;
background: none repeat scroll 0 0 white;
border: 0 none;
border-radius: 8px 8px 8px 8px;
box-shadow: -3px 3px 15px #888888;
color: black;
font: 12px sans-serif;
padding: 5px;
text-align: center;
}
path:hover{
cursor: pointer;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.10/d3.min.js"></script>
<div class="chart-container"></div>
<div class='tooltip'>
<span></span>
</div>
I've added functionality for on mousemove, mouseout and click.
Try to read and do the modification in click function.
Hope you got it,If not ask me for more.

Resources