@gemx-dev/heatmap-react 3.5.56 → 3.5.57
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/dist/esm/components/VizElement/BackdropCanvas.d.ts +38 -0
- package/dist/esm/components/VizElement/BackdropCanvas.d.ts.map +1 -0
- package/dist/esm/components/VizElement/DefaultRankBadges.d.ts.map +1 -1
- package/dist/esm/components/VizElement/ElementCallout.d.ts.map +1 -1
- package/dist/esm/components/VizElement/ElementCalloutClicked.d.ts +12 -0
- package/dist/esm/components/VizElement/ElementCalloutClicked.d.ts.map +1 -0
- package/dist/esm/components/VizElement/ElementCalloutHovered.d.ts +10 -0
- package/dist/esm/components/VizElement/ElementCalloutHovered.d.ts.map +1 -0
- package/dist/esm/components/VizElement/ElementCalloutOverlay.d.ts +3 -0
- package/dist/esm/components/VizElement/ElementCalloutOverlay.d.ts.map +1 -0
- package/dist/esm/components/VizElement/ElementMissing.d.ts +1 -0
- package/dist/esm/components/VizElement/ElementMissing.d.ts.map +1 -1
- package/dist/esm/components/VizElement/ElementOverlay.d.ts +3 -3
- package/dist/esm/components/VizElement/ElementOverlay.d.ts.map +1 -1
- package/dist/esm/components/VizElement/HeatmapElements.d.ts +1 -1
- package/dist/esm/components/VizElement/HeatmapElements.d.ts.map +1 -1
- package/dist/esm/components/VizElement/RankBadge.d.ts +2 -0
- package/dist/esm/components/VizElement/RankBadge.d.ts.map +1 -1
- package/dist/esm/configs/backdrop.d.ts +23 -0
- package/dist/esm/configs/backdrop.d.ts.map +1 -0
- package/dist/esm/configs/index.d.ts +1 -0
- package/dist/esm/configs/index.d.ts.map +1 -1
- package/dist/esm/constants/viz-elm-callout.d.ts +6 -1
- package/dist/esm/constants/viz-elm-callout.d.ts.map +1 -1
- package/dist/esm/helpers/canvas-backdrop.d.ts +28 -0
- package/dist/esm/helpers/canvas-backdrop.d.ts.map +1 -0
- package/dist/esm/helpers/index.d.ts +1 -0
- package/dist/esm/helpers/index.d.ts.map +1 -1
- package/dist/esm/helpers/viz-elm-callout/dimensions.d.ts +9 -8
- package/dist/esm/helpers/viz-elm-callout/dimensions.d.ts.map +1 -1
- package/dist/esm/helpers/viz-elm-callout/position-calculator.d.ts +4 -12
- package/dist/esm/helpers/viz-elm-callout/position-calculator.d.ts.map +1 -1
- package/dist/esm/helpers/viz-elm-callout/position-candidates.d.ts +4 -10
- package/dist/esm/helpers/viz-elm-callout/position-candidates.d.ts.map +1 -1
- package/dist/esm/helpers/viz-elm-callout/position-selector.d.ts +2 -8
- package/dist/esm/helpers/viz-elm-callout/position-selector.d.ts.map +1 -1
- package/dist/esm/helpers/viz-elm-callout/position-validator.d.ts +5 -3
- package/dist/esm/helpers/viz-elm-callout/position-validator.d.ts.map +1 -1
- package/dist/esm/helpers/viz-elm-callout/viz-elm.d.ts +2 -20
- package/dist/esm/helpers/viz-elm-callout/viz-elm.d.ts.map +1 -1
- package/dist/esm/hooks/viz-elm/useHoveredElement.d.ts.map +1 -1
- package/dist/esm/index.js +505 -222
- package/dist/esm/index.mjs +505 -222
- package/dist/esm/stores/viz-click.d.ts +5 -4
- package/dist/esm/stores/viz-click.d.ts.map +1 -1
- package/dist/esm/types/viz-elm-callout.d.ts +60 -9
- package/dist/esm/types/viz-elm-callout.d.ts.map +1 -1
- package/dist/style.css +3 -1
- package/dist/umd/components/VizElement/BackdropCanvas.d.ts +38 -0
- package/dist/umd/components/VizElement/BackdropCanvas.d.ts.map +1 -0
- package/dist/umd/components/VizElement/DefaultRankBadges.d.ts.map +1 -1
- package/dist/umd/components/VizElement/ElementCallout.d.ts.map +1 -1
- package/dist/umd/components/VizElement/ElementCalloutClicked.d.ts +12 -0
- package/dist/umd/components/VizElement/ElementCalloutClicked.d.ts.map +1 -0
- package/dist/umd/components/VizElement/ElementCalloutHovered.d.ts +10 -0
- package/dist/umd/components/VizElement/ElementCalloutHovered.d.ts.map +1 -0
- package/dist/umd/components/VizElement/ElementCalloutOverlay.d.ts +3 -0
- package/dist/umd/components/VizElement/ElementCalloutOverlay.d.ts.map +1 -0
- package/dist/umd/components/VizElement/ElementMissing.d.ts +1 -0
- package/dist/umd/components/VizElement/ElementMissing.d.ts.map +1 -1
- package/dist/umd/components/VizElement/ElementOverlay.d.ts +3 -3
- package/dist/umd/components/VizElement/ElementOverlay.d.ts.map +1 -1
- package/dist/umd/components/VizElement/HeatmapElements.d.ts +1 -1
- package/dist/umd/components/VizElement/HeatmapElements.d.ts.map +1 -1
- package/dist/umd/components/VizElement/RankBadge.d.ts +2 -0
- package/dist/umd/components/VizElement/RankBadge.d.ts.map +1 -1
- package/dist/umd/configs/backdrop.d.ts +23 -0
- package/dist/umd/configs/backdrop.d.ts.map +1 -0
- package/dist/umd/configs/index.d.ts +1 -0
- package/dist/umd/configs/index.d.ts.map +1 -1
- package/dist/umd/constants/viz-elm-callout.d.ts +6 -1
- package/dist/umd/constants/viz-elm-callout.d.ts.map +1 -1
- package/dist/umd/helpers/canvas-backdrop.d.ts +28 -0
- package/dist/umd/helpers/canvas-backdrop.d.ts.map +1 -0
- package/dist/umd/helpers/index.d.ts +1 -0
- package/dist/umd/helpers/index.d.ts.map +1 -1
- package/dist/umd/helpers/viz-elm-callout/dimensions.d.ts +9 -8
- package/dist/umd/helpers/viz-elm-callout/dimensions.d.ts.map +1 -1
- package/dist/umd/helpers/viz-elm-callout/position-calculator.d.ts +4 -12
- package/dist/umd/helpers/viz-elm-callout/position-calculator.d.ts.map +1 -1
- package/dist/umd/helpers/viz-elm-callout/position-candidates.d.ts +4 -10
- package/dist/umd/helpers/viz-elm-callout/position-candidates.d.ts.map +1 -1
- package/dist/umd/helpers/viz-elm-callout/position-selector.d.ts +2 -8
- package/dist/umd/helpers/viz-elm-callout/position-selector.d.ts.map +1 -1
- package/dist/umd/helpers/viz-elm-callout/position-validator.d.ts +5 -3
- package/dist/umd/helpers/viz-elm-callout/position-validator.d.ts.map +1 -1
- package/dist/umd/helpers/viz-elm-callout/viz-elm.d.ts +2 -20
- package/dist/umd/helpers/viz-elm-callout/viz-elm.d.ts.map +1 -1
- package/dist/umd/hooks/viz-elm/useHoveredElement.d.ts.map +1 -1
- package/dist/umd/index.js +2 -2
- package/dist/umd/stores/viz-click.d.ts +5 -4
- package/dist/umd/stores/viz-click.d.ts.map +1 -1
- package/dist/umd/types/viz-elm-callout.d.ts +60 -9
- package/dist/umd/types/viz-elm-callout.d.ts.map +1 -1
- package/package.json +4 -4
- package/dist/esm/components/VizElement/HoveredElementCallout.d.ts +0 -4
- package/dist/esm/components/VizElement/HoveredElementCallout.d.ts.map +0 -1
- package/dist/umd/components/VizElement/HoveredElementCallout.d.ts +0 -4
- package/dist/umd/components/VizElement/HoveredElementCallout.d.ts.map +0 -1
package/dist/esm/index.mjs
CHANGED
|
@@ -41,6 +41,29 @@ const GraphView = ({ children, width, height }) => {
|
|
|
41
41
|
return (jsxs(ReactFlow, { nodes: nodes, nodeTypes: nodeTypes, onNodesChange: onNodesChange, debug: true, minZoom: 0.5, maxZoom: 2, fitView: true, children: [jsx(Controls, {}), jsx(Background, {})] }));
|
|
42
42
|
};
|
|
43
43
|
|
|
44
|
+
/**
|
|
45
|
+
* Default backdrop configuration
|
|
46
|
+
*/
|
|
47
|
+
const BACKDROP_CONFIG = {
|
|
48
|
+
/**
|
|
49
|
+
* Default backdrop color
|
|
50
|
+
*/
|
|
51
|
+
COLOR: '#000000',
|
|
52
|
+
/**
|
|
53
|
+
* Default backdrop opacity (0-1)
|
|
54
|
+
*/
|
|
55
|
+
OPACITY: 0.5,
|
|
56
|
+
/**
|
|
57
|
+
* Default cutout expansion (pixels)
|
|
58
|
+
* Adds padding around the active element cutout
|
|
59
|
+
*/
|
|
60
|
+
CUTOUT_EXPANSION: 2,
|
|
61
|
+
/**
|
|
62
|
+
* Z-index for backdrop canvas
|
|
63
|
+
*/
|
|
64
|
+
Z_INDEX: 999,
|
|
65
|
+
};
|
|
66
|
+
|
|
44
67
|
// Portal mode: Full permissions for proper functionality
|
|
45
68
|
// Need allow-forms for add to cart, allow-popups for some features
|
|
46
69
|
const HEATMAP_IFRAME = {
|
|
@@ -1422,7 +1445,8 @@ const AREA_RENDERER_SELECTORS = {
|
|
|
1422
1445
|
|
|
1423
1446
|
const CALLOUT_PADDING = 0;
|
|
1424
1447
|
const CALLOUT_ARROW_SIZE = 8;
|
|
1425
|
-
const
|
|
1448
|
+
const CALLOUT_OFFSET = { x: -8, y: 0 };
|
|
1449
|
+
const CALLOUT_ALIGNMENT = 'left';
|
|
1426
1450
|
const CLICKED_ELEMENT_ID_BASE = 'gx-hm-clicked-element';
|
|
1427
1451
|
const SECONDARY_CLICKED_ELEMENT_ID_BASE = 'gx-hm-secondary-clicked-element';
|
|
1428
1452
|
const HOVERED_ELEMENT_ID_BASE = 'gx-hm-hovered-element';
|
|
@@ -2198,10 +2222,9 @@ function calculateRankPosition(rect, widthScale) {
|
|
|
2198
2222
|
};
|
|
2199
2223
|
}
|
|
2200
2224
|
|
|
2201
|
-
const getViewportDimensions = (containerElm, scale
|
|
2225
|
+
const getViewportDimensions = (containerElm, scale) => {
|
|
2202
2226
|
if (containerElm) {
|
|
2203
2227
|
const containerRect = containerElm.getBoundingClientRect();
|
|
2204
|
-
// If scale provided, adjust dimensions
|
|
2205
2228
|
const width = scale ? containerRect.width / scale : containerRect.width;
|
|
2206
2229
|
const height = scale ? containerRect.height / scale : containerRect.height;
|
|
2207
2230
|
return { width, height };
|
|
@@ -2211,48 +2234,12 @@ const getViewportDimensions = (containerElm, scale, scrollOffset) => {
|
|
|
2211
2234
|
height: window.innerHeight,
|
|
2212
2235
|
};
|
|
2213
2236
|
};
|
|
2214
|
-
const getElementDimensions = (
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
// Create virtual target rect from mouse position
|
|
2218
|
-
// Convert viewport coordinates to container-relative coordinates
|
|
2219
|
-
const relativeX = (mousePosition.x - containerRect.left) / scale;
|
|
2220
|
-
const relativeY = (mousePosition.y - containerRect.top) / scale;
|
|
2221
|
-
// Create a small rect (1x1) at mouse position
|
|
2222
|
-
targetRect = {
|
|
2223
|
-
top: relativeY,
|
|
2224
|
-
left: relativeX,
|
|
2225
|
-
right: relativeX + 1,
|
|
2226
|
-
bottom: relativeY + 1,
|
|
2227
|
-
width: 1,
|
|
2228
|
-
height: 1,
|
|
2229
|
-
x: relativeX,
|
|
2230
|
-
y: relativeY,
|
|
2231
|
-
toJSON: () => ({}),
|
|
2232
|
-
};
|
|
2233
|
-
}
|
|
2234
|
-
else if (mousePosition) {
|
|
2235
|
-
// Fixed mode: use viewport coordinates directly
|
|
2236
|
-
targetRect = {
|
|
2237
|
-
top: mousePosition.y,
|
|
2238
|
-
left: mousePosition.x,
|
|
2239
|
-
right: mousePosition.x + 1,
|
|
2240
|
-
bottom: mousePosition.y + 1,
|
|
2241
|
-
width: 1,
|
|
2242
|
-
height: 1,
|
|
2243
|
-
x: mousePosition.x,
|
|
2244
|
-
y: mousePosition.y,
|
|
2245
|
-
toJSON: () => ({}),
|
|
2246
|
-
};
|
|
2247
|
-
}
|
|
2248
|
-
else {
|
|
2249
|
-
// No mouse position, use actual target element
|
|
2250
|
-
targetRect = targetElm.getBoundingClientRect();
|
|
2251
|
-
}
|
|
2237
|
+
const getElementDimensions = (options) => {
|
|
2238
|
+
const { targetElm, calloutElm, scale, containerElm } = options;
|
|
2239
|
+
const targetRect = targetElm.getBoundingClientRect();
|
|
2252
2240
|
const calloutRect = calloutElm.getBoundingClientRect();
|
|
2253
|
-
|
|
2254
|
-
if (scale && containerRect
|
|
2255
|
-
// Convert viewport coordinates to container-relative coordinates, then scale
|
|
2241
|
+
const containerRect = containerElm.getBoundingClientRect();
|
|
2242
|
+
if (scale && containerRect) {
|
|
2256
2243
|
const relativeTop = (targetRect.top - containerRect.top) / scale;
|
|
2257
2244
|
const relativeLeft = (targetRect.left - containerRect.left) / scale;
|
|
2258
2245
|
const scaledWidth = targetRect.width / scale;
|
|
@@ -2274,7 +2261,6 @@ const getElementDimensions = (targetElm, calloutElm, scale, containerRect, mouse
|
|
|
2274
2261
|
},
|
|
2275
2262
|
};
|
|
2276
2263
|
}
|
|
2277
|
-
// Return with scaled callout rect if scale provided
|
|
2278
2264
|
if (scale) {
|
|
2279
2265
|
return {
|
|
2280
2266
|
targetRect,
|
|
@@ -2298,23 +2284,42 @@ const getAlignmentOrder = (alignment) => {
|
|
|
2298
2284
|
return ['right', 'center', 'left'];
|
|
2299
2285
|
}
|
|
2300
2286
|
};
|
|
2301
|
-
const calculateLeftPosition = (
|
|
2287
|
+
const calculateLeftPosition = (align, options) => {
|
|
2288
|
+
const { rectDimensions, offset } = options;
|
|
2289
|
+
const { targetRect, calloutRect } = rectDimensions;
|
|
2290
|
+
const { x: hozOffset } = offset;
|
|
2291
|
+
const relLeft = targetRect.left;
|
|
2292
|
+
const relRight = targetRect.right;
|
|
2293
|
+
const relWidth = targetRect.width;
|
|
2294
|
+
const calloutWidth = calloutRect.width;
|
|
2295
|
+
let left;
|
|
2302
2296
|
switch (align) {
|
|
2303
2297
|
case 'left':
|
|
2304
|
-
|
|
2298
|
+
left = relLeft + hozOffset;
|
|
2299
|
+
break;
|
|
2305
2300
|
case 'right':
|
|
2306
|
-
|
|
2301
|
+
left = relRight - calloutWidth - hozOffset;
|
|
2302
|
+
break;
|
|
2307
2303
|
case 'center':
|
|
2308
2304
|
default:
|
|
2309
|
-
|
|
2305
|
+
left = relLeft + relWidth / 2 - calloutWidth / 2;
|
|
2306
|
+
break;
|
|
2310
2307
|
}
|
|
2308
|
+
// No clamping - let validation determine if position is valid
|
|
2309
|
+
// If position would overflow, valid = false and system chooses different placement
|
|
2310
|
+
return left;
|
|
2311
2311
|
};
|
|
2312
|
-
const calculateVerticalPosition = (
|
|
2312
|
+
const calculateVerticalPosition = (placement, options) => {
|
|
2313
|
+
const { rectDimensions, padding, arrowSize, offset } = options;
|
|
2314
|
+
const { targetRect, calloutRect } = rectDimensions;
|
|
2315
|
+
const { y: offsetY } = offset;
|
|
2313
2316
|
return placement === 'top'
|
|
2314
2317
|
? targetRect.top - calloutRect.height - padding - arrowSize + offsetY
|
|
2315
2318
|
: targetRect.bottom + padding + arrowSize + offsetY;
|
|
2316
2319
|
};
|
|
2317
|
-
const
|
|
2320
|
+
const calculateHorizontalPosition = (placement, options) => {
|
|
2321
|
+
const { rectDimensions, padding, arrowSize } = options;
|
|
2322
|
+
const { targetRect, calloutRect } = rectDimensions;
|
|
2318
2323
|
const top = targetRect.top + targetRect.height / 2 - calloutRect.height / 2;
|
|
2319
2324
|
const left = placement === 'right'
|
|
2320
2325
|
? targetRect.right + padding + arrowSize
|
|
@@ -2322,98 +2327,115 @@ const calculateHorizontalPlacementPosition = (targetRect, calloutRect, placement
|
|
|
2322
2327
|
return { top, left };
|
|
2323
2328
|
};
|
|
2324
2329
|
|
|
2325
|
-
const
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
}
|
|
2329
|
-
|
|
2330
|
+
const EPSILON = 0.1; // Tolerance for floating point errors
|
|
2331
|
+
const isLeftPositionValid = (leftPos, options) => {
|
|
2332
|
+
const { rectDimensions, viewport, padding, offset } = options;
|
|
2333
|
+
const { width: calloutWidth } = rectDimensions.calloutRect;
|
|
2334
|
+
const { width: viewportWidth } = viewport;
|
|
2335
|
+
const absLeft = rectDimensions.targetAbsoluteRect?.left ?? 0;
|
|
2336
|
+
const relLeftPos = absLeft + leftPos - offset.x;
|
|
2337
|
+
const maxViewportWidth = viewportWidth - padding + EPSILON;
|
|
2338
|
+
const isValidLeft = relLeftPos >= padding - EPSILON;
|
|
2339
|
+
const isRectCalloutShowValid = relLeftPos + calloutWidth <= maxViewportWidth;
|
|
2340
|
+
return isValidLeft && isRectCalloutShowValid;
|
|
2330
2341
|
};
|
|
2331
|
-
const
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2342
|
+
const isRightPositionValid = (leftPos, options) => {
|
|
2343
|
+
const { rectDimensions, viewport, padding } = options;
|
|
2344
|
+
const { width: calloutWidth } = rectDimensions.calloutRect;
|
|
2345
|
+
const { width: viewportWidth } = viewport;
|
|
2346
|
+
const maxViewportWidth = viewportWidth - padding + EPSILON;
|
|
2347
|
+
const isValidRight = leftPos - calloutWidth - padding - EPSILON <= maxViewportWidth;
|
|
2348
|
+
return isValidRight;
|
|
2349
|
+
};
|
|
2350
|
+
const isVerticalPositionValid = (placement, options) => {
|
|
2351
|
+
const { rectDimensions, viewport, padding, arrowSize } = options;
|
|
2352
|
+
const { targetRect, calloutRect } = rectDimensions;
|
|
2353
|
+
const { height: viewportHeight } = viewport;
|
|
2354
|
+
const { height: calloutHeight } = calloutRect;
|
|
2337
2355
|
return placement === 'top'
|
|
2338
|
-
? targetRect.top -
|
|
2339
|
-
: targetRect.bottom +
|
|
2356
|
+
? targetRect.top - calloutHeight - padding - arrowSize > -EPSILON
|
|
2357
|
+
: targetRect.bottom + calloutHeight + padding + arrowSize < viewportHeight + EPSILON;
|
|
2340
2358
|
};
|
|
2341
|
-
const
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
}
|
|
2359
|
+
const isHorizontalPositionValid = (placement, options) => {
|
|
2360
|
+
const { rectDimensions, viewport, padding, arrowSize } = options;
|
|
2361
|
+
const { targetRect, calloutRect } = rectDimensions;
|
|
2362
|
+
const { width: viewportWidth } = viewport;
|
|
2363
|
+
const { width: calloutWidth } = calloutRect;
|
|
2347
2364
|
return placement === 'right'
|
|
2348
|
-
? targetRect.right +
|
|
2349
|
-
: targetRect.left -
|
|
2365
|
+
? targetRect.right + calloutWidth + padding + arrowSize < viewportWidth + EPSILON
|
|
2366
|
+
: targetRect.left - calloutWidth - padding - arrowSize > -EPSILON;
|
|
2350
2367
|
};
|
|
2351
2368
|
|
|
2352
|
-
const generateVerticalPositionCandidates = (
|
|
2369
|
+
const generateVerticalPositionCandidates = (options) => {
|
|
2370
|
+
const { alignment } = options;
|
|
2353
2371
|
const candidates = [];
|
|
2354
2372
|
const placements = ['top', 'bottom'];
|
|
2355
2373
|
placements.forEach((placement) => {
|
|
2356
|
-
const verticalPos = calculateVerticalPosition(
|
|
2357
|
-
const verticalValid = isVerticalPositionValid(
|
|
2374
|
+
const verticalPos = calculateVerticalPosition(placement, options);
|
|
2375
|
+
const verticalValid = isVerticalPositionValid(placement, options);
|
|
2358
2376
|
const alignmentOrder = getAlignmentOrder(alignment);
|
|
2359
2377
|
alignmentOrder.forEach((align) => {
|
|
2360
|
-
const
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2378
|
+
const leftPos = calculateLeftPosition(align, options);
|
|
2379
|
+
const isValidLeft = isLeftPositionValid(leftPos, options);
|
|
2380
|
+
const isValidRight = isRightPositionValid(leftPos, options);
|
|
2381
|
+
const candidate = { placement, top: verticalPos, left: leftPos, horizontalAlign: align, valid: false };
|
|
2382
|
+
switch (align) {
|
|
2383
|
+
case 'left':
|
|
2384
|
+
candidate.valid = verticalValid && isValidLeft;
|
|
2385
|
+
break;
|
|
2386
|
+
case 'right':
|
|
2387
|
+
candidate.valid = verticalValid && isValidRight;
|
|
2388
|
+
break;
|
|
2389
|
+
}
|
|
2390
|
+
candidates.push(candidate);
|
|
2373
2391
|
});
|
|
2374
2392
|
});
|
|
2375
2393
|
return candidates;
|
|
2376
2394
|
};
|
|
2377
|
-
const generateHorizontalPositionCandidates = (
|
|
2395
|
+
const generateHorizontalPositionCandidates = (options) => {
|
|
2378
2396
|
const placements = ['left', 'right'];
|
|
2379
2397
|
return placements.map((placement) => {
|
|
2380
|
-
const { top, left } =
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
horizontalAlign: 'center',
|
|
2386
|
-
valid: isHorizontalPlacementValid(targetRect, calloutRect, placement, viewportWidth, padding, arrowSize, containerRect),
|
|
2387
|
-
};
|
|
2398
|
+
const { top, left } = calculateHorizontalPosition(placement, options);
|
|
2399
|
+
const isValidHorizontal = isHorizontalPositionValid(placement, options);
|
|
2400
|
+
const candidate = { placement, top, left, horizontalAlign: 'center', valid: false };
|
|
2401
|
+
candidate.valid = isValidHorizontal;
|
|
2402
|
+
return candidate;
|
|
2388
2403
|
});
|
|
2389
2404
|
};
|
|
2390
|
-
const
|
|
2391
|
-
const
|
|
2392
|
-
const
|
|
2393
|
-
const horizontalCandidates = generateHorizontalPositionCandidates(targetRect, calloutRect, viewport.width, padding, arrowSize, containerRect);
|
|
2405
|
+
const generateAllCandidates = (options) => {
|
|
2406
|
+
const verticalCandidates = generateVerticalPositionCandidates(options);
|
|
2407
|
+
const horizontalCandidates = generateHorizontalPositionCandidates(options);
|
|
2394
2408
|
return [...verticalCandidates, ...horizontalCandidates];
|
|
2395
2409
|
};
|
|
2396
2410
|
|
|
2397
2411
|
const selectBestPosition = (candidates) => {
|
|
2398
2412
|
return candidates.find((p) => p.valid) || candidates[0];
|
|
2399
2413
|
};
|
|
2400
|
-
const constrainToViewport = (
|
|
2414
|
+
const constrainToViewport = (candidate, options) => {
|
|
2415
|
+
const { containerRect, padding, rectDimensions, viewport } = options;
|
|
2416
|
+
const { calloutRect } = rectDimensions;
|
|
2417
|
+
const { left: leftPos, top: topPos } = candidate;
|
|
2401
2418
|
if (containerRect) {
|
|
2402
|
-
const
|
|
2403
|
-
const
|
|
2419
|
+
const containerTop = containerRect.top + padding;
|
|
2420
|
+
const containerLeft = containerRect.left + padding;
|
|
2421
|
+
const containerRight = containerRect.right - calloutRect.width - padding;
|
|
2422
|
+
const containerBottom = containerRect.bottom - calloutRect.height - padding;
|
|
2423
|
+
const left = Math.max(containerLeft, Math.min(leftPos, containerRight));
|
|
2424
|
+
const top = Math.max(containerTop, Math.min(topPos, containerBottom));
|
|
2404
2425
|
return { top, left };
|
|
2405
2426
|
}
|
|
2406
|
-
const
|
|
2407
|
-
const
|
|
2427
|
+
const viewportLeft = padding;
|
|
2428
|
+
const viewportTop = padding;
|
|
2429
|
+
const viewportRight = viewport.width - calloutRect.width - padding;
|
|
2430
|
+
const viewportBottom = viewport.height - calloutRect.height - padding;
|
|
2431
|
+
const left = Math.max(viewportLeft, Math.min(leftPos, viewportRight));
|
|
2432
|
+
const top = Math.max(viewportTop, Math.min(topPos, viewportBottom));
|
|
2408
2433
|
return { top, left };
|
|
2409
2434
|
};
|
|
2410
2435
|
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
const getScrollOffset = (isAbsolute, visualRef) => {
|
|
2415
|
-
if (!isAbsolute || !visualRef?.current)
|
|
2416
|
-
return undefined;
|
|
2436
|
+
const getScrollOffset = (visualRef) => {
|
|
2437
|
+
if (!visualRef?.current)
|
|
2438
|
+
return;
|
|
2417
2439
|
return {
|
|
2418
2440
|
top: visualRef.current.scrollTop,
|
|
2419
2441
|
left: visualRef.current.scrollLeft,
|
|
@@ -2424,17 +2446,19 @@ const getScrollOffset = (isAbsolute, visualRef) => {
|
|
|
2424
2446
|
* - With scroll: represents visible area in container coordinates
|
|
2425
2447
|
* - Without scroll: represents full container in container coordinates
|
|
2426
2448
|
*/
|
|
2427
|
-
const createAdjustedContainerRect = (
|
|
2449
|
+
const createAdjustedContainerRect = (options) => {
|
|
2450
|
+
const { containerElm, scale, isAbsolute, visualRef } = options;
|
|
2451
|
+
const containerRect = containerElm.getBoundingClientRect();
|
|
2452
|
+
const scrollOffset = getScrollOffset(visualRef);
|
|
2428
2453
|
// No scale = fixed positioning, use raw rect
|
|
2429
|
-
if (!scale)
|
|
2430
|
-
return
|
|
2431
|
-
|
|
2432
|
-
const
|
|
2433
|
-
const scaledHeight = rawContainerRect.height / scale;
|
|
2454
|
+
if (!scale)
|
|
2455
|
+
return containerRect;
|
|
2456
|
+
const scaledWidth = containerRect.width / scale;
|
|
2457
|
+
const scaledHeight = containerRect.height / scale;
|
|
2434
2458
|
// Absolute positioning with scroll offset
|
|
2435
|
-
if (scrollOffset) {
|
|
2459
|
+
if (isAbsolute && scrollOffset) {
|
|
2436
2460
|
return {
|
|
2437
|
-
...
|
|
2461
|
+
...containerRect,
|
|
2438
2462
|
top: scrollOffset.top,
|
|
2439
2463
|
left: scrollOffset.left,
|
|
2440
2464
|
right: scrollOffset.left + scaledWidth,
|
|
@@ -2445,17 +2469,21 @@ const createAdjustedContainerRect = (rawContainerRect, scale, scrollOffset) => {
|
|
|
2445
2469
|
}
|
|
2446
2470
|
// Absolute positioning without scroll
|
|
2447
2471
|
return {
|
|
2448
|
-
...
|
|
2472
|
+
...containerRect,
|
|
2449
2473
|
top: 0,
|
|
2450
2474
|
left: 0,
|
|
2451
2475
|
right: scaledWidth,
|
|
2452
|
-
bottom: scaledHeight,
|
|
2453
2476
|
width: scaledWidth,
|
|
2477
|
+
bottom: scaledHeight,
|
|
2454
2478
|
height: scaledHeight,
|
|
2455
2479
|
};
|
|
2456
2480
|
};
|
|
2457
2481
|
const calcCalloutPosition = (options) => {
|
|
2458
|
-
const { targetElm, calloutElm, setPosition,
|
|
2482
|
+
const { targetElm, calloutElm, setPosition, positionMode, widthScale, visualRef } = options;
|
|
2483
|
+
const offset = options.offset ?? CALLOUT_OFFSET;
|
|
2484
|
+
const alignment = options.alignment ?? CALLOUT_ALIGNMENT;
|
|
2485
|
+
const padding = CALLOUT_PADDING;
|
|
2486
|
+
const arrowSize = CALLOUT_ARROW_SIZE;
|
|
2459
2487
|
return () => {
|
|
2460
2488
|
const isAbsolute = positionMode === 'absolute';
|
|
2461
2489
|
const scale = isAbsolute ? widthScale : 1;
|
|
@@ -2465,35 +2493,94 @@ const calcCalloutPosition = (options) => {
|
|
|
2465
2493
|
const containerElm = isAbsolute ? calloutElm.parentElement : visualRef?.current;
|
|
2466
2494
|
if (!containerElm)
|
|
2467
2495
|
return;
|
|
2468
|
-
const rawContainerRect = containerElm.getBoundingClientRect();
|
|
2469
|
-
const scrollOffset = getScrollOffset(isAbsolute, visualRef);
|
|
2470
|
-
// Step 1: Get element dimensions
|
|
2471
|
-
// For mousePosition: creates virtual 1x1 rect at mouse coordinates
|
|
2472
|
-
// For targetElm: uses actual element rect
|
|
2473
|
-
const rectDimensions = getElementDimensions(targetElm, calloutElm, scale, rawContainerRect, mousePosition);
|
|
2474
|
-
// Step 2: Get viewport dimensions
|
|
2475
2496
|
const viewport = getViewportDimensions(visualRef?.current, scale);
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
const
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2497
|
+
const rectDimensions = getElementDimensions({ targetElm, calloutElm, scale, containerElm });
|
|
2498
|
+
const containerRect = createAdjustedContainerRect({ containerElm, scale, isAbsolute, visualRef });
|
|
2499
|
+
const options = {
|
|
2500
|
+
rectDimensions,
|
|
2501
|
+
viewport,
|
|
2502
|
+
alignment,
|
|
2503
|
+
offset,
|
|
2504
|
+
padding,
|
|
2505
|
+
arrowSize,
|
|
2506
|
+
containerRect,
|
|
2507
|
+
};
|
|
2508
|
+
const candidates = generateAllCandidates(options);
|
|
2509
|
+
const candidate = selectBestPosition(candidates);
|
|
2510
|
+
// Constrain to viewport/container bounds
|
|
2511
|
+
const constrainedCandidate = constrainToViewport(candidate, options);
|
|
2512
|
+
// Final callout position
|
|
2488
2513
|
const finalPosition = {
|
|
2489
|
-
top:
|
|
2490
|
-
left:
|
|
2491
|
-
placement:
|
|
2492
|
-
horizontalAlign:
|
|
2514
|
+
top: constrainedCandidate.top,
|
|
2515
|
+
left: constrainedCandidate.left,
|
|
2516
|
+
placement: candidate.placement,
|
|
2517
|
+
horizontalAlign: candidate.horizontalAlign,
|
|
2493
2518
|
};
|
|
2494
2519
|
setPosition(finalPosition);
|
|
2495
2520
|
};
|
|
2496
2521
|
};
|
|
2522
|
+
const calcCalloutPositionAbsolute = (props) => {
|
|
2523
|
+
const { widthScale, calloutElm, containerElm, element, onChange } = props;
|
|
2524
|
+
const mousePosition = element?.mousePosition;
|
|
2525
|
+
if (!mousePosition)
|
|
2526
|
+
return;
|
|
2527
|
+
const padding = props.padding ?? CALLOUT_PADDING;
|
|
2528
|
+
const arrowSize = props.arrowSize ?? CALLOUT_ARROW_SIZE;
|
|
2529
|
+
const rawCalloutRect = calloutElm.getBoundingClientRect();
|
|
2530
|
+
if (rawCalloutRect.width === 0 || rawCalloutRect.height === 0)
|
|
2531
|
+
return;
|
|
2532
|
+
const calloutRect = {
|
|
2533
|
+
...rawCalloutRect,
|
|
2534
|
+
width: rawCalloutRect.width / widthScale,
|
|
2535
|
+
height: rawCalloutRect.height / widthScale,
|
|
2536
|
+
};
|
|
2537
|
+
const containerRect = containerElm.getBoundingClientRect();
|
|
2538
|
+
const containerWidth = containerRect.width / widthScale;
|
|
2539
|
+
const containerHeight = containerRect.height / widthScale;
|
|
2540
|
+
const mouseX = mousePosition.x;
|
|
2541
|
+
const mouseY = mousePosition.y;
|
|
2542
|
+
const targetRect = {
|
|
2543
|
+
top: mouseY,
|
|
2544
|
+
left: mouseX,
|
|
2545
|
+
right: mouseX + 1,
|
|
2546
|
+
bottom: mouseY + 1,
|
|
2547
|
+
width: 1,
|
|
2548
|
+
height: 1,
|
|
2549
|
+
x: mouseX,
|
|
2550
|
+
y: mouseY,
|
|
2551
|
+
toJSON: () => ({}),
|
|
2552
|
+
};
|
|
2553
|
+
const rectDimensions = {
|
|
2554
|
+
targetRect,
|
|
2555
|
+
calloutRect,
|
|
2556
|
+
targetAbsoluteRect: {
|
|
2557
|
+
top: element.top,
|
|
2558
|
+
left: element.left,
|
|
2559
|
+
},
|
|
2560
|
+
};
|
|
2561
|
+
const viewport = {
|
|
2562
|
+
width: containerWidth,
|
|
2563
|
+
height: containerHeight,
|
|
2564
|
+
};
|
|
2565
|
+
const options = {
|
|
2566
|
+
rectDimensions,
|
|
2567
|
+
viewport,
|
|
2568
|
+
alignment: CALLOUT_ALIGNMENT,
|
|
2569
|
+
offset: CALLOUT_OFFSET,
|
|
2570
|
+
padding,
|
|
2571
|
+
arrowSize,
|
|
2572
|
+
containerRect,
|
|
2573
|
+
};
|
|
2574
|
+
const candidates = generateAllCandidates(options);
|
|
2575
|
+
const bestPosition = selectBestPosition(candidates);
|
|
2576
|
+
const style = {
|
|
2577
|
+
position: 'absolute',
|
|
2578
|
+
top: bestPosition.top,
|
|
2579
|
+
left: bestPosition.left,
|
|
2580
|
+
zIndex: 1000,
|
|
2581
|
+
};
|
|
2582
|
+
onChange(style);
|
|
2583
|
+
};
|
|
2497
2584
|
|
|
2498
2585
|
/**
|
|
2499
2586
|
* Throttle a function using requestAnimationFrame
|
|
@@ -3639,6 +3726,59 @@ class IframeHeightProcessor {
|
|
|
3639
3726
|
}
|
|
3640
3727
|
}
|
|
3641
3728
|
|
|
3729
|
+
/**
|
|
3730
|
+
* Draw a backdrop overlay on canvas with a cutout for the active element
|
|
3731
|
+
* This creates a "spotlight" effect highlighting the active element
|
|
3732
|
+
*/
|
|
3733
|
+
const drawBackdropWithCutout = (options) => {
|
|
3734
|
+
const { canvas, activeRect, backdropColor = '#000000', backdropOpacity = 0.5, cutoutExpansion = 0 } = options;
|
|
3735
|
+
const ctx = canvas.getContext('2d');
|
|
3736
|
+
if (!ctx)
|
|
3737
|
+
return;
|
|
3738
|
+
const { width: canvasWidth, height: canvasHeight } = canvas;
|
|
3739
|
+
// Apply expansion to the cutout rect
|
|
3740
|
+
const top = Math.max(0, activeRect.top - cutoutExpansion);
|
|
3741
|
+
const left = Math.max(0, activeRect.left - cutoutExpansion);
|
|
3742
|
+
const width = Math.min(canvasWidth - left, activeRect.width + cutoutExpansion * 2);
|
|
3743
|
+
const height = Math.min(canvasHeight - top, activeRect.height + cutoutExpansion * 2);
|
|
3744
|
+
// Clear previous drawing
|
|
3745
|
+
ctx.clearRect(0, 0, canvasWidth, canvasHeight);
|
|
3746
|
+
// Set backdrop style
|
|
3747
|
+
ctx.fillStyle = backdropColor;
|
|
3748
|
+
ctx.globalAlpha = backdropOpacity;
|
|
3749
|
+
// Draw backdrop in 4 rectangles around the active element
|
|
3750
|
+
// This creates a cutout effect
|
|
3751
|
+
// Top rectangle (above active element)
|
|
3752
|
+
if (top > 0) {
|
|
3753
|
+
ctx.fillRect(0, 0, canvasWidth, top);
|
|
3754
|
+
}
|
|
3755
|
+
// Bottom rectangle (below active element)
|
|
3756
|
+
const bottomY = top + height;
|
|
3757
|
+
if (bottomY < canvasHeight) {
|
|
3758
|
+
ctx.fillRect(0, bottomY, canvasWidth, canvasHeight - bottomY);
|
|
3759
|
+
}
|
|
3760
|
+
// Left rectangle (left of active element)
|
|
3761
|
+
if (left > 0) {
|
|
3762
|
+
ctx.fillRect(0, top, left, height);
|
|
3763
|
+
}
|
|
3764
|
+
// Right rectangle (right of active element)
|
|
3765
|
+
const rightX = left + width;
|
|
3766
|
+
if (rightX < canvasWidth) {
|
|
3767
|
+
ctx.fillRect(rightX, top, canvasWidth - rightX, height);
|
|
3768
|
+
}
|
|
3769
|
+
// Reset alpha
|
|
3770
|
+
ctx.globalAlpha = 1.0;
|
|
3771
|
+
};
|
|
3772
|
+
/**
|
|
3773
|
+
* Clear the entire canvas
|
|
3774
|
+
*/
|
|
3775
|
+
const clearCanvas = (canvas) => {
|
|
3776
|
+
const ctx = canvas.getContext('2d');
|
|
3777
|
+
if (!ctx)
|
|
3778
|
+
return;
|
|
3779
|
+
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
3780
|
+
};
|
|
3781
|
+
|
|
3642
3782
|
function validateAreaCreation(dataInfo, hash, areas) {
|
|
3643
3783
|
if (!dataInfo?.elementMapInfo || !dataInfo?.totalClicks) {
|
|
3644
3784
|
logger$4.warn('Cannot create area: missing heatmap data');
|
|
@@ -4451,8 +4591,9 @@ const useHoveredElement = ({ iframeRef, getRect }) => {
|
|
|
4451
4591
|
reset();
|
|
4452
4592
|
return;
|
|
4453
4593
|
}
|
|
4454
|
-
|
|
4455
|
-
|
|
4594
|
+
const mousePosition = getElementMousePosition(event, widthScale);
|
|
4595
|
+
setHoveredElement({ ...elementInfo, mousePosition });
|
|
4596
|
+
}, [dataInfo, getRect, reset, widthScale, getHashFromEvent, setHoveredElement]);
|
|
4456
4597
|
const handleMouseMove = useMemo(() => throttleRAF(onHandleMouseMove), [onHandleMouseMove]);
|
|
4457
4598
|
const handleClick = useCallback((event, hash) => {
|
|
4458
4599
|
if (!hash)
|
|
@@ -4461,12 +4602,12 @@ const useHoveredElement = ({ iframeRef, getRect }) => {
|
|
|
4461
4602
|
setSelectedElement({ hash });
|
|
4462
4603
|
return;
|
|
4463
4604
|
}
|
|
4464
|
-
const mousePosition =
|
|
4605
|
+
const mousePosition = getElementMousePosition(event, widthScale);
|
|
4465
4606
|
setSelectedElement({
|
|
4466
4607
|
hash,
|
|
4467
4608
|
mousePosition,
|
|
4468
4609
|
});
|
|
4469
|
-
}, [setSelectedElement]);
|
|
4610
|
+
}, [setSelectedElement, widthScale]);
|
|
4470
4611
|
// Cleanup throttled function on unmount
|
|
4471
4612
|
useEffect(() => {
|
|
4472
4613
|
return () => {
|
|
@@ -4479,6 +4620,15 @@ const useHoveredElement = ({ iframeRef, getRect }) => {
|
|
|
4479
4620
|
handleClick,
|
|
4480
4621
|
};
|
|
4481
4622
|
};
|
|
4623
|
+
const getElementMousePosition = (event, widthScale) => {
|
|
4624
|
+
const containerElm = event.target;
|
|
4625
|
+
if (!containerElm)
|
|
4626
|
+
return;
|
|
4627
|
+
const containerRect = containerElm.getBoundingClientRect();
|
|
4628
|
+
const elementRelativeX = (event.clientX - containerRect.left) / widthScale;
|
|
4629
|
+
const elementRelativeY = (event.clientY - containerRect.top) / widthScale;
|
|
4630
|
+
return { x: elementRelativeX, y: elementRelativeY };
|
|
4631
|
+
};
|
|
4482
4632
|
const convertViewportToIframeCoords = (clientX, clientY, iframeRect, scale) => {
|
|
4483
4633
|
let x = clientX - iframeRect.left;
|
|
4484
4634
|
let y = clientY - iframeRect.top;
|
|
@@ -7582,7 +7732,11 @@ const VizAreaClick = ({ iframeRef, visualRef, shadowRoot, autoCreateTopN = 10, e
|
|
|
7582
7732
|
};
|
|
7583
7733
|
VizAreaClick.displayName = 'VizAreaClick';
|
|
7584
7734
|
|
|
7585
|
-
const RankBadgeComponent = ({ index, elementRect, widthScale, clickOnElement }) => {
|
|
7735
|
+
const RankBadgeComponent = ({ index, hash, elementRect, widthScale, show = true, clickOnElement, }) => {
|
|
7736
|
+
const clickedHash = useHeatmapClick((s) => s.selectedElement?.hash);
|
|
7737
|
+
const isShow = !!show && clickedHash !== hash;
|
|
7738
|
+
if (!isShow)
|
|
7739
|
+
return null;
|
|
7586
7740
|
const style = calculateRankPosition(elementRect, widthScale);
|
|
7587
7741
|
return (jsx("div", { className: "gx-hm-rank-badge", style: style, onClick: clickOnElement, children: index }));
|
|
7588
7742
|
};
|
|
@@ -7600,7 +7754,7 @@ const DefaultRankBadgesComponent = ({ getRect, hidden }) => {
|
|
|
7600
7754
|
const rect = getRect(element);
|
|
7601
7755
|
if (!rect)
|
|
7602
7756
|
return null;
|
|
7603
|
-
return jsx(RankBadge, { index: index + 1, elementRect: rect, widthScale: widthScale }, element.hash);
|
|
7757
|
+
return (jsx(RankBadge, { hash: element.hash, index: index + 1, elementRect: rect, widthScale: widthScale }, element.hash));
|
|
7604
7758
|
}) }));
|
|
7605
7759
|
};
|
|
7606
7760
|
DefaultRankBadgesComponent.displayName = 'DefaultRankBadges';
|
|
@@ -7612,10 +7766,40 @@ const DEFAULT_POSITION = {
|
|
|
7612
7766
|
placement: 'top',
|
|
7613
7767
|
horizontalAlign: 'center',
|
|
7614
7768
|
};
|
|
7615
|
-
const
|
|
7769
|
+
const ElementCallout = (props) => {
|
|
7770
|
+
const viewId = useViewIdContext();
|
|
7771
|
+
const CompElementCallout = useHeatmapControlStore((state) => state.controls.ElementCallout);
|
|
7772
|
+
const calloutRef = useRef(null);
|
|
7773
|
+
const element = props.element;
|
|
7774
|
+
const positionMode = props.positionMode ?? DEFAULT_POSITION_MODE;
|
|
7775
|
+
const isAbsolute = positionMode === 'absolute';
|
|
7776
|
+
const position = useAnchorPosition(calloutRef, props);
|
|
7777
|
+
const className = `clarity-callout clarity-callout--${position.placement} clarity-callout--align-${position.horizontalAlign}`;
|
|
7778
|
+
const portalContainerId = getPortalElmId();
|
|
7779
|
+
if (!portalContainerId)
|
|
7780
|
+
return null;
|
|
7781
|
+
const calloutContent = (jsx("div", { ref: calloutRef, className: className, style: {
|
|
7782
|
+
position: positionMode,
|
|
7783
|
+
top: position.top,
|
|
7784
|
+
left: position.left,
|
|
7785
|
+
zIndex: Z_INDEX.CALLOUT,
|
|
7786
|
+
}, "aria-live": "assertive", role: "tooltip", children: CompElementCallout && jsx(CompElementCallout, { elementHash: element.hash }) }));
|
|
7787
|
+
if (!document.getElementById(portalContainerId))
|
|
7788
|
+
return null;
|
|
7789
|
+
return createPortal(calloutContent, document.getElementById(portalContainerId));
|
|
7790
|
+
function getPortalElmId() {
|
|
7791
|
+
const containerElmId = `gx-hm-elements-${viewId}`;
|
|
7792
|
+
const vizContainerElmId = `gx-hm-viz-container-${viewId}`;
|
|
7793
|
+
if (!isAbsolute)
|
|
7794
|
+
return vizContainerElmId;
|
|
7795
|
+
if (!element.mousePosition)
|
|
7796
|
+
return containerElmId;
|
|
7797
|
+
return '';
|
|
7798
|
+
}
|
|
7799
|
+
};
|
|
7616
7800
|
const useAnchorPosition = (calloutRef, props) => {
|
|
7617
7801
|
const widthScale = useHeatmapViz((s) => s.widthScale);
|
|
7618
|
-
const { target, visualRef,
|
|
7802
|
+
const { target, visualRef, alignment, element, positionMode } = props;
|
|
7619
7803
|
const [position, setPosition] = useState(DEFAULT_POSITION);
|
|
7620
7804
|
const isAbsolute = positionMode === 'absolute';
|
|
7621
7805
|
const mousePosition = element.mousePosition;
|
|
@@ -7630,15 +7814,11 @@ const useAnchorPosition = (calloutRef, props) => {
|
|
|
7630
7814
|
targetElm,
|
|
7631
7815
|
calloutElm,
|
|
7632
7816
|
setPosition,
|
|
7633
|
-
offset,
|
|
7634
7817
|
alignment,
|
|
7635
7818
|
positionMode,
|
|
7636
7819
|
visualRef,
|
|
7637
7820
|
widthScale,
|
|
7638
|
-
mousePosition,
|
|
7639
7821
|
});
|
|
7640
|
-
// Delay initial calculation to allow scroll animations to complete
|
|
7641
|
-
// Use multiple frames to ensure layout is stable
|
|
7642
7822
|
const rafId1 = requestAnimationFrame(() => {
|
|
7643
7823
|
requestAnimationFrame(() => {
|
|
7644
7824
|
positionFn();
|
|
@@ -7647,13 +7827,9 @@ const useAnchorPosition = (calloutRef, props) => {
|
|
|
7647
7827
|
const handleUpdate = () => {
|
|
7648
7828
|
requestAnimationFrame(positionFn);
|
|
7649
7829
|
};
|
|
7650
|
-
// Listen to events based on positioning mode
|
|
7651
|
-
// Absolute mode: position is in container coordinates, doesn't change with scroll
|
|
7652
|
-
// Fixed mode: position is in viewport coordinates, needs scroll updates
|
|
7653
7830
|
const visualContainer = visualRef?.current;
|
|
7654
7831
|
window.addEventListener('resize', handleUpdate);
|
|
7655
7832
|
if (!isAbsolute) {
|
|
7656
|
-
// Fixed mode: listen to scroll events for viewport position updates
|
|
7657
7833
|
window.addEventListener('scroll', handleUpdate, true);
|
|
7658
7834
|
visualContainer?.addEventListener('scroll', handleUpdate);
|
|
7659
7835
|
}
|
|
@@ -7665,81 +7841,190 @@ const useAnchorPosition = (calloutRef, props) => {
|
|
|
7665
7841
|
visualContainer?.removeEventListener('scroll', handleUpdate);
|
|
7666
7842
|
}
|
|
7667
7843
|
};
|
|
7668
|
-
}, [element, target, visualRef,
|
|
7844
|
+
}, [element, target, visualRef, alignment, isAbsolute, widthScale, calloutRef, mousePosition, positionMode]);
|
|
7669
7845
|
return position;
|
|
7670
7846
|
};
|
|
7671
|
-
const ElementCallout = (props) => {
|
|
7672
|
-
const viewId = useViewIdContext();
|
|
7673
|
-
const CompElementCallout = useHeatmapControlStore((state) => state.controls.ElementCallout);
|
|
7674
|
-
const calloutRef = useRef(null);
|
|
7675
|
-
const element = props.element;
|
|
7676
|
-
const positionMode = props.positionMode ?? DEFAULT_POSITION_MODE;
|
|
7677
|
-
const isAbsolute = positionMode === 'absolute';
|
|
7678
|
-
const position = useAnchorPosition(calloutRef, props);
|
|
7679
|
-
const className = `clarity-callout clarity-callout--${position.placement} clarity-callout--align-${position.horizontalAlign}`;
|
|
7680
|
-
// Determine portal container based on position mode
|
|
7681
|
-
const containerElmId = `gx-hm-elements-${viewId}`;
|
|
7682
|
-
const vizContainerElmId = `gx-hm-viz-container-${viewId}`;
|
|
7683
|
-
const portalContainerId = isAbsolute ? containerElmId : vizContainerElmId;
|
|
7684
|
-
const calloutContent = (jsx("div", { ref: calloutRef, className: className, style: {
|
|
7685
|
-
position: positionMode,
|
|
7686
|
-
top: position.top,
|
|
7687
|
-
left: position.left,
|
|
7688
|
-
zIndex: Z_INDEX.CALLOUT,
|
|
7689
|
-
}, "aria-live": "assertive", role: "tooltip", children: CompElementCallout && jsx(CompElementCallout, { elementHash: element.hash }) }));
|
|
7690
|
-
return createPortal(calloutContent, document.getElementById(portalContainerId));
|
|
7691
|
-
};
|
|
7692
7847
|
|
|
7693
|
-
const ElementMissing = ({ show = true }) => {
|
|
7848
|
+
const ElementMissing = ({ show = true, visualRef }) => {
|
|
7694
7849
|
const widthScale = useHeatmapViz((s) => s.widthScale);
|
|
7850
|
+
const missingElementRef = useRef(null);
|
|
7851
|
+
const wrapperWidth = useHeatmapConfigStore((s) => s.width);
|
|
7852
|
+
const [scrollPosition, setScrollPosition] = useState({ scrollTop: 0, scrollLeft: 0 });
|
|
7853
|
+
useEffect(() => {
|
|
7854
|
+
const container = visualRef.current;
|
|
7855
|
+
if (!container)
|
|
7856
|
+
return;
|
|
7857
|
+
const updateScrollPosition = () => {
|
|
7858
|
+
setScrollPosition({
|
|
7859
|
+
scrollTop: container.scrollTop,
|
|
7860
|
+
scrollLeft: container.scrollLeft,
|
|
7861
|
+
});
|
|
7862
|
+
};
|
|
7863
|
+
// Initial position
|
|
7864
|
+
updateScrollPosition();
|
|
7865
|
+
// Listen to scroll events
|
|
7866
|
+
container.addEventListener('scroll', updateScrollPosition);
|
|
7867
|
+
return () => {
|
|
7868
|
+
container.removeEventListener('scroll', updateScrollPosition);
|
|
7869
|
+
};
|
|
7870
|
+
}, [visualRef]);
|
|
7695
7871
|
if (!show)
|
|
7696
7872
|
return null;
|
|
7697
|
-
|
|
7698
|
-
|
|
7699
|
-
|
|
7700
|
-
|
|
7701
|
-
|
|
7702
|
-
|
|
7703
|
-
|
|
7704
|
-
|
|
7705
|
-
|
|
7706
|
-
|
|
7707
|
-
|
|
7708
|
-
|
|
7709
|
-
|
|
7710
|
-
|
|
7711
|
-
|
|
7873
|
+
const container = visualRef.current;
|
|
7874
|
+
const containerRect = container?.getBoundingClientRect();
|
|
7875
|
+
const elementRect = missingElementRef.current?.getBoundingClientRect();
|
|
7876
|
+
const elementHeightCenter = elementRect?.height ?? 0;
|
|
7877
|
+
const scrollTop = scrollPosition.scrollTop ?? 0;
|
|
7878
|
+
const containerHeight = containerRect?.height ?? 0;
|
|
7879
|
+
const topPosition = scrollTop + (containerHeight + elementHeightCenter) / 2;
|
|
7880
|
+
const topPositionScaled = topPosition / widthScale;
|
|
7881
|
+
const leftPosition = wrapperWidth / 2;
|
|
7882
|
+
return (jsxs(Fragment, { children: [jsx("div", { className: "missingElement-backdrop", style: {
|
|
7883
|
+
position: 'absolute',
|
|
7884
|
+
top: 0,
|
|
7885
|
+
left: 0,
|
|
7886
|
+
right: 0,
|
|
7887
|
+
bottom: 0,
|
|
7888
|
+
background: 'rgba(0, 0, 0, 0.5)',
|
|
7889
|
+
zIndex: 9998,
|
|
7890
|
+
pointerEvents: 'none',
|
|
7891
|
+
} }), jsx("div", { ref: missingElementRef, className: "missingElement", style: {
|
|
7892
|
+
position: 'absolute',
|
|
7893
|
+
top: topPositionScaled,
|
|
7894
|
+
left: leftPosition,
|
|
7895
|
+
transform: `translate(-50%, -50%) scale(${1 / widthScale})`,
|
|
7896
|
+
background: 'rgba(0, 0, 0, 0.8)',
|
|
7897
|
+
color: 'white',
|
|
7898
|
+
padding: '12px 20px',
|
|
7899
|
+
borderRadius: '8px',
|
|
7900
|
+
fontSize: '14px',
|
|
7901
|
+
fontWeight: '500',
|
|
7902
|
+
zIndex: 9999,
|
|
7903
|
+
pointerEvents: 'none',
|
|
7904
|
+
whiteSpace: 'nowrap',
|
|
7905
|
+
}, "aria-live": "assertive", children: "Element not visible on current screen" })] }));
|
|
7712
7906
|
};
|
|
7713
7907
|
|
|
7714
|
-
|
|
7908
|
+
/**
|
|
7909
|
+
* Example component showing how to use canvas backdrop
|
|
7910
|
+
* Renders a dark overlay with cutout for active element
|
|
7911
|
+
*/
|
|
7912
|
+
const BackdropCanvas = ({ activeElement, viewportWidth, viewportHeight, borderWidth = 0, show = true, cutoutExpansion = BACKDROP_CONFIG.CUTOUT_EXPANSION, backdropColor = BACKDROP_CONFIG.COLOR, backdropOpacity = BACKDROP_CONFIG.OPACITY, }) => {
|
|
7913
|
+
const canvasRef = useRef(null);
|
|
7914
|
+
useEffect(() => {
|
|
7915
|
+
const canvas = canvasRef.current;
|
|
7916
|
+
if (!canvas || !show)
|
|
7917
|
+
return;
|
|
7918
|
+
// Set canvas dimensions
|
|
7919
|
+
canvas.width = viewportWidth;
|
|
7920
|
+
canvas.height = viewportHeight;
|
|
7921
|
+
if (!activeElement || (activeElement.width === 0 && activeElement.height === 0)) {
|
|
7922
|
+
// No active element - clear canvas
|
|
7923
|
+
clearCanvas(canvas);
|
|
7924
|
+
return;
|
|
7925
|
+
}
|
|
7926
|
+
// Draw backdrop with cutout for active element
|
|
7927
|
+
drawBackdropWithCutout({
|
|
7928
|
+
canvas,
|
|
7929
|
+
activeRect: {
|
|
7930
|
+
top: activeElement.top + borderWidth,
|
|
7931
|
+
left: activeElement.left + borderWidth,
|
|
7932
|
+
width: activeElement.width,
|
|
7933
|
+
height: activeElement.height,
|
|
7934
|
+
},
|
|
7935
|
+
backdropColor,
|
|
7936
|
+
backdropOpacity,
|
|
7937
|
+
cutoutExpansion,
|
|
7938
|
+
});
|
|
7939
|
+
}, [
|
|
7940
|
+
activeElement,
|
|
7941
|
+
viewportWidth,
|
|
7942
|
+
viewportHeight,
|
|
7943
|
+
borderWidth,
|
|
7944
|
+
show,
|
|
7945
|
+
cutoutExpansion,
|
|
7946
|
+
backdropColor,
|
|
7947
|
+
backdropOpacity,
|
|
7948
|
+
]);
|
|
7949
|
+
if (!show)
|
|
7950
|
+
return null;
|
|
7951
|
+
return (jsx("canvas", { ref: canvasRef, style: {
|
|
7952
|
+
position: 'absolute',
|
|
7953
|
+
top: 0,
|
|
7954
|
+
left: 0,
|
|
7955
|
+
width: viewportWidth,
|
|
7956
|
+
height: viewportHeight,
|
|
7957
|
+
pointerEvents: 'none', // Allow clicks to pass through
|
|
7958
|
+
zIndex: BACKDROP_CONFIG.Z_INDEX, // Below callout but above content
|
|
7959
|
+
} }));
|
|
7960
|
+
};
|
|
7961
|
+
|
|
7962
|
+
const ElementCalloutOverlay = (props) => {
|
|
7963
|
+
const { element, containerRef } = props;
|
|
7715
7964
|
const widthScale = useHeatmapViz((s) => s.widthScale);
|
|
7965
|
+
const CompElementCallout = useHeatmapControlStore((state) => state.controls.ElementCallout);
|
|
7966
|
+
const calloutRef = useRef(null);
|
|
7967
|
+
const [calloutStyle, setCalloutStyle] = useState(undefined);
|
|
7968
|
+
useEffect(() => {
|
|
7969
|
+
const calloutElm = calloutRef.current;
|
|
7970
|
+
const containerElm = containerRef?.current;
|
|
7971
|
+
if (!element || !calloutElm || !containerElm)
|
|
7972
|
+
return;
|
|
7973
|
+
calcCalloutPositionAbsolute({
|
|
7974
|
+
widthScale,
|
|
7975
|
+
calloutElm,
|
|
7976
|
+
containerElm,
|
|
7977
|
+
element,
|
|
7978
|
+
onChange: setCalloutStyle,
|
|
7979
|
+
});
|
|
7980
|
+
}, [element, widthScale, containerRef]);
|
|
7981
|
+
if (!element)
|
|
7982
|
+
return null;
|
|
7983
|
+
return (jsx("div", { ref: calloutRef, style: calloutStyle, className: "clarity-callout", children: CompElementCallout && jsx(CompElementCallout, { elementHash: element.hash }) }));
|
|
7984
|
+
};
|
|
7985
|
+
ElementCalloutOverlay.displayName = 'ElementCalloutOverlay';
|
|
7986
|
+
|
|
7987
|
+
const ElementOverlayComponent = (props) => {
|
|
7988
|
+
const { type, element, onClick, elementId } = props;
|
|
7989
|
+
const widthScale = useHeatmapViz((s) => s.widthScale);
|
|
7990
|
+
const viewportHeight = useHeatmapVizRect((s) => s.iframeHeight);
|
|
7991
|
+
const viewportWidth = useHeatmapConfigStore((s) => s.width);
|
|
7716
7992
|
const overlayStyle = useMemo(() => {
|
|
7717
|
-
|
|
7993
|
+
const isInvalid = !element || (element.width === 0 && element.height === 0);
|
|
7994
|
+
if (isInvalid)
|
|
7718
7995
|
return null;
|
|
7719
7996
|
return {
|
|
7720
7997
|
top: element.top + HEATMAP_CONFIG['borderWidthIframe'],
|
|
7721
7998
|
left: element.left + HEATMAP_CONFIG['borderWidthIframe'],
|
|
7722
7999
|
width: element.width,
|
|
7723
8000
|
height: element.height,
|
|
7724
|
-
cursor: 'pointer',
|
|
7725
8001
|
};
|
|
7726
8002
|
}, [element]);
|
|
7727
8003
|
if (!overlayStyle)
|
|
7728
8004
|
return null;
|
|
7729
8005
|
const isHovered = type === 'hovered';
|
|
7730
8006
|
const badgeWidthScale = isHovered ? 1 : widthScale;
|
|
7731
|
-
|
|
8007
|
+
const showCallout = !!element?.mousePosition && !isHovered;
|
|
8008
|
+
return (jsxs(Fragment$1, { children: [jsx("div", { onClick: onClick, className: `heatmapElement heatmapElement--${type}`, id: elementId, style: overlayStyle, children: showCallout && jsx(ElementCalloutOverlay, { ...props }) }), jsx(BackdropCanvas, { activeElement: overlayStyle, viewportWidth: viewportWidth, viewportHeight: viewportHeight, show: !isHovered }), jsx(RankBadge, { hash: element.hash, show: isHovered, index: element.rank, elementRect: element, widthScale: badgeWidthScale, clickOnElement: onClick })] }));
|
|
7732
8009
|
};
|
|
7733
8010
|
ElementOverlayComponent.displayName = 'ElementOverlay';
|
|
7734
8011
|
const ElementOverlay = memo(ElementOverlayComponent);
|
|
7735
8012
|
|
|
7736
|
-
const
|
|
7737
|
-
const
|
|
7738
|
-
|
|
8013
|
+
const ElementCalloutClickedComponent = (props) => {
|
|
8014
|
+
const viewId = useViewIdContext();
|
|
8015
|
+
const { clickedElement, showMissingElement, shouldShowCallout } = useClickedElement({
|
|
8016
|
+
visualRef: props.visualRef,
|
|
8017
|
+
getRect: props.getRect,
|
|
8018
|
+
});
|
|
8019
|
+
const elementId = getClickedElementId(viewId, props.isSecondary);
|
|
8020
|
+
if (!clickedElement && showMissingElement)
|
|
8021
|
+
return jsx(ElementMissing, { visualRef: props.visualRef });
|
|
8022
|
+
if (!clickedElement)
|
|
7739
8023
|
return null;
|
|
7740
|
-
|
|
8024
|
+
const isShowClickedElement = shouldShowCallout && !clickedElement?.mousePosition;
|
|
8025
|
+
return (jsxs(Fragment, { children: [jsx(ElementOverlay, { type: "clicked", element: clickedElement, elementId: elementId, containerRef: props.containerRef }), isShowClickedElement && (jsx(ElementCallout, { element: clickedElement, target: `#${elementId}`, visualRef: props.visualRef, positionMode: props.positionMode }))] }));
|
|
7741
8026
|
};
|
|
7742
|
-
memo(
|
|
8027
|
+
const ElementCalloutClicked = memo(ElementCalloutClickedComponent);
|
|
7743
8028
|
|
|
7744
8029
|
const HoveredElementOverlayComponent = ({ onClick }) => {
|
|
7745
8030
|
const viewId = useViewIdContext();
|
|
@@ -7756,16 +8041,19 @@ const HoveredElementOverlayComponent = ({ onClick }) => {
|
|
|
7756
8041
|
};
|
|
7757
8042
|
const HoveredElementOverlay = memo(HoveredElementOverlayComponent);
|
|
7758
8043
|
|
|
7759
|
-
const
|
|
7760
|
-
|
|
7761
|
-
|
|
8044
|
+
const IS_SHOW_CALLOUT = false;
|
|
8045
|
+
const ElementCalloutHoveredComponent = (props) => {
|
|
8046
|
+
const viewId = useViewIdContext();
|
|
8047
|
+
useHeatmapHover((s) => s.hoveredElement);
|
|
8048
|
+
getHoveredElementId(viewId, props.isSecondary);
|
|
8049
|
+
const isShowCallout = IS_SHOW_CALLOUT ;
|
|
8050
|
+
return (jsxs(Fragment, { children: [jsx(HoveredElementOverlay, { onClick: props.onClick }), isShowCallout ] }));
|
|
7762
8051
|
};
|
|
7763
|
-
const
|
|
8052
|
+
const ElementCalloutHovered = memo(ElementCalloutHoveredComponent);
|
|
8053
|
+
|
|
7764
8054
|
const HeatmapElements = (props) => {
|
|
7765
8055
|
const viewId = useViewIdContext();
|
|
7766
8056
|
const iframeHeight = useHeatmapVizRect((s) => s.iframeHeight);
|
|
7767
|
-
const clickedElementId = getClickedElementId(viewId, props.isSecondary);
|
|
7768
|
-
getHoveredElementId(viewId, props.isSecondary);
|
|
7769
8057
|
const elementCalloutRef = useRef(null);
|
|
7770
8058
|
const { iframeDimensions, isVisible = true, areDefaultRanksHidden, positionMode } = props;
|
|
7771
8059
|
const { getRect } = useHeatmapElementPosition({
|
|
@@ -7773,10 +8061,6 @@ const HeatmapElements = (props) => {
|
|
|
7773
8061
|
wrapperRef: props.wrapperRef,
|
|
7774
8062
|
visualizer: props.visualizer,
|
|
7775
8063
|
});
|
|
7776
|
-
const { clickedElement, showMissingElement, shouldShowCallout } = useClickedElement({
|
|
7777
|
-
visualRef: props.visualRef,
|
|
7778
|
-
getRect,
|
|
7779
|
-
});
|
|
7780
8064
|
const { handleMouseMove, handleMouseLeave, handleClick } = useHoveredElement({
|
|
7781
8065
|
iframeRef: props.iframeRef,
|
|
7782
8066
|
getRect,
|
|
@@ -7786,8 +8070,7 @@ const HeatmapElements = (props) => {
|
|
|
7786
8070
|
useRenderCount('HeatmapElements');
|
|
7787
8071
|
if (!isVisible)
|
|
7788
8072
|
return null;
|
|
7789
|
-
|
|
7790
|
-
return (jsxs("div", { id: `gx-hm-elements-${viewId}`, ref: elementCalloutRef, onMouseMove: handleMouseMove, onMouseLeave: handleMouseLeave, className: "gx-hm-elements", style: { ...iframeDimensions, height: `${iframeHeight}px` }, children: [jsx(ElementMissing, { show: showMissingElement }), jsx(DefaultRankBadges, { getRect: getRect, hidden: areDefaultRanksHidden }), jsx(ElementOverlay, { type: "clicked", element: clickedElement, elementId: clickedElementId }), jsx(HoveredElementOverlay, { onClick: handleClick }), IS_SHOW_HOVERED_ELEMENT , isShowClickedElement && (jsx(ElementCallout, { element: clickedElement, target: `#${clickedElementId}`, visualRef: props.visualRef, positionMode: props.positionMode, ...ELEMENT_CALLOUT }))] }));
|
|
8073
|
+
return (jsxs("div", { id: `gx-hm-elements-${viewId}`, ref: elementCalloutRef, onMouseMove: handleMouseMove, onMouseLeave: handleMouseLeave, className: "gx-hm-elements", style: { ...iframeDimensions, height: `${iframeHeight}px` }, children: [jsx(DefaultRankBadges, { getRect: getRect, hidden: areDefaultRanksHidden }), jsx(ElementCalloutClicked, { visualRef: props.visualRef, positionMode: props.positionMode, getRect: getRect, isSecondary: props.isSecondary, containerRef: elementCalloutRef }), jsx(ElementCalloutHovered, { visualRef: props.visualRef, onClick: handleClick, isSecondary: props.isSecondary, positionMode: props.positionMode })] }));
|
|
7791
8074
|
};
|
|
7792
8075
|
|
|
7793
8076
|
const VizElements = ({ iframeRef, visualRef, wrapperRef }) => {
|
|
@@ -8248,4 +8531,4 @@ const HeatmapLayout = ({ data, clickmap, clickAreas, scrollmap, controls, dataIn
|
|
|
8248
8531
|
}
|
|
8249
8532
|
};
|
|
8250
8533
|
|
|
8251
|
-
export { DEFAULT_SIDEBAR_WIDTH, DEFAULT_VIEW_ID, GraphView, HEATMAP_CONFIG, HEATMAP_IFRAME, HEATMAP_STYLE, HeatmapLayout, IClickMode, IClickType, IHeatmapType, IScrollType, ViewIdContext, Z_INDEX, compareViewPerformance, convertViewportToIframeCoords, createStorePerformanceTracker, downloadPerformanceReport, getCompareViewId, getMetricsByViewId, getPerformanceReportJSON, getScrollGradientColor, performanceLogger, printPerformanceSummary, scrollToElementIfNeeded, sendPerformanceReport, serializeAreas, trackStoreAction, useAreaCreation, useAreaEditMode, useAreaFilterVisible, useAreaHydration, useAreaInteraction, useAreaPositionsUpdater, useAreaRectSync, useAreaRendererContainer, useAreaTopAutoDetect, useClickedElement, useDebounceCallback, useElementCalloutVisible, useHeatmapAreaClick, useHeatmapCanvas, useHeatmapClick, useHeatmapCompareStore, useHeatmapConfigStore, useHeatmapCopyView, useHeatmapData, useHeatmapEffects, useHeatmapElementPosition, useHeatmapHover, useHeatmapLiveStore, useHeatmapRenderByMode, useHeatmapScale, useHeatmapScroll, useHeatmapViz, useHeatmapVizRect, useHoveredElement, useIframeHeight, useIframeHeightProcessor, useMeasureFunction, useRegisterConfig, useRegisterControl, useRegisterData, useRegisterHeatmap, useRenderCount, useScrollmapZones, useTrackHookCall, useViewIdContext, useVizLiveRender, useWhyDidYouUpdate, useWrapperRefHeight, useZonePositions, withPerformanceTracking };
|
|
8534
|
+
export { BACKDROP_CONFIG, DEFAULT_SIDEBAR_WIDTH, DEFAULT_VIEW_ID, GraphView, HEATMAP_CONFIG, HEATMAP_IFRAME, HEATMAP_STYLE, HeatmapLayout, IClickMode, IClickType, IHeatmapType, IScrollType, ViewIdContext, Z_INDEX, compareViewPerformance, convertViewportToIframeCoords, createStorePerformanceTracker, downloadPerformanceReport, getCompareViewId, getMetricsByViewId, getPerformanceReportJSON, getScrollGradientColor, performanceLogger, printPerformanceSummary, scrollToElementIfNeeded, sendPerformanceReport, serializeAreas, trackStoreAction, useAreaCreation, useAreaEditMode, useAreaFilterVisible, useAreaHydration, useAreaInteraction, useAreaPositionsUpdater, useAreaRectSync, useAreaRendererContainer, useAreaTopAutoDetect, useClickedElement, useDebounceCallback, useElementCalloutVisible, useHeatmapAreaClick, useHeatmapCanvas, useHeatmapClick, useHeatmapCompareStore, useHeatmapConfigStore, useHeatmapCopyView, useHeatmapData, useHeatmapEffects, useHeatmapElementPosition, useHeatmapHover, useHeatmapLiveStore, useHeatmapRenderByMode, useHeatmapScale, useHeatmapScroll, useHeatmapViz, useHeatmapVizRect, useHoveredElement, useIframeHeight, useIframeHeightProcessor, useMeasureFunction, useRegisterConfig, useRegisterControl, useRegisterData, useRegisterHeatmap, useRenderCount, useScrollmapZones, useTrackHookCall, useViewIdContext, useVizLiveRender, useWhyDidYouUpdate, useWrapperRefHeight, useZonePositions, withPerformanceTracking };
|