Published
Edited
Mar 9, 2021
Insert cell
md`# Complex Graph-V2`
Insert cell
chart = {
const links = graphData.links.map(d => Object.create(d));
const nodes = graphData.nodes.map(d => Object.create(d));

const simulation = d3.forceSimulation(nodes)
.force("link", d3.forceLink(links).id(d => d.id))
.force("charge", d3.forceManyBody().strength(-3500))
.force("center", d3.forceCenter(width / 2, height / 2))
.stop();

const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height]);

const link = svg.append("g")
.attr("stroke", "#999")
.attr("stroke-opacity", 0.9)
.selectAll("line")
.data(links)
.join("line")
.attr('stroke-dasharray', '2')
.attr("stroke-width", 1);

const onLinkChart = svg.append('g')
.selectAll('g')
.data(links)
.join('g')
.each(function(d) {
drawLinkChart(d3.select(this), d)
})

const node = svg.append("g")
.selectAll("g")
.data(nodes)
.join("g")
.each(function(d) {
drawFunc(d3.select(this), d)
})
node.call(drag(simulation))

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);

onLinkChart
.attr('transform', d => {
const vec = [d.target.x - d.source.x, d.target.y - d.source.y]
const rotateDeg = Math.atan(vec[1] / vec[0]) / Math.PI * 180
return `translate(${(d.source.x + d.target.x) / 2} ${(d.source.y + d.target.y) / 2}) rotate(${rotateDeg}) `
})

node
.attr('transform', d => `translate(${d.x} ${d.y})`)
simulation.on("tick", () => {
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);

onLinkChart
.attr('transform', d => {
const vec = [d.target.x - d.source.x, d.target.y - d.source.y]
const rotateDeg = Math.atan(vec[1] / vec[0]) / Math.PI * 180
return `translate(${(d.source.x + d.target.x) / 2} ${(d.source.y + d.target.y) / 2}) rotate(${rotateDeg}) `
})

node
.attr('transform', d => `translate(${d.x} ${d.y})`)
});
simulation.on('end', () => {
console.log(JSON.stringify(nodes))
})

invalidation.then(() => simulation.stop());

return svg.node();
}
Insert cell
drawLinkChart = (g, d) => {
g = g.append('g')
.attr('transform', `translate(${-85} ${-15}) `)
for (var k = 0; k < 4; k++) {
g = g.append('g')
.attr('transform', `translate(30,0) `)
g.append('rect')
.attr('width', 25)
.attr('height', 30)
.attr('fill', backgroundColor[k])
.attr('stroke', '#000000')
.attr('stroke-width', '1')

const xScale = d3.scaleBand()
.domain(d3.range(10))
.range([0, 100])
.padding(0.1)

const yScale = d3.scaleLinear()
.domain([0, 1])
.range([20, 0])

g.append('g')
.attr('transform', `translate(10 5)`)
.append('rect')
.attr('transform', `translate(-10,0) `)
.attr('width', Math.random() * 25)
.attr('height', 20)
.attr('fill', dataColor[k])
.attr('stroke', '#000000')
.attr('stroke-width', '1')
}
}
Insert cell
drawFunc = (g, d) => {
g = g.append('g')
g.append('circle')
.attr('r', 15)
.attr('fill', '#ccd2da')
.attr('stroke', '#afaeae')
.attr('stroke-width', '1')
g.append('g')
.attr('transform', 'translate(-4, -5)')
.append('text')
.attr('alignment-baseline', 'hanging')
.text(`${d.id}`)

const xScale = d3.scaleLinear()
.domain([0, 9])
.range([0, 50])

const yScale = d3.scaleLinear()
.domain([0, 1])
.range([30, 0])

const line = d3.line()
.x((d) => xScale(d.x))
.y((d) => yScale(d.y))
}
Insert cell
drag = simulation => {

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;
}

return d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended);
}
Insert cell
backgroundColor = ["#abf483", "#a6d3f6", "#f5f5a5", "#f5cfd1"]
Insert cell
dataColor = ["#1a7903", "#002cfe", "#fffc00", "#fa000b"]
Insert cell
chartData = d3.range(10).map((d) => ({x: d, y: d3.randomUniform(1)()}))
Insert cell
graphData = {
return {
nodes: [
{"id":0,"x":925.4093991140644,"y":333.4559194537089,"vy":-0.000682639507022945,"vx":0.0021234521793332684},
{"id":1,"x":807.9716776192328,"y":198.14968671422182,"vy":-0.00030031655427770334,"vx":0.0025109648460270627},
{"id":2,"x":503.2228592505249,"y":25.87282580281775,"vy":-0.0011644580524885191,"vx":0.0038744867317562874},
{"id":3,"x":386.40735925873275,"y":189.4201010403996,"vy":-0.002298276692793771,"vx":0.0023270253562025704},
{"id":4,"x":230.42900527570058,"y":58.25342768799508,"vy":-0.003271440406371248,"vx":0.0037287869304173495},
{"id":5,"x":103.37837565961664,"y":243.14020636378024,"vy":-0.004479273414583931,"vx":0.0017084244038430491},
{"id":6,"x":469.87385925093446,"y":481.9940152573297,"vy":-0.001424806292272636,"vx":0.0016684483275820699},
{"id":7,"x":647.6160217389419,"y":566.1577422011261,"vy":-0.0002613305742440475,"vx":0.0015115731442653629},
{"id":8,"x":787.4262487769847,"y":449.240268916034,"vy":-0.0003616405314113509,"vx":0.0024734497043879785},
{"id":9,"x":228.28725520210696,"y":454.29866189660004,"vy":-0.002900483961304653,"vx":0.0001345352168505327}
],
links: [
{
source: 0,
target: 1
},
{
source: 0,
target: 8
},
{
source: 1,
target: 2
},
{
source: 1,
target: 8
},
{
source: 2,
target: 3
},
{
source: 2,
target: 4
},
{
source: 3,
target: 4
},
{
source: 3,
target: 6
},
{
source: 4,
target: 5
},
{
source: 5,
target: 9
},
{
source: 6,
target: 7
},
{
source: 6,
target: 8
},
{
source: 6,
target: 9
},
{
source: 7,
target: 8
},
]
}
}
Insert cell
height = 600
Insert cell
d3 = require("d3@6")
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