@onetype/framework 2.0.39 → 2.0.41

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.
@@ -1,493 +0,0 @@
1
- transforms.ItemAdd({
2
- id: 'heatmap',
3
- icon: 'gradient',
4
- name: 'Heatmap',
5
- description: 'Visual heatmap data representation. Display data density with color-coded intensity maps.',
6
- js: [
7
- 'https://cdn.jsdelivr.net/npm/heatmap.js@2.0.5/build/heatmap.min.js'
8
- ],
9
- config: {
10
- 'data': ['array', []],
11
- 'max-value': ['number', 100],
12
- 'min-opacity': ['number', 0],
13
- 'max-opacity': ['number', 0.6],
14
- 'radius': ['number', 40],
15
- 'blur': ['number', 0.75],
16
- 'gradient': ['object', {}],
17
- 'container-height': ['number', 400],
18
- 'background-color': ['string', 'transparent'],
19
- 'background-image': ['string', ''],
20
- 'click-tracking': ['boolean', false],
21
- 'move-tracking': ['boolean', false],
22
- 'scroll-tracking': ['boolean', false],
23
- 'touch-tracking': ['boolean', false],
24
- 'auto-resize': ['boolean', true],
25
- 'show-tooltip': ['boolean', false],
26
- 'show-legend': ['boolean', false],
27
- 'legend-position': ['string', 'br'], // tl, tr, bl, br
28
- 'debug': ['boolean', false]
29
- },
30
- code: function(data, node, transformer)
31
- {
32
- const id = 'heatmap-' + onetype.Generate(8);
33
-
34
- this.setup = () =>
35
- {
36
- node.classList.add('heatmap');
37
- node.classList.add(id);
38
-
39
- // Set container styles
40
- node.style.position = 'relative';
41
- node.style.height = data['container-height'] + 'px';
42
- node.style.backgroundColor = data['background-color'];
43
-
44
- if(data['background-image'])
45
- {
46
- node.style.backgroundImage = `url(${data['background-image']})`;
47
- node.style.backgroundSize = 'cover';
48
- node.style.backgroundPosition = 'center';
49
- }
50
-
51
- // Create heatmap container
52
- const heatmapContainer = document.createElement('div');
53
- heatmapContainer.className = 'heatmap-container';
54
- heatmapContainer.style.position = 'absolute';
55
- heatmapContainer.style.top = '0';
56
- heatmapContainer.style.left = '0';
57
- heatmapContainer.style.width = '100%';
58
- heatmapContainer.style.height = '100%';
59
-
60
- // Preserve existing content if any
61
- const children = Array.from(node.children);
62
- if(children.length > 0)
63
- {
64
- const contentWrapper = document.createElement('div');
65
- contentWrapper.className = 'heatmap-content';
66
- contentWrapper.style.position = 'relative';
67
- contentWrapper.style.zIndex = '2';
68
-
69
- children.forEach(child => contentWrapper.appendChild(child));
70
- node.appendChild(contentWrapper);
71
- }
72
-
73
- node.insertBefore(heatmapContainer, node.firstChild);
74
- this.container = heatmapContainer;
75
- };
76
-
77
- this.gradient = () =>
78
- {
79
- const customGradient = data['gradient'];
80
-
81
- // Default gradients based on use case
82
- if(Object.keys(customGradient).length === 0)
83
- {
84
- return {
85
- '.00': 'rgb(0,0,255)',
86
- '.25': 'rgb(0,255,255)',
87
- '.50': 'rgb(0,255,0)',
88
- '.75': 'rgb(255,255,0)',
89
- '1.0': 'rgb(255,0,0)'
90
- };
91
- }
92
-
93
- return customGradient;
94
- };
95
-
96
- this.config = () =>
97
- {
98
- return {
99
- container: this.container,
100
- radius: data['radius'],
101
- maxOpacity: data['max-opacity'],
102
- minOpacity: data['min-opacity'],
103
- blur: data['blur'],
104
- gradient: this.gradient()
105
- };
106
- };
107
-
108
- this.sampleData = () =>
109
- {
110
- // Generate sample data if none provided
111
- const width = node.offsetWidth;
112
- const height = node.offsetHeight;
113
- const points = [];
114
-
115
- // Create interesting sample pattern
116
- for(let i = 0; i < 50; i++)
117
- {
118
- points.push({
119
- x: Math.floor(Math.random() * width),
120
- y: Math.floor(Math.random() * height),
121
- value: Math.floor(Math.random() * 100)
122
- });
123
- }
124
-
125
- // Add some hotspots
126
- for(let i = 0; i < 5; i++)
127
- {
128
- const x = Math.floor(Math.random() * width);
129
- const y = Math.floor(Math.random() * height);
130
-
131
- for(let j = 0; j < 20; j++)
132
- {
133
- points.push({
134
- x: x + (Math.random() - 0.5) * 100,
135
- y: y + (Math.random() - 0.5) * 100,
136
- value: 80 + Math.floor(Math.random() * 20)
137
- });
138
- }
139
- }
140
-
141
- return points;
142
- };
143
-
144
- this.processData = () =>
145
- {
146
- const inputData = data['data'];
147
-
148
- if(!inputData || inputData.length === 0)
149
- {
150
- return {
151
- max: data['max-value'],
152
- data: this.sampleData()
153
- };
154
- }
155
-
156
- // Ensure data points have correct format
157
- const processedData = inputData.map(point => ({
158
- x: parseInt(point.x || 0),
159
- y: parseInt(point.y || 0),
160
- value: parseInt(point.value || 1)
161
- }));
162
-
163
- return {
164
- max: data['max-value'],
165
- data: processedData
166
- };
167
- };
168
-
169
- this.tooltip = () =>
170
- {
171
- if(!data['show-tooltip'])
172
- {
173
- return;
174
- }
175
-
176
- const tooltip = document.createElement('div');
177
- tooltip.className = 'heatmap-tooltip';
178
- tooltip.style.cssText = `
179
- position: absolute;
180
- background: rgba(0, 0, 0, 0.8);
181
- color: white;
182
- padding: 5px 10px;
183
- border-radius: 4px;
184
- font-size: 12px;
185
- pointer-events: none;
186
- display: none;
187
- z-index: 1000;
188
- `;
189
-
190
- node.appendChild(tooltip);
191
- this.tooltip = tooltip;
192
-
193
- node.addEventListener('mousemove', (e) =>
194
- {
195
- const rect = node.getBoundingClientRect();
196
- const x = e.clientX - rect.left;
197
- const y = e.clientY - rect.top;
198
-
199
- const value = this.instance.getValueAt({
200
- x: Math.floor(x),
201
- y: Math.floor(y)
202
- });
203
-
204
- if(value > 0)
205
- {
206
- tooltip.textContent = `Value: ${value}`;
207
- tooltip.style.left = (x + 10) + 'px';
208
- tooltip.style.top = (y - 30) + 'px';
209
- tooltip.style.display = 'block';
210
- }
211
- else
212
- {
213
- tooltip.style.display = 'none';
214
- }
215
- });
216
-
217
- node.addEventListener('mouseleave', () =>
218
- {
219
- tooltip.style.display = 'none';
220
- });
221
- };
222
-
223
- this.legend = () =>
224
- {
225
- if(!data['show-legend'])
226
- {
227
- return;
228
- }
229
-
230
- const position = data['legend-position'];
231
- const legend = document.createElement('div');
232
- legend.className = 'heatmap-legend';
233
-
234
- const positions = {
235
- 'tl': 'top: 10px; left: 10px;',
236
- 'tr': 'top: 10px; right: 10px;',
237
- 'bl': 'bottom: 10px; left: 10px;',
238
- 'br': 'bottom: 10px; right: 10px;'
239
- };
240
-
241
- legend.style.cssText = `
242
- position: absolute;
243
- ${positions[position]}
244
- background: rgba(255, 255, 255, 0.9);
245
- padding: 10px;
246
- border-radius: 4px;
247
- box-shadow: 0 2px 4px rgba(0,0,0,0.1);
248
- z-index: 10;
249
- `;
250
-
251
- const gradientBar = document.createElement('div');
252
- gradientBar.style.cssText = `
253
- width: 150px;
254
- height: 20px;
255
- background: linear-gradient(to right,
256
- rgb(0,0,255),
257
- rgb(0,255,255),
258
- rgb(0,255,0),
259
- rgb(255,255,0),
260
- rgb(255,0,0)
261
- );
262
- border-radius: 2px;
263
- margin-bottom: 5px;
264
- `;
265
-
266
- const labels = document.createElement('div');
267
- labels.style.cssText = `
268
- display: flex;
269
- justify-content: space-between;
270
- font-size: 11px;
271
- color: #333;
272
- `;
273
- labels.innerHTML = `<span>0</span><span>${data['max-value']}</span>`;
274
-
275
- legend.appendChild(gradientBar);
276
- legend.appendChild(labels);
277
- node.appendChild(legend);
278
- };
279
-
280
- this.tracking = () =>
281
- {
282
- const trackedData = [];
283
- let tracking = false;
284
-
285
- const addPoint = (e, multiplier = 1) =>
286
- {
287
- const rect = node.getBoundingClientRect();
288
- const x = e.clientX - rect.left;
289
- const y = e.clientY - rect.top;
290
-
291
- if(x >= 0 && x <= rect.width && y >= 0 && y <= rect.height)
292
- {
293
- const point = {
294
- x: Math.floor(x),
295
- y: Math.floor(y),
296
- value: 10 * multiplier
297
- };
298
-
299
- trackedData.push(point);
300
- this.instance.addData(point);
301
-
302
- if(data['debug'])
303
- {
304
- console.log('Heatmap point added:', point);
305
- }
306
- }
307
- };
308
-
309
- if(data['click-tracking'])
310
- {
311
- node.addEventListener('click', (e) => addPoint(e, 5));
312
- }
313
-
314
- if(data['move-tracking'])
315
- {
316
- node.addEventListener('mousemove', (e) =>
317
- {
318
- if(Math.random() > 0.95) // Sample 5% of movements
319
- {
320
- addPoint(e, 1);
321
- }
322
- });
323
- }
324
-
325
- if(data['scroll-tracking'])
326
- {
327
- let scrollTimer;
328
- node.addEventListener('scroll', (e) =>
329
- {
330
- clearTimeout(scrollTimer);
331
- scrollTimer = setTimeout(() =>
332
- {
333
- const rect = node.getBoundingClientRect();
334
- const centerX = rect.width / 2;
335
- const centerY = rect.height / 2 + node.scrollTop;
336
-
337
- const point = {
338
- x: Math.floor(centerX),
339
- y: Math.floor(centerY),
340
- value: 20
341
- };
342
-
343
- this.instance.addData(point);
344
- }, 100);
345
- });
346
- }
347
-
348
- if(data['touch-tracking'])
349
- {
350
- node.addEventListener('touchstart', (e) =>
351
- {
352
- const touch = e.touches[0];
353
- addPoint(touch, 3);
354
- });
355
-
356
- node.addEventListener('touchmove', (e) =>
357
- {
358
- if(Math.random() > 0.9) // Sample 10% of touch movements
359
- {
360
- const touch = e.touches[0];
361
- addPoint(touch, 1);
362
- }
363
- });
364
- }
365
-
366
- // Store tracked data for export
367
- node.heatmapData = trackedData;
368
- };
369
-
370
- this.resize = () =>
371
- {
372
- if(!data['auto-resize'])
373
- {
374
- return;
375
- }
376
-
377
- let resizeTimer;
378
- const resizeObserver = new ResizeObserver(() =>
379
- {
380
- clearTimeout(resizeTimer);
381
- resizeTimer = setTimeout(() =>
382
- {
383
- if(this.instance)
384
- {
385
- const currentData = this.instance.getData();
386
- this.instance.setData(currentData);
387
- }
388
- }, 250);
389
- });
390
-
391
- resizeObserver.observe(node);
392
- };
393
-
394
- this.styles = () =>
395
- {
396
- const style = document.createElement('style');
397
-
398
- style.textContent = `
399
- .heatmap-${id} {
400
- position: relative;
401
- overflow: hidden;
402
- }
403
- .heatmap-${id} canvas {
404
- position: absolute;
405
- top: 0;
406
- left: 0;
407
- pointer-events: ${(data['click-tracking'] || data['move-tracking']) ? 'auto' : 'none'};
408
- }
409
- `;
410
-
411
- document.head.appendChild(style);
412
- };
413
-
414
- this.initialize = () =>
415
- {
416
- setTimeout(() =>
417
- {
418
- if(typeof h337 === 'undefined')
419
- {
420
- console.error('Heatmap.js library not loaded');
421
- return;
422
- }
423
-
424
- // Create heatmap instance
425
- this.instance = h337.create(this.config());
426
-
427
- // Set initial data
428
- this.instance.setData(this.processData());
429
-
430
- // Add tooltip
431
- this.tooltip();
432
-
433
- // Add legend
434
- this.legend();
435
-
436
- // Setup tracking
437
- this.tracking();
438
-
439
- // Setup resize handler
440
- this.resize();
441
-
442
- // Expose instance and methods
443
- node.heatmap = this.instance;
444
-
445
- // Add utility methods
446
- node.setHeatmapData = (newData) =>
447
- {
448
- if(this.instance)
449
- {
450
- this.instance.setData({
451
- max: data['max-value'],
452
- data: newData
453
- });
454
- }
455
- };
456
-
457
- node.addHeatmapPoint = (point) =>
458
- {
459
- if(this.instance)
460
- {
461
- this.instance.addData(point);
462
- }
463
- };
464
-
465
- node.clearHeatmap = () =>
466
- {
467
- if(this.instance)
468
- {
469
- this.instance.setData({max: 1, data: []});
470
- }
471
- };
472
-
473
- node.exportHeatmapData = () =>
474
- {
475
- return this.instance ? this.instance.getData() : null;
476
- };
477
-
478
- if(data['debug'])
479
- {
480
- console.log('Heatmap initialized:', {
481
- id: identifier,
482
- config: this.config(),
483
- data: this.processData()
484
- });
485
- }
486
- }, 100);
487
- };
488
-
489
- this.setup();
490
- this.styles();
491
- this.initialize();
492
- }
493
- });