bubble-chart-js 1.1.0 → 2.0.0

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/README.md CHANGED
@@ -34,7 +34,7 @@ Scientific Research – Show relationships in grouped experimental data.
34
34
 
35
35
  Here’s an example of the bubble chart generated using this package:
36
36
 
37
- ![Stacked Bubble Chart Example](https://github.com/Praga-Dev/bubbleChartJS/blob/HEAD/assets/bubble-chart.png)
37
+ ![Stacked Bubble Chart Example](https://github.com/praga-dev/bubble-chart-js/blob/HEAD/assets/bubble-chart.png)
38
38
 
39
39
  ## Installation
40
40
 
@@ -0,0 +1,323 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+
4
+ <head>
5
+ <meta charset="UTF-8" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>bubble-chart-js · Glassmorphism</title>
8
+ <style>
9
+ *,
10
+ *::before,
11
+ *::after {
12
+ box-sizing: border-box;
13
+ margin: 0;
14
+ padding: 0;
15
+ }
16
+
17
+ /* ── Page ──────────────────────────────────────────────────────────────── */
18
+ body {
19
+ min-height: 100vh;
20
+ background: #0b0d18;
21
+ display: flex;
22
+ flex-direction: column;
23
+ align-items: center;
24
+ justify-content: center;
25
+ font-family: system-ui, -apple-system, sans-serif;
26
+ overflow: hidden;
27
+ position: relative;
28
+ }
29
+
30
+ /* ── Ambient background orbs ──────────────────────────────────────────── */
31
+ .orb {
32
+ position: fixed;
33
+ border-radius: 50%;
34
+ filter: blur(80px);
35
+ pointer-events: none;
36
+ animation: drift linear infinite;
37
+ }
38
+
39
+ .orb-1 {
40
+ width: 520px;
41
+ height: 520px;
42
+ background: radial-gradient(circle, rgba(79, 159, 248, 0.18) 0%, transparent 70%);
43
+ top: -120px;
44
+ left: -100px;
45
+ animation-duration: 22s;
46
+ }
47
+
48
+ .orb-2 {
49
+ width: 440px;
50
+ height: 440px;
51
+ background: radial-gradient(circle, rgba(168, 85, 247, 0.14) 0%, transparent 70%);
52
+ bottom: -80px;
53
+ right: -80px;
54
+ animation-duration: 28s;
55
+ animation-direction: reverse;
56
+ }
57
+
58
+ .orb-3 {
59
+ width: 300px;
60
+ height: 300px;
61
+ background: radial-gradient(circle, rgba(45, 212, 191, 0.12) 0%, transparent 70%);
62
+ top: 40%;
63
+ right: 10%;
64
+ animation-duration: 18s;
65
+ }
66
+
67
+ .orb-4 {
68
+ width: 260px;
69
+ height: 260px;
70
+ background: radial-gradient(circle, rgba(244, 63, 94, 0.10) 0%, transparent 70%);
71
+ bottom: 20%;
72
+ left: 8%;
73
+ animation-duration: 24s;
74
+ animation-direction: reverse;
75
+ }
76
+
77
+ @keyframes drift {
78
+ 0% {
79
+ transform: translate(0, 0) scale(1);
80
+ }
81
+
82
+ 33% {
83
+ transform: translate(24px, -18px) scale(1.04);
84
+ }
85
+
86
+ 66% {
87
+ transform: translate(-16px, 22px) scale(0.97);
88
+ }
89
+
90
+ 100% {
91
+ transform: translate(0, 0) scale(1);
92
+ }
93
+ }
94
+
95
+ /* ── Dot-grid overlay ─────────────────────────────────────────────────── */
96
+ body::before {
97
+ content: '';
98
+ position: fixed;
99
+ inset: 0;
100
+ background-image: radial-gradient(rgba(255, 255, 255, 0.035) 1px, transparent 1px);
101
+ background-size: 28px 28px;
102
+ pointer-events: none;
103
+ }
104
+
105
+ /* ── Header ───────────────────────────────────────────────────────────── */
106
+ .header {
107
+ position: relative;
108
+ text-align: center;
109
+ margin-bottom: 2rem;
110
+ z-index: 1;
111
+ }
112
+
113
+ .header h1 {
114
+ font-size: 1.5rem;
115
+ font-weight: 700;
116
+ letter-spacing: -0.02em;
117
+ color: rgba(255, 255, 255, 0.90);
118
+ }
119
+
120
+ .header p {
121
+ font-size: 0.8rem;
122
+ color: rgba(255, 255, 255, 0.35);
123
+ margin-top: 0.3rem;
124
+ letter-spacing: 0.06em;
125
+ text-transform: uppercase;
126
+ }
127
+
128
+ /* ── Glassmorphism card ───────────────────────────────────────────────── */
129
+ .glass-card {
130
+ display: flex;
131
+ justify-content: center;
132
+ align-items: center;
133
+ flex-direction: column;
134
+ position: relative;
135
+ z-index: 1;
136
+ background: rgba(30, 37, 59, 0.6);
137
+ backdrop-filter: blur(12px);
138
+ -webkit-backdrop-filter: blur(12px);
139
+ border: 1px solid rgba(67, 71, 89, 0.15);
140
+ border-radius: 20px;
141
+ padding: 1.5rem;
142
+ box-shadow:
143
+ 0 0 0 1px rgba(255, 255, 255, 0.04) inset,
144
+ 0 24px 64px rgba(0, 0, 0, 0.5);
145
+ }
146
+
147
+ /* Subtle inner top-edge highlight */
148
+ .glass-card::before {
149
+ content: '';
150
+ position: absolute;
151
+ top: 0;
152
+ left: 10%;
153
+ right: 10%;
154
+ height: 1px;
155
+ background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.12), transparent);
156
+ border-radius: 50%;
157
+ }
158
+
159
+ /* ── Chart container ──────────────────────────────────────────────────── */
160
+ #chart-glass {
161
+ width: 680px;
162
+ height: 500px;
163
+ position: relative;
164
+
165
+ /* clip bubbles that drift past the edge */
166
+ overflow: hidden;
167
+ /* match the card corner so clipping looks natural */
168
+ border-radius: 12px;
169
+ }
170
+
171
+ /* ── Legend ───────────────────────────────────────────────────────────── */
172
+ .legend {
173
+ display: flex;
174
+ flex-wrap: wrap;
175
+ gap: 0.5rem 1.2rem;
176
+ margin-top: 1rem;
177
+ justify-content: center;
178
+ }
179
+
180
+ .legend-item {
181
+ display: flex;
182
+ align-items: center;
183
+ gap: 0.4rem;
184
+ font-size: 0.72rem;
185
+ color: rgba(255, 255, 255, 0.5);
186
+ letter-spacing: 0.03em;
187
+ }
188
+
189
+ .legend-dot {
190
+ width: 8px;
191
+ height: 8px;
192
+ border-radius: 50%;
193
+ flex-shrink: 0;
194
+ box-shadow: 0 0 6px currentColor;
195
+ }
196
+ </style>
197
+ </head>
198
+
199
+ <body>
200
+
201
+ <!-- Ambient light orbs -->
202
+ <div class="orb orb-1"></div>
203
+ <div class="orb orb-2"></div>
204
+ <div class="orb orb-3"></div>
205
+ <div class="orb orb-4"></div>
206
+
207
+ <!-- Header -->
208
+ <header class="header">
209
+ <h1>Frontend Ecosystem · 2025</h1>
210
+ <p>Community adoption · bubble area ∝ usage share</p>
211
+ </header>
212
+
213
+ <!-- Card -->
214
+ <div class="glass-card">
215
+ <div id="chart-glass"></div>
216
+ <div class="legend" id="legend"></div>
217
+ </div>
218
+
219
+ <script src="../dist/bubbleChart.umd.js"></script>
220
+ <script>
221
+ // UMD bundle exposes initializeChart directly on window.
222
+ // Alpha is encoded directly into bubbleColor as rgba() — works with any
223
+ // bundle version because SVG fill natively understands rgba() strings.
224
+
225
+ // ── Each entry: solid color for ring/legend + rgba fill for the bubble ───
226
+ const ITEMS = [
227
+ { label: 'Bubble 1', value: 42, solid: '#5b9cf6', fill: 'rgba(91,156,246,0.38)' },
228
+ { label: 'Bubble 2', value: 35, solid: '#8b6fd4', fill: 'rgba(139,111,212,0.38)' },
229
+ ];
230
+
231
+ // Map fill → solid so the border hook can use the full-opacity color
232
+ const fillToSolid = new Map(ITEMS.map(c => [c.fill, c.solid]));
233
+
234
+ const data = ITEMS.map(({ label, value, fill }) => ({
235
+ label,
236
+ value,
237
+ bubbleColor: fill, // rgba() — transparent fill, no rebuild required
238
+ }));
239
+
240
+ // svg
241
+ // // ── Chart init ───────────────────────────────────────────────────────────
242
+ // const chart = initializeChart({
243
+ // canvasContainerId: 'chart-glass',
244
+ // data,
245
+ // render: { mode: 'svg', theme: 'flat' },
246
+ // layout: { type: 'static' },
247
+ // defaultFontColor: 'rgba(255,255,255,0.88)',
248
+ // defaultFontFamily: 'system-ui',
249
+ // fontSize: 13,
250
+ // });
251
+
252
+ // canvas
253
+ const chart = initializeChart({
254
+ canvasContainerId: 'chart-glass',
255
+ data,
256
+ render: { mode: 'canvas', theme: 'flat' }, // ← only change here
257
+ layout: { type: 'static' },
258
+ defaultFontColor: 'rgba(255,255,255,0.88)',
259
+ defaultFontFamily: 'system-ui',
260
+ fontSize: 13,
261
+ });
262
+
263
+ // Canvas layer hook — same ring, different API
264
+ chart.addLayerHook({
265
+ layer: 'bubbles',
266
+ priority: 10,
267
+ fn(ctx, bubbles) {
268
+ if (!ctx.canvas) return; // ← ctx.canvas instead of ctx.svg
269
+ const c = ctx.canvas;
270
+ for (const b of bubbles) {
271
+ const r = b.renderRadius * b.renderScale;
272
+ c.beginPath();
273
+ c.arc(b.renderX, b.renderY, r - 0.5, 0, Math.PI * 2);
274
+ c.strokeStyle = fillToSolid.get(b.color) ?? b.color;
275
+ c.lineWidth = 1;
276
+ c.globalAlpha = 0.35;
277
+ c.stroke();
278
+ c.globalAlpha = 1;
279
+ }
280
+ },
281
+ });
282
+
283
+ // ── Layer hook: solid-color border ring ──────────────────────────────────
284
+ const NS = 'http://www.w3.org/2000/svg';
285
+ chart.addLayerHook({
286
+ layer: 'bubbles',
287
+ priority: 10,
288
+ fn(ctx, bubbles) {
289
+ if (!ctx.svg) return;
290
+ for (const b of bubbles) {
291
+ const r = b.renderRadius * b.renderScale;
292
+ const ring = document.createElementNS(NS, 'circle');
293
+ ring.setAttribute('cx', String(b.renderX));
294
+ ring.setAttribute('cy', String(b.renderY));
295
+ ring.setAttribute('r', String(r - 0.5));
296
+ ring.setAttribute('fill', 'none');
297
+ ring.setAttribute('stroke', fillToSolid.get(b.color) ?? b.color);
298
+ ring.setAttribute('stroke-width', '1');
299
+ ring.setAttribute('opacity', '0.35');
300
+ ctx.svg.appendChild(ring);
301
+ }
302
+ },
303
+ });
304
+
305
+ // ── Build legend ─────────────────────────────────────────────────────────
306
+ const legendEl = document.getElementById('legend');
307
+ for (const item of ITEMS) {
308
+ const div = document.createElement('div');
309
+ div.className = 'legend-item';
310
+
311
+ const dot = document.createElement('span');
312
+ dot.className = 'legend-dot';
313
+ dot.style.background = item.solid; // solid color for the legend dot
314
+ dot.style.color = item.solid;
315
+
316
+ div.appendChild(dot);
317
+ div.appendChild(document.createTextNode(`${item.label} · ${item.value}%`));
318
+ legendEl.appendChild(div);
319
+ }
320
+ </script>
321
+ </body>
322
+
323
+ </html>