I want to reorder table's data and animate the table's row exchange smoothly.
Code can be found at http://jsfiddle.net/HCLe5/1/
var table = d3.select("body").select("table#d3table");
var tHead = table.append("thead");
tHead.append("tr");
tHead.selectAll("th").data(thead).enter().append("th").text(function(d) {return d.id});
var tBody = table.append("tbody");
var tr = tBody.selectAll("tr").data(tbody).enter().append("tr");
tr.selectAll("td")
.data(function(d){return d.row})
.enter()
.append("td")
.text(function(d){return d.value + d.id})
// Some magick row position manipulation
Related
I want to insert a ta
console.clear()
var parsed = d3.csvParse(get_csv_text())
var g = d3.select('body')
.append('svg')
.append('g')
csv_table(g,parsed)
function csv_table(g,parsed) {
var caption = "demo table"
var xoff = 50
var yoff = 50
var width = 400
var height = 800
var headers = [Object.keys(parsed[0])]
var table = g.append("foreignObject")
.attr("width", width)
.attr("height", height)
.attr('x',xoff)
.attr('y',yoff)
.append("xhtml:table")
.style('font-weight','bold')
var thead = table.append("thead")
var tbody = table.append("tbody")
var tfoot = table.append("tfoot")
thead.selectAll("tr")
.data(headers).enter()
.append("tr")
.selectAll("th")
.data(d => d).enter()
.append("th")
.text(d => d)
.style('border-bottom','1px solid black')
tbody.selectAll("tr")
.data(parsed).enter()
.append("tr")
.selectAll("td")
.data(d => {
var elem = Object.entries(d).map(d => d[1])
return elem
}).enter()
.append("td")
.text(d => d)
thead.selectAll('tr')
.style('color','black')
.style('text-align','left')
g.selectAll('table')
.style('border-top','2px solid black')
.style('border-bottom','1.5px solid black')
tbody.selectAll('tr')
.style('text-align','left')
tbody.selectAll('tr:nth-child(even)')
.style('background-color','#eee')
table.append("caption")
.text(caption)
}
function get_csv_text() {
var data =`name,x,y
aaaaaaaaaaaa,8712.0,10631.0
b,9951.0,11806.0
c,12698.0,14797.0
d,13246.0,15391.0
e,14959.0,17237.0
f,15445.0,17842.0
g,26727.0,30004.0
h,8712.0,10631.0
i,9951.0,11806.0
j,12698.0,14797.0
k,13246.0,15391.0
l,14959.0,17237.0
m,15445.0,17842.0
n,26727.0,30004.0
`
return data
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.0.0/d3.min.js"></script>
How to make the element always fit the table?
The svg element is too small. You can move the height and width attributes up, and then use .attr("width", width).attr("height", height) after the .append('svg').
I am testing d3.js in meteor.
While trying to make a simple table for test,I met a trouble.
Here is my codes
<template name="ob">
<h4>Table test- {{name}}</h4>
<svg id="obTable"><table><tr></tr></table></svg>
</template>
And below is javascript file for template above...
Template.ob.onRendered(function() {
//Width and height
var w = 600;
var h = 350;
//Define key function, to be used when binding data
var key = function (d) {
return d.index;
};
//Create SVG element
var svg = d3.select("#obTable")
.attr("width", w)
.attr("height", h);
var dataset = require('../data/ob.json');
// var dataset = Bars.find({}).fetch();
//Select…
var table = svg.selectAll('table').append('table')
.style("border-collapse", "collapse")
.style("border", "2px black solid");
// .data(dataset, key);
console.log(table);
var rows = table.selectAll('tr')
.data(dataset, key)
.enter()
.append('tr');
console.log(rows);
rows.selectAll('td')
.data(function(d){ console.log(d); return d;} )
.enter()
.append('td')
.text(function(d) {console.log("here"); return d;})
.style("border", "1px black solid")
.style("padding", "10px")
.style("font-size","12px");
});
I've got no errors from those code above, but when I execute my app, I could not see any table or table contents. ( since I can see in contents well, I am sure there is no problem on showing template itself)
Things that I can't most understand is that I can see log messages from rows.selectAll('td').data(function(d){ console.log(d); return d;} ) well, but I can't see any log from .text(function(d) {console.log("here"); return d;})
I doubt this could be a reason for not showing table, but could not solve further.
I installed d3 from npm and it's version is 4.10.0
Any advice would be greatly appreciated.
I had this problem as well. Issue is that the dom is getting rewritten due to reactive updates, and your on render select is getting destroyed.
How I solved this was to do a template helper at the end of the template. Something like this...
<template name="ob">
<h4>Table test- {{name}}</h4>
<svg id="obTable"><table><tr></tr></table></svg>
{{doD3Stuff}}
</template>
Template.ob.helpers(function() {
doD3Stuff: function() {
// all your on render code here
//Width and height
var w = 600;
var h = 350;
//Define key function, to be used when binding data
var key = function (d) {
return d.index;
};
//Create SVG element
var svg = d3.select("#obTable")
.attr("width", w)
.attr("height", h);
var dataset = require('../data/ob.json');
// var dataset = Bars.find({}).fetch();
//Select…
var table = svg.selectAll('table').append('table')
.style("border-collapse", "collapse")
.style("border", "2px black solid");
// .data(dataset, key);
console.log(table);
var rows = table.selectAll('tr')
.data(dataset, key)
.enter()
.append('tr');
console.log(rows);
rows.selectAll('td')
.data(function(d){ console.log(d); return d;} )
.enter()
.append('td')
.text(function(d) {console.log("here"); return d;})
.style("border", "1px black solid")
.style("padding", "10px")
.style("font-size","12px");
}
I have created a d3 donut chart. Here is my code:
var width = 480;
var height = 480;
var radius = Math.min(width, height) / 2;
var doughnutWidth = 30;
var color = d3.scale.category10();
var arc = d3.svg.arc()
.outerRadius(radius - 10)
.innerRadius(radius - 70);
var pie = d3.layout.pie()
.sort(null)
.value(function(d) { return d[1]; });
var dataset = settings.dataset;
console.log(dataset);
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))
.enter()
.append('path')
.attr('d', arc)
.attr('fill', function(d, i) {
return color(d.data[0]);
})
I have a simple form on my web page which displays a dropdown menu with several options. Every time a user changes a value on the form a new dataset is sent to my script (settings.dataset) and the donut is redrawn on the page.
Problem is, some of the values from the previous dataset remain in the DOM. In the console output below, you can see that the second dataset only has two elements. The third one is from the previous dataset. This is messing up the chart, as it is displaying a value that shouldn't be there.
My question: how do I clear the old values? I've read up on .exit() and .remove(), but I can't get my head around these methods.
Create one function that (re)draws the pie when it's created and when it's updated.
New data should be added to pie using enter() and old data should be removed using exit().remove()
It is as simple as this:
path.enter().append("path")
.attr("fill", function(d, i) { return color(i); })
.attr("d", arc)
.each(function(d) {this._current = d;} );
path.transition()
.attrTween("d", arcTween);
path.exit().remove()
Full working code -> JSFIDDLE
There are two steps to implement the 'redraw' effect you want:
First, I suppose you want the svg canvas to be drawn only once when the page is loaded for the first time, and then update the chart in the svg instead of remove and redraw the svg:
var svg = d3.select("body")
.selectAll("svg")
.data([settings.dataset]);
// put data in an array with only one element
// this ensures there is only one consistent svg on the page when data is updated(when the script gets executed)
svg.enter().append("svg")
Second, understanding enter(), exit(), there are many great tutorials about this. In your case, I would suggest to draw the donut something like this:
var path = svg.selectAll(".donut")
.data(settings.data)
// bind data to elements, now you have elements belong to one of those
// three 'states', enter, exit, or update
// for `enter` selection, append elements
path.enter().append("path").attr("d", arc).attr("fill", "teal")
// for `update` selection, which means they are already binded with data
path.transition().attrTween("d", someFunction) // apply transition here if you want some animation for data change
// for `exit` selection, they shouldn't be on the svg canvas since there is no corresponding data, you can then remove them
path.exit().remove()
//remove and create svg
d3.select("svg").remove();
var svg = d3.select("body").append("svg").attr("width","960").attr("height", "600"),
inner = svg.append("g");
I'm trying to build an interactive population pyramid. I want to update the width of the bars.
Something is not working with my selections though. Female and male bars charts are updated to the same width, because they receive the same datum. I suspect that it has to do with the way I select or join the data. I've tried several combinations, now I'm stuck reading the doc on select and selectAll.
Any comments on what goes wrong here are highly appreciated.
The code (here is the fiddle):
var pyramidCanvas = d3.select("body")
.append("svg")
.attr("width",200)
.attr("height",100);
var pyramidHeight = 100;
var pyramidWidth = 100;
var pyramidBarsRight, pyramidBarsLeft;
function setupPyramid(){
var data = [300,20,40,50,10];
var pyramidHeight = 100;
var pyramidWidth = 100;
var xScale = d3.scale.linear()
.domain([0,d3.max(data,function(d){return d;})])
.range([0,pyramidWidth]);
var barHeight = pyramidHeight/data.length;
console.log(barHeight);
pyramidBarsLeft = pyramidCanvas.selectAll("g-female")
.data(data)
.enter()
.append("g")
.attr("transform",function(d,i){return "translate(0,"+ (i * 10)+ ")" ;});
pyramidBarsLeft.append("rect")
.attr("class","female-bar")
.attr("x",function(d){return pyramidWidth-xScale(d);})
.attr("y",function(d,i){
return i*10;
})
.attr("width",function(d){console.log(d);return xScale(d);})
.attr("height",10)
.style("fill","pink");
pyramidBarsRight = pyramidCanvas.selectAll("g-male")
.data(data)
.enter()
.append("g")
.attr("transform",function(d,i){return "translate(0,"+ (i * 10)+ ")" ;});
pyramidBarsRight.append("rect")
.attr("class","male-bar")
.attr("x",pyramidWidth)
.attr("y",function(d,i){
return i*10;
})
.attr("width",function(d){console.log(d);return xScale(d);})
.attr("height",10)
.style("fill","steelblue");
}
function updatePyramid(data){
var femData = data.slice(0,5);
var malData = data.slice(5,9);
console.log(femData);
console.log(malData);
console.log(pyramidBarsRight.selectAll("rect"));
var xScale = d3.scale.linear()
.domain([0,d3.max(data,function(d){return d;})])
.range([0,pyramidWidth]);
pyramidBarsLeft
.selectAll(".female-bar")
.data(femData)
.transition()
.duration(500)
.attr("x",function(d){return pyramidWidth-xScale(d);})
.attr("width",function(d){console.log(d);return xScale(d);})
pyramidBarsRight
.selectAll(".male-bar")
.data(malData)
.transition()
.duration(500)
.attr("width",function(d){console.log(d);return xScale(d);});
}
setupPyramid();
updatePyramid([20,10,50,100,600,30,22,54,91,19,10]);
You shouldn't save the result of an enter selection and use it like that. It works fine it you select from the canvas, see here. The reason is that elements in the enter selection merge into the update selection once DOM elements have been appended.
The data array contains exactly 5 objects.
The following code displays only the last 4, and skip the first :
d3.csv(csv_data, function(error, data){
var table = d3.select("#div");
var tr = table.selectAll("tr")
.data(data)
.enter()
.append("tr");
var td = tr.selectAll("td")
.data(function(d){return [d.x,d.y];})
.enter()
.append("td")
.html(function(d){return d;});
});