@gemx-dev/heatmap-react 3.5.44 → 3.5.46
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/ContentHeader.d.ts +4 -0
- package/dist/esm/components/Layout/ContentHeader.d.ts.map +1 -0
- package/dist/esm/components/Layout/VizMode.d.ts +2 -0
- package/dist/esm/components/Layout/VizMode.d.ts.map +1 -0
- package/dist/esm/components/Test.d.ts +121 -0
- package/dist/esm/components/Test.d.ts.map +1 -0
- package/dist/esm/components/VizDom/VizDomContainer.d.ts +6 -0
- package/dist/esm/components/VizDom/VizDomContainer.d.ts.map +1 -0
- package/dist/esm/components/VizDom/VizDomRenderer.d.ts.map +1 -1
- package/dist/esm/components/VizElement/ClickedElementOverlay.d.ts +17 -0
- package/dist/esm/components/VizElement/ClickedElementOverlay.d.ts.map +1 -0
- package/dist/esm/components/VizElement/HeatmapElements.d.ts.map +1 -1
- package/dist/esm/components/VizElement/HoveredElementOverlay.d.ts +12 -0
- package/dist/esm/components/VizElement/HoveredElementOverlay.d.ts.map +1 -0
- package/dist/esm/components/VizElement/MissingElementMessage.d.ts +7 -0
- package/dist/esm/components/VizElement/MissingElementMessage.d.ts.map +1 -0
- package/dist/esm/components/VizElement/VizElements.d.ts.map +1 -1
- package/dist/esm/components/VizElement/temp/ClarityVisualizer.d.ts +150 -0
- package/dist/esm/components/VizElement/temp/ClarityVisualizer.d.ts.map +1 -0
- package/dist/esm/components/VizElement/temp/VizElementRank.d.ts +74 -0
- package/dist/esm/components/VizElement/temp/VizElementRank.d.ts.map +1 -0
- package/dist/esm/components/VizLive/VizLive.d.ts +2 -0
- package/dist/esm/components/VizLive/VizLive.d.ts.map +1 -0
- package/dist/esm/components/VizLive/VizLiveHeatmap.d.ts.map +1 -1
- package/dist/esm/components/VizLive/VizLiveRenderer.d.ts.map +1 -1
- package/dist/esm/configs/style.d.ts +0 -2
- package/dist/esm/configs/style.d.ts.map +1 -1
- package/dist/esm/helpers/index.d.ts +2 -1
- package/dist/esm/helpers/index.d.ts.map +1 -1
- package/dist/esm/helpers/viewport-fixer.d.ts +13 -0
- package/dist/esm/helpers/viewport-fixer.d.ts.map +1 -0
- package/dist/esm/helpers/viewport-replacer.d.ts +26 -0
- package/dist/esm/helpers/viewport-replacer.d.ts.map +1 -0
- package/dist/esm/hooks/vix-elements/useHoveredElement.d.ts.map +1 -1
- package/dist/esm/hooks/viz-canvas/useClickmap.d.ts +1 -3
- package/dist/esm/hooks/viz-canvas/useClickmap.d.ts.map +1 -1
- package/dist/esm/hooks/viz-canvas/useHeatmapVizCanvas.d.ts +1 -1
- package/dist/esm/hooks/viz-canvas/useHeatmapVizCanvas.d.ts.map +1 -1
- package/dist/esm/hooks/viz-canvas/useScrollmap.d.ts +1 -3
- package/dist/esm/hooks/viz-canvas/useScrollmap.d.ts.map +1 -1
- package/dist/esm/hooks/viz-live/index.d.ts +1 -1
- package/dist/esm/hooks/viz-live/{useVizLiveIframeMsg.d.ts → useIframeMessage.d.ts} +10 -2
- package/dist/esm/hooks/viz-live/useIframeMessage.d.ts.map +1 -0
- package/dist/esm/hooks/viz-render/useHeatmapRender.d.ts.map +1 -1
- package/dist/esm/hooks/viz-scale/useContainerDimensions.d.ts.map +1 -1
- package/dist/esm/hooks/viz-scale/useHeatmapScale.d.ts +1 -1
- package/dist/esm/hooks/viz-scale/useHeatmapScale.d.ts.map +1 -1
- package/dist/esm/hooks/viz-scale/useIframeHeight.d.ts +10 -0
- package/dist/esm/hooks/viz-scale/useIframeHeight.d.ts.map +1 -0
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +203 -910
- package/dist/esm/index.mjs +203 -910
- package/dist/esm/stores/index.d.ts +0 -1
- package/dist/esm/stores/index.d.ts.map +1 -1
- package/dist/esm/stores/interaction.d.ts.map +1 -1
- package/dist/esm/stores/mode-live.d.ts +0 -4
- package/dist/esm/stores/mode-live.d.ts.map +1 -1
- package/dist/esm/stores/viz.d.ts +4 -0
- package/dist/esm/stores/viz.d.ts.map +1 -1
- package/dist/esm/types/index.d.ts +1 -1
- package/dist/esm/types/index.d.ts.map +1 -1
- package/dist/esm/types/viewport-fixer.d.ts +31 -0
- package/dist/esm/types/viewport-fixer.d.ts.map +1 -0
- package/dist/umd/components/Layout/ContentHeader.d.ts +4 -0
- package/dist/umd/components/Layout/ContentHeader.d.ts.map +1 -0
- package/dist/umd/components/Test.d.ts +121 -0
- package/dist/umd/components/Test.d.ts.map +1 -0
- package/dist/umd/components/VizDom/VizDomContainer.d.ts +2 -0
- package/dist/umd/components/VizDom/VizDomContainer.d.ts.map +1 -0
- package/dist/umd/components/VizDom/VizDomRenderer.d.ts.map +1 -1
- package/dist/umd/components/VizElement/ClickedElementOverlay.d.ts +17 -0
- package/dist/umd/components/VizElement/ClickedElementOverlay.d.ts.map +1 -0
- package/dist/umd/components/VizElement/HeatmapElements.d.ts.map +1 -1
- package/dist/umd/components/VizElement/HoveredElementOverlay.d.ts +12 -0
- package/dist/umd/components/VizElement/HoveredElementOverlay.d.ts.map +1 -0
- package/dist/umd/components/VizElement/MissingElementMessage.d.ts +7 -0
- package/dist/umd/components/VizElement/MissingElementMessage.d.ts.map +1 -0
- package/dist/umd/components/VizElement/VizElements.d.ts.map +1 -1
- package/dist/umd/components/VizElement/temp/ClarityVisualizer.d.ts +150 -0
- package/dist/umd/components/VizElement/temp/ClarityVisualizer.d.ts.map +1 -0
- package/dist/umd/components/VizElement/temp/VizElementRank.d.ts +74 -0
- package/dist/umd/components/VizElement/temp/VizElementRank.d.ts.map +1 -0
- package/dist/umd/components/VizLive/VizLiveHeatmap.d.ts.map +1 -1
- package/dist/umd/components/VizLive/VizLiveRenderer.d.ts.map +1 -1
- package/dist/umd/configs/style.d.ts +0 -2
- package/dist/umd/configs/style.d.ts.map +1 -1
- package/dist/umd/helpers/index.d.ts +2 -1
- package/dist/umd/helpers/index.d.ts.map +1 -1
- package/dist/umd/helpers/viewport-fixer.d.ts +13 -0
- package/dist/umd/helpers/viewport-fixer.d.ts.map +1 -0
- package/dist/umd/helpers/viewport-replacer.d.ts +26 -0
- package/dist/umd/helpers/viewport-replacer.d.ts.map +1 -0
- package/dist/umd/hooks/vix-elements/useHoveredElement.d.ts.map +1 -1
- package/dist/umd/hooks/viz-canvas/useClickmap.d.ts +1 -3
- package/dist/umd/hooks/viz-canvas/useClickmap.d.ts.map +1 -1
- package/dist/umd/hooks/viz-canvas/useHeatmapVizCanvas.d.ts +1 -1
- package/dist/umd/hooks/viz-canvas/useHeatmapVizCanvas.d.ts.map +1 -1
- package/dist/umd/hooks/viz-canvas/useScrollmap.d.ts +1 -3
- package/dist/umd/hooks/viz-canvas/useScrollmap.d.ts.map +1 -1
- package/dist/umd/hooks/viz-live/index.d.ts +1 -1
- package/dist/umd/hooks/viz-live/{useVizLiveIframeMsg.d.ts → useIframeMessage.d.ts} +10 -2
- package/dist/umd/hooks/viz-live/useIframeMessage.d.ts.map +1 -0
- package/dist/umd/hooks/viz-render/useHeatmapRender.d.ts.map +1 -1
- package/dist/umd/hooks/viz-scale/useContainerDimensions.d.ts.map +1 -1
- package/dist/umd/hooks/viz-scale/useHeatmapScale.d.ts +1 -1
- package/dist/umd/hooks/viz-scale/useHeatmapScale.d.ts.map +1 -1
- package/dist/umd/hooks/viz-scale/useIframeHeight.d.ts +10 -0
- package/dist/umd/hooks/viz-scale/useIframeHeight.d.ts.map +1 -0
- package/dist/umd/index.d.ts +1 -1
- package/dist/umd/index.d.ts.map +1 -1
- package/dist/umd/index.js +2 -2
- package/dist/umd/stores/index.d.ts +0 -1
- package/dist/umd/stores/index.d.ts.map +1 -1
- package/dist/umd/stores/interaction.d.ts.map +1 -1
- package/dist/umd/stores/mode-live.d.ts +0 -4
- package/dist/umd/stores/mode-live.d.ts.map +1 -1
- package/dist/umd/stores/viz.d.ts +4 -0
- package/dist/umd/stores/viz.d.ts.map +1 -1
- package/dist/umd/types/index.d.ts +1 -1
- package/dist/umd/types/index.d.ts.map +1 -1
- package/dist/umd/types/viewport-fixer.d.ts +31 -0
- package/dist/umd/types/viewport-fixer.d.ts.map +1 -0
- package/package.json +13 -15
- package/src/components/GraphView.tsx +58 -0
- package/src/components/Layout/ContentMetricBar.tsx +23 -0
- package/src/components/Layout/ContentToolbar.tsx +22 -0
- package/src/components/Layout/ContentTopBar.tsx +24 -0
- package/src/components/Layout/ContentVizByMode.tsx +14 -0
- package/src/components/Layout/HeatmapLayout.tsx +60 -0
- package/src/components/Layout/LeftSidebar.tsx +44 -0
- package/src/components/Layout/WrapperLayout.tsx +12 -0
- package/src/components/Layout/WrapperPreview.tsx +24 -0
- package/src/components/Layout/index.ts +1 -0
- package/src/components/VizDom/ReplayControls.tsx +48 -0
- package/src/components/VizDom/VizContainer.tsx +40 -0
- package/src/components/VizDom/VizDomHeatmap.tsx +28 -0
- package/src/components/VizDom/VizDomRenderer.tsx +82 -0
- package/src/components/VizDom/VizLoading.tsx +8 -0
- package/src/components/VizDom/WrapperVisual.tsx +73 -0
- package/src/components/VizDom/index.ts +5 -0
- package/src/components/VizElement/DefaultRankBadges.tsx +36 -0
- package/src/components/VizElement/ElementCallout.tsx +82 -0
- package/src/components/VizElement/ElementMissing.tsx +35 -0
- package/src/components/VizElement/ElementOverlay.tsx +66 -0
- package/src/components/VizElement/HeatmapElements.tsx +127 -0
- package/src/components/VizElement/HeatmapExample.tsx +70 -0
- package/src/components/VizElement/RankBadge.tsx +25 -0
- package/src/components/VizElement/VizElements.tsx +57 -0
- package/src/components/VizElement/index.ts +1 -0
- package/src/components/VizLive/VizLiveHeatmap.tsx +27 -0
- package/src/components/VizLive/VizLiveRenderer.tsx +47 -0
- package/src/components/VizLive/index.ts +1 -0
- package/src/components/VizScrollmap/AverageFoldLine.tsx +57 -0
- package/src/components/VizScrollmap/HoverZones.tsx +58 -0
- package/src/components/VizScrollmap/MetricRow.tsx +0 -0
- package/src/components/VizScrollmap/ScrollMapMinimap.tsx +64 -0
- package/src/components/VizScrollmap/ScrollMapOverlay.tsx +79 -0
- package/src/components/VizScrollmap/ScrollZoneHoverArea.tsx +35 -0
- package/src/components/VizScrollmap/ScrollZoneTooltip.tsx +146 -0
- package/src/components/VizScrollmap/ScrollmapMarker.tsx +106 -0
- package/src/components/VizScrollmap/VizScrollMap.tsx +36 -0
- package/src/components/VizScrollmap/index.ts +1 -0
- package/src/components/VizScrollmapV2/ScrollmapOverlay.css +94 -0
- package/src/components/VizScrollmapV2/ScrollmapOverlayV2.tsx +130 -0
- package/src/components/VizScrollmapV2/index.ts +1 -0
- package/src/components/VizScrollmapV2/scrollmap.types.ts +21 -0
- package/src/components/VizScrollmapV2/useScrollmapOverlay.ts +187 -0
- package/src/components/index.tsx +2 -0
- package/src/configs/iframe.ts +15 -0
- package/src/configs/index.ts +2 -0
- package/src/configs/style.ts +21 -0
- package/src/constants/index.ts +4 -0
- package/src/global.d.ts +5 -0
- package/src/helpers/elm-callout.ts +347 -0
- package/src/helpers/elm-getter.ts +70 -0
- package/src/helpers/iframe-helper/fixer.ts +100 -0
- package/src/helpers/iframe-helper/index.ts +1 -0
- package/src/helpers/iframe-helper/init.ts +56 -0
- package/src/helpers/iframe-helper/navigation-blocker-v2.ts +371 -0
- package/src/helpers/iframe-helper/navigation-blocker.ts +367 -0
- package/src/helpers/iframe-helper/style-replacer.ts +231 -0
- package/src/helpers/iframe.ts +42 -0
- package/src/helpers/index.ts +8 -0
- package/src/helpers/viz-canvas/area-clustering.ts +234 -0
- package/src/helpers/viz-canvas/area-overlay-manager-v2.ts +176 -0
- package/src/helpers/viz-canvas/area-overlay-manager.ts +273 -0
- package/src/helpers/viz-canvas/hierarchical-area-clustering.ts +420 -0
- package/src/helpers/viz-canvas/index.ts +2 -0
- package/src/helpers/viz-elements.ts +43 -0
- package/src/hooks/index.ts +8 -0
- package/src/hooks/register/index.ts +4 -0
- package/src/hooks/register/useRegisterConfig.ts +17 -0
- package/src/hooks/register/useRegisterControl.ts +13 -0
- package/src/hooks/register/useRegisterData.ts +36 -0
- package/src/hooks/register/useRegisterHeatmap.ts +38 -0
- package/src/hooks/viz-area/useAreaHeatmap.ts +336 -0
- package/src/hooks/viz-area/useAreaHeatmapManager.ts +692 -0
- package/src/hooks/viz-canvas/index.ts +1 -0
- package/src/hooks/viz-canvas/useAreamap.ts +162 -0
- package/src/hooks/viz-canvas/useClickmap.ts +24 -0
- package/src/hooks/viz-canvas/useHeatmapCanvas.ts +27 -0
- package/src/hooks/viz-canvas/useScrollmap.ts +22 -0
- package/src/hooks/viz-elements/index.ts +5 -0
- package/src/hooks/viz-elements/useClickedElement.ts +86 -0
- package/src/hooks/viz-elements/useElementCalloutVisible.ts +45 -0
- package/src/hooks/viz-elements/useHeatmapEffects.ts +30 -0
- package/src/hooks/viz-elements/useHeatmapElementPosition.ts +60 -0
- package/src/hooks/viz-elements/useHeatmapMouseHandler.ts +255 -0
- package/src/hooks/viz-elements/useHoveredElement.ts +170 -0
- package/src/hooks/viz-live/index.ts +1 -0
- package/src/hooks/viz-live/useVizLiveIframeMsg.ts +88 -0
- package/src/hooks/viz-live/useVizLiveRender.ts +67 -0
- package/src/hooks/viz-render/index.ts +1 -0
- package/src/hooks/viz-render/useHeatmapRender.ts +71 -0
- package/src/hooks/viz-render/useHeatmapVizRender.ts +20 -0
- package/src/hooks/viz-render/useReplayRender.ts +160 -0
- package/src/hooks/viz-scale/index.ts +2 -0
- package/src/hooks/viz-scale/useContainerDimensions.ts +48 -0
- package/src/hooks/viz-scale/useContentDimensions.ts +25 -0
- package/src/hooks/viz-scale/useHeatmapScale.ts +52 -0
- package/src/hooks/viz-scale/useObserveIframeHeight.ts +162 -0
- package/src/hooks/viz-scale/useScaleCalculation.ts +31 -0
- package/src/hooks/viz-scale/useScrollSync.ts +36 -0
- package/src/hooks/viz-scale/useWrapperRefHeight.ts +91 -0
- package/src/hooks/viz-scrollmap/index.ts +2 -0
- package/src/hooks/viz-scrollmap/useScrollmapZones.ts +165 -0
- package/src/hooks/viz-scrollmap/useZonePositions.ts +38 -0
- package/src/index.ts +10 -0
- package/src/stores/comp.ts +31 -0
- package/src/stores/config.ts +37 -0
- package/src/stores/data.ts +30 -0
- package/src/stores/index.ts +10 -0
- package/src/stores/interaction.ts +32 -0
- package/src/stores/mode-live.ts +38 -0
- package/src/stores/mode-single.ts +18 -0
- package/src/stores/viz-scrollmap.ts +22 -0
- package/src/stores/viz.ts +17 -0
- package/src/styles/base.css +1 -0
- package/src/styles/style.css +137 -0
- package/src/types/clarity.ts +45 -0
- package/src/types/control.ts +10 -0
- package/src/types/elm-callout.ts +9 -0
- package/src/types/heatmap-info.ts +11 -0
- package/src/types/heatmap.ts +25 -0
- package/src/types/iframe-helper.ts +18 -0
- package/src/types/index.ts +12 -0
- package/src/types/viz-canvas.ts +20 -0
- package/src/types/viz-element.ts +34 -0
- package/src/types/viz-scrollmap.ts +28 -0
- package/src/ui/BoxStack/BoxStack.tsx +136 -0
- package/src/ui/BoxStack/index.ts +1 -0
- package/src/ui/index.ts +1 -0
- package/src/utils/debounce.ts +10 -0
- package/src/utils/device.ts +7 -0
- package/src/utils/retry.ts +20 -0
- package/src/utils/sort.ts +5 -0
- package/dist/esm/helpers/iframe-helper/fixer.d.ts +0 -18
- package/dist/esm/helpers/iframe-helper/fixer.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/index.d.ts +0 -2
- package/dist/esm/helpers/iframe-helper/index.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/init.d.ts +0 -5
- package/dist/esm/helpers/iframe-helper/init.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/navigation-blocker-v2.d.ts +0 -28
- package/dist/esm/helpers/iframe-helper/navigation-blocker-v2.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/navigation-blocker.d.ts +0 -20
- package/dist/esm/helpers/iframe-helper/navigation-blocker.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/style-replacer.d.ts +0 -25
- package/dist/esm/helpers/iframe-helper/style-replacer.d.ts.map +0 -1
- package/dist/esm/hooks/vix-elements/useHeatmapMouseHandler.d.ts +0 -34
- package/dist/esm/hooks/vix-elements/useHeatmapMouseHandler.d.ts.map +0 -1
- package/dist/esm/hooks/viz-live/useVizLiveIframeMsg.d.ts.map +0 -1
- package/dist/esm/hooks/viz-live/useVizLiveRender.d.ts +0 -4
- package/dist/esm/hooks/viz-live/useVizLiveRender.d.ts.map +0 -1
- package/dist/esm/hooks/viz-scale/useObserveIframeHeight.d.ts +0 -10
- package/dist/esm/hooks/viz-scale/useObserveIframeHeight.d.ts.map +0 -1
- package/dist/esm/stores/mode-single.d.ts +0 -9
- package/dist/esm/stores/mode-single.d.ts.map +0 -1
- package/dist/esm/types/iframe-helper.d.ts +0 -20
- package/dist/esm/types/iframe-helper.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/fixer.d.ts +0 -18
- package/dist/umd/helpers/iframe-helper/fixer.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/index.d.ts +0 -2
- package/dist/umd/helpers/iframe-helper/index.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/init.d.ts +0 -5
- package/dist/umd/helpers/iframe-helper/init.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/navigation-blocker-v2.d.ts +0 -28
- package/dist/umd/helpers/iframe-helper/navigation-blocker-v2.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/navigation-blocker.d.ts +0 -20
- package/dist/umd/helpers/iframe-helper/navigation-blocker.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/style-replacer.d.ts +0 -25
- package/dist/umd/helpers/iframe-helper/style-replacer.d.ts.map +0 -1
- package/dist/umd/hooks/vix-elements/useHeatmapMouseHandler.d.ts +0 -34
- package/dist/umd/hooks/vix-elements/useHeatmapMouseHandler.d.ts.map +0 -1
- package/dist/umd/hooks/viz-live/useVizLiveIframeMsg.d.ts.map +0 -1
- package/dist/umd/hooks/viz-live/useVizLiveRender.d.ts +0 -4
- package/dist/umd/hooks/viz-live/useVizLiveRender.d.ts.map +0 -1
- package/dist/umd/hooks/viz-scale/useObserveIframeHeight.d.ts +0 -10
- package/dist/umd/hooks/viz-scale/useObserveIframeHeight.d.ts.map +0 -1
- package/dist/umd/stores/mode-single.d.ts +0 -9
- package/dist/umd/stores/mode-single.d.ts.map +0 -1
- package/dist/umd/types/iframe-helper.d.ts +0 -20
- package/dist/umd/types/iframe-helper.d.ts.map +0 -1
package/dist/esm/index.mjs
CHANGED
|
@@ -61,8 +61,6 @@ const HEATMAP_STYLE = {
|
|
|
61
61
|
},
|
|
62
62
|
wrapper: {
|
|
63
63
|
padding: `${HEATMAP_CONFIG.padding}px 0`,
|
|
64
|
-
paddingBlock: `${HEATMAP_CONFIG.padding}px`,
|
|
65
|
-
paddingInline: `${HEATMAP_CONFIG.padding}px`,
|
|
66
64
|
},
|
|
67
65
|
};
|
|
68
66
|
const DEFAULT_SIDEBAR_WIDTH = 260;
|
|
@@ -141,12 +139,15 @@ const useHeatmapVizStore = create()((set, get) => {
|
|
|
141
139
|
isRenderViz: false,
|
|
142
140
|
setIsRenderViz: (isRenderViz) => set({ isRenderViz }),
|
|
143
141
|
scale: 1,
|
|
142
|
+
vizRef: undefined,
|
|
143
|
+
iframeHeight: 0,
|
|
144
144
|
setScale: (scale) => set({ scale }),
|
|
145
|
+
setVizRef: (vizRef) => set({ vizRef }),
|
|
146
|
+
setIframeHeight: (iframeHeight) => set({ iframeHeight }),
|
|
145
147
|
};
|
|
146
148
|
});
|
|
147
149
|
|
|
148
150
|
const initialState = {
|
|
149
|
-
payloads: [],
|
|
150
151
|
htmlContent: '',
|
|
151
152
|
wrapperHeight: 0,
|
|
152
153
|
iframeHeight: 0,
|
|
@@ -155,23 +156,12 @@ const useHeatmapLiveStore = create()((set, get) => {
|
|
|
155
156
|
return {
|
|
156
157
|
...initialState,
|
|
157
158
|
reset: () => set(initialState),
|
|
158
|
-
setPayloads: (payloads) => set({ payloads }),
|
|
159
|
-
addPayload: (payload) => set((state) => ({ payloads: [...state.payloads, payload] })),
|
|
160
159
|
setHtmlContent: (htmlContent) => set({ htmlContent }),
|
|
161
160
|
setWrapperHeight: (wrapperHeight) => set({ wrapperHeight }),
|
|
162
161
|
setIframeHeight: (iframeHeight) => set({ iframeHeight }),
|
|
163
162
|
};
|
|
164
163
|
});
|
|
165
164
|
|
|
166
|
-
const useHeatmapSingleStore = create()((set, get) => {
|
|
167
|
-
return {
|
|
168
|
-
vizRef: null,
|
|
169
|
-
iframeHeight: 0,
|
|
170
|
-
setVizRef: (vizRef) => set({ vizRef }),
|
|
171
|
-
setIframeHeight: (iframeHeight) => set({ iframeHeight }),
|
|
172
|
-
};
|
|
173
|
-
});
|
|
174
|
-
|
|
175
165
|
const useRegisterConfig = () => {
|
|
176
166
|
const mode = useHeatmapConfigStore((state) => state.mode);
|
|
177
167
|
const width = useHeatmapConfigStore((state) => state.width);
|
|
@@ -511,311 +501,91 @@ function isElementInViewport(elementRect, visualRef, scale) {
|
|
|
511
501
|
return elementBottom > viewportTop && elementTop < viewportBottom;
|
|
512
502
|
}
|
|
513
503
|
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
504
|
+
const getScriptInjectCode = async () => {
|
|
505
|
+
const moduleResult = (await Promise.resolve().then(function () { return viewportReplacer; }));
|
|
506
|
+
const ActualClass = moduleResult.default;
|
|
507
|
+
const classCode = ActualClass.toString();
|
|
508
|
+
const classInstantiateCode = ActualClass.name;
|
|
509
|
+
const scriptCode = `
|
|
510
|
+
(function() {
|
|
511
|
+
'use strict';
|
|
512
|
+
${classCode}
|
|
513
|
+
new ${classInstantiateCode}()
|
|
514
|
+
})();
|
|
515
|
+
`;
|
|
516
|
+
return scriptCode;
|
|
517
|
+
};
|
|
518
|
+
class ViewportUnitsFixer {
|
|
519
|
+
iframe = null;
|
|
520
|
+
config;
|
|
521
|
+
constructor(config) {
|
|
522
|
+
this.config = config;
|
|
523
|
+
this.iframe = config.iframe;
|
|
528
524
|
this.init();
|
|
529
525
|
}
|
|
530
|
-
init() {
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
this.blockLinkNavigation();
|
|
535
|
-
// Chặn form submissions
|
|
536
|
-
this.blockFormSubmissions();
|
|
537
|
-
// Chặn window.open (này an toàn)
|
|
538
|
-
this.blockWindowOpen();
|
|
539
|
-
// Chặn beforeunload để prevent navigation
|
|
540
|
-
this.blockBeforeUnload();
|
|
541
|
-
// Monitor DOM changes để block dynamic links
|
|
542
|
-
this.monitorDOMChanges();
|
|
543
|
-
// Inject CSP nếu có thể
|
|
544
|
-
this.injectCSP();
|
|
545
|
-
}
|
|
546
|
-
catch (error) {
|
|
547
|
-
console.error('[NavigationBlocker] Init error:', error);
|
|
548
|
-
}
|
|
549
|
-
}
|
|
550
|
-
blockLinkNavigation() {
|
|
551
|
-
// Sử dụng capture phase để chặn sớm nhất
|
|
552
|
-
this.doc.addEventListener('click', (e) => {
|
|
553
|
-
if (!this.isEnabled)
|
|
554
|
-
return;
|
|
555
|
-
const target = e.target;
|
|
556
|
-
const link = target.closest('a');
|
|
557
|
-
if (link) {
|
|
558
|
-
const href = link.getAttribute('href');
|
|
559
|
-
// Cho phép hash links và empty links
|
|
560
|
-
if (!href || href === '' || href === '#' || href.startsWith('#')) {
|
|
561
|
-
console.log('[NavigationBlocker] Allowed hash navigation:', href);
|
|
562
|
-
return;
|
|
563
|
-
}
|
|
564
|
-
// Chặn tất cả các loại navigation
|
|
565
|
-
console.log('[NavigationBlocker] Blocked link navigation to:', href);
|
|
566
|
-
e.preventDefault();
|
|
567
|
-
e.stopPropagation();
|
|
568
|
-
e.stopImmediatePropagation();
|
|
569
|
-
this.notifyBlockedNavigation(href);
|
|
570
|
-
}
|
|
571
|
-
}, true);
|
|
572
|
-
// Chặn cả middle click và right click "open in new tab"
|
|
573
|
-
this.doc.addEventListener('auxclick', (e) => {
|
|
574
|
-
if (!this.isEnabled)
|
|
575
|
-
return;
|
|
576
|
-
const target = e.target;
|
|
577
|
-
const link = target.closest('a');
|
|
578
|
-
if (link) {
|
|
579
|
-
const href = link.getAttribute('href');
|
|
580
|
-
if (href && !href.startsWith('#')) {
|
|
581
|
-
console.log('[NavigationBlocker] Blocked auxclick navigation');
|
|
582
|
-
e.preventDefault();
|
|
583
|
-
e.stopPropagation();
|
|
584
|
-
e.stopImmediatePropagation();
|
|
585
|
-
}
|
|
586
|
-
}
|
|
587
|
-
}, true);
|
|
588
|
-
// Disable tất cả links ngay từ đầu
|
|
589
|
-
this.disableAllLinks();
|
|
590
|
-
}
|
|
591
|
-
disableAllLinks() {
|
|
592
|
-
this.doc.querySelectorAll('a[href]').forEach((link) => {
|
|
593
|
-
const href = link.getAttribute('href');
|
|
594
|
-
if (href && !href.startsWith('#')) {
|
|
595
|
-
// Thêm pointer-events: none và cursor
|
|
596
|
-
link.style.cursor = 'not-allowed';
|
|
597
|
-
link.setAttribute('data-navigation-blocked', 'true');
|
|
598
|
-
// Remove href để browser không hiện preview
|
|
599
|
-
link.setAttribute('data-original-href', href);
|
|
600
|
-
link.removeAttribute('href');
|
|
601
|
-
// Hoặc giữ href nhưng disable
|
|
602
|
-
// link.setAttribute('onclick', 'return false');
|
|
603
|
-
}
|
|
604
|
-
});
|
|
605
|
-
}
|
|
606
|
-
blockFormSubmissions() {
|
|
607
|
-
this.doc.addEventListener('submit', (e) => {
|
|
608
|
-
if (!this.isEnabled)
|
|
609
|
-
return;
|
|
610
|
-
const form = e.target;
|
|
611
|
-
const action = form.getAttribute('action');
|
|
612
|
-
// Cho phép forms không có action
|
|
613
|
-
if (!action || action === '' || action === '#') {
|
|
614
|
-
console.log('[NavigationBlocker] Allowed same-page form');
|
|
615
|
-
e.preventDefault();
|
|
616
|
-
this.handleFormSubmit(form);
|
|
617
|
-
return;
|
|
618
|
-
}
|
|
619
|
-
// Chặn tất cả external submissions
|
|
620
|
-
console.log('[NavigationBlocker] Blocked form submission to:', action);
|
|
621
|
-
e.preventDefault();
|
|
622
|
-
e.stopPropagation();
|
|
623
|
-
e.stopImmediatePropagation();
|
|
624
|
-
this.notifyBlockedNavigation(action);
|
|
625
|
-
}, true);
|
|
626
|
-
}
|
|
627
|
-
blockWindowOpen() {
|
|
628
|
-
// Override window.open - đây là safe
|
|
629
|
-
this.win.open = ((...args) => {
|
|
630
|
-
if (!this.isEnabled) {
|
|
631
|
-
return this.originalWindowOpen(...args);
|
|
632
|
-
}
|
|
633
|
-
const url = args[0]?.toString() || 'popup';
|
|
634
|
-
console.log('[NavigationBlocker] Blocked window.open:', url);
|
|
635
|
-
this.notifyBlockedNavigation(url);
|
|
636
|
-
return null;
|
|
637
|
-
});
|
|
638
|
-
}
|
|
639
|
-
blockBeforeUnload() {
|
|
640
|
-
// Chặn unload
|
|
641
|
-
this.win.addEventListener('beforeunload', (e) => {
|
|
642
|
-
if (!this.isEnabled)
|
|
643
|
-
return;
|
|
644
|
-
console.log('[NavigationBlocker] Blocked beforeunload');
|
|
645
|
-
e.preventDefault();
|
|
646
|
-
e.returnValue = '';
|
|
647
|
-
return '';
|
|
648
|
-
}, true);
|
|
649
|
-
// Chặn unload
|
|
650
|
-
this.win.addEventListener('unload', (e) => {
|
|
651
|
-
if (!this.isEnabled)
|
|
652
|
-
return;
|
|
653
|
-
console.log('[NavigationBlocker] Blocked unload');
|
|
654
|
-
e.preventDefault();
|
|
655
|
-
e.stopPropagation();
|
|
656
|
-
}, true);
|
|
657
|
-
// Monitor popstate
|
|
658
|
-
this.win.addEventListener('popstate', (e) => {
|
|
659
|
-
if (!this.isEnabled)
|
|
660
|
-
return;
|
|
661
|
-
console.log('[NavigationBlocker] Blocked popstate');
|
|
662
|
-
e.preventDefault();
|
|
663
|
-
e.stopPropagation();
|
|
664
|
-
}, true);
|
|
665
|
-
}
|
|
666
|
-
monitorDOMChanges() {
|
|
667
|
-
// Monitor khi có links mới được thêm vào
|
|
668
|
-
const observer = new MutationObserver((mutations) => {
|
|
669
|
-
if (!this.isEnabled)
|
|
670
|
-
return;
|
|
671
|
-
mutations.forEach((mutation) => {
|
|
672
|
-
mutation.addedNodes.forEach((node) => {
|
|
673
|
-
if (node.nodeType === Node.ELEMENT_NODE) {
|
|
674
|
-
const element = node;
|
|
675
|
-
// Nếu là link
|
|
676
|
-
if (element.tagName === 'A') {
|
|
677
|
-
const href = element.getAttribute('href');
|
|
678
|
-
if (href && !href.startsWith('#')) {
|
|
679
|
-
element.style.cursor = 'not-allowed';
|
|
680
|
-
element.setAttribute('data-navigation-blocked', 'true');
|
|
681
|
-
element.setAttribute('data-original-href', href);
|
|
682
|
-
element.removeAttribute('href');
|
|
683
|
-
}
|
|
684
|
-
}
|
|
685
|
-
// Tìm links trong subtree
|
|
686
|
-
element.querySelectorAll('a[href]').forEach((link) => {
|
|
687
|
-
const href = link.getAttribute('href');
|
|
688
|
-
if (href && !href.startsWith('#')) {
|
|
689
|
-
link.style.cursor = 'not-allowed';
|
|
690
|
-
link.setAttribute('data-navigation-blocked', 'true');
|
|
691
|
-
link.setAttribute('data-original-href', href);
|
|
692
|
-
link.removeAttribute('href');
|
|
693
|
-
}
|
|
694
|
-
});
|
|
695
|
-
}
|
|
696
|
-
});
|
|
697
|
-
});
|
|
698
|
-
});
|
|
699
|
-
observer.observe(this.doc.body, {
|
|
700
|
-
childList: true,
|
|
701
|
-
subtree: true,
|
|
702
|
-
});
|
|
703
|
-
this.observers.push(observer);
|
|
704
|
-
}
|
|
705
|
-
injectCSP() {
|
|
706
|
-
// Thêm CSP meta tag nếu chưa có (optional)
|
|
707
|
-
try {
|
|
708
|
-
const existingCSP = this.doc.querySelector('meta[http-equiv="Content-Security-Policy"]');
|
|
709
|
-
if (!existingCSP) {
|
|
710
|
-
const meta = this.doc.createElement('meta');
|
|
711
|
-
meta.httpEquiv = 'Content-Security-Policy';
|
|
712
|
-
meta.content = "navigate-to 'none'"; // Chặn tất cả navigation
|
|
713
|
-
this.doc.head.appendChild(meta);
|
|
714
|
-
console.log('[NavigationBlocker] Injected CSP');
|
|
715
|
-
}
|
|
526
|
+
async init() {
|
|
527
|
+
if (!this.iframe) {
|
|
528
|
+
console.error('[Parent] Required elements not found');
|
|
529
|
+
return;
|
|
716
530
|
}
|
|
717
|
-
|
|
718
|
-
|
|
531
|
+
// this.injectScriptContent = await generateIframeInjectScript();
|
|
532
|
+
window.addEventListener('message', this.handleMessage.bind(this));
|
|
533
|
+
if (this.iframe.contentDocument?.readyState === 'complete') {
|
|
534
|
+
await this.injectScript();
|
|
719
535
|
}
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
const formData = new FormData(form);
|
|
723
|
-
const data = {};
|
|
724
|
-
formData.forEach((value, key) => {
|
|
725
|
-
data[key] = value;
|
|
726
|
-
});
|
|
727
|
-
console.log('[NavigationBlocker] Handling form data:', data);
|
|
728
|
-
window.dispatchEvent(new CustomEvent('iframe-form-submit', {
|
|
729
|
-
detail: { form, data },
|
|
730
|
-
}));
|
|
731
|
-
}
|
|
732
|
-
notifyBlockedNavigation(url) {
|
|
733
|
-
console.warn('[NavigationBlocker] Navigation blocked to:', url);
|
|
734
|
-
window.dispatchEvent(new CustomEvent('iframe-navigation-blocked', {
|
|
735
|
-
detail: { url, timestamp: Date.now() },
|
|
736
|
-
}));
|
|
737
|
-
if (this.shouldShowMessage(url)) {
|
|
738
|
-
this.showBlockedMessage(url);
|
|
536
|
+
else {
|
|
537
|
+
this.iframe.addEventListener('load', () => this.injectScript());
|
|
739
538
|
}
|
|
740
539
|
}
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
}
|
|
744
|
-
showBlockedMessage(url) {
|
|
745
|
-
if (!this.showMessage)
|
|
540
|
+
async injectScript() {
|
|
541
|
+
if (!this.iframe?.contentWindow || !this.iframe.contentDocument)
|
|
746
542
|
return;
|
|
747
|
-
const
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
pointer-events: none;
|
|
763
|
-
`;
|
|
764
|
-
const shortUrl = url.length > 50 ? url.substring(0, 47) + '...' : url;
|
|
765
|
-
message.innerHTML = `
|
|
766
|
-
<div style="font-weight: 600; margin-bottom: 4px;">🚫 Navigation Blocked</div>
|
|
767
|
-
<div style="font-size: 12px; opacity: 0.9;">${this.escapeHtml(shortUrl)}</div>
|
|
768
|
-
`;
|
|
769
|
-
this.doc.body.appendChild(message);
|
|
770
|
-
setTimeout(() => {
|
|
771
|
-
message.style.opacity = '0';
|
|
772
|
-
message.style.transition = 'opacity 0.3s';
|
|
773
|
-
setTimeout(() => message.remove(), 300);
|
|
774
|
-
}, 3000);
|
|
775
|
-
}
|
|
776
|
-
escapeHtml(text) {
|
|
777
|
-
const div = this.doc.createElement('div');
|
|
778
|
-
div.textContent = text;
|
|
779
|
-
return div.innerHTML;
|
|
780
|
-
}
|
|
781
|
-
enable() {
|
|
782
|
-
this.isEnabled = true;
|
|
783
|
-
console.log('[NavigationBlocker] Enabled');
|
|
784
|
-
}
|
|
785
|
-
enableMessage() {
|
|
786
|
-
this.showMessage = true;
|
|
787
|
-
console.log('[NavigationBlocker] Enabled message');
|
|
788
|
-
}
|
|
789
|
-
disable() {
|
|
790
|
-
this.isEnabled = false;
|
|
791
|
-
console.log('[NavigationBlocker] Disabled');
|
|
543
|
+
const win = this.iframe.contentWindow;
|
|
544
|
+
const doc = this.iframe.contentDocument;
|
|
545
|
+
win.__viewportConfig = this.config;
|
|
546
|
+
const script = doc.createElement('script');
|
|
547
|
+
const codeInject = await getScriptInjectCode();
|
|
548
|
+
script.textContent = codeInject;
|
|
549
|
+
script.type = 'text/javascript';
|
|
550
|
+
script.id = 'viewport-replacer';
|
|
551
|
+
script.onload = () => console.log('[Parent] Viewport replacer module loaded');
|
|
552
|
+
script.onerror = () => {
|
|
553
|
+
this.config.onSuccess?.({
|
|
554
|
+
height: 1000,
|
|
555
|
+
});
|
|
556
|
+
};
|
|
557
|
+
doc.head.appendChild(script);
|
|
792
558
|
}
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
559
|
+
handleMessage(event) {
|
|
560
|
+
const data = event.data;
|
|
561
|
+
if (!data || data.type !== 'IFRAME_HEIGHT_CALCULATED')
|
|
562
|
+
return;
|
|
563
|
+
this.config.onSuccess?.(data);
|
|
796
564
|
}
|
|
797
|
-
|
|
798
|
-
this.
|
|
799
|
-
this.showMessage = false;
|
|
800
|
-
// Cleanup observers
|
|
801
|
-
this.observers.forEach((observer) => observer.disconnect());
|
|
802
|
-
this.observers = [];
|
|
803
|
-
console.log('[NavigationBlocker] Destroyed');
|
|
565
|
+
recalculate() {
|
|
566
|
+
this.injectScript();
|
|
804
567
|
}
|
|
805
568
|
}
|
|
569
|
+
function initViewportFixer(config) {
|
|
570
|
+
const fixer = new ViewportUnitsFixer(config);
|
|
571
|
+
window.viewportFixer = fixer;
|
|
572
|
+
window.addEventListener('iframe-dimensions-applied', ((e) => {
|
|
573
|
+
const ev = e;
|
|
574
|
+
console.log('Iframe dimensions finalized:', ev.detail);
|
|
575
|
+
}));
|
|
576
|
+
return fixer;
|
|
577
|
+
}
|
|
806
578
|
|
|
807
|
-
class
|
|
808
|
-
doc;
|
|
809
|
-
win;
|
|
579
|
+
class ViewportUnitsReplacer {
|
|
810
580
|
config;
|
|
811
581
|
regex = /([-.\d]+)(vh|svh|lvh|dvh|vw|svw|lvw|dvw)/gi;
|
|
812
|
-
constructor(
|
|
813
|
-
if (!
|
|
814
|
-
throw new Error('Iframe
|
|
582
|
+
constructor() {
|
|
583
|
+
if (!window.__viewportConfig) {
|
|
584
|
+
throw new Error('[Iframe] Do not have viewport config');
|
|
815
585
|
}
|
|
816
|
-
this.
|
|
817
|
-
|
|
818
|
-
this.
|
|
586
|
+
this.config = window.__viewportConfig;
|
|
587
|
+
console.log('[Iframe] ViewportUnitsReplacer started with config:', this.config);
|
|
588
|
+
this.init();
|
|
819
589
|
}
|
|
820
590
|
px(value) {
|
|
821
591
|
return `${value.toFixed(2)}px`;
|
|
@@ -841,28 +611,26 @@ class IframeStyleReplacer {
|
|
|
841
611
|
}
|
|
842
612
|
processInlineStyles() {
|
|
843
613
|
let count = 0;
|
|
844
|
-
|
|
614
|
+
document.querySelectorAll('[style]').forEach((el) => {
|
|
845
615
|
const style = el.getAttribute('style');
|
|
846
616
|
if (style && this.regex.test(style)) {
|
|
847
|
-
this.regex.lastIndex = 0;
|
|
848
617
|
el.setAttribute('style', this.replaceInText(style));
|
|
849
618
|
count++;
|
|
850
619
|
}
|
|
851
620
|
});
|
|
852
|
-
console.log(`[
|
|
621
|
+
console.log(`[Iframe] Replaced ${count} inline style elements`);
|
|
853
622
|
return count;
|
|
854
623
|
}
|
|
855
624
|
processStyleTags() {
|
|
856
625
|
let count = 0;
|
|
857
|
-
|
|
626
|
+
document.querySelectorAll('style').forEach((tag) => {
|
|
858
627
|
const css = tag.textContent || '';
|
|
859
628
|
if (this.regex.test(css)) {
|
|
860
|
-
this.regex.lastIndex = 0;
|
|
861
629
|
tag.textContent = this.replaceInText(css);
|
|
862
630
|
count++;
|
|
863
631
|
}
|
|
864
632
|
});
|
|
865
|
-
console.log(`[
|
|
633
|
+
console.log(`[Iframe] Replaced ${count} <style> tags`);
|
|
866
634
|
return count;
|
|
867
635
|
}
|
|
868
636
|
processRule(rule) {
|
|
@@ -873,7 +641,6 @@ class IframeStyleReplacer {
|
|
|
873
641
|
const prop = style[i];
|
|
874
642
|
const value = style.getPropertyValue(prop);
|
|
875
643
|
if (value && this.regex.test(value)) {
|
|
876
|
-
this.regex.lastIndex = 0;
|
|
877
644
|
style.setProperty(prop, this.replaceInText(value), style.getPropertyPriority(prop));
|
|
878
645
|
count++;
|
|
879
646
|
}
|
|
@@ -889,11 +656,11 @@ class IframeStyleReplacer {
|
|
|
889
656
|
}
|
|
890
657
|
processStylesheets() {
|
|
891
658
|
let total = 0;
|
|
892
|
-
Array.from(
|
|
659
|
+
Array.from(document.styleSheets).forEach((sheet) => {
|
|
893
660
|
try {
|
|
894
661
|
// Bỏ qua external CSS (cross-origin)
|
|
895
|
-
if (sheet.href && !sheet.href.startsWith(
|
|
896
|
-
console.log('[
|
|
662
|
+
if (sheet.href && !sheet.href.startsWith(location.origin)) {
|
|
663
|
+
console.log('[Iframe] Skipping external CSS:', sheet.href);
|
|
897
664
|
return;
|
|
898
665
|
}
|
|
899
666
|
const rules = sheet.cssRules || sheet.rules;
|
|
@@ -904,27 +671,26 @@ class IframeStyleReplacer {
|
|
|
904
671
|
}
|
|
905
672
|
}
|
|
906
673
|
catch (e) {
|
|
907
|
-
console.warn('[
|
|
674
|
+
console.warn('[Iframe] Cannot read stylesheet (CORS?):', e.message);
|
|
908
675
|
}
|
|
909
676
|
});
|
|
910
|
-
console.log(`[
|
|
677
|
+
console.log(`[Iframe] Replaced ${total} rules in stylesheets`);
|
|
911
678
|
return total;
|
|
912
679
|
}
|
|
913
680
|
async processLinkedStylesheets() {
|
|
914
|
-
const links =
|
|
681
|
+
const links = document.querySelectorAll('link[rel="stylesheet"]');
|
|
915
682
|
let count = 0;
|
|
916
683
|
for (const link of Array.from(links)) {
|
|
917
|
-
if (!link.href.startsWith(
|
|
918
|
-
console.log('[
|
|
684
|
+
if (!link.href.startsWith(location.origin)) {
|
|
685
|
+
console.log('[Iframe] Skipping external CSS:', link.href);
|
|
919
686
|
continue;
|
|
920
687
|
}
|
|
921
688
|
try {
|
|
922
689
|
const res = await fetch(link.href);
|
|
923
690
|
let css = await res.text();
|
|
924
691
|
if (this.regex.test(css)) {
|
|
925
|
-
this.regex.lastIndex = 0;
|
|
926
692
|
css = this.replaceInText(css);
|
|
927
|
-
const style =
|
|
693
|
+
const style = document.createElement('style');
|
|
928
694
|
style.textContent = css;
|
|
929
695
|
style.dataset.originalHref = link.href;
|
|
930
696
|
link.parentNode?.insertBefore(style, link);
|
|
@@ -933,25 +699,30 @@ class IframeStyleReplacer {
|
|
|
933
699
|
}
|
|
934
700
|
}
|
|
935
701
|
catch (e) {
|
|
936
|
-
console.warn('[
|
|
702
|
+
console.warn('[Iframe] Cannot load CSS:', link.href, e);
|
|
937
703
|
}
|
|
938
704
|
}
|
|
939
|
-
console.log(`[
|
|
705
|
+
console.log(`[Iframe] Replaced ${count} linked CSS files`);
|
|
940
706
|
return count;
|
|
941
707
|
}
|
|
942
708
|
getFinalHeight() {
|
|
943
709
|
// Trigger reflow
|
|
944
|
-
void
|
|
945
|
-
return Math.max(
|
|
710
|
+
void document.body.offsetHeight;
|
|
711
|
+
return Math.max(document.body.scrollHeight, document.body.offsetHeight, document.documentElement.scrollHeight, document.documentElement.offsetHeight, document.documentElement.clientHeight);
|
|
946
712
|
}
|
|
947
|
-
|
|
948
|
-
|
|
713
|
+
notifyParent(height) {
|
|
714
|
+
window.parent.postMessage({
|
|
715
|
+
type: 'IFRAME_HEIGHT_CALCULATED',
|
|
716
|
+
height,
|
|
717
|
+
width: document.body.scrollWidth,
|
|
718
|
+
}, '*');
|
|
719
|
+
console.log('[Iframe] Sent height to parent:', height);
|
|
949
720
|
}
|
|
950
721
|
async waitForResources() {
|
|
951
|
-
if ('fonts' in
|
|
952
|
-
await
|
|
722
|
+
if ('fonts' in document) {
|
|
723
|
+
await document.fonts.ready;
|
|
953
724
|
}
|
|
954
|
-
const images = Array.from(
|
|
725
|
+
const images = Array.from(document.images).filter((img) => !img.complete);
|
|
955
726
|
if (images.length > 0) {
|
|
956
727
|
await Promise.all(images.map((img) => new Promise((resolve) => {
|
|
957
728
|
img.onload = img.onerror = resolve;
|
|
@@ -960,131 +731,35 @@ class IframeStyleReplacer {
|
|
|
960
731
|
}
|
|
961
732
|
async run() {
|
|
962
733
|
try {
|
|
963
|
-
console.log('[IframeStyleReplacer] Starting viewport units replacement...');
|
|
964
734
|
this.processInlineStyles();
|
|
965
735
|
this.processStyleTags();
|
|
966
736
|
this.processStylesheets();
|
|
967
737
|
await this.processLinkedStylesheets();
|
|
968
738
|
// await this.waitForResources();
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
const width = this.getFinalWidth();
|
|
973
|
-
console.log('[IframeStyleReplacer] Calculated dimensions:', { height, width });
|
|
974
|
-
resolve({ height, width });
|
|
975
|
-
});
|
|
739
|
+
requestAnimationFrame(() => {
|
|
740
|
+
const height = this.getFinalHeight();
|
|
741
|
+
this.notifyParent(height);
|
|
976
742
|
});
|
|
977
743
|
}
|
|
978
744
|
catch (err) {
|
|
979
|
-
console.error('[
|
|
980
|
-
|
|
981
|
-
height: this.doc.body.scrollHeight || 1000,
|
|
982
|
-
width: this.doc.body.scrollWidth || 1000,
|
|
983
|
-
};
|
|
745
|
+
console.error('[Iframe] Critical error:', err);
|
|
746
|
+
this.notifyParent(document.body.scrollHeight || 1000);
|
|
984
747
|
}
|
|
985
748
|
}
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
}
|
|
990
|
-
|
|
991
|
-
class IframeHelperFixer {
|
|
992
|
-
iframe;
|
|
993
|
-
config;
|
|
994
|
-
replacer = null;
|
|
995
|
-
navigationBlocker = null;
|
|
996
|
-
constructor(config) {
|
|
997
|
-
this.config = config;
|
|
998
|
-
this.iframe = config.iframe;
|
|
999
|
-
this.init();
|
|
1000
|
-
}
|
|
1001
|
-
async init() {
|
|
1002
|
-
if (!this.iframe) {
|
|
1003
|
-
console.error('[IframeHelper] iframe not found');
|
|
1004
|
-
this.config.onError?.(new Error('iframe not found'));
|
|
1005
|
-
return;
|
|
1006
|
-
}
|
|
1007
|
-
// Wait for iframe to load completely
|
|
1008
|
-
if (this.iframe.contentDocument?.readyState === 'complete') {
|
|
1009
|
-
await this.process();
|
|
749
|
+
init() {
|
|
750
|
+
if (document.readyState === 'loading') {
|
|
751
|
+
document.addEventListener('DOMContentLoaded', () => this.run());
|
|
1010
752
|
}
|
|
1011
753
|
else {
|
|
1012
|
-
this.
|
|
1013
|
-
}
|
|
1014
|
-
}
|
|
1015
|
-
async process() {
|
|
1016
|
-
if (!this.iframe.contentDocument || !this.iframe.contentWindow) {
|
|
1017
|
-
console.error('[IframeHelper] Cannot access iframe document');
|
|
1018
|
-
this.config.onError?.(new Error('Cannot access iframe document'));
|
|
1019
|
-
return;
|
|
1020
|
-
}
|
|
1021
|
-
try {
|
|
1022
|
-
console.log('[IframeHelper] Processing viewport units...');
|
|
1023
|
-
// Create replacer instance
|
|
1024
|
-
this.replacer = new IframeStyleReplacer(this.iframe, this.config);
|
|
1025
|
-
// Create navigation blocker
|
|
1026
|
-
this.navigationBlocker = new IframeNavigationBlockerV2(this.iframe);
|
|
1027
|
-
// Run replacement
|
|
1028
|
-
const result = await this.replacer.run();
|
|
1029
|
-
console.log('[IframeHelper] Process completed:', result);
|
|
1030
|
-
// Trigger success callback
|
|
1031
|
-
this.config.onSuccess?.(result);
|
|
1032
|
-
// Dispatch custom event
|
|
1033
|
-
window.dispatchEvent(new CustomEvent('iframe-dimensions-applied', {
|
|
1034
|
-
detail: result,
|
|
1035
|
-
}));
|
|
1036
|
-
}
|
|
1037
|
-
catch (error) {
|
|
1038
|
-
console.error('[IframeHelper] Failed to process:', error);
|
|
1039
|
-
this.config.onError?.(error);
|
|
1040
|
-
}
|
|
1041
|
-
}
|
|
1042
|
-
async recalculate() {
|
|
1043
|
-
console.log('[IframeHelper] Recalculating...');
|
|
1044
|
-
await this.process();
|
|
1045
|
-
}
|
|
1046
|
-
updateConfig(config) {
|
|
1047
|
-
this.config = { ...this.config, ...config };
|
|
1048
|
-
if (this.replacer) {
|
|
1049
|
-
this.replacer.updateConfig(config);
|
|
754
|
+
this.run();
|
|
1050
755
|
}
|
|
1051
756
|
}
|
|
1052
|
-
enableNavigationBlocking() {
|
|
1053
|
-
this.navigationBlocker?.enable();
|
|
1054
|
-
}
|
|
1055
|
-
enableNavigationBlockingMessage() {
|
|
1056
|
-
this.navigationBlocker?.enableMessage();
|
|
1057
|
-
}
|
|
1058
|
-
disableNavigationBlocking() {
|
|
1059
|
-
this.navigationBlocker?.disable();
|
|
1060
|
-
}
|
|
1061
|
-
disableNavigationBlockingMessage() {
|
|
1062
|
-
this.navigationBlocker?.disableMessage();
|
|
1063
|
-
}
|
|
1064
|
-
destroy() {
|
|
1065
|
-
this.replacer = null;
|
|
1066
|
-
this.navigationBlocker?.destroy();
|
|
1067
|
-
this.navigationBlocker = null;
|
|
1068
|
-
console.log('[IframeHelper] Destroyed');
|
|
1069
|
-
}
|
|
1070
757
|
}
|
|
1071
758
|
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
console.log('[IframeHelper] Iframe dimensions finalized:', ev.detail);
|
|
1077
|
-
}));
|
|
1078
|
-
window.addEventListener('iframe-navigation-blocked', ((e) => {
|
|
1079
|
-
const ev = e;
|
|
1080
|
-
console.warn('[IframeHelper] Iframe tried to navigate to:', ev.detail.url);
|
|
1081
|
-
}));
|
|
1082
|
-
window.addEventListener('iframe-form-submit', ((e) => {
|
|
1083
|
-
const ev = e;
|
|
1084
|
-
console.log('[IframeHelper] Iframe form submitted:', ev.detail.data);
|
|
1085
|
-
}));
|
|
1086
|
-
return fixer;
|
|
1087
|
-
}
|
|
759
|
+
var viewportReplacer = /*#__PURE__*/Object.freeze({
|
|
760
|
+
__proto__: null,
|
|
761
|
+
default: ViewportUnitsReplacer
|
|
762
|
+
});
|
|
1088
763
|
|
|
1089
764
|
const scrollToElementIfNeeded = (visualRef, rect, scale) => {
|
|
1090
765
|
if (!visualRef.current)
|
|
@@ -1198,7 +873,7 @@ const useHeatmapEffects = ({ isVisible, isElementSidebarOpen, setShouldShowCallo
|
|
|
1198
873
|
|
|
1199
874
|
const useHeatmapElementPosition = ({ iframeRef, wrapperRef, visualizer }) => {
|
|
1200
875
|
const widthScale = useHeatmapVizStore((state) => state.scale);
|
|
1201
|
-
const iframeHeight =
|
|
876
|
+
const iframeHeight = useHeatmapVizStore((state) => state.iframeHeight);
|
|
1202
877
|
const heatmapWidth = useHeatmapConfigStore((state) => state.width);
|
|
1203
878
|
return useCallback((element) => {
|
|
1204
879
|
const hash = element?.hash;
|
|
@@ -1246,179 +921,6 @@ const debounce = (fn, delay) => {
|
|
|
1246
921
|
};
|
|
1247
922
|
};
|
|
1248
923
|
|
|
1249
|
-
// ===================== CONSTANTS =====================
|
|
1250
|
-
const HEATMAP_ELEMENT_ATTRIBUTE = 'data-clarity-hashalpha'; // Hoặc attribute bạn đang dùng
|
|
1251
|
-
// ===================== UTILITY FUNCTIONS =====================
|
|
1252
|
-
/**
|
|
1253
|
-
* Lấy bounding box tuyệt đối của element (relative to document)
|
|
1254
|
-
*/
|
|
1255
|
-
function getBoundingBox(element) {
|
|
1256
|
-
if (typeof element.getBoundingClientRect !== 'function') {
|
|
1257
|
-
return null;
|
|
1258
|
-
}
|
|
1259
|
-
const rect = element.getBoundingClientRect();
|
|
1260
|
-
// Lấy scroll offset (hỗ trợ cả cách cũ và mới)
|
|
1261
|
-
const scrollLeft = 'pageXOffset' in window ? window.pageXOffset : document.documentElement.scrollLeft;
|
|
1262
|
-
const scrollTop = 'pageYOffset' in window ? window.pageYOffset : document.documentElement.scrollTop;
|
|
1263
|
-
// Kiểm tra element có kích thước hợp lệ
|
|
1264
|
-
if (!rect || (rect.height === 0 && rect.width === 0)) {
|
|
1265
|
-
return null;
|
|
1266
|
-
}
|
|
1267
|
-
// Trả về vị trí tuyệt đối
|
|
1268
|
-
return {
|
|
1269
|
-
left: Math.floor(rect.left + scrollLeft),
|
|
1270
|
-
top: Math.floor(rect.top + scrollTop),
|
|
1271
|
-
width: Math.floor(rect.width),
|
|
1272
|
-
height: Math.floor(rect.height),
|
|
1273
|
-
};
|
|
1274
|
-
}
|
|
1275
|
-
/**
|
|
1276
|
-
* Lấy tất cả elements tại tọa độ (x, y), hỗ trợ Shadow DOM
|
|
1277
|
-
*/
|
|
1278
|
-
function getElementsAtPoint(documentOrShadowRoot, x, y, filterFunction, visitedShadowRoots = new Set()) {
|
|
1279
|
-
// Lấy tất cả elements tại vị trí
|
|
1280
|
-
const elementsAtPoint = documentOrShadowRoot.elementsFromPoint(x, y);
|
|
1281
|
-
if (!filterFunction) {
|
|
1282
|
-
return elementsAtPoint;
|
|
1283
|
-
}
|
|
1284
|
-
// Tìm element đầu tiên match với filter
|
|
1285
|
-
const matchedElement = elementsAtPoint.find(filterFunction);
|
|
1286
|
-
// Nếu element có Shadow DOM và chưa visit -> đệ quy vào
|
|
1287
|
-
if (matchedElement?.shadowRoot && !visitedShadowRoots.has(matchedElement.shadowRoot)) {
|
|
1288
|
-
visitedShadowRoots.add(matchedElement.shadowRoot);
|
|
1289
|
-
return getElementsAtPoint(matchedElement.shadowRoot, x, y, filterFunction, visitedShadowRoots);
|
|
1290
|
-
}
|
|
1291
|
-
return elementsAtPoint;
|
|
1292
|
-
}
|
|
1293
|
-
// ===================== MAIN HOOK =====================
|
|
1294
|
-
function useHeatmapMouseHandler(props) {
|
|
1295
|
-
const { heatmapWrapperRef, iframeRef, parentRef, heatmapInfo, scaleRatio, onElementHover } = props;
|
|
1296
|
-
const handleMouseMove = useCallback((event) => {
|
|
1297
|
-
// Kiểm tra tất cả refs và data cần thiết
|
|
1298
|
-
if (!heatmapWrapperRef?.current ||
|
|
1299
|
-
!iframeRef?.current ||
|
|
1300
|
-
!iframeRef.current.contentDocument ||
|
|
1301
|
-
!heatmapInfo?.elementMapInfo ||
|
|
1302
|
-
!parentRef?.current) {
|
|
1303
|
-
return;
|
|
1304
|
-
}
|
|
1305
|
-
try {
|
|
1306
|
-
// Tính toán scroll position (đã scale)
|
|
1307
|
-
const scrollTop = parentRef.current.scrollTop / scaleRatio;
|
|
1308
|
-
console.log(`🚀 🐥 ~ useHeatmapMouseHandler ~ scrollTop:`, scrollTop);
|
|
1309
|
-
// Lấy vị trí của heatmap wrapper
|
|
1310
|
-
const wrapperRect = heatmapWrapperRef.current.getBoundingClientRect();
|
|
1311
|
-
// Tính toán tọa độ chuột trong iframe (đã scale)
|
|
1312
|
-
const mouseX = (event.clientX - wrapperRect.left) / scaleRatio;
|
|
1313
|
-
const mouseY = (event.clientY - wrapperRect.top) / scaleRatio - scrollTop;
|
|
1314
|
-
// Tìm elements tại vị trí chuột
|
|
1315
|
-
const elementsAtPoint = getElementsAtPoint(iframeRef.current.contentDocument, Math.round(mouseX), Math.round(mouseY),
|
|
1316
|
-
// Filter: chỉ lấy elements có heatmap attribute
|
|
1317
|
-
(element) => element.hasAttribute(HEATMAP_ELEMENT_ATTRIBUTE));
|
|
1318
|
-
if (!elementsAtPoint || elementsAtPoint.length === 0) {
|
|
1319
|
-
return;
|
|
1320
|
-
}
|
|
1321
|
-
// Duyệt qua các elements tìm được
|
|
1322
|
-
for (let i = 0; i < elementsAtPoint.length; i++) {
|
|
1323
|
-
const element = elementsAtPoint[i];
|
|
1324
|
-
// Lấy hash/id của element
|
|
1325
|
-
const elementHash = element.getAttribute(HEATMAP_ELEMENT_ATTRIBUTE);
|
|
1326
|
-
// Kiểm tra element có data trong heatmapInfo không
|
|
1327
|
-
if (elementHash && heatmapInfo.elementMapInfo[elementHash]) {
|
|
1328
|
-
const elementData = heatmapInfo.elementMapInfo[elementHash];
|
|
1329
|
-
// Lấy bounding box của element
|
|
1330
|
-
const boundingBox = getBoundingBox(element);
|
|
1331
|
-
if (boundingBox) {
|
|
1332
|
-
// Tính rank của element
|
|
1333
|
-
const rank = Array.isArray(heatmapInfo.sortedElements) && elementData
|
|
1334
|
-
? heatmapInfo.sortedElements.indexOf(elementData) + 1
|
|
1335
|
-
: NaN;
|
|
1336
|
-
// Callback với thông tin element
|
|
1337
|
-
onElementHover({
|
|
1338
|
-
...boundingBox,
|
|
1339
|
-
// Giới hạn width không vượt quá width của heatmap
|
|
1340
|
-
width: Math.min(boundingBox.width, heatmapInfo.width || 0),
|
|
1341
|
-
// Adjust top position với scroll
|
|
1342
|
-
top: boundingBox.top + scrollTop,
|
|
1343
|
-
// Metadata
|
|
1344
|
-
hash: elementHash,
|
|
1345
|
-
clicks: elementData.totalclicks,
|
|
1346
|
-
rank: rank,
|
|
1347
|
-
selector: elementData.selector || '',
|
|
1348
|
-
});
|
|
1349
|
-
// Dừng loop khi tìm thấy element hợp lệ đầu tiên
|
|
1350
|
-
break;
|
|
1351
|
-
}
|
|
1352
|
-
}
|
|
1353
|
-
}
|
|
1354
|
-
}
|
|
1355
|
-
catch (error) {
|
|
1356
|
-
console.warn('Error handling mouse move on heatmap:', error);
|
|
1357
|
-
}
|
|
1358
|
-
}, [heatmapWrapperRef, iframeRef, parentRef, heatmapInfo, scaleRatio, onElementHover]);
|
|
1359
|
-
return { handleMouseMove };
|
|
1360
|
-
}
|
|
1361
|
-
// ===================== EXAMPLE USAGE =====================
|
|
1362
|
-
/*
|
|
1363
|
-
import { useRef, useState } from 'react';
|
|
1364
|
-
|
|
1365
|
-
function HeatmapComponent() {
|
|
1366
|
-
const heatmapWrapperRef = useRef<HTMLDivElement>(null);
|
|
1367
|
-
const iframeRef = useRef<HTMLIFrameElement>(null);
|
|
1368
|
-
const parentRef = useRef<HTMLDivElement>(null);
|
|
1369
|
-
|
|
1370
|
-
const [hoveredElement, setHoveredElement] = useState<HoveredElementInfo | null>(null);
|
|
1371
|
-
|
|
1372
|
-
const heatmapInfo = {
|
|
1373
|
-
width: 1920,
|
|
1374
|
-
elementMapInfo: {
|
|
1375
|
-
'hash123': {
|
|
1376
|
-
totalclicks: 45,
|
|
1377
|
-
selector: 'button.submit'
|
|
1378
|
-
}
|
|
1379
|
-
},
|
|
1380
|
-
sortedElements: [...]
|
|
1381
|
-
};
|
|
1382
|
-
|
|
1383
|
-
const { handleMouseMove } = useHeatmapMouseHandler({
|
|
1384
|
-
heatmapWrapperRef,
|
|
1385
|
-
iframeRef,
|
|
1386
|
-
parentRef,
|
|
1387
|
-
heatmapInfo,
|
|
1388
|
-
scaleRatio: 0.8, // 80% zoom
|
|
1389
|
-
onElementHover: (info) => {
|
|
1390
|
-
setHoveredElement(info);
|
|
1391
|
-
console.log('Hovered element:', info);
|
|
1392
|
-
}
|
|
1393
|
-
});
|
|
1394
|
-
|
|
1395
|
-
return (
|
|
1396
|
-
<div ref={parentRef}>
|
|
1397
|
-
<div
|
|
1398
|
-
ref={heatmapWrapperRef}
|
|
1399
|
-
onMouseMove={handleMouseMove}
|
|
1400
|
-
>
|
|
1401
|
-
<iframe ref={iframeRef} />
|
|
1402
|
-
|
|
1403
|
-
{hoveredElement && (
|
|
1404
|
-
<div className="tooltip" style={{
|
|
1405
|
-
position: 'absolute',
|
|
1406
|
-
left: hoveredElement.left,
|
|
1407
|
-
top: hoveredElement.top
|
|
1408
|
-
}}>
|
|
1409
|
-
Clicks: {hoveredElement.clicks}
|
|
1410
|
-
<br />
|
|
1411
|
-
Rank: #{hoveredElement.rank}
|
|
1412
|
-
<br />
|
|
1413
|
-
Selector: {hoveredElement.selector}
|
|
1414
|
-
</div>
|
|
1415
|
-
)}
|
|
1416
|
-
</div>
|
|
1417
|
-
</div>
|
|
1418
|
-
);
|
|
1419
|
-
}
|
|
1420
|
-
*/
|
|
1421
|
-
|
|
1422
924
|
const useHoveredElement = ({ iframeRef, getRect }) => {
|
|
1423
925
|
const hoveredElement = useHeatmapInteractionStore((state) => state.hoveredElement);
|
|
1424
926
|
const setHoveredElement = useHeatmapInteractionStore((state) => state.setHoveredElement);
|
|
@@ -1440,7 +942,7 @@ const useHoveredElement = ({ iframeRef, getRect }) => {
|
|
|
1440
942
|
const doc = iframe.contentDocument;
|
|
1441
943
|
const iframeRect = iframe.getBoundingClientRect();
|
|
1442
944
|
const { x, y } = convertViewportToIframeCoords(event.clientX, event.clientY, iframeRect, widthScale);
|
|
1443
|
-
const targetElement = findTargetElement(doc, x, y
|
|
945
|
+
const targetElement = findTargetElement(doc, x, y);
|
|
1444
946
|
if (!targetElement || !isValidElement(targetElement, heatmapInfo)) {
|
|
1445
947
|
reset();
|
|
1446
948
|
return;
|
|
@@ -1491,25 +993,7 @@ const convertViewportToIframeCoords = (clientX, clientY, iframeRect, scale) => {
|
|
|
1491
993
|
}
|
|
1492
994
|
return { x, y };
|
|
1493
995
|
};
|
|
1494
|
-
const findTargetElement = (doc, x, y
|
|
1495
|
-
const HEATMAP_ELEMENT_ATTRIBUTE = 'data-clarity-hashalpha';
|
|
1496
|
-
const elementsAtPoint = getElementsAtPoint(doc, Math.round(x), Math.round(y), (element) => element.hasAttribute(HEATMAP_ELEMENT_ATTRIBUTE));
|
|
1497
|
-
let dataElement = null;
|
|
1498
|
-
for (let i = 0; i < elementsAtPoint.length; i++) {
|
|
1499
|
-
const element = elementsAtPoint[i];
|
|
1500
|
-
const elementHash = element.getAttribute(HEATMAP_ELEMENT_ATTRIBUTE);
|
|
1501
|
-
if (elementHash && heatmapInfo.elementMapInfo?.[elementHash]) {
|
|
1502
|
-
heatmapInfo.elementMapInfo[elementHash];
|
|
1503
|
-
const boundingBox = getBoundingBox(element);
|
|
1504
|
-
if (boundingBox) {
|
|
1505
|
-
dataElement = element;
|
|
1506
|
-
break;
|
|
1507
|
-
}
|
|
1508
|
-
}
|
|
1509
|
-
}
|
|
1510
|
-
if (!!dataElement) {
|
|
1511
|
-
return dataElement;
|
|
1512
|
-
}
|
|
996
|
+
const findTargetElement = (doc, x, y) => {
|
|
1513
997
|
let targetElement = getElementAtPoint(doc, x, y);
|
|
1514
998
|
if (!targetElement) {
|
|
1515
999
|
targetElement = doc.elementFromPoint(x, y);
|
|
@@ -1533,9 +1017,9 @@ var MessageType;
|
|
|
1533
1017
|
MessageType["GX_DOM_TRACKING_PAYLOAD"] = "GX_DOM_TRACKING_PAYLOAD";
|
|
1534
1018
|
MessageType["CLARITY_READY"] = "CLARITY_READY";
|
|
1535
1019
|
})(MessageType || (MessageType = {}));
|
|
1536
|
-
function
|
|
1020
|
+
function useIframeMessage(options = {}) {
|
|
1537
1021
|
const { trustedOrigins = [], onMessage } = options;
|
|
1538
|
-
const
|
|
1022
|
+
const [payloads, setPayloads] = useState([]);
|
|
1539
1023
|
const [isReady, setIsReady] = useState(false);
|
|
1540
1024
|
const iframeRef = useRef(null);
|
|
1541
1025
|
const isValidOrigin = useCallback((origin) => {
|
|
@@ -1561,9 +1045,9 @@ function useVizLiveIframeMsg(options = {}) {
|
|
|
1561
1045
|
switch (message.type) {
|
|
1562
1046
|
case MessageType.GX_DOM_TRACKING_PAYLOAD:
|
|
1563
1047
|
if (message.payload) {
|
|
1564
|
-
const
|
|
1565
|
-
if (
|
|
1566
|
-
|
|
1048
|
+
const decodedPayloads = decodePayloads(message.payload);
|
|
1049
|
+
if (decodedPayloads) {
|
|
1050
|
+
setPayloads((prev) => [...prev, decodedPayloads]);
|
|
1567
1051
|
}
|
|
1568
1052
|
}
|
|
1569
1053
|
break;
|
|
@@ -1578,19 +1062,27 @@ function useVizLiveIframeMsg(options = {}) {
|
|
|
1578
1062
|
window.removeEventListener('message', handleMessage);
|
|
1579
1063
|
};
|
|
1580
1064
|
}, [handleMessage]);
|
|
1065
|
+
const clearPayloads = useCallback(() => {
|
|
1066
|
+
setPayloads([]);
|
|
1067
|
+
}, []);
|
|
1068
|
+
const reset = useCallback(() => {
|
|
1069
|
+
setPayloads([]);
|
|
1070
|
+
setIsReady(false);
|
|
1071
|
+
}, []);
|
|
1581
1072
|
return {
|
|
1582
1073
|
iframeRef,
|
|
1074
|
+
payloads,
|
|
1583
1075
|
isReady,
|
|
1076
|
+
clearPayloads,
|
|
1077
|
+
reset,
|
|
1584
1078
|
};
|
|
1585
1079
|
}
|
|
1586
|
-
|
|
1587
|
-
function useVizLiveRender() {
|
|
1080
|
+
function useIframeRender() {
|
|
1588
1081
|
const wrapperHeight = useHeatmapLiveStore((state) => state.wrapperHeight);
|
|
1589
|
-
const setIframeHeight = useHeatmapLiveStore((state) => state.setIframeHeight);
|
|
1590
1082
|
const contentWidth = useHeatmapConfigStore((state) => state.width);
|
|
1083
|
+
const setIframeHeight = useHeatmapVizStore((state) => state.setIframeHeight);
|
|
1591
1084
|
const htmlContent = useHeatmapLiveStore((state) => state.htmlContent);
|
|
1592
|
-
const
|
|
1593
|
-
const { iframeRef, isReady } = useVizLiveIframeMsg();
|
|
1085
|
+
const { iframeRef, payloads, isReady } = useIframeMessage();
|
|
1594
1086
|
useEffect(() => {
|
|
1595
1087
|
if (!htmlContent || !iframeRef.current)
|
|
1596
1088
|
return;
|
|
@@ -1610,50 +1102,50 @@ function useVizLiveRender() {
|
|
|
1610
1102
|
const iframe = iframeRef.current;
|
|
1611
1103
|
if (!iframe || !htmlContent)
|
|
1612
1104
|
return;
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
height && setIframeHeight(height);
|
|
1616
|
-
setIsRenderViz(true);
|
|
1105
|
+
reset$1(iframe, { width: contentWidth, height: wrapperHeight }, (height) => {
|
|
1106
|
+
setIframeHeight(height);
|
|
1617
1107
|
});
|
|
1618
1108
|
}, [isReady, contentWidth, wrapperHeight]);
|
|
1619
1109
|
return {
|
|
1620
1110
|
iframeRef,
|
|
1111
|
+
payloads,
|
|
1112
|
+
isReady,
|
|
1621
1113
|
};
|
|
1622
1114
|
}
|
|
1623
|
-
function reset(iframe,
|
|
1624
|
-
const
|
|
1625
|
-
targetWidth:
|
|
1626
|
-
targetHeight:
|
|
1115
|
+
function reset$1(iframe, payloads, onSuccess) {
|
|
1116
|
+
const viewportFixer = initViewportFixer({
|
|
1117
|
+
targetWidth: payloads.width,
|
|
1118
|
+
targetHeight: payloads.height,
|
|
1627
1119
|
iframe: iframe,
|
|
1628
1120
|
onSuccess: (data) => {
|
|
1629
|
-
iframe.height = `${data.height}px`;
|
|
1630
1121
|
onSuccess(data.height);
|
|
1122
|
+
iframe.height = `${data.height}px`;
|
|
1631
1123
|
},
|
|
1632
1124
|
});
|
|
1633
|
-
|
|
1634
|
-
|
|
1125
|
+
viewportFixer.recalculate();
|
|
1126
|
+
return iframe;
|
|
1635
1127
|
}
|
|
1636
1128
|
|
|
1637
|
-
let visualizer = new Visualizer();
|
|
1638
1129
|
const useHeatmapRender = () => {
|
|
1639
1130
|
const data = useHeatmapDataStore((state) => state.data);
|
|
1640
|
-
const setVizRef =
|
|
1131
|
+
const setVizRef = useHeatmapVizStore((state) => state.setVizRef);
|
|
1641
1132
|
const setIsRenderViz = useHeatmapVizStore((state) => state.setIsRenderViz);
|
|
1642
|
-
const setIframeHeight =
|
|
1133
|
+
const setIframeHeight = useHeatmapVizStore((state) => state.setIframeHeight);
|
|
1643
1134
|
const iframeRef = useRef(null);
|
|
1644
1135
|
const renderHeatmap = useCallback(async (payloads) => {
|
|
1645
1136
|
if (!payloads || payloads.length === 0)
|
|
1646
1137
|
return;
|
|
1647
1138
|
setIsRenderViz(false);
|
|
1139
|
+
const visualizer = new Visualizer();
|
|
1648
1140
|
const iframe = iframeRef.current;
|
|
1649
1141
|
if (!iframe?.contentWindow)
|
|
1650
1142
|
return;
|
|
1651
1143
|
await visualizer.html(payloads, iframe.contentWindow);
|
|
1652
|
-
|
|
1144
|
+
reset(iframe, payloads, (height) => {
|
|
1653
1145
|
height && setIframeHeight(height);
|
|
1654
1146
|
setIsRenderViz(true);
|
|
1655
|
-
setVizRef(visualizer);
|
|
1656
1147
|
});
|
|
1148
|
+
setVizRef(visualizer);
|
|
1657
1149
|
}, []);
|
|
1658
1150
|
useEffect(() => {
|
|
1659
1151
|
if (!data || data.length === 0)
|
|
@@ -1667,20 +1159,21 @@ const useHeatmapRender = () => {
|
|
|
1667
1159
|
iframeRef,
|
|
1668
1160
|
};
|
|
1669
1161
|
};
|
|
1670
|
-
function
|
|
1162
|
+
function reset(iframe, payloads, onSuccess) {
|
|
1671
1163
|
const { size } = findLastSizeOfDom(payloads);
|
|
1672
1164
|
const docWidth = size.width ?? 0;
|
|
1673
1165
|
const docHeight = size.height ?? 0;
|
|
1674
|
-
|
|
1166
|
+
const viewportFixer = initViewportFixer({
|
|
1675
1167
|
targetWidth: docWidth,
|
|
1676
1168
|
targetHeight: docHeight,
|
|
1677
1169
|
iframe: iframe,
|
|
1678
1170
|
onSuccess: (data) => {
|
|
1679
|
-
iframe.height = `${data.height}px`;
|
|
1680
1171
|
onSuccess(data.height);
|
|
1172
|
+
iframe.height = `${data.height}px`;
|
|
1681
1173
|
},
|
|
1682
1174
|
});
|
|
1683
|
-
|
|
1175
|
+
viewportFixer.recalculate();
|
|
1176
|
+
return iframe;
|
|
1684
1177
|
}
|
|
1685
1178
|
|
|
1686
1179
|
function isMobileDevice(userAgent) {
|
|
@@ -1865,64 +1358,30 @@ const useContentDimensions = ({ iframeRef, }) => {
|
|
|
1865
1358
|
return { contentWidth };
|
|
1866
1359
|
};
|
|
1867
1360
|
|
|
1868
|
-
const
|
|
1361
|
+
const useIframeHeight = (props) => {
|
|
1869
1362
|
const { iframeRef, setIframeHeight } = props;
|
|
1870
1363
|
const isRenderViz = useHeatmapVizStore((state) => state.isRenderViz);
|
|
1871
1364
|
const resizeObserverRef = useRef(null);
|
|
1872
1365
|
const mutationObserverRef = useRef(null);
|
|
1873
|
-
const debounceTimerRef = useRef(null);
|
|
1874
|
-
const lastHeightRef = useRef(0);
|
|
1875
|
-
const animationFrameRef = useRef(null);
|
|
1876
1366
|
const updateIframeHeight = useCallback(() => {
|
|
1877
1367
|
const iframe = iframeRef.current;
|
|
1878
|
-
if (!iframe
|
|
1368
|
+
if (!iframe)
|
|
1879
1369
|
return;
|
|
1880
1370
|
try {
|
|
1881
1371
|
const iframeDocument = iframe.contentDocument;
|
|
1882
1372
|
const iframeBody = iframeDocument?.body;
|
|
1883
|
-
|
|
1884
|
-
if (!iframeBody || !iframeDocumentElement)
|
|
1373
|
+
if (!iframeBody)
|
|
1885
1374
|
return;
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
if (actualHeight > 0) {
|
|
1892
|
-
lastHeightRef.current = actualHeight;
|
|
1893
|
-
iframe.height = `${actualHeight}px`;
|
|
1894
|
-
iframe.style.height = `${actualHeight}px`;
|
|
1895
|
-
setIframeHeight(actualHeight);
|
|
1896
|
-
}
|
|
1897
|
-
});
|
|
1375
|
+
const bodyHeight = Math.max(iframeBody.scrollHeight, iframeBody.offsetHeight, iframeBody.clientHeight);
|
|
1376
|
+
if (bodyHeight > 0) {
|
|
1377
|
+
iframe.height = `${bodyHeight}px`;
|
|
1378
|
+
setIframeHeight(bodyHeight);
|
|
1379
|
+
}
|
|
1898
1380
|
}
|
|
1899
1381
|
catch (error) {
|
|
1900
1382
|
console.warn('Cannot measure iframe content:', error);
|
|
1901
1383
|
}
|
|
1902
1384
|
}, [iframeRef, setIframeHeight]);
|
|
1903
|
-
const debouncedUpdate = useCallback(() => {
|
|
1904
|
-
// Cancel pending updates
|
|
1905
|
-
if (debounceTimerRef.current) {
|
|
1906
|
-
clearTimeout(debounceTimerRef.current);
|
|
1907
|
-
}
|
|
1908
|
-
if (animationFrameRef.current) {
|
|
1909
|
-
cancelAnimationFrame(animationFrameRef.current);
|
|
1910
|
-
}
|
|
1911
|
-
debounceTimerRef.current = setTimeout(() => {
|
|
1912
|
-
animationFrameRef.current = requestAnimationFrame(() => {
|
|
1913
|
-
updateIframeHeight();
|
|
1914
|
-
});
|
|
1915
|
-
}, 50);
|
|
1916
|
-
}, [updateIframeHeight]);
|
|
1917
|
-
// Immediate update không debounce (cho ResizeObserver)
|
|
1918
|
-
const immediateUpdate = useCallback(() => {
|
|
1919
|
-
if (animationFrameRef.current) {
|
|
1920
|
-
cancelAnimationFrame(animationFrameRef.current);
|
|
1921
|
-
}
|
|
1922
|
-
animationFrameRef.current = requestAnimationFrame(() => {
|
|
1923
|
-
updateIframeHeight();
|
|
1924
|
-
});
|
|
1925
|
-
}, [updateIframeHeight]);
|
|
1926
1385
|
useEffect(() => {
|
|
1927
1386
|
const iframe = iframeRef.current;
|
|
1928
1387
|
if (!iframe || !isRenderViz)
|
|
@@ -1940,24 +1399,22 @@ const useObserveIframeHeight = (props) => {
|
|
|
1940
1399
|
if (mutationObserverRef.current) {
|
|
1941
1400
|
mutationObserverRef.current.disconnect();
|
|
1942
1401
|
}
|
|
1402
|
+
// ResizeObserver for size changes
|
|
1943
1403
|
if (typeof window.ResizeObserver !== 'undefined') {
|
|
1944
|
-
resizeObserverRef.current = new ResizeObserver(
|
|
1404
|
+
resizeObserverRef.current = new ResizeObserver(updateIframeHeight);
|
|
1945
1405
|
resizeObserverRef.current.observe(iframeBody);
|
|
1946
|
-
const iframeDocumentElement = iframeDocument?.documentElement;
|
|
1947
|
-
if (iframeDocumentElement) {
|
|
1948
|
-
resizeObserverRef.current.observe(iframeDocumentElement);
|
|
1949
|
-
}
|
|
1950
1406
|
}
|
|
1407
|
+
// MutationObserver for DOM changes
|
|
1951
1408
|
if (typeof window.MutationObserver !== 'undefined') {
|
|
1952
|
-
mutationObserverRef.current = new MutationObserver(
|
|
1409
|
+
mutationObserverRef.current = new MutationObserver(updateIframeHeight);
|
|
1953
1410
|
mutationObserverRef.current.observe(iframeBody, {
|
|
1954
1411
|
childList: true,
|
|
1955
1412
|
subtree: true,
|
|
1956
1413
|
attributes: true,
|
|
1957
|
-
|
|
1958
|
-
characterData: false,
|
|
1414
|
+
characterData: true,
|
|
1959
1415
|
});
|
|
1960
1416
|
}
|
|
1417
|
+
// Initial measurement
|
|
1961
1418
|
updateIframeHeight();
|
|
1962
1419
|
}
|
|
1963
1420
|
catch (error) {
|
|
@@ -1971,23 +1428,15 @@ const useObserveIframeHeight = (props) => {
|
|
|
1971
1428
|
iframe.addEventListener('load', setupObservers, { once: true });
|
|
1972
1429
|
}
|
|
1973
1430
|
return () => {
|
|
1974
|
-
// Cleanup observers
|
|
1975
1431
|
if (resizeObserverRef.current) {
|
|
1976
1432
|
resizeObserverRef.current.disconnect();
|
|
1977
1433
|
}
|
|
1978
1434
|
if (mutationObserverRef.current) {
|
|
1979
1435
|
mutationObserverRef.current.disconnect();
|
|
1980
1436
|
}
|
|
1981
|
-
// Cleanup timers
|
|
1982
|
-
if (debounceTimerRef.current) {
|
|
1983
|
-
clearTimeout(debounceTimerRef.current);
|
|
1984
|
-
}
|
|
1985
|
-
if (animationFrameRef.current) {
|
|
1986
|
-
cancelAnimationFrame(animationFrameRef.current);
|
|
1987
|
-
}
|
|
1988
1437
|
iframe.removeEventListener('load', setupObservers);
|
|
1989
1438
|
};
|
|
1990
|
-
}, [iframeRef, isRenderViz, updateIframeHeight
|
|
1439
|
+
}, [iframeRef, isRenderViz, updateIframeHeight]);
|
|
1991
1440
|
return {};
|
|
1992
1441
|
};
|
|
1993
1442
|
|
|
@@ -2033,18 +1482,16 @@ const useHeatmapScale = (props) => {
|
|
|
2033
1482
|
// 2. Get content dimensions from config
|
|
2034
1483
|
const { contentWidth } = useContentDimensions({ iframeRef });
|
|
2035
1484
|
// 3. Observe iframe height (now reacts to width changes)
|
|
2036
|
-
|
|
1485
|
+
useIframeHeight({ iframeRef, setIframeHeight });
|
|
2037
1486
|
// 4. Calculate scale
|
|
2038
1487
|
const { scale } = useScaleCalculation({ containerWidth, contentWidth });
|
|
2039
1488
|
// 5. Setup scroll sync
|
|
2040
1489
|
const { handleScroll } = useScrollSync({ iframeRef });
|
|
2041
|
-
const scaledHeight = iframeHeight * scale;
|
|
2042
|
-
const scaledWidth = contentWidth * scale;
|
|
2043
1490
|
return {
|
|
2044
1491
|
containerWidth,
|
|
2045
1492
|
containerHeight,
|
|
2046
|
-
scaledWidth,
|
|
2047
|
-
scaledHeight,
|
|
1493
|
+
scaledWidth: contentWidth * scale,
|
|
1494
|
+
scaledHeight: iframeHeight * scale,
|
|
2048
1495
|
handleScroll,
|
|
2049
1496
|
};
|
|
2050
1497
|
};
|
|
@@ -2204,159 +1651,35 @@ const VizContainer = ({ children, setWrapperHeight }) => {
|
|
|
2204
1651
|
const useClickmap = () => {
|
|
2205
1652
|
const [isInitialized, setIsInitialized] = useState(false);
|
|
2206
1653
|
const clickmap = useHeatmapDataStore((state) => state.clickmap);
|
|
2207
|
-
const vizRef =
|
|
2208
|
-
|
|
1654
|
+
const vizRef = useHeatmapVizStore((state) => state.vizRef);
|
|
1655
|
+
useEffect(() => {
|
|
2209
1656
|
if (isInitialized)
|
|
2210
1657
|
return;
|
|
2211
1658
|
if (!vizRef || !clickmap || clickmap.length === 0)
|
|
2212
1659
|
return;
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
setIsInitialized(true);
|
|
2217
|
-
}
|
|
2218
|
-
catch (error) {
|
|
2219
|
-
console.error(`🚀 🐥 ~ useClickmap ~ error:`, error);
|
|
2220
|
-
}
|
|
1660
|
+
vizRef.clearmap();
|
|
1661
|
+
vizRef?.clickmap(clickmap);
|
|
1662
|
+
setIsInitialized(true);
|
|
2221
1663
|
}, [vizRef, clickmap]);
|
|
2222
|
-
return {
|
|
1664
|
+
return {};
|
|
2223
1665
|
};
|
|
2224
1666
|
|
|
2225
|
-
const DATA_SCROLLMAP = [
|
|
2226
|
-
{
|
|
2227
|
-
scrollReachY: 5,
|
|
2228
|
-
cumulativeSum: 0,
|
|
2229
|
-
percUsers: 0,
|
|
2230
|
-
},
|
|
2231
|
-
{
|
|
2232
|
-
scrollReachY: 10,
|
|
2233
|
-
cumulativeSum: 0,
|
|
2234
|
-
percUsers: 0,
|
|
2235
|
-
},
|
|
2236
|
-
{
|
|
2237
|
-
scrollReachY: 15,
|
|
2238
|
-
cumulativeSum: 0,
|
|
2239
|
-
percUsers: 0,
|
|
2240
|
-
},
|
|
2241
|
-
{
|
|
2242
|
-
scrollReachY: 20,
|
|
2243
|
-
cumulativeSum: 0,
|
|
2244
|
-
percUsers: 0,
|
|
2245
|
-
},
|
|
2246
|
-
{
|
|
2247
|
-
scrollReachY: 25,
|
|
2248
|
-
cumulativeSum: 0,
|
|
2249
|
-
percUsers: 0,
|
|
2250
|
-
},
|
|
2251
|
-
{
|
|
2252
|
-
scrollReachY: 30,
|
|
2253
|
-
cumulativeSum: 0,
|
|
2254
|
-
percUsers: 0,
|
|
2255
|
-
},
|
|
2256
|
-
{
|
|
2257
|
-
scrollReachY: 35,
|
|
2258
|
-
cumulativeSum: 0,
|
|
2259
|
-
percUsers: 0,
|
|
2260
|
-
},
|
|
2261
|
-
{
|
|
2262
|
-
scrollReachY: 40,
|
|
2263
|
-
cumulativeSum: 0,
|
|
2264
|
-
percUsers: 0,
|
|
2265
|
-
},
|
|
2266
|
-
{
|
|
2267
|
-
scrollReachY: 45,
|
|
2268
|
-
cumulativeSum: 0,
|
|
2269
|
-
percUsers: 0,
|
|
2270
|
-
},
|
|
2271
|
-
{
|
|
2272
|
-
scrollReachY: 50,
|
|
2273
|
-
cumulativeSum: 0,
|
|
2274
|
-
percUsers: 0,
|
|
2275
|
-
},
|
|
2276
|
-
{
|
|
2277
|
-
scrollReachY: 55,
|
|
2278
|
-
cumulativeSum: 0,
|
|
2279
|
-
percUsers: 0,
|
|
2280
|
-
},
|
|
2281
|
-
{
|
|
2282
|
-
scrollReachY: 60,
|
|
2283
|
-
cumulativeSum: 0,
|
|
2284
|
-
percUsers: 0,
|
|
2285
|
-
},
|
|
2286
|
-
{
|
|
2287
|
-
scrollReachY: 65,
|
|
2288
|
-
cumulativeSum: 0,
|
|
2289
|
-
percUsers: 0,
|
|
2290
|
-
},
|
|
2291
|
-
{
|
|
2292
|
-
scrollReachY: 70,
|
|
2293
|
-
cumulativeSum: 0,
|
|
2294
|
-
percUsers: 0,
|
|
2295
|
-
},
|
|
2296
|
-
{
|
|
2297
|
-
scrollReachY: 75,
|
|
2298
|
-
cumulativeSum: 0,
|
|
2299
|
-
percUsers: 0,
|
|
2300
|
-
},
|
|
2301
|
-
{
|
|
2302
|
-
scrollReachY: 80,
|
|
2303
|
-
cumulativeSum: 0,
|
|
2304
|
-
percUsers: 0,
|
|
2305
|
-
},
|
|
2306
|
-
{
|
|
2307
|
-
scrollReachY: 85,
|
|
2308
|
-
cumulativeSum: 0,
|
|
2309
|
-
percUsers: 0,
|
|
2310
|
-
},
|
|
2311
|
-
{
|
|
2312
|
-
scrollReachY: 90,
|
|
2313
|
-
cumulativeSum: 0,
|
|
2314
|
-
percUsers: 0,
|
|
2315
|
-
},
|
|
2316
|
-
{
|
|
2317
|
-
scrollReachY: 95,
|
|
2318
|
-
cumulativeSum: 0,
|
|
2319
|
-
percUsers: 0,
|
|
2320
|
-
},
|
|
2321
|
-
{
|
|
2322
|
-
scrollReachY: 100,
|
|
2323
|
-
cumulativeSum: 0,
|
|
2324
|
-
percUsers: 0,
|
|
2325
|
-
},
|
|
2326
|
-
];
|
|
2327
1667
|
const useScrollmap = () => {
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
// if (isInitialized) return;
|
|
2331
|
-
const scrollmap = DATA_SCROLLMAP;
|
|
2332
|
-
if (!vizRef || !scrollmap || scrollmap.length === 0)
|
|
2333
|
-
return;
|
|
2334
|
-
try {
|
|
2335
|
-
vizRef?.clearmap?.();
|
|
2336
|
-
vizRef?.scrollmap?.(scrollmap);
|
|
2337
|
-
// setIsInitialized(true);
|
|
2338
|
-
}
|
|
2339
|
-
catch (error) {
|
|
2340
|
-
console.error(`🚀 🐥 ~ useScrollmap ~ error:`, error);
|
|
2341
|
-
}
|
|
2342
|
-
}, [vizRef]);
|
|
2343
|
-
return { start };
|
|
1668
|
+
useHeatmapDataStore((state) => state.clickmap);
|
|
1669
|
+
return {};
|
|
2344
1670
|
};
|
|
2345
1671
|
|
|
2346
1672
|
const useHeatmapVizCanvas = () => {
|
|
2347
1673
|
const heatmapType = useHeatmapConfigStore((state) => state.heatmapType);
|
|
2348
|
-
const
|
|
2349
|
-
const { start: startScrollmap } = useScrollmap();
|
|
2350
|
-
useEffect(() => {
|
|
1674
|
+
const heatmapRender = useMemo(() => {
|
|
2351
1675
|
switch (heatmapType) {
|
|
2352
1676
|
case IHeatmapType.Click:
|
|
2353
|
-
|
|
2354
|
-
break;
|
|
1677
|
+
return useClickmap;
|
|
2355
1678
|
case IHeatmapType.Scroll:
|
|
2356
|
-
|
|
2357
|
-
break;
|
|
1679
|
+
return useScrollmap;
|
|
2358
1680
|
}
|
|
2359
|
-
}, [heatmapType
|
|
1681
|
+
}, [heatmapType]);
|
|
1682
|
+
return heatmapRender?.();
|
|
2360
1683
|
};
|
|
2361
1684
|
|
|
2362
1685
|
const CLICKED_ELEMENT_ID = 'gx-hm-clicked-element';
|
|
@@ -2419,7 +1742,7 @@ const ElementCallout = (props) => {
|
|
|
2419
1742
|
window.removeEventListener('resize', handleUpdate);
|
|
2420
1743
|
visualRef?.current?.removeEventListener('scroll', handleUpdate);
|
|
2421
1744
|
};
|
|
2422
|
-
}, [
|
|
1745
|
+
}, [target, visualRef, hozOffset, alignment]);
|
|
2423
1746
|
const calloutContent = (jsx("div", { ref: calloutRef, className: `clarity-callout clarity-callout--${position.placement} clarity-callout--align-${position.horizontalAlign}`, style: {
|
|
2424
1747
|
position: 'fixed',
|
|
2425
1748
|
top: position.top,
|
|
@@ -2484,8 +1807,7 @@ const ELEMENT_CALLOUT = {
|
|
|
2484
1807
|
alignment: 'left',
|
|
2485
1808
|
};
|
|
2486
1809
|
const HeatmapElements = (props) => {
|
|
2487
|
-
const
|
|
2488
|
-
const setHoveredElement = useHeatmapInteractionStore((state) => state.setHoveredElement);
|
|
1810
|
+
const height = useHeatmapVizStore((state) => state.iframeHeight);
|
|
2489
1811
|
const { iframeRef, wrapperRef, visualRef, visualizer, iframeDimensions, isElementSidebarOpen, isVisible = true, areDefaultRanksHidden, isSecondary, ...rest } = props;
|
|
2490
1812
|
const getRect = useHeatmapElementPosition({
|
|
2491
1813
|
iframeRef,
|
|
@@ -2500,27 +1822,6 @@ const HeatmapElements = (props) => {
|
|
|
2500
1822
|
iframeRef,
|
|
2501
1823
|
getRect,
|
|
2502
1824
|
});
|
|
2503
|
-
const heatmapInfo = useHeatmapDataStore((state) => state.dataInfo);
|
|
2504
|
-
useHeatmapMouseHandler({
|
|
2505
|
-
heatmapWrapperRef: wrapperRef,
|
|
2506
|
-
iframeRef,
|
|
2507
|
-
parentRef: visualRef,
|
|
2508
|
-
heatmapInfo: heatmapInfo || {},
|
|
2509
|
-
scaleRatio: 0.8, // 80% zoom
|
|
2510
|
-
onElementHover: (info) => {
|
|
2511
|
-
setHoveredElement({
|
|
2512
|
-
hash: info.hash,
|
|
2513
|
-
clicks: info.clicks,
|
|
2514
|
-
rank: info.rank,
|
|
2515
|
-
selector: info.selector,
|
|
2516
|
-
top: info.top,
|
|
2517
|
-
left: info.left,
|
|
2518
|
-
width: info.width,
|
|
2519
|
-
height: info.height,
|
|
2520
|
-
});
|
|
2521
|
-
console.log(`🚀 🐥 ~ HeatmapElements ~ info:`, info);
|
|
2522
|
-
},
|
|
2523
|
-
});
|
|
2524
1825
|
useElementCalloutVisible({
|
|
2525
1826
|
visualRef,
|
|
2526
1827
|
getRect,
|
|
@@ -2536,21 +1837,14 @@ const HeatmapElements = (props) => {
|
|
|
2536
1837
|
});
|
|
2537
1838
|
if (!isVisible)
|
|
2538
1839
|
return null;
|
|
2539
|
-
return (jsxs("div", { onMouseMove: (
|
|
2540
|
-
handleMouseMove(event);
|
|
2541
|
-
// handleMouseMove2(event as any);
|
|
2542
|
-
}, 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, isSecondary: isSecondary }), jsx(ElementOverlay, { type: "hovered", element: hoveredElement, isSecondary: isSecondary, onClick: handleClick }), hoveredElement?.hash !== clickedElement?.hash && hoveredElement && (jsx(ElementCallout, { element: hoveredElement, target: `#${HOVERED_ELEMENT_ID}`, visualRef: visualRef, ...ELEMENT_CALLOUT })), shouldShowCallout && clickedElement && (jsx(ElementCallout, { element: clickedElement, target: `#${CLICKED_ELEMENT_ID}`, visualRef: visualRef, ...ELEMENT_CALLOUT }))] }));
|
|
1840
|
+
return (jsxs("div", { onMouseMove: handleMouseMove, onMouseLeave: handleMouseLeave, className: "gx-hm-elements", style: { ...iframeDimensions, height }, children: [jsx(ElementMissing, { show: showMissingElement }), jsx(DefaultRankBadges, { getRect: getRect, hidden: areDefaultRanksHidden }), jsx(ElementOverlay, { type: "clicked", element: clickedElement, isSecondary: isSecondary }), jsx(ElementOverlay, { type: "hovered", element: hoveredElement, isSecondary: isSecondary, onClick: handleClick }), hoveredElement?.hash !== clickedElement?.hash && hoveredElement && (jsx(ElementCallout, { element: hoveredElement, target: `#${HOVERED_ELEMENT_ID}`, visualRef: visualRef, ...ELEMENT_CALLOUT })), shouldShowCallout && clickedElement && (jsx(ElementCallout, { element: clickedElement, target: `#${CLICKED_ELEMENT_ID}`, visualRef: visualRef, ...ELEMENT_CALLOUT }))] }));
|
|
2543
1841
|
};
|
|
2544
1842
|
|
|
2545
1843
|
const VizElements = ({ iframeRef, visualRef, wrapperRef }) => {
|
|
2546
1844
|
const heatmapInfo = useHeatmapDataStore((state) => state.dataInfo);
|
|
2547
|
-
const contentWidth =
|
|
2548
|
-
const vizRef = useHeatmapSingleStore((state) => state.vizRef);
|
|
1845
|
+
const contentWidth = useHeatmapDataStore((state) => state.config?.width ?? 0);
|
|
2549
1846
|
const visualizer = {
|
|
2550
1847
|
get: (hash) => {
|
|
2551
|
-
if (vizRef) {
|
|
2552
|
-
return vizRef.get(hash);
|
|
2553
|
-
}
|
|
2554
1848
|
const doc = iframeRef.current?.contentDocument;
|
|
2555
1849
|
if (!doc)
|
|
2556
1850
|
return null;
|
|
@@ -2610,8 +1904,8 @@ const WrapperVisual = ({ children, visualRef, wrapperRef, scaledHeight, iframeHe
|
|
|
2610
1904
|
|
|
2611
1905
|
const VizDomRenderer = ({ mode = 'heatmap' }) => {
|
|
2612
1906
|
const width = useHeatmapConfigStore((state) => state.width);
|
|
2613
|
-
const iframeHeight =
|
|
2614
|
-
const setIframeHeight =
|
|
1907
|
+
const iframeHeight = useHeatmapVizStore((state) => state.iframeHeight);
|
|
1908
|
+
const setIframeHeight = useHeatmapVizStore((state) => state.setIframeHeight);
|
|
2615
1909
|
const setSelectedElement = useHeatmapInteractionStore((state) => state.setSelectedElement);
|
|
2616
1910
|
const wrapperRef = useRef(null);
|
|
2617
1911
|
const visualRef = useRef(null);
|
|
@@ -2621,6 +1915,7 @@ const VizDomRenderer = ({ mode = 'heatmap' }) => {
|
|
|
2621
1915
|
iframeRef,
|
|
2622
1916
|
visualRef,
|
|
2623
1917
|
iframeHeight,
|
|
1918
|
+
setIframeHeight,
|
|
2624
1919
|
});
|
|
2625
1920
|
const contentWidth = width ?? 0;
|
|
2626
1921
|
const onScroll = (e) => {
|
|
@@ -2635,7 +1930,7 @@ const VizDomRenderer = ({ mode = 'heatmap' }) => {
|
|
|
2635
1930
|
useEffect(() => {
|
|
2636
1931
|
return cleanUp;
|
|
2637
1932
|
}, []);
|
|
2638
|
-
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" })] }));
|
|
1933
|
+
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, height: iframeHeight, scrolling: "no" })] }));
|
|
2639
1934
|
};
|
|
2640
1935
|
|
|
2641
1936
|
const VizLoading = () => {
|
|
@@ -2645,12 +1940,12 @@ const VizLoading = () => {
|
|
|
2645
1940
|
const VizDomHeatmap = () => {
|
|
2646
1941
|
const controls = useHeatmapControlStore((state) => state.controls);
|
|
2647
1942
|
const isRendering = useHeatmapDataStore((state) => state.isRendering);
|
|
2648
|
-
const iframeHeight =
|
|
2649
|
-
const setIframeHeight =
|
|
2650
|
-
const setVizRef =
|
|
1943
|
+
const iframeHeight = useHeatmapVizStore((state) => state.iframeHeight);
|
|
1944
|
+
const setIframeHeight = useHeatmapVizStore((state) => state.setIframeHeight);
|
|
1945
|
+
const setVizRef = useHeatmapVizStore((state) => state.setVizRef);
|
|
2651
1946
|
useEffect(() => {
|
|
2652
1947
|
return () => {
|
|
2653
|
-
setVizRef(
|
|
1948
|
+
setVizRef(undefined);
|
|
2654
1949
|
setIframeHeight(0);
|
|
2655
1950
|
};
|
|
2656
1951
|
}, []);
|
|
@@ -2665,7 +1960,7 @@ const VizLiveRenderer = () => {
|
|
|
2665
1960
|
const setIframeHeight = useHeatmapLiveStore((state) => state.setIframeHeight);
|
|
2666
1961
|
const visualRef = useRef(null);
|
|
2667
1962
|
const wrapperRef = useRef(null);
|
|
2668
|
-
const { iframeRef } =
|
|
1963
|
+
const { iframeRef } = useIframeRender();
|
|
2669
1964
|
const { scaledHeight, handleScroll } = useHeatmapScale({
|
|
2670
1965
|
wrapperRef,
|
|
2671
1966
|
iframeRef,
|
|
@@ -2677,15 +1972,13 @@ const VizLiveRenderer = () => {
|
|
|
2677
1972
|
const scrollTop = e.currentTarget.scrollTop;
|
|
2678
1973
|
handleScroll(scrollTop);
|
|
2679
1974
|
};
|
|
2680
|
-
return (jsx(WrapperVisual, { visualRef: visualRef, wrapperRef: wrapperRef, scaledHeight: scaledHeight, iframeHeight: iframeHeight, onScroll: onScroll, children: jsx("iframe", { ref: iframeRef, ...HEATMAP_IFRAME, width: contentWidth,
|
|
2681
|
-
// height={iframeHeight}
|
|
2682
|
-
scrolling: "no", sandbox: "allow-scripts allow-same-origin" }) }));
|
|
1975
|
+
return (jsx(WrapperVisual, { visualRef: visualRef, wrapperRef: wrapperRef, scaledHeight: scaledHeight, iframeHeight: iframeHeight, onScroll: onScroll, children: jsx("iframe", { ref: iframeRef, ...HEATMAP_IFRAME, width: contentWidth, height: iframeHeight, scrolling: "no", sandbox: "allow-scripts allow-same-origin" }) }));
|
|
2683
1976
|
};
|
|
2684
1977
|
|
|
2685
1978
|
const VizLiveHeatmap = () => {
|
|
2686
1979
|
const controls = useHeatmapControlStore((state) => state.controls);
|
|
2687
1980
|
const isRendering = useHeatmapDataStore((state) => state.isRendering);
|
|
2688
|
-
const iframeHeight =
|
|
1981
|
+
const iframeHeight = useHeatmapVizStore((state) => state.iframeHeight);
|
|
2689
1982
|
const wrapperHeight = useHeatmapLiveStore((state) => state.wrapperHeight);
|
|
2690
1983
|
const setWrapperHeight = useHeatmapLiveStore((state) => state.setWrapperHeight);
|
|
2691
1984
|
const reset = useHeatmapLiveStore((state) => state.reset);
|
|
@@ -2760,4 +2053,4 @@ const HeatmapLayout = ({ data, clickmap, controls, dataInfo, }) => {
|
|
|
2760
2053
|
}
|
|
2761
2054
|
};
|
|
2762
2055
|
|
|
2763
|
-
export { GraphView, HeatmapLayout, IHeatmapType, useHeatmapConfigStore, useHeatmapDataStore, useHeatmapInteractionStore, useHeatmapLiveStore
|
|
2056
|
+
export { GraphView, HeatmapLayout, IHeatmapType, useHeatmapConfigStore, useHeatmapDataStore, useHeatmapInteractionStore, useHeatmapLiveStore };
|