前几天在canvas——画板中做了个很简陋的画板,只能画简单的线条,可以选择颜色和线条粗度,今天在此简陋的画板上增加了新的形状,撤销,保存,橡皮擦等功能,虽然功能还是很简单,刚接触canvas,过程中还是遇到了很多困难。

形状包括:铅笔、直线、直角矩形,圆角矩形、原型(利用圆角矩形能够画出很多其他好玩的图形)

提供橡皮擦、撤销、重做、清屏、保存功能

1、html中使用两个canvas,一个相当于蒙版用于缓存

<div id="imgContent">
<canvas id="canvas" width="600" height="490">
浏览器不支持~
</canvas>
<!--此canvas用于暂存graph,绘制过程中需要清除context,因而需要缓存,否则更换形状时会出现问题 -->
<canvas id="canvasTemp"width="600" height="490" >&nbsp;</canvas>
</div>

2、主要鼠标事件:

        $(canvasTemp).unbind();
$(canvasTemp).bind('mousedown',down);
$(canvasTemp).bind('mousemove',move);
$(canvasTemp).bind('mouseup',up);
$(canvasTemp).bind('mouseout',out);

3、更换图形时需清空蒙版canvas即canvasTemp的context环境,并且将上次绘制内容添加到canvas中

4、另外需要为各种形状添加鼠标移动时的图标,例如选择circle时鼠标未按下时需要绘制一个小圆

    else if(type === "circle"){
clearContext();
if(mouseState === true){ //鼠标按下时
ctxTemp.beginPath();
var radius = Math.sqrt((oldX - newX) * (oldX - newX) + (oldY - newY) * (oldY - newY));
ctxTemp.arc(oldX,oldY,radius,0,Math.PI * 2,false);
ctxTemp.stroke();
}else{
//鼠标没有按下时出现小圆
ctxTemp.beginPath();
//ctxTemp.strokeStyle ='#9F35FF';
ctxTemp.arc(newX,newY,10 ,0, Math.PI * 2,false);
ctxTemp.stroke();
}

5、需要存储绘制的过程,以便撤销和重做

    function saveImageHistory(){
cancelTimes = 0;
imageHistoryList.push(canvas.toDataURL());
if(imageHistoryList.length > 0){
document.getElementById("undoImage").src="./images/undo.png";
}
}

6、由于body背景设置为蓝色,canvas fill 的是白色,因而用橡皮擦时如果直接用clearRect会擦出蓝色背景,因而采用填充白色代替

//ctx.clearRect(newX - lineWeight * 10 ,  newY - lineWeight * 10 , lineWeight * 20 , lineWeight * 20);
//重新填充白色背景,否则擦出后是颜色背景
ctx.fillStyle = "white";
ctx.fillRect(newX - lineWeight * 10 , newY - lineWeight * 10 , lineWeight * 20 , lineWeight * 20);

7.问题总结:

 1)body为蓝色背景,因而想将canvas背景设置为白色,然后尝试将canvas设置背景,这种方式是不行的,只能使用fillRect方式为canvas填充背景,此种方式为橡皮擦的擦除带来了问题,橡皮擦的擦除应该也使用fillRect方式而不能使用clearRect方式

   2)DOM中定义的id会再javasvript中以变量自动定义,因而一定注意js中与id同名的变量或者方法可能不起作用

 3)使用原生js时事件解绑中遇到问题,尝试了removeEventListener和最原始的将绑定事件置为null,但是没起作用,没找到解决方法因而使用了jQuery的unbind,希望有人指导

8.代码:

var canvas,
ctx,
canvasTemp,
ctxTemp,
mouseState = false, //初始化鼠标是否按下和坐标点位置, true为按下
oldX = 0,
oldY = 0,
pencilX = 0,
pencilY = 0,
lineColor = "black",
lineWeight = 1,
canvasTop,
canvasLeft,
canvasWidth = 700,
canvasHeight = 550,
cancelTimes = 0, //撤销次数
imageHistoryList = new Array(); //存储图片绘制历史信息 onLoad(function(){
init(); //初始化canvas //颜色和线宽绑定点击事件
var colorDiv = document.getElementById("color");
var lineDiv = document.getElementById("lineWeight");
colorDiv.addEventListener("click", chosen);
lineDiv.addEventListener("click", chosen); document.getElementById("pencil").click(); //未选择图形时默认为铅笔
document.getElementById("blackBtn").click(); //默认黑色
document.getElementById("line1").click(); //默认线宽2px
}); var chosen = function(event){
var parentNode = event.target.parentNode;
for(var i=0; i<parentNode.childNodes.length; i++){
parentNode.childNodes[i].className = "";
}
event.target.className = "chosen";
}; var init = function(){
//初始化canvas
canvas = document.getElementById("canvas");
canvas.width = canvasWidth;
canvas.height = canvasHeight;
//判断是否支持canvas
if(!canvas || !canvas.getContext){
return false;
}
ctx = canvas.getContext("2d"); //初始化画图区域白色背景
ctx.fillStyle = "white";
ctx.fillRect(0, 0, 700, 550); //初始化canvasTemp
canvasTemp = document.getElementById("canvasTemp");
canvasTemp.width = canvasWidth;
canvasTemp.height = canvasHeight;
ctxTemp = canvasTemp.getContext("2d"); canvasTop = canvas.offsetTop,
canvasLeft = canvas.offsetLeft; //初始化撤销和重做按钮状态
document.getElementById("undoImage").src="./images/undoDis.png";
document.getElementById("redoImage").src="./images/redoDis.png"; }; //绘制picture
var drawPicture = function(type, obj){
var down, //鼠标按下事件
up, //鼠标弹起事件
move, //鼠标移动事件
out, //鼠标离开区域
chosen, //图形选中
clearContext; //清除canvas环境 down = function(event){
mouseState = true;
event = event || window.event; oldX = event.clientX - canvasLeft;
pencilX = event.clientX - canvasLeft;
oldY = event.clientY - canvasTop;
pencilY = event.clientY - canvasTop; ctxTemp.strokeStyle = lineColor;
ctxTemp.lineWidth = lineWeight;
ctxTemp.lineCap = "round"; clearContext(); ctxTemp.moveTo(oldX, oldY); if(type === "rubber"){
//ctx.clearRect(oldX-lineWeight*10, oldY-lineWeight*10, lineWeight*20, lineWeight*20);
//重新填充白色背景,否则擦出后是颜色背景
ctx.fillStyle = "white";
ctx.fillRect(oldX-lineWeight*10, oldY-lineWeight*10, lineWeight*20, lineWeight*20);
}
}; up = function(event){
//更改鼠标状态
mouseState = false;
event = event || window.event; //将canvasTemp中graph添加到canvas中
var image = new Image();
if(type !== "rubber"){
image.src = canvasTemp.toDataURL();
image.onload = function(){
ctx.drawImage(image, 0, 0, image.width, image.height);
clearContext(); //保存历史记录,撤销时使用
saveImageHistory(); };
} }; chosen = function(obj){
var shape = document.getElementById("shape");
for(var i=0; i<shape.childNodes.length; i++){
shape.childNodes[i].className = "";
}
if(type !== "rubber"){
document.getElementById("rubber").className = "";
}
obj.className = "chosen";
}; //鼠标按下,拖动画图
move = function(event){
var newX = event.clientX - canvasLeft;
var newY = event.clientY - canvasTop;
if(type === "pencil"){
if(mouseState === true){
ctxTemp.beginPath();
ctxTemp.moveTo(pencilX, pencilY);
ctxTemp.lineTo(newX, newY);
ctxTemp.stroke();
pencilX = newX;
pencilY = newY;
}
}else if(type === "rec"){
clearContext();
if(mouseState === true){
ctxTemp.beginPath();
ctxTemp.moveTo(oldX, oldY);
ctxTemp.lineTo(newX, oldY);
ctxTemp.lineTo(newX, newY);
ctxTemp.lineTo(oldX, newY);
ctxTemp.lineTo(oldX, oldY);
ctxTemp.stroke();
}else{
//鼠标移动时出现矩形
ctxTemp.beginPath();
ctxTemp.moveTo(newX - 10 , newY - 10 );
ctxTemp.lineTo(newX + 10 , newY - 10 );
ctxTemp.lineTo(newX + 10 , newY + 10 );
ctxTemp.lineTo(newX - 10 , newY + 10 );
ctxTemp.lineTo(newX- 10 , newY - 10 );
ctxTemp.stroke();
}
}else if(type === "line"){
if(mouseState === true){
ctxTemp.beginPath();
clearContext();
ctxTemp.moveTo(oldX, oldY);
ctxTemp.lineTo(newX, newY);
ctxTemp.stroke();
}
}else if(type === "circle"){
clearContext();
if(mouseState === true){
ctxTemp.beginPath();
var radius = Math.sqrt((oldX - newX) * (oldX - newX) + (oldY - newY) * (oldY - newY));
ctxTemp.arc(oldX,oldY,radius,0,Math.PI * 2,false);
ctxTemp.stroke();
}else{
//鼠标没有按下时出现小圆
ctxTemp.beginPath();
//ctxTemp.strokeStyle ='#9F35FF';
ctxTemp.arc(newX,newY,10 ,0, Math.PI * 2,false);
ctxTemp.stroke();
}
}else if(type === "roundRec"){
clearContext();
if(mouseState === true){
ctxTemp.beginPath();
ctxTemp.moveTo(oldX, oldY);
ctxTemp.lineTo(newX, oldY);
ctxTemp.arcTo(newX+20,oldY, newX+20, oldY+20, 20);
ctxTemp.lineTo(newX+20, newY);
ctxTemp.arcTo(newX+20,newY+20, newX, newY+20, 20);
ctxTemp.lineTo(oldX, newY+20);
ctxTemp.arcTo(oldX-20,newY+20, oldX-20, newY, 20);
ctxTemp.lineTo(oldX-20, oldY+20);
ctxTemp.arcTo(oldX-20,oldY, oldX, oldY, 20);
ctxTemp.stroke();
}else{
//鼠标没有按下时出现小的圆角矩形
ctxTemp.beginPath();
//ctxTemp.strokeStyle ='#9F35FF';
ctxTemp.moveTo(newX - 10 , newY - 10);
ctxTemp.lineTo(newX, newY - 10);
ctxTemp.arcTo(newX + 10,newY - 10, newX + 10, newY, 10);
ctxTemp.lineTo(newX + 10, newY + 10);
ctxTemp.arcTo(newX + 10, newY + 20, newX, newY + 20, 10);
ctxTemp.lineTo(newX - 10, newY + 20);
ctxTemp.arcTo(newX - 20,newY + 20, newX - 20,newY + 10,10);
ctxTemp.lineTo(newX - 20,newY);
ctxTemp.arcTo(newX - 20,newY - 10, newX - 10,newY - 10, 10);
ctxTemp.stroke();
}
}else if(type === "rubber"){
//鼠标没有按下时出现橡皮擦图标
ctxTemp.beginPath();
clearContext();
ctxTemp.strokeStyle = '#000000';
ctxTemp.moveTo(newX - lineWeight * 10 , newY - lineWeight * 10 );
ctxTemp.lineTo(newX + lineWeight * 10 , newY - lineWeight * 10 );
ctxTemp.lineTo(newX + lineWeight * 10 , newY + lineWeight * 10 );
ctxTemp.lineTo(newX - lineWeight * 10 , newY + lineWeight * 10 );
ctxTemp.lineTo(newX- lineWeight * 10 , newY - lineWeight * 10 );
ctxTemp.stroke();
if(mouseState === true){
//ctx.clearRect(newX - lineWeight * 10 , newY - lineWeight * 10 , lineWeight * 20 , lineWeight * 20);
//重新填充白色背景,否则擦出后是颜色背景
ctx.fillStyle = "white";
ctx.fillRect(newX - lineWeight * 10 , newY - lineWeight * 10 , lineWeight * 20 , lineWeight * 20); }
} }; out = function(){
clearContext();
};
clearContext = function(){
ctxTemp.clearRect(0,0,canvas.width,canvas.height);
}; //将选中的形状置为选中状态
chosen(obj); //canvas添加鼠标事件, 鼠标移动、鼠标按下和鼠标弹起
/*
canvasTemp.addEventListener("mousemove", move);
canvasTemp.addEventListener("mousedown", down);
canvasTemp.addEventListener("mouseup", up);
canvasTemp.addEventListener("mouseout", out);
*/ /*
* 本来尝试使用原生js来写,但是在上面的事件解绑中遇到问题
* 尝试了removeEventListener和最原始的将绑定事件置为null,但是没起作用,没找到解决方法因而使用了jQuery的unbind
*
*/ $(canvasTemp).unbind();
$(canvasTemp).bind('mousedown',down);
$(canvasTemp).bind('mousemove',move);
$(canvasTemp).bind('mouseup',up);
$(canvasTemp).bind('mouseout',out);
}; /*
* 保存picture历史记录
*/
function saveImageHistory(){
cancelTimes = 0;
imageHistoryList.push(canvas.toDataURL());
if(imageHistoryList.length > 0){
document.getElementById("undoImage").src="./images/undo.png";
}
} var exportImage = function(event){
var imgSrc = canvas.toDataURL("image/png");
document.getElementById("image").src = imgSrc;
}; /*
* undo 撤销一次
*/
var undo = function(){
cancelTimes++;
if(cancelTimes >= imageHistoryList.length+1){
cancelTimes--;
return;
}else if(cancelTimes == imageHistoryList.length){
document.getElementById("redoImage").src="./images/redo.png";
ctx.clearRect(0, 0, canvasWidth, canvasHeight);
document.getElementById("undoImage").src="./images/undoDis.png";
}else{
document.getElementById("redoImage").src="./images/redo.png";
ctx.clearRect(0, 0, canvasWidth, canvasHeight);
var image = new Image();
image.src = imageHistoryList[imageHistoryList.length-1-cancelTimes];
image.onload = function(){
ctx.drawImage(image, 0, 0, image.width, image.height);
};
}
}; /*
* redo,重做上一次操作
*/
var redo = function(){
cancelTimes--;
if(cancelTimes < 0){
cancelTimes++;
return;
}else{
if(cancelTimes == 0){
document.getElementById("redoImage").src="./images/redoDis.png";
document.getElementById("undoImage").src="./images/undo.png";
}
ctx.clearRect(0, 0, canvasWidth, canvasHeight);
var image = new Image();
image.src = imageHistoryList[imageHistoryList.length-1-cancelTimes];
image.onload = function(){
ctx.drawImage(image, 0, 0, image.width, image.height);
};
}
}; /**
*清屏
*/
function clearScreen(){
ctx.clearRect(0, 0, canvasWidth, canvasHeight);
ctxTemp.clearRect(0, 0, canvasWidth, canvasHeight);
} /**
* 工具函数onLoad,当文档载入完成时调用一个函数
*/
function onLoad(f){
if(onLoad.loaded){
window.setTimeout(f,0);
}else if(window.addEventListener){
window.addEventListener("load",f,false);
}else if(window.attachEvent){
window.attachEvent("onload",f);
}
}
onLoad.loaded = false;
onLoad(function(){
onLoad.loaded = true;
});

canvas-画图改进版的更多相关文章

  1. html5之canvas画图基础

    HTML5+CSS3的好处是,你可以编写一个页面分别用于不同的平台,只需要设置不同的css样式就可以了,现在基本主流浏览器都支持全新的HTML5和CSS3,因为它的跨平台开发.因为是原生代码所以它的页 ...

  2. Canvas画图在360浏览器中跑偏的问题

    问题描述,canvas画图的js代码中编写的是画正方形的代码,结果在360浏览器上变成了长方形,不知道怎么回事,请问各位大神是否遇到过此类问题? <!DOCTYPE html> <h ...

  3. h5 canvas 画图

    h5 canvas 画图 <!DOCTYPE html> <html lang="en"> <head> <meta charset=&q ...

  4. html5 Canvas画图3:1px线条模糊问题

    点击查看原文地址: html5 Canvas画图3:1px线条模糊问题 本文属于<html5 Canvas画图系列教程> 接上一篇canvas画线条教程 上次我们讲到,canvas有时候会 ...

  5. 使用 canvas 画图时图像文字模糊的解决办法

    最近在使用 canvas 画图的时候,遇到了图像文字模糊的问题,解决思路就是根据分辨率创建不同尺寸的画布.以下是创建高分辨率画布的代码: /** * 创建高分辨率画布 * @param w 画布宽 * ...

  6. html5 canvas 画图移动端出现锯齿毛边的解决方法

    使用HTML5的canvas元素画出来的.在移动端手机上测试都发现画图有一点锯齿问题 出现这个问题的原因应该是手机的宽是720像素的, 而这个canvas是按照小于720像素画出来的, 所以在720像 ...

  7. HTML5 canvas画图

    HTML5 canvas画图 HTML5 <canvas> 标签用于绘制图像(通过脚本,通常是 JavaScript).不过,<canvas> 元素本身并没有绘制能力(它仅仅是 ...

  8. HTML5 Canvas画图与动画学习59例

    HTML5 Canvas画图与动画学习59例 学习HTML5 动画,画图的好资料. HTML5 Canvas画图与动画学习59例

  9. html Canvas 画图 能够选择并能移动

    canvas 画图,能够选中所画的图片并且能够随意移动图片 <html xmlns="http://www.w3.org/1999/xhtml"> <head r ...

  10. 毕业设计总结(1)-canvas画图

    去年6月底完成的毕业设计,到现在也才开始给它做个总结,里面有很多可以学习和借鉴的东西. 我的毕业设计的题目是“一种路径规划算法的改进与设计”,具体的要求可参见下面的表格: 题目 一种路径规划算法的改进 ...

随机推荐

  1. 24、Javascript BOM

    BOM(Browser Object Model)浏览器对象模型,一组浏览器提供的API. window对象 window对象表示当前浏览器的窗口,是Javascript的顶级对象,所有创建的对象.函 ...

  2. 使用Github建立个人博客

    总的说来 这个当有node.js 和gitbub的账号后,搭建一个自己的博客,想想还是挺美的事! 由于要把整个流程说清楚 估计lz还没这个实力,所以都是继承前辈们的经验,自己再添加一点遇到的问题和解决 ...

  3. BroadcastReceiver和Intetnt的理解 Day34

    BroadcastReceiver和Intetnt的理解 Day34 mobile4.0 短信监控 问题堆栈 1. 下载开源项目View.网址自己fork一下 2. ContentProvider原理 ...

  4. SQL内外左右交叉连接

    什么是连接查询? 概念:根据两个表或多个表的列之间的关系,从这些表中查询数据. 目的:实现多个表查询操作. 一般是用作关联两张或两张以上的数据表时用的.看起来有点抽象,我们举个例子,做两张表:学生表( ...

  5. XmlHttpRequest 使用

    1. IE7以后对xmlHttpRequest 对象的创建在不同浏览器上是兼容的.下面的方法是考虑兼容性的,实际项目中一般使用Jquery的ajax请求,可以不考虑兼容性问题. function ge ...

  6. oracle学习笔记2:创建修改表

    1.创建表 CREATE TABLE ORDERINFO ( ORDERID NUMBER(*, 0) NOT NULL , ORDERCODE VARCHAR2(20 BYTE) NOT NULL ...

  7. JS 定時刷新父類頁面

    function timeCount() { var url = "MAC.aspx"; parent.location.href = url; } function beginC ...

  8. Input的readonly 属性与disabled属性

    readonly 不可编辑,可以获得焦点,背景颜色默认灰色,值的字体颜色默认为灰色,值可以在请求中传递 disabled 不可编辑,不可以获得焦点,背景颜色默认灰色,值的字体颜色默认为灰色,值不可以在 ...

  9. 217. Contains Duplicate(C++)

    217. Contains Duplicate Given an array of integers, find if the array contains any duplicates. Your ...

  10. windows8一直更新不了的问题————解决方案

    以下是微软官方工程师的详细解答: 尊敬的佐先生: 您好! 感谢您联系微软技术支持!我是微软技术支持工程师,我姓张.我将协助您解决有关问题.您的问题编号是SRX 1274238225 对于您当前的更新问 ...