背景需求
当时做小程序时 遇到一个场景 用户拍摄照片=>智能解析题目=>页面回显框选
回显后,可能不是用户想要的某一区域或某一题,此时就需要用户手动编辑裁剪。先看下图片效果及视频演示
看完后 我们来分析一下
做的时候 我的第一反应就是canvas和movable-area的组合 但是怎么尝试都没有成功。然后去百度查看,各种杂七乱八的,都没有达到自己想要实现的效果。然后我就请教之前有做过的大佬,他给的答案是vanvas结合movable-area组合
先聊一下框选回显的问题吧
误区
动态获取放图片盒子的大小 然后比上手机屏幕的大小得到比例 根据返回的坐标点*比例 画出所有框选位置
纠正
动态获取盒子的高度(目的是后续裁剪使用)把对放图片盒子的操作 给Image操作
看下页面使用代码
<view v-if="vdata.selectBox" class="photographMain">
<view class="swiperMain">
<view class="handelImg" v-if="!vdata.imgList.length">
<nut-button loading type="warning"></nut-button>
<view>图片处理中</view>
</view>
<swiper
v-else
@change="getCurrent"
class="swiper"
indicator-color="#999"
indicator-active-color="#333"
:circular="false"
:indicator-dots="false"
:current="vdata.current - 1"
>
<swiper-item v-for="(item, i) in vdata.imgList" :key="i">
<view class="list-item">
<image :src="item.originUrl" class="imageContent" :mode="computedFixed">
<view class="mc">
<template v-if="item.contentListInfoList && item.contentListInfoList.length">
<view
class="mc-item"
v-for="(bg, key) in item.contentListInfoList"
:style="handlePosition(item, bg.point2dXYList)"
:key="key"
>
<view class="bj" @tap="editBox(item, bg.point2dXYList, bg)">编辑</view>
<view class="jj" v-show="!bg.isCheck">
<image
@tap="changeIsCheck(i, key, true)"
src="https://dcg-c-system.obs.cn-east-3.myhuaweicloud.com/ctb/69ddc2a38118419eb6815bb37f6fee70/addPot.png"
mode="scaleToFill"
/>
</view>
<view class="jy" v-show="bg.isCheck">
<image
@tap="changeIsCheck(i, key, false)"
src="https://dcg-c-system.obs.cn-east-3.myhuaweicloud.com/ctb/5fb2d6d087aa44b1b42c405f364610ca/commit.png"
mode="scaleToFill"
/>
</view>
</view>
</template>
</view>
</image>
</view>
</swiper-item>
</swiper>
<view class="current"> {
{ vdata.current }}/{
{ vdata.imgUrl.length }} </view>
</view>
</view>
<view v-else class="welMain">
<welCropper @cropdown="cropdown" :cropperOptions="vdata.cropperOptions" />
</view>
然后看下 welCropper 有两个版本 一个vue的版本 一个react的版本
就以vue版本为例吧
<template>
<scroll-view :class="['cropper_main_container', data.cropperData.hidden ? 'hidden' : '']">
<view
class="cropper_container"
:style="{ width: data.cropperData.W + 'px', height: data.cropperData.H + 'px' }"
>
<canvas
class="original_canvas"
canvas-id="originalCanvas"
:style="{
width: data.changableData.originalSize.width + 'px',
height: data.changableData.originalSize.height + 'px',
}"
></canvas>
<image
:src="data.cropperData.imageInfo.path"
class="scale-image cropper_canvas_container_item"
mode="aspectFill"
:style="{
left: data.changableData.previewImageInfo.x + 'px',
top: data.changableData.previewImageInfo.y + 'px',
width: data.changableData.previewImageInfo.w + 'px',
height: data.changableData.previewImageInfo.h + 'px',
transform: `rotate(${data.changableData.rotateDegree}deg)`,
}"
></image>
<!-- transform:rotate() -->
<view
:class="['cropper_canvas_container', data.cropperData.canvasType ? 'isOpacity' : '']"
:style="{
width: data.changableData.scaleSize.width + 'px',
height: data.changableData.scaleSize.height + 'px',
}"
>
<canvas
:type="data.cropperData.canvasType || ''"
:canvas-id="data.canvasId"
class="move_canvas cropper_canvas_container_item"
></canvas>
<template v-if="data.cropperData.drawSign == 1">
<movable-area
class="cropper_movable_area_container"
:style="{
width: data.changableData.scaleSize.width + 'px',
height: data.changableData.scaleSize.height + 'px',
}"
>
<template v-if="data.moveItems">
<template v-for="(item, i) in data.moveItems" :key="i">
<movable-view
class="move_item"
:style="{
width: data.cropperData.itemLength + 'px',
height: data.cropperData.itemLength + 'px',
}"
direction="all"
:x="item.x - data.cropperData.itemLength / 2"
:y="item.y - data.cropperData.itemLength / 2"
@touchmove="moveEvent"
@touchend="endEvent"
@touchcancel="touchcancelEvent"
:data-key="i"
></movable-view>
</template>
</template>
</movable-area>
</template>
<template v-else>
<movable-area
class="cropper_movable_area_container"
:style="{
width: data.changableData.scaleSize.width + 'px',
height: data.changableData.scaleSize.height + 'px',
}"
>
<template v-if="data.moveItems">
<template v-for="(item, i) in data.moveItems" :key="i">
<movable-view
class="move_item"
style="width:{
{data.cropperData.itemLength}}px; height:{
{data.cropperData.itemLength}}px;"
direction="all"
:x="item.x - data.cropperData.itemLength / 2"
:y="item.y - data.cropperData.itemLength / 2"
@touchmove="moveEvent"
@touchend="endEvent"
@touchcancel="touchcancelEvent"
data-key="{
{index}}"
></movable-view>
</template>
</template>
</movable-area>
</template>
</view>
</view>
</scroll-view>
</template>
遇到的坑及注意事项
1.封装组件时 外围盒子要定位
2.移动时,移动点位有偏差 (这里是100%等比例缩放的 如果自定义navbar需要减去所有以外的padding,margin,height)
3.一个页面反反复复使用 会遇到报错(canvas id已经使用了 不能再次使用) 动态设置cancasId
4.框选回显,坐标点位有偏差(始终保持图片大小等比例缩放 回显坐标不能使用px 最好使用%)
5.通过createSelectorQuery获取高度时,没有获取到 设置setTimerOut获取
这是welCropper所有的template代码 可以尝试根据代码去反推逻辑,有兴趣的小伙伴可以私信我或加wx:Darren_jm 备注csdn 获取全部代码