前幾天在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" > </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; });