I'm trying to set up a visualization so that the higher value cells are with gravity forced to the top and left, but I'm having trouble keeping multiple circles within the boundaries of the div with red area. Can you help me solve this?
function CreateCirclesOfProcessos(seletor, data, numWidth, numHeight) {
let numBoundaryDiameter = 50;
let numBoundaryRadius = 5;
let numMaxRadius = 100;
let numMargin = data.length * 10;
let n = 50;
const radiusScale = d3.scaleSqrt()
.domain([0, d3.max(data, d => d.value)])
.range([0, numMaxRadius]);
const radius = function (d) {
return radiusScale(d.value);
}
let objNodes = CreateProcessosNodes(n, numBoundaryRadius, numBoundaryDiameter, data, numWidth, numHeight);
let objGraphData = GetProcessosGraphData(radius, objNodes);
const objSVG = seletor.append('svg')
.attr("width", numWidth)
.attr("height", numHeight + numMargin);
let objGroup = objSVG.append('g')
.attr("transform", "translate(" + 70 + ", " + 70 + ")");
objGroup.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", numWidth)
.attr("height", numHeight)
.style("stroke", "none")
.style("fill", "none");
let objCircles = objGroup.selectAll("circle")
.data(objGraphData.nodes)
.enter()
.append("g")
.style("cursor", "pointer")
.attr("transform", function (d) { return "translate(" + d.x + "," + d.y + ")"; });
objCircles.append("circle")
.attr("cx", 0)
.attr("cy", 0)
.attr("r", radius)
.style("fill", "#FF5532")
.style("stroke", "white");
}
Thanks!!
This is my complete code on JsFiddle
Supply a custom tick function, and use it to keep items in bounds. We can also use forceCenter to keep items at the center:
const force = d3.forceSimulation(objNodes)
.force("x", d3.forceX().x(CoordinatePosition).strength(GetStrength))
.force("y", d3.forceY().y(CoordinatePosition).strength(GetStrength))
.force('many', d3.forceManyBody().strength(2))
.force('collide', d3.forceCollide().radius(numRadius).strength(1))
.force("center", d3.forceCenter())
.on('tick', () => {
nodes.attr("cx", d => d.x = Math.max(radius, Math.min(width - radius, d.x)))
.attr("cy", d => d.y = Math.max(radius, Math.min(height - radius, d.y)));
})
.stop();
where nodes represent your circles. In this case, you'll have to pass the objCircles selection from earlier in your code:
let objCircles = objGroup.selectAll("circle")
.data(objGraphData.nodes)
.enter()
.append("g")
.style("cursor", "pointer")
.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});
let objGraphData = GetProcessosGraphData(radius, objNodes, objCircles);
// ...
function GetProcessosGraphData(numRadius, objNodes, nodes) {
// ...
}
I solve my problem using d3.forceLimit, implementing the following code on my simulation method.
const wallForce = d3.forceLimit()
.radius(node => node.r)
.x0(0)
.x1(numWidth)
.y0(0)
.y1(numHeight);
const force = d3.forceSimulation()
.nodes(objNodes)
.force("x", d3.forceX().x(CoordinatePosition).strength(GetStrength))
.force("y", d3.forceY().y(CoordinatePosition).strength(GetStrength))
.force('many', d3.forceManyBody().strength(1))
.force('collide', d3.forceCollide().radius(numRadius).strength(2.5))
.force('walls', wallForce)
.stop();
Related
I'm trying to create a bar spiral in d3 and I'm using this resource: http://bl.ocks.org/larsenmtl/222043d93a41d48b58d2bfa1e3d4f708
I'm not getting an error, but also I'm just getting a blank page no chart at all. Any guidance on where I'm going wrong would be appreciated. Also the console.table isn't showing data, even though initially it did.
// reading in the data
const dataset = d3.csv("/Journalists_Death.csv").then(function(data) {
console.log(data[0]);
});
//creating spiral chart
var width = 500,
height = 500,
start = 0,
end = 2.25,
numSpirals = 4;
var theta = function(r) {
return numSpirals * Math.PI * r;
};
var r = d3.min([width, height]) / 2 - 40;
var radius = d3.scaleLinear()
.domain([start, end])
.range([40, r]);
var svg = d3.select("#chart").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("tranform", "translate(" + width / 2 + ","+ height / 2 +")");
// create the spiral, borrowed from http://bl.ocks.org/syntagmatic/3543186
var points = d3.range(start, end + 0.001, (end = start) / 1000);
var spiral = d3.radialLine()
.curve(d3.curveCardinal)
.angle(theta)
.radius(radius);
var path = svg.append("path")
.datum(points)
.attr("id", "spiral")
.attr("d", spiral)
.style("fill", "none")
.style("stroke", "steelblue");
//fudge some data, 2 years of data starting today
var spiralLength = path.node().getTotalLength(),
N = 730,
barWidth = (spiralLength / N) - 1;
year = d => d.year
Total = d => d.Total
//here's our time scale that'll run along the spiral
var timeScale = d3.scaleTime() //line 52
.domain(d3.extent(dataset, function(d){
return d.year;
}))
.range([0, spiralLength]);
//yScale for the bar height
var yScale = d3.scaleLinear()
.domain([0, d3.max(dataset, function(d){
return d.Total
})])
.range([0, (r/numSpirals) - 30]);
//append our rects
svg.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("x", function(d,i){
//placement calculations
var linePer = timeScale(d.year),
posOnLine = path.node().getPointAtLength(linePer),
angleOnLine = path.node().getPointAtLength(linePer - barWidth);
d.linePer = linePer; // % of distance are on the spiral
d.x = posOnLine.x; // x position on the spiral
d.y = posOnLine.y; // y on position on the spiral
d.a = (Math.atan2(angleOnLine.y, angleOnLine.x) * 180 / Math.PI) - 90;
return d.x;
})
.attr("y", function(d){
return d.y;
})
.attr("width", function(d){
return barWidth;
})
.attr("height", function(d){
return yScale(d.Total);
})
.style("fill", "steelblue")
.style("stroke", "none")
.attr("transform", function(d){
return "rotate(" + d.a + "," + d.x + "," + d.y + ")";
});
I have made a violin plot in D3.js with the following code:
<script src="https://d3js.org/d3.v4.js"></script>`
<div id="power"></div>
<script>
var margin = {top: 120, right: 100, bottom: 80, left: 100},
width = 2600 - margin.left - margin.right,
height = 620 - margin.top - margin.bottom;
var svg = d3.select("#power")
.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 + ")");
// Read the data and compute summary statistics for each
d3.csv("static/csv/violinsummary.csv", function (data) {
// Show the X scale
var x = d3.scaleBand()
.range([0, width])
.domain(["2017-09", "2017-10", "2018-02", "2018-03"])
.paddingInner(0)
.paddingOuter(.5);
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
// Show the Y scale
var y = d3.scaleLinear()
.domain([80, 105])
.range([height, 0]);
svg.append("g").call(d3.axisLeft(y));
// Features of density estimate
var kde = kernelDensityEstimator(kernelEpanechnikov(.2), y.ticks(50));
// Compute the binning for each group of the dataset
var sumstat = d3.nest()
.key(function (d) {
return d.DATE;
})
.rollup(function (d) { // For each key..
input = d.map(function (g) {
return g.Power;
});
density = kde(input); // And compute the binning on it.
return (density);
})
.entries(data);
var maxNum = 0;
for (i in sumstat) {
allBins = sumstat[i].value;
kdeValues = allBins.map(function (a) {
return a[1]
});
biggest = d3.max(kdeValues);
if (biggest > maxNum) {
maxNum = biggest
}
}
// The maximum width of a violin must be x.bandwidth = the width dedicated to a group
var xNum = d3.scaleLinear()
.range([0, x.bandwidth()])
.domain([-maxNum, maxNum]);
svg
.selectAll("myViolin")
.data(sumstat)
.enter() // So now we are working group per group
.append("g")
.attr("transform", function (d) {
return ("translate(" + x(d.key) + " ,0)")
}) // Translation on the right to be at the group position
.append("path")
.datum(function (d) {
return (d.value)
}) // So now we are working density per density
.style("opacity", .7)
.style("fill", "#317fc8")
.attr("d", d3.area()
.x0(function (d) {
return (xNum(-d[1]))
})
.x1(function (d) {
return (xNum(d[1]))
})
.y(function (d) {
return (y(d[0]))
})
.curve(d3.curveCatmullRom));
});
function kernelDensityEstimator(kernel, X) {
return function (V) {
return X.map(function (x) {
return [x, d3.mean(V, function (v) {
return kernel(x - v);
})];
});
}
}
function kernelEpanechnikov(k) {
return function (v) {
return Math.abs(v /= k) <= 1 ? 0.75 * (1 - v * v) / k : 0;
};
}
</script>
Data (violinsummary.csv):
Power,DATE
89.29,2017-09
89.9,2017-09
91.69,2017-09
89.23,2017-09
91.54,2017-09
88.49,2017-09
89.15,2017-09
90.85,2017-09
89.59,2017-09
93.38,2017-10
92.41,2017-10
90.65,2017-10
91.07,2017-10
90.13,2017-10
91.73,2017-10
91.09,2017-10
93.21,2017-10
91.62,2017-10
89.58,2017-10
90.59,2017-10
92.57,2017-10
89.99,2017-10
90.59,2017-10
88.12,2017-10
91.3,2017-10
89.59,2018-02
91.9,2018-02
87.83,2018-02
90.36,2018-02
91.38,2018-02
91.56,2018-02
91.89,2018-02
90.95,2018-02
90.15,2018-02
90.24,2018-02
94.04,2018-02
85.4,2018-02
88.47,2018-02
92.3,2018-02
92.46,2018-02
92.26,2018-02
88.78,2018-02
90.13,2018-03
89.95,2018-03
92.98,2018-03
91.94,2018-03
90.29,2018-03
91.2,2018-03
94.22,2018-03
90.71,2018-03
93.03,2018-03
91.89,2018-03
I am trying to make a tooltip for each violin that shows the median and mean upon hover. I cannot figure out how to make the tooltip show up.
I know I need to do something like this with mouseover and mouseout but I'm not sure...
var tooltip = d3.select('#power')
.append('div')
.attr('class', 'tooltip')
.style("opacity", 0);
Any tips/guidance would be very appreciated.
You can implement the tooltip functionality by following two steps.
Step 1:
Initialize the tooltip container which already you did I guess.
var tooltip = svg.append("g")
.attr("class", "tooltip")
.style("display", "none");
tooltip.append("rect")
.attr("width", 30)
.attr("height", 20)
.attr("fill", "white")
.style("opacity", 0.5);
tooltip.append("text")
.attr("x", 15)
.attr("dy", "1.2em")
.style("text-anchor", "middle")
.attr("font-size", "12px")
.attr("font-weight", "bold");
Step 2:
Change the visibility property of the tooltip in the mouseover, mouseout event of the element. In your case, it's myViolin
.on("mouseover", function() {
tooltip.style("display", null);
})
.on("mouseout", function() {
tooltip.style("display", "none");
})
.on("mousemove", function(d) {
var xPosition = d3.mouse(this)[0] - 15;
var yPosition = d3.mouse(this)[1] - 25;
tooltip.attr("transform", "translate(" + xPosition + "," + yPosition + ")");
tooltip.select("text").text(d.y);
});
Here is the implementation of tooltip jsFiddle
Hope it helps :)
Can someone help me implementing a spiral chart similar to the one below using d3.js?
I've just got the basic spiral plot (a simple one) as of now but not been able to append bars to the plot based on the timeline as shown in the image. I'm trying out a few things (if you see the commented code).
Here's my fiddle, and my code:
var width = 400,
height = 430,
axes = 12,
tick_axis = 9,
start = 0,
end = 2.25;
var theta = function(r) {
return 2 * Math.PI * r;
};
var angle = d3.scale.linear()
.domain([0, axes]).range([0, 360])
var r = d3.min([width, height]) / 2 - 40;
var r2 = r;
var radius = d3.scale.linear()
.domain([start, end])
.range([0, r]);
var svg = d3.select("#chart").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + (height / 2 + 8) + ")");
var points = d3.range(start, end + 0.001, (end - start) / 1000);
var spiral = d3.svg.line.radial()
.interpolate("cardinal")
.angle(theta)
.radius(radius);
var path = svg.selectAll(".spiral")
.data([points])
.enter().append("path")
.attr("class", "spiral")
.attr("d", spiral)
var z = d3.scale.category20();
var circles = svg.selectAll('.circle')
.data(points);
/* circles.enter().append('circle')
.attr('r', 5)
.attr('transform', function(d) { return 'translate(' + d + ')'})
.style('fill', function(d) { return z(d); });
*/
var circle = svg.append("circle")
.attr("r", 13)
.attr("transform", "translate(" + points[0] + ")");
var movingCircle = circle.transition().duration(4000)
.attrTween('transform', translateAlongPath(path.node()))
// .attr('cx', function(d) { return radius(d) * Math.cos(theta(d))})
// .attr('cy', function(d) { return radius(d) * Math.sin(theta(d))})
function translateAlongPath(path) {
var l = path.getTotalLength();
return function(d, i, a) {
return function(t) {
var p = path.getPointAtLength(t * l);
//console.log(p)
return "translate(" + p.x + "," + p.y + ")";
};
};
}
function pathXY(path) {
var l = path.getTotalLength();
var start = 0;
/* for(i=start; i<l; i++) {
var point = path.getPointAtLength(i);
svg.append('rect').transition().duration(400).attr('transform', 'translate(' + point.x +','+point.y+')')
.attr('width', 10).attr('height', 30).style('fill', z);
}*/
}
pathXY(path.node());
/*var test = translateAlongPath(path.node())()();
//console.log(test)
var bars = svg.selectAll('.bar')
.data(points).enter().append('rect').transition().duration(2000)
// .attrTween('transform', translateAlongPath(path.node()))
.attr('class', 'bar')
.attr('width', 10)
.attr('height', 20)
.style('fill', function(d) { return z(d)});
*/
var rect = svg.append('rect').attr('width', 10).attr('height', 10);
rect.transition().duration(3400)
.attrTween('transform', translateAlongPath(path.node()));
It'd be great to have a few similar examples (i.e. spiral timeline plot).
Thanks.
Glad you came back and updated your question, because this is an interesting one. Here's a running minimal implementation. I've commented it ok, so let me know if you have any questions...
<!DOCTYPE html>
<html>
<head>
<script data-require="d3#4.0.0" data-semver="4.0.0" src="https://d3js.org/d3.v4.js"></script>
</head>
<body>
<div id="chart"></div>
<script>
var width = 500,
height = 500,
start = 0,
end = 2.25,
numSpirals = 4;
var theta = function(r) {
return numSpirals * Math.PI * r;
};
var r = d3.min([width, height]) / 2 - 40;
var radius = d3.scaleLinear()
.domain([start, end])
.range([40, r]);
var svg = d3.select("#chart").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
// create the spiral, borrowed from http://bl.ocks.org/syntagmatic/3543186
var points = d3.range(start, end + 0.001, (end - start) / 1000);
var spiral = d3.radialLine()
.curve(d3.curveCardinal)
.angle(theta)
.radius(radius);
var path = svg.append("path")
.datum(points)
.attr("id", "spiral")
.attr("d", spiral)
.style("fill", "none")
.style("stroke", "steelblue");
// fudge some data, 2 years of data starting today
var spiralLength = path.node().getTotalLength(),
N = 730,
barWidth = (spiralLength / N) - 1;
var someData = [];
for (var i = 0; i < N; i++) {
var currentDate = new Date();
currentDate.setDate(currentDate.getDate() + i);
someData.push({
date: currentDate,
value: Math.random()
});
}
// here's our time scale that'll run along the spiral
var timeScale = d3.scaleTime()
.domain(d3.extent(someData, function(d){
return d.date;
}))
.range([0, spiralLength]);
// yScale for the bar height
var yScale = d3.scaleLinear()
.domain([0, d3.max(someData, function(d){
return d.value;
})])
.range([0, (r / numSpirals) - 30]);
// append our rects
svg.selectAll("rect")
.data(someData)
.enter()
.append("rect")
.attr("x", function(d,i){
// placement calculations
var linePer = timeScale(d.date),
posOnLine = path.node().getPointAtLength(linePer),
angleOnLine = path.node().getPointAtLength(linePer - barWidth);
d.linePer = linePer; // % distance are on the spiral
d.x = posOnLine.x; // x postion on the spiral
d.y = posOnLine.y; // y position on the spiral
d.a = (Math.atan2(angleOnLine.y, angleOnLine.x) * 180 / Math.PI) - 90; //angle at the spiral position
return d.x;
})
.attr("y", function(d){
return d.y;
})
.attr("width", function(d){
return barWidth;
})
.attr("height", function(d){
return yScale(d.value);
})
.style("fill", "steelblue")
.style("stroke", "none")
.attr("transform", function(d){
return "rotate(" + d.a + "," + d.x + "," + d.y + ")"; // rotate the bar
});
// add date labels
var tF = d3.timeFormat("%b %Y"),
firstInMonth = {};
svg.selectAll("text")
.data(someData)
.enter()
.append("text")
.attr("dy", 10)
.style("text-anchor", "start")
.style("font", "10px arial")
.append("textPath")
// only add for the first of each month
.filter(function(d){
var sd = tF(d.date);
if (!firstInMonth[sd]){
firstInMonth[sd] = 1;
return true;
}
return false;
})
.text(function(d){
return tF(d.date);
})
// place text along spiral
.attr("xlink:href", "#spiral")
.style("fill", "grey")
.attr("startOffset", function(d){
return ((d.linePer / spiralLength) * 100) + "%";
})
</script>
</body>
</html>
I am creating an arc diagram where I'd like to, hopefully, find a way to prevent the overlap of arcs. There's an example of the working bl.ock here.
The darker lines in this case are overlapping lines where multiple nodes share the same edge. I'd like to prevent that, perhaps by doing two passes: the first would alternate the arc to go above the nodes rather than below, giving a sort of helix appearance; the second would draw a slightly larger arc if an arc already exists above/below to help differentiate the links.
var width = 1000,
height = 500,
margin = 20,
pad = margin / 2,
radius = 6,
yfixed = pad + radius;
var color = d3.scale.category10();
// Main
//-----------------------------------------------------
function arcDiagram(graph) {
var radius = d3.scale.sqrt()
.domain([0, 20])
.range([0, 15]);
var svg = d3.select("#chart").append("svg")
.attr("id", "arc")
.attr("width", width)
.attr("height", height);
// create plot within svg
var plot = svg.append("g")
.attr("id", "plot")
.attr("transform", "translate(" + pad + ", " + pad + ")");
// fix graph links to map to objects
graph.links.forEach(function(d,i) {
d.source = isNaN(d.source) ? d.source : graph.nodes[d.source];
d.target = isNaN(d.target) ? d.target : graph.nodes[d.target];
});
linearLayout(graph.nodes);
drawLinks(graph.links);
drawNodes(graph.nodes);
}
// layout nodes linearly
function linearLayout(nodes) {
nodes.sort(function(a,b) {
return a.uniq - b.uniq;
})
var xscale = d3.scale.linear()
.domain([0, nodes.length - 1])
.range([radius, width - margin - radius]);
nodes.forEach(function(d, i) {
d.x = xscale(i);
d.y = yfixed;
});
}
function drawNodes(nodes) {
var gnodes = d3.select("#plot").selectAll("g.node")
.data(nodes)
.enter().append('g');
var nodes = gnodes.append("circle")
.attr("class", "node")
.attr("id", function(d, i) { return d.name; })
.attr("cx", function(d, i) { return d.x; })
.attr("cy", function(d, i) { return d.y; })
.attr("r", 5)
.style("stroke", function(d, i) { return color(d.gender); });
nodes.append("text")
.attr("dx", function(d) { return 20; })
.attr("cy", ".35em")
.text(function(d) { return d.name; })
}
function drawLinks(links) {
var radians = d3.scale.linear()
.range([Math.PI / 2, 3 * Math.PI / 2]);
var arc = d3.svg.line.radial()
.interpolate("basis")
.tension(0)
.angle(function(d) { return radians(d); });
d3.select("#plot").selectAll(".link")
.data(links)
.enter().append("path")
.attr("class", "link")
.attr("transform", function(d,i) {
var xshift = d.source.x + (d.target.x - d.source.x) / 2;
var yshift = yfixed;
return "translate(" + xshift + ", " + yshift + ")";
})
.attr("d", function(d,i) {
var xdist = Math.abs(d.source.x - d.target.x);
arc.radius(xdist / 2);
var points = d3.range(0, Math.ceil(xdist / 3));
radians.domain([0, points.length - 1]);
return arc(points);
});
}
Any pointers on how I might start approaching the problem?
Here is a bl.ock for reference. It shows your original paths in gray, and the proposed paths in red.
First store the counts for how many times a given path occurs:
graph.links.forEach(function(d,i) {
var pathCount = 0;
for (var j = 0; j < i; j++) {
var otherPath = graph.links[j];
if (otherPath.source === d.source && otherPath.target === d.target) {
pathCount++;
}
}
d.pathCount = pathCount;
});
Then once you have that data, I would use an ellipse instead of a radial line since it appears the radial line can only draw a curve for a circle:
d3.select("#plot").selectAll(".ellipse-link")
.data(links)
.enter().append("ellipse")
.attr("fill", "transparent")
.attr("stroke", "gray")
.attr("stroke-width", 1)
.attr("cx", function(d) {
return (d.target.x - d.source.x) / 2 + radius;
})
.attr("cy", pad)
.attr("rx", function(d) {
return Math.abs(d.target.x - d.source.x) / 2;
})
.attr("ry", function(d) {
return 150 + d.pathCount * 20;
})
.attr("transform", function(d,i) {
var xshift = d.source.x - radius;
var yshift = yfixed;
return "translate(" + xshift + ", " + yshift + ")";
});
Note that changing the value for ry above will change the heights of different curves.
Finally you'll have to use a clippath to restrict the area of each ellipse that's actually shown, so that they only display below the nodes. (This is not done in the bl.ock)
Hi there I currently have a template helper that returns me an array with various values used to generate different rows in a table in my HTML.
<template name="stop">
{{#each thumb}}
<tr>
<td>
<h2> Do you like this product? </h2>
<h2>{{text}}</h2>
<svg id="donutChart"> </svg>
</td>
</tr>
{{/each}}
</template>
It also contains a svg tag which I also want to generate a graph for each element generated as a table row and this is what the template helper looks like.
Template.stop.helpers({
'thumb': function(data) {
var result = tweetImages.findOne();
var newResult = [];
for (var i = 0; i < result.data.length; i++) {
newResult[i] = {
data: result.data[i],
text: result.text[i]
};
}
console.log(newResult)
return newResult;
}
I'm trying to create a pie reactive pie chart for each element in the table however I don't seem to be able to access the svg in the stop template.
The d3 code works fine outside that table but cant seem to be generated for each element of the table because it can't access the svg element.
Template.donutChart.rendered = function() {
//my d3 code is here
//Width and height
var w = 300;
var h = 300;
var center = w / 2;
var outerRadius = w / 2;
var innerRadius = 0;
var radius = 150;
var arc = d3.svg.arc()
.innerRadius(40)
.outerRadius(radius + 10 - 25);
var pie = d3.layout.pie()
.sort(null)
.value(function(d) {
return d.data;
});
//Create SVG element
var svg = d3.select("#donutChart")
.attr("width", w)
.attr("height", h)
.attr("transform", "translate(" + 200 + "," + 100 + ")");
// GROUP FOR CENTER TEXT
var center_group = svg.append("svg:g")
.attr("class", "ctrGroup")
.attr("transform", "translate(" + (w / 2) + "," + (h / 2) + ")");
// CENTER LABEL
var pieLabel = center_group.append("svg:text")
.attr("dy", ".35em").attr("class", "chartLabel")
.attr("text-anchor", "middle")
.text("Clothes")
.attr("fill", "white");
Deps.autorun(function() {
var modifier = {
fields: {
value: 1
}
};
Deps.autorun(function() {
var arcs = svg.selectAll("g.arc")
.data(pie(players))
var arcOutter = d3.svg.arc()
.innerRadius(outerRadius - 10)
.outerRadius(outerRadius);
var arcPhantom = d3.svg.arc()
.innerRadius(-180)
.outerRadius(outerRadius + 180);
var newGroups =
arcs
.enter()
.append("g")
.attr("class", "arc")
.attr("transform", "translate(" + 150 + "," + 150 + ")")
//Set up outter arc groups
var outterArcs = svg.selectAll("g.outter-arc")
.data(pie(players))
.enter()
.append("g")
.attr("class", "outter-arc")
.attr("transform", "translate(" + 150 + ", " + 150 + ")");
//Set up phantom arc groups
var phantomArcs = svg.selectAll("g.phantom-arc")
.data(pie(players))
.enter()
.append("g")
.attr("class", "phantom-arc")
.attr("transform", "translate(" + center + ", " + center + ")");
outterArcs.append("path")
.attr("fill", function(d, i) {
return slickColor[i];
})
.attr("fill-opacity", 0.85)
.attr("d", arcOutter).style('stroke', '#0ca7d2')
.style('stroke-width', 2)
//Draw phantom arc paths
phantomArcs.append("path")
.attr("fill", 'white')
.attr("fill-opacity", 0.1)
.attr("d", arcPhantom).style('stroke', '#0ca7d2')
.style('stroke-width', 5);
//Draw arc paths
newGroups
.append("path")
.attr("fill", function(d, i) {
return slickColor[i];
})
.attr("d", arc);
//Labels
newGroups
.append("text")
.attr("transform", function(d) {
return "translate(" + arc.centroid(d) + ")";
})
.attr("text-anchor", "middle")
.text(function(d) {
return d.value;
})
.style("font-size", function(d) {
return 24;
})
svg.selectAll("g.phantom-arc")
.transition()
.select('path')
.attrTween("d", function(d) {
this._current = this._current || d;
var interpolate = d3.interpolate(this._current, d);
this._current = interpolate(0);
return function(t) {
return arc(interpolate(t));
};
});
arcs
.transition()
.select('path')
.attrTween("d", function(d) {
this._current = this._current || d;
var interpolate = d3.interpolate(this._current, d);
this._current = interpolate(0);
return function(t) {
return arc(interpolate(t));
};
});
arcs
.transition()
.select('text')
.attr("transform", function(d) {
return "translate(" + arc.centroid(d) + ")";
})
.text(function(d) {
return d.value;
})
.attr("fill", function(d, i) {
return textColor[i];
})
arcs
.exit()
.remove();
});
});
}
}
I can't seem to find much information on using d3.js or SVG's within a templates #each wrapper. Any help would be truly appreciated.
I would suggest wrapping your d3 code in a Deps.autorun() function as what's most likely happening is your data isn't available yet when your pie is bound to the data function and thus doesn't render anything.
Template.donutChart.rendered = function() {
Tracker.autorun(function () {
//all d3 code
});
}
You look like you're using autoruns further down but not for the bit that gets your data.