Have below piece of code for drawing progress-bar,but not able to append text like below image, beginnig of rectangle "E" end of rectangle "F" and top/bottom of rectangle as shown in the image, how we
can append text beginning of rectangle by giving negative value for x but d3 does not consume negative values for this.
var self = this;
var progressWidth = this.getInteger("progressWidth");
var progressFill = this.getString("progressFill");
var progressBarWidth = this.getInteger("progressBarWidth");
var progressBarHeight = this.getInteger("progressBarHeight");
var isRoundCorners = this.getBoolean("isRoundCorners");
var backgroundFill = this.getString("backgroundFill");
var roundedCorners = 0;
var progressWidthValue = 0;
if(!progressBarWidth) {
progressBarWidth = 250;
}
if(!progressBarHeight) {
progressBarHeight = 15
}
if(progressWidth) {
progressWidthValue = (progressBarWidth * progressWidth)/100;
}
if(!progressFill) {
progressFill = 'blue';
}
if(isRoundCorners) {
roundedCorners = 10;
} else {
roundedCorners = 0;
}
if(!backgroundFill) {
backgroundFill = '#D8D8D8';
}
var svg = args.svg;
svg = svg
.append('svg');
// .attr('height', 100)
// .attr('width', 500);
svg.append('rect')
.attr('class', 'bg-rect')
.attr('rx', roundedCorners)
.attr('ry', roundedCorners)
.attr('fill', backgroundFill)
.attr('height', progressBarHeight)
.attr('width', progressBarWidth)
.attr('x', 0);
var progress = svg.append('rect')
.attr('class', 'progress-rect')
.attr('fill', progressFill)
.attr('height', progressBarHeight)
.attr('width', 0)
.attr('rx', roundedCorners)
.attr('ry', roundedCorners)
.attr('x', 0);
progress.transition()
.duration(1000)
.attr('width',progressWidthValue);
[![enter image description here][1]][1]
[1]: https://i.stack.imgur.com/c4Sm3.png
You can append text to the svg with x and y values like that :
svg.append('rect')
.attr('class', 'bg-rect')
.attr('rx', 5)
.attr('ry', 5)
.attr('fill', 'blue')
.attr('height', 10)
.attr('width', rectWidth)
.attr('x', xRect)
.attr('y', 20);
svg.append('text')
.attr('color', 'red')
.attr('x', 5)
.attr('y', 30)
.text('A')
svg.append('text')
.attr('color', 'red')
.attr('x', rectWidth + xRect)
.attr('y', 30)
.text('B')
see http://jsfiddle.net/k76yx4am/
Related
After having created several rectangles each with a different id, I would like to get their x attribute. From several questions on SO, I found that I should do this:
d3.select('rect name1').attr('x')`
But it returns:
Uncaught TypeError: Cannot read property 'getAttribute' of null`,
Even though d3.select('rect name1') doesn't give a error and returns st {_groups: Array(1), _parents: Array(1)}
var dataRectangle = [];
for (var i=0; i < 10 ; i++) {
dataRectangle.push(i);
}
var svg = d3.select('body').append('svg')
.attr('width', 1024)
.attr('height', 500);
var baseCircle = svg.selectAll('rect');
baseCircle = baseCircle.data(dataRectangle).enter().append('g');
baseCircle.append('rect')
.attr('width', 10)
.attr('height', 10)
.attr('x', 20)
.attr('y', 20)
.attr('fill', "none")
.attr("stroke-width", 4)
.style('stroke', "green")
.attr("id", function(d, i) { return 'name'+i; });
First of all, you have to use # for IDs:
d3.select('rect #name1').attr('x')
But this is not the only problem. Besides that, there is a wrong space here:
d3.select('rect #name1').attr('x')
//space here---^
Because of that, you're selecting all the elements with that given ID that are children of the <rect>. Have a look here: https://developer.mozilla.org/en-US/docs/Learn/CSS/Introduction_to_CSS/Combinators_and_multiple_selectors
Obviously, there is none. You said that...
d3.select('rect name1') doesn't give a error and returns st {_groups: Array(1), _parents: Array(1)}
... but, if you look at that selection, you'll see that it is an empty selection. Let's prove it:
var dataRectangle = [];
for (var i = 0; i < 10; i++) {
dataRectangle.push(i);
}
var svg = d3.select('body').append('svg')
.attr('width', 300)
.attr('height', 200);
var baseCircle = svg.selectAll('rect');
baseCircle = baseCircle.data(dataRectangle).enter().append('g');
baseCircle.append('rect')
.attr('width', 10)
.attr('height', 10)
.attr('x', 20)
.attr('y', 20)
.attr('fill', "none")
.attr("stroke-width", 4)
.style('stroke', "green")
.attr("id", function(d, i) {
return 'name' + i;
});
console.log("The size of the selection is: " + d3.select('rect name1').size())
<script src="https://d3js.org/d3.v4.min.js"></script>
And that explains why you cannot read property 'getAttribute' of null.
Solution
It should be:
d3.select('rect#name1').attr('x')
Or, since IDs are unique, simply:
d3.select('#name1').attr('x')
Here is your code with that change:
var dataRectangle = [];
for (var i = 0; i < 10; i++) {
dataRectangle.push(i);
}
var svg = d3.select('body').append('svg')
.attr('width', 300)
.attr('height', 200);
var baseCircle = svg.selectAll('rect');
baseCircle = baseCircle.data(dataRectangle).enter().append('g');
baseCircle.append('rect')
.attr('width', 10)
.attr('height', 10)
.attr('x', 20)
.attr('y', 20)
.attr('fill', "none")
.attr("stroke-width", 4)
.style('stroke', "green")
.attr("id", function(d, i) {
return 'name' + i;
});
console.log(d3.select('rect#name1').attr("x"))
<script src="https://d3js.org/d3.v4.min.js"></script>
This error also shows up if you don't have a tag in your html file. for example. you are calling d3.select("svg") but there is no svg element defined in the html file.
I need to make my doughnut chart a horizontal graph like in this image >
this is the code that i use for other doughnut charts
var dataset = {
hddrives: [total - value, value],
};
var width = 460,
height = 300,
radius = Math.min(width, height) / 2;
var color = d3.scale.ordinal()
.range([secondColor, mainColor]);
var pie = d3.layout.pie()
.sort(null);
var arc = d3.svg.arc()
.innerRadius(radius - 100)
.outerRadius(radius - 70);
var svg = d3.select(divName).append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
//Draw the Circle
svg.append("circle")
.attr("cx", 0)
.attr("cy", 0)
.attr("r", 65)
.attr("fill", "#F6FBF3");
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", "0em")
.style("text-anchor", "middle")
.attr("class", "inside")
.attr("font-size", "30px")
.text(function (d) { return value; });
svg.append("text")
.attr("dy", "1.5em")
.style("text-anchor", "middle")
.attr("class", "data")
.text(function (d) { return nomeGtin; });
}
I tried messing around with the attr values and the arc value, but without success, any ideas on how to approach this? Thanks
That isn't much of a donut chart, it's now a stacked bar chart (with a single bar). The pie and arc helpers aren't much help for that, they are concerned with calculating angles and circular things; you are now dealing with rectangles. d3.stack could help, but is probably overkill. Here's a quicky where I've just done the math (ie positioning) myself:
<!DOCTYPE html>
<html>
<head>
<script data-require="d3#3.5.17" data-semver="3.5.17" src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.js"></script>
</head>
<body>
<script>
var width = 500,
height = 200,
w = 300,
h = 100;
var svg = d3.select('body')
.append('svg')
.attr('width', width)
.attr('height', height);
var total = 0,
l = 0,
// fake random data
raw = d3.range(5).map(function(d){
var v = Math.random() * 10;
total += v;
return v;
}),
// calculate percents and cumulative position
data = raw.map(function(d){
var rv = {
v: d,
l: l,
p: d/total
}
l += rv.p;
return rv;
});
// scale and color
var s = d3.scale.linear()
.range([0, w])
.domain([0, 1]),
c = d3.scale.category20();
svg.selectAll('rect')
.data(data)
.enter()
.append('rect')
.attr('x', function(d){
return s(d.l) + width/2 - w/2; // place based on cumulative
})
.attr('width', function(d){
return s(d.p); // width from scale
})
.attr('height', h)
.attr('y', height/2 - h/2)
.style('fill', function(d,i){
return c(i);
})
.style('stroke', 'white')
.style('stroke-width', '2px');
</script>
</body>
</html>
I'm trying to plot a pie chart with a legend inside of it. And I got into troubles to get it plotted, since I get the errors abound undefined variables. I managed to draw the chart itself and the half of the legend, but not in the right colors, what should match the pie chart.
function drawPieChart(d3div, chart_data) {
// chart_data.data is a list of data elements.
// each should contain fields: val, col, name
d3div.html(""); // clear the div
var title = getopt(chart_data, 'title', '');
// desired width and height of chart
var w = getopt(chart_data, 'width', 300);
var h = getopt(chart_data, 'height', 300);
var pad = getopt(chart_data, 'pad', 50);
var textmargin = getopt(chart_data, 'textmargin', 20);
var r = Math.min(w, h) / 2 - pad; // radius of pie chart
var div = d3div.append('div');
if(title !== '') {
div.append('p').attr('class', 'pietitle').text(title);
}
var arc = d3.svg.arc()
.outerRadius(r)
.cornerRadius(20)
.innerRadius(150);
var arcLarge = d3.svg.arc()
.innerRadius(150)
.cornerRadius(20)
.outerRadius(r + 50);
var toggleArc = function(p){
p.state = !p.state;
var dest = p.state ? arcLarge : arc;
d3.select(this).select("path").transition()
.duration(160)
.attr("d", dest);};
var pie = d3.layout.pie()
.padAngle(.03)
.sort(null)
.value(function(d) { return d.val; });
var svg = d3.select("#piechart").append("svg")
.attr("width", w)
.attr("height", h)
.append("g")
.attr("transform", "translate(" + w / 2 + "," + h / 2 + ")");
var g = svg.selectAll(".arc")
.data(pie(chart_data.data))
.enter().append("g")
.attr("class", "arc")
.attr("stroke", "#999")
.attr("id",function(d){return d.data;})
.on("mouseover",toggleArc)
.on("mouseout",toggleArc);
g.append("path")
.attr("d", arc)
.style("fill", function(d) { return d.data.col; });
var color = d3.scale.category20b();
var legendRectSize = 18;
var legendSpacing = 4;
// FROM here the code is not produced the desired result
var legend = svg.selectAll('.legend')
.data(chart_data.data)
.enter()
.append('g')
.attr('class', 'legend')
.attr("id",function(d){return d.data;})
.attr('transform', function(d, i) {
var height = legendRectSize + legendSpacing;
var offset = height * chart_data.data.length / 2;
var horz = -2 * legendRectSize;
var vert = i * height - offset;
return 'translate(' + horz + ',' + vert + ')';
});
legend.append('rect')
.data(chart_data.data)
.attr('width', legendRectSize)
.attr('height', legendRectSize)
.style("fill", function(d) { return d.data.col; });
legend.append("text")
.attr('x', legendRectSize + legendSpacing)
.attr('y', legendRectSize - legendSpacing)
.text(function(d) { return d.data.name; });
}
The code actually works fine untill the line var legend = svg.selectAll('.legend')
Then i start to define the legend, but D3 complains about undefined d.data every time i try to access d.data below the line I written above(also in the last line of the code).
I don't understand where i got on the wrong way.
If instead of defining the whole non working part(var legend...) i write this code:
g.append("text")
.attr("stroke", "none")
.attr("fill", function(d) { return d.data.col; })
.text(function(d) { return d.data.name; });
I'm able to access the d.data.name.
Unfortunately wrong colors of the boxes and not description.
Thanks!
Really struggling to get the donut chart updated with new data coming from several csv files.
How can I update the chart with the new csv file? Im using setInterval() to circulate the array of files.
My code:
var updateChart = function(){}
var width = 360;
var height = 360;
var radius = Math.min(width, height) / 2;
var donutWidth = 75;
var legendRectSize = 18;
var legendSpacing = 4;
var color = d3.scale.category20b();
var svg = d3.select('#chart')
.append('svg')
.attr('width', width)
.attr('height', height)
.append('g')
.attr('transform', 'translate(' + (width / 2) +
',' + (height / 2) + ')');
var arc = d3.svg.arc()
.innerRadius(radius - donutWidth)
.outerRadius(radius);
var pie = d3.layout.pie()
.value(function(d) { return d.population; })
.sort(null);
d3.csv('data.csv', function(error, dataset) {
dataset.forEach(function(d) {
d.population = +d.population;
}); /
var path = svg.selectAll('path')
.data(pie(dataset))
.enter()
.append('path')
.attr('d', arc)
.attr('fill', function(d, i) {
return color(d.data.age);
});
var legend = svg.selectAll('.legend')
.data(color.domain())
.enter()
.append('g')
.attr('class', 'legend')
.attr('transform', function(d, i) {
var height = legendRectSize + legendSpacing;
var offset = height * color.domain().length / 2;
var horz = -2 * legendRectSize;
var vert = i * height - offset;
return 'translate(' + horz + ',' + vert + ')';
});
legend.append('rect')
.attr('width', legendRectSize)
.attr('height', legendRectSize)
.style('fill', color)
.style('stroke', color);
legend.append('text')
.attr('x', legendRectSize + legendSpacing)
.attr('y', legendRectSize - legendSpacing)
.text(function(d) { return d; });
});
THE CSV FORMAT:
age,population
Cumulative,2704659
Cumulative Prev,4499890
I am learning D3js and trying to chain some animations together.
Basically I have three svg elements that I want to simultaneously transition. There is a circle, a rectangle, and a text element.
For example, I am trying to make the circle transition from black to green, the rectangle transition from black to blue, and replace the text with a fade out, fade in effect.
I can do this one time, but I want a series of these animations to occur in sequence.
Here is the first fiddle of 1 transition working:
http://jsfiddle.net/mgcdanny/6nbRK/
Here is my attempt to sequence these using a for loop and JSON, but only the last transition happens:
http://jsfiddle.net/mgcdanny/U7StQ/
Perhaps this would be better as a series of enter(), update(), exit() commands?
Thanks for the help!
Fiddle 1 Code:
`
var svg = d3.select("body")
.append('svg')
.attr('width', 500)
.attr('height', 500)
var circle = d3.select("svg")
.append("circle")
.attr('cx', 10)
.attr('cy', 10)
.attr('r', 10)
var rect = d3.select("svg")
.append("rect")
.attr('width', 20)
.attr('height', 20)
.attr('x', 30)
.attr('y', 30)
var text = d3.select("svg")
.append("text")
.text("hello")
.attr("x",60)
.attr("y",60)
.attr('opacity',1)
var tran = svg.transition().duration(2000)
tran.select("rect").attr('fill', 'red')
tran.select("circle").attr('fill', 'blue')
tran.select("text").attr('opacity', 0)
//new transition
svg.transition()
.duration(2000)
.delay(2000)
.select("text")
.attr('opacity', 1)
.text("hello again!")
.attr("x",60)
.attr("y",60)
</script>
</body>
`
Fiddle 2 Code:
'
theData = [
{"words":"today", "rect_color": "red", "circle_color":"blue"},
{"words":"tomorrow", "rect_color": "green", "circle_color":"yellow"},
{"words":"Day After That", "rect_color": "purple", "circle_color":"brown"}]
var svg = d3.select("body")
.append('svg')
.attr('width', 500)
.attr('height', 500)
var circle = d3.select("svg")
.append("circle")
.attr('cx', 10)
.attr('cy', 10)
.attr('r', 10)
var rect = d3.select("svg")
.append("rect")
.attr('width', 20)
.attr('height', 20)
.attr('x', 30)
.attr('y', 30)
var text = d3.select("svg")
.append("text")
.text("hello")
.attr("x",60)
.attr("y",60)
.attr('opacity',1)
var tranFunc = function(object){
var tran = svg.transition().duration(2000)
tran.select("rect").attr('fill', object.rect_color)
tran.select("circle").attr('fill', object.circle_color)
tran.select("text").attr('opacity', 0)
var tran2 = tran
tran2.transition().select("text")
.attr('opacity', 1)
.text(object.words)
}
var allTran = function(list){
for(var i = 0; i < list.length; i++){
tranFunc(list[i])
}
}
allTran(theData)
</script>
'