canvas-画图改进版

原文:canvas-画图改进版

 

前几天在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;
    });
    

 

 

时间: 2024-11-30 09:18:56

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

JS实现简单的Canvas画图实例

这篇文章介绍了JS实现简单的Canvas画图实例代码,有需要的朋友可以参考一下   定义变量:[javascript] 复制代码 代码如下: var startX; var startY; var endX; var endY; var radius; var canvas = document.getElementById("myCanvas"); var context = canvas.getContext("2d"); var select = docume

Android canvas画图操作之切割画布实现方法(clipRect)_Android

本文实例讲述了Android canvas画图操作之切割画布实现方法.分享给大家供大家参考,具体如下: android切割画布的历程不算很难,可是理解起来也比较麻烦,这里写一下我的理解 但是不一定正确: canvas.clipRect(30, 30, 70, 70, Region.Op.XOR); 最后一个参数有多个选择分别是: //DIFFERENCE是第一次不同于第二次的部分显示出来 //REPLACE是显示第二次的 //REVERSE_DIFFERENCE 是第二次不同于第一次的部分显示

android 在 view 里我使用一个 自定义的 canvas 画图 出现问题

问题描述 android 在 view 里我使用一个 自定义的 canvas 画图 出现问题 在 view 里我使用一个 自定义 canvas 画图.先在 canvas 里画出背景, 再画出几个图片. 背景是一个张图片.当触发 onTouchEvent 后,图片移动 canvas 重画背景画出来会有图片移动的痕迹. 如果背景指定了一个颜色就不会有这样的问题. 怎么解决? canvas = new Canvas(bgbitmap); 绘制背景: canvas.drawColor(selectedC

Android canvas画图操作之切割画布实现方法(clipRect)

本文实例讲述了Android canvas画图操作之切割画布实现方法.分享给大家供大家参考,具体如下: android切割画布的历程不算很难,可是理解起来也比较麻烦,这里写一下我的理解 但是不一定正确: canvas.clipRect(30, 30, 70, 70, Region.Op.XOR); 最后一个参数有多个选择分别是: //DIFFERENCE是第一次不同于第二次的部分显示出来 //REPLACE是显示第二次的 //REVERSE_DIFFERENCE 是第二次不同于第一次的部分显示

用Swt的canvas画图后,怎样保存所画的图,需要写详细点

问题描述 如题 解决方案 解决方案二:不懂,帮顶~解决方案三:我的实现方法是把你画的图的数据保存在一个文件中,比如是一个多边型,然后把点的坐标保存在一个File中,下次用到的时间只是去读这个文件就可以了,当然具体情况还是要具体处理的我个人是这样处理的,解决方案四:我已经实现了,还是比较简单的,但现在最郁闷的就是,只能够获取当前canvas区域的所画图片,却不能够获取整个图片.(图片大小比画板大).解决方案五:不懂解决方案六:呵呵你这样的需求我个人觉得要用到gef框架了解决方案七:貌似gis中的地

JS实现简单的Canvas画图实例_javascript技巧

定义变量:[javascript] 复制代码 代码如下: var startX; var startY; var endX; var endY; var radius; var canvas = document.getElementById("myCanvas"); var context = canvas.getContext("2d"); var select = document.getElementsByTagName("select"

玩转html5&amp;lt;canvas&amp;gt;画图

玩转html5<canvas>画图 导航 前言 基本知识 绘制矩形 清除矩形区域 圆弧 路径 绘制线段 绘制贝塞尔曲线 线性渐变 径向渐变(发散) 图形变形(平移.旋转.缩放) 矩阵变换(图形变形的机制) 图形组合 给图形绘制阴影 绘制图像(图片平铺.裁剪.像素处理[不只图像.包括其他绘制图形]) 绘制文字 保存和恢复状态(context) 保存文件 结合setInterval制作动画 结语.demo下载   前言      <canvas></canvas>是html

html5-HTML5如何在现有的背景图片上进行画图?(canvas如何实现)

问题描述 HTML5如何在现有的背景图片上进行画图?(canvas如何实现) 就是我已经实现了canvas画图功能,我现在想在一张已有的图片上进行画图,如何实现? 解决方案 给画布设置背景,然后直接绘图就可以了http://bbs.csdn.net/topics/350078984

html5 canvas-HTML5 canvas,画图时有什么属性或者方法可以看到画图的路径过程

问题描述 HTML5 canvas,画图时有什么属性或者方法可以看到画图的路径过程 HTML5 canvas,画图时有什么属性或者方法可以看到画图的路径过程?画一个矩形,要看到矩形是怎么画出来的,一个过程动画,谢谢大大给我解答 解决方案 Html5 Canvas画图html5-canvas画图html5 canvas画图

canvas需要在标签里直接定义宽高

 以前用canvas画图时,都是直接在canvas标签里直接写上宽高,没有问题,但也没有探究过为什么宽高要直接写在canvas标签里,因为各个资料的例子上都是这么写的.今天王sir提出了一个问题:如果把宽高写在<style>里,看看会有什么不同.自己试了以下,果然有问题. 先看一下代码: 代码如下: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title&g