Javascript + svg,在两个给定点之间绘制正弦(波)线

时间:2016-07-27 08:22:10

标签: javascript svg sine

我正在尝试用svg编写一个javascript加载器。想法是在两侧均匀地从下到上填充圆圈,装载机的顶线是从左到右连续移动的正弦波。

我能够根据这样的百分比为装载程序创建一个弧:

    var d_arc = function(x, y, r, sa, ea) { // calculate arc path from given parameters
        var start = pfa(x, y, r, ea),
            end = pfa(x, y, r, sa),
            sw = ea - sa <= 180 ? '0' : '1';

        return '<path d="M ' + start.x + ' ' + start.y + ' A ' + r + ' ' + r + ' 0 ' + sw + ' 0 ' + end.x + ' ' + end.y + '" class="path-progress"></path>';
    };

如果您将100%负载作为参数传递,则上面的代码实际上是创建“U”形弧,该弧变为整圆。现在的问题是顶线需要是一个动画波。我尝试用二次贝塞尔曲线做到这一点,但我在计算里面的点时遇到了问题。我只知道start(x,y)和end(x,y)点,不知道如何计算其他点。

第二种方法是这个脚本:

https://jsfiddle.net/assa0r70/7/

但它对我不起作用,因为我无法指定起点和终点,而且正弦线总是在错误的位置绘制。

最终目标是用一些颜色填充整个形状(“U”弧和关闭正弦线),因此正弦线必须从上面的代码中包含弧形路径

d="M ' + start.x + ' ' + start.y + ' A ' + r + ' ' + r + ' 0 ' + sw + ' 0 ' + end.x + ' ' + end.y + ' //sine line continue here

这是一个完整的方法代码(不工作,只是想法):

https://jsfiddle.net/9hnuzp1d/11/

有没有人知道如何创建从A点到B点的正弦线,这可以像本例https://jsfiddle.net/assa0r70/7/一样动画? ;)

1 个答案:

答案 0 :(得分:2)

此示例为通过正弦波的参数方程构建的折线设置动画。它还使用了Paul Lebeau关于面具圈的建议。它将根据百分比选择向上/向下移动。

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title>Animate Sine Wave</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
</head>
<body onload=animateSineWave() style='font-family:arial'>
<center>
<div style='width:90%;background-color:gainsboro;text-align:justify;padding:10px;border-radius:6px;'>
Animate a sine wave, using parametric equation to build a polyline. Move it up/down circle via Percentage selection.
</div>

<div id="svgDiv" style='background-color:lightgreen;width:400px;height:400px;'>
<svg id="mySVG" width="400" height="400">
    <defs>
        <mask id="circle">
            <circle cx="200" cy="200" r="200" fill="white"/>
        </mask>
    </defs>
     <polyline id=sineWave stroke=blue stroke-width=3  fill="#ccc" stroke="red" mask="url(#circle)" />
    <circle cx="200" cy="200" r="200" fill="none" stroke="red"/>
</svg>
</div>
Percentage:<select id=percentSelect>
<option value=.1 >10%</option>
<option value=.3 >30%</option>
<option value=.5 >50%</option>
<option selected value=.8 >80%</option>
</select>

</center>

<script>
function buildSineWave(amplitude)
{
    //---mask fill bottom of circle
    var startPoint=[0,400]
    var endPoint=[400,400]

    var originX=0
    var percent=parseFloat(percentSelect.options[percentSelect.selectedIndex].value)
    var originY=400*(1-percent)

    var width=400
    var pointSpacing=1
    var angularFrequency=.02
    var phaseAngle=90

    var origin = { //origin of axes
    x: originX,
    y: originY
    }

    var points=[]
    points.push(startPoint)
    var x,y
    for (var i = 0; i < width/pointSpacing; i++)
    {
        x= i * pointSpacing + origin.x
        y= Math.sin(angularFrequency*(i + phaseAngle)) * amplitude + origin.y
        points.push([x,y])
    }
    points.push(endPoint)
    sineWave.setAttribute("points",points.join(" "))
}

function animateSineWave()
{
    var range=60 //--amplitude +/- ---
    var FPS=120  //---frames per second---
    var duration=2000 //---ms, 2 seconds---
    //----core animation function---
		new AnimateJS(
		{
			delay: 1000/FPS,
			duration: duration,
			delta: linear,
			output: function(delta)
			{
                if(delta<=.5)
                var amplitude=range*delta
                else
                var amplitude=60-range*delta

                buildSineWave(amplitude)
                if(progress==1)//---run again---
                    animateSineWave()
			}
		})

}
/*---generalized animate core function
 Inspired by: Ilya Kantor - http://javascript.info/tutorial/animation
*/
var linear=function linear(p){return p}//---linear---
//----Animate Object---
var AnimateJS=function(options){
    this.options=options
	var start = new Date
	var iT = setInterval(
	function(){
		var timePassed = new Date - start
		var progress = timePassed / options.duration
		if (progress > 1) progress = 1
		this.progress=progress
		var delta = options.delta(progress)
		options.output(delta)
		if (progress == 1)clearInterval(iT);
	},options.delay)
}


</script>

</script>
</body>
</html>