我一直使用JavaScript library制作动画天气符号。我现在正在做the cloud symbol的SVG版本,并且想知道哪种方法可能是最好的。
所以我创建了云的跟踪/路径,静态(jsFiddle)和basic rotation isn't the right effect,因为原始云(in the js canvas animation)基本上有5条曲线,它们在扩展和收缩时转动。
我想到的可能方法:
制作5个圆圈,使用短划线显示所需的圆弧,然后制作动画&扩大/收缩圈子
制作5 sub-paths并以某种方式制作扩展动画并签约合同
使用5个animateMotion动画
这有更好的逻辑吗?任何关于如何认为这种逻辑都很棒的指针。
与上面的jsFiddle相同的例子,使用SE应用程序:
error: unable to create file externals/Telerik.Web.UI.xml (Permission denied)
fatal: Could not reset index file to revision 'HEAD'.
var skycons = new Skycons({
"color": "black"
});
var canvas = document.querySelectorAll('canvas');
[].forEach.call(canvas, function (el) {
skycons.add(el, el.dataset.icon);
});
skycons.play();
答案 0 :(得分:1)
我没有足够的声誉回复@Kaiido,但我尝试按照描述转换路径,但它没有提供所需的结果。遗憾。
http://codepen.io/Stuey192/pen/dYwPJr
<path id="XMLID_21_" class="lineDetail" d="M75.2,29.6c0,0,15.1,26.2-17,31.5" />
<animate xlink:href="#XMLID_21_" attributeName="d" attributeType="XML" from="M75.2,29.6c0,0,15.1,26.2-17,31.5" to="M58.2,61.1c0,0-11.7,10.8-25.2-0.2" dur="10s" fill="freeze" repeatCount="indefinite" />
<path id="XMLID_22_" class="lineDetail" d="M58.2,61.1c0,0-11.7,10.8-25.2-0.2"/>
<animate xlink:href="#XMLID_22_" attributeName="d" attributeType="XML" from="M58.2,61.1c0,0-11.7,10.8-25.2-0.2" to="M33,60.9C21.8,62,5,49.7,15.4,29.4" dur="10s" fill="freeze" repeatCount="indefinite" />
<path id="XMLID_23_" class="lineDetail" d="M33,60.9C21.8,62,5,49.7,15.4,29.4"/>
<animate xlink:href="#XMLID_23_" attributeName="d" attributeType="XML" from="M33,60.9C21.8,62,5,49.7,15.4,29.4" to="M15.4,29.6c0,0,4-26.3,30.2-17.8" dur="10s" fill="freeze" repeatCount="indefinite" />
<path id="XMLID_24_" class="lineDetail" d="M15.4,29.6c0,0,4-26.3,30.2-17.8"/>
<animate xlink:href="#XMLID_24_" attributeName="d" attributeType="XML" from="M15.4,29.6c0,0,4-26.3,30.2-17.8" to="M45.6,11.9c0,0,23.5-8,29.6,17.7" dur="10s" fill="freeze" repeatCount="indefinite" />
答案 1 :(得分:1)
我被您提供的svg代码误导了:
我首先想到你的画布代码正在绘制一个Path2d,使用moveTo
,arcTo
或quadraticCurveTo
方法,这些方法很容易调整,以便与你的svg路径进行交互d
属性,因为canvas的path命令几乎与SVG的命令相同。
但是,我猜你通过像InkScape或Illustrator这样的软件将位图转换为矢量来获得当前的svg代码。
实际上,Skycons代码所做的是它绘制5个圆,同时预先形成复合运算,因此只有非重叠笔划可见。
在这里,我修改了代码,使其显而易见:
(function(global) {
"use strict";
var requestInterval = function(fn, delay) {
var handle = {value: null};
function loop() {
handle.value = requestAnimationFrame(loop);
fn();
}
loop();
return handle;
},
cancelInterval = function(handle) {
cancelAnimationFrame(handle.value);
};
var KEYFRAME = 500,
STROKE = 0.08,
TAU = 2.0 * Math.PI,
TWO_OVER_SQRT_2 = 2.0 / Math.sqrt(2);
function circle(ctx, x, y, r) {
ctx.beginPath();
ctx.arc(x, y, r, 0, TAU, false);
ctx.stroke();
}
function puff(ctx, t, cx, cy, rx, ry, rmin, rmax) {
var c = Math.cos(t * TAU),
s = Math.sin(t * TAU);
rmax -= rmin;
circle(
ctx,
cx - s * rx,
cy + c * ry + rmax * 0.5,
rmin + (1 - c * 0.5) * rmax
);
}
function puffs(ctx, t, cx, cy, rx, ry, rmin, rmax) {
var i;
for(i = 5; i--; )
puff(ctx, t + i / 5, cx, cy, rx, ry, rmin, rmax);
}
function cloud(ctx, t, cx, cy, cw, s, color) {
t /= 30000;
var a = cw * 0.21,
b = cw * 0.12,
c = cw * 0.24,
d = cw * 0.28;
puffs(ctx, t, cx, cy, a, b, c, d);
puffs(ctx, t, cx, cy, a, b, c - s, d - s);
}
var Skycons = function(opts) {
this.list = [];
this.interval = null;
this.color = opts && opts.color ? opts.color : "black";
this.resizeClear = !!(opts && opts.resizeClear);
};
Skycons.CLOUDY = function(ctx, t, color) {
var w = ctx.canvas.width,
h = ctx.canvas.height,
s = Math.min(w, h);
cloud(ctx, t, w * 0.5, h * 0.5, s, s * STROKE, color);
};
Skycons.prototype = {
_determineDrawingFunction: function(draw) {
if(typeof draw === "string")
draw = Skycons[draw.toUpperCase().replace(/-/g, "_")] || null;
return draw;
},
add: function(el, draw) {
var obj;
if(typeof el === "string")
el = document.getElementById(el);
// Does nothing if canvas name doesn't exists
if(el === null)
return;
draw = this._determineDrawingFunction(draw);
// Does nothing if the draw function isn't actually a function
if(typeof draw !== "function")
return;
obj = {
element: el,
context: el.getContext("2d"),
drawing: draw
};
this.list.push(obj);
this.draw(obj, KEYFRAME);
},
set: function(el, draw) {
var i;
if(typeof el === "string")
el = document.getElementById(el);
for(i = this.list.length; i--; )
if(this.list[i].element === el) {
this.list[i].drawing = this._determineDrawingFunction(draw);
this.draw(this.list[i], KEYFRAME);
return;
}
this.add(el, draw);
},
remove: function(el) {
var i;
if(typeof el === "string")
el = document.getElementById(el);
for(i = this.list.length; i--; )
if(this.list[i].element === el) {
this.list.splice(i, 1);
return;
}
},
draw: function(obj, time) {
var canvas = obj.context.canvas;
if(this.resizeClear)
canvas.width = canvas.width;
else
obj.context.clearRect(0, 0, canvas.width, canvas.height);
obj.drawing(obj.context, time, this.color);
},
play: function() {
var self = this;
this.pause();
this.interval = requestInterval(function() {
var now = Date.now(),
i;
for(i = self.list.length; i--; )
self.draw(self.list[i], now);
}, 1000 / 60);
},
pause: function() {
var i;
if(this.interval) {
cancelInterval(this.interval);
this.interval = null;
}
}
};
global.Skycons = Skycons;
}(this));
var skycons = new Skycons({
"color": "black"
});
var canvas = document.querySelectorAll('canvas');
[].forEach.call(canvas, function (el) {
skycons.add(el, el.dataset.icon);
});
skycons.play();
<canvas id="fe_current_icon" data-icon="cloudy" width="160" height="160" style="width:120px; height:120px"></canvas>
要重现相同的动画,您确实必须为您的圈子创建<animationPath>
,然后分别设置keyPoints
和keyTimes
。
浏览器仍然不支持svg's compositing operations,因此您必须使用<clipPath>
并声明两次圆圈动画。
以下是一个例子:
<svg version="1.1" id="svg" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" viewBox="-30 -30 160 160" width=200 height=200>
<defs>
<style>
circle {stroke: #000; stroke-width: 7px; fill: white;}
</style>
<path id="mainmotion" d="M15.5-3.9c13.2,0,23.9,7.4,23.9,16.5S28.7,29.2,15.5,29.2S-8.4,21.8-8.4,12.7S2.3-3.9,15.5-3.9"/>
<g id="g">
<circle id="c1" cx="37.7" cy="32.3" r="27.5">
<animateMotion dur="6s" repeatCount="indefinite" calcMode="linear" keyPoints="0; 0.2; 0.4; 0.6; 0.8; 1" keyTimes="0; 0.2; 0.4; 0.6; 0.8; 1">
<mpath xlink:href="#mainmotion" />
</animateMotion>
</circle>
<circle id="c2" cx="37.7" cy="32.3" r="27.5">
<animateMotion dur="6s" repeatCount="indefinite" calcMode="linear" keyPoints="0.2; 0.4; 0.6; 0.8; 1; 0; 0.2" keyTimes="0; 0.2; 0.4; 0.6; 0.8; 0.8; 1">
<mpath xlink:href="#mainmotion" />
</animateMotion>
</circle>
<circle id="c3" cx="37.7" cy="32.3" r="27.5">
<animateMotion dur="6s" repeatCount="indefinite" calcMode="linear" keyPoints="0.4; 0.6; 0.8; 1; 0; 0.2; 0.4" keyTimes="0; 0.2; 0.4; 0.6; 0.6; 0.8; 1">
<mpath xlink:href="#mainmotion" />
</animateMotion>
</circle>
<circle id="c4" cx="37.7" cy="32.3" r="27.5">
<animateMotion dur="6s" repeatCount="indefinite" calcMode="linear" keyPoints="0.6; 0.8; 1; 0; 0.2; 0.4; 0.6" keyTimes="0; 0.2; 0.4; 0.4; 0.6; 0.8; 1">
<mpath xlink:href="#mainmotion" />
</animateMotion>
</circle>
<circle id="c5" cx="37.7" cy="32.3" r="27.5">
<animateMotion dur="6s" repeatCount="indefinite" calcMode="linear" keyPoints="0.8; 1; 0; 0.2; 0.4; 0.6; 0.8" keyTimes="0; 0.2; 0.2; 0.4; 0.6; 0.8; 1">
<mpath xlink:href="#mainmotion" />
</animateMotion>
</circle>
</g>
<clipPath id="clip">
<use xlink:href="#c1"/>
<use xlink:href="#c2"/>
<use xlink:href="#c3"/>
<use xlink:href="#c4"/>
<use xlink:href="#c5"/>
</clipPath>
</defs>
<use xlink:href="#g"/>
<rect x=0 y=0 width=160 height=160 clip-path="url(#clip)" fill="white" />
</svg>