raain-ui 2.3.16 → 2.3.18

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.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [2.3.17] - 2025-10-09
11
+
12
+ ### Fixed
13
+
14
+ - MapElement changeMarkerStyle
15
+
16
+ ## [2.3.16] - 2025-07-04
17
+
10
18
  ### Fixed
11
19
 
12
20
  - UT with local labels in CI
package/README.md CHANGED
@@ -99,6 +99,54 @@ npm start
99
99
  This will open the example application at http://localhost:1234, where you can explore the various components and
100
100
  features of raain-ui.
101
101
 
102
+ ### 🌬️ Wind Marker Animations
103
+
104
+ raain-ui includes CSS animations for visualizing wind speed and direction on map markers. To use these animations in your application:
105
+
106
+ **1. Import the CSS file in your global styles:**
107
+
108
+ ```scss
109
+ // In your global.scss or styles.scss
110
+ @import "~raain-ui/data/wind-markers.css";
111
+ ```
112
+
113
+ **Or in HTML:**
114
+
115
+ ```html
116
+ <link rel="stylesheet" href="node_modules/raain-ui/dist/data/wind-markers.css">
117
+ ```
118
+
119
+ **2. Use with MapElement:**
120
+
121
+ ```typescript
122
+ import { MapLatLng } from 'raain-ui';
123
+
124
+ // Create a marker with wind data
125
+ const windMarker = new MapLatLng(
126
+ lat, // latitude
127
+ lng, // longitude
128
+ azimuth, // alt property: azimuth 0-360° (0=North, 90=East, 180=South, 270=West)
129
+ id, // marker id
130
+ name, // marker name
131
+ strengthInMs // value property: wind strength in meters/second
132
+ );
133
+
134
+ // Apply wind animation
135
+ mapElement.changeMarkerStyle(
136
+ windMarker,
137
+ 'marker-wind marker-wind-225', // classes: base + direction
138
+ { strength: 10 } // CSS variable: wind strength
139
+ );
140
+ ```
141
+
142
+ **Available azimuth classes:** 0, 10, 20, 30, 45, 90, 135, 180, 200, 225, 270, 315
143
+
144
+ The animation automatically:
145
+ - Shows a directional arrow indicating wind direction
146
+ - Animates marker movement in the wind direction
147
+ - Adjusts animation speed based on wind strength
148
+ - Displays a blue glow with intensity matching wind strength
149
+
102
150
  ## 📚 Documentation
103
151
 
104
152
  Comprehensive API documentation is available in the [specifications](./specs) directory. This includes detailed
@@ -0,0 +1,174 @@
1
+ /* ============================================================================
2
+ * Wind Speed/Direction Animation for Leaflet Markers
3
+ * ============================================================================
4
+ * Usage: Import this CSS file in your app's global styles or index.html
5
+ *
6
+ * @import "~raain-ui/data/wind-markers.css";
7
+ *
8
+ * Or in HTML:
9
+ * <link rel="stylesheet" href="node_modules/raain-ui/dist/data/wind-markers.css">
10
+ *
11
+ * Then apply classes to markers via MapElement.changeMarkerStyle():
12
+ * mapElement.changeMarkerStyle(marker, 'marker-wind marker-wind-200', {strength: 10});
13
+ */
14
+
15
+ /* Base wind marker class */
16
+ .marker-wind {
17
+ /* Calculate animation speed: stronger wind = faster animation */
18
+ --duration: calc(5s - (min(var(--strength, 5), 25) * 0.08s));
19
+
20
+ /* Calculate displacement: strength in m/s * 2 = pixels */
21
+ --displacement: calc(var(--strength, 5) * 2);
22
+
23
+ /* Visual glow intensity based on strength */
24
+ filter: drop-shadow(0 0 calc(var(--strength, 5) * 0.5px) rgba(100, 150, 255, 0.8));
25
+
26
+ position: relative;
27
+
28
+ /* Rotation will be set by direction-specific classes */
29
+ --rotation: 0deg;
30
+ }
31
+
32
+ .marker-wind img {
33
+ transform: rotate(var(--rotation)) !important;
34
+ }
35
+
36
+ /* Variant: Travel animation (move from src to target, disappear, reappear at src)
37
+ Usage: Add 'marker-wind-travel' class in addition to marker-wind and direction class
38
+ Example: 'marker-wind marker-wind-travel marker-wind-200' */
39
+ .marker-wind-travel {
40
+ /* Override animation to use travel mode */
41
+ }
42
+
43
+ /* Pulse animation (brightness/opacity) */
44
+ @keyframes wind-pulse {
45
+ 0%, 100% {
46
+ opacity: 1;
47
+ filter: brightness(1);
48
+ }
49
+ 50% {
50
+ opacity: 0.85;
51
+ filter: brightness(1.15);
52
+ }
53
+ }
54
+
55
+ /* Travel mode pulse - fade out at destination */
56
+ @keyframes wind-pulse-travel {
57
+ 0% {
58
+ filter: brightness(1.2);
59
+ }
60
+ 70% {
61
+ filter: brightness(0.8);
62
+ }
63
+ 71%, 99% {
64
+ filter: brightness(0);
65
+ }
66
+ 100% {
67
+ filter: brightness(1.2);
68
+ }
69
+ }
70
+
71
+ /* Direction arrow indicator */
72
+ .marker-wind::after {
73
+ content: '→';
74
+ position: absolute;
75
+ top: -20px;
76
+ left: 50%;
77
+ font-size: 18px;
78
+ font-weight: bold;
79
+ color: rgba(100, 150, 255, 0.95);
80
+ text-shadow: 0 0 4px rgba(0, 0, 0, 0.7);
81
+ pointer-events: none;
82
+ transform-origin: center;
83
+ }
84
+
85
+ /* Wind direction classes for every available degree */
86
+ /* Azimuth 0 = North (upward), 90 = East (right), 180 = South (down), 270 = West (left) */
87
+ /* SVG arrow points right (East), so 90° = 0° rotation, others adjust from there */
88
+
89
+ .marker-wind-0::after, .marker-wind-360::after { transform: translateX(-50%) rotate(180deg); }
90
+ .marker-wind-0, .marker-wind-360 { --rotation: -90deg; animation: wind-0 var(--duration) ease-in-out infinite, wind-pulse var(--duration) ease-in-out infinite; }
91
+ @keyframes wind-0 { 0%, 100% { translate: 0 0; } 50% { translate: 0 calc(var(--displacement) * -1px); } }
92
+ .marker-wind-travel.marker-wind-0, .marker-wind-travel.marker-wind-360 { animation: wind-0-travel var(--duration) linear infinite, wind-pulse-travel var(--duration) linear infinite; }
93
+ @keyframes wind-0-travel { 0% { translate: 0 0; opacity: 1; } 70% { translate: 0 calc(var(--displacement) * -1px); opacity: 1; } 71% { opacity: 0; } 99% { translate: 0 0; opacity: 0; } 100% { translate: 0 0; opacity: 1; } }
94
+
95
+ .marker-wind-10::after { transform: translateX(-50%) rotate(190deg); }
96
+ .marker-wind-10 { --rotation: -80deg; animation: wind-10 var(--duration) ease-in-out infinite, wind-pulse var(--duration) ease-in-out infinite; }
97
+ @keyframes wind-10 { 0%, 100% { translate: 0 0; } 50% { translate: calc(var(--displacement) * 0.17px) calc(var(--displacement) * -0.98px); } }
98
+
99
+ .marker-wind-20::after { transform: translateX(-50%) rotate(200deg); }
100
+ .marker-wind-20 { --rotation: -70deg; animation: wind-20 var(--duration) ease-in-out infinite, wind-pulse var(--duration) ease-in-out infinite; }
101
+ @keyframes wind-20 { 0%, 100% { translate: 0 0; } 50% { translate: calc(var(--displacement) * 0.34px) calc(var(--displacement) * -0.94px); } }
102
+
103
+ .marker-wind-30::after { transform: translateX(-50%) rotate(210deg); }
104
+ .marker-wind-30 { --rotation: -60deg; animation: wind-30 var(--duration) ease-in-out infinite, wind-pulse var(--duration) ease-in-out infinite; }
105
+ @keyframes wind-30 { 0%, 100% { translate: 0 0; } 50% { translate: calc(var(--displacement) * 0.5px) calc(var(--displacement) * -0.87px); } }
106
+
107
+ .marker-wind-45::after { transform: translateX(-50%) rotate(225deg); }
108
+ .marker-wind-45 { --rotation: -45deg; animation: wind-45 var(--duration) ease-in-out infinite, wind-pulse var(--duration) ease-in-out infinite; }
109
+ @keyframes wind-45 { 0%, 100% { translate: 0 0; } 50% { translate: calc(var(--displacement) * 0.71px) calc(var(--displacement) * -0.71px); } }
110
+
111
+ .marker-wind-90::after { transform: translateX(-50%) rotate(270deg); }
112
+ .marker-wind-90 { --rotation: 0deg; animation: wind-90 var(--duration) ease-in-out infinite, wind-pulse var(--duration) ease-in-out infinite; }
113
+ @keyframes wind-90 { 0%, 100% { translate: 0 0; } 50% { translate: calc(var(--displacement) * 1px) 0; } }
114
+
115
+ .marker-wind-135::after { transform: translateX(-50%) rotate(315deg); }
116
+ .marker-wind-135 { --rotation: 45deg; animation: wind-135 var(--duration) ease-in-out infinite, wind-pulse var(--duration) ease-in-out infinite; }
117
+ @keyframes wind-135 { 0%, 100% { translate: 0 0; } 50% { translate: calc(var(--displacement) * 0.71px) calc(var(--displacement) * 0.71px); } }
118
+
119
+ .marker-wind-180::after { transform: translateX(-50%) rotate(0deg); }
120
+ .marker-wind-180 { --rotation: 90deg; animation: wind-180 var(--duration) ease-in-out infinite, wind-pulse var(--duration) ease-in-out infinite; }
121
+ @keyframes wind-180 { 0%, 100% { translate: 0 0; } 50% { translate: 0 calc(var(--displacement) * 1px); } }
122
+
123
+ .marker-wind-200::after { transform: translateX(-50%) rotate(20deg); }
124
+ .marker-wind-200 { --rotation: 110deg; animation: wind-200 var(--duration) ease-in-out infinite, wind-pulse var(--duration) ease-in-out infinite; }
125
+ @keyframes wind-200 { 0%, 100% { translate: 0 0; } 50% { translate: calc(var(--displacement) * 0.34px) calc(var(--displacement) * 0.94px); } }
126
+
127
+ .marker-wind-225::after { transform: translateX(-50%) rotate(45deg); }
128
+ .marker-wind-225 { --rotation: 135deg; animation: wind-225 var(--duration) ease-in-out infinite, wind-pulse var(--duration) ease-in-out infinite; }
129
+ @keyframes wind-225 { 0%, 100% { translate: 0 0; } 50% { translate: calc(var(--displacement) * -0.71px) calc(var(--displacement) * 0.71px); } }
130
+
131
+ .marker-wind-270::after { transform: translateX(-50%) rotate(90deg); }
132
+ .marker-wind-270 { --rotation: 180deg; animation: wind-270 var(--duration) ease-in-out infinite, wind-pulse var(--duration) ease-in-out infinite; }
133
+ @keyframes wind-270 { 0%, 100% { translate: 0 0; } 50% { translate: calc(var(--displacement) * -1px) 0; } }
134
+
135
+ .marker-wind-315::after { transform: translateX(-50%) rotate(135deg); }
136
+ .marker-wind-315 { --rotation: -135deg; animation: wind-315 var(--duration) ease-in-out infinite, wind-pulse var(--duration) ease-in-out infinite; }
137
+ @keyframes wind-315 { 0%, 100% { translate: 0 0; } 50% { translate: calc(var(--displacement) * -0.71px) calc(var(--displacement) * -0.71px); } }
138
+
139
+ /* ============================================================================
140
+ * Travel Mode Animations - Move from source to target, disappear, reappear
141
+ * ============================================================================ */
142
+
143
+ .marker-wind-travel.marker-wind-10 { animation: wind-10-travel var(--duration) linear infinite, wind-pulse-travel var(--duration) linear infinite; }
144
+ @keyframes wind-10-travel { 0% { translate: 0 0; opacity: 1; } 70% { translate: calc(var(--displacement) * 0.17px) calc(var(--displacement) * -0.98px); opacity: 1; } 71% { opacity: 0; } 99% { translate: 0 0; opacity: 0; } 100% { translate: 0 0; opacity: 1; } }
145
+
146
+ .marker-wind-travel.marker-wind-20 { animation: wind-20-travel var(--duration) linear infinite, wind-pulse-travel var(--duration) linear infinite; }
147
+ @keyframes wind-20-travel { 0% { translate: 0 0; opacity: 1; } 70% { translate: calc(var(--displacement) * 0.34px) calc(var(--displacement) * -0.94px); opacity: 1; } 71% { opacity: 0; } 99% { translate: 0 0; opacity: 0; } 100% { translate: 0 0; opacity: 1; } }
148
+
149
+ .marker-wind-travel.marker-wind-30 { animation: wind-30-travel var(--duration) linear infinite, wind-pulse-travel var(--duration) linear infinite; }
150
+ @keyframes wind-30-travel { 0% { translate: 0 0; opacity: 1; } 70% { translate: calc(var(--displacement) * 0.5px) calc(var(--displacement) * -0.87px); opacity: 1; } 71% { opacity: 0; } 99% { translate: 0 0; opacity: 0; } 100% { translate: 0 0; opacity: 1; } }
151
+
152
+ .marker-wind-travel.marker-wind-45 { animation: wind-45-travel var(--duration) linear infinite, wind-pulse-travel var(--duration) linear infinite; }
153
+ @keyframes wind-45-travel { 0% { translate: 0 0; opacity: 1; } 70% { translate: calc(var(--displacement) * 0.71px) calc(var(--displacement) * -0.71px); opacity: 1; } 71% { opacity: 0; } 99% { translate: 0 0; opacity: 0; } 100% { translate: 0 0; opacity: 1; } }
154
+
155
+ .marker-wind-travel.marker-wind-90 { animation: wind-90-travel var(--duration) linear infinite, wind-pulse-travel var(--duration) linear infinite; }
156
+ @keyframes wind-90-travel { 0% { translate: 0 0; opacity: 1; } 70% { translate: calc(var(--displacement) * 1px) 0; opacity: 1; } 71% { opacity: 0; } 99% { translate: 0 0; opacity: 0; } 100% { translate: 0 0; opacity: 1; } }
157
+
158
+ .marker-wind-travel.marker-wind-135 { animation: wind-135-travel var(--duration) linear infinite, wind-pulse-travel var(--duration) linear infinite; }
159
+ @keyframes wind-135-travel { 0% { translate: 0 0; opacity: 1; } 70% { translate: calc(var(--displacement) * 0.71px) calc(var(--displacement) * 0.71px); opacity: 1; } 71% { opacity: 0; } 99% { translate: 0 0; opacity: 0; } 100% { translate: 0 0; opacity: 1; } }
160
+
161
+ .marker-wind-travel.marker-wind-180 { animation: wind-180-travel var(--duration) linear infinite, wind-pulse-travel var(--duration) linear infinite; }
162
+ @keyframes wind-180-travel { 0% { translate: 0 0; opacity: 1; } 70% { translate: 0 calc(var(--displacement) * 1px); opacity: 1; } 71% { opacity: 0; } 99% { translate: 0 0; opacity: 0; } 100% { translate: 0 0; opacity: 1; } }
163
+
164
+ .marker-wind-travel.marker-wind-200 { animation: wind-200-travel var(--duration) linear infinite, wind-pulse-travel var(--duration) linear infinite; }
165
+ @keyframes wind-200-travel { 0% { translate: 0 0; opacity: 1; } 70% { translate: calc(var(--displacement) * 0.34px) calc(var(--displacement) * 0.94px); opacity: 1; } 71% { opacity: 0; } 99% { translate: 0 0; opacity: 0; } 100% { translate: 0 0; opacity: 1; } }
166
+
167
+ .marker-wind-travel.marker-wind-225 { animation: wind-225-travel var(--duration) linear infinite, wind-pulse-travel var(--duration) linear infinite; }
168
+ @keyframes wind-225-travel { 0% { translate: 0 0; opacity: 1; } 70% { translate: calc(var(--displacement) * -0.71px) calc(var(--displacement) * 0.71px); opacity: 1; } 71% { opacity: 0; } 99% { translate: 0 0; opacity: 0; } 100% { translate: 0 0; opacity: 1; } }
169
+
170
+ .marker-wind-travel.marker-wind-270 { animation: wind-270-travel var(--duration) linear infinite, wind-pulse-travel var(--duration) linear infinite; }
171
+ @keyframes wind-270-travel { 0% { translate: 0 0; opacity: 1; } 70% { translate: calc(var(--displacement) * -1px) 0; opacity: 1; } 71% { opacity: 0; } 99% { translate: 0 0; opacity: 0; } 100% { translate: 0 0; opacity: 1; } }
172
+
173
+ .marker-wind-travel.marker-wind-315 { animation: wind-315-travel var(--duration) linear infinite, wind-pulse-travel var(--duration) linear infinite; }
174
+ @keyframes wind-315-travel { 0% { translate: 0 0; opacity: 1; } 70% { translate: calc(var(--displacement) * -0.71px) calc(var(--displacement) * -0.71px); opacity: 1; } 71% { opacity: 0; } 99% { translate: 0 0; opacity: 0; } 100% { translate: 0 0; opacity: 1; } }