【发布时间】:2017-12-13 16:48:10
【问题描述】:
我使用 d3 v4 已经有几个月的时间了,并且做了很多研究。我终于掌握了数据连接的概念,但在试图弄清楚如何更新分组条形图时遇到了困难。
我认为我的问题是我在执行连接时没有选择正确的 SVG 元素,因此 update() 和 exit() 方法总是返回空集。这是我基于 d3 块的代码:Codepen 请参见 #135 行,其中所有的魔法应该正在发生。
/* Based on https://bl.ocks.org/mbostock/3887051 */
var svg = d3.select("svg"),
margin = { top: 20, right: 20, bottom: 100, left: 40 },
width = +svg.attr("width") - margin.left - margin.right,
height = +svg.attr("height") - margin.top - margin.bottom,
g = svg
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var formatTime = d3.timeFormat("%X");
var legendKeys = new Map();
var x0 = d3
.scaleBand()
.rangeRound([0, width])
.paddingInner(0.1);
var x1 = d3.scaleBand().padding(0.05);
var y = d3.scaleLinear().rangeRound([height, 0]);
var z = d3
.scaleOrdinal()
.range([
"#98abc5",
"#8a89a6",
"#7b6888",
"#6b486b",
"#a05d56",
"#d0743c",
"#ff8c00"
]);
var data = [];
for (var i = 0; i < 5; i++) {
generateData();
}
var keys = Object.keys(data[0].y);
keys.forEach(k => legendKeys.set(".data-" + k.replace(/ /g, "")));
g.append("g").attr("class", "bars");
var xAxis = g
.append("g")
.attr("class", "x--axis")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x0).tickFormat(formatTime));
var yAxis = g
.append("g")
.attr("class", "y--axis")
.call(d3.axisLeft(y).ticks(null, "s"));
var legend = g
.append("g")
.attr("font-family", "sans-serif")
.attr("font-size", 8)
.attr("text-anchor", "end")
.attr("class", "legend")
.selectAll("g")
.data(keys.slice())
.enter()
.append("g")
.attr("transform", function(d, i) {
return "translate(0," + i * 20 + ")";
});
legend
.append("rect")
.attr("x", width - 19)
.attr("width", 19)
.attr("height", 19)
.attr("style", "cursor:pointer")
.attr("fill", z)
.on("click", function(d) {
var key = ".data-" + d.replace(/ /g, "");
// determine if current line is visible
var active = legendKeys.get(key) ? false : true,
newOpacity = active ? 0 : 1;
// hide or show the elements
d3.selectAll(key).style("opacity", newOpacity);
// update whether or not the elements are active
legendKeys.set(key, active);
this.style.opacity = active ? 0.5 : 1;
});
legend
.append("text")
.attr("x", width - 24)
.attr("y", 9.5)
.attr("dy", "0.32em")
.text(function(d) {
return d;
});
window.setInterval(() => {
generateData();
if (data.length > 14) {
data.shift();
}
updateChart();
}, 1000);
function updateChart() {
x0.domain(
data.map(function(d) {
return d.x;
})
);
x1.domain(keys).rangeRound([0, x0.bandwidth()]);
y
.domain([
0,
d3.max(data, function(d) {
return d3.max(keys, function(key) {
return d.y[key];
});
})
])
.nice();
d3.select(".x--axis")
.transition()
.call(d3.axisBottom(x0).tickFormat(formatTime));
d3.select(".y--axis")
.transition()
.call(d3.axisLeft(y));
var barGroups = g
.select(".bars")
.selectAll(".barGroup")
.data(data);
barGroups
.enter()
.append("g")
.attr("transform", function(d) {
return "translate(" + x0(d.x) + ",0)";
})
.attr("class", "barGroup")
.selectAll("rect")
.data(function(d) {
return keys.map(function(key) {
return { key: key, value: d.y[key] };
});
})
.enter()
.append("rect")
.attr("x", function(d) {
return x1(d.key);
})
.attr("y", function(d) {
return y(d.value);
})
.attr("width", x1.bandwidth())
.attr("height", function(d) {
return height - y(d.value);
})
.attr("class", function(d) {
return "data-" + d.key.replace(/ /g, "");
})
.attr("fill", function(d) {
return z(d.key);
})
.merge(barGroups)
.attr("width", x1.bandwidth())
.attr("height", function(d) {
return height - y(d.value);
})
.attr("x", function(d) {
return x1(d.key);
})
.attr("y", function(d) {
return y(d.value);
});
// Exit
var old = barGroups
.exit()
.remove();
// Release memory for elements that were removed
old = null;
}
function generateData() {
var lastDate = new Date();
if (data.length > 0) {
lastDate = new Date(data[data.length - 1].x);
}
lastDate.setHours(lastDate.getHours() + 1);
data.push({
x: lastDate,
y: {
A: d3.randomUniform(0, 100)(),
B: d3.randomUniform(0, 100)(),
C: d3.randomUniform(0, 100)()
}
});
}
/* Based on https://bl.ocks.org/mbostock/3887051 */
rect.bar {
fill: steelblue;
}
text {
fill: #000;
font: 11px sans-serif;
font-weight:500;
}
/* body {
background-color: #f00;
} */
.legend rect:hover {
stroke-width:0.5;
stroke: black;
}
svg {
background-color:#eee;
shape-rendering: crispEdges;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.11.0/d3.min.js"></script>
<!-- Based on https://bl.ocks.org/mbostock/3887051 -->
<svg width="900" height="400"></svg>
【问题讨论】:
-
群组似乎更新得很好,是条形图没有更新。他们将需要自己的更新模式。
-
@RyanMorton 我该怎么做?
-
在回答这个问题 (stackoverflow.com/questions/38921456/…) 时,有两个变量(状态和条形图)都遵循更新模式。我认为它展示了通常所做的事情。
-
@RyanMorton 我看了你提到的那个问题,但我仍然没有看到如何更新/删除这些栏组。同样在引用的问题中,他们正在使用 d3 v3,并且在 d3 v4 中更改了 enter.append 行为。
标签: javascript d3.js graph