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


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

      

  • 相关阅读:
    设计模式天天练。
    系统资料库msdb置疑或者不可用的解决方法
    依赖注入IOC
    重载、重写、隐藏的区别
    ASP.NET中的HttpWorkerRequest对像及其应用
    ASP.NET的错误处理机制
    Web.Config
    asp.net 2.0页面生命周期
    FileUpLoad控件上传大容量文件
    大文件上传
  • 原文地址:https://www.cnblogs.com/xunhuang/p/8483501.html
Copyright © 2020-2023  润新知