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 uglify = require('gulp-uglify');
|
||||||
var sourcemaps = require('gulp-sourcemaps');
|
var sourcemaps = require('gulp-sourcemaps');
|
||||||
var browserSync = require('browser-sync');
|
var browserSync = require('browser-sync');
|
||||||
|
var jsonld = require('jsonld');
|
||||||
|
|
||||||
|
|
||||||
|
var through = require('through2')
|
||||||
// todo: rollup for d3 & possibly jsonld
|
// todo: rollup for d3 & possibly jsonld
|
||||||
|
|
||||||
var paths = {
|
var paths = {
|
||||||
|
@ -19,7 +23,7 @@ var paths = {
|
||||||
},
|
},
|
||||||
"data": {
|
"data": {
|
||||||
"src": "./rubenvandeven.jsonld",
|
"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
|
.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() {
|
var watchStylesAndScripts = function() {
|
||||||
gulp.watch(paths.styles.src,['styles']);
|
gulp.watch(paths.styles.src,['styles']);
|
||||||
gulp.watch(paths.scripts.src,['scripts', browserSync.reload]);
|
gulp.watch(paths.scripts.src,['scripts', browserSync.reload]);
|
||||||
|
gulp.watch([paths.data.src], ['jsonld', browserSync.reload]);
|
||||||
}
|
}
|
||||||
|
|
||||||
gulp.task('watch', watchStylesAndScripts);
|
gulp.task('watch', watchStylesAndScripts);
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<html xmlns:xlink="http://www.w3.org/1999/xlink">
|
<html xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
<head>
|
<head>
|
||||||
<title></title>
|
<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">
|
<link rel="stylesheet" href="/assets/css/portfolio.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
@ -44,6 +44,10 @@
|
||||||
<clipPath id="clipNodeImage">
|
<clipPath id="clipNodeImage">
|
||||||
<circle cx="40" cy="40" r="40" />
|
<circle cx="40" cy="40" r="40" />
|
||||||
</clipPath>
|
</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>
|
</defs>
|
||||||
</svg>
|
</svg>
|
||||||
<div id="nodeDetails">
|
<div id="nodeDetails">
|
||||||
|
@ -52,6 +56,8 @@
|
||||||
<div id="graphControls">
|
<div id="graphControls">
|
||||||
<span class="typeJump">Show:</span>
|
<span class="typeJump">Show:</span>
|
||||||
<ul id='typeLinks'></ul>
|
<ul id='typeLinks'></ul>
|
||||||
|
<span class="showMoreTypeLinks">...</span>
|
||||||
|
<ul id='moreTypeLinks'></ul>
|
||||||
<!-- <ul id='relLinks'></ul> -->
|
<!-- <ul id='relLinks'></ul> -->
|
||||||
</div>
|
</div>
|
||||||
<!-- <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/jsonld@0.5.21/dist/jsonld.js"></script> -->
|
<!-- <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",
|
"url": "https://rubenvandeven.com",
|
||||||
"author":
|
"author":
|
||||||
{
|
{
|
||||||
|
"@id": "https://rubenvandeven.com/ruben",
|
||||||
"@type": "Person",
|
"@type": "Person",
|
||||||
"name": "Ruben van de Ven",
|
"name": "Ruben van de Ven",
|
||||||
"email": "info@rubenvandeven.com",
|
"email": "info@rubenvandeven.com",
|
||||||
"nationality": "The Netherlands",
|
"nationality": "The Netherlands",
|
||||||
|
"jobTitle": "digital artist / researcher of software culture",
|
||||||
"@reverse": {
|
"@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": [
|
"author": [
|
||||||
{
|
{
|
||||||
"@type": "MediaObject",
|
"@type": "MediaObject",
|
||||||
|
@ -56,7 +70,7 @@
|
||||||
"@reverse": {
|
"@reverse": {
|
||||||
"workFeatured": [
|
"workFeatured": [
|
||||||
{
|
{
|
||||||
"@id": "kick2018exhibit",
|
"@id": "https://rubenvandeven.com/#kick2018exhibit",
|
||||||
"@type": "ExhibitionEvent",
|
"@type": "ExhibitionEvent",
|
||||||
"name": "KickstART",
|
"name": "KickstART",
|
||||||
"location": {
|
"location": {
|
||||||
|
@ -68,7 +82,7 @@
|
||||||
"endDate": "2018-03-28"
|
"endDate": "2018-03-28"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "in4artSalon",
|
"@id": "https://rubenvandeven.com/#in4artSalon",
|
||||||
"@type": "ExhibitionEvent",
|
"@type": "ExhibitionEvent",
|
||||||
"name": "Salon VI - Innovatism",
|
"name": "Salon VI - Innovatism",
|
||||||
"location": {
|
"location": {
|
||||||
|
@ -92,7 +106,7 @@
|
||||||
"@reverse": {
|
"@reverse": {
|
||||||
"workFeatured":
|
"workFeatured":
|
||||||
{
|
{
|
||||||
"@id": "kick2018exhibit"
|
"@id": "https://rubenvandeven.com/#kick2018exhibit"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"image": [
|
"image": [
|
||||||
|
@ -106,7 +120,7 @@
|
||||||
"@reverse": {
|
"@reverse": {
|
||||||
"workFeatured":
|
"workFeatured":
|
||||||
{
|
{
|
||||||
"@id": "kick2018exhibit"
|
"@id": "https://rubenvandeven.com/#kick2018exhibit"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"image": [
|
"image": [
|
||||||
|
@ -126,7 +140,7 @@
|
||||||
"name": "The Black Box Concern",
|
"name": "The Black Box Concern",
|
||||||
"url": "....",
|
"url": "....",
|
||||||
"location": {
|
"location": {
|
||||||
"@id": "v2_"
|
"@id": "https://rubenvandeven.com/#v2_"
|
||||||
},
|
},
|
||||||
"startDate": "2017-12",
|
"startDate": "2017-12",
|
||||||
"workFeatured": []
|
"workFeatured": []
|
||||||
|
@ -140,7 +154,7 @@
|
||||||
{
|
{
|
||||||
"@type": "MediaObject",
|
"@type": "MediaObject",
|
||||||
"name": "Emotion Hero",
|
"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",
|
"url": "https://emotionhero.com",
|
||||||
"@reverse": {
|
"@reverse": {
|
||||||
"workFeatured": [
|
"workFeatured": [
|
||||||
|
@ -190,7 +204,7 @@
|
||||||
},
|
},
|
||||||
"startDate": "2017-09",
|
"startDate": "2017-09",
|
||||||
"endDate": "2017-09",
|
"endDate": "2017-09",
|
||||||
"organiser": { "@id":"v2_" },
|
"organiser": { "@id":"vhttps://rubenvandeven.com/#2_" },
|
||||||
"funded": "Creative Industries Fund",
|
"funded": "Creative Industries Fund",
|
||||||
"workFeatured": []
|
"workFeatured": []
|
||||||
},
|
},
|
||||||
|
@ -209,7 +223,7 @@
|
||||||
"workFeatured": []
|
"workFeatured": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "codesandmodes",
|
"@id": "https://rubenvandeven.com/#codesandmodes",
|
||||||
"@type": "ExhibitionEvent",
|
"@type": "ExhibitionEvent",
|
||||||
"name": "Codes & Modes II",
|
"name": "Codes & Modes II",
|
||||||
"organiser": "Integrated Media Arts MFA",
|
"organiser": "Integrated Media Arts MFA",
|
||||||
|
@ -223,7 +237,7 @@
|
||||||
"workFeatured": []
|
"workFeatured": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "stateofemotion",
|
"@id": "https://rubenvandeven.com/#stateofemotion",
|
||||||
"@type": "ExhibitionEvent",
|
"@type": "ExhibitionEvent",
|
||||||
"name": "STATE of Emotion",
|
"name": "STATE of Emotion",
|
||||||
"location": {
|
"location": {
|
||||||
|
@ -293,7 +307,7 @@
|
||||||
"name": "Test_Lab the Graduation Edition",
|
"name": "Test_Lab the Graduation Edition",
|
||||||
"url": "...",
|
"url": "...",
|
||||||
"location": {
|
"location": {
|
||||||
"@id": "v2_",
|
"@id": "https://rubenvandeven.com/#v2_",
|
||||||
"@type": "Place",
|
"@type": "Place",
|
||||||
"name": "V2_",
|
"name": "V2_",
|
||||||
"address": "Rotterdam"
|
"address": "Rotterdam"
|
||||||
|
@ -334,6 +348,7 @@
|
||||||
"dateCreated": "2016",
|
"dateCreated": "2016",
|
||||||
"description": "...",
|
"description": "...",
|
||||||
"author": {
|
"author": {
|
||||||
|
"@id": "http://randomizer.info",
|
||||||
"@type": "Person",
|
"@type": "Person",
|
||||||
"name": "Cristina Cochior",
|
"name": "Cristina Cochior",
|
||||||
"url": "http://randomizer.info"
|
"url": "http://randomizer.info"
|
||||||
|
@ -412,10 +427,10 @@
|
||||||
"@reverse": {
|
"@reverse": {
|
||||||
"workFeatured": [
|
"workFeatured": [
|
||||||
{
|
{
|
||||||
"@id": "codesandmodes"
|
"@id": "https://rubenvandeven.com/#codesandmodes"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "stateofemotion"
|
"@id": "https://rubenvandeven.com/#stateofemotion"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@type": "ExhibitionEvent",
|
"@type": "ExhibitionEvent",
|
||||||
|
@ -424,7 +439,7 @@
|
||||||
"startDate": "2015-06",
|
"startDate": "2015-06",
|
||||||
"endDate": "2015-06",
|
"endDate": "2015-06",
|
||||||
"location": {
|
"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;
|
var graph;
|
||||||
|
// map nodes to their ID
|
||||||
var nodeMap = {};
|
var nodeMap = {};
|
||||||
jsonld.flatten(window.location.protocol + "//" + window.location.host + "/rubenvandeven.jsonld", {"@context": "https://schema.org/"},(err, flattened)=> {
|
// TODO: map node IDs to their linked node IDs
|
||||||
console.log(err);
|
var linkMap = {};
|
||||||
data = flattened;
|
// TODO: use linkMap to create breadcrumbs per node
|
||||||
graph = jsonLdToGraph(flattened['@graph']);
|
var breadcrumbs = {};
|
||||||
// create a map of nodes by id.
|
// load the flattened jsonld file
|
||||||
for(let i in graph.nodes) {
|
const requestPromise = fetch('/assets/js/rubenvandeven.jsonld')
|
||||||
nodeMap[graph.nodes[i]['id']] = graph.nodes[i];
|
.then(r => r.json())
|
||||||
}
|
.then(data => {
|
||||||
// console.log(graph);
|
graph = jsonLdToGraph(data['@graph']);
|
||||||
startGraph(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) {
|
function inCircle(dx, dy, r) {
|
||||||
// fastest check if in circle: https://stackoverflow.com/a/7227057
|
// 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 = {};
|
var nodePositions = {};
|
||||||
function startGraph(graph){
|
function startGraph(graph){
|
||||||
|
|
||||||
|
@ -116,11 +157,16 @@ function startGraph(graph){
|
||||||
// config
|
// config
|
||||||
var nodeSize = 40;
|
var nodeSize = 40;
|
||||||
var selectedNodeSize = 140;
|
var selectedNodeSize = 140;
|
||||||
|
var firstNodeId = "https://rubenvandeven.com/ruben";
|
||||||
|
|
||||||
// set some vars
|
// set some vars
|
||||||
var currentNodeIdx = 0;
|
var currentNodeIdx = 0;
|
||||||
var currentNodePositionRadius = 0;
|
var currentNodePositionRadius = 0;
|
||||||
var types = {};
|
var types = {};
|
||||||
|
|
||||||
|
linkMap = createLinkMap(graph);
|
||||||
|
breadcrumbs = createBreadcrumbs(linkMap, firstNodeId);
|
||||||
|
|
||||||
for (let nodeIdx in graph['nodes']) {
|
for (let nodeIdx in graph['nodes']) {
|
||||||
let type = graph['nodes'][nodeIdx]["type"];
|
let type = graph['nodes'][nodeIdx]["type"];
|
||||||
if(typeof types[type] == 'undefined') {
|
if(typeof types[type] == 'undefined') {
|
||||||
|
@ -130,19 +176,26 @@ for (let nodeIdx in graph['nodes']) {
|
||||||
}
|
}
|
||||||
var graphControlsEl = document.getElementById('graphControls');
|
var graphControlsEl = document.getElementById('graphControls');
|
||||||
var typeLinksEl = document.getElementById('typeLinks');
|
var typeLinksEl = document.getElementById('typeLinks');
|
||||||
|
var moreTypeLinksEl = document.getElementById('moreTypeLinks');
|
||||||
var relLinksEl = document.getElementById('relLinks');
|
var relLinksEl = document.getElementById('relLinks');
|
||||||
|
|
||||||
// make controls
|
// make controls
|
||||||
|
let i = 0;
|
||||||
for (let typeName in types) {
|
for (let typeName in types) {
|
||||||
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");
|
||||||
|
typeLinkCountEl.innerHTML = types[typeName].length;
|
||||||
typeLinkAEl.innerHTML = typeName;
|
typeLinkAEl.innerHTML = typeName;
|
||||||
typeLinkAEl.addEventListener('click', function(){
|
typeLinkAEl.addEventListener('click', function(){
|
||||||
centerByType(typeName);
|
centerByType(typeName);
|
||||||
// positionNodesInCenter(types[typeName]);
|
// positionNodesInCenter(types[typeName]);
|
||||||
});
|
});
|
||||||
typeLinkEl.append(typeLinkAEl);
|
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');
|
nodeEls[nIdx].classList.add('visibleNode');
|
||||||
} else {
|
} else {
|
||||||
nodeEls[nIdx].classList.remove('centeredNode');
|
nodeEls[nIdx].classList.remove('centeredNode');
|
||||||
|
nodeEls[nIdx].classList.remove('visibleNode');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -319,9 +373,16 @@ var setDetails = function(nodeDatum, nodeIdx) {
|
||||||
nodeDetailEl.removeChild(nodeDetailEl.lastChild);
|
nodeDetailEl.removeChild(nodeDetailEl.lastChild);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: replace relUp & relDown with linkMap
|
||||||
let relUp = [];
|
let relUp = [];
|
||||||
let relDown = [];
|
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 titleAttr = getTitleAttribute(nodeDatum);
|
||||||
let titleEl = document.createElement('h2');
|
let titleEl = document.createElement('h2');
|
||||||
titleEl.innerHTML = getNodeTitle(nodeDatum);
|
titleEl.innerHTML = getNodeTitle(nodeDatum);
|
||||||
|
@ -457,30 +518,14 @@ var selectNode = function(idx){
|
||||||
// set global var
|
// set global var
|
||||||
positionNodesInCenter(idx);
|
positionNodesInCenter(idx);
|
||||||
|
|
||||||
/* DISABLED: Make selected nodes bigger
|
let currentCrumbs = breadcrumbs[nodeDatum['id']].slice();
|
||||||
// update collision: the selected node should get plenty of space.
|
currentCrumbs[currentCrumbs.length] = nodeDatum['id'];
|
||||||
simulation.force("collision").radius(function(d, idx){
|
console.log(currentCrumbs);
|
||||||
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');
|
|
||||||
|
|
||||||
if(typeof nodePositions[idx] !== 'undefined') {
|
// set active links.
|
||||||
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;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
*/
|
|
||||||
let linkedIdxs = [];
|
let linkedIdxs = [];
|
||||||
link.each(function(d,idx,linkEls,q){
|
link.each(function(d,idx,linkEls,q){
|
||||||
|
// set nodes 'visible'/highlighted when linked to active node
|
||||||
if(d.source == nodeDatum || d.target == nodeDatum) {
|
if(d.source == nodeDatum || d.target == nodeDatum) {
|
||||||
linkEls[idx].classList.add('activeLink','visibleLink');
|
linkEls[idx].classList.add('activeLink','visibleLink');
|
||||||
linkEls[idx].getElementsByTagName("line")[0].setAttribute("marker-end", "url(#arrowHeadSelected)");
|
linkEls[idx].getElementsByTagName("line")[0].setAttribute("marker-end", "url(#arrowHeadSelected)");
|
||||||
|
@ -491,11 +536,19 @@ var selectNode = function(idx){
|
||||||
}
|
}
|
||||||
return r;
|
return r;
|
||||||
}).classed('visibleNode', true);
|
}).classed('visibleNode', true);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
linkEls[idx].classList.remove('activeLink');
|
linkEls[idx].classList.remove('activeLink');
|
||||||
linkEls[idx].getElementsByTagName("line")[0].setAttribute("marker-end", "url(#arrowHead)");
|
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);
|
let i = linkedIdxs.indexOf(idx);
|
||||||
|
@ -542,8 +595,8 @@ simulation.force('centerActive', function force(alpha) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
n.vx += dx * k /5;
|
n.vx += dx * k*3;
|
||||||
n.vy += dy * k /5;
|
n.vy += dy * k*3;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -597,10 +650,7 @@ node.append('circle')
|
||||||
.attr("r", nodeSize)
|
.attr("r", nodeSize)
|
||||||
.attr("class", "nodeBg")
|
.attr("class", "nodeBg")
|
||||||
;
|
;
|
||||||
node.append('circle')
|
|
||||||
.attr("r", nodeSize * 1.08) // nodeSize + margin
|
|
||||||
.attr("class", "highlightCircle")
|
|
||||||
;
|
|
||||||
|
|
||||||
node.append('text')
|
node.append('text')
|
||||||
.append("textPath")
|
.append("textPath")
|
||||||
|
@ -608,17 +658,28 @@ node.append('text')
|
||||||
.text(getNodeTitle);
|
.text(getNodeTitle);
|
||||||
|
|
||||||
node.each(function(d) {
|
node.each(function(d) {
|
||||||
|
let n = d3.select(this);
|
||||||
if(!d.contentUrl) {
|
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")
|
// node.append("title")
|
||||||
|
@ -713,6 +774,10 @@ function ticked() {
|
||||||
let x = d.source.x + dx;
|
let x = d.source.x + dx;
|
||||||
let y = d.source.y + dy;
|
let y = d.source.y + dy;
|
||||||
let deg = Math.atan(dy / dx) * 180 / Math.PI;
|
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)";
|
return "translate("+x+" "+y+") rotate("+deg+") translate(0, -10)";
|
||||||
});
|
});
|
||||||
// linkPath.attr("d", function(d) {
|
// linkPath.attr("d", function(d) {
|
||||||
|
@ -797,7 +862,7 @@ function moveViewboxPx(dx, dy){
|
||||||
// start by selecting the first node :-)
|
// start by selecting the first node :-)
|
||||||
// selectNode(currentNodeIdx+1);
|
// selectNode(currentNodeIdx+1);
|
||||||
// positionNodesInCenter(currentNodeIdx);
|
// positionNodesInCenter(currentNodeIdx);
|
||||||
selectNode(currentNodeIdx); //deselectNode();
|
selectNode(graph['nodes'].length - 1);
|
||||||
closeDetails();
|
// closeDetails(); // hide details at first
|
||||||
// positionNodesInCenter(currentNodeIdx+1);
|
// positionNodesInCenter(currentNodeIdx+1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,36 +6,9 @@ $detailSlideMobile: -30vh;
|
||||||
|
|
||||||
body{
|
body{
|
||||||
margin:0;overflow: hidden;
|
margin:0;overflow: hidden;
|
||||||
font-family: sans-serif;
|
font-family: "CMU Bright", sans-serif;
|
||||||
/* background: #fceabb;
|
height: 100vh;
|
||||||
background: -moz-linear-gradient(-45deg, #fceabb 0%, #fccd4d 50%, #f8b500 51%, #fbdf93 100%);
|
background: black;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
a, a:link, a:visited{
|
a, a:link, a:visited{
|
||||||
|
@ -69,80 +42,116 @@ g.node{
|
||||||
stroke: blue;
|
stroke: blue;
|
||||||
stroke-width: 0;
|
stroke-width: 0;
|
||||||
transition: stroke-width .5s;
|
transition: stroke-width .5s;
|
||||||
opacity: 0;
|
|
||||||
pointer-events: none;
|
|
||||||
transition: opacity 1s;
|
|
||||||
}
|
|
||||||
g.node.visibleNode/* , g.node.ImageObject */
|
|
||||||
{
|
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
pointer-events: auto;
|
// pointer-events: none;
|
||||||
}
|
transition: opacity 1s;
|
||||||
g.node circle.highlightCircle{
|
|
||||||
fill: none;
|
&.visibleNode{
|
||||||
stroke-width:0px;
|
opacity: 1;
|
||||||
stroke-dasharray: 3 2;
|
pointer-events: auto;
|
||||||
}
|
*{
|
||||||
g.node:hover circle.highlightCircle{
|
// transform: scale(1);
|
||||||
stroke-width: 1px;
|
}
|
||||||
stroke: blue;
|
}
|
||||||
}
|
|
||||||
g.node:active circle.highlightCircle{
|
*{
|
||||||
stroke-width:1px;
|
// transform: scale(.4);
|
||||||
stroke: red;
|
}
|
||||||
}
|
|
||||||
g.node.centeredNode circle.highlightCircle{
|
.highlightCircle{
|
||||||
stroke-width:1px;
|
fill: none;
|
||||||
stroke: red;
|
stroke-width:0px;
|
||||||
}
|
stroke-dasharray: 3 2;
|
||||||
/* g.node.selectedNode circle.highlightCircle{
|
}
|
||||||
stroke-width:1px;
|
|
||||||
stroke: red;
|
&:hover .highlightCircle{
|
||||||
} */
|
stroke-width: 1px;
|
||||||
g.node.drag{
|
stroke: yellow;
|
||||||
cursor:grabbing;
|
}
|
||||||
}
|
|
||||||
.node text{
|
&.drag{
|
||||||
text-anchor: start;
|
cursor: grabbing;
|
||||||
|
}
|
||||||
|
|
||||||
|
text{
|
||||||
|
text-anchor: start;
|
||||||
|
font-family: "CMU Bright", sans-serif;
|
||||||
|
font-size: 10pt;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.relationship{
|
.relationship{
|
||||||
display:none;
|
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{
|
circle.nodeBg{
|
||||||
fill: white;
|
fill: white;
|
||||||
/*stroke-width:.2em;*/
|
// fill: url(#img1);
|
||||||
fill:url(#blueGrad);
|
// fill:url(#blueGrad);
|
||||||
|
stroke-width: 3px;
|
||||||
|
stroke: black;
|
||||||
|
|
||||||
|
.visibleNode & {
|
||||||
|
stroke: yellow;
|
||||||
|
}
|
||||||
|
|
||||||
.MediaObject & {
|
.MediaObject & {
|
||||||
fill:url(#orangeGrad);
|
// fill:url(#orangeGrad);
|
||||||
}
|
}
|
||||||
.Person & {
|
.Person & {
|
||||||
fill:url(#redGrad);
|
// fill:url(#redGrad);
|
||||||
}
|
}
|
||||||
|
|
||||||
.PublicationEvent & {
|
.PublicationEvent & {
|
||||||
fill:url(#limeGrad);
|
// fill:url(#limeGrad);
|
||||||
|
}
|
||||||
|
|
||||||
|
.centeredNode &{
|
||||||
|
fill: yellow;
|
||||||
|
stroke: yellow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
text{
|
text{
|
||||||
|
|
Loading…
Reference in a new issue