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

版权声明 » 帅华君原创文章,未经允许不得转载。

基于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();
	// draw-line
	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();
	//draw-light
	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();
	// draw-dot
	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();
	}
	// draw-poly
	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();
	}
}