konvajs / konva

Konva.js is an HTML5 Canvas JavaScript framework that extends the 2d context by enabling canvas interactivity for desktop and mobile applications.
http://konvajs.org/
Other
11.37k stars 916 forks source link

The generation of adsorption reference lines through multi-element dragging is very slow #1803

Open ruxinzhang789 opened 1 month ago

ruxinzhang789 commented 1 month ago

Demo from the official website used,There are 100 elements,use vue-konva, https://konvajs.org/docs/sandbox/Objects_Snapping.html

<v-stage id="stagecontent" ref="stage" :config="stageSize" @mousedown="handleStageMouseDown" @mouseup="handleStageMouseUp" @touchstart="handleStageMouseDown" @mousemove="handleStageDrag" @mouseleave="handleStageMouseUp"

` handleElementDragMove(e) { const stage = this.$refs.stage.getNode() stage.container().style.cursor = 'move' const layer = this.$refs.layer.getNode() layer.find('.guid-line').forEach(l => l.destroy()) let lineGuideStops = this.getLineGuideStops(e.target) let itemBounds = this.getObjectSnappingEdges(e.target) let guides = this.getGuides(lineGuideStops, itemBounds) if (!guides.length) { return } this.drawGuides(guides) let absPos = e.target.absolutePosition() guides.forEach(lg => { switch (lg.orientation) { case 'V': { absPos.x = lg.lineGuide + lg.offset break } case 'H': { absPos.y = lg.lineGuide + lg.offset break } } }) e.target.absolutePosition(absPos) }

getLineGuideStops(skipShape) { const transformerNode = this.$refs.transformer.getNode() const stage = transformerNode.getStage() var vertical = [0, stage.width() / 2, stage.width()] var horizontal = [0, stage.height() / 2, stage.height()] const filterList = this.layers.filter(item => { return !this.selectedShapeName.includes(item.name) }) const filterNode = filterList.map(item => { return stage.findOne('.' + item.name) }) filterNode.forEach(guideItem => { // if (guideItem === skipShape) { // return // } var box = guideItem.getClientRect() vertical.push([box.x, box.x + box.width, box.x + box.width / 2]) horizontal.push([box.y, box.y + box.height, box.y + box.height / 2]) }) return { vertical: [...new Set(vertical.flat())], horizontal: [...new Set(horizontal.flat())] } },

getObjectSnappingEdges(node) {
  var box = node.getClientRect()
  var absPos = node.absolutePosition()
  return {
    vertical: [
      {
        guide: Math.round(box.x),
        offset: Math.round(absPos.x - box.x),
        snap: 'start'
      },
      {
        guide: Math.round(box.x + box.width / 2),
        offset: Math.round(absPos.x - box.x - box.width / 2),
        snap: 'center'
      },
      {
        guide: Math.round(box.x + box.width),
        offset: Math.round(absPos.x - box.x - box.width),
        snap: 'end'
      }
    ],
    horizontal: [
      {
        guide: Math.round(box.y),
        offset: Math.round(absPos.y - box.y),
        snap: 'start'
      },
      {
        guide: Math.round(box.y + box.height / 2),
        offset: Math.round(absPos.y - box.y - box.height / 2),
        snap: 'center'
      },
      {
        guide: Math.round(box.y + box.height),
        offset: Math.round(absPos.y - box.y - box.height),
        snap: 'end'
      }
    ]
  }
},

getGuides(lineGuideStops, itemBounds) {
  var resultV = []
  var resultH = []

  lineGuideStops.vertical.forEach(lineGuide => {
    itemBounds.vertical.forEach(itemBound => {
      var diff = Math.abs(lineGuide - itemBound.guide)
      if (diff < 5) {
        resultV.push({
          lineGuide: lineGuide,
          diff: diff,
          snap: itemBound.snap,
          offset: itemBound.offset
        })
      }
    })
  })

  lineGuideStops.horizontal.forEach(lineGuide => {
    itemBounds.horizontal.forEach(itemBound => {
      var diff = Math.abs(lineGuide - itemBound.guide)
      if (diff < 5) {
        resultH.push({
          lineGuide: lineGuide,
          diff: diff,
          snap: itemBound.snap,
          offset: itemBound.offset
        })
      }
    })
  })
  var guides = []
  var minV = resultV.sort((a, b) => a.diff - b.diff)[0]
  var minH = resultH.sort((a, b) => a.diff - b.diff)[0]
  if (minV) {
    guides.push({
      lineGuide: minV.lineGuide,
      offset: minV.offset,
      orientation: 'V',
      snap: minV.snap
    })
  }
  if (minH) {
    guides.push({
      lineGuide: minH.lineGuide,
      offset: minH.offset,
      orientation: 'H',
      snap: minH.snap
    })
  }
  return guides
},

drawGuides(guides) {
  const layer = this.$refs.layer.getNode()
  guides.forEach(lg => {
    if (lg.orientation === 'H') {
      var line = new Konva.Line({
        points: [-6000, 0, 6000, 0],
        stroke: 'rgb(0, 161, 255)',
        strokeWidth: 1,
        name: 'guid-line',
        dash: [4, 6]
      })
      layer.add(line)
      line.absolutePosition({
        x: 0,
        y: lg.lineGuide
      })
    } else if (lg.orientation === 'V') {
      let line = new Konva.Line({
        points: [0, -6000, 0, 6000],
        stroke: 'rgb(0, 161, 255)',
        strokeWidth: 1,
        name: 'guid-line',
        dash: [4, 6]
      })
      layer.add(line)
      line.absolutePosition({
        x: lg.lineGuide,
        y: 0
      })
    }
  })
},`
lavrton commented 1 month ago

Demo?