【js案例】使用js制作写字画布

canvas实现画板功能

需求分析 
1.具有基本的铅笔功能 
2.即时直线绘制 
3.即时绘制矩形 
4.即时圆形 
5.即时橡皮擦 
7.插入图片 
8.把画板保存为图片并下载 //此处还没做好,画板底色是黑色的 
9.选择颜色 
10.选择线条粗细

Setp1:构建网页基本样式

html代码

    <!--可选操作-->
    <div id="select">
        <button id="pen">铅笔</button>
        <button id="line">直线</button>
        <button id="rect">矩形</button>
        <button id="arc">圆形</button>
        <button id="robber">橡皮檫</button>
        <button id="img">图片</button>
        <button id="save">保存</button>
        <input type="file" id="file" name="img" style="display: none"/>
        <input type="color" id="color"/>
        <input type="number" id="lineWidth"/>
    </div>

    <!--画板-->
    <canvas id="penal" width="800" height="800"></canvas>

css代码

    /*只有一句,用来初始化画板颜色*/
    #penal {
        width: 800px;
        height: 800px;
        background-color: #ccc;
    }

Step2:构造实现画板各个功能的js代码

1.构造Draw()类,并初始化必要的参数

    var Draw = function(){
        this.type = 'pen';  //选项类型,默认为铅笔
        this.penal = document.getElementById('penal');
        this.pen = this.penal.getContext('2d');
        this.isDraw = false;    //绘画开关
        this.color = document.getElementById('color');
        this.lineWidth = document.getElementById('lineWidth');
        this.select = document.getElementById('select');    //选择面板
        this.img = new Image();//用于动态绘制直线,矩形,圆形
    };

2.这里只需要构造一个初始化函数init()

初始化函数内部需要用到的变量

    Draw.prototype.init = function(){
        var self = this;
        var originX = null;
        var originY = null;
    }

先绑定选择操作

    this.select.addEventListener('click',function(event){
        if(event.target.id == 'pen'){
            self.type = 'pen';
        }else if(event.target.id == 'line'){
            self.type = 'line';
        }else if(event.target.id == 'rect'){
            self.type = 'rect';
        }else if(event.target.id == 'arc'){
            self.type = 'arc';
        }else if(event.target.id == 'robber'){
            self.type = 'robber';
        }else if(event.target.id == 'img'){
            document.getElementById('file').click();    //默认触发选择文件操作
            document.getElementById('file').onchange = function(e){
                var reader = new FileReader();          //这是H5新增加的读取文件函数
                reader.readAsDataURL(e.target.files[0]);
                reader.onload = function(ent){          //文件读取完毕后触发操作
                    var img = new Image();
                    img.src = ent.target.result;        //读取的结果默认存放在result上
                    self.pen.drawImage(img,0,0);        //把图片直接画在画布上
                }
            }
        }
        else if(event.target.id == 'save'){
            var a = document.createElement('a');
            a.href = self.penal.toDataURL('image/png');     //把画布转化为base64
            a.download = 'image.jpeg';
            a.id = 'download';
            a.innerHTML = 'download';
            document.body.appendChild(a);
            document.getElementById('download').style.display = 'none';
            document.getElementById('download').click();    //默认出发下载操作

        }
    },false);

可以知道当绘画时,mousedown事件触发时,需要把this.isDraw = true,同时记录鼠标所在坐标,获取选择的colorlinewidth,并开启绘画路径

    this.penal.addEventListener('mousedown',function(event){
        self.isDraw = true;
        originX = event.clientX - self.penal.offsetLeft;    //原点x坐标
        originY = event.clientY - self.penal.offsetTop;     //原点y坐标
        self.pen.moveTo(originX, originY);
        self.pen.strokeStyle = self.color.value;
        self.pen.lineWidth = self.lineWidth.value;
        self.pen.beginPath();

    },false);

然后当触发mouseup事件时,可知需要结束绘画,若鼠标离开画布,即mouseleave时,也需要结束绘画,这部分很简单只需把this.isDraw = false和关闭绘画路径

    this.penal.addEventListener('mouseleave', function () {
        if(self.isDraw){
            self.pen.closePath();
            self.isDraw = false;
        }
    },false);
    this.penal.addEventListener('mouseup', function (event) {
        if(self.isDraw){
            self.pen.closePath();
            self.isDraw = false;
        }
    },false);

接下来就是最难的部分的,当mouseover时,需要即时绘制 
先实现铅笔功能

    this.penal.addEventListener('mousemove',function(event){
        //只有可绘画时才可画
        if(self.isDraw){
            var x = event.clientX - self.penal.offsetLeft;  //移动过程中的x坐标
            var y = event.clientY - self.penal.offsetTop;   //移动过程中的y坐标

            if(self.type == 'pen'){
                self.pen.lineTo(x,y);
                self.pen.stroke();
            }
        }
    },false);

接下来实现橡皮擦功能,实现方法是把绘画线条加粗,并颜色默认选择画布底色

    if(self.type == 'robber'){
         self.pen.strokeStyle = '#ccc';
         self.pen.clearRect(x-10,y-10,20,20);
    }

接下来实现绘制直线,矩形和圆形的方法其实大同小异,然后为了能让我们画矩形和圆形能在所有方向都能画,我们增加了newOriginXnewOriginY两个变量

    var newOriginX  = originX,newOriginY = originY;

    if(self.type == 'line'){
        self.pen.moveTo(originX,originY);
        self.pen.lineTo(x,y);
        self.pen.stroke();

    }else if(self.type == 'rect'){
        if(x < originX){
            newOriginX = x;
        }
        if(y < originY){
            newOriginY = y;
        }
        self.pen.rect(newOriginX,newOriginY,Math.abs(x-originX),Math.abs(y-originY));
        self.pen.stroke();
    }else if(self.type == 'arc'){
        if(x < originX){
            newOriginX = x;
        }
        if(y < originY){
            newOriginY = y;
        }
        var r = Math.sqrt(Math.abs(x-originX) * Math.abs(x-originX) + Math.abs(y-originY) * Math.abs(y-originY))
        self.pen.arc(Math.abs(x-originX)+newOriginX, Math.abs(y-originY)+newOriginY , r, 0, 2*Math.PI);
        self.pen.fillStyle = self.color.value;
        self.pen.fill();
    }

question:此时我们发现画的直线,矩形和圆形都会在画的时候留下移动的痕迹,这不是我们希望的结果,所以解决方法是: 
mousedown时,把当前画布内容保存为图片,并用初始化时一直没有使用过的this.img来保存,然后每次画直线等的时候先把画布全部清空,然后在把this.img画到画布上 
把原来的mousedown事件添加一句代码

    this.penal.addEventListener('mousedown',function(event){
        self.isDraw = true;

        //增加一句代码
        self.img.src = self.penal.toDataURL('image/png');

        originX = event.clientX - self.penal.offsetLeft;    //原点x坐标
        originY = event.clientY - self.penal.offsetTop;     //原点y坐标
        self.pen.moveTo(originX, originY);
        self.pen.strokeStyle = self.color.value;
        self.pen.lineWidth = self.lineWidth.value;
        self.pen.beginPath();

    },false);

mouseover事件的代码稍作更改

    if(self.type == 'line'){

        self.pen.clearRect(0,0,800,800);//增加代码
        self.pen.drawImage(self.img, 0, 0);//增加代码
        self.pen.beginPath();//增加代码

        self.pen.moveTo(originX,originY);
        self.pen.lineTo(x,y);
        self.pen.stroke();

        self.pen.closePath();//增加代码
    }else if(self.type == 'rect'){
        self.pen.clearRect(0,0,800,800);//增加代码
        self.pen.drawImage(self.img, 0, 0);//增加代码
        self.pen.beginPath();//增加代码

        if(x < originX){
            newOriginX = x;
        }
        if(y < originY){
            newOriginY = y;
        }
        self.pen.rect(newOriginX,newOriginY,Math.abs(x-originX),Math.abs(y-originY));
        self.pen.stroke();

        self.pen.closePath();//增加代码
    }else if(self.type == 'arc'){
        self.pen.clearRect(0,0,800,800);//增加代码
        self.pen.drawImage(self.img, 0, 0);//增加代码
        self.pen.beginPath();//增加代码

        if(x < originX){
            newOriginX = x;
        }
        if(y < originY){
            newOriginY = y;
        }
        var r = Math.sqrt(Math.abs(x-originX) * Math.abs(x-originX) + Math.abs(y-originY) * Math.abs(y-originY))
        self.pen.arc(Math.abs(x-originX)+newOriginX, Math.abs(y-originY)+newOriginY , r, 0, 2*Math.PI);
        self.pen.fillStyle = self.color.value;
        self.pen.fill();
        self.pen.closePath();//增加代码
    }

Step3:加载js文件

    <script src="draw.js"></script>
    <script>
        window.onload = function (){
            var draw = new Draw();
            draw.init();
        };
    </script>

最后简单的画板功能就是实现了,如有不足之处请指出 
demo地址:https://github.com/1364137942/canvas-draw-panel


转自: https://blog.csdn.net/ali1995/article/details/52734253



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值