canvas 综合练习
此案例为前端小白所写,还望多多指教,欢迎review
大图在此
知识点总结
- Element.getBoundingClientRect(); // 获取元素的大小及其相对于视口的位置
- context.setLineDash([10]); // 一个Array数组。一组描述交替绘制线段和间距(坐标空间单位)长度的数字。 如果数组元素的数量是奇数, 数组的元素会被复制并重复。例如, [5, 15, 25] 会变成 [5, 15, 25, 5, 15, 25]。
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no" />
<meta charset="UTF-8" />
<meta name="keywords" content="" />
<meta name="description" content="" />
<title>学写一个字</title>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<style>
*{padding:0;margin:0;}
body{font-family:"Microsoft YaHei";}
a{text-decoration:none;color:#333;}
.canvas{
display:block;
margin:30px auto;
}
.controlbox{
width:500px;
margin:0 auto;
}
.controlbox .btn{
display:inline-block;
width:30px;
height:30px;
margin:5px;
border:3px solid #fff;
color:#fff;
}
.controlbox .btn:hover{
border-color:#26c;
opacity:0.8;
filter:alpha(opacity=80);
}
.controlbox .btn.active{
border-color:#666;
}
.input_color{
display:block;
float:left;
padding:0 10px;
height:35px;
margin:5px;
border:1px solid;
}
.btn_reset,
.btn_more{
display:inline-block;
padding:0 10px;
line-height:35px;
margin:5px;
text-align:center;
background-color:#ccc;
border:1px solid;
cursor:pointer;
}
.btn_more{
float:left;
}
.btn_reset{
float:right;
}
.btn_reset:hover,
.btn_more:hover{
background-color:#eee;
}
</style>
</head>
<body>
<canvas id="canvas" class="canvas">Your browser didn't support this tag (canvas)</canvas>
<div class="controlbox" id="controlbox">
<a href="javascript:void(0);" class="btn active" style="background-color:#000000;"><!-- black --></a>
<a href="javascript:void(0);" class="btn" style="background-color:#ff0000;"><!-- red --></a>
<a href="javascript:void(0);" class="btn" style="background-color:#ffa500;"><!-- orange --></a>
<a href="javascript:void(0);" class="btn" style="background-color:#008000;"><!-- green --></a>
<a href="javascript:void(0);" class="btn" style="background-color:#0000ff;"><!-- blue --></a>
<a href="javascript:void(0);" class="btn" style="background-color:#800080;"><!-- purple --></a>
<div>
<input type="color" value="#666666" id="input_color" class="input_color" title="请选择颜色" />
<label class="btn_more" id="btn_more">应用此颜色</label>
<span class="btn_reset" id="btn_reset">清除</span>
<div style="clear:both"></div>
</div>
</div>
<!--scripts-->
<script type="text/javascript">
// 主
function init() {
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var canvasWidth=Math.min(500,$(window).width()-30);
var canvasHeight=canvasWidth;
var isMouseDown=false; // 鼠标按下flag
var lastPos={x:0,y:0}; // 历史位置
var lastTime=new Date().getTime(); // 历史时间戳
var lastLineWidth=-1; // 历史线宽
var defaultFontColor="#000000"; // 默认绘制字体颜色
var $btnColors=$(".btn");
// 设置画布大小
canvas.width=canvasWidth;
canvas.height=canvasHeight;
// 设置控制盒的大小
$("#controlbox").css("width",canvasWidth);
// 米字格绘制函数
function drawBlock() {
var borderLineWidth=6; // 边框宽
ctx.save();
// 边框
ctx.beginPath();
ctx.moveTo(borderLineWidth/2,borderLineWidth/2);
ctx.lineTo(canvasWidth-borderLineWidth/2,borderLineWidth/2);
ctx.lineTo(canvasWidth-borderLineWidth/2,canvasHeight-borderLineWidth/2);
ctx.lineTo(borderLineWidth/2,canvasHeight-borderLineWidth/2);
ctx.closePath();
ctx.lineWidth=borderLineWidth;
ctx.stroke();
// 斜线1
ctx.beginPath();
ctx.moveTo(borderLineWidth,borderLineWidth);
ctx.lineTo(canvasWidth-borderLineWidth,canvasHeight-borderLineWidth);
ctx.strokeStyle="#f00";
ctx.setLineDash([10]); // 虚线
ctx.lineWidth=1;
ctx.stroke();
// 斜线2
ctx.beginPath();
ctx.moveTo(canvasWidth-borderLineWidth,borderLineWidth);
ctx.lineTo(borderLineWidth,canvasHeight-borderLineWidth);
ctx.setLineDash([10]);
ctx.stroke();
// 横线
ctx.beginPath();
ctx.moveTo(borderLineWidth,canvasHeight/2);
ctx.lineTo(canvasWidth-borderLineWidth,canvasHeight/2);
ctx.setLineDash([10]);
ctx.stroke();
// 竖线
ctx.beginPath();
ctx.moveTo(canvasWidth/2,borderLineWidth);
ctx.lineTo(canvasWidth/2,canvasHeight-borderLineWidth);
ctx.setLineDash([10]);
ctx.stroke();
ctx.restore();
}
// 写字函数
function drawFont(lastPos,curpos,lastTime,curTime) {
ctx.save();
ctx.beginPath();
ctx.moveTo(lastPos.x,lastPos.y);
ctx.lineTo(curpos.x,curpos.y);
ctx.lineCap="round";
ctx.lineJoin="round";
ctx.strokeStyle=defaultFontColor;
// 根据绘制速度确定线宽
ctx.lineWidth=setLineWidth(lastPos,curpos,lastTime,curTime);
ctx.stroke();
ctx.restore();
}
// 计算鼠标相对于canvas的坐标
function getCanvasCoord(position,obj) {
var canvasOffset=obj.getBoundingClientRect(); // 返回元素的大小及其相对于视口的位置
return {x:Math.round(position.x-canvasOffset.left),y:Math.round(position.y-canvasOffset.top)};
}
// 计算线宽
function setLineWidth(lastPos,curpos,lastTime,curTime) {
var s=Math.sqrt((lastPos.x-curpos.x)*(lastPos.x-curpos.x)+(lastPos.y-curpos.y)*(lastPos.y-curpos.y)); // 计算两点间的距离
var t=curTime-lastTime;
var lineWidth=1;
var maxLineWidth=10;
var minLineWidth=1;
var v=s/t;
if (v<=0.1) {
lineWidth=maxLineWidth;
} else if (v>=1) {
lineWidth=minLineWidth;
} else {
lineWidth=maxLineWidth*(1-v/(1-0.1));
}
if (lastLineWidth==-1) {
lastLineWidth=lineWidth;
}
return lineWidth*1/3+lastLineWidth*2/3; // 历史线宽和当前线宽,按比例结合,实现线段的过渡
}
// 开始绘制
function drawStart(ev) {
isMouseDown=true;
// 记录鼠标的历史位置,时间
lastPos=getCanvasCoord({x:ev.clientX,y:ev.clientY},canvas);
lastTime=new Date().getTime();
}
// 绘制中
function drawMove(ev) {
var curpos=getCanvasCoord({x:ev.clientX,y:ev.clientY},canvas);
var curTime=new Date().getTime();
// 写字
drawFont(lastPos,curpos,lastTime,curTime);
// 更新鼠标的历史位置,时间
lastPos=curpos;
lastTime=curTime;
}
// 结束绘制
function drawEnd() {
isMouseDown=false;
}
// 初始化
// 绘制米字格
drawBlock();
// 改变字体颜色
$btnColors.click(function () {
$btnColors.each(function (index,item) {
$(item).removeClass("active");
});
$(this).addClass("active");
defaultFontColor=$(this).css("backgroundColor");
});
$("#btn_more").click(function () {
defaultFontColor=$("#input_color").val();
});
// 清除
$("#btn_reset").click(function () {
// 清除画布
ctx.clearRect(0,0,canvasWidth,canvasHeight);
// 绘制米字格
drawBlock();
});
// 交互
// PC端的鼠标事件
canvas.addEventListener("mousedown",function (ev) {
var ev=ev?ev:window.event;
drawStart(ev);
},false);
canvas.addEventListener("mousemove",function (ev) {
var ev=ev?ev:window.event;
if (isMouseDown) {
drawMove(ev);
}
},false);
canvas.addEventListener("mouseup",function () {
drawEnd();
lastLineWidth=-1; // 鼠标抬起,恢复线宽
},false);
canvas.addEventListener("mouseout",function () {
drawEnd();
},false);
// Mobile端的触摸事件
canvas.addEventListener("touchstart",function (ev) {
var ev=ev?ev:window.event;
drawStart(ev.touches[0]);
},false);
canvas.addEventListener("touchmove",function (ev) {
var ev=ev?ev:window.event;
if (isMouseDown) {
drawMove(ev.touches[0]);
}
},false);
canvas.addEventListener("touchend",function () {
drawEnd();
lastLineWidth=-1; // 鼠标抬起,恢复线宽
},false);
}
window.addEventListener("load",init,false);
</script>
</body>
</html>
<p style="text-align:right;">Yangfan 2016.12.24</p>