uni-app在image上绘制点位并回显

发布于:2024-12-18 ⋅ 阅读:(71) ⋅ 点赞:(0)

在 Uni-app 中绘制多边形可以通过使用 Canvas API 来实现。Uni-app 是一个使用 Vue.js 开发所有前端应用的框架,同时支持编译为 H5、小程序等多个平台。由于 Canvas 是 H5 和小程序中都支持的 API,所以通过 Canvas 绘制多边形是一个比较通用的方法。

1. 创建一个新的 Uni-app 项目(如果还没有的话)

vue create -p dcloudio/uni-preset-vue my-uni-app
cd my-uni-app

2. 开始绘制

背景:在image上绘制多边形,并将点位回传。回传后的数据格式'(1,2),(3,4)',所以需要一些方法进行处理。如你没有转换需求,可自行删除。

<template>
  <view class="layout-wrap">
    <view class="draw-wrap">
      <view class="camera-wrap">
        <img
          :style="{ width: `${canvasWidth}px`, height: `${canvasHeight}px` }"
          :src="cameraUrl"
          mode="aspectFill"
          class="popup-img"
        />
        <canvas
          id="myCanvas"
          canvas-id="myCanvas"
          @touchstart="onTouchStart"
          @touchend="onTouchEnd"
          :style="{ width: `${canvasWidth}px`, height: `${canvasHeight}px` }"
        ></canvas>
      </view>
    </view>
    <view class="btn-wrap">
      <view class="btn reset-btn" @click="handleClear">清 除</view>
      <view class="btn" @click="handleSubmit">确 定</view>
    </view>
  </view>
</template>

<script>
import { addCameraRegion, getCameraId } from "@/api/cabinet";
import config from "@/config";
const baseUrl = config.baseUrl;
export default {
  name: "draw",
  data() {
    return {
      points: [], // 存储触摸点
      canvasWidth: "",
      canvasHeight: "",
      ctx: "",
      cameraUrl: "",
      rate: "",
      touchNum: 0,
    };
  },
  onShow() {
    this.init();
  },
  methods: {
    init() {
      // 获取配置及绘制图形
       getCameraId(config.hostInfoId).then((res) => {
        const data = res.data;
        this.monitorPoints = data.monitorPoints;
        this.rate =  data.monitorWidth / data.monitorHeight;
        this.canvasWidth = 1000
        this.canvasHeight = this.canvasWidth / this.rate;
        this.cameraUrl =
          baseUrl +
          "/api/monitor/player?cameraId=" +
          data.monitorCameraId +
          "&time=" +
          new Date().getTime();
        const ctx = uni.createCanvasContext("myCanvas");
        this.ctx = ctx;
        this.touchNum = 0
        this.setRect();
      });
    },
    onTouchStart(e) {
     if (this.touchNum === 0) {
        this.handleClear()
      }
      this.touchNum++;
      const touch = e.touches[0];
      this.points.push({ x: touch.x, y: touch.y });
    },
    onTouchEnd(e) {
      this.drawPolygon();
      this.ctx.draw();
    },

    drawPolygon() {
      const ctx = this.ctx;
      ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight); // 清除画布
      ctx.setStrokeStyle("#00ff00"); // 设置多边形边框颜色
      // 设置填充样式和透明度
      ctx.setLineWidth(10); // 设置多边形边框宽度
      ctx.beginPath();
      this.points.forEach((point, index) => {
        if (index === 0) {
          ctx.moveTo(point.x, point.y);
        } else {
          ctx.lineTo(point.x, point.y);
        }
      });

      // 如果需要闭合多边形,取消注释以下行
      ctx.closePath();
      ctx.stroke();
      // 绘制填充
      ctx.setFillStyle("rgba(0, 255, 0, 0.4)");
      ctx.fill();
    },
    // 根据之前的数据回显多边形(如果有的话)
    setRect() {
      try {
        const pointsArr = this.monitorPoints.slice(1, -1).split("),(");
        if (pointsArr && pointsArr.length > 1) {
          pointsArr.map((p) => {
            this.points.push({
              x: Math.round(p.split(",")[0] / this.rate),
              y: Math.round(p.split(",")[1] / this.rate),
            });
          });
          console.log(this.canvasWidth, this.canvasHeight);
          console.log(this.points);
          this.drawPolygon();
          setTimeout(() => {
            //必须延迟执行 不然H5不显示
            this.ctx.draw(); //必须加上  uniapp 没这儿玩意儿 显示不出来不比原生  不加可以显示
          }, 200);
        }
      } catch (error) {
        console.error("绘制多边形时出错:", error);
      }
    },
    // 提交    
    handleSubmit() {
      if (this.points.length > 1) {
        // 转换并发送多边形的顶点坐标
        const scaledPoints = [];
        this.points.map((point) => {
          scaledPoints.push(
            `(${Math.round(point.x * this.rate)},${Math.round(
              point.y * this.rate
            )})`
          );
        });

       // 提交请求

      } else {
        uni.showToast({
          title: "请绘制",
          icon: "none",
        });
      }
    },
    // 清除
    handleClear() {
      this.points = [];
      this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight); // 清除画布
      this.ctx.draw();
    },
  },
};
</script>
<style lang="scss" scoped>
.draw-wrap {
  position: relative;
  margin-top: 2vh;
  left: 7vw;
}
.camera-wrap {
  height: 76vh;
}
.popup-img {
  position: absolute;
  top: 0;
  left: 0;
  object-fit: contain;
  border: 6rpx solid #093763;
  box-sizing: border-box;
}

#myCanvas {
  position: absolute;
  top: 0;
  left: 0;
}
</style>

3. 效果图

4. 解释

  • uni.createCanvasContext('myCanvas') 用于获取 Canvas 的绘图上下文。
  • ctx.setStrokeStyle('red') 和 ctx.setLineWidth(10) 用于设置描边颜色和宽度。
  • ctx.beginPath() 开始一个新的路径。
  • ctx.moveTo(points[0].x, points[0].y) 和 ctx.lineTo(points[i].x, points[i].y) 用于绘制线段。
  • ctx.closePath() 闭合路径,使之成为一个多边形。
  • ctx.stroke() 描边。
  • ctx.setFillStyle('rgba(30, 144, 255,0.5)') 和 ctx.fill() 用于填充多边形。
  • ctx.draw() 将所有绘图操作提交到 Canvas 上。

5. 坑

回显的时候,苦恼了很久,为什么点位已经传入,不能回显。后来发现,是draw方法需要加延时。


网站公告

今日签到

点亮在社区的每一天
去签到