回顾
要求开发一个模板图片,上传图片,可以对图片移动,缩放,保存到本地
总结
canvas movable-view 问题
- 首先想法是canvas移动缩放.不能移动canvas移动在真机和开发工具是不一样的,
-
- 他的touchas对象中没有pageX,pageY。
- 他的touchart数组会发生一些变化
- 双指之后和一些不明原因会导致移动位置不准确,
- movable-view 移动缩放问题不大,
-
- 但有时也会不灵,差异不大,
- 但是不能保存到本地
- movable-area父元素没有这个也不会有效果
2.解决方案,两者结合,
注意、
1.canvas位置要定位到页面之外,不然会对页面有影响,
2.小程序要申请相应的隐私权限,拍照,相册等。
3.canvas 配置项,宽高要与页面的这种层和movable-view 相同 ctx.translate(x,y)canvase位置和movable-view移动的位置相同ctx.scale(scale,scale)与缩放的倍数相同
4.canvas保存本地时要加延时器确保能够正常保存图片
5.movable-view 事件用到chang和scale事件注意的是scale事件x,y也会发生变化,所以事件中更改三个值。 5.背景图想要子啊moveble-view上又不影响他的操作需要定位后加一个 pointer-events: none;让他不会触发事件
<template>
<view>
<view class="img_box">
//遮罩层
<view class="img_zhe">
<image src="../static/mbg.png" class="imag"></image>
</view>
<movable-area style="width: 100%;height: 1200rpx; overflow: hidden;">
<movable-view :x="x" :y="y" direction="all" @change="onChange" style="width: 100%;height: 1200rpx;"
:scale="true" @scale="scaleChange" scale-min="0.5" scale-max="3" scale-value="0.9">
<image :src="tempImagePath" class="imag" style="width: 100%;height: 100%"></image>
</movable-view>
</movable-area>
</view>
<view>
<view class="flex">
<view class="flex_item">
<view class="item_b">{{ '运动小将' }}</view>
<view class="item_g">{{ '订单类型' }}</view>
</view>
<view class="line">
</view>
<view class="flex_item">
<view class="item_b">{{ '5元' }}</view>
<view class="item_g">{{ '购买金额' }}</view>
</view>
<view class="line">
</view>
<view class="flex_item">
<view class="item_b">{{ '5分钟' }}</view>
<view class="item_g">{{ '骑行时常' }}</view>
</view>
</view>
<view class="flex buttom">
<button class="btn" @click="takePhoto">拍照</button>
<button class="btn" @click="upImg">本地图片</button>
<button class=" btn save" @click="captureAndSave">保存图片</button>
</view>
</view>
<canvas class="canvs" canvas-id="bacbackground" ref="canvas"
:style="'width:750rpx;height:1200rpx; bacbackground-color:#333'"></canvas>
</view>
</template>
<script>
export default {
data() {
return {
tempImagePath: '', // 存储临时图片路径
canvasWidth: 0, // 画布宽度
canvasHeight: 0, // 画布高度
img: null, // 图片对象
scale: 0.9,
translateX: 0, // X轴偏移
translateY: 0, // Y轴偏移
touchStart: { x: 0, y: 0 }, // 触摸起始点
touchMove: { x: 0, y: 0 }, // 触摸移动点
isTouching: false, // 是否正在触摸
ctx: null, // canvas 2d 上下文
backgroundImagePath: '../static/mbg.png',
initialPinchDistance: 0,
pinch: false,//双指
initialDistance: 0,
clear: 0,
x: 0,
y: 0,
};
},
methods: {
upImg() {
// 选择本地图片
uni.chooseImage({
count: 1,
sizeType: ['compressed'],
sourceType: ['album'],
success: (res) => {
const tempFilePath = res.tempFilePaths[0];
// 更新页面或其他操作
this.tempImagePath = tempFilePath;
console.log('选择的本地图片路径:', tempFilePath);
},
});
},
onChange(event) {
console.log('change', event)
this.translateX = event.detail.x
this.translateY = event.detail.y
},
scaleChange(event) {
console.log('scale', event)
this.translateX = event.detail.x
this.translateY = event.detail.y
this.scale = event.detail.scale
},
takePhoto() {
// 选择图片
uni.chooseImage({
count: 1,
sizeType: ['compressed'],
sourceType: ['camera'],
success: (res) => {
const tempFilePaths = res.tempFilePaths;
// 将临时图片路径存储在 data 中
this.tempImagePath = tempFilePaths[0];
},
});
},
initCanvas() {
// 获取图片信息
uni.getImageInfo({
src: this.tempImagePath,
success: (info) => {
// 计算画布大小,使用画布的大小作为背景图片的大小
this.canvasWidth = uni.upx2px(750); // 100upx
this.canvasHeight = uni.upx2px(1200); // 1200upx
// 初始化 canvas 上下文
// 初始化画布
this.drawCanvas();
},
});
},
drawCanvas() {
//
console.log('画布更新了')
// 清空画布
this.ctx = null
this.ctx = uni.createCanvasContext('bacbackground', this);
this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
// 设置图片的位置和缩放
this.ctx.translate(this.translateX, this.translateY);
this.ctx.scale(this.scale, this.scale);
// 旋转图片
this.ctx.rotate((this.clear * Math.PI) / 180);
// 绘制拍照的图片
this.ctx.drawImage(this.tempImagePath, 0, 0, this.canvasWidth, this.canvasHeight);
// // 重置变换矩阵,确保接下来的操作不影响之前绘制的图片
this.ctx.setTransform(1, 0, 0, 1, 0, 0);
// 绘制背景图片
this.ctx.drawImage(
this.backgroundImagePath,
0,
0,
this.canvasWidth,
this.canvasHeight
);
// 将绘制的内容显示到画布上
this.ctx.draw();
setTimeout(() => {
this.fopush()
}, 100);
},
captureAndSave() {
if (this.tempImagePath) {
this.initCanvas()
} else {
uni.showToast({
title: '请先上传图片',
icon: 'none',
duration: 2000,
});
}
},
fopush() {
return new Promise((resolve, reject) => {
// 将 canvas 截图生成临时文件路径
uni.canvasToTempFilePath({
canvasId: 'bacbackground', // canvas-id
success: (res) => {
// 保存成功,res.tempFilePath 是保存到本地的路径
const tempFilePath = res.tempFilePath;
// 保存到相册
uni.saveImageToPhotosAlbum({
filePath: tempFilePath,
success: () => {
uni.showToast({
title: '保存成功',
icon: 'success',
duration: 2000,
});
resolve(tempFilePath);
},
fail: (err) => {
uni.showToast({
title: '保存失败',
icon: 'none',
duration: 2000,
});
reject(err);
},
});
},
fail: (err) => {
console.error(err);
uni.showToast({
title: '截图失败',
icon: 'none',
duration: 2000,
});
reject(err);
},
});
});
}
},
};
</script>
<style lang="scss" scoped>
.img_box {
height: 1200rpx;
position: relative;
}
.canvs {
position: absolute;
top: 0;
left: -1200rpx;
pointer-events: none;
}
.btn_slider {
width: 50%;
display: flex;
align-items: center;
}
.imag {
width: 100%;
height: 1200rpx;
}
.buttom_btn {
display: flex;
// margin: 10 30rpx;
font-size: 35rpx;
// border: 2rpx solid red;
padding: 10rpx 30rpx;
}
::v-deep .u-number-box__plus {
width: 80rpx !important;
}
/* 将 canvas 隐藏在页面外 */
// canvas {
// position: absolute;
// top: 0;
// left: 0;
// }
.flex {
margin-top: 10rpx;
display: flex;
justify-content: space-between;
padding: 10rpx;
height: 80rpx;
.item_b {
font-size: 30rpx;
font-weight: bold;
}
.item_g {
font-size: 25rpx;
color: #9a9a9a;
}
.flex_item {
width: 200rpx;
text-align: center;
padding: 10rpx;
}
.line {
width: 2rpx;
background-color: #333;
}
}
.img_zhe {
width: 100%;
height: 1200rpx;
position: absolute;
top: 0;
left: 0;
z-index: 99;
pointer-events: none;
image {
width: 100%;
height: 100%;
}
}
.btn {
font-size: 30rpx;
width: 250rpx;
border-radius: 50rpx;
background: white;
box-sizing: border-box;
border: 2rpx solid #9a9a;
}
</style>