chart = {
const links = data.links.map(d => Object.create(d));
const nodes = data.nodes.map(d => Object.create(d));
const forceY = d3.forceY((d, i) => {
var yScale;
var iLargest = 0;
if (d.color == 1) {
iLargest = (i>iLargest) ? i : iLargest;
}
yScale = d3.scaleLinear()
.domain([0,200])
.range([300-height/2, 500]);
var yPosition = (d.color == 1) ? yScale(i) : 800;
console.log ('yPosition = ', yPosition, i);
return yPosition;
}).strength(0.2)
var xScale = d3.scalePoint()
.domain([3, 4, 5, 6, 7, 8, 9])
.range([200-width/2, width/2 - 200]);
const forceX = d3.forceX((d) => d.color == 1 ? 0 : xScale(d.color)).strength(0.15);
const simulation = d3.forceSimulation(nodes)
.force("link", d3.forceLink(links).id(d => d.id).distance(0).strength(0))
.force("x", forceX)
.force("y", forceY)
.force("collide", d3.forceCollide().radius(radius))
.force("charge", d3.forceManyBody().strength(5))
.force("center", d3.forceCenter(0, 500));
simulation.on("tick", ticked);
const svg = d3.select(DOM.svg(width, height))
.attr("viewBox", [-width/2, -height/2, width, height]);
//.attr("viewBox", [-width / 2, -height, width, height*2]);
const link = svg.append("g")
.selectAll(".line")
.data(links)
.enter()
.append("line")
.attr("stroke", "#000")
.attr("stroke-opacity", 0.6)
// .attr("stroke-width", 1.5);
.attr("stroke-width", d => Math.sqrt(d.value))
.attr('fill','none');
const node = svg.selectAll('n') // from https://stackoverflow.com/questions/42250305/d3-v4-missing-node
.data(nodes)
.enter().append('g')
.attr('transform', ({ x, y }) => `translate(${x}, ${y})`);
var maxradius = 0;
node.each(function (d, i) {
console.log('d in each function is: ', d);
const _this = d3.select(this)
//var c = "svgGradient";
const circle = _this.append('circle')
.attr('r', radius)
.attr('fill', color)
.attr("stroke", "#fff")
.classed("poet", function (d) { (d.color < 2); })
if( d.color < 2 ) {
d.fixed = true;
d.x = Math.floor(i/12);
d.y = i % 12;
var r1=(d.id).split("-")[0].length;
maxradius=(r1>maxradius) ? r1 : maxradius;
const label = _this.append('foreignObject')
.attr('x',(0-r1*10/2))
.attr('y',-10)
// .attr('width',(poetradius-5)*2)
.attr('height',(poetradius-5)*2)
.attr('width',r1*10+5)
.append('xhtml:div')
.style('line-height','100%')
.style('font-family', "'CapitaFont', Helvetica, Arial, sans-serif")
.style('text-align','center')
.style('font-style','bold')
.style('text-transform', 'capitalize')
.style('color', '#fff')
.style('cursor', 'default')
.style('font-size', '1.7rem')
// .style('flex-shrink', '0')
.attr('text-anchor', 'middle')
.attr('title', d.title)
.html((d.id).split("-")[0])
}
});
//.call(drag(simulation)); //will removed this - not needed for fpp
console.log(maxradius);
//node.attr('r', maxradius*10);
node.append("title")
.text(d => d.title);
var nodeClicked = false;
/* from Hover Effect Autism Douban example */
node.transition()
.duration(300)
.ease(d3.easeLinear);
link.transition()
.duration(300)
.ease(d3.easeLinear);
function focus(d) {
if (!nodeClicked) { // if poet node has not been clicked
var nodeIndex=[];
var linkIndex=[];
var isLink = d.hasOwnProperty('source')
if(isLink){
nodeIndex.push(d.source.index)
nodeIndex.push(d.target.index)
linkIndex.push(d.index)
}else{
nodeIndex.push(d.index)
links.forEach(function(e,i){
if(e.source.index == d.index || e.target.index == d.index){
linkIndex.push(i)
nodeIndex.push(e.source.index)
nodeIndex.push(e.target.index)
}
})
}
node.transition()
.duration(300)
.ease(d3.easeLinear)
.style("opacity", function(o){
// node.transition(t).style("opacity", function(o){
// return nodeIndex.includes(o.index)?"block":"none";
return nodeIndex.includes(o.index)? 1:0.0; //originally was 0.1
})
link.transition()
.duration(300)
.ease(d3.easeLinear)
.style("opacity", function(o){
// link.transition(t).style("opacity", function(o){
// return linkIndex.includes(o.index)?"block":"none";
return linkIndex.includes(o.index)? 1:0.0;
})
}
}
function unfocus() {
if (!nodeClicked) { // if poet node has not been clicked
// node.attr("display", "block");
node.transition()
.duration(750)
.ease(d3.easeLinear)
.style("opacity", 1);
// link.attr("display", "block");
link.transition()
.duration(750)
.ease(d3.easeLinear)
.style("opacity", 1);
}
}
function gotourl(d) {
if (d.color > 2) { // only nonpoet and nonpoem nodes are clickable
window.open( d.links_to, "_blank");
}
else {
nodeClicked = !nodeClicked; // toggle nodeClicked
unfocus(d);
}
}
function checkFocus(d) {
if (nodeClicked) {
nodeClicked = false;
unfocus(d);
}
}
node.on("mouseover", focus)
.on("mouseout", unfocus)
.on("click", gotourl);
link.on("mouseover",focus)
.on("mouseout",unfocus);
//svg.on("click", checkFocus);
// node.transition(t)
// link.transition(t)
function ticked() {
// node
// .attr( "transform", d => `translate(${d.x}, ${d.y})`);
/* node
.attr( "transform", function (d,i) {
console.log('in ticked d: ', d);
console.log('in ticked i: ', i);
if (d.color > 1) {
return 'translate(${Math.floor(i/12)}, ${i%12})';
}
else {
return d => `translate(${d.x}, ${d.y})`;
}
} ); */
// }
// else {
node
.attr( "transform", d => `translate(${d.x}, ${d.y})`);
//.attr('transform', ({ x, y }) => `translate(${x}, ${y})`);
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)
//.attr("d",positionLink); no shape to the path so this is not needed.
}
// Quote from https://beta.observablehq.com/@bumbeishvili/d3-dag-topological
function positionLink(d) {
var offset = 110;
var midpoint_x = (d.source.x + d.target.x) / 2;
var midpoint_y = (d.source.y + d.target.y) / 2;
var dx = (d.target.x - d.source.x);
var dy = (d.target.y - d.source.y);
var normalise = Math.sqrt((dx * dx) + (dy * dy));
var offSetX = midpoint_x + offset*(dy/normalise);
var offSetY = midpoint_y - offset*(dx/normalise);
return "M" + d.source.x + "," + d.source.y +
"S" + offSetX + "," + offSetY +
" " + d.target.x + "," + d.target.y;
}
/* end Hover Effect Autism Douban example */
invalidation.then(() => simulation.stop());
return svg.node();
}