diff --git a/canvas-demo/1.png b/canvas-demo/1.png new file mode 100644 index 0000000..a771e00 Binary files /dev/null and b/canvas-demo/1.png differ diff --git a/canvas-demo/chart.html b/canvas-demo/chart.html new file mode 100644 index 0000000..8cf691a --- /dev/null +++ b/canvas-demo/chart.html @@ -0,0 +1,39 @@ + + + + + + + + + +
+ + + + + + \ No newline at end of file diff --git a/canvas-demo/sChart.js b/canvas-demo/sChart.js new file mode 100644 index 0000000..a8cb86b --- /dev/null +++ b/canvas-demo/sChart.js @@ -0,0 +1,205 @@ +function sBarChart(canvas, data, options) { + this.canvas = document.getElementById(canvas); + this.ctx = this.canvas.getContext('2d'); + this.data = data; // 存放图表数据 + this.dataLength = this.data.length; // 图表数据的长度 + this.width = this.canvas.width; // canvas 宽度 + this.height = this.canvas.height; // canvas 高度 + this.padding = 50; // canvas 内边距 + this.yEqual = 5; // y轴分成5等分 + this.yLength = 0; // y轴坐标点之间的真实长度 + this.xLength = 0; // x轴坐标点之间的真实长度 + this.yFictitious = 0; // y轴坐标点之间显示的间距 + this.yRatio = 0; // y轴坐标真实长度和坐标间距的比 + this.bgColor = '#ffffff'; // 默认背景颜色 + this.fillColor = '#1E9FFF'; // 默认填充颜色 + this.axisColor = '#666666'; // 坐标轴颜色 + this.contentColor = '#eeeeee'; // 内容横线颜色 + this.titleColor = '#000000'; // 图表标题颜色 + this.title = ''; // 图表标题 + this.titlePosition = 'top'; // 图表标题位置: top / bottom + this.looped = null; // 是否循环 + this.current = 0; // 当前加载柱状图高度的百分数 + this.currentIndex = -1; + this.onceMove = -1; + this.init(options); +} +sBarChart.prototype = { + init: function(options) { + if(options){ + this.padding = options.padding || 50; + this.yEqual = options.yEqual || 5; + this.bgColor = options.bgColor || '#ffffff'; + this.fillColor = options.fillColor || '#1E9FFF'; + this.axisColor = options.axisColor || '#666666'; + this.contentColor = options.contentColor || '#eeeeee'; + this.titleColor = options.titleColor || '#000000'; + this.title = options.title; + this.titlePosition = options.titlePosition || 'top'; + } + this.yLength = Math.floor((this.height - this.padding * 2 - 10) / this.yEqual); + this.xLength = Math.floor((this.width - this.padding * 1.5 - 10) / this.dataLength); + this.yFictitious = this.getYFictitious(this.data); + this.yRatio = this.yLength / this.yFictitious; + this.looping(); + }, + looping: function() { + this.looped = requestAnimationFrame(this.looping.bind(this)); + if(this.current < 100){ + this.current = (this.current + 3) > 100 ? 100 : (this.current + 3); + this.drawAnimation(); + }else{ + window.cancelAnimationFrame(this.looped); + this.looped = null; + this.watchHover(); + } + }, + drawAnimation: function() { + for(var i = 0; i < this.dataLength; i++) { + var x = Math.ceil(this.data[i].value * this.current / 100 * this.yRatio); + var y = this.height - this.padding - x; + + this.data[i].left = this.padding + this.xLength * (i + 0.25); + this.data[i].top = y; + this.data[i].right = this.padding + this.xLength * (i + 0.75); + this.data[i].bottom = this.height - this.padding; + this.drawUpdate(); + } + }, + drawUpdate: function() { + this.ctx.fillStyle = this.bgColor; + this.ctx.fillRect(0, 0, this.width, this.height); + this.drawAxis(); + this.drawPoint(); + this.drawTitle(); + this.drawChart(); + }, + drawChart: function() { + this.ctx.fillStyle = this.fillColor; + for(var i = 0; i < this.dataLength; i++) { + this.ctx.fillRect( + this.data[i].left, + this.data[i].top, + this.data[i].right - this.data[i].left, + this.data[i].bottom - this.data[i].top + ); + this.ctx.font = '12px Arial' + this.ctx.fillText( + this.data[i].value * this.current / 100, + this.data[i].left + this.xLength / 4, + this.data[i].top - 5 + ); + } + }, + drawAxis: function() { + this.ctx.beginPath(); + this.ctx.strokeStyle = this.axisColor; + // y轴线, +0.5是为了解决canvas画1像素会显示成2像素的问题 + this.ctx.moveTo(this.padding + 0.5, this.height - this.padding + 0.5); + this.ctx.lineTo(this.padding + 0.5, this.padding + 0.5); + // x轴线 + this.ctx.moveTo(this.padding + 0.5, this.height - this.padding + 0.5); + this.ctx.lineTo(this.width - this.padding / 2 + 0.5, this.height - this.padding + 0.5); + this.ctx.stroke(); + }, + drawPoint: function() { + // x轴坐标点 + this.ctx.beginPath(); + this.ctx.font = '12px Microsoft YaHei'; + this.ctx.textAlign = 'center'; + this.ctx.fillStyle = this.axisColor; + for(var i = 0; i < this.dataLength; i ++){ + var xAxis = this.data[i].xAxis; + var xlen = this.xLength * (i + 1); + this.ctx.moveTo(this.padding + xlen + 0.5, this.height - this.padding + 0.5); + this.ctx.lineTo(this.padding + xlen + 0.5, this.height - this.padding + 5.5); + this.ctx.fillText(xAxis, this.padding + xlen - this.xLength / 2, this.height - this.padding + 15); + } + this.ctx.stroke(); + + // y轴坐标点 + this.ctx.beginPath(); + this.ctx.font = '12px Microsoft YaHei'; + this.ctx.textAlign = 'right'; + this.ctx.fillStyle = this.axisColor; + this.ctx.moveTo(this.padding + 0.5, this.height - this.padding + 0.5); + this.ctx.lineTo(this.padding - 4.5, this.height - this.padding + 0.5); + this.ctx.fillText(0, this.padding - 10, this.height - this.padding + 5); + for(var i=0; i < this.yEqual; i ++){ + var y = this.yFictitious * (i + 1); + var ylen = this.yLength * (i + 1); + this.ctx.beginPath(); + this.ctx.strokeStyle = this.axisColor; + this.ctx.moveTo(this.padding + 0.5, this.height - this.padding - ylen + 0.5); + this.ctx.lineTo(this.padding - 4.5, this.height - this.padding - ylen + 0.5); + this.ctx.stroke(); + this.ctx.fillText(y,this.padding - 10, this.height - this.padding - ylen + 5); + this.ctx.beginPath(); + this.ctx.strokeStyle = this.contentColor; + this.ctx.moveTo(this.padding + 0.5, this.height - this.padding - ylen + 0.5) + this.ctx.lineTo(this.width - this.padding / 2 + 0.5, this.height - this.padding - ylen+0.5); + this.ctx.stroke(); + } + }, + drawTitle: function() { + if(this.title){ + this.ctx.beginPath(); + this.ctx.textAlign = 'center'; + this.ctx.fillStyle = this.titleColor; + this.ctx.font = '16px Microsoft YaHei'; + if(this.titlePosition === 'bottom' && this.padding >= 40){ + this.ctx.fillText(this.title, this.width / 2, this.height - 5) + }else{ + this.ctx.fillText(this.title, this.width / 2, this.padding / 2) + } + } + }, + /** + * 监听鼠标移动事件 + */ + watchHover: function() { + var self = this; + self.canvas.addEventListener('mousemove', function(ev) { + ev = ev || window.event; + self.currentIndex = -1; + for (var i = 0; i < self.data.length; i ++){ + if( ev.offsetX > self.data[i].left && + ev.offsetX < self.data[i].right && + ev.offsetY > self.data[i].top && + ev.offsetY < self.data[i].bottom ) + { + self.currentIndex = i; + } + } + self.drawHover(); + }) + }, + drawHover: function() { + if(this.currentIndex !== -1){ + if(this.onceMove === -1){ + this.onceMove = this.currentIndex; + this.canvas.style.cursor = 'pointer'; + } + }else{ + if(this.onceMove !== -1){ + this.onceMove = -1; + this.canvas.style.cursor = 'inherit'; + } + } + }, + /** + * y轴坐标点之间显示的间距 + * @param data + * @return y轴坐标间距 + */ + getYFictitious: function(data) { + var arr = data.slice(0); + arr.sort(function(a,b){ + return -(a.value-b.value); + }); + var len = Math.ceil(arr[0].value / this.yEqual); + var pow = len.toString().length - 1; + pow = pow > 2 ? 2 : pow; + return Math.ceil(len / Math.pow(10,pow)) * Math.pow(10,pow); + } +} \ No newline at end of file