From 2dda26ff77670b8b056ca2c80bf7ea09a5e3e5d2 Mon Sep 17 00:00:00 2001 From: Ruben van de Ven Date: Wed, 28 Apr 2021 09:38:06 +0200 Subject: [PATCH] Title placement --- www/graph.css | 229 +++++++++++++++++++++++++++++++++++-------------- www/graph.js | 96 ++++++++++++++++++--- www/index.html | 33 ++++--- 3 files changed, 268 insertions(+), 90 deletions(-) diff --git a/www/graph.css b/www/graph.css index aaf449b..8af3e5e 100644 --- a/www/graph.css +++ b/www/graph.css @@ -1,5 +1,11 @@ +@font-face { + font-family: 'Lexend Mega Regular'; + font-style: normal; + font-weight: normal; + src: local('Lexend Mega Regular'), url('LexendMega-Regular.woff') format('woff'); +} -:root{ +:root { --color1: #f94144; --color2: #f3722c; --color3: #f8961e; @@ -10,7 +16,6 @@ --color8: #4d908e; --color9: #577590; --color10: #277da1; - --hover-color: var(--color1); /* --hover-color: var(darkblue); */ --selected-color: var(--color1); @@ -21,7 +26,7 @@ body { margin: 0; /* overflow: hidden; */ /* background: linear-gradient(to top, #040308, #AD4A28, #DD723C, #fc7001, #dcb697, #9ba5ae, #3e5879, #020b1a); */ - background:linear-gradient(to top, #414141, #99a6b8); + background: linear-gradient(to top, #414141, #99a6b8); font-family: sans-serif; min-height: 100vh; } @@ -35,117 +40,168 @@ svg.dragging { cursor: grabbing; } -svg .links line,svg .links path{ +svg .links line, svg .links path { stroke: #f3722c; stroke-width: 6; - fill:none; + fill: none; transition: stroke-width 1s; cursor: pointer; } -svg .links line.hover, svg .links path.hover{ - stroke:var(--hover-color); +svg .links line.hover, svg .links path.hover { + stroke: var(--hover-color); stroke-width: 12; } -svg.zoomed .links line, svg.zoomed .links path{ +svg.zoomed .links line, svg.zoomed .links path { stroke-width: 2; } -svg.zoomed .links line, svg.zoomed .links path.hover{ + +svg.zoomed .links line, svg.zoomed .links path.hover { stroke-width: 2; stroke-width: 4; } -.links text{ - display:none; - font-size:5pt; +svg .title { + font-size: 200; +} + +svg .subtitle { + font-size: 100; +} + +svg #countries .country{ + fill:rgba(200,200,200,0.7); +} +svg #countries .country.eu_country{ + fill:black; +} + +svg #header #titlePath, svg #header #subtitlePath { + stroke: none; + fill: none; +} + +svg #header text { + font-size: 180px; + font-family: "Lexend Mega Regular"; + /*Comfortaa*/ + opacity: .8; + fill: black; + text-shadow: rgba(0, 0, 0, .5) 5px 5px 10px; + /* text-transform: uppercase; */ +} + +svg #header text:nth-of-type(2) { + dominant-baseline: hanging; + transform: translate(10px, 25px); +} + +svg #header text#subtitle { + font-size: 70px; + fill: var(--color9); +} + +.links text { + display: none; + font-size: 5pt; text-anchor: middle; fill: whitesmoke; } -.node{ - +.node { cursor: pointer; } -.node text.nodeTitle{ +.node text.nodeTitle { text-anchor: start; - dominant-baseline: hanging; /*achieves a 'text-anchor: top'*/ - font-size:16pt; + dominant-baseline: hanging; + /*achieves a 'text-anchor: top'*/ + font-size: 16pt; transition: font-size .4s, opacity 1s; fill: white; opacity: 1; - pointer-events: none; /*prevent mouse glitches*/ + pointer-events: none; + /*prevent mouse glitches*/ } -.node:not(:hover):not(.linkHover) text.nodeTitle.overlapping{ + +.node:not(:hover):not(.linkHover) text.nodeTitle.overlapping { opacity: 0; } - -svg.zoomed .node text.nodeTitle{ - font-size:6pt; -} -svg.zoomed.zoomed2 .node text.nodeTitle{ - font-size:3pt; +svg.zoomed .node text.nodeTitle { + font-size: 6pt; } -.node circle{ +svg.zoomed.zoomed2 .node text.nodeTitle { + font-size: 3pt; +} + +.node circle { fill: white; } /* Whenever a connected link is hovered */ -.node.linkHover circle{ + +.node.linkHover circle { stroke: var(--hover-color); stroke-width: 5px; } -.node.linkHover text.nodeTitle.overlapping{ + +.node.linkHover text.nodeTitle.overlapping { transition: opacity 0s; } -.node:hover circle{ +.node:hover circle { stroke: var(--hover-color); stroke-width: 5px; } -.node:hover text{ + +.node:hover text { transition: none; - fill: var(--hover-color); + fill: var(--hover-color); } -.node.selected circle{ + +.node.selected circle { stroke: var(--selected-color); stroke-width: 5px; } -.node.City circle{ - display:none; +.node.City circle { + display: none; } -.node.City{ - fill:white; + +.node.City { + fill: white; stroke: black; stroke-width: .5px; font-size: 20px; } + .node.Person circle { fill: lightgreen } + .node.Technology circle { fill: lightcoral; } + .node.Deployment circle { fill: lightblue; } + .node.Institution circle { fill: lightgoldenrodyellow } + .node.Dataset circle { fill: plum } - - -.labels .label text{ - fill:yellow; +.labels .label text { + fill: yellow; opacity: 1 !important; -} +} /* .node.Person circle { fill: var(--color2) @@ -163,69 +219,114 @@ svg.zoomed.zoomed2 .node text.nodeTitle{ fill: var(--color7) } */ - -#nodeInfo{ +#nodeInfo { position: fixed; - display:block; - right:20px; - bottom:20px; - background:white; + display: block; + right: 20px; + bottom: 20px; + background: white; padding: 10px; border: solid 1px #ccc; } -#nodeInfo.hidden{ - display:none; +#nodeInfo.hidden { + display: none; } -#nodeInfo h2{ +#nodeInfo h2 { margin: 0; padding: 0; } -#nodeInfo iframe{ +#nodeInfo iframe { width: 50vw; height: calc(100vh - 40px - 20px - 30px); } -#closeInfo{ +#closeInfo { cursor: pointer; position: absolute; right: 10px; top: 10px; } -#closeInfo:hover{ +#closeInfo:hover { color: var(--hover-color); } -a, a:link{ +a, a:link { text-decoration: none; } -a:hover{ + +a:hover { text-decoration: underline; } -#filters,#menu{ +header { position: fixed; - left: 0; - top: 0; + bottom: 0; + right: 0; background: white; padding: 10px; } -#map .borders{ +h1 { + /* color:var(--color9); */ + margin: 0; + text-transform: uppercase; + display: none; +} + +p.subtitle { + margin: 0; + color: var(--color10); + /* text-transform: uppercase;; */ + display: none; +} + +#filters h3{ + text-align: center;; +} +#filters label { + cursor: pointer; + display: block; + padding: 10px; +} + +#filters span:hover { + color: var(--hover-color); +} + +#filters input { + /* display: none; */ +} + +#filters input+span { + display: inline-block; + padding-left: 10px; + + /* background: var(--color9); */ + text-decoration:line-through; +} + +#filters input:checked+span { + /* color: var(--selected-color); */ + text-decoration: none; + /* box-shadow: inset 0 0 5px black; */ +} + +#map .borders { stroke-width: 6px; stroke: white; - fill:none; + fill: none; } -#alluvial{ +#alluvial { /* position:fixed; */ - top:0; - left:0; + top: 0; + left: 0; } -#alluvial .flow_label text{ +#alluvial .flow_label text { font-size: 30; } \ No newline at end of file diff --git a/www/graph.js b/www/graph.js index b128b7d..df6faa4 100644 --- a/www/graph.js +++ b/www/graph.js @@ -1,5 +1,7 @@ const CONFIG = { + 'title': "Biometric Mass Surveillance", + 'subtitle': "Connections in the European Union & beyond", // 'nodeSize': 8, 'nodeRadius': 5, 'nodeRepositionPadding': 3, @@ -56,6 +58,29 @@ const CONFIG = { // let height = window.innerHeight; +// 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, ''); + + // Make the string lowercase + str = str.toLowerCase(); + + // Remove accents, swap ñ for n, etc + var from = "ÁÄÂÀÃÅČÇĆĎÉĚËÈÊẼĔȆÍÌÎÏŇÑÓÖÒÔÕØŘŔŠŤÚŮÜÙÛÝŸŽáäâàãåčçćďéěëèêẽĕȇíìîïňñóöòôõøðřŕšťúůüùûýÿžþÞĐđßÆa·/_,:;"; + var to = "AAAAAACCCDEEEEEEEEIIIINNOOOOOORRSTUUUUUYYZaaaaaacccdeeeeeeeeiiiinnooooooorrstuuuuuyyzbBDdBAa------"; + for (var i = 0, l = from.length; i < l; i++) { + str = str.replace(new RegExp(from.charAt(i), 'g'), to.charAt(i)); + } + + // Remove invalid chars + str = str.replace(/[^a-z0-9 -]/g, '') + // Collapse whitespace and replace by - + .replace(/\s+/g, '-') + // Collapse dashes + .replace(/-+/g, '-'); + + return str; +} @@ -202,6 +227,7 @@ class NodeMap { render() { this.svg = this.root.append('svg') this.svg.append('defs').html(''); + this.resize(); this.projection = d3.geoHill() @@ -236,14 +262,14 @@ class NodeMap { .data(this.countries) .enter() .append("path") - .attr("class", "countries") - .attr("d", this.proj) - .attr("fill", (n) => { + .attr("class", (n) => { if (CONFIG.countries.indexOf(n.properties.name) !== -1) { - return ''; + return 'country eu_country'; } - return "rgba(200,200,200,.7)"; - }); + return "country"; + }) + .attr("d", this.proj) + // .attr("fill", ); this.g_borders .append("path") @@ -270,6 +296,49 @@ class NodeMap { .call(zoom) .call(zoom.transform, d3.zoomIdentity.scale(.5, .5)); + this.title = this.container.append('g').attr('id', 'header'); + + const titleFeature = { + "type": "LineString", + "coordinates": [] + }; + const subtitleFeature = { + "type": "LineString", + "coordinates": [] + }; + for (let index = 26; index < 70; index++) { + // projection apparently tries to find the shortest path between two points + // which is NOT following a lat/lon line on the globe + titleFeature.coordinates.push([index, 52]); + subtitleFeature.coordinates.push([index, 49]); + } + this.title.append("path") + .attr("id", "titlePath") + .attr("d", this.proj(titleFeature)) + ; + this.title.append("path") + .attr("id", "subtitlePath") + .attr("d", this.proj(subtitleFeature)) + ; + this.title.append("text") + .html('Biometric') + this.title.append("text") + .html('Mass Surveillance') + this.title.append("text") + .attr("id", "subtitle") + .html('' + CONFIG.subtitle + '') + + // this.title.append('text') + // .attr('class', 'title') + // .attr('x', 1000) + // .attr('y', 1000) + // .text(CONFIG.title); + // this.title.append('text') + // .attr('class', 'subtitle') + // .attr('x', 1000) + // .attr('y', 1200) + // .text(CONFIG.subtitle); + this.link = this.container.append("g") .attr('class', 'links') .selectAll(".link"); @@ -376,7 +445,7 @@ class NodeMap { let alpha = 0; // angle let step = 1; const d_alpha = Math.PI / 4; - const r = this.getNodeRadius(n) + CONFIG.nodeRepositionPadding/2; + const r = this.getNodeRadius(n) + CONFIG.nodeRepositionPadding / 2; let foundNodes; let i = 0; // find a new pos until it's not overlapping anymore... @@ -387,10 +456,10 @@ class NodeMap { this.store.quadtree.add(n); alpha += d_alpha; // on to the next round: - if(alpha > Math.PI * 2) { + if (alpha > Math.PI * 2) { step++; - alpha -= Math.PI *2; - alpha += d_alpha-2; // little offset + alpha -= Math.PI * 2; + alpha += d_alpha - 2; // little offset } i++; @@ -406,9 +475,9 @@ class NodeMap { if (i > 0) { // we moved something, update tree - + console.debug('resolved for', n.fulltext, i); - moved ++; + moved++; } }); @@ -516,7 +585,8 @@ class NodeMap { .data(this.graph.links) .join( enter => { - let group = enter.append("g").attr("class", "link"); + let group = enter.append("g") + .attr("class", (l) => "link " + slugify(l.name)); group.append("path") .attr("marker-end", "url(#arrowHead)") .attr('id', (d, i) => 'linkid_' + i) diff --git a/www/index.html b/www/index.html index 5fc6b0e..8b80336 100644 --- a/www/index.html +++ b/www/index.html @@ -3,27 +3,34 @@ - + -
-
+
+ -
- -
+
+

Biometric Mass Surveillance

+

Connections in the European Union & beyond

- - - - + - - - +
+ + + + + + + + + + \ No newline at end of file