canvas画板,比较简易,目前还有很多bug
1、手机端上下会晃动
2、下载按钮微信上没法用
3、下载后背景色是透明
4、切换成橡皮擦后,需要先点铅笔才能绘画,不能直接点颜色

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <meta name="viewport" content="width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <style>
        ul,ol{list-style:none;}
        *{margin: 0;padding: 0;}
        body{overflow: hidden;}
        .icon {
            width: 1em; height: 1em;
            vertical-align: -0.15em;
            fill: currentColor;
            overflow: hidden;
        }
        .canvas{
            background: white;
            display: block;
            position:fixed;
            top:0;
            left:0;
        }
        #actions{
            position: fixed;
            top: 0;
            left:5px;
        }
        #actions  svg{
            width: 1.5em;
            height: 2em;
            transition: all 0.3s;
            margin: 10px;
        }
       #actions .action{
            fill:red;
            transform: scale(1.2);
       }
       .colors{
           position: fixed;
           top:41px;
           left:12px;
       }
       .color{
           transform: scale(1.2);
       }
        .colors > li{
            width:20px;
            height:20px;
            margin:10px 0;
            border-radius: 50%;
        }
        .colors > li.black{
            background: black;
        }
        .colors > li.red{
            background: red;
        }
        .colors > li.green{
            background: green;
        }
        .colors > li.blue{
            background: blue;
        }
    </style>
</head>
<body>
        <canvas id="xxx" class="canvas"></canvas>
        <div id="actions">
            <svg id="pen" class="icon action" aria-hidden="true">
                <use xlink:href="#icon-pen"></use>
            </svg>
            <svg id="eraser" class="icon" aria-hidden="true">
                <use xlink:href="#icon-eraser"></use>
            </svg>
            <svg id="clear" class="icon" aria-hidden="true">
                <use xlink:href="#icon-custom-clear"></use>
            </svg>
            <svg id="download" class="icon" aria-hidden="true">
                <use xlink:href="#icon-download1"></use>
            </svg>
            <!--<button id="eraser">橡皮擦</button>-->
            <!--<button id="brush">画笔</button>-->
        </div>
        <ol class="colors">
            <li id="black" class="black color"></li>
            <li id="red" class="red"></li>
            <li id="green" class="green"></li>
            <li id="blue" class="blue"></li>
        </ol>
        <!--<div id="canvas"></div>-->
        <script src="//at.alicdn.com/t/font_663139_nbdaue5y67gmn29.js"></script>
        <script src="js/canvas3.js"></script>
</body>
</html>

JS代码

<script>
    var yyy = document.getElementById('xxx');
    var ctx = yyy.getContext("2d");
    
    autoCanvasSize(yyy);
    
    listenToUser(yyy);
    
    //是否使用橡皮擦
    var eraserEnable = false;
    
    eraser.onclick = function () {
        eraserEnable = true;
        eraser.classList.add('action');
        pen.classList.remove('action');
    };
    pen.onclick = function () {
        eraserEnable = false;
        pen.classList.add('action');
        eraser.classList.remove('action');
    };
    
    red.onclick = function () {
        ctx.fillStyle = "red";
        ctx.strokeStyle = "red";
        red.classList.add('color');
        green.classList.remove('color');
        blue.classList.remove('color');
        black.classList.remove('color');
    };
    green.onclick = function () {
        ctx.fillStyle = "green";
        ctx.strokeStyle = "green";
        green.classList.add('color');
        red.classList.remove('color');
        blue.classList.remove('color');
        black.classList.remove('color');
    };
    blue.onclick = function () {
        ctx.fillStyle = "blue";
        ctx.strokeStyle = "blue";
        blue.classList.add('color');
        red.classList.remove('color');
        green.classList.remove('color');
        black.classList.remove('color');
    };
    black.onclick = function () {
        ctx.fillStyle = "black";
        ctx.strokeStyle = "black";
        black.classList.add('color');
        red.classList.remove('color');
        blue.classList.remove('color');
        green.classList.remove('color');
    };
    clear.onclick = function () {
        ctx.clearRect(0,0,yyy.width,yyy.height);
    };
    download.onclick = function () {
        var url = yyy.toDataURL("image/png");
        var a = document.createElement('a');
        document.body.appendChild(a);
        a.href = url;
        a.download = "我的画";
        a.target = "_blank";
        a.click();
    };
    
    //设置画板
    function autoCanvasSize(canvas) {
        function setCanvasSize(){
            var pageWidth = document.documentElement.clientWidth;   // 获取屏幕宽度
            var pageHeight = document.documentElement.clientHeight;     //获取屏幕高度
    
            canvas.width = pageWidth;       //画板宽等于屏幕宽度
            canvas.height = pageHeight;     //画板高等于屏幕高度
        }
    
        setCanvasSize();
    
        window.onresize = function ( ){ //改变窗口大小
            setCanvasSize();
        };
    }
    
    //监听用户鼠标事件
    function listenToUser(canvas) {
        var painting = false;
        var lastPoint = {};
    
        if(document.body.ontouchstart !== undefined){
            canvas.ontouchstart = function (aaa) {
                console.log(aaa);
                var x = aaa.touches[0].clientX;     //console.log打印出aaa,找到里面的touches(多点触控),第一个用touches[0]
                var y = aaa.touches[0].clientY;
                painting = true;
                if(eraserEnable){
                    ctx.clearRect(x-5,y-5,10,10);
                }else{
                    lastPoint = {"x":x,"y":y};      //在每次动的时候把当前点和动的点连成一条线
                    drawCircle(x,y,4);
                }
            };
            canvas.ontouchmove = function (aaa) {
                var x = aaa.touches[0].clientX;
                var y = aaa.touches[0].clientY;
                var newPoint = {x:x,y:y};
                if(!painting){return;}
                if(eraserEnable){
                    ctx.clearRect(x-5,y-5,10,10);
                }else{
                    drawCircle(x,y,4);
                    drawLine(lastPoint.x,lastPoint.y,newPoint.x,newPoint.y,10);
                    lastPoint = newPoint;           //实时更新上一个点的坐标,不然都和第一个点连接了
                }
            };
    
            canvas.ontouchend = function () {
                painting = false;
            }
        }else{
            //鼠标按下
            canvas.onmousedown = function (aaa) {
                var x = aaa.clientX;
                var y = aaa.clientY;
                painting = true;
                if(eraserEnable){
                    ctx.clearRect(x-5,y-5,10,10);
                }else{
                    lastPoint = {"x":x,"y":y};      //在每次动的时候把当前点和动的点连成一条线
                    drawCircle(x,y,4);
                }
            };
    
            //鼠标移动
            canvas.onmousemove = function (aaa) {
                var x = aaa.clientX;
                var y = aaa.clientY;
                var newPoint = {x:x,y:y};
                if(!painting){return;}
                if(eraserEnable){
                    ctx.clearRect(x-5,y-5,10,10);
                }else{
                    drawCircle(x,y,4);
                    drawLine(lastPoint.x,lastPoint.y,newPoint.x,newPoint.y,10);
                    lastPoint = newPoint;           //实时更新上一个点的坐标,不然都和第一个点连接了
                }
            };
    
            //松开鼠标
            canvas.onmouseup = function () {
                painting = false;
            };
        }
    }
    
    //画圆
    function drawCircle(x,y,radius){
        ctx.beginPath();
        ctx.arc(x,y,radius,0,Math.PI*2);
        ctx.fill()
    }

    //连线
    function drawLine(x1,y1,x2,y2,lineWidth){
        ctx.beginPath();
        ctx.moveTo(x1,y1);
        ctx.lineWidth = lineWidth;
        ctx.lineTo(x2,y2);
        ctx.stroke();
        ctx.closePath();
    }

</script>

总结:
1、按下鼠标和移动鼠标后它们中间会有空隙,解决方法:用线连接鼠标移动前后的两点。lasePointnewPoint
2、painting = false监听用户是否在绘画。true再绘画false不在绘画。
3、eraserEnable = false;监测用户是在使用橡皮檫,true是在使用橡皮擦,停止使用铅笔。
4、判断用户是使用pc还是手机,需要监测是否有touch事件,如果有,首先使用touch事件;在pc端document.body.ontouchstart === undefined,在移动端是null,只要不等于undefined就可以确定是移动端。
5、状态切换,不直接修改css里面内容,通过js切换class来实现状态切换。比如:上面橡皮擦和铅笔的切换。
6、使用x.className = 'active'class会变为active;使用x.classList.add('active')class后面会增加一个属性值active
7、document.documentElement.clientWidth的作用是获取document宽度(也就是viewport宽度)
8、移动端支持多点触控,所以要获取clientX需要加上touches[0],表示touch第一个值


uccs
756 声望88 粉丝

3年 gis 开发,wx:ttxbg210604