迷你PS小程序-集成的开放式画报、油墨电子签名、图片拖拽可单独食用 ...

米娜桑,哦哈哟~

个人制作,该文章主要讲解最近基于 uni-app 框架编写的集图文拖拽等多方位编辑、油墨电子签名、开放式海报于一体的小程序的制作思路和实现代码。

目录

1、完整源码链接

2、实现思路

3、核心代码

3-1、图文多方位编辑

3-2、油墨电子签名

3-3、开放式海报

3-4、小结

4.效果展示和体验

1、完整源码链接:

完整代码:https://github.com/TensionMax/mini-ps

其中演示的文字编辑、图片编辑、油墨电子签名、开放式海报可单独食用,含文档说明。

2、实现思路

该工具主要由五个不同组件模块:文字编辑、图片编辑,油墨电子签名、控制、开放式海报

1、文字编辑模块设置好的文字参数对象插入到文字队列中。

2、图片编辑模块设置好的图片参数对象插入到图片队列中。

3、油墨电子签名模块完成绘制后转为利用 canvasToTempFilePath 转成临时图片,获取参数后插入图片队列中,也可以直接导出。

4、利用控制模块调整/文字队列和图片队列的参数。

5、开放式海报模块,利用控制台的参数将PS画板上的效果绘制到canvas上来实现的效果,接着再利用 canvasToTempFilePath 转成图片导出。

3、核心代码

3-1、文字/图片编辑模块

文字/图片编辑模块主要是实现移动/缩放功能,其他附带的属于甜品,

由于两个模块功能类似,该篇仅讲解图片编辑模块。

HTML

<img
 style="position: absolute"
 :style="{
     left: item.x+'px',top: item.y+'px',width: item.w+'px',height: item.h+'px',}"
  @touchstart='touchStart($event,item,index)' 
  @longpress='longPress($event,index)'
  @touchmove.stop='touchMove($event,index)' 
  @touchcancel="touchEnd($event,index)" 
  @touchend='touchEnd($event,index)'
  v-for="(item,index) of imagelist"
  :key="index" 
  :src="item.src"
  />

在 imageList 的数组标签中,每个绑定的事件中用 $event 来调用事件本身的参数,其中 $event 的 touches 或 changedTouches 包含我们需要的位置参数,示例如下:

touches:[{
        clientX: 14 //与显示区域(不含顶部栏)左上角的水平距离
        clientY: 16 //与显示区域(不含顶部栏)左上角的垂直距离
        pageX: //与整个页面(不含顶部栏)左上角的水平距离
        pageY: //与整个页面(不含顶部栏)左上角的垂直距离
        },{
        14
        16
        16
        }]

touches 长度为2代表双指触碰,通过判定双指触摸点的变化方向可实现双指缩放效果。因为每个标签都设置为 style="position: absolute" 所以只需要根据位置参数来更新 x、y、w、h 即可

题外话-性能问题

一次移动多次操作DOM影响性能

—— 虚拟DOM了解一下

为何不用事件委派

—— 不必要,Vue已经帮我们做了优化,在非常影响性能时再考虑

图片编辑Demo

3-2、油墨电子签名板

由于 touchmove 事件在小程序真机的触发频率和精确度很迷,不太好根据速度来判定绘制的线宽,我只好用其他方式去实现,虽然效果不完美。

其实现思路是通过多次的循环绘制以达到油墨效果,每次循环绘制的长度和宽度都不相同。

<canvas canvas-id="canvas" @touchstart.stop="touchStart" @touchmove.stop="touchMove" @touchend.stop="touchEnd" > </canvas>

JAVASCRIPT

export default {
data() {
    return {
        lineWidth0: 5,//初始线宽 建议1~5
        ctx: null,x0: 0,136);">//初始横坐标或上一段touchmove事件中触摸点的横坐标
        y0: //初始纵坐标或上一段touchmove事件中触摸点的纵坐标
        t0: //初始时间或上一段touchmove事件发生时间
        v0: //初始速率或touchmove事件间发生速率
        lineWidth: //动态线宽
        keenness: //油墨程度 建议0~5
        k: 0.3,136);">//油墨因子,即每次绘制线条时线宽的变化程度
    }
},onReady() {
    this.ctx = uni.createCanvasContext('canvas',this);
    this.ctx.setLineCap('round')
},methods: {
    //设置初始值
    touchStart(e) {
        this.lineWidth = this.lineWidth0
        this.t0 = new Date().getTime()
        this.v0 = 0
        this.x0 = e.touches[0].clientX
        this.y0 = e.touches[0].clientY
    },touchMove(e) {
        let dx = e.touches[0].clientX - this.x0,dy = e.touches[0].clientY - this.y0,ds = Math.pow(dx * dx + dy * dy,0.5),dt = (new Date().getTime()) - this.t0,v1 = ds / dt; //同 this.v0 初始速率或touchmove事件间发生速率
        if (this.keenness === 0) { //油墨为0时
            this.ctx.moveTo(this.y0)
            this.ctx.lineTo(this.x0 + dx,51); font-weight: 700;">this.y0 + dy)
            this.ctx.setLineWidth(this.lineWidth)
            this.ctx.stroke()
            this.ctx.draw(true)
        } else {
            //由于touchMove的触发频率问题,这里采用for循环绘制,原理如图所示
            //这里的k因为
            let a = this.keenness
            this.keenness > 5) {
                a = 5
            }
            for (let i = 0; i < a; i++) {
                this.x0 + dx * i / a,51); font-weight: 700;">this.y0 + dy * i / a)
                this.x0 + dx * (i + 1) / a,51); font-weight: 700;">this.y0 + dy * (i + 1) / a)
                //此时touchmove事件间发生与上一个事件的发生的速率比较
                if (v1 < this.v0) {
                    this.lineWidth -= this.k
                    this.lineWidth < this.lineWidth * 0.25) 0.25
                } else {
                    this.lineWidth += this.lineWidth > 1.5) 1.5
                }
                this.lineWidth)
                this.ctx.stroke()
                true)
            }
        }
        0].clientY
        this.v0 = v1
    },touchEnd(e) {
        this.x0 = this.y0 = this.t0 = 0
    }
}
}

使用的大部分是canvas的基础api,注意绘制单位都为px。

油墨电子签名Demo

3-3、开放式海报模块

如果说微信小程序是银色金滩,那么截至2020年1月6日或者未来,小程序的canvas就是金滩上充斥着未知数个的玻璃块的那一片 ——

鲁迅

说起小程序canvas,那bug不是一般的多,部分不常见bug我会在代码注释里说明。

<canvas canvas-id="generate" "{ width: canvasW + 'rpx',height: canvasH + 'rpx'}"></canvas>

相关介绍

spread 语法

async 函数

如果图片是网络路径,记得获取临时路径。

//别忘了在函数前加 async
let src = 'https://s2.ax1x.com/2020/01/05/lrCDx0.jpg'
src = (await uni.getImageInfo({src}))[1].path;

JAVASCRIPT输出字段部分

,51); font-weight: 700;">x: y: w: 100,51); font-weight: 700;">h: r: 50,136);">//圆角度
            degrees: 30,136);">//旋转度
            mirror: true//是否镜像
            }],51); font-weight: 700;">text:[{
                content: 'TensionMax',51); font-weight: 700;">lineHeight: 35,136);">//行间距
                color: '#000000',51); font-weight: 700;">size: 28,51); font-weight: 700;">weight: 'normal',136);">//字体粗细
                lineThrough: true,136);">//是否贯穿
            }],51); font-weight: 700;">ctx: null,51); font-weight: 700;">k: null //单位转换因子
    };
}

JAVASCRIPTrpx 或 upx与 px 的单位统一转换方法

px2rpx() {
    //当转换的参数只有一个时直接返回数值如
    //当不为一个时返回数组,然后用spread语法将其展开为几个参数
    //Math.floor()是为了防止在安卓机上造成的数据紊乱,开发者工具无此bug
    if (arguments.length === 1) return Math.floor(arguments[0] / this.k)
    let params = []
    for (let i of arguments) {
        params.push(Math.floor(i / this.k))
    }
    return params
},rpx2px() {
    0] * Math.floor(i * async drawImg() {
this.ctx.setFillStyle('#FFFFFF')
this.ctx.fillRect(this.rpx2px(this.canvasW,51); font-weight: 700;">this.canvasH)) //绘制背景
for (let i of this.img) { //for循环绘制图片
    i.src = (await uni.getImageInfo({src: i.src}))[1].path;//获取图片临时路径
    this.ctx.save() //保存当前绘制内容
    if (i.mirror) { //如果设置镜像
        //因为canvas的translate属性是基于原点(初始原点为右上角)变化
        //所以需要先将原点移动至图片中心,变化后再还原
        //旋转变化同理
        this.ctx.translate(...this.rpx2px(i.x + i.w / 2,i.y + i.h / 2))
        this.ctx.scale(-1,0);">1)
        this.rpx2px(-i.x - i.w / 2))
    }
    if (i.degrees) { //如果设置旋转
        this.ctx.rotate(i.degrees * Math.PI / 180)
        this.radiusRect(...this.rpx2px(i.x,i.y,i.w,i.h,i.r)) //圆角或矩形路径绘制
    this.ctx.clip() //裁剪
    this.ctx.drawImage(i.src,i.h))
    this.ctx.restore() //恢复非裁剪区域
}
true) 
}

radiusRect(x,y,w,h,r) {
    if (r > w / 2 || r > h / 2) {
        r = Math.min(w,h) / 2
    }
    this.ctx.beginPath();
    this.ctx.moveTo(x,y); // 将操作点移至左上角
    this.ctx.arcTo(x + w,x + w,y + r,r); // 画右上角的弧
    this.ctx.lineTo(x + w,y) //可省略,但由于安卓真机的小程序bug,留之,下同。
    // 画右下角的弧
    //可省略
    this.ctx.arcTo(x,x,y + h - r,136);">// 画左下角的弧
    this.ctx.lineTo(x,x + r,136);">// 画左上角的弧
    //可省略
},254);'>绘制自定义文字

文字绘制稍微麻烦些,主要是canvas不会自动帮我们换行排版,网上类似的实现方法太多,该篇就不讲,直接放在Demo里面。

开放式海报Demo

3-4、小结

既然我们知道了这几个组件自定义调整参数的方式,那么最后只需要一个父组件作为控制台来调整他们的参数即可,可以通过 props 、 sync 修饰符 等来实现父子通信,当然如果想做更复杂的可以考虑用 Vuex 传参。接下来就可以根据这思路来实现繁琐的业务逻辑了。

4、效果展示

效果图如下,如果由什么疑问欢迎到下方评论区讨论。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


判断H5页面环境在微信中还是小程序中 用小程序提供的wx.miniProgram.getEnv可以获取环境参数 &lt;script type=&quot;text/javascript&quot; src=&quot;https://res.wx.qq.com/open/js/jweixin-1.
wx.reLaunch和wx.navigateTo,wx.navigateTo的区别 2019-03-23 11:18:05 wx.navigateTo 用于保留当前页面、跳转到应用内的某个页面,使用 wx.navigateBack可以返回到原页面。对于页面不是特别多的小程序,通常推荐使用 wx.n
微信小程序如何从数组里取值_微信小程序 传值取值的几种方法总结 小程序里常见的取值有以下几种,一个完整的项目写下来,用到的概率几乎是100%。 列表index下标取值 页面传值 form表单取值 1. 列表index下标取值 实现方式是:data-index=&quot;{{index}}&quot
H5项目接入微信授权登录,通过 UA 区分微信还是普通浏览器: let&#160;ua&#160;=&#160;navigator.userAgent.toLowerCase(); let&#160;isWeixin&#160;=&#160;ua.indexOf(&#39;micromessenge
微信小程序获取data-xx=&quot;&quot;属性的值,自定义属性设置和获取(data-) 微信小程序&lt;view class=&quot;details-btn&quot; data-taskId=&quot;111&quot; bindtap=&#39;taskdetails&#39
小程序报错:TypeError: Cannot read property ‘addEventListener‘ of undefined 解决办法 将调试基础库由2.16.0(或者当前的) -&gt; 2.14.1 解决问题
H5跳转微信小程序-成功案例(VUE)(踩坑无数) TuoMei 已于 2022-07-29 09:52:22 修改 准备工作 根据官方提供的资料需准备以下几点: 1、已认证的服务号 2、绑定JS接口安全域名 (在微信公众平台设置) 3、IP白名单 (在微信公众平台设置) 4、将小程序和H5公众号进
微信小程序 页面跳转和数据传递实例详解 这篇文章主要介绍了微信小程序 页面跳转和数据传递实例详解的相关资料,这里附有实例代码帮助到家学习理解,需要的朋友可以参考下 微信小程序 页面跳转和数据传递 1.先导 在Android中,我们Activity和Fragment都有栈的概念在里面,微信小程序页面也
情景1.拉取公司代码演示: 因为github有墙,这里我们以gitee(码云)为例作为演示 (其实就是国产github,也非常好用~) 步骤一:打开Git界面 先在一个空文件夹右击Git Bash Here,打开git界面 步骤二:输入克隆远程仓库指令 别人复制的链接在这里获取 拿到别人赋值的链接自
如何开发微信小程序? 作为一名10多年一直从事互联网平台开发的从业者,我来回答下这个问题吧。 微信小程序开发流程总体可以归纳为4个步骤, 老张带您捋一捋整个环节,小白用户可以收藏了。 好了废话不多说,开始! 一、开发前小程序需要准备的资料 我们在开发微信小程序前,需要准备下相关资料。这个资料主要是后
原生小程序开发优化方案 为了更好的制定优化方案,我们 有必要先了解下小程序的底层架构、以及与普通网页开发的差异 小程序最终渲染载体与当下一些热门的技术 Flutter、React Native等不同,依然是浏览器内核,而不是原生客户端。 而对于传统的网页来说,UI 渲染和 JS 脚本是在同一个线程中
1,不要下两倍尺寸的图片, 小程序本身自己就会对元素缩小两倍,设计图片的一杯就已经很清晰了。 2,图片压缩,(主要是压缩静态资源,ps 可以压缩,然后有一些在线压缩工具,保持600-800kb 的静态) 3,通用的代码组件化 4,是在工程量太大可以分包,分包现在最大支持20m(一般都不会去分包的)
文章浏览阅读189次。人工智能研究实验室OpenAI在2022年11月30日发布了自然语言生成模型ChatGPT,上线两个月就已经超过一亿用户,成为了人工智能界当之无愧的超级大网红。ChatGPT凭借着自身强大的拟人化及时应答能力迅速破圈,引起了各行各业的热烈讨论。简单来说ChatGPT就是可以基于用户文本输入自动生成回答的人工智能聊天机器人。那肯定会有人说这不就是Siri嘛,虽然都是交互机器人但是两者的差别可老大了。那么ChatGPT在人机交互时为什么会有这么出色的表现?它到底会不会取代搜索引擎?90%的人真的会因为ChatG
文章浏览阅读193次。8. 导航和路由管理:掌握小程序的导航方式,如使用wx.navigateTo跳转页面、使用wx.redirect重定向页面等,学会实现页面之间的跳转和传参。1. 小程序的基本概念和架构:了解小程序的定义、特点以及与传统APP的区别,掌握小程序的运行环境、组件和API等基本概念。10. 支付功能:学习小程序的支付方式,如微信支付、支付宝支付等,了解支付流程和注意事项,学会实现小程序的支付功能。9. 用户授权和登录:了解小程序的用户授权机制,如获取用户信息、调用微信API等,学会实现用户的登录和注册功能。_微信小程序开发知识点总结
文章浏览阅读4.8k次,点赞7次,收藏18次。一、准备工作1. 安装微信开发者工具,并登录微信小程序账号;2. 准备斗地主游戏的图片资源;3. 准备斗地主游戏的音效资源;二、创建小程序1. 打开微信开发者工具,点击“新建小程序”,输入小程序名称,选择小程序的项目目录,点击“创建”;2. 在小程序的项目目录中,新建文件夹“images”,将准备好的斗地主游戏的图片资源放入“images”文件夹中;3. 在小程序的项目目录中,新建文件夹“sounds”,将准备好的斗地主游戏的音效资源放入“sounds”文件夹中;三、编写代码1. 在小程_扑克牌微信小程序代码
文章浏览阅读3.9k次,点赞3次,收藏7次。一、准备工作:1. 安装微信开发者工具,创建小程序项目;2. 准备游戏角色图片;3. 准备游戏背景音乐;二、实现步骤:1. 创建游戏页面,添加游戏角色图片,添加游戏背景音乐;2. 创建游戏角色类,定义游戏角色属性,如角色名称、角色图片、角色能力等;3. 创建游戏类,定义游戏属性,如游戏人数、游戏角色、游戏规则等;4. 创建游戏控制类,定义游戏流程,如游戏开始、游戏结束、游戏角色分配等;5. 创建游戏界面,实现游戏流程,如游戏开始、游戏结束、游戏角色分配等;6. 创建游戏结果页面,显示游戏_微信小程序游戏代码
文章浏览阅读1.7k次。1. 创建小程序项目:使用微信开发者工具创建一个小程序项目,并在项目中添加一个页面,用于模拟聊天。 2. 定义数据结构:定义一个数据结构,用于存储聊天记录,包括发送者、接收者、消息内容等信息。 3. 实现聊天功能:实现聊天功能,包括发送消息、接收消息、显示消息等功能。 4. 实现界面:使用微信小程序的界面框架,实现聊天界面,包括聊天记录列表、输入框等。代码示例:// 定义数据结构var chatData = { sender: '', receiver: '', message: '' };_制作聊天对话小程序代码
文章浏览阅读2.1k次。1、创建小程序项目:使用微信开发者工具,新建一个小程序项目,输入项目名称,选择项目目录,点击“创建”按钮,即可创建小程序项目。2、添加页面:在小程序项目中,可以添加多个页面,每个页面都有自己的页面文件,比如首页、分类页、购物车页、我的页面等。3、添加组件:在小程序项目中,可以添加多个组件,比如商品列表组件、购物车组件、订单组件等,用于在页面中显示商品信息、购物车信息、订单信息等。4、添加接口:在小程序项目中,可以添加多个接口,用于获取商品信息、购物车信息、订单信息等,以便在页面中显示。5、_微信开发者工具做一个我的商城
文章浏览阅读515次。首先在配置页面index.json 添加以下代码。然后在index.jx页面配置下拉刷新。_小程序云开发上拉刷新