html5 (canvas) +css+js 实现画图工具

效果图:

js:

var canvas= document.getElementById("cans");
var cxt=canvas.getContext("2d");
var startX,startY,endX,endY;
var data;
var shapes = new Array();
var mousedown,mouseout;
var shape=1;

// 创建图形对象,保存该图形的开始、结束坐标以及相关属性
function create_shape(Shape,startx,starty,endx,endy){
	var color = cxt.strokeStyle.toString();
	var size = cxt.lineWidth;
	shapes[shapes.length]={
		"Shape":Shape,
		"startx":startx,
		"endx":endx,
		"starty":starty,
		"endy":endy,
		"color":color,
		"size":size,	
		"x":[],
		"y":[],
	};
}

//点击画布,获取起始坐标,由于加了标题栏,坐标存在一个偏移量
function StartPos(e){
	mousedown =0;
	mouseout = 0;	
	var rect = canvas.getBoundingClientRect();   
	startX=e.clientX - rect.left * (canvas.width / rect.width);  
	startY=e.clientY - rect.top * (canvas.height / rect.height) ;
	//如果是任意线,创建该对象
	if(shape==4){
		create_shape(4,startX,startY,endX,endY);
		shapes[shapes.length-1].x.push(startX);
		shapes[shapes.length-1].y.push(startY);
	}
	//如果是橡皮擦,调用擦除功能函数
	if(shape==5){
		delete_picture();		
	}
	//保存当前画面
	data=cxt.getImageData(0, 0, canvas.width, canvas.height);
}

// 获取终点坐标
function EndPos(e){
	if(startX!=null){
		var rect = canvas.getBoundingClientRect();   
		endX=e.clientX - rect.left * (canvas.width / rect.width);
		endY=e.clientY - rect.top * (canvas.height / rect.height) ;	
	}
}

// 松开鼠标
function Mouseup(){
	if(startX!=null&&endX!=null&&shape!=5&&shape!=4&&!(mousedown==1&&mouseout==1)){
		//创建该图形对象,并保存相关属性
			create_shape(shape,startX,startY,endX,endY);
			endX=null;		
	}	
	startX=null;
}

// 按下鼠标
function Mousedown(){
	//如果鼠标是在画布外按下的,mousedown=1
	if(mouseout == 1)
		mousedown=1;
}

// 鼠标移出了画布,mouseout=1
function MouseOut(){
	mouseout=1;
}

// 选择画直线
function line(){
	shape=1;
}
// 选择画圆
function circle(){
	shape=2
}
// 选择画矩形
function rectangle(){
	shape=3;
}
// 选择画自由线
function pencil(){
	shape=4;
}
// 选择橡皮擦
function rubber(){
	shape = 5;
}

// 鼠标移动过程中画画
function draw(){
		// 如果起始坐标不为空而且不是橡皮擦状态
		if(startX!=null&&shape!=5){
			//如果不是任意线状态,清空当前画布,展示上一个画布状态
			if(shape!=4){
				cxt.clearRect(0,0,canvas.width,canvas.height);
				cxt.putImageData(data,0,0);
			}
			//调用画图函数画图
			draw_picture(shape,startX,startY,endX,endY);
		}
}

// 画图
function draw_picture(Shape,startx,starty,endx,endy){
	switch(Shape){	
	case 1://直线
		cxt.beginPath();
		cxt.moveTo(startx,starty);
		cxt.lineTo(endx,endy);
		cxt.stroke();
		cxt.closePath();
		break;
	case 2://圆
		var temp=Math.sqrt(Math.pow((endx-startx),2)+Math.pow((endy-starty),2));
		cxt.beginPath();
		cxt.arc(startx,starty,temp,0,Math.PI*2,true);
		cxt.stroke();
		cxt.closePath();
		break;	
	case 3://矩形
		cxt.beginPath();
		cxt.rect(startx,starty,endx-startx,endy-starty);
		cxt.stroke();
		cxt.closePath();
		break;	
	case 4://任意线
		draw_pencil();
	}
}

//画任意线
function draw_pencil(){
	//如果不是橡皮擦状态,记录走过的位置坐标
	if(shape!=5){
	shapes[shapes.length-1].x.push(endX);
	shapes[shapes.length-1].y.push(endY);
	}
	//画任意线
	cxt.beginPath();
	cxt.lineJoin="round";
	cxt.moveTo(startX,startY);	
	cxt.lineTo(endX,endY);	
	cxt.stroke();
	cxt.closePath();
	startX=endX;
	startY=endY;
}

//橡皮擦功能函数,这里橡皮惨的功能是删除点击位置所存在的图形对象
function delete_picture(){
	cxt.clearRect(0,0,canvas.width,canvas.height);	// 清除画布
	var list =new Array();// 用list记录需要删除的对象的下标
	var current_size = cxt.lineWidth;// 用current_size记录当前的lineWidth
	for( var j=0 in shapes){
		var isPointIn = -1;// 标志该点是否存在当前对象中
		var Error = judgeError(shapes[j].size);
		switch(shapes[j].Shape){			
		case 1: // 直线
				//判断点到直线的距离
				var a=shapes[j].endy-shapes[j].starty;
				var b=shapes[j].startx-shapes[j].endx;
				var c=-shapes[j].endy*shapes[j].startx+shapes[j].endx*shapes[j].starty;	
				var distance=Math.pow((a*startX+b*startY+c),2)/(Math.pow(a,2)+Math.pow(b,2));	
				//如果该距离小于2,则视为该点在直线上,删除该对象,否则画出该直线
				if(distance<(Error*Error)){
					isPointIn = 1;
					break;
				}
				isPointIn = 0;
				break;
				
		case 2:// 圆
				var x1=shapes[j].startx,y1=shapes[j].starty,x2=shapes[j].endx,y2=shapes[j].endy;
				var radius=Math.sqrt(Math.pow((x2-x1),2)+Math.pow((y2-y1),2));
				cxt.arc(shapes[j].startx,shapes[j].starty,radius,0,Math.PI*2,true);
				// 判断该点到圆心的距离,与半径进行比较
				var distance = Math.sqrt(Math.pow((x1-startX),2)+Math.pow((y1-startY),2));
				if(distance<=radius+Error && distance>=radius-Error){
					isPointIn = 1;
					break;
				}				
				isPointIn = 0;
				break;			
		case 3://矩形
				// 判断该点是否在矩形边上,在则删除该对象,记录下标,否则画出该矩形
					var y1 = Math.max(shapes[j].endy,shapes[j].starty);			
					var y2 = Math.min(shapes[j].endy,shapes[j].starty);
					var x1 = Math.max(shapes[j].startx,shapes[j].endx);				
					var x2 = Math.min(shapes[j].endx,shapes[j].startx);
				if((x1<=startX+Error && x1>=startX-Error)||(x2<=startX+Error && x2>=startX-Error)){
					if(startY>=y2-Error&&startY<=y1+Error){
						isPointIn = 1;
						break;
					}
				}	
				if((y1<=startY+Error&&y1>=startY-Error)||(y2<=startY+Error&&y2>=startY-Error)){
					if(startX>=x2-Error&&startX<=x1+Error){
						isPointIn = 1;
						break;
					}
				}
				isPointIn = 0;
					break;								
		case 4:			
				cxt.beginPath();
				var k;	
				//依次取出任意线轨迹中的相邻两点,并且以这两点为对角顶点,做矩形
				for(k=0;k<shapes[j].x.length-1;k++){	
					var y1 = Math.max(shapes[j].y[k],shapes[j].y[k+1]);			
					var y2 = Math.min(shapes[j].y[k],shapes[j].y[k+1]);
					var x1 = Math.max(shapes[j].x[k],shapes[j].x[k+1]);				
					var x2 = Math.min(shapes[j].x[k],shapes[j].x[k+1]);					
					cxt.rect(shapes[j].x[k],shapes[j].y[k],shapes[j].x[k+1]
							-shapes[j].x[k],shapes[j].y[k+1]-shapes[j].y[k]);
					//如果该点在这个矩形中,则视为该点在这个对象上,删除对象
					if(startX<=x1&&startX>=x2&&startY<=y1&&startY>=y2){
						k=-1;
						break;
					}
					if(startX-Error<x1&&startX+Error>x2&&startY-Error<y1&&startY+Error>y2){
						k=-1;
						break;
					}
				}
				if(k==-1){
					cxt.closePath();			
					list.push(j);
					break;
				}
				//该点不在对象上,设置当前画布属性与该对象一致,画出该任意线
				else{
					cxt.lineWidth = shapes[j].size;
					cxt.strokeStyle = shapes[j].color;
					for(k=0;k<shapes[j].x.length-1;k++){
						cxt.beginPath();
					cxt.moveTo(shapes[j].x[k],shapes[j].y[k]);	
					cxt.lineTo(shapes[j].x[k+1],shapes[j].y[k+1]);
					cxt.stroke();
					cxt.closePath();
					}
				}			
		}
		//如果该图形不是任意线,且该点不在对象上,设置当前画布属性与该对象一致,画出该图形
		if(isPointIn==0&&shapes[j].Shape!=4){
			cxt.lineWidth = shapes[j].size;
			cxt.strokeStyle = shapes[j].color;
			draw_picture(shapes[j].Shape,shapes[j].startx,shapes[j].starty,shapes[j].endx,shapes[j].endy);
		}
		if(isPointIn ==1){
			list.push(j);
		}
	}
	//删除该点所经过的对象
	for(var k=0;k<list.length;k++){
			var a= list[k]-k;
			shapes.splice(a,1);
		}
	//恢复当前画布属性到使用橡皮擦之前
	cxt.strokeStyle = document.getElementById("color").value;
	cxt.lineWidth = current_size;
}

//判断当前画笔粗细,来决定橡皮擦的误差
function judgeError(num){
	switch(num){
		case 1: return 2;
		case 3: return 2;
		case 5: return 3;
		case 10: return 4;
		case 15: return 8;
		case 20: return 11;
	}
}

//清除画布
function clear(){
	// 提示该操作不可逆
	var reminder=confirm("The operation is irreversible!");
	// 如果确认要清除,初始化界面
	if(reminder==true){
			cxt.clearRect(0,0,canvas.width,canvas.height);
			endX=null;
			shapes =[];
	}
}

//设置笔画粗细
function line_Width(new_width){
	cxt.lineWidth = new_width;
}

//保存当前画布
function reserve(){
	//清空localstorage
	localStorage.clear();
	//把当前对象保存到localstorage
	for (var j=0 in shapes){
		var json = JSON.stringify(shapes[j]);
		localStorage.setItem(j.toString(),json);
	}
}

//打开之前保存的画布
function open(){
	//清空画布,清空对象
	cxt.clearRect(0,0,canvas.width,canvas.height);
	shapes=[];
	//把locastorag的对象添加到当前的对象组
	for(var j=0;j<localStorage.length;j++){
		var json = localStorage.getItem(j.toString());
		shapes[j] = JSON.parse(json);
	}	
	// 在画布上输出这些对象
	for( var j=0 in localStorage){
		cxt.strokeStyle = shapes[j].color;
		cxt.lineWidth = shapes[j].size;
		draw_picture(shapes[j].Shape,shapes[j].startx,shapes[j].starty,shapes[j].endx,shapes[j].endy);
	}
}

//菜单栏的响应式设计
document.getElementById("color").οnchange=function(){cxt.strokeStyle=this.value};
var x = document.getElementsByName("shape");
// 用shape_click记录当前被选中的按钮,默认为直线,直线的背景设为pink
var shape_click=0;
x[0].style.background = "pink";
for(var j=0;j<x.length;j++){
	var select_shape = j;
	//当鼠标移到图形选项上时,背景色变成蓝色
	x[j].οnmοuseοver=(function(select_shape){	
		return function(){
			var Select = select_shape;		
			if(shape_click!= Select)
				this.style.background="skyblue";
		}
	})(select_shape);
	//当鼠标离开时,恢复原来的背景色
	x[j].onmouseout = (function(select_shape){
		var Select = select_shape;
		return function(){
			if(shape_click!=Select)
				this.style.background = "black";
		}
	})(select_shape);
	//当选中该图形选项时,背景色变为粉色	
	x[j].onclick = (function(select_shape){
		var Select = select_shape;
		return function(){
			recover(shape_click);
			shape_click = Select;
			this.style.background = "pink";
		}
	})(select_shape);
}

 //当图形选项改变时,恢复上一个被选中选项的背景色
function recover(shape_num){
	document.getElementsByName("shape")[shape_num].style.background ="black";
}
Line.addEventListener("click",line,false);
Circle.addEventListener("click",circle,false);
Rectangle.addEventListener("click",rectangle,false);
Pencil.addEventListener("click",pencil,false);
Rubber.addEventListener("click",rubber,false);
Clear.addEventListener("click",clear,false);
Reserve.addEventListener("click",reserve,false);
Open.addEventListener("click",open,false);


canvas.addEventListener("mousedown",StartPos,false);
myCans.addEventListener("mousedown",Mousedown,false);
canvas.addEventListener("mouseout",MouseOut,false);
myCans.addEventListener("mouseup",Mouseup,false);
myCans.addEventListener("mousemove",EndPos,false);
myCans.addEventListener("mousemove",draw,false);



html:

 <body>
 <div id="myCans" class="mycans" >
 	<br><br>
	<form name="form1">
	<center>
	<div class="black" >
		<center>		
		<span name="shape" id="Line" > Line</span><!--
		--><span name="shape" id="Circle"  >Circle</span><!--
		--><span name="shape" id="Rectangle">Rectangle</span><!--
		--><span name="shape" id="Pencil">Pencil</span><!--
		--><span name="shape" id="Rubber">Rubber</span>
		</center>
	</div>
	<br>
	<center>
	<input type="button" value="open" id="Open">
	<input type="button" value="Save" id="Reserve">
	<input type="color" id="color" >
	<select id="linewidth" name="line_width" οnchange="line_Width(form1.line_width.options[selectedIndex].value)">
	<option value="1" slected="slected">1px</option>
	<option value="3" >3px</option>
	<option value="5" >5px</option>
	<option value="10" >10px</option>
	<option value="15" >15px</option>
	<option value="20" >20px</option>
	</select>	
	<input type="button" value="clear" id="Clear" >
	</center>	
	</center>
	</form>	
	<br><br>
	<center>
	<canvas id="cans" width="1300" height="500"></canvas>
	</center>
</div>
 </body>

css:

.black{
	background:black;
	padding:8px;
	width:500px;
	color:white;
}
canvas{
	background: white;
}
.mycans{
	height:758px;	
	background: black;
	}

body{
	margin:0;
	background: black;
	-moz-user-select: none;
	-webkit-user-select: none;
	-ms-user-select: none;
	-khtml-user-select: none;
	user-select: none;
}

span{
	display:inline-block;
	width:80px;
	cursor:pointer;
}
  • 10
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值