restructure menu & create breadcrumbs
This commit is contained in:
parent
14bae34193
commit
a0a66bcc65
3 changed files with 324 additions and 69 deletions
|
@ -41,6 +41,7 @@
|
||||||
</linearGradient>
|
</linearGradient>
|
||||||
<marker markerHeight="4" markerWidth="4" refY="0" refX="6" viewBox="0 -3 6 6" preserveAspectRatio="none" orient="auto" id="arrowHead" fill="#999"><path d="M0,-3L8,0L0,3"></path></marker>
|
<marker markerHeight="4" markerWidth="4" refY="0" refX="6" viewBox="0 -3 6 6" preserveAspectRatio="none" orient="auto" id="arrowHead" fill="#999"><path d="M0,-3L8,0L0,3"></path></marker>
|
||||||
<marker markerHeight="4" markerWidth="4" refY="0" refX="6" viewBox="0 -3 6 6" preserveAspectRatio="none" orient="auto" id="arrowHeadSelected"><path d="M0,-3L8,0L0,3" fill="white"></path></marker>
|
<marker markerHeight="4" markerWidth="4" refY="0" refX="6" viewBox="0 -3 6 6" preserveAspectRatio="none" orient="auto" id="arrowHeadSelected"><path d="M0,-3L8,0L0,3" fill="white"></path></marker>
|
||||||
|
<marker markerHeight="4" markerWidth="4" refY="0" refX="6" viewBox="0 -3 6 6" preserveAspectRatio="none" orient="auto" id="arrowHeadCrumbTrail"><path d="M0,-3L8,0L0,3" fill="yellow"></path></marker>
|
||||||
<clipPath id="clipNodeImage">
|
<clipPath id="clipNodeImage">
|
||||||
<circle cx="40" cy="40" r="40" />
|
<circle cx="40" cy="40" r="40" />
|
||||||
</clipPath>
|
</clipPath>
|
||||||
|
@ -54,9 +55,9 @@
|
||||||
</div>
|
</div>
|
||||||
</svg>
|
</svg>
|
||||||
<div id="graphControls">
|
<div id="graphControls">
|
||||||
<span class="typeJump">Show:</span>
|
<span class="typeJump">Types:</span>
|
||||||
<ul id='typeLinks'></ul>
|
<ul id='typeLinks'></ul>
|
||||||
<span class="showMoreTypeLinks">...</span>
|
<a id="showMoreTypeLinks"></a>
|
||||||
<ul id='moreTypeLinks'></ul>
|
<ul id='moreTypeLinks'></ul>
|
||||||
<!-- <ul id='relLinks'></ul> -->
|
<!-- <ul id='relLinks'></ul> -->
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -21,6 +21,12 @@ function getTitleAttribute(node) {
|
||||||
function getNodeTitle(node){
|
function getNodeTitle(node){
|
||||||
return node[getTitleAttribute(node)];
|
return node[getTitleAttribute(node)];
|
||||||
}
|
}
|
||||||
|
function getNodeYear(n){
|
||||||
|
if(typeof n['dateCreated'] !== 'undefined') {
|
||||||
|
return n['dateCreated'].substr(0,4);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
Transform a flattened jsonld into a d3 compatible graph
|
Transform a flattened jsonld into a d3 compatible graph
|
||||||
@param Object data flattened jsonld data
|
@param Object data flattened jsonld data
|
||||||
|
@ -81,9 +87,7 @@ function jsonLdToGraph(data){
|
||||||
var graph;
|
var graph;
|
||||||
// map nodes to their ID
|
// map nodes to their ID
|
||||||
var nodeMap = {};
|
var nodeMap = {};
|
||||||
// TODO: map node IDs to their linked node IDs
|
|
||||||
var linkMap = {};
|
var linkMap = {};
|
||||||
// TODO: use linkMap to create breadcrumbs per node
|
|
||||||
var breadcrumbs = {};
|
var breadcrumbs = {};
|
||||||
// load the flattened jsonld file
|
// load the flattened jsonld file
|
||||||
const requestPromise = fetch('/assets/js/rubenvandeven.jsonld')
|
const requestPromise = fetch('/assets/js/rubenvandeven.jsonld')
|
||||||
|
@ -133,20 +137,32 @@ function createLinkMap(graph) {
|
||||||
// TODO: make sure, 'shortest' path is favoured.
|
// TODO: make sure, 'shortest' path is favoured.
|
||||||
function createBreadcrumbs(linkMap, srcId) {
|
function createBreadcrumbs(linkMap, srcId) {
|
||||||
let crumbs = {};
|
let crumbs = {};
|
||||||
let path = [];
|
|
||||||
let collectLinks = function(srcId, path){
|
let createBreadcrumbLayer = function(srcId) {
|
||||||
if(typeof crumbs[srcId] !== 'undefined') {
|
let path = crumbs[srcId];
|
||||||
return;
|
let newPath = path.slice();
|
||||||
}
|
newPath.push(srcId);
|
||||||
crumbs[srcId] = path.slice();
|
|
||||||
path[path.length] = srcId;
|
let nextSrcIds = [];
|
||||||
let links = linkMap[srcId];
|
|
||||||
// collect links, append given list & skip srcId
|
for (let link of linkMap[srcId]) {
|
||||||
for(let link of links) {
|
if(typeof crumbs[link['id']] !== 'undefined') continue;
|
||||||
collectLinks(link['id'], path.slice());
|
crumbs[link['id']] = newPath;
|
||||||
|
nextSrcIds.push(link['id']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nextSrcIds;
|
||||||
|
}
|
||||||
|
crumbs[srcId] = [];
|
||||||
|
let nextIds = [srcId];
|
||||||
|
while(nextIds.length > 0) {
|
||||||
|
let newNextIds = [];
|
||||||
|
for (let nextId of nextIds) {
|
||||||
|
let r = createBreadcrumbLayer(nextId);
|
||||||
|
newNextIds = newNextIds.concat(r);
|
||||||
|
}
|
||||||
|
nextIds = newNextIds;
|
||||||
}
|
}
|
||||||
collectLinks(srcId, path);
|
|
||||||
return crumbs;
|
return crumbs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,25 +188,48 @@ for (let nodeIdx in graph['nodes']) {
|
||||||
if(typeof types[type] == 'undefined') {
|
if(typeof types[type] == 'undefined') {
|
||||||
types[type] = [];
|
types[type] = [];
|
||||||
}
|
}
|
||||||
types[type][types[type].length] = nodeIdx;
|
types[type].push(nodeIdx);
|
||||||
}
|
}
|
||||||
var graphControlsEl = document.getElementById('graphControls');
|
var graphControlsEl = document.getElementById('graphControls');
|
||||||
var typeLinksEl = document.getElementById('typeLinks');
|
var typeLinksEl = document.getElementById('typeLinks');
|
||||||
|
var showMoreTypeLinksEl = document.getElementById('showMoreTypeLinks');
|
||||||
var moreTypeLinksEl = document.getElementById('moreTypeLinks');
|
var moreTypeLinksEl = document.getElementById('moreTypeLinks');
|
||||||
var relLinksEl = document.getElementById('relLinks');
|
var relLinksEl = document.getElementById('relLinks');
|
||||||
|
|
||||||
|
// sort types by count:
|
||||||
|
var typeCounts = Object.keys(types).map(function(key) {
|
||||||
|
return [key, types[key].length];
|
||||||
|
});
|
||||||
|
typeCounts.sort(function(first, second) {
|
||||||
|
return second[1] - first[1];
|
||||||
|
});
|
||||||
|
|
||||||
// make controls
|
// make controls
|
||||||
let i = 0;
|
let i = 0;
|
||||||
for (let typeName in types) {
|
for (let typeCountIdx in typeCounts) {
|
||||||
|
let typeName = typeCounts[typeCountIdx][0];
|
||||||
let typeLinkEl = document.createElement("li");
|
let typeLinkEl = document.createElement("li");
|
||||||
let typeLinkAEl = document.createElement("a");
|
let typeLinkAEl = document.createElement("a");
|
||||||
let typeLinkCountEl = document.createElement("span");
|
let typeLinkCountEl = document.createElement("span");
|
||||||
typeLinkCountEl.innerHTML = types[typeName].length;
|
typeLinkCountEl.innerHTML = typeCounts[typeCountIdx][1];
|
||||||
|
typeLinkCountEl.classList.add('typeCount');
|
||||||
typeLinkAEl.innerHTML = typeName;
|
typeLinkAEl.innerHTML = typeName;
|
||||||
typeLinkAEl.addEventListener('click', function(){
|
typeLinkAEl.addEventListener('click', function(){
|
||||||
centerByType(typeName);
|
centerByType(typeName);
|
||||||
// positionNodesInCenter(types[typeName]);
|
// positionNodesInCenter(types[typeName]);
|
||||||
});
|
});
|
||||||
|
typeLinkAEl.addEventListener('mouseover', function() {
|
||||||
|
let typeNodeEls = document.getElementsByClassName(typeName);
|
||||||
|
for(let typeNodeEl of typeNodeEls) {
|
||||||
|
typeNodeEl.classList.add('typeHighlight');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
typeLinkAEl.addEventListener('mouseout', function() {
|
||||||
|
let typeNodeEls = document.getElementsByClassName(typeName);
|
||||||
|
for(let typeNodeEl of typeNodeEls) {
|
||||||
|
typeNodeEl.classList.remove('typeHighlight');
|
||||||
|
}
|
||||||
|
});
|
||||||
typeLinkEl.append(typeLinkAEl);
|
typeLinkEl.append(typeLinkAEl);
|
||||||
typeLinkEl.append(typeLinkCountEl);
|
typeLinkEl.append(typeLinkCountEl);
|
||||||
(i < 5 ? typeLinksEl: moreTypeLinksEl).appendChild(typeLinkEl);
|
(i < 5 ? typeLinksEl: moreTypeLinksEl).appendChild(typeLinkEl);
|
||||||
|
@ -198,6 +237,19 @@ for (let typeName in types) {
|
||||||
// typeLinksEl.appendChild(typeLinkEl);
|
// typeLinksEl.appendChild(typeLinkEl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
showMoreTypeLinksEl.addEventListener('click', function () {
|
||||||
|
console.log('showMore');
|
||||||
|
document.body.classList.add('showMoreLinks');
|
||||||
|
var hideMoreTypeLinks = function(e) {
|
||||||
|
console.log('removeMore');
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
document.body.removeEventListener('mouseup', hideMoreTypeLinks, true);
|
||||||
|
document.body.classList.remove('showMoreLinks');
|
||||||
|
}
|
||||||
|
document.body.addEventListener('mouseup', hideMoreTypeLinks, true);
|
||||||
|
}, false)
|
||||||
|
|
||||||
|
|
||||||
// make svg
|
// make svg
|
||||||
var svg = d3.select("svg"),
|
var svg = d3.select("svg"),
|
||||||
|
@ -247,9 +299,7 @@ var getViewbox = function() {
|
||||||
return svg.attr("viewBox").split(" ").map(parseFloat);
|
return svg.attr("viewBox").split(" ").map(parseFloat);
|
||||||
}
|
}
|
||||||
var positionNodesInCenter = function(idxs) {
|
var positionNodesInCenter = function(idxs) {
|
||||||
let viewBox = getViewbox();
|
setViewboxForceCenter(); // sets forceCx & forceCy
|
||||||
let cx = viewBox[0] + viewBox[2]/2;
|
|
||||||
let cy = viewBox[1] + viewBox[3]/2;
|
|
||||||
|
|
||||||
if(typeof idxs == "object" && idxs !== null && idxs.length == 1) {
|
if(typeof idxs == "object" && idxs !== null && idxs.length == 1) {
|
||||||
idxs = idxs[0];
|
idxs = idxs[0];
|
||||||
|
@ -279,8 +329,8 @@ var positionNodesInCenter = function(idxs) {
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
nodePositions[idxs] = [
|
nodePositions[idxs] = [
|
||||||
cx,
|
forceCx,
|
||||||
cy
|
forceCy
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -300,6 +350,7 @@ var positionNodesInCenter = function(idxs) {
|
||||||
}
|
}
|
||||||
var positionNodesInCircle = function(idxs, r) {
|
var positionNodesInCircle = function(idxs, r) {
|
||||||
let viewBox = getViewbox();
|
let viewBox = getViewbox();
|
||||||
|
setViewboxForceCenter(); // sets forceCx & forceCy
|
||||||
if(typeof r == 'undefined') {
|
if(typeof r == 'undefined') {
|
||||||
if(idxs.length == 1) {
|
if(idxs.length == 1) {
|
||||||
r = viewBox[2] / 6;
|
r = viewBox[2] / 6;
|
||||||
|
@ -308,14 +359,14 @@ var positionNodesInCircle = function(idxs, r) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
currentNodePositionRadius = r;
|
currentNodePositionRadius = r;
|
||||||
let cx = viewBox[0] + viewBox[2]/2;
|
let forceCx = viewBox[0] + viewBox[2]/2;
|
||||||
let cy = viewBox[1] + viewBox[3]/2;
|
let forceCy = viewBox[1] + viewBox[3]/2;
|
||||||
|
|
||||||
let stepSize = 2*Math.PI / idxs.length;
|
let stepSize = 2*Math.PI / idxs.length;
|
||||||
for (var i = 0; i < idxs.length; i++) {
|
for (var i = 0; i < idxs.length; i++) {
|
||||||
nodePositions[idxs[i]] = [
|
nodePositions[idxs[i]] = [
|
||||||
cx + Math.sin(stepSize * i) * r,
|
forceCx + Math.sin(stepSize * i) * r,
|
||||||
cy + Math.cos(stepSize * i) * r
|
forceCy + Math.cos(stepSize * i) * r
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -348,7 +399,11 @@ var createRelationshipEl = function(relNode, i) {
|
||||||
let el = document.createElement("dd");
|
let el = document.createElement("dd");
|
||||||
el.classList.add('relLink');
|
el.classList.add('relLink');
|
||||||
let titleEl = document.createElement('a');
|
let titleEl = document.createElement('a');
|
||||||
titleEl.innerHTML = getNodeTitle(relNode);
|
titleEl.innerHTML = getNodeTitle(relNode)
|
||||||
|
let year = getNodeYear(relNode);
|
||||||
|
if(year !== null) {
|
||||||
|
titleEl.innerHTML += `<span class='nodeYear'>${getNodeYear(relNode)}</span>`;
|
||||||
|
}
|
||||||
titleEl.classList.add('nodeTitle');
|
titleEl.classList.add('nodeTitle');
|
||||||
titleEl.classList.add('nodeTitleNr'+i);
|
titleEl.classList.add('nodeTitleNr'+i);
|
||||||
titleEl.addEventListener('click',function(e){
|
titleEl.addEventListener('click',function(e){
|
||||||
|
@ -376,10 +431,39 @@ var setDetails = function(nodeDatum, nodeIdx) {
|
||||||
// TODO: replace relUp & relDown with linkMap
|
// TODO: replace relUp & relDown with linkMap
|
||||||
let relUp = [];
|
let relUp = [];
|
||||||
let relDown = [];
|
let relDown = [];
|
||||||
let breadcrumbsEl = document.createElement('div');
|
let nodeDetailScalerEl = document.createElement('div');
|
||||||
|
// nodeDetailScalerEl.innerHTML = `<div id='scalarbar'></div>`;
|
||||||
|
nodeDetailScalerEl.id = 'nodeDetailsScaler';
|
||||||
|
nodeDetailScalerEl.addEventListener('mousedown', function(e){
|
||||||
|
// console.log('go');
|
||||||
|
let drag = function(e) {
|
||||||
|
// 5px for padding
|
||||||
|
nodeDetailEl.style.width = (window.innerWidth - e.clientX + 5) +'px';
|
||||||
|
}
|
||||||
|
document.body.addEventListener('mousemove', drag);
|
||||||
|
document.body.addEventListener('mouseup', function(){
|
||||||
|
document.body.removeEventListener('mousemove', drag);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
nodeDetails.appendChild(nodeDetailScalerEl);
|
||||||
|
|
||||||
|
let breadcrumbsEl = document.createElement('ul');
|
||||||
breadcrumbsEl.classList.add('breadcrumbs');
|
breadcrumbsEl.classList.add('breadcrumbs');
|
||||||
for(let crumbNodeId of breadcrumbs[nodeDatum['id']]) {
|
for(let crumbNodeId of breadcrumbs[nodeDatum['id']]) {
|
||||||
breadcrumbsEl.innerHTML += ` <span class='crumb'>${getNodeTitle(nodeMap[crumbNodeId])}</span>`;
|
let crumbWrapEl = document.createElement('li');
|
||||||
|
let crumbEl = document.createElement('span');
|
||||||
|
crumbEl.classList.add('crumb');
|
||||||
|
crumbEl.addEventListener('click', function(e){
|
||||||
|
let idx = graph.nodes.indexOf(nodeMap[crumbNodeId]);
|
||||||
|
selectNode(idx);
|
||||||
|
});
|
||||||
|
crumbEl.innerHTML = `${getNodeTitle(nodeMap[crumbNodeId])}`;
|
||||||
|
let nodeYear = getNodeYear(nodeMap[crumbNodeId]);
|
||||||
|
if(nodeYear !== null) {
|
||||||
|
crumbEl.innerHTML += `<span class='nodeYear'>${nodeYear}</span>`;
|
||||||
|
}
|
||||||
|
crumbWrapEl.appendChild(crumbEl);
|
||||||
|
breadcrumbsEl.appendChild(crumbWrapEl);
|
||||||
}
|
}
|
||||||
nodeDetailEl.appendChild(breadcrumbsEl);
|
nodeDetailEl.appendChild(breadcrumbsEl);
|
||||||
|
|
||||||
|
@ -398,10 +482,15 @@ var setDetails = function(nodeDatum, nodeIdx) {
|
||||||
|
|
||||||
let listEl = document.createElement("dl");
|
let listEl = document.createElement("dl");
|
||||||
// listEl.innerHTML += `<dt>type</dt><dd>${nodeDatum['type']}</dd>`;
|
// listEl.innerHTML += `<dt>type</dt><dd>${nodeDatum['type']}</dd>`;
|
||||||
|
|
||||||
|
let skipNodeAttributes = [
|
||||||
|
'id','x','y','index','type','vy','vx','fx','fy','leftX','rightX'
|
||||||
|
];
|
||||||
|
if(titleAttr !== 'contentUrl') {
|
||||||
|
skipNodeAttributes[skipNodeAttributes.length] = titleAttr;
|
||||||
|
}
|
||||||
for (let attr in nodeDatum) {
|
for (let attr in nodeDatum) {
|
||||||
if([
|
if(skipNodeAttributes.indexOf(attr) != -1) {
|
||||||
'id','x','y','index','type','vy','vx','fx','fy','leftX','rightX', titleAttr
|
|
||||||
].indexOf(attr) != -1) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -417,6 +506,7 @@ var setDetails = function(nodeDatum, nodeIdx) {
|
||||||
if(attr == 'url') {
|
if(attr == 'url') {
|
||||||
listEl.innerHTML += `<dt class='dt-${attr}'>${attr}</dt><dd class='dd-${attr}'><a href='${nodeAttr[i]}'>${nodeAttr[i]}</a></dd>`;
|
listEl.innerHTML += `<dt class='dt-${attr}'>${attr}</dt><dd class='dd-${attr}'><a href='${nodeAttr[i]}'>${nodeAttr[i]}</a></dd>`;
|
||||||
} else if(attr == 'contentUrl') {
|
} else if(attr == 'contentUrl') {
|
||||||
|
console.log('test', attr);
|
||||||
listEl.innerHTML += `<dt class='dt-${attr}'>${attr}</dt><dd class='dd-${attr}'><a href='${nodeAttr[i]}'>${nodeAttr[i]}</a></dd>`;
|
listEl.innerHTML += `<dt class='dt-${attr}'>${attr}</dt><dd class='dd-${attr}'><a href='${nodeAttr[i]}'>${nodeAttr[i]}</a></dd>`;
|
||||||
listEl.innerHTML += `<dd class='dd-contentobject'><object data='${nodeAttr[i]}'></object></dd>`;
|
listEl.innerHTML += `<dd class='dd-contentobject'><object data='${nodeAttr[i]}'></object></dd>`;
|
||||||
} else {
|
} else {
|
||||||
|
@ -545,7 +635,7 @@ var selectNode = function(idx){
|
||||||
let posTrg = currentCrumbs.indexOf(d.target['id']);
|
let posTrg = currentCrumbs.indexOf(d.target['id']);
|
||||||
if(posSrc > -1 && posTrg > -1 && Math.abs(posSrc - posTrg) == 1) {
|
if(posSrc > -1 && posTrg > -1 && Math.abs(posSrc - posTrg) == 1) {
|
||||||
linkEls[idx].classList.add('breadcrumbLink');
|
linkEls[idx].classList.add('breadcrumbLink');
|
||||||
// linkEls[idx].getElementsByTagName("line")[0].setAttribute("marker-end", "url(#arrowHeadSelected)");
|
linkEls[idx].getElementsByTagName("line")[0].setAttribute("marker-end", "url(#arrowHeadCrumbTrail)");
|
||||||
} else {
|
} else {
|
||||||
linkEls[idx].classList.remove('breadcrumbLink');
|
linkEls[idx].classList.remove('breadcrumbLink');
|
||||||
}
|
}
|
||||||
|
@ -570,9 +660,18 @@ var deselectNode = function() {
|
||||||
closeDetails();
|
closeDetails();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var forceCx, forceCy;
|
||||||
|
var setViewboxForceCenter = function() {
|
||||||
|
let viewBox = getViewbox();
|
||||||
|
forceCx = viewBox[0] + viewBox[2]/2;
|
||||||
|
forceCy = viewBox[1] + viewBox[3]/2;
|
||||||
|
}
|
||||||
|
setViewboxForceCenter(); // sets forceCx & forceCy
|
||||||
|
|
||||||
simulation.force('centerActive', function force(alpha) {
|
simulation.force('centerActive', function force(alpha) {
|
||||||
// let currentNode = node.selectAll('.detail');
|
// let currentNode = node.selectAll('.detail');
|
||||||
// console.log(currentNode);
|
// console.log(currentNode);
|
||||||
|
// console.log(forceCx, forceCy);
|
||||||
node.each(function(d, idx, nodes){
|
node.each(function(d, idx, nodes){
|
||||||
let n = d;
|
let n = d;
|
||||||
let k = alpha * 0.1;
|
let k = alpha * 0.1;
|
||||||
|
@ -585,12 +684,10 @@ simulation.force('centerActive', function force(alpha) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let viewBox = getViewbox();
|
|
||||||
let cx = viewBox[0] + viewBox[2]/2;
|
|
||||||
let cy = viewBox[1] + viewBox[3]/2;
|
|
||||||
|
|
||||||
let dx = n.x - cx;
|
|
||||||
let dy = n.y - cy;
|
let dx = n.x - forceCx;
|
||||||
|
let dy = n.y - forceCy;
|
||||||
if(!inCircle(dx, dy, currentNodePositionRadius)) {
|
if(!inCircle(dx, dy, currentNodePositionRadius)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -656,9 +753,33 @@ node.append('circle')
|
||||||
;
|
;
|
||||||
|
|
||||||
node.append('text')
|
node.append('text')
|
||||||
.append("textPath")
|
.attr("class", "nodeType")
|
||||||
.attr( "xlink:href",function(d, idx){return '#nodePath'+idx;})
|
.text(function(n){
|
||||||
.text(getNodeTitle);
|
return n['type'];
|
||||||
|
})
|
||||||
|
|
||||||
|
node.append('text')
|
||||||
|
.attr("class", "nodeYear")
|
||||||
|
.attr("y", "22")
|
||||||
|
.text(function(n){
|
||||||
|
return getNodeYear(n);
|
||||||
|
})
|
||||||
|
;
|
||||||
|
node.append('text')
|
||||||
|
.attr("class", "nodeTitle")
|
||||||
|
.attr("y", "5")
|
||||||
|
// .append("textPath")
|
||||||
|
// .attr( "xlink:href",function(d, idx){return '#nodePath'+idx;})
|
||||||
|
.text(getNodeTitle)
|
||||||
|
.each(function(){
|
||||||
|
let self = d3.select(this),
|
||||||
|
textLength = self.node().getComputedTextLength()
|
||||||
|
;
|
||||||
|
if(textLength > nodeSize * 2) {
|
||||||
|
self.attr('transform', `scale(${(nodeSize * 2) / textLength})`);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
;
|
||||||
|
|
||||||
node.each(function(d) {
|
node.each(function(d) {
|
||||||
if(!d.contentUrl) {
|
if(!d.contentUrl) {
|
||||||
|
@ -685,12 +806,12 @@ simulation.force("link")
|
||||||
.links(graph.links)
|
.links(graph.links)
|
||||||
.distance(function(l){
|
.distance(function(l){
|
||||||
switch (l.name) {
|
switch (l.name) {
|
||||||
case 'publishedAt':
|
// case 'publishedAt':
|
||||||
return 400;
|
// return 200;
|
||||||
case 'image':
|
// case 'image':
|
||||||
return 100;
|
// return 200;
|
||||||
default:
|
default:
|
||||||
return 200;
|
return 300;
|
||||||
}
|
}
|
||||||
}) // distance between the nodes / link length
|
}) // distance between the nodes / link length
|
||||||
// .charge(-100)
|
// .charge(-100)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
$detailsPadding: 20px;
|
$detailsPadding: 20px;
|
||||||
$detailsWidth: 700px;
|
$detailsWidth: 740px;
|
||||||
$detailSlide: -1 * ($detailsWidth + 2 * $detailsPadding);
|
$detailSlide: -1 * ($detailsWidth);
|
||||||
$detailSlideMobile: -30vh;
|
$detailSlideMobile: -30vh;
|
||||||
|
|
||||||
|
|
||||||
|
@ -64,17 +64,41 @@ g.node{
|
||||||
stroke-dasharray: 3 2;
|
stroke-dasharray: 3 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover .highlightCircle{
|
&.typeHighlight {
|
||||||
stroke-width: 1px;
|
.highlightCircle{
|
||||||
stroke: yellow;
|
stroke-width: 1px;
|
||||||
|
stroke: yellow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover{
|
||||||
|
.highlightCircle{
|
||||||
|
stroke-width: 1px;
|
||||||
|
stroke: yellow;
|
||||||
|
}
|
||||||
|
.nodeBg{
|
||||||
|
fill: yellow;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.drag{
|
&.drag{
|
||||||
cursor: grabbing;
|
cursor: grabbing;
|
||||||
}
|
}
|
||||||
|
|
||||||
text{
|
text.nodeType{
|
||||||
text-anchor: start;
|
text-anchor: middle;
|
||||||
|
font-size: 10pt;
|
||||||
|
display:none;
|
||||||
|
}
|
||||||
|
|
||||||
|
text.nodeYear{
|
||||||
|
transition: transform .5s;
|
||||||
|
text-anchor: middle;
|
||||||
|
font-size: 8pt;
|
||||||
|
}
|
||||||
|
text.nodeTitle{
|
||||||
|
text-anchor: middle;
|
||||||
|
// text-anchor: start;
|
||||||
font-family: "CMU Bright", sans-serif;
|
font-family: "CMU Bright", sans-serif;
|
||||||
font-size: 10pt;
|
font-size: 10pt;
|
||||||
}
|
}
|
||||||
|
@ -183,6 +207,24 @@ text{
|
||||||
transition: opacity 1s, right 1s;
|
transition: opacity 1s, right 1s;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
box-sizing: border-box; // Because of the scaler: we can just set width now
|
||||||
|
|
||||||
|
#nodeDetailsScaler{
|
||||||
|
position:absolute;
|
||||||
|
top:0;
|
||||||
|
left:0;
|
||||||
|
bottom:0;
|
||||||
|
width: 20px;
|
||||||
|
cursor: col-resize;
|
||||||
|
// background: #ccc;
|
||||||
|
padding: 5px;
|
||||||
|
#scalarbar{
|
||||||
|
height:100%;
|
||||||
|
border-right:solid 1px black;
|
||||||
|
border-left:solid 1px #333;
|
||||||
|
width:0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.nodeTitle{
|
.nodeTitle{
|
||||||
|
|
||||||
|
@ -199,10 +241,55 @@ text{
|
||||||
color:blue;
|
color:blue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ul.breadcrumbs{
|
||||||
|
list-style: none;
|
||||||
|
margin:0;
|
||||||
|
padding: 0;
|
||||||
|
li{
|
||||||
|
display:inline-block;
|
||||||
|
&:not(:first-child)::before{
|
||||||
|
content: "::";
|
||||||
|
color: black;
|
||||||
|
text-decoration: none;
|
||||||
|
margin: 0 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.crumb{
|
||||||
|
cursor: pointer;
|
||||||
|
color: blue;
|
||||||
|
&:hover{
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
span.nodeYear{
|
||||||
|
margin-left:15px;
|
||||||
|
|
||||||
|
&::before{
|
||||||
|
content:'(';
|
||||||
|
}
|
||||||
|
&::after{
|
||||||
|
content:')';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
h4{
|
||||||
|
border-top: solid 1px black;
|
||||||
|
padding-top: 40px;
|
||||||
|
font-size: 120%;
|
||||||
|
}
|
||||||
|
|
||||||
dt{
|
dt{
|
||||||
float:left;
|
float:left;
|
||||||
width: 120px;
|
width: 120px;
|
||||||
font-weight:bold;
|
font-weight:bold;
|
||||||
|
min-height:25px;
|
||||||
|
}
|
||||||
|
dd{
|
||||||
|
min-height:25px;
|
||||||
}
|
}
|
||||||
dd:not(.nodeTitleNr1) {
|
dd:not(.nodeTitleNr1) {
|
||||||
margin-left: 130px;
|
margin-left: 130px;
|
||||||
|
@ -244,21 +331,67 @@ svg#portfolioGraph {
|
||||||
height: auto;
|
height: auto;
|
||||||
background: white;
|
background: white;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
|
|
||||||
|
.typeCount::before{
|
||||||
|
content: "(";
|
||||||
|
padding-left: 5px;
|
||||||
|
}
|
||||||
|
.typeCount::after{
|
||||||
|
content: ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
ul#typeLinks{
|
||||||
|
margin:0;
|
||||||
|
padding: 0;
|
||||||
|
display:inline-block;
|
||||||
|
|
||||||
|
li{
|
||||||
|
list-style:none;
|
||||||
|
display: inline-block;
|
||||||
|
margin: 10px 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#showMoreTypeLinks{
|
||||||
|
display:inline-block;
|
||||||
|
width:20px;
|
||||||
|
text-align: right;
|
||||||
|
cursor: pointer;
|
||||||
|
&::before{
|
||||||
|
content:"...";
|
||||||
|
}
|
||||||
|
&:hover{
|
||||||
|
text-decoration:unline;
|
||||||
|
}
|
||||||
|
.showMoreLinks & {
|
||||||
|
pointer-events:none;
|
||||||
|
&::before{
|
||||||
|
content:"x";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#moreTypeLinks {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
background: white;
|
||||||
|
list-style: none;
|
||||||
|
padding: 20px 30px;
|
||||||
|
text-align: left;
|
||||||
|
margin: 0;
|
||||||
|
display:none;
|
||||||
|
.showMoreLinks & {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.typeJump{
|
||||||
|
font-weight:bold;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#graphControls .typeJump{
|
|
||||||
font-weight:bold;
|
|
||||||
}
|
|
||||||
#graphControls ul{
|
|
||||||
margin:0;
|
|
||||||
padding: 0;
|
|
||||||
display:inline-block;
|
|
||||||
}
|
|
||||||
#graphControls li{
|
|
||||||
list-style:none;
|
|
||||||
display: inline-block;
|
|
||||||
margin: 10px 10px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 1000px) {
|
@media (max-width: 1000px) {
|
||||||
body{
|
body{
|
||||||
|
|
Loading…
Reference in a new issue