Automatisch afgestemde lay-out
Een grafiek van vijf knooppunten en een grafiek van vijfhonderd vereisen heel verschillende natuurkunde, en dat geldt ook voor een grafiek met kleine stippen versus een grafiek met grote afbeeldingskaarten. In plaats van plukken één set krachtinstellingen en in de hoop dat Pivotick deze afleidt van wat werkelijk is op het scherm – aantal knooppunten, knooppuntgrootte, canvasgrootte – en herleidt ze telkens wanneer de grafiek verandert. Dit is de standaardinstelling.
Laat de onderstaande grafiek groter worden en zie hoe de knoppen bewegen: de verbindingsafstand neemt af naarmate het canvas groter wordt het wordt druk en de centreerkracht gaat omhoog om alles in frame te houden.
- Het beweegt alleen knoppen die je kunt zien. Auto bestuurt dezelfde bedieningselementen als de Physics flyout, en de schuifregelaars volgen – er gebeurt niets achter een verborgen hendel.
- Je wint altijd. Sleep een schuifregelaar of kies Strak / Loose, en stopt automatisch voorgoed; het zal nooit opnieuw afstemmen op een keuze die je hebt gemaakt.
- Het blijft kalm. Triggers die samen aankomen worden samengevoegd, en ook een verandering klein om te zien wordt overgeslagen - dus een draaipunt dat veertig knooppunten toevoegt, kost één relay-out.
- Een gepauzeerde simulatie wordt nooit geactiveerd.
Auto is ingeschakeld tenzij de grafiek zelf een kracht configureert, zodat bestaande instellingen behouden blijven die van hen. Zie Automatische lay-outafstemming voor de exacte regel.
// Nothing here configures a force, so the layout tunes itself — that is the
// default. `physics: 'auto'` is spelled out only because the documentation
// gallery pins every other example to `'manual'` for stable screenshots.
//
// Setting any force option instead (d3LinkDistance, d3ManyBodyStrength,
// d3CollideRadiusMultiplier, d3VelocityDecay, d3GravityStrength,
// d3GravityStrengthConnected, d3AlphaDecay, cooldownTime) would keep your value
// and switch the tuning off for that graph.
const options = {
simulation: { physics: 'auto' }
}// Auto re-tunes on every visible change to the graph, so growing it is all it
// takes to watch the knobs move. Triggers arriving together are coalesced into a
// single pass, and a change too small to matter is skipped entirely — so a pivot
// that adds forty nodes costs one relayout, not forty.
let seq = 0
function addBatch(graph, size = 20) {
const existing = graph.getNodes()
const nodes = []
const edges = []
for (let i = 0; i < size; i++) {
const id = `n-${++seq}`
const pool = existing.concat(nodes)
const parent = pool[Math.floor(Math.random() * pool.length)]
nodes.push({ id, data: { label: id } })
edges.push({ from: parent.id, to: id })
}
graph.updateData(nodes, edges)
}
function reset(graph) {
for (const node of graph.getNodes()) {
if (!data.nodes.some((seed) => seed.id === node.id)) graph.removeNode(node.id)
}
seq = 0
}// Auto only ever moves the knobs the Physics flyout exposes, so whatever it
// decided can simply be read back — and overridden by dragging a slider, which
// hands control back to you for good.
function readKnobs(graph) {
const { repulsion, linkDistance, centering } = graph.simulation.getPhysicsKnobs()
return {
nodes: graph.getNodes().length,
repulsion,
linkDistance,
centering,
auto: graph.simulation.isAutoPhysicsEnabled()
}
}// A small seed graph — small enough that fixed force settings would leave it
// huddled in the middle of the canvas.
const data = {
nodes: [
{ id: 'core', data: { label: 'core' } },
{ id: 'api', data: { label: 'api' } },
{ id: 'web', data: { label: 'web' } },
{ id: 'db', data: { label: 'db' } },
{ id: 'queue', data: { label: 'queue' } }
],
edges: [
{ from: 'web', to: 'api' },
{ from: 'api', to: 'core' },
{ from: 'core', to: 'db' },
{ from: 'core', to: 'queue' }
]
}