Public
Edited
Feb 27, 2024
1 star
Insert cell
Insert cell
Insert cell
d3 = require("d3@5")
Insert cell
{
let height = 600;

var svg = d3.create("svg").attr("width", width).attr("height", height);

var zoom = d3
.zoom()
.scaleExtent([-8 / 2, 4])
.on("zoom", zoomed);

svg.call(zoom);

var g = svg.append("g");

var simulation = d3
.forceSimulation()
.force(
"link",
d3.forceLink().id(function (d) {
return d.id;
})
)
.force("charge", d3.forceManyBody())
.force("center", d3.forceCenter(width / 2, height / 2));

var graph = {
nodes: [
{
id: "Myriel",
group: 1
},
{
id: "Napoleon",
group: 1
},
{
id: "Mlle.Baptistine",
group: 1
},
{
id: "Mme.Magloire",
group: 1
},
{
id: "CountessdeLo",
group: 1
},
{
id: "Geborand",
group: 1
},
{
id: "Champtercier",
group: 1
},
{
id: "Cravatte",
group: 1
},
{
id: "Count",
group: 1
},
{
id: "OldMan",
group: 1
},
{
id: "Labarre",
group: 2
},
{
id: "Valjean",
group: 2
},
{
id: "Marguerite",
group: 3
},
{
id: "Mme.deR",
group: 2
},
{
id: "Isabeau",
group: 2
},
{
id: "Gervais",
group: 2
},
{
id: "Tholomyes",
group: 3
},
{
id: "Listolier",
group: 3
},
{
id: "Fameuil",
group: 3
},
{
id: "Blacheville",
group: 3
},
{
id: "Favourite",
group: 3
},
{
id: "Dahlia",
group: 3
},
{
id: "Zephine",
group: 3
},
{
id: "Fantine",
group: 3
},
{
id: "Mme.Thenardier",
group: 4
},
{
id: "Thenardier",
group: 4
},
{
id: "Cosette",
group: 5
},
{
id: "Javert",
group: 4
},
{
id: "Fauchelevent",
group: 0
},
{
id: "Bamatabois",
group: 2
},
{
id: "Perpetue",
group: 3
},
{
id: "Simplice",
group: 2
},
{
id: "Scaufflaire",
group: 2
},
{
id: "Woman1",
group: 2
},
{
id: "Judge",
group: 2
},
{
id: "Champmathieu",
group: 2
},
{
id: "Brevet",
group: 2
},
{
id: "Chenildieu",
group: 2
},
{
id: "Cochepaille",
group: 2
},
{
id: "Pontmercy",
group: 4
},
{
id: "Boulatruelle",
group: 6
},
{
id: "Eponine",
group: 4
},
{
id: "Anzelma",
group: 4
},
{
id: "Woman2",
group: 5
},
{
id: "MotherInnocent",
group: 0
},
{
id: "Gribier",
group: 0
},
{
id: "Jondrette",
group: 7
},
{
id: "Mme.Burgon",
group: 7
},
{
id: "Gavroche",
group: 8
},
{
id: "Gillenormand",
group: 5
},
{
id: "Magnon",
group: 5
},
{
id: "Mlle.Gillenormand",
group: 5
},
{
id: "Mme.Pontmercy",
group: 5
},
{
id: "Mlle.Vaubois",
group: 5
},
{
id: "Lt.Gillenormand",
group: 5
},
{
id: "Marius",
group: 8
},
{
id: "BaronessT",
group: 5
},
{
id: "Mabeuf",
group: 8
},
{
id: "Enjolras",
group: 8
},
{
id: "Combeferre",
group: 8
},
{
id: "Prouvaire",
group: 8
},
{
id: "Feuilly",
group: 8
},
{
id: "Courfeyrac",
group: 8
},
{
id: "Bahorel",
group: 8
},
{
id: "Bossuet",
group: 8
},
{
id: "Joly",
group: 8
},
{
id: "Grantaire",
group: 8
},
{
id: "MotherPlutarch",
group: 9
},
{
id: "Gueulemer",
group: 4
},
{
id: "Babet",
group: 4
},
{
id: "Claquesous",
group: 4
},
{
id: "Montparnasse",
group: 4
},
{
id: "Toussaint",
group: 5
},
{
id: "Child1",
group: 10
},
{
id: "Child2",
group: 10
},
{
id: "Brujon",
group: 4
},
{
id: "Mme.Hucheloup",
group: 8
}
],
links: [
{
source: "Napoleon",
target: "Myriel",
value: 1
},
{
source: "Mlle.Baptistine",
target: "Myriel",
value: 8
},
{
source: "Mme.Magloire",
target: "Myriel",
value: 10
}
]
};

var link = g
.append("g")
.attr("class", "links")
.selectAll("line")
.data(graph.links)
.enter()
.append("line");

var node = g
.append("g")
.attr("class", "nodes")
.selectAll("circle")
.data(graph.nodes)
.enter()
.append("circle")
.attr("r", 2.5)
.on("click", clicked);

node.append("title").text(function (d) {
return d.id;
});

simulation.nodes(graph.nodes).on("tick", ticked);

simulation.force("link").links(graph.links);

var check = true;
svg.attr("cursor", "wait");

function ticked() {
console.log(this.alpha());
if (this.alpha() > 0.04) {
// set up zoom transform:
var xExtent = d3.extent(node.data(), function (d) {
return d.x;
});
var yExtent = d3.extent(node.data(), function (d) {
return d.y;
});

// get scales:
var xScale = (width / (xExtent[1] - xExtent[0])) * 0.75;
var yScale = (height / (yExtent[1] - yExtent[0])) * 0.75;

// get most restrictive scale
var minScale = Math.min(xScale, yScale);

if (minScale < 1) {
var transform = d3.zoomIdentity
.translate(width / 2, height / 2)
.scale(minScale)
.translate(
-(xExtent[0] + xExtent[1]) / 2,
-(yExtent[0] + yExtent[1]) / 2
);
svg.call(zoom.transform, transform);
}
} else {
svg.attr("cursor", "pointer");
if (check) console.log("check");
var check = false;
}

link
.attr("x1", function (d) {
return d.source.x;
})
.attr("y1", function (d) {
return d.source.y;
})
.attr("x2", function (d) {
return d.target.x;
})
.attr("y2", function (d) {
return d.target.y;
});

node
.attr("cx", function (d) {
return d.x;
})
.attr("cy", function (d) {
return d.y;
})
.attr("r", 20);
}

var active = d3.select(null);

function clicked(d) {
if (active.node() === this) {
active.classed("active", false);
return reset();
}

active = d3.select(this).classed("active", true);

svg
.transition()
.duration(750)
.call(
zoom.transform,
d3.zoomIdentity
.translate(width / 2, height / 2)
.scale(8)
.translate(-+active.attr("cx"), -+active.attr("cy"))
);
}

function reset() {
svg
.transition()
.duration(750)
.call(zoom.transform, d3.zoomIdentity.translate(0, 0).scale(1));
}

function zoomed() {
g.attr("transform", d3.event.transform);
}

return svg.node();
}
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more