jquery画图插件jPainter

一、总结

一句话总结:四年前的项目,四年无更新,不好用。

二、基于HTML5 Canvas和jQuery 的画图工具的实现

简介

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 的原理实际上很简单,就是当每执行一次绘画,则将画板的内容转换成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 下载

 

jquery画图插件jPainter的更多相关文章

  1. 深入学习jQuery自定义插件

    原文地址:jQuery自定义插件学习 1.定义插件的方法 对象级别的插件扩展,即为jQuery类的实例增加方法, 调用:$(选择器).函数名(参数);      $(‘#id’).myPlugin(o ...

  2. [jQuery]jQuery DataTables插件自定义Ajax分页实现

    前言 昨天在博客园的博问上帮一位园友解决了一个问题,我觉得有必要记录一下,万一有人也遇上了呢. 问题描述 园友是做前端的,产品经理要求他使用jQuery DataTables插件显示一个列表,要实现分 ...

  3. 使用jQuery.form插件,实现完美的表单异步提交

    传送门:异步编程系列目录…… 时间真快,转眼一个月快结束了,一个月没写博客了!手开始生了,怎么开始呢…… 示例下载:使用jQuery.form插件,实现完美的表单异步提交.rar 月份的尾巴,今天的主 ...

  4. 为jQuery写插件

    很多场合,我们都会调用jQuery的插件去完成某个功能,比如slider. 如下图,做一个div,通过“$( "#slider" ).slider();”的方式直接将div变成sl ...

  5. bootstrap-简洁实用的jQuery手风琴插件

    前端 <html lang="zh"> <head> <meta charset="UTF-8"> <meta htt ...

  6. 推荐15款响应式的 jQuery Lightbox 插件

    利用现代 Web 技术,网络变得越来越轻巧与.模态框是突出展现内容的重要形式,能够让用户聚焦到重要的内容上去.在这个列表中,我们编制了15款响应式的 jQuery 灯箱库,这将有助于开发人员创建和设计 ...

  7. Chocolat.js – 响应式的 jQuery Lightbox 插件

    Chocolat.js 使您能够显示一个或多个图像在同一页面上.给用户展示一组图片缩略图,可以显示全页或块.Chocolat.js 可以很好地处理所有主要的浏览器.它在下面这些浏览器测试通过:IE7+ ...

  8. 让网站动起来!12款优秀的 jQuery 动画插件推荐

    如今,大多数设计师和开发人员被要客户要求开发动态的网站.创造视觉震撼和醒目的动态网站是艰巨的任务,因为它需要大量的努力和创造力.在网络上有大量的工具和插件可用于创建网站动画.许多开发人员正在使用 HT ...

  9. 一个强大的jquery分页插件

    点击这里查看效果 这个分页插件使用方便,引用keleyidivpager.js和keleyidivpager.css文件,然后在htm(或者php,aspx,jsp等)页面中对分页总数,参数名,前缀后 ...

随机推荐

  1. asp.net 前后台数据交互方式(转)

    https://blog.csdn.net/luckyrass/article/details/38758007 一.前台直接输出后台传递的数据 后台代码: // .aspx.cs public st ...

  2. arcgis webapp builder 安装试用

    ArcGIS WebApp Builder 是针对开发者的,用于高速构建基于HTML5/Javascript 技术的美观的 Web应用的一个工具. 用过Flex版本号的AppBuilder应该非常清楚 ...

  3. php设置http请求头信息和响应头信息

    php设置http请求头信息和响应头信息 设置请求服务器的头信息可以用fsockopen,curl组件,header函数只能用来设置客户端响应的头信息,不能设置服务器的头信息. 例子;  一.head ...

  4. .NET中StringBuilder用法实例分析

    string s1 = "33"; string s2 = "44"; string s3 = "55"; //需求是把s1 s2 s3拼接 ...

  5. VUE笔记 - 列表过渡动画 v-enter, v-leave-to | v-enter-active, v-leave-active | v-move

    本例要结合过渡动画四个过程的示意图一起理解. https://cn.vuejs.org/v2/guide/transitions.html 疑问: v-for="(item,i) in li ...

  6. C# socket beginAccept

    服务端:    需要增加的命名空间:using System.Threading;using System.Net;using System.Net.Sockets;    以下是具体实现.C# co ...

  7. 【习题 6-5 UVA-1600】Patrol Robot

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 设dis[x][y][z]表示到(x,y)连续走了z个墙的最短路 bfs一下就ok [代码] /* 1.Shoud it use l ...

  8. LeetCode Algorithm 03_Longest Substring Without Repeating Characters

    Given a string, find the length of the longest substring without repeating characters. For example, ...

  9. POJ 3669 Meteor Shower BFS 水~

    http://poj.org/problem?id=3669 题目大意: 一个人从(0,0)出发,这个地方会落下陨石,当陨石落在(x,y)时,会把(x,y)这个地方和相邻的的四个地方破坏掉,求该人到达 ...

  10. MySQL字符编码问题,Incorrect string value

    MySQL上插入汉字时报错例如以下.详细见后面分析. Incorrect string value: '\xD0\xC2\xC8A\xBEW' for column 'ctnr' at row 1 M ...