昨天我们分享了一款基于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两个方法。全部代码可以下载源码来学习。源代码下载

基于HTML5 Canvas的饼状图表实现教程的更多相关文章

  1. 基于HTML5 Canvas的线性区域图表教程

    之前我们看到过很多用jQuery实现的网页图表,有些还是比较实用的.今天我们来介绍一款基于HTML5 Canvas的线性区域图表应用,这个图表应用允许你使用多组数据来同时展示,并且将数据结果以线性图的 ...

  2. 基于html5 Canvas图表库 : ECharts

    ECharts开源来自百度商业前端数据可视化团队,基于html5 Canvas,是一个纯Javascript图表库,提供直观,生动,可交互,可个性化定制的数据可视化图表.创新的拖拽重计算.数据视图.值 ...

  3. 18个基于 HTML5 Canvas 开发的图表库

    如今,HTML5 可谓如众星捧月一般,受到许多业内巨头的青睐.很多Web开发者也尝试着用 HTML 5 来制作各种各样的富 Web 应用.HTML 5 规范引进了很多新特性,其中之一就是 Canvas ...

  4. 基于HTML5 Canvas实现的图片马赛克模糊特效

    效果请点击下面网址: http://hovertree.com/texiao/html5/1.htm 一.开门见山受美国肖像画家Chuck Close的启发,此脚本通过使用HTML5 canvas元素 ...

  5. 基于html5 canvas和js实现的水果忍者网页版

    今天爱编程小编给大家分享一款基于html5 canvas和js实现的水果忍者网页版. <水果忍者>是一款非常受喜欢的手机游戏,刚看到新闻说<水果忍者>四周年新版要上线了.网页版 ...

  6. 基于HTML5 Canvas的网页画板实现教程

    HTML5的功能非常强大,尤其是Canvas的应用更加广泛,Canvas画布上面不仅可以绘制任意的图形,而且可以实现多种多样的动画,甚至是一些交互式的应用,比如网页网版.这次我们要来看的就是一款基于H ...

  7. 基于HTML5 Canvas实现用户交互

    很多人都有这样的疑问,基于HTML5 Canvas实现的元素怎么和用户进行交互?在这里我们用到HT for Web(http://www.hightopo.com/guide/guide/core/b ...

  8. 基于html5 canvas 的客户端异步上传图片的插件,支持客户端压缩图片尺寸

    /** * Created by xx on 15-05-28. * 基于html5 canvas 的客户端异步上传画片的插件 * 在实际应用中,常常要用于上传图片的功能.在现在越来越多的手机weba ...

  9. 基于 HTML5 Canvas 的智能安防 SCADA 巡逻模块

    基于 HTML5 Canvas 的智能安防 SCADA 巡逻模块 前言 最近学习了 HT for Web flow 插件,除了正常的 flow 效果,其中还有两个十分好用的两个接口 getPercen ...

随机推荐

  1. Android Studio Gradle 缓存目录设置

    ======================================================== 笔者:qiujuer 博客:blog.csdn.net/qiujuer 站点:www. ...

  2. [CSAPP笔记][第九章虚拟存储器][吐血1500行]

    9.虚拟存储器 为了更加有效地管理存储器且少出错,现代系统提供了对主存的抽象概念,叫做虚拟存储器(VM). 虚拟存储器是硬件异常,硬件地址翻译,主存,磁盘文件和内核软件的完美交互. 为每个进程提供一个 ...

  3. C:应用于字符串处理函数

    出于对C的不够熟悉,在读代码的过程中,平凡出现的字符串处理函数,成为了一个理解代码的大问题. 为了更方便的读取和理解代码,特意将接触到的字符串处理函数列出,方便查询: 1.strstr(str1,st ...

  4. Oracle 空间管理

    表空间:组数据文件的一种途径 分类: 目录表空间(sysaux) 常表空间(system) 系统临时表空间(temp) 用户临时表空间(user) undo表空间 创建表空间: //表空间名为name ...

  5. python面对对象编程----1:BlackJack(21点)

    昨天读完了<Mastering Object-oriented Python>的第一部分,做一些总结. 首先,第一部分总过八章,名字叫Pythonic Classes via Specia ...

  6. Ecstore中Mootools和Jquery如何同时存在,解决冲突?

  7. <customErrors>节点说明1

    <customErrors>节点用于定义一些自定义错误信息的信息.此节点有Mode和defaultRedirect两个属性, 其中defaultRedirect属性是一个可选属性,表示应用 ...

  8. char * 和 void *

    POSIX.1 将 read函数的原型做了修改,经典的定义为 int read(int filedes, char *buf, unsigned nbytes); 修改为 ssize_t read(i ...

  9. ssh key报but this does not map back to the address – POSSIBLE BREAK-IN ATTEMPT!错误

    在/etc/hosts 文件加上对方的主机名  ip地址,可以ping通主机名即可.

  10. SQL server概述

    sqlserver中包含的对象: 数据库.事务日志.索引.文件组.数据库关系图.视图.存储过程.用户自定义函数.用户.角色.程序集.表.报表.全文目录.用户自定义数据类型 数据库实际上是最高层对象,其 ...