Compare commits

..

No commits in common. "ea9862eddca749a3306be6e0d3eeb2e7bea8f071" and "c97af5bc01dc88c9d8d8527033c460b326da425c" have entirely different histories.

3 changed files with 78 additions and 206 deletions

View file

@ -7,13 +7,12 @@
:root { :root {
--color1: #9741f9; --color1: #9741f9;
--color2: #f04a2d; --color2: #f3722c;
--color3: #0083ff; --color3: #f8961e;
/* --color4: #f9844a; */ /* --color4: #f9844a; */
--color5: #24C3B2; --color5: #f9c74f;
--color6: #7bc748; --color6: #90be6d;
--color7: #e4a02b;/*#fff239;*/ --color7: #43aa8b;
--color7-2: #e4a02b;
--color8: #4d908e; --color8: #4d908e;
--color9: #577590; --color9: #577590;
--color10: #277da1; --color10: #277da1;
@ -66,36 +65,28 @@ svg .links line, svg .links path {
/* stroke: #f3722c; */ /* stroke: #f3722c; */
/* stroke: #9df32c; */ /* stroke: #9df32c; */
stroke: var(--link-color); stroke: var(--link-color);
stroke-width: calc(12px / var(--zoom)); stroke-width: calc(10px / var(--zoom));
fill: none; fill: none;
/* transition: stroke-width 1s; */ /* transition: stroke-width 1s; */
cursor: pointer; cursor: pointer;
stroke-linecap: round;
}
svg .selectedNode .links line, svg .selectedNode .links path {
opacity: .3;
} }
svg .links line.hover, svg .links path.hover { svg .links line.hover, svg .links path.hover {
stroke: var(--link-hover-color) !important; stroke: var(--link-hover-color) !important;
opacity: 1;
/* stroke-width: 12; */ /* stroke-width: 12; */
/* marker-end: url(#arrowHeadSelected) !important; */ marker-end: url(#arrowHeadSelected) !important;
} }
svg .links .linkedHover path{ svg .links .linkedHover path{
stroke: var(--link-hover-related-color); stroke: var(--link-hover-related-color);
opacity: 1;
stroke-width: calc(12px / var(--zoom)); stroke-width: calc(12px / var(--zoom));
/* marker-end: url(#arrowHeadSelectedRelated); */ marker-end: url(#arrowHeadSelectedRelated);
} }
svg .links .linkedSelected path{ svg .links .linkedSelected path{
stroke: var(--link-hover-related-color); stroke: var(--link-hover-related-color);
opacity: 1;
stroke-width: calc(12px / var(--zoom)); stroke-width: calc(12px / var(--zoom));
/* marker-end: url(#arrowHeadSelectedRelated); */ marker-end: url(#arrowHeadSelectedRelated);
} }
/* svg.zoomed .links line, svg.zoomed .links path { /* svg.zoomed .links line, svg.zoomed .links path {
@ -174,7 +165,7 @@ svg #header text#subtitle {
/* font-size: 16pt; */ /* font-size: 16pt; */
/*Set this in JS*/ /*Set this in JS*/
transition: opacity 1s; transition: opacity 1s;
fill: black; /*also when hovering node*/ fill: #5d5d5f; /*also when hovering node*/
opacity: 1; opacity: 1;
/* pointer-events: none; */ /* pointer-events: none; */
/*prevent mouse glitches*/ /*prevent mouse glitches*/
@ -187,12 +178,6 @@ svg #header text#subtitle {
pointer-events: none; pointer-events: none;
} }
.selectedNode .node:not(.linkedSelected):not(.selected) text.nodeTitle{
/* used to be shown on hover, but disabled now that we have a tooltip */
opacity: 0;
pointer-events: none;
}
svg.zoomed .node text.nodeTitle { svg.zoomed .node text.nodeTitle {
/* font-size: 6pt; */ /* font-size: 6pt; */
} }
@ -203,12 +188,6 @@ svg.zoomed.zoomed2 .node text.nodeTitle {
.node circle, .node path { .node circle, .node path {
fill: lightgray; fill: lightgray;
transform: scale(calc(1.5 / var(--zoom-sqrt)));
}
#filters .node circle, #filters .node path {
transform: none;
} }
/* Whenever a connected link is hovered */ /* Whenever a connected link is hovered */
@ -218,12 +197,8 @@ svg.zoomed.zoomed2 .node text.nodeTitle {
stroke: var(--hover-related-color); stroke: var(--hover-related-color);
stroke-width: 2px; stroke-width: 2px;
} }
.node.linkHover text, .node.linkedHover text{
fill: var(--hover-related-color) !important;
}
.selectedNode .node:not(.linkedSelected) path { .selectedNode .node:not(.linkedSelected) path {
fill: lightgray !important; fill: lightgray !important;
opacity: .5;
/* same as linkHover/linkedHover but without border */ /* same as linkHover/linkedHover but without border */
} }
@ -236,11 +211,6 @@ svg.zoomed.zoomed2 .node text.nodeTitle {
stroke: var(--hover-color); stroke: var(--hover-color);
stroke-width: 2px; stroke-width: 2px;
} }
.node:hover text, .node.selected text {
fill: var(--hover-color) !important;
}
/* /*
.node:hover text { .node:hover text {
transition: none; transition: none;
@ -284,8 +254,7 @@ svg.zoomed.zoomed2 .node text.nodeTitle {
.node.Institution circle, .node.Institution path { .node.Institution circle, .node.Institution path {
/* fill: lightcoral; */ /* fill: lightcoral; */
/* fill: #11F999; */ fill: #11F999;
fill: darkgray;
} }
.node.Dataset circle, .node.Dataset path { .node.Dataset circle, .node.Dataset path {
@ -297,29 +266,26 @@ svg.zoomed.zoomed2 .node text.nodeTitle {
opacity: 1 !important; opacity: 1 !important;
} }
.node.Institution.Institution-company path, .node.Institution.Institution-company text{ .node.Institution.Institution-company path{
fill: var(--color2); fill: #45F68A;
} }
.node.Institution.Institution-government path, .node.Institution.Institution-government text{ .node.Institution.Institution-government path{
fill: var(--color3); fill: #60F37B;
} }
.node.Institution.Institution-local-government path{ .node.Institution.Institution-local-government path{
fill: #75F06D; fill: #75F06D;
} }
.node.Institution.Institution-law-enforcement path{ .node.Institution.Institution-law-enforcement path{
fill: var(--color7); fill: #87EC60;
} }
.node.Institution.Institution-law-enforcement text{ .node.Institution.Institution-ngo path{
fill: var(--color7-2); fill: #97E853;
}
.node.Institution.Institution-ngo path, .node.Institution.Institution-ngo text{
fill: var(--color5);
} }
.node.Institution.Institution-university path{ .node.Institution.Institution-university path{
fill: #A6E447; fill: #A6E447;
} }
.node.Institution.Institution-research path, .node.Institution.Institution-research text{ .node.Institution.Institution-research path{
fill: var(--color6); fill: #B4E03C;
} }
.node.Institution.Institution-project path{ .node.Institution.Institution-project path{
fill: #C1DB31; fill: #C1DB31;
@ -453,7 +419,6 @@ header {
background: white; background: white;
padding: 10px; padding: 10px;
border-top-left-radius: 5px; border-top-left-radius: 5px;
min-width: 300px;
} }
h1 { h1 {
@ -478,7 +443,7 @@ p.subtitle {
#filters label { #filters label {
cursor: pointer; cursor: pointer;
display: block; display: block;
padding: 5px 10px; padding: 10px;
} }
#filters label svg { #filters label svg {
@ -509,43 +474,6 @@ p.subtitle {
/* box-shadow: inset 0 0 5px black; */ /* box-shadow: inset 0 0 5px black; */
} }
#filters .institution_types{
margin-left: 30px;
}
#filter-items.filter-institution .institution_types{
/* display:none */
color: darkgray;
pointer-events: none;
}
#filter-items.filter-institution .institution_types span{
text-decoration: line-through;
}
#filters h3{
cursor: pointer;
}
#filters h3::before{
display: inline-block;
float: left;
content: '\fe3f'; /*⬆*/
transform: rotate(180deg);
transition: transform .8s;
}
#filters.hide h3::before{
transform: rotate(0deg);
}
#filter-items{
max-height: 1000px;
transition: max-height .8s;
}
#filters.hide #filter-items{
max-height: 0px;
}
#map .borders { #map .borders {
stroke-width: 6px; stroke-width: 6px;
stroke: rgb(221, 210, 210); stroke: rgb(221, 210, 210);
@ -562,21 +490,3 @@ p.subtitle {
font-size: 30; font-size: 30;
} }
#closeSelection{
pointer-events: none;
opacity: 0;
position: absolute;
top: 0;
right: 0;
background-color: white;
font-size: 200%;
width: 35px;
text-align:center;
z-index: 10;
}
.selectedNode #closeSelection{
pointer-events: all;;
opacity: 1;
cursor: pointer;
}

View file

@ -6,7 +6,7 @@ const CONFIG = {
'nodeRadius': 5, 'nodeRadius': 5,
'nodeRepositionPadding': 12, 'nodeRepositionPadding': 12,
'baseUrl': 'https://www.securityvision.io/wiki/index.php/', 'baseUrl': 'https://www.securityvision.io/wiki/index.php/',
'dataUrl': 'result3.json', 'dataUrl': 'result2.json',
'preSimulate': false, // run simulation before starting, so we don't start with lines jumping around 'preSimulate': false, // run simulation before starting, so we don't start with lines jumping around
'labels': { 'labels': {
'rotate': true, 'rotate': true,
@ -17,16 +17,6 @@ const CONFIG = {
'lonMax': 35, 'lonMax': 35,
'center': [11, 47], 'center': [11, 47],
}, },
"institution_map": {
"Local Government": "Government",
"Regional Government": "Government",
"International Organization": "Government",
"Watchdog": "Government",
// "NGO": "Organisation",
"Foundation": "NGO",
"University": "Research",
"Expert Group": "Research",
},
"filters": { "filters": {
"Institution": { "Institution": {
"label": "Institution", "label": "Institution",
@ -39,63 +29,62 @@ const CONFIG = {
// [12:08, 07-05-2021] Francesco Ragazzi: NGO, Foundation can be grouped // [12:08, 07-05-2021] Francesco Ragazzi: NGO, Foundation can be grouped
// [12:08, 07-05-2021] Francesco Ragazzi: University, Research, Expert group can be grouped // [12:08, 07-05-2021] Francesco Ragazzi: University, Research, Expert group can be grouped
// [12:08, 07-05-2021] Francesco Ragazzi: Watchdog and can also be grouped with government // [12:08, 07-05-2021] Francesco Ragazzi: Watchdog and can also be grouped with government
"Government": {
// "label": "Institution",
"type": "institution_types",
},
"Law Enforcement": { "Law Enforcement": {
// "label": "Institution", // "label": "Institution",
"type": "institution_types", "type": "institution_types",
}, },
"Company": {
// "label": "Institution",
"type": "institution_types",
},
"NGO": { "NGO": {
// "label": "Institution", // "label": "Institution",
"type": "institution_types", "type": "institution_types",
}, },
"Government": {
// "Regional Government": { // "label": "Institution",
// // "label": "Institution", "type": "institution_types",
// "type": "institution_types", },
// }, "Regional Government": {
// "Local Government": { // "label": "Institution",
// // "label": "Institution", "type": "institution_types",
// "type": "institution_types", },
// }, "Local Government": {
// "Foundation": { // "label": "Institution",
// // "label": "Institution", "type": "institution_types",
// "type": "institution_types", },
// }, "Company": {
// "University": { // "label": "Institution",
// // "label": "Institution", "type": "institution_types",
// "type": "institution_types", },
// }, "Foundation": {
// "label": "Institution",
"type": "institution_types",
},
"University": {
// "label": "Institution",
"type": "institution_types",
},
"Research": { "Research": {
// "label": "Institution", // "label": "Institution",
"type": "institution_types", "type": "institution_types",
}, },
// "Labour Union": { "Labour Union": {
// // "label": "Institution", // "label": "Institution",
// "type": "institution_types", "type": "institution_types",
// }, },
// "Watchdog": { "Watchdog": {
// // "label": "Institution", // "label": "Institution",
// "type": "institution_types", "type": "institution_types",
// }, },
// "Expert Group": { "Expert Group": {
// // "label": "Institution", // "label": "Institution",
// "type": "institution_types", "type": "institution_types",
// }, },
// "International Organization": { "International Organization": {
// // "label": "Institution", // "label": "Institution",
// "type": "institution_types", "type": "institution_types",
// }, },
// "Art Project": { "Art Project": {
// // "label": "Institution", // "label": "Institution",
// "type": "institution_types", "type": "institution_types",
// }, },
"Deployments": { "Deployments": {
"label": "Deployment", "label": "Deployment",
"type": "categories", "type": "categories",
@ -184,7 +173,7 @@ const CONFIG = {
}, },
"zoom": { "zoom": {
"scale_min": .2, "scale_min": .2,
"scale_max": 10, "scale_max": 20,
}, },
"cases": [ "cases": [
@ -343,7 +332,6 @@ function getCategories(obj) {
cats.push(getInstitutionClass(type.fulltext)); cats.push(getInstitutionClass(type.fulltext));
}); });
} }
// return
return cats; return cats;
} }
function getInstitutionClass(name) { function getInstitutionClass(name) {
@ -386,16 +374,8 @@ class NodeMap {
this.render(); this.render();
} }
// calculate which text labels overlap.
calculateLabels() { calculateLabels() {
let els; const els = document.querySelectorAll('.node text')
if(this.selectedNode === null) {
els = document.querySelectorAll('.node text')
} else {
// only related texts are visible
// so only these need to be considered
els = document.querySelectorAll('.node.linkedSelected text, .node.selected text')
}
for (let i = 0; i < els.length; i++) { for (let i = 0; i < els.length; i++) {
const el = els[i]; const el = els[i];
let overlapping = false; let overlapping = false;
@ -527,7 +507,6 @@ class NodeMap {
clearTimeout(zoomTimeout) clearTimeout(zoomTimeout)
} }
document.querySelector(':root').style.setProperty('--zoom', evt.transform.k); document.querySelector(':root').style.setProperty('--zoom', evt.transform.k);
document.querySelector(':root').style.setProperty('--zoom-sqrt', Math.pow(evt.transform.k, 1/3));
zoomTimeout = setTimeout(() => { zoomTimeout = setTimeout(() => {
this.g_nodes.attr('style', `font-size:${22000 / this.height / evt.transform.k}pt`) this.g_nodes.attr('style', `font-size:${22000 / this.height / evt.transform.k}pt`)
setTimeout(() => { setTimeout(() => {
@ -867,7 +846,6 @@ class NodeMap {
// see also: https://www.createwithdata.com/enter-exit-with-d3-join/ // see also: https://www.createwithdata.com/enter-exit-with-d3-join/
this.node = this.node.data(this.graph.nodes, d => d.id) this.node = this.node.data(this.graph.nodes, d => d.id)
.join((enter) => { .join((enter) => {
// let group = enter.insert("g", ":first-child")
let group = enter.append("g") let group = enter.append("g")
.attr("class", getClasses) .attr("class", getClasses)
.attr("id", (n) => getIdForTitle(n.fulltext)); .attr("id", (n) => getIdForTitle(n.fulltext));
@ -1002,7 +980,7 @@ class NodeMap {
.attr("class", (l) => "link " + slugify(l.name)) .attr("class", (l) => "link " + slugify(l.name))
.attr("id", getLinkId); .attr("id", getLinkId);
group.append("path") group.append("path")
// .attr("marker-end", "url(#arrowHead)") .attr("marker-end", "url(#arrowHead)")
.attr('id', (d, i) => 'linkpath_' + i) .attr('id', (d, i) => 'linkpath_' + i)
.on("mouseover", (ev, link) => { .on("mouseover", (ev, link) => {
d3.select(ev.target).classed('hover', true); d3.select(ev.target).classed('hover', true);
@ -1188,7 +1166,6 @@ class NodeMap {
} }
} }
// zoom & translate the graph to fit the provided nodes
zoomFit(nodes, paddingPercent = 0.8, transitionDuration = 2000) { zoomFit(nodes, paddingPercent = 0.8, transitionDuration = 2000) {
// var bounds = root.node().getBBox(); // var bounds = root.node().getBBox();
const x0 = Math.min(...nodes.map(n => n.x - CONFIG.nodeRadius)); const x0 = Math.min(...nodes.map(n => n.x - CONFIG.nodeRadius));
@ -1386,17 +1363,6 @@ JsonToGraph = function (data) {
i++; i++;
let node = data.results[node_id]; let node = data.results[node_id];
node.id = getIdForTitle(node.fulltext); //node_id; node.id = getIdForTitle(node.fulltext); //node_id;
// group institution types
if(node.printouts['Institution Type'].length ){
for (let idx = 0; idx < node.printouts['Institution Type'].length; idx++) {
const type = node.printouts['Institution Type'][idx];
if(CONFIG.institution_map.hasOwnProperty(type.fulltext)){
node.printouts['Institution Type'][idx].fulltext = CONFIG.institution_map[type.fulltext];
}
}
// node.printouts['Institution Type'] = CONFIG.institution_map[node.printouts['Institution Type']];
}
nodes.push(node); nodes.push(node);
// console.log(node_id, node); // console.log(node_id, node);
@ -1670,6 +1636,8 @@ class Store {
'institution_types': [], 'institution_types': [],
} }
this.filter(); this.filter();
} }
@ -1779,17 +1747,15 @@ class Store {
Object.keys(CONFIG.filters).forEach(f => { Object.keys(CONFIG.filters).forEach(f => {
const settings = CONFIG.filters[f]; const settings = CONFIG.filters[f];
// if (settings.type == 'institution_types') if (settings.type == 'institution_types')
// // TODO; For now, skip // TODO; For now, skip
// return; return;
let categories = [f]; let categories = [f];
if (settings.type == 'institution_types') if (settings.type == 'institution_types')
categories = ['Institution', getInstitutionClass(f)]; categories = ['Institution', getInstitutionClass(f)];
let labelEl = document.createElement('label'); let labelEl = document.createElement('label')
labelEl.setAttribute('id', 'filter-'+slugify(f));
labelEl.classList.add(settings.type)
let inputEl = document.createElement('input') let inputEl = document.createElement('input')
let textEl = document.createElement('span'); let textEl = document.createElement('span');
let svg = d3.select(labelEl).append('svg') let svg = d3.select(labelEl).append('svg')
@ -1799,7 +1765,7 @@ class Store {
.append('path') .append('path')
.attr('d', getSymbolForCategories(categories)()); .attr('d', getSymbolForCategories(categories)());
inputEl.type = "checkbox"; inputEl.type = "checkbox";
textEl.innerText = settings.hasOwnProperty('label') ? settings.label : f; textEl.innerText = f;
labelEl.appendChild(inputEl); labelEl.appendChild(inputEl);
labelEl.appendChild(textEl); labelEl.appendChild(textEl);
@ -1814,12 +1780,10 @@ class Store {
this.filters[settings.type].splice(i, 1); this.filters[settings.type].splice(i, 1);
} }
}); });
this.root.classList.remove('filter-'+slugify(f))
} else { } else {
if (!this.filters[settings.type].includes(f)) { if (!this.filters[settings.type].includes(f)) {
this.filters[settings.type].push(f); this.filters[settings.type].push(f);
} }
this.root.classList.add('filter-'+slugify(f))
} }
this.filter(); this.filter();
this.update(); this.update();
@ -1844,7 +1808,7 @@ Promise.all([fetch(req_data), fetch(req_world)])
}) })
.then(([data, world]) => { .then(([data, world]) => {
var graph = JsonToGraph(data); var graph = JsonToGraph(data);
var store = new Store(graph, '#filter-items'); var store = new Store(graph, '#filters');
mapGraph.setWorld(world); mapGraph.setWorld(world);
mapGraph.setStore(store); mapGraph.setStore(store);

View file

@ -9,7 +9,6 @@
<body> <body>
<div id='tooltip'></div> <div id='tooltip'></div>
<div id='closeSelection'>&times;</div>
<div id='map'></div> <div id='map'></div>
<!-- <div id='alluvial'></div> --> <!-- <div id='alluvial'></div> -->
@ -19,8 +18,7 @@
<aside id="filters"> <aside id="filters">
<h3 onclick="this.parentNode.classList.toggle('hide');">Filter</h3> <h3>Filter</h3>
<div id="filter-items"></div>
</aside> </aside>
</header> </header>