基于canvas实时渲染竞赛排行榜单

竞赛系统排行榜单,基于canvas实时渲染。

简要回忆demo从需求到设计到实现的大体思路,介绍部分canvas属性和方法,以及面向对象的编程思维在该demo中的应用。

使用“类”(ES5中的new加构造器函数创建对象或ES6中的class特性声明类)从具体实现层面将面向对象编程(OOP)思维具象化。

分析排行榜单最小单位应当包含的信息。

将排行榜单每一项功能需求转换为视觉语言。

确定最终的视觉方案。

名为Rank的函数名,使用new关键词实例化对象。

function Rank(o){
  this.x = o.x;
  this.y = o.y;
  this.height = 80;
  this.rankNumber = o.rankNumber;
  this.borderLineWidth = 2;
  this.width = o.width || 310;
  switch(this.rankNumber){
    case 1:
      this.colorH = 5;
      break;
    case 2:
      this.colorH = 52;
      break;
    case 3:
      this.colorH = 151;
      break;
    default:
      this.colorH = 184;
      break;
  }
  this.starManager = [];
  for(var i=0; i<this.starNumber; i++){
    this.starManager.push({
      isFinshed: false,
    });
  }
  this.fireMarginBottom = 3;
  this.dotMaxDistance = 40;
  this.dotManager = [];
  for(var i=0; i<30; i++){
    this.dotManager.push({
      x: Math.random() * this.width,
      y: -this.fireMarginBottom,
      distance: parseInt(this.dotMaxDistance + Math.random()*20),
      alpha: Math.random(),
      speed_y: 0.2 + Math.random()*0.4,
      speed_x: 0,
      radius: 2 + Math.random() * 2.6,
    });
  }
  this.polyMaxDistance = 20;
  this.polyManager = [];
  for(var i=0; i<20; i++){
    this.polyManager.push({
      x: Math.random() * this.width,
      y: -this.fireMarginBottom,
      distance: parseInt(this.polyMaxDistance + Math.random()*20),
      alpha: Math.random(),
      speed_y: 0.2 + Math.random()*0.4,
      speed_x: 0,
      radius: 0.6 + Math.random() * 1.6,
      scale: Math.random() * 2,
      rotation: Math.random() * 360,
    });
  }
}
Rank.prototype.updateFire = function(){
  for(var i=0; i<this.dotManager.length; i++){
    this.dotManager[i].y -= this.dotManager[i].speed_y;
    this.dotManager[i].x += this.dotManager[i].speed_x;
    this.dotManager[i].alpha = 1 - Math.abs(this.dotManager[i].y) / Math.abs(this.dotManager[i].distance);
    if(this.dotManager[i].y <= -this.dotManager[i].distance){
      this.dotManager[i].y = -this.fireMarginBottom;
      this.dotManager[i].radius = 2 + Math.random() * 2.6;
      this.dotManager[i].speed_x = -0.2 + Math.random()*0.4;
      this.dotManager[i].x = Math.random() * this.width;
      this.dotManager[i].rotation = Math.random() * 360;
      this.dotManager[i].distance = (1-(Math.abs(this.width/2 - this.dotManager[i].x) / this.width)) * parseInt(this.dotMaxDistance + Math.random()*20);
    }
  }
  for(var i=0; i<this.polyManager.length; i++){
    this.polyManager[i].y -= this.polyManager[i].speed_y;
    this.polyManager[i].x += this.polyManager[i].speed_x;
    this.polyManager[i].alpha = 1 - Math.abs(this.polyManager[i].y) / Math.abs(this.polyManager[i].distance);
    this.polyManager[i].rotation += 1;
    if(this.polyManager[i].y <= -this.polyManager[i].distance){
      this.polyManager[i].y = -this.fireMarginBottom;
      this.polyManager[i].radius = 0.6 + Math.random() * 1.6;
      this.polyManager[i].speed_x = -0.2 + Math.random()*0.4;
      this.polyManager[i].x = Math.random() * this.width;
      this.polyManager[i].distance = (1-(Math.abs(this.width/2 - this.polyManager[i].x) / this.width)) * parseInt(this.dotMaxDistance + Math.random()*20);
    }
  }
}
Rank.prototype.draw = function(ctx){
  this.updateFire();
  ctx.save();
  ctx.translate(this.x, this.y);
  ctx.beginPath();
  ctx.moveTo(0, -this.fireMarginBottom);
  ctx.lineTo(this.width, -this.fireMarginBottom);
  ctx.closePath();
  ctx.lineWidth = 0.8;
  var _linear_gradient = ctx.createLinearGradient(0, 0, this.width, 0);
  _linear_gradient.addColorStop(0, 'hsla('+this.colorH+', 100%, 50%, 0)');
  _linear_gradient.addColorStop(0.5, 'hsla('+this.colorH+', 100%, 50%, 1)');
  _linear_gradient.addColorStop(1, 'hsla('+this.colorH+', 100%, 50%, 0)');
  ctx.strokeStyle = _linear_gradient;
  ctx.stroke();
  ctx.restore();
  ctx.save();
  ctx.translate(this.x + this.width/2, this.y);
  ctx.beginPath();
  ctx.rect(-this.width/2, -50 - this.fireMarginBottom, this.width, 50);
  ctx.closePath();
  ctx.clip();
  ctx.scale(1, 0.18);
  ctx.beginPath();
  ctx.arc(0, 0, this.width/2, 0, Math.PI*2, true);
  ctx.closePath();
  var _radial_gradient = ctx.createRadialGradient(0, 0, 0, 0, 0, this.width/2);
  _radial_gradient.addColorStop(0, 'hsla('+this.colorH+', 100%, 50%, 1)');
  _radial_gradient.addColorStop(1, 'hsla('+this.colorH+', 100%, 20%, 0)');
  ctx.fillStyle = _radial_gradient;
  ctx.fill();
  ctx.restore();
  for(var i=0; i<this.dotManager.length; i++){
    ctx.save();
    ctx.globalAlpha = this.dotManager[i].alpha;
    ctx.shadowBlur = 12;
    ctx.shadowColor = 'hsla('+this.colorH+', 100%, 50%, 1)';
    ctx.translate(this.x + this.dotManager[i].x, this.y + this.dotManager[i].y);
    ctx.beginPath();
    ctx.arc(0, 0, this.dotManager[i].radius, 0, Math.PI*2, true);
    ctx.closePath();
    var _radial_gradient = ctx.createRadialGradient(0, 0, 0, 0, 0, this.dotManager[i].radius);
    _radial_gradient.addColorStop(0, 'hsla('+this.colorH+', 100%, 50%, 1)');
    _radial_gradient.addColorStop(1, 'hsla('+this.colorH+', 100%, 20%, 0)');
    ctx.fillStyle = _radial_gradient;
    ctx.fill();
    ctx.restore();
  }
  for(var i=0; i<this.polyManager.length; i++){
    ctx.save();
    ctx.globalAlpha = this.polyManager[i].alpha;
    ctx.shadowBlur = 12;
    ctx.shadowColor = 'hsla('+this.colorH+', 100%, 50%, 1)';
    ctx.translate(this.x + this.polyManager[i].x, this.y + this.polyManager[i].y);
    ctx.scale(this.polyManager[i].scale, this.polyManager[i].scale);
    ctx.rotate(this.polyManager[i].rotation * Math.PI/180);
    ctx.beginPath();
    ctx.moveTo(-2, 2);
    ctx.lineTo(2,-2);
    ctx.lineTo(2,5);
    ctx.closePath();
    ctx.lineCap = 'round';
    ctx.lineJoin = 'round';
    ctx.fillStyle = 'hsla('+this.colorH+', 100%, 50%, 0.5)';
    ctx.strokeStyle = 'hsla('+this.colorH+', 100%, 50%, 1)';
    ctx.fill();
    ctx.stroke();
    ctx.restore();
  }
}

版权声明 » 自由转载-署名-非商用-相同方式共享

作者署名 » 陈帅华-探索技术艺术与国学之美

发布日期 » 2018年1月1日 星期一

我要留言