Первый переход d3 при обновлении внутри интервала не переходит

У меня есть кольцевая диаграмма, которая используется как способ показать прогресс. У меня нет возможности показать вам кольцевую диаграмму, но код достаточно прост для копирования и вставки.

Я добавил код, чтобы показать вам пример. Я пробовал различные неразумные методы, чтобы переход работал с первого раза. Но почему-то до сих пор не работает. Все примеры в Интернете очень похожи, поэтому я не совсем уверен, почему это происходит.

    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>
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
Раскрытие чувствительных данных
Раскрытие чувствительных данных
Все внешние компоненты, рассмотренные здесь до сих пор, взаимодействуют с клиентской стороной. Однако, если они подвергаются атаке, они не...
Зод: сила проверки и преобразования данных
Зод: сила проверки и преобразования данных
Сегодня я хочу познакомить вас с библиотекой Zod и раскрыть некоторые ее особенности, например, возможности валидации и трансформации данных, а также...
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Мы провели Twitter Space, обсудив несколько проблем, связанных с последними дополнениями в Angular. Также прошла Angular Tiny Conf с 25 докладами.
Руководство ChatGPT по продаже мини JS-файлов
Руководство ChatGPT по продаже мини JS-файлов
JS-файл - это файл, содержащий код JavaScript. JavaScript - это язык программирования, который в основном используется для добавления интерактивности...
5
0
149
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Если мы посмотрим на вашу функцию твина, мы увидим проблему:

    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 нет свойств, интерполятор просто использует статическое значение для каждой точки интерполяции, отсюда и отсутствие перехода при первом обновлении: каждая интерполируемая точка одинакова: значения конечных точек.

Ничего себе, хорошо имеет смысл. Я предполагаю, что мой дополнительный вопрос будет таким: почему при вызове функции интерполятора не возникает ошибка, если this._current не определен?

essessonsee 18.12.2020 19:25

@essessonsee, добавил некоторые подробности о том, почему вы не видите ошибку.

Andrew Reid 19.12.2020 05:13

Другие вопросы по теме