Konva - изменение положения смещения после масштабирования и поворота

Я пытаюсь реализовать функцию поворота и масштабирования с помощью ползунка. Мне нужно, чтобы изображение всегда вращалось из центра области просмотра. Основная идея - изменить положение и смещение сцены после события перетаскивания. Вот что я пробовал

const width = window.innerWidth
const height = window.innerHeight

// scale is temp
let stage = new Konva.Stage({
  container: 'canvas',
  width,
  height,
  draggable: true,
  offset: {
    x: width / 2,
    y: height / 2
  },
  x: width / 2,
  y: height / 2
})

let mapLayer = new Konva.Layer()
let imageObj = new Image()

imageObj.onload = function () {
  let map = new Konva.Image({
    image: imageObj,
    prevX: 0,
    prevY: 0
  })

  layer.add(map)
  stage.add(mapLayer)

  stage.on('dragstart', () => {
    map.prevX = map.getAbsolutePosition().x
    map.prevY = map.getAbsolutePosition().y
  })

  stage.on('dragend', () => {
    let curX = map.getAbsolutePosition().x
    let curY = map.getAbsolutePosition().y
    let deltaX = Math.abs(map.prevX - curX)
    let deltaY = Math.abs(map.prevY - curY)

    if (curX > map.prevX) {
      stage.offsetX(stage.offsetX() - deltaX)
      stage.x(stage.x() - deltaX)
    } else {
      stage.offsetX(stage.offsetX() + deltaX)
      stage.x(stage.x() + deltaX)
    }

    if (curY > map.prevY) {
      stage.offsetY(stage.offsetY() - deltaY)
      stage.y(stage.y() - deltaY)
    } else {
      stage.offsetY(stage.offsetY() + deltaY)
      stage.y(stage.y() + deltaY)
    }

    stage.draw()
  })
}

(если вам нужен полный исходный код, клонируйте его отсюда и запустите yarn run dev из терминала, приложение работает на localhost:3000

Он отлично работает, когда изображение находится в нормальном положении (еще не увеличено и не повернуто), но после ЛЮБОГО поворота или масштабирования перетаскивание сцены приведет к изменению положения сцены странным образом (смещение все еще правильное, хотя ). Как правильно установить положение и смещение?


person Cristopher Namchee    schedule 23.03.2019    source источник
comment
Чтобы он работал правильно в текущем состоянии, потребуется некоторая тригонометрия для исправления перетаскивания после вращения. Я бы предложил использовать разные слои для разных действий - родительское окно с шириной / высотой, равной контейнеру, всегда вращаемому со смещением в центре и перетаскиванием / масштабированием вложенного элемента (с опцией draggable без каких-либо вычислений). Таким образом, в любом состоянии перетаскивания смещение родителя будет таким же в том же месте, но будет отображаться другая часть вложенного изображения.   -  person extempl    schedule 23.03.2019
comment
Однако могут возникнуть некоторые проблемы с масштабированием, поскольку оно также требует смещения. Тогда я бы поиграл с масштабированием на том же слое, что и вращение.   -  person extempl    schedule 23.03.2019
comment
Под родительским окном вы имеете в виду сцену или новый слой?   -  person Cristopher Namchee    schedule 24.03.2019


Ответы (1)


Решение вашей первоначальной проблемы ниже. Обратите внимание, что я также поместил круг и всплывающую подсказку на один слой, чтобы их можно было перетаскивать как один. Кроме того, он должен быть добавлен после map для работы привязки.

import Konva from 'konva'
import map from './../resources/unpar.svg'

const width = window.innerWidth
const height = window.innerHeight

// scale is temp
let stage = new Konva.Stage({
  container: 'canvas',
  width,
  height,
  offset: {
    x: width / 2,
    y: height / 2
  },
  x: width / 2,
  y: height / 2
})

let layer = new Konva.Layer({draggable: true})

let testCircle = new Konva.Circle({
  x: 633,
  y: 590,
  radius: 10,
  fill: 'white',
  stroke: 'black'
})

testCircle.on('mousemove', function () {
  tooltip.position({
    x: testCircle.x() - 90,
    y: testCircle.y() - 50
  })
  tooltip.text('Pintu Depan Gedung 10')
  tooltip.show()
  layer.batchDraw()
})

testCircle.on('mouseout', function () {
  tooltip.hide()
  layer.draw()
})

var tooltip = new Konva.Text({
  text: '',
  fontFamily: 'Calibri',
  fontSize: 18,
  padding: 5,
  textFill: 'white',
  fill: 'black',
  alpha: 0.75,
  visible: false
})

let imageObj = new Image()

imageObj.onload = function () {
  const map = new Konva.Image({
    image: imageObj,
  })

  layer.add(map)
  layer.add(testCircle)
  layer.add(tooltip)
  stage.add(layer)
}

imageObj.src = map

export default stage
person extempl    schedule 24.03.2019
comment
Я знаю, что это работает, но можно ли сделать это, не помещая весь объект в один слой? - person Cristopher Namchee; 24.03.2019
comment
@CristopherNamchee Теоретически да, но я не уверен, как на данный момент, поскольку это требует некоторого исследования. Если бы вы могли добавить один слой к другому, это было бы довольно просто, но существует множество ограничений типов, которые могут включать только определенные типы контейнеров / узлов. - person extempl; 24.03.2019