基于HTML5 Canvas的网页画板实现教程
HTML5的功能非常强大,尤其是Canvas的应用更加广泛,Canvas画布上面不仅可以绘制任意的图形,而且可以实现多种多样的动画,甚至是一些交互式的应用,比如网页网版。这次我们要来看的就是一款基于HTML5 Canvas的网页画板,在这里仅对一些关键性的代码进行记录,大家也可以下载全部源代码研究。
你也可以再这里查看在线演示
下面我们来简单地分析一下实现这个HTML5网页画板的原理及代码,代码由HTML以及Javascript组成,主要还是Javascript代码。
HTML代码:
- <div style="width:530px;margin:10px auto">
- <div id="canvasDiv"></div>
- </div>
HTML代码非常简单,仅仅是构造了一个canvas容器,我们的画板就在这个地方生成。
Javascript代码:
首先我们通过一组变量来定义画板的样式,以及一些数据的初始化:

- var canvas;
- var context;
- var canvasWidth = 490;
- var canvasHeight = 220;
- var padding = 25;
- var lineWidth = 8;
- var colorPurple = "#cb3594";
- var colorGreen = "#659b41";
- var colorYellow = "#ffcf33";
- var colorBrown = "#986928";
- var outlineImage = new Image();
- var crayonImage = new Image();
- var markerImage = new Image();
- var eraserImage = new Image();
- var crayonBackgroundImage = new Image();
- var markerBackgroundImage = new Image();
- var eraserBackgroundImage = new Image();
- var crayonTextureImage = new Image();
- var clickX = new Array();
- var clickY = new Array();
- var clickColor = new Array();
- var clickTool = new Array();
- var clickSize = new Array();
- var clickDrag = new Array();
- var paint = false;
- var curColor = colorPurple;
- var curTool = "crayon";
- var curSize = "normal";
- var mediumStartX = 18;
- var mediumStartY = 19;
- var mediumImageWidth = 93;
- var mediumImageHeight = 46;
- var drawingAreaX = 111;
- var drawingAreaY = 11;
- var drawingAreaWidth = 267;
- var drawingAreaHeight = 200;
- var toolHotspotStartY = 23;
- var toolHotspotHeight = 38;
- var sizeHotspotStartY = 157;
- var sizeHotspotHeight = 36;
- var sizeHotspotWidthObject = new Object();
- sizeHotspotWidthObject.huge = 39;
- sizeHotspotWidthObject.large = 25;
- sizeHotspotWidthObject.normal = 18;
- sizeHotspotWidthObject.small = 16;
- var totalLoadResources = 8;
- var curLoadResNum = 0;

接下来开始准备画布,也就是初始化Canvas对象:

- function prepareCanvas()
- {
- // Create the canvas (Neccessary for IE because it doesn't know what a canvas element is)
- var canvasDiv = document.getElementById('canvasDiv');
- canvas = document.createElement('canvas');
- canvas.setAttribute('width', canvasWidth);
- canvas.setAttribute('height', canvasHeight);
- canvas.setAttribute('id', 'canvas');
- canvasDiv.appendChild(canvas);
- if(typeof G_vmlCanvasManager != 'undefined') {
- canvas = G_vmlCanvasManager.initElement(canvas);
- }
- context = canvas.getContext("2d"); // Grab the 2d canvas context
- // Note: The above code is a workaround for IE 8 and lower. Otherwise we could have used:
- // context = document.getElementById('canvas').getContext("2d");
- // Load images
- // -----------
- crayonImage.onload = function() { resourceLoaded();
- };
- crayonImage.src = "images/crayon-outline.png";
- //context.drawImage(crayonImage, 0, 0, 100, 100);
- markerImage.onload = function() { resourceLoaded();
- };
- markerImage.src = "images/marker-outline.png";
- eraserImage.onload = function() { resourceLoaded();
- };
- eraserImage.src = "images/eraser-outline.png";
- crayonBackgroundImage.onload = function() { resourceLoaded();
- };
- crayonBackgroundImage.src = "images/crayon-background.png";
- markerBackgroundImage.onload = function() { resourceLoaded();
- };
- markerBackgroundImage.src = "images/marker-background.png";
- eraserBackgroundImage.onload = function() { resourceLoaded();
- };
- eraserBackgroundImage.src = "images/eraser-background.png";
- crayonTextureImage.onload = function() { resourceLoaded();
- };
- crayonTextureImage.src = "images/crayon-texture.png";
- outlineImage.onload = function() { resourceLoaded();
- };
- outlineImage.src = "images/watermelon-duck-outline.png";
- // Add mouse events
- // ----------------
- $('#canvas').mousedown(function(e)
- {
- // Mouse down location
- var mouseX = e.pageX - this.offsetLeft;
- var mouseY = e.pageY - this.offsetTop;
- if(mouseX < drawingAreaX) // Left of the drawing area
- {
- if(mouseX > mediumStartX)
- {
- if(mouseY > mediumStartY && mouseY < mediumStartY + mediumImageHeight){
- curColor = colorPurple;
- }else if(mouseY > mediumStartY + mediumImageHeight && mouseY < mediumStartY + mediumImageHeight * 2){
- curColor = colorGreen;
- }else if(mouseY > mediumStartY + mediumImageHeight * 2 && mouseY < mediumStartY + mediumImageHeight * 3){
- curColor = colorYellow;
- }else if(mouseY > mediumStartY + mediumImageHeight * 3 && mouseY < mediumStartY + mediumImageHeight * 4){
- curColor = colorBrown;
- }
- }
- }
- else if(mouseX > drawingAreaX + drawingAreaWidth) // Right of the drawing area
- {
- if(mouseY > toolHotspotStartY)
- {
- if(mouseY > sizeHotspotStartY)
- {
- var sizeHotspotStartX = drawingAreaX + drawingAreaWidth;
- if(mouseY < sizeHotspotStartY + sizeHotspotHeight && mouseX > sizeHotspotStartX)
- {
- if(mouseX < sizeHotspotStartX + sizeHotspotWidthObject.huge){
- curSize = "huge";
- }else if(mouseX < sizeHotspotStartX + sizeHotspotWidthObject.large + sizeHotspotWidthObject.huge){
- curSize = "large";
- }else if(mouseX < sizeHotspotStartX + sizeHotspotWidthObject.normal + sizeHotspotWidthObject.large + sizeHotspotWidthObject.huge){
- curSize = "normal";
- }else if(mouseX < sizeHotspotStartX + sizeHotspotWidthObject.small + sizeHotspotWidthObject.normal + sizeHotspotWidthObject.large + sizeHotspotWidthObject.huge){
- curSize = "small";
- }
- }
- }
- else
- {
- if(mouseY < toolHotspotStartY + toolHotspotHeight){
- curTool = "crayon";
- }else if(mouseY < toolHotspotStartY + toolHotspotHeight * 2){
- curTool = "marker";
- }else if(mouseY < toolHotspotStartY + toolHotspotHeight * 3){
- curTool = "eraser";
- }
- }
- }
- }
- else if(mouseY > drawingAreaY && mouseY < drawingAreaY + drawingAreaHeight)
- {
- // Mouse click location on drawing area
- }
- paint = true;
- addClick(mouseX, mouseY, false);
- redraw();
- });
- $('#canvas').mousemove(function(e){
- if(paint==true){
- addClick(e.pageX - this.offsetLeft, e.pageY - this.offsetTop, true);
- redraw();
- }
- });
- $('#canvas').mouseup(function(e){
- paint = false;
- redraw();
- });
- $('#canvas').mouseleave(function(e){
- paint = false;
- });
- }

看起来很复杂,前面主要是初始化canvas的背景图片,后面主要是初始化画笔事件,像click、mouseup、mouseleave等鼠标事件。
下面是draw的主要方法:

- function redraw()
- {
- // Make sure required resources are loaded before redrawing
- if(curLoadResNum < totalLoadResources){ return; }
- clearCanvas();
- var locX;
- var locY;
- if(curTool == "crayon")
- {
- // Draw the crayon tool background
- context.drawImage(crayonBackgroundImage, 0, 0, canvasWidth, canvasHeight);
- // Purple
- locX = (curColor == colorPurple) ? 18 : 52;
- locY = 19;
- context.beginPath();
- context.moveTo(locX + 41, locY + 11);
- context.lineTo(locX + 41, locY + 35);
- context.lineTo(locX + 29, locY + 35);
- context.lineTo(locX + 29, locY + 33);
- context.lineTo(locX + 11, locY + 27);
- context.lineTo(locX + 11, locY + 19);
- context.lineTo(locX + 29, locY + 13);
- context.lineTo(locX + 29, locY + 11);
- context.lineTo(locX + 41, locY + 11);
- context.closePath();
- context.fillStyle = colorPurple;
- context.fill();
- if(curColor == colorPurple){
- context.drawImage(crayonImage, locX, locY, mediumImageWidth, mediumImageHeight);
- }else{
- context.drawImage(crayonImage, 0, 0, 59, mediumImageHeight, locX, locY, 59, mediumImageHeight);
- }
- // Green
- locX = (curColor == colorGreen) ? 18 : 52;
- locY += 46;
- context.beginPath();
- context.moveTo(locX + 41, locY + 11);
- context.lineTo(locX + 41, locY + 35);
- context.lineTo(locX + 29, locY + 35);
- context.lineTo(locX + 29, locY + 33);
- context.lineTo(locX + 11, locY + 27);
- context.lineTo(locX + 11, locY + 19);
- context.lineTo(locX + 29, locY + 13);
- context.lineTo(locX + 29, locY + 11);
- context.lineTo(locX + 41, locY + 11);
- context.closePath();
- context.fillStyle = colorGreen;
- context.fill();
- if(curColor == colorGreen){
- context.drawImage(crayonImage, locX, locY, mediumImageWidth, mediumImageHeight);
- }else{
- context.drawImage(crayonImage, 0, 0, 59, mediumImageHeight, locX, locY, 59, mediumImageHeight);
- }
- // Yellow
- locX = (curColor == colorYellow) ? 18 : 52;
- locY += 46;
- context.beginPath();
- context.moveTo(locX + 41, locY + 11);
- context.lineTo(locX + 41, locY + 35);
- context.lineTo(locX + 29, locY + 35);
- context.lineTo(locX + 29, locY + 33);
- context.lineTo(locX + 11, locY + 27);
- context.lineTo(locX + 11, locY + 19);
- context.lineTo(locX + 29, locY + 13);
- context.lineTo(locX + 29, locY + 11);
- context.lineTo(locX + 41, locY + 11);
- context.closePath();
- context.fillStyle = colorYellow;
- context.fill();
- if(curColor == colorYellow){
- context.drawImage(crayonImage, locX, locY, mediumImageWidth, mediumImageHeight);
- }else{
- context.drawImage(crayonImage, 0, 0, 59, mediumImageHeight, locX, locY, 59, mediumImageHeight);
- }
- // Yellow
- locX = (curColor == colorBrown) ? 18 : 52;
- locY += 46;
- context.beginPath();
- context.moveTo(locX + 41, locY + 11);
- context.lineTo(locX + 41, locY + 35);
- context.lineTo(locX + 29, locY + 35);
- context.lineTo(locX + 29, locY + 33);
- context.lineTo(locX + 11, locY + 27);
- context.lineTo(locX + 11, locY + 19);
- context.lineTo(locX + 29, locY + 13);
- context.lineTo(locX + 29, locY + 11);
- context.lineTo(locX + 41, locY + 11);
- context.closePath();
- context.fillStyle = colorBrown;
- context.fill();
- if(curColor == colorBrown){
- context.drawImage(crayonImage, locX, locY, mediumImageWidth, mediumImageHeight);
- }else{
- context.drawImage(crayonImage, 0, 0, 59, mediumImageHeight, locX, locY, 59, mediumImageHeight);
- }
- }
- else if(curTool == "marker")
- {
- // Draw the marker tool background
- context.drawImage(markerBackgroundImage, 0, 0, canvasWidth, canvasHeight);
- // Purple
- locX = (curColor == colorPurple) ? 18 : 52;
- locY = 19;
- context.beginPath();
- context.moveTo(locX + 10, locY + 24);
- context.lineTo(locX + 10, locY + 24);
- context.lineTo(locX + 22, locY + 16);
- context.lineTo(locX + 22, locY + 31);
- context.closePath();
- context.fillStyle = colorPurple;
- context.fill();
- if(curColor == colorPurple){
- context.drawImage(markerImage, locX, locY, mediumImageWidth, mediumImageHeight);
- }else{
- context.drawImage(markerImage, 0, 0, 59, mediumImageHeight, locX, locY, 59, mediumImageHeight);
- }
- // Green
- locX = (curColor == colorGreen) ? 18 : 52;
- locY += 46;
- context.beginPath();
- context.moveTo(locX + 10, locY + 24);
- context.lineTo(locX + 10, locY + 24);
- context.lineTo(locX + 22, locY + 16);
- context.lineTo(locX + 22, locY + 31);
- context.closePath();
- context.fillStyle = colorGreen;
- context.fill();
- if(curColor == colorGreen){
- context.drawImage(markerImage, locX, locY, mediumImageWidth, mediumImageHeight);
- }else{
- context.drawImage(markerImage, 0, 0, 59, mediumImageHeight, locX, locY, 59, mediumImageHeight);
- }
- // Yellow
- locX = (curColor == colorYellow) ? 18 : 52;
- locY += 46;
- context.beginPath();
- context.moveTo(locX + 10, locY + 24);
- context.lineTo(locX + 10, locY + 24);
- context.lineTo(locX + 22, locY + 16);
- context.lineTo(locX + 22, locY + 31);
- context.closePath();
- context.fillStyle = colorYellow;
- context.fill();
- if(curColor == colorYellow){
- context.drawImage(markerImage, locX, locY, mediumImageWidth, mediumImageHeight);
- }else{
- context.drawImage(markerImage, 0, 0, 59, mediumImageHeight, locX, locY, 59, mediumImageHeight);
- }
- // Yellow
- locX = (curColor == colorBrown) ? 18 : 52;
- locY += 46;
- context.beginPath();
- context.moveTo(locX + 10, locY + 24);
- context.lineTo(locX + 10, locY + 24);
- context.lineTo(locX + 22, locY + 16);
- context.lineTo(locX + 22, locY + 31);
- context.closePath();
- context.fillStyle = colorBrown;
- context.fill();
- if(curColor == colorBrown){
- context.drawImage(markerImage, locX, locY, mediumImageWidth, mediumImageHeight);
- }else{
- context.drawImage(markerImage, 0, 0, 59, mediumImageHeight, locX, locY, 59, mediumImageHeight);
- }
- }
- else if(curTool == "eraser")
- {
- context.drawImage(eraserBackgroundImage, 0, 0, canvasWidth, canvasHeight);
- context.drawImage(eraserImage, 18, 19, mediumImageWidth, mediumImageHeight);
- }else{
- alert("Error: Current Tool is undefined");
- }
- if(curSize == "small"){
- locX = 467;
- }else if(curSize == "normal"){
- locX = 450;
- }else if(curSize == "large"){
- locX = 428;
- }else if(curSize == "huge"){
- locX = 399;
- }
- locY = 189;
- context.beginPath();
- context.rect(locX, locY, 2, 12);
- context.closePath();
- context.fillStyle = '#333333';
- context.fill();
- // Keep the drawing in the drawing area
- context.save();
- context.beginPath();
- context.rect(drawingAreaX, drawingAreaY, drawingAreaWidth, drawingAreaHeight);
- context.clip();
- var radius;
- var i = 0;
- for(; i < clickX.length; i++)
- {
- if(clickSize[i] == "small"){
- radius = 2;
- }else if(clickSize[i] == "normal"){
- radius = 5;
- }else if(clickSize[i] == "large"){
- radius = 10;
- }else if(clickSize[i] == "huge"){
- radius = 20;
- }else{
- alert("Error: Radius is zero for click " + i);
- radius = 0;
- }
- context.beginPath();
- if(clickDrag[i] && i){
- context.moveTo(clickX[i-1], clickY[i-1]);
- }else{
- context.moveTo(clickX[i], clickY[i]);
- }
- context.lineTo(clickX[i], clickY[i]);
- context.closePath();
- if(clickTool[i] == "eraser"){
- //context.globalCompositeOperation = "destination-out"; // To erase instead of draw over with white
- context.strokeStyle = 'white';
- }else{
- //context.globalCompositeOperation = "source-over"; // To erase instead of draw over with white
- context.strokeStyle = clickColor[i];
- }
- context.lineJoin = "round";
- context.lineWidth = radius;
- context.stroke();
- }
- //context.globalCompositeOperation = "source-over";// To erase instead of draw over with white
- context.restore();
- // Overlay a crayon texture (if the current tool is crayon)
- if(curTool == "crayon"){
- context.globalAlpha = 0.4; // No IE support
- context.drawImage(crayonTextureImage, 0, 0, canvasWidth, canvasHeight);
- }
- context.globalAlpha = 1; // No IE support
- // Draw the outline image
- context.drawImage(outlineImage, drawingAreaX, drawingAreaY, drawingAreaWidth, drawingAreaHeight);
- }

其实HTML5说白了还是需要很多Javascript支持,不过Canvas非常不错,可以让你在上面自由地绘制图形和动画。这款基于HTML5 Canvas的网页画板就是一个很好的例子
基于HTML5 Canvas的网页画板实现教程的更多相关文章
- 基于HTML5 Canvas的线性区域图表教程
之前我们看到过很多用jQuery实现的网页图表,有些还是比较实用的.今天我们来介绍一款基于HTML5 Canvas的线性区域图表应用,这个图表应用允许你使用多组数据来同时展示,并且将数据结果以线性图的 ...
- 基于html5 canvas和js实现的水果忍者网页版
今天爱编程小编给大家分享一款基于html5 canvas和js实现的水果忍者网页版. <水果忍者>是一款非常受喜欢的手机游戏,刚看到新闻说<水果忍者>四周年新版要上线了.网页版 ...
- 一款基于HTML5 Canvas的画板涂鸦动画
今天给各网友分享一款基于HTML5 Canvas的画板涂鸦动画.记得之前我们分享过一款HTML5 Canvas画板工具,可以切换不同的笔刷,功能十分强大.本文今天要再来分享一款基于HTML5 Canv ...
- 基于html5 Canvas图表库 : ECharts
ECharts开源来自百度商业前端数据可视化团队,基于html5 Canvas,是一个纯Javascript图表库,提供直观,生动,可交互,可个性化定制的数据可视化图表.创新的拖拽重计算.数据视图.值 ...
- 基于HTML5 Canvas和jQuery 的绘图工具的实现
简单介绍 HTML5 提供了强大的Canvas元素.使用Canvas并结合Javascript 能够实现一些很强大的功能.本文就介绍一下基于HTML5 Canvas 的绘图工具的实现.废话少说,先看成 ...
- 18个基于 HTML5 Canvas 开发的图表库
如今,HTML5 可谓如众星捧月一般,受到许多业内巨头的青睐.很多Web开发者也尝试着用 HTML 5 来制作各种各样的富 Web 应用.HTML 5 规范引进了很多新特性,其中之一就是 Canvas ...
- 基于HTML5 Canvas实现的图片马赛克模糊特效
效果请点击下面网址: http://hovertree.com/texiao/html5/1.htm 一.开门见山受美国肖像画家Chuck Close的启发,此脚本通过使用HTML5 canvas元素 ...
- 基于HTML5 Canvas实现用户交互
很多人都有这样的疑问,基于HTML5 Canvas实现的元素怎么和用户进行交互?在这里我们用到HT for Web(http://www.hightopo.com/guide/guide/core/b ...
- 基于html5 canvas 的客户端异步上传图片的插件,支持客户端压缩图片尺寸
/** * Created by xx on 15-05-28. * 基于html5 canvas 的客户端异步上传画片的插件 * 在实际应用中,常常要用于上传图片的功能.在现在越来越多的手机weba ...
随机推荐
- 电子科大POJ "a^b"
a ^ b Time Limit: 3000/1000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others) C-sources: ...
- 杭电oj1236 排名
Tips:此题比较简单,最好将每一个学生的信息构建一个结构体,另外需要注意的是,若分数相同,排序按姓名排序,我看网上很多都是使用<algorithm>中的sort算法,只需重写cmp函数即 ...
- H264 编码详解
H264 编码详解(收集转载) (1) x264_param_default( x264_param_t *param ) 作用: 对编码器进行参数设定 cqm:量化表相关信息 csp: ...
- TagBuilder 性能如此低下?
本文来自:http://www.cnblogs.com/zhuisha/archive/2010/03/12/1684022.html 需要通过ASP.NET MVC生成一个列表,MVC里面根正苗红的 ...
- spark安装mysql与hive
第一眼spark安装文件夹lib\spark-assembly-1.0.0-hadoop2.2.0.jar\org\apache\spark\sql下有没有hive文件夹,假设没有的话先下载支持hiv ...
- 超级强大的SVG SMIL animation动画详解
本文花费精力惊人,具有先驱前瞻性,转载规则以及申明见文末,当心予以追究.本文地址:http://www.zhangxinxu.com/wordpress/?p=4333 //zxx: 本文的SVG在有 ...
- StringBuffer工具类整理(一)
package com.gzcivil.utils; /** * 同StringBuffer * * @author Dragon * @time 2013-3-1 */ public class S ...
- UILabel头文件常见属性
text : default is nil 文本属性,默认值是 nil @property(nullable, nonatomic,copy) NSString *text; font : defau ...
- 基于TcpDump和pcap文件分析的Android平台网络抓包程序设计与实现【随便】
一.考虑使用Tcpdump,将抓到的包保存到cap文件中,然后手动分析.参考资料:1. http://www.cnblogs.com/tt-0411/archive/2012/09/23/269936 ...
- yii2 安装过程中的问题及解决方法
一.php版本要求5.4+,如果使用wamp组合包,建议更换 二.各种模块的支持,一般只要修改php.ini文件,去掉相应模块前的注释即可. 注意,Intl extension模块的支持需要将 ...