Fancier markers and legend

This commit is contained in:
Ruben van de Ven 2021-04-28 11:18:02 +02:00
parent 7751fc05a8
commit 4dec76a325
2 changed files with 84 additions and 29 deletions

View File

@ -6,7 +6,7 @@
} }
:root { :root {
--color1: #f94144; --color1: #9741f9;
--color2: #f3722c; --color2: #f3722c;
--color3: #f8961e; --color3: #f8961e;
/* --color4: #f9844a; */ /* --color4: #f9844a; */
@ -40,8 +40,17 @@ svg.dragging {
cursor: grabbing; cursor: grabbing;
} }
#arrowHead {
fill: #9df32c;
}
#arrowHeadSelected {
fill: var(--hover-color);;
}
svg .links line, svg .links path { svg .links line, svg .links path {
stroke: #f3722c; stroke: #f3722c;
stroke: #9df32c;
stroke-width: 6; stroke-width: 6;
fill: none; fill: none;
transition: stroke-width 1s; transition: stroke-width 1s;
@ -51,6 +60,7 @@ svg .links line, svg .links path {
svg .links line.hover, svg .links path.hover { svg .links line.hover, svg .links path.hover {
stroke: var(--hover-color); stroke: var(--hover-color);
stroke-width: 12; stroke-width: 12;
marker-end: url(#arrowHeadSelected);
} }
svg.zoomed .links line, svg.zoomed .links path { svg.zoomed .links line, svg.zoomed .links path {
@ -70,11 +80,12 @@ svg .subtitle {
font-size: 100; font-size: 100;
} }
svg #countries .country{ svg #countries .country {
fill:rgba(200,200,200,0.7); fill: rgba(200, 200, 200, 0.7);
} }
svg #countries .country.eu_country{
fill:black; svg #countries .country.eu_country {
fill: black;
} }
svg #header #titlePath, svg #header #subtitlePath { svg #header #titlePath, svg #header #subtitlePath {
@ -117,7 +128,8 @@ svg #header text#subtitle {
text-anchor: start; text-anchor: start;
dominant-baseline: hanging; dominant-baseline: hanging;
/*achieves a 'text-anchor: top'*/ /*achieves a 'text-anchor: top'*/
/* font-size: 16pt; */ /*Set this in JS*/ /* font-size: 16pt; */
/*Set this in JS*/
transition: font-size .4s, opacity 1s; transition: font-size .4s, opacity 1s;
fill: white; fill: white;
opacity: 1; opacity: 1;
@ -137,13 +149,14 @@ svg.zoomed.zoomed2 .node text.nodeTitle {
font-size: 3pt; font-size: 3pt;
} }
.node circle { .node circle, .node path {
fill: white; fill: lightgray;
} }
/* Whenever a connected link is hovered */ /* Whenever a connected link is hovered */
.node.linkHover circle { .node.linkHover circle, .node.linkHover path, label:hover .node path {
fill: var(--hover-color) !important;
stroke: var(--hover-color); stroke: var(--hover-color);
stroke-width: 5px; stroke-width: 5px;
} }
@ -152,7 +165,8 @@ svg.zoomed.zoomed2 .node text.nodeTitle {
transition: opacity 0s; transition: opacity 0s;
} }
.node:hover circle { .node:hover circle, .node:hover path {
fill: var(--hover-color) !important;
stroke: var(--hover-color); stroke: var(--hover-color);
stroke-width: 5px; stroke-width: 5px;
} }
@ -162,12 +176,13 @@ svg.zoomed.zoomed2 .node text.nodeTitle {
fill: var(--hover-color); fill: var(--hover-color);
} }
.node.selected circle { .node.selected circle, .node.selected path {
fill: var(--selected-color) !important;
stroke: var(--selected-color); stroke: var(--selected-color);
stroke-width: 5px; stroke-width: 5px;
} }
.node.City circle { .node.City circle, .node.City path {
display: none; display: none;
} }
@ -178,24 +193,24 @@ svg.zoomed.zoomed2 .node text.nodeTitle {
font-size: 20px; font-size: 20px;
} }
.node.Person circle { .node.Person circle, .node.Person path {
fill: lightgreen fill: lightgreen
} }
.node.Technology circle { .node.Technology circle, .node.Technology path {
fill: lightcoral; fill: plum;
} }
.node.Deployment circle { .node.Deployments circle, .node.Deployments path {
fill: lightblue; fill: lightblue;
} }
.node.Institution circle { .node.Institution circle, .node.Institution path {
fill: lightgoldenrodyellow fill: lightcoral
} }
.node.Dataset circle { .node.Dataset circle, .node.Dataset path {
fill: plum fill: lightgoldenrodyellow
} }
.labels .label text { .labels .label text {
@ -284,29 +299,37 @@ p.subtitle {
display: none; display: none;
} }
#filters h3{ #filters h3 {
text-align: center;; text-align: center;
;
} }
#filters label { #filters label {
cursor: pointer; cursor: pointer;
display: block; display: block;
padding: 10px; padding: 10px;
} }
#filters label svg {
display: inline;
width: 30px;
height: 30px;
vertical-align: middle;
}
#filters span:hover { #filters span:hover {
color: var(--hover-color); color: var(--hover-color);
} }
#filters input { #filters input {
/* display: none; */ display: none;
} }
#filters input+span { #filters input+span {
display: inline-block; display: inline-block;
padding-left: 10px; padding-left: 10px;
/* background: var(--color9); */ /* background: var(--color9); */
text-decoration:line-through; text-decoration: line-through;
} }
#filters input:checked+span { #filters input:checked+span {

View File

@ -4,7 +4,7 @@ const CONFIG = {
'subtitle': "Connections in the European Union & beyond", 'subtitle': "Connections in the European Union & beyond",
// 'nodeSize': 8, // 'nodeSize': 8,
'nodeRadius': 5, 'nodeRadius': 5,
'nodeRepositionPadding': 3, 'nodeRepositionPadding': 8,
'baseUrl': 'https://www.securityvision.io/wiki/index.php/', 'baseUrl': 'https://www.securityvision.io/wiki/index.php/',
'dataUrl': 'result.json', 'dataUrl': 'result.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
@ -58,6 +58,27 @@ const CONFIG = {
// let height = window.innerHeight; // let height = window.innerHeight;
function getSymbolForCategories(classes) {
if(!Array.isArray(classes)) {
classes = [classes];
}
if (classes.includes('Institution')) {
return d3.symbol()
.type(d3.symbolTriangle)
.size(CONFIG.nodeRadius * 16);
}
return d3.symbol()
.type(d3.symbolCircle)
.size(CONFIG.nodeRadius * 16);
}
// returns a symbol function
function getSymbolForNode(n) {
const classes = getCategories(n);
return getSymbolForCategories(classes);
}
// Slugify a string, by https://lucidar.me/en/web-dev/how-to-slugify-a-string-in-javascript/ // Slugify a string, by https://lucidar.me/en/web-dev/how-to-slugify-a-string-in-javascript/
function slugify(str) { function slugify(str) {
str = str.replace(/^\s+|\s+$/g, ''); str = str.replace(/^\s+|\s+$/g, '');
@ -226,7 +247,7 @@ class NodeMap {
render() { render() {
this.svg = this.root.append('svg') this.svg = this.root.append('svg')
this.svg.append('defs').html(`<marker markerHeight="4" markerWidth="4" refY="0" refX="6" viewBox="0 -3 8 6" preserveAspectRatio="none" orient="auto" id="arrowHead" fill="#f3722c"><path d="M0,-3L8,0L0,3"></path></marker><marker markerHeight="4" markerWidth="4" refY="0" refX="6" viewBox="0 -3 8 6" preserveAspectRatio="none" orient="auto" id="arrowHeadSelected"><path d="M0,-3L8,0L0,3" fill="white"></path></marker> this.svg.append('defs').html(`<marker markerHeight="4" markerWidth="4" refY="0" refX="6" viewBox="0 -3 8 6" preserveAspectRatio="none" orient="auto" id="arrowHead" ><path d="M0,-3L8,0L0,3"></path></marker><marker markerHeight="4" markerWidth="4" refY="0" refX="6" viewBox="0 -3 8 6" preserveAspectRatio="none" orient="auto" id="arrowHeadSelected"><path d="M0,-3L8,0L0,3"></path></marker>
<!--Sketching:--> <!--Sketching:-->
<defs> <defs>
<filter id="tint"> <filter id="tint">
@ -302,7 +323,7 @@ class NodeMap {
this.container.attr("transform", transform); this.container.attr("transform", transform);
const oldZoom = this.svg.classed('zoomed'); const oldZoom = this.svg.classed('zoomed');
const newZoom = transform.k > 2.0; const newZoom = transform.k > 2.0;
if(zoomTimeout) { if (zoomTimeout) {
clearTimeout(zoomTimeout) clearTimeout(zoomTimeout)
} }
zoomTimeout = setTimeout(() => { zoomTimeout = setTimeout(() => {
@ -522,7 +543,11 @@ class NodeMap {
let group = enter.append("g").attr("class", getClasses); let group = enter.append("g").attr("class", getClasses);
// group.call(drag(simulation)); // group.call(drag(simulation));
group.on("click", (evt, n) => selectNode(evt, n, node)); group.on("click", (evt, n) => selectNode(evt, n, node));
group.append('circle').attr("r", 5 /*this.nodeSize*/); // group.append('circle').attr("r", 5 /*this.nodeSize*/);
group.append('path')
.attr('d', (n) => {
return getSymbolForNode(n)(n);
})
var nodeTitle = group.append('text').attr("class", "nodeTitle").attr("y", "3").attr('x', 5); var nodeTitle = group.append('text').attr("class", "nodeTitle").attr("y", "3").attr('x', 5);
nodeTitle nodeTitle
.each(function (node, i, nodes) { .each(function (node, i, nodes) {
@ -1288,9 +1313,16 @@ class Store {
render() { render() {
CONFIG.filters.forEach(f => { CONFIG.filters.forEach(f => {
let labelEl = document.createElement('label') let labelEl = document.createElement('label')
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')
.attr("viewBox", [-12,-12,24,24]);
svg.append('g')
.attr("class", "node "+ f)
.append('path')
.attr('d', getSymbolForCategories(f)());
inputEl.type = "checkbox"; inputEl.type = "checkbox";
textEl.innerText = f; textEl.innerText = f;
labelEl.appendChild(inputEl); labelEl.appendChild(inputEl);