intia-theme 0.1.55 → 0.1.58

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e11e8ffb9117ba3c2c84d577e7bcadf8b2448ca3c928258c736f692bb3242c3f
4
- data.tar.gz: 92bd9a1442b8ce5eb5cee06b55fbfa4132a866227c890cce3e5041fb7294ee55
3
+ metadata.gz: d25c5ec7822b7e8507e5e37884f63ac9c5d52f8d00db0179b62009c839a7086c
4
+ data.tar.gz: ef34a988198fe93e6b2b459197e5b7a7f5de38b405de6b021602822330b1c097
5
5
  SHA512:
6
- metadata.gz: f21348681e693afd862ad1a9ff1df839a0eb6b43a73f64d4633e420e6aa0d8e821556f2de35168f49c2715383957a706e1c3d9a63b78139848fb4643bae244a3
7
- data.tar.gz: f0f76f7d6ca8bfe9127528f8ff0f826dc1cc1c0880f07842cabb5e1067de2a67c20167f0458bd57f27d7bbad70456191ad5d6946e0ac53b275e58860cb85be09
6
+ metadata.gz: bc7fc1d7430b70b258f754e22de2639f23e284f14497dd5916b6ea823abac5c3130579b45209fb4f13c394ca5f3f9121701e1558c80541343a1e796d45e41cae
7
+ data.tar.gz: 8716e317c6f3dd200c9024ab1885d79279354cf25b9612656799787082e3ebb3ecbc6d31cb6311ad3733ca7cff0b67e7343a7ebcab8fd1aeb55c64ab3f117fc1
@@ -1,6 +1,6 @@
1
1
  {% assign entries=site.glossary | sort:page.sort %}
2
2
  {% for entry in entries %}
3
- <h2> {{entry.title}} </h2>
3
+ <h2 class="has-text-left"> {{entry.title}} </h2>
4
4
  <p class="text-green has-text-weight-bold">{{entry.subtitle}}</p>
5
5
 
6
6
  {{entry.abstract}}
data/_includes/head.html CHANGED
@@ -11,8 +11,9 @@
11
11
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma-carousel@4.0.3/dist/css/bulma-carousel.min.css">
12
12
  {% unless site.hide_radar %}
13
13
  <script src="https://d3js.org/d3.v5.min.js"></script>
14
- <script src="https://methods.intia.de/src/radar/radar.js"></script>
15
- <link rel="stylesheet" href="https://methods.intia.de/src/radar/radar.css" />
14
+ <!--<script src="https://methods.intia.de/src/radar/radar.js"></script>-->
15
+ <script src="{{ site.baseurl }}/assets/js/radar.js"></script>
16
+ <!--<link rel="stylesheet" href="https://methods.intia.de/src/radar/radar.css" />-->
16
17
  {% endunless %}
17
18
  {% unless site.hide_share_buttons %}
18
19
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma-social@1/bin/bulma-social.min.css">
@@ -2,7 +2,7 @@
2
2
  <div class="container">
3
3
  <div class="navbar-brand">
4
4
  <a href="{{ site.baseurl }}/" class="">
5
- <img src="{{ site.baseurl }}/assets/img/logo-black.png">
5
+ <img id="navbar-logo" src="/assets/img/logo-horizontal-short.png">
6
6
  </a>
7
7
  <a role="button" class="navbar-burger burger" aria-label="menu" aria-expanded="false" data-target="navMenu"
8
8
  :class="{ 'is-active': openNav }" x-on:click="openNav = !openNav">
data/_sass/_main.scss CHANGED
@@ -17,3 +17,4 @@ $dark: #09443e;
17
17
  @import "helper";
18
18
  @import "icons";
19
19
  @import "print";
20
+ @import "radar";
data/_sass/_radar.scss ADDED
@@ -0,0 +1,317 @@
1
+ #radar {
2
+ /* Generel */
3
+ --fontFamily: "Verdana", sans-serif;
4
+ --borderRadius: 0;
5
+ --lineWidth: 1;
6
+ --spacing: 8px;
7
+ --textPadding: 0.25em;
8
+ --dropdownBoxShadow: 0 5px 20px rgba(0,0,0,0.1);
9
+ /* FontSizes */
10
+ --radarDropdown: 16px;
11
+ --radarCardTitle: 16px;
12
+ --radarCardItem: 14px;
13
+ --radarName: 30px;
14
+ --radarSelectionButton: 14px;
15
+ --radarSectorName: 16px;
16
+ --radarSegmentName: 11px;
17
+ --radarLegendCardItemText: 14px;
18
+ --radarBlipLegendSector: 14px;
19
+ --radarBlipLegendSegment: 12px;
20
+ --radarBlipLegendBlip: 11px;
21
+ /* Colors */
22
+ --primaryFontColor: #000000;
23
+ --secondaryFontColor: #ffffff;
24
+ --cardBackgroundColor: #ffffff;
25
+ --buttonHoverColor: #ecf0f1;
26
+ --lineColor: rgb(255, 255, 255);
27
+ --bubbleColor: rgba(178, 190, 195,1.0);
28
+ }
29
+
30
+ /* #region div structur */
31
+ .radarContainer {
32
+ display: grid;
33
+ grid-template:
34
+ 'radarTitle'
35
+ 'radarSelection'
36
+ 'radar';
37
+ grid-gap: var(--spacing);
38
+ /* background-color: rgb(250, 250, 250); */
39
+ background-color: rgba(0, 0, 0, 0.02);
40
+ border-radius: var(--borderRadius);
41
+ padding: var(--spacing);
42
+ font-family: var(--fontFamily);
43
+ fill: var(--primaryFontColor);
44
+ }
45
+ .radarTitle {
46
+ grid-area: radarTitle;
47
+ font-size: var(--radarName);
48
+ padding: var(--textPadding);
49
+ border-radius: var(--borderRadius);
50
+ background-color: var(--cardBackgroundColor);
51
+ }
52
+ .radarSelection{
53
+ grid-area: radarSelection;
54
+ }
55
+ .radar{
56
+ grid-area: radar;
57
+ background-color: var(--cardBackgroundColor);
58
+ border-radius: var(--borderRadius);
59
+ padding: var(--spacing);
60
+ height: min-content;
61
+ }
62
+ .radarLegend{
63
+ margin-top: var(--spacing);
64
+ }
65
+ .radarBlipLegend{
66
+ overflow: auto;
67
+ grid-area: radarBlipLegend;
68
+ display: grid;
69
+ grid-auto-rows: min-content;
70
+ gap: var(--spacing);
71
+ }
72
+ /* #endregion */
73
+
74
+ /* #region dropdown */
75
+ .radarContainer .dropdown{
76
+ position: relative;
77
+ border-radius: var(--borderRadius);
78
+ /* padding: var(--textPadding); */
79
+ user-select: none;
80
+ cursor: pointer;
81
+ background-color: var(--cardBackgroundColor);
82
+ font-size: var(--radarDropdown);
83
+ }
84
+ .radarContainer .dropdown:hover{
85
+ background-color: var(--buttonHoverColor);
86
+ }
87
+ /* dropdown arrow */
88
+ .radarContainer .dropdown::before{
89
+ content: '';
90
+ position: absolute;
91
+ right: calc(var(--textPadding) * 2);
92
+ top: calc(var(--textPadding) * 2);
93
+ z-index: 10000;
94
+ width: calc(var(--radarDropdown) / 2);
95
+ height: calc(var(--radarDropdown) / 2);
96
+ border: 2px solid var(--primaryFontColor);
97
+ border-top: 2px solid rgba(0,0,0,0);
98
+ border-right: 2px solid rgba(0,0,0,0);
99
+ transform: rotate(-45deg);
100
+ transition: 250ms;
101
+ }
102
+ .radarContainer .dropdown.active::before{
103
+ top: calc(var(--textPadding) * 3);
104
+ transform: rotate(135deg);
105
+ }
106
+ .radarContainer .dropdownText{
107
+ width: 100%;
108
+ height: 100%;
109
+ }
110
+ .radarContainer .dropdown .dropdownContent{
111
+ position: absolute;
112
+ display: none;
113
+ user-select: none;
114
+ z-index: 10000;
115
+ border-radius: var(--borderRadius);
116
+ box-shadow: var(--dropdownBoxShadow);
117
+ background-color: var(--cardBackgroundColor);
118
+ width: 100%;
119
+ left: 0;
120
+ margin-top: var(--spacing);
121
+ }
122
+ .radarContainer .dropdown.active .dropdownContent{
123
+ display: block;
124
+ }
125
+ /* #endregion */
126
+
127
+ /* #region card */
128
+ .radarContainer .card{
129
+ padding: var(--spacing);
130
+ background-color: var(--cardBackgroundColor);
131
+ border-radius: var(--borderRadius);
132
+ }
133
+ .radarContainer .subCard{
134
+ padding: 0;
135
+ border-radius: var(--borderRadius);
136
+ }
137
+ .radarContainer .cardTitle{
138
+ padding: var(--textPadding);
139
+ font-size: var(--radarCardTitle);
140
+ font-weight: bold;
141
+ }
142
+ .radarContainer .cardItem{
143
+ position: relative;
144
+ border-radius: var(--borderRadius);
145
+ padding: var(--textPadding);
146
+ cursor: pointer;
147
+ }
148
+ .radarContainer .cardItem:hover{
149
+ background-color: var(--buttonHoverColor);
150
+ }
151
+ .radarContainer .cardItem.active{
152
+ background-color: var(--buttonHoverColor);
153
+ }
154
+ .radarContainer .cardItem .text{
155
+ font-size: var(--radarCardItem);
156
+ font-weight: lighter;
157
+ text-decoration: none;
158
+ }
159
+
160
+ /* #endregion */
161
+
162
+ /* #region radarSelection ------------------------------------------ */
163
+ .radarContainer .radarSelection{
164
+ text-align: center;
165
+ }
166
+ .radarContainer .selectionButton{
167
+ font-size: var(--radarSelectionButton);
168
+ text-align: center;
169
+ user-select: none;
170
+ padding: var(--textPadding);
171
+ border-radius: var(--borderRadius);
172
+ background-color: var(--cardBackgroundColor);
173
+ }
174
+ .radarContainer .selectionButton:hover{
175
+ background-color: var(--buttonHoverColor);
176
+ }
177
+ /* #endregion */
178
+
179
+ /* #region radar ------------------------------------------------ */
180
+ .radarContent{
181
+ display: inline-block;
182
+ position: relative;
183
+ width: 100%;
184
+ padding-bottom: 100%;
185
+ vertical-align: top;
186
+ overflow: visible;
187
+ border-top-left-radius: var(--borderRadius);
188
+ border-top-right-radius: var(--borderRadius);
189
+ background-color: var(--cardBackgroundColor);
190
+ }
191
+ .radarContent .radarSVG{
192
+ display: inline-block;
193
+ position: absolute;
194
+ top: 0;
195
+ left: 0;
196
+ /* margin: 8px; */
197
+ overflow: visible;
198
+ }
199
+
200
+ /* #region Text ------------------------------------------------------- */
201
+ .sectorName{
202
+ font-size: var(--radarSectorName);
203
+ font-weight: bold;
204
+ pointer-events: none;
205
+ user-select: none;
206
+ }
207
+ .radarContent .segmentName{
208
+ font-size: var(--radarSegmentName);
209
+ font-weight: bold;
210
+ pointer-events: none;
211
+ user-select: none;
212
+ }
213
+
214
+ .methodStatesText {
215
+ vertical-align: middle;
216
+ pointer-events: none;
217
+ user-select: none;
218
+ }
219
+ .blipText {
220
+ /* font-size scales by blipSize set in config-File */
221
+ font-weight: bold;
222
+ /* fill: var(--secondaryFontColor); */
223
+ fill: white;
224
+ pointer-events: none;
225
+ user-select: none;
226
+ }
227
+ .bubbleText {
228
+ /* font-size scales by blipSize set in config-File */
229
+ fill: var(--secondaryFontColor);
230
+ }
231
+ /* #endregion */
232
+
233
+ .radarBubble{
234
+ pointer-events: none;
235
+ user-select: none;
236
+ }
237
+ .radarBubble .background{
238
+ fill: var(--bubbleColor);
239
+ }
240
+ .radarLines{
241
+ stroke-width: var(--lineWidth);
242
+ stroke: var(--lineColor);
243
+ }
244
+ .radarContainer .blip{
245
+ cursor: pointer;
246
+ }
247
+ /* #endregion */
248
+
249
+ /* #region radarLegend --------------------------------------------- */
250
+ .radarLegend .dropdownContent{
251
+ height: 14rem;
252
+ overflow: auto;
253
+ }
254
+ .radarLegend .paddingText{
255
+ font-size: var(--radarLegendCardItemText);
256
+ padding-left: calc(var(--radarLegendCardItemText) + var(--textPadding));
257
+ font-weight: lighter;
258
+ text-decoration: none;
259
+ }
260
+ .radarLegend .stateColor{
261
+ position: absolute;
262
+ top: 25%;
263
+ width: var(--radarLegendCardItemText);
264
+ height: var(--radarLegendCardItemText);
265
+ border-radius: 50%;
266
+ }
267
+ .radarLegend .movementIndicator{
268
+ position: absolute;
269
+ top: 25%;
270
+ width: var(--radarLegendCardItemText);
271
+ height: var(--radarLegendCardItemText);
272
+ border: 2px solid black;
273
+ border-radius: 50%;
274
+ transform: rotate(90deg);
275
+ }
276
+ .radarLegend .movementIndicator.in{
277
+ border-left: 2px solid rgba(0,0,0,0.25);
278
+ border-right: 2px solid rgba(0,0,0,0.25);
279
+ border-bottom: 2px solid rgba(0,0,0,0.25);
280
+ }
281
+ .radarLegend .movementIndicator.out{
282
+ border-left: 2px solid rgba(0,0,0,0.25);
283
+ border-right: 2px solid rgba(0,0,0,0.25);
284
+ border-top: 2px solid rgba(0,0,0,0.25);
285
+ }
286
+ /* #endregion */
287
+
288
+ /* #region radarBlipLegend ----------------------------------------- */
289
+ .radarContainer .blipLegendSector{
290
+ font-size: var(--radarBlipLegendSector);
291
+ font-weight: bold;
292
+ }
293
+ .radarContainer .blipLegendSegment{
294
+ font-size: var(--radarBlipLegendSegment);
295
+ font-weight: lighter;
296
+ }
297
+ .radarContainer .blipLegendBlip{
298
+ user-select: none;
299
+ font-size: var(--radarBlipLegendBlip);
300
+ }
301
+ /* #endregion */
302
+
303
+
304
+ /* for tablet or desktop */
305
+ /*
306
+ @media screen and (min-width: 600px){
307
+ .radarContainer{
308
+ display: grid;
309
+ grid-template:
310
+ 'radarTitle radarTitle'
311
+ 'radarSelection radarSelection'
312
+ 'radarBlipLegend radar';
313
+ grid-template-columns: 0.25fr 0.75fr;
314
+ grid-template-rows: min-content min-content 0fr;
315
+ }
316
+ }
317
+ */
Binary file
data/assets/js/main.js CHANGED
@@ -132,9 +132,14 @@ function updateSite() {
132
132
 
133
133
  // Font size
134
134
  var html=document.querySelector('html');
135
-
135
+ var logo = document.getElementById("navbar-logo");
136
136
  function updateFontSize() {
137
137
  html.style.fontSize=siteData.fontSize+"rem";
138
+ if(siteData.fontSize == 1.2){
139
+ logo.src = "/assets/img/logo-horizontal-short.png";
140
+ }else{
141
+ logo.src = "/assets/img/logo-short.png";
142
+ }
138
143
  }
139
144
 
140
145
  // Change font size Button
@@ -0,0 +1,902 @@
1
+ /*
2
+ all occurring angles are in radian
3
+ */
4
+ function createRadar(config, structure, entries){
5
+ //#region variable definition #######################################################
6
+ const
7
+ radarId = config.radar.id,
8
+ diameter = config.radar.renderResolution,
9
+ radius = diameter / 2,
10
+ sectorThickness = 2 * Math.PI / structure.sectors.length,
11
+ blipMinSize = config.blip.size;
12
+
13
+ const fillingRatio = Math.PI / Math.sqrt(18); // ~0.74
14
+
15
+
16
+ let
17
+ radarData={}, // object to save all radar data
18
+ seed = 42, // seed number for reproducible random sequence
19
+ blipIdCounter = 1, // counter variable to give each blip a unique id
20
+ onlyOneSectorDisplayed = false;
21
+
22
+ //#endregion ########################################################################
23
+
24
+ window.onresize = () => {
25
+ mobileMode = (getSvgDivWidth() < diameter) ? true : false;
26
+ update();
27
+ }
28
+
29
+ //#region helper function math ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
30
+ /*-------------------------------------------------------------------
31
+ custom random number generator, to make random sequence reproducible
32
+ source: https://stackoverflow.com/questions/521295
33
+ -------------------------------------------------------------------*/
34
+ let random = () => {let x = Math.sin(seed++) * 10000; return x - Math.floor(x);};
35
+ let random_between = (min, max) => (min+random()*(max-min));
36
+ let normal_between = (min, max) => (min+(random()+random())*0.5*(max-min));
37
+
38
+ let pointByAngleAndRadius = (angle, radius) => ({
39
+ x: Math.cos(angle) * radius,
40
+ y: Math.sin(angle) * radius
41
+ })
42
+
43
+ let angleAndRadiusByPoint = (point) => ({
44
+ angle: angleOfPoint(point),
45
+ radius: radiusOfPoint(point),
46
+ })
47
+
48
+ let angleOfPoint = (point) => (point.y < 0)
49
+ ? Math.PI*2 + Math.atan2(point.y, point.x)
50
+ : Math.atan2(point.y, point.x);
51
+
52
+ let radiusOfPoint = (point) =>
53
+ Math.sqrt(point.x * point.x + point.y * point.y);
54
+
55
+ let calcOffsetAngle = (radius) =>
56
+ Math.atan(blipRadiusWithPadding / radius);
57
+
58
+ // NEW
59
+ let occupiedSpaceByBlips = (blipCount) => {
60
+ let radius = blipMinSize/2 + config.blip.margin;
61
+ return Math.pow(radius, 2) * Math.PI * blipCount;
62
+ }
63
+
64
+ let calcAngleRatio = (angle) => angle / (2 * Math.PI);
65
+
66
+ let blipAreaInSegment = (segment) => {
67
+ let radii = Math.pow(segment.outerRadius, 2) - Math.pow(segment.innerRadius, 2)
68
+ return Math.PI * radii * calcAngleRatio(segment.angleSpan) * fillingRatio;
69
+ }
70
+
71
+ let blipMaxRadiusInArea = (blipCount, area) =>
72
+ Math.sqrt(area / (Math.PI * blipCount));
73
+
74
+ let calcSegmentOuterRadius = (innerRadius, angle, blipCount) => {
75
+ let blipSpace = occupiedSpaceByBlips(blipCount);
76
+ let angleRatio = calcAngleRatio(angle);
77
+ let squareRootTerm = blipSpace / (Math.PI * angleRatio * fillingRatio) + Math.pow(innerRadius, 2);
78
+ return Math.sqrt(squareRootTerm);
79
+ }
80
+
81
+ let calcSegmentAngleSpan = (innerRadius, outerRadius, blipCount) => {
82
+ let blipSpace = occupiedSpaceByBlips(blipCount);
83
+ let denominator = (Math.PI * (Math.pow(outerRadius, 2) - Math.pow(innerRadius, 2)) * fillingRatio);
84
+ return blipSpace / denominator * (2 * Math.PI)
85
+ }
86
+ //#endregion ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
87
+
88
+ //#region helper function segment borders ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
89
+ /* Checks if a value is in interval between min and max.
90
+ -> If the value is below the interval minimum, the interval minimum is returned.
91
+ -> If the value is above the interval maximum, the interval maximum is returned.*/
92
+ let bounded_interval = (value, min, max) => {
93
+ let low = Math.min(min, max);
94
+ let high = Math.max(min, max);
95
+ return Math.min(Math.max(value, low), high);
96
+ }
97
+
98
+ let boundedRadius = (point, minRadius, maxRadius) => ({
99
+ angle: point.angle,
100
+ radius: bounded_interval(point.radius, minRadius, maxRadius)
101
+ })
102
+
103
+ let boundedAngle = (point, minAngle, maxAngle) => {
104
+ let blipPointRadius = radiusOfPoint(point);
105
+ let offsetAngle = calcOffsetAngle(blipPointRadius);
106
+ let minOffsetAngle = minAngle + offsetAngle;
107
+ let maxOffsetAngle = maxAngle - offsetAngle;
108
+ let blipPointAngle = angleOfPoint(point);
109
+ let angle = bounded_interval(blipPointAngle, minOffsetAngle, maxOffsetAngle);
110
+ //if the blip was outside the interval the blip point is recalculated
111
+ if(angle == minOffsetAngle) return pointByAngleAndRadius(minOffsetAngle, blipPointRadius);
112
+ if(angle == maxOffsetAngle) return pointByAngleAndRadius(maxOffsetAngle, blipPointRadius);
113
+ else return point;
114
+ }
115
+
116
+ let segmentFunctions = (segment) => ({
117
+ clip: (blip) => {
118
+ let pointInAngleInterval = boundedAngle(blip, segment.startAngle, segment.endAngle);
119
+ let pointInRadiusInterval = boundedRadius(
120
+ angleAndRadiusByPoint(pointInAngleInterval),
121
+ segment.blipMinRadius,
122
+ segment.blipMaxRadius
123
+ );
124
+ blip.x = pointByAngleAndRadius(pointInRadiusInterval.angle, pointInRadiusInterval.radius).x;
125
+ blip.y = pointByAngleAndRadius(pointInRadiusInterval.angle, pointInRadiusInterval.radius).y;
126
+ return { x: blip.x, y: blip.y };
127
+ },
128
+ random: () => pointByAngleAndRadius(
129
+ random_between(segment.startAngle, segment.endAngle),
130
+ normal_between(segment.blipMinRadius, segment.blipMaxRadius))
131
+ })
132
+ //#endregion ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
133
+
134
+ //#region helper functions svg ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
135
+ let getSvgDivWidth = () => {
136
+ // returns the width of the div tag where the svg is placed in excluding the padding
137
+ let radarOffsetWidth = radarDiv.select(`.radar`).node().offsetWidth;
138
+ let padding = parseInt(window.getComputedStyle(radarDiv.select(`.radar`).node()).paddingLeft) * 2;
139
+ return radarOffsetWidth - padding;
140
+ }
141
+
142
+ let translate = (x, y) => `translate(${x}, ${y})`;
143
+
144
+ let arc = (segment) => {
145
+ const startMaxPoint = pointByAngleAndRadius(segment.startAngle, segment.outerRadius);
146
+ const startMinPoint = pointByAngleAndRadius(segment.startAngle, segment.innerRadius);
147
+ const endMaxPoint = pointByAngleAndRadius(segment.endAngle, segment.outerRadius);
148
+ const endMinPoint = pointByAngleAndRadius(segment.endAngle, segment.innerRadius);
149
+ return [
150
+ 'M', startMaxPoint.x, startMaxPoint.y,
151
+ 'A', segment.outerRadius, segment.outerRadius, 0, 0, 1, endMaxPoint.x, endMaxPoint.y,
152
+ 'L', endMinPoint.x, endMinPoint.y,
153
+ 'A', segment.innerRadius, segment.innerRadius, 0, 0, 0, startMinPoint.x, startMinPoint.y,
154
+ 'L', startMaxPoint.x, startMaxPoint.y,
155
+ 'Z'
156
+ ].join(' ');
157
+ }
158
+
159
+ let sectorNamePath = (segment) => {
160
+ const radius = segment.outerRadius;
161
+ const startPoint = pointByAngleAndRadius(segment.startAngle, radius);
162
+ const endPoint = pointByAngleAndRadius(segment.endAngle, radius);
163
+ return [
164
+ 'M', startPoint.x, startPoint.y,
165
+ 'A', radius, radius, 0, 0, 1, endPoint.x, endPoint.y
166
+ ].join(' ');
167
+ }
168
+
169
+ let segmentNamePath = (segment) => {
170
+ const endMaxPoint = pointByAngleAndRadius(segment.endAngle, segment.outerRadius);
171
+ const endMinPoint = pointByAngleAndRadius(segment.endAngle, segment.innerRadius);
172
+
173
+ if(segment.endAngle > 1.5 * Math.PI && segment.endAngle <= 2 * Math.PI ||
174
+ segment.endAngle < 0.5 * Math.PI){
175
+ return [
176
+ 'M', endMinPoint.x, endMinPoint.y,
177
+ 'L', endMaxPoint.x, endMaxPoint.y
178
+ ].join(' ');
179
+ }
180
+ return [
181
+ 'M', endMaxPoint.x, endMaxPoint.y,
182
+ 'L', endMinPoint.x, endMinPoint.y
183
+ ].join(' ');
184
+ }
185
+
186
+ let getSectorColorPalette = (colorCode) => {
187
+ let colorStart, colorEnd, brighterColor;
188
+ switch (true){
189
+ case config.sector.useColor && config.segment.colorGradient:
190
+ brighterColor = d3.hsl(colorCode);
191
+ brighterColor.l *= config.segment.colorGradientLimit;
192
+ colorStart = d3.rgb(colorCode);
193
+ colorEnd = d3.rgb(brighterColor);
194
+ break;
195
+ case config.segment.colorGradient:
196
+ brighterColor = d3.hsl(config.radar.defaultColor);
197
+ brighterColor.l *= config.segment.colorGradientLimit;
198
+ colorStart = d3.rgb(config.radar.defaultColor);
199
+ colorEnd = d3.rgb(brighterColor);
200
+ break;
201
+ case config.sector.useColor:
202
+ colorStart = d3.rgb(colorCode);
203
+ colorEnd = d3.rgb(colorCode);
204
+ break;
205
+ default:
206
+ colorStart = d3.rgb(config.radar.defaultColor);
207
+ colorEnd = d3.rgb(config.radar.defaultColor);
208
+ }
209
+ return d3.scaleLinear()
210
+ .domain([0, structure.rings.list.length])
211
+ .range([colorStart, colorEnd]);
212
+ }
213
+
214
+ let getBlipColor = (blip) =>
215
+ (blip.stateID >= 0 && blip.stateID < structure.entryStates.list.length)
216
+ ? structure.entryStates.list[blip.stateID].color
217
+ : config.blip.defaultColor;
218
+
219
+ let getBlipRingColor = (blip) => {
220
+ let color = (blip.stateID >= 0 && blip.stateID < structure.entryStates.list.length)
221
+ ? d3.rgb(structure.entryStates.list[blip.stateID].color)
222
+ : d3.rgb(config.blip.defaultColor);
223
+ if(blip.moved != 0) color.opacity = 0.25;
224
+ return color;
225
+ }
226
+ let getBlipMovedIndicator = (blip) => {
227
+ if(blip.moved != 0){
228
+ let radius = config.blip.outerCircleRadius;
229
+
230
+ let startAngle = (blip.moved > 0)
231
+ ? radarData.sectors[blip.sectorID].startAngle + Math.PI
232
+ : radarData.sectors[blip.sectorID].startAngle;
233
+ let endAngle = (blip.moved > 0)
234
+ ? radarData.sectors[blip.sectorID].endAngle + Math.PI
235
+ : radarData.sectors[blip.sectorID].endAngle;
236
+ let startPoint = pointByAngleAndRadius(startAngle, radius);
237
+ let endPoint = pointByAngleAndRadius(endAngle, radius);
238
+ return [
239
+ 'M', startPoint.x, startPoint.y,
240
+ 'A', radius, radius, 0, 0, 1, endPoint.x, endPoint.y,
241
+ ].join(' ');
242
+ }
243
+ return ``;
244
+ }
245
+ //#endregion ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
246
+
247
+ //#region preparing radar data ||||||||||||||||||||||||||||||||||||||||||||||||||||||
248
+
249
+
250
+
251
+
252
+
253
+ // create data structure ----------------------------------------------------------
254
+ radarData.rings = structure.rings.list.map((ring, index) => ({
255
+ ...ring,
256
+ index: index,
257
+ }));
258
+ radarData.sectors = structure.sectors.map((sector, index) => ({
259
+ ...sector,
260
+ id: index,
261
+ idText: `${radarId}_sector${index}`,
262
+ color: getSectorColorPalette(sector.color),
263
+ segments: radarData.rings,
264
+ }));
265
+ radarData.sectors.forEach(sector => {
266
+ sector.segments = sector.segments.map((segment, index) => ({
267
+ ...segment,
268
+ idText: `${sector.idText}_segment${index}`,
269
+ color: sector.color(index),
270
+ blips: entries.filter(entry =>
271
+ entry.sectorID == sector.id &&
272
+ entry.ringID == index &&
273
+ entry.active)
274
+ .sort((a, b) => a.name.localeCompare(b.name)),
275
+ }))
276
+ });
277
+ // --------------------------------------------------------------------------------
278
+ // adding ring radii and ring thickness -----------------------------------------
279
+ radarData.rings.forEach((ring, index) => {
280
+ ring.innerRadius = (index == 0) ? 0 : radarData.rings[index - 1].outerRadius;
281
+ ring.outerRadius = radarData.sectors.reduce((prev, curr) =>
282
+ Math.max(prev, calcSegmentOuterRadius(ring.innerRadius, sectorThickness, curr.segments[index].blips.length))
283
+ , 0);
284
+ ring.radiusThickness = ring.outerRadius - ring.innerRadius;
285
+ });
286
+ /* if the last outer radius is larger or smaller than the given radar radius, the rings must be
287
+ adjusted in such a way that any open space is evenly filled or any space that overlaps is evenly
288
+ subtracted from all ring thicknesses. */
289
+ let ringsLastOuterRadius = radarData.rings[radarData.rings.length - 1].outerRadius;
290
+ let ringThicknessCorrection = (radius - ringsLastOuterRadius) / radarData.rings.length;
291
+ radarData.rings.forEach((ring, index) => {
292
+ ring.radiusThickness = ring.radiusThickness + ringThicknessCorrection;
293
+ ring.innerRadius = (index == 0) ? 0 : radarData.rings[index - 1].outerRadius;
294
+ ring.outerRadius = ring.innerRadius + ring.radiusThickness;
295
+ });
296
+ // update segments
297
+ radarData.sectors.forEach(sector => {
298
+ sector.segments = sector.segments.map((segment, index) => ({
299
+ ...segment,
300
+ radiusThickness: radarData.rings[index].radiusThickness,
301
+ innerRadius: radarData.rings[index].innerRadius,
302
+ outerRadius: radarData.rings[index].outerRadius,
303
+ }))
304
+ });
305
+
306
+ // add needed min angle span for each sector
307
+ radarData.sectors.forEach((sector) => {
308
+ sector.angleSpan = sector.segments.reduce((prev, curr) =>
309
+ Math.max(prev, calcSegmentAngleSpan(curr.innerRadius, curr.outerRadius, curr.blips.length))
310
+ , 0);
311
+ });
312
+ // add up all sector angle spans
313
+ let sectorAngleSpanSum = radarData.sectors.reduce((prev, curr) => prev + curr.angleSpan, 0);
314
+ let sectorAngleCorrection = ((Math.PI * 2) - sectorAngleSpanSum) / radarData.sectors.length;
315
+ radarData.sectors.forEach((sector, index) => {
316
+ sector.angleSpan = sector.angleSpan + sectorAngleCorrection;
317
+ sector.startAngle = (index == 0) ? 0 : radarData.sectors[index - 1].endAngle;
318
+ sector.endAngle = sector.startAngle + sector.angleSpan;
319
+ });
320
+ // update segments
321
+ radarData.sectors.forEach(sector => {
322
+ sector.segments = sector.segments.map((segment, index) => ({
323
+ ...segment,
324
+ angleSpan: sector.angleSpan,
325
+ startAngle: sector.startAngle,
326
+ endAngle: sector.endAngle,
327
+ }))
328
+ })
329
+ // ------------------------------------------------------------------------------
330
+
331
+
332
+
333
+ // ------------------------------------------------------------------------------
334
+ // Blip anpassung
335
+ let sectorMinBilpRadius = radarData.sectors.reduce((prev, curr) => {
336
+ let segmentMinBilpRadius = curr.segments.reduce((prev, curr) => {
337
+ let area = blipAreaInSegment(curr);
338
+ let radius = blipMaxRadiusInArea(curr.blips.length, area);
339
+ let size = (radius - config.blip.margin) * 2;
340
+ return Math.min(size, prev)
341
+ }, Number.MAX_VALUE)
342
+ return Math.min(prev, segmentMinBilpRadius)
343
+ }, Number.MAX_VALUE);
344
+
345
+ const
346
+ blipSize = Math.max(sectorMinBilpRadius, blipMinSize),
347
+ blipRadiusWithPadding = blipSize / 2 + config.segment.padding;
348
+
349
+ config.blip.size = blipSize;
350
+
351
+ radarData.sectors.forEach(sector => {
352
+ sector.segments = sector.segments.map((segment, index) => ({
353
+ ...segment,
354
+ blipMinRadius: (index == 0)
355
+ ? blipRadiusWithPadding / Math.sin(sector.angleSpan / 2)
356
+ : segment.innerRadius + blipRadiusWithPadding,
357
+ blipMaxRadius: segment.outerRadius - blipRadiusWithPadding
358
+ }))
359
+ })
360
+
361
+ // ------------------------------------------------------------------------------
362
+
363
+
364
+
365
+
366
+
367
+
368
+ radarData.blips = []; // list of all blips, for a better processing later on
369
+ radarData.sectors.forEach(sector => sector.segments.forEach(segment => {
370
+ // give each blip the corresponding segment functions
371
+ segment.blips = segment.blips.map(blip => ({
372
+ ...blip,
373
+ idText: `${segment.idText}_blip${blipIdCounter}`,
374
+ id: blipIdCounter++,
375
+ focused: false,
376
+ segmentFunctions: segmentFunctions(segment),
377
+ }))
378
+ // save each blip in a list, for better processing later on
379
+ segment.blips.forEach(blip => radarData.blips.push(blip))
380
+ }));
381
+
382
+ // give each blip the first random position
383
+ radarData.blips.forEach(blip => {
384
+ let point = blip.segmentFunctions.random();
385
+ blip.x = point.x;
386
+ blip.y = point.y;
387
+ });
388
+
389
+ // add data to the configuration of a blip to create blips later on
390
+ let fontSize = blipSize * 0.33,
391
+ blipRadius = blipSize * 0.5,
392
+ strokeWidth = blipRadius * 0.2,
393
+ outerCircleRadius = blipRadius ,
394
+ innerCircleRadius = outerCircleRadius - strokeWidth;
395
+ config.blip = ({
396
+ ...config.blip,
397
+ fontSize: fontSize,
398
+ radius: blipRadius,
399
+ strokeWidth: strokeWidth,
400
+ outerCircleRadius: outerCircleRadius,
401
+ innerCircleRadius: innerCircleRadius
402
+ });
403
+
404
+ structure.entryStates.list = structure.entryStates.list.map((state, index)=>({
405
+ ...state,
406
+ index: index
407
+ }));
408
+
409
+
410
+ //#endregion ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
411
+
412
+ //#region create div structure ______________________________________________________
413
+ let radarDiv = d3.select(`div#${radarId}`).classed(`radarContainer`, true);
414
+ if(config.radar.showName){
415
+ radarDiv.append(`div`)
416
+ .classed(`radarTitle`, true)
417
+ .text(config.radar.name);
418
+ }
419
+ // select sector dropdown
420
+ radarDiv.append(`div`)
421
+ .attr(`id`, `${radarId}_selectionDropdown`)
422
+ .classed(`radarSelection dropdown`, true);
423
+ radarDiv.append(`div`)
424
+ .classed(`radar`, true)
425
+ .attr(`id`, `${radarId}_radarDiv`);
426
+ /*
427
+ radarDiv.append(`div`)
428
+ .classed(`radarBlipLegend`, true);
429
+ */
430
+ //#endregion ________________________________________________________________________
431
+
432
+ //#region create radar SVG and radar legend _________________________________________
433
+ radarDiv.select(`.radar`)
434
+ .append(`div`)
435
+ .classed(`radarContent`, true)
436
+ .append(`svg`)
437
+ .attr(`id`, `${radarId}_svg`)
438
+ .classed(`radarSVG`, true)
439
+ .attr(`preserveAspectRatio`, `xMinYMin meet`)
440
+ .attr(`viewBox`, `0 0 ${diameter} ${diameter}`);
441
+ radarDiv.select(`svg#${radarId}_svg`).append(`g`)
442
+ .attr(`id`, `${radarId}_radarContent`)
443
+ .attr(`transform`, translate(radius, radius));
444
+ // append radar legend div
445
+ radarDiv.select(`.radar`)
446
+ .append(`div`)
447
+ .attr(`id`, `${radarId}_radarLegend`)
448
+ .classed(`radarLegend dropdown`, true)
449
+ .on(`click`, ()=>
450
+ document.getElementById(`${radarId}_radarLegend`).classList.toggle(`active`))
451
+ .text(config.radar.legendDropdownText);
452
+ //#endregion ________________________________________________________________________
453
+
454
+ // can be declared only after the radar svg is appended
455
+ let mobileMode = (getSvgDivWidth() < diameter) ? true : false;
456
+ // let mobileMode = (getSvgDivWidth() < 400) ? true : false;
457
+
458
+ //#region event fuctions general ****************************************************
459
+ let update = () => {
460
+ selectionDropdownContent.select(`.selectionButton`)
461
+ .style(`display`, (mobileMode) ? `none` : `block`);
462
+ if(mobileMode && !onlyOneSectorDisplayed){
463
+ displaySector(radarData.sectors[0]);
464
+ changeSvgViewbox(radarData.sectors[0].idText);
465
+ selectionDropdownText.text(radarData.sectors[0].name);
466
+ }
467
+ else changeSvgViewbox(`${radarId}_radarContent`);
468
+ }
469
+
470
+ let changeSvgViewbox = (idText) => {
471
+ onlyOneSectorDisplayed = (idText == `${radarId}_radarContent`) ? false : true;
472
+ let box = radarDiv.select(`g#${idText}`).node().getBBox()
473
+ let size = Math.max(box.width, box.height);
474
+ let x = radius + box.x;
475
+ let y = radius + box.y;
476
+ d3.select(`svg#${radarId}_svg`).attr(`viewBox`, `${x} ${y} ${size} ${size}`);
477
+ }
478
+ //#endregion ************************************************************************
479
+
480
+ //#region event functions sector ****************************************************
481
+ let displayAllSectors = () => {
482
+ sectors.style(`display`, `block`);
483
+ blipLegendSectors.style(`display`, `block`);
484
+ }
485
+ let displaySector = (sector) => {
486
+ sectors.style(`display`, `none`);
487
+ radarDiv.select(`g#${sector.idText}`).style(`display`, `block`);
488
+ blipLegendSectors.style(`display`, `none`);
489
+ radarDiv.select(`div#${sector.idText}_legend`).style(`display`, `block`);
490
+ }
491
+ let focusAllSector = () => {
492
+ sectors.style(`opacity`, 1);
493
+ blipLegendSectors.style(`opacity`, 1);
494
+ }
495
+ let focusSector = (sector) => {
496
+ if(!onlyOneSectorDisplayed){
497
+ sectors.style(`opacity`, 0.25);
498
+ radarDiv.select(`g#${sector.idText}`).style(`opacity`, 1);
499
+ blipLegendSectors.style(`opacity`, 0.25);
500
+ radarDiv.select(`div#${sector.idText}_legend`).style(`opacity`, 1);
501
+ }
502
+ }
503
+ //#endregion ************************************************************************
504
+
505
+ //#region event functions ring ******************************************************
506
+ let focusRing = (ring) => {
507
+ segments.style(`opacity`, 0.25)
508
+ segments.filter(seg => seg.index == ring.index).style(`opacity`, 1)
509
+ }
510
+ let focusAllRings = () => segments.style(`opacity`, 1);
511
+ //#endregion ************************************************************************
512
+
513
+ //#region event functions blip ******************************************************
514
+ let blipClick = (blip) => {
515
+ let blipData = radarData.blips.find(data => data.id == blip.id);
516
+ if (blipData.focused){
517
+ window.open(blipData.link);
518
+ }
519
+ else blipData.focused = true;
520
+ }
521
+
522
+ let focusAllBlips = () => {
523
+ radarData.blips.forEach(blip => blip.focused = false);
524
+ blips.style(`opacity`, 1);
525
+ radarDiv.selectAll(`.blipLegendBlip`).classed(`active`, false);
526
+ hideBubble();
527
+ }
528
+
529
+ let focusBlip = (blip) => {
530
+ radarData.blips.find(data => data.id == blip.id).focused = true;
531
+ blips.filter(data => data.sectorID == blip.sectorID).style(`opacity`, 0.25);
532
+ radarDiv.select(`g#${blip.idText}`).style(`opacity`, 1);
533
+ blipLegendBlips.filter(data => data.id == blip.id).classed(`active`, true);
534
+ showBubble(blip);
535
+ }
536
+
537
+ let focusBlipByState = (state) => {
538
+ blips.style(`opacity`, 0.25);
539
+ blips.filter(data => data.stateID == state.index).style(`opacity`, 1);
540
+ blipLegendBlips.filter(data => data.stateID == state.index).classed(`active`, true);
541
+ }
542
+
543
+ let focusBlipByMovement = (movementValue) => {
544
+ blips.style(`opacity`, 0.25);
545
+ if(movementValue > 0) {
546
+ blips.filter(data => data.moved > 0).style(`opacity`, 1);
547
+ blipLegendBlips.filter(data => data.moved > 0).classed(`active`, true);
548
+ }
549
+ if(movementValue < 0) {
550
+ blips.filter(data => data.moved < 0).style(`opacity`, 1);
551
+ blipLegendBlips.filter(data => data.moved < 0).classed(`active`, true);
552
+ }
553
+ if(movementValue == 0) {
554
+ blips.filter(data => data.moved == 0).style(`opacity`, 1);
555
+ blipLegendBlips.filter(data => data.moved == 0).classed(`active`, true);
556
+ }
557
+ }
558
+ //#endregion ************************************************************************
559
+
560
+ //#region event functions bubble ****************************************************
561
+ let showBubble = (blip) => {
562
+ bubble.style(`display`, `block`);
563
+ let text = bubble.select(`text`).text(blip.name);
564
+ let textBox = text.node().getBBox();
565
+ bubble.attr('transform', translate(blip.x - textBox.width / 2, blip.y - 19))
566
+ bubble.select(`rect`)
567
+ .attr('x', -5)
568
+ .attr('y', -textBox.height)
569
+ .attr('width', textBox.width + 10)
570
+ .attr('height', textBox.height + 4);
571
+ bubble.select(`path`).attr('transform', translate(textBox.width / 2 - 5, 3));
572
+ }
573
+ let hideBubble = () =>
574
+ radarDiv.select(`g#${radarId}_bubble`).style(`display`, `none`);
575
+ //#endregion ************************************************************************
576
+
577
+ //#region d3-components radar -------------------------------------------------------
578
+ /* to place text on an svg-path the attribute alignment-baseline has been used,
579
+ the options of this attribute are well explained here
580
+ https://vanseodesign.com/web-design/svg-text-baseline-alignment/
581
+ */
582
+ let makeSector = (selection) => {
583
+ selection
584
+ .attr(`id`, sector => `${sector.idText}`)
585
+ .classed(`sector`, true)
586
+ .on(`mouseover`, sector => focusSector(sector))
587
+ .on(`mouseout`, focusAllSector)
588
+ .on(`click`, sector => {
589
+ displaySector(sector);
590
+ changeSvgViewbox(sector.idText);
591
+ });
592
+ if(config.sector.showName){
593
+ let name = selection.append(`g`)
594
+ .attr(`class`, `sectorName`)
595
+ name.append(`path`)
596
+ .attr(`id`, sector => `${sector.idText}_name`)
597
+ .attr(`d`, sector => sectorNamePath(sector.segments[sector.segments.length-1]))
598
+ .attr(`fill`, `none`);
599
+ name.append(`text`).append(`textPath`)
600
+ .attr(`href`, sector => `#${sector.idText}_name`, `http://www.w3.org/1999/xlink`)
601
+ .attr(`alignment-baseline`, `after-edge`)
602
+ .attr(`startOffset`, `50%`)
603
+ .attr(`style`, `text-anchor:middle;`)
604
+ .text(sector => sector.name);
605
+ }
606
+ }
607
+
608
+ let makeSegment = (selection) => {
609
+ selection
610
+ .attr(`id`, segment => `${segment.idText}`)
611
+ .classed(`segment`, true)
612
+ .append(`path`)
613
+ .classed(`radarLines`, true)
614
+ .attr(`d`, segment => arc(segment))
615
+ .attr(`fill`, segment => segment.color);
616
+
617
+ if(config.segment.showName){
618
+ let name = selection.append(`g`)
619
+ .classed(`segmentName`, true);
620
+ name.append(`path`)
621
+ .attr(`id`, segment => `${segment.idText}_namePath`)
622
+ .attr(`d`, segment => segmentNamePath(segment))
623
+ .attr(`fill`, `none`);
624
+ name.append(`text`).append(`textPath`)
625
+ .attr(`href`, segment => `#${segment.idText}_namePath`, `http://www.w3.org/1999/xlink`)
626
+ .attr(`alignment-baseline`, segment =>
627
+ (segment.endAngle > 1.5 * Math.PI && segment.endAngle <= 2 * Math.PI ||
628
+ segment.endAngle < 0.5 * Math.PI)
629
+ ? `before-edge`
630
+ : `after-edge`)
631
+ .attr(`startOffset`,`50%`)
632
+ .attr(`style`, `text-anchor:middle;`)
633
+ .text(segment => (config.segment.showNameAsId) ? segment.index : segment.name);
634
+ }
635
+ }
636
+
637
+ let makeBlip = (selection) => {
638
+ selection
639
+ .attr(`id`, data => `${data.idText}`)
640
+ .classed(`blip`, true)
641
+ .attr(`transform`, data => translate(data.x, data.y))
642
+ .on(`click`, data => blipClick(data))
643
+ .on(`mouseover`, data => focusBlip(data))
644
+ .on(`mouseout`, data => focusAllBlips(data));
645
+ // blip outer ring
646
+ selection.append(`circle`)
647
+ .attr(`r`, config.blip.outerCircleRadius)
648
+ .attr(`fill`, `rgba(0, 0, 0, 0)`)
649
+ .attr(`stroke-width`, config.blip.strokeWidth)
650
+ .attr(`stroke`, getBlipRingColor);
651
+ // blip indicater for movement
652
+ selection.append(`path`)
653
+ .attr(`d`, getBlipMovedIndicator)
654
+ .attr(`fill`, `none`)
655
+ .attr(`stroke-width`, config.blip.strokeWidth)
656
+ .attr(`stroke`, getBlipColor);
657
+ // blip innerCircle
658
+ selection.append('circle')
659
+ .attr('r', config.blip.innerCircleRadius)
660
+ .attr('fill', getBlipColor);
661
+ // blip text
662
+ selection.append('text')
663
+ .classed('blipText', true)
664
+ .attr('y', config.blip.fontSize/3)
665
+ .attr('text-anchor', 'middle')
666
+ .style(`font-size`, config.blip.fontSize)
667
+ .text(data => data.id);
668
+ }
669
+
670
+ let makeBubble = (selection) => {
671
+ selection
672
+ .classed(`radarBubble`, true)
673
+ .attr(`id`, `${radarId}_bubble`)
674
+ .style(`display`, `none`)
675
+ let fontSize = config.blip.radius;
676
+ selection.append('rect')
677
+ .attr('class', 'background')
678
+ .attr('rx', 4)
679
+ .attr('ry', 4);
680
+ selection.append('text')
681
+ .attr('class', 'bubbleText')
682
+ .attr(`y`, -fontSize/9)
683
+ .style(`font-size`, fontSize);
684
+ selection.append('path')
685
+ .attr('class', 'background')
686
+ .attr('d', 'M 0,0 10,0 5,8 z');
687
+ }
688
+ //#endregion ------------------------------------------------------------------------
689
+
690
+ //#region d3-components radar legend ------------------------------------------------
691
+ let makeLegendBlipStates = (selection) => {
692
+ selection.append(`span`)
693
+ .classed(`stateColor`, true)
694
+ .style(`background-color`, data => data.color);
695
+ selection.append(`span`)
696
+ .classed(`paddingText`, true)
697
+ .text(data => data.name);
698
+ }
699
+
700
+ let makeLegendBlipMovement = (selection) => {
701
+ selection.append(`span`)
702
+ .classed(`movementIndicator`, true)
703
+ .classed(`in`, data => data.value > 0)
704
+ .classed(`out`, data => data.value < 0);
705
+ selection.append(`span`)
706
+ .classed(`paddingText`, true)
707
+ .text(data => data.name);
708
+ }
709
+
710
+ let makeLegendRings = (selection) => {
711
+ selection.append(`span`)
712
+ .classed(`text`, true)
713
+ .text(data => `${data.index}. ${data.name}`);
714
+ }
715
+ //#endregion ------------------------------------------------------------------------
716
+
717
+ //#region d3-components radar blip legend -------------------------------------------
718
+ let makeBlipLegendSector = (selection) => {
719
+ selection
720
+ .attr(`id`, sector => `${sector.idText}_legend`)
721
+ .classed(`blipLegendSector card`, true)
722
+ .on(`click, mouseover`, sector => focusSector(sector))
723
+ .on(`mouseout`, focusAllSector)
724
+ .text(sector => sector.name);
725
+ }
726
+
727
+ let makeBlipLegendSegment = (selection) => {
728
+ selection
729
+ .attr(`id`, segment => `${segment.idText}_legend`)
730
+ .classed(`blipLegendSegment subCard`, true)
731
+ .text(segment => segment.name);
732
+ }
733
+
734
+ let makeBlipLegendBlip = (selection) => {
735
+ selection
736
+ .attr(`id`, blip => `${blip.idText}_legend`)
737
+ .classed(`blipLegendBlip cardItem`, true)
738
+ .on(`click`, blip => blipClick(blip))
739
+ .on(`mouseover`, blip => focusBlip(blip))
740
+ .on(`mouseout`, blip => focusAllBlips(blip))
741
+ .text(blip => `${blip.id} ${blip.name}`);
742
+ }
743
+ //#endregion ------------------------------------------------------------------------
744
+
745
+ //#region generate selection ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
746
+ let selectionDropdownText = radarDiv.select(`.radarSelection`)
747
+ .on(`click`, ()=> {
748
+ document.getElementById(`${radarId}_selectionDropdown`)
749
+ .classList.toggle(`active`);
750
+ })
751
+ .append(`span`)
752
+ .classed(`dropdownText`, true)
753
+ .text(config.radar.showAllSectorsText);
754
+
755
+ // append a dropdown content div to add the dropdown options
756
+ let selectionDropdownContent = radarDiv.select(`.radarSelection`)
757
+ .append(`div`)
758
+ .classed(`dropdownContent`, true);
759
+
760
+ // append the first dropdown option to show the whole radar
761
+ selectionDropdownContent
762
+ .append(`div`)
763
+ .classed(`selectionButton`, true)
764
+ .style(`display`, (mobileMode) ? `none` : `block`)
765
+ .text(config.radar.showAllSectorsText)
766
+ .on(`click`, () => {
767
+ displayAllSectors();
768
+ changeSvgViewbox(`${radarId}_radarContent`);
769
+ selectionDropdownText.text(config.radar.showAllSectorsText);
770
+ });
771
+
772
+ // append a dropdown option for each sector in radar
773
+ selectionDropdownContent.selectAll(null)
774
+ .data(radarData.sectors)
775
+ .enter()
776
+ .append(`div`)
777
+ .classed(`selectionButton`, true)
778
+ .text(sector => sector.name)
779
+ .on(`click`, sector => {
780
+ displaySector(sector);
781
+ changeSvgViewbox(sector.idText);
782
+ selectionDropdownText.text(sector.name);
783
+ });
784
+ //#endregion ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
785
+
786
+ //#region generate radar ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
787
+ let sectors = d3.select(`g#${radarId}_radarContent`)
788
+ .selectAll(`.sector`)
789
+ .data(radarData.sectors)
790
+ .enter()
791
+ .append(`g`)
792
+ .call(makeSector);
793
+
794
+ let segments = sectors.selectAll(`.segment`)
795
+ .data(sector => sector.segments )
796
+ .enter()
797
+ .append(`g`)
798
+ .call(makeSegment);
799
+
800
+ let blips = segments.selectAll(`.blip`)
801
+ .data(segment => segment.blips)
802
+ .enter()
803
+ .append(`g`)
804
+ .call(makeBlip);
805
+
806
+ let bubble = d3.select(`g#${radarId}_radarContent`)
807
+ .append(`g`)
808
+ .call(makeBubble);
809
+ //#endregion ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
810
+
811
+ //#region generate radar legend +++++++++++++++++++++++++++++++++++++++++++++++++++++
812
+ let radarLegendContainer = radarDiv.select(`.radarLegend`)
813
+ .append(`div`)
814
+ .attr(`id`, `${radarId}_radarLegendContainer`)
815
+ .classed(`dropdownContent`, true);
816
+
817
+ // generate entry states legend
818
+ let entryStatesLegend = radarLegendContainer.append(`div`)
819
+ .classed(`card`, true)
820
+ entryStatesLegend.append(`div`)
821
+ .classed(`cardTitle`, true)
822
+ .text(structure.entryStates.legendTitle);
823
+ entryStatesLegend.selectAll(null)
824
+ .data(structure.entryStates.list)
825
+ .enter()
826
+ .append(`div`)
827
+ .classed(`cardItem`, true)
828
+ .call(makeLegendBlipStates)
829
+ .on(`mouseover`, (data)=> focusBlipByState(data))
830
+ .on(`mouseout`, data => focusAllBlips(data));
831
+
832
+ // generate entry movement legend
833
+ let entryMovementLegend = radarLegendContainer.append(`div`)
834
+ .classed(`card`, true);
835
+ entryMovementLegend.append(`div`)
836
+ .classed(`cardTitle`, true)
837
+ .text(structure.entryMovement.legendTitle);
838
+ entryMovementLegend.selectAll(null)
839
+ .data(structure.entryMovement.list)
840
+ .enter()
841
+ .append(`div`)
842
+ .classed(`cardItem`, true)
843
+ .call(makeLegendBlipMovement)
844
+ .on(`mouseover`, (data)=> focusBlipByMovement(data.value))
845
+ .on(`mouseout`, data => focusAllBlips(data));
846
+
847
+ // generate ring legend
848
+ let ringLegend = radarLegendContainer.append(`div`)
849
+ .classed(`card`, true);
850
+ ringLegend.append(`div`)
851
+ .classed(`cardTitle`, true)
852
+ .text(structure.rings.legendTitle);
853
+ ringLegend.selectAll(null)
854
+ .data(radarData.rings)
855
+ .enter()
856
+ .append(`div`)
857
+ .classed(`cardItem`, true)
858
+ .call(makeLegendRings)
859
+ .on(`mouseover`, (data)=> focusRing(data))
860
+ .on(`mouseout`, ()=> focusAllRings());
861
+ //#endregion ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
862
+
863
+ //#region generate radar blip legend ++++++++++++++++++++++++++++++++++++++++++++++++
864
+ let blipLegendSectors = radarDiv.select(`.radarBlipLegend`).selectAll(null)
865
+ .data(radarData.sectors)
866
+ .enter()
867
+ .append(`div`)
868
+ .call(makeBlipLegendSector);
869
+
870
+ let blipLegendSegments = blipLegendSectors.selectAll(null)
871
+ .data(sector => sector.segments.filter(segment => segment.blips.length != 0))
872
+ .enter()
873
+ .append(`div`)
874
+ .call(makeBlipLegendSegment);
875
+
876
+ let blipLegendBlips = blipLegendSegments.selectAll(null)
877
+ .data(segment => segment.blips)
878
+ .enter()
879
+ .append(`div`)
880
+ .call(makeBlipLegendBlip)
881
+ //#endregion ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
882
+
883
+ //#region forceSimulation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
884
+ // make sure that blips stay inside their segment
885
+ let ticked = () => blips.attr(`transform`, (d) => translate(
886
+ d.segmentFunctions.clip(d).x,
887
+ d.segmentFunctions.clip(d).y
888
+ ));
889
+ // distribute blips, while avoiding collisions
890
+ d3.forceSimulation(radarData.blips)
891
+ .force(`collision`,
892
+ d3.forceCollide()
893
+ .radius(blipSize/2 + config.blip.margin)
894
+ .strength(0.15))
895
+ .on(`tick`, ticked);
896
+ //#endregion %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
897
+
898
+ update();
899
+ console.log(radarData, config);
900
+
901
+
902
+ }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: intia-theme
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.55
4
+ version: 0.1.58
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marc Schmidt
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-05-10 00:00:00.000000000 Z
11
+ date: 2022-05-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: jekyll
@@ -56,6 +56,7 @@ files:
56
56
  - _sass/_layout.scss
57
57
  - _sass/_main.scss
58
58
  - _sass/_print.scss
59
+ - _sass/_radar.scss
59
60
  - assets/img/404.png
60
61
  - assets/img/arrow-down.png
61
62
  - assets/img/arrow-left.png
@@ -72,8 +73,9 @@ files:
72
73
  - assets/img/icons/remove.svg
73
74
  - assets/img/icons/search.svg
74
75
  - assets/img/internal-link.png
75
- - assets/img/logo-black.png
76
76
  - assets/img/logo-dites.png
77
+ - assets/img/logo-horizontal-short.png
78
+ - assets/img/logo-short.png
77
79
  - assets/img/logo-white.png
78
80
  - assets/img/logos/BMBF_logo.jpg
79
81
  - assets/img/logos/DiTes_Single.png
@@ -86,6 +88,7 @@ files:
86
88
  - assets/img/logos/fjmk.png
87
89
  - assets/js/bulma-carousel/js/bulma-carousel.js
88
90
  - assets/js/main.js
91
+ - assets/js/radar.js
89
92
  - assets/js/search.js
90
93
  - assets/styles/main.scss
91
94
  - assets/templates/contact.png
Binary file