找回密码
 立即注册

QQ登录

只需一步,快速开�

[Demo源码] 微信小程序Demo:柠檬手帐 - 界面简洁的图片编辑应用,支...

[复制链接]
查看: 473|回复: 2
最佳答案
0 

1

主题

1

帖子

40

积分

新人求带

积分
40
 楼主| 发表于 2020-1-10 11:26:23 | 显示全部楼层 |阅读模式
微信小程序Demo:柠檬手帐 - 界面简洁的图片编辑应用,支持图片和文字的移动、旋转、缩放、保存编辑状态并生成预览图

核心代码

组件的移动、旋转和缩放

主要思路是把 <image> 标签(对应图片)和 <text> 标签(对应文字)封装在同一个自定义组件 <sticker> 中,通过对外暴露的 text 变量是否为空来进行条件渲染,然后绑定 onTouchStart() 、onTouchEnd() 和 onTouchMove() 三个事件来对整个组件的位置、角度、大小、层级以及 “旋转” 和 “移除” 两个按钮的行为进行操作
onTouchStart: function (e) {
    // 若未选中则直接返回
    if (!this.data.selected) {
        return
    }

    switch (e.target.id) {
        case 'sticker': {
            this.touch_target = e.target.id
            this.start_x = e.touches[0].clientX * 2
            this.start_y = e.touches[0].clientY * 2
            break
        }
        case 'handle': {
            // 隐藏移除按钮
            this.setData({
                hideRemove: true
            })

            this.touch_target = e.target.id
            this.start_x = e.touches[0].clientX * 2
            this.start_y = e.touches[0].clientY * 2

            this.sticker_center_x = this.data.stickerCenterX;
            this.sticker_center_y = this.data.stickerCenterY;
            this.remove_center_x = this.data.removeCenterX;
            this.remove_center_y = this.data.removeCenterY;
            this.handle_center_x = this.data.handleCenterX;
            this.handle_center_y = this.data.handleCenterY;

            this.scale = this.data.scale;
            this.rotate = this.data.rotate;
            break
        }
    }
},

onTouchEnd: function (e) {
    this.active()
    this.touch_target = ''

    // 显示移除按钮
    this.setData({
        removeCenterX: 2 * this.data.stickerCenterX - this.data.handleCenterX,
        removeCenterY: 2 * this.data.stickerCenterY - this.data.handleCenterY,
        hideRemove: false
    })

    // 若点击移除按钮则触发移除事件,否则触发刷新数据事件
    if (e.target.id === 'remove') {
        this.triggerEvent('removeSticker', this.data.sticker_id)
    } else {
        this.triggerEvent('refreshData', this.data)
    }
},

onTouchMove: function (e) {
    // 若无选中目标则返回
    if (!this.touch_target) {
        return
    }

    var current_x = e.touches[0].clientX * 2
    var current_y = e.touches[0].clientY * 2
    var diff_x = current_x - this.start_x
    var diff_y = current_y - this.start_y

    switch (e.target.id) {
        case 'sticker': {
            // 拖动组件则所有控件同时移动
            this.setData({
                stickerCenterX: this.data.stickerCenterX + diff_x,
                stickerCenterY: this.data.stickerCenterY + diff_y,
                removeCenterX: this.data.removeCenterX + diff_x,
                removeCenterY: this.data.removeCenterY + diff_y,
                handleCenterX: this.data.handleCenterX + diff_x,
                handleCenterY: this.data.handleCenterY + diff_y
            })
            break
        }
        case 'handle': {
            // 拖动操作按钮则原地旋转缩放
            this.setData({
                handleCenterX: this.data.handleCenterX + diff_x,
                handleCenterY: this.data.handleCenterY + diff_y
            })

            var diff_x_before = this.handle_center_x - this.sticker_center_x;
            var diff_y_before = this.handle_center_y - this.sticker_center_y;
            var diff_x_after = this.data.handleCenterX - this.sticker_center_x;
            var diff_y_after = this.data.handleCenterY - this.sticker_center_y;
            var distance_before = Math.sqrt(diff_x_before * diff_x_before + diff_y_before * diff_y_before);
            var distance_after = Math.sqrt(diff_x_after * diff_x_after + diff_y_after * diff_y_after);
            var angle_before = Math.atan2(diff_y_before, diff_x_before) / Math.PI * 180;
            var angle_after = Math.atan2(diff_y_after, diff_x_after) / Math.PI * 180;

            this.setData({
                scale: distance_after / distance_before * this.scale,
                rotate: angle_after - angle_before + this.rotate
            })
            break
        }
    }

    this.start_x = current_x;
    this.start_y = current_y;
}

编辑状态的保存

一篇手帐包含的组件类型包括 sticker(软件自带的贴纸)、image(用户上传的图片)和 text(自定义文字)三种,全部保存在一个如下格式的 json 对象中,每个独立组件都包含了一个不重复的 id 以及相关的信息,保存时由客户端生成该对象并编码成 json 字符串存储在数据库,恢复编辑状态时通过解析 json 字符串获得对象,再由编辑页面渲染
  1. {
  2.     "backgroundId": "5",                                        背景图id
  3.     "assemblies": [
  4.         {
  5.             "id": "jhjg",                                       组件id
  6.             "component_type": "image",                          组件类型(自定义图片)
  7.             "image_url": "https://example.com/jhjg.png",        图片地址
  8.             "stickerCenterX": 269,                              中心横坐标
  9.             "stickerCenterY": 664,                              中心纵坐标
  10.             "scale": 1.7123667831396403,                        缩放比例
  11.             "rotate": -3.0127875041833434,                      旋转角度
  12.             "wh_scale": 1,                                      图片宽高比
  13.             "z_index": 19                                       组件层级
  14.         },
  15.         {
  16.             "id": "gs47",
  17.             "component_type": "text",                           组件类型(文字)
  18.             "text": "test",                                     文字内容
  19.             "stickerCenterX": 479,
  20.             "stickerCenterY": 546,
  21.             "scale": 1.808535318980528,
  22.             "rotate": 29.11614626607893,
  23.             "z_index": 10
  24.         },
  25.         {
  26.             "id": "chjn",
  27.             "component_type": "sticker",                        组件类型(贴纸)
  28.             "sticker_type": "food",                             贴纸类型
  29.             "sticker_id": "1",                                  贴纸id
  30.             "image_url": "https://example.com/weapp/stickers/food/1.png",
  31.             "stickerCenterX": 277,
  32.             "stickerCenterY": 260,
  33.             "scale": 1.3984276885130673,
  34.             "rotate": -16.620756913892055,
  35.             "z_index": 5
  36.         }
  37.     ]
  38. }
复制代码

4343443.png
Weapp-Demo-LemonJournal-master.zip (6.61 MB, 下载次数: 45)
回复

使用道具 举报

最佳答案
0 

0

主题

68

帖子

1320

积分

等待验证会员

积分
1320
发表于 2020-1-14 17:51:44 | 显示全部楼层
就像备忘录吗?
回复 支持 反对

使用道具 举报

最佳答案
0 

0

主题

11

帖子

140

积分

等待验证会员

积分
140
发表于 6 天前 | 显示全部楼层
谢谢大佬分享,膜拜3分钟
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



www.henkuai.com—微信开发者的分享交流平台,专注微信开发生态。

天津市滨海新区
中新生态城中成大道生态建设公寓9号楼3层301

微信公众号

广告推广
QQ:805874290

市场合作
zhongcong@henkuai.com