Добавление масштабирования к визуализации упакованного круга с помощью Konva (Масштабирование и перемещение из центра)

#javascript #konvajs #konva

Вопрос:

Я создал визуализацию упакованного круга с помощью d3 и нарисовал его с помощью Konva. Если вы нажмете на круг в визуализации упакованного круга, окно просмотра должно приблизиться к этому кругу.

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

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

 function zoom(circle) {

  
  // By what value do we neeed to scale the group?
  let scaleBy = root.data.konva.radius() / circle.radius()
 
  group.scale({x: scaleBy, y: scaleBy})
  
  // By what values do we neeed to reposition the group?
  let newX = (circle.x() - root.data.konva.x() ) * scaleBy
  let newY = (circle.y() - root.data.konva.y()) * scaleBy
    
  group.position({x: newX, y: newY})
}
 

введите описание изображения здесь

 const data = { children: [{ children: [{ children: [] },{ children: [] }] },{ children: [{ children: [] },{ children: [{ children: [] },{ children: [] }] }] }] }

const width = 600
const height = 400

let pack = d3.pack().size([width, height])

let root = d3.hierarchy(data)
  .sum(d => {
    if(d.children amp;amp; d.children.length > 0) {
      return d.children.length  
    }
    return 1
  })

pack(root)

// ---

const  stage = new Konva.Stage({
  container: 'container',
  width: width,
  height: height
 })
 
const layer = new Konva.Layer()
const group = new Konva.Group()
   
layer.add(group)
stage.add(layer)

// ---

root.descendants().forEach( (node,i) => { 
    
  const circle = new Konva.Circle({
    x: node.x,
    y: node.y,
    radius: node.r,
    fill: 'grey',
    opacity: (0.1 * node.depth)   0.1
  })
  
  node.data.konva = circle
  circle.data = { d3: node }
  
  group.add(circle)
  
  circle.on('click', () => zoom(circle))
})

// ---


function zoom(circle) {

  
  // By what value do we neeed to scale the group?
  let scaleBy = root.data.konva.radius() / circle.radius()
  
  console.log(`Scaling by: ${scaleBy}`)

  group.scale({x: scaleBy, y: scaleBy})
  
  // By what values do we neeed to reposition the group?
  let newX = (circle.x() - root.data.konva.x() ) * scaleBy
  let newY = (circle.y() - root.data.konva.y()) * scaleBy
  
  console.log(`Repositioning by: x:${newX}, y:${newY}`)
  
  group.position({x: newX, y: newY})
} 
 .konvajs-content {
  background: rgba(124, 7, 12, 0.1);
} 
 <script src="https://cdn.jsdelivr.net/npm/konva@8.1.3/konva.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

<div id="container"></div> 

Комментарии:

1. Если мой ответ верен, пожалуйста, поставьте галочку, чтобы принять его, или дайте мне знать, если это не решение вашей проблемы.

Ответ №1:

Задача состоит в том, чтобы переместить положение сцены (x, y) так, чтобы центр целевого круга находился в середине окна просмотра, что означает видимые границы элемента HTML canvas.

PosX = (ширина окна просмотра / 2) — (круг.поз.x * масштаб) PosY = (высота окна просмотра/ 2) — (круг.поз.y * масштаб)

И использование вашего кода означает, что:

  let newX = (width / 2) - (circle.x() * scaleBy)  
 let newY = (height / 2) -  (circle.y() * scaleBy) 
 

Смотрите рабочий фрагмент ниже, изменились только эти строки.

 const data = { children: [{ children: [{ children: [] },{ children: [] }] },{ children: [{ children: [] },{ children: [{ children: [] },{ children: [] }] }] }] }

const width = 600
const height = 400

let pack = d3.pack().size([width, height])

let root = d3.hierarchy(data)
  .sum(d => {
    if(d.children amp;amp; d.children.length > 0) {
      return d.children.length  
    }
    return 1
  })

pack(root)

// ---

const  stage = new Konva.Stage({
  container: 'container',
  width: width,
  height: height
 })
 
const layer = new Konva.Layer()
const group = new Konva.Group()
   
layer.add(group)
stage.add(layer)

// ---

root.descendants().forEach( (node,i) => { 
    
  const circle = new Konva.Circle({
    x: node.x,
    y: node.y,
    radius: node.r,
    fill: 'grey',
    opacity: (0.1 * node.depth)   0.1
  })
  
  node.data.konva = circle
  circle.data = { d3: node }
  
  group.add(circle)
  
  circle.on('click', () => zoom(circle))
})

// ---


function zoom(circle) {

  
  // By what value do we neeed to scale the group?
  let scaleBy = root.data.konva.radius() / circle.radius()
  
  
  console.log(`Scaling by: ${scaleBy}`)

  group.scale({x: scaleBy, y: scaleBy})
  
  // By what values do we neeed to reposition the group?
 let newX = (width / 2) - (circle.x() * scaleBy)  
 let newY = (height / 2) -  (circle.y() * scaleBy)
  
  console.log(`Repositioning by: x:${newX}, y:${newY}`)
  
  group.position({x: newX, y: newY})
} 
 .konvajs-content {
  background: rgba(124, 7, 12, 0.1);
} 
 <script src="https://cdn.jsdelivr.net/npm/konva@8.1.3/konva.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

<div id="container"></div>