美文网首页
电子围栏 vue

电子围栏 vue

作者: 于美美 | 来源:发表于2020-07-24 15:32 被阅读0次

电子围栏 vue

https://www.matteomattei.com/projects/jpolygon/

1.预览
image.png
2.代码
<template>
  <div>
    <canvas ref="jPolygon" width="300" height="200" style="cursor:crosshair;" data-imgsrc="https://picsum.photos/400" @mousedown="point_it($event)" oncontextmenu="return false;">
      Your browser does not support the HTML5 canvas tag.
    </canvas>

    <a-button @click="undo()">Undo</a-button>
    <a-button @click="clear_canvas()">Clear</a-button>
    <textarea ref="coordinates" disabled="disabled" style="width:300px; height:200px;"></textarea>
  </div>
</template>

<script>
  let ctx = undefined
  const pointsArr = [{"x":141,"y":91},{"x":90,"y":124},{"x":183,"y":157},{"x":243,"y":78}]

  export default {
    name: 'jPolygon',
    data () {
      return {
        perimeter: [],
        complete: false,
        canvas: null
      }
    },
    mounted () {
      this.canvas = this.$refs.jPolygon
      this.clear_canvas()
      this.init()
    },
    methods: {
      init () {
        this.perimeter = pointsArr
      },
      clear_canvas () {
        ctx = undefined
        this.perimeter = []
        this.complete = false
        this.$refs.coordinates.value = ''
        this.start(false)
      },
      start (with_draw) {
        const _this = this
        let { canvas } = _this
        var img = new Image();
        img.src = canvas.getAttribute('data-imgsrc')

        img.onload = () => {
          ctx = canvas.getContext("2d");
          ctx.drawImage(img, 0, 0, canvas.width, canvas.height);

          if(with_draw == true){
            _this.draw(false);
          } else {
            _this.draw(true);
          }
        }
      },
      draw (end) {
        let { perimeter, complete } = this
        ctx.lineWidth = 2
        ctx.strokeStyle = 'yellow'
        ctx.lineCap = 'square'
        ctx.beginPath()

        if (perimeter.length) {
          for(var i=0; i<perimeter.length; i++){
            if(i==0){
              ctx.moveTo(perimeter[i]['x'],perimeter[i]['y']);
              end || this.point(perimeter[i]['x'],perimeter[i]['y']);
            } else {
              ctx.lineTo(perimeter[i]['x'],perimeter[i]['y']);
              end || this.point(perimeter[i]['x'],perimeter[i]['y']);
            }
          }
        }

        if(end && perimeter.length){
          ctx.lineTo(perimeter[0]['x'],perimeter[0]['y']);
          ctx.closePath();
          ctx.fillStyle = 'rgba(255, 255, 0, 0.2)';
          ctx.fill();
          ctx.strokeStyle = 'yellow';
          complete = true;
        }
        ctx.stroke();

        // print coordinates
        if(perimeter.length == 0){
          this.$refs.coordinates.value = '';
        } else {
          this.$refs.coordinates.value = JSON.stringify(perimeter);
        }
      },
      point_it (event) {
        let { complete, perimeter, canvas } = this

        if(complete){
          alert('Polygon already created');
          return false;
        }
        var rect, x, y;

        if(event.ctrlKey || event.which === 3 || event.button === 2){
          if(perimeter.length==2){
            alert('You need at least three points for a polygon');
            return false;
          }
          x = perimeter[0]['x'];
          y = perimeter[0]['y'];
          if(this.check_intersect(x,y)){
            alert('The line you are drowing intersect another line');
            return false;
          }
          this.draw(true);
          alert('Polygon closed');
          event.preventDefault();
          return false;
        } else {
          rect = canvas.getBoundingClientRect();
          x = event.clientX - rect.left;
          y = event.clientY - rect.top;
          if (perimeter.length>0 && x == perimeter[perimeter.length-1]['x'] && y == perimeter[perimeter.length-1]['y']){
            // same point - double click
            return false;
          }
          if(this.check_intersect(x,y)){
            alert('The line you are drowing intersect another line');
            return false;
          }
          perimeter.push({'x':x,'y':y});
          this.draw(false);
          return false;
        }
      },
      check_intersect (x, y) {
        let { perimeter } = this
        if(perimeter.length < 4){
          return false;
        }
        var p0 = new Array();
        var p1 = new Array();
        var p2 = new Array();
        var p3 = new Array();

        p2['x'] = perimeter[perimeter.length-1]['x'];
        p2['y'] = perimeter[perimeter.length-1]['y'];
        p3['x'] = x;
        p3['y'] = y;

        for(var i=0; i<perimeter.length-1; i++){
          p0['x'] = perimeter[i]['x'];
          p0['y'] = perimeter[i]['y'];
          p1['x'] = perimeter[i+1]['x'];
          p1['y'] = perimeter[i+1]['y'];
          if(p1['x'] == p2['x'] && p1['y'] == p2['y']){ continue; }
          if(p0['x'] == p3['x'] && p0['y'] == p3['y']){ continue; }
          if(this.line_intersects(p0,p1,p2,p3)==true){
            return true;
          }
        }
        return false;
      },
      line_intersects (p0, p1, p2, p3) {
        var s1_x, s1_y, s2_x, s2_y;
        s1_x = p1['x'] - p0['x'];
        s1_y = p1['y'] - p0['y'];
        s2_x = p3['x'] - p2['x'];
        s2_y = p3['y'] - p2['y'];

        var s, t;
        s = (-s1_y * (p0['x'] - p2['x']) + s1_x * (p0['y'] - p2['y'])) / (-s2_x * s1_y + s1_x * s2_y);
        t = ( s2_x * (p0['y'] - p2['y']) - s2_y * (p0['x'] - p2['x'])) / (-s2_x * s1_y + s1_x * s2_y);

        if (s >= 0 && s <= 1 && t >= 0 && t <= 1)
        {
          // Collision detected
          return true;
        }
        return false; // No collision
      },
      point (x, y) {
        ctx.fillStyle="yellow";
        ctx.strokeStyle = 'yellow';
        ctx.fillRect(x-2,y-2,4,4);
        ctx.moveTo(x,y);
      },
      undo(){
        ctx = undefined;
        this.perimeter.pop();
        this.complete = false;
        this.start(true);
      }
    }
  }
</script>

相关文章

网友评论

      本文标题:电子围栏 vue

      本文链接:https://www.haomeiwen.com/subject/smnjlktx.html