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

时间: 2024-07-30 06:12:19

canvas知识03:学写一个字案例的相关文章

学写jQuery插件开发方法

jQuery如此流行,各式各样的jQuery插件也是满天飞.你有没有想过把自己的一些常用的JS功能也写成jQuery插件呢?如果你的答案是肯定的,那么来吧!和我一起学写jQuery插件吧! 很多公司的前端设计开发人员都是女孩子,而这些女孩子很多JavaScript技能都不是很好.而前端开发过程中,JavaScript技能又是必不可少的.所以,如果前端小MM正在为某个JavaScript效果发愁的时候,你潇洒的过去,然后对她说:“嗨,美女,用这个吧.这是我写的一个jQuery插件.”我想基本上你的

一点一点学写Makefile(3)-增加第三方库和头文件

我们在写代码的时候不一定都是有自己来完成,一个工程中会大量使用一些比较优秀的动态库.静态库等,我们在使用这些库完成所有的代码后,需要在编译的时候将这些库使用的头文件添加到我们的工程上,将他的库文件也添加到我们的工程中,接下来我们就来看一下怎么来添加. 我们在项目中很少将第三方库与我们自己的代码放到同一个目录中,而是有一些约定俗成的存放方法: 如上图,我们会将第三方库的头文件放到include文件夹,将第三方的静态库放到lib文件夹,将动态库放到bin文件夹,(注:如果是使用开源库尽可能使用静态库

跟我一起学写jQuery插件开发方法(转载)

jQuery如此流行,各式各样的jQuery插件也是满天飞.你有没有想过把自己的一些常用的JS功能也写成jQuery插件呢?如果你的答案是肯定的,那么来吧!和我一起学写jQuery插件吧! 很多公司的前端设计开发人员都是女孩子,而这些女孩子很多JavaScript技能都不是很好.而前端开发过程中,JavaScript技能又是必不可少的.所以,如果前端小MM正在为某个JavaScript效果发愁的时候,你潇洒的过去,然后对她说:“嗨,美女,用这个吧.这是我写的一个jQuery插件.”我想基本上你的

【任意输入一串整数输出该数的位数】新手每天学写C程序(1)

#include"stdio.h" int main() { int a; int n=0; scanf("%d",&a); n++; a=a/10; while(a>0) { n++; a=a/10; } printf("%d",n); return 0; } [任意输入一串整数输出该数的位数]新手每天学写C程序(1)

学写js Calender控件

好几个月没写博客了,一直在赶项目.项目现在终于处于稳定的状态,只是修修改改.作为后台程序员的我真是苦逼啊,从web到手机端接口我都得写,杂七杂八的事情...这两天终于闲下来了,没事儿看了一下关于js日期的一些函数,突然想到了日历控件,于是试着写了一个,作为后台程序员的我水平有限,大家抱着学习的态度看看我写的这个例子吧... 首先一个常用的日期函数:Date(year,month,day) var   date=new  Date(); 获取年份            var   year=thi

为什么要学写编译器

大树告诉我:根有多深,枝有多茂 高楼跟我说:我只所以能建么高,全仗我有深深的基础 盖茨用亲身经历启迪我:编写BASIC编译器的技术积淀对其事业成功很重要,其辉煌的人生履历从此开始. 一位哲人说:决定人生高度的不是浮在表面的一些东西,而是摒弃浮华. 踏踏实实打下的深深基础. 一位游泳教练教导学员:学再多游泳知识,站在岸上不下水的人永远也学不会游泳. 一位武师告诫弟子:练武不练功,到头一场空. 有位读者问作者:学会了写编译器能赚多少钱? 作者回答:编译器编写是练內功,打基础,通过实战完成技术积淀的过

【核心整理】那些让你起飞的计算机基础知识:学什么,怎么学?

我之前里的文章,写的大部分都是与计算机基础知识相关的,这些基础知识,就像我们的内功,如果在未来想要走的更远,这些内功是必须要修炼的.框架千变万化,而这些通用的底层知识,却是几乎不变的,了解了这些知识,可以帮助我们更快着学习一门知识,更加懂得计算机的运行机制.当然,在面试中也经常会被问到,特别是对于应届生,对于春秋招,也可以看看我前阵子写过的文章历经两个月,我的秋招之路结束了!.也有读者经常问的计算机基础知识究竟是指啥?学习顺序?推荐书籍? 我公众号的读者学生以及非科班的应该挺多的,所以我今天这篇

[500lines]500行代码学写web server

项目地址:https://github.com/aosabook/500lines/tree/master/web-server.作者是来自Mozilla的Greg Wilson.项目是用py2写成.下面文章中贴出的是已经转换后的能在python3.4下运行的代码,所以可能会与原先的有少许不同. 简单地讲,你在浏览器里输入一个网址,浏览器作为客户端会通过DNS解析域名找到对应的IP,并将这串字符串的一部分作为请求发给这个IP的服务器,服务器解析字符串,解析出你的请求内容做出相应处理,然后把一串字

关于json序列化和反序列的问题,没事写个案例,希望能帮到那些需要帮忙的朋友!

现在关于json的读写问题,有许许多多的解决方法,因人而异,根据实际问题去选择自己想要的最容易方法.我觉得自带的Newtonsoft.Json是个不错的选择,随便写两个例子吧! 一:关于简单的json序列化和反序列化,可以用Newtonsoft.Json+实体类去解决.首先搞个jsonhelp类 using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Run