原文地址:http://jeffzhong.space/2017/10/26/solar/
  学习canvas有一段时间了,顺便写个小项目练手,该类型用到的知识点包含:

  1. ES6面向对象
  2. 中央的三角形函数
  3. canvas部分有:坐标变换,渐变,混合方式,线条和图片的绘图。

实际效果: solar
system(推荐在chrome或safari下运行)

2018正版葡京赌侠诗 1

场景

  首先建立场景类,首要用来社团管理对象,统一更新和制图对象。那里运用了ES6的类语法,构造函数建立目的列表属性planets,绘制背景方法drawBG,使用requestAnimationFrame反复实践的动画方法animate

  绘制背景使用到了向阳渐变:createRadialGradient(x1,y1,r1,x2,y2,r2);
该渐变紧要用来创立多个圆相交过渡效果,即使前后八个圆心相同(x1==x2 &&
y1==y2),则会协会同心圆样式的渐变。
那样大家就以阳光为主干的风骚调渐变到粉灰色,最终用fillRect填充整个背景。

    //场景
    class Stage {
        constructor(){
            this.planets=[];
        }
        init(ctx){
            ctx.translate(W/2,H/2);//坐标重置为中间
            this.animate(ctx);
        }
        //绘制背景
        drawBG(ctx){
            ctx.save();
            ctx.globalCompositeOperation = "source-over";
            var gradient=ctx.createRadialGradient(0,0,0,0,0,600);
            gradient.addColorStop(0,'rgba(3,12,13,0.1)');
            gradient.addColorStop(1,'rgba(0,0,0,1');
            ctx.fillStyle=gradient;
            // ctx.fillStyle='rgba(0,0,0,0.9)';
            ctx.fillRect(-W/2,-H/2,W,H);
            ctx.restore();
        }
        //执行动画
        animate(ctx){
            var that=this,
                startTime=new Date();
            (function run(){
                that.drawBG(ctx);
                that.planets.forEach(item=>{
                    item.update(startTime);
                    item.draw(ctx);
                });
                requestAnimationFrame(run);
            }());
        }
    }

星球

  然后建立星球基类,除构造函数,还有立异地方角度的措施Update,对象绘制方法draw。之后所有的星星,都会开端化该类或者接续该类建立对应星球。

  行星绕太阳做圆日运动,那个可以用三角函数根据角度和半径求出x,y,但还有更为方便的法门,那就是运用canvas提供的坐标旋转格局rotate,以360度为一个周期。

    /**
     * 星球基类
     */
    class Planet{
        /**
         * @param  {Number} x         x坐标
         * @param  {Number} y         y坐标
         * @param  {Number} r         半径
         * @param  {Number} duration  周期(秒)
         * @param  {Object} fillStyle 
         * @param  {Object} blurStyle 
         */
        constructor(x,y,r,duration,fillStyle,blurStyle){
            this.x=x;
            this.y=y;
            this.r=r;
            this.duration=duration;
            this.angle=0;
            this.fillStyle=fillStyle;
            this.blurStyle=blurStyle;
        }
        update(startTime){
            this.angle=Tween.linear(new Date()-startTime,0,Math.PI*2,this.duration*1000);
        }
        draw(ctx){
            ctx.save();
            ctx.rotate(this.angle);
            // ctx.translate(this.x,this.y);
            drawCircle(this.x,this.blurStyle.color);
            ctx.beginPath();
            // ctx.globalCompositeOperation = "lighter";
            ctx.fillStyle=this.fillStyle;
            ctx.shadowColor=this.blurStyle.color;
            ctx.shadowBlur=this.blurStyle.blur;             
            // ctx.arc(0,0,this.r,Math.PI*2,false);
            ctx.arc(this.x,this.y,this.r,0,Math.PI*2,false);
            ctx.fill();
            ctx.restore();
        }
    };

太阳

  开头创造首个目的-太阳,继承下面的星辰基类Planet,重写draw方法

    /**
     * 太阳
     */
    class Sun extends Planet{
        draw(ctx){
            ctx.save();
            ctx.beginPath();
            ctx.globalCompositeOperation = "source-over";
            ctx.fillStyle=this.fillStyle;
            ctx.shadowColor=this.blurStyle.color;
            ctx.shadowBlur=this.blurStyle.blur;             
            ctx.arc(this.x,this.y,this.r,0,Math.PI*2,false);
            ctx.fill();
            ctx.restore();  
        }
    }

土星

  金星有赏心悦目的火星环,所以也持续出一个独门的类,重写draw方法,其中蚀星环比较劳累,建立了许多颜料节点的朝向渐变。

    /**
     * 土星
     */
    class Saturn extends Planet{
        draw(ctx){
            ctx.save();
            ctx.rotate(this.angle);
            drawCircle(this.x,this.blurStyle.color);

            ctx.beginPath();
            ctx.fillStyle=this.fillStyle;           
            ctx.arc(this.x,this.y,this.r,Math.PI*2,false);
            ctx.fill();

            //土星光环
            ctx.globalCompositeOperation = "source-over";
            var gradient=ctx.createRadialGradient(this.x,this.y,0,this.x,this.y,this.r+25);
            var startStop=(this.r+3)/(this.r+24);
            gradient.addColorStop(startStop,'#282421');
            gradient.addColorStop(startStop+0.06,'#282421');
            gradient.addColorStop(startStop+0.1,'#7e7966');
            gradient.addColorStop(startStop+0.18,'#706756');
            gradient.addColorStop(startStop+0.24,'#7e7966');
            gradient.addColorStop(startStop+0.25,'#282421');
            gradient.addColorStop(startStop+0.26,'#282421');
            gradient.addColorStop(startStop+0.27,'#807766');
            gradient.addColorStop(1,'#595345');
            ctx.fillStyle=gradient;
            ctx.beginPath();
            ctx.arc(this.x,this.y,this.r+24,0,Math.PI*2,true);
            ctx.arc(this.x,this.y,this.r+3,0,Math.PI*2,false);
            ctx.fill();
            ctx.restore();  
        }
    }

树立星球

  接着开头开始化星球对象,包含太阳和八大行星,然后所有的星星颜色都利用了通往渐变,那样越发的赏心悦目。那里给出太阳,金星,水星的例子,其余的行星如此类推。

    // 初始化场景类
    var stage=new Stage();

    // sun
    var sunStyle=ctx.createRadialGradient(0,0,0,0,0,60);
    sunStyle.addColorStop(0,'white');
    sunStyle.addColorStop(0.5,'white');
    sunStyle.addColorStop(0.8,'#ffca1e');
    sunStyle.addColorStop(1,'#b4421d');
    var sun=new Sun(0,0,60,0,sunStyle,{color:'#b4421d',blur:300});
    stage.planets.push(sun);

    // mercury
    var mercuryStyle=ctx.createRadialGradient(100,0,0,100,0,9);
    mercuryStyle.addColorStop(0,'#75705a');
    mercuryStyle.addColorStop(1,'#464646');
    var mercury=new Planet(100,0,9,8.77,mercuryStyle,{color:'#464646'});
    stage.planets.push(mercury);


    //saturn 
    var saturnStyle=ctx.createRadialGradient(500,0,0,500,0,26);
    saturnStyle.addColorStop(0,'#f2e558');
    saturnStyle.addColorStop(1,'#4c4a3b');
    var saturn =new Saturn(500,0,26,1075.995,saturnStyle,{color:'#4c4a3b'});
    stage.planets.push(saturn);

小行星带

  当然还有土星和月孛星之间的小行星带,同理继承星球基类,那里运用了图像混合格局globalCompositeOperation,使用xor可以和背景相比度没那么突然。当然还有其它属性值,比如source-over,
lighter等。这里大家随便生成了300个目的,一样填充进场景类的planets属性统一更新绘制。

    /**
     * 小行星
     */
    class Asteroid extends Planet{
        draw(ctx){
            ctx.save();
            ctx.rotate(this.angle);
            ctx.beginPath();
            ctx.globalCompositeOperation = "xor";
            ctx.fillStyle=this.fillStyle;           
            ctx.arc(this.x,this.y,this.r,0,Math.PI*2,false);
            ctx.fill();
            ctx.restore();  
        }
    }

    function createAsteroids(){
        var asteroid=null,
            x=300,y=0, r=2,rd=300,
            angle=0, d=283, 
            color='#fff';
        for(var i=0;i<400;i++){
            rd=Random(300,320);
            angle=Random(0,Math.PI*2*1000)/1000;
            x=Math.round(Math.cos(angle)*rd);
            y=Math.round(Math.sin(angle)*rd);
            r=Random(1,3);
            d=Random(28.3,511);
            color=getAsteroidColor();
            // console.log(angle,color);
            asteroid = new Asteroid(x,y,r,d,color,{color:color,blur:1});
            stage.planets.push(asteroid);
        }
    }

彗星

  基本快已毕了,但我们除了,可以再添加做椭圆运动的彗星,这样越发酷。一样自由生成20个彗星填充进场景类统一更新绘制。

    /**
     * 彗星
     */
    class Comet {
        constructor(cx,cy,a,b,r,angle,color,duration){
            this.a=a;
            this.b=b;
            this.r=r;
            this.cx=cx;
            this.cy=cy;
            this.x=0;
            this.y=0;
            this.color=color;
            this.angle=angle;
            this.duration=duration;
        }
        update(startTime){
            var t=Tween.linear(new Date()-startTime,0,Math.PI*2,this.duration*1000);
            this.x=this.cx+this.a*Math.cos(this.angle+t);
            this.y=this.cy+this.b*Math.sin(this.angle+t);
        }
        draw(){
            ctx.save();
            ctx.rotate(this.angle);
            //画运动轨迹
            ctx.lineWidth=0.5;
            ctx.strokeStyle='rgba(15,69,116,0.2)';
            Shape.ellipse(ctx,this.cx,this.cy,this.a,this.b);

            //画球
            ctx.beginPath();
            // ctx.globalCompositeOperation = "lighter";
            ctx.globalCompositeOperation = "source-atop";
            ctx.shadowColor=this.color;
            ctx.shadowBlur=1;
            ctx.fillStyle=this.color;
            ctx.arc(this.x,this.y,this.r,0,Math.PI*2,false);
            ctx.fill();
            //画尾迹
            ctx.restore();
        }
    }

    function createComets(){
        var l=180,
            a=800,b=300,
            cx=a-l,cy=0,
            r=3,duration=30,angle=0,color='#fff',
            comet = null;
        for(var i=0;i<20;i++){
            l=Random(120,350)
            a=Random(600,1000);
            b=a/Random(1,3);
            cx=a-l;
            r=Random(2,4);
            angle=Random(0,Math.PI*2*1000)/1000;
            color=getCometColor();
            duration=Random(20,100);
            stage.planets.push(new Comet(cx,cy,a,b,r,angle,color,duration));
        }
    }

运动轨迹

  最终的细节,就是标识骑行星圆日运动的清规戒律,当然最简便的是按运动半径画个圆。但大家用线性渐变添加美观的尾迹,那样效果更好

    function drawCircle(r,color){
        var hsl=Color.hexToHsl(color);
        ctx.lineWidth=1;
        // ctx.strokeStyle='rgba(176,184,203,0.3)';
        // ctx.arc(0,0,this.x,Math.PI*2,false);
        // ctx.stroke();
        var gradient=ctx.createLinearGradient(-r,0,r,0);
        gradient.addColorStop(0,'hsla('+hsl[0]+','+hsl[1]+'%,0%,.3)');
        gradient.addColorStop(0.6,'hsla('+hsl[0]+','+hsl[1]+'%,50%,.9)');
        gradient.addColorStop(1,'hsla('+hsl[0]+','+hsl[1]+'%,80%,1)');
        ctx.strokeStyle=gradient;
            // ctx.shadowColor=color;
            // ctx.shadowBlur=4;    
        ctx.beginPath();
        ctx.arc(0,0,r,0,Math.PI,true);
        ctx.stroke();
    }

最后

  所有的有的都早已形成,大家只需求启动场景类即可

    createAsteroids();
    createComets();
    stage.init(ctx);

发表评论

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

网站地图xml地图