前阵子手上的事情比较少,研究了一下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>