2011-04-12 42 views
3

我在Inkscape中製作了一個徽標。爲了學習,我想通過SVG中的動畫支持來旋轉徽標中的輪子形狀。計算轉換矩陣應用後的路徑中心

這很容易實現旋轉,但我很難能夠指定正確的旋轉軸。這個形狀是一個齒輪,我想讓它圍繞它的中心旋轉。試錯法給出了xy座標(47.1275,1004.17)(其組件奇怪地是不對稱的,但我想這與Inkscape適用的轉換矩陣有關)是一個很好的近似值(請參見下面的animateTransform標籤),但是我將如何從第一原則得到那個?

<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 321.281 150.799" xmlns:dc="http://purl.org/dc/elements/1.1/"> 
    <g transform="translate(-9.9178912,-891.57237)"> 
     <g transform="matrix(1.9522781,0,0,1.9522781,4.6434311,-1008.1558)"> 
      <animateTransform attributeType="xml" attributeName="transform" type="rotate" from="0 47.1275 1004.17" to="45 47.1275 1004.17" dur="2s" fill="freeze" additive="sum" repeatCount="indefinite" /> 
      <g transform="matrix(0.65043772,0,0,0.65043772,-143.67477,980.4256)" stroke="#666" stroke-miterlimit="4" stroke-dasharray="none" stroke-width="7.68713093" fill="none"> 
       <path stroke-linejoin="miter" d="m293.404-3.51576c-2.73916,0-5.41514,0.287192-8,0.8125v6.1875c-3.47484,0.838872-6.7198,2.18462-9.6875,4l-4.375-4.375c-2.24264,1.48612-4.29226,3.22977-6.1875,5.125s-3.63888,3.94486-5.125,6.1875l4.375,4.375c-1.81538,2.9677-3.16112,6.21265-4,9.6875h-6.1875c-0.5253,2.58486-0.8125,5.26083-0.8125,8s0.2872,5.41515,0.8125,8h6.1875c0.83888,3.47485,2.18462,6.7198,4,9.6875l-4.375,4.375c1.48612,2.24264,3.22976,4.29227,5.125,6.1875s3.94486,3.63888,6.1875,5.125l4.375-4.375c2.9677,1.81538,6.21266,3.16113,9.6875,4v6.1875c2.58486,0.525308,5.26082,0.8125,8,0.8125,2.73916,0,5.41514-0.287192,8-0.8125v-6.1875c3.47484-0.838872,6.7198-2.18462,9.6875-4l4.375,4.375c2.24264-1.48612,4.29226-3.22977,6.1875-5.125s3.63888-3.94486,5.125-6.1875l-4.375-4.375c1.81538-2.9677,3.16112-6.21266,4-9.6875h6.1875c0.5253-2.58485,0.8125-5.26083,0.8125-8s-0.2872-5.41515-0.8125-8h-6.1875c-0.83888-3.47485-2.18462-6.7198-4-9.6875l4.375-4.375c-1.48612-2.24264-3.22976-4.29227-5.125-6.1875s-3.94486-3.63888-6.1875-5.125l-4.375,4.375c-2.9677-1.81538-6.21266-3.16113-9.6875-4v-6.1875c-2.58486-0.525308-5.26084-0.8125-8-0.8125z" stroke-dashoffset="162" stroke="#666" stroke-linecap="butt" stroke-miterlimit="4" stroke-dasharray="none" stroke-width="7.68713093" fill="none"/> 
      </g> 
     </g> 
    </g> 
</svg> 

從我在規範讀過我想說應用的變換矩陣

1.9522781 0    4.6434311 
0   1.9522781 -1008.1558 
0   0    1 

0.65043772 0   -143.67477 
0   0.65043772 980.4256 
0   0    1 

他們是應用在XYZ座標後(-9.9178912,-891.57237,0)翻譯轉換?

我想上面的正確分析會讓我看到描述的路徑的左上角點,或者可能是第一個句柄的座標。在那之後,是否必須解析路徑來決定邊界框,從而決定路徑的中心(因爲它涉及一個有點圓形的對象)?

這是不是所有的教訓,不要試圖手動對自由創建的形狀做動畫?

+0

如果您將Inkscape設置爲將轉換應用於路徑值,它可能會看起來更清晰一些。嘗試'Inkscape Prefs>轉換>存儲轉換:優化'。 – 2011-04-12 13:08:17

回答

6

我認爲這個轉換將會從最內層向外應用,所以transform="translate(-9.9178912,-891.57237)"將會最後完成。但是你可以忽略其他的轉換,如果你把你的動畫在最裏面的區域,即路徑本身:

<g transform1> 
    <g transform2> 
     <g transform3> 
     <path d="coordinates"> 
      <animateTransform your transformation here> 
     </path> 
     </g> 
    </g> 
    </g> 

然後你只需要找到自己的道路,這是很容易在Inkscape中做的中心,但很難做到即時(相關問題在這裏:programmatically How to get shape width in SVG document using java)。

就個人而言,我會在svg中使用一個腳本,以便您可以使用getBBox來查找您的形狀的邊界框。如果您添加以下元素到您的SVG,你可以做任何元素用id =「COG」圍繞其中心依次是:

<script type="text/ecmascript"><![CDATA[ 
    var svgNS = "http://www.w3.org/2000/svg"; 

    function init(evt) 
    { 
    if (window.svgDocument == null) 
    { 
     svgDocument = evt.target.ownerDocument; 
    } 
    addRotateTransform('cog'); 
    } 

    function addRotateTransform(target_id) 
    { 
    var element_to_rotate = svgDocument.getElementById(target_id); 
    var my_transform = svgDocument.createElementNS(svgNS, "animateTransform"); 

    var bb = element_to_rotate.getBBox(); 
    var cx = bb.x + bb.width/2; 
    var cy = bb.y + bb.height/2; 

    my_transform.setAttributeNS(null, "attributeName", "transform"); 
    my_transform.setAttributeNS(null, "attributeType", "XML"); 
    my_transform.setAttributeNS(null, "type", "rotate"); 
    my_transform.setAttributeNS(null, "dur", "4s"); 
    my_transform.setAttributeNS(null, "repeatCount", "indefinite"); 
    my_transform.setAttributeNS(null, "from", "0 "+cx+" "+cy); 
    my_transform.setAttributeNS(null, "to", "360 "+cx+" "+cy); 

    element_to_rotate.appendChild(my_transform); 
    my_transform.beginElement(); 
    } 
]]></script> 

您還需要添加的onload =「的init(EVT)」作爲一個屬性SVG標籤。例如

<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" 
    xmlns="http://www.w3.org/2000/svg" 
    version="1.1" 
    xmlns:cc="http://creativecommons.org/ns#" 
    xmlns:xlink="http://www.w3.org/1999/xlink" 
    viewBox="0 0 321.281 150.799" 
    xmlns:dc="http://purl.org/dc/elements/1.1/" 
    onload="init(evt)"> 

這將在第一次加載SVG時調用init()函數。 init()函數調用addRotateTransform()來查找具有給定id的元素。然後它使用getBBox()找到該對象的中心,並在相關中心中添加animateTransform方法。您可以更改確定完整旋轉速度的dur屬性。

它看起來像很多代碼,但我認爲這是確定路徑中心的最簡單方法。這也意味着可以通過將init()函數添加addRotateTransform('whatever-id');來輕鬆添加其他旋轉元素。

+0

謝謝,我喜歡這個問題的處理方式。它涉及到我沒有經驗的SVG的元素,但這是完美的,因爲我這樣做是爲了學習:-)這是一個業餘時間項目,此時空閒時間稀少,所以我不會將它實現爲一會兒。如果我在嘗試這種方法後發現需要添加的問題/答案,我會回到這裏。 – 2011-06-18 08:56:49

+1

我意識到它可能看起來像一個過於複雜的方式來獲得元素的中心,但我不知道更簡單的方法。我真的建議您在有空的時候試用EMCAScript。它允許您在SVG中執行任意複雜的動畫。 – 2011-06-18 09:47:53

+2

我創建了一些轉動裝置的示例:http://www.petercollingridge.co.uk/sites/files/peter/4gears.svg – 2011-06-18 14:26:46