前阵子手上的事情比较少,研究了一下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{ 800px; margin:0 auto; } .op_btn{ float: right; margin:10px 0 0 10px; border:2px solid #aaa; 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,0,t:lastTimestamp-endTime}) } function endStroke(){ locHistory.push({x:lastLoc.x,y:lastLoc.y,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>