Public
Edited
Aug 8, 2023
Fork of TimeTravel
1 fork
Insert cell
Insert cell
Insert cell
chart = d3
.create('svg')
.attr("viewBox", [0, 0, width, height])
.attr("cursor", "pointer")
.call(domainZoom()
.x(xScale)
.axisX(timeline)
.link(updateData))
.call(drawData)
.node()
Insert cell
drawData = function(svg) {
svg.append("text")
.join("tspan")
.attr("x", margin.left)
.attr("y", (height * 3 / 5) + 30)
.text("Researchers")
.style('font-family', '"Open Sans", sans-serif');
//SimulationForce
var simulation = d3.forceSimulation(data.object)
.force('x', d3.forceX((d) => xScale(parseTime(d.date))))
.force('y', d3.forceY((d) => y(d.domain)))
.force('collide', d3.forceCollide(d => d.radius))
.on("tick", tick);

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


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


function ticked() {
svg.selectAll('#circle2')
.data(data.person)
.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', 100)
.attr('y2', height * 3 / 5 - margin.top)
.attr('stroke-width', 1)
.attr('stroke', 'lightgray').select(".domain").style('stroke-opacity', '0');

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

node.append('pattern')
.attr("id", d => "image"+ d.id)
.attr("width", 1)
.attr("height", 1)
.append("svg:image")
.attr("xlink:href", d => d.url)
.attr("width", 40)
.attr("height", 40);

//BeeSwarm
svg.selectAll("circle")
.data(data.object)
.join("circle")
.attr('class', d => "circle2" + d.year + "+" + d.id)
.attr("id", "circle1")
.attr("r", d => d.radius)
.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 + "Score: 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');
});

console.log(data)
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", d => `url(#image${d.id})`)
//.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 + "Score: 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 + "Score: 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('x', d => d.x)
.attr('y', d => d.y)
.style('fill', '#fff')
.attr("transform" , `translate(${-10}, ${6.5})`)
.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(d => d.radius))
.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(d => d.radius))
.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);
d3.select(".domain").style('stroke-opacity', '0')
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');

});
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
multiFormat = ["shortYear", "fullYear", "decade"]
Insert cell
xIntercept = 50
Insert cell
vOffset = 20
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
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