heatspot 0.2.2 → 0.2.4
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 +84 -3
- package/dist/heatspot-element.d.ts +12 -0
- package/dist/heatspot-element.js +52 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,6 +8,28 @@
|
|
|
8
8
|
|
|
9
9
|
`heatspot` is an ESM TypeScript library for capturing pointer heat data and rendering an embeddable heatmap web component.
|
|
10
10
|
|
|
11
|
+
## Try the Demo
|
|
12
|
+
|
|
13
|
+
Live demo:
|
|
14
|
+
|
|
15
|
+
- [](https://davidhanson90.github.io/heatspot/)
|
|
16
|
+
|
|
17
|
+
How to try it:
|
|
18
|
+
|
|
19
|
+
1. Open the demo URL.
|
|
20
|
+
2. Move your cursor around the demo area for a few seconds.
|
|
21
|
+
3. Click the toggle icon in the top-left of the component to show the heat overlay.
|
|
22
|
+
4. Continue interacting to see hotspots update in real time.
|
|
23
|
+
|
|
24
|
+
To run the demo locally:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm install
|
|
28
|
+
npm start
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Then open the local URL shown in your terminal (Vite default is usually `http://localhost:5173`).
|
|
32
|
+
|
|
11
33
|
## Features
|
|
12
34
|
|
|
13
35
|
- ESM package output with TypeScript declarations
|
|
@@ -59,11 +81,43 @@ Example with hidden toolbar:
|
|
|
59
81
|
</heat-spot>
|
|
60
82
|
```
|
|
61
83
|
|
|
62
|
-
###
|
|
84
|
+
### 3. Read heatmap data from a `<heat-spot>` element
|
|
63
85
|
|
|
64
|
-
|
|
86
|
+
```ts
|
|
87
|
+
const element = document.querySelector<HeatSpotElement>('heat-spot');
|
|
88
|
+
|
|
89
|
+
const snapshot = element.getHeatmapData();
|
|
90
|
+
|
|
91
|
+
console.log(snapshot);
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Example data shape:
|
|
95
|
+
|
|
96
|
+
```json
|
|
97
|
+
{
|
|
98
|
+
"totalSamples": 42,
|
|
99
|
+
"trackedSince": 1741351200000,
|
|
100
|
+
"viewport": { "width": 960, "height": 540 },
|
|
101
|
+
"hotspots": [
|
|
102
|
+
{
|
|
103
|
+
"id": "hs-0",
|
|
104
|
+
"x": 418.2,
|
|
105
|
+
"y": 225.6,
|
|
106
|
+
"count": 18,
|
|
107
|
+
"intensity": 1
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
"id": "hs-1",
|
|
111
|
+
"x": 701.1,
|
|
112
|
+
"y": 392.8,
|
|
113
|
+
"count": 9,
|
|
114
|
+
"intensity": 0.5
|
|
115
|
+
}
|
|
116
|
+
]
|
|
117
|
+
}
|
|
118
|
+
```
|
|
65
119
|
|
|
66
|
-
###
|
|
120
|
+
### 4. Optional global tracking API
|
|
67
121
|
|
|
68
122
|
```ts
|
|
69
123
|
import {
|
|
@@ -84,6 +138,33 @@ stopMouseTracking();
|
|
|
84
138
|
resetMouseHeatmap();
|
|
85
139
|
```
|
|
86
140
|
|
|
141
|
+
### 5. Export the heatmap visualization as an image
|
|
142
|
+
|
|
143
|
+
```ts
|
|
144
|
+
const element = document.querySelector<HeatSpotElement>("heat-spot");
|
|
145
|
+
|
|
146
|
+
if (element) {
|
|
147
|
+
const imageDataUrl = element.getHeatmapImage();
|
|
148
|
+
|
|
149
|
+
if (imageDataUrl) {
|
|
150
|
+
console.log(imageDataUrl);
|
|
151
|
+
// Example prefix:
|
|
152
|
+
// data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...
|
|
153
|
+
|
|
154
|
+
// Optional download example
|
|
155
|
+
const link = document.createElement("a");
|
|
156
|
+
link.href = imageDataUrl;
|
|
157
|
+
link.download = "heatmap.png";
|
|
158
|
+
link.click();
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
`getHeatmapImage()` returns:
|
|
164
|
+
|
|
165
|
+
- A `data:` URL string when the component has measurable dimensions.
|
|
166
|
+
- `null` if the element has no measurable surface yet (for example, hidden or not laid out).
|
|
167
|
+
|
|
87
168
|
## Scripts
|
|
88
169
|
|
|
89
170
|
- `npm run build` - compile library to `dist/`
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { LitElement } from "lit";
|
|
2
|
+
import { type HeatmapSnapshot } from "./contracts/heatmap-contracts.js";
|
|
2
3
|
export declare class HeatSpotElement extends LitElement {
|
|
3
4
|
static properties: {
|
|
4
5
|
heatmapVisible: {
|
|
@@ -15,6 +16,17 @@ export declare class HeatSpotElement extends LitElement {
|
|
|
15
16
|
private readonly tracker;
|
|
16
17
|
static styles: import("lit").CSSResult;
|
|
17
18
|
constructor();
|
|
19
|
+
/**
|
|
20
|
+
* Returns the current tracked heatmap snapshot for this element instance.
|
|
21
|
+
*/
|
|
22
|
+
getHeatmapData(): HeatmapSnapshot;
|
|
23
|
+
/**
|
|
24
|
+
* Renders the current heatmap visualization into an image data URL.
|
|
25
|
+
*/
|
|
26
|
+
getHeatmapImage(options?: {
|
|
27
|
+
type?: string;
|
|
28
|
+
quality?: number;
|
|
29
|
+
}): string | null;
|
|
18
30
|
/**
|
|
19
31
|
* Stops frame rendering when element leaves the document.
|
|
20
32
|
*/
|
package/dist/heatspot-element.js
CHANGED
|
@@ -40,14 +40,22 @@ export class HeatSpotElement extends LitElement {
|
|
|
40
40
|
color: #ffffff;
|
|
41
41
|
padding: 0;
|
|
42
42
|
line-height: 1;
|
|
43
|
-
font-size: 0.92rem;
|
|
44
|
-
font-weight: 700;
|
|
45
43
|
cursor: pointer;
|
|
46
44
|
z-index: 10001;
|
|
45
|
+
opacity: 0.72;
|
|
46
|
+
transition: opacity 180ms ease;
|
|
47
|
+
display: grid;
|
|
48
|
+
place-items: center;
|
|
47
49
|
}
|
|
48
50
|
|
|
49
51
|
.toggle:hover {
|
|
50
|
-
|
|
52
|
+
opacity: 1;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.toggle-icon {
|
|
56
|
+
width: 0.95rem;
|
|
57
|
+
height: 0.95rem;
|
|
58
|
+
fill: currentColor;
|
|
51
59
|
}
|
|
52
60
|
|
|
53
61
|
.overlay {
|
|
@@ -64,6 +72,36 @@ export class HeatSpotElement extends LitElement {
|
|
|
64
72
|
this.heatmapVisible = false;
|
|
65
73
|
this.toolbar = "simple";
|
|
66
74
|
}
|
|
75
|
+
/**
|
|
76
|
+
* Returns the current tracked heatmap snapshot for this element instance.
|
|
77
|
+
*/
|
|
78
|
+
getHeatmapData() {
|
|
79
|
+
return this.tracker.getSnapshot();
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Renders the current heatmap visualization into an image data URL.
|
|
83
|
+
*/
|
|
84
|
+
getHeatmapImage(options = {}) {
|
|
85
|
+
const surface = this.renderRoot.querySelector(".surface");
|
|
86
|
+
if (!surface) {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
const width = Math.round(surface.clientWidth);
|
|
90
|
+
const height = Math.round(surface.clientHeight);
|
|
91
|
+
if (width <= 0 || height <= 0) {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
const imageCanvas = document.createElement("canvas");
|
|
95
|
+
imageCanvas.width = width;
|
|
96
|
+
imageCanvas.height = height;
|
|
97
|
+
const context = imageCanvas.getContext("2d");
|
|
98
|
+
if (!context) {
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
const snapshot = this.tracker.getSnapshot();
|
|
102
|
+
renderHeatmapOverlay(context, width, height, snapshot.hotspots);
|
|
103
|
+
return imageCanvas.toDataURL(options.type ?? "image/png", options.quality);
|
|
104
|
+
}
|
|
67
105
|
/**
|
|
68
106
|
* Stops frame rendering when element leaves the document.
|
|
69
107
|
*/
|
|
@@ -165,7 +203,17 @@ export class HeatSpotElement extends LitElement {
|
|
|
165
203
|
${this.toolbar === "hidden"
|
|
166
204
|
? null
|
|
167
205
|
: html `<button class="toggle" @click=${this.toggleHeatmap} aria-label="Toggle heatmap">
|
|
168
|
-
|
|
206
|
+
<svg
|
|
207
|
+
class="toggle-icon"
|
|
208
|
+
viewBox="0 0 24 24"
|
|
209
|
+
role="img"
|
|
210
|
+
aria-label="Heatmap fire icon"
|
|
211
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
212
|
+
>
|
|
213
|
+
<path
|
|
214
|
+
d="M12 2.5c.4 2.3-.2 3.9-1.3 5.3-1.2 1.5-2.6 2.9-2.6 5.3 0 2.2 1.8 4 3.9 4 .8 0 1.6-.2 2.2-.6-1.1-.4-1.9-1.5-1.9-2.8 0-1.9 1.6-3 2.7-4.4.8-1 .9-2.1.8-3.3 2.3 1.5 4.2 4 4.2 7.1 0 4.2-3.4 7.6-7.6 7.6S4.8 17.3 4.8 13.1c0-4.3 2.5-6.7 4.5-8.7C10.4 3.3 11.2 2.6 12 2.5z"
|
|
215
|
+
/>
|
|
216
|
+
</svg>
|
|
169
217
|
</button>`}
|
|
170
218
|
${this.heatmapVisible ? html `<canvas id="heatmap" class="overlay"></canvas>` : null}
|
|
171
219
|
`;
|