forked from security_vision/semantic_graph
Fancier markers and legend
This commit is contained in:
parent
7751fc05a8
commit
4dec76a325
2 changed files with 84 additions and 29 deletions
|
@ -6,7 +6,7 @@
|
|||
}
|
||||
|
||||
:root {
|
||||
--color1: #f94144;
|
||||
--color1: #9741f9;
|
||||
--color2: #f3722c;
|
||||
--color3: #f8961e;
|
||||
/* --color4: #f9844a; */
|
||||
|
@ -40,8 +40,17 @@ svg.dragging {
|
|||
cursor: grabbing;
|
||||
}
|
||||
|
||||
#arrowHead {
|
||||
fill: #9df32c;
|
||||
}
|
||||
|
||||
#arrowHeadSelected {
|
||||
fill: var(--hover-color);;
|
||||
}
|
||||
|
||||
svg .links line, svg .links path {
|
||||
stroke: #f3722c;
|
||||
stroke: #9df32c;
|
||||
stroke-width: 6;
|
||||
fill: none;
|
||||
transition: stroke-width 1s;
|
||||
|
@ -51,6 +60,7 @@ svg .links line, svg .links path {
|
|||
svg .links line.hover, svg .links path.hover {
|
||||
stroke: var(--hover-color);
|
||||
stroke-width: 12;
|
||||
marker-end: url(#arrowHeadSelected);
|
||||
}
|
||||
|
||||
svg.zoomed .links line, svg.zoomed .links path {
|
||||
|
@ -70,11 +80,12 @@ svg .subtitle {
|
|||
font-size: 100;
|
||||
}
|
||||
|
||||
svg #countries .country{
|
||||
fill:rgba(200,200,200,0.7);
|
||||
svg #countries .country {
|
||||
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 {
|
||||
|
@ -117,7 +128,8 @@ svg #header text#subtitle {
|
|||
text-anchor: start;
|
||||
dominant-baseline: hanging;
|
||||
/*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;
|
||||
fill: white;
|
||||
opacity: 1;
|
||||
|
@ -137,13 +149,14 @@ svg.zoomed.zoomed2 .node text.nodeTitle {
|
|||
font-size: 3pt;
|
||||
}
|
||||
|
||||
.node circle {
|
||||
fill: white;
|
||||
.node circle, .node path {
|
||||
fill: lightgray;
|
||||
}
|
||||
|
||||
/* 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-width: 5px;
|
||||
}
|
||||
|
@ -152,7 +165,8 @@ svg.zoomed.zoomed2 .node text.nodeTitle {
|
|||
transition: opacity 0s;
|
||||
}
|
||||
|
||||
.node:hover circle {
|
||||
.node:hover circle, .node:hover path {
|
||||
fill: var(--hover-color) !important;
|
||||
stroke: var(--hover-color);
|
||||
stroke-width: 5px;
|
||||
}
|
||||
|
@ -162,12 +176,13 @@ svg.zoomed.zoomed2 .node text.nodeTitle {
|
|||
fill: var(--hover-color);
|
||||
}
|
||||
|
||||
.node.selected circle {
|
||||
.node.selected circle, .node.selected path {
|
||||
fill: var(--selected-color) !important;
|
||||
stroke: var(--selected-color);
|
||||
stroke-width: 5px;
|
||||
}
|
||||
|
||||
.node.City circle {
|
||||
.node.City circle, .node.City path {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
@ -178,24 +193,24 @@ svg.zoomed.zoomed2 .node text.nodeTitle {
|
|||
font-size: 20px;
|
||||
}
|
||||
|
||||
.node.Person circle {
|
||||
.node.Person circle, .node.Person path {
|
||||
fill: lightgreen
|
||||
}
|
||||
|
||||
.node.Technology circle {
|
||||
fill: lightcoral;
|
||||
.node.Technology circle, .node.Technology path {
|
||||
fill: plum;
|
||||
}
|
||||
|
||||
.node.Deployment circle {
|
||||
.node.Deployments circle, .node.Deployments path {
|
||||
fill: lightblue;
|
||||
}
|
||||
|
||||
.node.Institution circle {
|
||||
fill: lightgoldenrodyellow
|
||||
.node.Institution circle, .node.Institution path {
|
||||
fill: lightcoral
|
||||
}
|
||||
|
||||
.node.Dataset circle {
|
||||
fill: plum
|
||||
.node.Dataset circle, .node.Dataset path {
|
||||
fill: lightgoldenrodyellow
|
||||
}
|
||||
|
||||
.labels .label text {
|
||||
|
@ -284,29 +299,37 @@ p.subtitle {
|
|||
display: none;
|
||||
}
|
||||
|
||||
#filters h3{
|
||||
text-align: center;;
|
||||
#filters h3 {
|
||||
text-align: center;
|
||||
;
|
||||
}
|
||||
|
||||
#filters label {
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
#filters label svg {
|
||||
display: inline;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
#filters span:hover {
|
||||
color: var(--hover-color);
|
||||
}
|
||||
|
||||
#filters input {
|
||||
/* display: none; */
|
||||
display: none;
|
||||
}
|
||||
|
||||
#filters input+span {
|
||||
display: inline-block;
|
||||
padding-left: 10px;
|
||||
|
||||
/* background: var(--color9); */
|
||||
text-decoration:line-through;
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
#filters input:checked+span {
|
||||
|
|
40
www/graph.js
40
www/graph.js
|
@ -4,7 +4,7 @@ const CONFIG = {
|
|||
'subtitle': "Connections in the European Union & beyond",
|
||||
// 'nodeSize': 8,
|
||||
'nodeRadius': 5,
|
||||
'nodeRepositionPadding': 3,
|
||||
'nodeRepositionPadding': 8,
|
||||
'baseUrl': 'https://www.securityvision.io/wiki/index.php/',
|
||||
'dataUrl': 'result.json',
|
||||
'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;
|
||||
|
||||
|
||||
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/
|
||||
function slugify(str) {
|
||||
str = str.replace(/^\s+|\s+$/g, '');
|
||||
|
@ -226,7 +247,7 @@ class NodeMap {
|
|||
|
||||
render() {
|
||||
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:-->
|
||||
<defs>
|
||||
<filter id="tint">
|
||||
|
@ -302,7 +323,7 @@ class NodeMap {
|
|||
this.container.attr("transform", transform);
|
||||
const oldZoom = this.svg.classed('zoomed');
|
||||
const newZoom = transform.k > 2.0;
|
||||
if(zoomTimeout) {
|
||||
if (zoomTimeout) {
|
||||
clearTimeout(zoomTimeout)
|
||||
}
|
||||
zoomTimeout = setTimeout(() => {
|
||||
|
@ -522,7 +543,11 @@ class NodeMap {
|
|||
let group = enter.append("g").attr("class", getClasses);
|
||||
// group.call(drag(simulation));
|
||||
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);
|
||||
nodeTitle
|
||||
.each(function (node, i, nodes) {
|
||||
|
@ -1288,9 +1313,16 @@ class Store {
|
|||
|
||||
render() {
|
||||
CONFIG.filters.forEach(f => {
|
||||
|
||||
let labelEl = document.createElement('label')
|
||||
let inputEl = document.createElement('input')
|
||||
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";
|
||||
textEl.innerText = f;
|
||||
labelEl.appendChild(inputEl);
|
||||
|
|
Loading…
Reference in a new issue