Gauge实现canvas仪表盘转动动画效果

代码语言:html

所属分类:动画

代码描述:Gauge实现canvas仪表盘转动动画效果

代码标签: 仪表盘 转动 动画 效果

下面为部分代码预览,完整代码请点击下载或在bfwstudio webide中打开

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title></title>
<meta charset="utf-8" />
<style>
html, body, div, canvas, a {
	margin: 0px;
	padding: 0px;
}

#clockBoard {
	width: 550px;
	height: 760px;
	margin: 0px auto;
	margin-bottom: 0px;
}

#pointer {
	position: relative;
	top: -560px;
}
</style>
</head>
<body>

<div id="clockBoard">

	<canvas id="gauge1" width="310" height="310"></canvas>
	<canvas id="gauge" width="310" height="310"></canvas>

</div>


<script type="text/javascript">
(function (window) {
	var PIDEG = Math.PI / 180;
	function Gauge(options) {
		//set defaults
		var properties = {
			tick_length: 80,
			large_tick_length: 110,
			tick_thickness: 6,
			tick_group_length: 9,
			ticks_groups_begin: 0,
			total_degrees: 240,
			tick_color: "#555962",
			tick_on_color: "#527d98",
			on_color_gradient: null,
			bg_color: null,
			gauge_scale: 1,
			animation_duration: 550,
			total_tick: 101,
			show_num: true,
			show_center_num: true,
			center_font_size: 200,
			center_font_color: '#555962',
			cur_score_circle_color: '#555962',
			center_offset: {
				x: 0,
				y: 0
			},
			center_num_font_family: 'HanHei SC, PingFang SC, Helvetica Neue Thin, Helvetica, STHeitiSC-Light, Arial, sans-serif',
			num_gap: 1,
			num_begin: 0,
			num_font_size: 16,
			tickmask_offset: 0,
			num_font_family: 'HanHei SC, PingFang SC, Helvetica Neue Thin, Helvetica, STHeitiSC-Light, Arial, sans-serif',
			circle_radius: 5,
			circle_offset: 0,
			center_text_unit: '分',
			center_text_offset: {
				x: 16,
				y: 8
			}
		};
		this.mergeOptions(properties, options)
		this._canvas = options.canvas;
		this.canvas = document.createElement('canvas');
		this.canvas.width = this._canvas.width;
		this.canvas.height = this._canvas.height;
		this.delatLength = this.large_tick_length - this.tick_length;
		this.context = this.canvas.getContext('2d');
		this._context = this._canvas.getContext('2d');
		this._percent = options.percent || 0;
		this._target_percent = this._percent;
		this.tickmask_offset = this.getTickMarkOffset(this.tickmask_offset)
		this._halfCanvasWidth = this.canvas.width / 2;
		this._halfCanvasHeight = this.canvas.height / 2;
		this._rotation_deg = this.getRotationDeg()
		return this;
	}
	Gauge.prototype.mergeOptions = function (defaultOpt, options) {
		var _this = this;
		this._property_list = Object.keys(defaultOpt);
		this._property_list.forEach(function (key) {
			_this[key] = typeof options[key] === 'undefined' ? defaultOpt[key] : options[key]
		})
	}
	Gauge.prototype.getTickMarkOffset = function () {
		return this.tickmask_offset + this.circle_radius * 2 + this.circle_offset;
	}
	Gauge.prototype.getRotationDeg = function () {
		return this.total_degrees / (this.total_tick - 1) * PIDEG;
	}
	Gauge.prototype.render = function (percent) {
		if (typeof percent !== 'undefined') {
			this._percent = percent
		}
		var canvas = this.canvas;
		var context = this.context;
		context.save(); //save original state of context to that it can be restore after rendering
		this._prepareStage();
		//figure out how many degrees between each tick
		var num_ticks = this.total_tick;
		//adjust for smaller than 180 degree gauges
		var starting_deg = (180 - this.total_degrees) / 2;
		context.rotate(starting_deg * PIDEG);
		this._drawScoreTipCircle(this._halfCanvasWidth - this.circle_radius, this.circle_radius, 0);
		//draw all of the ticks
		for (var i = 1; i <= num_ticks; i++) {
			//should this tick be on or off?
			var is_on = (((i - 1) / num_ticks) * 100 < this._percent);
			//scale the ticks at group split
			var _isLargeTick = this._isLargeTick(i)
			var rect_scale = _isLargeTick ? this.large_tick_scale : 1;
			var tick_length = _isLargeTick ? this.large_tick_length : this.tick_length;
			//draw tick
			var color = this._getTickColor(is_on, i);
			context.fillStyle = color;
			if (_isLargeTick) {
				context.fillRect(-1 * this._halfCanvasWidth + this.circle_radius * 2 + this.circle_offset, -this.tick_thickness / 2, tick_length, this.tick_thickness);
				if (this.show_num) {
					this._drawGaugeNum(tick_length, i);
				}
			} else {
				context.fillRect(-1 * this._halfCanvasWidth + this.circle_radius * 2 + this.circle_offset + this.delatLength, -this.tick_thickness / 2, tick_length, this.tick_thickness);
			}
			//rotate for next tick to be placed
			context.rotate(this._rotation_deg);
		}
		this._context.clearRect(0, 0, this._canvas.width, this._canvas.height);
		this._context.drawImage(this.canvas, 0, 0);
		context.restore(); //set back to original state
	};

	Gauge.prototype.setTickOnColor = function (option) {
		this.tick_on_color = option.tick_on_color || this.tick_on_color;
		this.on_color_gradient = option.on_color_gradient || null;
		this.center_font_color = option.center_font_color || this.tick_on_color;
		this.cur_score_circle_color = option.cur_score_circle_color || this.cur_score_circle_color || this.tick_on_color;
	}

	Gauge.prototype.setAnimaDur = function (duration) {
		this.animation_duration = duration;
	}

	Gauge.prototype.updatePercent = function (percent, options) {
		if (percent - 0.1 < 0) {
			return;
		}
		var _this = this;
		this._target_percent = percent;
		options = options || {};
		var duration = ('animation_duration' in options) ? options.animation_duration : _this.animation_duration;
		if (duration) {
			var lastUpdate = +new Date();
			var start = this._percent;
			var end = this._target_percent;
			var change_per_ms = (end - start) / duration;
			var increasing = change_per_ms > 0 ? 1 : 0;
			this.colorArray = this._gradientColorArray();
			var update = function () {
				var now = +new Date();
				var elapsed = now - lastUpdate;
				_this._percent += elapsed * change_per_ms;
				lastUpdate = now;
				//check if we've made it to our stopping point
				if ((increasing && _this._percent < _this._target_percent)
				  || (!increasing && _this._percent > _this._target_percent)) {
					_this.render();
					_this._requestAnimFrame(update);
				}
				else {
					_this._percent = _this._target_percent;
					_this.render();
				}
			};
			_this._requestAnimFrame(update);
		}
		else {
			_this._percent = percent;
			_this.render();
		}
	};

	// 私有函数
	Gauge.prototype._requestAnimFrame = function (f) {
		var anim = window.requestAnimationFrame
		  || window.webkitRequestAnimationFrame
		  || window.mozRequestAnimationFrame
		  || window.oRequestAnimationFrame
		  || window.msRequestAnimationFrame
		  || function (callback, element) {
			  window.setTimeout(function () {
				  callback(+new Date);
			  }, 1000 / 60);
		  };
		anim(f);
	};

	Gauge.prototype._applyBG = function () {
		var canvas = this.canvas;
		var context = this.context;
		if (this.bg_color) {
			context.save();
			context.fillStyle = this.bg_color;
			context.fillRect(0, 0, canvas.width, canvas.height);
			context.restore();
		}
	};

	Gauge.prototype._prepareStage = function () {
		var canvas = this.canvas;
		var context = this.context;
		//clear canvas
		context.clearRect(0, 0, canvas.width, canvas.height);
		//set background
		this._applyBG();
		//set the center of rotation to the bottom/center of the canvas
		context.translate(this._halfCanvasWidth, this._halfCanvasHeight - this.tick_thickness / 2);
		//set the scale of the gauge (will naturally fill the width of the canvas
		context.scale(this.gauge_scale, this.gauge_scale);
		//draw center big num
		if (this.show_center_num) {
			this._drawCenterNum();
		}
	};

	Gauge.prototype._gradientColorArray = function () {
		var colorArray = []
		if (!this.on_color_gradient || !this._target_percent) {
			return
		}
		for (var i = 0; i < this.on_color_gradient.length - 1; i++) {
			var next = this.on_color.........完整代码请登录后点击上方下载按钮下载查看

网友评论0