New styling WIP, with square images
This commit is contained in:
parent
e1072f9899
commit
b21c467c54
6 changed files with 272 additions and 19464 deletions
21
gulpfile.js
21
gulpfile.js
|
@ -6,6 +6,10 @@ var rename = require('gulp-rename');
|
|||
var uglify = require('gulp-uglify');
|
||||
var sourcemaps = require('gulp-sourcemaps');
|
||||
var browserSync = require('browser-sync');
|
||||
var jsonld = require('jsonld');
|
||||
|
||||
|
||||
var through = require('through2')
|
||||
// todo: rollup for d3 & possibly jsonld
|
||||
|
||||
var paths = {
|
||||
|
@ -19,7 +23,7 @@ var paths = {
|
|||
},
|
||||
"data": {
|
||||
"src": "./rubenvandeven.jsonld",
|
||||
"dest": "./assets/rubenvandeven.jsonld"
|
||||
"dest": "./assets/js/"
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -47,9 +51,24 @@ gulp.task('scripts', function() {
|
|||
.pipe(gulp.dest(paths.scripts.dest)) // save .min.js
|
||||
});
|
||||
|
||||
gulp.task('jsonld', function(){
|
||||
return gulp.src(paths.data.src)
|
||||
.pipe(through.obj(function (file, enc, callback) {
|
||||
let data = JSON.parse(file.contents.toString(enc));
|
||||
var transformedFile = file.clone();
|
||||
// console.log(data);
|
||||
jsonld.flatten(data, {"@context": "https://schema.org/"}, (err, flattened)=> {
|
||||
transformedFile.contents = Buffer.from(JSON.stringify(flattened), enc);
|
||||
callback(null, transformedFile)
|
||||
});
|
||||
}))
|
||||
.pipe(gulp.dest(paths.data.dest));
|
||||
});
|
||||
|
||||
var watchStylesAndScripts = function() {
|
||||
gulp.watch(paths.styles.src,['styles']);
|
||||
gulp.watch(paths.scripts.src,['scripts', browserSync.reload]);
|
||||
gulp.watch([paths.data.src], ['jsonld', browserSync.reload]);
|
||||
}
|
||||
|
||||
gulp.task('watch', watchStylesAndScripts);
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<html xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<head>
|
||||
<title></title>
|
||||
<link href="rubenvandeven.jsonld" rel="alternate" type="application/ld+json" />
|
||||
<link href="/rubenvandeven.jsonld" rel="alternate" type="application/ld+json" />
|
||||
<link rel="stylesheet" href="/assets/css/portfolio.css">
|
||||
</head>
|
||||
<body>
|
||||
|
@ -44,6 +44,10 @@
|
|||
<clipPath id="clipNodeImage">
|
||||
<circle cx="40" cy="40" r="40" />
|
||||
</clipPath>
|
||||
|
||||
<pattern id="img1" patternUnits="userSpaceOnUse" width="100" height="100">
|
||||
<image xlink:href="testback.png" x="0" y="0" width="100" height="100" />
|
||||
</pattern>
|
||||
</defs>
|
||||
</svg>
|
||||
<div id="nodeDetails">
|
||||
|
@ -52,6 +56,8 @@
|
|||
<div id="graphControls">
|
||||
<span class="typeJump">Show:</span>
|
||||
<ul id='typeLinks'></ul>
|
||||
<span class="showMoreTypeLinks">...</span>
|
||||
<ul id='moreTypeLinks'></ul>
|
||||
<!-- <ul id='relLinks'></ul> -->
|
||||
</div>
|
||||
<!-- <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/jsonld@0.5.21/dist/jsonld.js"></script> -->
|
||||
|
|
|
@ -4,11 +4,25 @@
|
|||
"url": "https://rubenvandeven.com",
|
||||
"author":
|
||||
{
|
||||
"@id": "https://rubenvandeven.com/ruben",
|
||||
"@type": "Person",
|
||||
"name": "Ruben van de Ven",
|
||||
"email": "info@rubenvandeven.com",
|
||||
"nationality": "The Netherlands",
|
||||
"jobTitle": "digital artist / researcher of software culture",
|
||||
"@reverse": {
|
||||
"member": [
|
||||
{
|
||||
"@id": "http://plottingd.at/a",
|
||||
"@type": "PerformingGroup",
|
||||
"name": "PlottingD.at/a",
|
||||
"url": "http://plottingd.at/a",
|
||||
"description": "A collaboration between Ruben van de Ven and Cristina Cochior.",
|
||||
"member": [
|
||||
{"@id": "http://randomizer.info"}
|
||||
]
|
||||
}
|
||||
],
|
||||
"author": [
|
||||
{
|
||||
"@type": "MediaObject",
|
||||
|
@ -56,7 +70,7 @@
|
|||
"@reverse": {
|
||||
"workFeatured": [
|
||||
{
|
||||
"@id": "kick2018exhibit",
|
||||
"@id": "https://rubenvandeven.com/#kick2018exhibit",
|
||||
"@type": "ExhibitionEvent",
|
||||
"name": "KickstART",
|
||||
"location": {
|
||||
|
@ -68,7 +82,7 @@
|
|||
"endDate": "2018-03-28"
|
||||
},
|
||||
{
|
||||
"@id": "in4artSalon",
|
||||
"@id": "https://rubenvandeven.com/#in4artSalon",
|
||||
"@type": "ExhibitionEvent",
|
||||
"name": "Salon VI - Innovatism",
|
||||
"location": {
|
||||
|
@ -92,7 +106,7 @@
|
|||
"@reverse": {
|
||||
"workFeatured":
|
||||
{
|
||||
"@id": "kick2018exhibit"
|
||||
"@id": "https://rubenvandeven.com/#kick2018exhibit"
|
||||
}
|
||||
},
|
||||
"image": [
|
||||
|
@ -106,7 +120,7 @@
|
|||
"@reverse": {
|
||||
"workFeatured":
|
||||
{
|
||||
"@id": "kick2018exhibit"
|
||||
"@id": "https://rubenvandeven.com/#kick2018exhibit"
|
||||
}
|
||||
},
|
||||
"image": [
|
||||
|
@ -126,7 +140,7 @@
|
|||
"name": "The Black Box Concern",
|
||||
"url": "....",
|
||||
"location": {
|
||||
"@id": "v2_"
|
||||
"@id": "https://rubenvandeven.com/#v2_"
|
||||
},
|
||||
"startDate": "2017-12",
|
||||
"workFeatured": []
|
||||
|
@ -140,7 +154,7 @@
|
|||
{
|
||||
"@type": "MediaObject",
|
||||
"name": "Emotion Hero",
|
||||
"description": "Emotion recognition software is being used both as a tool for \u2018objective\u2019 measurements as well as a tool for training one\u2019s facial expressions, eg. for job interviews. Emotion Hero is a literal translation of the paradoxical relation between these applications of the technology.\n\nEmotion Hero is a two-part artwork. On the one hand is a video-game that is freely downloadable for everybody with an Android device (see <a href=\"https://play.google.com\/store\/apps\/details?id=com.rubenvandeven.emotion_hero\">Google Play<\/a>). Inspired by Guitar Hero, the user scores points by following given cues. It provides detailed feedback on the mechanics of the face (eg. \u201cYou showed on 10% Joy when you had to show 100%, smile 99.32% more.\u201d), revealing that rather than being a window into the brain, the face is a controllable surface.\n\nThe second part is a projection that shows the aggregated scores of the game. In order to substantiate their discourse, companies in facial expression measurement employ a huge amount of data collection and processing. The results are displayed in a fixed grid, recalling historical practices that, trough extensive measurement and administration, also aimed to delineate something which is conceptually undelineated: think of Duchenne de Boulogne, Lombroso, and Charcot.\n\nEmotion Hero is a playful invitation to open up the box of expression analysis to reveal the assumptions that underlie this technology.\n\nThe game's emotional intelligence is powered by Affectiva (I was also <a href=\"http://blog.affectiva.com\/sdk-on-the-spot-emotion-hero-app-encourages-play-with-facial-expressions\">interviewed<\/a> by them). This project is produced as part of the <a href=\"http://summersessions.net\/17-projects\/projects-2016\/55-emotion-hero\">Summer Sessions Network for Talent Development<\/a> in a co-production of Arquivo 237 and V2_ Lab for the Unstable Media, with support of the Creative Industries Fund NL.\nIt has been exhibited at the <a href=\"http://www.statefestival.org\/2016\/program-entry\/2016\/emotion-hero-2016\">State Festival 2016<\/a> (Berlin, DE) and Digital <Dis>orders (Frankfurt, DE).",
|
||||
"description": "Emotion recognition software is being used both as a tool for \u2018objective\u2019 measurements as well as a tool for training one\u2019s facial expressions, eg. for job interviews. Emotion Hero is a literal translation of the paradoxical relation between these applications of the technology.\n\nEmotion Hero is a two-part artwork. On the one hand is a video-game that is freely downloadable for everybody with an Android device (see <a href=\"https://play.google.com\/store\/apps\/details?id=com.rubenvandeven.emotion_hero\">Google Play<\/a>). Inspired by Guitar Hero, the user scores points by following given cues. It provides detailed feedback on the mechanics of the face (eg. \u201cYou showed on 10% Joy when you had to show 100%, smile 99.32% more.\u201d), revealing that rather than being a window into the brain, the face is a controllable surface.\n\nThe second part is a projection that shows the aggregated scores of the game. In order to substantiate their discourse, companies in facial expression measurement employ a huge amount of data collection and processing. The results are displayed in a fixed grid, recalling historical practices that, trough extensive measurement and administration, also aimed to delineate something which is conceptually undelineated: think of Duchenne de Boulogne, Lombroso, and Charcot.\n\nEmotion Hero is a playful invitation to open up the box of expression analysis to reveal the assumptions that underlie this technology.\nThe game's emotional intelligence is powered by Affectiva (I was also <a href=\"http://blog.affectiva.com\/sdk-on-the-spot-emotion-hero-app-encourages-play-with-facial-expressions\">interviewed<\/a> by them). This project is produced as part of the <a href=\"http://summersessions.net\/17-projects\/projects-2016\/55-emotion-hero\">Summer Sessions Network for Talent Development<\/a> in a co-production of Arquivo 237 and V2_ Lab for the Unstable Media, with support of the Creative Industries Fund NL.\nIt has been exhibited at the <a href=\"http://www.statefestival.org\/2016\/program-entry\/2016\/emotion-hero-2016\">State Festival 2016<\/a> (Berlin, DE) and Digital <Dis>orders (Frankfurt, DE).",
|
||||
"url": "https://emotionhero.com",
|
||||
"@reverse": {
|
||||
"workFeatured": [
|
||||
|
@ -190,7 +204,7 @@
|
|||
},
|
||||
"startDate": "2017-09",
|
||||
"endDate": "2017-09",
|
||||
"organiser": { "@id":"v2_" },
|
||||
"organiser": { "@id":"vhttps://rubenvandeven.com/#2_" },
|
||||
"funded": "Creative Industries Fund",
|
||||
"workFeatured": []
|
||||
},
|
||||
|
@ -209,7 +223,7 @@
|
|||
"workFeatured": []
|
||||
},
|
||||
{
|
||||
"@id": "codesandmodes",
|
||||
"@id": "https://rubenvandeven.com/#codesandmodes",
|
||||
"@type": "ExhibitionEvent",
|
||||
"name": "Codes & Modes II",
|
||||
"organiser": "Integrated Media Arts MFA",
|
||||
|
@ -223,7 +237,7 @@
|
|||
"workFeatured": []
|
||||
},
|
||||
{
|
||||
"@id": "stateofemotion",
|
||||
"@id": "https://rubenvandeven.com/#stateofemotion",
|
||||
"@type": "ExhibitionEvent",
|
||||
"name": "STATE of Emotion",
|
||||
"location": {
|
||||
|
@ -293,7 +307,7 @@
|
|||
"name": "Test_Lab the Graduation Edition",
|
||||
"url": "...",
|
||||
"location": {
|
||||
"@id": "v2_",
|
||||
"@id": "https://rubenvandeven.com/#v2_",
|
||||
"@type": "Place",
|
||||
"name": "V2_",
|
||||
"address": "Rotterdam"
|
||||
|
@ -334,6 +348,7 @@
|
|||
"dateCreated": "2016",
|
||||
"description": "...",
|
||||
"author": {
|
||||
"@id": "http://randomizer.info",
|
||||
"@type": "Person",
|
||||
"name": "Cristina Cochior",
|
||||
"url": "http://randomizer.info"
|
||||
|
@ -412,10 +427,10 @@
|
|||
"@reverse": {
|
||||
"workFeatured": [
|
||||
{
|
||||
"@id": "codesandmodes"
|
||||
"@id": "https://rubenvandeven.com/#codesandmodes"
|
||||
},
|
||||
{
|
||||
"@id": "stateofemotion"
|
||||
"@id": "https://rubenvandeven.com/#stateofemotion"
|
||||
},
|
||||
{
|
||||
"@type": "ExhibitionEvent",
|
||||
|
@ -424,7 +439,7 @@
|
|||
"startDate": "2015-06",
|
||||
"endDate": "2015-06",
|
||||
"location": {
|
||||
"@id": "v2_"
|
||||
"@id": "https://rubenvandeven.com/#v2_"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
19306
src/js/jsonld.js
19306
src/js/jsonld.js
File diff suppressed because it is too large
Load diff
|
@ -79,19 +79,23 @@ function jsonLdToGraph(data){
|
|||
}
|
||||
|
||||
var graph;
|
||||
// map nodes to their ID
|
||||
var nodeMap = {};
|
||||
jsonld.flatten(window.location.protocol + "//" + window.location.host + "/rubenvandeven.jsonld", {"@context": "https://schema.org/"},(err, flattened)=> {
|
||||
console.log(err);
|
||||
data = flattened;
|
||||
graph = jsonLdToGraph(flattened['@graph']);
|
||||
// create a map of nodes by id.
|
||||
for(let i in graph.nodes) {
|
||||
nodeMap[graph.nodes[i]['id']] = graph.nodes[i];
|
||||
}
|
||||
// console.log(graph);
|
||||
startGraph(graph);
|
||||
});
|
||||
|
||||
// TODO: map node IDs to their linked node IDs
|
||||
var linkMap = {};
|
||||
// TODO: use linkMap to create breadcrumbs per node
|
||||
var breadcrumbs = {};
|
||||
// load the flattened jsonld file
|
||||
const requestPromise = fetch('/assets/js/rubenvandeven.jsonld')
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
graph = jsonLdToGraph(data['@graph']);
|
||||
// create a map of nodes by id.
|
||||
for(let i in graph.nodes) {
|
||||
nodeMap[graph.nodes[i]['id']] = graph.nodes[i];
|
||||
}
|
||||
startGraph(graph);
|
||||
});
|
||||
|
||||
function inCircle(dx, dy, r) {
|
||||
// fastest check if in circle: https://stackoverflow.com/a/7227057
|
||||
|
@ -109,6 +113,43 @@ function inCircle(dx, dy, r) {
|
|||
}
|
||||
}
|
||||
|
||||
function createLinkMap(graph) {
|
||||
let linkMap = {};
|
||||
for(let link of graph['links']){
|
||||
if(typeof linkMap[link['source']] == 'undefined') {
|
||||
linkMap[link['source']] = [];
|
||||
}
|
||||
linkMap[link['source']][linkMap[link['source']].length] = {'id': link['target'], 'name': link['name']};
|
||||
|
||||
|
||||
if(typeof linkMap[link['target']] == 'undefined') {
|
||||
linkMap[link['target']] = [];
|
||||
}
|
||||
linkMap[link['target']][linkMap[link['target']].length] = {'id': link['source'], 'name': link['name']};
|
||||
}
|
||||
return linkMap;
|
||||
}
|
||||
|
||||
// TODO: make sure, 'shortest' path is favoured.
|
||||
function createBreadcrumbs(linkMap, srcId) {
|
||||
let crumbs = {};
|
||||
let path = [];
|
||||
let collectLinks = function(srcId, path){
|
||||
if(typeof crumbs[srcId] !== 'undefined') {
|
||||
return;
|
||||
}
|
||||
crumbs[srcId] = path.slice();
|
||||
path[path.length] = srcId;
|
||||
let links = linkMap[srcId];
|
||||
// collect links, append given list & skip srcId
|
||||
for(let link of links) {
|
||||
collectLinks(link['id'], path.slice());
|
||||
}
|
||||
}
|
||||
collectLinks(srcId, path);
|
||||
return crumbs;
|
||||
}
|
||||
|
||||
var nodePositions = {};
|
||||
function startGraph(graph){
|
||||
|
||||
|
@ -116,11 +157,16 @@ function startGraph(graph){
|
|||
// config
|
||||
var nodeSize = 40;
|
||||
var selectedNodeSize = 140;
|
||||
var firstNodeId = "https://rubenvandeven.com/ruben";
|
||||
|
||||
// set some vars
|
||||
var currentNodeIdx = 0;
|
||||
var currentNodePositionRadius = 0;
|
||||
var types = {};
|
||||
|
||||
linkMap = createLinkMap(graph);
|
||||
breadcrumbs = createBreadcrumbs(linkMap, firstNodeId);
|
||||
|
||||
for (let nodeIdx in graph['nodes']) {
|
||||
let type = graph['nodes'][nodeIdx]["type"];
|
||||
if(typeof types[type] == 'undefined') {
|
||||
|
@ -130,19 +176,26 @@ for (let nodeIdx in graph['nodes']) {
|
|||
}
|
||||
var graphControlsEl = document.getElementById('graphControls');
|
||||
var typeLinksEl = document.getElementById('typeLinks');
|
||||
var moreTypeLinksEl = document.getElementById('moreTypeLinks');
|
||||
var relLinksEl = document.getElementById('relLinks');
|
||||
|
||||
// make controls
|
||||
let i = 0;
|
||||
for (let typeName in types) {
|
||||
let typeLinkEl = document.createElement("li");
|
||||
let typeLinkAEl = document.createElement("a");
|
||||
let typeLinkCountEl = document.createElement("span");
|
||||
typeLinkCountEl.innerHTML = types[typeName].length;
|
||||
typeLinkAEl.innerHTML = typeName;
|
||||
typeLinkAEl.addEventListener('click', function(){
|
||||
centerByType(typeName);
|
||||
// positionNodesInCenter(types[typeName]);
|
||||
});
|
||||
typeLinkEl.append(typeLinkAEl);
|
||||
typeLinksEl.appendChild(typeLinkEl);
|
||||
typeLinkEl.append(typeLinkCountEl);
|
||||
(i < 5 ? typeLinksEl: moreTypeLinksEl).appendChild(typeLinkEl);
|
||||
i++;
|
||||
// typeLinksEl.appendChild(typeLinkEl);
|
||||
}
|
||||
|
||||
|
||||
|
@ -237,6 +290,7 @@ var positionNodesInCenter = function(idxs) {
|
|||
nodeEls[nIdx].classList.add('visibleNode');
|
||||
} else {
|
||||
nodeEls[nIdx].classList.remove('centeredNode');
|
||||
nodeEls[nIdx].classList.remove('visibleNode');
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -319,9 +373,16 @@ var setDetails = function(nodeDatum, nodeIdx) {
|
|||
nodeDetailEl.removeChild(nodeDetailEl.lastChild);
|
||||
}
|
||||
|
||||
|
||||
// TODO: replace relUp & relDown with linkMap
|
||||
let relUp = [];
|
||||
let relDown = [];
|
||||
let breadcrumbsEl = document.createElement('div');
|
||||
breadcrumbsEl.classList.add('breadcrumbs');
|
||||
for(let crumbNodeId of breadcrumbs[nodeDatum['id']]) {
|
||||
breadcrumbsEl.innerHTML += ` <span class='crumb'>${getNodeTitle(nodeMap[crumbNodeId])}</span>`;
|
||||
}
|
||||
nodeDetailEl.appendChild(breadcrumbsEl);
|
||||
|
||||
let titleAttr = getTitleAttribute(nodeDatum);
|
||||
let titleEl = document.createElement('h2');
|
||||
titleEl.innerHTML = getNodeTitle(nodeDatum);
|
||||
|
@ -457,30 +518,14 @@ var selectNode = function(idx){
|
|||
// set global var
|
||||
positionNodesInCenter(idx);
|
||||
|
||||
/* DISABLED: Make selected nodes bigger
|
||||
// update collision: the selected node should get plenty of space.
|
||||
simulation.force("collision").radius(function(d, idx){
|
||||
if(typeof nodePositions[idx] != 'undefined'){
|
||||
return selectedNodeSize * 1.2;
|
||||
}
|
||||
return nodeSize * 1.1;
|
||||
});
|
||||
node.each(function(d, idx, nodeEls){
|
||||
let nodeEl = nodeEls[idx];
|
||||
let nodeD3 = d3.select(nodeEl);
|
||||
let circleD3 = nodeD3.select('circle');
|
||||
let currentCrumbs = breadcrumbs[nodeDatum['id']].slice();
|
||||
currentCrumbs[currentCrumbs.length] = nodeDatum['id'];
|
||||
console.log(currentCrumbs);
|
||||
|
||||
if(typeof nodePositions[idx] !== 'undefined') {
|
||||
circleD3.transition(selectedNodeTransition).attr('r', selectedNodeSize);
|
||||
// nodeEl.getElementsByTagName("circle")[0].attributes.r.value = selectedNodeSize;
|
||||
} else {
|
||||
circleD3.transition(selectedNodeTransition).attr('r', nodeSize);
|
||||
// nodeEl.getElementsByTagName("circle")[0].attributes.r.value = nodeSize;
|
||||
}
|
||||
});
|
||||
*/
|
||||
// set active links.
|
||||
let linkedIdxs = [];
|
||||
link.each(function(d,idx,linkEls,q){
|
||||
// set nodes 'visible'/highlighted when linked to active node
|
||||
if(d.source == nodeDatum || d.target == nodeDatum) {
|
||||
linkEls[idx].classList.add('activeLink','visibleLink');
|
||||
linkEls[idx].getElementsByTagName("line")[0].setAttribute("marker-end", "url(#arrowHeadSelected)");
|
||||
|
@ -491,11 +536,19 @@ var selectNode = function(idx){
|
|||
}
|
||||
return r;
|
||||
}).classed('visibleNode', true);
|
||||
|
||||
} else {
|
||||
linkEls[idx].classList.remove('activeLink');
|
||||
linkEls[idx].getElementsByTagName("line")[0].setAttribute("marker-end", "url(#arrowHead)");
|
||||
}
|
||||
// check if link is part of breadcrumb trail
|
||||
let posSrc = currentCrumbs.indexOf(d.source['id']);
|
||||
let posTrg = currentCrumbs.indexOf(d.target['id']);
|
||||
if(posSrc > -1 && posTrg > -1 && Math.abs(posSrc - posTrg) == 1) {
|
||||
linkEls[idx].classList.add('breadcrumbLink');
|
||||
// linkEls[idx].getElementsByTagName("line")[0].setAttribute("marker-end", "url(#arrowHeadSelected)");
|
||||
} else {
|
||||
linkEls[idx].classList.remove('breadcrumbLink');
|
||||
}
|
||||
});
|
||||
|
||||
let i = linkedIdxs.indexOf(idx);
|
||||
|
@ -542,8 +595,8 @@ simulation.force('centerActive', function force(alpha) {
|
|||
return;
|
||||
}
|
||||
|
||||
n.vx += dx * k /5;
|
||||
n.vy += dy * k /5;
|
||||
n.vx += dx * k*3;
|
||||
n.vy += dy * k*3;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -597,10 +650,7 @@ node.append('circle')
|
|||
.attr("r", nodeSize)
|
||||
.attr("class", "nodeBg")
|
||||
;
|
||||
node.append('circle')
|
||||
.attr("r", nodeSize * 1.08) // nodeSize + margin
|
||||
.attr("class", "highlightCircle")
|
||||
;
|
||||
|
||||
|
||||
node.append('text')
|
||||
.append("textPath")
|
||||
|
@ -608,17 +658,28 @@ node.append('text')
|
|||
.text(getNodeTitle);
|
||||
|
||||
node.each(function(d) {
|
||||
let n = d3.select(this);
|
||||
if(!d.contentUrl) {
|
||||
return;
|
||||
n.append('circle')
|
||||
.attr("r", nodeSize * 1.08) // nodeSize + margin
|
||||
.attr("class", "highlightCircle")
|
||||
;
|
||||
} else {
|
||||
n.append('svg:image')
|
||||
.attr("xlink:href", d.contentUrl)
|
||||
.attr("width", nodeSize*2)
|
||||
.attr("height", nodeSize*2)
|
||||
.attr("transform","translate(-"+nodeSize+" -"+nodeSize+")")
|
||||
// .attr("clip-path","url(#clipNodeImage)")
|
||||
.attr("preserveAspectRatio","xMidYMid slice")
|
||||
;
|
||||
n.append('rect')
|
||||
.attr("width", nodeSize * 1.08 * 2) // nodeSize + margin
|
||||
.attr("height", nodeSize * 1.08 * 2) // nodeSize + margin
|
||||
.attr("transform","translate(-"+nodeSize * 1.08 +" -"+nodeSize * 1.08 +")")
|
||||
.attr("class", "highlightCircle")
|
||||
;
|
||||
}
|
||||
d3.select(this).append('svg:image')
|
||||
.attr("xlink:href", d.contentUrl)
|
||||
.attr("width", nodeSize*2)
|
||||
.attr("height", nodeSize*2)
|
||||
.attr("transform","translate(-"+nodeSize+" -"+nodeSize+")")
|
||||
.attr("clip-path","url(#clipNodeImage)")
|
||||
.attr("preserveAspectRatio","xMidYMid slice")
|
||||
;
|
||||
});
|
||||
|
||||
// node.append("title")
|
||||
|
@ -713,6 +774,10 @@ function ticked() {
|
|||
let x = d.source.x + dx;
|
||||
let y = d.source.y + dy;
|
||||
let deg = Math.atan(dy / dx) * 180 / Math.PI;
|
||||
// if dx/dy == 0/0 -> deg == NaN
|
||||
if(isNaN(deg)) {
|
||||
return "";
|
||||
}
|
||||
return "translate("+x+" "+y+") rotate("+deg+") translate(0, -10)";
|
||||
});
|
||||
// linkPath.attr("d", function(d) {
|
||||
|
@ -797,7 +862,7 @@ function moveViewboxPx(dx, dy){
|
|||
// start by selecting the first node :-)
|
||||
// selectNode(currentNodeIdx+1);
|
||||
// positionNodesInCenter(currentNodeIdx);
|
||||
selectNode(currentNodeIdx); //deselectNode();
|
||||
closeDetails();
|
||||
selectNode(graph['nodes'].length - 1);
|
||||
// closeDetails(); // hide details at first
|
||||
// positionNodesInCenter(currentNodeIdx+1);
|
||||
}
|
||||
|
|
|
@ -6,36 +6,9 @@ $detailSlideMobile: -30vh;
|
|||
|
||||
body{
|
||||
margin:0;overflow: hidden;
|
||||
font-family: sans-serif;
|
||||
/* background: #fceabb;
|
||||
background: -moz-linear-gradient(-45deg, #fceabb 0%, #fccd4d 50%, #f8b500 51%, #fbdf93 100%);
|
||||
background: -webkit-linear-gradient(-45deg, #fceabb 0%,#fccd4d 50%,#f8b500 51%,#fbdf93 100%);
|
||||
background: linear-gradient(135deg, #fceabb 0%,#fccd4d 50%,#f8b500 51%,#fbdf93 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#fceabb', endColorstr='#fbdf93',GradientType=1 ); */
|
||||
/*background: #f7fbfc;
|
||||
background: -moz-linear-gradient(45deg, #f7fbfc 0%, #d9edf2 40%, #add9e4 100%);
|
||||
background: -webkit-linear-gradient(45deg, #f7fbfc 0%,#d9edf2 40%,#add9e4 100%);
|
||||
background: linear-gradient(45deg, #f7fbfc 0%,#d9edf2 40%,#add9e4 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#f7fbfc', endColorstr='#add9e4',GradientType=1 );*/
|
||||
/*background: #e2e2e2;
|
||||
background: -moz-linear-gradient(45deg, #e2e2e2 0%, #dbdbdb 50%, #d1d1d1 51%, #fefefe 100%);
|
||||
background: -webkit-linear-gradient(45deg, #e2e2e2 0%,#dbdbdb 50%,#d1d1d1 51%,#fefefe 100%);
|
||||
background: linear-gradient(45deg, #e2e2e2 0%,#dbdbdb 50%,#d1d1d1 51%,#fefefe 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#e2e2e2', endColorstr='#fefefe',GradientType=1 );*/
|
||||
/*background: #d2dfed;
|
||||
background: -moz-linear-gradient(45deg, #d2dfed 0%, #c8d7eb 26%, #bed0ea 51%, #a6c0e3 51%, #afc7e8 62%, #bad0ef 75%, #99b5db 88%, #799bc8 100%);
|
||||
background: -webkit-linear-gradient(45deg, #d2dfed 0%,#c8d7eb 26%,#bed0ea 51%,#a6c0e3 51%,#afc7e8 62%,#bad0ef 75%,#99b5db 88%,#799bc8 100%);
|
||||
background: linear-gradient(45deg, #d2dfed 0%,#c8d7eb 26%,#bed0ea 51%,#a6c0e3 51%,#afc7e8 62%,#bad0ef 75%,#99b5db 88%,#799bc8 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#d2dfed', endColorstr='#799bc8',GradientType=1 );*/
|
||||
background: #d2dfed;
|
||||
background: -moz-linear-gradient(45deg, #d2dfed 0%, #afc1d8 13%, #d5e0ef 28%, #bed0ea 51%, #a8c0dd 51%, #c0d0e5 63%, #bad0ef 75%, #a2bad8 88%, #799bc8 100%);
|
||||
background: -webkit-linear-gradient(45deg, #d2dfed 0%,#afc1d8 13%,#d5e0ef 28%,#bed0ea 51%,#a8c0dd 51%,#c0d0e5 63%,#bad0ef 75%,#a2bad8 88%,#799bc8 100%);
|
||||
background: linear-gradient(45deg, #d2dfed 0%,#afc1d8 13%,#d5e0ef 28%,#bed0ea 51%,#a8c0dd 51%,#c0d0e5 63%,#bad0ef 75%,#a2bad8 88%,#799bc8 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#d2dfed', endColorstr='#799bc8',GradientType=1 );
|
||||
height: 100vh;
|
||||
/*-moz-animation: bgShift 5s infinite;
|
||||
background-size: 400% 400%;*/
|
||||
// font-size:18px;
|
||||
font-family: "CMU Bright", sans-serif;
|
||||
height: 100vh;
|
||||
background: black;
|
||||
}
|
||||
|
||||
a, a:link, a:visited{
|
||||
|
@ -69,80 +42,116 @@ g.node{
|
|||
stroke: blue;
|
||||
stroke-width: 0;
|
||||
transition: stroke-width .5s;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
transition: opacity 1s;
|
||||
}
|
||||
g.node.visibleNode/* , g.node.ImageObject */
|
||||
{
|
||||
opacity: 1;
|
||||
pointer-events: auto;
|
||||
}
|
||||
g.node circle.highlightCircle{
|
||||
fill: none;
|
||||
stroke-width:0px;
|
||||
stroke-dasharray: 3 2;
|
||||
}
|
||||
g.node:hover circle.highlightCircle{
|
||||
stroke-width: 1px;
|
||||
stroke: blue;
|
||||
}
|
||||
g.node:active circle.highlightCircle{
|
||||
stroke-width:1px;
|
||||
stroke: red;
|
||||
}
|
||||
g.node.centeredNode circle.highlightCircle{
|
||||
stroke-width:1px;
|
||||
stroke: red;
|
||||
}
|
||||
/* g.node.selectedNode circle.highlightCircle{
|
||||
stroke-width:1px;
|
||||
stroke: red;
|
||||
} */
|
||||
g.node.drag{
|
||||
cursor:grabbing;
|
||||
}
|
||||
.node text{
|
||||
text-anchor: start;
|
||||
// pointer-events: none;
|
||||
transition: opacity 1s;
|
||||
|
||||
&.visibleNode{
|
||||
opacity: 1;
|
||||
pointer-events: auto;
|
||||
*{
|
||||
// transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
*{
|
||||
// transform: scale(.4);
|
||||
}
|
||||
|
||||
.highlightCircle{
|
||||
fill: none;
|
||||
stroke-width:0px;
|
||||
stroke-dasharray: 3 2;
|
||||
}
|
||||
|
||||
&:hover .highlightCircle{
|
||||
stroke-width: 1px;
|
||||
stroke: yellow;
|
||||
}
|
||||
|
||||
&.drag{
|
||||
cursor: grabbing;
|
||||
}
|
||||
|
||||
text{
|
||||
text-anchor: start;
|
||||
font-family: "CMU Bright", sans-serif;
|
||||
font-size: 10pt;
|
||||
}
|
||||
}
|
||||
|
||||
.relationship{
|
||||
display:none;
|
||||
// opacity: .2;
|
||||
|
||||
&.visibleLink{
|
||||
display:block;
|
||||
// opacity: 1;
|
||||
|
||||
}
|
||||
|
||||
line{
|
||||
fill:none;
|
||||
stroke: #999;
|
||||
stroke-width: 2px;
|
||||
|
||||
}
|
||||
|
||||
text{
|
||||
fill:black;
|
||||
font-family: "Noto Mono", monospace;
|
||||
font-size: 9pt;
|
||||
// font-size: 75%;
|
||||
display:none;
|
||||
}
|
||||
&.activeLink{
|
||||
line{
|
||||
stroke: white;
|
||||
}
|
||||
text{
|
||||
fill:white;
|
||||
display:block;
|
||||
}
|
||||
}
|
||||
&.breadcrumbLink{
|
||||
display: block;
|
||||
|
||||
line {
|
||||
stroke: yellow !important;
|
||||
display: block;
|
||||
}
|
||||
text{
|
||||
fill: yellow !important;
|
||||
display:block;
|
||||
}
|
||||
}
|
||||
}
|
||||
.relationship.visibleLink{
|
||||
display:block;
|
||||
}
|
||||
.relationship line{
|
||||
fill:none;
|
||||
stroke: #999;
|
||||
stroke-width: 2px;
|
||||
}
|
||||
.relationship text{
|
||||
fill:black;
|
||||
/* text-transform: lowercase; */
|
||||
font-size: 75%;
|
||||
display:none;
|
||||
}
|
||||
.relationship.activeLink text{
|
||||
fill:white;
|
||||
display:block;
|
||||
}
|
||||
.relationship.activeLink line{
|
||||
stroke: white;
|
||||
}
|
||||
|
||||
circle.nodeBg{
|
||||
fill: white;
|
||||
/*stroke-width:.2em;*/
|
||||
fill:url(#blueGrad);
|
||||
// fill: url(#img1);
|
||||
// fill:url(#blueGrad);
|
||||
stroke-width: 3px;
|
||||
stroke: black;
|
||||
|
||||
.visibleNode & {
|
||||
stroke: yellow;
|
||||
}
|
||||
|
||||
.MediaObject & {
|
||||
fill:url(#orangeGrad);
|
||||
// fill:url(#orangeGrad);
|
||||
}
|
||||
.Person & {
|
||||
fill:url(#redGrad);
|
||||
// fill:url(#redGrad);
|
||||
}
|
||||
|
||||
.PublicationEvent & {
|
||||
fill:url(#limeGrad);
|
||||
// fill:url(#limeGrad);
|
||||
}
|
||||
|
||||
.centeredNode &{
|
||||
fill: yellow;
|
||||
stroke: yellow;
|
||||
}
|
||||
}
|
||||
text{
|
||||
|
|
Loading…
Reference in a new issue