gpt4 book ai didi

javascript - 从 D3 v3 改编到 v5 的代码需要额外更新才能正确呈现

转载 作者:行者123 更新时间:2023-11-29 10:55:55 27 4
gpt4 key购买 nike

我尝试从 Block 改编代码时发现了一些问题它使用 D3 v3 到更新版本 D3 v5

图表在第一次执行时显示不正确,但是,通过调用函数 changeData 更新两次后会正确显示。在 D3 v3 中,图表直接向上显示。我做错了什么?

这是显示错误的演示:

let svg;
let radius;
let pie;
let arc;
let outerArc;
let data_ready;
let slice;
let width = 700, height= 400;

let dataChart = [];

svg = d3.select(".chart-d3")
.append("svg")
.append("g");
radius = Math.min(width, height) / 2.5;
svg.append("g").attr("class", "slices").attr("name", "slices");
svg.append("g").attr("class", "labels");
svg.append("g").attr("class", "lines");
pie = d3.pie()
.sort(null)
.value(function(d){
return d.value;
});

arc = d3.arc()
.outerRadius(radius * 0.8)
.innerRadius(radius * 0.4);

outerArc = d3.arc()
.innerRadius(radius * 0.9)
.outerRadius(radius * 0.9);
svg.attr("transform", "translate (" + width / 2 + "," + height / 2 + ")" );

let key = function(d){
return d.data.label;
}

var color = d3.scaleOrdinal()
.domain(["Lorem ipsum", "dolor sit", "amet", "consectetur", "adipisicing", "elit", "sed", "do", "eiusmod", "tempor", "incididunt"])
.range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);

function randomData(){
let labels = color.domain();
let dataFor = labels.map(function(label){
return { label : label, value: Math.random() }
});
return dataFor;
}

changeData(randomData());

function changeData(data){
data_ready = pie(data);
slice = svg.select(".slices").selectAll("path.slice").data(data_ready, key);
slice
.enter()
.append('path')
.style('fill', function(d){ return color(d.data.label) })
.attr("class", "slice");

slice
.transition().duration(1000)
.attrTween("d", function(d) {
this._current = this._current || d;
var interpolate = d3.interpolate(this._current, d);
this._current = interpolate();
return function(t) {
return arc(interpolate(t));
};
})
slice.exit()
.remove();

/* ------- TEXT LABELS -------*/
var text = svg.select(".labels").selectAll("text")
.data(data_ready, key);

text.enter()
.append("text")
.attr("dy", ".35em")
.text(function(d) {
return d.data.label + "(" + Math.round(d.data.value * 1000) + ")";
});

text.transition().duration(1000)

.attrTween("transform", function(d){
this._current = this._current || d;
let interpolate = d3.interpolate(this._current, d);
this._current = interpolate(0);
return function(t){
let d2 = interpolate(t);
let pos = outerArc.centroid(d2);
pos[0] = radius * (midAngle(d) < Math.PI ? 1 : -1);
return "translate(" + pos + ")";
}
})
.styleTween("text-anchor", function(d){
this._current = this._current || d;
var interpolate = d3.interpolate(this._current, d);
this._current = interpolate(0);
return function(t) {
var d2 = interpolate(t);
return midAngle(d2) < Math.PI ? "start":"end";
};
});

function midAngle(d){
return d.startAngle + (d.endAngle - d.startAngle)/2;
}

text.exit()
.remove();

/* ------- SLICE TO TEXT POLYLINES -------*/

var polyline = svg.select(".lines").selectAll("polyline")
.data(data_ready, key);

polyline.enter()
.append("polyline");

polyline.transition().duration(1000)
.attrTween("points", function(d){
this._current = this._current || d;
var interpolate = d3.interpolate(this._current, d);
this._current = interpolate(0);
return function(t) {
var d2 = interpolate(t);
var pos = outerArc.centroid(d2);
pos[0] = radius * 0.95 * (midAngle(d2) < Math.PI ? 1 : -1);
return [arc.centroid(d2), outerArc.centroid(d2), pos];
};
});

polyline.exit()
.remove();
}
.chart-d3{
height: 400px;
width: 700px;
margin: 10px auto; box-shadow: 1px 1px 10px 3px gray;
display: flex;
flex-direction: column;
}
svg{
width: 100%;
height: 100%;
}
path.slice{
stroke-width: 2px;
}
polyline{
opacity: .3;
stroke: black;
stroke-width: 2px;
fill: none;
}
button{
height: 40px;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script src="https://d3js.org/d3.v5.min.js"></script>
</head>
<body>
<div class="chart-d3">
<button onclick="changeData(randomData())">Update</button>
</div>
</body>
</html>

最佳答案

从 D3 v4 开始,常规更新模式 的行为发生了变化。来自changelog :

selection.append no longer merges entering nodes into the update selection; use selection.merge to combine enter and update after a data join.

这就是您的图形在第一次运行时损坏的原因;新输入的元素未被选中,因此不会过渡到它们的最终位置。这在第二次运行期间得到解决,因为这些相同的元素都将成为更新选择的一部分。

而不是做

slice = svg.select(".slices").selectAll("path.slice").data(data_ready, key);
slice
.enter()
.append('path')
.style('fill', function(d){ return color(d.data.label) })
.attr("class", "slice");

slice // <-- This is just the update selection without newly entered elements
.transition().duration(1000)

你的代码应该是这样的:

slice = svg.select(".slices").selectAll("path.slice").data(data_ready, key);
slice = slice // <══ 2. Store in update selection ══════════════════════╗
.enter() // ║
.append('path') // ║
.style('fill', function(d){ return color(d.data.label) }) // ║
.attr("class", "slice") // ║
.merge(slice); // ═══ 1. Merge update selection into enter selection ════╝

slice // <-- Now, this holds both entered as well as updated elements.
.transition().duration(1000)

当然,同样需要应用于文本和折线。

查看更新后的工作演示:

let svg;
let radius;
let pie;
let arc;
let outerArc;
let data_ready;
let slice;
let width = 700, height= 400;

let dataChart = [];

svg = d3.select(".chart-d3")
.append("svg")
.append("g");
radius = Math.min(width, height) / 2.5;
svg.append("g").attr("class", "slices").attr("name", "slices");
svg.append("g").attr("class", "labels");
svg.append("g").attr("class", "lines");
pie = d3.pie()
.sort(null)
.value(function(d){
return d.value;
});

arc = d3.arc()
.outerRadius(radius * 0.8)
.innerRadius(radius * 0.4);

outerArc = d3.arc()
.innerRadius(radius * 0.9)
.outerRadius(radius * 0.9);
svg.attr("transform", "translate (" + width / 2 + "," + height / 2 + ")" );

let key = function(d){
return d.data.label;
}

var color = d3.scaleOrdinal()
.domain(["Lorem ipsum", "dolor sit", "amet", "consectetur", "adipisicing", "elit", "sed", "do", "eiusmod", "tempor", "incididunt"])
.range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);

function randomData(){
let labels = color.domain();
let dataFor = labels.map(function(label){
return { label : label, value: Math.random() }
});
return dataFor;
}

changeData(randomData());

function changeData(data){
data_ready = pie(data);
slice = svg.select(".slices").selectAll("path.slice").data(data_ready, key);
slice = slice
.enter()
.append('path')
.style('fill', function(d){ return color(d.data.label) })
.attr("class", "slice")
.merge(slice);

slice
.transition().duration(1000)
.attrTween("d", function(d) {
this._current = this._current || d;
var interpolate = d3.interpolate(this._current, d);
this._current = interpolate();
return function(t) {
return arc(interpolate(t));
};
})
slice.exit()
.remove();

/* ------- TEXT LABELS -------*/
var text = svg.select(".labels").selectAll("text")
.data(data_ready, key);

text = text.enter()
.append("text")
.attr("dy", ".35em")
.text(function(d) {
return d.data.label + "(" + Math.round(d.data.value * 1000) + ")";
}).merge(text);

text.transition().duration(1000)

.attrTween("transform", function(d){
this._current = this._current || d;
let interpolate = d3.interpolate(this._current, d);
this._current = interpolate(0);
return function(t){
let d2 = interpolate(t);
let pos = outerArc.centroid(d2);
pos[0] = radius * (midAngle(d) < Math.PI ? 1 : -1);
return "translate(" + pos + ")";
}
})
.styleTween("text-anchor", function(d){
this._current = this._current || d;
var interpolate = d3.interpolate(this._current, d);
this._current = interpolate(0);
return function(t) {
var d2 = interpolate(t);
return midAngle(d2) < Math.PI ? "start":"end";
};
});

function midAngle(d){
return d.startAngle + (d.endAngle - d.startAngle)/2;
}

text.exit()
.remove();

/* ------- SLICE TO TEXT POLYLINES -------*/

var polyline = svg.select(".lines").selectAll("polyline")
.data(data_ready, key);

polyline = polyline.enter()
.append("polyline").merge(polyline);

polyline.transition().duration(1000)
.attrTween("points", function(d){
this._current = this._current || d;
var interpolate = d3.interpolate(this._current, d);
this._current = interpolate(0);
return function(t) {
var d2 = interpolate(t);
var pos = outerArc.centroid(d2);
pos[0] = radius * 0.95 * (midAngle(d2) < Math.PI ? 1 : -1);
return [arc.centroid(d2), outerArc.centroid(d2), pos];
};
});

polyline.exit()
.remove();
}
.chart-d3{
height: 400px;
width: 700px;
margin: 10px auto; box-shadow: 1px 1px 10px 3px gray;
display: flex;
flex-direction: column;
}
svg{
width: 100%;
height: 100%;
}
path.slice{
stroke-width: 2px;
}
polyline{
opacity: .3;
stroke: black;
stroke-width: 2px;
fill: none;
}
button{
height: 40px;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script src="https://d3js.org/d3.v5.min.js"></script>
</head>
<body>
<div class="chart-d3">
<button onclick="changeData(randomData())">Update</button>
</div>
</body>
</html>

关于javascript - 从 D3 v3 改编到 v5 的代码需要额外更新才能正确呈现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57321262/

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