intia-theme 0.1.56 → 0.1.57

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c3d3b98390c39c7b9199ccb9ab7a697e00b9dfcbef1577c558243fb729f9ce8c
4
- data.tar.gz: cf2f452d0da883c2f4b4bc3c9ab4857653f695af018c4986c6a31316f4a7a7be
3
+ metadata.gz: a61c54d1efa22b8bb6f9ffe42b0ce87b1086d2f9193b859e9aab9ddc4741657a
4
+ data.tar.gz: d3c4a657f48e4a7fa087b7867f47ec250502dffc66416e5c6773cc84d77969cb
5
5
  SHA512:
6
- metadata.gz: 1c4344e05d1df9f424d720635a31f4f09300f4d1a45a02d4b038515973863331e902492706bcb4d68c63b4c86eab638934667e76f7619f232ef9ee779a6e2f89
7
- data.tar.gz: c47d43986c8970ec0ebec47ddc651c1ae43812968dfc5948957b2ed46fac03df90a897dcd7359f96dae5505b8e1cb3f2296e2810e3b90426d59e6b6d51e68aa8
6
+ metadata.gz: 19c3d4ac1b03650a4906e57efc83be1c98a2377922b3801e760e16b9f5bf169204558ebc6af80822358fc86d78deaf41359f151ef4dc6e53e76cc38f229679a0
7
+ data.tar.gz: d33d81b549feddf7c3dd450d71ec0c53fad74e5be8ad19bb3419af7f97b59349095d377e02164d2b11d6d7b76c8a88d5d3d0284c9a1f295663b7d379b73e974e
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.56
4
+ version: 0.1.57
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-11 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