Могут ли переход и ротация d3 хорошо сочетаться друг с другом?

Переходы в сочетании с поворотами дают странные результаты.

Вот скрипт с моей проблемой: http://jsfiddle.net/emperorz/E3G3z/1/ Попробуйте нажать на каждый квадрат, чтобы увидеть различное поведение.

Пожалуйста, простите взломанный код, но если я использую переход с вращением (и размещением x/y), то он зацикливается.

Я пытался:

1) все в преобразовании (поверните, затем переведите), и это кажется в основном нормальным. Немного шаткий.

2) просто поверните в преобразовании, позиционированном с использованием атрибутов x/y. Летает повсюду, но попадает в нужное место. Очень странно.

3) все в процессе трансформации (перевести, затем повернуть), улетает и оказывается в (совершенно) неправильном месте.

Хм. Странный.

Есть ли правильный подход к вращению фигур с переходами?

Интуитивно было бы хорошо, если бы работал второй вариант.

Спасибо


person emperorz    schedule 19.09.2012    source источник


Ответы (2)


Чтобы повернуть SVG-объект по произвольной оси, вам нужно два преобразования: translate (для установки оси) и rotate. Что вы действительно хотите, так это сначала полностью применить translate, а затем повернуть уже перемещенный элемент, но похоже, что translate и rotate работают независимо и одновременно. Это заканчивается в нужном месте, но анимация translate, по сути, перемещает ось во время вращения, создавая колебание. Вы можете изолировать translate от rotate, разместив их в разных местах в иерархии элементов SVG. Например, взгляните на следующее:

<g class="outer">
    <g class="rect-container">
        <rect class="rotate-me" width=200 height=100 />
    </g>
</g>

Вы можете центрировать <rect> на (0,0) с помощью translate (-100, -50). Он будет колебаться, если вы примените вращение к элементу <rect>, но он будет вращаться чисто, если вы rotate к элементу g.rect-container. Если вы хотите изменить положение, масштабировать или иным образом преобразовать элемент, сделайте это на g.outer. Вот и все. Теперь у вас есть полный контроль над вашими преобразованиями.

Найти центр <rect> легко, но найти центр <path>, <g> и т. д. намного сложнее. К счастью, в .getBBox() метод (код на CoffeeScript; см. ниже версию JavaScript*):

centerToOrigin = (el) ->
    boundingBox = el.getBBox()
    return {
        x: -1 * Math.floor(boundingBox.width/2),
        y: -1 * Math.floor(boundingBox.height/2) 
    }

Теперь вы можете центрировать свой элемент/группу, передав элемент без обертки (используя метод .node() D3)

group = d3.select("g.rotate-me")
center = centerToOrigin(group.node())
group.attr("transform", "translate(#{center.x}, #{center.y})")

Код, который реализует это как на одном <rect>, так и на <g> из 2 rect с изменением положения и масштабированием, см. скрипка.


*Javascript приведенного выше кода:

var center, centerToOrigin, group;

centerToOrigin = function(el) {
  var boundingBox;
  boundingBox = el.getBBox();
  return {
    x: -1 * Math.floor(boundingBox.width / 2),
    y: -1 * Math.floor(boundingBox.height / 2)
  };
};

group = d3.select("g.rotate-me");
center = centerToOrigin(group.node());
group.attr("transform", "translate(" + center.x + ", " + center.y + ")");
person rdickert    schedule 14.02.2013
comment
Вы рулите, первый абзац и пример бесценны! Слава! - person johndodo; 28.01.2014
comment
Спасибо! Рад, что это помогло! - person rdickert; 29.01.2014

iirc translate относится к 0,0, тогда как вращение вокруг центральной точки объекта

Таким образом, поскольку ваши фигуры смещены от 0,0 (например, 100 200 или 200 100), они в конечном итоге мигрируют при переводе. Это можно увидеть, изменив смещения для Diamond3 на [50,50] — гораздо меньшая миграция по экрану.

Решением будет переустановка точки 0,0 в центр ромба. Есть способ сделать это в D3 - но я не могу вспомнить, что это за макушка :(

person logical Chimp    schedule 19.09.2012
comment
Возможно, я вас неправильно понимаю, но на самом деле 1 и 2 должны быть одинаковыми. Они заканчиваются в одинаковых местах (нет геометрической разницы в конечных точках перехода), но во время перехода пути представляют собой большие зацикленные эпициклы. Я предполагаю, что небольшие колебания происходят из-за ошибок в функции арктангенса или чего-то подобного, но большие циклы просто странные. - person emperorz; 19.09.2012
comment
В примере, когда вы щелкаете, вы снова добавляете значения X, Y к начальной точке (и снова, и снова). Итак, когда страница загружается, вы переводите Diamond2 в 100 200. Когда пользователь нажимает, ромб2 поворачивается на 65 градусов и снова перемещается на 100 200. Различное поведение вызвано тем, что сначала вращается, а затем перемещается, вращается во время перемещения или сначала перемещается, а различие в масштабе вызвано различными значениями перемещения. Чтобы доказать это, отредактируйте свою скрипту, чтобы удалить «Diamond2.x» и «Diamond2.y» из преобразования обработчика кликов. - person logical Chimp; 19.09.2012
comment
Нет, это не постоянное изменение перевода. Поворот увеличивается, но перевод остается точно таким же. - person emperorz; 20.09.2012
comment
Я немного почистил вещи. «Проблема», похоже, заключается в том, как выполняется интерполяция. Хм. Я мог бы сделать чистую svg-анимацию и посмотреть, будет ли она делать то же самое. - person emperorz; 20.09.2012
comment
ХОРОШО. После возни с нативной анимацией SVG и борьбы с абсолютным и относительным позиционированием и вращением (ооочень неинтуитивно), теперь я знаю, как избежать этой проблемы. Итак, вот мой обходной путь, пока я не получу ответ, хотя я не задерживаю дыхание. Постройте все фигуры вокруг начала координат. Определите свой собственный относительный кадр, используя группу и преобразование (чтобы избежать абсолютного положения, но неприятности относительного вращения). Переход каждый в отдельности и отдельно. Теперь мне нужно посмотреть, выполняются ли переходы параллельно (как SVG) или последовательно. В любом случае, никаких шатаний, ура! - person emperorz; 20.09.2012
comment
параллельно. Дело сделано. Спасибо, что потратили время на это логическое :). - person emperorz; 20.09.2012
comment
@emperorz, не могли бы вы опубликовать код, демонстрирующий ваше решение? Я только что столкнулся с этой проблемой и все еще обдумываю ответ. - person rdickert; 07.02.2013