#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>