uni-app小程序使用canvas绘制图片、在图片上涂鸦、撤销

2021-05-31  本文已影响0人  回到唐朝做IT
image.png

需求

功能注意点

撤销操作逻辑

以下为全部代码

HTML

<template>
    <view class="container">
        <!--画布区域-->
        <cover-view class="topBox">
            <button class="backStep" type="default" @click="backStep" size="mini">撤销</button>
            <button class="saveBtn" type="warn" @click="saveimg" size="mini">保存</button>
        </cover-view>
        <view class="canvas_area">
            <canvas
                canvas-id="myCanvas"
                class="myCanvas"
                disable-scroll="false"
                @touchstart="touchStart"
                @touchmove="touchMove"
                @touchend="touchEnd"
                :style="{ width: w + 'px', height: h + 'px' }"
            ></canvas>
        </view>
        <!--画布工具区域-->
        <view class="canvas_tools">
            <view class="box box1" @click="penSelect(3)"></view>
            <view class="box box2" @click="penSelect(15)"></view>
            <view class="box box3" @click="colorSelect('#cc0033')"></view>
            <view class="box box4" @click="colorSelect('#ff9900')"></view>
            <view class="box box5" @click="colorSelect('#00CD00')"></view>
        </view>
    </view>
</template>

JS

<script>
export default {
    data() {
        return {
            imgurl: '',
            pen: 3, //画笔粗细默认值
            color: '#cc0033', //画笔颜色默认值
            startX: 0, //保存X坐标轴变量
            startY: 0, //保存X坐标轴变量
            w: '', //canvas宽高区域
            h: '',
            ctx: wx.createContext('myCanvas', this),
            allDrawWorksPath: [] //图片路径 用于撤销
        };
    },
    onLoad(option) {
        //真实环境为后端返回图片路径
        this.imgurl = 'https://ss3.baidu.com/9fo3dSag_xI4khGko9WTAnF6hhy/zhidao/pic/item/72f082025aafa40f2982756baa64034f78f0193b.jpg';
        this.getSystemInfo(); //获取设备信息
    },
    onReady(option) {
        var that = this;
        console.log('imgurl', that.imgurl);
        wx.getImageInfo({
            src: that.imgurl,
            success: function(ress) {
                console.log('图片信息', ress);
                that.ctx.drawImage(ress.path, 0, 0, that.w, that.h);
                that.ctx.stroke();
                wx.drawCanvas({
                    canvasId: 'myCanvas',
                    reserve: true,
                    actions: that.ctx.getActions() // 获取绘图动作数组
                });
            },
            fail(err) {
                console.log('err', err);
            }
        });
    },
    methods: {
        // 保存图片
        saveimg() {
            var _this = this;
            this.ctx.draw();
            setTimeout(function() {
                _this.drawAfter();
            }, 500);
        },
        // 保存
        drawAfter() {
            let that = this;
            wx.canvasToTempFilePath(
                {
                    width: that.w, //686
                    height: that.h,
                    canvasId: 'myCanvas',
                    success: function success(res) {
                        console.log('保存图片', res);
                        var tempFilePath = res.tempFilePath;
                        console.log(tempFilePath);
                        //把图片保存到相册
                        wx.saveImageToPhotosAlbum({
                            filePath: tempFilePath
                        });
                        //把图片保存到相册
                        //进行文件的拷贝
                        //上传
                    }
                },
                this
            );
        },
        // 开始
        touchStart(e) {
            console.log('开始绘制');
            //得到触摸点的坐标
            this.startX = e.changedTouches[0].x;
            this.startY = e.changedTouches[0].y;
            console.log('画笔颜色', this.color, this.pen);
            this.ctx.setStrokeStyle(this.color); //画笔颜色
            this.ctx.setLineWidth(this.pen); //线条宽度
            this.ctx.setLineCap('round'); // 让线条圆润
            this.ctx.beginPath();
            this.saveCurrentDrawWorks(); //记录每一步步骤-撤销
        },
        //手指触摸后移动
        touchMove(e) {
            console.log('开始移动中');
            var startX1 = e.changedTouches[0].x;
            var startY1 = e.changedTouches[0].y;
            this.ctx.moveTo(this.startX, this.startY);
            this.ctx.lineTo(startX1, startY1);
            this.ctx.stroke();
            this.startX = startX1;
            this.startY = startY1;

            //只是一个记录方法调用的容器,用于生成记录绘制行为的actions数组。
            // context跟<canvas/>不存在对应关系,一个context生成画布的绘制动作数组可以应用于多个<canvas/>
            wx.drawCanvas({
                canvasId: 'myCanvas',
                reserve: true,
                actions: this.ctx.getActions() // 获取绘图动作数组
            });
        },
        //手指触摸动作结束
        touchEnd() {
            console.log('停止');
        },
        //更改画笔大小的方法
        penSelect(e) {
            console.log(e);
            this.pen = e;
        },
        //更改画笔颜色的方法
        colorSelect(e) {
            console.log(e);
            this.color = e;
        },
        // 保存每一步操作
        saveCurrentDrawWorks() {
            let that = this;
            wx.canvasToTempFilePath({
                x: 0,
                y: 0,
                width: 0,
                height: 0,
                canvasId: 'myCanvas',
                success: function(res) {
                    var imgPath = res.tempFilePath;
                    that.allDrawWorksPath = [...that.allDrawWorksPath, imgPath];
                    console.log('步骤', that.allDrawWorksPath);
                },
                fail: res => {
                    console.log('获取画布图片失败', res);
                }
            });
        },
        // 撤销一步
        backStep() {
            var allDrawWorksPath = this.allDrawWorksPath;
            if (allDrawWorksPath == null || allDrawWorksPath.length == 0 || allDrawWorksPath == undefined) {
                uni.showToast({
                    icon: 'none',
                    title: '已经撤销到起始位置'
                });
                this.allDrawWorksPath = [];
                return;
            }
            var privWorksPath = allDrawWorksPath.pop();
            this.allDrawWorksPath = allDrawWorksPath;

            this.ctx.drawImage(privWorksPath, 0, 0, this.w, this.h);
            this.ctx.stroke();
            let that = this;
            wx.drawCanvas({
                canvasId: 'myCanvas',
                reserve: true,
                actions: that.ctx.getActions() // 获取绘图动作数组
            });
        },
        // 获取设备信息
        getSystemInfo() {
            let that = this;
            uni.getSystemInfo({
                success(res) {
                    console.log('设备信息', res);
                    that.h = res.windowHeight; //若加底部操作区域 需-60
                    that.w = res.windowWidth;
                }
            });
        }
    }
};
</script>

CSS

<style lang="scss">
.container {
    position: relative;
    width: 100%;
    height: 100%;
    .topBox {
        position: fixed;
        z-index: 99999;
        width: 100%;
        .backStep {
            width: 50px;
            top: 2px;
            left: 2px;
        }
        .saveBtn {
            width: 50px;
            position: absolute;
            top: 2px;
            right: 2px;
        }
    }
    .canvas_tools {
        position: fixed;
        left: 0;
        bottom: 0;
        width: 100%;
        height: 60px;
        display: flex;
        flex-direction: row;
        justify-content: space-around;
        background-color: #eee;
        align-items: center;
    }
    .box {
        width: 100rpx;
        height: 100rpx;
        line-height: 100rpx;
        border-radius: 50%;
        background-color: rebeccapurple;
    }
    .box1 {
        background-color: #99cccc;
        background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAgCAYAAAAbifjMAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QA/wD/AP+gvaeTAAAAB3RJTUUH3gUEFTU3owPJ+gAAArpJREFUSMeVlU9IVFEUxn/nvjdTaTQZYyaaZlEpIfhvkVSMSAmBFRZpYYugbcs2QbWpXUFKC3chLdpFUFHQpqxE2rQ0ahEp5BRm6TgqODP3tpg78nzznukHF+7lnfOd73zn8q7gw8jISGFbCzQCLvAGmANIJBKr4l3CcRqIAhVAFngRFKRCqu8ALtkCMeAyEPHFFBN40Am0Ajm7TgDNayrwMEeBi4ADGLu2ARf+24JFE9AR4kmdv40ggnPWAz/2Ad2BCjyMVbZSGHqtqSs5fgVdwIE1CFqBo6sUeKpvAc4TPplCTJ81uEhBM9Ae0KKf8DjQUGjD+7EH2G73WeAV8A54DoySHydAJXDGr6DK5/AjK/Uj8NKSP/EVi3sJOoH9dv8XGALmPQnTwCCQsudGIFEg2Ex+9gVj5m2CH0kgbfdRa3hEAW3AEU9gHDgUQFAPlHnOHUCLIn/v454PJcANOxUFiJV83Y6xgAqg3wVOBlRrB54BY4AGDpP/wfjRrYAHHnO8qLZ99oUkp4EhZd29AyyzfuSAe8B9ZSUOAgN2vx48BO4CWac1vsTS3HSurffKh9mpHzsRaRFRIqIIWko5T8t2H7w6/np4Pjk+itw4tRdgl85lmsqq6ytr2rpuupFNdcba74XOZWeS42O3k5/Hvjpu9AvwTW6dbcAY0yMij0VEKaUcUcoxBrRe3ZExWhutsyLiGGOuiciAW3WsH7RRynGiNbW1amtpKQALi4tMTkz4SRT5W4gx2lHKwS0prwOjcdyIKd9TTywWAyCVSvF7SRWpWFGjNcpxcTPpGYwxOI5L+s9PJLOQH3I6zXJ6Bp3TxWYYMMYSTL4dBmMQEabeRxClVipkMpnQORoDogQ3szAL1nH/TRLCYQAl4IoIxs5srYRABgE3p/OPj5gNpeefLA3up++/CueNwgD8A0fm3rIoh3Y0AAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE2LTA5LTE3VDE1OjIwOjM4KzA4OjAwDAwhawAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNC0wNS0wNFQyMTo1Mzo1NSswODowMMTKtgsAAABNdEVYdHNvZnR3YXJlAEltYWdlTWFnaWNrIDcuMC4xLTYgUTE2IHg4Nl82NCAyMDE2LTA5LTE3IGh0dHA6Ly93d3cuaW1hZ2VtYWdpY2sub3Jn3dmlTgAAABh0RVh0VGh1bWI6OkRvY3VtZW50OjpQYWdlcwAxp/+7LwAAABl0RVh0VGh1bWI6OkltYWdlOjpIZWlnaHQAMTA2Mx0uiBoAAAAXdEVYdFRodW1iOjpJbWFnZTo6V2lkdGgANTM3XiCV0QAAABl0RVh0VGh1bWI6Ok1pbWV0eXBlAGltYWdlL3BuZz+yVk4AAAAXdEVYdFRodW1iOjpNVGltZQAxMzk5MjExNjM1VZFQ9AAAABJ0RVh0VGh1bWI6OlNpemUAMTguNEtCh1extQAAAF90RVh0VGh1bWI6OlVSSQBmaWxlOi8vL2hvbWUvd3d3cm9vdC9zaXRlL3d3dy5lYXN5aWNvbi5uZXQvY2RuLWltZy5lYXN5aWNvbi5jbi9zcmMvMTE2MDIvMTE2MDI0NC5wbmcC2t7tAAAAAElFTkSuQmCC);
        background-repeat: no-repeat;
        background-position: center;
    }
    .box2 {
        background-color: #0099cc;
        background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAeCAMAAAAvtQ9FAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAACf1BMVEUAAAB8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiN8TiNINiWHUyJ+TyN9TyN9TyN9TyN9TyN+TyOPVyJBMyYoKCgpKChaPyVkQyVjQyVjQyVjQyVjQyVTPCYmJygoKCgfHx8eHh4fHx4gHx4gHx4gHx4gHx4gHx4eHh4eHh4fHx8TExITExITExITExITExITExITExITExITExITExITExITExITExITExITExITExITExITExITExITExITExITExITExITExITExITExITExIHBwcHBwcHBwcHBwd8TiMTExITExITExITExIHBwf////3ECwAAAAAznRSTlMAAAAARX4EAAAAAFLkqwIAAAAAVOv/vQkAAAA54v//4CEAAAARvP////1qAAAAAGj9/////9o1AAAAFMb/////2WgXAE70//////7BLI///////6O+/////+fY///84f///dz///HI/////9Wl/////6hy/f///G056////+YxDr7/////sggAcv////1hAAAg3P/////JEwBMTLj//v7//pxKS+j7+//////++vvi1f///////////83V///O1f//ztX//87V///O1f//zSidjOsAAAABYktHRNQJuwuFAAAAB3RJTUUH3gUEFTU21AT5bAAAAS9JREFUGNNjYGBgZGJmYWVjZwABDk4ubh5ePn4QW0BQSFhEVExcAsSRlJKWkZWTV1BUAnKUVVTV1DU0tbR1dBkY9PQNDI2MTUzNzC0sGaysbWzPnbOzd3B0cmZwcXU7d+6cu4enl7cPg6+f/zkQCAgMCmYICQ0Dc86FR0QyREWfg4KYWIa4eBgnIZEhKRnGSUllSEvPgLAzs7IZcnLzIJz8gkKGouISCKe0rJyhorIKzK6uqa1jqG9obAJxmlta2xjaOzq7QBLdPb19DP0TJk6aPHnylKnTps9gmDlr9py58+bNX7Bw0WKGJUuXLV+xcuWq1WvWrmNYv2Hjps1btmzdtn3HToZdu89DwZ69DPv2X4CCAwfxcA4dvggFR44yHDt+CQpOnGQ4dfoyFJw5CwBZdsIQZAP16AAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAxNi0wOS0xN1QxNToyMDozOCswODowMAwMIWsAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMTQtMDUtMDRUMjE6NTM6NTQrMDg6MDBivb2/AAAATXRFWHRzb2Z0d2FyZQBJbWFnZU1hZ2ljayA3LjAuMS02IFExNiB4ODZfNjQgMjAxNi0wOS0xNyBodHRwOi8vd3d3LmltYWdlbWFnaWNrLm9yZ93ZpU4AAAAYdEVYdFRodW1iOjpEb2N1bWVudDo6UGFnZXMAMaf/uy8AAAAZdEVYdFRodW1iOjpJbWFnZTo6SGVpZ2h0ADEwNjMdLogaAAAAF3RFWHRUaHVtYjo6SW1hZ2U6OldpZHRoADQyNaj3r4sAAAAZdEVYdFRodW1iOjpNaW1ldHlwZQBpbWFnZS9wbmc/slZOAAAAF3RFWHRUaHVtYjo6TVRpbWUAMTM5OTIxMTYzNCKWYGIAAAASdEVYdFRodW1iOjpTaXplADEyLjdLQs+hF00AAABfdEVYdFRodW1iOjpVUkkAZmlsZTovLy9ob21lL3d3d3Jvb3Qvc2l0ZS93d3cuZWFzeWljb24ubmV0L2Nkbi1pbWcuZWFzeWljb24uY24vc3JjLzExNjAyLzExNjAyNDMucG5nsPoC/QAAAABJRU5ErkJggg==);
        background-repeat: no-repeat;
        background-position: center;
    }
    .box3 {
        background-color: #cc0033;
    }
    .box4 {
        background-color: #ff9900;
    }
    .box5 {
        background-color: #00cd00;
    }
    .box6 {
        text-align: center;
        color: #fff;
    }
}
</style>
上一篇下一篇

猜你喜欢

热点阅读