2013-06-20 7 views
0

У меня встроенный SVG в HTML-документе. Круг (SVG) анимируется с использованием <animate>. Я пытался найти способ разместить какой-то прослушиватель событий на этом круге только тогда, когда он перемещается горизонтально.Поймать изменения в круге элементов SVG и изменить атрибуты в другом месте через js

При перемещении (по горизонтали), я хотел бы найти x-координаты формы круга и установить третью (внешнюю) ширину прямоугольной формы в относительное положение круга. Этот третий прямоугольник будет похож на индикатор выполнения, отслеживающий горизонтальный ход круга.

Либо SVG-круг (кстати, круг внутри SVG-группы), перемещаемый триггером какого-либо события, я могу установить прослушиватель, чтобы затем я мог изменить атрибут width своего рода прогресса бар?

Я думал, что если либо <animate>, либо элемент перемещен/изменен, инициирует какое-то событие, которое я мог бы попытаться поймать, а затем изменить ширину на панели.

Я обнаружил, что не очень хорошо использовать «независимый» анимированный на пряме, поскольку темп роста очень отличается, когда круг перемещается вверх. Я не использую элемент canvas, потому что я пытаюсь сохранить масштабируемость и семантику форм. (Я предпочел бы использовать javascript-решение, но я был бы благодарен за другие подходы.)

ИЗМЕНИТЬ после ответа: Ансер очень полезен для piint и (я думаю) полезен. Я очень новичок в SVG, и я, возможно, неправильно истолковал. Вот почему я включаю код.

Я попытался выполнить ваши рекомендации, и я, похоже, не увенчался успехом. .cx.animVal.value, примененное к кругу, похоже, не дает мне то, что мне нужно. Я буду включать исправленную версию моего кода, которая должна перемещать мяч по пути, который сам перемещается горизонтально; два прямоугольника (inBar и outBar) должны отслеживать горизонтальное перемещение, растущее горизонтально более или менее с той же скоростью, что и мяч. Чтобы убедиться, что setInterval работает, и позиция правильно собрана, строка была добавлена ​​в список oBall..animVal и oball..baseVal. В FF 21.0 нет изменений для animVal по смещению. Правильно ли я понял ваши предложения? Отсюда следуют код (включая заголовки и т.д., как я нуб в SVG, в частности):

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" dir="ltr"> 
    <head><title>Motion</title> 
    <script>function beginAnim(anim,sPos){anim.beginElement();}</script> 
    </head> 
    <body> 
    <div id="here"> 
    <button onclick="beginAnim(document.getElementById('anim'),'out');">START</button> 
    </div> 
    <div style="height:350px;"> 
    <svg width="100%" height="100%" version="1.1" xmlns="http://www.w3.org/2000/svg"> 
    <script type="text/ecmascript"> 
    <![CDATA[ 
     function trckngBars(){ 
     oDiv=document.getElementById('here'); 
     var oBall=document.getElementById('ball'); 
     var oBar=[document.getElementById('inBar'),document.getElementById('outBar')]; 
     idTimer=self.setInterval(function(){updtBars(oBall,oBar);},100); 
     } 
     function updtBars(oBall,oBar){ 
     var xCoor=String(oBall.cx.animVal.value); 
     oDiv.innerHTML+='==>'+oBall.cx.animVal.value+'..'+oBall.cx.baseVal.value; 
     oBar[0].setAttribute("width",xCoor); 
     oBar[1].setAttribute("width",xCoor); 
     } 
    // ]]> 
    </script> 
    <defs> 
    <path id="throw" d="M0,0 q 80,-55 200,20" style="fill: none; stroke: blue;" /> 
    </defs> 
    <g> 
     <g> 
     <rect x="2" y="50" width="400" height="110" style="fill: yellow; stroke: black;"></rect> 
     </g> 
     <g> 
     <!-- show the path along which the circle will move --> 
     <use id="throw_path" visibility="hidden" xlink:href="#throw" x="50" y="130" /> 
     <circle id="ball" cx="50" cy="130" r="10" style="fill: red; stroke: black;"> 
      <animateMotion id="ball_anim" begin="anim.begin+1s" dur="6s" fill="freeze" onbegin="trckngBars();" onend="window.clearInterval(idTimer);"> 
      <mpath xlink:href="#throw" /> 
      </animateMotion> 
     </circle> 
     <rect id="inBar" x="50" y="205" width="20" height="30" style="fill: purple;stroke-linecap: butt;"> 
    <!-- <animate attributeType="XML" attributeName="width" from="0" to="200" begin="ball_anim.begin" dur="6s" fill="freeze" /> --> 
</rect> 
     </g> 
     <animateTransform id="anim" attributeType="XML" attributeName="transform" type="translate" from="0" to="200" begin="indefinite" dur="10s" fill="freeze" /> 
    </g> 
    <rect id="outBar" x="50" y="235" width="10" height="30" style="fill: orange;stroke-linecap: butt;"> 
    <!-- <animate attributeType="XML" attributeName="width" from="0" to="400" begin="anim.begin+1s" dur="10s" fill="freeze" /> --> 
</rect> 
    </svg> 
    </div> 
    </body> 
    </html> 

Если код запускается, кажется, что animVal для движущейся #ball остается на том же х coordinat (50), хотя он явно движется.

ответ

1

Событие запускается при анимации begin, end or repeat, но не (как вы хотите) всякий раз, когда происходит изменение значения анимации.

Поскольку анимации детерминированы, вы можете просто начать анимацию прямой формы так много секунд после начала анимации круга.

var cx = myCircle.cx.animVal.value; 

даст вам анимированное значение, если оно вам понадобится, при условии, что это атрибут, который вы анимируете.

Вы используете animateMotion, а не анимируете атрибуты cx и cy сами по себе. Я думаю, что единственный способ получить сообщение о положении в круге, что преобразование - вызвать getBBox.

+0

Благодарим за быстрый ответ. При поиске более элегантного решения я попытался установить интервал таймера, связанный с началом и завершением событий, поскольку это можно сделать из вашего ответа. Хотя мне удалось установить интервал и изменить бары, я обнаружил, что не могу получить текущую позицию круга myCircle.getAttribute ('cx') всегда возвращает исходную позицию. Знаете ли вы, что происходит с элементом SVG при перемещении? – user1938578

+0

Нашел то, что происходит (например) [ссылка] (http://edutechwiki.unige.ch/en/SVG/SMIL_animation_tutorial#Overview_of_SMIL_animation_markup) [чуть выше названия]. Похоже, что значения атрибута элемента в DOM не изменяются до конца анимации, и, если мое понимание верное, замораживание - это код для этого.Любые указатели от кого-либо на то, как получить доступ к текущей позиции в данный момент или определить позицию (x-) в данный момент в анимации SVG с SMIL? – user1938578

+0

Еще раз спасибо за то, что вы продолжаете улучшать ответ. Тант звучит так, как мне нужно. Я попробую немного с моим кодом. – user1938578

0

@Robert Большое спасибо за помощь. Ваш ответ был хорошим погружением в SVG и SMIL (и позволил мне добавить холод).Я не смог использовать getBBox, но проверяя спецификацию по путям ([link] http://www.w3.org/TR/SVG11/paths.html) и animateMotion (тот же сайт), он показывает, что может быть достигнуто, поскольку анимация SMIL - это детерминированный, как было предложено в вашем ответе.

Анимация имеет очень мало событийных триггеров и по дизайну, которые, похоже, так же обеспокоены базовым состоянием цели анимации, как и текущая позиция (они называются «базовыми значениями» и «значениями представления»). (Все следующие работы в javascript выполняются FF 21.) Мы можем опросить текущее время анимации, применяя getCurrentTime для объекта animateMotion. Я предполагаю, что анимация делает это с постоянной скоростью, поэтому мы определяем, насколько объект движется по пути и получает пройденную длину (так как мы можем получить общую длину всего пути с помощью метода getTotalLength).

Затем, зная длину, мы можем определить текущую позицию на пути (используя метод getPointAtLength). Обратите внимание, что возвращаемые значения, как время, так и позиция, относятся к объекту-контейнеру и, следовательно, они масштабируемы и/или требуют преобразования).

Для (простого) рабочего примера код javascript в примере кода вопроса может быть заменен следующим. Оказывается, работать с очень немногих тестов, которые я сделал:

function trckngBars(){ 
    /* Upon beginning an animation (onbegin event), the required objects are gathered 
    and an interval is set */ 
    var oBall=[document.getElementById('throw'),document.getElementById('ball_anim')]; 
    var oBar=document.getElementById('inBar'); 
    /* idTimer is set as a global variable so that it can be accessed from anywhere 
    to clear the interval*/ 
    idTimer=self.setInterval(function(){updtBars(oBall,oBar);},50); 
    } 
    function updtBars(oBall,oBar){ 
    /* This function, whose purpose is only to illustrate path method getPointLength 
    and animateMotion method getCurentTime, is quick and dirty. Note that oBall[0] is 
    the path and oBall[1] is the animate(Motion) */ 
    //Calculates the amount of time passed as a ratio to the total time of the animation 
    var t_ratio=((oBall[1].getCurrentTime()-oBall[1].getStartTime())/oBall[1].getSimpleDuration()); 
    // As mentioned, it assumes that animateMotion performs uniform motion along path 
    var l=oBall[0].getTotalLenth()*t_ratio; 
    // Gets (relative referred as user in documentation) horizontal coordinate 
    var xCoor=oBall[0].getPointAtLength(l).x; 
    oBar.setAttribute("width",xCoor); 
    } 
    function endTAnim(){ 
    /* This function can be triggered _onend_ of an animation to clear the interval 
    and leave bars with the exact last dimensions */ 
    window.clearInterval(idTimer); 
    var oBar=[document.getElementById('inBar'),document.getElementById('outBar')]; 
    oBar[0].setAttribute("width",200); //hardcoded for convenience 
    } 

Таким образом, самый простой метод, который я смог найти требуется объект анимации (для получения времени) и объекта пути («предсказать» позиция), и это не связано с перемещением фактического элемента анимацией. (Из-за первоначального вопроса несколько упрощается, чтобы не обсуждать разные системы координат при использовании составленных анимаций. Это можно было бы лучше обсудить отдельно).

Хотя я не заметил никакого запаздывания (поскольку фактический SVG является не намного сложнее), мне было бы интересно знать вычислительно более дешевые методы, поскольку я рассматривал возможность использования этого подхода для поиска и рисования сегмента расстояния между двумя анимированными объектами SMIL.

Конечно, все это зависит от предположения о равномерном движении по пути, если бы это было не так и в больших изображениях, которые можно было бы заметить и компенсировать. Я также был бы благодарен за любые указатели на это (если не считать лучшего анимация непосредственно на javascript/языке программирования, и поэтому у вас есть полный контроль). Благодарим вас за все те изменения, которые вы избежали попадания в трясину - единственное, что я знал о SVG три дня назад, это то, что это был XML.

0

Некоторое время назад я столкнулся с той же проблемой, которую вы описываете. Я хотел бы остановить анимацию наполовину, основываясь на событиях, вызванных пользователем, и сохранить элементы в их достигнутом положении. Невозможно сделать это с SMIL я решил ковать свою собственную систему анимации для svg.js, небольшая библиотека JavaScript Я работаю на:

http://documentup.com/wout/svg.js#animating-elements

Это может быть полезно для того, что вы пытаетесь достичь.