У меня есть кольцевая диаграмма, которая используется как способ показать прогресс. У меня нет возможности показать вам кольцевую диаграмму, но код достаточно прост для копирования и вставки.
Я добавил код, чтобы показать вам пример. Я пробовал различные неразумные методы, чтобы переход работал с первого раза. Но почему-то до сих пор не работает. Все примеры в Интернете очень похожи, поэтому я не совсем уверен, почему это происходит.
var data = [95, 5];
var pie = d3.pie().sort(null);
var svg = d3.select("svg"),
width = svg.attr("width"),
height = svg.attr("height"),
radius = Math.min(width, height) / 2;
var arc = d3.arc()
.innerRadius(60)
.outerRadius(radius);
function createdonut() {
g = svg.append("g").attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
//Inner SVG Circle
svg.append("svg:circle")
.attr("cx", width / 2)
.attr("cy", height / 2)
.attr("r", 60)
.style("fill", "#ead4d4")
.append("g");
var color = d3.scaleOrdinal(['#4daf4a', '#377eb8', '#ff7f00', '#984ea3', '#e41a1c']);
//Generate groups
var arcs = g.selectAll("arc")
.data(pie(data))
.enter()
.append("g")
.attr("class", "arc")
//Draw arc paths
arcs.append("path")
.attr("fill", function (d, i) {
return color(i);
})
.attr("d", arc)
.on('mouseover', mouseover);
function mouseover(d, i) {
$('#percentage').html(i.data + ' units');
}
}
function updateDoNut(update) {
data[0] = data[0] - update;
data[1] = data[1] + update;
var path = d3.select("svg").selectAll("path").data(pie(data));
/*path.enter().append("path")
.attr("fill", function (d, i) {
return color[i];
})
.attr("d", arc);*/
path.transition().duration(100).attrTween("d", arcTween);
}
function arcTween(a) {
var i = d3.interpolate(this._current, a);
this._current = i(0);
return function (t) {
return arc(i(t));
};
}
createdonut();
//updateDoNut(0);
var inter = setInterval(function () { updateDoNut(5); }, 3000);
<script src = "https://d3js.org/d3.v6.min.js"></script>
<div id = "my_dataviz">
<svg width = "300" height = "200"> </svg>
<div id = "percentage">0 units</div>
</div>
Если мы посмотрим на вашу функцию твина, мы увидим проблему:
var i = d3.interpolate(this._current, a);
this._current = i(0);
This.current не определено, когда вы впервые начинаете переходить — так как же D3 интерполировать между undefined и объектом, содержащим свойства дуги? Это не так. Результатом является отсутствие перехода, который вы видите. Установите this._current при добавлении дуг:
arcs.append("path")
.attr("fill", function (d, i) {
return color(i);
})
.attr("d", arc)
.each(function(d) {
this._current = d;
})
.on('mouseover', mouseover);
Теперь, когда вы обновляете окружность, для интерполятора есть допустимая начальная точка, и вы должны увидеть переход:
var data = [95, 5];
var pie = d3.pie().sort(null);
var svg = d3.select("svg"),
width = svg.attr("width"),
height = svg.attr("height"),
radius = Math.min(width, height) / 2;
var arc = d3.arc()
.innerRadius(60)
.outerRadius(radius);
function createdonut() {
g = svg.append("g").attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
//Inner SVG Circle
svg.append("svg:circle")
.attr("cx", width / 2)
.attr("cy", height / 2)
.attr("r", 60)
.style("fill", "#ead4d4")
.append("g");
var color = d3.scaleOrdinal(['#4daf4a', '#377eb8', '#ff7f00', '#984ea3', '#e41a1c']);
//Generate groups
var arcs = g.selectAll("arc")
.data(pie(data))
.enter()
.append("g")
.attr("class", "arc")
//Draw arc paths
arcs.append("path")
.attr("fill", function (d, i) {
return color(i);
})
.attr("d", arc)
.each(function(d) {
this._current = d;
})
.on('mouseover', mouseover);
function mouseover(d, i) {
$('#percentage').html(i.data + ' units');
}
}
function updateDoNut(update) {
data[0] = data[0] - update;
data[1] = data[1] + update;
var path = d3.select("svg").selectAll("path").data(pie(data));
path.transition().duration(2000).attrTween("d", arcTween);
}
function arcTween(a) {
var i = d3.interpolate(this._current, a);
this._current = i(0);
return function (t) {
return arc(i(t));
};
}
createdonut();
//updateDoNut(0);
var inter = setInterval(function () { updateDoNut(5); }, 3000);
<script src = "https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src = "https://d3js.org/d3.v6.min.js"></script>
<div id = "my_dataviz">
<svg width = "300" height = "200"> </svg>
<div id = "percentage">0 units</div>
</div>
Почему эта интерполяция между undefined и объектом не приводит к ошибке? Ну, D3-interpolate будет очень сильно пытаться интерполировать. В этом случае между undefined и объектом будет использоваться d3-interpolateObject, который будет интерполировать следующим образом:
Для каждого свойства в b, если существует соответствующее свойство в a, общий интерполятор создается для двух элементов с использованием интерполировать. Если такого свойства нет, статическое значение из b равно используется в шаблоне. (документы)
Итак, поскольку в undefined нет свойств, интерполятор просто использует статическое значение для каждой точки интерполяции, отсюда и отсутствие перехода при первом обновлении: каждая интерполируемая точка одинакова: значения конечных точек.
@essessonsee, добавил некоторые подробности о том, почему вы не видите ошибку.
Ничего себе, хорошо имеет смысл. Я предполагаю, что мой дополнительный вопрос будет таким: почему при вызове функции интерполятора не возникает ошибка, если this._current не определен?