@gemx-dev/heatmap-react 3.5.43 → 3.5.45
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/Layout/HeatmapLayout.d.ts +3 -2
- package/dist/esm/components/Layout/HeatmapLayout.d.ts.map +1 -1
- package/dist/esm/components/VizDom/VizDomRenderer.d.ts.map +1 -1
- package/dist/esm/components/VizElement/HeatmapElements.d.ts +2 -2
- package/dist/esm/components/VizElement/HeatmapElements.d.ts.map +1 -1
- package/dist/esm/components/VizElement/HeatmapExample.d.ts +2 -0
- package/dist/esm/components/VizElement/HeatmapExample.d.ts.map +1 -0
- package/dist/esm/components/VizScrollmap/AverageFoldLine.d.ts +8 -0
- package/dist/esm/components/VizScrollmap/AverageFoldLine.d.ts.map +1 -0
- package/dist/esm/components/VizScrollmap/HoverZones.d.ts +10 -0
- package/dist/esm/components/VizScrollmap/HoverZones.d.ts.map +1 -0
- package/dist/esm/components/VizScrollmap/MetricRow.d.ts +1 -0
- package/dist/esm/components/VizScrollmap/MetricRow.d.ts.map +1 -0
- package/dist/esm/components/VizScrollmap/ScrollMapMinimap.d.ts +8 -0
- package/dist/esm/components/VizScrollmap/ScrollMapMinimap.d.ts.map +1 -0
- package/dist/esm/components/VizScrollmap/ScrollMapOverlay.d.ts +7 -0
- package/dist/esm/components/VizScrollmap/ScrollMapOverlay.d.ts.map +1 -0
- package/dist/esm/components/VizScrollmap/ScrollZoneHoverArea.d.ts +14 -0
- package/dist/esm/components/VizScrollmap/ScrollZoneHoverArea.d.ts.map +1 -0
- package/dist/esm/components/VizScrollmap/ScrollZoneTooltip.d.ts +10 -0
- package/dist/esm/components/VizScrollmap/ScrollZoneTooltip.d.ts.map +1 -0
- package/dist/esm/components/VizScrollmap/ScrollmapMarker.d.ts +7 -0
- package/dist/esm/components/VizScrollmap/ScrollmapMarker.d.ts.map +1 -0
- package/dist/esm/components/VizScrollmap/VizScrollMap.d.ts +7 -0
- package/dist/esm/components/VizScrollmap/VizScrollMap.d.ts.map +1 -0
- package/dist/esm/components/VizScrollmap/index.d.ts +2 -0
- package/dist/esm/components/VizScrollmap/index.d.ts.map +1 -0
- package/dist/esm/components/VizScrollmapV2/ScrollmapOverlayV2.d.ts +5 -0
- package/dist/esm/components/VizScrollmapV2/ScrollmapOverlayV2.d.ts.map +1 -0
- package/dist/esm/components/VizScrollmapV2/index.d.ts +2 -0
- package/dist/esm/components/VizScrollmapV2/index.d.ts.map +1 -0
- package/dist/esm/components/VizScrollmapV2/scrollmap.types.d.ts +18 -0
- package/dist/esm/components/VizScrollmapV2/scrollmap.types.d.ts.map +1 -0
- package/dist/esm/components/VizScrollmapV2/useScrollmapOverlay.d.ts +16 -0
- package/dist/esm/components/VizScrollmapV2/useScrollmapOverlay.d.ts.map +1 -0
- package/dist/esm/helpers/elm-getter.d.ts +2 -2
- package/dist/esm/helpers/elm-getter.d.ts.map +1 -1
- package/dist/esm/helpers/iframe-helper/fixer.d.ts +18 -0
- package/dist/esm/helpers/iframe-helper/fixer.d.ts.map +1 -0
- package/dist/esm/helpers/iframe-helper/index.d.ts +2 -0
- package/dist/esm/helpers/iframe-helper/index.d.ts.map +1 -0
- package/dist/esm/helpers/iframe-helper/init.d.ts +5 -0
- package/dist/esm/helpers/iframe-helper/init.d.ts.map +1 -0
- package/dist/esm/helpers/iframe-helper/navigation-blocker-v2.d.ts +28 -0
- package/dist/esm/helpers/iframe-helper/navigation-blocker-v2.d.ts.map +1 -0
- package/dist/esm/helpers/iframe-helper/navigation-blocker.d.ts +20 -0
- package/dist/esm/helpers/iframe-helper/navigation-blocker.d.ts.map +1 -0
- package/dist/{umd/helpers/viewport-replacer.d.ts → esm/helpers/iframe-helper/style-replacer.d.ts} +5 -5
- package/dist/esm/helpers/iframe-helper/style-replacer.d.ts.map +1 -0
- package/dist/esm/helpers/index.d.ts +2 -2
- package/dist/esm/helpers/index.d.ts.map +1 -1
- package/dist/esm/helpers/viz-canvas/area-clustering.d.ts +44 -0
- package/dist/esm/helpers/viz-canvas/area-clustering.d.ts.map +1 -0
- package/dist/esm/helpers/viz-canvas/area-overlay-manager-v2.d.ts +17 -0
- package/dist/esm/helpers/viz-canvas/area-overlay-manager-v2.d.ts.map +1 -0
- package/dist/esm/helpers/viz-canvas/area-overlay-manager.d.ts +51 -0
- package/dist/esm/helpers/viz-canvas/area-overlay-manager.d.ts.map +1 -0
- package/dist/esm/helpers/viz-canvas/hierarchical-area-clustering.d.ts +73 -0
- package/dist/esm/helpers/viz-canvas/hierarchical-area-clustering.d.ts.map +1 -0
- package/dist/esm/helpers/viz-canvas/index.d.ts +3 -0
- package/dist/esm/helpers/viz-canvas/index.d.ts.map +1 -0
- package/dist/esm/hooks/index.d.ts +2 -1
- package/dist/esm/hooks/index.d.ts.map +1 -1
- package/dist/esm/hooks/register/useRegisterData.d.ts +2 -2
- package/dist/esm/hooks/register/useRegisterData.d.ts.map +1 -1
- package/dist/esm/hooks/register/useRegisterHeatmap.d.ts +7 -2
- package/dist/esm/hooks/register/useRegisterHeatmap.d.ts.map +1 -1
- package/dist/esm/hooks/viz-area/useAreaHeatmap.d.ts +59 -0
- package/dist/esm/hooks/viz-area/useAreaHeatmap.d.ts.map +1 -0
- package/dist/esm/hooks/viz-area/useAreaHeatmapManager.d.ts +77 -0
- package/dist/esm/hooks/viz-area/useAreaHeatmapManager.d.ts.map +1 -0
- package/dist/esm/hooks/viz-canvas/index.d.ts +1 -1
- package/dist/esm/hooks/viz-canvas/index.d.ts.map +1 -1
- package/dist/esm/hooks/viz-canvas/useAreamap.d.ts +14 -0
- package/dist/esm/hooks/viz-canvas/useAreamap.d.ts.map +1 -0
- package/dist/esm/hooks/viz-canvas/useHeatmapCanvas.d.ts +4 -0
- package/dist/esm/hooks/viz-canvas/useHeatmapCanvas.d.ts.map +1 -0
- package/dist/esm/hooks/viz-canvas/useScrollmap.d.ts.map +1 -1
- package/dist/esm/hooks/{vix-elements → viz-elements}/index.d.ts.map +1 -1
- package/dist/esm/hooks/{vix-elements → viz-elements}/useClickedElement.d.ts.map +1 -1
- package/dist/esm/hooks/{vix-elements → viz-elements}/useElementCalloutVisible.d.ts.map +1 -1
- package/dist/esm/hooks/{vix-elements → viz-elements}/useHeatmapEffects.d.ts.map +1 -1
- package/dist/esm/hooks/{vix-elements → viz-elements}/useHeatmapElementPosition.d.ts.map +1 -1
- package/dist/esm/hooks/{vix-elements → viz-elements}/useHeatmapMouseHandler.d.ts +2 -2
- package/dist/esm/hooks/{vix-elements → viz-elements}/useHeatmapMouseHandler.d.ts.map +1 -1
- package/dist/esm/hooks/{vix-elements → viz-elements}/useHoveredElement.d.ts +4 -0
- package/dist/esm/hooks/{vix-elements → viz-elements}/useHoveredElement.d.ts.map +1 -1
- package/dist/esm/hooks/viz-scrollmap/index.d.ts +3 -0
- package/dist/esm/hooks/viz-scrollmap/index.d.ts.map +1 -0
- package/dist/esm/hooks/viz-scrollmap/useScrollmapZones.d.ts +29 -0
- package/dist/esm/hooks/viz-scrollmap/useScrollmapZones.d.ts.map +1 -0
- package/dist/esm/hooks/viz-scrollmap/useZonePositions.d.ts +12 -0
- package/dist/esm/hooks/viz-scrollmap/useZonePositions.d.ts.map +1 -0
- package/dist/esm/index.js +825 -242
- package/dist/esm/index.mjs +825 -242
- package/dist/esm/stores/config.d.ts +5 -1
- package/dist/esm/stores/config.d.ts.map +1 -1
- package/dist/esm/stores/data.d.ts +5 -3
- package/dist/esm/stores/data.d.ts.map +1 -1
- package/dist/esm/stores/index.d.ts +1 -0
- package/dist/esm/stores/index.d.ts.map +1 -1
- package/dist/esm/stores/viz-scrollmap.d.ts +11 -0
- package/dist/esm/stores/viz-scrollmap.d.ts.map +1 -0
- package/dist/esm/types/clarity.d.ts +5 -0
- package/dist/esm/types/clarity.d.ts.map +1 -1
- package/dist/esm/types/heatmap-info.d.ts +11 -0
- package/dist/esm/types/heatmap-info.d.ts.map +1 -0
- package/dist/esm/types/heatmap.d.ts +13 -0
- package/dist/esm/types/heatmap.d.ts.map +1 -1
- package/dist/esm/types/iframe-helper.d.ts +20 -0
- package/dist/esm/types/iframe-helper.d.ts.map +1 -0
- package/dist/esm/types/index.d.ts +4 -1
- package/dist/esm/types/index.d.ts.map +1 -1
- package/dist/esm/types/viz-canvas.d.ts +23 -0
- package/dist/esm/types/viz-canvas.d.ts.map +1 -0
- package/dist/esm/types/viz-element.d.ts +0 -6
- package/dist/esm/types/viz-element.d.ts.map +1 -1
- package/dist/esm/types/viz-scrollmap.d.ts +27 -0
- package/dist/esm/types/viz-scrollmap.d.ts.map +1 -0
- package/dist/umd/components/Layout/HeatmapLayout.d.ts +3 -2
- package/dist/umd/components/Layout/HeatmapLayout.d.ts.map +1 -1
- package/dist/umd/components/VizDom/VizDomRenderer.d.ts.map +1 -1
- package/dist/umd/components/VizElement/HeatmapElements.d.ts +2 -2
- package/dist/umd/components/VizElement/HeatmapElements.d.ts.map +1 -1
- package/dist/umd/components/VizElement/HeatmapExample.d.ts +2 -0
- package/dist/umd/components/VizElement/HeatmapExample.d.ts.map +1 -0
- package/dist/umd/components/VizScrollmap/AverageFoldLine.d.ts +8 -0
- package/dist/umd/components/VizScrollmap/AverageFoldLine.d.ts.map +1 -0
- package/dist/umd/components/VizScrollmap/HoverZones.d.ts +10 -0
- package/dist/umd/components/VizScrollmap/HoverZones.d.ts.map +1 -0
- package/dist/umd/components/VizScrollmap/MetricRow.d.ts +1 -0
- package/dist/umd/components/VizScrollmap/MetricRow.d.ts.map +1 -0
- package/dist/umd/components/VizScrollmap/ScrollMapMinimap.d.ts +8 -0
- package/dist/umd/components/VizScrollmap/ScrollMapMinimap.d.ts.map +1 -0
- package/dist/umd/components/VizScrollmap/ScrollMapOverlay.d.ts +7 -0
- package/dist/umd/components/VizScrollmap/ScrollMapOverlay.d.ts.map +1 -0
- package/dist/umd/components/VizScrollmap/ScrollZoneHoverArea.d.ts +14 -0
- package/dist/umd/components/VizScrollmap/ScrollZoneHoverArea.d.ts.map +1 -0
- package/dist/umd/components/VizScrollmap/ScrollZoneTooltip.d.ts +10 -0
- package/dist/umd/components/VizScrollmap/ScrollZoneTooltip.d.ts.map +1 -0
- package/dist/umd/components/VizScrollmap/ScrollmapMarker.d.ts +7 -0
- package/dist/umd/components/VizScrollmap/ScrollmapMarker.d.ts.map +1 -0
- package/dist/umd/components/VizScrollmap/VizScrollMap.d.ts +7 -0
- package/dist/umd/components/VizScrollmap/VizScrollMap.d.ts.map +1 -0
- package/dist/umd/components/VizScrollmap/index.d.ts +2 -0
- package/dist/umd/components/VizScrollmap/index.d.ts.map +1 -0
- package/dist/umd/components/VizScrollmapV2/ScrollmapOverlayV2.d.ts +5 -0
- package/dist/umd/components/VizScrollmapV2/ScrollmapOverlayV2.d.ts.map +1 -0
- package/dist/umd/components/VizScrollmapV2/index.d.ts +2 -0
- package/dist/umd/components/VizScrollmapV2/index.d.ts.map +1 -0
- package/dist/umd/components/VizScrollmapV2/scrollmap.types.d.ts +18 -0
- package/dist/umd/components/VizScrollmapV2/scrollmap.types.d.ts.map +1 -0
- package/dist/umd/components/VizScrollmapV2/useScrollmapOverlay.d.ts +16 -0
- package/dist/umd/components/VizScrollmapV2/useScrollmapOverlay.d.ts.map +1 -0
- package/dist/umd/helpers/elm-getter.d.ts +2 -2
- package/dist/umd/helpers/elm-getter.d.ts.map +1 -1
- package/dist/umd/helpers/iframe-helper/fixer.d.ts +18 -0
- package/dist/umd/helpers/iframe-helper/fixer.d.ts.map +1 -0
- package/dist/umd/helpers/iframe-helper/index.d.ts +2 -0
- package/dist/umd/helpers/iframe-helper/index.d.ts.map +1 -0
- package/dist/umd/helpers/iframe-helper/init.d.ts +5 -0
- package/dist/umd/helpers/iframe-helper/init.d.ts.map +1 -0
- package/dist/umd/helpers/iframe-helper/navigation-blocker-v2.d.ts +28 -0
- package/dist/umd/helpers/iframe-helper/navigation-blocker-v2.d.ts.map +1 -0
- package/dist/umd/helpers/iframe-helper/navigation-blocker.d.ts +20 -0
- package/dist/umd/helpers/iframe-helper/navigation-blocker.d.ts.map +1 -0
- package/dist/{esm/helpers/viewport-replacer.d.ts → umd/helpers/iframe-helper/style-replacer.d.ts} +5 -5
- package/dist/umd/helpers/iframe-helper/style-replacer.d.ts.map +1 -0
- package/dist/umd/helpers/index.d.ts +2 -2
- package/dist/umd/helpers/index.d.ts.map +1 -1
- package/dist/umd/helpers/viz-canvas/area-clustering.d.ts +44 -0
- package/dist/umd/helpers/viz-canvas/area-clustering.d.ts.map +1 -0
- package/dist/umd/helpers/viz-canvas/area-overlay-manager-v2.d.ts +17 -0
- package/dist/umd/helpers/viz-canvas/area-overlay-manager-v2.d.ts.map +1 -0
- package/dist/umd/helpers/viz-canvas/area-overlay-manager.d.ts +51 -0
- package/dist/umd/helpers/viz-canvas/area-overlay-manager.d.ts.map +1 -0
- package/dist/umd/helpers/viz-canvas/hierarchical-area-clustering.d.ts +73 -0
- package/dist/umd/helpers/viz-canvas/hierarchical-area-clustering.d.ts.map +1 -0
- package/dist/umd/helpers/viz-canvas/index.d.ts +3 -0
- package/dist/umd/helpers/viz-canvas/index.d.ts.map +1 -0
- package/dist/umd/hooks/index.d.ts +2 -1
- package/dist/umd/hooks/index.d.ts.map +1 -1
- package/dist/umd/hooks/register/useRegisterData.d.ts +2 -2
- package/dist/umd/hooks/register/useRegisterData.d.ts.map +1 -1
- package/dist/umd/hooks/register/useRegisterHeatmap.d.ts +7 -2
- package/dist/umd/hooks/register/useRegisterHeatmap.d.ts.map +1 -1
- package/dist/umd/hooks/viz-area/useAreaHeatmap.d.ts +59 -0
- package/dist/umd/hooks/viz-area/useAreaHeatmap.d.ts.map +1 -0
- package/dist/umd/hooks/viz-area/useAreaHeatmapManager.d.ts +77 -0
- package/dist/umd/hooks/viz-area/useAreaHeatmapManager.d.ts.map +1 -0
- package/dist/umd/hooks/viz-canvas/index.d.ts +1 -1
- package/dist/umd/hooks/viz-canvas/index.d.ts.map +1 -1
- package/dist/umd/hooks/viz-canvas/useAreamap.d.ts +14 -0
- package/dist/umd/hooks/viz-canvas/useAreamap.d.ts.map +1 -0
- package/dist/umd/hooks/viz-canvas/useHeatmapCanvas.d.ts +4 -0
- package/dist/umd/hooks/viz-canvas/useHeatmapCanvas.d.ts.map +1 -0
- package/dist/umd/hooks/viz-canvas/useScrollmap.d.ts.map +1 -1
- package/dist/umd/hooks/{vix-elements → viz-elements}/index.d.ts.map +1 -1
- package/dist/umd/hooks/{vix-elements → viz-elements}/useClickedElement.d.ts.map +1 -1
- package/dist/umd/hooks/{vix-elements → viz-elements}/useElementCalloutVisible.d.ts.map +1 -1
- package/dist/umd/hooks/{vix-elements → viz-elements}/useHeatmapEffects.d.ts.map +1 -1
- package/dist/umd/hooks/{vix-elements → viz-elements}/useHeatmapElementPosition.d.ts.map +1 -1
- package/dist/umd/hooks/{vix-elements → viz-elements}/useHeatmapMouseHandler.d.ts +2 -2
- package/dist/umd/hooks/{vix-elements → viz-elements}/useHeatmapMouseHandler.d.ts.map +1 -1
- package/dist/umd/hooks/{vix-elements → viz-elements}/useHoveredElement.d.ts +4 -0
- package/dist/umd/hooks/{vix-elements → viz-elements}/useHoveredElement.d.ts.map +1 -1
- package/dist/umd/hooks/viz-scrollmap/index.d.ts +3 -0
- package/dist/umd/hooks/viz-scrollmap/index.d.ts.map +1 -0
- package/dist/umd/hooks/viz-scrollmap/useScrollmapZones.d.ts +29 -0
- package/dist/umd/hooks/viz-scrollmap/useScrollmapZones.d.ts.map +1 -0
- package/dist/umd/hooks/viz-scrollmap/useZonePositions.d.ts +12 -0
- package/dist/umd/hooks/viz-scrollmap/useZonePositions.d.ts.map +1 -0
- package/dist/umd/index.js +2 -2
- package/dist/umd/stores/config.d.ts +5 -1
- package/dist/umd/stores/config.d.ts.map +1 -1
- package/dist/umd/stores/data.d.ts +5 -3
- package/dist/umd/stores/data.d.ts.map +1 -1
- package/dist/umd/stores/index.d.ts +1 -0
- package/dist/umd/stores/index.d.ts.map +1 -1
- package/dist/umd/stores/viz-scrollmap.d.ts +11 -0
- package/dist/umd/stores/viz-scrollmap.d.ts.map +1 -0
- package/dist/umd/types/clarity.d.ts +5 -0
- package/dist/umd/types/clarity.d.ts.map +1 -1
- package/dist/umd/types/heatmap-info.d.ts +11 -0
- package/dist/umd/types/heatmap-info.d.ts.map +1 -0
- package/dist/umd/types/heatmap.d.ts +13 -0
- package/dist/umd/types/heatmap.d.ts.map +1 -1
- package/dist/umd/types/iframe-helper.d.ts +20 -0
- package/dist/umd/types/iframe-helper.d.ts.map +1 -0
- package/dist/umd/types/index.d.ts +4 -1
- package/dist/umd/types/index.d.ts.map +1 -1
- package/dist/umd/types/viz-canvas.d.ts +23 -0
- package/dist/umd/types/viz-canvas.d.ts.map +1 -0
- package/dist/umd/types/viz-element.d.ts +0 -6
- package/dist/umd/types/viz-element.d.ts.map +1 -1
- package/dist/umd/types/viz-scrollmap.d.ts +27 -0
- package/dist/umd/types/viz-scrollmap.d.ts.map +1 -0
- package/package.json +1 -1
- package/dist/esm/helpers/viewport-fixer.d.ts +0 -15
- package/dist/esm/helpers/viewport-fixer.d.ts.map +0 -1
- package/dist/esm/helpers/viewport-replacer.d.ts.map +0 -1
- package/dist/esm/hooks/viz-canvas/useHeatmapVizCanvas.d.ts +0 -2
- package/dist/esm/hooks/viz-canvas/useHeatmapVizCanvas.d.ts.map +0 -1
- package/dist/esm/types/viewport-fixer.d.ts +0 -31
- package/dist/esm/types/viewport-fixer.d.ts.map +0 -1
- package/dist/umd/helpers/viewport-fixer.d.ts +0 -15
- package/dist/umd/helpers/viewport-fixer.d.ts.map +0 -1
- package/dist/umd/helpers/viewport-replacer.d.ts.map +0 -1
- package/dist/umd/hooks/viz-canvas/useHeatmapVizCanvas.d.ts +0 -2
- package/dist/umd/hooks/viz-canvas/useHeatmapVizCanvas.d.ts.map +0 -1
- package/dist/umd/types/viewport-fixer.d.ts +0 -31
- package/dist/umd/types/viewport-fixer.d.ts.map +0 -1
- /package/dist/esm/hooks/{vix-elements → viz-elements}/index.d.ts +0 -0
- /package/dist/esm/hooks/{vix-elements → viz-elements}/useClickedElement.d.ts +0 -0
- /package/dist/esm/hooks/{vix-elements → viz-elements}/useElementCalloutVisible.d.ts +0 -0
- /package/dist/esm/hooks/{vix-elements → viz-elements}/useHeatmapEffects.d.ts +0 -0
- /package/dist/esm/hooks/{vix-elements → viz-elements}/useHeatmapElementPosition.d.ts +0 -0
- /package/dist/umd/hooks/{vix-elements → viz-elements}/index.d.ts +0 -0
- /package/dist/umd/hooks/{vix-elements → viz-elements}/useClickedElement.d.ts +0 -0
- /package/dist/umd/hooks/{vix-elements → viz-elements}/useElementCalloutVisible.d.ts +0 -0
- /package/dist/umd/hooks/{vix-elements → viz-elements}/useHeatmapEffects.d.ts +0 -0
- /package/dist/umd/hooks/{vix-elements → viz-elements}/useHeatmapElementPosition.d.ts +0 -0
package/dist/esm/index.mjs
CHANGED
|
@@ -93,18 +93,37 @@ var IHeatmapType;
|
|
|
93
93
|
IHeatmapType["Click"] = "click";
|
|
94
94
|
IHeatmapType["Scroll"] = "scroll";
|
|
95
95
|
})(IHeatmapType || (IHeatmapType = {}));
|
|
96
|
+
var IClickType;
|
|
97
|
+
(function (IClickType) {
|
|
98
|
+
IClickType["Total"] = "total-clicks";
|
|
99
|
+
IClickType["Rage"] = "rage-clicks";
|
|
100
|
+
IClickType["Dead"] = "dead-clicks";
|
|
101
|
+
IClickType["Error"] = "error-clicks";
|
|
102
|
+
IClickType["First"] = "first-clicks";
|
|
103
|
+
IClickType["Last"] = "last-clicks";
|
|
104
|
+
})(IClickType || (IClickType = {}));
|
|
105
|
+
var IScrollType;
|
|
106
|
+
(function (IScrollType) {
|
|
107
|
+
IScrollType["Depth"] = "scroll-depth";
|
|
108
|
+
IScrollType["Attention"] = "attention-scroll";
|
|
109
|
+
IScrollType["Revenue"] = "revenue-scroll";
|
|
110
|
+
})(IScrollType || (IScrollType = {}));
|
|
96
111
|
|
|
97
112
|
const useHeatmapConfigStore = create()((set, get) => {
|
|
98
113
|
return {
|
|
99
114
|
mode: 'single',
|
|
100
115
|
width: 1440,
|
|
101
116
|
sidebarWidth: DEFAULT_SIDEBAR_WIDTH,
|
|
102
|
-
heatmapType: IHeatmapType.
|
|
117
|
+
heatmapType: IHeatmapType.Scroll,
|
|
118
|
+
clickType: IClickType.Total,
|
|
119
|
+
scrollType: IScrollType.Depth,
|
|
103
120
|
setMode: (mode) => set({ mode }),
|
|
104
121
|
resetMode: () => set({ mode: 'single' }),
|
|
105
122
|
setWidth: (width) => set({ width }),
|
|
106
123
|
setSidebarWidth: (sidebarWidth) => set({ sidebarWidth }),
|
|
107
124
|
setHeatmapType: (heatmapType) => set({ heatmapType }),
|
|
125
|
+
setClickType: (clickType) => set({ clickType }),
|
|
126
|
+
setScrollType: (scrollType) => set({ scrollType }),
|
|
108
127
|
};
|
|
109
128
|
});
|
|
110
129
|
|
|
@@ -113,11 +132,13 @@ const useHeatmapDataStore = create()((set, get) => {
|
|
|
113
132
|
data: undefined,
|
|
114
133
|
clickmap: undefined,
|
|
115
134
|
dataInfo: undefined,
|
|
135
|
+
scrollmap: undefined,
|
|
116
136
|
isRendering: true,
|
|
117
137
|
setIsRendering: (isRendering) => set({ isRendering }),
|
|
118
138
|
setDataInfo: (dataInfo) => set({ dataInfo }),
|
|
119
139
|
setData: (data) => set({ data }),
|
|
120
140
|
setClickmap: (clickmap) => set({ clickmap }),
|
|
141
|
+
setScrollmap: (scrollmap) => set({ scrollmap }),
|
|
121
142
|
};
|
|
122
143
|
});
|
|
123
144
|
|
|
@@ -145,6 +166,17 @@ const useHeatmapVizStore = create()((set, get) => {
|
|
|
145
166
|
};
|
|
146
167
|
});
|
|
147
168
|
|
|
169
|
+
const useHeatmapVizScrollmapStore = create()((set, get) => {
|
|
170
|
+
return {
|
|
171
|
+
zones: [],
|
|
172
|
+
hoveredZone: null,
|
|
173
|
+
showMinimap: true,
|
|
174
|
+
setZones: (zones) => set({ zones }),
|
|
175
|
+
setHoveredZone: (hoveredZone) => set({ hoveredZone }),
|
|
176
|
+
setShowMinimap: (showMinimap) => set({ showMinimap }),
|
|
177
|
+
};
|
|
178
|
+
});
|
|
179
|
+
|
|
148
180
|
const initialState = {
|
|
149
181
|
payloads: [],
|
|
150
182
|
htmlContent: '',
|
|
@@ -219,16 +251,25 @@ const useRegisterData = (data, dataInfo) => {
|
|
|
219
251
|
}, [dataInfo]);
|
|
220
252
|
};
|
|
221
253
|
|
|
222
|
-
const useRegisterHeatmap = (clickmap) => {
|
|
254
|
+
const useRegisterHeatmap = ({ clickmap, scrollmap }) => {
|
|
223
255
|
const setClickmap = useHeatmapDataStore((state) => state.setClickmap);
|
|
256
|
+
const setScrollmap = useHeatmapDataStore((state) => state.setScrollmap);
|
|
224
257
|
const handleSetClickmap = useCallback((clickmap) => {
|
|
225
258
|
if (!clickmap)
|
|
226
259
|
return;
|
|
227
260
|
setClickmap(clickmap);
|
|
228
261
|
}, [clickmap]);
|
|
262
|
+
const handleSetScrollmap = useCallback((scrollmap) => {
|
|
263
|
+
if (!scrollmap)
|
|
264
|
+
return;
|
|
265
|
+
setScrollmap(scrollmap);
|
|
266
|
+
}, [scrollmap]);
|
|
229
267
|
useEffect(() => {
|
|
230
268
|
handleSetClickmap(clickmap);
|
|
231
269
|
}, [clickmap]);
|
|
270
|
+
useEffect(() => {
|
|
271
|
+
handleSetScrollmap(scrollmap);
|
|
272
|
+
}, [scrollmap]);
|
|
232
273
|
};
|
|
233
274
|
|
|
234
275
|
const PADDING = 0;
|
|
@@ -511,7 +552,300 @@ function isElementInViewport(elementRect, visualRef, scale) {
|
|
|
511
552
|
return elementBottom > viewportTop && elementTop < viewportBottom;
|
|
512
553
|
}
|
|
513
554
|
|
|
514
|
-
class
|
|
555
|
+
class IframeNavigationBlockerV2 {
|
|
556
|
+
doc;
|
|
557
|
+
win;
|
|
558
|
+
isEnabled = false;
|
|
559
|
+
showMessage = false;
|
|
560
|
+
originalWindowOpen;
|
|
561
|
+
observers = [];
|
|
562
|
+
constructor(iframe) {
|
|
563
|
+
if (!iframe.contentDocument || !iframe.contentWindow) {
|
|
564
|
+
throw new Error('Iframe document or window not accessible');
|
|
565
|
+
}
|
|
566
|
+
this.doc = iframe.contentDocument;
|
|
567
|
+
this.win = iframe.contentWindow;
|
|
568
|
+
this.originalWindowOpen = this.win.open.bind(this.win);
|
|
569
|
+
this.init();
|
|
570
|
+
}
|
|
571
|
+
init() {
|
|
572
|
+
console.log('[NavigationBlocker] Initializing...');
|
|
573
|
+
try {
|
|
574
|
+
// Chặn navigation qua links
|
|
575
|
+
this.blockLinkNavigation();
|
|
576
|
+
// Chặn form submissions
|
|
577
|
+
this.blockFormSubmissions();
|
|
578
|
+
// Chặn window.open (này an toàn)
|
|
579
|
+
this.blockWindowOpen();
|
|
580
|
+
// Chặn beforeunload để prevent navigation
|
|
581
|
+
this.blockBeforeUnload();
|
|
582
|
+
// Monitor DOM changes để block dynamic links
|
|
583
|
+
this.monitorDOMChanges();
|
|
584
|
+
// Inject CSP nếu có thể
|
|
585
|
+
this.injectCSP();
|
|
586
|
+
}
|
|
587
|
+
catch (error) {
|
|
588
|
+
console.error('[NavigationBlocker] Init error:', error);
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
blockLinkNavigation() {
|
|
592
|
+
// Sử dụng capture phase để chặn sớm nhất
|
|
593
|
+
this.doc.addEventListener('click', (e) => {
|
|
594
|
+
if (!this.isEnabled)
|
|
595
|
+
return;
|
|
596
|
+
const target = e.target;
|
|
597
|
+
const link = target.closest('a');
|
|
598
|
+
if (link) {
|
|
599
|
+
const href = link.getAttribute('href');
|
|
600
|
+
// Cho phép hash links và empty links
|
|
601
|
+
if (!href || href === '' || href === '#' || href.startsWith('#')) {
|
|
602
|
+
console.log('[NavigationBlocker] Allowed hash navigation:', href);
|
|
603
|
+
return;
|
|
604
|
+
}
|
|
605
|
+
// Chặn tất cả các loại navigation
|
|
606
|
+
console.log('[NavigationBlocker] Blocked link navigation to:', href);
|
|
607
|
+
e.preventDefault();
|
|
608
|
+
e.stopPropagation();
|
|
609
|
+
e.stopImmediatePropagation();
|
|
610
|
+
this.notifyBlockedNavigation(href);
|
|
611
|
+
}
|
|
612
|
+
}, true);
|
|
613
|
+
// Chặn cả middle click và right click "open in new tab"
|
|
614
|
+
this.doc.addEventListener('auxclick', (e) => {
|
|
615
|
+
if (!this.isEnabled)
|
|
616
|
+
return;
|
|
617
|
+
const target = e.target;
|
|
618
|
+
const link = target.closest('a');
|
|
619
|
+
if (link) {
|
|
620
|
+
const href = link.getAttribute('href');
|
|
621
|
+
if (href && !href.startsWith('#')) {
|
|
622
|
+
console.log('[NavigationBlocker] Blocked auxclick navigation');
|
|
623
|
+
e.preventDefault();
|
|
624
|
+
e.stopPropagation();
|
|
625
|
+
e.stopImmediatePropagation();
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
}, true);
|
|
629
|
+
// Disable tất cả links ngay từ đầu
|
|
630
|
+
this.disableAllLinks();
|
|
631
|
+
}
|
|
632
|
+
disableAllLinks() {
|
|
633
|
+
this.doc.querySelectorAll('a[href]').forEach((link) => {
|
|
634
|
+
const href = link.getAttribute('href');
|
|
635
|
+
if (href && !href.startsWith('#')) {
|
|
636
|
+
// Thêm pointer-events: none và cursor
|
|
637
|
+
link.style.cursor = 'not-allowed';
|
|
638
|
+
link.setAttribute('data-navigation-blocked', 'true');
|
|
639
|
+
// Remove href để browser không hiện preview
|
|
640
|
+
link.setAttribute('data-original-href', href);
|
|
641
|
+
link.removeAttribute('href');
|
|
642
|
+
// Hoặc giữ href nhưng disable
|
|
643
|
+
// link.setAttribute('onclick', 'return false');
|
|
644
|
+
}
|
|
645
|
+
});
|
|
646
|
+
}
|
|
647
|
+
blockFormSubmissions() {
|
|
648
|
+
this.doc.addEventListener('submit', (e) => {
|
|
649
|
+
if (!this.isEnabled)
|
|
650
|
+
return;
|
|
651
|
+
const form = e.target;
|
|
652
|
+
const action = form.getAttribute('action');
|
|
653
|
+
// Cho phép forms không có action
|
|
654
|
+
if (!action || action === '' || action === '#') {
|
|
655
|
+
console.log('[NavigationBlocker] Allowed same-page form');
|
|
656
|
+
e.preventDefault();
|
|
657
|
+
this.handleFormSubmit(form);
|
|
658
|
+
return;
|
|
659
|
+
}
|
|
660
|
+
// Chặn tất cả external submissions
|
|
661
|
+
console.log('[NavigationBlocker] Blocked form submission to:', action);
|
|
662
|
+
e.preventDefault();
|
|
663
|
+
e.stopPropagation();
|
|
664
|
+
e.stopImmediatePropagation();
|
|
665
|
+
this.notifyBlockedNavigation(action);
|
|
666
|
+
}, true);
|
|
667
|
+
}
|
|
668
|
+
blockWindowOpen() {
|
|
669
|
+
// Override window.open - đây là safe
|
|
670
|
+
this.win.open = ((...args) => {
|
|
671
|
+
if (!this.isEnabled) {
|
|
672
|
+
return this.originalWindowOpen(...args);
|
|
673
|
+
}
|
|
674
|
+
const url = args[0]?.toString() || 'popup';
|
|
675
|
+
console.log('[NavigationBlocker] Blocked window.open:', url);
|
|
676
|
+
this.notifyBlockedNavigation(url);
|
|
677
|
+
return null;
|
|
678
|
+
});
|
|
679
|
+
}
|
|
680
|
+
blockBeforeUnload() {
|
|
681
|
+
// Chặn unload
|
|
682
|
+
this.win.addEventListener('beforeunload', (e) => {
|
|
683
|
+
if (!this.isEnabled)
|
|
684
|
+
return;
|
|
685
|
+
console.log('[NavigationBlocker] Blocked beforeunload');
|
|
686
|
+
e.preventDefault();
|
|
687
|
+
e.returnValue = '';
|
|
688
|
+
return '';
|
|
689
|
+
}, true);
|
|
690
|
+
// Chặn unload
|
|
691
|
+
this.win.addEventListener('unload', (e) => {
|
|
692
|
+
if (!this.isEnabled)
|
|
693
|
+
return;
|
|
694
|
+
console.log('[NavigationBlocker] Blocked unload');
|
|
695
|
+
e.preventDefault();
|
|
696
|
+
e.stopPropagation();
|
|
697
|
+
}, true);
|
|
698
|
+
// Monitor popstate
|
|
699
|
+
this.win.addEventListener('popstate', (e) => {
|
|
700
|
+
if (!this.isEnabled)
|
|
701
|
+
return;
|
|
702
|
+
console.log('[NavigationBlocker] Blocked popstate');
|
|
703
|
+
e.preventDefault();
|
|
704
|
+
e.stopPropagation();
|
|
705
|
+
}, true);
|
|
706
|
+
}
|
|
707
|
+
monitorDOMChanges() {
|
|
708
|
+
// Monitor khi có links mới được thêm vào
|
|
709
|
+
const observer = new MutationObserver((mutations) => {
|
|
710
|
+
if (!this.isEnabled)
|
|
711
|
+
return;
|
|
712
|
+
mutations.forEach((mutation) => {
|
|
713
|
+
mutation.addedNodes.forEach((node) => {
|
|
714
|
+
if (node.nodeType === Node.ELEMENT_NODE) {
|
|
715
|
+
const element = node;
|
|
716
|
+
// Nếu là link
|
|
717
|
+
if (element.tagName === 'A') {
|
|
718
|
+
const href = element.getAttribute('href');
|
|
719
|
+
if (href && !href.startsWith('#')) {
|
|
720
|
+
element.style.cursor = 'not-allowed';
|
|
721
|
+
element.setAttribute('data-navigation-blocked', 'true');
|
|
722
|
+
element.setAttribute('data-original-href', href);
|
|
723
|
+
element.removeAttribute('href');
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
// Tìm links trong subtree
|
|
727
|
+
element.querySelectorAll('a[href]').forEach((link) => {
|
|
728
|
+
const href = link.getAttribute('href');
|
|
729
|
+
if (href && !href.startsWith('#')) {
|
|
730
|
+
link.style.cursor = 'not-allowed';
|
|
731
|
+
link.setAttribute('data-navigation-blocked', 'true');
|
|
732
|
+
link.setAttribute('data-original-href', href);
|
|
733
|
+
link.removeAttribute('href');
|
|
734
|
+
}
|
|
735
|
+
});
|
|
736
|
+
}
|
|
737
|
+
});
|
|
738
|
+
});
|
|
739
|
+
});
|
|
740
|
+
observer.observe(this.doc.body, {
|
|
741
|
+
childList: true,
|
|
742
|
+
subtree: true,
|
|
743
|
+
});
|
|
744
|
+
this.observers.push(observer);
|
|
745
|
+
}
|
|
746
|
+
injectCSP() {
|
|
747
|
+
// Thêm CSP meta tag nếu chưa có (optional)
|
|
748
|
+
try {
|
|
749
|
+
const existingCSP = this.doc.querySelector('meta[http-equiv="Content-Security-Policy"]');
|
|
750
|
+
if (!existingCSP) {
|
|
751
|
+
const meta = this.doc.createElement('meta');
|
|
752
|
+
meta.httpEquiv = 'Content-Security-Policy';
|
|
753
|
+
meta.content = "navigate-to 'none'"; // Chặn tất cả navigation
|
|
754
|
+
this.doc.head.appendChild(meta);
|
|
755
|
+
console.log('[NavigationBlocker] Injected CSP');
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
catch (error) {
|
|
759
|
+
console.warn('[NavigationBlocker] Could not inject CSP:', error);
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
handleFormSubmit(form) {
|
|
763
|
+
const formData = new FormData(form);
|
|
764
|
+
const data = {};
|
|
765
|
+
formData.forEach((value, key) => {
|
|
766
|
+
data[key] = value;
|
|
767
|
+
});
|
|
768
|
+
console.log('[NavigationBlocker] Handling form data:', data);
|
|
769
|
+
window.dispatchEvent(new CustomEvent('iframe-form-submit', {
|
|
770
|
+
detail: { form, data },
|
|
771
|
+
}));
|
|
772
|
+
}
|
|
773
|
+
notifyBlockedNavigation(url) {
|
|
774
|
+
console.warn('[NavigationBlocker] Navigation blocked to:', url);
|
|
775
|
+
window.dispatchEvent(new CustomEvent('iframe-navigation-blocked', {
|
|
776
|
+
detail: { url, timestamp: Date.now() },
|
|
777
|
+
}));
|
|
778
|
+
if (this.shouldShowMessage(url)) {
|
|
779
|
+
this.showBlockedMessage(url);
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
shouldShowMessage(url) {
|
|
783
|
+
return !url.startsWith('#') && url !== 'reload' && url !== 'popup';
|
|
784
|
+
}
|
|
785
|
+
showBlockedMessage(url) {
|
|
786
|
+
if (!this.showMessage)
|
|
787
|
+
return;
|
|
788
|
+
const message = this.doc.createElement('div');
|
|
789
|
+
message.style.cssText = `
|
|
790
|
+
position: fixed;
|
|
791
|
+
top: 20px;
|
|
792
|
+
right: 20px;
|
|
793
|
+
background: #ff6b6b;
|
|
794
|
+
color: white;
|
|
795
|
+
padding: 12px 20px;
|
|
796
|
+
border-radius: 8px;
|
|
797
|
+
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
|
|
798
|
+
z-index: 999999;
|
|
799
|
+
font-family: system-ui, -apple-system, sans-serif;
|
|
800
|
+
font-size: 14px;
|
|
801
|
+
max-width: 300px;
|
|
802
|
+
word-break: break-word;
|
|
803
|
+
pointer-events: none;
|
|
804
|
+
`;
|
|
805
|
+
const shortUrl = url.length > 50 ? url.substring(0, 47) + '...' : url;
|
|
806
|
+
message.innerHTML = `
|
|
807
|
+
<div style="font-weight: 600; margin-bottom: 4px;">🚫 Navigation Blocked</div>
|
|
808
|
+
<div style="font-size: 12px; opacity: 0.9;">${this.escapeHtml(shortUrl)}</div>
|
|
809
|
+
`;
|
|
810
|
+
this.doc.body.appendChild(message);
|
|
811
|
+
setTimeout(() => {
|
|
812
|
+
message.style.opacity = '0';
|
|
813
|
+
message.style.transition = 'opacity 0.3s';
|
|
814
|
+
setTimeout(() => message.remove(), 300);
|
|
815
|
+
}, 3000);
|
|
816
|
+
}
|
|
817
|
+
escapeHtml(text) {
|
|
818
|
+
const div = this.doc.createElement('div');
|
|
819
|
+
div.textContent = text;
|
|
820
|
+
return div.innerHTML;
|
|
821
|
+
}
|
|
822
|
+
enable() {
|
|
823
|
+
this.isEnabled = true;
|
|
824
|
+
console.log('[NavigationBlocker] Enabled');
|
|
825
|
+
}
|
|
826
|
+
enableMessage() {
|
|
827
|
+
this.showMessage = true;
|
|
828
|
+
console.log('[NavigationBlocker] Enabled message');
|
|
829
|
+
}
|
|
830
|
+
disable() {
|
|
831
|
+
this.isEnabled = false;
|
|
832
|
+
console.log('[NavigationBlocker] Disabled');
|
|
833
|
+
}
|
|
834
|
+
disableMessage() {
|
|
835
|
+
this.showMessage = false;
|
|
836
|
+
console.log('[NavigationBlocker] Disabled message');
|
|
837
|
+
}
|
|
838
|
+
destroy() {
|
|
839
|
+
this.isEnabled = false;
|
|
840
|
+
this.showMessage = false;
|
|
841
|
+
// Cleanup observers
|
|
842
|
+
this.observers.forEach((observer) => observer.disconnect());
|
|
843
|
+
this.observers = [];
|
|
844
|
+
console.log('[NavigationBlocker] Destroyed');
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
class IframeStyleReplacer {
|
|
515
849
|
doc;
|
|
516
850
|
win;
|
|
517
851
|
config;
|
|
@@ -556,7 +890,7 @@ class ViewportUnitsReplacer {
|
|
|
556
890
|
count++;
|
|
557
891
|
}
|
|
558
892
|
});
|
|
559
|
-
console.log(`[
|
|
893
|
+
console.log(`[IframeStyleReplacer] Replaced ${count} inline style elements`);
|
|
560
894
|
return count;
|
|
561
895
|
}
|
|
562
896
|
processStyleTags() {
|
|
@@ -569,7 +903,7 @@ class ViewportUnitsReplacer {
|
|
|
569
903
|
count++;
|
|
570
904
|
}
|
|
571
905
|
});
|
|
572
|
-
console.log(`[
|
|
906
|
+
console.log(`[IframeStyleReplacer] Replaced ${count} <style> tags`);
|
|
573
907
|
return count;
|
|
574
908
|
}
|
|
575
909
|
processRule(rule) {
|
|
@@ -600,7 +934,7 @@ class ViewportUnitsReplacer {
|
|
|
600
934
|
try {
|
|
601
935
|
// Bỏ qua external CSS (cross-origin)
|
|
602
936
|
if (sheet.href && !sheet.href.startsWith(this.win.location.origin)) {
|
|
603
|
-
console.log('[
|
|
937
|
+
console.log('[IframeStyleReplacer] Skipping external CSS:', sheet.href);
|
|
604
938
|
return;
|
|
605
939
|
}
|
|
606
940
|
const rules = sheet.cssRules || sheet.rules;
|
|
@@ -611,10 +945,10 @@ class ViewportUnitsReplacer {
|
|
|
611
945
|
}
|
|
612
946
|
}
|
|
613
947
|
catch (e) {
|
|
614
|
-
console.warn('[
|
|
948
|
+
console.warn('[IframeStyleReplacer] Cannot read stylesheet (CORS?):', e.message);
|
|
615
949
|
}
|
|
616
950
|
});
|
|
617
|
-
console.log(`[
|
|
951
|
+
console.log(`[IframeStyleReplacer] Replaced ${total} rules in stylesheets`);
|
|
618
952
|
return total;
|
|
619
953
|
}
|
|
620
954
|
async processLinkedStylesheets() {
|
|
@@ -622,7 +956,7 @@ class ViewportUnitsReplacer {
|
|
|
622
956
|
let count = 0;
|
|
623
957
|
for (const link of Array.from(links)) {
|
|
624
958
|
if (!link.href.startsWith(this.win.location.origin)) {
|
|
625
|
-
console.log('[
|
|
959
|
+
console.log('[IframeStyleReplacer] Skipping external CSS:', link.href);
|
|
626
960
|
continue;
|
|
627
961
|
}
|
|
628
962
|
try {
|
|
@@ -640,10 +974,10 @@ class ViewportUnitsReplacer {
|
|
|
640
974
|
}
|
|
641
975
|
}
|
|
642
976
|
catch (e) {
|
|
643
|
-
console.warn('[
|
|
977
|
+
console.warn('[IframeStyleReplacer] Cannot load CSS:', link.href, e);
|
|
644
978
|
}
|
|
645
979
|
}
|
|
646
|
-
console.log(`[
|
|
980
|
+
console.log(`[IframeStyleReplacer] Replaced ${count} linked CSS files`);
|
|
647
981
|
return count;
|
|
648
982
|
}
|
|
649
983
|
getFinalHeight() {
|
|
@@ -667,7 +1001,7 @@ class ViewportUnitsReplacer {
|
|
|
667
1001
|
}
|
|
668
1002
|
async run() {
|
|
669
1003
|
try {
|
|
670
|
-
console.log('[
|
|
1004
|
+
console.log('[IframeStyleReplacer] Starting viewport units replacement...');
|
|
671
1005
|
this.processInlineStyles();
|
|
672
1006
|
this.processStyleTags();
|
|
673
1007
|
this.processStylesheets();
|
|
@@ -677,13 +1011,13 @@ class ViewportUnitsReplacer {
|
|
|
677
1011
|
requestAnimationFrame(() => {
|
|
678
1012
|
const height = this.getFinalHeight();
|
|
679
1013
|
const width = this.getFinalWidth();
|
|
680
|
-
console.log('[
|
|
1014
|
+
console.log('[IframeStyleReplacer] Calculated dimensions:', { height, width });
|
|
681
1015
|
resolve({ height, width });
|
|
682
1016
|
});
|
|
683
1017
|
});
|
|
684
1018
|
}
|
|
685
1019
|
catch (err) {
|
|
686
|
-
console.error('[
|
|
1020
|
+
console.error('[IframeStyleReplacer] Critical error:', err);
|
|
687
1021
|
return {
|
|
688
1022
|
height: this.doc.body.scrollHeight || 1000,
|
|
689
1023
|
width: this.doc.body.scrollWidth || 1000,
|
|
@@ -695,10 +1029,11 @@ class ViewportUnitsReplacer {
|
|
|
695
1029
|
}
|
|
696
1030
|
}
|
|
697
1031
|
|
|
698
|
-
class
|
|
1032
|
+
class IframeHelperFixer {
|
|
699
1033
|
iframe;
|
|
700
1034
|
config;
|
|
701
1035
|
replacer = null;
|
|
1036
|
+
navigationBlocker = null;
|
|
702
1037
|
constructor(config) {
|
|
703
1038
|
this.config = config;
|
|
704
1039
|
this.iframe = config.iframe;
|
|
@@ -706,10 +1041,11 @@ class ViewportUnitsFixer {
|
|
|
706
1041
|
}
|
|
707
1042
|
async init() {
|
|
708
1043
|
if (!this.iframe) {
|
|
709
|
-
console.error('[
|
|
1044
|
+
console.error('[IframeHelper] iframe not found');
|
|
710
1045
|
this.config.onError?.(new Error('iframe not found'));
|
|
711
1046
|
return;
|
|
712
1047
|
}
|
|
1048
|
+
// Wait for iframe to load completely
|
|
713
1049
|
if (this.iframe.contentDocument?.readyState === 'complete') {
|
|
714
1050
|
await this.process();
|
|
715
1051
|
}
|
|
@@ -719,17 +1055,19 @@ class ViewportUnitsFixer {
|
|
|
719
1055
|
}
|
|
720
1056
|
async process() {
|
|
721
1057
|
if (!this.iframe.contentDocument || !this.iframe.contentWindow) {
|
|
722
|
-
console.error('[
|
|
1058
|
+
console.error('[IframeHelper] Cannot access iframe document');
|
|
723
1059
|
this.config.onError?.(new Error('Cannot access iframe document'));
|
|
724
1060
|
return;
|
|
725
1061
|
}
|
|
726
1062
|
try {
|
|
727
|
-
console.log('[
|
|
728
|
-
//
|
|
729
|
-
this.replacer = new
|
|
730
|
-
//
|
|
1063
|
+
console.log('[IframeHelper] Processing viewport units...');
|
|
1064
|
+
// Create replacer instance
|
|
1065
|
+
this.replacer = new IframeStyleReplacer(this.iframe, this.config);
|
|
1066
|
+
// Create navigation blocker
|
|
1067
|
+
this.navigationBlocker = new IframeNavigationBlockerV2(this.iframe);
|
|
1068
|
+
// Run replacement
|
|
731
1069
|
const result = await this.replacer.run();
|
|
732
|
-
console.log('[
|
|
1070
|
+
console.log('[IframeHelper] Process completed:', result);
|
|
733
1071
|
// Trigger success callback
|
|
734
1072
|
this.config.onSuccess?.(result);
|
|
735
1073
|
// Dispatch custom event
|
|
@@ -738,12 +1076,12 @@ class ViewportUnitsFixer {
|
|
|
738
1076
|
}));
|
|
739
1077
|
}
|
|
740
1078
|
catch (error) {
|
|
741
|
-
console.error('[
|
|
1079
|
+
console.error('[IframeHelper] Failed to process:', error);
|
|
742
1080
|
this.config.onError?.(error);
|
|
743
1081
|
}
|
|
744
1082
|
}
|
|
745
1083
|
async recalculate() {
|
|
746
|
-
console.log('[
|
|
1084
|
+
console.log('[IframeHelper] Recalculating...');
|
|
747
1085
|
await this.process();
|
|
748
1086
|
}
|
|
749
1087
|
updateConfig(config) {
|
|
@@ -752,16 +1090,39 @@ class ViewportUnitsFixer {
|
|
|
752
1090
|
this.replacer.updateConfig(config);
|
|
753
1091
|
}
|
|
754
1092
|
}
|
|
1093
|
+
enableNavigationBlocking() {
|
|
1094
|
+
this.navigationBlocker?.enable();
|
|
1095
|
+
}
|
|
1096
|
+
enableNavigationBlockingMessage() {
|
|
1097
|
+
this.navigationBlocker?.enableMessage();
|
|
1098
|
+
}
|
|
1099
|
+
disableNavigationBlocking() {
|
|
1100
|
+
this.navigationBlocker?.disable();
|
|
1101
|
+
}
|
|
1102
|
+
disableNavigationBlockingMessage() {
|
|
1103
|
+
this.navigationBlocker?.disableMessage();
|
|
1104
|
+
}
|
|
755
1105
|
destroy() {
|
|
756
1106
|
this.replacer = null;
|
|
757
|
-
|
|
1107
|
+
this.navigationBlocker?.destroy();
|
|
1108
|
+
this.navigationBlocker = null;
|
|
1109
|
+
console.log('[IframeHelper] Destroyed');
|
|
758
1110
|
}
|
|
759
1111
|
}
|
|
760
|
-
|
|
761
|
-
|
|
1112
|
+
|
|
1113
|
+
function initIframeHelperFixer(config) {
|
|
1114
|
+
const fixer = new IframeHelperFixer(config);
|
|
762
1115
|
window.addEventListener('iframe-dimensions-applied', ((e) => {
|
|
763
1116
|
const ev = e;
|
|
764
|
-
console.log('[
|
|
1117
|
+
console.log('[IframeHelper] Iframe dimensions finalized:', ev.detail);
|
|
1118
|
+
}));
|
|
1119
|
+
window.addEventListener('iframe-navigation-blocked', ((e) => {
|
|
1120
|
+
const ev = e;
|
|
1121
|
+
console.warn('[IframeHelper] Iframe tried to navigate to:', ev.detail.url);
|
|
1122
|
+
}));
|
|
1123
|
+
window.addEventListener('iframe-form-submit', ((e) => {
|
|
1124
|
+
const ev = e;
|
|
1125
|
+
console.log('[IframeHelper] Iframe form submitted:', ev.detail.data);
|
|
765
1126
|
}));
|
|
766
1127
|
return fixer;
|
|
767
1128
|
}
|
|
@@ -926,8 +1287,6 @@ const debounce = (fn, delay) => {
|
|
|
926
1287
|
};
|
|
927
1288
|
};
|
|
928
1289
|
|
|
929
|
-
// ===================== CONSTANTS =====================
|
|
930
|
-
const HEATMAP_ELEMENT_ATTRIBUTE = 'data-clarity-hashalpha'; // Hoặc attribute bạn đang dùng
|
|
931
1290
|
// ===================== UTILITY FUNCTIONS =====================
|
|
932
1291
|
/**
|
|
933
1292
|
* Lấy bounding box tuyệt đối của element (relative to document)
|
|
@@ -970,74 +1329,6 @@ function getElementsAtPoint(documentOrShadowRoot, x, y, filterFunction, visitedS
|
|
|
970
1329
|
}
|
|
971
1330
|
return elementsAtPoint;
|
|
972
1331
|
}
|
|
973
|
-
// ===================== MAIN HOOK =====================
|
|
974
|
-
function useHeatmapMouseHandler(props) {
|
|
975
|
-
const { heatmapWrapperRef, iframeRef, parentRef, heatmapInfo, scaleRatio, onElementHover } = props;
|
|
976
|
-
const handleMouseMove = useCallback((event) => {
|
|
977
|
-
// Kiểm tra tất cả refs và data cần thiết
|
|
978
|
-
if (!heatmapWrapperRef?.current ||
|
|
979
|
-
!iframeRef?.current ||
|
|
980
|
-
!iframeRef.current.contentDocument ||
|
|
981
|
-
!heatmapInfo?.elementMapInfo ||
|
|
982
|
-
!parentRef?.current) {
|
|
983
|
-
return;
|
|
984
|
-
}
|
|
985
|
-
try {
|
|
986
|
-
// Tính toán scroll position (đã scale)
|
|
987
|
-
const scrollTop = parentRef.current.scrollTop / scaleRatio;
|
|
988
|
-
console.log(`🚀 🐥 ~ useHeatmapMouseHandler ~ scrollTop:`, scrollTop);
|
|
989
|
-
// Lấy vị trí của heatmap wrapper
|
|
990
|
-
const wrapperRect = heatmapWrapperRef.current.getBoundingClientRect();
|
|
991
|
-
// Tính toán tọa độ chuột trong iframe (đã scale)
|
|
992
|
-
const mouseX = (event.clientX - wrapperRect.left) / scaleRatio;
|
|
993
|
-
const mouseY = (event.clientY - wrapperRect.top) / scaleRatio - scrollTop;
|
|
994
|
-
// Tìm elements tại vị trí chuột
|
|
995
|
-
const elementsAtPoint = getElementsAtPoint(iframeRef.current.contentDocument, Math.round(mouseX), Math.round(mouseY),
|
|
996
|
-
// Filter: chỉ lấy elements có heatmap attribute
|
|
997
|
-
(element) => element.hasAttribute(HEATMAP_ELEMENT_ATTRIBUTE));
|
|
998
|
-
if (!elementsAtPoint || elementsAtPoint.length === 0) {
|
|
999
|
-
return;
|
|
1000
|
-
}
|
|
1001
|
-
// Duyệt qua các elements tìm được
|
|
1002
|
-
for (let i = 0; i < elementsAtPoint.length; i++) {
|
|
1003
|
-
const element = elementsAtPoint[i];
|
|
1004
|
-
// Lấy hash/id của element
|
|
1005
|
-
const elementHash = element.getAttribute(HEATMAP_ELEMENT_ATTRIBUTE);
|
|
1006
|
-
// Kiểm tra element có data trong heatmapInfo không
|
|
1007
|
-
if (elementHash && heatmapInfo.elementMapInfo[elementHash]) {
|
|
1008
|
-
const elementData = heatmapInfo.elementMapInfo[elementHash];
|
|
1009
|
-
// Lấy bounding box của element
|
|
1010
|
-
const boundingBox = getBoundingBox(element);
|
|
1011
|
-
if (boundingBox) {
|
|
1012
|
-
// Tính rank của element
|
|
1013
|
-
const rank = Array.isArray(heatmapInfo.sortedElements) && elementData
|
|
1014
|
-
? heatmapInfo.sortedElements.indexOf(elementData) + 1
|
|
1015
|
-
: NaN;
|
|
1016
|
-
// Callback với thông tin element
|
|
1017
|
-
onElementHover({
|
|
1018
|
-
...boundingBox,
|
|
1019
|
-
// Giới hạn width không vượt quá width của heatmap
|
|
1020
|
-
width: Math.min(boundingBox.width, heatmapInfo.width || 0),
|
|
1021
|
-
// Adjust top position với scroll
|
|
1022
|
-
top: boundingBox.top + scrollTop,
|
|
1023
|
-
// Metadata
|
|
1024
|
-
hash: elementHash,
|
|
1025
|
-
clicks: elementData.totalclicks,
|
|
1026
|
-
rank: rank,
|
|
1027
|
-
selector: elementData.selector || '',
|
|
1028
|
-
});
|
|
1029
|
-
// Dừng loop khi tìm thấy element hợp lệ đầu tiên
|
|
1030
|
-
break;
|
|
1031
|
-
}
|
|
1032
|
-
}
|
|
1033
|
-
}
|
|
1034
|
-
}
|
|
1035
|
-
catch (error) {
|
|
1036
|
-
console.warn('Error handling mouse move on heatmap:', error);
|
|
1037
|
-
}
|
|
1038
|
-
}, [heatmapWrapperRef, iframeRef, parentRef, heatmapInfo, scaleRatio, onElementHover]);
|
|
1039
|
-
return { handleMouseMove };
|
|
1040
|
-
}
|
|
1041
1332
|
// ===================== EXAMPLE USAGE =====================
|
|
1042
1333
|
/*
|
|
1043
1334
|
import { useRef, useState } from 'react';
|
|
@@ -1291,7 +1582,7 @@ function useVizLiveRender() {
|
|
|
1291
1582
|
if (!iframe || !htmlContent)
|
|
1292
1583
|
return;
|
|
1293
1584
|
setIsRenderViz(false);
|
|
1294
|
-
reset
|
|
1585
|
+
reset(iframe, { width: contentWidth, height: wrapperHeight }, (height) => {
|
|
1295
1586
|
height && setIframeHeight(height);
|
|
1296
1587
|
setIsRenderViz(true);
|
|
1297
1588
|
});
|
|
@@ -1300,8 +1591,8 @@ function useVizLiveRender() {
|
|
|
1300
1591
|
iframeRef,
|
|
1301
1592
|
};
|
|
1302
1593
|
}
|
|
1303
|
-
function reset
|
|
1304
|
-
const
|
|
1594
|
+
function reset(iframe, rect, onSuccess) {
|
|
1595
|
+
const fixer = initIframeHelperFixer({
|
|
1305
1596
|
targetWidth: rect.width,
|
|
1306
1597
|
targetHeight: rect.height,
|
|
1307
1598
|
iframe: iframe,
|
|
@@ -1310,8 +1601,8 @@ function reset$1(iframe, rect, onSuccess) {
|
|
|
1310
1601
|
onSuccess(data.height);
|
|
1311
1602
|
},
|
|
1312
1603
|
});
|
|
1313
|
-
|
|
1314
|
-
|
|
1604
|
+
// fixer.recalculate();
|
|
1605
|
+
fixer.enableNavigationBlocking();
|
|
1315
1606
|
}
|
|
1316
1607
|
|
|
1317
1608
|
let visualizer = new Visualizer();
|
|
@@ -1329,7 +1620,7 @@ const useHeatmapRender = () => {
|
|
|
1329
1620
|
if (!iframe?.contentWindow)
|
|
1330
1621
|
return;
|
|
1331
1622
|
await visualizer.html(payloads, iframe.contentWindow);
|
|
1332
|
-
|
|
1623
|
+
initIframe(iframe, payloads, (height) => {
|
|
1333
1624
|
height && setIframeHeight(height);
|
|
1334
1625
|
setIsRenderViz(true);
|
|
1335
1626
|
setVizRef(visualizer);
|
|
@@ -1347,11 +1638,11 @@ const useHeatmapRender = () => {
|
|
|
1347
1638
|
iframeRef,
|
|
1348
1639
|
};
|
|
1349
1640
|
};
|
|
1350
|
-
function
|
|
1641
|
+
function initIframe(iframe, payloads, onSuccess) {
|
|
1351
1642
|
const { size } = findLastSizeOfDom(payloads);
|
|
1352
1643
|
const docWidth = size.width ?? 0;
|
|
1353
1644
|
const docHeight = size.height ?? 0;
|
|
1354
|
-
|
|
1645
|
+
initIframeHelperFixer({
|
|
1355
1646
|
targetWidth: docWidth,
|
|
1356
1647
|
targetHeight: docHeight,
|
|
1357
1648
|
iframe: iframe,
|
|
@@ -1360,8 +1651,7 @@ function reset(iframe, payloads, onSuccess) {
|
|
|
1360
1651
|
onSuccess(data.height);
|
|
1361
1652
|
},
|
|
1362
1653
|
});
|
|
1363
|
-
|
|
1364
|
-
return iframe;
|
|
1654
|
+
// fixer.recalculate();
|
|
1365
1655
|
}
|
|
1366
1656
|
|
|
1367
1657
|
function isMobileDevice(userAgent) {
|
|
@@ -1799,6 +2089,135 @@ const useWrapperRefHeight = (props) => {
|
|
|
1799
2089
|
return {};
|
|
1800
2090
|
};
|
|
1801
2091
|
|
|
2092
|
+
const useZonePositions = (options) => {
|
|
2093
|
+
const iframeHeight = useHeatmapSingleStore((state) => state.iframeHeight);
|
|
2094
|
+
const getZonePosition = useCallback((zone) => {
|
|
2095
|
+
if (!iframeHeight) {
|
|
2096
|
+
return null;
|
|
2097
|
+
}
|
|
2098
|
+
const startYPx = (zone.startY / 100) * iframeHeight;
|
|
2099
|
+
const heightPx = ((zone.endY - zone.startY) / 100) * iframeHeight;
|
|
2100
|
+
return {
|
|
2101
|
+
top: startYPx,
|
|
2102
|
+
height: heightPx,
|
|
2103
|
+
};
|
|
2104
|
+
}, [iframeHeight]);
|
|
2105
|
+
return {
|
|
2106
|
+
getZonePosition,
|
|
2107
|
+
};
|
|
2108
|
+
};
|
|
2109
|
+
|
|
2110
|
+
const SCROLL_GRADIENT_COLORS = [
|
|
2111
|
+
[255, 0, 0], // Red
|
|
2112
|
+
[255, 255, 0], // Yellow
|
|
2113
|
+
[0, 255, 0], // Green
|
|
2114
|
+
];
|
|
2115
|
+
const useScrollmapZones = (options) => {
|
|
2116
|
+
const { mode = 'basic', enabled = true, iframeRef, wrapperRef } = options;
|
|
2117
|
+
const [isReady, setIsReady] = useState(false);
|
|
2118
|
+
const [zones, setZones] = useState([]);
|
|
2119
|
+
const scrollmap = useHeatmapDataStore((state) => state.scrollmap);
|
|
2120
|
+
const scrollMapInfo = useHeatmapDataStore((state) => state.dataInfo?.scrollMapInfo);
|
|
2121
|
+
const { getZonePosition } = useZonePositions();
|
|
2122
|
+
const maxUsers = useMemo(() => {
|
|
2123
|
+
if (!scrollmap || scrollmap.length === 0)
|
|
2124
|
+
return 100;
|
|
2125
|
+
return Math.max(...scrollmap.map((d) => d.percUsers));
|
|
2126
|
+
}, [scrollmap]);
|
|
2127
|
+
const createZones = useCallback((data) => {
|
|
2128
|
+
if (mode === 'basic') {
|
|
2129
|
+
const breakpoints = [0, 25, 50, 75, 100];
|
|
2130
|
+
const zones = [];
|
|
2131
|
+
for (let i = 0; i < breakpoints.length - 1; i++) {
|
|
2132
|
+
const startY = breakpoints[i];
|
|
2133
|
+
const endY = breakpoints[i + 1];
|
|
2134
|
+
const pointsInRange = data.filter((d) => d.scrollReachY >= startY && d.scrollReachY < endY);
|
|
2135
|
+
const avgUsers = pointsInRange.length > 0
|
|
2136
|
+
? pointsInRange.reduce((sum, p) => sum + p.percUsers, 0) / pointsInRange.length
|
|
2137
|
+
: 0;
|
|
2138
|
+
zones.push({
|
|
2139
|
+
id: `zone_${startY}_${endY}`,
|
|
2140
|
+
startY,
|
|
2141
|
+
endY,
|
|
2142
|
+
percUsers: avgUsers,
|
|
2143
|
+
label: `${startY}% - ${endY}%`,
|
|
2144
|
+
});
|
|
2145
|
+
}
|
|
2146
|
+
return zones;
|
|
2147
|
+
}
|
|
2148
|
+
else {
|
|
2149
|
+
// Metrics mode: 20 zones (5% intervals)
|
|
2150
|
+
const zones = [];
|
|
2151
|
+
const interval = 5;
|
|
2152
|
+
// Prepare metrics map
|
|
2153
|
+
let metricsMap;
|
|
2154
|
+
if (scrollMapInfo && Object.keys(scrollMapInfo).length > 0) {
|
|
2155
|
+
metricsMap = new Map();
|
|
2156
|
+
Object.entries(scrollMapInfo).forEach(([key, value]) => {
|
|
2157
|
+
metricsMap.set(Number(key), value);
|
|
2158
|
+
});
|
|
2159
|
+
}
|
|
2160
|
+
for (let i = 0; i < 100; i += interval) {
|
|
2161
|
+
const startY = i;
|
|
2162
|
+
const endY = i + interval;
|
|
2163
|
+
const point = data.find((d) => d.scrollReachY === startY) || {
|
|
2164
|
+
scrollReachY: startY,
|
|
2165
|
+
cumulativeSum: 0,
|
|
2166
|
+
percUsers: 0,
|
|
2167
|
+
};
|
|
2168
|
+
const metrics = metricsMap?.get(startY);
|
|
2169
|
+
zones.push({
|
|
2170
|
+
id: `zone_${startY}_${endY}`,
|
|
2171
|
+
startY,
|
|
2172
|
+
endY,
|
|
2173
|
+
percUsers: point.percUsers,
|
|
2174
|
+
metrics,
|
|
2175
|
+
label: `${startY}% - ${endY}%`,
|
|
2176
|
+
});
|
|
2177
|
+
}
|
|
2178
|
+
return zones;
|
|
2179
|
+
}
|
|
2180
|
+
}, [mode, scrollMapInfo]);
|
|
2181
|
+
/**
|
|
2182
|
+
* Initialize zones
|
|
2183
|
+
*/
|
|
2184
|
+
useEffect(() => {
|
|
2185
|
+
if (!enabled || !scrollmap || scrollmap.length === 0) {
|
|
2186
|
+
setIsReady(false);
|
|
2187
|
+
return;
|
|
2188
|
+
}
|
|
2189
|
+
try {
|
|
2190
|
+
const newZones = createZones(scrollmap);
|
|
2191
|
+
setZones(newZones);
|
|
2192
|
+
setIsReady(true);
|
|
2193
|
+
console.log(`[useScrollmap] Created ${newZones.length} zones in ${mode} mode`);
|
|
2194
|
+
}
|
|
2195
|
+
catch (error) {
|
|
2196
|
+
console.error('[useScrollmap] Error:', error);
|
|
2197
|
+
setIsReady(false);
|
|
2198
|
+
}
|
|
2199
|
+
}, [enabled, scrollmap, mode, createZones]);
|
|
2200
|
+
return {
|
|
2201
|
+
zones,
|
|
2202
|
+
isReady,
|
|
2203
|
+
maxUsers,
|
|
2204
|
+
getZonePosition,
|
|
2205
|
+
};
|
|
2206
|
+
};
|
|
2207
|
+
/**
|
|
2208
|
+
* Get scroll gradient color for minimap
|
|
2209
|
+
*/
|
|
2210
|
+
const getScrollGradientColor = (normalized) => {
|
|
2211
|
+
const idx = Math.min(Math.floor(normalized * 2), 1);
|
|
2212
|
+
const [r1, g1, b1] = SCROLL_GRADIENT_COLORS[idx];
|
|
2213
|
+
const [r2, g2, b2] = SCROLL_GRADIENT_COLORS[idx + 1];
|
|
2214
|
+
const localPercent = (normalized * 2) % 1;
|
|
2215
|
+
const r = Math.round(r1 + (r2 - r1) * localPercent);
|
|
2216
|
+
const g = Math.round(g1 + (g2 - g1) * localPercent);
|
|
2217
|
+
const b = Math.round(b1 + (b2 - b1) * localPercent);
|
|
2218
|
+
return `rgb(${r}, ${g}, ${b})`;
|
|
2219
|
+
};
|
|
2220
|
+
|
|
1802
2221
|
const BoxStack = forwardRef(({ children, ...props }, ref) => {
|
|
1803
2222
|
const id = props.id;
|
|
1804
2223
|
const flexDirection = props.flexDirection;
|
|
@@ -1903,113 +2322,11 @@ const useClickmap = () => {
|
|
|
1903
2322
|
return { start };
|
|
1904
2323
|
};
|
|
1905
2324
|
|
|
1906
|
-
const DATA_SCROLLMAP = [
|
|
1907
|
-
{
|
|
1908
|
-
scrollReachY: 5,
|
|
1909
|
-
cumulativeSum: 0,
|
|
1910
|
-
percUsers: 0,
|
|
1911
|
-
},
|
|
1912
|
-
{
|
|
1913
|
-
scrollReachY: 10,
|
|
1914
|
-
cumulativeSum: 0,
|
|
1915
|
-
percUsers: 0,
|
|
1916
|
-
},
|
|
1917
|
-
{
|
|
1918
|
-
scrollReachY: 15,
|
|
1919
|
-
cumulativeSum: 0,
|
|
1920
|
-
percUsers: 0,
|
|
1921
|
-
},
|
|
1922
|
-
{
|
|
1923
|
-
scrollReachY: 20,
|
|
1924
|
-
cumulativeSum: 0,
|
|
1925
|
-
percUsers: 0,
|
|
1926
|
-
},
|
|
1927
|
-
{
|
|
1928
|
-
scrollReachY: 25,
|
|
1929
|
-
cumulativeSum: 0,
|
|
1930
|
-
percUsers: 0,
|
|
1931
|
-
},
|
|
1932
|
-
{
|
|
1933
|
-
scrollReachY: 30,
|
|
1934
|
-
cumulativeSum: 0,
|
|
1935
|
-
percUsers: 0,
|
|
1936
|
-
},
|
|
1937
|
-
{
|
|
1938
|
-
scrollReachY: 35,
|
|
1939
|
-
cumulativeSum: 0,
|
|
1940
|
-
percUsers: 0,
|
|
1941
|
-
},
|
|
1942
|
-
{
|
|
1943
|
-
scrollReachY: 40,
|
|
1944
|
-
cumulativeSum: 0,
|
|
1945
|
-
percUsers: 0,
|
|
1946
|
-
},
|
|
1947
|
-
{
|
|
1948
|
-
scrollReachY: 45,
|
|
1949
|
-
cumulativeSum: 0,
|
|
1950
|
-
percUsers: 0,
|
|
1951
|
-
},
|
|
1952
|
-
{
|
|
1953
|
-
scrollReachY: 50,
|
|
1954
|
-
cumulativeSum: 0,
|
|
1955
|
-
percUsers: 0,
|
|
1956
|
-
},
|
|
1957
|
-
{
|
|
1958
|
-
scrollReachY: 55,
|
|
1959
|
-
cumulativeSum: 0,
|
|
1960
|
-
percUsers: 0,
|
|
1961
|
-
},
|
|
1962
|
-
{
|
|
1963
|
-
scrollReachY: 60,
|
|
1964
|
-
cumulativeSum: 0,
|
|
1965
|
-
percUsers: 0,
|
|
1966
|
-
},
|
|
1967
|
-
{
|
|
1968
|
-
scrollReachY: 65,
|
|
1969
|
-
cumulativeSum: 0,
|
|
1970
|
-
percUsers: 0,
|
|
1971
|
-
},
|
|
1972
|
-
{
|
|
1973
|
-
scrollReachY: 70,
|
|
1974
|
-
cumulativeSum: 0,
|
|
1975
|
-
percUsers: 0,
|
|
1976
|
-
},
|
|
1977
|
-
{
|
|
1978
|
-
scrollReachY: 75,
|
|
1979
|
-
cumulativeSum: 0,
|
|
1980
|
-
percUsers: 0,
|
|
1981
|
-
},
|
|
1982
|
-
{
|
|
1983
|
-
scrollReachY: 80,
|
|
1984
|
-
cumulativeSum: 0,
|
|
1985
|
-
percUsers: 0,
|
|
1986
|
-
},
|
|
1987
|
-
{
|
|
1988
|
-
scrollReachY: 85,
|
|
1989
|
-
cumulativeSum: 0,
|
|
1990
|
-
percUsers: 0,
|
|
1991
|
-
},
|
|
1992
|
-
{
|
|
1993
|
-
scrollReachY: 90,
|
|
1994
|
-
cumulativeSum: 0,
|
|
1995
|
-
percUsers: 0,
|
|
1996
|
-
},
|
|
1997
|
-
{
|
|
1998
|
-
scrollReachY: 95,
|
|
1999
|
-
cumulativeSum: 0,
|
|
2000
|
-
percUsers: 0,
|
|
2001
|
-
},
|
|
2002
|
-
{
|
|
2003
|
-
scrollReachY: 100,
|
|
2004
|
-
cumulativeSum: 0,
|
|
2005
|
-
percUsers: 0,
|
|
2006
|
-
},
|
|
2007
|
-
];
|
|
2008
2325
|
const useScrollmap = () => {
|
|
2009
2326
|
const vizRef = useHeatmapSingleStore((state) => state.vizRef);
|
|
2327
|
+
const scrollmap = useHeatmapDataStore((state) => state.scrollmap);
|
|
2010
2328
|
const start = useCallback(() => {
|
|
2011
2329
|
// if (isInitialized) return;
|
|
2012
|
-
const scrollmap = DATA_SCROLLMAP;
|
|
2013
2330
|
if (!vizRef || !scrollmap || scrollmap.length === 0)
|
|
2014
2331
|
return;
|
|
2015
2332
|
try {
|
|
@@ -2020,11 +2337,11 @@ const useScrollmap = () => {
|
|
|
2020
2337
|
catch (error) {
|
|
2021
2338
|
console.error(`🚀 🐥 ~ useScrollmap ~ error:`, error);
|
|
2022
2339
|
}
|
|
2023
|
-
}, [vizRef]);
|
|
2340
|
+
}, [vizRef, scrollmap]);
|
|
2024
2341
|
return { start };
|
|
2025
2342
|
};
|
|
2026
2343
|
|
|
2027
|
-
const
|
|
2344
|
+
const useHeatmapCanvas = ({ iframeRef, }) => {
|
|
2028
2345
|
const heatmapType = useHeatmapConfigStore((state) => state.heatmapType);
|
|
2029
2346
|
const { start: startClickmap } = useClickmap();
|
|
2030
2347
|
const { start: startScrollmap } = useScrollmap();
|
|
@@ -2034,7 +2351,7 @@ const useHeatmapVizCanvas = () => {
|
|
|
2034
2351
|
startClickmap();
|
|
2035
2352
|
break;
|
|
2036
2353
|
case IHeatmapType.Scroll:
|
|
2037
|
-
|
|
2354
|
+
startScrollmap();
|
|
2038
2355
|
break;
|
|
2039
2356
|
}
|
|
2040
2357
|
}, [heatmapType, startClickmap, startScrollmap]);
|
|
@@ -2166,8 +2483,7 @@ const ELEMENT_CALLOUT = {
|
|
|
2166
2483
|
};
|
|
2167
2484
|
const HeatmapElements = (props) => {
|
|
2168
2485
|
const iframeHeight = useHeatmapSingleStore((state) => state.iframeHeight);
|
|
2169
|
-
const
|
|
2170
|
-
const { iframeRef, wrapperRef, visualRef, visualizer, iframeDimensions, isElementSidebarOpen, isVisible = true, areDefaultRanksHidden, isSecondary, ...rest } = props;
|
|
2486
|
+
const { iframeRef, wrapperRef, visualRef, visualizer, iframeDimensions, isElementSidebarOpen, isVisible = true, areDefaultRanksHidden, isSecondary, } = props;
|
|
2171
2487
|
const getRect = useHeatmapElementPosition({
|
|
2172
2488
|
iframeRef,
|
|
2173
2489
|
wrapperRef,
|
|
@@ -2181,27 +2497,6 @@ const HeatmapElements = (props) => {
|
|
|
2181
2497
|
iframeRef,
|
|
2182
2498
|
getRect,
|
|
2183
2499
|
});
|
|
2184
|
-
const heatmapInfo = useHeatmapDataStore((state) => state.dataInfo);
|
|
2185
|
-
useHeatmapMouseHandler({
|
|
2186
|
-
heatmapWrapperRef: wrapperRef,
|
|
2187
|
-
iframeRef,
|
|
2188
|
-
parentRef: visualRef,
|
|
2189
|
-
heatmapInfo: heatmapInfo || {},
|
|
2190
|
-
scaleRatio: 0.8, // 80% zoom
|
|
2191
|
-
onElementHover: (info) => {
|
|
2192
|
-
setHoveredElement({
|
|
2193
|
-
hash: info.hash,
|
|
2194
|
-
clicks: info.clicks,
|
|
2195
|
-
rank: info.rank,
|
|
2196
|
-
selector: info.selector,
|
|
2197
|
-
top: info.top,
|
|
2198
|
-
left: info.left,
|
|
2199
|
-
width: info.width,
|
|
2200
|
-
height: info.height,
|
|
2201
|
-
});
|
|
2202
|
-
console.log(`🚀 🐥 ~ HeatmapElements ~ info:`, info);
|
|
2203
|
-
},
|
|
2204
|
-
});
|
|
2205
2500
|
useElementCalloutVisible({
|
|
2206
2501
|
visualRef,
|
|
2207
2502
|
getRect,
|
|
@@ -2257,6 +2552,293 @@ const VizElements = ({ iframeRef, visualRef, wrapperRef }) => {
|
|
|
2257
2552
|
} }));
|
|
2258
2553
|
};
|
|
2259
2554
|
|
|
2555
|
+
const AverageFoldLine = ({ iframeRef, wrapperRef }) => {
|
|
2556
|
+
const averageFold = useHeatmapDataStore((state) => state.dataInfo?.averageFold || 50);
|
|
2557
|
+
const { getZonePosition } = useZonePositions();
|
|
2558
|
+
const position = getZonePosition({
|
|
2559
|
+
startY: averageFold,
|
|
2560
|
+
endY: averageFold,
|
|
2561
|
+
});
|
|
2562
|
+
if (!position)
|
|
2563
|
+
return null;
|
|
2564
|
+
return (jsx("div", { style: {
|
|
2565
|
+
position: 'absolute',
|
|
2566
|
+
top: `${position.top}px`,
|
|
2567
|
+
left: 0,
|
|
2568
|
+
width: '100%',
|
|
2569
|
+
height: '2px',
|
|
2570
|
+
backgroundColor: '#0078D4',
|
|
2571
|
+
pointerEvents: 'none',
|
|
2572
|
+
zIndex: 2,
|
|
2573
|
+
boxShadow: '0 0 4px rgba(0,120,212,0.5)',
|
|
2574
|
+
display: 'flex',
|
|
2575
|
+
alignItems: 'center',
|
|
2576
|
+
}, children: jsxs("div", { style: {
|
|
2577
|
+
position: 'absolute',
|
|
2578
|
+
padding: '8px',
|
|
2579
|
+
backgroundColor: 'rgba(0, 120, 212, 0.9)',
|
|
2580
|
+
color: 'white',
|
|
2581
|
+
fontSize: '16px',
|
|
2582
|
+
fontWeight: 600,
|
|
2583
|
+
borderRadius: '4px',
|
|
2584
|
+
whiteSpace: 'nowrap',
|
|
2585
|
+
left: '12px',
|
|
2586
|
+
minWidth: '120px',
|
|
2587
|
+
textAlign: 'center',
|
|
2588
|
+
}, children: ["Average fold - ", averageFold.toFixed(0), "%"] }) }));
|
|
2589
|
+
};
|
|
2590
|
+
|
|
2591
|
+
const ScrollmapMarker = ({ iframeRef, wrapperRef }) => {
|
|
2592
|
+
const scrollmap = useHeatmapDataStore((state) => state.scrollmap);
|
|
2593
|
+
const scrollType = useHeatmapConfigStore((state) => state.scrollType);
|
|
2594
|
+
const { getZonePosition } = useZonePositions();
|
|
2595
|
+
if (!scrollmap || scrollmap.length === 0)
|
|
2596
|
+
return null;
|
|
2597
|
+
const findScrollPositionForUserPercent = (targetPercent) => {
|
|
2598
|
+
for (let i = 0; i < scrollmap.length; i++) {
|
|
2599
|
+
if (scrollmap[i].percUsers <= targetPercent) {
|
|
2600
|
+
if (i > 0) {
|
|
2601
|
+
return scrollmap[i - 1].scrollReachY;
|
|
2602
|
+
}
|
|
2603
|
+
return scrollmap[i].scrollReachY;
|
|
2604
|
+
}
|
|
2605
|
+
}
|
|
2606
|
+
return scrollmap[scrollmap.length - 1]?.scrollReachY || null;
|
|
2607
|
+
};
|
|
2608
|
+
const boundaries = [
|
|
2609
|
+
{ percent: 75, label: '75%', color: '#10B981' },
|
|
2610
|
+
{ percent: 50, label: '50%', color: '#F59E0B' },
|
|
2611
|
+
{ percent: 25, label: '25%', color: '#EF4444' },
|
|
2612
|
+
{ percent: 5, label: '5%', color: '#8B5CF6' },
|
|
2613
|
+
];
|
|
2614
|
+
const isScrollDepth = scrollType === IScrollType.Depth;
|
|
2615
|
+
if (!isScrollDepth)
|
|
2616
|
+
return null;
|
|
2617
|
+
return (jsx(Fragment, { children: boundaries.map((boundary) => {
|
|
2618
|
+
const scrollY = findScrollPositionForUserPercent(boundary.percent);
|
|
2619
|
+
if (scrollY === null)
|
|
2620
|
+
return null;
|
|
2621
|
+
const position = getZonePosition({
|
|
2622
|
+
startY: scrollY,
|
|
2623
|
+
endY: scrollY,
|
|
2624
|
+
});
|
|
2625
|
+
if (!position)
|
|
2626
|
+
return null;
|
|
2627
|
+
return (jsx("div", { className: `marker-boundary-line-${boundary.percent}`, style: {
|
|
2628
|
+
position: 'absolute',
|
|
2629
|
+
top: `${position.top}px`,
|
|
2630
|
+
left: 0,
|
|
2631
|
+
transformOrigin: 'left center',
|
|
2632
|
+
width: '100%',
|
|
2633
|
+
height: '0px',
|
|
2634
|
+
// borderBottom: `2px dashed #323130`,
|
|
2635
|
+
borderBottom: `2px solid ${boundary.color}`,
|
|
2636
|
+
// background: 'repeating-linear-gradient(90deg, #323130, transparent 2px 3px)',
|
|
2637
|
+
zIndex: 1,
|
|
2638
|
+
display: 'flex',
|
|
2639
|
+
alignItems: 'center',
|
|
2640
|
+
}, children: jsx("div", { style: {
|
|
2641
|
+
position: 'absolute',
|
|
2642
|
+
padding: '8px',
|
|
2643
|
+
backgroundColor: boundary.color,
|
|
2644
|
+
color: 'white',
|
|
2645
|
+
fontSize: '16px',
|
|
2646
|
+
fontWeight: 600,
|
|
2647
|
+
borderRadius: '4px',
|
|
2648
|
+
whiteSpace: 'nowrap',
|
|
2649
|
+
left: '12px',
|
|
2650
|
+
minWidth: '120px',
|
|
2651
|
+
textAlign: 'center',
|
|
2652
|
+
// textAlign: 'center',
|
|
2653
|
+
// padding: '8px',
|
|
2654
|
+
// paddingInline: '8px',
|
|
2655
|
+
// fontSize: '16px',
|
|
2656
|
+
// background: '#fff',
|
|
2657
|
+
// width: 'auto',
|
|
2658
|
+
// borderRadius: '4px',
|
|
2659
|
+
// position: 'absolute',
|
|
2660
|
+
// left: '12px',
|
|
2661
|
+
// minWidth: '120px',
|
|
2662
|
+
}, children: boundary.label }) }, boundary.label));
|
|
2663
|
+
}) }));
|
|
2664
|
+
};
|
|
2665
|
+
|
|
2666
|
+
const ScrollMapMinimap = ({ zones, maxUsers }) => {
|
|
2667
|
+
const showMinimap = useHeatmapVizScrollmapStore((state) => state.showMinimap);
|
|
2668
|
+
const scrollType = useHeatmapConfigStore((state) => state.scrollType);
|
|
2669
|
+
const isScrollType = [IScrollType.Attention].includes(scrollType);
|
|
2670
|
+
if (!showMinimap || !isScrollType)
|
|
2671
|
+
return null;
|
|
2672
|
+
return (jsx("div", { style: {
|
|
2673
|
+
position: 'fixed',
|
|
2674
|
+
left: '20px',
|
|
2675
|
+
top: '50%',
|
|
2676
|
+
transform: 'translateY(-50%)',
|
|
2677
|
+
width: '60px',
|
|
2678
|
+
height: '400px',
|
|
2679
|
+
backgroundColor: 'white',
|
|
2680
|
+
borderRadius: '8px',
|
|
2681
|
+
boxShadow: '0 4px 16px rgba(0,0,0,0.15)',
|
|
2682
|
+
zIndex: 10002,
|
|
2683
|
+
padding: '8px',
|
|
2684
|
+
boxSizing: 'border-box',
|
|
2685
|
+
}, children: jsx("div", { style: {
|
|
2686
|
+
width: '100%',
|
|
2687
|
+
height: '100%',
|
|
2688
|
+
borderRadius: '4px',
|
|
2689
|
+
overflow: 'hidden',
|
|
2690
|
+
display: 'flex',
|
|
2691
|
+
flexDirection: 'column',
|
|
2692
|
+
}, children: zones.map((zone) => {
|
|
2693
|
+
const normalized = maxUsers > 0 ? zone.percUsers / maxUsers : 0;
|
|
2694
|
+
const color = getScrollGradientColor(normalized);
|
|
2695
|
+
return (jsx("div", { title: `${zone.label}: ${zone.percUsers.toFixed(2)}%`, style: {
|
|
2696
|
+
width: '100%',
|
|
2697
|
+
flex: `${zone.endY - zone.startY}`,
|
|
2698
|
+
backgroundColor: color,
|
|
2699
|
+
borderBottom: '1px solid rgba(255,255,255,0.2)',
|
|
2700
|
+
} }, zone.id));
|
|
2701
|
+
}) }) }));
|
|
2702
|
+
};
|
|
2703
|
+
|
|
2704
|
+
const ScrollZoneTooltip = ({ zone, position, currentScrollPercent, scrollmap, }) => {
|
|
2705
|
+
const tooltipRef = useRef(null);
|
|
2706
|
+
const currentData = useMemo(() => {
|
|
2707
|
+
if (!scrollmap || scrollmap.length === 0)
|
|
2708
|
+
return null;
|
|
2709
|
+
const roundedPercent = Math.floor(currentScrollPercent);
|
|
2710
|
+
return scrollmap.find((d) => d.scrollReachY === roundedPercent) || null;
|
|
2711
|
+
}, [scrollmap, currentScrollPercent]);
|
|
2712
|
+
return (jsxs("div", { id: "gx-hm-scrollmap-tooltip", ref: tooltipRef, style: {
|
|
2713
|
+
position: 'fixed',
|
|
2714
|
+
top: `${position.y}px`,
|
|
2715
|
+
backgroundColor: 'black',
|
|
2716
|
+
zIndex: 10001,
|
|
2717
|
+
pointerEvents: 'none',
|
|
2718
|
+
width: '100%',
|
|
2719
|
+
height: '2px',
|
|
2720
|
+
}, children: [jsxs("div", { style: {
|
|
2721
|
+
position: 'absolute',
|
|
2722
|
+
left: '50%',
|
|
2723
|
+
top: '-50%',
|
|
2724
|
+
transform: 'translate(-50%, -50%)',
|
|
2725
|
+
padding: '16px',
|
|
2726
|
+
borderRadius: '8px',
|
|
2727
|
+
boxShadow: '0 4px 16px rgba(0,0,0,0.15)',
|
|
2728
|
+
fontSize: '14px',
|
|
2729
|
+
width: 'fit-content',
|
|
2730
|
+
backgroundColor: 'white',
|
|
2731
|
+
minWidth: '230px',
|
|
2732
|
+
display: 'flex',
|
|
2733
|
+
gap: '8px',
|
|
2734
|
+
alignItems: 'center',
|
|
2735
|
+
}, children: [jsxs("p", { style: {
|
|
2736
|
+
fontWeight: 650,
|
|
2737
|
+
fontSize: '20px',
|
|
2738
|
+
lineHeight: '24px',
|
|
2739
|
+
letterSpacing: '-0.2px',
|
|
2740
|
+
verticalAlign: 'middle',
|
|
2741
|
+
fontVariantNumeric: 'tabular-nums',
|
|
2742
|
+
}, children: [currentData?.percUsers?.toFixed(2), "%", ' '] }), jsx("p", { style: { fontWeight: 450 }, children: "user scrolled this far" })] }), jsx(TooltipByZone, { zone: zone })] }));
|
|
2743
|
+
};
|
|
2744
|
+
const TooltipByZone = ({ zone }) => {
|
|
2745
|
+
const scrollType = useHeatmapConfigStore((state) => state.scrollType);
|
|
2746
|
+
if (!zone)
|
|
2747
|
+
return null;
|
|
2748
|
+
const contentMarkup = () => {
|
|
2749
|
+
switch (scrollType) {
|
|
2750
|
+
case IScrollType.Depth:
|
|
2751
|
+
return jsx(BasicTooltipContent, { zone: zone });
|
|
2752
|
+
case IScrollType.Attention:
|
|
2753
|
+
return jsx(MetricsTooltipContent, { zone: zone });
|
|
2754
|
+
default:
|
|
2755
|
+
return jsx(BasicTooltipContent, { zone: zone });
|
|
2756
|
+
}
|
|
2757
|
+
};
|
|
2758
|
+
return (jsx("div", { style: { paddingTop: '12px', borderTop: '1px solid #E5E7EB' }, children: contentMarkup() }));
|
|
2759
|
+
};
|
|
2760
|
+
const BasicTooltipContent = ({ zone }) => {
|
|
2761
|
+
if (!zone)
|
|
2762
|
+
return null;
|
|
2763
|
+
return (jsxs(Fragment, { children: [jsx("div", { style: { fontWeight: 600, marginBottom: '8px' }, children: zone.label }), jsxs("div", { style: { fontSize: '24px', fontWeight: 700, color: '#0078D4' }, children: [zone.percUsers.toFixed(2), "%"] }), jsx("div", { style: { fontSize: '12px', color: '#605E5C', marginTop: '4px' }, children: "of users reached this point" })] }));
|
|
2764
|
+
};
|
|
2765
|
+
const MetricsTooltipContent = ({ zone }) => {
|
|
2766
|
+
if (!zone)
|
|
2767
|
+
return null;
|
|
2768
|
+
return (jsxs(Fragment, { children: [jsx("div", { style: { fontWeight: 600, marginBottom: '8px' }, children: zone.label }), jsxs("div", { style: { fontSize: '20px', fontWeight: 700, marginBottom: '8px' }, children: [zone.percUsers.toFixed(2), "% users"] }), zone.metrics && (jsxs("div", { style: { display: 'grid', gap: '6px', fontSize: '13px' }, children: [zone.metrics.revenue !== undefined && (jsx(MetricRow, { label: "Revenue", value: `$${zone.metrics.revenue.toFixed(2)}` })), zone.metrics.conversionRate !== undefined && (jsx(MetricRow, { label: "Conversion", value: `${zone.metrics.conversionRate.toFixed(2)}%` })), zone.metrics.orders !== undefined && (jsx(MetricRow, { label: "Orders", value: zone.metrics.orders.toString() }))] }))] }));
|
|
2769
|
+
};
|
|
2770
|
+
const MetricRow = ({ label, value }) => (jsxs("div", { style: { display: 'flex', justifyContent: 'space-between' }, children: [jsxs("span", { style: { color: '#605E5C' }, children: [label, ":"] }), jsx("span", { style: { fontWeight: 600 }, children: value })] }));
|
|
2771
|
+
|
|
2772
|
+
const HoverZones = ({ iframeRef, wrapperRef, position, currentScrollPercent, }) => {
|
|
2773
|
+
const scrollmap = useHeatmapDataStore((state) => state.scrollmap);
|
|
2774
|
+
// const hoveredZone = useHeatmapVizScrollmapStore((state) => state.hoveredZone);
|
|
2775
|
+
// const setHoveredZone = useHeatmapVizScrollmapStore((state) => state.setHoveredZone);
|
|
2776
|
+
const { zones, isReady, maxUsers } = useScrollmapZones({
|
|
2777
|
+
iframeRef,
|
|
2778
|
+
wrapperRef,
|
|
2779
|
+
});
|
|
2780
|
+
if (!isReady || !zones.length)
|
|
2781
|
+
return null;
|
|
2782
|
+
if (!position)
|
|
2783
|
+
return null;
|
|
2784
|
+
return (jsxs(Fragment, { children: [jsx(ScrollZoneTooltip, { position: position, currentScrollPercent: currentScrollPercent, scrollmap: scrollmap || [] }), jsx(ScrollMapMinimap, { zones: zones, maxUsers: maxUsers })] }));
|
|
2785
|
+
};
|
|
2786
|
+
|
|
2787
|
+
const ScrollMapOverlay = ({ wrapperRef, iframeRef }) => {
|
|
2788
|
+
const overlayRef = useRef(null);
|
|
2789
|
+
const [position, setPosition] = useState();
|
|
2790
|
+
const [currentScrollPercent, setCurrentScrollPercent] = useState(0);
|
|
2791
|
+
const widthScale = useHeatmapVizStore((state) => state.scale);
|
|
2792
|
+
const iframeHeight = useHeatmapSingleStore((state) => state.iframeHeight);
|
|
2793
|
+
const handleMouseMove = (event) => {
|
|
2794
|
+
if (!iframeRef.current || !wrapperRef.current)
|
|
2795
|
+
return;
|
|
2796
|
+
const iframe = iframeRef.current;
|
|
2797
|
+
const iframeRect = iframe.getBoundingClientRect();
|
|
2798
|
+
const { x, y } = convertViewportToIframeCoords(event.clientX, event.clientY, iframeRect, widthScale);
|
|
2799
|
+
const wrapperEl = wrapperRef.current;
|
|
2800
|
+
const scrollOffset = (wrapperEl?.scrollTop || 0) / widthScale;
|
|
2801
|
+
const actualY = y + scrollOffset;
|
|
2802
|
+
const scrollPercent = Math.min(100, Math.max(0, (actualY / iframeHeight) * 100));
|
|
2803
|
+
setCurrentScrollPercent(scrollPercent);
|
|
2804
|
+
setPosition({ x, y });
|
|
2805
|
+
};
|
|
2806
|
+
const onMouseMove = useCallback((event) => {
|
|
2807
|
+
requestAnimationFrame(() => handleMouseMove(event));
|
|
2808
|
+
}, [handleMouseMove]);
|
|
2809
|
+
const onMouseLeave = () => {
|
|
2810
|
+
requestAnimationFrame(() => {
|
|
2811
|
+
setCurrentScrollPercent(0);
|
|
2812
|
+
setPosition(undefined);
|
|
2813
|
+
});
|
|
2814
|
+
};
|
|
2815
|
+
return (jsx("div", { ref: overlayRef, id: "gx-hm-scrollmap-overlay", onMouseMove: onMouseMove, onMouseLeave: onMouseLeave, style: {
|
|
2816
|
+
position: 'absolute',
|
|
2817
|
+
top: 0,
|
|
2818
|
+
left: 0,
|
|
2819
|
+
width: '100%',
|
|
2820
|
+
height: `${iframeHeight}px`,
|
|
2821
|
+
zIndex: 3,
|
|
2822
|
+
}, children: jsx(HoverZones, { position: position, currentScrollPercent: currentScrollPercent, iframeRef: iframeRef, wrapperRef: wrapperRef }) }));
|
|
2823
|
+
};
|
|
2824
|
+
|
|
2825
|
+
const SCROLL_TYPES = [IHeatmapType.Scroll];
|
|
2826
|
+
const VizScrollMap = ({ iframeRef, wrapperRef }) => {
|
|
2827
|
+
const iframeHeight = useHeatmapSingleStore((state) => state.iframeHeight);
|
|
2828
|
+
const heatmapType = useHeatmapConfigStore((state) => state.heatmapType);
|
|
2829
|
+
const isHeatmapScroll = SCROLL_TYPES.includes(heatmapType);
|
|
2830
|
+
if (!iframeHeight || !isHeatmapScroll)
|
|
2831
|
+
return null;
|
|
2832
|
+
return (jsxs("div", { style: {
|
|
2833
|
+
position: 'absolute',
|
|
2834
|
+
top: 0,
|
|
2835
|
+
left: '2px',
|
|
2836
|
+
width: `calc(100% - 4px)`,
|
|
2837
|
+
height: '100%',
|
|
2838
|
+
transform: 'translateZ(0)',
|
|
2839
|
+
}, children: [jsx(ScrollmapMarker, { iframeRef: iframeRef, wrapperRef: wrapperRef }), jsx(AverageFoldLine, { iframeRef: iframeRef, wrapperRef: wrapperRef }), jsx(ScrollMapOverlay, { wrapperRef: wrapperRef, iframeRef: iframeRef })] }));
|
|
2840
|
+
};
|
|
2841
|
+
|
|
2260
2842
|
const WrapperVisual = ({ children, visualRef, wrapperRef, scaledHeight, iframeHeight, onScroll, }) => {
|
|
2261
2843
|
const contentWidth = useHeatmapConfigStore((state) => state.width);
|
|
2262
2844
|
const widthScale = useHeatmapVizStore((state) => state.scale);
|
|
@@ -2291,6 +2873,7 @@ const WrapperVisual = ({ children, visualRef, wrapperRef, scaledHeight, iframeHe
|
|
|
2291
2873
|
|
|
2292
2874
|
const VizDomRenderer = ({ mode = 'heatmap' }) => {
|
|
2293
2875
|
const width = useHeatmapConfigStore((state) => state.width);
|
|
2876
|
+
const heatmapType = useHeatmapConfigStore((state) => state.heatmapType);
|
|
2294
2877
|
const iframeHeight = useHeatmapSingleStore((state) => state.iframeHeight);
|
|
2295
2878
|
const setIframeHeight = useHeatmapSingleStore((state) => state.setIframeHeight);
|
|
2296
2879
|
const setSelectedElement = useHeatmapInteractionStore((state) => state.setSelectedElement);
|
|
@@ -2308,7 +2891,7 @@ const VizDomRenderer = ({ mode = 'heatmap' }) => {
|
|
|
2308
2891
|
const scrollTop = e.currentTarget.scrollTop;
|
|
2309
2892
|
handleScroll(scrollTop);
|
|
2310
2893
|
};
|
|
2311
|
-
|
|
2894
|
+
useHeatmapCanvas({ iframeRef: iframeRef });
|
|
2312
2895
|
const cleanUp = () => {
|
|
2313
2896
|
setIframeHeight(0);
|
|
2314
2897
|
setSelectedElement(null);
|
|
@@ -2316,7 +2899,7 @@ const VizDomRenderer = ({ mode = 'heatmap' }) => {
|
|
|
2316
2899
|
useEffect(() => {
|
|
2317
2900
|
return cleanUp;
|
|
2318
2901
|
}, []);
|
|
2319
|
-
return (jsxs(WrapperVisual, { visualRef: visualRef, wrapperRef: wrapperRef, scaledHeight: scaledHeight, onScroll: onScroll, iframeHeight: iframeHeight, children: [jsx(VizElements, { iframeRef: iframeRef, visualRef: visualRef, wrapperRef: wrapperRef }), jsx("iframe", { ref: iframeRef, ...HEATMAP_IFRAME, width: contentWidth, scrolling: "no" })] }));
|
|
2902
|
+
return (jsxs(WrapperVisual, { visualRef: visualRef, wrapperRef: wrapperRef, scaledHeight: scaledHeight, onScroll: onScroll, iframeHeight: iframeHeight, children: [heatmapType === IHeatmapType.Click && (jsx(VizElements, { iframeRef: iframeRef, visualRef: visualRef, wrapperRef: wrapperRef })), jsx("iframe", { ref: iframeRef, ...HEATMAP_IFRAME, width: contentWidth, scrolling: "no" }), jsx(VizScrollMap, { iframeRef: iframeRef, wrapperRef: visualRef })] }));
|
|
2320
2903
|
};
|
|
2321
2904
|
|
|
2322
2905
|
const VizLoading = () => {
|
|
@@ -2423,10 +3006,10 @@ const WrapperLayout = () => {
|
|
|
2423
3006
|
return (jsxs(BoxStack, { id: "gx-hm-layout", flexDirection: "column", flex: "1", children: [jsx(ContentTopBar, {}), jsx(WrapperPreview, {})] }));
|
|
2424
3007
|
};
|
|
2425
3008
|
|
|
2426
|
-
const HeatmapLayout = ({ data, clickmap, controls, dataInfo, }) => {
|
|
3009
|
+
const HeatmapLayout = ({ data, clickmap, scrollmap, controls, dataInfo, }) => {
|
|
2427
3010
|
useRegisterControl(controls);
|
|
2428
3011
|
useRegisterData(data, dataInfo);
|
|
2429
|
-
useRegisterHeatmap(clickmap);
|
|
3012
|
+
useRegisterHeatmap({ clickmap, scrollmap });
|
|
2430
3013
|
useRegisterConfig();
|
|
2431
3014
|
return (jsx(BoxStack, { id: "gx-hm-project", flexDirection: "column", flex: "1", height: "100%", style: getVariableStyle(), children: jsx(BoxStack, { id: "gx-hm-project-content", flexDirection: "column", flex: "1", children: jsx("div", { style: {
|
|
2432
3015
|
minHeight: '100%',
|
|
@@ -2441,4 +3024,4 @@ const HeatmapLayout = ({ data, clickmap, controls, dataInfo, }) => {
|
|
|
2441
3024
|
}
|
|
2442
3025
|
};
|
|
2443
3026
|
|
|
2444
|
-
export { GraphView, HeatmapLayout, IHeatmapType, useHeatmapConfigStore, useHeatmapDataStore, useHeatmapInteractionStore, useHeatmapLiveStore, useHeatmapVizStore };
|
|
3027
|
+
export { GraphView, HeatmapLayout, IClickType, IHeatmapType, IScrollType, useHeatmapConfigStore, useHeatmapDataStore, useHeatmapInteractionStore, useHeatmapLiveStore, useHeatmapVizStore };
|