使用 Konva(从中心缩放和重新定位)向压缩圆可视化添加缩放
Adding zoom to a packed circle visualisation using Konva (Scale and reposition from center)
我使用 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 && 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>
任务之一是移动舞台位置 (x, y),使目标圆的中心位于视口的中间 - 即 HTML canvas 元素可见边界.
PosX = (viewPort.width / 2) - (circle.pos.x * 比例)
PosY = (viewPort.height/ 2) - (circle.pos.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 && 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>
我使用 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 && 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>
任务之一是移动舞台位置 (x, y),使目标圆的中心位于视口的中间 - 即 HTML canvas 元素可见边界.
PosX = (viewPort.width / 2) - (circle.pos.x * 比例) PosY = (viewPort.height/ 2) - (circle.pos.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 && 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>