Other similar answers I have found on StackOverflow are old and no longer apply to the latest version.
My zoomed function is being called. The transform
parameter contains:
I assume I will need to take the information in transform.transform
and apply it to the transform
attribute on the svg. The this
variable contains a reference to the SVG.
What I am not sure about is exactly how to do that...?
const width = 1000
const height = 400
const node_data = Array.from({ length: 5 }, () => ({
group: Math.floor(Math.random() * 3),
}))
const edge_data = Array.from({ length: 10 }, () => ({
source: Math.floor(Math.random() * 5),
target: Math.floor(Math.random() * 5),
value: Math.floor(Math.random() * 10) + 1,
}))
const links = edge_data.map((d) => ({ ...d }))
const nodes = node_data.map((d, index) => ({ id: index, ...d }))
const color = d3.scaleOrdinal(d3.schemeCategory10)
//
//
//
function zoomed(transform) {
// console.log(`🚀 ~ zoomed ~ this:`, this)
// console.log(`🚀 ~ zoomed ~ transform:`, transform)
}
const svg = d3.select('#chart').call(d3.zoom().on('zoom', zoomed))
const simulation = d3
.forceSimulation(nodes)
.force(
'link',
d3
.forceLink(links)
.id((d) => d.id)
.distance((d) => 100)
)
.force('charge', d3.forceManyBody())
.force('center', d3.forceCenter(width / 2, height / 2))
.on('tick', ticked)
const link = svg
.append('g')
.attr('stroke', '#999')
.attr('stroke-opacity', 0.6)
.selectAll()
.data(links)
.join('line')
.attr('stroke-width', (d) => Math.sqrt(d.value))
const node = svg
.append('g')
.attr('stroke', '#fff')
.attr('stroke-width', 1.5)
.selectAll()
.data(nodes)
.join('circle')
.attr('r', 16)
.attr('fill', (d) => color(d.group))
node.append('title').text((d) => `hello ${d.id}`)
function ticked() {
link
.attr('x1', (d) => d.source.x)
.attr('y1', (d) => d.source.y)
.attr('x2', (d) => d.target.x)
.attr('y2', (d) => d.target.y)
node.attr('cx', (d) => d.x).attr('cy', (d) => d.y)
}
node.call(d3.drag().on('start', dragstarted).on('drag', dragged).on('end', dragended))
function dragstarted(event) {
if (!event.active) simulation.alphaTarget(0.3).restart()
event.subject.fx = event.subject.x
event.subject.fy = event.subject.y
}
function dragged(event) {
event.subject.fx = event.x
event.subject.fy = event.y
}
function dragended(event) {
if (!event.active) simulation.alphaTarget(0)
event.subject.fx = null
event.subject.fy = null
}
.graph {
width: 1000px;
height: 400px;
}
<script src="https://d3js.org/d3.v7.min.js" charset="utf-8"></script>
<svg ref="chart" id="chart" class="graph"></svg>
The most straight-forward implementation is:
function zoomed(e) {
zoomG.attr('transform', e.transform); //<-- apply zoom
}
const svg = d3.select('#chart').call(d3.zoom().on('zoom', zoomed)); //<-- add zoom behavior
const zoomG = svg.append('g'); //<-- wrap drawing in g to apply zoom on
const width = 1000
const height = 400
const node_data = Array.from({ length: 5 }, () => ({
group: Math.floor(Math.random() * 3),
}))
const edge_data = Array.from({ length: 10 }, () => ({
source: Math.floor(Math.random() * 5),
target: Math.floor(Math.random() * 5),
value: Math.floor(Math.random() * 10) + 1,
}))
const links = edge_data.map((d) => ({ ...d }))
const nodes = node_data.map((d, index) => ({ id: index, ...d }))
const color = d3.scaleOrdinal(d3.schemeCategory10)
//
//
//
function zoomed(e) {
zoomG.attr('transform', e.transform); //<-- apply zoome
}
const svg = d3.select('#chart').call(d3.zoom().on('zoom', zoomed)); //<-- add zoom behavior
const zoomG = svg.append('g'); //<-- wrap drawing in g to apply zoom on
const simulation = d3
.forceSimulation(nodes)
.force(
'link',
d3
.forceLink(links)
.id((d) => d.id)
.distance((d) => 100)
)
.force('charge', d3.forceManyBody())
.force('center', d3.forceCenter(width / 2, height / 2))
.on('tick', ticked)
const link = zoomG
.append('g')
.attr('stroke', '#999')
.attr('stroke-opacity', 0.6)
.selectAll()
.data(links)
.join('line')
.attr('stroke-width', (d) => Math.sqrt(d.value))
const node = zoomG
.append('g')
.attr('stroke', '#fff')
.attr('stroke-width', 1.5)
.selectAll()
.data(nodes)
.join('circle')
.attr('r', 16)
.attr('fill', (d) => color(d.group))
node.append('title').text((d) => `hello ${d.id}`)
function ticked() {
link
.attr('x1', (d) => d.source.x)
.attr('y1', (d) => d.source.y)
.attr('x2', (d) => d.target.x)
.attr('y2', (d) => d.target.y)
node.attr('cx', (d) => d.x).attr('cy', (d) => d.y)
}
node.call(d3.drag().on('start', dragstarted).on('drag', dragged).on('end', dragended))
function dragstarted(event) {
if (!event.active) simulation.alphaTarget(0.3).restart()
event.subject.fx = event.subject.x
event.subject.fy = event.subject.y
}
function dragged(event) {
event.subject.fx = event.x
event.subject.fy = event.y
}
function dragended(event) {
if (!event.active) simulation.alphaTarget(0)
event.subject.fx = null
event.subject.fy = null
}
.graph {
width: 1000px;
height: 400px;
}
<script src="https://d3js.org/d3.v7.min.js" charset="utf-8"></script>
<svg ref="chart" id="chart" class="graph"></svg>