|
|
@@ -39,40 +39,28 @@
|
|
|
scale="true"
|
|
|
scale-min="1"
|
|
|
scale-max="5"
|
|
|
+ :style="{ height: containerHeight }"
|
|
|
>
|
|
|
<view class="image-container">
|
|
|
- <!-- 原图 -->
|
|
|
<image
|
|
|
- :src="currentImg.addr"
|
|
|
+ :src="canvasImagePath || currentImg.addr"
|
|
|
class="main-photo-image"
|
|
|
mode="widthFix"
|
|
|
@load="onImageLoad"
|
|
|
/>
|
|
|
- <!-- 虫子标记层 -->
|
|
|
- <view class="bug-markers" v-if="bugMarkers.length > 0">
|
|
|
- <view
|
|
|
- v-for="(marker, index) in bugMarkers"
|
|
|
- :key="index"
|
|
|
- class="bug-marker"
|
|
|
- :style="{
|
|
|
- left: marker.x + '%',
|
|
|
- top: marker.y + '%',
|
|
|
- width: marker.width + '%',
|
|
|
- height: marker.height + '%',
|
|
|
- borderColor: marker.color
|
|
|
- }"
|
|
|
- >
|
|
|
- <view class="bug-label" :style="{ color: marker.color }">
|
|
|
- {{ getPestName(marker.id) }}
|
|
|
- </view>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
</view>
|
|
|
</movable-view>
|
|
|
</movable-area>
|
|
|
<view class="photo-timestamp">{{ formatDate(currentImg.addtime) }}</view>
|
|
|
</view>
|
|
|
|
|
|
+ <!-- 隐藏画布,用于绘制标注图 -->
|
|
|
+ <canvas
|
|
|
+ canvas-id="annotatedCanvas"
|
|
|
+ :style="{ width: canvasWidth + 'px', height: canvasHeight + 'px' }"
|
|
|
+ style="position: fixed; left: -9999px; top: -9999px;"
|
|
|
+ ></canvas>
|
|
|
+
|
|
|
<!-- 缩略图预览 -->
|
|
|
<view class="thumbnail-preview">
|
|
|
<view class="thumbnail-scroll">
|
|
|
@@ -179,6 +167,9 @@ export default {
|
|
|
imageWidth: 0,
|
|
|
imageHeight: 0,
|
|
|
imgOld_id:'',
|
|
|
+ canvasImagePath: '',
|
|
|
+ canvasWidth: 375,
|
|
|
+ canvasHeight: 300,
|
|
|
containerHeight: '300px',
|
|
|
device_type_id:'',
|
|
|
cmd:'sy',
|
|
|
@@ -370,8 +361,37 @@ export default {
|
|
|
},
|
|
|
});
|
|
|
this.currentImg = res;
|
|
|
+ this.canvasImagePath = '';
|
|
|
+
|
|
|
+ // 获取图片信息和本地路径
|
|
|
+ let localImagePath = '';
|
|
|
+ try {
|
|
|
+ const imageInfo = await new Promise((resolve, reject) => {
|
|
|
+ uni.getImageInfo({
|
|
|
+ src: res.addr,
|
|
|
+ success: resolve,
|
|
|
+ fail: reject
|
|
|
+ });
|
|
|
+ });
|
|
|
+ this.imageWidth = imageInfo.width;
|
|
|
+ this.imageHeight = imageInfo.height;
|
|
|
+ localImagePath = imageInfo.path;
|
|
|
+
|
|
|
+ // 计算容器高度
|
|
|
+ const systemInfo = uni.getSystemInfoSync();
|
|
|
+ const screenWidth = systemInfo.windowWidth;
|
|
|
+ const containerWidth = screenWidth - 24;
|
|
|
+ const displayHeight = (containerWidth / this.imageWidth) * this.imageHeight;
|
|
|
+ this.containerHeight = displayHeight + 'px';
|
|
|
+ } catch(e) {
|
|
|
+ console.error('获取图片信息失败:', e);
|
|
|
+ this.imageWidth = 1000;
|
|
|
+ this.imageHeight = 1000;
|
|
|
+ }
|
|
|
+
|
|
|
// 处理label参数生成bugMarkers
|
|
|
this.processBugMarkers();
|
|
|
+
|
|
|
const pest_list = res.pest_list
|
|
|
const pestArr = new Map()
|
|
|
const pesAlltList = []
|
|
|
@@ -406,23 +426,23 @@ export default {
|
|
|
if (this.currentImg.is_mark != 0) {
|
|
|
this.processBugMarkers();
|
|
|
}
|
|
|
+
|
|
|
+ // 绘制标注图片(异步,不阻塞)
|
|
|
+ if (localImagePath) {
|
|
|
+ this.drawAnnotatedImage(localImagePath);
|
|
|
+ }
|
|
|
+
|
|
|
this.pestList = pestList
|
|
|
},
|
|
|
onImageLoad(e) {
|
|
|
- this.imageWidth = e.detail.width;
|
|
|
- this.imageHeight = e.detail.height;
|
|
|
-
|
|
|
- // 计算容器显示高度(根据屏幕宽度和图片宽高比)
|
|
|
- const systemInfo = uni.getSystemInfoSync();
|
|
|
- const screenWidth = systemInfo.windowWidth;
|
|
|
- const containerWidth = screenWidth - 24; // 减去左右margin (24rpx ≈ 12px)
|
|
|
- const displayHeight = (containerWidth / this.imageWidth) * this.imageHeight;
|
|
|
-
|
|
|
- this.containerHeight = displayHeight + 'px';
|
|
|
- console.log('图片尺寸:', this.imageWidth, this.imageHeight, '容器高度:', this.containerHeight);
|
|
|
-
|
|
|
- // 图片加载完成后处理bugMarkers
|
|
|
- this.processBugMarkers();
|
|
|
+ // 仅在容器高度未计算时更新
|
|
|
+ if (!this.containerHeight || this.containerHeight === '300px') {
|
|
|
+ const systemInfo = uni.getSystemInfoSync();
|
|
|
+ const screenWidth = systemInfo.windowWidth;
|
|
|
+ const containerWidth = screenWidth - 24;
|
|
|
+ const displayHeight = (containerWidth / e.detail.width) * e.detail.height;
|
|
|
+ this.containerHeight = displayHeight + 'px';
|
|
|
+ }
|
|
|
},
|
|
|
|
|
|
processBugMarkers() {
|
|
|
@@ -491,7 +511,7 @@ export default {
|
|
|
// this.pestList = [];
|
|
|
const markers = [];
|
|
|
// 根据原图宽度计算缩放比例
|
|
|
- let scaleRatio = 3.06;
|
|
|
+ let scaleRatio = 3.07;
|
|
|
// if (this.imageWidth >= 5000) {
|
|
|
// scaleRatio = 4;
|
|
|
// } else if (this.imageWidth >= 4000) {
|
|
|
@@ -541,6 +561,80 @@ export default {
|
|
|
this.bugMarkers = markers;
|
|
|
}
|
|
|
},
|
|
|
+ async drawAnnotatedImage(localImagePath) {
|
|
|
+ if (!localImagePath || !this.bugMarkers.length) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 计算画布尺寸(匹配显示区域)
|
|
|
+ const sysInfo = uni.getSystemInfoSync();
|
|
|
+ const displayWidth = sysInfo.windowWidth - 24;
|
|
|
+ const displayHeight = (displayWidth / this.imageWidth) * this.imageHeight;
|
|
|
+
|
|
|
+ this.canvasWidth = Math.round(displayWidth);
|
|
|
+ this.canvasHeight = Math.round(displayHeight);
|
|
|
+
|
|
|
+ // 等待画布尺寸更新
|
|
|
+ await this.$nextTick();
|
|
|
+
|
|
|
+ const ctx = uni.createCanvasContext('annotatedCanvas', this);
|
|
|
+
|
|
|
+ // 绘制原始图片
|
|
|
+ ctx.drawImage(localImagePath, 0, 0, this.canvasWidth, this.canvasHeight);
|
|
|
+
|
|
|
+ // 绘制虫子标记
|
|
|
+ this.bugMarkers.forEach(marker => {
|
|
|
+ const x = (marker.x / 100) * this.canvasWidth;
|
|
|
+ const y = (marker.y / 100) * this.canvasHeight;
|
|
|
+ const w = (marker.width / 100) * this.canvasWidth;
|
|
|
+ const h = (marker.height / 100) * this.canvasHeight;
|
|
|
+
|
|
|
+ // 绘制矩形框
|
|
|
+ ctx.setStrokeStyle(marker.color);
|
|
|
+ ctx.setLineWidth(1);
|
|
|
+ ctx.strokeRect(x, y, w, h);
|
|
|
+
|
|
|
+ // 绘制标签(上方优先,超出画布上边界时放到框下方)
|
|
|
+ const pestName = this.getPestName(marker.id);
|
|
|
+ const fontSize = 12;
|
|
|
+ ctx.setFontSize(fontSize);
|
|
|
+ ctx.setFillStyle(marker.color);
|
|
|
+ if (y - fontSize - 4 < 0) {
|
|
|
+ ctx.fillText(pestName, x + 4, y + h + fontSize + 4);
|
|
|
+ } else {
|
|
|
+ ctx.fillText(pestName, x + 4, y - 4);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 提交绘制
|
|
|
+ await new Promise((resolve) => {
|
|
|
+ ctx.draw(false, () => {
|
|
|
+ setTimeout(resolve, 300);
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ // 转为临时图片
|
|
|
+ const tempFile = await new Promise((resolve, reject) => {
|
|
|
+ uni.canvasToTempFilePath({
|
|
|
+ canvasId: 'annotatedCanvas',
|
|
|
+ x: 0,
|
|
|
+ y: 0,
|
|
|
+ width: this.canvasWidth,
|
|
|
+ height: this.canvasHeight,
|
|
|
+ destWidth: this.canvasWidth * 2,
|
|
|
+ destHeight: this.canvasHeight * 2,
|
|
|
+ success: resolve,
|
|
|
+ fail: reject
|
|
|
+ }, this);
|
|
|
+ });
|
|
|
+
|
|
|
+ this.canvasImagePath = tempFile.tempFilePath;
|
|
|
+ } catch (error) {
|
|
|
+ console.error('绘制标注图片失败:', error);
|
|
|
+ this.canvasImagePath = '';
|
|
|
+ }
|
|
|
+ },
|
|
|
handleBack() {
|
|
|
uni.navigateBack({
|
|
|
delta: 1
|