Unable to get values of d in d3.js - javascript

I am building a pie chart in d3. In this I have a very specific need to have labels extruding out with a horizontal line attached to the slice ticks.
Here is my code
svg.selectAll("g.arc")
.data(pie)
.enter()
.append("text")
.attr("text-anchor", "middle")
.attr("x", function(d) {
var a = 180-(d.startAngle + (d.endAngle - d.startAngle)/2)-45 - Math.PI/2;
d.cx = Math.cos(a) * (radius - 75);
return d.x =(width/3)+ Math.cos(a) * (oldRadius - 20);
})
.attr("y", function(d) {
var a = 180-(d.startAngle + (d.endAngle - d.startAngle)/2)-45 - Math.PI/2;
d.cy = Math.sin(a) * (radius - 75);
return d.y =(height/2)- Math.sin(a) * (oldRadius - 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("g.arc")
.data(pie)
.enter()
.append("path")
.attr("class", "pointer")
.style("fill", "none")
.style("stroke", "black")
.attr("marker-end", "url(#circ)")
.attr("d", function(d,i) {
alert(d.cx);
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;
}
});
For this i need to use some values like cx,ox,sx from d variable.I am setting these values when i am building the chart in the first block of code.
The problem is when I am trying to retrieve these values when I am printing labels and ticks,i am getting 'undefined' values. Can anybody point out what i am doing wrong here,do i need to change something???
Thanks in advance

A fiddle would be helpful here...
I suspect that the issue is that you don't need the following two lines when appending the paths:
.data(pie)
.enter()
This is resetting the data. If you just select the arcs, svg.selectAll("g.arc"), the modified data should be available.
Here is a snippet where the values are not undefined (although using your math above, the lines are wonky).
<!DOCTYPE html>
<html>
<meta charset="utf-8">
<style>
body {
font: 10px sans-serif;
}
.arc path {
stroke: #fff;
}
</style>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<script>
var width = 200,
height = 200,
radius = Math.min(width, height) / 2;
var color = d3.scale.ordinal()
.range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);
var data = [
{age: "<5", population: "2704659"},
{age: "5-13", population: "4499890"},
{age: "14-17", population: "2159981"},
{age: "18-24", population: "3853788"},
{age: "25-44", population: "14106543"},
{age: "45-64", population: "8819342"},
{age: "≥65", population: "612463"}];
var arc = d3.svg.arc()
.outerRadius(radius - 10)
.innerRadius(0);
var pie = d3.layout.pie()
.sort(null)
.value(function(d) { return d.population; });
var svg = d3.select("body").append("svg")
.attr("width", 600)
.attr("height", 600)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
data.forEach(function(d) {
d.population = +d.population;
});
var g = svg.selectAll(".arc")
.data(pie(data))
.enter().append("g")
.attr("class", "arc");
g.append("path")
.attr("d", arc)
.style("fill", function(d) { return color(d.data.age); });
var oldRadius = radius / 2;
svg.selectAll("g.arc")
.append("text")
.attr("text-anchor", "middle")
.attr("x", function (d) {
var a = 180 - (d.startAngle + (d.endAngle - d.startAngle) / 2) - 45 - Math.PI / 2;
d.cx = Math.cos(a) * (radius - 75);
d.x = (width / 3) + Math.cos(a) * (oldRadius - 20);
return d.x;
})
.attr("y", function (d) {
var a = 180 - (d.startAngle + (d.endAngle - d.startAngle) / 2) - 45 - Math.PI / 2;
d.cy = Math.sin(a) * (radius - 75);
d.y = (height / 2) - Math.sin(a) * (oldRadius - 20);
return d.y;
})
.text(function (d) {
return d.data.population;
})
.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("g.arc")
.append("path")
.attr("class", "pointer")
.style("fill", "none")
.style("stroke", "black")
.attr("marker-end", "url(#circ)")
.attr("d", function (d, i) {
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>
</html>

Related

D3 Donut Chart with Connectors

I'm trying to create a static d3 donut chart with labels and connectors from a json object. I've been able to get it to work with an array in this fiddle but can't get the connectors or label text to appear with the data object that I need.
The donut chart is working and the labels are appearing with the percentages, but I need them to appear with the labels and connectors. I think that it has something to do with the way that I am trying to map the connectors but can't figure out the error.
Code is below and also here is a link to a working fiddle: https://jsfiddle.net/hef1u71o/
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<script src="https://d3js.org/d3.v3.min.js"></script>
<script>
var data = [{
percentage: 19,
label: 'Consulting'
},{
percentage: 3,
label: 'Consumer Goods'
},{
percentage: 5,
label: 'Energy/Chemical/Gas'
},{
percentage: 3,
label: 'Entrepreneurship'
},{
percentage: 1,
label: 'Environment & Sustainability'
},{
percentage: 19,
label: 'Financial Services'
},{
percentage: 3,
label: 'General Management'
},{
percentage: 6,
label: 'Government'
},{
percentage: 7,
label: 'Hospital/Health Care/Health Services'
},{
percentage: 2,
label: 'Human Resources'
},{
percentage: 4,
label: 'IT'
},{
percentage: 2,
label: 'International Development'
},{
percentage: 3,
label: 'Manufacturing/Operations'
},{
percentage: 4,
label: 'Marketing/PR/Advertising'
},{
percentage: 1,
label: 'Media/Sports/Entertainment'
},{
percentage: 7,
label: 'Nonprofit/Education/Special Org.'
},{
percentage: 6,
label: 'Other'
},{
percentage: 2,
label: 'Research & Development'
},{
percentage: 4,
label: 'Sales/Business Development'
},];
var width = 300,
height = 300,
radius = Math.min(width, height) / 2;
var color = d3.scale.ordinal()
.range(["#243668", "#2b7eb4", "#186b97", "#6391a1", "#d2c5b7", "#9c9286", "#5b5b59"]);
var pie = d3.layout.pie()
.sort(null)
.value(function(d) { return d.percentage; });
var arc = d3.svg.arc()
.innerRadius(radius - 100)
.outerRadius(radius - 50);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var path = svg.selectAll("path")
.data(pie(data))
.enter().append("path")
.attr("fill", function(d, i) { return color(i); })
.attr("d", arc);
svg.selectAll("text").data(pie(data))
.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(pie(data)).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>
</html>
Save your data into variable:
var pieData = pie(data);
And use this variable here:
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) { // !!! you extent the dataset here
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;
});
and here:
svg.selectAll("path.pointer").data(pieData).enter()
.append("path")
.attr("class", "pointer")
...
It's important because of you extend the data (see each method). You will use extended properties for calculating of connectors position and you should use the same dataset for both cases.
Check working demo.

How to rotate the D3 chart so that the selected arc is at the bottom?

I am trying to develop an application where users can click on the D3 pie chart and see information which relates to the selection. How can I rotate the arc's so that the clicked arc comes to the bottom (the centre of the arc clicked on should be at the bottom)? I have been playing around with rotating the pie by selecting the arc group but I would appreciate any idea on how to achieve this.
Here is some code I have so far.
var self = this;
var instanceId = Math.floor(Math.random() * 100000);
var margin = {
top: 5,
right: 15,
bottom: 50,
left: 20
};
self.width = this.htmlElement.parentElement.parentElement.offsetWidth - margin.right - margin.left;
self.height = window.innerHeight / 3 ;
self.curAngle = 0;
self.svgParent.html("<h4 style='color:green;'>Sponsors </h4><br>");
// Update data for the chart
self.updateChartData = function () {
if(!self.svg) {
this.svg = this.svgParent
.classed("svg-container", true)
.append("svg")
.attr("preserveAspectRatio", "xMinYMin meet")
.attr("viewBox", "0 0 " + this.width + " " + this.height)
.append("g")
.classed("svg-content-responsive", true);
//.attr("transform", "translate(" + this.width / 2 + "," + this.height / 2 + ")");
}
var svgg = this.svg
.append("g")
.classed("svg-content-responsive", true)
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
self.svg.selectAll(".arctext").remove();
self.svg.selectAll(".pie-widget-total-label").remove();
var pie = d3.pie().sort(sort)(self.selectedData.map(function (d: any) {
return d.count;
}));
var path = d3.arc()
.outerRadius(radius)
.innerRadius(radius / 2);
var outsideLabel = d3.arc()
.outerRadius(radius * 0.9)
.innerRadius(radius * 0.9);
var middleLabel = d3.arc()
.outerRadius(radius * 0.75)
.innerRadius(radius * 0.75);
var insideLabel = d3.arc()
.outerRadius(radius * 0.6)
.innerRadius(radius * 0.6);
var g = self.svg
.attr("width", self.width + margin.left + margin.right)
.attr("height", self.height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + self.width / 2 + "," + self.height / 2 + ")");
var defs = g.append("defs");
var lightGradients = defs.selectAll(".arc")
.data(pie)
.enter()
.append("radialGradient")
.attr("id", function (d: any) {
return "lightGradient-" + instanceId + "-" + d.index;
})
.attr("gradientUnits", "userSpaceOnUse")
.attr("cx", "0")
.attr("cy", "0")
.attr("r", "120%");
var darkGradients = defs.selectAll(".arc")
.data(pie)
.enter()
.append("radialGradient")
.attr("id", function (d: any) {
return "darkGradient-" + instanceId + "-" + d.index;
})
.attr("gradientUnits", "userSpaceOnUse")
.attr("cx", "0")
.attr("cy", "0")
.attr("r", "120%");
lightGradients.append("stop")
.attr("offset", "0%")
.attr("style", function (d: any) {
return "stop-color: " + d3.color(color(d.index)) + ";";
});
lightGradients.append("stop")
.attr("offset", "100%")
.attr("style", function (d: any) {
return "stop-color: black;";
});
darkGradients.append("stop")
.attr("offset", "0%")
.attr("style", function (d: any) {
return "stop-color: " + d3.color(color(d.index)).darker(0.5) + ";";
});
darkGradients.append("stop")
.attr("offset", "100%")
.attr("style", function (d: any) {
return "stop-color: black;";
});
self.tooltip = d3.select("body")
.append("div")
.attr("class", "pie-widget-tooltip")
.style("opacity", 0);
self.arc = g.selectAll(".arc")
.data(pie)
.enter()
.append("g")
.attr("class", "arc");
var arcpath = self.arc.append("path")
.attr("id", function (d: any) {
return d.index;
})
.attr("d", path)
.attr("stroke", "white")
.attr("stroke-width", "2px")
.attr("fill", function (d: any) {
return "url(#lightGradient-" + instanceId + "-" + d.index + ")";
})
.on("click", function (d: any) {
console.log("About to send::::" + getStudyLabel(d.index));
self.selectedIndustryTypeService.sendMessage(getStudyLabel(d.index));
self.showDialog();
self.rotateChart();
})
.transition()
.duration(function(d:any, i:any) {
return i * 800;
})
.attrTween('d', function(d:any) {
var i = d3.interpolate(d.startAngle + 0.1, d.endAngle);
return function (t: any) {
d.endAngle = i(t);
return path(d);
}
});
function arcTween(a: any) {
var i = d3.interpolate(this._current, a);
this._current = i(0);
return function(t: any) {
return path(i(t));
};
}
var gtext = self.svg
.append("g")
.attr("transform", "translate(" + self.width / 2 + "," + self.height / 2 + ")");
var arctext = gtext.selectAll(".arctext")
.data(pie)
.enter()
.append("g")
.attr("class", "arctext");
var primaryLabelText = arctext.append("text")
.on("click", function (d: any) {
console.log("About to send::::" + getStudyLabel(d.index));
self.selectedIndustryTypeService.sendMessage(getStudyLabel(d.index));
self.showDialog();
})
.transition()
.duration(750)
.attr("transform", function (d: any) {
return "translate(" + middleLabel.centroid(d) + ")";
})
.attr("dy", "-0.75em")
.attr("font-family", "sans-serif")
.attr("font-size", "15px")
.attr("class", "sponsor-pie-widget-label")
.text(function (d: any) {
if (d.endAngle - d.startAngle < 0.3) {
return "";
} else {
return getStudyLabel(d.index);
}
});
var secondaryLabelText = arctext.append("text")
.on("click", function (d: any) {
console.log("About to send::::" + getStudyLabel(d.index));
self.selectedIndustryTypeService.sendMessage(getStudyLabel(d.index));
self.showDialog();
})
.transition()
.duration(750)
.attr("transform", function (d: any) {
return "translate(" + middleLabel.centroid(d) + ")";
})
.attr("dy", "0.75em")
.attr("font-family", "sans-serif")
.attr("font-size", "10px")
.attr("class", "sponsor-pie-widget-label")
.text(function (d: any) {
if (d.endAngle - d.startAngle < 0.3) {
return "";
} else {
return getPatientsLabel(d.index);
}
});
var n = 0;
for (var i = 0; i < self.selectedData.length; i++) {
n = n + this.selectedData[i]["count"];
}
var total = self.svg
.append("g")
.attr("transform", "translate(" + (self.width / 2 - 20 ) + "," + self.height / 2 + ")")
total.append("text")
.attr("class", "pie-widget-total-label")
.text("Total\r\n" + n);
}.bind(self);
self.showDialog = function() {
this.router.navigateByUrl('/myRouteName');
}.bind(self);
self.rotateChart = function() {
self.arc.attr("transform", "rotate(-45)");
}.bind(self);
You could rotate the arcs by changing their start/end angles as appropriate, but this would be more complex than needed.
A simpler solution would be to just rotate a g that holds the entire pie chart, at the same time, rotate any labels the other way so they remain level.
I've just used the canonical pie chart from this block as an example:
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height"),
radius = Math.min(width, height) / 2,
g = svg.append("g").attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var color = d3.scaleOrdinal(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);
var data = [ {age:"<5", population: 2704659},{age:"5-13", population: 4499890},{age:"14-17", population: 2159981},{age:"18-24", population: 3853788},{age:"25-44", population: 14106543},{age:"45-64", population: 8819342},{age:"≥65", population: 612463} ]
var pie = d3.pie()
.sort(null)
.value(function(d) { return d.population; });
var path = d3.arc()
.outerRadius(radius - 10)
.innerRadius(0);
var label = d3.arc()
.outerRadius(radius - 40)
.innerRadius(radius - 40);
var arc = g.selectAll(".arc")
.data(pie(data))
.enter().append("g")
.attr("class", "arc");
arc.append("path")
.attr("d", path)
.attr("fill", function(d) { return color(d.data.age); })
.on("click",function(d) {
// The amount we need to rotate:
var rotate = 180-(d.startAngle + d.endAngle)/2 / Math.PI * 180;
// Transition the pie chart
g.transition()
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ") rotate(" + rotate + ")")
.duration(1000);
// Τransition the labels:
text.transition()
.attr("transform", function(dd) {
return "translate(" + label.centroid(dd) + ") rotate(" + (-rotate) + ")"; })
.duration(1000);
});
var text = arc.append("text")
.attr("transform", function(d) { return "translate(" + label.centroid(d) + ")"; })
.attr("dy", "0.35em")
.text(function(d) { return d.data.age; });
.arc text {
font: 10px sans-serif;
text-anchor: middle;
}
.arc path {
stroke: #fff;
}
<svg width="960" height="500"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>

Legend not generating

I'm trying to build a legend to a calendar view graph using d3 js like this one
but i'm trying to build a legend to it like the kind of shown in the pic
but i'm not able to generate this
here's my code to generated calender view map
var Comparison_Type_Max = d3.max(inputData, function(d) { return d.value; });
var data = d3.nest()
.key(function(d) { return d.Date; })
.rollup(function(d) { return (d[0].value ); })
.map(inputData);
var margin = { top: 20, right: 50, bottom: 10, left: 60 },
width = $(dom_element_to_append_to).parent().width() - margin.left - margin.right,
cellSize = Math.floor(width/52),
height = cellSize * 7 + margin.top + margin.bottom ,
week_days = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'],
month = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
$rootScope.defaultWidth = width;
$rootScope.cellSize = cellSize;
var day = d3.time.format("%w"),
week = d3.time.format("%U"),
percent = d3.format(".1%"),
format = d3.time.format("%Y%m%d"),
legendElementWidth = cellSize * 2,
buckets = 9,
parseDate = d3.time.format("%Y%m%d").parse;
var color = d3.scale.linear().range(colorRange)
.domain([0, 1]);
var colorScale = d3.scale.quantile()
.domain([0, buckets - 1, d3.max(data, function (d) { return d.value; })])
.range(colorRange);
var svg = d3.select(dom_element_to_append_to).selectAll("svg")
.data(d3.range(year, year+1))
.enter().append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.attr("data-height", '0.5678')
.attr("class", "RdYlGn")
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
//.attr("transform", "translate(" + ((width - cellSize * 53) / 2) + "," + (height - cellSize * 7 - 1) + ")");
console.log("1");
svg.append("text")
.attr("transform", "translate(-38," + cellSize * 3.5 + ")rotate(-90)")
.style("text-anchor", "middle")
.text(function(d) { return d; });
for (var i=0; i<7; i++)
{
svg.append("text")
.attr("transform", "translate(-5," + cellSize*(i+1) + ")")
.style("text-anchor", "end")
.attr("dy", "-.25em")
.text(function(d) { return week_days[i]; });
}
var rect = svg.selectAll(".day")
.data(function(d) { return d3.time.days(new Date(d, 0, 1), new Date(d + 1, 0, 1)); })
.enter()
.append("rect")
.attr("class", "day")
.attr("width", cellSize)
.attr("height", cellSize)
.attr("x", function(d) { return week(d) * cellSize; })
.attr("y", function(d) { return day(d) * cellSize; })
.attr("fill",'#fff')
.datum(format);
console.log("2");
/* var legend = svg.selectAll(".legend")
.data(data)
.enter().append("g")
.attr("class", "legend");
//.attr("transform", function(d, i) { return "translate(" + (((i+1) * cellSize*4.33)) + ",0)"; });
legend.append("rect")
.attr("x", function(d, i) { return legendElementWidth * i; })
.attr("y", height)
.attr("width", legendElementWidth)
.attr("height", cellSize / 2)
.style("fill", function(d, i) { return color(Math.sqrt(data[d] / Comparison_Type_Max )); });
legend.append("text")
.attr("class", "mono")
.text(function(d) { return "≥ " + Math.round(d); })
.attr("x", function(d, i) { return legendElementWidth * i; })
.attr("y", height + cellSize);
*/
var legend = svg.selectAll(".legend")
.data([0].concat(colorScale.quantiles()), function(d) { return d; });
legend.enter().append("g")
.attr("class", "legend");
legend.append("rect")
.attr("x", function(d, i) { return legendElementWidth * i; })
.attr("y", height)
.attr("width", legendElementWidth)
.attr("height", cellSize / 2)
.style("fill", function(d, i) { return color(Math.sqrt(data[i] / Comparison_Type_Max )); });
legend.append("text")
.attr("class", "mono")
.text(function(d) { return "≥ " + Math.round(d); })
.attr("x", function(d, i) { return legendElementWidth * i; })
.attr("y", height + cellSize);
legend.exit().remove();
svg.selectAll(".month")
.data(function(d) { return d3.time.months(new Date(d, 0, 1), new Date(d + 1, 0, 1)); })
.enter().append("path")
.attr("class", "month")
.attr("id", function(d,i){ return month[i] + "" + varID })
.attr("d", monthPath);
console.log("4");
var tip = d3.tip()
.attr('class', 'd3-tip')
.offset([-10, 0])
.html(function(d) {
var year = d/10000;
year = Math.floor(year);
var month = d/100;
month = Math.floor(month % 100);
var day = d % 100;
if(day<10) day = "0" + day;
if(month < 10) month = "0" + month;
if(isCurrency)
return "<div><span>Date:</span> <span style='color:white'>" + day + "/" + month + "/" + year + "</span></div>" +
"<div><span>Value:</span> <span style='color:white'><span>&#8377</span>" + d3.format(",")(data[d]) + "</span></div>";
else
return "<div><span>Date:</span> <span style='color:white'>" + day + "/" + month + "/" + year + "</span></div>" +
"<div><span>Value:</span> <span style='color:white'>" + d3.format(",")(data[d]) + "</span></div>";
});
console.log("5");
svg.call(tip);
console.log("6");
rect.filter(function(d) { return d in data; })
.on("click", function(d){
console.log(d);
var year = d/10000;
year = Math.floor(year);
var monthInt = d/100;
console.log(dom_element_to_append_to);
var val,id;
if(dom_element_to_append_to=='.sms-yearheatmap-container-negative')
val = 0;
else if (dom_element_to_append_to=='.sms-yearheatmap-container-positive')
val = 1;
else val = 2;
monthInt = Math.floor(monthInt % 100);
for (var itr = 0; itr<12; ++itr) {
id = month[itr] + "" + varID;
$('#' + id).css("z-index",0);
$('#' + id).css("stroke","#000");
$('#' + id).css("stroke-width", "2.5px");
}
id = month[monthInt-1] + "" + varID;
$('#' + id).css("stroke","blue");
$('#' + id).css("position","relative");
$('#' + id).css("z-index",1000);
$('#' + id).css("stroke-width", "4.5px");
console.log("year " + year + " month" + monthInt);
$rootScope.loadDayHourHeatGraph(year, monthInt , val, isCurrency);
})
.attr("fill", function(d) { return color(Math.sqrt(data[d] / Comparison_Type_Max )); })
.on('mouseover', tip.show)
.on('mouseout', tip.hide);
/*.attr("data-title", function(d) { return "value : "+Math.round(data[d])});
$("rect").tooltip({container: 'body', html: true, placement:'top'}); */
/* $("rect").on("click", function(d) {
console.log(d);
});*/
function numberWithCommas(x) {
x = x.toString();
var pattern = /(-?\d+)(\d{3})/;
while (pattern.test(x))
x = x.replace(pattern, "$1,$2");
return x;
it is generting the graph correctly but my legend is not generating with it
here's the code of legend which i wrote above
var legend = svg.selectAll(".legend")
.data([0].concat(colorScale.quantiles()), function(d) { return d; });
legend.enter().append("g")
.attr("class", "legend");
legend.append("rect")
.attr("x", function(d, i) { return legendElementWidth * i; })
.attr("y", height)
.attr("width", legendElementWidth)
.attr("height", cellSize / 2)
.style("fill", function(d, i) { return color(Math.sqrt(data[i] / Comparison_Type_Max )); });
legend.append("text")
.attr("class", "mono")
.text(function(d) { return "≥ " + Math.round(d); })
.attr("x", function(d, i) { return legendElementWidth * i; })
.attr("y", height + cellSize);
legend.exit().remove();
i don't want to use the colorscale variable instead i want to generate the legend according to the color variable defined in the main code, the colorscale variable is not used anywhere in the code but only in the legend just for a start, the whole calender view graph is generated using the the colorscheme provided by the color variable

Changing position of label base D3

Right, so I have this graph that works great. It has tooltips, labels, and a total value in the center:
However, when I hover over one of the arcs to activate the tooltips, the little dot that has the pointer coming out of it stays put, as seen here:
This is my mouse movement code
path.on('mouseenter', function(d){
d3.select(this)
.transition()
.duration(500)
.attr("d", arcOver);
});
path.on('mouseleave', function(d){
d3.select(this).transition()
.duration(500)
.attr("d", arc);
});
path.on('mouseover', function(d) {
var percent = Math.round(1000 * d.data.value / sum) / 10;
tooltip.style('opacity', 0);
tooltip.select('.label').html(d.data.label);
tooltip.select('.value').html(d3.format("$,.2f")(d.data.value));
tooltip.select('.percent').html(percent + '%');
tooltip.style('display', 'block');
tooltip.transition()
.duration(600)
.style("opacity",1);
});
path.on('mouseout', function() {
tooltip.transition()
.duration(600)
.style("opacity",0)
.style('pointer-events', 'none')
});
Here's the code that creates the labels:
svg.selectAll("text").data(pieData)
.enter()
.append("text")
.attr("class", "stickLabels")
.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 - 37.5);
return d.x = Math.cos(a) * (radius + 40);
})
.attr("y", function(d) {
var a = d.startAngle + (d.endAngle - d.startAngle)/2 - Math.PI/2;
d.cy = Math.sin(a) * (radius - 37.5);
return d.y = Math.sin(a) * (radius + 40);
})
.text(function(d) { return d3.format("s")(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;
}
});
And here's a fiddle of the whole code: http://jsfiddle.net/18L6u5xf/
My question is this: How do I move the dot with the arc.
PS I know what I need to change it to, I just don't know how to do it with a mouseover. This is what it needs to end up being:
d.cx = Math.cos(a) * (radius - 17.5);
PPS It looks better with my styling than in the fiddle, just bear with me.
A slightly cleaner way of doing this is to wrap the arc, path and text in g and then just transition that on mouseenter and mouseout. This way you aren't repeating the same data binding and calculations 3 separate times:
// create a group
var gs = svg.selectAll('.slice')
.data(pieData)
.enter()
.append('g')
.attr('class', 'slice');
// add arcs to it
gs.append('path')
.attr('d', arc)
.attr('id', function(d){return d.data.id;})
.attr('class', 'arcPath')
.attr('fill', function(d, i) {
return color(d.data.label);
});
// add text to it
gs.append("text")
.attr("class", "stickLabels")
.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 - 37.5);
return d.x = Math.cos(a) * (radius + 40);
})
.attr("y", function(d) {
var a = d.startAngle + (d.endAngle - d.startAngle)/2 - Math.PI/2;
d.cy = Math.sin(a) * (radius - 37.5);
return d.y = Math.sin(a) * (radius + 40);
})
.text(function(d) { return d3.format("s")(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;
});
// add connection paths
gs.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;
}
});
// mouseenter of group
gs.on('mouseenter', function(d){
d3.select(this)
.transition()
.duration(500)
.attr("transform",function(d){
var a = d.startAngle + (d.endAngle - d.startAngle)/2 - Math.PI/2;
var x = Math.cos(a) * 20;
var y = Math.sin(a) * 20;
return 'translate(' + x + ',' + y + ')';
});
});
// on mouse leave
gs.on('mouseleave', function(d){
d3.select(this)
.transition()
.duration(500)
.attr("transform",function(d){
return 'translate(0,0)';
});
});
Example here.

How to transform and rotate the rectangles on partition layout in d3.js

I want to place rectangles inside partition layout with transform of arc position.
just like below image
JSfiddle
D3.js:
svg.selectAll("rect")
.data(node)
.enter()
.append("rect")
.attr("x", function (d) {return d.x;})
.attr("y", function (d) { return d.x + d.dx - 0.01 / (d.depth + 2.6); })
.attr("width", 20)
.attr("height", 100)
.attr("transform", function(d) { return "translate("+arc.centroid(d)+")rotate(" + ((2*Math.PI)+2.6*(d.x + d.dx))+ ")"});
In rect transform ,rotate need to rotate(" + ((d.x + (d.dx / 2)) - Math.PI ) / Math.PI * 180 + ")" instead of rotate(" + ((d.x + (d.dx / 2)) - Math.PI/2 ) / Math.PI * 180 + ")"
FIDDLE
svg.selectAll("rect")
.data(node)
.enter()
.append("rect")
.attr("x", function (d) {return d.x;})
.attr("y", function (d) { return d.x + d.dx - 0.01 / (d.depth + 2.6); })
.attr("width", 20)
.attr("height", 100)
.attr("transform", function(d) { return "translate("+arc.centroid(d)+")rotate(" + ((d.x + (d.dx / 2)) - Math.PI ) / Math.PI * 180 + ")"});

Categories