前陣子手上的事情比較少,研究了一下canvas畫圖,寫了一個簡單的demo,寫字和復顯寫字過程的功能。今天抽了個空把邏輯和代碼整理記錄一下。
先把效果圖展示一下:
下面附上源碼:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0"> <script src="./jquery.js"></script> <style> #canvas{ display: block; margin: 0 auto; } #controller{ width:800px; margin:0 auto; } .op_btn{ float: right; margin:10px 0 0 10px; border:2px solid #aaa; width:80px; height:40px; line-height: 40px; text-align: center; font-size: 20px; border-radius: 5px; cursor: pointer; background-color:#fff; font-weight: bold } .op_btn:hover{ background-color:#def; } .clearfix{ clear: both; } </style> </head> <body> <canvas id="canvas"></canvas> <div id="controller"> <div id="clear_btn" class="op_btn">清除</div> <div id="submit" class="op_btn">完成</div> <div class="clearfix"></div> </div> <canvas id="canvas_show"></canvas> </body> <script> //調整畫筆粗細 var canvasWidth = Math.min(800,$(window).width()-20); var canvasHeight = canvasWidth; var isMouseDown = false; var lastLoc = {x:0,y:0};//用戶上一次繪制的位置 var lastTimestamp = 0; var lastLineWidth = -1; //以下兩個變量(locHistory ,endTime )用於復顯寫字過程,將軌跡坐標和時間保存於本地,實際項目中應存於服務器端 var locHistory = []; var endTime = ''; var canvas = document.getElementById("canvas"); var context = canvas.getContext("2d"); canvas.height = canvasHeight; canvas.width = canvasWidth; $('#controller').css('width',canvasWidth+'px') drawGrid() document.getElementById('clear_btn').onclick = function(){ context.clearRect(0,0,canvasWidth,canvasHeight) drawGrid();//重繪底部寫字格 localStorage.removeItem('locHistory') // 清除本地數據,實際項目中不需要 } $('#submit').click(function(){ //保存軌跡和時間到本地,實際項目中應將數據傳給服務器端 localStorage.setItem('locHistory',JSON.stringify(locHistory)) }) //開始繪制 function beginStroke(point){ isMouseDown = true // console.log('mouse down') lastTimestamp = new Date().getTime() lastLoc = windowToCanvas(point.x,point.y) locHistory.push({x:lastLoc.x,y:lastLoc.y,width:0,t:lastTimestamp-endTime}) } function endStroke(){ locHistory.push({x:lastLoc.x,y:lastLoc.y,width:0,t:0}) isMouseDown = false; endTime = new Date().getTime() console.log(locHistory) } function moveStroke(point){ // console.log("mouse move") var curLoc = windowToCanvas(point.x,point.y) var curTimestamp = new Date().getTime(); var s = calcDistance(curLoc,lastLoc) var t = curTimestamp- lastTimestamp; var lineWidth = calcLineWidth(t,s) console.log(lineWidth) //draw context.beginPath() context.moveTo(lastLoc.x,lastLoc.y) context.lineTo(curLoc.x,curLoc.y) locHistory.push({x:curLoc.x,y:curLoc.y,with:lineWidth,t:t}) context.lineWidth = lineWidth context.lineCap = "round" context.linJoin = "round" context.stroke() ; //每次過程結束時,將結束值賦給初始值,一直延續 lastLoc = curLoc lastTimestamp = curTimestamp lastLineWidth = lineWidth } canvas.onmousedown = function(e){ e.preventDefault(); beginStroke({x:e.clientX,y:e.clientY}) } canvas.onmouseup = function(e){ e.preventDefault(); endStroke() } canvas.onmouseout = function(e){ e.preventDefault(); endStroke() } canvas.onmousemove = function(e){ e.preventDefault(); if(isMouseDown){ moveStroke({x:e.clientX,y:e.clientY}) } } // 移動端觸控 canvas.addEventListener('touchstart',function(e){ e.preventDefault(); touch = e.touches[0]; beginStroke({x:touch.pageX , y:touch.pageY}) }) canvas.addEventListener('touchmove',function(e){ e.preventDefault(); if(isMouseDown){ touch = e.touches[0]; moveStroke({x:touch.pageX , y:touch.pageY}) } }) canvas.addEventListener('touchend',function(e){ e.preventDefault(); endStroke() }) // 根據速度計算畫筆粗細,計算方式不唯一,可根據需要修改 function calcLineWidth(t,s){ var v = s/t; var resultLineWidth; if(v <= 0.1){ resultLineWidth = 20; }else if(v >= 10){ resultLineWidth = 4 }else{ resultLineWidth = 20 - (v-0.1)/(10-0.1)*(20-4) } if(lastLineWidth == -1){ return resultLineWidth } return lastLineWidth*2/3 + resultLineWidth*1/3 } function calcDistance(loc1,loc2){ return Math.sqrt((loc1.x - loc2.x)*(loc1.x - loc2.x) + (loc1.y - loc2.y)*(loc1.y - loc2.y)) //通過起始結束坐標x,y值計算路程長度 } function windowToCanvas(x,y){ var bbox = canvas.getBoundingClientRect(); //獲取canvas的位置信息 return {x:Math.round(x-bbox.left),y:Math.round(y-bbox.top)} //返回當前鼠標相對於canvas的位置 } function drawGrid(){ context.save()//保存context的原始狀態 context.strokeStyle = "rgb(230,11,9)"; context.beginPath() context.moveTo(3,3) context.lineTo(canvasWidth-3,3) context.lineTo(canvasWidth - 3,canvasHeight -3) context.lineTo(3,canvasHeight -3) context.closePath() context.lineWidth = "6" context.stroke() context.beginPath() context.moveTo(0,0) context.lineTo(canvasWidth,canvasHeight) context.moveTo(canvasWidth,0) context.lineTo(0,canvasHeight) context.moveTo(canvasWidth/2,0) context.lineTo(canvasWidth/2,canvasHeight) context.moveTo(0,canvasHeight/2) context.lineTo(canvasWidth,canvasHeight/2) context.closePath() context.lineWidth = "1" context.stroke() context.restore()//避免影響外部的程序 } //復顯繪制過程 var locaData = JSON.parse(localStorage.getItem('locHistory')) var i = 0; console.log(locaData) showFont() function showFont(){ i++; if(i<locaData.length-1 && locaData[i].t != 0){ setTimeout(function(){ context.beginPath() context.moveTo(locaData[i].x,locaData[i].y) context.lineTo(locaData[i-0+1].x,locaData[i-0+1].y) context.lineWidth = locaData[i].with; context.lineCap = "round" context.linJoin = "round" context.stroke() ; showFont() },locaData[i].t) }else if(i<locaData.length-1){ showFont() } } </script> </html>