昨天我们分享了一款基于HTML5的线性图表应用,效果非常不错,可以看在线DEMO或者实现教程。今天我们继续来分享一款基于HTML5的网页图表,它也是利用Canvas绘制的,但是和前面不同的是,这款图表是饼状图,并且我们可以点击右侧的表格来选中激活当前的图表数据,具体效果可以看DEMO演示。

你也可以在这里查看在线演示

下面是实现的过程及源码,一起分享给大家。

HTML代码:

<div id="container">

        <canvas id="chart" width="600" height="500"></canvas>
<table id="chartData">
<tr>
<th>脚本素材</th><th>下载量</th>
</tr>
<tr style="color:#0DA068">
<td>jquery图片特效</td><td>1862.12</td>
</tr>
<tr style="color:#194E9C">
<td>jquery导航菜单</td><td>1316.00</td>
</tr>
<tr style="color:#ED9C13">
<td>jquery选项卡特效</td><td>712.49</td>
</tr>
<tr style="color:#ED5713">
<td>jquery文字特效</td><td>3236.27</td>
</tr>
<tr style="color:#057249">
<td>jquery表单特效</td><td>6122.06</td>
</tr>
<tr style="color:#5F91DC">
<td>html5特效</td><td>128.11</td>
</tr>
<tr style="color:#F88E5D">
<td>html5 图表</td><td>245.55</td>
</tr>
</table>
</div>

HTML代码有两部分,第一部分是一个canvas标签,我们的饼状图就在这里绘制。另一部分是右侧的数据分类表格,点击表格的行就可以选中并激活图表中对应的数据块。

接下来是CSS代码:

/* reset */
*{margin:;padding:;list-style-type:none;}
a{blr:expression(this.onFocus=this.blur())}/*去掉a标签的虚线框,避免出现奇怪的选中区域*/
:focus{outline:;}
label{cursor:pointer;}
img{vertical-align:middle;}
table{empty-cells:show;border-collapse:collapse;border-spacing:;}
h1{font-size:16px;}h2,h3,h4{font-size:14px;}h5,h6{font-size:12px;}
abbr,acronym{border:;font-variant:normal}
address,caption,cite,code,dfn,em,th,var,optgroup{font-style:normal;font-weight:normal}
input,button,textarea,select,optgroup,option{font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit}
input,button,textarea,select{*font-size:100%}
a,img{border:;}
a,a:visited{color:#5e5e5e; text-decoration:none;}
a:hover{color:#4183C4;text-decoration:underline;}
.clear{display:block;overflow:hidden;clear:both;height:;line-height:;font-size:;}
.clearfix:after{content:".";display:block;height:;clear:both;visibility:hidden;}
.clearfix{display:inline-table;}/* Hides from IE-mac \*/
*html .clearfix{height:1%;}
.clearfix{display:block;}/* End hide from IE-mac */
*+html .clearfix{min-height:1%;}
body{font:12px/180% Arial,Lucida,Verdana,"宋体",Helvetica,sans-serif;color:#333;background:#fff;}
/* shortcut */
.shortcut{position:fixed;top:;left:;z-index:;width:100%;}
*html,*html body /* 修正IE6振动bug */{background-image:url(about:blank);background-attachment:fixed;}
*html .shortcut{position:absolute;top:expression(eval(document.documentElement.scrollTop));}
.shortcut{height:28px;line-height:28px;font-size:12px;background:#EEEEEE;text-transform:uppercase;box-shadow:1px 0px 2px rgba(0,0,0,0.2);border-bottom:1px solid #DDDDDD;}
.shortcut h1{font-size:14px;font-family:"微软雅黑","宋体";}
.shortcut a,.shortcut h1{padding:0px 10px;letter-spacing:1px;color:#333;text-shadow:0px 1px 1px #fff;display:block;float:left;}
.shortcut a:hover{background:#fff;}
.shortcut span.right{float:right;}
.shortcut span.right a{float:left;display:block;color:#ff6600;font-weight:;}
.headeline{height:40px;overflow:hidden;}
.adv960x90{width:960px;height:90px;overflow:hidden;border:solid 1px #E6E6E6;margin:0 auto;}
.adv728x90{width:728px;height:90px;overflow:hidden;border:solid 1px #E6E6E6;margin:0 auto;}

一些基本页面样式设置,没什么特别的。

最后是Javascript代码:

$( pieChart );

function pieChart() {

  // Config settings
var chartSizePercent = 55; // The chart radius relative to the canvas width/height (in percent)
var sliceBorderWidth = 1; // Width (in pixels) of the border around each slice
var sliceBorderStyle = "#fff"; // Colour of the border around each slice
var sliceGradientColour = "#ddd"; // Colour to use for one end of the chart gradient
var maxPullOutDistance = 25; // How far, in pixels, to pull slices out when clicked
var pullOutFrameStep = 4; // How many pixels to move a slice with each animation frame
var pullOutFrameInterval = 40; // How long (in ms) between each animation frame
var pullOutLabelPadding = 65; // Padding between pulled-out slice and its label
var pullOutLabelFont = "bold 16px 'Trebuchet MS', Verdana, sans-serif"; // Pull-out slice label font
var pullOutValueFont = "bold 12px 'Trebuchet MS', Verdana, sans-serif"; // Pull-out slice value font
var pullOutValuePrefix = "$"; // Pull-out slice value prefix
var pullOutShadowColour = "rgba( 0, 0, 0, .5 )"; // Colour to use for the pull-out slice shadow
var pullOutShadowOffsetX = 5; // X-offset (in pixels) of the pull-out slice shadow
var pullOutShadowOffsetY = 5; // Y-offset (in pixels) of the pull-out slice shadow
var pullOutShadowBlur = 5; // How much to blur the pull-out slice shadow
var pullOutBorderWidth = 2; // Width (in pixels) of the pull-out slice border
var pullOutBorderStyle = "#333"; // Colour of the pull-out slice border
var chartStartAngle = -.5 * Math.PI; // Start the chart at 12 o'clock instead of 3 o'clock // Declare some variables for the chart
var canvas; // The canvas element in the page
var currentPullOutSlice = -1; // The slice currently pulled out (-1 = no slice)
var currentPullOutDistance = 0; // How many pixels the pulled-out slice is currently pulled out in the animation
var animationId = 0; // Tracks the interval ID for the animation created by setInterval()
var chartData = []; // Chart data (labels, values, and angles)
var chartColours = []; // Chart colours (pulled from the HTML table)
var totalValue = 0; // Total of all the values in the chart
var canvasWidth; // Width of the canvas, in pixels
var canvasHeight; // Height of the canvas, in pixels
var centreX; // X-coordinate of centre of the canvas/chart
var centreY; // Y-coordinate of centre of the canvas/chart
var chartRadius; // Radius of the pie chart, in pixels // Set things up and draw the chart
init(); /**
* Set up the chart data and colours, as well as the chart and table click handlers,
* and draw the initial pie chart
*/ function init() { // Get the canvas element in the page
canvas = document.getElementById('chart'); // Exit if the browser isn't canvas-capable
if ( typeof canvas.getContext === 'undefined' ) return; // Initialise some properties of the canvas and chart
canvasWidth = canvas.width;
canvasHeight = canvas.height;
centreX = canvasWidth / 2;
centreY = canvasHeight / 2;
chartRadius = Math.min( canvasWidth, canvasHeight ) / 2 * ( chartSizePercent / 100 ); // Grab the data from the table,
// and assign click handlers to the table data cells var currentRow = -1;
var currentCell = 0; $('#chartData td').each( function() {
currentCell++;
if ( currentCell % 2 != 0 ) {
currentRow++;
chartData[currentRow] = [];
chartData[currentRow]['label'] = $(this).text();
} else {
var value = parseFloat($(this).text());
totalValue += value;
value = value.toFixed(2);
chartData[currentRow]['value'] = value;
} // Store the slice index in this cell, and attach a click handler to it
$(this).data( 'slice', currentRow );
$(this).click( handleTableClick ); // Extract and store the cell colour
if ( rgb = $(this).css('color').match( /rgb\((\d+), (\d+), (\d+)/) ) {
chartColours[currentRow] = [ rgb[1], rgb[2], rgb[3] ];
} else if ( hex = $(this).css('color').match(/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/) ) {
chartColours[currentRow] = [ parseInt(hex[1],16) ,parseInt(hex[2],16), parseInt(hex[3], 16) ];
} else {
alert( "Error: Colour could not be determined! Please specify table colours using the format '#xxxxxx'" );
return;
} } ); // Now compute and store the start and end angles of each slice in the chart data var currentPos = 0; // The current position of the slice in the pie (from 0 to 1) for ( var slice in chartData ) {
chartData[slice]['startAngle'] = 2 * Math.PI * currentPos;
chartData[slice]['endAngle'] = 2 * Math.PI * ( currentPos + ( chartData[slice]['value'] / totalValue ) );
currentPos += chartData[slice]['value'] / totalValue;
} // All ready! Now draw the pie chart, and add the click handler to it
drawChart();
$('#chart').click ( handleChartClick );
} /**
* Process mouse clicks in the chart area.
*
* If a slice was clicked, toggle it in or out.
* If the user clicked outside the pie, push any slices back in.
*
* @param Event The click event
*/ function handleChartClick ( clickEvent ) { // Get the mouse cursor position at the time of the click, relative to the canvas
var mouseX = clickEvent.pageX - this.offsetLeft;
var mouseY = clickEvent.pageY - this.offsetTop; // Was the click inside the pie chart?
var xFromCentre = mouseX - centreX;
var yFromCentre = mouseY - centreY;
var distanceFromCentre = Math.sqrt( Math.pow( Math.abs( xFromCentre ), 2 ) + Math.pow( Math.abs( yFromCentre ), 2 ) ); if ( distanceFromCentre <= chartRadius ) { // Yes, the click was inside the chart.
// Find the slice that was clicked by comparing angles relative to the chart centre. var clickAngle = Math.atan2( yFromCentre, xFromCentre ) - chartStartAngle;
if ( clickAngle < 0 ) clickAngle = 2 * Math.PI + clickAngle; for ( var slice in chartData ) {
if ( clickAngle >= chartData[slice]['startAngle'] && clickAngle <= chartData[slice]['endAngle'] ) { // Slice found. Pull it out or push it in, as required.
toggleSlice ( slice );
return;
}
}
} // User must have clicked outside the pie. Push any pulled-out slice back in.
pushIn();
} /**
* Process mouse clicks in the table area.
*
* Retrieve the slice number from the jQuery data stored in the
* clicked table cell, then toggle the slice
*
* @param Event The click event
*/ function handleTableClick ( clickEvent ) {
var slice = $(this).data('slice');
toggleSlice ( slice );
} /**
* Push a slice in or out.
*
* If it's already pulled out, push it in. Otherwise, pull it out.
*
* @param Number The slice index (between 0 and the number of slices - 1)
*/ function toggleSlice ( slice ) {
if ( slice == currentPullOutSlice ) {
pushIn();
} else {
startPullOut ( slice );
}
} /**
* Start pulling a slice out from the pie.
*
* @param Number The slice index (between 0 and the number of slices - 1)
*/ function startPullOut ( slice ) { // Exit if we're already pulling out this slice
if ( currentPullOutSlice == slice ) return; // Record the slice that we're pulling out, clear any previous animation, then start the animation
currentPullOutSlice = slice;
currentPullOutDistance = 0;
clearInterval( animationId );
animationId = setInterval( function() { animatePullOut( slice ); }, pullOutFrameInterval ); // Highlight the corresponding row in the key table
$('#chartData td').removeClass('highlight');
var labelCell = $('#chartData td:eq(' + (slice*2) + ')');
var valueCell = $('#chartData td:eq(' + (slice*2+1) + ')');
labelCell.addClass('highlight');
valueCell.addClass('highlight');
} /**
* Draw a frame of the pull-out animation.
*
* @param Number The index of the slice being pulled out
*/ function animatePullOut ( slice ) { // Pull the slice out some more
currentPullOutDistance += pullOutFrameStep; // If we've pulled it right out, stop animating
if ( currentPullOutDistance >= maxPullOutDistance ) {
clearInterval( animationId );
return;
} // Draw the frame
drawChart();
} /**
* Push any pulled-out slice back in.
*
* Resets the animation variables and redraws the chart.
* Also un-highlights all rows in the table.
*/ function pushIn() {
currentPullOutSlice = -1;
currentPullOutDistance = 0;
clearInterval( animationId );
drawChart();
$('#chartData td').removeClass('highlight');
} /**
* Draw the chart.
*
* Loop through each slice of the pie, and draw it.
*/ function drawChart() { // Get a drawing context
var context = canvas.getContext('2d'); // Clear the canvas, ready for the new frame
context.clearRect ( 0, 0, canvasWidth, canvasHeight ); // Draw each slice of the chart, skipping the pull-out slice (if any)
for ( var slice in chartData ) {
if ( slice != currentPullOutSlice ) drawSlice( context, slice );
} // If there's a pull-out slice in effect, draw it.
// (We draw the pull-out slice last so its drop shadow doesn't get painted over.)
if ( currentPullOutSlice != -1 ) drawSlice( context, currentPullOutSlice );
} /**
* Draw an individual slice in the chart.
*
* @param Context A canvas context to draw on
* @param Number The index of the slice to draw
*/ function drawSlice ( context, slice ) { // Compute the adjusted start and end angles for the slice
var startAngle = chartData[slice]['startAngle'] + chartStartAngle;
var endAngle = chartData[slice]['endAngle'] + chartStartAngle; if ( slice == currentPullOutSlice ) { // We're pulling (or have pulled) this slice out.
// Offset it from the pie centre, draw the text label,
// and add a drop shadow. var midAngle = (startAngle + endAngle) / 2;
var actualPullOutDistance = currentPullOutDistance * easeOut( currentPullOutDistance/maxPullOutDistance, .8 );
startX = centreX + Math.cos(midAngle) * actualPullOutDistance;
startY = centreY + Math.sin(midAngle) * actualPullOutDistance;
context.fillStyle = 'rgb(' + chartColours[slice].join(',') + ')';
context.textAlign = "center";
context.font = pullOutLabelFont;
context.fillText( chartData[slice]['label'], centreX + Math.cos(midAngle) * ( chartRadius + maxPullOutDistance + pullOutLabelPadding ), centreY + Math.sin(midAngle) * ( chartRadius + maxPullOutDistance + pullOutLabelPadding ) );
context.font = pullOutValueFont;
context.fillText( pullOutValuePrefix + chartData[slice]['value'] + " (" + ( parseInt( chartData[slice]['value'] / totalValue * 100 + .5 ) ) + "%)", centreX + Math.cos(midAngle) * ( chartRadius + maxPullOutDistance + pullOutLabelPadding ), centreY + Math.sin(midAngle) * ( chartRadius + maxPullOutDistance + pullOutLabelPadding ) + 20 );
context.shadowOffsetX = pullOutShadowOffsetX;
context.shadowOffsetY = pullOutShadowOffsetY;
context.shadowBlur = pullOutShadowBlur; } else { // This slice isn't pulled out, so draw it from the pie centre
startX = centreX;
startY = centreY;
} // Set up the gradient fill for the slice
var sliceGradient = context.createLinearGradient( 0, 0, canvasWidth*.75, canvasHeight*.75 );
sliceGradient.addColorStop( 0, sliceGradientColour );
sliceGradient.addColorStop( 1, 'rgb(' + chartColours[slice].join(',') + ')' ); // Draw the slice
context.beginPath();
context.moveTo( startX, startY );
context.arc( startX, startY, chartRadius, startAngle, endAngle, false );
context.lineTo( startX, startY );
context.closePath();
context.fillStyle = sliceGradient;
context.shadowColor = ( slice == currentPullOutSlice ) ? pullOutShadowColour : "rgba( 0, 0, 0, 0 )";
context.fill();
context.shadowColor = "rgba( 0, 0, 0, 0 )"; // Style the slice border appropriately
if ( slice == currentPullOutSlice ) {
context.lineWidth = pullOutBorderWidth;
context.strokeStyle = pullOutBorderStyle;
} else {
context.lineWidth = sliceBorderWidth;
context.strokeStyle = sliceBorderStyle;
} // Draw the slice border
context.stroke();
} /**
* Easing function.
*
* A bit hacky but it seems to work! (Note to self: Re-read my school maths books sometime)
*
* @param Number The ratio of the current distance travelled to the maximum distance
* @param Number The power (higher numbers = more gradual easing)
* @return Number The new ratio
*/ function easeOut( ratio, power ) {
return ( Math.pow ( 1 - ratio, power ) + 1 );
} };

这里主要是drawChart和drawSlice两个方法。全部代码可以下载源码来学习。源代码下载

最新文章

  1. Shader实例:边缘发光和描边
  2. C#正则表达式判断输入日期格式是否正确
  3. 学习使用vim,熟悉Linux
  4. HTML CSS 中DIV内容居中汇总
  5. 判断null
  6. 升级Flash Builder 4.7中的AIR SDK
  7. 2015 年 Ruby 大盘点
  8. e-mail Web端管理
  9. 读书共享 Primer Plus C-part 12
  10. (79)Wangdao.com第十五天_JavaScript 对象的继承_prototype原型对象_封装_函数式编程
  11. Lock和Synchronized
  12. freemarker写入word【未完,待续】
  13. Oracle partition by 使用说明
  14. JavaScript术语:shim 和 polyfill
  15. HDU 2842 Chinese Rings(常数矩阵)
  16. 【刷题】BZOJ 1124 [POI2008]枪战Maf
  17. Js组件的一些写法
  18. Spark你需要知道这些
  19. Iphone6手机不同浏览器页面尺寸设计
  20. Linux服务器修改时区时间

热门文章

  1. Qt中使用cout, cin, cerr
  2. Two-Phase-Commit for Distributed In-Memory Caches--reference
  3. 常用git命令整理
  4. UVA 12378 Ball Blasting Game 【Manacher回文串】
  5. OD: DEP - Ret2Libc via VirtualProtect() &amp; VirtualAlloc()
  6. C#进程启动实例
  7. IE下判断IE版本的语句
  8. Using Notepad++ to Execute Oracle SQL
  9. 武汉科技大学ACM:1005: 华科版C语言程序设计教程(第二版)例题5.8
  10. HAOI 硬币购物