简体   繁体   English

如何为HTML5 canvas中的上下文填充不透明度动画?

[英]How to animate fill opacity of a context in HTML5 canvas?

How can I animate fill opacity of a context (or add a fade-in effect) in HTML canvas? 我怎样才能动画fill上下文的不透明性(或添加淡入效果)的HTML画布?

For example at following example the ctx.fillStyle fill opacity is set to 0 and how can I animate it to 1 ? 例如,在下面的示例中, ctx.fillStyle填充不透明度设置为0 ,我如何将其设置为1动画?

 var c = document.getElementById("myCanvas"); var ctx = c.getContext("2d"); ctx.beginPath(); ctx.fillStyle = 'rgba(255, 165, 0, 0)'; ctx.rect(20, 20, 150, 100); ctx.fill(); 
 <canvas id="myCanvas" width="300" height="300" style="border:1px solid #d3d3d3;"> Your browser does not support the HTML5 canvas tag. </canvas> 

You can achieve this using window.requestAnimationFrame : 您可以使用window.requestAnimationFrame来实现:

 var /* Save the canvas' context. */ ctx = document.getElementById("myCanvas").getContext("2d"), /* The starting opacity. */ opacity = 0, /* The duration of the animation in milliseconds. */ duration = 500, /* Cache the starting time in milliseconds since page load. */ past = performance.now(); /* The animation function. */ function animate(present) { /* Find the difference between the previous and current times. */ var step = present - past; /* Set the present time to past. */ past = present; /* Increment the opacity by a linear step. */ opacity += step / duration; /* Create the shape. */ ctx.beginPath(); ctx.fillStyle = "rgba(255, 165, 0, " + opacity + ")"; ctx.clearRect(20, 20, 150, 100); ctx.rect(20, 20, 150, 100); ctx.fill(); /* Continue the animation until the opacity is 1. */ if (opacity < 1) window.requestAnimationFrame(animate); } /* Start the animation. */ window.requestAnimationFrame(animate); 
 <canvas id="myCanvas" width="300" height="300" style="border:1px solid #d3d3d3;"> Your browser does not support the HTML5 canvas tag. </canvas> 


Notes: 笔记:

  1. You can adjust the speed of the animation by changing the duration to what suits you best. 您可以通过将持续时间更改为最适合自己的时间来调整动画的速度。 The value is in milliseconds. 该值以毫秒为单位。

  2. On each call of animate , we use clearRect to clear the canvas, to avoid creating one shape on top of another, so that the opacity is incremented as expected. 每次调用animate ,我们都使用clearRect清除画布,以避免在另一个形状上创建一个形状,从而使不透明度按预期增加。

  3. Different browsers handle requestAnimationFrame differently, so to achieve a consistent, cross-browser result you must use a polyfill that accounts for the differences between browsers. 不同的浏览器对requestAnimationFrame处理方式不同,因此,要获得一致的跨浏览器结果,您必须使用考虑到浏览器之间差异的polyfill。 I have provided one below. 我在下面提供了一个。

  4. Another way to proceed with the animation would be through the use of setInterval , but I believe this is a thing of the past. 进行动画处理的另一种方法是使用setInterval ,但是我相信这已经成为过去。 See this article for more. 有关更多信息,请参见本文


Polyfill: Polyfill:

(This polyfill is a modified version of this one , created by Paul Irish) (这是填充工具的改良版这一个 ,由保罗·爱尔兰创建)

;(function (prefices, lastTime) {       
    /* Iterate over every browser-engine-specific prefix. */
    for (var i = 0; i < prefices.length && !window.requestAnimationFrame; i++) {
        /* Normalise requestAnimationFrame and cancelAnimationFrame. */
        window.requestAnimationFrame = window[prefices[i] + "RequestAnimationFrame"];
        window.cancelAnimationFrame =
            window[prefices[i] + "CancelAnimationFrame"] ||
            window[prefices[i] + "CancelRequestAnimationFrame"];
    }

    /* If requestAnimationFrame is not defined use a custom function. */
    window.requestAnimationFrame = window.requestAnimationFrame
        || function (callback, element) {
        var
            /* Save the present time and the time between it and the last time. */
            now = Date.now() || new Date().getTime(),
            timeToCall = Math.max(0, 16 - (now - lastTime)),

            /* Save the id of the timeout. */
            id = window.setTimeout(function () {
                /* Call the callback function passing the time passed & the element. */
                callback(now + timeToCall, element);
            }, timeToCall);

        /* Update the last time with the present time plus the time in between. */
        lastTime = now + timeToCall;

        /* Return the id of the timeout. */
        return id;
    };

    /* If cancelAnimationFrame is not defined set it to clear the timeout. */
    window.cancelAnimationFrame = window.cancelAnimationFrame || function (id) {
        clearTimeout(id);
    }
})(["webkit", "moz", "ms", "o"], 0);

You can't "animate" like you would with CSS. 您不能像使用CSS那样“动画”。 With a canvas, you're drawing the primative, so you'll have to do the math and timing yourself. 使用画布,您正在绘制图元,因此您必须自己进行数学计算和计时。

Here is a simple linear progression from one value to another. 这是从一个值到另一个值的简单线性级数。

 var c = document.getElementById("myCanvas"); var ctx = c.getContext("2d"); const duration = 1000; // ms const step = 10; // ms let opacity = 0; function draw() { if (opacity == 1) return; opacity += (step / duration); ctx.clearRect(20, 20, 150, 100); ctx.beginPath(); ctx.fillStyle = `rgba(255, 165, 0, ${opacity})`; ctx.rect(20, 20, 150, 100); ctx.fill(); setTimeout(draw, step); } draw(); 
 <canvas id="myCanvas" width="300" height="300" style="border:1px solid #d3d3d3;"> Your browser does not support the HTML5 canvas tag.</canvas> 

Basically, you keep track of the current opacity, how long you want it to go, and how frequently you want it to trigger. 基本上,您会跟踪当前的不透明度,希望它持续多长时间以及触发它的频率。 Then, you increase your opacity by the percent of your step to your duration and redraw. 然后,将不透明度增加您的step duration的百分比,然后重新绘制。

Also, since you are dealing with opacity, you have to remember to clear it each step as well, or it'll get dark really fast. 另外,由于您要处理不透明性,因此必须记住也要清除每个步骤,否则它很快就会变黑。

You could also use window.requestAnimationFrame , but then (if you want to control the speed), you'll need to track time instead of step: 您还可以使用window.requestAnimationFrame ,但是(如果您想控制速度),则需要跟踪时间而不是步骤:

 var c = document.getElementById("myCanvas"); var ctx = c.getContext("2d"); const duration = 1000; // ms let lastTime = performance.now(); let opacity = 0; function draw(now) { if (opacity >= 1) return; opacity += ((now - lastTime) / duration); lastTime = now; ctx.clearRect(20, 20, 150, 100); ctx.beginPath(); ctx.fillStyle = `rgba(255, 165, 0, ${opacity})`; ctx.rect(20, 20, 150, 100); ctx.fill(); window.requestAnimationFrame(draw); } draw(lastTime); 
 <canvas id="myCanvas" width="300" height="300" style="border:1px solid #d3d3d3;"> Your browser does not support the HTML5 canvas tag.</canvas> 

Notice now instead of opacity += step / duration , we're using the number of milliseconds since our last update opacity += (now - lastTime) / duration . 现在注意,而不是opacity += step / duration ,我们使用的是自上次更新opacity += (now - lastTime) / duration以来的毫秒数。

If you want to do different transitions (like step-in-out), you would need to tweak the amount of opacity increase as a factor of time. 如果要进行不同的过渡(例如,移出),则需要调整不透明度的增加量作为时间的因素。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM