Skip to content

Commit

Permalink
link force example
Browse files Browse the repository at this point in the history
  • Loading branch information
mbostock committed Jun 22, 2023
1 parent 95ddc9b commit 987a2f2
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 0 deletions.
89 changes: 89 additions & 0 deletions docs/components/ExampleLinkForce.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
<script setup>
import * as d3 from "d3";
import {ref, onMounted, onUnmounted} from "vue";
const container = ref();
const width = 688;
const height = 540;
const n = 20;
const nodes = Array.from({length: n * n}, (_, i) => ({index: i}));
const links = [];
for (let y = 0; y < n; ++y) {
for (let x = 0; x < n; ++x) {
if (y > 0) links.push({source: (y - 1) * n + x, target: y * n + x});
if (x > 0) links.push({source: y * n + (x - 1), target: y * n + x});
}
}
let simulation;
const drag = d3.drag()
.subject(({x, y}) => simulation.find(x - width / 2, y - height / 2, 40))
.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;
}
onMounted(() => {
const svg = d3.select(container.value)
.call(drag);
simulation = d3.forceSimulation(nodes)
.force("charge", d3.forceManyBody().strength(-40))
.force("link", d3.forceLink(links).strength(1).distance(10).iterations(10))
.force("x", d3.forceX())
.force("y", d3.forceY())
.on("tick", ticked);
const link = svg.append("g")
.attr("stroke", "currentColor")
.attr("stroke-opacity", 0.3)
.selectAll()
.data(links)
.join("line");
const node = svg.append("g")
.attr("fill", "currentColor")
.attr("stroke", "var(--vp-c-bg-alt)")
.selectAll()
.data(nodes)
.join("circle")
.attr("r", 2.5);
function ticked() {
node.attr("cx", (d) => d.x).attr("cy", (d) => d.y);
link.attr("x1", (d) => d.source.x).attr("y1", (d) => d.source.y);
link.attr("x2", (d) => d.target.x).attr("y2", (d) => d.target.y);
}
});
onUnmounted(() => {
simulation?.stop();
});
</script>
<template>
<div style="margin: 1em 0;">
<svg :width="width" :height="height" :viewBox="[-width / 2, -height / 2, width, height].join(' ')" fill="currentColor" style="overflow: visible; position: relative; z-index: 2; max-width: 100%; height: auto;" ref="container"></svg>
<a href="https://observablehq.com/@d3/force-directed-lattice?intent=fork" style="font-size: smaller;" target="_blank">Fork ↗︎</a>
</div>
</template>
8 changes: 8 additions & 0 deletions docs/d3-force/link.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
<script setup>

import ExampleLinkForce from "../components/ExampleLinkForce.vue";

</script>

# Link force

<ExampleLinkForce />

The link force pushes linked nodes together or apart according to the desired [link distance](#link_distance). The strength of the force is proportional to the difference between the linked nodes’ distance and the target distance, similar to a spring force.

## forceLink(*links*) {#forceLink}
Expand Down

0 comments on commit 987a2f2

Please sign in to comment.