chart = {
var links = data.links.map(d => Object.create(d));
var nodes = data.nodes.map(d => Object.create(d));
var simulation = d3.forceSimulation(nodes)
.force("link", d3.forceLink(links).id(d => d.id))
.force("charge", d3.forceManyBody())
.force("center", d3.forceCenter(width / 2, height / 2));
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height]);
var marker = svg
.append("svg:defs")
.selectAll("marker")
.data(["end"])
.enter()
.append("svg:marker")
.attr("id", String)
.attr("viewBox", "0 -5 10 10")
.attr("refX", 0)
.attr("refY", 0)
.attr("markerWidth", 3)
.attr("markerHeight", 2)
.attr("orient", "auto")
.append("svg:path")
.attr("d", "M0,-5L10,0L0,5");
.attr("stroke", "Gray")
.selectAll("line")
.data(links)
.join("line")
.attr("stroke-width",1)
.attr("marker-mid", "url(#end)")*/
var link = svg
.selectAll(".link")
.data(links)
.enter()
.append("polyline") //Create as polyline for arrows
.attr("stroke", "Gray")
.attr("stroke-width",3) // Set default stroke width
.attr("marker-mid", "url(#end)") // Add Marker
// Create nodes
var node = svg
.append("g")
.attr("stroke", "White")
.selectAll("circle")
.data(nodes)
.join("circle")
.attr("r", d=>5*Math.sqrt(d.value))
//.attr("fill", function(d) { return color(d.group); })
.attr("fill", function(d) { return mycolor(d.group); })
//.attr("fill", function(d) { return "pink"; })
.call(drag(simulation)).attr('class', 'node');
var nodeLinkStatus = {};
links.forEach(d => {
nodeLinkStatus[`${d.source.index},${d.target.index}`] = 1;
});
function isConnected(a, b) {
return nodeLinkStatus[`${a.index},${b.index}`] || nodeLinkStatus[`${b.index},${a.index}`] || a.index === b.index;
}
// Node interactibility
node.on('mouseover',function (d) {
node.style('stroke-opacity', function (o) {
var thisOpacity = 0;
if(isConnected(d, o)){
thisOpacity = 1;
} else{
thisOpacity = 0.3;
}
this.setAttribute('fill-opacity', thisOpacity);
return thisOpacity;
});
link.style('opacity', function(l) {
if (d === l.source || d === l.target){
return 1;
}
else{
return 0.2;
}
});
link.style('stroke-width', function(l) {
if (d === l.source || d === l.target){
return 5;
}else{
return 3;
}
});
var xpos =d.x;
var ypos = d.y;
var tgrp = svg.append("g")
.attr("id", "tooltip")
.attr("transform", (d, i) => `translate(${xpos+10},${ypos})`);
tgrp.append("rect")
.attr("width", "40px")
.attr("height", "24px")
.attr("fill", "gray")
tgrp.append("text")
.attr("x", 5)
.attr("y", 14)
.attr("text-anchor", "left")
.attr("font-family", "sans-serif")
.attr("font-size", "110px")
.attr("font-weight", "bold")
.attr("fill", "white")
.text(`${d.name}`);
});
node.on('mouseout',function (d) {
node.style('stroke-opacity', function (o) {
this.setAttribute('fill-opacity', 1);
return 1;
});
link.style('opacity',1);
link.style('stroke-width',3);
d3.select("#tooltip").remove();
});
// Legend
var allGroupNames = ['Targaryen','Stark','Lannister','Greyjoy','Baratheon','Snow','Other']
var groupHouses = (color.domain()).slice(0,7)
var colorLegend = svg
.selectAll('.colorLegend')
.data(groupHouses)
.enter().append("g") //下面是图标的位置
.attr('transform', function(d, i) {
return 'translate('+(10)+',' + (10+(25*i)) +')';
})
colorLegend.append('rect')
//这里对应的是左上角图标的颜色
.attr('fill', function(d) { return color(d); })
//.attr('fill', function(d) { return "black"; })
.attr('width', 20)
.attr('height', 20);
colorLegend.append("text")
.attr('x', 25)
.attr('y', 25/2)
.text(function(d) {return allGroupNames[d-1]; });
// Simulation tick
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("points", function(d) {
return d.source.x + "," + d.source.y + " " +
(d.source.x + d.target.x)/2 + "," + (d.source.y + d.target.y)/2 + " " +
d.target.x + "," + d.target.y; });
node
.attr("cx", d => d.x)
.attr("cy", d => d.y);
});
// Event listener for edge coloring
function update() {
link.style('stroke', function(l) {
var query = viewof order.value
if (query.includes("sibling")){
if (l.relationship === "sibling" || l.relationship === "siblings"){
return '#DC143C';
}
}
else if (l.relationship === query){
return '#DC143C';
}
else{
return 'gray';
}
})
}
function changeFunction() {
svg.selectAll("*").remove();
var targaryen = document.getElementById('1').checked;
var stark = document.getElementById('2').checked;
var lannister = document.getElementById('3').checked;
var grayjoy = document.getElementById('4').checked;
var baratheon = document.getElementById('7').checked;
var snow = document.getElementById('6').checked;
var other = document.getElementById('5').checked;
var houses = [targaryen,stark,lannister,grayjoy,baratheon,snow,other];
var validNodes = [];
var validLinks = [];
var i;
for (i=0;i<data.nodes.length;i++){
if(houses[(data.nodes[i].group)-1] == true){
validNodes.push(data.nodes[i])
};
}
var j;
for(j=0;j<data.links.length;j++){
var k;
for(k=0;k<validNodes.length;k++){
if(validNodes[k].name === data.links[j].source){
var m;
for(m=0;m<validNodes.length;m++){
if(validNodes[m].name === data.links[j].target){
validLinks.push(data.links[j]);
continue;
}
};
};
}
}
nodes = validNodes.map(d => Object.create(d));
links = validLinks.map(d => Object.create(d));
// Force Diagram
simulation = d3.forceSimulation(nodes)
.force("link", d3.forceLink(links).id(d => d.id))
.force("charge", d3.forceManyBody())
.force("center", d3.forceCenter(width / 2, height / 2));
//Create marker arrows
marker = svg
.append("svg:defs")
.selectAll("marker")
.data(["end"])
.enter()
.append("svg:marker")
.attr("id", String)
.attr("viewBox", "0 -5 10 10")
.attr("refX", 0)
.attr("refY", 0)
.attr("markerWidth", 3)
.attr("markerHeight", 2)
.attr("orient", "auto")
.append("svg:path")
.attr("d", "M0,-5L10,0L0,5");
link = svg
.selectAll(".link")
.data(links)
.enter()
.append("polyline") //Create as polyline for arrows
.attr("stroke", "Gray")
.attr("stroke-width",3) // Set default stroke width
.attr("marker-mid", "url(#end)") // Add Marker
// Create nodes
node = svg
.append("g")
.attr("stroke", "White")
.selectAll("circle")
.data(nodes)
.join("circle")
.attr("r", d=>5*Math.sqrt(d.value))
.attr("fill", function(d) { return color(d.group); })
//.attr("fill", function(d) { return "black"; })
.call(drag(simulation)).attr('class', 'node');
nodeLinkStatus = {};
links.forEach(d => {
nodeLinkStatus[`${d.source.index},${d.target.index}`] = 1;
});
// Node interactibility
node.on('mouseover',function (d) {
node.style('stroke-opacity', function (o) {
var thisOpacity = 0;
if(isConnected(d, o)){
thisOpacity = 1;
} else{
thisOpacity = 0.3;
}
this.setAttribute('fill-opacity', thisOpacity);
return thisOpacity;
});
link.style('opacity', function(l) {
if (d === l.source || d === l.target){
return 1;
}
else{
return 0.2;
}
});
link.style('stroke-width', function(l) {
if (d === l.source || d === l.target){
return 5;
}else{
return 3;
}
});
var xpos =d.x;
var ypos = d.y;
var tgrp = svg.append("g")
.attr("id", "tooltip")
.attr("transform", (d, i) => `translate(${xpos+10},${ypos})`);
tgrp.append("rect")
.attr("width", "40px")
.attr("height", "24px")
.attr("fill", "gray")
tgrp.append("text")
.attr("x", 5)
.attr("y", 14)
.attr("text-anchor", "left")
.attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("font-weight", "bold")
.attr("fill", "white")
.text(`${d.name}`);
});
node.on('mouseout',function (d) {
node.style('stroke-opacity', function (o) {
this.setAttribute('fill-opacity', 1);
return 1;
});
link.style('opacity',1);
link.style('stroke-width',3);
d3.select("#tooltip").remove();
});
colorLegend = svg.selectAll('.colorLegend')
.data(groupHouses)
.enter().append("g")
.attr('transform', function(d, i) {
return 'translate('+(10)+',' + (10+(25*i)) +')';
})
colorLegend.append('rect')
//.attr('fill', function(d) { return color(d); })
.attr('fill', function(d) { return "black"; })
.attr('width', 20)
.attr('height', 20);
colorLegend.append("text")
.attr('x', 25)
.attr('y', 25/2)
.text(function(d) {return allGroupNames[d-1]; });
// Simulation tick
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("points", function(d) {
return d.source.x + "," + d.source.y + " " +
(d.source.x + d.target.x)/2 + "," + (d.source.y + d.target.y)/2 + " " +
d.target.x + "," + d.target.y; });
node
.attr("cx", d => d.x)
.attr("cy", d => d.y);
});
}
viewof order.addEventListener("input", update);
invalidation.then(() => viewof order.removeEventListener("input", update));
viewof orderHouse.addEventListener("input", changeFunction);
invalidation.then(() => viewof orderHouse.removeEventListener("input",changeFunction));
return svg.node();
}