canvas礼花小程序

作者: 刘满 分类: JavaScript 发布时间: 2018-12-02 19:06
<!DOCTYPE html>
<html>
<head>
    <title></title>
</head>
<body style="  background-color: #000;">
<canvas id="canvas"></canvas>

<script>
window.requestAnimFrame = ( function() {
    return window.requestAnimationFrame ||
                window.webkitRequestAnimationFrame ||
                window.mozRequestAnimationFrame ||
                function( callback ) {
                    window.setTimeout( callback, 1000 / 60 );
                };
})();
var canvas = document.getElementById( 'canvas' ),
        ctx = canvas.getContext( '2d' ),
        cw = window.innerWidth,
        ch = window.innerHeight,
        fireworks = [],
        particles = [],
        hue = 120,
        limiterTotal = 5,
        limiterTick = 0,
        timerTotal = 80,
        timerTick = 0,
        mousedown = false,
        mx,
        my;
        
canvas.width = cw;
canvas.height = ch;  

function random( min, max ) {
    return Math.random() * ( max - min ) + min;
}

function calculateDistance( p1x, p1y, p2x, p2y ) {
    var xDistance = p1x - p2x,
            yDistance = p1y - p2y;
    return Math.sqrt( Math.pow( xDistance, 2 ) + Math.pow( yDistance, 2 ) );
}

function Firework( sx, sy, tx, ty ) {
    
    this.x = sx;
    this.y = sy;
    
    this.sx = sx;
    this.sy = sy;
    
    this.tx = tx;
    this.ty = ty;
    
    this.distanceToTarget = calculateDistance( sx, sy, tx, ty );
    this.distanceTraveled = 0;
    
    this.coordinates = [];
    this.coordinateCount = 3;
    
    while( this.coordinateCount-- ) {
        this.coordinates.push( [ this.x, this.y ] );
    }
    this.angle = Math.atan2( ty - sy, tx - sx );
    this.speed = 2;
    this.acceleration = 1.05;
    this.brightness = random( 50, 70 );
    
    this.targetRadius = 1;
}


Firework.prototype.update = function( index ) {
    
    this.coordinates.pop();
    
    this.coordinates.unshift( [ this.x, this.y ] );
    
    if( this.targetRadius < 8 ) {
        this.targetRadius += 0.3;
    } else {
        this.targetRadius = 1;
    }
    
    this.speed *= this.acceleration;
    
    var vx = Math.cos( this.angle ) * this.speed,
            vy = Math.sin( this.angle ) * this.speed;
    
    this.distanceTraveled = calculateDistance( this.sx, this.sy, this.x + vx, this.y + vy );
    
    if( this.distanceTraveled >= this.distanceToTarget ) {
        createParticles( this.tx, this.ty );
        fireworks.splice( index, 1 );
    } else {
        this.x += vx;
        this.y += vy;
    }
}

Firework.prototype.draw = function() {
    ctx.beginPath();
    ctx.moveTo( this.coordinates[ this.coordinates.length - 1][ 0 ], this.coordinates[ this.coordinates.length - 1][ 1 ] );
    ctx.lineTo( this.x, this.y );
    ctx.strokeStyle = 'hsl(' + hue + ', 100%, ' + this.brightness + '%)';
    ctx.stroke();
    
    ctx.beginPath();
    ctx.arc( this.tx, this.ty, this.targetRadius, 0, Math.PI * 2 );
    ctx.stroke();
}

function Particle( x, y ) {
    this.x = x;
    this.y = y;
    
    this.coordinates = [];
    this.coordinateCount = 5;
    while( this.coordinateCount-- ) {
        this.coordinates.push( [ this.x, this.y ] );
    }
    
    this.angle = random( 0, Math.PI * 2 );
    this.speed = random( 1, 10 );
    
    this.friction = 0.95;
    this.gravity = 1;
    
    this.hue = random( hue - 20, hue + 20 );
    this.brightness = random( 50, 80 );
    this.alpha = 1;
    this.decay = random( 0.015, 0.03 );
    //this.decay = 0;
}

Particle.prototype.update = function( index ) {
    
    this.coordinates.pop();
    this.coordinates.unshift( [ this.x, this.y ] );
    this.speed *= this.friction;
    this.x += Math.cos( this.angle ) * this.speed;
    this.y += Math.sin( this.angle ) * this.speed + this.gravity;
    this.alpha -= this.decay;
    
    if( this.alpha <= this.decay ) {
        particles.splice( index, 1 );
    }
}

Particle.prototype.draw = function() {
    ctx. beginPath();
    ctx.moveTo( this.coordinates[ this.coordinates.length - 1 ][ 0 ], this.coordinates[ this.coordinates.length - 1 ][ 1 ] );
    ctx.lineTo( this.x, this.y );
    ctx.strokeStyle = 'hsla(' + this.hue + ', 100%, ' + this.brightness + '%, ' + this.alpha + ')';
    ctx.stroke();
}

function createParticles( x, y ) {
    var particleCount = 30;
    while( particleCount-- ) {
        particles.push( new Particle( x, y ) );
    }
}


function loop() {
    requestAnimFrame( loop );
    
    hue += 0.5;
    
    ctx.globalCompositeOperation = 'destination-out';
    ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
    ctx.fillRect( 0, 0, cw, ch );
    ctx.globalCompositeOperation = 'lighter';
    
    var i = fireworks.length;
    while( i-- ) {
        fireworks[ i ].draw();
        fireworks[ i ].update( i );
    }
    
    var i = particles.length;
    while( i-- ) {
        particles[ i ].draw();
        particles[ i ].update( i );
    }
    
    if( timerTick >= timerTotal ) {
        if( !mousedown ) {
            fireworks.push( new Firework( cw / 2, ch, random( 0, cw ), random( 0, ch / 2 ) ) );
            timerTick = 0;
        }
    } else {
        timerTick++;
    }
    
    if( limiterTick >= limiterTotal ) {
        if( mousedown ) {
            fireworks.push( new Firework( cw / 2, ch, mx, my ) );
            limiterTick = 0;
        }
    } else {
        limiterTick++;
    }
}

canvas.addEventListener( 'mousemove', function( e ) {
    mx = e.pageX - canvas.offsetLeft;
    my = e.pageY - canvas.offsetTop;
});

canvas.addEventListener( 'mousedown', function( e ) {
    e.preventDefault();
    mousedown = true;
});

canvas.addEventListener( 'mouseup', function( e ) {
    e.preventDefault();
    mousedown = false;
});

window.onload = loop;
</script>
</body>
</html>

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据