@gemx-dev/heatmap-react 3.5.56 → 3.5.58
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/components/VizScrollmap/VizScrollMap.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/view-context/useHeatmapViz.d.ts +2 -26
- package/dist/esm/hooks/view-context/useHeatmapViz.d.ts.map +1 -1
- package/dist/esm/hooks/viz-elm/useHoveredElement.d.ts.map +1 -1
- package/dist/esm/hooks/viz-scale/useScaleCalculation.d.ts.map +1 -1
- package/dist/esm/index.js +527 -233
- package/dist/esm/index.mjs +527 -233
- 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/components/VizScrollmap/VizScrollMap.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/view-context/useHeatmapViz.d.ts +2 -26
- package/dist/umd/hooks/view-context/useHeatmapViz.d.ts.map +1 -1
- package/dist/umd/hooks/viz-elm/useHoveredElement.d.ts.map +1 -1
- package/dist/umd/hooks/viz-scale/useScaleCalculation.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.js
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;
|
|
@@ -6416,6 +6566,8 @@ const useObserveIframeHeight = (props) => {
|
|
|
6416
6566
|
return {};
|
|
6417
6567
|
};
|
|
6418
6568
|
|
|
6569
|
+
// Max zoom ratio constant: 100% = fit to width
|
|
6570
|
+
const MAX_ZOOM_RATIO = 100;
|
|
6419
6571
|
const useScaleCalculation = (props) => {
|
|
6420
6572
|
const widthScale = useHeatmapViz((s) => s.widthScale);
|
|
6421
6573
|
const zoomRatio = useHeatmapViz((s) => s.zoomRatio);
|
|
@@ -6427,23 +6579,31 @@ const useScaleCalculation = (props) => {
|
|
|
6427
6579
|
const { containerWidth, containerHeight, contentWidth, contentHeight } = props;
|
|
6428
6580
|
const calculateScaleResult = useCallback(() => {
|
|
6429
6581
|
if (containerWidth > 0 && contentWidth > 0 && containerHeight > 0 && contentHeight > 0) {
|
|
6430
|
-
// 1. Calculate
|
|
6582
|
+
// 1. Calculate available dimensions
|
|
6431
6583
|
const availableWidth = containerWidth - HEATMAP_CONFIG['padding'] * 2;
|
|
6432
|
-
const widthScale = Math.min(availableWidth / contentWidth, 1);
|
|
6433
|
-
// 2. Calculate available height
|
|
6434
6584
|
const toolbarHeight = HEATMAP_CONFIG['heightToolbar'] || 0;
|
|
6435
6585
|
const paddingTotal = HEATMAP_CONFIG['padding'] * 2;
|
|
6436
|
-
const availableHeight = containerHeight - toolbarHeight - paddingTotal;
|
|
6437
|
-
//
|
|
6438
|
-
|
|
6439
|
-
|
|
6440
|
-
|
|
6441
|
-
//
|
|
6442
|
-
|
|
6586
|
+
const availableHeight = containerHeight - toolbarHeight - paddingTotal;
|
|
6587
|
+
// 2. Calculate widthScale (base scale to fit content width into container width)
|
|
6588
|
+
// This represents 100% zoom (fit to width)
|
|
6589
|
+
const widthScale = Math.min(availableWidth / contentWidth, 1);
|
|
6590
|
+
// 3. Calculate minZoomRatio (zoom ratio to fit height)
|
|
6591
|
+
// At minZoomRatio, the content should fit entirely within the container height
|
|
6592
|
+
// Formula: contentHeight * widthScale * (minZoomRatio / 100) = availableHeight
|
|
6593
|
+
// => minZoomRatio = (availableHeight / (contentHeight * widthScale)) * 100
|
|
6594
|
+
const calculatedMinZoomRatio = (availableHeight / (contentHeight * widthScale)) * 100;
|
|
6595
|
+
// Limit minZoomRatio: cannot exceed MAX_ZOOM_RATIO (100%)
|
|
6596
|
+
// and should have a reasonable minimum (e.g., 1%)
|
|
6597
|
+
const finalMinZoomRatio = Math.max(1, Math.min(calculatedMinZoomRatio, MAX_ZOOM_RATIO));
|
|
6598
|
+
// 4. Apply zoom ratio (clamp between min and max)
|
|
6599
|
+
const clampedZoomRatio = Math.max(finalMinZoomRatio, Math.min(zoomRatio, MAX_ZOOM_RATIO));
|
|
6443
6600
|
const zoomMultiplier = clampedZoomRatio / 100;
|
|
6444
6601
|
// 5. Calculate finalScale
|
|
6602
|
+
// finalScale = widthScale * zoomMultiplier
|
|
6603
|
+
// At 100% zoom: finalScale = widthScale (content fits container width)
|
|
6604
|
+
// At minZoomRatio: finalScale fits content entirely in container
|
|
6445
6605
|
const finalScale = widthScale * zoomMultiplier;
|
|
6446
|
-
// 6. Check if it is currently fitted
|
|
6606
|
+
// 6. Check if it is currently fitted (at minimum zoom)
|
|
6447
6607
|
const isCurrentlyFitted = zoomRatio <= finalMinZoomRatio;
|
|
6448
6608
|
// 7. Update store
|
|
6449
6609
|
setScale(finalScale);
|
|
@@ -7582,7 +7742,11 @@ const VizAreaClick = ({ iframeRef, visualRef, shadowRoot, autoCreateTopN = 10, e
|
|
|
7582
7742
|
};
|
|
7583
7743
|
VizAreaClick.displayName = 'VizAreaClick';
|
|
7584
7744
|
|
|
7585
|
-
const RankBadgeComponent = ({ index, elementRect, widthScale, clickOnElement }) => {
|
|
7745
|
+
const RankBadgeComponent = ({ index, hash, elementRect, widthScale, show = true, clickOnElement, }) => {
|
|
7746
|
+
const clickedHash = useHeatmapClick((s) => s.selectedElement?.hash);
|
|
7747
|
+
const isShow = !!show && clickedHash !== hash;
|
|
7748
|
+
if (!isShow)
|
|
7749
|
+
return null;
|
|
7586
7750
|
const style = calculateRankPosition(elementRect, widthScale);
|
|
7587
7751
|
return (jsx("div", { className: "gx-hm-rank-badge", style: style, onClick: clickOnElement, children: index }));
|
|
7588
7752
|
};
|
|
@@ -7600,7 +7764,7 @@ const DefaultRankBadgesComponent = ({ getRect, hidden }) => {
|
|
|
7600
7764
|
const rect = getRect(element);
|
|
7601
7765
|
if (!rect)
|
|
7602
7766
|
return null;
|
|
7603
|
-
return jsx(RankBadge, { index: index + 1, elementRect: rect, widthScale: widthScale }, element.hash);
|
|
7767
|
+
return (jsx(RankBadge, { hash: element.hash, index: index + 1, elementRect: rect, widthScale: widthScale }, element.hash));
|
|
7604
7768
|
}) }));
|
|
7605
7769
|
};
|
|
7606
7770
|
DefaultRankBadgesComponent.displayName = 'DefaultRankBadges';
|
|
@@ -7612,10 +7776,40 @@ const DEFAULT_POSITION = {
|
|
|
7612
7776
|
placement: 'top',
|
|
7613
7777
|
horizontalAlign: 'center',
|
|
7614
7778
|
};
|
|
7615
|
-
const
|
|
7779
|
+
const ElementCallout = (props) => {
|
|
7780
|
+
const viewId = useViewIdContext();
|
|
7781
|
+
const CompElementCallout = useHeatmapControlStore((state) => state.controls.ElementCallout);
|
|
7782
|
+
const calloutRef = useRef(null);
|
|
7783
|
+
const element = props.element;
|
|
7784
|
+
const positionMode = props.positionMode ?? DEFAULT_POSITION_MODE;
|
|
7785
|
+
const isAbsolute = positionMode === 'absolute';
|
|
7786
|
+
const position = useAnchorPosition(calloutRef, props);
|
|
7787
|
+
const className = `clarity-callout clarity-callout--${position.placement} clarity-callout--align-${position.horizontalAlign}`;
|
|
7788
|
+
const portalContainerId = getPortalElmId();
|
|
7789
|
+
if (!portalContainerId)
|
|
7790
|
+
return null;
|
|
7791
|
+
const calloutContent = (jsx("div", { ref: calloutRef, className: className, style: {
|
|
7792
|
+
position: positionMode,
|
|
7793
|
+
top: position.top,
|
|
7794
|
+
left: position.left,
|
|
7795
|
+
zIndex: Z_INDEX.CALLOUT,
|
|
7796
|
+
}, "aria-live": "assertive", role: "tooltip", children: CompElementCallout && jsx(CompElementCallout, { elementHash: element.hash }) }));
|
|
7797
|
+
if (!document.getElementById(portalContainerId))
|
|
7798
|
+
return null;
|
|
7799
|
+
return createPortal(calloutContent, document.getElementById(portalContainerId));
|
|
7800
|
+
function getPortalElmId() {
|
|
7801
|
+
const containerElmId = `gx-hm-elements-${viewId}`;
|
|
7802
|
+
const vizContainerElmId = `gx-hm-viz-container-${viewId}`;
|
|
7803
|
+
if (!isAbsolute)
|
|
7804
|
+
return vizContainerElmId;
|
|
7805
|
+
if (!element.mousePosition)
|
|
7806
|
+
return containerElmId;
|
|
7807
|
+
return '';
|
|
7808
|
+
}
|
|
7809
|
+
};
|
|
7616
7810
|
const useAnchorPosition = (calloutRef, props) => {
|
|
7617
7811
|
const widthScale = useHeatmapViz((s) => s.widthScale);
|
|
7618
|
-
const { target, visualRef,
|
|
7812
|
+
const { target, visualRef, alignment, element, positionMode } = props;
|
|
7619
7813
|
const [position, setPosition] = useState(DEFAULT_POSITION);
|
|
7620
7814
|
const isAbsolute = positionMode === 'absolute';
|
|
7621
7815
|
const mousePosition = element.mousePosition;
|
|
@@ -7630,15 +7824,11 @@ const useAnchorPosition = (calloutRef, props) => {
|
|
|
7630
7824
|
targetElm,
|
|
7631
7825
|
calloutElm,
|
|
7632
7826
|
setPosition,
|
|
7633
|
-
offset,
|
|
7634
7827
|
alignment,
|
|
7635
7828
|
positionMode,
|
|
7636
7829
|
visualRef,
|
|
7637
7830
|
widthScale,
|
|
7638
|
-
mousePosition,
|
|
7639
7831
|
});
|
|
7640
|
-
// Delay initial calculation to allow scroll animations to complete
|
|
7641
|
-
// Use multiple frames to ensure layout is stable
|
|
7642
7832
|
const rafId1 = requestAnimationFrame(() => {
|
|
7643
7833
|
requestAnimationFrame(() => {
|
|
7644
7834
|
positionFn();
|
|
@@ -7647,13 +7837,9 @@ const useAnchorPosition = (calloutRef, props) => {
|
|
|
7647
7837
|
const handleUpdate = () => {
|
|
7648
7838
|
requestAnimationFrame(positionFn);
|
|
7649
7839
|
};
|
|
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
7840
|
const visualContainer = visualRef?.current;
|
|
7654
7841
|
window.addEventListener('resize', handleUpdate);
|
|
7655
7842
|
if (!isAbsolute) {
|
|
7656
|
-
// Fixed mode: listen to scroll events for viewport position updates
|
|
7657
7843
|
window.addEventListener('scroll', handleUpdate, true);
|
|
7658
7844
|
visualContainer?.addEventListener('scroll', handleUpdate);
|
|
7659
7845
|
}
|
|
@@ -7665,81 +7851,190 @@ const useAnchorPosition = (calloutRef, props) => {
|
|
|
7665
7851
|
visualContainer?.removeEventListener('scroll', handleUpdate);
|
|
7666
7852
|
}
|
|
7667
7853
|
};
|
|
7668
|
-
}, [element, target, visualRef,
|
|
7854
|
+
}, [element, target, visualRef, alignment, isAbsolute, widthScale, calloutRef, mousePosition, positionMode]);
|
|
7669
7855
|
return position;
|
|
7670
7856
|
};
|
|
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
7857
|
|
|
7693
|
-
const ElementMissing = ({ show = true }) => {
|
|
7858
|
+
const ElementMissing = ({ show = true, visualRef }) => {
|
|
7694
7859
|
const widthScale = useHeatmapViz((s) => s.widthScale);
|
|
7860
|
+
const missingElementRef = useRef(null);
|
|
7861
|
+
const wrapperWidth = useHeatmapConfigStore((s) => s.width);
|
|
7862
|
+
const [scrollPosition, setScrollPosition] = useState({ scrollTop: 0, scrollLeft: 0 });
|
|
7863
|
+
useEffect(() => {
|
|
7864
|
+
const container = visualRef.current;
|
|
7865
|
+
if (!container)
|
|
7866
|
+
return;
|
|
7867
|
+
const updateScrollPosition = () => {
|
|
7868
|
+
setScrollPosition({
|
|
7869
|
+
scrollTop: container.scrollTop,
|
|
7870
|
+
scrollLeft: container.scrollLeft,
|
|
7871
|
+
});
|
|
7872
|
+
};
|
|
7873
|
+
// Initial position
|
|
7874
|
+
updateScrollPosition();
|
|
7875
|
+
// Listen to scroll events
|
|
7876
|
+
container.addEventListener('scroll', updateScrollPosition);
|
|
7877
|
+
return () => {
|
|
7878
|
+
container.removeEventListener('scroll', updateScrollPosition);
|
|
7879
|
+
};
|
|
7880
|
+
}, [visualRef]);
|
|
7695
7881
|
if (!show)
|
|
7696
7882
|
return null;
|
|
7697
|
-
|
|
7698
|
-
|
|
7699
|
-
|
|
7700
|
-
|
|
7701
|
-
|
|
7702
|
-
|
|
7703
|
-
|
|
7704
|
-
|
|
7705
|
-
|
|
7706
|
-
|
|
7707
|
-
|
|
7708
|
-
|
|
7709
|
-
|
|
7710
|
-
|
|
7711
|
-
|
|
7883
|
+
const container = visualRef.current;
|
|
7884
|
+
const containerRect = container?.getBoundingClientRect();
|
|
7885
|
+
const elementRect = missingElementRef.current?.getBoundingClientRect();
|
|
7886
|
+
const elementHeightCenter = elementRect?.height ?? 0;
|
|
7887
|
+
const scrollTop = scrollPosition.scrollTop ?? 0;
|
|
7888
|
+
const containerHeight = containerRect?.height ?? 0;
|
|
7889
|
+
const topPosition = scrollTop + (containerHeight + elementHeightCenter) / 2;
|
|
7890
|
+
const topPositionScaled = topPosition / widthScale;
|
|
7891
|
+
const leftPosition = wrapperWidth / 2;
|
|
7892
|
+
return (jsxs(Fragment, { children: [jsx("div", { className: "missingElement-backdrop", style: {
|
|
7893
|
+
position: 'absolute',
|
|
7894
|
+
top: 0,
|
|
7895
|
+
left: 0,
|
|
7896
|
+
right: 0,
|
|
7897
|
+
bottom: 0,
|
|
7898
|
+
background: 'rgba(0, 0, 0, 0.5)',
|
|
7899
|
+
zIndex: 9998,
|
|
7900
|
+
pointerEvents: 'none',
|
|
7901
|
+
} }), jsx("div", { ref: missingElementRef, className: "missingElement", style: {
|
|
7902
|
+
position: 'absolute',
|
|
7903
|
+
top: topPositionScaled,
|
|
7904
|
+
left: leftPosition,
|
|
7905
|
+
transform: `translate(-50%, -50%) scale(${1 / widthScale})`,
|
|
7906
|
+
background: 'rgba(0, 0, 0, 0.8)',
|
|
7907
|
+
color: 'white',
|
|
7908
|
+
padding: '12px 20px',
|
|
7909
|
+
borderRadius: '8px',
|
|
7910
|
+
fontSize: '14px',
|
|
7911
|
+
fontWeight: '500',
|
|
7912
|
+
zIndex: 9999,
|
|
7913
|
+
pointerEvents: 'none',
|
|
7914
|
+
whiteSpace: 'nowrap',
|
|
7915
|
+
}, "aria-live": "assertive", children: "Element not visible on current screen" })] }));
|
|
7712
7916
|
};
|
|
7713
7917
|
|
|
7714
|
-
|
|
7918
|
+
/**
|
|
7919
|
+
* Example component showing how to use canvas backdrop
|
|
7920
|
+
* Renders a dark overlay with cutout for active element
|
|
7921
|
+
*/
|
|
7922
|
+
const BackdropCanvas = ({ activeElement, viewportWidth, viewportHeight, borderWidth = 0, show = true, cutoutExpansion = BACKDROP_CONFIG.CUTOUT_EXPANSION, backdropColor = BACKDROP_CONFIG.COLOR, backdropOpacity = BACKDROP_CONFIG.OPACITY, }) => {
|
|
7923
|
+
const canvasRef = useRef(null);
|
|
7924
|
+
useEffect(() => {
|
|
7925
|
+
const canvas = canvasRef.current;
|
|
7926
|
+
if (!canvas || !show)
|
|
7927
|
+
return;
|
|
7928
|
+
// Set canvas dimensions
|
|
7929
|
+
canvas.width = viewportWidth;
|
|
7930
|
+
canvas.height = viewportHeight;
|
|
7931
|
+
if (!activeElement || (activeElement.width === 0 && activeElement.height === 0)) {
|
|
7932
|
+
// No active element - clear canvas
|
|
7933
|
+
clearCanvas(canvas);
|
|
7934
|
+
return;
|
|
7935
|
+
}
|
|
7936
|
+
// Draw backdrop with cutout for active element
|
|
7937
|
+
drawBackdropWithCutout({
|
|
7938
|
+
canvas,
|
|
7939
|
+
activeRect: {
|
|
7940
|
+
top: activeElement.top + borderWidth,
|
|
7941
|
+
left: activeElement.left + borderWidth,
|
|
7942
|
+
width: activeElement.width,
|
|
7943
|
+
height: activeElement.height,
|
|
7944
|
+
},
|
|
7945
|
+
backdropColor,
|
|
7946
|
+
backdropOpacity,
|
|
7947
|
+
cutoutExpansion,
|
|
7948
|
+
});
|
|
7949
|
+
}, [
|
|
7950
|
+
activeElement,
|
|
7951
|
+
viewportWidth,
|
|
7952
|
+
viewportHeight,
|
|
7953
|
+
borderWidth,
|
|
7954
|
+
show,
|
|
7955
|
+
cutoutExpansion,
|
|
7956
|
+
backdropColor,
|
|
7957
|
+
backdropOpacity,
|
|
7958
|
+
]);
|
|
7959
|
+
if (!show)
|
|
7960
|
+
return null;
|
|
7961
|
+
return (jsx("canvas", { ref: canvasRef, style: {
|
|
7962
|
+
position: 'absolute',
|
|
7963
|
+
top: 0,
|
|
7964
|
+
left: 0,
|
|
7965
|
+
width: viewportWidth,
|
|
7966
|
+
height: viewportHeight,
|
|
7967
|
+
pointerEvents: 'none', // Allow clicks to pass through
|
|
7968
|
+
zIndex: BACKDROP_CONFIG.Z_INDEX, // Below callout but above content
|
|
7969
|
+
} }));
|
|
7970
|
+
};
|
|
7971
|
+
|
|
7972
|
+
const ElementCalloutOverlay = (props) => {
|
|
7973
|
+
const { element, containerRef } = props;
|
|
7974
|
+
const widthScale = useHeatmapViz((s) => s.widthScale);
|
|
7975
|
+
const CompElementCallout = useHeatmapControlStore((state) => state.controls.ElementCallout);
|
|
7976
|
+
const calloutRef = useRef(null);
|
|
7977
|
+
const [calloutStyle, setCalloutStyle] = useState(undefined);
|
|
7978
|
+
useEffect(() => {
|
|
7979
|
+
const calloutElm = calloutRef.current;
|
|
7980
|
+
const containerElm = containerRef?.current;
|
|
7981
|
+
if (!element || !calloutElm || !containerElm)
|
|
7982
|
+
return;
|
|
7983
|
+
calcCalloutPositionAbsolute({
|
|
7984
|
+
widthScale,
|
|
7985
|
+
calloutElm,
|
|
7986
|
+
containerElm,
|
|
7987
|
+
element,
|
|
7988
|
+
onChange: setCalloutStyle,
|
|
7989
|
+
});
|
|
7990
|
+
}, [element, widthScale, containerRef]);
|
|
7991
|
+
if (!element)
|
|
7992
|
+
return null;
|
|
7993
|
+
return (jsx("div", { ref: calloutRef, style: calloutStyle, className: "clarity-callout", children: CompElementCallout && jsx(CompElementCallout, { elementHash: element.hash }) }));
|
|
7994
|
+
};
|
|
7995
|
+
ElementCalloutOverlay.displayName = 'ElementCalloutOverlay';
|
|
7996
|
+
|
|
7997
|
+
const ElementOverlayComponent = (props) => {
|
|
7998
|
+
const { type, element, onClick, elementId } = props;
|
|
7715
7999
|
const widthScale = useHeatmapViz((s) => s.widthScale);
|
|
8000
|
+
const viewportHeight = useHeatmapVizRect((s) => s.iframeHeight);
|
|
8001
|
+
const viewportWidth = useHeatmapConfigStore((s) => s.width);
|
|
7716
8002
|
const overlayStyle = useMemo(() => {
|
|
7717
|
-
|
|
8003
|
+
const isInvalid = !element || (element.width === 0 && element.height === 0);
|
|
8004
|
+
if (isInvalid)
|
|
7718
8005
|
return null;
|
|
7719
8006
|
return {
|
|
7720
8007
|
top: element.top + HEATMAP_CONFIG['borderWidthIframe'],
|
|
7721
8008
|
left: element.left + HEATMAP_CONFIG['borderWidthIframe'],
|
|
7722
8009
|
width: element.width,
|
|
7723
8010
|
height: element.height,
|
|
7724
|
-
cursor: 'pointer',
|
|
7725
8011
|
};
|
|
7726
8012
|
}, [element]);
|
|
7727
8013
|
if (!overlayStyle)
|
|
7728
8014
|
return null;
|
|
7729
8015
|
const isHovered = type === 'hovered';
|
|
7730
8016
|
const badgeWidthScale = isHovered ? 1 : widthScale;
|
|
7731
|
-
|
|
8017
|
+
const showCallout = !!element?.mousePosition && !isHovered;
|
|
8018
|
+
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
8019
|
};
|
|
7733
8020
|
ElementOverlayComponent.displayName = 'ElementOverlay';
|
|
7734
8021
|
const ElementOverlay = memo(ElementOverlayComponent);
|
|
7735
8022
|
|
|
7736
|
-
const
|
|
7737
|
-
const
|
|
7738
|
-
|
|
8023
|
+
const ElementCalloutClickedComponent = (props) => {
|
|
8024
|
+
const viewId = useViewIdContext();
|
|
8025
|
+
const { clickedElement, showMissingElement, shouldShowCallout } = useClickedElement({
|
|
8026
|
+
visualRef: props.visualRef,
|
|
8027
|
+
getRect: props.getRect,
|
|
8028
|
+
});
|
|
8029
|
+
const elementId = getClickedElementId(viewId, props.isSecondary);
|
|
8030
|
+
if (!clickedElement && showMissingElement)
|
|
8031
|
+
return jsx(ElementMissing, { visualRef: props.visualRef });
|
|
8032
|
+
if (!clickedElement)
|
|
7739
8033
|
return null;
|
|
7740
|
-
|
|
8034
|
+
const isShowClickedElement = shouldShowCallout && !clickedElement?.mousePosition;
|
|
8035
|
+
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
8036
|
};
|
|
7742
|
-
memo(
|
|
8037
|
+
const ElementCalloutClicked = memo(ElementCalloutClickedComponent);
|
|
7743
8038
|
|
|
7744
8039
|
const HoveredElementOverlayComponent = ({ onClick }) => {
|
|
7745
8040
|
const viewId = useViewIdContext();
|
|
@@ -7756,16 +8051,19 @@ const HoveredElementOverlayComponent = ({ onClick }) => {
|
|
|
7756
8051
|
};
|
|
7757
8052
|
const HoveredElementOverlay = memo(HoveredElementOverlayComponent);
|
|
7758
8053
|
|
|
7759
|
-
const
|
|
7760
|
-
|
|
7761
|
-
|
|
8054
|
+
const IS_SHOW_CALLOUT = false;
|
|
8055
|
+
const ElementCalloutHoveredComponent = (props) => {
|
|
8056
|
+
const viewId = useViewIdContext();
|
|
8057
|
+
useHeatmapHover((s) => s.hoveredElement);
|
|
8058
|
+
getHoveredElementId(viewId, props.isSecondary);
|
|
8059
|
+
const isShowCallout = IS_SHOW_CALLOUT ;
|
|
8060
|
+
return (jsxs(Fragment, { children: [jsx(HoveredElementOverlay, { onClick: props.onClick }), isShowCallout ] }));
|
|
7762
8061
|
};
|
|
7763
|
-
const
|
|
8062
|
+
const ElementCalloutHovered = memo(ElementCalloutHoveredComponent);
|
|
8063
|
+
|
|
7764
8064
|
const HeatmapElements = (props) => {
|
|
7765
8065
|
const viewId = useViewIdContext();
|
|
7766
8066
|
const iframeHeight = useHeatmapVizRect((s) => s.iframeHeight);
|
|
7767
|
-
const clickedElementId = getClickedElementId(viewId, props.isSecondary);
|
|
7768
|
-
getHoveredElementId(viewId, props.isSecondary);
|
|
7769
8067
|
const elementCalloutRef = useRef(null);
|
|
7770
8068
|
const { iframeDimensions, isVisible = true, areDefaultRanksHidden, positionMode } = props;
|
|
7771
8069
|
const { getRect } = useHeatmapElementPosition({
|
|
@@ -7773,10 +8071,6 @@ const HeatmapElements = (props) => {
|
|
|
7773
8071
|
wrapperRef: props.wrapperRef,
|
|
7774
8072
|
visualizer: props.visualizer,
|
|
7775
8073
|
});
|
|
7776
|
-
const { clickedElement, showMissingElement, shouldShowCallout } = useClickedElement({
|
|
7777
|
-
visualRef: props.visualRef,
|
|
7778
|
-
getRect,
|
|
7779
|
-
});
|
|
7780
8074
|
const { handleMouseMove, handleMouseLeave, handleClick } = useHoveredElement({
|
|
7781
8075
|
iframeRef: props.iframeRef,
|
|
7782
8076
|
getRect,
|
|
@@ -7786,8 +8080,7 @@ const HeatmapElements = (props) => {
|
|
|
7786
8080
|
useRenderCount('HeatmapElements');
|
|
7787
8081
|
if (!isVisible)
|
|
7788
8082
|
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 }))] }));
|
|
8083
|
+
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
8084
|
};
|
|
7792
8085
|
|
|
7793
8086
|
const VizElements = ({ iframeRef, visualRef, wrapperRef }) => {
|
|
@@ -8070,6 +8363,7 @@ const VizScrollMap = ({ iframeRef, wrapperRef }) => {
|
|
|
8070
8363
|
width: `calc(100% - 4px)`,
|
|
8071
8364
|
height: '100%',
|
|
8072
8365
|
transform: 'translateZ(0)',
|
|
8366
|
+
zIndex: 2,
|
|
8073
8367
|
}, children: [jsx(ScrollmapMarker, { iframeRef: iframeRef, wrapperRef: wrapperRef }), jsx(AverageFoldLine, { iframeRef: iframeRef, wrapperRef: wrapperRef }), jsx(ScrollMapOverlay, { wrapperRef: wrapperRef, iframeRef: iframeRef })] }));
|
|
8074
8368
|
};
|
|
8075
8369
|
|
|
@@ -8248,4 +8542,4 @@ const HeatmapLayout = ({ data, clickmap, clickAreas, scrollmap, controls, dataIn
|
|
|
8248
8542
|
}
|
|
8249
8543
|
};
|
|
8250
8544
|
|
|
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 };
|
|
8545
|
+
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 };
|