Make two pie charts with the same d3js code - d3.js

I have a pie chart that was made with d3js.
The data is read from an url.
I want to use the same code to generate the chart, changing the colors of the chart and the data, but I am not managing how can I do.
In witch regard changing the data, the only variable that change its name is earth_footprint, that will be IHD.
Here there is the fiddle of how the code is today.
In this fiddle there are the div on where I want to have my second chart:
<div id="donut2"></div>
And the data that i want to use to the second chart is on this link.
Thanks a lot!!

make a function that encloses everything in your code and make two function calls
function drawChart(url, id, key) {
d3.json(url)
.then(function(data) {
data = data.filter(dataPoint => dataPoint.year == 2015);
const heightValue = 300;
const widthValue = 600;
const strokeWidth = 1.5;
const margin = {
top: 0,
bottom: 20,
left: 30,
right: 20
};
var width = 600 - margin.left - margin.right - (strokeWidth * 2);
var height = 250 - margin.top - margin.bottom;
var radius = Math.min(width, height) / 2;
var color = d3.scaleOrdinal()
.range(["#e688a1", "#ed9a73", "#e3c878", "#64b2cd", "#e1b12c", "red", "green", "violet", "steelblue"]);
var pie = d3.pie()
.value(function(d) {
return d[key];
})(data);
var arc = d3.arc()
.outerRadius(radius - 10)
.innerRadius(0);
var svg =
d3
.select(id)
.append("svg")
.attr("viewBox", `0 0 ${widthValue} ${heightValue}`)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var g = svg.selectAll("arc")
.data(pie)
.enter().append("g")
.attr("class", "arc")
g.on('mouseover', function(d, i) {
d3.select(this).transition()
.duration('50')
.attr('opacity', '.95')
.attr("stroke", "#23374d")
g.append("text")
.attr("class", "text remove")
.style("text-anchor", "middle")
.attr("stroke", "#23374d")
.attr("fill", "#23374d")
.text(d.data.country_name)
})
.on('mouseout', function(d, i) {
d3.select(this).transition()
.duration('50')
.attr('opacity', '1')
.attr("stroke", "none")
g.select(".text.remove").remove();
})
.attr('transform', 'translate(0, 0)');
g.append("path")
.attr("d", arc)
.style("fill", function(d) {
return color(d.data.country_name);
});
g
.append("text")
.attr("text-anchor", "middle")
.attr("x", function(d) {
var a = d.startAngle + (d.endAngle - d.startAngle) / 2 - Math.PI / 2;
d.cx = Math.cos(a) * (radius - 45);
return d.x = Math.cos(a) * (radius + 30);
})
.attr("y", function(d) {
var a = d.startAngle + (d.endAngle - d.startAngle) / 2 - Math.PI / 2;
d.cy = Math.sin(a) * (radius - 12);
return d.y = Math.sin(a) * (radius - 5);
})
.text(function(d) {
return d.value.toFixed(2);
})
.each(function(d) {
var bbox = this.getBBox();
d.sx = d.x - bbox.width / 2 - 2;
d.ox = d.x + bbox.width / 2 + 2;
d.sy = d.oy = d.y + 5;
});
g.append("path")
.attr("class", "pointer")
.style("fill", "none")
.style("stroke", "#2c3e50")
.attr("d", function(d) {
if (d.cx > d.ox) {
return "M" + d.sx + "," + d.sy + "L" + d.ox + "," + d.oy + " " + d.cx + "," + d.cy;
} else {
return "M" + d.ox + "," + d.oy + "L" + d.sx + "," + d.sy + " " + d.cx + "," + d.cy;
}
});
});
}
drawChart("https://raw.githubusercontent.com/cvrnogueira/CODWorkData/master/database/topfive/biggestEarthFootprint.json",
"#donut",
"earth_footprint"
)
drawChart("https://raw.githubusercontent.com/cvrnogueira/CODWorkData/master/database/topfive/biggestIHD.json",
"#donut2",
"IHD"
)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<script src="https://d3js.org/d3.v5.min.js"></script>
<title>JS Bin</title>
</head>
<body>
<div id="donut"></div>
<br>
<br>
<div id="donut2"></div>
</body>
</html>
So your function now takes the url, the id upon which to load and the key you want to read from in the data.

Related

semicircle bar graphs with extended edges using d3.js

I'm trying to draw a d3 chart with extended edges like in the image, "this is the link to the design"
I was able to achieve a semi circle in the same fashion, but I'm a little confused how to do the extended edge, this is the code for what I have done so far, link to codepen
JS:
var width = 300,
height = 300;
var twoPi = Math.PI; // Full circle
var formatPercent = d3.format(".0%");
const color = [
"#F9C969",
"#FB8798",
"#51D6D8",
"#B192FD",
"#509FFD",
"#5B65B7"
];
console.log(d3.schemeCategory10);
var data = [
{ count: 1000 },
{ count: 800 },
{ count: 800 },
{ count: 700 },
{ count: 900 },
{ count: 600 }
];
var percent = d3.max(data, function (d) {
return +d.count / 10;
});
var max = d3.max(data, function (d) {
return +d.count;
});
var baseRad = 0.25,
cgap = 12,
maxVal = max + percent;
var cx1 = width / 2.5;
var cy1 = height / 2.5;
var cl = "c0";
var ind = 0;
var rad;
var rad2;
rad = baseRad;
rad2 = baseRad;
var svg = d3
.select("body")
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 10 + "," + height / 10 + ")");
var svg2 = d3
.select("svg")
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 10 + "," + height / 10 + ")");
svg2
.selectAll("path")
.data(data)
.enter()
.append("path")
// .each(drawBackArc)
.each(drawArc)
.style("fill", function (d, i) {
return color[i % 6];
});
svg
.selectAll("path")
.data(data)
.enter()
.append("path")
// .each(drawBackArc)
.each(drawBackArc)
.style("fill", "#F1F1F1");
// .attr("ax", "-100px")
// .attr("ay", "-100px");
function drawArc(d, i) {
console.log(d, i);
var ratio = d.count / maxVal;
var arc = d3.svg
.arc()
.startAngle(3.14159)
// .(true)
.endAngle(6.28319 * ratio)
.innerRadius(72 + cgap * rad)
.outerRadius(80 + cgap * rad);
d3.select(this)
.attr("transform", "translate(" + cx1 + "," + cy1 + ")")
.attr("d", arc)
.style("fill", function (d, i) {
return color[i % 6];
});
rad++;
}
function drawBackArc(d, i) {
var ratio = d.count / maxVal;
var arc = d3.svg
.arc()
.startAngle(twoPi)
// .(true)
.endAngle(twoPi * 2)
.innerRadius(72 + cgap * rad2)
.outerRadius(80 + cgap * rad2);
d3.select(this)
.attr("transform", "translate(" + cx1 + "," + cy1 + ")")
.attr("d", arc)
.style("fill", "#F1F1F1");
rad2++;
}
HTML:
<script src="https://d3js.org/d3.v3.min.js"></script>
<body></body>
CSS:
body{background-color: #fff;margin: 1.5rem 6rem}
I have seen tutorial explaining how to draw different shapes in d3.js and I can think of drawing a rectangle shape at one end to achieve the design, but even then the issue is how to get the data in both the separate shapes, is it possible in d3? if not please suggest any other possible ways if any.
Thanks
Since you know your center point, you added 2 translations (30,30) and (120,120), so your center point is 150,150
Now you can get the end points of all the arcs, x value be same as centerpoint and y after adjusting radius.
Added below changes to your code Please adjust your graph for length and width of the line. Also add the length of the line to the lenght of arc to get correct percantage and overlap with filled line same as below with desired length if percentage increase the length of an arc
var centerPoint = [150, 150] //added for translation
var radius = 72 + cgap * rad2;
gLines.append("line")
.attr("x1", centerPoint[0])
.attr("x2", centerPoint[0] + 140) // Add length of the bar
.attr("y1", centerPoint[0] - radius + 16)
.attr("y2", centerPoint[0] - radius + 16) // This will adjust line width and inner and outer radius
.style("stroke", "#F2F2F2")
.style("stroke-width", "8");
var width = 300,
height = 300;
var twoPi = Math.PI; // Full circle
var formatPercent = d3.format(".0%");
const color = [
"#F9C969",
"#FB8798",
"#51D6D8",
"#B192FD",
"#509FFD",
"#5B65B7"
];
console.log(d3.schemeCategory10);
var data = [{
count: 500,
color: "#F9C969"
},
{
count: 800,
color: "#FB8798"
},
{
count: 800,
color: "#51D6D8"
},
{
count: 700,
color: "#B192FD"
},
{
count: 900,
color: "#509FFD"
},
{
count: 600,
color: "#5B65B7"
}
];
var percent = d3.max(data, function(d) {
return +d.count / 10;
});
var max = d3.max(data, function(d) {
return +d.count;
});
var baseRad = 0.25,
cgap = 12,
maxVal = max + percent;
var cx1 = width / 2.5;
var cy1 = height / 2.5;
var cl = "c0";
var ind = 0;
var rad;
var rad2;
rad = baseRad;
rad2 = baseRad;
var svg = d3
.select("body")
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 10 + "," + height / 10 + ")");
var svg2 = d3
.select("svg")
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 10 + "," + height / 10 + ")");
var gLines = d3.select("svg").append("g");
svg2
.selectAll("path")
.data(data)
.enter()
.append("path")
// .each(drawBackArc)
.each(drawArc)
.style("fill", function(d, i) {
return color[i % 6];
});
svg
.selectAll("path")
.data(data)
.enter()
.append("path")
// .each(drawBackArc)
.each(drawBackArc)
.style("fill", "#F1F1F1");
// .attr("ax", "-100px")
// .attr("ay", "-100px");
function drawArc(d, i) {
console.log(d, i);
var ratio = (d.count * 2) / maxVal;
console.log(ratio);
var arc = d3.svg
.arc()
.startAngle(twoPi)
// .(true)
.endAngle(twoPi * ratio)
.innerRadius(72 + cgap * rad)
.outerRadius(80 + cgap * rad);
d3.select(this)
.attr("transform", "translate(" + cx1 + "," + cy1 + ")")
.attr("d", arc)
.style("fill", function(d, i) {
return color[i % 6];
});
rad++;
}
function drawBackArc(d, i) {
var ratio = d.count / maxVal;
var arc = d3.svg
.arc()
.startAngle(twoPi)
// .(true)
.endAngle(twoPi * 2)
.innerRadius(72 + cgap * rad2 - 20)
.outerRadius(80 + cgap * rad2 - 20);
d3.select(this)
.attr("transform", "translate(" + cx1 + "," + cy1 + ")")
.attr("d", arc)
.style("fill", "#F1F1F1");
var centerPoint = [150, 150] //added for translation
var radius = 72 + cgap * rad2;
gLines.append("line")
.attr("x1", centerPoint[0])
.attr("x2", centerPoint[0] + 140) // Add Width of the
.attr("y1", centerPoint[0] - radius + 16)
.attr("y2", centerPoint[0] - radius + 16)
.style("stroke", "#F2F2F2")
.style("stroke-width", "8");
rad2++;
}
<script src="https://d3js.org/d3.v3.min.js"></script>
<body></body>

Need help to break long text and display in arc in d3.js

I am facing issue to align and wrap big text in Arc segment.
I have tried to implement tspan but unable to transform it correctly.
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.arc text,
.wedge text {
font: 10px sans-serif;
text-anchor: middle;
}
.arc path,
.wedge path {
stroke: #fff;
}
</style>
<body>
<script src="https://d3js.org/d3.v3.min.js"></script>
<script>
var width = 494,
height = 504,
radius = Math.min(width, height) / 2;
var color = d3.scale.ordinal()
.range(["#f38e36","#d79ae2","#dac2ad","#89e1ea"])
.domain(["Social", "Livability","Knowledge","Economy"]);
var arc = d3.svg.arc()
.outerRadius(radius - 0)
.innerRadius(radius - 110);
var wedge = d3.svg.arc()
.outerRadius(radius - 110)
.innerRadius(0);
var labelWedge = d3.svg.arc()
.outerRadius(radius-200)
.innerRadius(radius-200);
var pie = d3.layout.pie()
.sort(null)
.value(function(d) { return d.count; });
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
d3.csv("data.csv", type, function(error, data) {
if (error) throw error;
nested = [{"category":"Social","count":25},{"category":"Livability","count":25},{"category":"Knowledge","count":25},{"category":"Economy","count":25}];
data1=
[{"category":"Social","subcategory":"Eduction and Employment","count":0.39},
{"category":"Social","subcategory":"Social Support","count":0.39},
{"category":"Social","subcategory":"Housing & Communities","count":0.39},
{"category":"Social","subcategory":"Civil Society","count":0.39},
{"category":"Livability","subcategory":"Activation and Calendaring","count":0.26},
{"category":"Livability","subcategory":"Mobility","count":0.26},
{"category":"Livability","subcategory":"Nature","count":0.26},
{"category":"Livability","subcategory":"Healthy and Sustainable Lifestyle","count":0.26},
{"category":"Livability","subcategory":"Marketing","count":0.26},
{"category":"Livability","subcategory":"Source of Distinctiveness","count":0.26},
{"category":"Knowledge","subcategory":"Vibrant Tech Companies","count":0.39},
{"category":"Knowledge","subcategory":"Tech Talent Attraction","count":0.39},
{"category":"Knowledge","subcategory":"Distinctive Tech Eduction","count":0.39},
{"category":"Knowledge","subcategory":"Full-Fledge R&D System","count":0.39},
{"category":"Economy","subcategory":"Business Environment Companiesetitiveness","count":0.39},
{"category":"Economy","subcategory":"Tourism","count":0.39},
{"category":"Economy","subcategory":"SME Support","count":0.39},
{"category":"Economy","subcategory":"Private Sector Incentivization","count":0.39}];
console.log("nested", nested);
console.log("nested", data1);
var g = svg.selectAll(".arc")
.data(pie(data1))
.enter().append("g")
.attr("class", "arc");
g.append("path")
.attr("d", arc)
.style("fill", function(d) { return color(d.data.category); });
g.append("text")
.attr("transform", function(d) { return transformLabel(d); })
.attr("dy", ".35em")
.text(function(d) { return d.data.subcategory; });
var g = svg.selectAll(".wedge")
.data(pie(nested))
.enter().append("g")
.attr("class", "wedge");
g.append("path")
.attr("d", wedge)
.style("fill", function(d) { return color(d.data.category); });
g.append("text")
.attr("transform", function(d) { return "translate(" + labelWedge.centroid(d) + ")"; })
.attr("dy", ".35em")
.text(function(d) { return d.data.category; });
});
function type(d) {
d.count = +d.count;
return d;
}
function transformLabel(d){
[x, y] = arc.centroid(d);
var rotation = d.endAngle < Math.PI ? (d.startAngle / 2 + d.endAngle / 2) * 180 / Math.PI : (d.startAngle / 2 + d.endAngle / 2 + Math.PI) * 180 / Math.PI;
let label = "translate(" + [x, y] + ") rotate(-90) rotate(" + rotation + ")";
return label;
}
function wrap(text, width) {
text.each(function () {
var text = d3.select(this),
words = text.text().split(/\s+/).reverse(),
word,
line = [],
lineNumber = 0,
lineHeight = 1.1, // ems
x = text.attr("x"),
y = text.attr("y"),
dy = 0, //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);
}
}
});
}
</script>
calling wrap text not working properly. when I call the wraptext function i got the text but they are mostly not aligned.also what is best option to add the shadow to the each segment of arc.

D3JS: Unable to place a group of text elements over several rectangles

I'm trying to create a set of text elements and place them above various rect elements so that it looks as if they were inside. the thing is that I haven't been able to accomplish this simple task.
The text elements I need inside the column of rect's are the elements of the array: var dataDnt4 = [42,31,16,4,3,2,1];
I'll leave a running snippet so that you can my progress so far.
Your help is very appreciated. thanks
var icon2 = '<g><path class="st0" d="M23.1,34.9c6.9,0,12.5-5.6,12.5-12.5c0-6.9-5.6-12.5-12.5-12.5c-6.9,0-12.5,5.6-12.5,12.5 C10.6,29.3,16.2,34.9,23.1,34.9L23.1,34.9z"/><path class="st0" d="M39.2,54.6c0.2,0,0.4,0,0.7,0c-3.7-3-6-7.5-6-12.6c0-1.2,0.1-2.4,0.4-3.6c-0.1,0-0.3,0-0.4,0H12.4 C5.5,38.5-0.1,44.1-0.1,51v17.9h23.3C24.1,60.8,30.9,54.6,39.2,54.6L39.2,54.6z"/><path class="st0" d="M76.8,34.9c6.9,0,12.5-5.6,12.5-12.5c0-6.9-5.6-12.5-12.5-12.5c-6.9,0-12.5,5.6-12.5,12.5 C64.2,29.3,69.9,34.9,76.8,34.9L76.8,34.9z"/><path class="st0" d="M87.5,38.5H66c-0.1,0-0.3,0-0.4,0c0.3,1.1,0.4,2.3,0.4,3.6c0,5.1-2.4,9.6-6,12.6c0.2,0,0.4,0,0.7,0 c8.3,0,15.1,6.3,16,14.3H100V51C100,44.1,94.4,38.5,87.5,38.5L87.5,38.5z"/><path class="st0" d="M49.9,54.6c6.9,0,12.5-5.6,12.5-12.5c0-6.9-5.6-12.5-12.5-12.5c-6.9,0-12.5,5.6-12.5,12.5 C37.4,49,43,54.6,49.9,54.6L49.9,54.6z"/><path class="st0" d="M60.7,58.1H39.2c-6.9,0-12.5,5.6-12.5,12.5v17.9h46.5V70.7C73.2,63.7,67.6,58.1,60.7,58.1L60.7,58.1z"/></g>'
var dataDnt4 = [42, 31, 16, 4, 3, 2, 1];
var distanciaRect = [25, 50, 75, 100, 125, 150, 175]
var width = 512,
height = 600
radius = (Math.min(width, height) / 2.5) - 60;
var sym = "%"
var legendTextArr = ["alpha", "beta", "Gamma", "vvv", "www", "xxx", "yyy", "zzz"]
var color_rect = ["#00338D", "#BC204B", "#0091DA", "#eaaa00", "#005eb8", "#f68d2e", "#009444", "#470a68"]
var pie = d3.pie()
.value(function(d) {
return d
})(dataDnt4);
var arc = d3.arc()
.outerRadius(radius - 10)
.innerRadius(radius - (radius / 2.4));
var labelArc = d3.arc()
.outerRadius(radius - 35)
.innerRadius(radius - 35);
var svg = d3.select("#chartdiv")
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2.4 + ")");
var title = svg.append("text")
.attr("font-weight", "bold")
.attr("class", "title1")
.html("title 1")
.attr("transform", function() {
return "translate(" + (-184) + "," + (-180) + ")"
})
var title = svg.append("text")
.attr("font-weight", "bold")
.attr("class", "title2")
.html("title 2")
.attr("transform", function() {
return "translate(" + (-184) + "," + (-160) + ")"
})
var legendG = svg.append("g")
.attr("class", "legendG")
.attr("transform", function() {
return "translate(" + (-60) + "," + (155) + ")"
})
var legendG = svg.append("g")
.attr("class", "legendG")
.attr("transform", function() {
return "translate(" + (-60) + "," + (155) + ")"
})
var legendText = legendG.selectAll("text")
.data(distanciaRect)
.enter()
.append("text")
.attr("x", -80)
.attr("y", function(d, i) {
return d + 10
})
.data(legendTextArr)
.html(function(d) {
return d
})
var legends = legendG.selectAll(".rect")
.data(distanciaRect)
.enter()
.append("rect")
.attr("x", -120)
.attr("y", function(d, i) {
return d
})
.attr("width", 25)
.attr("height", 17)
.attr("class", "icon1")
.data(color_rect)
.attr("fill", function(d, i) {
return d
})
var g = svg.selectAll("arc")
.data(pie)
.enter().append("g")
.attr("class", "arc");
function easeInverse(ease) {
return function(e) {
var min = 0,
max = 1;
while (max - min > 1e-3) {
var mid = (max + min) * 0.5;
emid = ease(mid);
if (emid > e) {
max = mid;
} else {
min = mid;
}
}
return max;
}
}
var inverseCubic = easeInverse(d3.easeCubic);
var oneOver2Pi = 1.0 / (2 * Math.PI);
var total_msec = 2000;
g.append("path")
.attr("d", arc)
.attr("transform", function() {
return "translate(" + (-16) + "," + (0) + ")"
})
.style("fill", function(d, i) {
return color_rect[i];
})
.transition()
.ease(d3.easeLinear)
.delay(function(d) {
return total_msec * inverseCubic(d.startAngle * oneOver2Pi);
})
.duration(function(d) {
return total_msec * (inverseCubic(d.endAngle * oneOver2Pi) - inverseCubic(d.startAngle * oneOver2Pi));
})
.attrTween("d", arcTween);
function arcTween(d) {
var i = d3.interpolate(inverseCubic(d.startAngle * oneOver2Pi), inverseCubic(d.endAngle * oneOver2Pi));
return function(t) {
d.endAngle = 2 * Math.PI * d3.easeCubic(i(t));
return arc(d);
}
}
svg.append("g")
.attr("class", "icon2")
.html(icon2);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://d3js.org/d3.v5.min.js"></script>
<div id="chartdiv"></div>
There are numerous ways to do this, so here is one possible way. I would group together the three pieces of the legend--the rectangle, the key text, and the text over the rectangle--in a g element and bind dataDnt4 to each item. The rectangle colour and the legend text can be retrieved by position, i.e. the first dataDnt4 item corresponds to color_rect[0] and legendTextArr[0], the second to color_rect[1] and legendTextArr[1], etc.
I've cut out the code that is not relevant to the positioning of the legend items -- you can restore that in your script.
var width = 512,
height = 600,
radius = (Math.min(width, height) / 2.5) - 60;
var sym = "%"
var legendTextArr = ["alpha", "beta", "Gamma", "vvv", "www", "xxx", "yyy", "zzz"]
var dataDnt4 = [42, 31, 16, 4, 3, 2, 1];
var color_rect = ["#00338D", "#BC204B", "#0091DA", "#eaaa00", "#005eb8", "#f68d2e", "#009444", "#470a68"]
var svg = d3.select("#chartdiv")
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2.4 + ")");
var title = svg.append("text")
.attr("font-weight", "bold")
.attr("class", "title1")
.html("scroll down!")
.attr("transform", function() {
return "translate(" + -184 + "," + -180 + ")"
})
var legendG = svg.append("g")
.attr("class", "legendG")
.attr("transform", function() {
// this moves the whole legend box
// you can change this to whatever transformation is appropriate for your chart
return "translate(" + -((width / 2)-40) + "," + 120 + ")"
})
// group each legend item in a `g` element
var legendText = legendG.selectAll("g")
.data(dataDnt4)
.enter()
.append('g')
.attr('transform', function(d, i) {
// instead of having a hard-coded list of multiples of 25, you can multiply
// the array index, `i`, by 25 to get the correct position
return 'translate(0,' + (i*25) + ')';
});
legendText.append("rect")
.attr("width", 25)
.attr("height", 17)
.attr("class", "icon1")
.attr("fill", function(d, i) {
return color_rect[i];
})
// the text "in" the rectangle
// use 'text-anchor: middle' and an x offset of 12.5 (rectangle width / 2)
// to centre the labels
// change the `y` attribute to alter the vertical positioning
legendText.append("text")
.attr("x", 12.5)
.attr("y", 13)
.attr('text-anchor', 'middle')
.attr('fill', 'white')
// d is the items in dataDnt4
.text(function(d) {
return d;
})
// legend text items
legendText.append("text")
.attr("x", 40)
.attr("y", 13)
// take legendTextArr item in position i
.text(function(d,i) {
return legendTextArr[i];
})
<script src="https://d3js.org/d3.v5.min.js"></script>
<div id="chartdiv"></div>
You have some errors in your code (e.g. you declare the variables legendG and title twice), and it would probably be helpful for you to run your code through a code linter so you can see the problems that you might not pick up by eye.

How to update the innerRadius and the outterRadius of a donut chart in d3?

I'm trying to change the innerRadius and the outterRadius of a donut chart by using a slider.
Here is the JSFiddle link: https://jsfiddle.net/SashimiEthan/woetyLg3/3/
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="bootstrap.css">
<link href='http://fonts.googleapis.com/css?family=Lato' rel='stylesheet' type='text/css' />
<link rel="stylesheet" type="text/css" href="style.css">
<script src="d3.min.js"></script>
<script scr="color.min.js"></script>
<script scr="d3.slider.js"></script>
</head>
<body>
<div class="content">
<div class="wrapper" id="wheel"></div>
</div>
<script>
var width = 300;
r = width / 2,
labelr = r + 20
outerRadius = 150,
innerRadius = outerRadius - 30;
; // radius for label anchor
var mySvg = d3.select("#wheel").append("svg")
.attr("width", 500)
.attr("height", 500);
var myGroup = mySvg.append("g")
.attr("transform", "translate(200,200)" );
var arc = d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius);
var arc1 = d3.svg.arc()
.innerRadius(innerRadius-30)
.outerRadius(outerRadius-30);
var numberOfSegments = 12;
var radians;
var degrees;
// function render (arc) {
radians = (Math.PI * 2) / numberOfSegments;
degrees = 360 / numberOfSegments;
arc.startAngle(function (d,i) { return radians * i } );
arc.endAngle(function (d,i) { return radians * (i + 1) });
var g = myGroup.selectAll("g").data(d3.range(numberOfSegments));
g.enter().append("g").attr("class", "arc");
g.append("path")
.attr("class", "seg")
.attr("d", arc)
.attr("fill", function(d,i) {
return "hsl(" + (i * degrees) + ",100%,50%)";
});
g.append('text').attr("transform", function(d,i) {
var c = arc.centroid(d,i),
x = c[0],
y = c[1],
// pythagorean theorem for hypotenuse
h = Math.sqrt(x*x + y*y);
console.log(c);
return "translate(" + (x/h * labelr) + ',' +(y/h * labelr) + ")";
})
.attr("dy", ".35em")
.attr("dx", "-0.9em")
.attr("text-anchor", function(d) {
// are we past the center?
return (d.endAngle + d.startAngle)/2 > Math.PI ?
"end" : "start";
})
.text(function(d,i) {
return i * degrees + "°";
});
g.exit().remove();
// }
// render(arc);
var margin = {top: 10, right: 50, bottom: 10, left: 50},
width = 300 - margin.left - margin.right, //controller
height = 50 - margin.bottom - margin.top; //controller
startingValue1 = 1;
var x = d3.scale.linear()
.domain([0, 1])
.range([0, width])
.clamp(true);
var brush1 = d3.svg.brush()
.x(x)
.extent([0, 0]) //brush length
.on("brush", brushed1);
var svg = d3.select("body").append("svg") //controller area
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")"); //move controller
svg.append("text").text("Saturation")
var axis = svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height / 2 + ")")
.call(d3.svg.axis()
.scale(x)
.orient("bottom")
.tickValues([0, 0.5, 1])
.tickSize(0)
.tickPadding(10))
.select(".domain")
.select(function() { return this.parentNode.appendChild(this.cloneNode(true)); })
.attr("class", "halo");
var slider = svg.append("g")
.attr("class", "slider")
.call(brush1);
slider.selectAll(".extent,.resize")
.remove();
slider.select(".background")
.attr("height", height);
var handle = slider.append("g")
.attr("class", "handle")
handle.append("circle")
.attr("class","ctl")
.attr("transform", "translate(0," + height / 2 + ")")
.attr("r", 8);
handle.append('text')
.text(startingValue1)
.attr("transform", "translate(" + (-5) + " ,0)");
slider
.call(brush1.event)
.call(brush1.extent([1, 1]))
.call(brush1.event);
function brushed1() {
var value = brush1.extent()[0];
if (d3.event.sourceEvent) {
handle.select('text');
value = x.invert(d3.mouse(this)[0]);
brush1.extent([value, value]);
}
handle.attr("transform", "translate(" + x(value) + ",0)");
var format = d3.format(".1f");
handle.select('text').text(format(value))
var newarc = d3.svg.arc()
.innerRadius(innerRadius-30)
.outerRadius(outerRadius-30);
d3.selectAll(".seg").attr("d",newarc);
d3.selectAll(".seg").style("fill",function(d,i) {
return d3.hsl(i * degrees, value, 0.5)
});
}
</script>
(Sorry the code is messy. I'm new to d3) So I got the saturation adjustment part working, but the radius adjustment part
var newarc = d3.svg.arc()
.innerRadius(innerRadius-30)
.outerRadius(outerRadius-30);
d3.selectAll(".seg").attr("d",newarc)
always gave me the error: Invalid value for attribute d="……"
T^T
When you define newarc after moving the slider, you need to include the startAngle and endAngle attributes, in the same way as you do when you first define arc.
This is all you need to do:
var newarc = d3.svg.arc()
.innerRadius(innerRadius - (30 * value))
.outerRadius(outerRadius)
.startAngle(function(d, i) {
return radians * i
})
.endAngle(function(d, i) {
return radians * (i + 1)
});
d3.selectAll(".seg").attr("d", newarc);
Note that to make it clearer what's happening when the slider is moved, I've made the innerRadius value dependent on the slider's value.
See a working fiddle here: http://jsfiddle.net/henbox/vxq9o2a8/1/

How use text variable for label d3 graphic

I am learning d3, i use the "dataset" variable for the values of the graphic,
i wish use dataset.nombre values for label the d3 graphic, but i can only use dataset.numbers, this is a simplified code version:
<body>
<div id="container2"></div>
<script>
var dataset = {
numbers: [15, 3, 10, 2, 14,17,1],
nombre:["a","b","c","d","e","f","g"]
};
var color = d3.scale.category20();
var pie = d3.layout.pie()
.sort(null);
var piedata = pie(dataset.apples);
var arc = d3.svg.arc()
.innerRadius(radius - 100)
.outerRadius(radius - 50);
var svg = d3.select("#container2").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var path = svg.selectAll("path")
.data(piedata)
.enter().append("path")
.attr("fill", function(d, i) { return color(i); })
.attr("d", arc);
svg.selectAll("text").data(piedata)
.enter()
.append("text")
.attr("text-anchor", "middle")
.attr("x", function(d) {
var a = d.startAngle + (d.endAngle - d.startAngle)/2 - Math.PI/2;
d.cx = Math.cos(a) * (radius - 75);
return d.x = Math.cos(a) * (radius - 20);
})
.attr("y", function(d) {
var a = d.startAngle + (d.endAngle - d.startAngle)/2 - Math.PI/2;
d.cy = Math.sin(a) * (radius - 75);
return d.y = Math.sin(a) * (radius - 20);
})
.text(function(d) { return d.value; })
.each(function(d) {
var bbox = this.getBBox();
d.sx = d.x - bbox.width/2 - 2;
d.ox = d.x + bbox.width/2 + 2;
d.sy = d.oy = d.y + 5;
});
svg.append("defs").append("marker")
.attr("id", "circ")
.attr("markerWidth", 6)
.attr("markerHeight", 6)
.attr("refX", 3)
.attr("refY", 3)
.append("circle")
.attr("cx", 3)
.attr("cy", 3)
.attr("r", 3);
svg.selectAll("path.pointer").data(piedata).enter()
.append("path")
.attr("class", "pointer")
.style("fill", "none")
.style("stroke", "black")
.attr("marker-end", "url(#circ)")
.attr("d", function(d) {
if(d.cx > d.ox) {
return "M" + d.sx + "," + d.sy + "L" + d.ox + "," + d.oy + " " + d.cx + "," + d.cy;
} else {
return "M" + d.ox + "," + d.oy + "L" + d.sx + "," + d.sy + " " + d.cx + "," + d.cy;
}
});
</script>
</body>
Ideally you'd have objects instead of numbers as the data you pass to the pie layout; then you'd be able to use the data directly. In your case, you can still do so by using the index:
.text(function(d, i) { return dataset.nombre[i]; })
Complete demo here.

Resources