gpt4 book ai didi

javascript - d3 使用 selection.join 更新堆积条形图

转载 作者:行者123 更新时间:2023-12-01 15:43:56 24 4
gpt4 key购买 nike

我正在创建一个堆积条形图,该条形图应该随着数据的变化而更新,我想使用 d3v5 和 selection.join,如此处所述 https://observablehq.com/@d3/learn-d3-joins?collection=@d3/learn-d3 .
输入数据时,一切都按预期工作,但是永远不会调用更新函数(即用于调试的 console.log()。)。
所以看起来它一直在输入新数据。
我怎样才能让它按预期工作?

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
body {
margin: 0;
}
.y.axis .domain {
display: none;
}
</style>
</head>
<body>
<div id="chart"></div>

<script src="https://d3js.org/d3.v5.min.js"></script>
<script>

let xVar = "year";

let alphabet = "abcdef".split("");
let years = [1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003];

let margin = { left:80, right:20, top:50, bottom:100 };

let width = 600 - margin.left - margin.right,
height = 600 - margin.top - margin.bottom;

let g = d3.select("#chart")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + ", " + margin.top + ")");

let color = d3.scaleOrdinal(["#66c2a5","#fc8d62","#8da0cb","#e78ac3","#a6d854","#ffd92f"])
let x = d3.scaleBand()
.rangeRound([0, width])
.domain(years)
.padding(.25);

let y = d3.scaleLinear()
.rangeRound([height, 0]);

let xAxis = d3.axisBottom(x);

let yAxis = d3.axisRight(y)
.tickSize(width)

g.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);

g.append("g")
.attr("class", "y axis")
.call(yAxis);

let stack = d3.stack()
.keys(alphabet)
.order(d3.stackOrderNone)
.offset(d3.stackOffsetNone);

redraw(randomData());

d3.interval(function(){
redraw(randomData());
}, 1000);

function redraw(data){

// update the y scale
y.domain([0, d3.max(data.map(d => d.sum ))])
g.select(".y")
.transition().duration(1000)
.call(yAxis);

groups = g.append('g')
.selectAll('g')
.data(stack(data))
.join('g')
.style('fill', (d,i) => color(d.key));
groups.selectAll('.stack')
.data(d => d)
.attr('class', 'stack')
.join(
enter => enter.append('rect')
.data(d => d)
.attr('x', d => x(d.data.year))
.attr('y', y(0))
.attr('width', x.bandwidth())
.call(enter => enter.transition().duration(1000)
.attr('y', d => y(d[1]))
.attr('height', d => y(d[0]) - y(d[1]))
),
update => update
.attr('x', d => x(d.data.year))
.attr('y', y(0))
.attr('width', x.bandwidth())
.call(update => update.transition().duration(1000)
.attr('y', d => y(d[1]))
.attr('height', d => y(d[0]) - y(d[1]))
.attr(d => console.log('update stack'))
)
)

}

function randomData(data){
return years.map(function(d){
let obj = {};
obj.year = d;
let nums = [];
alphabet.forEach(function(e){
let num = Math.round(Math.random()*2);
obj[e] = num;
nums.push(num);
});
obj.sum = nums.reduce((a, b) => a + b, 0);
return obj;
});
}

</script>
</body>
</html>

这是一个工作的jsfiddle: https://jsfiddle.net/blabbath/yeq5d1tp/

编辑:我首先提供了一个错误的链接,这里是正确的。
我的示例很大程度上基于此: https://bl.ocks.org/HarryStevens/7e3ec1a6722a153a5d102b6c42f4501d

最佳答案

几天前我遇到了同样的问题。我这样做的方式如下:

我们有两个 .join ,父级用于堆栈,子级用于矩形。

enter父连接,我们称之为 updateRects为了第一次绘制矩形,这个 updateRects函数会做 child .join ,第二个连接函数将绘制矩形。

对于更新,我们做同样的事情,但不是在 enter 中进行。 join的函数,我们在update .

此外,我的 SVG 以不同的方式构造,我有一个堆栈组,然后我有堆栈组和一个条形组,在这个条形组中我添加了矩形。在下面的 fiddle 中,您可以看到我添加了具有类 stack 的父组.

两个函数如下:

更新堆栈:

  function updateStack(data) {
// update the y scale
y.domain([0, d3.max(data.map((d) => d.sum))]);
g.select(".y").transition().duration(1000).call(yAxis);

const stackData = stack(data);

stackData.forEach((stackedBar) => {
stackedBar.forEach((stack) => {
stack.id = `${stackedBar.key}-${stack.data.year}`;
});
});

let bars = g
.selectAll("g.stacks")
.selectAll(".stack")
.data(stackData, (d) => {
return d.key;
});

bars.join(
(enter) => {
const barsEnter = enter.append("g").attr("class", "stack");

barsEnter
.append("g")
.attr("class", "bars")
.attr("fill", (d) => {
return color(d.key);
});

updateRects(barsEnter.select(".bars"));

return enter;
},
(update) => {
const barsUpdate = update.select(".bars");
updateRects(barsUpdate);
},
(exit) => {
return exit.remove();
}
);
}

更新矩形:
  function updateRects(childRects) {
childRects
.selectAll("rect")
.data(
(d) => d,
(d) => d.id
)
.join(
(enter) =>
enter
.append("rect")
.attr("id", (d) => d.id)
.attr("class", "bar")
.attr("x", (d) => x(d.data.year))
.attr("y", y(0))
.attr("width", x.bandwidth())
.call((enter) =>
enter
.transition()
.duration(1000)
.attr("y", (d) => y(d[1]))
.attr("height", (d) => y(d[0]) - y(d[1]))
),
(update) =>
update.call((update) =>
update
.transition()
.duration(1000)
.attr("y", (d) => y(d[1]))
.attr("height", (d) => y(d[0]) - y(d[1]))
),
(exit) =>
exit.call((exit) =>
exit
.transition()
.duration(1000)
.attr("y", height)
.attr("height", height)
)
);
}

这是一个更新 jsfiddle https://jsfiddle.net/5oqwLxdj/1/

我希望它有所帮助。

关于javascript - d3 使用 selection.join 更新堆积条形图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61087443/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com