canvas知识03:学写一个字案例

效果

    

 

一、知识点

  • 屏幕坐标系与canvas坐标系的转换;
  • canvas中API的使用:路径状态保存、线的绘制及设置、虚线的使用;
  • 根据速度(v=s/t)动态计算线宽及路程的计算方式;
  • JS鼠标事件和触屏事件;
  • 屏幕自适应的应用。

 

二、HTML代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width , height=device-height , initial-scale=1.0 , user-scalable=no">
    <title>Canvas学写一个字</title>
    <link rel="stylesheet" href="css/main.css">
</head>
<body>
<canvas id="mycanvas"></canvas>
<div class="controlBox">
    <div class="colorBox">
        <a href="javascript:;" class="color_red"></a>
        <a href="javascript:;" class="color_orange"></a>
        <a href="javascript:;" class="color_yellow"></a>
        <a href="javascript:;" class="color_green"></a>
        <a href="javascript:;" class="color_blue"></a>
    </div>
    <button id="clearBtn">清除</button>
    <div class="clearfix"></div>
</div>
<script src="js/jquery-1.9.1.js"></script>
<script src="js/drawWord.js"></script>
</body>
</html>

 

三、CSS代码

body{ 
    background-color: #333; 
}
#mycanvas{
    background-color: #fff;    display: block;    margin: 0 auto;
}
.controlBox{ 
    margin: 10px auto; 
}
.colorBox{
    float: left; width: 80%;
}
.colorBox a{
    border-radius: 6px;    display: inline-block;    width: 16%;    height: 30px; box-sizing:border-box;
}
.colorBox .on{
    border:solid 1px rgba(100,100,100,0.6);    box-shadow: 2px 2px 5px  rgba(0,0,0,0.6) inset;
}
.colorBox .color_red{ background-color: red; }
.colorBox .color_orange{ background-color: orange; }
.colorBox .color_yellow{ background-color: yellow; }
.colorBox .color_green { background-color: green;}
.colorBox .color_blue{ background-color: blue;}
#clearBtn{
    border: none; border-radius: 3px; cursor: pointer;    width: 20%;    height: 30px; line-height: 30px;
    text-align: center;    float: right;
}
.controlBox #clearBtn:hover{
    background-color: #e58c00;
}
.clearfix{ clear: both; }

 

三、JS代码(API画虚线的方法)

var myCavs = document.getElementById('mycanvas');
var context = myCavs.getContext('2d');
var startPos = null;                             //鼠标按下时的初始位置
var isMouseDown = false;                         //鼠标是否按下
var strokeColor = 'black';                       //字笔画颜色
var startTime = 0;                               //记录鼠标按下时间
var preLineW = -1;                               //上一次线条宽度

// 设置canvas的尺寸
var publicW = Math.min( 660 , $(window).width()-20 );
myCavs.width = publicW;
myCavs.height = publicW;
$('.controlBox').css({
    width:publicW
});

// 颜色选择
$(".colorBox a").each(function(){
    $(this).click(function(){
        $(this).addClass('on').siblings().removeClass('on')
        var curColor = $(this).css('backgroundColor');
        strokeColor = curColor;
    })
})
// 功能按钮
$("#clearBtn").click(function(){
    context.clearRect(0,0,myCavs.width,myCavs.height);
    drawFrame();
})

// 初始化米字格
drawFrame();

// 画米字格框架方法
function drawFrame(){
context.save(); context.strokeStyle
= 'red'; context.beginPath(); context.moveTo(10, 10); context.lineTo(publicW-10,10); context.lineTo(publicW-10,publicW-10); context.lineTo(10,publicW-10); context.closePath(); context.lineWidth = 3; context.stroke(); // 画竖向的虚线 context.setLineDash([5, 10]); context.beginPath(); context.moveTo((publicW-10)/2+5,16); context.lineTo((publicW-10)/2+5,publicW-10); context.lineWidth = 2; context.stroke(); //画横向的虚线 context.beginPath(); context.moveTo(16,(publicW-10)/2+5); context.lineTo(publicW-10,(publicW-10)/2+5); context.lineWidth = 2; context.stroke(); //画"\"方向虚线 context.beginPath(); context.moveTo(16,16); context.lineTo(publicW-10,publicW-10); context.lineWidth = 2; context.stroke(); //画"/"方向虚线 context.beginPath(); context.moveTo(publicW-16,16); context.lineTo(10,publicW-10); context.lineWidth = 2; context.stroke(); context.restore(); } // 开始绘制 function drawStart(piont02){ startPos = getCavPos(piont02); // 记录时间和位置 startTime = new Date().getTime(); isMouseDown = true; } // 绘制过程 function drawMove(piont02){ var s = calcDis(startPos,getCavPos(piont02)); var curTime = new Date().getTime(); var t = curTime - startTime; var lineW = calcLineW(s,t); context.strokeStyle = strokeColor; context.beginPath(); context.moveTo(startPos.x, startPos.y); context.lineTo(getCavPos(piont02).x , getCavPos(piont02).y); context.lineWidth = lineW; context.lineCap = 'round'; context.lineJion = 'round'; context.stroke(); // 更新鼠标按下位置、按下时间、线宽 startPos = getCavPos(piont02); startTime = curTime; preLineW = lineW; } // 绘制结束状态 function drawEnd(e){ isMouseDown = false; } // 鼠标按下 myCavs.onmousedown = function(e){ // 记录鼠标按下的位置 drawStart({x:e.clientX,y:e.clientY}); e.preventDefault(); } // 鼠标移动 myCavs.onmousemove = function(e){ if(isMouseDown){ drawMove({x:e.clientX,y:e.clientY}) } e.preventDefault(); } // 鼠标抬起 document.onmouseup = myCavs.onmouseup = function(e){ drawEnd(e); e.preventDefault(); } // 触屏事件touchstart myCavs.addEventListener('touchstart', function(e){ // 记录鼠标按下的位置 var touch = e.changedTouches[0]; drawStart({x:touch.pageX,y:touch.pageY}); e.preventDefault(); }) // 触屏事件touchmove myCavs.addEventListener('touchmove', function(e){ if(isMouseDown){ var touch = e.changedTouches[0]; drawMove({x:touch.pageX,y:touch.pageY}) } e.preventDefault(); }) // 触屏事件touchup myCavs.addEventListener('touchup', function(e){ drawEnd(e); e.preventDefault(); }) // 获取canvas坐标系 function getCavPos(piont){ var cavPos = myCavs.getBoundingClientRect(); return { x:piont.x - cavPos.left, y:piont.y - cavPos.top } } // 计算距离 function calcDis(startPos,endPos){ //对x,y坐标开平方 return Math.abs(Math.sqrt( (endPos.x - startPos.x)*(endPos.x - startPos.x) + (endPos.y - startPos.y)*(endPos.y - startPos.y)) ) } // 根据速度计算线宽 function calcLineW(s,t){ var speed = s / t, ResultlineW = 10; // 速度很慢时 if(speed <= 0.1 ){ ResultlineW = Math.random()*10+20; } // 速度很快时 else if(speed > 10 ){ ResultlineW = Math.random()+2; } //一般速度(线性插值计算方式) else{ ResultlineW = 26 - (speed - 0.1)/(10-0.1) * (30 - 1); } // 极端情况下的运笔速度(速度从0.1突然到10),重新计算 if(preLineW == -1){ return ResultlineW; }else{ return preLineW*6/10 + ResultlineW*4/10; } }

 

四、JS代码(自定义画虚线的方法)

// 画虚线方法
function drawDotLine(sx,sy,dx,dy,dis){ //(sx,sy:起始坐标),(dx,dy:结束坐标),(dis:虚线间距)
    var len,count = 0;
    // 画竖向的虚线
    if(sx == dx && sy !== dy){
        len = Math.ceil((dy-sy)/dis/2);
        for( var i=0; i<len; i++){
            context.moveTo( sx, sy + dis*count );
            context.lineTo( sx, sy + dis*(count+1) );
            count+= 2;            
        }
    }
    //画横向的虚线
    else if(sy == dy && sx !== dx){
        len = Math.ceil((dx-sx)/dis/2);
        for( var i=0; i<len; i++){
            context.moveTo( sx + dis*count, sy );
            context.lineTo( sx + dis*(count+1), sy );
            count+= 2;            
        }        
    }
    //画"\"方向斜线
    else if((dx-sx)>0 && (dy-sy)>0){
        var dis02 = Math.sqrt(dis*dis*2);
        len = Math.floor((dx-sx)/dis02/2);
        for( var i=0; i<len; i++){
            context.moveTo( sx + dis02*count, sy + dis02*count);
            context.lineTo( sx + dis02*(count+1), sy + dis02*(count+1) );
            count+= 2;            
        }
    }
    //画"/"方向斜线
    else if((dx-sx)<0 && (dy-sy)>0){
        var dis02 = Math.sqrt(dis*dis*2);
        len = Math.floor((Math.abs(dx-sx))/dis02/2);
        for( var i=0; i<len; i++){
            context.moveTo( sx - dis02*count, sy + dis02*count);
            context.lineTo( sx - dis02*(count+1), sy + dis02*(count+1) );
            count+= 2;            
        }
    }
}

 

参考课程:http://www.imooc.com/learn/284

 

posted @ 2016-05-17 16:27  奔跑的蜗牛~  阅读(313)  评论(0编辑  收藏  举报