封装一个knova插件的类,包含各种小功能

包含的功能

  • 图片渲染

  • 矩形绘制,矩形渲染

  • 图形的删除(通过id)

  • 文字的渲染, 文字位置更新

  • 矩形的变换(使矩形可以拖动,放大,缩小,通过拖动下图的点来实现图形变换),移除矩形变换函数

  • 最后面添加了点击绘制线段和多边形的函数,需要的可自行添加到类里面
    在这里插入图片描述

  • 图片放大缩小

  • 矩形框的高亮

  • 类的自定义事件(可以将类里面的数据传递到组件)

代码(引用的代码在最下面)

import { hintMessage } from '@/utils/hintMessage';
import { toRaw } from 'vue';
// import { useDataOverviewStore } from '@/store';
// import { rectListtype } from '@/store/modules/dataOverview/types';
import Konva from 'konva';
import { Layer } from 'konva/lib/Layer';
import { Stage } from 'konva/lib/Stage';
import { generateString } from './generateString';
import {
  convertFourCoodinateToXYWidthHeight,
  convertXYWidthHeightToFourCoodinate,
  getOffset,
  getRectInImageOutside,
  getTextCoodinate,
} from './knovaCoordinateCalculation';
import { roundNumber } from './numberHandle';

export default class KnovaDraw {
  stage: Stage;

  layerShape: Layer;

  layerImg: Layer;

  // pictureLoading = false;

  // 图片缩放倍数
  pantographRatio = 1;

  config: any;

  isDrawRect = false;

  // dataOverviewStore: any;

  imgOffset = {
    x: 0,
    y: 0,
  };

  isTransform = false; // 判断是否正在进行图形变换

  _eventHandlers: any

  isEditStatus = false

  oldAttrs: any = {}

  constructor(config: any) {
    // this.stage = new Konva.Stage({
    //   container: document.getElementById('knovaCanvas') as HTMLDivElement,
    //   width: config.width,
    //   height: config.height,
    // });
    // this.dataOverviewStore = useDataOverviewStore();
    this.config = config;
    this.stage = new Konva.Stage({
      container: document.getElementById('knovaCanvas') as HTMLDivElement,
      width: config.width,
      height: config.height,
      draggable: true,
    });
    this.layerShape = new Konva.Layer();
    this.layerImg = new Konva.Layer();
    this.init(config.url, this.config.rectList);
    this.clickEvent();
    this.dblclickEvent();
    this.wheelEvent();
    this._eventHandlers = {};
  }

  init(url: string, rectList: any) {
    // console.log(url);
    
    // this.drawImg()
    const img = new Image();
    img.src = url;
    // this.pictureLoading = true;
    // 清除上一张图片
    this.layerImg.removeChildren();
    img.onload = () => {
      // 获取缩放倍数
      this.pantographRatio =
        img.width / this.config.width > img.height / this.config.height
          ? img.width / this.config.width
          : img.height / this.config.height;
      // if (this.config.isMap) {
      //   this.drawImg(img, this.config.width * 10, this.config.height * 10);
      // } else {
      // }
      const imgWidth = roundNumber(img.width / this.pantographRatio);
      const imgHeight = roundNumber(img.height / this.pantographRatio);
      this.imgOffset = getOffset(
        imgWidth,
        imgHeight,
        this.config.width,
        this.config.height
      );
      this.drawImg(img, imgWidth, imgHeight);
      // 渲染矩形框数据
      this.renderRects(rectList)
      // if (this.config.isShowReviewData) {
      // } else {
      //   this.renderRects(this.config.shapeList)
      // }
    };
    this.drawRect();
  }

  setIsEditStatus(bool: boolean) {
    this.isEditStatus = bool
    // 控制矩形框是否可以拖动
    this.stage.find('.shape').forEach(item => {
      item.setAttrs({
        ...item.attrs,
        draggable: bool,
      });
    })
  }

  drawImg(img: any, width: number, height: number) {
    const imgs = new Konva.Image({
      x: 0,
      y: 0,
      image: img,
      width,
      height,
      offsetX: this.imgOffset.x,
      offsetY: this.imgOffset.y,
    });
    this.layerImg.add(imgs);
    this.stage.add(this.layerImg);
  }

  // 绘制一组矩形框
  renderRects(rectList: Array<any>) {
    this.layerShape.removeChildren();
    rectList.forEach(item => {
      const rectParams = {
        ...convertFourCoodinateToXYWidthHeight(
          item.polygon_point_list,
          this.pantographRatio,
          this.imgOffset
        ),
        id: item.id + '',
      };
      this.Rect(rectParams)
      const textParams = {
        id: 'textid' + item.id,
        text: item.object_name,
        ...getTextCoodinate(
          item.polygon_point_list,
          this.pantographRatio,
          this.imgOffset
        ),
      };
      this.Text(textParams)
    })
    this.stage.add(this.layerShape);
  }

  Rect(payload: any, draggable = false) {
    const rect = new Konva.Rect({
      ...payload,
      stroke: 'red',
      name: 'shape',
      type: 'rect',
      strokeWidth: 1,
      draggable,
    });
    this.layerShape.add(rect);
    // 添加矩形拖动事件
    rect.on('dragstart', (e) => {
      this.isTransform = true;
      const { attrs } = e.target;
      this.oldAttrs = JSON.parse(JSON.stringify(attrs))
    })
    rect.on('dragend', (e) => {
      this.isTransform = false;
      // setTimeout(() => {this.isTransform = false;}, 100)
      const { attrs } = e.target;
      this.modificationRectInfo(attrs);
    });
  }

  deleteShape(id: string) {
    this.stage.find(`#${id}`).forEach(item => item.destroy())
  }

  Text(payload: any) {
    const text = new Konva.Text({
      ...payload,
      fontSize: 18,
      fill: 'red',
      offsetX: 0,
      offsetY: 18,
      type: 'text',
    });
    this.layerShape.add(text);
  }

  updatedText(info: { id: string; text: string}) {
    this.stage.find(`#textid${info.id}`).forEach(item => item.setAttrs({...item, text: info.text}))
  }

  // 让矩形可以变换
  transformerFun() {
    // console.log('让矩形可以变换1');
    this.stage.find('.shape').forEach((item) => {
      // console.log('让矩形可以变换');
      console.log(item);

      const tr = new Konva.Transformer({
        anchorStroke: 'red',
        // anchorFill: 'yellow',
        anchorSize: 4,
        borderStroke: 'red',
        borderDash: [],
        nodes: [item],
        id: `Transformer${item.attrs.id}`,
        rotateEnabled: false,
        name: 'transformer',
      });
      this.layerShape.add(tr);

      tr.on('transformstart', (e) => {
        const { attrs } = e.target;
        // console.log('start', toRaw(attrs).y);
        this.oldAttrs = JSON.parse(JSON.stringify(attrs))
        this.isTransform = true;
      });
      tr.on('transformend', (e) => {
        this.isTransform = false;
        const { attrs } = e.target;
        // console.log(this.imgOffset);

        // console.log(attrs.id, attrs);
        // this.stage.find(`#${attrs.id}`).forEach((itema) => {
        //   // const aaa = e.target.attrs;
        //   // console.log(itema);
        //   itema.setAttrs({
        //     width: itema.width() * itema.attrs.scaleX,
        //     height: itema.height() * itema.attrs.scaleY,
        //     scaleX: 1,
        //     scaleY: 1,
        //   });
        // });
        console.log('end', attrs.y, this.imgOffset);
        // 获取y轴的值,解决插件bug
        // const rectX = getRectX(toRaw(attrs).y, toRaw(attrs).scaleY);
        const parload = {
          id: attrs.id,
          x: attrs.x,
          y: toRaw(attrs).y,
          width: attrs.width * attrs.scaleX,
          height: attrs.height * attrs.scaleY,
        };
        this.modificationRectInfo(parload);
      });
    });
    this.stage.add(this.layerShape);
  }

  removeTransformerFun() {
    this.stage.find('.transformer').forEach(item => item.destroy())
  }

  // 修改矩形框的位置及大小
  modificationRectInfo(attrs: any) {
    const newCoordinate = convertXYWidthHeightToFourCoodinate(
      attrs.x,
      attrs.y,
      attrs.width,
      attrs.height,
      this.pantographRatio,
      this.imgOffset
    );
    console.log('修改矩形框的位置及大小', getRectInImageOutside(
      attrs.x,
      attrs.y,
      this.layerImg.children![0].attrs,
      this.stage.attrs,
      attrs.width,
      attrs.height
    ));
    if (getRectInImageOutside(
      attrs.x,
      attrs.y,
      this.layerImg.children![0].attrs,
      this.stage.attrs,
      attrs.width,
      attrs.height
    )) {
      hintMessage('warning', '不允许在图片外面绘制信息');
      this.stage.find(`#${this.oldAttrs.id}`).forEach(item => {
        item.setAttrs({...this.oldAttrs})
        // item.setAttrs({...item, x: this.oldAttrs.x, y: this.oldAttrs.y, width: this.oldAttrs.width, height: this.oldAttrs.height})
      })
    } else {
      this.stage.find(`#textid${attrs.id}`).forEach(item => {
        item.setAttrs({
          ...item,
          x: attrs.x,
          y: attrs.y,
        })
      })
      this.fireEvent('rectCoordinateChange', {
        Coordinate: newCoordinate,
        id: attrs.id,
      })
    }
    // 更新矩形框位置
    // this.dataOverviewStore.updatedRectInfo(attrs.id, newCoordinate);
  }

  drawRect() {
    let initPosition: { x: number; y: number } | null = null;
    let shape = new Konva.Rect();
    let shapeId = generateString();
    // const dataOverviewStore = useDataOverviewStore();
    const stageMouseDown = () => {
      if (!this.isEditStatus || !this.isDrawRect || this.isTransform) {
        // initPosition = null
        return;
      }
      console.log('stageMouseDown');
      
      this.stage.draggable(false);
      if (this.stage) {
        const RelativePointerPosition = this.stage.getRelativePointerPosition();
        initPosition = {
          x: RelativePointerPosition!.x,
          y: RelativePointerPosition!.y,
        };
        if (
          getRectInImageOutside(
            initPosition!.x,
            initPosition!.y,
            this.layerImg.children![0].attrs,
            this.stage.attrs
          )
        ) {
          hintMessage('warning', '不允许在图片外面绘制信息');
          return;
        }
        shape.setAttrs({
          ...initPosition,
          stroke: 'red',
          id: shapeId,
          name: 'shape',
          type: 'rect',
        });
        this.layerShape.add(shape);
        this.stage.add(this.layerShape);
      }
    };
    this.stage.on('mousedown', () => {
      this.stage.draggable(false);
      // const RelativePointerPosition = this.stage.getRelativePointerPosition();
      //   initPosition = {
      //     x: RelativePointerPosition!.x,
      //     y: RelativePointerPosition!.y,
      //   };
      setTimeout(() => {
        stageMouseDown()
      }, 100)
    });
    const stageMouseMove = () => {
      if (!this.isEditStatus || !this.isDrawRect) {
        return;
      }
      if (this.isTransform) {
        initPosition = null
        return
      }
      // console.log('stageMouseMove', initPosition);
      
      if (!initPosition) return;
      let x = initPosition?.x;
      let y = initPosition?.y;
      if (this.stage) {
        const RelativePointerPosition = this.stage.getRelativePointerPosition();
        const width = Math.abs(initPosition!.x - RelativePointerPosition!.x);
        const height = Math.abs(initPosition!.y - RelativePointerPosition!.y);
        if (RelativePointerPosition!.x < x!) {
          x = RelativePointerPosition!.x;
        }
        if (RelativePointerPosition!.y < y!) {
          y = RelativePointerPosition!.y;
        }
        shape!.setAttrs({
          width,
          x,
          y,
          height,
        });
      }
    };
    this.stage.on('mousemove', stageMouseMove);
    this.stage.on('mouseup', () => {
      if (!this.isEditStatus || !this.isDrawRect || !shape.attrs.id || this.isTransform) {
        return;
      }
      console.log('mouseup');
      
      this.stage.draggable(true);

      if (this.stage) {
        const labelWidth = shape.getSize().width;
        const labelHeight = shape.getSize().height;
        const newShape = {
          type: 'rect',
          x: shape.getPosition().x,
          y: shape.getPosition().y,
          id: shapeId,
          width: labelWidth,
          height: labelHeight,
        };
        if (
          getRectInImageOutside(
            shape.getPosition().x,
            shape.getPosition().y,
            this.layerImg.children![0].attrs,
            this.stage.attrs,
            labelWidth,
            labelHeight
          )
        ) {
          hintMessage('warning', '不允许在图片外面绘制信息');
        } else if (newShape.width > 4 && newShape.height > 4) {
          // this.dataOverviewStore.setPopupFormData({
          //   delect_id: '',
          //   category_id: '',
          // });
          // 打开弹出框
          // this.dataOverviewStore.setIsShowPopup(true);
          // 存储画框信息
          const rectPointInfo = convertXYWidthHeightToFourCoodinate(
            shape.getPosition().x,
            shape.getPosition().y,
            labelWidth,
            labelHeight,
            this.pantographRatio,
            this.imgOffset
          );
          console.log('mouse up');
          
          this.fireEvent('addRect', {
            rectPointInfo,
            rectInfo: {
              x: shape.getPosition().x,
              y: shape.getPosition().y,
              width: labelWidth,
              height: labelHeight,
            }
          })
          // this.dataOverviewStore.setCurrentBBoxInfo(bbox);
        }

        // shape.setAttrs(newShape);
        this.stage.find(`#${shapeId}`).forEach((item) => {
          item.destroy();
        });
        shape = new Konva.Rect();
        initPosition = null;
        shapeId = generateString();
      }
    });
  }

  setIsDrawRect(bool: boolean) {
    this.isDrawRect = bool;
  }

  // 点击事件
  clickEvent(): void {
    // const dataOverviewStore = useDataOverviewStore();
    this.stage.on('click', (e) => {
      const { attrs } = e.target;
      if (this.isEditStatus && attrs.type === 'rect') {
        this.fireEvent('rectClick', attrs)
      }
    });
  }

  // 双击事件
  dblclickEvent() {
    this.stage.on('dblclick', (e) => {
      // if (!this.dataOverviewStore.getEditStatus) {
      //   return;
      // }
      const { attrs } = e.target;
      if (attrs.type === 'rect') {
        const bbox = convertXYWidthHeightToFourCoodinate(
          attrs.x,
          attrs.y,
          attrs.width,
          attrs.height,
          this.pantographRatio,
          this.imgOffset
        );
        // this.dataOverviewStore.setCurrentBBoxInfo(bbox);
        // const itemVal = toRaw(this.dataOverviewStore.rectList).find(
        //   (item: any) => item.delect_id === Number(attrs.id)
        // );
        // this.dataOverviewStore.setPopupFormData({
        //   delect_id: itemVal.delect_id,
        //   category_id: itemVal.delect_detail.category_id,
        // });
        // this.dataOverviewStore.setIsShowPopup(true);
        // dataOverviewStore.setCurrentSelectTable(Number(attrs.id));
      }
    });
  }

  // 图片放大缩小
  wheelEvent() {
    this.stage.on('wheel', (e) => {
      const max = 4; // 放大最大的比例
      const min = 0.5; // 缩小最小的比例
      const step = 0.03; // 每次缩放的比例

      const x = e.evt.offsetX;
      const y = e.evt.offsetY;
      if (this.stage) {
        const offsetX =
          ((x - this.stage.offsetX()) * this.stage.scaleX()) /
            (this.stage.scaleX() - step) -
          (x - this.stage.offsetX());
        const offsetY =
          ((y - this.stage.offsetY()) * this.stage.scaleY()) /
            (this.stage.scaleY() - step) -
          (y - this.stage.offsetY());
        // eslint-disable-next-line prefer-destructuring
        const evt: any = e.evt;
        if (evt.wheelDelta) {
          if (evt.wheelDelta > 0) {
            // 放大
            if (this.stage?.scaleX() < max && this.stage?.scaleY() < max) {
              // eslint-disable-next-line no-unsafe-optional-chaining
              this.stage?.scaleX(this.stage?.scaleX() + step);
              // eslint-disable-next-line no-unsafe-optional-chaining
              this.stage?.scaleY(this.stage?.scaleY() + step);
              this.stage?.move({ x: -offsetX, y: -offsetY }); // 跟随鼠标偏移位置
            }
          } else {
            // 缩小
            // eslint-disable-next-line no-lonely-if
            if (this.stage?.scaleX() > min && this.stage?.scaleY() > min) {
              // eslint-disable-next-line no-unsafe-optional-chaining
              this.stage?.scaleX(this.stage?.scaleX() - step);
              // eslint-disable-next-line no-unsafe-optional-chaining
              this.stage?.scaleY(this.stage?.scaleY() - step);
              this.stage?.move({ x: offsetX, y: offsetY }); // 跟随鼠标偏移位置
            }
          }
        }
      }
    });
  }

  rectHighlight(id: string) {
    // const rectId = id;
    // this.stage.find('.shape').forEach((item) => {
    //   if (item.attrs.id === rectId) {
    //     item.setAttrs({
    //       ...item.attrs,
    //       stroke: 'blue',
    //     });
    //   } else {
    //     item.setAttrs({
    //       ...item.attrs,
    //       stroke: 'red',
    //     });
    //   }
    // });
    
    const rectId = `Transformer${id}`;
    this.stage.find('.transformer').forEach((item) => {
      console.log(item.attrs.id, rectId);
      if (item.attrs.id === rectId) {
        item.setAttrs({
          ...item.attrs,
          anchorStroke: 'blue',
          borderStroke: 'blue',
        });
      } else {
        item.setAttrs({
          ...item.attrs,
          anchorStroke: 'red',
          borderStroke: 'red',
        });
      }
    });
  }
  

  // 退出编辑状态
  // exitEditStatus() {

  // }

  // 自定义事件
  addEventListener(eventType: string, handler: Function) {
    if (!this._eventHandlers[eventType]) {
      this._eventHandlers[eventType] = [];
    }
    this._eventHandlers[eventType].push(handler);
  }

  removeEventListener(eventType: string, handler: Function) {
    if (this._eventHandlers[eventType]) {
      const index = this._eventHandlers[eventType].indexOf(handler);
      if (index > -1) {
        this._eventHandlers[eventType].splice(index, 1);
      }
    }
  }
  fireEvent(eventType: string, data: any) {
    const handlers = this._eventHandlers[eventType];
    if (handlers) {
      handlers.forEach((handler: Function) => {
        handler(data);
      });
    }
  }
}

// file '@/utils/hintMessage';
import { Message } from '@arco-design/web-vue';

type MessageType = 'info' | 'success' | 'warning' | 'error' | 'loading';
let messageClose: any = null;
export const hintMessage = (type: MessageType, content: string) => {
  if (messageClose) {
    messageClose.close();
  }
  messageClose = Message[type]({
    content,
    closable: true,
  });
};
// file './knovaCoordinateCalculation'
import { roundNumber } from "./numberHandle";

/**
 * Convert the four coodinate points to x,y,width,height
 * @param list two-dimensional array
 * @param common_scale Message type
 * @returns {x, y, width, height}
 */
export const convertFourCoodinateToXYWidthHeight = (
  list: Array<Array<number>>,
  common_scale: number,
  offset: {
    x: number;
    y: number;
  }
) => {
  return {
    width: (list[3][0] - list[0][0]) / common_scale,
    height: (list[2][1] - list[0][1]) / common_scale,
    x: list[0][0] / common_scale - offset.x,
    y: list[0][1] / common_scale - offset.y,
  };
};
/**
 * Getting text coordinates
 * @param list two-dimensional array
 * @param common_scale Message type
 * @returns {x, y}
 */
export const getTextCoodinate = (
  list: Array<Array<number>>,
  common_scale: number,
  offset: {
    x: number;
    y: number;
  }
) => {
  return {
    x: list[0][0] / common_scale - offset.x,
    y: list[0][1] / common_scale - offset.y,
  };
};
// Formatting coordinate points
export const formatCoordinatePoints = (
  payload: Array<Array<number>>,
  common_scale: number
) => {
  // const zoom = actualDisplayGraphics.value.zoomValue
  if (common_scale) {
    const originPoints = payload.map((item) => {
      return [item[0] * common_scale, item[1] * common_scale];
    });
    return originPoints;
  }
};
/**
 * Convert the x,y,width,height to four coodinate points
 * @param x
 * @param y
 * @param width
 * @param height
 * @param common_scale Multiple of scale
 * @returns Array<Array<Number>>
 */
export const convertXYWidthHeightToFourCoodinate = (
  x: number,
  y: number,
  width: number,
  height: number,
  common_scale: number,
  offset: {
    x: number;
    y: number;
  }
) => {
  const arr: Array<Array<number>> = [];
  const originX = x + offset.x;
  const originY = y + offset.y;
  for (let index = 0; index < 4; index++) {
    if (index === 0) {
      arr.push([roundNumber(originX * common_scale), roundNumber(originY * common_scale)]);
    } else if (index === 1) {
      arr.push([roundNumber(originX * common_scale), roundNumber((originY + height) * common_scale)]);
    } else if (index === 2) {
      arr.push([roundNumber((originX + width) * common_scale), roundNumber((originY + height) * common_scale)]);
    } else if (index === 3) {
      arr.push([roundNumber((originX + width) * common_scale), roundNumber(originY * common_scale)]);
    }
  }
  return arr;
};

export const getOffset = (
  imgWidth: number,
  imgHeight: number,
  knovaWidth: number,
  knovaHeight: number
) => {
  // console.log(imgWidth, imgHeight, knovaWidth, knovaHeight);
  if (imgWidth === knovaWidth) {
    return {
      x: 0,
      y: -((knovaHeight - imgHeight) / 2),
    };
  }
  if (imgHeight === knovaHeight) {
    return {
      x: -((knovaWidth - imgWidth) / 2),
      y: 0,
    };
  }
  return {
    x: -((knovaWidth - imgWidth) / 2),
    y: -((knovaHeight - imgHeight) / 2),
  };
};
/**
 * 判断绘制的矩形是否在图片外面
 *
 *
 * @example
 *
 *
 * @type {Function}
 */
export const getRectInImageOutside = (
  x: number,
  y: number,
  imgAttrs: any,
  stageAttrs: any,
  labelWidth = 0,
  labelHeight = 0
) => {
  const limitX = {
    max: 0,
    min: 0,
  };
  const limitY = {
    max: 0,
    min: 0,
  };
  limitX.min = (stageAttrs.width - imgAttrs.width) / 2;
  limitY.min = (stageAttrs.height - imgAttrs.height) / 2;
  limitX.max = imgAttrs.width + limitX.min;
  limitY.max = imgAttrs.height + limitY.min;
  let bool = false;
  if (labelWidth) {
    if (
      x + labelWidth < limitX.min ||
      x + labelWidth > limitX.max ||
      y + labelHeight < limitY.min ||
      y + labelHeight > limitY.max
    ) {
      bool = true;
    }
  }
  if (
    x < limitX.min ||
    x > limitX.max ||
    y < limitY.min ||
    y > limitY.max ||
    bool
  ) {
    return true;
  }
  return false;
};
// file './numberHandle'
// 数字取整
// eslint-disable-next-line import/prefer-default-export
export function roundNumber(num: number): number {
  return Math.round(num);
}

多边形

drawPolygon() {
    console.log(111, this.stage);
    const initLine = {
      id: generateId() + '',
      type: "polygon",
      stroke: "black",
      strokeWidth: 5,
      fill: "red",
    };
    let polygonShape = new Konva.Line(initLine)
    // 这个是辅助线
    let auxiliaryLine = new Konva.Line({
      points: [],
      stroke: "green",
      strokeWidth: 2,
      lineJoin: "round",
      dash: [10],
    });
    let path = []
    const onMousedown = ({evt}) => {
      // if ()
      if (!polygonShape) { return }
      console.log(222);
      const x = evt.offsetX;
      const y = evt.offsetY;
      // 判断有没有闭合,方便操作,当点击到起始位置的一定范围内即视为闭合
      if (Math.abs(path?.[0] - x) <= 5 && Math.abs(path?.[1] - y) <= 5) {
        console.log(333);
        auxiliaryLine.destroy();
        polygonShape.destroy();
        polygonShape = new Konva.Line(initLine)
        auxiliaryLine = new Konva.Line({
          points: [],
          stroke: "green",
          strokeWidth: 2,
          lineJoin: "round",
          dash: [10],
        });
        this.polygon(path, generateId() + '', 'blue', this.fixedShapeName)
        path = []
        return;
      }
      console.log(444);
      path.push(...[x, y]);
      polygonShape.setAttrs({ points: path });
      // path只有2个位置(一对x,y)就代表第一次插入,把图形放到 layer 里
      if (path.length === 2) {
        this.fixedLayer.add(auxiliaryLine);
        this.fixedLayer.add(polygonShape);
      }
      this.stage.add(this.fixedLayer)
    }
    const onMouseMove = ({evt}) => {
      const closePathX = path[0];
      const closePathY = path[1];
      const lastPathX = path[path.length - 2];
      const lastPathY = path[path.length - 1];
      const x = evt.offsetX;
      const y = evt.offsetY;

      if (!lastPathX || !lastPathY) return;
      //做个吸附效果,如果鼠标当前位置非常接近闭合点,把线移动过去
      if (Math.abs(closePathX - x) <= 5 && Math.abs(closePathY - y) <= 5) {
        auxiliaryLine.setAttrs({
          points: [lastPathX, lastPathY, closePathX, closePathY],
        });
      } else {
        //  辅助线的第一个点永远是 path 的最后一个位置,第二个点是当前鼠标所在的点
        auxiliaryLine.setAttrs({
          points: [lastPathX, lastPathY, x, y],
        });
      }
    }
    this.stage.on('mousedown', onMousedown)
    this.stage.on("mousemove", onMouseMove);
  }

线段

drawLine() {
    console.log(111, this.stage);
    const initLine = {
      id: generateId() + '',
      type: "polygon",
      stroke: "black",
      strokeWidth: 5,
      fill: "red",
    };
    let polygonShape = new Konva.Line(initLine)
    // 这个是辅助线
    let auxiliaryLine = new Konva.Line({
      points: [],
      stroke: "green",
      strokeWidth: 2,
      lineJoin: "round",
      dash: [10],
    });
    let path = []
    const onMousedown = ({evt}) => {
      // if ()
      if (!polygonShape) { return }
      console.log(222);
      const x = evt.offsetX;
      const y = evt.offsetY;
      path.push(...[x, y]);
      // 判断有没有闭合,方便操作,当点击到起始位置的一定范围内即视为闭合
      if (path.length === 4) {
        console.log(333);
        auxiliaryLine.destroy();
        polygonShape.destroy();
        polygonShape = new Konva.Line(initLine)
        auxiliaryLine = new Konva.Line({
          points: [],
          stroke: "green",
          strokeWidth: 2,
          lineJoin: "round",
          dash: [10],
        });
        // console.log();
        // path.push(...[x, y]);
        this.polygon(path, generateId() + '', 'blue', this.fixedShapeName)
        path = []
        return;
      }
      console.log(444);
      polygonShape.setAttrs({ points: path });
      // path只有2个位置(一对x,y)就代表第一次插入,把图形放到 layer 里
      if (path.length === 2) {
        this.fixedLayer.add(auxiliaryLine);
        this.fixedLayer.add(polygonShape);
      }
      this.stage.add(this.fixedLayer)
    }
    const onMouseMove = ({evt}) => {
      const lastPathX = path[path.length - 2];
      const lastPathY = path[path.length - 1];
      const x = evt.offsetX;
      const y = evt.offsetY;

      if (!lastPathX || !lastPathY) return;
      auxiliaryLine.setAttrs({
        points: [lastPathX, lastPathY, x, y],
      });
    }
    this.stage.on('mousedown', onMousedown)
    this.stage.on("mousemove", onMouseMove);
  }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值