canvas-畫圖改進版 canvas——畫板

 

前幾天在canvas——畫板中作了個很簡陋的畫板,只能畫簡單的線條,能夠選擇顏色和線條粗度,今天在此簡陋的畫板上增長了新的形狀,撤銷,保存,橡皮擦等功能,雖然功能仍是很簡單,剛接觸canvas,過程當中仍是遇到了不少困難。html

 

形狀包括:鉛筆、直線、直角矩形,圓角矩形、原型(利用圓角矩形可以畫出不少其餘好玩的圖形)java

提供橡皮擦、撤銷、重作、清屏、保存功能canvas

 

 

一、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>

 

二、主要鼠標事件:緩存

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

 

三、更換圖形時需清空濛版canvas即canvasTemp的context環境,而且將上次繪製內容添加到canvas中app

 

四、另外須要爲各類形狀添加鼠標移動時的圖標,例如選擇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();
                }

 

五、須要存儲繪製的過程,以便撤銷和重作工具

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

 

六、因爲body背景設置爲藍色,canvas fill 的是白色,於是用橡皮擦時若是直接用clearRect會擦出藍色背景,於是採用填充白色代替post

//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;
    });
    
相關文章
相關標籤/搜索