我正在尝试在D3.js中制作交互式条形图 我uploaded everything to github以便于参考。我在问题的最后也加入了index.html。
我的出发点是data.json,其中包含7个项目(即国家/地区)的数组。每个国家/地区都有一个属性' name'和其他四个属性。这些代表了2009年和2014年私人银行和国家对希腊债务的阐述。
我的目标是创建一个条形图,首先显示2009年每个国家/地区的银行和公共部门的展示(每个国家/地区有两个条形图),并在用户点击后更改为2014年适当的按钮。
我设法让一切顺利!但是,我必须为我需要使用的每个(子)数据集手动创建单独的列表。例如,我创建了一个名为y2009,其中包括国家1的银行和州的说明,然后是国家2的相同,等等。 (我离开了其中一个清单并在第43行评论了它)
我想让我的代码更灵活,所以我创建了一个for循环,它提取数据并为我创建列表。 (见第46-60行)。这不起作用,因为for循环将在数据实际加载之前启动。因此,我最终会得到空列表。 所以我将for循环分组为一个函数(prepare())并在加载数据的函数中执行该函数(第18-30行)。这解决了这个问题......
..并创建了一个新的!应该设置比例的两个函数(参见第67-73行)不起作用,因为它们的计算需要在for循环创建的一个列表上(即' total')。 (我假设这是因为在调用缩放方法之后创建了列表。)
奇怪的是,如果我运行脚本,然后在控制台中复制xScale和yScale函数,然后复制绘制函数(第101-212行)一切正常。 因此,我尝试将所有内容分组为函数(例如setScales,draw),以便在脚本结束时按照我想要的顺序调用它们(第214-215行),但这会产生问题,因为某些变量(例如xScale和yScale)需要全球化。 我还尝试首先在全局空间中创建它们,然后通过setScales修改它们。这也不起作用。
总结一下,等一下我不明白是:
我应该以哪种顺序编写代码以使其工作(再次)?在函数中包装操作(例如设置比例,绘图条和标签)然后以正确的顺序调用函数是一个好主意吗?
使用缩放方法创建哪种类型的对象?我对它们是否是实际功能感到困惑。
我希望阅读并感谢所有人,这并不是太痛苦!
菲德
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="d3.min.js"></script>
</head>
<body>
<p>Introductory text here!</p>
<p>
<button id="change2009"> 2009 </button>
<button id="change2014"> 2014 </button>
</p>
<div id="country"></div>
<script type="text/javascript">
d3.json("data.json", function(error, json) {
if (error) {
console.log(error);
} else{
console.log(json);
dataset=json;
}
prepare (dataset);
});
//load data
var dataset;
var bank09=[];
var state09=[];
var bank14=[];
var state14=[];
var y2009=[];
var y2014=[];
var total=[];
var xScale;
var yScale;
//var total = [4.76, 0, 0.12, 6.36, 4.21, 0, 0.04, 7.96, 78.82, 0, 1.81, 46.56, 45, 0, 13.51, 61.74, 6.86, 0, 1.06, 40.87, 12.21, 0, 1.22, 13.06, 1.21, 0, 0.39, 27.35];
function prepare (dataset){
for (i in dataset) {bank09.push(dataset[i].bank09);
state09.push(dataset[i].state09);
bank14.push(dataset[i].bank14);
state14.push(dataset[i].state14);
y2009.push(dataset[i].bank09);
y2009.push(dataset[i].state09);
y2014.push(dataset[i].bank14);
y2014.push(dataset[i].state14);
total.push(dataset[i].bank09);
total.push(dataset[i].state09);
total.push(dataset[i].bank14);
total.push(dataset[i].state14);
}
}
//overwrite dataset
dataset2=y2009;
//scales
function setScales () {
var xScale = d3.scale.ordinal()
.domain(d3.range(total.length/2))
.rangeRoundBands([0, w], 0.1);
var yScale = d3.scale.linear()
.domain([0, d3.max(total)])
.range([0, h]);
console.log(yScale(89));
}
//layout
var w = 600;
var h = 600;
var barPadding = 1;
//coountry names
var country = ["Austria", "Belgium", "France", "Germany", "Italy", "Holland", "Spain"];
d3.select("#country")
.data(country)
.enter()
.append("rect")
.attr("class", "country")
//.append("text")
//.text(function(d){
// return d;
// })
//draw svg
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
function draw () {
//draw bars
svg.selectAll("rect")
.data(dataset2)
.enter()
.append("rect")
.attr("x", function(d, i) {
return xScale(i);
})
.attr("y", function(d){
return h - yScale(d);
})
.attr("width", xScale.rangeBand)
.attr("height", function(d) {
return yScale(d);
})
.attr("fill", "black");
//add labels
svg.selectAll("text")
.data(dataset2)
.enter()
.append("text")
.text(function(d){
return d;
})
.attr("text-anchor", "middle")
.attr("font-family", "sans-serif")
.attr("font-size", "12px")
.attr("fill", "red")
.attr("x", function(d, i){
return xScale(i) + xScale.rangeBand() / 2;
})
.attr("y", function(d) {
if (d<3) {
return h - 15;
} else {
return h - yScale(d) + 15;}
})
//interactivity
d3.select("#change2014")
.on("click", function() {
//update data
dataset2=y2014;
//update bars
svg.selectAll("rect")
.data(dataset2)
.transition()
.duration(3000)
.attr("y", function(d){
return h - yScale(d);
})
.attr("height", function(d) {
return yScale(d);
})
//update labels
svg.selectAll("text")
.data(dataset2)
.transition()
.duration(3000)
.text(function(d){
return d;
})
.attr("x", function(d, i){
return xScale(i) + xScale.rangeBand() / 2;
})
.attr("y", function(d) {
if (d<3) {
return h - 15;
} else {
return h - yScale(d) + 15;}
})
})
d3.select("#change2009")
.on("click", function() {
//update data
dataset2=y2009;
//update bars
svg.selectAll("rect")
.data(dataset2)
.transition()
.duration(3000)
.attr("y", function(d){
return h - yScale(d);
})
.attr("height", function(d) {
return yScale(d);
})
//update labels
svg.selectAll("text")
.data(dataset2)
.transition()
.duration(3000)
.text(function(d){
return d;
})
.attr("x", function(d, i){
return xScale(i) + xScale.rangeBand() / 2;
})
.attr("y", function(d) {
if (d<3) {
return h - 15;
} else {
return h - yScale(d) + 15;}
})
})
}
setScales ();
draw();
</script>
答案 0 :(得分:0)
我应该以哪种顺序编写代码以使其工作(再次)?是 将操作包装在函数中是个好主意(例如设置 缩放,绘图栏和标签)然后调用中的函数 正确的订单?
正如Lars所指出的那样,你可以将所有内容放在d3.json回调中。这是因为您只想在获得数据后开始使用D3进行渲染。 d3.json方法是异步的,这意味着在调用d3.json()之后,之后的代码将在d3.json方法内的函数完成之前首先执行。有关Javascript中异步行为的更多信息,请查看http://rowanmanning.com/posts/javascript-for-beginners-async/。
鉴于您只想在d3.json方法完成后开始渲染,您还可以将代码的其他部分组织成较小的函数,并在d3.json成功回调中调用某种初始化函数,有点像你正在准备的功能。这是一种更简洁的方法,并开始将您带入模型 - 视图范例。
使用缩放方法创建哪种类型的对象?我很迷惑 关于它们是否是实际功能。
scale方法确实返回一个函数,但在其原型中添加了其他函数。尝试打印出“someScale.prototype”以查看可以使用的所有各种方法。我也强烈推荐Scott Murray关于D3的教程。以下是关于比例的章节:http://alignedleft.com/tutorials/d3/scales