@gemx-dev/clarity-visualize 0.8.61 → 0.8.63
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/build/clarity.visualize.js +153 -102
- package/build/clarity.visualize.min.js +1 -1
- package/build/clarity.visualize.module.js +153 -102
- package/package.json +2 -2
- package/src/heatmap.ts +33 -3
- package/src/visualizer.ts +14 -2
- package/types/visualize.d.ts +2 -0
|
@@ -67,105 +67,6 @@ function __generator(thisArg, body) {
|
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
var _a$1;
|
|
71
|
-
var DataHelper = /** @class */ (function () {
|
|
72
|
-
function DataHelper(state) {
|
|
73
|
-
var _this = this;
|
|
74
|
-
this.regionMap = {};
|
|
75
|
-
this.regions = {};
|
|
76
|
-
this.metrics = {};
|
|
77
|
-
this.lean = false;
|
|
78
|
-
this.reset = function () {
|
|
79
|
-
_this.metrics = {};
|
|
80
|
-
_this.lean = false;
|
|
81
|
-
_this.regions = {};
|
|
82
|
-
_this.regionMap = {};
|
|
83
|
-
};
|
|
84
|
-
this.metric = function (event) {
|
|
85
|
-
var _a;
|
|
86
|
-
if (_this.state.options.metadata) {
|
|
87
|
-
var metricMarkup = [];
|
|
88
|
-
var regionMarkup = [];
|
|
89
|
-
// Copy over metrics for future reference
|
|
90
|
-
for (var m in event.data) {
|
|
91
|
-
var eventType = typeof event.data[m];
|
|
92
|
-
if (eventType === "number" || (event.event === 1 /* Data.Event.Dimension */ && m === 37 /* Data.Dimension.InteractionNextPaint */.toString())) {
|
|
93
|
-
if (!(m in _this.metrics)) {
|
|
94
|
-
_this.metrics[m] = 0;
|
|
95
|
-
}
|
|
96
|
-
var key = parseInt(m, 10);
|
|
97
|
-
var value = eventType === "object" ? Number((_a = event.data[m]) === null || _a === void 0 ? void 0 : _a[0]) : event.data[m];
|
|
98
|
-
if (m in DataHelper.METRIC_MAP && (DataHelper.METRIC_MAP[m].unit === "html-price" || DataHelper.METRIC_MAP[m].unit === "ld-price")) {
|
|
99
|
-
_this.metrics[m] = value;
|
|
100
|
-
}
|
|
101
|
-
else {
|
|
102
|
-
_this.metrics[m] += value;
|
|
103
|
-
}
|
|
104
|
-
_this.lean = key === 1 /* Data.Metric.Playback */ && value === 0 ? true : _this.lean;
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
for (var entry in _this.metrics) {
|
|
108
|
-
if (entry in DataHelper.METRIC_MAP) {
|
|
109
|
-
var m = _this.metrics[entry];
|
|
110
|
-
var map = DataHelper.METRIC_MAP[entry];
|
|
111
|
-
var unit = "unit" in map ? map.unit : "" /* Data.Constant.Empty */;
|
|
112
|
-
metricMarkup.push("<li><h2>".concat(_this.value(m, unit), "<span>").concat(_this.key(unit), "</span></h2>").concat(map.name, "</li>"));
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
// Append region information to metadata
|
|
116
|
-
for (var name_1 in _this.regions) {
|
|
117
|
-
var r = _this.regions[name_1];
|
|
118
|
-
var className = (r.visibility === 10 /* Layout.RegionVisibility.Visible */ ? "visible" : (r.interaction === 20 /* Layout.InteractionState.Clicked */ ? "clicked" : "" /* Data.Constant.Empty */));
|
|
119
|
-
regionMarkup.push("<span class=\"".concat(className, "\">").concat(name_1, "</span>"));
|
|
120
|
-
}
|
|
121
|
-
_this.state.options.metadata.innerHTML = "<ul>".concat(metricMarkup.join("" /* Data.Constant.Empty */), "</ul><div>").concat(regionMarkup.join("" /* Data.Constant.Empty */), "</div>");
|
|
122
|
-
}
|
|
123
|
-
};
|
|
124
|
-
this.key = function (unit) {
|
|
125
|
-
switch (unit) {
|
|
126
|
-
case "html-price":
|
|
127
|
-
case "ld-price":
|
|
128
|
-
case "cls":
|
|
129
|
-
return "" /* Data.Constant.Empty */;
|
|
130
|
-
default: return unit;
|
|
131
|
-
}
|
|
132
|
-
};
|
|
133
|
-
this.value = function (num, unit) {
|
|
134
|
-
switch (unit) {
|
|
135
|
-
case "KB": return Math.round(num / 1024);
|
|
136
|
-
case "s": return Math.round(num / 10) / 100;
|
|
137
|
-
case "cls": return num / 1000;
|
|
138
|
-
case "html-price": return num / 100;
|
|
139
|
-
default: return num;
|
|
140
|
-
}
|
|
141
|
-
};
|
|
142
|
-
this.state = state;
|
|
143
|
-
}
|
|
144
|
-
DataHelper.prototype.region = function (event) {
|
|
145
|
-
var data = event.data;
|
|
146
|
-
for (var _i = 0, data_1 = data; _i < data_1.length; _i++) {
|
|
147
|
-
var r = data_1[_i];
|
|
148
|
-
if (!(r.name in this.regions)) {
|
|
149
|
-
this.regions[r.name] = { interaction: r.interaction, visibility: r.visibility };
|
|
150
|
-
}
|
|
151
|
-
this.regionMap[r.id] = r.name;
|
|
152
|
-
}
|
|
153
|
-
};
|
|
154
|
-
DataHelper.METRIC_MAP = (_a$1 = {},
|
|
155
|
-
_a$1[2 /* Data.Metric.TotalBytes */] = { name: "Total Bytes", unit: "KB" },
|
|
156
|
-
_a$1[4 /* Data.Metric.TotalCost */] = { name: "Total Cost", unit: "ms" },
|
|
157
|
-
_a$1[3 /* Data.Metric.LayoutCost */] = { name: "Layout Cost", unit: "ms" },
|
|
158
|
-
_a$1[8 /* Data.Metric.LargestPaint */] = { name: "LCP", unit: "s" },
|
|
159
|
-
_a$1[9 /* Data.Metric.CumulativeLayoutShift */] = { name: "CLS", unit: "cls" },
|
|
160
|
-
_a$1[7 /* Data.Metric.LongTaskCount */] = { name: "Long Tasks" },
|
|
161
|
-
_a$1[24 /* Data.Metric.CartTotal */] = { name: "Cart Total", unit: "html-price" },
|
|
162
|
-
_a$1[13 /* Data.Metric.ProductPrice */] = { name: "Product Price", unit: "ld-price" },
|
|
163
|
-
_a$1[6 /* Data.Metric.ThreadBlockedTime */] = { name: "Thread Blocked", unit: "ms" },
|
|
164
|
-
_a$1[37 /* Data.Dimension.InteractionNextPaint */] = { name: "INP", unit: "ms" },
|
|
165
|
-
_a$1);
|
|
166
|
-
return DataHelper;
|
|
167
|
-
}());
|
|
168
|
-
|
|
169
70
|
// tslint:disable: no-bitwise
|
|
170
71
|
function hash (input, precision) {
|
|
171
72
|
if (precision === void 0) { precision = null; }
|
|
@@ -186,12 +87,26 @@ function hash (input, precision) {
|
|
|
186
87
|
hash = Math.abs(hashOne + (hashTwo * 11579));
|
|
187
88
|
return (precision ? hash % Math.pow(2, precision) : hash).toString(36);
|
|
188
89
|
}
|
|
90
|
+
|
|
91
|
+
function __spreadArray(to, from, pack) {
|
|
92
|
+
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
93
|
+
if (ar || !(i in from)) {
|
|
94
|
+
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
95
|
+
ar[i] = from[i];
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return to.concat(ar || Array.prototype.slice.call(from));
|
|
99
|
+
}
|
|
189
100
|
|
|
190
101
|
var excludeClassNames = "load,active,fixed,visible,focus,show,collaps,animat" /* Constant.ExcludeClassNames */.split("," /* Constant.Comma */);
|
|
102
|
+
var extraExcludeClassNames = [];
|
|
191
103
|
var selectorMap = {};
|
|
192
104
|
function reset$8() {
|
|
193
105
|
selectorMap = {};
|
|
194
106
|
}
|
|
107
|
+
function configure(classNames) {
|
|
108
|
+
extraExcludeClassNames = classNames || [];
|
|
109
|
+
}
|
|
195
110
|
function get$1(input, type) {
|
|
196
111
|
var a = input.attributes;
|
|
197
112
|
var prefix = input.prefix ? input.prefix[type] : null;
|
|
@@ -263,7 +178,7 @@ function filter(value) {
|
|
|
263
178
|
if (!value) {
|
|
264
179
|
return false;
|
|
265
180
|
} // Do not process empty strings
|
|
266
|
-
if (
|
|
181
|
+
if (getExcludeClassNames().some(function (x) { return value.toLowerCase().indexOf(x) >= 0; })) {
|
|
267
182
|
return false;
|
|
268
183
|
}
|
|
269
184
|
for (var i = 0; i < value.length; i++) {
|
|
@@ -274,9 +189,13 @@ function filter(value) {
|
|
|
274
189
|
}
|
|
275
190
|
return true;
|
|
276
191
|
}
|
|
192
|
+
function getExcludeClassNames() {
|
|
193
|
+
return __spreadArray(__spreadArray([], excludeClassNames, true), extraExcludeClassNames, true);
|
|
194
|
+
}
|
|
277
195
|
|
|
278
196
|
var selector = /*#__PURE__*/Object.freeze({
|
|
279
197
|
__proto__: null,
|
|
198
|
+
configure: configure,
|
|
280
199
|
get: get$1,
|
|
281
200
|
reset: reset$8
|
|
282
201
|
});
|
|
@@ -312,6 +231,105 @@ function lookup(hash) {
|
|
|
312
231
|
|
|
313
232
|
var helper = { hash: hash, selector: selector, get: get$2, getNode: getNode, lookup: lookup };
|
|
314
233
|
|
|
234
|
+
var _a$1;
|
|
235
|
+
var DataHelper = /** @class */ (function () {
|
|
236
|
+
function DataHelper(state) {
|
|
237
|
+
var _this = this;
|
|
238
|
+
this.regionMap = {};
|
|
239
|
+
this.regions = {};
|
|
240
|
+
this.metrics = {};
|
|
241
|
+
this.lean = false;
|
|
242
|
+
this.reset = function () {
|
|
243
|
+
_this.metrics = {};
|
|
244
|
+
_this.lean = false;
|
|
245
|
+
_this.regions = {};
|
|
246
|
+
_this.regionMap = {};
|
|
247
|
+
};
|
|
248
|
+
this.metric = function (event) {
|
|
249
|
+
var _a;
|
|
250
|
+
if (_this.state.options.metadata) {
|
|
251
|
+
var metricMarkup = [];
|
|
252
|
+
var regionMarkup = [];
|
|
253
|
+
// Copy over metrics for future reference
|
|
254
|
+
for (var m in event.data) {
|
|
255
|
+
var eventType = typeof event.data[m];
|
|
256
|
+
if (eventType === "number" || (event.event === 1 /* Data.Event.Dimension */ && m === 37 /* Data.Dimension.InteractionNextPaint */.toString())) {
|
|
257
|
+
if (!(m in _this.metrics)) {
|
|
258
|
+
_this.metrics[m] = 0;
|
|
259
|
+
}
|
|
260
|
+
var key = parseInt(m, 10);
|
|
261
|
+
var value = eventType === "object" ? Number((_a = event.data[m]) === null || _a === void 0 ? void 0 : _a[0]) : event.data[m];
|
|
262
|
+
if (m in DataHelper.METRIC_MAP && (DataHelper.METRIC_MAP[m].unit === "html-price" || DataHelper.METRIC_MAP[m].unit === "ld-price")) {
|
|
263
|
+
_this.metrics[m] = value;
|
|
264
|
+
}
|
|
265
|
+
else {
|
|
266
|
+
_this.metrics[m] += value;
|
|
267
|
+
}
|
|
268
|
+
_this.lean = key === 1 /* Data.Metric.Playback */ && value === 0 ? true : _this.lean;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
for (var entry in _this.metrics) {
|
|
272
|
+
if (entry in DataHelper.METRIC_MAP) {
|
|
273
|
+
var m = _this.metrics[entry];
|
|
274
|
+
var map = DataHelper.METRIC_MAP[entry];
|
|
275
|
+
var unit = "unit" in map ? map.unit : "" /* Data.Constant.Empty */;
|
|
276
|
+
metricMarkup.push("<li><h2>".concat(_this.value(m, unit), "<span>").concat(_this.key(unit), "</span></h2>").concat(map.name, "</li>"));
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
// Append region information to metadata
|
|
280
|
+
for (var name_1 in _this.regions) {
|
|
281
|
+
var r = _this.regions[name_1];
|
|
282
|
+
var className = (r.visibility === 10 /* Layout.RegionVisibility.Visible */ ? "visible" : (r.interaction === 20 /* Layout.InteractionState.Clicked */ ? "clicked" : "" /* Data.Constant.Empty */));
|
|
283
|
+
regionMarkup.push("<span class=\"".concat(className, "\">").concat(name_1, "</span>"));
|
|
284
|
+
}
|
|
285
|
+
_this.state.options.metadata.innerHTML = "<ul>".concat(metricMarkup.join("" /* Data.Constant.Empty */), "</ul><div>").concat(regionMarkup.join("" /* Data.Constant.Empty */), "</div>");
|
|
286
|
+
}
|
|
287
|
+
};
|
|
288
|
+
this.key = function (unit) {
|
|
289
|
+
switch (unit) {
|
|
290
|
+
case "html-price":
|
|
291
|
+
case "ld-price":
|
|
292
|
+
case "cls":
|
|
293
|
+
return "" /* Data.Constant.Empty */;
|
|
294
|
+
default: return unit;
|
|
295
|
+
}
|
|
296
|
+
};
|
|
297
|
+
this.value = function (num, unit) {
|
|
298
|
+
switch (unit) {
|
|
299
|
+
case "KB": return Math.round(num / 1024);
|
|
300
|
+
case "s": return Math.round(num / 10) / 100;
|
|
301
|
+
case "cls": return num / 1000;
|
|
302
|
+
case "html-price": return num / 100;
|
|
303
|
+
default: return num;
|
|
304
|
+
}
|
|
305
|
+
};
|
|
306
|
+
this.state = state;
|
|
307
|
+
}
|
|
308
|
+
DataHelper.prototype.region = function (event) {
|
|
309
|
+
var data = event.data;
|
|
310
|
+
for (var _i = 0, data_1 = data; _i < data_1.length; _i++) {
|
|
311
|
+
var r = data_1[_i];
|
|
312
|
+
if (!(r.name in this.regions)) {
|
|
313
|
+
this.regions[r.name] = { interaction: r.interaction, visibility: r.visibility };
|
|
314
|
+
}
|
|
315
|
+
this.regionMap[r.id] = r.name;
|
|
316
|
+
}
|
|
317
|
+
};
|
|
318
|
+
DataHelper.METRIC_MAP = (_a$1 = {},
|
|
319
|
+
_a$1[2 /* Data.Metric.TotalBytes */] = { name: "Total Bytes", unit: "KB" },
|
|
320
|
+
_a$1[4 /* Data.Metric.TotalCost */] = { name: "Total Cost", unit: "ms" },
|
|
321
|
+
_a$1[3 /* Data.Metric.LayoutCost */] = { name: "Layout Cost", unit: "ms" },
|
|
322
|
+
_a$1[8 /* Data.Metric.LargestPaint */] = { name: "LCP", unit: "s" },
|
|
323
|
+
_a$1[9 /* Data.Metric.CumulativeLayoutShift */] = { name: "CLS", unit: "cls" },
|
|
324
|
+
_a$1[7 /* Data.Metric.LongTaskCount */] = { name: "Long Tasks" },
|
|
325
|
+
_a$1[24 /* Data.Metric.CartTotal */] = { name: "Cart Total", unit: "html-price" },
|
|
326
|
+
_a$1[13 /* Data.Metric.ProductPrice */] = { name: "Product Price", unit: "ld-price" },
|
|
327
|
+
_a$1[6 /* Data.Metric.ThreadBlockedTime */] = { name: "Thread Blocked", unit: "ms" },
|
|
328
|
+
_a$1[37 /* Data.Dimension.InteractionNextPaint */] = { name: "INP", unit: "ms" },
|
|
329
|
+
_a$1);
|
|
330
|
+
return DataHelper;
|
|
331
|
+
}());
|
|
332
|
+
|
|
315
333
|
var EnrichHelper = /** @class */ (function () {
|
|
316
334
|
function EnrichHelper() {
|
|
317
335
|
var _this = this;
|
|
@@ -805,6 +823,7 @@ var HeatmapHelper = /** @class */ (function () {
|
|
|
805
823
|
if (canvas === null) {
|
|
806
824
|
canvas = doc.createElement("CANVAS" /* Constant.Canvas */);
|
|
807
825
|
canvas.id = "clarity-heatmap-canvas" /* Constant.HeatmapCanvas */;
|
|
826
|
+
canvas.classList.add("clarity-heatmap-canvas" /* Constant.HeatmapCanvas */);
|
|
808
827
|
canvas.width = 0;
|
|
809
828
|
canvas.height = 0;
|
|
810
829
|
canvas.style.position = "absolute" /* Constant.Absolute */;
|
|
@@ -881,12 +900,27 @@ var HeatmapHelper = /** @class */ (function () {
|
|
|
881
900
|
var points = {};
|
|
882
901
|
var localMax = 0;
|
|
883
902
|
var height = _this.state.window && _this.state.window.document ? _this.state.window.document.documentElement.clientHeight : 0;
|
|
903
|
+
// DEBUG LOG
|
|
904
|
+
console.group("[Heatmap] transform \u2014 total elements: ".concat(_this.data.length, ", height: ").concat(height, ", max: ").concat(_this.max));
|
|
884
905
|
for (var _i = 0, _a = _this.data; _i < _a.length; _i++) {
|
|
885
906
|
var element = _a[_i];
|
|
886
907
|
var el = _this.layout.get(element.hash);
|
|
908
|
+
if (!el) {
|
|
909
|
+
console.warn("[Heatmap] SKIP hash=\"".concat(element.hash, "\" \u2014 element not found in DOM"));
|
|
910
|
+
continue;
|
|
911
|
+
}
|
|
912
|
+
if (typeof el.getBoundingClientRect !== "function") {
|
|
913
|
+
console.warn("[Heatmap] SKIP hash=\"".concat(element.hash, "\" \u2014 getBoundingClientRect not available"), el);
|
|
914
|
+
continue;
|
|
915
|
+
}
|
|
916
|
+
var r = el.getBoundingClientRect();
|
|
917
|
+
var v = _this.visible(el, r, height);
|
|
918
|
+
if (!v && _this.max !== null) {
|
|
919
|
+
console.warn("[Heatmap] SKIP hash=\"".concat(element.hash, "\" \u2014 not visible on re-render"), { rect: { top: r.top, left: r.left, width: r.width, height: r.height }, maxIsSet: _this.max !== null });
|
|
920
|
+
continue;
|
|
921
|
+
}
|
|
887
922
|
if (el && typeof el.getBoundingClientRect === "function") {
|
|
888
|
-
|
|
889
|
-
var v = _this.visible(el, r, height);
|
|
923
|
+
console.log("[Heatmap] PROCESS hash=\"".concat(element.hash, "\" visible=").concat(v, " points=").concat(element.points), { rect: { top: r.top, left: r.left, width: r.width, height: r.height } });
|
|
890
924
|
// Process clicks for only visible elements
|
|
891
925
|
if (_this.max === null || v) {
|
|
892
926
|
for (var i = 0; i < element.points; i++) {
|
|
@@ -895,6 +929,7 @@ var HeatmapHelper = /** @class */ (function () {
|
|
|
895
929
|
var k = "".concat(x).concat("X" /* Constant.Separator */).concat(y).concat("X" /* Constant.Separator */).concat(v ? 1 : 0);
|
|
896
930
|
points[k] = k in points ? points[k] + element.clicks[i] : element.clicks[i];
|
|
897
931
|
localMax = Math.max(points[k], localMax);
|
|
932
|
+
console.log(" point[".concat(i, "] x=").concat(x, " y=").concat(y, " visible=").concat(v, " clicks=").concat(element.clicks[i]));
|
|
898
933
|
}
|
|
899
934
|
}
|
|
900
935
|
}
|
|
@@ -902,6 +937,7 @@ var HeatmapHelper = /** @class */ (function () {
|
|
|
902
937
|
// Set the max value from the firs t
|
|
903
938
|
_this.max = _this.max ? _this.max : localMax;
|
|
904
939
|
// Once all points are accounted for, convert everything into absolute (x, y)
|
|
940
|
+
var skippedInvisible = 0;
|
|
905
941
|
for (var _b = 0, _c = Object.keys(points); _b < _c.length; _b++) {
|
|
906
942
|
var coordinates = _c[_b];
|
|
907
943
|
var parts = coordinates.split("X" /* Constant.Separator */);
|
|
@@ -909,7 +945,12 @@ var HeatmapHelper = /** @class */ (function () {
|
|
|
909
945
|
if (parts[2] === "1") {
|
|
910
946
|
output.push({ x: parseInt(parts[0], 10), y: parseInt(parts[1], 10), a: alpha });
|
|
911
947
|
}
|
|
948
|
+
else {
|
|
949
|
+
skippedInvisible++;
|
|
950
|
+
}
|
|
912
951
|
}
|
|
952
|
+
console.log("[Heatmap] Result \u2014 drawn: ".concat(output.length, ", skipped invisible: ").concat(skippedInvisible, ", max: ").concat(_this.max));
|
|
953
|
+
console.groupEnd();
|
|
913
954
|
return output;
|
|
914
955
|
};
|
|
915
956
|
this.visible = function (el, r, height) {
|
|
@@ -2309,6 +2350,11 @@ var Visualizer = /** @class */ (function () {
|
|
|
2309
2350
|
this._state = null;
|
|
2310
2351
|
this.renderTime = 0;
|
|
2311
2352
|
this.hashFoundTime = -1;
|
|
2353
|
+
this._excludeClassNames = [];
|
|
2354
|
+
this.configure = function (opts) {
|
|
2355
|
+
_this._excludeClassNames = opts.excludeClassNames || [];
|
|
2356
|
+
helper.selector.configure(_this._excludeClassNames);
|
|
2357
|
+
};
|
|
2312
2358
|
this.dom = function (event) { return __awaiter(_this, void 0, void 0, function () {
|
|
2313
2359
|
return __generator(this, function (_a) {
|
|
2314
2360
|
switch (_a.label) {
|
|
@@ -2429,6 +2475,7 @@ var Visualizer = /** @class */ (function () {
|
|
|
2429
2475
|
decoded = decoded.sort(_this.sortPayloads);
|
|
2430
2476
|
// Re-initialize enrich class if someone ends up calling merge function directly
|
|
2431
2477
|
_this.enrich = _this.enrich || new EnrichHelper();
|
|
2478
|
+
helper.selector.configure(_this._excludeClassNames);
|
|
2432
2479
|
_this.enrich.reset();
|
|
2433
2480
|
// Walk through payloads and generate merged payload from an array of decoded payloads
|
|
2434
2481
|
for (var _i = 0, decoded_1 = decoded; _i < decoded_1.length; _i++) {
|
|
@@ -2467,6 +2514,10 @@ var Visualizer = /** @class */ (function () {
|
|
|
2467
2514
|
switch (_a.label) {
|
|
2468
2515
|
case 0:
|
|
2469
2516
|
this.reset();
|
|
2517
|
+
if (options.excludeClassNames) {
|
|
2518
|
+
this._excludeClassNames = options.excludeClassNames;
|
|
2519
|
+
helper.selector.configure(options.excludeClassNames);
|
|
2520
|
+
}
|
|
2470
2521
|
// Infer options
|
|
2471
2522
|
options.pointer = "pointer" in options ? options.pointer : true;
|
|
2472
2523
|
options.canvas = "canvas" in options ? options.canvas : true;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gemx-dev/clarity-visualize",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.63",
|
|
4
4
|
"description": "Clarity visualize",
|
|
5
5
|
"author": "Microsoft Corp.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"unpkg": "build/clarity.visualize.min.js",
|
|
10
10
|
"types": "types/index.d.ts",
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@gemx-dev/clarity-decode": "^0.8.
|
|
12
|
+
"@gemx-dev/clarity-decode": "^0.8.63"
|
|
13
13
|
},
|
|
14
14
|
"devDependencies": {
|
|
15
15
|
"@rollup/plugin-commonjs": "^24.0.0",
|
package/src/heatmap.ts
CHANGED
|
@@ -198,6 +198,7 @@ export class HeatmapHelper {
|
|
|
198
198
|
if (canvas === null) {
|
|
199
199
|
canvas = doc.createElement(Constant.Canvas) as HTMLCanvasElement;
|
|
200
200
|
canvas.id = Constant.HeatmapCanvas;
|
|
201
|
+
canvas.classList.add(Constant.HeatmapCanvas);
|
|
201
202
|
canvas.width = 0;
|
|
202
203
|
canvas.height = 0;
|
|
203
204
|
canvas.style.position = Constant.Absolute;
|
|
@@ -275,11 +276,31 @@ export class HeatmapHelper {
|
|
|
275
276
|
let points: { [key: string]: number } = {};
|
|
276
277
|
let localMax = 0;
|
|
277
278
|
let height = this.state.window && this.state.window.document ? this.state.window.document.documentElement.clientHeight : 0;
|
|
279
|
+
|
|
280
|
+
// DEBUG LOG
|
|
281
|
+
console.group(`[Heatmap] transform — total elements: ${this.data.length}, height: ${height}, max: ${this.max}`);
|
|
282
|
+
|
|
278
283
|
for (let element of this.data) {
|
|
279
284
|
let el = this.layout.get(element.hash) as HTMLElement;
|
|
285
|
+
if (!el) {
|
|
286
|
+
console.warn(`[Heatmap] SKIP hash="${element.hash}" — element not found in DOM`);
|
|
287
|
+
continue;
|
|
288
|
+
}
|
|
289
|
+
if (typeof el.getBoundingClientRect !== "function") {
|
|
290
|
+
console.warn(`[Heatmap] SKIP hash="${element.hash}" — getBoundingClientRect not available`, el);
|
|
291
|
+
continue;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
let r = el.getBoundingClientRect();
|
|
295
|
+
let v = this.visible(el, r, height);
|
|
296
|
+
|
|
297
|
+
if (!v && this.max !== null) {
|
|
298
|
+
console.warn(`[Heatmap] SKIP hash="${element.hash}" — not visible on re-render`, { rect: { top: r.top, left: r.left, width: r.width, height: r.height }, maxIsSet: this.max !== null });
|
|
299
|
+
continue;
|
|
300
|
+
}
|
|
301
|
+
|
|
280
302
|
if (el && typeof el.getBoundingClientRect === "function") {
|
|
281
|
-
|
|
282
|
-
let v = this.visible(el, r, height);
|
|
303
|
+
console.log(`[Heatmap] PROCESS hash="${element.hash}" visible=${v} points=${element.points}`, { rect: { top: r.top, left: r.left, width: r.width, height: r.height } });
|
|
283
304
|
// Process clicks for only visible elements
|
|
284
305
|
if (this.max === null || v) {
|
|
285
306
|
for(let i = 0; i < element.points; i++) {
|
|
@@ -288,6 +309,7 @@ export class HeatmapHelper {
|
|
|
288
309
|
let k = `${x}${Constant.Separator}${y}${Constant.Separator}${v ? 1 : 0}`;
|
|
289
310
|
points[k] = k in points ? points[k] + element.clicks[i] : element.clicks[i];
|
|
290
311
|
localMax = Math.max(points[k], localMax);
|
|
312
|
+
console.log(` point[${i}] x=${x} y=${y} visible=${v} clicks=${element.clicks[i]}`);
|
|
291
313
|
}
|
|
292
314
|
}
|
|
293
315
|
}
|
|
@@ -297,12 +319,20 @@ export class HeatmapHelper {
|
|
|
297
319
|
this.max = this.max ? this.max : localMax;
|
|
298
320
|
|
|
299
321
|
// Once all points are accounted for, convert everything into absolute (x, y)
|
|
322
|
+
let skippedInvisible = 0;
|
|
300
323
|
for (let coordinates of Object.keys(points)) {
|
|
301
324
|
let parts = coordinates.split(Constant.Separator);
|
|
302
325
|
let alpha = Math.min((points[coordinates] / this.max) + Setting.AlphaBoost, 1);
|
|
303
|
-
if (parts[2] === "1") {
|
|
326
|
+
if (parts[2] === "1") {
|
|
327
|
+
output.push({ x: parseInt(parts[0], 10), y: parseInt(parts[1], 10), a: alpha });
|
|
328
|
+
} else {
|
|
329
|
+
skippedInvisible++;
|
|
330
|
+
}
|
|
304
331
|
}
|
|
305
332
|
|
|
333
|
+
console.log(`[Heatmap] Result — drawn: ${output.length}, skipped invisible: ${skippedInvisible}, max: ${this.max}`);
|
|
334
|
+
console.groupEnd();
|
|
335
|
+
|
|
306
336
|
return output;
|
|
307
337
|
}
|
|
308
338
|
|
package/src/visualizer.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { Activity, Constant, ErrorLogger, LinkHandler, MergedPayload, Options, PlaybackState, ScrollMapInfo, Setting, ShortCircuitStrategy, Visualizer as VisualizerType } from "@clarity-types/visualize";
|
|
2
|
-
import { Data } from "@gemx-dev/clarity-js";
|
|
3
1
|
import type { Data as DecodedData, Interaction, Layout } from "@gemx-dev/clarity-decode";
|
|
2
|
+
|
|
3
|
+
import { Activity, Constant, ErrorLogger, LinkHandler, MergedPayload, Options, PlaybackState, ScrollMapInfo, Setting, ShortCircuitStrategy, Visualizer as VisualizerType } from "@clarity-types/visualize";
|
|
4
|
+
import { Data, helper } from "@gemx-dev/clarity-js";
|
|
4
5
|
import { DataHelper } from "./data";
|
|
5
6
|
import { EnrichHelper } from "./enrich";
|
|
6
7
|
import { HeatmapHelper } from "./heatmap";
|
|
@@ -12,6 +13,7 @@ export class Visualizer implements VisualizerType {
|
|
|
12
13
|
_state: PlaybackState = null;
|
|
13
14
|
renderTime = 0;
|
|
14
15
|
hashFoundTime = -1;
|
|
16
|
+
_excludeClassNames: string[] = [];
|
|
15
17
|
|
|
16
18
|
enrich: EnrichHelper;
|
|
17
19
|
layout: LayoutHelper;
|
|
@@ -23,6 +25,11 @@ export class Visualizer implements VisualizerType {
|
|
|
23
25
|
return this._state;
|
|
24
26
|
}
|
|
25
27
|
|
|
28
|
+
public configure = (opts: { excludeClassNames?: string[] }): void => {
|
|
29
|
+
this._excludeClassNames = opts.excludeClassNames || [];
|
|
30
|
+
helper.selector.configure(this._excludeClassNames);
|
|
31
|
+
}
|
|
32
|
+
|
|
26
33
|
public dom = async (event: Layout.DomEvent): Promise<void> => {
|
|
27
34
|
await this.layout.dom(event);
|
|
28
35
|
}
|
|
@@ -116,6 +123,7 @@ export class Visualizer implements VisualizerType {
|
|
|
116
123
|
decoded = decoded.sort(this.sortPayloads);
|
|
117
124
|
// Re-initialize enrich class if someone ends up calling merge function directly
|
|
118
125
|
this.enrich = this.enrich || new EnrichHelper();
|
|
126
|
+
helper.selector.configure(this._excludeClassNames);
|
|
119
127
|
this.enrich.reset();
|
|
120
128
|
// Walk through payloads and generate merged payload from an array of decoded payloads
|
|
121
129
|
for (let payload of decoded) {
|
|
@@ -148,6 +156,10 @@ export class Visualizer implements VisualizerType {
|
|
|
148
156
|
|
|
149
157
|
public setup = async (target: Window, options: Options): Promise<Visualizer> => {
|
|
150
158
|
this.reset();
|
|
159
|
+
if (options.excludeClassNames) {
|
|
160
|
+
this._excludeClassNames = options.excludeClassNames;
|
|
161
|
+
helper.selector.configure(options.excludeClassNames);
|
|
162
|
+
}
|
|
151
163
|
// Infer options
|
|
152
164
|
options.pointer = "pointer" in options ? options.pointer : true;
|
|
153
165
|
options.canvas = "canvas" in options ? options.canvas : true;
|
package/types/visualize.d.ts
CHANGED
|
@@ -27,6 +27,7 @@ export class Visualizer {
|
|
|
27
27
|
merge: (decoded: Data.DecodedPayload[]) => MergedPayload;
|
|
28
28
|
render: (events: Data.DecodedEvent[]) => void;
|
|
29
29
|
setup: (target: Window, options: Options) => Promise<Visualizer>;
|
|
30
|
+
configure: (opts: { excludeClassNames?: string[] }) => void;
|
|
30
31
|
time: () => number;
|
|
31
32
|
get: (hash: string) => HTMLElement;
|
|
32
33
|
}
|
|
@@ -70,6 +71,7 @@ export interface Options {
|
|
|
70
71
|
mobile?: boolean;
|
|
71
72
|
vNext?: boolean;
|
|
72
73
|
locale?: string;
|
|
74
|
+
excludeClassNames?: string[];
|
|
73
75
|
}
|
|
74
76
|
|
|
75
77
|
export interface NodeData {
|