【问题标题】:animate vector element to swing like a pendulum with SVG or Canvas?使用 SVG 或 Canvas 将矢量元素设置为像钟摆一样摆动?
【发布时间】:2011-05-06 09:59:19
【问题描述】:

我想在我的网页上制作一张图片。

目前我正在使用 gif。

http://dev.thepenline.com/TEMP/Hol_10_swingingBell.gif

我想对其动画进行更多控制,哪个 js lib/framework 最能帮助我?

我应该使用画布还是 SVG? 哪个(小)库最好用?

我碰巧知道一点raphael.js 但我不确定如何完成这个效果。

【问题讨论】:

  • 你期待什么样的控制?
  • @Ninja 更流畅的动画和基于矢量。 (可扩展)

标签: animation canvas svg


【解决方案1】:

我已经用 SVG 完成了一些接近您想要实现的目标:http://live.echo-flow.com/stackoverflow/clock.svg

如果我把这个例子记下来,这里是相关代码。

clock.svg:

<?xml version="1.0"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100%" height="100%" viewBox="0 0 100 100">

<rect x="0" y="0" height="100" width="100" fill="none" stroke="blue" id="border"/>

<script type="text/ecmascript" xlink:href="clock.js"></script>

</svg>

clock.js:

var svgRoot = document.documentElement;
var svgNS = "http://www.w3.org/2000/svg";

var ident = svgRoot.createSVGMatrix();

function Pendulum(thetaZero,period,tempo,fillColor){

        //sensible default values
        thetaZero = thetaZero || 0;
        period = period || 20;
        tempo = tempo || 20;
        fillColor = fillColor || "red";

        if(fillColor == "randomize"){
                fillColor = "rgb(" + Math.random() * 254 +
                                "," + Math.random() * 254 +
                                "," + Math.random() * 254 + ")";
        }

        //construct his representation in DOM
        var g = document.createElementNS(svgNS,"g");
        g.setAttributeNS(null,"transform","translate(50,20) rotate(" + thetaZero + ")");

        var rotateTransform = g.transform.baseVal.getItem(1);

        var path = document.createElementNS(svgNS,"line");
        path.setAttributeNS(null,"x1",0);
        path.setAttributeNS(null,"y1",0);
        path.setAttributeNS(null,"x2",0);
        path.setAttributeNS(null,"y2",40);
        path.setAttributeNS(null,"stroke","black");

        var c = document.createElementNS(svgNS,"circle");
        var styleString = "fill:" +fillColor;
        //console.log(styleString);
        c.setAttributeNS(null,"cx",0);
        c.setAttributeNS(null,"cy",50);
        c.setAttributeNS(null,"r",10);
        c.setAttributeNS(null,"style",styleString);
        c.setAttributeNS(null,"stroke","black");
        c.setAttributeNS(null,"opacity",.5);
        g.appendChild(path);
        g.appendChild(c);

        svgRoot.appendChild(g);

        this.node=g;

        //timeout

        var timeStep = 10; //in milliseconds
        var timeCount = 0;
        var _animateTimeStep = function(){
                timeCount++;

                var adjustedTimeCount = timeCount/tempo;

                //compute theta
                //theta(t) = period * sin(t + thetaZero)
                var theta = period * Math.sin(adjustedTimeCount  + thetaZero);

                //set his current rotate transformation to the new theta
                rotateTransform.setMatrix(ident.rotate(theta));
        }

        var timerId = null;

        //method definitions
        this.go=function(){
                timerId = window.setInterval(_animateTimeStep,timeStep);
        };

        this.stop=function(){
                window.clearInterval(timerId);
        };
}


//Pendulum(thetaZero,period,tempo,fillColor)
var p1 = new Pendulum(-10,20,40,"red");
p1.go();

var p2 = new Pendulum(20,20,40,"yellow");
p2.go();

var p3 = new Pendulum(-20,20,40,"blue");
p3.go();

var p4 = new Pendulum(10,20,40,"purple");
p4.go();

【讨论】:

  • 谢谢,太好了,我可以在像 inkscape 这样的 SVG 编辑器中创建一些东西,然后在该对象上运行动画吗?类似于这个动画。
  • 是的,当然。该脚本仅使用 DOM 绘制一些简单的形状,然后使用 sin 函数对其进行动画处理,这是获得看起来像钟摆的动画的一种非常有效的方法。不过,您可以使用任何您喜欢的位图或矢量图像,并且技术是相同的。您只需使用 getElementById 从 DOM 中获取相关节点,而不是像我在这里所做的那样使用 DOM 创建它们。
  • 我正试图让它工作,但不知何故它的动画不正确。见dev.thepenline.com/TEMP/OurClock.svgJSdev.thepenline.com/TEMP/OurClock.js
【解决方案2】:

使用 Raphael.js,您可以这样做:

var img = paper.image("image.png", 10, 10, 80, 80);
(function swingRight(){
  img.animate({'rotation': 30}, 1000, '<>', function swingLeft(){
    img.animate({'rotation': -30}, 1000, '<>', swingRight);
  });
}());

【讨论】:

  • 谢谢,我怎么能把它当成钟摆(上面有锚?)
  • 您可以将图片的长度加倍,因此“摆动”的中心位于锚点的顶部。
  • 我不确定 100% 你的意思,请解释一下。
  • 新建一张比旧图高一倍的新图,把旧图放在新图的下半部分。然后旧图片顶部的中心将位于新图片的中心,它将使用非常简单的 Raphael.js 脚本“摆动”(旋转)。
【解决方案3】:

使用画布

window.onload    = function() {
  var canvas   = document.getElementById('canvas');
  var ctx      = canvas.getContext('2d');
  var width    = canvas.width = 500;
  var height   = canvas.height  = 300;
  var fixedx   = width/2;
  var fixedy   = 20;
  var radius   = 150;
  var dir      = 2;
  var minangle = 45;
  var maxangle = 135;
  var color = rgb();  
  var x = minangle;
  (draw = function() {
    var posx = fixedx + radius * Math.cos(x * Math.PI / 180);
    var posy = fixedy + radius * Math.sin(x * Math.PI / 180);

    with(ctx) {
      fillStyle   = '#000';
      fillRect(0, 0, width, height);
      fill();
      beginPath();
      strokeStyle = '#fff';
      moveTo(fixedx, fixedy);
      lineWidth   = 5;
      lineCap     = 'round';
      lineTo(posx, posy);  
      stroke();
      closePath();
      beginPath();  
      fillStyle   = color;
      arc(posx, posy, 20, 0, Math.PI * 2, 0);
      fill();
      closePath();
    }  
    x += 1 * dir;
    if(x >= maxangle || x <= minangle) {
      dir = -dir;
      if(Math.abs(dir) == dir) {
        color = rgb();
      }  
    }
    setTimeout(draw, 1000/30);    
  })();

  function rgb() {
    var clr = 'rgb(';
    for(var i =0; i< 3; i++) {
      clr  += Math.floor(Math.random() * 255) + ',';
    }
    return clr.replace(/\,$/,')');
  }
};

Simple Demo

【讨论】:

  • 老兄,谢谢,但我怎么会有光栅图像?让它像钟摆一样摆动?
【解决方案4】:

CodePen

HTML:

<svg id="clock" viewBox="0 0 100 100" width="500" height="500"> 
  <circle id="face" cx="50" cy="50" r="45"/>  
  <g id="pendulum">
    <line id="stick" x1="50" y1="50" x2="50" y2="80"/>
    <circle id="end" cx="50" cy="85" r="5"/>  
  </g>
</svg>

JS:

var amplitude=90,startAngle=90,wtime=700,timeout=40
var animation,start,correction,running=false

var pendulum = document.getElementById("pendulum")
pendulum.setAttribute("transform", "rotate(" + startAngle + ",50,50)")

correction=2*Math.asin(startAngle/amplitude)
start=(new Date()).getTime()
movePendulum()

function movePendulum(){
    var angle
    var pi=Math.PI,sin=Math.sin,asin=Math.asin,abs=Math.abs

    var now=(new Date()).getTime()
    var time=now-start
    time=time/wtime
    time=(time-correction)/2

    var easeVal=sin(time)
    angle=-amplitude*easeVal

    var pendulum = document.getElementById("pendulum")
    pendulum.setAttribute("transform", "rotate(" + angle + ",50,50)")
    animation=setTimeout(movePendulum,timeout)
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-05-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-05
    • 1970-01-01
    相关资源
    最近更新 更多