javaScript 利用canvas实现简单画板

本文主要实现画板基本功能和介绍canvas的具体的使用

<1> 实现鼠标绘制功能

首先是HTML代码:
直接在body中添加canvas标签

 <canvas id="mycanvas"></canvas>

js代码:

$(function() {

    var mycanvas = document.getElementById("mycanvas");
    var ctx = mycanvas.getContext("2d");
    var mX = 0;
    var mY = 0;
    var isDraw = false;
    var width = document.documentElement.clientWidth;
    var height = document.documentElement.clientHeight;
    mycanvas.width = width;
    mycanvas.height = height;

    ctx.lineWidth = "2";  //设置画笔的大小
    ctx.strokeStyle = "#FFA500";  //设置画笔的颜色

    $("#mycanvas").on("mousedown", function(e) {
        isDraw = true;
        mX =e.pageX;   //记录按下的位置X
        mY = e.pageY;  //记录按下的位置Y

    });
    $("#mycanvas").on("mousemove", function(e) {
        if(isDraw) {
            var tX = e.pageX;
            var tY = e.pageY;
            draw(mX,mY,tX,tY);
        }
    });

    $("#mycanvas").on("mouseup", function(e) {
        isDraw=false;
    });

    function draw(ox, oy, newX, newY) {
        ctx.beginPath();   //开始
        ctx.moveTo(ox, oy);  //移动到...
        ctx.lineTo(newX, newY);   //To...
        ctx.stroke();  //绘制
        mX = newX;
        mY = newY;
        ctx.closePath();  //结束
    }

});

其中需要注意的是,在CSS中给canvas设置的宽高和在标签中设置width和height是不一样的,建议在js中重新设置宽高

    mycanvas.width=document.documentElement.clientWidth;
    mycanvas.height=document.documentElement.clientHeight

到这个时候已经实现可以用鼠标在画布上绘制了。

<2>实现绘制图案功能
先从绘制直线开始
/**
 * 
 * @param {Object} ox   起点X
 * @param {Object} oy   起点Y
 * @param {Object} newX  终点X
 * @param {Object} newY  终点Y
 */
    function drawLine(ox, oy, newX, newY) {
        ctx.beginPath();
        ctx.moveTo(ox, oy);
        ctx.lineTo(newX, newY);
        ctx.stroke();
        ctx.closePath();
    }

在mousemove事件中调用该方法,鼠标拖动绘制时会出现以下效果:
这里写图片描述
这显然不是想要的效果,原因是在拖动的时候会不停的绘制直线(问题1)

(问题1)解决办法:每次绘制之前,先清理画板

function drawLine(ox, oy, newX, newY) {
        ctx.clearRect(0, 0, width, height);   //清除整个画板,width和height都等于浏览器的大小
        ctx.beginPath();
        ctx.moveTo(ox, oy);
        ctx.lineTo(newX, newY);
        ctx.stroke();
        ctx.closePath();
    }

这样可以绘制出一条直线的效果了;
但当绘制第二条的时候,第一条直线却被清除了,原因在于每次绘制前都把画布给清理一遍了ctx.clearRect(0, 0, width, height),(问题2)

(问题2)解决办法:
我们应该在每次绘制后,先将画布上的内容保存一份出来,在下次绘制时先清理画布,然后把保存的内容重新绘制出来,再进行接下来的动作。
在这里使用到canvas的两个方法putImageData和getImageData,分别对应绘制数据和获取画布数据,
先创建一个数组用于保存画布数据:

var imageData = [];

在松开鼠标的时候便保存画布数据,所以在mouseup事件中:

imageData.push(ctx.getImageData(0, 0, width, height));

数据保存后,在清理画布之后要绘制出来:

    function drawLine(ox, oy, newX, newY) {
        ctx.clearRect(0, 0, width, height);
        if(imageData.length > 0)
            ctx.putImageData(imageData[imageData.length - 1], 0, 0, 0, 0, width, height);  //将数据显示在画布上
        ctx.beginPath();
        ctx.moveTo(ox, oy);
        ctx.lineTo(newX, newY);
        ctx.stroke();
        ctx.closePath();
    }

至此,我们就完成绘制直线的功能了。
绘制矩形和圆形,思路都是一样的

    function drawRect(startX, startY, endX, endY) {
        ctx.clearRect(0, 0, width, height);
        if(imageData.length > 0)
            ctx.putImageData(imageData[imageData.length - 1], 0, 0, 0, 0, width, height);
        ctx.beginPath();
        ctx.rect(startX, startY, endX - startX, endY - startY);  //创建矩形
        ctx.stroke();
        ctx.closePath();
    }

    function drawArc(startX, startY, endX, endY) {
        ctx.clearRect(0, 0, width, height);
        if(imageData.length > 0)
            ctx.putImageData(imageData[imageData.length - 1], 0, 0, 0, 0, width, height);
        ctx.beginPath();
        var radius = Math.abs(Math.max((endX - startX), (endY - startY)));
        //创建圆形,参数分别对应:圆心X,圆心Y,半径,起点(时钟3点方向为0度),终点 PI=180度,从0度开始
        ctx.arc(startX, startY, radius, 0, 2 * Math.PI);   
        ctx.stroke();
        ctx.closePath();
    }

注:上述画圆效果可能和想象中不一样(请自行测试),现提供另一种效果(效果请自行测试):

//代码不是很复杂,就不多做解析了
function drawArc2(startX, startY, endX, endY) {
        ctx.clearRect(0, 0, width, height);
        if(imageData.length > 0)
            ctx.putImageData(imageData[imageData.length - 1], 0, 0, 0, 0, width, height);

        var offsetX = Math.abs(endX - startX);
        var offsetY = Math.abs(endY - startY);
        var radius = offsetX > offsetY ? offsetY / 2 : offsetX / 2;

        ctx.beginPath();
        if((endX - startX) < 0 && (endY - startY) < 0) {
            ctx.arc(startX - radius, startY - radius, Math.abs(radius), 0, 2 * Math.PI);
        } else if(endX - startX < 0) {
            ctx.arc(startX - radius, startY + radius, Math.abs(radius), 0, 2 * Math.PI);
        } else if(endY - startY < 0) {
            ctx.arc(startX + radius, startY - radius, Math.abs(radius), 0, 2 * Math.PI);
        } else {
            ctx.arc(startX + radius, startY + radius, Math.abs(radius), 0, 2 * Math.PI);
        }

        ctx.stroke();
        ctx.closePath();

    }

到现在,基本的画板功能都已经实现了,最后,当然少不了橡皮擦:

    function eraser(x, y) {
        var o = 5;  //擦除区域大小
        ctx.clearRect(x - o, y - o, o * 2, o * 2);
    }

很简单,和清除画布一样,只是把清除的区域限制好就行了。

最后,附上完整一点的代码:

$(function() {

    var imageData = [];
    var mycanvas = document.getElementById("mycanvas");
    var ctx = mycanvas.getContext("2d");
    var mX = 0;
    var mY = 0;
    var isDraw = false;
    var width = document.documentElement.clientWidth;
    var height = document.documentElement.clientHeight;
    mycanvas.width = width;
    mycanvas.height = height;

    ctx.lineWidth = "2";
    ctx.strokeStyle = "#FFA500";

    $("#mycanvas").on("mousedown", function(e) {
        isDraw = true;
        mX = e.pageX;
        mY = e.pageY;
        //eraser(mX,mY);

    });
    $("#mycanvas").on("mousemove", function(e) {
        if(isDraw) {
            var tX = e.pageX;
            var tY = e.pageY;
            //draw(mX,mY,tX,tY);
            //drawLine(mX, mY, tX, tY);
            //drawRect(mX, mY, tX, tY);
            //drawArc(mX, mY, tX, tY);
            //drawArc2(mX, mY, tX, tY);
            //eraser(tX,tY);
        }
    });

    $("#mycanvas").on("mouseup", function(e) {
        isDraw = false;
        imageData.push(ctx.getImageData(0, 0, width, height));
    });

    function draw(ox, oy, newX, newY) {
        ctx.beginPath();
        ctx.moveTo(ox, oy);
        ctx.lineTo(newX, newY);
        ctx.stroke();
        mX = newX;
        mY = newY;
        ctx.closePath();
    }

    /**
     * 绘制直线
     * @param {Object} ox   起点X
     * @param {Object} oy   起点Y
     * @param {Object} newX  终点X
     * @param {Object} newY  终点Y
     */
    function drawLine(ox, oy, newX, newY) {
        ctx.clearRect(0, 0, width, height);
        if(imageData.length > 0)
            ctx.putImageData(imageData[imageData.length - 1], 0, 0, 0, 0, width, height);
        ctx.beginPath();
        ctx.setLineDash([5, 15]);
        ctx.moveTo(ox, oy);
        ctx.lineTo(newX, newY);
        ctx.stroke();
        ctx.closePath();
    }

    /**
     * 绘制矩形
     * @param {Object} startX
     * @param {Object} startY
     * @param {Object} endX
     * @param {Object} endY
     */
    function drawRect(startX, startY, endX, endY) {
        ctx.clearRect(0, 0, width, height);
        if(imageData.length > 0)
            ctx.putImageData(imageData[imageData.length - 1], 0, 0, 0, 0, width, height);
        ctx.beginPath();
        ctx.rect(startX, startY, endX - startX, endY - startY);
        ctx.stroke();
        ctx.closePath();
    }

    function drawArc(startX, startY, endX, endY) {
        ctx.clearRect(0, 0, width, height);
        if(imageData.length > 0)
            ctx.putImageData(imageData[imageData.length - 1], 0, 0, 0, 0, width, height);
        ctx.beginPath();
        var radius = Math.abs(Math.max((endX - startX), (endY - startY)));
        ctx.arc(startX, startY, radius, 0, 2 * Math.PI);
        ctx.stroke();
        ctx.closePath();

    }

    function drawArc2(startX, startY, endX, endY) {
        ctx.clearRect(0, 0, width, height);
        if(imageData.length > 0)
            ctx.putImageData(imageData[imageData.length - 1], 0, 0, 0, 0, width, height);

        var offsetX = Math.abs(endX - startX);
        var offsetY = Math.abs(endY - startY);
        var radius = offsetX > offsetY ? offsetY / 2 : offsetX / 2;

        ctx.beginPath();
        if((endX - startX) < 0 && (endY - startY) < 0) {
            ctx.arc(startX - radius, startY - radius, Math.abs(radius), 0, 2 * Math.PI);
        } else if(endX - startX < 0) {
            ctx.arc(startX - radius, startY + radius, Math.abs(radius), 0, 2 * Math.PI);
        } else if(endY - startY < 0) {
            ctx.arc(startX + radius, startY - radius, Math.abs(radius), 0, 2 * Math.PI);
        } else {
            ctx.arc(startX + radius, startY + radius, Math.abs(radius), 0, 2 * Math.PI);
        }

        ctx.stroke();
        ctx.closePath();

    }

    function eraser(x, y) {
        var o = 5;
        ctx.clearRect(x - o, y - o, o * 2, o * 2);
    }

});

关于鼠标事件,选择绘制什么图案,就需要自己去做选择了。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值