我正在D3中构建一个瀑布图。当页面加载时,它将呈现默认页面,但用户可以从下拉菜单中选择不同的“公司”和“年份”。我已经能够创建我想要的图表了。但是当我选择任何不同的公司或年份时,D3会在现有图表的基础上添加另一个图表,而不是替换它,这是因为我的目标是HTML中的特定div / svg。我如何使用D3用新数据更新图表,而不是添加另一个top?如果我能让图表条的移动带有过渡效果,那就太棒了。
超文本标记语言是一个简单的svg:
<svg class="chart"></svg>
这是创建Ajax调用成功时我调用的图表的函数:
function waterfallChart (dataset) {
var data = [];
for (var key in dataset[0]) {
data.push({
name: key,
value: dataset[0][key]
})
}
var margin = {top: 20, right: 30, bottom: 30, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom,
padding = 0.3;
var x = d3.scaleBand()
.domain(data.map(function(d) {
return d.name
}))
.range([0, width])
.padding(padding);
var y = d3.scaleLinear()
.range([height, 0]);
var xAxis = d3.axisBottom(x)
var yAxis = d3.axisLeft(y)
.tickFormat(function(d) {
return dollarFormatter(d);
});
var chart = d3.select(".chart")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var cumulative = 0;
for (var i = 0; i < data.length; i++) {
data[i].start = cumulative;
cumulative += data[i].value;
data[i].end = cumulative;
data[i].class = (data[i].value >= 0) ? 'positive' : 'negative'
}
data.push({
name: 'Total',
end: cumulative,
start: 0,
class: 'total'
});
x.domain(data.map(function(d) {
return d.name;
}));
y.domain([0, d3.max(data, function(d) {
return d.end;
})]);
chart.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
chart.append("g")
.attr("class", "y axis")
.call(yAxis);
var bar = chart.selectAll(".bar")
.data(data)
.enter().append("g")
.attr("class", function(d) {
return "bar " + d.class
})
.attr("transform", function(d) {
return "translate(" + x(d.name) + ",0)";
});
bar.append("rect")
.attr("y", function(d) {
return y(Math.max(d.start, d.end));
})
.attr("height", function(d) {
return Math.abs(y(d.start) - y(d.end));
})
.attr("width", x.bandwidth());
bar.append("text")
.attr("x", x.bandwidth() / 2)
.attr("y", function(d) {
return y(d.end) + 5;
})
.attr("dy", function(d) {
return ((d.class == 'negative') ? '-' : '') + ".75em"
})
.text(function(d) {
return dollarFormatter(d.end - d.start);
});
bar.filter(function(d) {
return d.class != "total"
}).append("line")
.attr("class", "connector")
.attr("x1", x.bandwidth() + 5)
.attr("y1", function(d) {
return y(d.end)
})
.attr("x2", x.bandwidth() / (1 - padding) - 5)
.attr("y2", function(d) {
return y(d.end)
})
function dollarFormatter(n) {
n = Math.round(n);
var result = n;
if (Math.abs(n) > 1000) {
result = Math.round(n/1000) + 'B';
}
return '$ ' + result;
}
}
下面是我有事件侦听器的代码,在选择时它将运行上述函数:
$("#airline-selected, #year-selected").change(function chartsData(event) {
event.preventDefault();
var airlineSelected = $('#airline-selected').find(":selected").val();
var yearSelected = $('#year-selected').find(":selected").val();
$.ajax({
url: "{% url 'airline_specific_filtered' %}",
method: 'GET',
data : {
airline_category: airlineSelected,
year_category: yearSelected
},
success: function(dataset){
waterfallChart(dataset)
},
error: function(error_data){
console.log("error")
console.log(error_data)
}
})
});
你在这里错过了一些非常重要的东西。如果要对数据进行更新,则需要执行一些操作。
>
为<code>data()
.data(data, function(d) { return d.name })
现在,假设<code>d,d3将能够区分数据项。名称是唯一标识符。
您需要为更新期间删除的数据提供 exit()。
您需要保存数据联接选择,以便可以对其调用 enter
和 exit
:
var bar = chart.selectAll(".bar")
.data(data, function(d) { return d.name})
现在您可以调用:bar.exit()。删除()
来删除已删除的项目,调用bar.enter()
来添加项目。
您需要选择一个没有调用< code>enter()来更新属性的选项。
可能更多的是样式问题,但您应该在更新函数之外设置SVG和边距,因为它们的状态相同。您仍可以通过在更新中调用相应的函数来更新轴和缩放。
你发布的代码对其他人来说有点难运行—
下面是一个示例,根据您的代码在两个数据集之间更新setInterval
。但是您还应该看看一般的更新模式——它们非常简单,但几乎包含了您需要了解的所有内容。(https://bl.ocks.org/mbostock/3808234)
dataset = [
{name: "Albert", start: 0, end:220},
{name: "Mark", start: 0, end:200},
{name: "Søren", start: 0, end:100},
{name: "Immanuel", start: 0, end:60},
{name: "Michel", start: 0, end:90},
{name: "Jean Paul", start: 0, end: 80}
]
dataset2 = [
{name: "Albert", start: 0, end:20},
{name: "Immanuel", start:0, end:220},
{name: "Jaques", start: 0, end:100},
{name: "Gerhard", start:0 , end:50},
{name: "Søren", start: 0, end:150},
{name: "William", start: 0, end: 180}
]
var margin = {
top: 10,
right: 30,
bottom: 30,
left: 40
},
width = 400 - margin.left - margin.right,
height = 200 - margin.top - margin.bottom,
padding = 0.3;
var chart = d3.select(".chart")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var x = d3.scaleBand()
.range([0, width])
.padding(padding);
var y = d3.scaleLinear()
.range([height, 0])
chart.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
chart.append("g")
.attr("class", "y axis")
var currentData = dataset
waterfallChart(currentData)
setInterval(function() {
currentData = currentData === dataset ? dataset2 : dataset
waterfallChart(currentData)
}, 3000)
function waterfallChart(data) {
var t = d3.transition()
.duration(750)
x.domain(data.map(function(d) {
return d.name
}))
y.domain([0, d3.max(data, function(d) {
return d.end
})])
var xAxis = d3.axisBottom(x)
var yAxis = d3.axisLeft(y)
d3.select('g.x').transition(t).call(xAxis)
d3.select('g.y').call(yAxis)
var bar = chart.selectAll(".bar")
.data(data, function(d) {
return d.name
})
// ENTER -- ADD ITEMS THAT ARE NEW IN DATA
bar.enter().append("g")
.attr("transform", function(d) {
return "translate(" + x(d.name) + ",0)"
})
.attr("class", 'bar')
.append("rect")
.attr("y", function(d) {
return y(Math.max(d.start, d.end));
})
.attr("height", function(d) {
return Math.abs(y(d.start) - y(d.end));
})
.attr("width", x.bandwidth())
// UPDATE EXISTING ITEMS
chart.selectAll(".bar")
.transition(t)
.attr("transform", function(d) {
return "translate(" + x(d.name) + ",0)"
})
.select('rect')
.attr("y", function(d) {
return y(Math.max(d.start, d.end))
})
.attr("height", function(d) {
return Math.abs(y(d.start) - y(d.end))
})
.attr("width", x.bandwidth())
// REMOVE ITEMS DELETED FROM DATA
bar.exit().remove()
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg class="chart"></svg>
问题内容: 我正在建立一个网站来学习编码,并且正在尝试建立一个工具,用户单击一个选择/下拉列表,其中包含从数据库 cat 提取的某些类别名称,然后另一个选择与从数据库 subcat 提取的子类别名称一起出现。这几乎与Yelp的(向下分类)完全一样,就像Yelp的(向下分类)一样。 我还做了一个图: 我已经有一个从 cat 数据库中提取的类别下拉列表: 我有一个从subcat数据库中提取的subca
我想从下面的列表中选择一个使用selenium的选项: 这里 但问题是没有列表可供选择。 在此输入图像说明 我到目前为止的代码: 需要帮助!!
问题内容: 我在尝试制作自己的内容时遇到了麻烦,具体取决于其他方面的选择值。第一个的内容来自我的数据库中的一个表,并且运行良好,但是第二个的内容应该来自另一个表,但是我无法使其工作。这是我的,我只是在尝试证明其工作原理: 这是我的Bean部分,应该获取第二个菜单的内容: 我已经为此工作了好几个小时,但还是一无所获,我真的很着急,如果能在这里给我一些帮助,我将不胜感激。非常感谢您:D 问题答案: i
我正在编写一个python脚本,它将调用一个网页,并从下拉列表中选择一个选项来下载该文件。为了完成这个任务,我使用chropath。它是一个浏览器扩展,可以为您提供网页上任何按钮或字段的相对xpath或id,我们可以使用它从python脚本调用它。 上图显示了下拉菜单,其中我必须选择作为年份并下载文件。在图像的下部,您可以看到我使用了来获取下拉菜单的相对xpath,即 下面是我使用的代码: 从上面
各位前端大佬们,小白求助Echarts图表根据下拉列表选择日期更新数据。 这种功能应该怎么实现,或者有没有什么案例可以借鉴。 感激感激������ 尝试了写写 和百度 没有结果��
问题内容: 我试图使用AngularJS创建一个链接/级联的下拉列表(选择元素),但是我很难用我的对象属性过滤和更新“ selected”属性。 首次加载页面时,所选项目将被过滤并正确显示在下拉菜单中。更改父级下拉菜单后,子级选择项不会抓住已过滤列表中的第一个项,导致子级下拉项不会更新。 任何见解将不胜感激,请注意,我将父/子/孙子数组分开(而不是在子数组中),因为最终我将从SQL中的单独spoc