canvas学习(十五):学写一个字

先来张效果图:
canvas学习(十五):学写一个字

这个特效是跟着慕课网上的视频学的,视频链接如下:https://www.imooc.com/learn/284

源码和技术点已经上传到附件,有需要的可以查看、下载。

下面直接上代码(PS:代码中的注释是根据个人理解添加的,并不是老师原有的注释):

页面结构

<!doctype html>
<html lang="en">
 <head>
  <meta charset="UTF-8">
  <meta name="Generator" content="EditPlus®">
  <meta name="Author" content="">
  <meta name="Keywords" content="">
  <meta name="Description" content="">
  <title>canvas学习-学写一个字</title>
  <link type="text/css" href="handwriting.css" rel="stylesheet"/>
  <meta name="viewport"
		content="height=device-height,
				width=device-width,
				initial-scale=1.0,
				minimum-scale=1.0,
				maximum-scale=1.0,
				user-scalable=no"/>
  <script type="text/javascript" src="handwriting.js"></script>
  <script type="text/javascript" src="jquery.min.js"></script>
 </head>
 <body>
  <canvas id="myCanvas">
		您的浏览器不支持canvas,请换个浏览器试试
		<!--这句话在支持canvas的浏览器中会被忽略,不支持的则会显示出来-->
	</canvas>
	
	<!--颜色选择和清除 -->
	<div id="controller">
		<div id="black_btn" class="color_btn color_btn_selected"></div>
		<div id="red_btn" class="color_btn"></div>
		<div id="orange_btn" class="color_btn"></div>
		<div id="yellow_btn" class="color_btn"></div>
		<div id="green_btn" class="color_btn"></div>
		<div id="cyan_btn" class="color_btn"></div>
		<div id="blue_btn" class="color_btn"></div>		

		<div id="clear_btn" class="op_btn">清&nbsp;除</div>
		<div class="clearfix"></div>
	</div>
 </body>
</html>

CSS样式

#myCanvas{
	height:100%;
	display:block;
	margin:0 auto;
}
#controller{
	margin:0 auto;
}
.op_btn{
	float:right;
	margin:10px 0 0 10px;
	border:2px solid #aaa;
	width:80px;
	height:40px;
	line-height:40px;
	font-size:20px;
	text-align:center;
	border-radius:5px 5px;
	cursor:pointer;
	background-color:white;
	font-weight:bold;
	font-family:Microsoft Yahei,Arial;
}
.op_btn:hover{
	background-color:#def;
}
.clearfix{
	clear:both;
}
.color_btn{
	float:left;
	margin:10px 5px 0 0;
	border:5px solid white;
	width:40px;
	height:40px;
	border-radius:5px 5px;
	cursor:pointer;
}
.color_btn:hover{
	border:5px solid violet;
}
.color_btn_selected{
	border:5px solid blueviolet;
}
#black_btn{
	background-color:black;
}
#red_btn{
	background-color:red;
}
#orange_btn{
	background-color:orange;
}
#yellow_btn{
	background-color:yellow;
}
#green_btn{
	background-color:green;
}
#blue_btn{
	background-color:blue;
}
#cyan_btn{
	background-color:cyan;
}

JS代码

//学习链接:http://www.imooc.com/learn/284
var windowWidth = 600;
var windowHeight = 600;
var isMouseDowm=false;//鼠标是否按下

var myCanvas = null;
var context = null;
var lastLoc = {x:0,y:0};//鼠标最后一个落脚点
var lastTimestamp=0;
var lastLineWidth = -1;//最后一次笔画的大小
	
var strokeColor = "black";
window.onload=function(){
	myCanvas = document.getElementById("myCanvas");
	if(myCanvas.getContext("2d")){
		windowWidth = document.documentElement.clientWidth-20;
		windowHeight = document.documentElement.clientHeight-20-60;//60:清除按钮所需要的高度
		//取两个数中最小的那个值
		if(windowWidth>windowHeight){windowWidth = windowHeight;}
		else{windowHeight = windowWidth;}
		//alert(windowWidth);
		myCanvas.width = windowWidth;
		myCanvas.height = windowHeight;
		context =myCanvas.getContext("2d");
		//alert(myCanvas.width+"\n"+myCanvas.height);
	
		//控制功能区的大小
		$("#controller").css("width",windowWidth+"px");
		//绘制一个米字格
		drawGird();

		//阻止鼠标的默认事件
		myCanvas.onmousedown=function(e){
			e.preventDefault();
			//console.log("mouse down");
			startStroke({x:e.clientX,y:e.clientY});
		}
		myCanvas.onmouseup=function(e){
			e.preventDefault();
			//console.log("mouse up");
			endStroke();
		}
		myCanvas.onmouseout=function(e){
			e.preventDefault();
			//console.log("mouse out");
			endStroke();
		}
		myCanvas.onmousemove=function(e){
			e.preventDefault();
			if(isMouseDowm){
				//console.log("mouse move");
				moveStroke({x:e.clientX,y:e.clientY});
			}
		}

		//添加触控事件
		myCanvas.addEventListener("touchstart",function(e){
			e.preventDefault();
			var touch = e.touches[0];//只获取一个触控点
			startStroke({x:touch.pageX,y:touch.pageY});
		});
		myCanvas.addEventListener("touchend",function(e){
			e.preventDefault();
			endStroke();
		});
		myCanvas.addEventListener("touchmove",function(e){
			e.preventDefault();
			if(isMouseDowm){
				var touch = e.touches[0];//只获取一个触控点
				moveStroke({x:touch.pageX,y:touch.pageY});
			}
		});

		//清除功能
		document.getElementById("clear_btn").onclick=function(){
			//清除画布中的内容
			context.clearRect(0,0,windowWidth,windowHeight);
			//重新绘制米字格
			drawGird();
		}

		//选择颜色功能
		$(".color_btn").click(function(){
			//清除选中状态
			$(".color_btn").removeClass("color_btn_selected");
			$(this).addClass("color_btn_selected");
			strokeColor = $(this).css("background-color");
		});
		
	}else{
		return false;
	}
}

//开始绘制
function startStroke(point){
	isMouseDowm=true;
	lastLoc = windowToCanvas(point.x,point.y);
	lastTimestamp = new Date().getTime();
	//alert(lastLoc.x+","+lastLoc.y);
}

//结束绘制
function endStroke(){
	isMouseDowm=false;
}

//绘制过程中
function moveStroke(point){
	//获取鼠标所在canvas的当前位置
	var curLoc = windowToCanvas(point.x,point.y);
	
	//添加“根据写字速度的快慢调整笔画大小”的应用
	//计算两个点之间的距离
	var s = calcDistance(curLoc,lastLoc);
	//计算绘制两个点需要的时间
	var curTimestamp = new Date().getTime();
	var t = curTimestamp-lastTimestamp;//使用当前时间减去最后一个落笔的时间
	//根据s和t的值计算线的宽度
	var lineWidth = calcLineWidth(s,t);

	//alert(curLoc);
	context.beginPath();
	context.moveTo(lastLoc.x,lastLoc.y);
	context.lineTo(curLoc.x,curLoc.y);
	context.closePath();
	context.strokeStyle = strokeColor;
	context.lineCap="round";
	context.lineJoin="round";
	context.lineWidth = lineWidth;
	context.stroke();

	lastLoc = curLoc;
	lastTimestamp = curTimestamp;
	lastLineWidth = lineWidth;
}

//该方法用来将窗口坐标转换成canvas中的坐标
function windowToCanvas(x,y){
	var bbox = myCanvas.getBoundingClientRect();
	return {x:Math.round(x-bbox.left),y:Math.round(y-bbox.top)};
}

//该方法用来计算两个点之间的距离
function calcDistance(loc1,loc2){
	return Math.sqrt((loc1.x-loc2.x)*(loc1.x-loc2.x)+(loc1.y-loc2.y)*(loc1.y-loc2.y));
}

//该方法根据路程和时间计算速度,依次计算线条宽度
function calcLineWidth(s,t){
	var v = s/t;
	//先判断运笔速度较快和较慢时的情况
	var min = 5,max = 20;//笔画大小
	var min2 = 0.5,max2=10;//运笔速度大小
	var result = min;
	if(v<=min2){//运笔速度特别慢,那么笔画应该特别大
		result = max;
	}else if(v>=max2){//运笔速度特别快,那么笔画应该特别小
		result = min;
	}else{//不快也不慢的情况下,使用差值的方式逐渐减
		//计算方法:使用最大值-(当前速度与最小速度之间的差值)占(最大速度与最小速度之间差值)的比例 * (最大笔画与最小笔画之间的差值)
		result = max - (v-min2)/(max2-min2)*(max-min)
	}

	//解决平滑问题
	if(lastLineWidth==-1){//说明还没有赋值
		return result;
	}

	return lastLineWidth*3/4+result*1/4;
}

//该方法用来绘制米字格
function drawGird(){
	context.save();
	//绘制一个红色的正方形
	context.strokeStyle="rgb(230,11,9)";
	context.beginPath();
	context.rect(0,0,windowWidth,windowWidth);
	context.closePath();
	context.lineWidth = 5;
	context.stroke();

	//绘制米字格
	context.beginPath();
	context.moveTo(0,0);
	context.lineTo(windowWidth,windowHeight);

	context.moveTo(windowWidth/2,0);
	context.lineTo(windowWidth/2,windowHeight);

	context.moveTo(windowWidth,0);
	context.lineTo(0,windowHeight);

	context.moveTo(0,windowHeight/2);
	context.lineTo(windowWidth,windowHeight/2);

	context.closePath();
	context.lineWidth = 1;
	context.stroke();
	context.restore();
}

相关推荐