Just started using d3.js and javascript. I have this weird chart requirement. Want to create the chart exactly like pie chart but, in square shaped. Just like below.
So, I thought, may be I create the pie chart and add the square between the pie chart and erase the part outside square. But, it is not working out yet.
Secondly, I thought, I can do this with CSS. I did this. But, I am not happy with this solution. It is too hacky. Can someone help me with good solution.
This is my jsfiddle link.
//// Done this to create the square.
var svgContainer = d3.select("#square").append("svg")
.attr("width", 200)
.attr("height", 200);
var rectangle = svgContainer.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", 200)
.attr("fill", '#ec4c4a')
.attr("height", 200);
// Done this to create the pie chart. Found this example some where.
var element_id = 'pie'
var elementSelector = '#pie';
svgWidth = 390;
svgHeight = 320;
svgInnerRadius = 0;
svgOuterRadius = 145;
heightOffset = 0;
scoreFontSize = '49px';
$(elementSelector).replaceWith('<svg id="'+ element_id +'" class="scoreBar" width="'+ svgWidth +'" height="'+ (svgHeight - heightOffset) +'"></svg>');
$(elementSelector).css({'width': svgWidth + 'px', 'height': (svgHeight-heightOffset) + 'px'});
var anglePercentage = d3.scale.linear().domain([0, 100]).range([0, 2 * Math.PI]);
var fullAnglePercentage = 100;
var color = d3.scale.ordinal().range(["#ACACAC", "#EAEAEA", "#123123", "#DDEEAA", "#BACBAC"]);
data = [[50, 90, 1],
[50, 30, 2],
[30, 10, 3],
[10, -1, 4],
[-1, -10, 5]]
var vis = d3.select(elementSelector);
var arc = d3.svg.arc()
.innerRadius(svgInnerRadius)
.outerRadius(svgOuterRadius)
.startAngle(function(d){return anglePercentage(d[0]);})
.endAngle(function(d){return anglePercentage(d[1]);});
vis.selectAll("path")
.data(data)
.enter()
.append("path")
.attr("d", arc)
.style("fill", function(d){return color(d[2]);})
.attr("transform", "translate(" + svgWidth / 2 + ", " + svgHeight / 2 + ")");
Thanks in advance.
You can achieve this using clip path. What is a clip path?
To SVG add defs of clippath
var svg1 = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
//making a clip square as per your requirement.
svg1.append("defs").append("svg:clipPath")
.attr("id", "clip")
.append("svg:rect")
.attr("id", "clip-rect")
.attr("x", -120)
.attr("y", -100)
.attr("width", radius)
.attr("height", radius);
Make your normal d3 pie chart like:
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);
});
To the main group add the clip like this:
var svg = svg1.append("g").attr("clip-path", "url(#clip)")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
Full working code here.
Related
I'm trying to display a donut chart within a tooltip. I thought it'll be simply just adding the function name or creating the chart within .html() but that isn't the case sadly. Can anyone tell me where i'm going wrong?
Here's my code:
tooltip.select('.label').html(donutChart());
function donutChart(){
var dataset = {
hddrives: [20301672448, 9408258048, 2147483648, 21474836480, 35622912,32212254720],
};
var width = 460,
height = 300,
radius = Math.min(width, height) / 2;
var color = d3.scale.ordinal()
.range(["#2DA7E2"]);
var pie = d3.layout.pie()
.sort(null);
var arc = d3.svg.arc()
.innerRadius(radius - 100)
.outerRadius(radius - 70);
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(dataset.hddrives))
.enter().append("path")
.attr("class", "arc")
.attr("fill", function(d, i) { return color(i); })
.attr("d", arc);
svg.append("text")
.attr("dy", ".35em")
.style("text-anchor", "middle")
.attr("class", "inside")
.text(function(d) { return 'Test'; });
}
Your function donutChart appends the <svg> to the body, not inside the tooltip.
A solution can be writing this in your .html():
.html("<h1>My Donut Chart</h1><br><svg class='myDonut'></svg>")
And then call your donutChart after that line, remembering to change your var svg:
var svg = d3.select(".myDonut")
Take care for not repeating the same variable names, even if they are inside a function (separate scope)... it can cause unnecessary confusion.
I'm trying to draw a circle with different data values as angles but for some reason, it's only the last data point that gets the color and display. I've tried to translate the svg but it seems not to budge.
I'm fairly new to D3 so I'm sure I've done something less intelligent without realizing it. As far I could tell, the angles in the g and path elements are as supposed to.
var height = 400, width = 600, radius = Math.min(height, width) / 2;
var colors = ["#red", "pink", "green", "yellow", "blue","magent","brown","olive","orange"];
var data = [1,2,1,2,1,2,1,3,1];
var chart = d3.select("#chart").append("svg")
.attr("width", width).attr("height", height);
chart.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var pie = d3.layout.pie().sort(null).value(function (d) { return d; });
var arc = d3.svg.arc().startAngle(0).innerRadius(0).outerRadius(radius);
var grx = chart.selectAll(".sector").data(pie(data))
.enter().append("g").attr("class", "sector");
grx.append("path")
.attr("d", arc)
.style("fill", function (d, i) {
console.log(d);
return colors[i];
});
The problem is that you're appending all the sectors of the pie to the svg node when they should be appended to the translated g node, you have two options to solve this problem
make chart equal to the translated g node
select g before all the .sectors and store that in grx
The first solution is simpler e.g.
var chart = d3.select("#chart").append("svg")
.attr("width", width).attr("height", height);
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
demo
Does anyone know of a JavaScript charting library that is capable of drawing a a gauge like this:
I've already looked at Highcharts, Kendo UI and FusionCharts, but I couldn't find any samples with a non-constant width of the arc...but that could also be because I don't even know what to search for exactly.
I found this post which seems to go in the right direction, but I'd rather not have to draw SVG myself if there's an out of the box solution.
In case anyone else ever needs something like that, I ended up building it myself using D3. Full animated sample is available at http://jsfiddle.net/0288wscf/11/
var domain = [1, 100];
var angleScale = d3.scale.linear().domain(domain).range([minAngle, maxAngle]);
var radiusScale = d3.scale.linear().domain(domain).range([radius - minWidth, radius - maxWidth]);
var colorScale = d3.scale.linear().domain(domain).range([minColor, maxColor]);
var svg = d3.select("body").append("svg")
.attr("width", 2 * radius)
.attr("height", 2 * radius);
var gauge = svg.append("g")
.attr("transform", "translate(" + radius + "," + radius + ")")
var arc = d3.svg.arc()
.innerRadius(radiusScale)
.outerRadius(radius)
.startAngle(angleScale)
.endAngle(angleScale);
function update(n) {
var ticks = gauge.selectAll(".tick").data(d3.range(1, n), function(d) { return d; });
ticks.enter()
.append("path")
.attr("class", "tick")
.attr("stroke", colorScale)
.attr("d", arc)
.attr("stroke-width", tickThickness)
.attr("opacity", 0)
.transition()
.delay(enterDuration)
.attr("opacity", 1);
ticks.exit()
.transition()
.delay(exitDuration)
.remove();
}
I need a heatmap matrix like this,
Now I tried using D3.js, I am able to make matrix and also made it zoomable too, but now I am stuck at adding Notes to rectangles as SVG doesn't supports it.
Am I on right track or can I use Div and jQuery instead to develop this heatmap, I visited hundreds of plugins but non satisfies my needs.
Proper matrix - http://jsfiddle.net/nhe613kt/49/
Trying adding Notes with one rectangle - http://jsfiddle.net/nhe613kt/60
Can I use any other plugin or simple HTML ?
var width = 600,
height = 600;
var margin = {top: -5, right: -5, bottom: -5, left: -5};
var zoom = d3.behavior.zoom()
.scaleExtent([1, 15])
.on("zoom", zoomed);
var svgContainer = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.style("background-color", "black")
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.right + ")")
.call(zoom);
var zoomed = function () {
svgContainer.attr("transform", "translate("+ d3.event.translate + ")scale(" + d3.event.scale + ")");
};
var zoom = d3.behavior.zoom()
.scaleExtent([1, 8])
.on("zoom", zoomed)
.size([width, height]);
svgContainer.call(zoom);
var rectangle1 = svgContainer.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", 100)
.attr("height", 100)
.attr("fill", "red")
.append("text")
.text("Hahaha");
You need to configure the text node properly:
svgContainer.append("text")
.attr("x", 10)
.attr("y", 20)
.attr("fill", "blue")
.text("Hahaha");
Otherwise, it might be outside of the visible are (y=0 is a common mistake; the Y coordinate moves the baseline of the text, not the top-right corner). Also without a color, the text will inherit one from the parent.
Demo: http://jsfiddle.net/nhe613kt/65/
http://tributary.io/inlet/10932495
I can't seem to figure out why my text labels are not showing up on my chart. Help or suggestions? Link above shows my pie chart and my code as well as my csv data.
var arvadaData = tributary.arvadaPayments
var sumPayments = d3.sum(arvadaData, function(d) {return +d.payments;});
var svg = d3.select("svg");
var width = 527,
height = 562,
radius = Math.min(width, height) / 2;
var outerRadius = width/2;
var colorScale = d3.scale.category20(); //built in range of 20 colors
var arc = d3.svg.arc() //creates <path> elements using arc data
.outerRadius(width / 2)
.innerRadius(100);
var pie = d3.layout.pie()
.sort(null)
.value(function(d){ return +d.payments });
var g = svg.selectAll("g.arc")
.data(pie(arvadaData))
.enter()
.append("g")
.attr("class", "arc")
.attr("transform", "translate(" + width/2 + "," + height/2 + ")");
g.append("path")
.attr("fill", function(d, i){return colorScale(i);})
.attr("d", arc);
g.append("text")
.attr("transform", function(d){ return "translate(" + arc.centroid(d) +")"; })
.attr("text-anchor", "middle")
.text(function(d){ return d[i].specialty; });
The text elements are added and positioned correctly, but their content isn't set correctly. You're passing in the data coming from the pie layout -- the original data is available under the .data member in this case. That is, the expression to set the text should be
.text(function(d){ return d.data.specialty; });
Complete demo here.