Public
Edited
Jul 7, 2024
1 fork
1 star
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
{
const container = d3
.create("div")
.attr("width", width)
.attr("height", height)
.attr("class", "container");

const imgContainer = container
.append("div")
.attr("width", width)
.attr("height", height)
.attr("class", "imgContainer");

const svg = container
.append("svg")
.attr("width", width)
.attr("height", height);

const links = Array.from(links_array); // links_array.map((d) => Object.create(d));
const nodes = [...nodes_array]; //nodes_array.map((d) => Object.create(d));

const toolTip = d3.select("body").append("div").attr("class", "toolTip");

// svg.append("svg:image")
// .attr("xlink:href", "https://images.pexels.com/photos/998641/pexels-photo-998641.jpeg")
// .attr("width", width)
// .attr("height", height)
// .attr('object-fit', 'cover')
// .attr("x", 0)
// .attr("y",0);

const yScale = d3
.scaleLinear()
.domain([1980, 2022])
.range([30, height - 30]);

// center — pulls all nodes to the center
// charge — nodes repel from each other which prevents overlap
// link — specifies that id is the link variable
const simulation = d3
.forceSimulation(nodes)
.force(
"link",
d3
.forceLink(links)
.id((d) => d.id)
.strength(1.5)
.distance(22)
)
// .force("link", d3.forceLink(links).id(d => d.id).strength(1).distance(10))
.force("center", d3.forceCenter(width / 2, height / 2))
.force("charge", d3.forceManyBody().strength(-172)) // -400
// .force("collide", d3.forceCollide(10))
.force("x", d3.forceX())
.force("y", d3.forceY());
// .force('y', d3.forceY().y(d => yScale(d.year)))
// .force('collision', d3.forceCollide().radius(function(d) {
// return d.radius;
// }))

const array = [];
const link = svg
.append("g")
.selectAll("line")
.data(links)
.join("line")
.style("stroke", blue)
.attr("stroke-width", 1.2)
// .style("stroke", "rgba(255,255,255,1)")
// .attr("stroke-width", .75)
.on("mousemove", function (event, d, index) {
toolTip
.style("left", event.pageX + 18 + "px")
.style("top", event.pageY + 18 + "px")
.style("display", "block").html(`<div>
<div class="tooltip-movie">${d.data.name} (${d.data.year})</div>
<div class="tooltip-director">${d.data.director} <span>director</span></div>
<div class="tooltip-star">${d.data.star} </div>
</div>`);
// .html(`Tooltip for <strong>${d.source.id} - ${d.target.id}</strong>`);

// d3.select(this).attr("stroke-width", 3.8);
// console.log(d);

link.attr("stroke-width", (d2) =>
d2.data.name === d.data.name ? 3.8 : 1.2
);
})
.on("mouseout", function () {
toolTip.style("display", "none");
link.attr("stroke-width", 1.2);
// d3.select(this).attr("stroke-width", 1.1);
});

// const link = svg.append("g")
// .attr("fill", "none")
// .selectAll("path")
// .data(links)
// .join("path")
// .attr("stroke", '#1fd5d5')
// .attr("stroke-width", 1)

const node = svg
.append("g")
.attr("fill", "currentColor")
.attr("stroke-linecap", "round")
.attr("stroke-linejoin", "round")
.selectAll("g")
.data(nodes)
.join("g")
.call(drag(simulation));

node
.append("text")
.text((d) => (d.type !== "name" ? d.id : ""))
// .attr('dx', 6)
.attr("text-anchor", "middle")
// .style('fill', d => d.type === 'director' ? '#333' : blue) //008fb2
.style("fill", (d) => (d.type === "director" ? "#efefef" : "#a9ecfd")) //008fb2
.attr("class", (d) => (d.type === "director" ? "director" : "star"))
.style("opacity", (d) =>
d.type === "director" ? 1 : d.type === "star" ? 1 : 0
)
.clone(true)
.lower()
.attr("stroke", "rgba(0,0,0,0.95)")
.attr("stroke-width", 2.2)
.on("mousemove", function (event, d, index) {
d3.select(this).style("opacity", 1);
});

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

// link.attr("d", linkArc);
node.attr("transform", (d) => `translate(${d.x},${d.y})`);
});

return container.node();
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
nodes_array = {
let array = []
selected_data.map((d, i) => {
if(i === 0) {
array.push({id: d.director, type: 'director', year: d.year })
array.push({id: d.star, type: 'star', year: d.year})
array.push({id: d.name, type: 'name', year: d.year})
}
else {
array.filter(item => item.id === d.director).length > 0 ? '' : array.push({id: d.director, type: 'director', year: d.year})
array.filter(item => item.id === d.star).length > 0 ? '' : array.push({id: d.star, type: 'star', year: d.year})
array.filter(item => item.id === d.name).length > 0 ? '' : array.push({id: d.name, type: 'name', year: d.year})
}
})
return array
}
Insert cell
selected_data = getRepeatedRel(cleaned_data)
Insert cell
Insert cell
Insert cell
distinct_korea_directors = [... new Set(korea_data.map(d => d.director))]
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
minNumProjects = 3
Insert cell
getRepeatedRel = (thisData) => {
const relArray = thisData.map((d) =>
d.director !== d.star ? `${d.director}-${d.star}` : ""
);
const repeatedRelArray = [];

thisData.map((d) => {
const thisRel = `${d.director}-${d.star}`;
if (relArray.filter((rel) => rel === thisRel).length >= minNumProjects) {
repeatedRelArray.push(d);
}
});

return repeatedRelArray;
}
Insert cell
Insert cell
Insert cell
cleaned_data = raw_data.map((d) => {
d.year = parseInt(d.year);
d.score = parseInt(d.score);
return d;
})
// .filter(d => d.score > 6)
// .filter(d => d.country === 'France')
// .filter(d => d.country === 'United States')
// .filter((d) => d.country === "South Korea" || d.country === "United States")
// .filter((d) => d.year > 1990 && d.year < 2020)
Insert cell
Insert cell
html`<style>

body {
cursor: pointer;
}

.container {
background-color: #222222;

}

// .imgContainer {
// background-color: red;
// // background-size: cover;
// // background-image: url("https://images.pexels.com/photos/7736089/pexels-photo-7736089.jpeg");
// // opacity: 0.4;
// }

.director {
padding-left: 5px;
font-family: Arial;
text-transform: uppercase;
font-size: 13px;
// color: rgba(255, 255, 255, 0.82);
font-weight: bold;
}

.star {
font-family: Arial;
// text-transform: uppercase;
font-size: 13px;
// color: #9de1e1;
// font-weight: bold;
// text-shadow: #000 1px 0 1px;
// text-shadow: rgba(255,255,255,0.4) 1px 0 5px;
}

.toolTip {
font-family: Arial;
position: absolute;
display: none;
min-width: 30px;
max-width: 240px;
border-radius: 10px;
height: auto;
background: #111;
padding: 10px 13px;
text-align: left;
z-index: 1000;
line-height: 1em;
color: #f1f1f1;
border: 1px solid rgba(255, 255, 255, 0.18);
}
.tooltip-movie {
font-size: 13px;
font-weight: bold;
}
.tooltip-director {
font-size: 12px;
margin-top: 8px;
}
.tooltip-director span {
font-size: 11px;
color: #888;
}
.tooltip-star{
font-size: 12px;
}

</style>`
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