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