Published
Edited
Jun 29, 2021
Fork of TimeTravel
1 star
Insert cell
Insert cell
Insert cell
/*
1) Links issue (nice to have)
4) Recommenders Pics
5) Zoom (nice to have)
*/

chart = {

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

//Recommenders Text
svg.append("text")
.join("tspan")
.attr("x", margin.left)
.attr("y", (height * 3 / 5) + 30)
.text("Recommenders")
.style('font-family', '"Open Sans", sans-serif');

//SimulationForce
var simulation = d3.forceSimulation(data.object)
.force('forceX', d3.forceX((d) => xScale(parseTime(d.date))).strength(1))
.force('forceY', d3.forceY((d) => y(d.domain)))
.force('collide', d3.forceCollide(radius + padding + 3))
.on("tick", tick);


var simulation1 = d3.forceSimulation(data.person)
.force('forceX', d3.forceX(width / 2).strength(3))
.force('forceY', d3.forceY(height2 + 200).strength(10))
.force('collide', d3.forceCollide(30).strength(1))
.on('tick', ticked)


//ForceSimulation Ticks
function tick() {
svg.selectAll('#circle1')
.data(data.object)
.attr('cx', d => d.x)
.attr('cy', d => d.y);
}



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


let links = [];
let links_object_list = [];

for (let i = 0; i < data.object.length; i++) {
for (let p = 0; p < data.person.length; p++) {
for (let j = 0; j < data.links.length; j++) {
if (data.object[i].id == data.links[j].target && data.person[p].id == data.links[j].source) {

const coor = d3.linkVertical()({
source: [data.person[p].x, data.person[p].y],
target: [data.object[i].x, data.object[i].y]
}),

link_object = {
color: data.object[i].Color,
coord: coor,
source_x: data.person[p].x,
source_y: data.person[p].y,
target_x: data.object[i].x,
target_y: data.object[i].y,
source: [data.person[p].x, data.person[p].y],
target: [data.object[i].x, data.object[i].y],
id_source: data.person[p].id,
id_target: data.object[i].id
};

links.push(coor)
links_object_list.push(link_object)
}
}
}
}


var link = d3.linkVertical()
.source(function (d) {
return [d.source[0], d.source[1]];
})
.target(function (d) {
return [d.target[0], d.target[1]];
});

const gradient1 = g.append("g")
.selectAll('linearGradient')
.data(links_object_list)
.enter().append('linearGradient')
.attr("id", d => "gradient1" + d.color)
.attr("spreadMethod", "reflect")
.attr('cx', width / 2)
.attr('cy', height / 2)
.attr('r', 600)

gradient1
.append("stop")
.attr("offset", "30%")
.attr("stop-color", "#ee2681")

gradient1
.append("stop")
.attr("offset", "70%")
.attr("stop-color", d => d.color);

gradient1.append("animate")
.attr("attributeName", "x1")
.attr("values", "0%;-200%")
.attr("dur", "7s")
.attr("repeatCount", "indefinite");

gradient1.append("animate")
.attr("attributeName", "x2")
.attr("values", "-100%;-300%")
.attr("dur", "7s")
.attr("repeatCount", "indefinite")

g.selectAll("path")
.data(links_object_list)
.join('path')
.attr("d", link)
.attr('stroke-opacity', '0')
.attr('stroke', d => `url(#gradient1${d.color})`)
.attr('id', d => "path" + d.id_source)
.attr('class', d => "path" + d.id_target)
.attr('fill', 'none');

//Vertical Lines
svg.selectAll('.line-decade')
.data(xScale.ticks())
.join('line')
.attr('class', 'line-decade')
.attr('x1', d => xScale(d))
.attr('x2', d => xScale(d))
.attr('y1', 10)
.attr('y2', height * 3 / 5 - margin.top)
.attr('stroke-width', 1)
.attr('stroke', 'lightgray');

const node = g.append("g")
.selectAll("g")
.data(data.person)
.enter().append("g")


function ticked() {

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

d3.selectAll("#circletext")
.attr("transform" , `translate(${-10}, ${5})`)

}
//BeeSwarm
svg.selectAll("circle")
.data(data.object)
.join("circle")
.attr('class', d => "circle2" + d.year + "+" + d.id)
.attr("id", "circle1")
.attr("r", 5)
.attr("fill", d => d.Color)
.on('click', function (d) {})
.on("mouseover", function (d, data) {
tooltipcircle
.html("<link rel=preconnect href=https://fonts.gstatic.com> <link href=https://fonts.googleapis.com/css2?family=Montserrat&display=swap rel=stylesheet><div class=full-width><h1 class=h1full-width>" + plus + "Relevance: 0.0</h1></div><h1 class=h1tooltipcircle>Date</h1><hr><p>" + data.date + "</p><h1 class=h1tooltipcircle>Title</h1><hr><p>" + data.name + "</p><h1 class=h1tooltipcircle>DOI</h1><hr><p>" + data.DOI + "</p><h1 class=h1tooltipcircle>Knowlage Domain</h1><p>" + data.domain + "</p><h1 class=h1tooltipcircle>Keywords</h1><p>" + data.keywords + "</p><h1 class=h1tooltipcircle>Authors</h1><p>" + data.authors + "</p>")
.style('visibility', 'visible');
})
.on('mousemove', function (d) {
if (d.clientX > width / 2) {
tooltipcircle
.style('top', d.clientY + 10 + 'px')
.style('left', d.clientX - 425 + 'px')
.style("display", "inline-block");
} else {
tooltipcircle
.style('top', d.clientY + 10 + 'px')
.style('left', d.clientX + 20 + 'px')
.style("display", "inline-block");
}
})
.on('mouseout', function () {
tooltipcircle.style('visibility', 'hidden');
});


var most_recent = ''

const datalinks = data

node.append("circle")
//.attr('r', d => Math.random() * 30)
.attr('r', 20)
.attr("id", "circle2")
.attr('class', d => "circle" + d.profile)
.attr("fill", "#d7467e")
.on('click', function (d, data) {
if (most_recent == data.profile) {
d3.selectAll('circle').style("opacity", 1);
d3.selectAll('#circle2').style("opacity", 0.6);
d3.select(this).attr("stroke", "black").style("opacity", 1)
d3.selectAll('#circle2').on('mouseout', function (d, data) {
tooltip.style('visibility', 'hidden');
d3.selectAll("path").style('stroke-opacity', '0')
d3.selectAll("circle")
.attr("stroke", "white")
.style("opacity", 1)
});
d3.selectAll('#circle2').on('mouseover', function (d, data) {
let links3 = [];
const links_object_list3 = [];

for (let i = 0; i < datalinks.object.length; i++) {
for (let p = 0; p < datalinks.person.length; p++) {
for (let j = 0; j < datalinks.links.length; j++) {
if (datalinks.object[i].id == datalinks.links[j].target && datalinks.person[p].id == datalinks.links[j].source) {

const coor3 = d3.linkVertical()({
source: [datalinks.person[p].x, datalinks.person[p].y],
target: [datalinks.object[i].x, datalinks.object[i].y]
}),

link_object3 = {
color: datalinks.object[i].Color,
coord: coor3,
source_x: datalinks.person[p].x,
source_y: datalinks.person[p].y,
target_x: datalinks.object[i].x,
target_y: datalinks.object[i].y,
source: [datalinks.person[p].x, datalinks.person[p].y],
target: [datalinks.object[i].x, datalinks.object[i].y],
id_source: datalinks.person[p].id,
id_target: datalinks.object[i].id
};

links3.push(coor3)
links_object_list3.push(link_object3)
}
}
}
}

var link3 = d3.linkVertical()
.source(function (d) {
return [d.source[0], d.source[1]];
})
.target(function (d) {
return [d.target[0], d.target[1]];
});

g.selectAll("path")
.data(links_object_list3)
.join('path')
.attr("d", link3)
.attr('stroke-opacity', '0')
.attr('stroke', d => `url(#gradient1${d.color})`)
.attr('id', d => "path" + d.id_source)
.attr('class', d => "path" + d.id_target)
.attr('fill', 'none');
var image = "<img src=" + data.url + "/>"
tooltip
.html("<h1>" + facebook + twitter + chat + person + "Relevance: 0.0 </h1><hr>" + image + "<br/><h1>" + data.name + "</h1><h2>Ph.D.</h2><h1>ORCID</h1><p>" + data.profile + "</p>")
.style('visibility', 'visible')
filterOver("circle" + data.profile, data.id)
d3.select(this).attr("stroke", "black").style("opacity", 1)
d3.select(this).style("cursor", "pointer");
})
most_recent = ""
} else {
most_recent = data.profile
d3.selectAll('circle')
.style("opacity", 0)
d3.select(this)
.style("opacity", 1)
d3.selectAll('#circle1')
.style("opacity", 1)
d3.selectAll('#path' + data.profile)
.style("opacity", 1)
d3.selectAll('#circle2')
.on('mouseout', null)
d3.selectAll('#circle2')
.on('mouseover', null)
most_recent = data.profile
tooltip.html(``)
.style('visibility', 'hidden')
d3.select(this)
.style("cursor", "pointer")
d3.select(this).attr("stroke", "black").style("opacity", 1)
};
})
.on('mouseover', function (d, c) {
let links3 = [];
const links_object_list3 = [];

for (let i = 0; i < datalinks.object.length; i++) {
for (let p = 0; p < datalinks.person.length; p++) {
for (let j = 0; j < datalinks.links.length; j++) {
if (datalinks.object[i].id == datalinks.links[j].target && datalinks.person[p].id == datalinks.links[j].source) {

const coor3 = d3.linkVertical()({
source: [datalinks.person[p].x, datalinks.person[p].y],
target: [datalinks.object[i].x, datalinks.object[i].y]
}),

link_object3 = {
color: datalinks.object[i].Color,
coord: coor3,
source_x: datalinks.person[p].x,
source_y: datalinks.person[p].y,
target_x: datalinks.object[i].x,
target_y: datalinks.object[i].y,
source: [datalinks.person[p].x, datalinks.person[p].y],
target: [datalinks.object[i].x, datalinks.object[i].y],
id_source: datalinks.person[p].id,
id_target: datalinks.object[i].id
};

links3.push(coor3)
links_object_list3.push(link_object3)
}
}
}
}

var link3 = d3.linkVertical()
.source(function (d) {
return [d.source[0], d.source[1]];
})
.target(function (d) {
return [d.target[0], d.target[1]];
});

g.selectAll("path")
.data(links_object_list3)
.join('path')
.attr("d", link3)
.attr('stroke-opacity', '0')
.attr('stroke', d => `url(#gradient1${d.color})`)
.attr('id', d => "path" + d.id_source)
.attr('class', d => "path" + d.id_target)
.attr('fill', 'none');

var image = "<img src=" + c.url + "/>"
tooltip
.html("<h1>" + facebook + twitter + chat + person + "Relevance: 0.0 </h1><hr>" + image + "<br/><h1>" + c.name + "</h1><h2>Ph.D.</h2><h1>ORCID</h1><p>" + c.profile + "</p>")
.style('visibility', 'visible')
filterOver("circle" + c.profile, c.id)
d3.select(this).attr("stroke", "black").style("opacity", 1)
d3.select(this).style("cursor", "pointer");

})
.on('mouseout', function (d, data) {
d3.selectAll("#path" + data.id).style('stroke-opacity', '0')
filterOut("circle" + data.profile)
d3.select(this).attr("stroke", "white").style("opacity", 1)
tooltip.style('visibility', 'hidden');
})
.on('mousemove', function (d, data) {
if (d.clientX > width / 2) {
tooltip
.style('top', d.clientY + 10 + 'px')
.style('left', d.clientX - 375 + 'px')
.style("display", "inline-block");
} else {
tooltip
.style('top', d.clientY + 10 + 'px')
.style('left', d.clientX + 20 + 'px')
.style("display", "inline-block");
}
});


node.append('text')
.text(d => d.name.slice(0, 2))
.attr("id", "circletext")
.style('fill', '#fff')
.attr("font-weight", "bold")

//AxisTop
svg.append('g').call(xAxis).selectAll("text")
.attr("transform", "translate(25,10)rotate(270)")
.attr("color", "black");

d3.select('#clusterButton').on('click', () => {

d3.selectAll("path").style('stroke-opacity', '0')

d3.selectAll("#circle2").attr("pointer-events", "all");

simulation = d3.forceSimulation(data.object)
.force('forceX', d3.forceX((d) => xScale(parseTime(d.date))).strength(1))
.force('forceY', d3.forceY((d) => y(d.domain)))
.force('collide', d3.forceCollide(radius + padding + 3))
.restart()
.on("tick", tick);

document.getElementById("AllButton").disabled = false;
});

d3.select('#groupButton').on('click', () => {

d3.selectAll("#cicle2").attr("pointer-events", "none");

d3.selectAll("path").style('stroke-opacity', '0')

simulation = d3.forceSimulation(data.object)
.force('forceX', d3.forceX((d) => xScale(parseTime(d.date))).strength(6))
.force('forceY', d3.forceY(height / 4).strength(1))
.force('collide', d3.forceCollide(radius + padding + 3))
.on("tick", tick);

//document.getElementById("AllButton").disabled = true;
});


d3.select('#NoOneButton').on('click', () => {

d3.selectAll('path')
.style("stroke-opacity", 0);


});

d3.select('#AllButton').on('click', () => {

d3.selectAll('path')
.style("stroke-opacity", 1);

let links2 = [];
const links_object_list2 = [];

for (let i = 0; i < data.object.length; i++) {
for (let p = 0; p < data.person.length; p++) {
for (let j = 0; j < data.links.length; j++) {
if (data.object[i].id == data.links[j].target && data.person[p].id == data.links[j].source) {

const coor2 = d3.linkVertical()({
source: [data.person[p].x, data.person[p].y],
target: [data.object[i].x, data.object[i].y]
}),

link_object2 = {
color: data.object[i].Color,
coord: coor2,
source_x: data.person[p].x,
source_y: data.person[p].y,
target_x: data.object[i].x,
target_y: data.object[i].y,
source: [data.person[p].x, data.person[p].y],
target: [data.object[i].x, data.object[i].y],
id_source: data.person[p].id,
id_target: data.object[i].id
};

links2.push(coor2)
links_object_list2.push(link_object2)
}
}
}
}

var link2 = d3.linkVertical()
.source(function (d) {
return [d.source[0], d.source[1]];
})
.target(function (d) {
return [d.target[0], d.target[1]];
});

g.selectAll("path")
.data(links_object_list2)
.join('path')
.attr("d", link2)
.attr('stroke-opacity', '0')
.attr('stroke', d => `url(#gradient1${d.color})`)
.attr('id', d => "path" + d.id_source)
.attr('class', d => "path" + d.id_target)
.attr('fill', 'none');

});

/*ZOOM
svg.call(d3.zoom()
.extent([[0, 0], [width, height]])
.scaleExtent([1, 8])
.on("zoom", zoomed));

function zoomed({transform}) {
g.attr("transform", transform);
}
*/
return svg.node();
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
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