一段时间后淡出画布图像

时间:2017-04-18 11:46:50

标签: javascript html5 html5-canvas

我正在尝试使用html 5 canvas和javascript在图像上创建一些云型效果。我在主图像上方使用画布绘制图像,但现在我必须随机淡出图像。但是当我尝试使用普通的jquery淡出功能时它似乎不起作用,下面是我的代码。

var canvas = document.getElementById("myCanvas"),
    context = canvas.getContext("2d"),
    img = new Image();

img.src = '/images/smoke-2.png';

var v = 0;
var vt = 0;
var count = 0;

img.onload = function(){
  //console.log(Math.ceil(canvas.width/70));

  var t = Math.ceil(canvas.width/5);
  var ht = Math.ceil(canvas.height/5);
    for (var w = 0; w < t; w++) {
      vt = 0;
      for (var h = 0; h < ht; h++) {
        //console.log(vt);
        context.drawImage(img, v, vt);
        vt += 5;
        count++;
      }
      v += 5;
      //console.log(v);
    }

}

任何人都可以帮我解决一下。

小提琴链接https://jsfiddle.net/apatxedf/

2 个答案:

答案 0 :(得分:0)

您无法使用for loop。您应该使用setTimeout。请根据您的代码尝试以下代码。

var canvas = document.getElementById("myCanvas"),
context = canvas.getContext("2d"),
img = new Image();

img.src = '/images/smoke-2.png';

var v = 0;
var vt = 0;
var count = 0;

img.onload = function(){
  var t = Math.ceil(canvas.width/5);
  var ht = Math.ceil(canvas.height/5);

  var w=0, h=0;
  var timer = setTimeout(drawFunc, 1000);

  function drawFunc() {
      context.drawImage(img, v, vt);
      h++;
      vt += 5;
      count++;
      if(h==ht) {
        h=0;
        vt=0;
        w++;
        v+=5;
        if(w==t) {
          clearTimeout(timer);
        }
      }
      timer = setTimeout(drawFunc, 1000);
  }
}

答案 1 :(得分:0)

不是真正的答案,但我碰巧做了一些非常相似的事情,涉及从纯色渐变到图像,因此修改了SO和OP的图像(用火和闪电现在是浅色和鲜花)并添加了评论。

使用许多层,渐变,粒子和复合模式绘制图像和淡入fx。底层图像缓慢旋转和缩放。

&#13;
&#13;
// create canvas and context
var canvas = document.createElement("canvas");
canvas.style.position = "absolute";
canvas.style.left = canvas.style.top = "0px";
canvas.style.zIndex = 100000;
canvas.style.border = "none";
var ctx = canvas.getContext("2d");
// add to DOM
document.body.appendChild(canvas);
var currentLoopFunction;
var firstRun = true;
var timeoutHandle;
// resize canvas will restart animation
function resize() {
    canvas.width = innerWidth;
    canvas.height = innerHeight;
    ctx.setTransform(1, 0, 0, 1, 0, 0);
    // stack overflow is causing problems here so have added 
    // a timers to delay the restart
    if(!firstRun){
        clearTimeout(timeoutHandle);
        timeoutHandle = setTimeout(()=>currentLoopFunction = restart,500);
        //currentLoopFunction = restart;
    }
    firstRun = false;
}
resize();
currentLoopFunction = loadText;
const fx = {
    growRate: 1, // number of pixels per frame on average that the smoke image grows by
    smokeMove: 0.01, // rotate the smoke to make it look like its is swirling
    ringDist: 0.85, // distance from image center to stop movement of smoke outward. As a fraction of radius ofa canvas bounding circle 
    centerPull: 0.125, // pull all smoke in towards the center of canvas at start
    scaleRange: 5, // the close smoke is to center the larger it is. This sets the max center scale multiplier
    pCount: 100, // Approx number of particles to render
    flowerScaleGrow: 0.03, // slowly grow flower image to normal scale
    flowerScaleStart: 0.9, // scale of flower at start
    flowerScaleEnd: 1.3, // scale of flower towards end. Will never get to this value
    flowerRotate: 0.01, // rate to rotate flower
    flowerRotateStart: -0.6, // Startng angle of flower image
    flowerRotateEnd: 0.0, // end angle of flower image
    sCurveSlope: 1.2, // slope of s curve at origin (not real slope) must be > 1 and smaller valuesreduce the rate of change
    // this controls flower rotate and grow
    globalAlphaRate: 0.01, // controls the rate global alpha is reduced
}

function sCurve(x) {
    return (2 / (1 + Math.pow(fx.sCurveSlope, -x))) - 1;
}
var imageAspect = 1;
var imageScaleToFill = 1;
var globalAlpha = 1;
var frameCounter; // counts frames
var smoke = new Image;
var flowers = new Image;
var imageCount = 0; // count the image as they load and used to stage setup

// Two radial gradients from transparent white in center to white at edges
// first one is smaller and a softer transition
// The second one is used to cover corners if display canvas aspect ratio is extreme
var ringGrad;
var ringGrad1;


// load the images
smoke.src = "http://www.emqubeweb.com/smoke-2.png";
flowers.src = "http://www.emqubeweb.com/flower.png";
smoke.onload = flowers.onload = function() {
    imageCount += 1
};
// draws a particle
function drawImage(p) { // p is particle
    ctx.setTransform(p.scale, 0, 0, p.scale, p.x, p.y);
    ctx.rotate(p.angle);
    ctx.globalAlpha = p.alpha * globalAlpha;
    ctx.drawImage(smoke, -smoke.width / 2, -smoke.height / 2);
}

// object that controls particles.
var particles = {
    items: [], // array of particles
    update() { // updates the scale position, rotation and alpha of particle
        var i, p, cw, ch, dx, dy, dist, distMax, area, r;

        // get canvas center
        cw = canvas.width / 2;
        ch = canvas.height / 2;
        distMax = Math.sqrt(cw * cw + ch * ch) * fx.ringDist; // extend diagonal max dist from center

        // do each particle in turn
        for (i = 0; i < this.items.length; i++) {
            p = this.items[i];

            // get vector from center to particle and normalise it
            dx = p.x - cw;
            dy = p.y - ch;
            dist = Math.sqrt(dx * dx + dy * dy) + 0.001; // the 0.001 added is to stop / by zero
            dx /= dist;
            dy /= dist;

            // move outward. The futher out the slowre it moves
            p.x += (1 - dist / distMax) * dx * (p.rand * 0.25 + 0.1);
            p.y += (1 - dist / distMax) * dy * (p.rand * 0.25 + 0.1);

            // add a little movement along the tangent to the center
            p.y -= (1 - dist / distMax) * dx * (p.rand * 0.2 + 0.1);
            p.x += (1 - dist / distMax) * dy * (p.rand * 0.2 + 0.1);

            // get the particle area
            area = (smoke.width * smoke.height) * p.scale;

            // increase area and then caculate new scale for the new area
            p.scale *= Math.sqrt(area + (Math.random() + Math.random()) * fx.growRate) / Math.sqrt(area);
            p.angle += fx.smokeMove * (p.rand * 0.5 + 0.5);

            // as particles volume increase reduce the transparency
            p.alpha = p.startVol / (area * smoke.height);
        }
    },
    draw() {
        var i;;
        for (i = 0; i < this.items.length; i++) {
            drawImage(this.items[i])
        }
    }
}

// render loading screen 
function loadText() {
    ctx.font = "32px arial";
    ctx.textAlign = "center";
    ctx.fillStyle = "black";
    ctx.fillText("Loading images, please wait.", canvas.width / 2, canvas.height / 2);
    ctx.fillText("Best viewed fullpage.", canvas.width / 2, canvas.height / 2 + 36);
 
    currentLoopFunction = wait; // set the loop function to wait
}

function blackenSmoke() {

    // so the following creates a copy of the smoke image adding some grays to give extra FX
    var smoke1 = document.createElement("canvas");
    smoke1.width = smoke.width;
    smoke1.height = smoke.height;
    smoke1.ctx = smoke1.getContext("2d");

    // add black
    smoke1.ctx.fillStyle = "#d5d";
    smoke1.ctx.fillRect(0, 0, smoke.width, smoke.height);

    // mask out black with smoke
    smoke1.ctx.globalCompositeOperation = "destination-in";
    smoke1.ctx.setTransform(0.95, 0, 0, 0.95, smoke.width / 2, smoke.height / 2);
    smoke1.ctx.rotate(0.1);
    smoke1.ctx.drawImage(smoke, -smoke.width / 2, -smoke.height / 2);

    // draw smoke a little smaller and rotated
    smoke1.ctx.setTransform(0.93, 0, 0, 0.93, smoke.width / 2, smoke.height / 2);
    smoke1.ctx.rotate(-0.1);
    smoke1.ctx.globalCompositeOperation = "source-over";
    smoke1.ctx.drawImage(smoke, -smoke.width / 2, -smoke.height / 2);
    smoke1.ctx.globalCompositeOperation = "multiply";
    smoke1.ctx.drawImage(smoke1, -smoke.width / 2, -smoke.height / 2);

    // draw once more to bring up the brightness
    smoke1.ctx.globalCompositeOperation = "lighten";
    smoke1.ctx.drawImage(smoke, -smoke.width / 2, -smoke.height / 2);
    smoke1.ctx.globalCompositeOperation = "multiply";
    smoke1.ctx.drawImage(smoke1, -smoke.width / 2, -smoke.height / 2);

    // set the new smoke image.
    smoke = smoke1;
}
// create gradients
function createGradients(){
    ringGrad = ctx.createRadialGradient(0, 0, 0, 0, 0, Math.min(canvas.width, canvas.height) / 2);
    ringGrad.addColorStop(0, "rgba(255,255,255,0)");
    ringGrad.addColorStop(0.2, "rgba(255,255,255,0)");
    ringGrad.addColorStop(0.5, "rgba(255,255,255,0.2)");
    ringGrad.addColorStop(0.9, "rgba(255,255,255,0.8)");
    ringGrad.addColorStop(1, "rgba(255,255,255,1)");
    ringGrad1 = ctx.createRadialGradient(0, 0, 0, 0, 0, Math.max(canvas.width, canvas.height) * 0.25);
    ringGrad1.addColorStop(0.0, "rgba(255,255,255,0.0)");
    ringGrad1.addColorStop(0.6, "rgba(255,255,255,0.0)");
    ringGrad1.addColorStop(0.7, "rgba(255,255,255,0.2)");
    ringGrad1.addColorStop(0.8, "rgba(255,255,255,0.6)");
    ringGrad1.addColorStop(1, "rgba(255,255,255,1)");
 }

// Wait for images to load
function wait() {
    if (imageCount === 2) {
        blackenSmoke();
        start();
        window.addEventListener("resize", resize);

    }
}

function restart() {
    particles.items.length = 0;
    start();
}

function start() {
    var x, y, dx, dy, px, py, dist, scale, cw, ch;

    // get the particle width and height to match the canvas
    w = canvas.width / Math.ceil(Math.sqrt(fx.pCount));
    h = canvas.height / Math.ceil(Math.sqrt(fx.pCount));

    // set the particle scale
    scale = Math.min(w / smoke.width, h / smoke.height);

    // find the center and diagonal distance from center to top left
    cw = canvas.width / 2;
    ch = canvas.height / 2;
    distMax = Math.sqrt(cw * cw + ch * ch); // extend diagonal max dist from center    

    // add particles 
    for (y = 0; y < canvas.height; y += h) {
        for (x = 0; x < canvas.width; x += w) {
            // get particle center location plus randomise by its width and height
            px = x + (Math.random() - Math.random()) * w + w / 2;
            py = y + (Math.random() - Math.random()) * h + h / 2;

            // find he vector and distance from canvas center to particle
            dx = px - canvas.width / 2;
            dy = py - canvas.height / 2;
            dist = Math.sqrt(dx * dx + dy * dy);
            if (dist > 5) { // if to close to center particle gets stuck so just only particles at least 5 pixels from center

                // move the particle towards the center for start position
                px -= dx * fx.centerPull;
                py -= dy * fx.centerPull;

                // The closer to the center the particle is the bigger it should be.
                // dist multiplies the scale
                dist = Math.cos((dist / distMax) * Math.PI * 0.5) * fx.scaleRange;
                // add the particle. Get the volume approximating a cubic volume for the smoke
                particles.items.push({
                    x: px,
                    y: py,
                    rand: Math.random()*0.9 + 0.1, // a constant random per particle for various fx
                    alpha: 1,
                    scale: scale * dist,
                    startVol: smoke.width * smoke.height * smoke.height * scale * dist,
                    angle: Math.random() * Math.PI * 2,
                })
            }
        }
    }

    // set the image aspect
    imageAspect = flowers.height / flowers.width;
    // changed to scale to fit use min (to fill use Math.max)
    imageScaleToFill = Math.max(flowers.height / canvas.height, flowers.width / canvas.width);
    createGradients();
    frameCounter = 0;
    currentLoopFunction = fadeIn; // function to loop
}

function fadeIn() {
    // clears canvas and renders layers
    ctx.globalCompositeOperation = "source-over";
    frameCounter += 1;
    ctx.setTransform(1, 0, 0, 1, 0, 0);
    ctx.globalAlpha = 1;

    // white background layer
    ctx.fillStyle = "white";
    ctx.fillRect(0, 0, canvas.width, canvas.height);

    // Main image layer slowly rotated and scaled
    var scale = fx.flowerScaleStart + sCurve(frameCounter * fx.flowerScaleGrow) * (fx.flowerScaleEnd - fx.flowerScaleStart);
    globalAlpha = 1 - sCurve(frameCounter * fx.globalAlphaRate)
    ctx.setTransform(scale * imageScaleToFill, 0, 0, scale * imageScaleToFill, canvas.width / 2, canvas.height / 2);
    ctx.rotate(fx.flowerRotateStart + sCurve(frameCounter * fx.flowerRotate) * (fx.flowerRotateEnd - fx.flowerRotateStart));
    ctx.drawImage(flowers, -canvas.width / 2, -canvas.width * 0.5 * imageAspect, canvas.width, canvas.width * imageAspect);

    // Draw flower image again with multiply to increase the contrast
    ctx.globalCompositeOperation = "multiply";
    ctx.globalAlpha = 1 - globalAlpha;
    ctx.drawImage(flowers, -canvas.width / 2, -(canvas.width / 2) * imageAspect, canvas.width, canvas.width * imageAspect);
    ctx.globalAlpha = 1;

    // Draw the smoke particles
    ctx.globalCompositeOperation = "source-over";
    particles.update();
    particles.draw();

    // draw a white round boarder
    ctx.globalCompositeOperation = "lighten";
    ctx.setTransform(scale * scale, 0, 0, scale * scale, canvas.width / 2, canvas.height / 2);
    ctx.fillStyle = ringGrad;
    ctx.fillRect(-canvas.width, -canvas.height, canvas.width * 2, canvas.height * 2);

    //Draw smoke image over to ease the transition from white to the smokes grays
    ctx.globalCompositeOperation = "source-over";
    ctx.globalAlpha = globalAlpha;
    ctx.drawImage(smoke, -canvas.width / 2, -canvas.height / 2, canvas.width, canvas.height);

    // flat white layer ensures that at start there is only white.
    ctx.fillStyle = "white";
    ctx.fillRect(-canvas.width, -canvas.height, canvas.width * 2, canvas.height * 2);

    // Finnal outer ring gradient to clean up edges if image display aspect is extreme
    ctx.globalAlpha = 1;
    ctx.fillStyle = ringGrad1;
    ctx.fillRect(-canvas.width, -canvas.height, canvas.width * 2, canvas.height * 2);
    if (globalAlpha < 0.001) { // when global alpha is very small (well below visible)
        currentLoopFunction = restart; // restart
    }
}
// main loop calls various functions as needed
function mainLoop() {
    currentLoopFunction();
    requestAnimationFrame(mainLoop);
}
requestAnimationFrame(mainLoop);
&#13;
&#13;
&#13;