关于canvas 写字板,画板的实例2.0

这是继一篇《关于canvas 写字板,画板的实例1.0》的改进版,除了1.0的画线,保存图片,清除功能外,另外添加了一些其他功能。

先来张截图:

这里没有考虑太多布局上的问题,因为我的h5基本上都是在移动端上运行的,所以这里只做了移动端的,如有需要,把几个事件改下,就能在pc端运行了。

从左到右依次是:画笔颜色选择,线条粗细选择,画笔切换,橡皮切换,撤销操作,反撤销操作,保存图片,清除所有。可根据个人需要添加其他功能。

之前写的一些小实例,基本都没贴链接,害的我跑回去给它们又贴了一遍链接,以后要是还写些什么的话,先把链接贴着吧。

这是链接:点我看效果 //建议在chrome浏览器打开,传到github上,有的浏览器出问题了,本地测试都还好没问题。

接下来就步入正题了,首先是html:

<body>

<div class="write-content ab">
    <div class="ab header">
        <img class="ab " src="img/yes.png" alt=""/>
        <img class="ab hide" src="img/delete.png" alt=""/>
    </div>
    <div class="write-title ab ">
        <ul class="write-ul">
            <li class="color li_1 bg1 re">
                <img class="ab" src="img/color.png" alt=""/>
                <img class="ab" src="img/color.png" alt=""/>
                <ul class="change-color ab hide">
                    <li data-canvas="white" class="white color-size fl"></li>
                    <li data-canvas="black" class="black color-size fl"></li>
                    <li data-canvas="red" class="red color-size fl"></li>
                    <li data-canvas="yellow" class="yellow color-size fl"></li>
                    <li data-canvas="blue" class="blue color-size fl"></li>
                </ul>
            </li>
            <li class="width  li_1 bg1 re">
                <img class="ab" src="img/width1.png" alt=""/>
                <img class="ab" src="img/width.png" alt=""/>
                <ul class="change-width ab hide" >
                    <li data-canvas="1" class="width_1 width-size"></li>
                    <li data-canvas="3" class="width_2 width-size"></li>
                    <li data-canvas="5" class="width_3 width-size"></li>
                    <li data-canvas="7" class="width_4 width-size"></li>
                    <li data-canvas="9" class="width_5 width-size"></li>
                </ul>
            </li>
            <li class="write  li_1 bg1 re">
                <img class="ab" src="img/write1.png" alt=""/>
                <img class="ab" src="img/write.png" alt=""/>

            </li>
            <li class="rubber  li_1 bg1 re">
                <img class="ab" src="img/rubber1.png" alt=""/>
                <img class="ab" src="img/rubber.png" alt=""/>
            </li>
            <li class="_left  li_1 bg1 re">
                <img class="ab" src="img/left1.png" alt=""/>
                <img class="ab" src="img/left.png" alt=""/>
            </li>
            <li class="_right  li_1 bg1 re">
                <img class="ab" src="img/right1.png" alt=""/>
                <img class="ab" src="img/right.png" alt=""/>
            </li>
            <li class="save  li_1 bg1 re">
                <img class="ab" src="img/save1.png" alt=""/>
                <img class="ab" src="img/save.png" alt=""/>

            </li>
            <li class="clear  li_1 bg1 re ">
                <img class="ab" src="img/clear1.png" alt=""/>
                <img class="ab" src="img/clear.png" alt=""/>
            </li>
        </ul>
    </div>
    <div class="write-body ">
        <canvas   id="canvas" class="ab">
        </canvas>
    </div>
    <div class="saveImg ab" id="showImg">
        <img id="img" src="" alt="">
    </div>
</div>

</body>

然后是css:

*{
    margin: 0;
    padding:0;
}
ul li{
    list-style: none;
}

.re{
    position: relative;
}
.ab{
    position: absolute;
}
.fl{
    float: left;
}
.fr{
    float: right;
}
.hide{
    display: none;
}
.show{
    display: block;
}
body{
    overflow: hidden;
}

#canvas{
    z-index: 0;
}
#canvas_bak{
    z-index: 1;
}

.write{
    width:100%;
    height:100%;
}

.write-title{
    height:7%;
    background-color: #999;
    top:53%;
}
.write-content{
    /*top:49%;*/
}

.header{
    height:5%;
    width:9.6666%;
    left:45%;
    top:48.5%;
    z-index: 100;
}
.header img{
    height: 100%;
    width: 100%;
}
.write-ul .li_1{

    background-size: 70% 70%;
    float: left;
    height:7%;
    width:12.5%;
}
.bg1{
    background:url("../img/bg1.png") no-repeat center;
}
.bg{
    background:url("../img/bg.png") no-repeat center;
}
/*.write-ul .li_1:hover{
    background:url("../img/bg.png") no-repeat center;
    background-size: 70% 70%;
}*/
.write-ul .li_1 img{
    height:50%;
    width:50%;
    left:25%;
    top:25%;
}
.change-color{
    border:1px solid #333;
    left:0;
    top:100%;
    background: #eee;
    z-index: 1000;
}
.color-size{
    height:10px;
    width:10px;
    margin: 2px;
    border:1px solid #fff;
}
/*.color-size:hover{
    border:1px solid #333;
}*/
.white{
    background: white;
}

.black{
    background: black;
}
.red{
    background: red;
}
.yellow{
    background:yellow;
}
.blue{
    background:blue;
}
.change-width{
    border:1px solid #333;
    width:100%
    left:0;
    top:100%;
    background: #eee;
    z-index: 1000;
}
.width-size{
    width:40px;
    margin:5px; ;
    background: #000;
    border:1px solid #000;
}
/*.width-size:hover{
    border:1px solid #fff;
}*/
.width_1{
    height:1px;
}
.width_2{
    height:3px;
}
.width_3{
    height:5px;
}
.width_4{
    height:7px;
}
.width_5{
    height:9px;
}
.border3{
    border:1px solid #333;
}
.borderf{
    border:1px solid #fff;
}
canvas{
    top:60%;
}
.saveImg{
    display: none;
    left:0;
    top:0;
    z-index: 1111111;
}
@-webkit-keyframes down{
    0%{
        -webkit-transform: translate3d(0, 148%, 0);
    }

    100%{
        -webkit-transform: translate3d(0, 0, 0);
    }
}
.down{
    -webkit-animation:  down 3s ease   ;
}
@-webkit-keyframes up{
    0%{
        -webkit-transform: translate3d(0, 148%, 0);
    }

    100%{
        -webkit-transform: translate3d(0, 0, 0);
    }
}
.up{
    -webkit-animation:  up 3s ease   ;
}

最后是js:

这个js 也就200多行,不算多。

这几挑几个重点的模块:

首先是几个变量:

//用于撤销的数组
    var cancelList = new Array();
    //撤销的次数
    var cancelIndex = 0;
    //颜色,宽度框影藏显示标识
    var temp1 = 1;
    var temp2 = 1;
cancelList是用来存放每次画笔动作结束后的图像,用于撤销,
cancelIndex用来记录撤销的次数,撤销:cancelIndex++;反撤销cancelIndex--,保证每次动作能得到对应的图像。
temp1,temp2这两个是记录选择框的显示隐藏的,注释也有。

这是核心代码:

write_touch:function(){
var _temp=0;
el.on("touchstart",function(e){
$(".change-width").hide();
$(".change-color").hide();
temp1 = 1;
temp2 = 1;
$("#showImg").removeClass("up");
_temp = 1;
var touch = e.touches[0];
ctx.beginPath();
ctx.moveTo(touch.pageX - canvas.offsetLeft, touch.pageY - canvas.offsetTop);

});
el.on("touchmove",function(e){
console.log(123);
// 重新获取位置
var touch = e.touches[0];
var x=touch.pageX - canvas.offsetLeft;
var y=touch.pageY - canvas.offsetTop;
//橡皮功能;
if($(".rubber").hasClass('bg')){
_temp=0;
ctx.clearRect(x-5, y-5 ,10,10);
}
if (_temp==1) {
//获取颜色和大小
var _color=$(".change-color li.border3").attr("data-canvas");
var _size=$(".change-width li.borderf").attr("data-canvas");
ctx.strokeStyle=_color;
ctx.lineWidth=_size;
//画
ctx.lineTo(x, y);
ctx.stroke();
};
});
el.on("touchend",function(){
page.saveImageToAry();
});
},
 

这里将划线与橡皮擦除功能写在一起了,刚开始我写的时候,擦除是让线条颜色变白色,就用来模拟擦除功能,后来发现这么做是不对的,这是改进后的,这里有一点没写,就是橡皮的大小是固定的10*10;

每次 touchend事件后,都要保存现在的图像到数组里,以便用于撤销,

撤销动作:

cancel : function(){
            cancelIndex++;
            ctx.clearRect(0,0,pageW-2,pageH/2.5);
            var  image = new Image();
            var index = cancelList.length-1 - cancelIndex  ;
            var url = cancelList[index];
            image.src = url;
            image.onload = function(){
                ctx.drawImage(image , 0 ,0 , image.width , image.height , 0 ,0 , pageW-2 , pageH/2.5);
            }
        }

看这代码就明白了,是将之前存储在数组的图像,重新渲染到画布上,

同上反撤销也是一样的道理,这里我把它两个分开写了,其实两个用的方法是一样的,应该合起来才好点。

撤销的逻辑,需根据自身需求来写。

还有,获取颜色,线条粗细比较简单,就不多写了,以及保存图片,清除画布跟上一篇一样,也就不写了。

这里还要说的就是,我在写这篇的时候,发现之前写的代码有些不合理的地方,顺便给改进了,之前用的是两个画布,一个用来画线条,一个用来存储图像,当时做得到时候是因为在一个画布里面同时画线条存储图像,妹画依次,图像都会往下有个1px的位移,当时也没搞懂什么情况,现在解决了,不需要两个画布,只要一个就可以了。算是给自己长知识了。上面给的链接,还是以前两个画布的写法就不更新了。

补充:完整js:

/**
 * Created by chuyunshi on 17-05-31.
 */
$(document).ready(function(){
    var pageH,pageW;
    var canvas = document.getElementById("canvas");
    var showImg=document.getElementById("showImg");
    var ctx = canvas.getContext("2d");
    var el = $("#canvas");
    //用于撤销的数组
    var cancelList = new Array();
    //撤销的次数
    var cancelIndex = 0;
    //颜色,宽度框影藏显示标识
    var temp1 = 1;
    var temp2 = 1;
    page={
        init:function(){
            page.resize();
            page.show_hide();
            page.change_bg();
            page.color_change();
            page.width_change();
            page.click_border();
            page.write_touch();
            page.clear();
            page.save();
            //阻止页面滑动,主要是微信打开的页面往下滑动,整个页面跟着滑动
            $('body').on("touchmove",function (e) {
                e.preventDefault();
            });
            //撤销事件
            $('._left').on("click",function(){
                console.log(cancelList.length)
                console.log(cancelIndex)
                if(cancelIndex < cancelList.length){
                    page.cancel();
                }
            })
            //反撤销事件
            $('._right').on("click",function(){
                if(cancelIndex>0){
                    page.next();
                }
            })
        },
        resize:function(){
            console.log(123);
            pageH = $(window).height();
            pageW = $(window).width();
            canvas.height=pageH/2.5;
            canvas.width=pageW-2;
            $("body,.write-content, .write-ul").height(pageH).width(pageW);
            $("#showImg").css({
                "height":pageH/2.5,
                "width":pageW-2
            })
        },
        //整个画布的影藏显示,该功能已被注销
        show_hide:function(){
            var temp=0;
            $(".header").click(function(){
                if(temp==0){
                    $(this).find('img').eq(0).hide();
                    $(this).find('img').eq(1).show();
                    temp=1;
                   // $(".write-content").css('top','0%')
                }else{
                    $(this).find('img').eq(1).hide();
                    $(this).find('img').eq(0).show();
                    $("#showImg").hide();
                    temp=0;
                  //  $(".write-content").css('top','49%')
                }

            })
        },
        change_bg:function(){
            $('.write-ul .li_1').click(function(){
                $(this).addClass("bg").removeClass("bg1");
                $(this).siblings().addClass("bg1").removeClass("bg");

                $(this).find('img').eq(0).show();
                $(this).find('img').eq(1).hide();
                for(var i=0;i<12;i++){
                    $(this).siblings().find('img').eq(2*i+1).show();
                }
            })

        },
        //颜色选择框隐藏显示
        color_change:function(){
            $(".color").click(function(){
                if(temp1==1){
                    $(".change-color").show();
                    temp1=0;
                }else{
                    $(".change-color").hide();
                    temp1=1;
                }
            })
        },
        //宽度选择框显示影藏
        width_change:function(){
            $(".width").click(function(){
                if(temp2 == 1){
                    $(".change-width").show();
                    temp2 = 0;
                }else{
                    $(".change-width").hide();
                    temp2 = 1;
                }
            })
        },
        //给被选择的颜色,宽度加标识框
        click_border:function(){
            $(".change-color li").click(function(){
                $(this).addClass('border3').siblings().removeClass('border3')
            })
            $(".change-width li").click(function(){
                $(this).addClass('borderf').siblings().removeClass('borderf')
            })
        },
        //书写及橡皮功能
        write_touch:function(){
            var _temp=0;
            el.on("touchstart",function(e){
                    $(".change-width").hide();
                    $(".change-color").hide();
                    temp1 = 1;
                    temp2 = 1;
                    $("#showImg").removeClass("up");
                    _temp = 1;
                    var touch = e.touches[0];
                    ctx.beginPath();
                    ctx.moveTo(touch.pageX - canvas.offsetLeft, touch.pageY - canvas.offsetTop);

                });
            el.on("touchmove",function(e){
                console.log(123);
                // 重新获取鼠标位置
                var touch = e.touches[0];
                var x=touch.pageX - canvas.offsetLeft;
                var y=touch.pageY - canvas.offsetTop;
                //橡皮功能;
                if($(".rubber").hasClass('bg')){
                    _temp=0;
                    ctx.clearRect(x-5, y-5 ,10,10);
                }
                if (_temp==1) {
                    //获取颜色和大小
                    var _color=$(".change-color li.border3").attr("data-canvas");
                    var _size=$(".change-width li.borderf").attr("data-canvas");
                    ctx.strokeStyle=_color;
                    ctx.lineWidth=_size;
                    //
                    ctx.lineTo(x, y);
                    ctx.stroke();
                };
            });
            el.on("touchend",function(){
                page.saveImageToAry();
            });
        },
        //撤销上一个操作
        cancel : function(){
            cancelIndex++;
            ctx.clearRect(0,0,pageW-2,pageH/2.5);
            var  image = new Image();
            var index = cancelList.length-1 - cancelIndex  ;
            var url = cancelList[index];
            image.src = url;
            image.onload = function(){
                ctx.drawImage(image , 0 ,0 , image.width , image.height , 0 ,0 , pageW-2 , pageH/2.5);
            }
        },
        //反撤销上一个操作
        next : function(){
            cancelIndex--;
            console.log( cancelIndex);
            ctx.clearRect(0,0,pageW-2,pageH/2.5);
            var  image = new Image();
            var index = cancelList.length-1 - cancelIndex  ;
            var url = cancelList[index];
            image.src = url;
            image.onload = function(){
                ctx.drawImage(image , 0 ,0 , image.width , image.height , 0 ,0 , pageW-2 , pageH/2.5);
            }
        },
        //保存历史 用于撤销
        saveImageToAry:function (){
            cancelIndex = 0;
            var dataUrl =  canvas.toDataURL();
            cancelList.push(dataUrl);
        },
        //清除画布
        clear:function(){
            $(".clear").click(function(){
                ctx.clearRect(0, 0, pageW-2, pageH/2.5);
                showImg.style.display="none";
                $("#showImg").removeClass("up");
            })

        },
        //画布保存成图片
        save:function(){
            $(".save").click(function() {
                var img = document.getElementById("img");
                img.src = canvas.toDataURL();
                ctx.clearRect(0, 0, pageW-2, pageH/2.5);
                showImg.style.display = "block";
                $("#showImg").addClass("up");
            });
        },
    }
    page.init();
})

 

 




posted on 2017-06-01 16:46  楚云实  阅读(1006)  评论(0)    收藏  举报

导航