Title placement

This commit is contained in:
Ruben van de Ven 2021-04-28 09:38:06 +02:00
parent 9a79cea9d7
commit 2dda26ff77
3 changed files with 268 additions and 90 deletions

View File

@ -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;
}

View File

@ -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('<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.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('<textPath xlink:href="#titlePath">Biometric</textPath>')
this.title.append("text")
.html('<textPath xlink:href="#titlePath">Mass Surveillance</textPath>')
this.title.append("text")
.attr("id", "subtitle")
.html('<textPath xlink:href="#subtitlePath">' + CONFIG.subtitle + '</textPath>')
// 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)

View File

@ -3,27 +3,34 @@
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="graph.css">
</head>
<body>
<div id='map'></div>
<div id='alluvial'></div>
<div id='map'></div>
<!-- <div id='alluvial'></div> -->
<div id="filters">
</div>
<header>
<h1>Biometric Mass Surveillance</h1>
<p class='subtitle'>Connections in the European Union & beyond</p>
<script src="https://d3js.org/d3.v6.js"></script>
<script src="https://d3js.org/d3-geo-projection.v3.min.js"></script>
<script src="https://d3js.org/topojson.v3.min.js"></script>
<script src="//unpkg.com/d3-geo-zoom"></script>
<aside id="filters">
<h3>Legend</h3>
</aside>
<script src="https://unpkg.com/d3-sankey@0"></script>
<!-- <script src="//unpkg.com/d3fc@14.0.1"></script> -->
<script src="graph.js"></script>
</header>
<script src="https://d3js.org/d3.v6.js"></script>
<script src="https://d3js.org/d3-geo-projection.v3.min.js"></script>
<script src="https://d3js.org/topojson.v3.min.js"></script>
<script src="//unpkg.com/d3-geo-zoom"></script>
<script src="https://unpkg.com/d3-sankey@0"></script>
<!-- <script src="//unpkg.com/d3fc@14.0.1"></script> -->
<script src="graph.js"></script>
</body>
</html>