箭头绘制参考了:https://blog.csdn.net/qq_45939676/article/details/127425426 这位大佬的文章

gitee地址: https://gitee.com/philippines-kisses-snow/uniapp-image-edit.git

组件预览

功能介绍

  1. 剪切
  2. 添加文本
  3. 涂鸦
  4. 绘制图形(支持箭头,圆形,矩形)
  5. 旋转

实现思路

  1. 将屏幕分为两部分:图片编辑部分、操作栏部分
  2. 图片编辑部分当中创建一个图片容器,容器大小为:图片大小*缩放比例,在容器当中使用<image />标签显示图片内容,<image />的大小占满父容器
  3. 创建一个<canvas />,canvas的大小为图片容器的大小,创建后用于保存图片编辑后的内容,并导出图片,再将image上的图片替换为canvas导出的图片,利用css将这个仅用于保存的canvas标签设置为不可见

一、 剪切

这里只设置了四个夹角用于拖动:左上角、右上角、左下角、右下角

剪切蒙版使用定位,相当于图片容器进行定位,那么蒙版的大小就是可以通过left、top、right、bottom的定位控制

  1. 设置蒙版颜色和边框,给蒙版的四个角设置拖动点,添加4个元素,定位到四个角,给这4个元素添加边框,使边框刚好包裹图片的菱角
  2. 给这四个元素添加拖动事件,并记录每次拖动的起始点,注:在touchmove当中需要更新起始点为当前位置的坐标font>
<view @touchmove.stop="cropTouchMove($event, CROP_TYPE.TOP_LEFT)" @touchstart.stop="cropTouchStart" class="top-left"></view>
<view @touchmove.stop="cropTouchMove($event, CROP_TYPE.TOP_RIGHT)" @touchstart.stop="cropTouchStart" class="top-right"></view>
<view @touchmove.stop="cropTouchMove($event, CROP_TYPE.BOTTOM_RIGHT)" @touchstart.stop="cropTouchStart" class="bottom-right"></view>
<view @touchmove.stop="cropTouchMove($event, CROP_TYPE.BOTTOM_LEFT)" @touchstart.stop="cropTouchStart" class="bottom-left"></view>
  1. 根据始末位置的坐标差计算定位
例如:移动左上角时:
起始点是(x = 0, y = 0)
当前点为(x = 2, y = 2)
移动差:(diffx = 2, diffy = 2)
由于移动点为左上角,蒙版的定位只有top、left会变化:
top变为:top + diffy
left变为: left + diffx,同理其他几个点类似: 右上角:top变为:top + diffy,right变为: right - diffx
左下角:bottom变为:bottom - diffy,left变为: left + diffx
右下角:bottom变为:bottom - diffy,right变为: right - diffx 出界判断:
0 <= top <= 图片容器高
0 <= left <= 图片容器宽
0 <= right <= 图片容器宽
0 <= bottom <= 图片容器高 最小剪切框大小限制:
图片宽 - right - left >= 最小宽
图片高 - bottom - top >= 最小高
  1. 导出,剪切完成后通过canvas的drawImage将图片渲染到canvas上,然后导出时,根据剪切蒙版的定位坐标计算出蒙版宽高,以蒙版左上角坐标开始导出蒙版宽高的图片即可

二、添加文本

文本添加与剪切类似,在图片容器内添加一个文本容器,并相对于图片容器定位,大小占满图片容器,创建一个文本数组用于保存文本框的属性:内容、位置,在文本容器内循环遍历文本数组,删除时只需删除对应索引的文本即可,保存时遍历数组,将文本循环绘制到canvas上,最后保存即可,双击图片可以新建一个文本框

// 绘制时的文本换行处理:
/**
* 绘制文本
* @param {Object} _this 组件实例
* @param {String} canvasID canvasID
* @param {String} text 文本字符串
* @param {Number} fontH 单行字体高度
* @param {Number} maxW 最大文本域宽
* @param {Number} startX 开始x坐标
* @param {Number} startY 开始y坐标
*/
export function drawText(_this, canvasID, textArea, fontSize, fontH, maxW, startX, startY) {
const ctx = uni.createCanvasContext(canvasID, _this)
const text = textArea.text
ctx.setFontSize(fontSize)
ctx.fillStyle = textArea.color
let rowW = 0
let rowTexts = []
let startIndex = 0
// 将一段长文本拆分为多段
for(let i = 0; i < text.length; i++) {
rowW += ctx.measureText(text[i]).width
if(rowW > maxW) {
rowTexts.push(text.substr(startIndex, i))
startIndex = i
rowW = 0
}
}
rowTexts.push(text.substr(startIndex))
// 分段绘制
rowTexts.forEach((str, index) => {
const y = index === 0 ? startY : index*fontH + startY
ctx.fillText(str, startX, y);
ctx.draw(true)
})
}

三、涂鸦

由于涂鸦实时性要求较高,图形不规则且连贯,需要使用canvas进行实时绘制

  1. 在图片容器内创建一个canvas,canvas大小为图片容器大小
  2. 涂鸦时直接在canvas上绘制即可(具体绘制过程的代码就不贴了,可在git当中查看)
  3. 保存时需导出该涂鸦图片,使用保存用的canvas绘制这两张图片,先绘制原图,再绘制涂鸦,导出即可

四、图形

在图片容器当中创建两个canvas(其中一个可与绘制涂鸦的canvas复用),获取起始点与当前点坐标在最外层的canvas上绘制相应图形,在滑动结束后将图形信息用数组保存起来,遍历数组绘制到下层的canvas上,清空最外层的canvas

箭头绘制需在箭头终点绘制两侧箭头边,具体计算可查看代码和参考的文章

uniapp H5图片编辑器(安卓/iOS适用)的更多相关文章

  1. 移动端H5制作安卓和IOS的坑 持续更新...

    移动端H5制作安卓和IOS的坑 持续更新... 前言:最近参加公司的H5页面创意竞赛,又遇到不少页面在不同系统上的坑.踩坑之余,觉得很多之前遇到的知识点都忘了,索性开一篇博文,把这些坑都统一归纳起来, ...

  2. H5与安卓、IOS的交互,判断微信、移动设备、安卓、ios

    一.通过用户代理可以判断网页当前所在的环境 var browser={ versions:function(){ var u = navigator.userAgent, app = navigato ...

  3. h5与安卓、ios交互

    1.安卓交互 h5调用安卓方法 window.webview.xxx() 安卓调用h5方法, 方法需要在全局注册 window['showUnreadMsg'] = () => { this.$ ...

  4. 点击复制文字到剪贴板兼容性安卓ios

    一般那种活动H5分享可能会用到点击复制文字到剪贴板,很简单的功能 于是搜了一搜:js复制文字到剪贴板,可用结果大致分为两类: 一类是js原生方法,这种方法兼容性不好,不兼容ios: https://d ...

  5. 史上最简单JS复制功能,兼容安卓ios!

    1.JS复制原理: 被复制内容的元素不能被其他元素遮盖,否则无效.  (设置opacity透明为0,不可以设置display:none); 2.常规的复制方法 function copyUrl2() ...

  6. .net 安卓IOS跨平台des加解密双向的(可以互相加解密)

    #region 跨平台加解密(c# 安卓 IOS) // public static string sKey = "12345678"; // /// // /// 解密 // / ...

  7. 安卓ios和angularjs相互调用解决首次调用ios传递标题失败的问题

    1.angular 调用客户端方法放在 try catch中 try { js_invoke.showShareDialog(angular.toJson(obj));  // 在这里放客户端的方法即 ...

  8. 安卓ios各版本及分辨率占比

    Google Play 安装统计数据 只有安卓的 https://developer.android.com/about/dashboards/index.html?hl=zh-cn 腾讯移动分析 安 ...

  9. H5移动端IOS/Android兼容性总结,持续更新中…

    H5移动端IOS/Android兼容性总结,持续更新中… 1. IOS不识别日期 new Date("2018-07-01 08:00:00")在Android下正常显示可以直接进 ...

  10. uni-app h5端跳转到底部导航栏的时候使用方法uni.switchTab跳转刷新页面更新数据

    h5端的uni-app项目 需求:uni-app h5端跳转到底部导航栏的时候使用方法uni.switchTab跳转刷新页面更新数据 百度的方法如下: uni.switchTab({ url: '/p ...

随机推荐

  1. re模块相关介绍

    re模块 模块和实际工作时间的关系 time模块和时间是什么关系?re模块和正则表达式的关系? 有了re模块就可以在python语言中操作正则表达式 正则表达式 1:什么是正则表达式? 一套规则--- ...

  2. HTML完整语法学习

    https://www.cnblogs.com/douluo/archive/2021/11/20/15582217.html

  3. Linux_Shell脚本

    Shell脚本 shell基础 shell变量 shell扩展 shell基础 shell简介 1.什么是shell? shell是一种命令解释器 shell也是一种编程语言 shell,python ...

  4. 基于CMMI的软件工程第一章读书笔记

    基于CMMI的软件工程第一章读书笔记 软件作为产品,就如机械业以及一般的加工业一样,只有对产品的产生流程和角色分工及其相应的管理活动有一个成熟的模式,能"更快,更好,更便宜"地开发 ...

  5. vector的使用方法

    vector是STL容器的可变长度数组.可变长度数组的头文件是<vector>,有以下常见的使用方法: 1.vector<int> v(N,i):建立一个可变长度数组v,内部元 ...

  6. css 多行文本展开收起

    <template> <div class="content"> <div :class="[isOpen ? 'text' : 'text ...

  7. Python数据可视化-条形图渐变颜色

    import pandas as pd from pyecharts.charts import Bar from pyecharts.commons.utils import JsCode data ...

  8. 什么是js严格模式?

    (use strict)严格模式是一种将更好的错误检查引入代码中的方法. 在使用严格模式时,无法使用隐式声明的变量.将值赋给只读属性或将属性添加到不可扩展的对象等. 1. 严格模式的目的 1) 消除J ...

  9. Python Type Hint中Optional[str]=None和str=None的区别

    Python Type Hint中Optional[str]=None和str=None的区别 1 问题来源 在读到Fluent Python, 2ed Edition, P260时产生了一些疑问: ...

  10. 通过Dnsmasq自建干净的DNS服务

    不晓得为撒,用网上的一些公共DNS服务的时候,总是莫名其妙的有些网站无法解析,有时候114能解析,阿里DNS不行或者腾讯DNS不行,导致总是来回切换DNS,很是烦心. 于是就想着自己搭建一个DNS服务 ...