canvas结合js实现写字绘图功能

前阵子手上的事情比较少,研究了一下canvas画图,写了一个简单的demo,写字和复显写字过程的功能。今天抽了个空把逻辑和代码整理记录一下。

先把效果图展示一下:

  canvas结合js实现写字绘图功能

下面附上源码:

  

<!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 ></canvas>
	<div >
		<div >清除</div>
		<div >完成</div>
		<div class="clearfix"></div>
	</div>

	<canvas ></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>