Newer
Older
IntegratedFront / src / views / page / device / components / drawArea.vue
liyaguang 24 days ago 5 KB 优化电子围栏功能
<!--
  Description: 设备管理 - 区域绘制(电子围栏)
  Author: 李亚光
  Date: 2024-11-01
 -->

<script lang="ts" setup name="DrawArea">
const $props = defineProps({
  disabled: {
    type: Boolean,
    default: true
  },
  width: {
    type: Number,
    default: 426.4
  },
  height: {
    type: Number,
    default: 240
  }
})
const points = ref([
  { x: 30, y: 30 },
  { x: 395, y: 30 },
  { x: 395, y: 210 },
  { x: 30, y: 210 },
])
const elementId = ref(`${new Date().getTime()}`)
const setSize = () => {
  const container = document.getElementById(`${elementId.value}-container`) as HTMLElement
  container.style.width = `${$props.width}px`
  container.style.height = `${$props.height}px`
  const canvas = document.getElementById(`${elementId.value}-canvas`) as HTMLCanvasElement
  canvas.width = $props.width
  canvas.height = $props.height
}
const initDraw = () => {
  const canvas = document.getElementById(`${elementId.value}-canvas`)
  const container = document.getElementById(`${elementId.value}-container`)
  const ctx = canvas.getContext('2d')
  // console.log(canvas, points.value, 'canvas')
  ctx.clearRect(0, 0, container.clientWidth, container.clientHeight)
  // 初始位置
  function draw() {
    if (points.value.length !== 4) { return }
    ctx.clearRect(0, 0, canvas.width, canvas.height)
    ctx.beginPath()
    ctx.moveTo(points.value[0].x, points.value[0].y)
    ctx.lineTo(points.value[1].x, points.value[1].y)
    ctx.lineTo(points.value[2].x, points.value[2].y)
    ctx.lineTo(points.value[3].x, points.value[3].y)
    ctx.closePath()
    ctx.strokeStyle = 'red'
    ctx.lineWidth = 1
    ctx.stroke()
  }

  function drag(e, pointIndex) {
    if ($props.disabled) {
      return true
    }
    e = e || window.event
    e.preventDefault()
    var mousePos = { x: e.clientX - canvas.getBoundingClientRect().left, y: e.clientY - canvas.getBoundingClientRect().top }
    // console.log(mousePos, 'mousePos')
    // 限制在指定区域内
    if (mousePos.x < 0) {
      mousePos.x = 0
    }
    else if (mousePos.x > 533) {
      mousePos.x = 533
    }
    if (mousePos.y < 0) {
      mousePos.y = 0
    }
    else if (mousePos.y > 300) {
      mousePos.y = 300
    }
    points.value[pointIndex].x = mousePos.x
    points.value[pointIndex].y = mousePos.y
    draw()
  }

  function addDragEvents() {
    // if ($props.disabled) {
    //   return true
    // }
    var dragEvents = {
      dragStart(e) {
        e = e || window.event
        var target = e.target || e.srcElement
        var pointIndex = parseInt(target.getAttribute('data-point-index'), 10)
        if (isNaN(pointIndex)) { return }
        document.onmouseup = function () {
          document.onmouseup = null
          document.onmousemove = null
        }
        document.onmousemove = function (e) {
          drag(e, pointIndex)
        }
      },
    }

    var pointsElements = document.getElementsByClassName('point')
    for (var i = 0; i < pointsElements.length; i++) {
      pointsElements[i].addEventListener('mousedown', dragEvents.dragStart)
      pointsElements[i].setAttribute('data-point-index', i)
    }
  }

  function init() {
    if (points.value.length !== 4) { return }
    draw()
    setTimeout(() => {
      addDragEvents()
    })
  }
  init()
}
onMounted(() => {
  setSize()
  setTimeout(() => {
    initDraw()
  }, 100);
})

const style = ref([
  {
    top: `${points.value[0].y - 5}px`,
    left: `${points.value[0].x - 5}px`,
  },
  {
    top: `${points.value[1].y - 5}px`,
    left: `${points.value[1].x - 5}px`,
  },
  {
    top: `${points.value[2].y - 5}px`,
    left: `${points.value[2].x - 5}px`,
  },
  {
    top: `${points.value[3].y - 5}px`,
    left: `${points.value[3].x - 5}px`,
  },
])

watch(() => points.value, () => {
  if (points.value.length !== 4) {
    style.value = []
    return
  }
  style.value = [
    {
      top: `${points.value[0].y - 5}px`,
      left: `${points.value[0].x - 5}px`,
    },
    {
      top: `${points.value[1].y - 5}px`,
      left: `${points.value[1].x - 5}px`,
    },
    {
      top: `${points.value[2].y - 5}px`,
      left: `${points.value[2].x - 5}px`,
    },
    {
      top: `${points.value[3].y - 5}px`,
      left: `${points.value[3].x - 5}px`,
    },
  ]
}, {
  deep: true,
})
const getPoints = () => {
  return points.value.map((item) => ([item.x / $props.width, item.y / $props.height]))
}
const setPonits = (data) => {
  if (!data) {
    points.value = [
      { x: 30, y: 30 },
      { x: 395, y: 30 },
      { x: 395, y: 210 },
      { x: 30, y: 210 },
    ]
    initDraw()
    return
  }

  const pointsArr = JSON.parse(data)
  points.value = pointsArr.map((item: any) => ({
    x: Number(item[0]) * $props.width,
    y: Number(item[1]) * $props.height,
  }))
  initDraw()
}
defineExpose({
  points,
  getPoints,
  setPonits
})
watch([() => $props.width, $props.height], () => {
  //
  // console.log(document.getElementById('myCanvas'))
  // console.log($props.width, $props.height, '123')
}, {
  deep: true,
  immediate: true
})
</script>

<template>
  <div :style="{ width: `${$props.width}px`, height: `${$props.height}px`, position: 'relative', 'z-index': '9' }"
    :id="`${elementId}-container`">
    <canvas :id="`${elementId}-canvas`" :width="$props.width" :height="$props.height" class="canvans" />
    <div v-for="(item, index) in points" :key="index" class="point" :class="$props.disabled ? 'no' : ''"
      :style="style[index]" />
  </div>
</template>

<style scoped>
#draw-area {
  /* border: 1px solid #000; */
}

.canvans {
  padding: 0;
  margin: 0;

  /* position: absolute; */

  /* width: 100%;
  height: 100%; */

  /* left: 0;
  top: 0; */
  position: relative;
}

.point {
  width: 10px;
  height: 10px;
  position: absolute;
  border-radius: 50%;
  background-color: red;
  opacity: 0.5;
  top: 0;
  left: 0;
  z-index: 99;

  &:hover {
    cursor: move;
  }

}

.no {
  &:hover {
    cursor: default !important;
  }
}
</style>