简单介绍

HTML5 提供了强大的Canvas元素。使用Canvas并结合Javascript 能够实现一些很强大的功能。本文就介绍一下基于HTML5 Canvas 的绘图工具的实现。废话少说,先看成品:

该应用是遵循所见即所得(WYSIWYG, What you see is what you get)原则设计的,它具有下面功能:

1. 能够绘制自由曲线、直线、矩形框和文字。

2. 能够依据须要定义线段和矩形框的颜色和宽度;

3. 你能够须要字体的大小、颜色、字体;

4. 支持undo、redo操作;

5. 支持橡皮擦功能。

6. 支持本地图片保存功能。

源代码下载       1. 读者能够去我的GitHub jPainter项目下下载,

2. 或者直接使用git 工具:https://github.com/LuanLouis/jPainter.git

       3. 或者 通过
http://download.csdn.net/detail/u010349169/7748093 下载

开发心得分享

上述功能的实现,难点倒不是非常多,值得一提的有下面几点:

1.  鼠标按下并移动 事件应该如何实现 

2. 如何实现所见即所得  的设计

3. undo redo 的实现原理

4. 画板信息另存为图片

鼠标按下并移动 事件应该如何实现

        假设我们在画板想画自由曲线,我们须要捕获鼠标按下并拖动的过程中 拖动的轨迹。

那么如何捕获这种事件呢?
熟悉javascript 事件的读者应该知道,鼠标移动事件的句柄是 onmousemove。有的读者可能觉得。能够直接为onmousemove 绑定事件处理函数。从event事件对象的button属性来推断是鼠标的哪一个键点击不即可了吗?代码例如以下:

$(function() {
$(document).mousemove(function(e){
console.log(e.button+" "+e.which);
})
});

而实际上,上述的代码执行时,当我们在页面上不管是点击鼠标的哪个键。都是输出例如以下的信息:

从输出的结果能够看出。结果和我们预期的并不一样。这是为什么呢?

原因是:  javascript的事件机制是这种。当用户触发了事件之后,javascript宿主-浏览器会将事件封装成event对象,然后依据事件的类型对event属性进行赋值。然后依据event的类型,依据什么类型的事件来调用对应的事件处理函数。举例来说。假设我们在界面上按下了鼠标的右键,那么。浏览器会首先创建一个event对象,然后对event属性赋值,而对应的button会被置为2、which为3表示右键被按下;然后javascript
会将此event对象作为參数传递给相应的事件处理函数,运行事件处理函数。

也就是说。event的button属性(以及jquery封装后的which属性)仅仅有当 click、mousedown,mousup 相应的事件处理函数才有意义。

那么。我们如何才干推断当鼠标移动时,鼠标键是否被按下呢?

解决方法:鼠标按下和松开是个过程。我们能够设置一个 flag。在鼠标按下的时候置为true,鼠标松开的时候置为false。然后在鼠标移动的事件处理函数中推断这个flag。进而能够区分鼠标是否被按下。

如果我们须要在<body> 元素上捕获 对应的鼠标事件,下面是使用jquery 进行事件处理函数的绑定:

    //onmousemove 事件
$("body").mousemove(function(e){
if(flag) {
// 鼠标被按下
} }) //onmousedown事件
$("body").onmousedown(function(e){
flag = true; // 事件处理
}) //onmouseup事件
$("body").mouseup(function(e){
flag = false; // 事件处理
})

当然,假设读者有其它的实现方案。还请指教。共同学习!

如何实现所见即所得的设计

使用Canvas画图时。其画图是通过javascript控制的,比方,我想绘制一个矩形,应该使用类似下面的代码:

var c=document.getElementById("myCanvas");
var cxt=c.getContext("2d");
cxt.fillStyle="#FF0000";
cxt.fillRect(0,0,150,75);

可是对于对于可交互的用户界面,假设想创建一个矩形,应该是通过鼠标在画板上拖动,然后能够随时看到我将要画的矩形的大小、边框、颜色等等。如何让用户能够看到动态的效果呢? 当然了,使用canvas 肯定是实现不了的。这里我想到了一个方法。就是使用<DIV> 元素模拟我们须要绘制的矩形,当用户在拖动鼠标的过程中,使用DIV 显示矩形的信息,一旦用户松开鼠标,那么。将此DIV隐藏。依据鼠标的轨迹以及矩形配置,使用javascript绘制在相应的形状。

类似地,绘画直线和加入文字也是通过HTML伪装的逻辑:

绘画直线时,用户在画板上拖动并按下鼠标时,动态地显示出一条使用HTML伪装的直线,能够随着用户鼠标的移动而变化。当用户松开鼠标时。相应模拟直线的HTML元素隐藏,调用javavscript绘制真正的直线。

加入文字时。这里使用的<textarea>元素 进行模拟文本输入框。当用户在画板上加入文字时,能够拖动鼠标设置输入框的大小,然后输入文字,一旦输入框失去焦点,则隐藏此<textarea> 元素,然后使用javascript绘制对应的文字

undo redo 的实现原理

在介绍 undo  redo 的实现之前。要先讲一下canvas的toDataURL()方法。

toDataURL()方法将canvas上所绘制的内容转换成格式png格式图片,并将图片通过base64编码。转换成形如如:data:image/png;base64,iVBORw0KGg....... 的字符串,用来表示图片数据。

(PS:对此比較困惑的读者能够自行查找关于HTML
图片 BASE64 存储
的相关问题,这个知识点还是非常重要的)

undo redo 的原理实际上非常easy。就是当每运行一次绘画,则将画板的内容转换成base64编码的字符串,存到缓存数组中去,然后在须要undo 的时候,将画板清空。再将缓存数组中的最后一次编辑的图片绘制到画板上就可以。相关的实现细节例如以下代码所看到的:

			      //undo redo
var history =new Array();
var cStep = -1; /**
* put current canvas to cache
*/
function historyPush()
{
cStep++;
if (cStep < history.length)
{
history.length = cStep;
} history.push($("#myCanvas").get(0).toDataURL());
}
/**
* function: undo
*/
function undo()
{
if (cStep >= 0)
{
cStep--;
var tempImage = new Image();
tempImage.src = history[cStep];
tempImage.onload = function () { ctx.drawImage(tempImage, 0, 0);};
} } /**
* function: redo
*/
function redo()
{
if (cStep <history.length-1)
{
clearCanvas();
cStep++;
var tempImage = new Image();
tempImage.src = history[cStep];
tempImage.onload = function () { ctx.drawImage(tempImage, 0, 0); };
}
}

画板信息存为图片

代码例如以下:

				  /**
* save canvas content as image
*/
function saveItAsImage()
{
var image = $("#myCanvas").get(0).toDataURL("image/png").replace("image/png", "image/octet-stream");
//locally save
window.location.href=image;
}

源代码下载      
1. 读者能够去我的GitHub jPainter项目下下载,

2. 或者直接使用git 工具:https://github.com/LuanLouis/jPainter.git

       3. 或者 通过 http://download.csdn.net/detail/u010349169/7748093 下载

-----------------------------------------------------------------------------------------------------------------------------------------

本文源自  http://blog.csdn.net/luanlouis/。如需转载。请注明出处,谢谢!

基于HTML5 Canvas和jQuery 的绘图工具的实现的更多相关文章

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

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

  2. 一款基于HTML5 Canvas的画板涂鸦动画

    今天给各网友分享一款基于HTML5 Canvas的画板涂鸦动画.记得之前我们分享过一款HTML5 Canvas画板工具,可以切换不同的笔刷,功能十分强大.本文今天要再来分享一款基于HTML5 Canv ...

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

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

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

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

  5. 基于html5 Canvas图表库 : ECharts

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

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

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

  7. JavaScript 基于HTML5 canvas 获取文本占用的像素宽度

    基于HTML5 canvas 获取文本占用的像素宽度   by:授客 QQ:1033553122 直接上代码   // 获取单行文本的像素宽度 getTextPixelWith(text, fontS ...

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

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

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

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

随机推荐

  1. 使用systemctl命令管理服务mysql

    启动mysql systemctl start mysqld.service 停止mysql systemctl stop mysqld.service 重启mysql systemctl resta ...

  2. Neural Networks and Deep Learning

    Neural Networks and Deep Learning This is the first course of the deep learning specialization at Co ...

  3. Leetcode 335.路径交叉

    路径交叉 给定一个含有 n 个正数的数组 x.从点 (0,0) 开始,先向北移动 x[0] 米,然后向西移动 x[1] 米,向南移动 x[2] 米,向东移动 x[3] 米,持续移动.也就是说,每次移动 ...

  4. Leetcode 334.递增的三元子序列

    递增的三元子序列 给定一个未排序的数组,判断这个数组中是否存在长度为 3 的递增子序列. 数学表达式如下: 如果存在这样的 i, j, k,  且满足 0 ≤ i < j < k ≤ n- ...

  5. [Kubernetes]深入解析Pod

    Pod是Kubernetes项目的原子调度单位 为什么需要Pod? 容器是未来云计算系统中的进程,容器镜像就是这个系统里的".exe"安装包,那Kubernetes就是操作系统. ...

  6. OkHttpUtil

    package jp.co.gunmabank.util import android.os.Handlerimport android.os.Looperimport com.google.gson ...

  7. 【Luogu】P1594护卫队(前缀和+DP)

    TM搞了半天的二维DP方程还是错的. 这是题目链接: 设f[i]表示前i辆车顺利通过的最小时间. 则对于每一个i枚举该组车的起点j,然后从所有的f[j]+Min[j][i]中选一个最小的. Min[j ...

  8. BZOJ 1226 [SDOI2009]学校食堂Dining ——状压DP

    看到B<=8,直接状态压缩即可. dp[i][j][k]表示当前相对位置是关于i的,并且i以前的已经就餐完毕,j表示i和之后的就餐情况,k表示上一个就餐的人的相对位置. 然后Dp即可 #incl ...

  9. 刷题总结——保留道路(ssoj)

    题目: 题目背景 161114-练习-DAY1-AHSDFZ T3 题目描述 很久很久以前有一个国家,这个国家有 N 个城市,城市由 1,2,3,…,,N 标号,城市间有 M 条双向道路,每条道路都有 ...

  10. BS4(BeautifulSoup4)的使用--find_all()篇

    可以直接参考 BS4文档:https://www.crummy.com/software/BeautifulSoup/bs4/doc/index.zh.html#find-all 注意的是: 1.有些 ...