Неожиданный переход при использовании CSS calc в d3js styleTween - PullRequest
3 голосов
/ 05 июня 2019

Я хочу использовать CSS calc, чтобы вычислить начальное и / или конечное значение для свойства left элемента div, которое я хотел бы плавно перемещать с помощью d3js styleTween.Но перед началом перехода к правильной конечной точке div переходит в противоположном направлении.

Я протестировал код с Chromium Version 73.0.3683.75 и Firefox 60.7.0esr (64-битная версия).Которые оба приводят к одному и тому же неожиданному поведению.

Использование this.style.left в качестве первого аргумента в d3.interpolate не изменит результат.

Я не нашел заметки в d3jsДокументация styleTween, которая предупреждает об использовании calc и работает для конца перехода.

Я ожидаю, что вычисление сначала значения calc, а затем просто передача результата в функцию интерполяции решит проблему.Но я не уверен, возможно ли это.

<!DOCTYPE html>
<html>
    <head>
        <title>Odd interpolation with CSS calc and d3 styleTween</title>

        <style>
        html {height: 100%;}
        body {height: 100%; margin:0; }

        div.button {
        position: absolute;
        left: 20%;
        width: 3rem;
        height: 100%;
        background-color: #0af;
        }
        </style>
    </head>

    <body>
        <div class="button" id="menu_toggle"></div>
    </body>

    <script src="https://d3js.org/d3.v4.min.js" />
    <script>
        menu = function()
        {
            var div = d3.select('div.button');
            var is_left = true;
            function toggle_menu()
        {
            var left = "20%"
            var right = "calc(80% - 3rem)"
            if (is_left)
            {
                is_left = false;
                div.transition().duration(2000)
                                .styleTween('left', function() { return d3.interpolate(left, right); });
            }
            else
            {
                is_left = true;
                div.transition().duration(2000)
                                .styleTween('left', function() { return d3.interpolate(right, left); });
            }
        }
        return {toggle_menu:toggle_menu}
        }()

        d3.select('#menu_toggle').on("click", menu.toggle_menu)
    </script>
</html>

Я ожидаю плавного перехода между двумя позициями 20% и 80% -3rem.

Вместо этого, когда div начинается слева, он сначала прыгает на 3rem влево, прежде чем двигатьсяправо.Точно так же, если div находится справа, он сначала прыгает на 3rem вправо, а затем двигается влево.

1 Ответ

2 голосов
/ 05 июня 2019

Проблема довольно проста: вы интерполируете строки , а не их оцененные значения.

Когда вы делаете это в CSS ...

calc(80% - 3rem)

... будет оценено в пикселях. Все идет нормально. Тем не менее, D3-интерполятор буквально (каламбур) интерполирует от "20%" до "calc(80% - 3rem)". Конечно, интерполятор не знает, как с этим справиться, и на самом деле он интерполирует от "calc(20% - 3rem)" до "calc(80% - 3rem)".

Посмотрим:

const interpolator = d3.interpolate("20%", "calc(80% - 3rem)");
d3.range(0, 1.1, 0.1).forEach(d => {
  console.log(interpolator(d))
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

Самое простое решение - , оценивающее результат calc() и использующее это значение в интерполяторе. Есть несколько способов сделать это, например, использовать эту библиотеку .

Итак, предположим, что после оценки у нас есть некоторые значения, такие как 150px и 430px. Теперь интерполяция проста:

const interpolator = d3.interpolate("150px", "430px");
d3.range(0, 1.1, 0.1).forEach(d => {
  console.log(interpolator(d))
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
...