@gemx-dev/heatmap-react 3.5.46 → 3.5.48
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/ContentToolbar.d.ts.map +1 -1
- 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/VizElement/VizElements.d.ts.map +1 -1
- 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/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/{src/components/VizScrollmap/index.ts → dist/esm/components/VizScrollmap/index.d.ts} +1 -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/{src/components/VizScrollmapV2/index.ts → dist/esm/components/VizScrollmapV2/index.d.ts} +1 -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/configs/style.d.ts +2 -0
- package/dist/esm/configs/style.d.ts.map +1 -1
- 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/esm/helpers/iframe-helper/style-replacer.d.ts +25 -0
- 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/{src/helpers/viz-canvas/index.ts → dist/esm/helpers/viz-canvas/index.d.ts} +1 -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/useClickmap.d.ts +3 -1
- package/dist/esm/hooks/viz-canvas/useClickmap.d.ts.map +1 -1
- 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 +3 -1
- 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/viz-elements/useHeatmapMouseHandler.d.ts +34 -0
- package/dist/esm/hooks/viz-elements/useHeatmapMouseHandler.d.ts.map +1 -0
- package/dist/esm/hooks/{vix-elements → viz-elements}/useHoveredElement.d.ts +4 -0
- package/dist/esm/hooks/viz-elements/useHoveredElement.d.ts.map +1 -0
- package/dist/esm/hooks/viz-live/index.d.ts +1 -1
- package/dist/{umd/hooks/viz-live/useIframeMessage.d.ts → esm/hooks/viz-live/useVizLiveIframeMsg.d.ts} +2 -10
- package/dist/esm/hooks/viz-live/useVizLiveIframeMsg.d.ts.map +1 -0
- package/dist/esm/hooks/viz-live/useVizLiveRender.d.ts +4 -0
- package/dist/esm/hooks/viz-live/useVizLiveRender.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/useObserveIframeHeight.d.ts +10 -0
- package/dist/esm/hooks/viz-scale/useObserveIframeHeight.d.ts.map +1 -0
- package/dist/esm/hooks/viz-scale/useScaleCalculation.d.ts +4 -0
- package/dist/esm/hooks/viz-scale/useScaleCalculation.d.ts.map +1 -1
- package/{src/hooks/viz-scrollmap/index.ts → dist/esm/hooks/viz-scrollmap/index.d.ts} +1 -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.d.ts +1 -1
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +1237 -220
- package/dist/esm/index.mjs +1237 -220
- 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 +2 -0
- 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 +4 -0
- package/dist/esm/stores/mode-live.d.ts.map +1 -1
- package/dist/esm/stores/mode-single.d.ts +9 -0
- package/dist/esm/stores/mode-single.d.ts.map +1 -0
- package/dist/esm/stores/viz-scrollmap.d.ts +11 -0
- package/dist/esm/stores/viz-scrollmap.d.ts.map +1 -0
- package/dist/esm/stores/viz.d.ts +6 -4
- package/dist/esm/stores/viz.d.ts.map +1 -1
- 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/ContentToolbar.d.ts.map +1 -1
- 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/VizElement/VizElements.d.ts.map +1 -1
- 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/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/configs/style.d.ts +2 -0
- package/dist/umd/configs/style.d.ts.map +1 -1
- 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/umd/helpers/iframe-helper/style-replacer.d.ts +25 -0
- 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/useClickmap.d.ts +3 -1
- package/dist/umd/hooks/viz-canvas/useClickmap.d.ts.map +1 -1
- 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 +3 -1
- 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/viz-elements/useHeatmapMouseHandler.d.ts +34 -0
- package/dist/umd/hooks/viz-elements/useHeatmapMouseHandler.d.ts.map +1 -0
- package/dist/umd/hooks/{vix-elements → viz-elements}/useHoveredElement.d.ts +4 -0
- package/dist/umd/hooks/viz-elements/useHoveredElement.d.ts.map +1 -0
- package/dist/umd/hooks/viz-live/index.d.ts +1 -1
- package/dist/{esm/hooks/viz-live/useIframeMessage.d.ts → umd/hooks/viz-live/useVizLiveIframeMsg.d.ts} +2 -10
- package/dist/umd/hooks/viz-live/useVizLiveIframeMsg.d.ts.map +1 -0
- package/dist/umd/hooks/viz-live/useVizLiveRender.d.ts +4 -0
- package/dist/umd/hooks/viz-live/useVizLiveRender.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/useObserveIframeHeight.d.ts +10 -0
- package/dist/umd/hooks/viz-scale/useObserveIframeHeight.d.ts.map +1 -0
- package/dist/umd/hooks/viz-scale/useScaleCalculation.d.ts +4 -0
- package/dist/umd/hooks/viz-scale/useScaleCalculation.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.d.ts +1 -1
- package/dist/umd/index.d.ts.map +1 -1
- 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 +2 -0
- 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 +4 -0
- package/dist/umd/stores/mode-live.d.ts.map +1 -1
- package/dist/umd/stores/mode-single.d.ts +9 -0
- package/dist/umd/stores/mode-single.d.ts.map +1 -0
- package/dist/umd/stores/viz-scrollmap.d.ts +11 -0
- package/dist/umd/stores/viz-scrollmap.d.ts.map +1 -0
- package/dist/umd/stores/viz.d.ts +6 -4
- package/dist/umd/stores/viz.d.ts.map +1 -1
- 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 +14 -11
- package/dist/esm/components/Layout/ContentHeader.d.ts +0 -4
- package/dist/esm/components/Layout/ContentHeader.d.ts.map +0 -1
- package/dist/esm/components/Layout/VizMode.d.ts +0 -2
- package/dist/esm/components/Layout/VizMode.d.ts.map +0 -1
- package/dist/esm/components/Test.d.ts +0 -121
- package/dist/esm/components/Test.d.ts.map +0 -1
- package/dist/esm/components/VizDom/VizDomContainer.d.ts +0 -6
- package/dist/esm/components/VizDom/VizDomContainer.d.ts.map +0 -1
- package/dist/esm/components/VizElement/ClickedElementOverlay.d.ts +0 -17
- package/dist/esm/components/VizElement/ClickedElementOverlay.d.ts.map +0 -1
- package/dist/esm/components/VizElement/HoveredElementOverlay.d.ts +0 -12
- package/dist/esm/components/VizElement/HoveredElementOverlay.d.ts.map +0 -1
- package/dist/esm/components/VizElement/MissingElementMessage.d.ts +0 -7
- package/dist/esm/components/VizElement/MissingElementMessage.d.ts.map +0 -1
- package/dist/esm/components/VizElement/temp/ClarityVisualizer.d.ts +0 -150
- package/dist/esm/components/VizElement/temp/ClarityVisualizer.d.ts.map +0 -1
- package/dist/esm/components/VizElement/temp/VizElementRank.d.ts +0 -74
- package/dist/esm/components/VizElement/temp/VizElementRank.d.ts.map +0 -1
- package/dist/esm/components/VizLive/VizLive.d.ts +0 -2
- package/dist/esm/components/VizLive/VizLive.d.ts.map +0 -1
- package/dist/esm/helpers/viewport-fixer.d.ts +0 -13
- package/dist/esm/helpers/viewport-fixer.d.ts.map +0 -1
- package/dist/esm/helpers/viewport-replacer.d.ts +0 -26
- package/dist/esm/helpers/viewport-replacer.d.ts.map +0 -1
- package/dist/esm/hooks/vix-elements/useHoveredElement.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/hooks/viz-live/useIframeMessage.d.ts.map +0 -1
- package/dist/esm/hooks/viz-scale/useIframeHeight.d.ts +0 -10
- package/dist/esm/hooks/viz-scale/useIframeHeight.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/components/Layout/ContentHeader.d.ts +0 -4
- package/dist/umd/components/Layout/ContentHeader.d.ts.map +0 -1
- package/dist/umd/components/Test.d.ts +0 -121
- package/dist/umd/components/Test.d.ts.map +0 -1
- package/dist/umd/components/VizDom/VizDomContainer.d.ts +0 -2
- package/dist/umd/components/VizDom/VizDomContainer.d.ts.map +0 -1
- package/dist/umd/components/VizElement/ClickedElementOverlay.d.ts +0 -17
- package/dist/umd/components/VizElement/ClickedElementOverlay.d.ts.map +0 -1
- package/dist/umd/components/VizElement/HoveredElementOverlay.d.ts +0 -12
- package/dist/umd/components/VizElement/HoveredElementOverlay.d.ts.map +0 -1
- package/dist/umd/components/VizElement/MissingElementMessage.d.ts +0 -7
- package/dist/umd/components/VizElement/MissingElementMessage.d.ts.map +0 -1
- package/dist/umd/components/VizElement/temp/ClarityVisualizer.d.ts +0 -150
- package/dist/umd/components/VizElement/temp/ClarityVisualizer.d.ts.map +0 -1
- package/dist/umd/components/VizElement/temp/VizElementRank.d.ts +0 -74
- package/dist/umd/components/VizElement/temp/VizElementRank.d.ts.map +0 -1
- package/dist/umd/helpers/viewport-fixer.d.ts +0 -13
- package/dist/umd/helpers/viewport-fixer.d.ts.map +0 -1
- package/dist/umd/helpers/viewport-replacer.d.ts +0 -26
- package/dist/umd/helpers/viewport-replacer.d.ts.map +0 -1
- package/dist/umd/hooks/vix-elements/useHoveredElement.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/hooks/viz-live/useIframeMessage.d.ts.map +0 -1
- package/dist/umd/hooks/viz-scale/useIframeHeight.d.ts +0 -10
- package/dist/umd/hooks/viz-scale/useIframeHeight.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/src/components/GraphView.tsx +0 -58
- package/src/components/Layout/ContentMetricBar.tsx +0 -23
- package/src/components/Layout/ContentToolbar.tsx +0 -22
- package/src/components/Layout/ContentTopBar.tsx +0 -24
- package/src/components/Layout/ContentVizByMode.tsx +0 -14
- package/src/components/Layout/HeatmapLayout.tsx +0 -60
- package/src/components/Layout/LeftSidebar.tsx +0 -44
- package/src/components/Layout/WrapperLayout.tsx +0 -12
- package/src/components/Layout/WrapperPreview.tsx +0 -24
- package/src/components/Layout/index.ts +0 -1
- package/src/components/VizDom/ReplayControls.tsx +0 -48
- package/src/components/VizDom/VizContainer.tsx +0 -40
- package/src/components/VizDom/VizDomHeatmap.tsx +0 -28
- package/src/components/VizDom/VizDomRenderer.tsx +0 -82
- package/src/components/VizDom/VizLoading.tsx +0 -8
- package/src/components/VizDom/WrapperVisual.tsx +0 -73
- package/src/components/VizDom/index.ts +0 -5
- package/src/components/VizElement/DefaultRankBadges.tsx +0 -36
- package/src/components/VizElement/ElementCallout.tsx +0 -82
- package/src/components/VizElement/ElementMissing.tsx +0 -35
- package/src/components/VizElement/ElementOverlay.tsx +0 -66
- package/src/components/VizElement/HeatmapElements.tsx +0 -127
- package/src/components/VizElement/HeatmapExample.tsx +0 -70
- package/src/components/VizElement/RankBadge.tsx +0 -25
- package/src/components/VizElement/VizElements.tsx +0 -57
- package/src/components/VizElement/index.ts +0 -1
- package/src/components/VizLive/VizLiveHeatmap.tsx +0 -27
- package/src/components/VizLive/VizLiveRenderer.tsx +0 -47
- package/src/components/VizLive/index.ts +0 -1
- package/src/components/VizScrollmap/AverageFoldLine.tsx +0 -57
- package/src/components/VizScrollmap/HoverZones.tsx +0 -58
- package/src/components/VizScrollmap/MetricRow.tsx +0 -0
- package/src/components/VizScrollmap/ScrollMapMinimap.tsx +0 -64
- package/src/components/VizScrollmap/ScrollMapOverlay.tsx +0 -79
- package/src/components/VizScrollmap/ScrollZoneHoverArea.tsx +0 -35
- package/src/components/VizScrollmap/ScrollZoneTooltip.tsx +0 -146
- package/src/components/VizScrollmap/ScrollmapMarker.tsx +0 -106
- package/src/components/VizScrollmap/VizScrollMap.tsx +0 -36
- package/src/components/VizScrollmapV2/ScrollmapOverlay.css +0 -94
- package/src/components/VizScrollmapV2/ScrollmapOverlayV2.tsx +0 -130
- package/src/components/VizScrollmapV2/scrollmap.types.ts +0 -21
- package/src/components/VizScrollmapV2/useScrollmapOverlay.ts +0 -187
- package/src/components/index.tsx +0 -2
- package/src/configs/iframe.ts +0 -15
- package/src/configs/index.ts +0 -2
- package/src/configs/style.ts +0 -21
- package/src/constants/index.ts +0 -4
- package/src/global.d.ts +0 -5
- package/src/helpers/elm-callout.ts +0 -347
- package/src/helpers/elm-getter.ts +0 -70
- package/src/helpers/iframe-helper/fixer.ts +0 -100
- package/src/helpers/iframe-helper/index.ts +0 -1
- package/src/helpers/iframe-helper/init.ts +0 -56
- package/src/helpers/iframe-helper/navigation-blocker-v2.ts +0 -371
- package/src/helpers/iframe-helper/navigation-blocker.ts +0 -367
- package/src/helpers/iframe-helper/style-replacer.ts +0 -231
- package/src/helpers/iframe.ts +0 -42
- package/src/helpers/index.ts +0 -8
- package/src/helpers/viz-canvas/area-clustering.ts +0 -234
- package/src/helpers/viz-canvas/area-overlay-manager-v2.ts +0 -176
- package/src/helpers/viz-canvas/area-overlay-manager.ts +0 -273
- package/src/helpers/viz-canvas/hierarchical-area-clustering.ts +0 -420
- package/src/helpers/viz-elements.ts +0 -43
- package/src/hooks/index.ts +0 -8
- package/src/hooks/register/index.ts +0 -4
- package/src/hooks/register/useRegisterConfig.ts +0 -17
- package/src/hooks/register/useRegisterControl.ts +0 -13
- package/src/hooks/register/useRegisterData.ts +0 -36
- package/src/hooks/register/useRegisterHeatmap.ts +0 -38
- package/src/hooks/viz-area/useAreaHeatmap.ts +0 -336
- package/src/hooks/viz-area/useAreaHeatmapManager.ts +0 -692
- package/src/hooks/viz-canvas/index.ts +0 -1
- package/src/hooks/viz-canvas/useAreamap.ts +0 -162
- package/src/hooks/viz-canvas/useClickmap.ts +0 -24
- package/src/hooks/viz-canvas/useHeatmapCanvas.ts +0 -27
- package/src/hooks/viz-canvas/useScrollmap.ts +0 -22
- package/src/hooks/viz-elements/index.ts +0 -5
- package/src/hooks/viz-elements/useClickedElement.ts +0 -86
- package/src/hooks/viz-elements/useElementCalloutVisible.ts +0 -45
- package/src/hooks/viz-elements/useHeatmapEffects.ts +0 -30
- package/src/hooks/viz-elements/useHeatmapElementPosition.ts +0 -60
- package/src/hooks/viz-elements/useHeatmapMouseHandler.ts +0 -255
- package/src/hooks/viz-elements/useHoveredElement.ts +0 -170
- package/src/hooks/viz-live/index.ts +0 -1
- package/src/hooks/viz-live/useVizLiveIframeMsg.ts +0 -88
- package/src/hooks/viz-live/useVizLiveRender.ts +0 -67
- package/src/hooks/viz-render/index.ts +0 -1
- package/src/hooks/viz-render/useHeatmapRender.ts +0 -71
- package/src/hooks/viz-render/useHeatmapVizRender.ts +0 -20
- package/src/hooks/viz-render/useReplayRender.ts +0 -160
- package/src/hooks/viz-scale/index.ts +0 -2
- package/src/hooks/viz-scale/useContainerDimensions.ts +0 -48
- package/src/hooks/viz-scale/useContentDimensions.ts +0 -25
- package/src/hooks/viz-scale/useHeatmapScale.ts +0 -52
- package/src/hooks/viz-scale/useObserveIframeHeight.ts +0 -162
- package/src/hooks/viz-scale/useScaleCalculation.ts +0 -31
- package/src/hooks/viz-scale/useScrollSync.ts +0 -36
- package/src/hooks/viz-scale/useWrapperRefHeight.ts +0 -91
- package/src/hooks/viz-scrollmap/useScrollmapZones.ts +0 -165
- package/src/hooks/viz-scrollmap/useZonePositions.ts +0 -38
- package/src/index.ts +0 -10
- package/src/stores/comp.ts +0 -31
- package/src/stores/config.ts +0 -37
- package/src/stores/data.ts +0 -30
- package/src/stores/index.ts +0 -10
- package/src/stores/interaction.ts +0 -32
- package/src/stores/mode-live.ts +0 -38
- package/src/stores/mode-single.ts +0 -18
- package/src/stores/viz-scrollmap.ts +0 -22
- package/src/stores/viz.ts +0 -17
- package/src/styles/base.css +0 -1
- package/src/styles/style.css +0 -137
- package/src/types/clarity.ts +0 -45
- package/src/types/control.ts +0 -10
- package/src/types/elm-callout.ts +0 -9
- package/src/types/heatmap-info.ts +0 -11
- package/src/types/heatmap.ts +0 -25
- package/src/types/iframe-helper.ts +0 -18
- package/src/types/index.ts +0 -12
- package/src/types/viz-canvas.ts +0 -20
- package/src/types/viz-element.ts +0 -34
- package/src/types/viz-scrollmap.ts +0 -28
- package/src/ui/BoxStack/BoxStack.tsx +0 -136
- package/src/ui/BoxStack/index.ts +0 -1
- package/src/ui/index.ts +0 -1
- package/src/utils/debounce.ts +0 -10
- package/src/utils/device.ts +0 -7
- package/src/utils/retry.ts +0 -20
- package/src/utils/sort.ts +0 -5
- /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
|
@@ -61,6 +61,8 @@ 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`,
|
|
64
66
|
},
|
|
65
67
|
};
|
|
66
68
|
const DEFAULT_SIDEBAR_WIDTH = 260;
|
|
@@ -91,18 +93,37 @@ var IHeatmapType;
|
|
|
91
93
|
IHeatmapType["Click"] = "click";
|
|
92
94
|
IHeatmapType["Scroll"] = "scroll";
|
|
93
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 = {}));
|
|
94
111
|
|
|
95
112
|
const useHeatmapConfigStore = create()((set, get) => {
|
|
96
113
|
return {
|
|
97
114
|
mode: 'single',
|
|
98
115
|
width: 1440,
|
|
99
116
|
sidebarWidth: DEFAULT_SIDEBAR_WIDTH,
|
|
100
|
-
heatmapType: IHeatmapType.
|
|
117
|
+
heatmapType: IHeatmapType.Scroll,
|
|
118
|
+
clickType: IClickType.Total,
|
|
119
|
+
scrollType: IScrollType.Depth,
|
|
101
120
|
setMode: (mode) => set({ mode }),
|
|
102
121
|
resetMode: () => set({ mode: 'single' }),
|
|
103
122
|
setWidth: (width) => set({ width }),
|
|
104
123
|
setSidebarWidth: (sidebarWidth) => set({ sidebarWidth }),
|
|
105
124
|
setHeatmapType: (heatmapType) => set({ heatmapType }),
|
|
125
|
+
setClickType: (clickType) => set({ clickType }),
|
|
126
|
+
setScrollType: (scrollType) => set({ scrollType }),
|
|
106
127
|
};
|
|
107
128
|
});
|
|
108
129
|
|
|
@@ -111,11 +132,13 @@ const useHeatmapDataStore = create()((set, get) => {
|
|
|
111
132
|
data: undefined,
|
|
112
133
|
clickmap: undefined,
|
|
113
134
|
dataInfo: undefined,
|
|
135
|
+
scrollmap: undefined,
|
|
114
136
|
isRendering: true,
|
|
115
137
|
setIsRendering: (isRendering) => set({ isRendering }),
|
|
116
138
|
setDataInfo: (dataInfo) => set({ dataInfo }),
|
|
117
139
|
setData: (data) => set({ data }),
|
|
118
140
|
setClickmap: (clickmap) => set({ clickmap }),
|
|
141
|
+
setScrollmap: (scrollmap) => set({ scrollmap }),
|
|
119
142
|
};
|
|
120
143
|
});
|
|
121
144
|
|
|
@@ -138,16 +161,30 @@ const useHeatmapVizStore = create()((set, get) => {
|
|
|
138
161
|
return {
|
|
139
162
|
isRenderViz: false,
|
|
140
163
|
setIsRenderViz: (isRenderViz) => set({ isRenderViz }),
|
|
164
|
+
zoomRatio: 100,
|
|
165
|
+
minZoomRatio: 10,
|
|
166
|
+
setMinZoomRatio: (minZoomRatio) => set({ minZoomRatio }),
|
|
167
|
+
setZoomRatio: (zoomRatio) => set({ zoomRatio }),
|
|
141
168
|
scale: 1,
|
|
142
|
-
vizRef: undefined,
|
|
143
|
-
iframeHeight: 0,
|
|
144
169
|
setScale: (scale) => set({ scale }),
|
|
145
|
-
|
|
146
|
-
|
|
170
|
+
isScaledToFit: false,
|
|
171
|
+
setIsScaledToFit: (isScaledToFit) => set({ isScaledToFit }),
|
|
172
|
+
};
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
const useHeatmapVizScrollmapStore = create()((set, get) => {
|
|
176
|
+
return {
|
|
177
|
+
zones: [],
|
|
178
|
+
hoveredZone: null,
|
|
179
|
+
showMinimap: true,
|
|
180
|
+
setZones: (zones) => set({ zones }),
|
|
181
|
+
setHoveredZone: (hoveredZone) => set({ hoveredZone }),
|
|
182
|
+
setShowMinimap: (showMinimap) => set({ showMinimap }),
|
|
147
183
|
};
|
|
148
184
|
});
|
|
149
185
|
|
|
150
186
|
const initialState = {
|
|
187
|
+
payloads: [],
|
|
151
188
|
htmlContent: '',
|
|
152
189
|
wrapperHeight: 0,
|
|
153
190
|
iframeHeight: 0,
|
|
@@ -156,12 +193,23 @@ const useHeatmapLiveStore = create()((set, get) => {
|
|
|
156
193
|
return {
|
|
157
194
|
...initialState,
|
|
158
195
|
reset: () => set(initialState),
|
|
196
|
+
setPayloads: (payloads) => set({ payloads }),
|
|
197
|
+
addPayload: (payload) => set((state) => ({ payloads: [...state.payloads, payload] })),
|
|
159
198
|
setHtmlContent: (htmlContent) => set({ htmlContent }),
|
|
160
199
|
setWrapperHeight: (wrapperHeight) => set({ wrapperHeight }),
|
|
161
200
|
setIframeHeight: (iframeHeight) => set({ iframeHeight }),
|
|
162
201
|
};
|
|
163
202
|
});
|
|
164
203
|
|
|
204
|
+
const useHeatmapSingleStore = create()((set, get) => {
|
|
205
|
+
return {
|
|
206
|
+
vizRef: null,
|
|
207
|
+
iframeHeight: 0,
|
|
208
|
+
setVizRef: (vizRef) => set({ vizRef }),
|
|
209
|
+
setIframeHeight: (iframeHeight) => set({ iframeHeight }),
|
|
210
|
+
};
|
|
211
|
+
});
|
|
212
|
+
|
|
165
213
|
const useRegisterConfig = () => {
|
|
166
214
|
const mode = useHeatmapConfigStore((state) => state.mode);
|
|
167
215
|
const width = useHeatmapConfigStore((state) => state.width);
|
|
@@ -209,16 +257,25 @@ const useRegisterData = (data, dataInfo) => {
|
|
|
209
257
|
}, [dataInfo]);
|
|
210
258
|
};
|
|
211
259
|
|
|
212
|
-
const useRegisterHeatmap = (clickmap) => {
|
|
260
|
+
const useRegisterHeatmap = ({ clickmap, scrollmap }) => {
|
|
213
261
|
const setClickmap = useHeatmapDataStore((state) => state.setClickmap);
|
|
262
|
+
const setScrollmap = useHeatmapDataStore((state) => state.setScrollmap);
|
|
214
263
|
const handleSetClickmap = useCallback((clickmap) => {
|
|
215
264
|
if (!clickmap)
|
|
216
265
|
return;
|
|
217
266
|
setClickmap(clickmap);
|
|
218
267
|
}, [clickmap]);
|
|
268
|
+
const handleSetScrollmap = useCallback((scrollmap) => {
|
|
269
|
+
if (!scrollmap)
|
|
270
|
+
return;
|
|
271
|
+
setScrollmap(scrollmap);
|
|
272
|
+
}, [scrollmap]);
|
|
219
273
|
useEffect(() => {
|
|
220
274
|
handleSetClickmap(clickmap);
|
|
221
275
|
}, [clickmap]);
|
|
276
|
+
useEffect(() => {
|
|
277
|
+
handleSetScrollmap(scrollmap);
|
|
278
|
+
}, [scrollmap]);
|
|
222
279
|
};
|
|
223
280
|
|
|
224
281
|
const PADDING = 0;
|
|
@@ -501,91 +558,311 @@ function isElementInViewport(elementRect, visualRef, scale) {
|
|
|
501
558
|
return elementBottom > viewportTop && elementTop < viewportBottom;
|
|
502
559
|
}
|
|
503
560
|
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
class ViewportUnitsFixer {
|
|
519
|
-
iframe = null;
|
|
520
|
-
config;
|
|
521
|
-
constructor(config) {
|
|
522
|
-
this.config = config;
|
|
523
|
-
this.iframe = config.iframe;
|
|
561
|
+
class IframeNavigationBlockerV2 {
|
|
562
|
+
doc;
|
|
563
|
+
win;
|
|
564
|
+
isEnabled = false;
|
|
565
|
+
showMessage = false;
|
|
566
|
+
originalWindowOpen;
|
|
567
|
+
observers = [];
|
|
568
|
+
constructor(iframe) {
|
|
569
|
+
if (!iframe.contentDocument || !iframe.contentWindow) {
|
|
570
|
+
throw new Error('Iframe document or window not accessible');
|
|
571
|
+
}
|
|
572
|
+
this.doc = iframe.contentDocument;
|
|
573
|
+
this.win = iframe.contentWindow;
|
|
574
|
+
this.originalWindowOpen = this.win.open.bind(this.win);
|
|
524
575
|
this.init();
|
|
525
576
|
}
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
577
|
+
init() {
|
|
578
|
+
console.log('[NavigationBlocker] Initializing...');
|
|
579
|
+
try {
|
|
580
|
+
// Chặn navigation qua links
|
|
581
|
+
this.blockLinkNavigation();
|
|
582
|
+
// Chặn form submissions
|
|
583
|
+
this.blockFormSubmissions();
|
|
584
|
+
// Chặn window.open (này an toàn)
|
|
585
|
+
this.blockWindowOpen();
|
|
586
|
+
// Chặn beforeunload để prevent navigation
|
|
587
|
+
this.blockBeforeUnload();
|
|
588
|
+
// Monitor DOM changes để block dynamic links
|
|
589
|
+
this.monitorDOMChanges();
|
|
590
|
+
// Inject CSP nếu có thể
|
|
591
|
+
this.injectCSP();
|
|
535
592
|
}
|
|
536
|
-
|
|
537
|
-
|
|
593
|
+
catch (error) {
|
|
594
|
+
console.error('[NavigationBlocker] Init error:', error);
|
|
538
595
|
}
|
|
539
596
|
}
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
597
|
+
blockLinkNavigation() {
|
|
598
|
+
// Sử dụng capture phase để chặn sớm nhất
|
|
599
|
+
this.doc.addEventListener('click', (e) => {
|
|
600
|
+
if (!this.isEnabled)
|
|
601
|
+
return;
|
|
602
|
+
const target = e.target;
|
|
603
|
+
const link = target.closest('a');
|
|
604
|
+
if (link) {
|
|
605
|
+
const href = link.getAttribute('href');
|
|
606
|
+
// Cho phép hash links và empty links
|
|
607
|
+
if (!href || href === '' || href === '#' || href.startsWith('#')) {
|
|
608
|
+
console.log('[NavigationBlocker] Allowed hash navigation:', href);
|
|
609
|
+
return;
|
|
610
|
+
}
|
|
611
|
+
// Chặn tất cả các loại navigation
|
|
612
|
+
console.log('[NavigationBlocker] Blocked link navigation to:', href);
|
|
613
|
+
e.preventDefault();
|
|
614
|
+
e.stopPropagation();
|
|
615
|
+
e.stopImmediatePropagation();
|
|
616
|
+
this.notifyBlockedNavigation(href);
|
|
617
|
+
}
|
|
618
|
+
}, true);
|
|
619
|
+
// Chặn cả middle click và right click "open in new tab"
|
|
620
|
+
this.doc.addEventListener('auxclick', (e) => {
|
|
621
|
+
if (!this.isEnabled)
|
|
622
|
+
return;
|
|
623
|
+
const target = e.target;
|
|
624
|
+
const link = target.closest('a');
|
|
625
|
+
if (link) {
|
|
626
|
+
const href = link.getAttribute('href');
|
|
627
|
+
if (href && !href.startsWith('#')) {
|
|
628
|
+
console.log('[NavigationBlocker] Blocked auxclick navigation');
|
|
629
|
+
e.preventDefault();
|
|
630
|
+
e.stopPropagation();
|
|
631
|
+
e.stopImmediatePropagation();
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
}, true);
|
|
635
|
+
// Disable tất cả links ngay từ đầu
|
|
636
|
+
this.disableAllLinks();
|
|
637
|
+
}
|
|
638
|
+
disableAllLinks() {
|
|
639
|
+
this.doc.querySelectorAll('a[href]').forEach((link) => {
|
|
640
|
+
const href = link.getAttribute('href');
|
|
641
|
+
if (href && !href.startsWith('#')) {
|
|
642
|
+
// Thêm pointer-events: none và cursor
|
|
643
|
+
link.style.cursor = 'not-allowed';
|
|
644
|
+
link.setAttribute('data-navigation-blocked', 'true');
|
|
645
|
+
// Remove href để browser không hiện preview
|
|
646
|
+
link.setAttribute('data-original-href', href);
|
|
647
|
+
link.removeAttribute('href');
|
|
648
|
+
// Hoặc giữ href nhưng disable
|
|
649
|
+
// link.setAttribute('onclick', 'return false');
|
|
650
|
+
}
|
|
651
|
+
});
|
|
652
|
+
}
|
|
653
|
+
blockFormSubmissions() {
|
|
654
|
+
this.doc.addEventListener('submit', (e) => {
|
|
655
|
+
if (!this.isEnabled)
|
|
656
|
+
return;
|
|
657
|
+
const form = e.target;
|
|
658
|
+
const action = form.getAttribute('action');
|
|
659
|
+
// Cho phép forms không có action
|
|
660
|
+
if (!action || action === '' || action === '#') {
|
|
661
|
+
console.log('[NavigationBlocker] Allowed same-page form');
|
|
662
|
+
e.preventDefault();
|
|
663
|
+
this.handleFormSubmit(form);
|
|
664
|
+
return;
|
|
665
|
+
}
|
|
666
|
+
// Chặn tất cả external submissions
|
|
667
|
+
console.log('[NavigationBlocker] Blocked form submission to:', action);
|
|
668
|
+
e.preventDefault();
|
|
669
|
+
e.stopPropagation();
|
|
670
|
+
e.stopImmediatePropagation();
|
|
671
|
+
this.notifyBlockedNavigation(action);
|
|
672
|
+
}, true);
|
|
673
|
+
}
|
|
674
|
+
blockWindowOpen() {
|
|
675
|
+
// Override window.open - đây là safe
|
|
676
|
+
this.win.open = ((...args) => {
|
|
677
|
+
if (!this.isEnabled) {
|
|
678
|
+
return this.originalWindowOpen(...args);
|
|
679
|
+
}
|
|
680
|
+
const url = args[0]?.toString() || 'popup';
|
|
681
|
+
console.log('[NavigationBlocker] Blocked window.open:', url);
|
|
682
|
+
this.notifyBlockedNavigation(url);
|
|
683
|
+
return null;
|
|
684
|
+
});
|
|
685
|
+
}
|
|
686
|
+
blockBeforeUnload() {
|
|
687
|
+
// Chặn unload
|
|
688
|
+
this.win.addEventListener('beforeunload', (e) => {
|
|
689
|
+
if (!this.isEnabled)
|
|
690
|
+
return;
|
|
691
|
+
console.log('[NavigationBlocker] Blocked beforeunload');
|
|
692
|
+
e.preventDefault();
|
|
693
|
+
e.returnValue = '';
|
|
694
|
+
return '';
|
|
695
|
+
}, true);
|
|
696
|
+
// Chặn unload
|
|
697
|
+
this.win.addEventListener('unload', (e) => {
|
|
698
|
+
if (!this.isEnabled)
|
|
699
|
+
return;
|
|
700
|
+
console.log('[NavigationBlocker] Blocked unload');
|
|
701
|
+
e.preventDefault();
|
|
702
|
+
e.stopPropagation();
|
|
703
|
+
}, true);
|
|
704
|
+
// Monitor popstate
|
|
705
|
+
this.win.addEventListener('popstate', (e) => {
|
|
706
|
+
if (!this.isEnabled)
|
|
707
|
+
return;
|
|
708
|
+
console.log('[NavigationBlocker] Blocked popstate');
|
|
709
|
+
e.preventDefault();
|
|
710
|
+
e.stopPropagation();
|
|
711
|
+
}, true);
|
|
712
|
+
}
|
|
713
|
+
monitorDOMChanges() {
|
|
714
|
+
// Monitor khi có links mới được thêm vào
|
|
715
|
+
const observer = new MutationObserver((mutations) => {
|
|
716
|
+
if (!this.isEnabled)
|
|
717
|
+
return;
|
|
718
|
+
mutations.forEach((mutation) => {
|
|
719
|
+
mutation.addedNodes.forEach((node) => {
|
|
720
|
+
if (node.nodeType === Node.ELEMENT_NODE) {
|
|
721
|
+
const element = node;
|
|
722
|
+
// Nếu là link
|
|
723
|
+
if (element.tagName === 'A') {
|
|
724
|
+
const href = element.getAttribute('href');
|
|
725
|
+
if (href && !href.startsWith('#')) {
|
|
726
|
+
element.style.cursor = 'not-allowed';
|
|
727
|
+
element.setAttribute('data-navigation-blocked', 'true');
|
|
728
|
+
element.setAttribute('data-original-href', href);
|
|
729
|
+
element.removeAttribute('href');
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
// Tìm links trong subtree
|
|
733
|
+
element.querySelectorAll('a[href]').forEach((link) => {
|
|
734
|
+
const href = link.getAttribute('href');
|
|
735
|
+
if (href && !href.startsWith('#')) {
|
|
736
|
+
link.style.cursor = 'not-allowed';
|
|
737
|
+
link.setAttribute('data-navigation-blocked', 'true');
|
|
738
|
+
link.setAttribute('data-original-href', href);
|
|
739
|
+
link.removeAttribute('href');
|
|
740
|
+
}
|
|
741
|
+
});
|
|
742
|
+
}
|
|
743
|
+
});
|
|
555
744
|
});
|
|
556
|
-
};
|
|
557
|
-
doc.
|
|
745
|
+
});
|
|
746
|
+
observer.observe(this.doc.body, {
|
|
747
|
+
childList: true,
|
|
748
|
+
subtree: true,
|
|
749
|
+
});
|
|
750
|
+
this.observers.push(observer);
|
|
751
|
+
}
|
|
752
|
+
injectCSP() {
|
|
753
|
+
// Thêm CSP meta tag nếu chưa có (optional)
|
|
754
|
+
try {
|
|
755
|
+
const existingCSP = this.doc.querySelector('meta[http-equiv="Content-Security-Policy"]');
|
|
756
|
+
if (!existingCSP) {
|
|
757
|
+
const meta = this.doc.createElement('meta');
|
|
758
|
+
meta.httpEquiv = 'Content-Security-Policy';
|
|
759
|
+
meta.content = "navigate-to 'none'"; // Chặn tất cả navigation
|
|
760
|
+
this.doc.head.appendChild(meta);
|
|
761
|
+
console.log('[NavigationBlocker] Injected CSP');
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
catch (error) {
|
|
765
|
+
console.warn('[NavigationBlocker] Could not inject CSP:', error);
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
handleFormSubmit(form) {
|
|
769
|
+
const formData = new FormData(form);
|
|
770
|
+
const data = {};
|
|
771
|
+
formData.forEach((value, key) => {
|
|
772
|
+
data[key] = value;
|
|
773
|
+
});
|
|
774
|
+
console.log('[NavigationBlocker] Handling form data:', data);
|
|
775
|
+
window.dispatchEvent(new CustomEvent('iframe-form-submit', {
|
|
776
|
+
detail: { form, data },
|
|
777
|
+
}));
|
|
778
|
+
}
|
|
779
|
+
notifyBlockedNavigation(url) {
|
|
780
|
+
console.warn('[NavigationBlocker] Navigation blocked to:', url);
|
|
781
|
+
window.dispatchEvent(new CustomEvent('iframe-navigation-blocked', {
|
|
782
|
+
detail: { url, timestamp: Date.now() },
|
|
783
|
+
}));
|
|
784
|
+
if (this.shouldShowMessage(url)) {
|
|
785
|
+
this.showBlockedMessage(url);
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
shouldShowMessage(url) {
|
|
789
|
+
return !url.startsWith('#') && url !== 'reload' && url !== 'popup';
|
|
558
790
|
}
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
if (!data || data.type !== 'IFRAME_HEIGHT_CALCULATED')
|
|
791
|
+
showBlockedMessage(url) {
|
|
792
|
+
if (!this.showMessage)
|
|
562
793
|
return;
|
|
563
|
-
this.
|
|
794
|
+
const message = this.doc.createElement('div');
|
|
795
|
+
message.style.cssText = `
|
|
796
|
+
position: fixed;
|
|
797
|
+
top: 20px;
|
|
798
|
+
right: 20px;
|
|
799
|
+
background: #ff6b6b;
|
|
800
|
+
color: white;
|
|
801
|
+
padding: 12px 20px;
|
|
802
|
+
border-radius: 8px;
|
|
803
|
+
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
|
|
804
|
+
z-index: 999999;
|
|
805
|
+
font-family: system-ui, -apple-system, sans-serif;
|
|
806
|
+
font-size: 14px;
|
|
807
|
+
max-width: 300px;
|
|
808
|
+
word-break: break-word;
|
|
809
|
+
pointer-events: none;
|
|
810
|
+
`;
|
|
811
|
+
const shortUrl = url.length > 50 ? url.substring(0, 47) + '...' : url;
|
|
812
|
+
message.innerHTML = `
|
|
813
|
+
<div style="font-weight: 600; margin-bottom: 4px;">🚫 Navigation Blocked</div>
|
|
814
|
+
<div style="font-size: 12px; opacity: 0.9;">${this.escapeHtml(shortUrl)}</div>
|
|
815
|
+
`;
|
|
816
|
+
this.doc.body.appendChild(message);
|
|
817
|
+
setTimeout(() => {
|
|
818
|
+
message.style.opacity = '0';
|
|
819
|
+
message.style.transition = 'opacity 0.3s';
|
|
820
|
+
setTimeout(() => message.remove(), 300);
|
|
821
|
+
}, 3000);
|
|
564
822
|
}
|
|
565
|
-
|
|
566
|
-
this.
|
|
823
|
+
escapeHtml(text) {
|
|
824
|
+
const div = this.doc.createElement('div');
|
|
825
|
+
div.textContent = text;
|
|
826
|
+
return div.innerHTML;
|
|
827
|
+
}
|
|
828
|
+
enable() {
|
|
829
|
+
this.isEnabled = true;
|
|
830
|
+
console.log('[NavigationBlocker] Enabled');
|
|
831
|
+
}
|
|
832
|
+
enableMessage() {
|
|
833
|
+
this.showMessage = true;
|
|
834
|
+
console.log('[NavigationBlocker] Enabled message');
|
|
835
|
+
}
|
|
836
|
+
disable() {
|
|
837
|
+
this.isEnabled = false;
|
|
838
|
+
console.log('[NavigationBlocker] Disabled');
|
|
839
|
+
}
|
|
840
|
+
disableMessage() {
|
|
841
|
+
this.showMessage = false;
|
|
842
|
+
console.log('[NavigationBlocker] Disabled message');
|
|
843
|
+
}
|
|
844
|
+
destroy() {
|
|
845
|
+
this.isEnabled = false;
|
|
846
|
+
this.showMessage = false;
|
|
847
|
+
// Cleanup observers
|
|
848
|
+
this.observers.forEach((observer) => observer.disconnect());
|
|
849
|
+
this.observers = [];
|
|
850
|
+
console.log('[NavigationBlocker] Destroyed');
|
|
567
851
|
}
|
|
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
852
|
}
|
|
578
853
|
|
|
579
|
-
class
|
|
854
|
+
class IframeStyleReplacer {
|
|
855
|
+
doc;
|
|
856
|
+
win;
|
|
580
857
|
config;
|
|
581
858
|
regex = /([-.\d]+)(vh|svh|lvh|dvh|vw|svw|lvw|dvw)/gi;
|
|
582
|
-
constructor() {
|
|
583
|
-
if (!
|
|
584
|
-
throw new Error('
|
|
859
|
+
constructor(iframe, config) {
|
|
860
|
+
if (!iframe.contentDocument || !iframe.contentWindow) {
|
|
861
|
+
throw new Error('Iframe document or window not accessible');
|
|
585
862
|
}
|
|
586
|
-
this.
|
|
587
|
-
|
|
588
|
-
this.
|
|
863
|
+
this.doc = iframe.contentDocument;
|
|
864
|
+
this.win = iframe.contentWindow;
|
|
865
|
+
this.config = config;
|
|
589
866
|
}
|
|
590
867
|
px(value) {
|
|
591
868
|
return `${value.toFixed(2)}px`;
|
|
@@ -611,26 +888,28 @@ class ViewportUnitsReplacer {
|
|
|
611
888
|
}
|
|
612
889
|
processInlineStyles() {
|
|
613
890
|
let count = 0;
|
|
614
|
-
|
|
891
|
+
this.doc.querySelectorAll('[style]').forEach((el) => {
|
|
615
892
|
const style = el.getAttribute('style');
|
|
616
893
|
if (style && this.regex.test(style)) {
|
|
894
|
+
this.regex.lastIndex = 0;
|
|
617
895
|
el.setAttribute('style', this.replaceInText(style));
|
|
618
896
|
count++;
|
|
619
897
|
}
|
|
620
898
|
});
|
|
621
|
-
console.log(`[
|
|
899
|
+
console.log(`[IframeStyleReplacer] Replaced ${count} inline style elements`);
|
|
622
900
|
return count;
|
|
623
901
|
}
|
|
624
902
|
processStyleTags() {
|
|
625
903
|
let count = 0;
|
|
626
|
-
|
|
904
|
+
this.doc.querySelectorAll('style').forEach((tag) => {
|
|
627
905
|
const css = tag.textContent || '';
|
|
628
906
|
if (this.regex.test(css)) {
|
|
907
|
+
this.regex.lastIndex = 0;
|
|
629
908
|
tag.textContent = this.replaceInText(css);
|
|
630
909
|
count++;
|
|
631
910
|
}
|
|
632
911
|
});
|
|
633
|
-
console.log(`[
|
|
912
|
+
console.log(`[IframeStyleReplacer] Replaced ${count} <style> tags`);
|
|
634
913
|
return count;
|
|
635
914
|
}
|
|
636
915
|
processRule(rule) {
|
|
@@ -641,6 +920,7 @@ class ViewportUnitsReplacer {
|
|
|
641
920
|
const prop = style[i];
|
|
642
921
|
const value = style.getPropertyValue(prop);
|
|
643
922
|
if (value && this.regex.test(value)) {
|
|
923
|
+
this.regex.lastIndex = 0;
|
|
644
924
|
style.setProperty(prop, this.replaceInText(value), style.getPropertyPriority(prop));
|
|
645
925
|
count++;
|
|
646
926
|
}
|
|
@@ -656,11 +936,11 @@ class ViewportUnitsReplacer {
|
|
|
656
936
|
}
|
|
657
937
|
processStylesheets() {
|
|
658
938
|
let total = 0;
|
|
659
|
-
Array.from(
|
|
939
|
+
Array.from(this.doc.styleSheets).forEach((sheet) => {
|
|
660
940
|
try {
|
|
661
941
|
// Bỏ qua external CSS (cross-origin)
|
|
662
|
-
if (sheet.href && !sheet.href.startsWith(location.origin)) {
|
|
663
|
-
console.log('[
|
|
942
|
+
if (sheet.href && !sheet.href.startsWith(this.win.location.origin)) {
|
|
943
|
+
console.log('[IframeStyleReplacer] Skipping external CSS:', sheet.href);
|
|
664
944
|
return;
|
|
665
945
|
}
|
|
666
946
|
const rules = sheet.cssRules || sheet.rules;
|
|
@@ -671,26 +951,27 @@ class ViewportUnitsReplacer {
|
|
|
671
951
|
}
|
|
672
952
|
}
|
|
673
953
|
catch (e) {
|
|
674
|
-
console.warn('[
|
|
954
|
+
console.warn('[IframeStyleReplacer] Cannot read stylesheet (CORS?):', e.message);
|
|
675
955
|
}
|
|
676
956
|
});
|
|
677
|
-
console.log(`[
|
|
957
|
+
console.log(`[IframeStyleReplacer] Replaced ${total} rules in stylesheets`);
|
|
678
958
|
return total;
|
|
679
959
|
}
|
|
680
960
|
async processLinkedStylesheets() {
|
|
681
|
-
const links =
|
|
961
|
+
const links = this.doc.querySelectorAll('link[rel="stylesheet"]');
|
|
682
962
|
let count = 0;
|
|
683
963
|
for (const link of Array.from(links)) {
|
|
684
|
-
if (!link.href.startsWith(location.origin)) {
|
|
685
|
-
console.log('[
|
|
964
|
+
if (!link.href.startsWith(this.win.location.origin)) {
|
|
965
|
+
console.log('[IframeStyleReplacer] Skipping external CSS:', link.href);
|
|
686
966
|
continue;
|
|
687
967
|
}
|
|
688
968
|
try {
|
|
689
969
|
const res = await fetch(link.href);
|
|
690
970
|
let css = await res.text();
|
|
691
971
|
if (this.regex.test(css)) {
|
|
972
|
+
this.regex.lastIndex = 0;
|
|
692
973
|
css = this.replaceInText(css);
|
|
693
|
-
const style =
|
|
974
|
+
const style = this.doc.createElement('style');
|
|
694
975
|
style.textContent = css;
|
|
695
976
|
style.dataset.originalHref = link.href;
|
|
696
977
|
link.parentNode?.insertBefore(style, link);
|
|
@@ -699,30 +980,25 @@ class ViewportUnitsReplacer {
|
|
|
699
980
|
}
|
|
700
981
|
}
|
|
701
982
|
catch (e) {
|
|
702
|
-
console.warn('[
|
|
983
|
+
console.warn('[IframeStyleReplacer] Cannot load CSS:', link.href, e);
|
|
703
984
|
}
|
|
704
985
|
}
|
|
705
|
-
console.log(`[
|
|
986
|
+
console.log(`[IframeStyleReplacer] Replaced ${count} linked CSS files`);
|
|
706
987
|
return count;
|
|
707
988
|
}
|
|
708
989
|
getFinalHeight() {
|
|
709
990
|
// Trigger reflow
|
|
710
|
-
void
|
|
711
|
-
return Math.max(
|
|
991
|
+
void this.doc.body.offsetHeight;
|
|
992
|
+
return Math.max(this.doc.body.scrollHeight, this.doc.body.offsetHeight, this.doc.documentElement.scrollHeight, this.doc.documentElement.offsetHeight, this.doc.documentElement.clientHeight);
|
|
712
993
|
}
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
type: 'IFRAME_HEIGHT_CALCULATED',
|
|
716
|
-
height,
|
|
717
|
-
width: document.body.scrollWidth,
|
|
718
|
-
}, '*');
|
|
719
|
-
console.log('[Iframe] Sent height to parent:', height);
|
|
994
|
+
getFinalWidth() {
|
|
995
|
+
return Math.max(this.doc.body.scrollWidth, this.doc.body.offsetWidth, this.doc.documentElement.scrollWidth, this.doc.documentElement.offsetWidth, this.doc.documentElement.clientWidth);
|
|
720
996
|
}
|
|
721
997
|
async waitForResources() {
|
|
722
|
-
if ('fonts' in
|
|
723
|
-
await
|
|
998
|
+
if ('fonts' in this.doc) {
|
|
999
|
+
await this.doc.fonts.ready;
|
|
724
1000
|
}
|
|
725
|
-
const images = Array.from(
|
|
1001
|
+
const images = Array.from(this.doc.images).filter((img) => !img.complete);
|
|
726
1002
|
if (images.length > 0) {
|
|
727
1003
|
await Promise.all(images.map((img) => new Promise((resolve) => {
|
|
728
1004
|
img.onload = img.onerror = resolve;
|
|
@@ -731,35 +1007,131 @@ class ViewportUnitsReplacer {
|
|
|
731
1007
|
}
|
|
732
1008
|
async run() {
|
|
733
1009
|
try {
|
|
1010
|
+
console.log('[IframeStyleReplacer] Starting viewport units replacement...');
|
|
734
1011
|
this.processInlineStyles();
|
|
735
1012
|
this.processStyleTags();
|
|
736
1013
|
this.processStylesheets();
|
|
737
1014
|
await this.processLinkedStylesheets();
|
|
738
1015
|
// await this.waitForResources();
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
1016
|
+
return await new Promise((resolve) => {
|
|
1017
|
+
requestAnimationFrame(() => {
|
|
1018
|
+
const height = this.getFinalHeight();
|
|
1019
|
+
const width = this.getFinalWidth();
|
|
1020
|
+
console.log('[IframeStyleReplacer] Calculated dimensions:', { height, width });
|
|
1021
|
+
resolve({ height, width });
|
|
1022
|
+
});
|
|
742
1023
|
});
|
|
743
1024
|
}
|
|
744
1025
|
catch (err) {
|
|
745
|
-
console.error('[
|
|
746
|
-
|
|
1026
|
+
console.error('[IframeStyleReplacer] Critical error:', err);
|
|
1027
|
+
return {
|
|
1028
|
+
height: this.doc.body.scrollHeight || 1000,
|
|
1029
|
+
width: this.doc.body.scrollWidth || 1000,
|
|
1030
|
+
};
|
|
747
1031
|
}
|
|
748
1032
|
}
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
1033
|
+
updateConfig(config) {
|
|
1034
|
+
this.config = { ...this.config, ...config };
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
class IframeHelperFixer {
|
|
1039
|
+
iframe;
|
|
1040
|
+
config;
|
|
1041
|
+
replacer = null;
|
|
1042
|
+
navigationBlocker = null;
|
|
1043
|
+
constructor(config) {
|
|
1044
|
+
this.config = config;
|
|
1045
|
+
this.iframe = config.iframe;
|
|
1046
|
+
this.init();
|
|
1047
|
+
}
|
|
1048
|
+
async init() {
|
|
1049
|
+
if (!this.iframe) {
|
|
1050
|
+
console.error('[IframeHelper] iframe not found');
|
|
1051
|
+
this.config.onError?.(new Error('iframe not found'));
|
|
1052
|
+
return;
|
|
1053
|
+
}
|
|
1054
|
+
// Wait for iframe to load completely
|
|
1055
|
+
if (this.iframe.contentDocument?.readyState === 'complete') {
|
|
1056
|
+
await this.process();
|
|
752
1057
|
}
|
|
753
1058
|
else {
|
|
754
|
-
this.
|
|
1059
|
+
this.iframe.addEventListener('load', () => this.process());
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
async process() {
|
|
1063
|
+
if (!this.iframe.contentDocument || !this.iframe.contentWindow) {
|
|
1064
|
+
console.error('[IframeHelper] Cannot access iframe document');
|
|
1065
|
+
this.config.onError?.(new Error('Cannot access iframe document'));
|
|
1066
|
+
return;
|
|
1067
|
+
}
|
|
1068
|
+
try {
|
|
1069
|
+
console.log('[IframeHelper] Processing viewport units...');
|
|
1070
|
+
// Create replacer instance
|
|
1071
|
+
this.replacer = new IframeStyleReplacer(this.iframe, this.config);
|
|
1072
|
+
// Create navigation blocker
|
|
1073
|
+
this.navigationBlocker = new IframeNavigationBlockerV2(this.iframe);
|
|
1074
|
+
// Run replacement
|
|
1075
|
+
const result = await this.replacer.run();
|
|
1076
|
+
console.log('[IframeHelper] Process completed:', result);
|
|
1077
|
+
// Trigger success callback
|
|
1078
|
+
this.config.onSuccess?.(result);
|
|
1079
|
+
// Dispatch custom event
|
|
1080
|
+
window.dispatchEvent(new CustomEvent('iframe-dimensions-applied', {
|
|
1081
|
+
detail: result,
|
|
1082
|
+
}));
|
|
1083
|
+
}
|
|
1084
|
+
catch (error) {
|
|
1085
|
+
console.error('[IframeHelper] Failed to process:', error);
|
|
1086
|
+
this.config.onError?.(error);
|
|
755
1087
|
}
|
|
756
1088
|
}
|
|
1089
|
+
async recalculate() {
|
|
1090
|
+
console.log('[IframeHelper] Recalculating...');
|
|
1091
|
+
await this.process();
|
|
1092
|
+
}
|
|
1093
|
+
updateConfig(config) {
|
|
1094
|
+
this.config = { ...this.config, ...config };
|
|
1095
|
+
if (this.replacer) {
|
|
1096
|
+
this.replacer.updateConfig(config);
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
enableNavigationBlocking() {
|
|
1100
|
+
this.navigationBlocker?.enable();
|
|
1101
|
+
}
|
|
1102
|
+
enableNavigationBlockingMessage() {
|
|
1103
|
+
this.navigationBlocker?.enableMessage();
|
|
1104
|
+
}
|
|
1105
|
+
disableNavigationBlocking() {
|
|
1106
|
+
this.navigationBlocker?.disable();
|
|
1107
|
+
}
|
|
1108
|
+
disableNavigationBlockingMessage() {
|
|
1109
|
+
this.navigationBlocker?.disableMessage();
|
|
1110
|
+
}
|
|
1111
|
+
destroy() {
|
|
1112
|
+
this.replacer = null;
|
|
1113
|
+
this.navigationBlocker?.destroy();
|
|
1114
|
+
this.navigationBlocker = null;
|
|
1115
|
+
console.log('[IframeHelper] Destroyed');
|
|
1116
|
+
}
|
|
757
1117
|
}
|
|
758
1118
|
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
1119
|
+
function initIframeHelperFixer(config) {
|
|
1120
|
+
const fixer = new IframeHelperFixer(config);
|
|
1121
|
+
window.addEventListener('iframe-dimensions-applied', ((e) => {
|
|
1122
|
+
const ev = e;
|
|
1123
|
+
console.log('[IframeHelper] Iframe dimensions finalized:', ev.detail);
|
|
1124
|
+
}));
|
|
1125
|
+
window.addEventListener('iframe-navigation-blocked', ((e) => {
|
|
1126
|
+
const ev = e;
|
|
1127
|
+
console.warn('[IframeHelper] Iframe tried to navigate to:', ev.detail.url);
|
|
1128
|
+
}));
|
|
1129
|
+
window.addEventListener('iframe-form-submit', ((e) => {
|
|
1130
|
+
const ev = e;
|
|
1131
|
+
console.log('[IframeHelper] Iframe form submitted:', ev.detail.data);
|
|
1132
|
+
}));
|
|
1133
|
+
return fixer;
|
|
1134
|
+
}
|
|
763
1135
|
|
|
764
1136
|
const scrollToElementIfNeeded = (visualRef, rect, scale) => {
|
|
765
1137
|
if (!visualRef.current)
|
|
@@ -873,7 +1245,7 @@ const useHeatmapEffects = ({ isVisible, isElementSidebarOpen, setShouldShowCallo
|
|
|
873
1245
|
|
|
874
1246
|
const useHeatmapElementPosition = ({ iframeRef, wrapperRef, visualizer }) => {
|
|
875
1247
|
const widthScale = useHeatmapVizStore((state) => state.scale);
|
|
876
|
-
const iframeHeight =
|
|
1248
|
+
const iframeHeight = useHeatmapSingleStore((state) => state.iframeHeight);
|
|
877
1249
|
const heatmapWidth = useHeatmapConfigStore((state) => state.width);
|
|
878
1250
|
return useCallback((element) => {
|
|
879
1251
|
const hash = element?.hash;
|
|
@@ -921,6 +1293,109 @@ const debounce = (fn, delay) => {
|
|
|
921
1293
|
};
|
|
922
1294
|
};
|
|
923
1295
|
|
|
1296
|
+
// ===================== UTILITY FUNCTIONS =====================
|
|
1297
|
+
/**
|
|
1298
|
+
* Lấy bounding box tuyệt đối của element (relative to document)
|
|
1299
|
+
*/
|
|
1300
|
+
function getBoundingBox(element) {
|
|
1301
|
+
if (typeof element.getBoundingClientRect !== 'function') {
|
|
1302
|
+
return null;
|
|
1303
|
+
}
|
|
1304
|
+
const rect = element.getBoundingClientRect();
|
|
1305
|
+
// Lấy scroll offset (hỗ trợ cả cách cũ và mới)
|
|
1306
|
+
const scrollLeft = 'pageXOffset' in window ? window.pageXOffset : document.documentElement.scrollLeft;
|
|
1307
|
+
const scrollTop = 'pageYOffset' in window ? window.pageYOffset : document.documentElement.scrollTop;
|
|
1308
|
+
// Kiểm tra element có kích thước hợp lệ
|
|
1309
|
+
if (!rect || (rect.height === 0 && rect.width === 0)) {
|
|
1310
|
+
return null;
|
|
1311
|
+
}
|
|
1312
|
+
// Trả về vị trí tuyệt đối
|
|
1313
|
+
return {
|
|
1314
|
+
left: Math.floor(rect.left + scrollLeft),
|
|
1315
|
+
top: Math.floor(rect.top + scrollTop),
|
|
1316
|
+
width: Math.floor(rect.width),
|
|
1317
|
+
height: Math.floor(rect.height),
|
|
1318
|
+
};
|
|
1319
|
+
}
|
|
1320
|
+
/**
|
|
1321
|
+
* Lấy tất cả elements tại tọa độ (x, y), hỗ trợ Shadow DOM
|
|
1322
|
+
*/
|
|
1323
|
+
function getElementsAtPoint(documentOrShadowRoot, x, y, filterFunction, visitedShadowRoots = new Set()) {
|
|
1324
|
+
// Lấy tất cả elements tại vị trí
|
|
1325
|
+
const elementsAtPoint = documentOrShadowRoot.elementsFromPoint(x, y);
|
|
1326
|
+
if (!filterFunction) {
|
|
1327
|
+
return elementsAtPoint;
|
|
1328
|
+
}
|
|
1329
|
+
// Tìm element đầu tiên match với filter
|
|
1330
|
+
const matchedElement = elementsAtPoint.find(filterFunction);
|
|
1331
|
+
// Nếu element có Shadow DOM và chưa visit -> đệ quy vào
|
|
1332
|
+
if (matchedElement?.shadowRoot && !visitedShadowRoots.has(matchedElement.shadowRoot)) {
|
|
1333
|
+
visitedShadowRoots.add(matchedElement.shadowRoot);
|
|
1334
|
+
return getElementsAtPoint(matchedElement.shadowRoot, x, y, filterFunction, visitedShadowRoots);
|
|
1335
|
+
}
|
|
1336
|
+
return elementsAtPoint;
|
|
1337
|
+
}
|
|
1338
|
+
// ===================== EXAMPLE USAGE =====================
|
|
1339
|
+
/*
|
|
1340
|
+
import { useRef, useState } from 'react';
|
|
1341
|
+
|
|
1342
|
+
function HeatmapComponent() {
|
|
1343
|
+
const heatmapWrapperRef = useRef<HTMLDivElement>(null);
|
|
1344
|
+
const iframeRef = useRef<HTMLIFrameElement>(null);
|
|
1345
|
+
const parentRef = useRef<HTMLDivElement>(null);
|
|
1346
|
+
|
|
1347
|
+
const [hoveredElement, setHoveredElement] = useState<HoveredElementInfo | null>(null);
|
|
1348
|
+
|
|
1349
|
+
const heatmapInfo = {
|
|
1350
|
+
width: 1920,
|
|
1351
|
+
elementMapInfo: {
|
|
1352
|
+
'hash123': {
|
|
1353
|
+
totalclicks: 45,
|
|
1354
|
+
selector: 'button.submit'
|
|
1355
|
+
}
|
|
1356
|
+
},
|
|
1357
|
+
sortedElements: [...]
|
|
1358
|
+
};
|
|
1359
|
+
|
|
1360
|
+
const { handleMouseMove } = useHeatmapMouseHandler({
|
|
1361
|
+
heatmapWrapperRef,
|
|
1362
|
+
iframeRef,
|
|
1363
|
+
parentRef,
|
|
1364
|
+
heatmapInfo,
|
|
1365
|
+
scaleRatio: 0.8, // 80% zoom
|
|
1366
|
+
onElementHover: (info) => {
|
|
1367
|
+
setHoveredElement(info);
|
|
1368
|
+
console.log('Hovered element:', info);
|
|
1369
|
+
}
|
|
1370
|
+
});
|
|
1371
|
+
|
|
1372
|
+
return (
|
|
1373
|
+
<div ref={parentRef}>
|
|
1374
|
+
<div
|
|
1375
|
+
ref={heatmapWrapperRef}
|
|
1376
|
+
onMouseMove={handleMouseMove}
|
|
1377
|
+
>
|
|
1378
|
+
<iframe ref={iframeRef} />
|
|
1379
|
+
|
|
1380
|
+
{hoveredElement && (
|
|
1381
|
+
<div className="tooltip" style={{
|
|
1382
|
+
position: 'absolute',
|
|
1383
|
+
left: hoveredElement.left,
|
|
1384
|
+
top: hoveredElement.top
|
|
1385
|
+
}}>
|
|
1386
|
+
Clicks: {hoveredElement.clicks}
|
|
1387
|
+
<br />
|
|
1388
|
+
Rank: #{hoveredElement.rank}
|
|
1389
|
+
<br />
|
|
1390
|
+
Selector: {hoveredElement.selector}
|
|
1391
|
+
</div>
|
|
1392
|
+
)}
|
|
1393
|
+
</div>
|
|
1394
|
+
</div>
|
|
1395
|
+
);
|
|
1396
|
+
}
|
|
1397
|
+
*/
|
|
1398
|
+
|
|
924
1399
|
const useHoveredElement = ({ iframeRef, getRect }) => {
|
|
925
1400
|
const hoveredElement = useHeatmapInteractionStore((state) => state.hoveredElement);
|
|
926
1401
|
const setHoveredElement = useHeatmapInteractionStore((state) => state.setHoveredElement);
|
|
@@ -942,7 +1417,7 @@ const useHoveredElement = ({ iframeRef, getRect }) => {
|
|
|
942
1417
|
const doc = iframe.contentDocument;
|
|
943
1418
|
const iframeRect = iframe.getBoundingClientRect();
|
|
944
1419
|
const { x, y } = convertViewportToIframeCoords(event.clientX, event.clientY, iframeRect, widthScale);
|
|
945
|
-
const targetElement = findTargetElement(doc, x, y);
|
|
1420
|
+
const targetElement = findTargetElement(doc, x, y, heatmapInfo);
|
|
946
1421
|
if (!targetElement || !isValidElement(targetElement, heatmapInfo)) {
|
|
947
1422
|
reset();
|
|
948
1423
|
return;
|
|
@@ -993,7 +1468,25 @@ const convertViewportToIframeCoords = (clientX, clientY, iframeRect, scale) => {
|
|
|
993
1468
|
}
|
|
994
1469
|
return { x, y };
|
|
995
1470
|
};
|
|
996
|
-
const findTargetElement = (doc, x, y) => {
|
|
1471
|
+
const findTargetElement = (doc, x, y, heatmapInfo) => {
|
|
1472
|
+
const HEATMAP_ELEMENT_ATTRIBUTE = 'data-clarity-hashalpha';
|
|
1473
|
+
const elementsAtPoint = getElementsAtPoint(doc, Math.round(x), Math.round(y), (element) => element.hasAttribute(HEATMAP_ELEMENT_ATTRIBUTE));
|
|
1474
|
+
let dataElement = null;
|
|
1475
|
+
for (let i = 0; i < elementsAtPoint.length; i++) {
|
|
1476
|
+
const element = elementsAtPoint[i];
|
|
1477
|
+
const elementHash = element.getAttribute(HEATMAP_ELEMENT_ATTRIBUTE);
|
|
1478
|
+
if (elementHash && heatmapInfo.elementMapInfo?.[elementHash]) {
|
|
1479
|
+
heatmapInfo.elementMapInfo[elementHash];
|
|
1480
|
+
const boundingBox = getBoundingBox(element);
|
|
1481
|
+
if (boundingBox) {
|
|
1482
|
+
dataElement = element;
|
|
1483
|
+
break;
|
|
1484
|
+
}
|
|
1485
|
+
}
|
|
1486
|
+
}
|
|
1487
|
+
if (!!dataElement) {
|
|
1488
|
+
return dataElement;
|
|
1489
|
+
}
|
|
997
1490
|
let targetElement = getElementAtPoint(doc, x, y);
|
|
998
1491
|
if (!targetElement) {
|
|
999
1492
|
targetElement = doc.elementFromPoint(x, y);
|
|
@@ -1017,9 +1510,9 @@ var MessageType;
|
|
|
1017
1510
|
MessageType["GX_DOM_TRACKING_PAYLOAD"] = "GX_DOM_TRACKING_PAYLOAD";
|
|
1018
1511
|
MessageType["CLARITY_READY"] = "CLARITY_READY";
|
|
1019
1512
|
})(MessageType || (MessageType = {}));
|
|
1020
|
-
function
|
|
1513
|
+
function useVizLiveIframeMsg(options = {}) {
|
|
1021
1514
|
const { trustedOrigins = [], onMessage } = options;
|
|
1022
|
-
const
|
|
1515
|
+
const addPayload = useHeatmapLiveStore((state) => state.addPayload);
|
|
1023
1516
|
const [isReady, setIsReady] = useState(false);
|
|
1024
1517
|
const iframeRef = useRef(null);
|
|
1025
1518
|
const isValidOrigin = useCallback((origin) => {
|
|
@@ -1045,9 +1538,9 @@ function useIframeMessage(options = {}) {
|
|
|
1045
1538
|
switch (message.type) {
|
|
1046
1539
|
case MessageType.GX_DOM_TRACKING_PAYLOAD:
|
|
1047
1540
|
if (message.payload) {
|
|
1048
|
-
const
|
|
1049
|
-
if (
|
|
1050
|
-
|
|
1541
|
+
const data = decodePayloads(message.payload);
|
|
1542
|
+
if (data) {
|
|
1543
|
+
addPayload(data);
|
|
1051
1544
|
}
|
|
1052
1545
|
}
|
|
1053
1546
|
break;
|
|
@@ -1062,27 +1555,19 @@ function useIframeMessage(options = {}) {
|
|
|
1062
1555
|
window.removeEventListener('message', handleMessage);
|
|
1063
1556
|
};
|
|
1064
1557
|
}, [handleMessage]);
|
|
1065
|
-
const clearPayloads = useCallback(() => {
|
|
1066
|
-
setPayloads([]);
|
|
1067
|
-
}, []);
|
|
1068
|
-
const reset = useCallback(() => {
|
|
1069
|
-
setPayloads([]);
|
|
1070
|
-
setIsReady(false);
|
|
1071
|
-
}, []);
|
|
1072
1558
|
return {
|
|
1073
1559
|
iframeRef,
|
|
1074
|
-
payloads,
|
|
1075
1560
|
isReady,
|
|
1076
|
-
clearPayloads,
|
|
1077
|
-
reset,
|
|
1078
1561
|
};
|
|
1079
1562
|
}
|
|
1080
|
-
|
|
1563
|
+
|
|
1564
|
+
function useVizLiveRender() {
|
|
1081
1565
|
const wrapperHeight = useHeatmapLiveStore((state) => state.wrapperHeight);
|
|
1566
|
+
const setIframeHeight = useHeatmapLiveStore((state) => state.setIframeHeight);
|
|
1082
1567
|
const contentWidth = useHeatmapConfigStore((state) => state.width);
|
|
1083
|
-
const setIframeHeight = useHeatmapVizStore((state) => state.setIframeHeight);
|
|
1084
1568
|
const htmlContent = useHeatmapLiveStore((state) => state.htmlContent);
|
|
1085
|
-
const
|
|
1569
|
+
const setIsRenderViz = useHeatmapVizStore((state) => state.setIsRenderViz);
|
|
1570
|
+
const { iframeRef, isReady } = useVizLiveIframeMsg();
|
|
1086
1571
|
useEffect(() => {
|
|
1087
1572
|
if (!htmlContent || !iframeRef.current)
|
|
1088
1573
|
return;
|
|
@@ -1102,50 +1587,50 @@ function useIframeRender() {
|
|
|
1102
1587
|
const iframe = iframeRef.current;
|
|
1103
1588
|
if (!iframe || !htmlContent)
|
|
1104
1589
|
return;
|
|
1105
|
-
|
|
1106
|
-
|
|
1590
|
+
setIsRenderViz(false);
|
|
1591
|
+
reset(iframe, { width: contentWidth, height: wrapperHeight }, (height) => {
|
|
1592
|
+
height && setIframeHeight(height);
|
|
1593
|
+
setIsRenderViz(true);
|
|
1107
1594
|
});
|
|
1108
1595
|
}, [isReady, contentWidth, wrapperHeight]);
|
|
1109
1596
|
return {
|
|
1110
1597
|
iframeRef,
|
|
1111
|
-
payloads,
|
|
1112
|
-
isReady,
|
|
1113
1598
|
};
|
|
1114
1599
|
}
|
|
1115
|
-
function reset
|
|
1116
|
-
const
|
|
1117
|
-
targetWidth:
|
|
1118
|
-
targetHeight:
|
|
1600
|
+
function reset(iframe, rect, onSuccess) {
|
|
1601
|
+
const fixer = initIframeHelperFixer({
|
|
1602
|
+
targetWidth: rect.width,
|
|
1603
|
+
targetHeight: rect.height,
|
|
1119
1604
|
iframe: iframe,
|
|
1120
1605
|
onSuccess: (data) => {
|
|
1121
|
-
onSuccess(data.height);
|
|
1122
1606
|
iframe.height = `${data.height}px`;
|
|
1607
|
+
onSuccess(data.height);
|
|
1123
1608
|
},
|
|
1124
1609
|
});
|
|
1125
|
-
|
|
1126
|
-
|
|
1610
|
+
// fixer.recalculate();
|
|
1611
|
+
fixer.enableNavigationBlocking();
|
|
1127
1612
|
}
|
|
1128
1613
|
|
|
1614
|
+
let visualizer = new Visualizer();
|
|
1129
1615
|
const useHeatmapRender = () => {
|
|
1130
1616
|
const data = useHeatmapDataStore((state) => state.data);
|
|
1131
|
-
const setVizRef =
|
|
1617
|
+
const setVizRef = useHeatmapSingleStore((state) => state.setVizRef);
|
|
1132
1618
|
const setIsRenderViz = useHeatmapVizStore((state) => state.setIsRenderViz);
|
|
1133
|
-
const setIframeHeight =
|
|
1619
|
+
const setIframeHeight = useHeatmapSingleStore((state) => state.setIframeHeight);
|
|
1134
1620
|
const iframeRef = useRef(null);
|
|
1135
1621
|
const renderHeatmap = useCallback(async (payloads) => {
|
|
1136
1622
|
if (!payloads || payloads.length === 0)
|
|
1137
1623
|
return;
|
|
1138
1624
|
setIsRenderViz(false);
|
|
1139
|
-
const visualizer = new Visualizer();
|
|
1140
1625
|
const iframe = iframeRef.current;
|
|
1141
1626
|
if (!iframe?.contentWindow)
|
|
1142
1627
|
return;
|
|
1143
1628
|
await visualizer.html(payloads, iframe.contentWindow);
|
|
1144
|
-
|
|
1629
|
+
initIframe(iframe, payloads, (height) => {
|
|
1145
1630
|
height && setIframeHeight(height);
|
|
1146
1631
|
setIsRenderViz(true);
|
|
1632
|
+
setVizRef(visualizer);
|
|
1147
1633
|
});
|
|
1148
|
-
setVizRef(visualizer);
|
|
1149
1634
|
}, []);
|
|
1150
1635
|
useEffect(() => {
|
|
1151
1636
|
if (!data || data.length === 0)
|
|
@@ -1159,21 +1644,20 @@ const useHeatmapRender = () => {
|
|
|
1159
1644
|
iframeRef,
|
|
1160
1645
|
};
|
|
1161
1646
|
};
|
|
1162
|
-
function
|
|
1647
|
+
function initIframe(iframe, payloads, onSuccess) {
|
|
1163
1648
|
const { size } = findLastSizeOfDom(payloads);
|
|
1164
1649
|
const docWidth = size.width ?? 0;
|
|
1165
1650
|
const docHeight = size.height ?? 0;
|
|
1166
|
-
|
|
1651
|
+
initIframeHelperFixer({
|
|
1167
1652
|
targetWidth: docWidth,
|
|
1168
1653
|
targetHeight: docHeight,
|
|
1169
1654
|
iframe: iframe,
|
|
1170
1655
|
onSuccess: (data) => {
|
|
1171
|
-
onSuccess(data.height);
|
|
1172
1656
|
iframe.height = `${data.height}px`;
|
|
1657
|
+
onSuccess(data.height);
|
|
1173
1658
|
},
|
|
1174
1659
|
});
|
|
1175
|
-
|
|
1176
|
-
return iframe;
|
|
1660
|
+
// fixer.recalculate();
|
|
1177
1661
|
}
|
|
1178
1662
|
|
|
1179
1663
|
function isMobileDevice(userAgent) {
|
|
@@ -1358,30 +1842,64 @@ const useContentDimensions = ({ iframeRef, }) => {
|
|
|
1358
1842
|
return { contentWidth };
|
|
1359
1843
|
};
|
|
1360
1844
|
|
|
1361
|
-
const
|
|
1845
|
+
const useObserveIframeHeight = (props) => {
|
|
1362
1846
|
const { iframeRef, setIframeHeight } = props;
|
|
1363
1847
|
const isRenderViz = useHeatmapVizStore((state) => state.isRenderViz);
|
|
1364
1848
|
const resizeObserverRef = useRef(null);
|
|
1365
1849
|
const mutationObserverRef = useRef(null);
|
|
1850
|
+
const debounceTimerRef = useRef(null);
|
|
1851
|
+
const lastHeightRef = useRef(0);
|
|
1852
|
+
const animationFrameRef = useRef(null);
|
|
1366
1853
|
const updateIframeHeight = useCallback(() => {
|
|
1367
1854
|
const iframe = iframeRef.current;
|
|
1368
|
-
if (!iframe)
|
|
1855
|
+
if (!iframe || !setIframeHeight)
|
|
1369
1856
|
return;
|
|
1370
1857
|
try {
|
|
1371
1858
|
const iframeDocument = iframe.contentDocument;
|
|
1372
1859
|
const iframeBody = iframeDocument?.body;
|
|
1373
|
-
|
|
1860
|
+
const iframeDocumentElement = iframeDocument?.documentElement;
|
|
1861
|
+
if (!iframeBody || !iframeDocumentElement)
|
|
1374
1862
|
return;
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1863
|
+
iframe.style.height = 'auto';
|
|
1864
|
+
requestAnimationFrame(() => {
|
|
1865
|
+
const bodyHeight = Math.max(iframeBody.scrollHeight, iframeBody.offsetHeight, iframeBody.clientHeight);
|
|
1866
|
+
const documentHeight = Math.max(iframeDocumentElement.scrollHeight, iframeDocumentElement.offsetHeight, iframeDocumentElement.clientHeight);
|
|
1867
|
+
const actualHeight = Math.max(bodyHeight, documentHeight);
|
|
1868
|
+
if (actualHeight > 0) {
|
|
1869
|
+
lastHeightRef.current = actualHeight;
|
|
1870
|
+
iframe.height = `${actualHeight}px`;
|
|
1871
|
+
iframe.style.height = `${actualHeight}px`;
|
|
1872
|
+
setIframeHeight(actualHeight);
|
|
1873
|
+
}
|
|
1874
|
+
});
|
|
1380
1875
|
}
|
|
1381
1876
|
catch (error) {
|
|
1382
1877
|
console.warn('Cannot measure iframe content:', error);
|
|
1383
1878
|
}
|
|
1384
1879
|
}, [iframeRef, setIframeHeight]);
|
|
1880
|
+
const debouncedUpdate = useCallback(() => {
|
|
1881
|
+
// Cancel pending updates
|
|
1882
|
+
if (debounceTimerRef.current) {
|
|
1883
|
+
clearTimeout(debounceTimerRef.current);
|
|
1884
|
+
}
|
|
1885
|
+
if (animationFrameRef.current) {
|
|
1886
|
+
cancelAnimationFrame(animationFrameRef.current);
|
|
1887
|
+
}
|
|
1888
|
+
debounceTimerRef.current = setTimeout(() => {
|
|
1889
|
+
animationFrameRef.current = requestAnimationFrame(() => {
|
|
1890
|
+
updateIframeHeight();
|
|
1891
|
+
});
|
|
1892
|
+
}, 50);
|
|
1893
|
+
}, [updateIframeHeight]);
|
|
1894
|
+
// Immediate update không debounce (cho ResizeObserver)
|
|
1895
|
+
const immediateUpdate = useCallback(() => {
|
|
1896
|
+
if (animationFrameRef.current) {
|
|
1897
|
+
cancelAnimationFrame(animationFrameRef.current);
|
|
1898
|
+
}
|
|
1899
|
+
animationFrameRef.current = requestAnimationFrame(() => {
|
|
1900
|
+
updateIframeHeight();
|
|
1901
|
+
});
|
|
1902
|
+
}, [updateIframeHeight]);
|
|
1385
1903
|
useEffect(() => {
|
|
1386
1904
|
const iframe = iframeRef.current;
|
|
1387
1905
|
if (!iframe || !isRenderViz)
|
|
@@ -1399,22 +1917,24 @@ const useIframeHeight = (props) => {
|
|
|
1399
1917
|
if (mutationObserverRef.current) {
|
|
1400
1918
|
mutationObserverRef.current.disconnect();
|
|
1401
1919
|
}
|
|
1402
|
-
// ResizeObserver for size changes
|
|
1403
1920
|
if (typeof window.ResizeObserver !== 'undefined') {
|
|
1404
|
-
resizeObserverRef.current = new ResizeObserver(
|
|
1921
|
+
resizeObserverRef.current = new ResizeObserver(immediateUpdate);
|
|
1405
1922
|
resizeObserverRef.current.observe(iframeBody);
|
|
1923
|
+
const iframeDocumentElement = iframeDocument?.documentElement;
|
|
1924
|
+
if (iframeDocumentElement) {
|
|
1925
|
+
resizeObserverRef.current.observe(iframeDocumentElement);
|
|
1926
|
+
}
|
|
1406
1927
|
}
|
|
1407
|
-
// MutationObserver for DOM changes
|
|
1408
1928
|
if (typeof window.MutationObserver !== 'undefined') {
|
|
1409
|
-
mutationObserverRef.current = new MutationObserver(
|
|
1929
|
+
mutationObserverRef.current = new MutationObserver(immediateUpdate);
|
|
1410
1930
|
mutationObserverRef.current.observe(iframeBody, {
|
|
1411
1931
|
childList: true,
|
|
1412
1932
|
subtree: true,
|
|
1413
1933
|
attributes: true,
|
|
1414
|
-
|
|
1934
|
+
attributeFilter: ['style', 'class'],
|
|
1935
|
+
characterData: false,
|
|
1415
1936
|
});
|
|
1416
1937
|
}
|
|
1417
|
-
// Initial measurement
|
|
1418
1938
|
updateIframeHeight();
|
|
1419
1939
|
}
|
|
1420
1940
|
catch (error) {
|
|
@@ -1428,30 +1948,74 @@ const useIframeHeight = (props) => {
|
|
|
1428
1948
|
iframe.addEventListener('load', setupObservers, { once: true });
|
|
1429
1949
|
}
|
|
1430
1950
|
return () => {
|
|
1951
|
+
// Cleanup observers
|
|
1431
1952
|
if (resizeObserverRef.current) {
|
|
1432
1953
|
resizeObserverRef.current.disconnect();
|
|
1433
1954
|
}
|
|
1434
1955
|
if (mutationObserverRef.current) {
|
|
1435
1956
|
mutationObserverRef.current.disconnect();
|
|
1436
1957
|
}
|
|
1958
|
+
// Cleanup timers
|
|
1959
|
+
if (debounceTimerRef.current) {
|
|
1960
|
+
clearTimeout(debounceTimerRef.current);
|
|
1961
|
+
}
|
|
1962
|
+
if (animationFrameRef.current) {
|
|
1963
|
+
cancelAnimationFrame(animationFrameRef.current);
|
|
1964
|
+
}
|
|
1437
1965
|
iframe.removeEventListener('load', setupObservers);
|
|
1438
1966
|
};
|
|
1439
|
-
}, [iframeRef, isRenderViz, updateIframeHeight]);
|
|
1967
|
+
}, [iframeRef, isRenderViz, updateIframeHeight, debouncedUpdate, immediateUpdate]);
|
|
1440
1968
|
return {};
|
|
1441
1969
|
};
|
|
1442
1970
|
|
|
1443
1971
|
const useScaleCalculation = (props) => {
|
|
1444
1972
|
const scale = useHeatmapVizStore((state) => state.scale);
|
|
1973
|
+
const zoomRatio = useHeatmapVizStore((state) => state.zoomRatio);
|
|
1445
1974
|
const setScale = useHeatmapVizStore((state) => state.setScale);
|
|
1446
|
-
const
|
|
1447
|
-
|
|
1448
|
-
|
|
1975
|
+
const isScaledToFit = useHeatmapVizStore((state) => state.isScaledToFit);
|
|
1976
|
+
const setIsScaledToFit = useHeatmapVizStore((state) => state.setIsScaledToFit);
|
|
1977
|
+
const minZoomRatio = useHeatmapVizStore((state) => state.minZoomRatio);
|
|
1978
|
+
const setMinZoomRatio = useHeatmapVizStore((state) => state.setMinZoomRatio);
|
|
1979
|
+
const { containerWidth, containerHeight, contentWidth, contentHeight } = props;
|
|
1980
|
+
const calculateScaleResult = useCallback(() => {
|
|
1981
|
+
if (containerWidth > 0 && contentWidth > 0 && containerHeight > 0 && contentHeight > 0) {
|
|
1982
|
+
// 1. Calculate widthScale (base scale from width)
|
|
1449
1983
|
const availableWidth = containerWidth - HEATMAP_CONFIG['padding'] * 2;
|
|
1450
|
-
const
|
|
1451
|
-
|
|
1984
|
+
const widthScale = Math.min(availableWidth / contentWidth, 1);
|
|
1985
|
+
// 2. Calculate available height
|
|
1986
|
+
const toolbarHeight = HEATMAP_CONFIG['heightToolbar'] ;
|
|
1987
|
+
const paddingTotal = HEATMAP_CONFIG['padding'] * 2;
|
|
1988
|
+
const availableHeight = containerHeight - toolbarHeight - paddingTotal; // 10px buffer to avoid scroll bar
|
|
1989
|
+
// 3. Calculate minZoomRatio (zoom ratio minimum to fit iframe in container)
|
|
1990
|
+
const roundedMinZoomRatio = (availableHeight / (contentHeight * widthScale)) * 100;
|
|
1991
|
+
// Limit minZoomRatio to a reasonable range (10-100)
|
|
1992
|
+
const finalMinZoomRatio = Math.max(10, Math.min(roundedMinZoomRatio, 100));
|
|
1993
|
+
// 4. Apply zoom ratio (cannot be less than minZoomRatio)
|
|
1994
|
+
const clampedZoomRatio = Math.max(zoomRatio, finalMinZoomRatio);
|
|
1995
|
+
const zoomMultiplier = clampedZoomRatio / 100;
|
|
1996
|
+
// 5. Calculate finalScale
|
|
1997
|
+
const finalScale = widthScale * zoomMultiplier;
|
|
1998
|
+
// 6. Check if it is currently fitted
|
|
1999
|
+
const isCurrentlyFitted = zoomRatio <= finalMinZoomRatio;
|
|
2000
|
+
// 7. Update store
|
|
2001
|
+
setScale(finalScale);
|
|
2002
|
+
setIsScaledToFit(isCurrentlyFitted);
|
|
2003
|
+
setMinZoomRatio(finalMinZoomRatio);
|
|
1452
2004
|
}
|
|
1453
|
-
}, [
|
|
1454
|
-
|
|
2005
|
+
}, [
|
|
2006
|
+
containerWidth,
|
|
2007
|
+
containerHeight,
|
|
2008
|
+
contentWidth,
|
|
2009
|
+
contentHeight,
|
|
2010
|
+
zoomRatio,
|
|
2011
|
+
setScale,
|
|
2012
|
+
setIsScaledToFit,
|
|
2013
|
+
setMinZoomRatio,
|
|
2014
|
+
]);
|
|
2015
|
+
useEffect(() => {
|
|
2016
|
+
calculateScaleResult();
|
|
2017
|
+
}, [calculateScaleResult]);
|
|
2018
|
+
return { scale, isScaledToFit, minZoomRatio };
|
|
1455
2019
|
};
|
|
1456
2020
|
|
|
1457
2021
|
const useScrollSync = ({ iframeRef }) => {
|
|
@@ -1482,16 +2046,23 @@ const useHeatmapScale = (props) => {
|
|
|
1482
2046
|
// 2. Get content dimensions from config
|
|
1483
2047
|
const { contentWidth } = useContentDimensions({ iframeRef });
|
|
1484
2048
|
// 3. Observe iframe height (now reacts to width changes)
|
|
1485
|
-
|
|
2049
|
+
useObserveIframeHeight({ iframeRef, setIframeHeight });
|
|
1486
2050
|
// 4. Calculate scale
|
|
1487
|
-
const { scale } = useScaleCalculation({
|
|
2051
|
+
const { scale } = useScaleCalculation({
|
|
2052
|
+
containerWidth,
|
|
2053
|
+
containerHeight,
|
|
2054
|
+
contentWidth,
|
|
2055
|
+
contentHeight: iframeHeight,
|
|
2056
|
+
});
|
|
1488
2057
|
// 5. Setup scroll sync
|
|
1489
2058
|
const { handleScroll } = useScrollSync({ iframeRef });
|
|
2059
|
+
const scaledHeight = iframeHeight * scale;
|
|
2060
|
+
const scaledWidth = contentWidth * scale;
|
|
1490
2061
|
return {
|
|
1491
2062
|
containerWidth,
|
|
1492
2063
|
containerHeight,
|
|
1493
|
-
scaledWidth
|
|
1494
|
-
scaledHeight
|
|
2064
|
+
scaledWidth,
|
|
2065
|
+
scaledHeight,
|
|
1495
2066
|
handleScroll,
|
|
1496
2067
|
};
|
|
1497
2068
|
};
|
|
@@ -1565,6 +2136,135 @@ const useWrapperRefHeight = (props) => {
|
|
|
1565
2136
|
return {};
|
|
1566
2137
|
};
|
|
1567
2138
|
|
|
2139
|
+
const useZonePositions = (options) => {
|
|
2140
|
+
const iframeHeight = useHeatmapSingleStore((state) => state.iframeHeight);
|
|
2141
|
+
const getZonePosition = useCallback((zone) => {
|
|
2142
|
+
if (!iframeHeight) {
|
|
2143
|
+
return null;
|
|
2144
|
+
}
|
|
2145
|
+
const startYPx = (zone.startY / 100) * iframeHeight;
|
|
2146
|
+
const heightPx = ((zone.endY - zone.startY) / 100) * iframeHeight;
|
|
2147
|
+
return {
|
|
2148
|
+
top: startYPx,
|
|
2149
|
+
height: heightPx,
|
|
2150
|
+
};
|
|
2151
|
+
}, [iframeHeight]);
|
|
2152
|
+
return {
|
|
2153
|
+
getZonePosition,
|
|
2154
|
+
};
|
|
2155
|
+
};
|
|
2156
|
+
|
|
2157
|
+
const SCROLL_GRADIENT_COLORS = [
|
|
2158
|
+
[255, 0, 0], // Red
|
|
2159
|
+
[255, 255, 0], // Yellow
|
|
2160
|
+
[0, 255, 0], // Green
|
|
2161
|
+
];
|
|
2162
|
+
const useScrollmapZones = (options) => {
|
|
2163
|
+
const { mode = 'basic', enabled = true, iframeRef, wrapperRef } = options;
|
|
2164
|
+
const [isReady, setIsReady] = useState(false);
|
|
2165
|
+
const [zones, setZones] = useState([]);
|
|
2166
|
+
const scrollmap = useHeatmapDataStore((state) => state.scrollmap);
|
|
2167
|
+
const scrollMapInfo = useHeatmapDataStore((state) => state.dataInfo?.scrollMapInfo);
|
|
2168
|
+
const { getZonePosition } = useZonePositions();
|
|
2169
|
+
const maxUsers = useMemo(() => {
|
|
2170
|
+
if (!scrollmap || scrollmap.length === 0)
|
|
2171
|
+
return 100;
|
|
2172
|
+
return Math.max(...scrollmap.map((d) => d.percUsers));
|
|
2173
|
+
}, [scrollmap]);
|
|
2174
|
+
const createZones = useCallback((data) => {
|
|
2175
|
+
if (mode === 'basic') {
|
|
2176
|
+
const breakpoints = [0, 25, 50, 75, 100];
|
|
2177
|
+
const zones = [];
|
|
2178
|
+
for (let i = 0; i < breakpoints.length - 1; i++) {
|
|
2179
|
+
const startY = breakpoints[i];
|
|
2180
|
+
const endY = breakpoints[i + 1];
|
|
2181
|
+
const pointsInRange = data.filter((d) => d.scrollReachY >= startY && d.scrollReachY < endY);
|
|
2182
|
+
const avgUsers = pointsInRange.length > 0
|
|
2183
|
+
? pointsInRange.reduce((sum, p) => sum + p.percUsers, 0) / pointsInRange.length
|
|
2184
|
+
: 0;
|
|
2185
|
+
zones.push({
|
|
2186
|
+
id: `zone_${startY}_${endY}`,
|
|
2187
|
+
startY,
|
|
2188
|
+
endY,
|
|
2189
|
+
percUsers: avgUsers,
|
|
2190
|
+
label: `${startY}% - ${endY}%`,
|
|
2191
|
+
});
|
|
2192
|
+
}
|
|
2193
|
+
return zones;
|
|
2194
|
+
}
|
|
2195
|
+
else {
|
|
2196
|
+
// Metrics mode: 20 zones (5% intervals)
|
|
2197
|
+
const zones = [];
|
|
2198
|
+
const interval = 5;
|
|
2199
|
+
// Prepare metrics map
|
|
2200
|
+
let metricsMap;
|
|
2201
|
+
if (scrollMapInfo && Object.keys(scrollMapInfo).length > 0) {
|
|
2202
|
+
metricsMap = new Map();
|
|
2203
|
+
Object.entries(scrollMapInfo).forEach(([key, value]) => {
|
|
2204
|
+
metricsMap.set(Number(key), value);
|
|
2205
|
+
});
|
|
2206
|
+
}
|
|
2207
|
+
for (let i = 0; i < 100; i += interval) {
|
|
2208
|
+
const startY = i;
|
|
2209
|
+
const endY = i + interval;
|
|
2210
|
+
const point = data.find((d) => d.scrollReachY === startY) || {
|
|
2211
|
+
scrollReachY: startY,
|
|
2212
|
+
cumulativeSum: 0,
|
|
2213
|
+
percUsers: 0,
|
|
2214
|
+
};
|
|
2215
|
+
const metrics = metricsMap?.get(startY);
|
|
2216
|
+
zones.push({
|
|
2217
|
+
id: `zone_${startY}_${endY}`,
|
|
2218
|
+
startY,
|
|
2219
|
+
endY,
|
|
2220
|
+
percUsers: point.percUsers,
|
|
2221
|
+
metrics,
|
|
2222
|
+
label: `${startY}% - ${endY}%`,
|
|
2223
|
+
});
|
|
2224
|
+
}
|
|
2225
|
+
return zones;
|
|
2226
|
+
}
|
|
2227
|
+
}, [mode, scrollMapInfo]);
|
|
2228
|
+
/**
|
|
2229
|
+
* Initialize zones
|
|
2230
|
+
*/
|
|
2231
|
+
useEffect(() => {
|
|
2232
|
+
if (!enabled || !scrollmap || scrollmap.length === 0) {
|
|
2233
|
+
setIsReady(false);
|
|
2234
|
+
return;
|
|
2235
|
+
}
|
|
2236
|
+
try {
|
|
2237
|
+
const newZones = createZones(scrollmap);
|
|
2238
|
+
setZones(newZones);
|
|
2239
|
+
setIsReady(true);
|
|
2240
|
+
console.log(`[useScrollmap] Created ${newZones.length} zones in ${mode} mode`);
|
|
2241
|
+
}
|
|
2242
|
+
catch (error) {
|
|
2243
|
+
console.error('[useScrollmap] Error:', error);
|
|
2244
|
+
setIsReady(false);
|
|
2245
|
+
}
|
|
2246
|
+
}, [enabled, scrollmap, mode, createZones]);
|
|
2247
|
+
return {
|
|
2248
|
+
zones,
|
|
2249
|
+
isReady,
|
|
2250
|
+
maxUsers,
|
|
2251
|
+
getZonePosition,
|
|
2252
|
+
};
|
|
2253
|
+
};
|
|
2254
|
+
/**
|
|
2255
|
+
* Get scroll gradient color for minimap
|
|
2256
|
+
*/
|
|
2257
|
+
const getScrollGradientColor = (normalized) => {
|
|
2258
|
+
const idx = Math.min(Math.floor(normalized * 2), 1);
|
|
2259
|
+
const [r1, g1, b1] = SCROLL_GRADIENT_COLORS[idx];
|
|
2260
|
+
const [r2, g2, b2] = SCROLL_GRADIENT_COLORS[idx + 1];
|
|
2261
|
+
const localPercent = (normalized * 2) % 1;
|
|
2262
|
+
const r = Math.round(r1 + (r2 - r1) * localPercent);
|
|
2263
|
+
const g = Math.round(g1 + (g2 - g1) * localPercent);
|
|
2264
|
+
const b = Math.round(b1 + (b2 - b1) * localPercent);
|
|
2265
|
+
return `rgb(${r}, ${g}, ${b})`;
|
|
2266
|
+
};
|
|
2267
|
+
|
|
1568
2268
|
const BoxStack = forwardRef(({ children, ...props }, ref) => {
|
|
1569
2269
|
const id = props.id;
|
|
1570
2270
|
const flexDirection = props.flexDirection;
|
|
@@ -1626,7 +2326,6 @@ const ContentMetricBar = () => {
|
|
|
1626
2326
|
const ContentToolbar = () => {
|
|
1627
2327
|
const controls = useHeatmapControlStore((state) => state.controls);
|
|
1628
2328
|
return (jsx("div", { id: "gx-hm-content-toolbar", style: {
|
|
1629
|
-
zIndex: 2,
|
|
1630
2329
|
position: 'absolute',
|
|
1631
2330
|
bottom: 0,
|
|
1632
2331
|
left: '8px',
|
|
@@ -1651,35 +2350,57 @@ const VizContainer = ({ children, setWrapperHeight }) => {
|
|
|
1651
2350
|
const useClickmap = () => {
|
|
1652
2351
|
const [isInitialized, setIsInitialized] = useState(false);
|
|
1653
2352
|
const clickmap = useHeatmapDataStore((state) => state.clickmap);
|
|
1654
|
-
const vizRef =
|
|
1655
|
-
|
|
2353
|
+
const vizRef = useHeatmapSingleStore((state) => state.vizRef);
|
|
2354
|
+
const start = useCallback(() => {
|
|
1656
2355
|
if (isInitialized)
|
|
1657
2356
|
return;
|
|
1658
2357
|
if (!vizRef || !clickmap || clickmap.length === 0)
|
|
1659
2358
|
return;
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
2359
|
+
try {
|
|
2360
|
+
vizRef?.clearmap?.();
|
|
2361
|
+
vizRef?.clickmap?.(clickmap);
|
|
2362
|
+
setIsInitialized(true);
|
|
2363
|
+
}
|
|
2364
|
+
catch (error) {
|
|
2365
|
+
console.error(`🚀 🐥 ~ useClickmap ~ error:`, error);
|
|
2366
|
+
}
|
|
1663
2367
|
}, [vizRef, clickmap]);
|
|
1664
|
-
return {};
|
|
2368
|
+
return { start };
|
|
1665
2369
|
};
|
|
1666
2370
|
|
|
1667
2371
|
const useScrollmap = () => {
|
|
1668
|
-
|
|
1669
|
-
|
|
2372
|
+
const vizRef = useHeatmapSingleStore((state) => state.vizRef);
|
|
2373
|
+
const scrollmap = useHeatmapDataStore((state) => state.scrollmap);
|
|
2374
|
+
const start = useCallback(() => {
|
|
2375
|
+
// if (isInitialized) return;
|
|
2376
|
+
if (!vizRef || !scrollmap || scrollmap.length === 0)
|
|
2377
|
+
return;
|
|
2378
|
+
try {
|
|
2379
|
+
vizRef?.clearmap?.();
|
|
2380
|
+
vizRef?.scrollmap?.(scrollmap);
|
|
2381
|
+
// setIsInitialized(true);
|
|
2382
|
+
}
|
|
2383
|
+
catch (error) {
|
|
2384
|
+
console.error(`🚀 🐥 ~ useScrollmap ~ error:`, error);
|
|
2385
|
+
}
|
|
2386
|
+
}, [vizRef, scrollmap]);
|
|
2387
|
+
return { start };
|
|
1670
2388
|
};
|
|
1671
2389
|
|
|
1672
|
-
const
|
|
2390
|
+
const useHeatmapCanvas = ({ iframeRef, }) => {
|
|
1673
2391
|
const heatmapType = useHeatmapConfigStore((state) => state.heatmapType);
|
|
1674
|
-
const
|
|
2392
|
+
const { start: startClickmap } = useClickmap();
|
|
2393
|
+
const { start: startScrollmap } = useScrollmap();
|
|
2394
|
+
useEffect(() => {
|
|
1675
2395
|
switch (heatmapType) {
|
|
1676
2396
|
case IHeatmapType.Click:
|
|
1677
|
-
|
|
2397
|
+
startClickmap();
|
|
2398
|
+
break;
|
|
1678
2399
|
case IHeatmapType.Scroll:
|
|
1679
|
-
|
|
2400
|
+
startScrollmap();
|
|
2401
|
+
break;
|
|
1680
2402
|
}
|
|
1681
|
-
}, [heatmapType]);
|
|
1682
|
-
return heatmapRender?.();
|
|
2403
|
+
}, [heatmapType, startClickmap, startScrollmap]);
|
|
1683
2404
|
};
|
|
1684
2405
|
|
|
1685
2406
|
const CLICKED_ELEMENT_ID = 'gx-hm-clicked-element';
|
|
@@ -1742,7 +2463,7 @@ const ElementCallout = (props) => {
|
|
|
1742
2463
|
window.removeEventListener('resize', handleUpdate);
|
|
1743
2464
|
visualRef?.current?.removeEventListener('scroll', handleUpdate);
|
|
1744
2465
|
};
|
|
1745
|
-
}, [target, visualRef, hozOffset, alignment]);
|
|
2466
|
+
}, [element, target, visualRef, hozOffset, alignment]);
|
|
1746
2467
|
const calloutContent = (jsx("div", { ref: calloutRef, className: `clarity-callout clarity-callout--${position.placement} clarity-callout--align-${position.horizontalAlign}`, style: {
|
|
1747
2468
|
position: 'fixed',
|
|
1748
2469
|
top: position.top,
|
|
@@ -1807,8 +2528,8 @@ const ELEMENT_CALLOUT = {
|
|
|
1807
2528
|
alignment: 'left',
|
|
1808
2529
|
};
|
|
1809
2530
|
const HeatmapElements = (props) => {
|
|
1810
|
-
const
|
|
1811
|
-
const { iframeRef, wrapperRef, visualRef, visualizer, iframeDimensions, isElementSidebarOpen, isVisible = true, areDefaultRanksHidden, isSecondary,
|
|
2531
|
+
const iframeHeight = useHeatmapSingleStore((state) => state.iframeHeight);
|
|
2532
|
+
const { iframeRef, wrapperRef, visualRef, visualizer, iframeDimensions, isElementSidebarOpen, isVisible = true, areDefaultRanksHidden, isSecondary, } = props;
|
|
1812
2533
|
const getRect = useHeatmapElementPosition({
|
|
1813
2534
|
iframeRef,
|
|
1814
2535
|
wrapperRef,
|
|
@@ -1837,14 +2558,21 @@ const HeatmapElements = (props) => {
|
|
|
1837
2558
|
});
|
|
1838
2559
|
if (!isVisible)
|
|
1839
2560
|
return null;
|
|
1840
|
-
return (jsxs("div", { onMouseMove:
|
|
2561
|
+
return (jsxs("div", { onMouseMove: (event) => {
|
|
2562
|
+
handleMouseMove(event);
|
|
2563
|
+
// handleMouseMove2(event as any);
|
|
2564
|
+
}, 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 }))] }));
|
|
1841
2565
|
};
|
|
1842
2566
|
|
|
1843
2567
|
const VizElements = ({ iframeRef, visualRef, wrapperRef }) => {
|
|
1844
2568
|
const heatmapInfo = useHeatmapDataStore((state) => state.dataInfo);
|
|
1845
|
-
const contentWidth =
|
|
2569
|
+
const contentWidth = useHeatmapConfigStore((state) => state.width);
|
|
2570
|
+
const vizRef = useHeatmapSingleStore((state) => state.vizRef);
|
|
1846
2571
|
const visualizer = {
|
|
1847
2572
|
get: (hash) => {
|
|
2573
|
+
if (vizRef) {
|
|
2574
|
+
return vizRef.get(hash);
|
|
2575
|
+
}
|
|
1848
2576
|
const doc = iframeRef.current?.contentDocument;
|
|
1849
2577
|
if (!doc)
|
|
1850
2578
|
return null;
|
|
@@ -1870,6 +2598,293 @@ const VizElements = ({ iframeRef, visualRef, wrapperRef }) => {
|
|
|
1870
2598
|
} }));
|
|
1871
2599
|
};
|
|
1872
2600
|
|
|
2601
|
+
const AverageFoldLine = ({ iframeRef, wrapperRef }) => {
|
|
2602
|
+
const averageFold = useHeatmapDataStore((state) => state.dataInfo?.averageFold || 50);
|
|
2603
|
+
const { getZonePosition } = useZonePositions();
|
|
2604
|
+
const position = getZonePosition({
|
|
2605
|
+
startY: averageFold,
|
|
2606
|
+
endY: averageFold,
|
|
2607
|
+
});
|
|
2608
|
+
if (!position)
|
|
2609
|
+
return null;
|
|
2610
|
+
return (jsx("div", { style: {
|
|
2611
|
+
position: 'absolute',
|
|
2612
|
+
top: `${position.top}px`,
|
|
2613
|
+
left: 0,
|
|
2614
|
+
width: '100%',
|
|
2615
|
+
height: '2px',
|
|
2616
|
+
backgroundColor: '#0078D4',
|
|
2617
|
+
pointerEvents: 'none',
|
|
2618
|
+
zIndex: 2,
|
|
2619
|
+
boxShadow: '0 0 4px rgba(0,120,212,0.5)',
|
|
2620
|
+
display: 'flex',
|
|
2621
|
+
alignItems: 'center',
|
|
2622
|
+
}, children: jsxs("div", { style: {
|
|
2623
|
+
position: 'absolute',
|
|
2624
|
+
padding: '8px',
|
|
2625
|
+
backgroundColor: 'rgba(0, 120, 212, 0.9)',
|
|
2626
|
+
color: 'white',
|
|
2627
|
+
fontSize: '16px',
|
|
2628
|
+
fontWeight: 600,
|
|
2629
|
+
borderRadius: '4px',
|
|
2630
|
+
whiteSpace: 'nowrap',
|
|
2631
|
+
left: '12px',
|
|
2632
|
+
minWidth: '120px',
|
|
2633
|
+
textAlign: 'center',
|
|
2634
|
+
}, children: ["Average fold - ", averageFold.toFixed(0), "%"] }) }));
|
|
2635
|
+
};
|
|
2636
|
+
|
|
2637
|
+
const ScrollmapMarker = ({ iframeRef, wrapperRef }) => {
|
|
2638
|
+
const scrollmap = useHeatmapDataStore((state) => state.scrollmap);
|
|
2639
|
+
const scrollType = useHeatmapConfigStore((state) => state.scrollType);
|
|
2640
|
+
const { getZonePosition } = useZonePositions();
|
|
2641
|
+
if (!scrollmap || scrollmap.length === 0)
|
|
2642
|
+
return null;
|
|
2643
|
+
const findScrollPositionForUserPercent = (targetPercent) => {
|
|
2644
|
+
for (let i = 0; i < scrollmap.length; i++) {
|
|
2645
|
+
if (scrollmap[i].percUsers <= targetPercent) {
|
|
2646
|
+
if (i > 0) {
|
|
2647
|
+
return scrollmap[i - 1].scrollReachY;
|
|
2648
|
+
}
|
|
2649
|
+
return scrollmap[i].scrollReachY;
|
|
2650
|
+
}
|
|
2651
|
+
}
|
|
2652
|
+
return scrollmap[scrollmap.length - 1]?.scrollReachY || null;
|
|
2653
|
+
};
|
|
2654
|
+
const boundaries = [
|
|
2655
|
+
{ percent: 75, label: '75%', color: '#10B981' },
|
|
2656
|
+
{ percent: 50, label: '50%', color: '#F59E0B' },
|
|
2657
|
+
{ percent: 25, label: '25%', color: '#EF4444' },
|
|
2658
|
+
{ percent: 5, label: '5%', color: '#8B5CF6' },
|
|
2659
|
+
];
|
|
2660
|
+
const isScrollDepth = scrollType === IScrollType.Depth;
|
|
2661
|
+
if (!isScrollDepth)
|
|
2662
|
+
return null;
|
|
2663
|
+
return (jsx(Fragment, { children: boundaries.map((boundary) => {
|
|
2664
|
+
const scrollY = findScrollPositionForUserPercent(boundary.percent);
|
|
2665
|
+
if (scrollY === null)
|
|
2666
|
+
return null;
|
|
2667
|
+
const position = getZonePosition({
|
|
2668
|
+
startY: scrollY,
|
|
2669
|
+
endY: scrollY,
|
|
2670
|
+
});
|
|
2671
|
+
if (!position)
|
|
2672
|
+
return null;
|
|
2673
|
+
return (jsx("div", { className: `marker-boundary-line-${boundary.percent}`, style: {
|
|
2674
|
+
position: 'absolute',
|
|
2675
|
+
top: `${position.top}px`,
|
|
2676
|
+
left: 0,
|
|
2677
|
+
transformOrigin: 'left center',
|
|
2678
|
+
width: '100%',
|
|
2679
|
+
height: '0px',
|
|
2680
|
+
// borderBottom: `2px dashed #323130`,
|
|
2681
|
+
borderBottom: `2px solid ${boundary.color}`,
|
|
2682
|
+
// background: 'repeating-linear-gradient(90deg, #323130, transparent 2px 3px)',
|
|
2683
|
+
zIndex: 1,
|
|
2684
|
+
display: 'flex',
|
|
2685
|
+
alignItems: 'center',
|
|
2686
|
+
}, children: jsx("div", { style: {
|
|
2687
|
+
position: 'absolute',
|
|
2688
|
+
padding: '8px',
|
|
2689
|
+
backgroundColor: boundary.color,
|
|
2690
|
+
color: 'white',
|
|
2691
|
+
fontSize: '16px',
|
|
2692
|
+
fontWeight: 600,
|
|
2693
|
+
borderRadius: '4px',
|
|
2694
|
+
whiteSpace: 'nowrap',
|
|
2695
|
+
left: '12px',
|
|
2696
|
+
minWidth: '120px',
|
|
2697
|
+
textAlign: 'center',
|
|
2698
|
+
// textAlign: 'center',
|
|
2699
|
+
// padding: '8px',
|
|
2700
|
+
// paddingInline: '8px',
|
|
2701
|
+
// fontSize: '16px',
|
|
2702
|
+
// background: '#fff',
|
|
2703
|
+
// width: 'auto',
|
|
2704
|
+
// borderRadius: '4px',
|
|
2705
|
+
// position: 'absolute',
|
|
2706
|
+
// left: '12px',
|
|
2707
|
+
// minWidth: '120px',
|
|
2708
|
+
}, children: boundary.label }) }, boundary.label));
|
|
2709
|
+
}) }));
|
|
2710
|
+
};
|
|
2711
|
+
|
|
2712
|
+
const ScrollMapMinimap = ({ zones, maxUsers }) => {
|
|
2713
|
+
const showMinimap = useHeatmapVizScrollmapStore((state) => state.showMinimap);
|
|
2714
|
+
const scrollType = useHeatmapConfigStore((state) => state.scrollType);
|
|
2715
|
+
const isScrollType = [IScrollType.Attention].includes(scrollType);
|
|
2716
|
+
if (!showMinimap || !isScrollType)
|
|
2717
|
+
return null;
|
|
2718
|
+
return (jsx("div", { style: {
|
|
2719
|
+
position: 'fixed',
|
|
2720
|
+
left: '20px',
|
|
2721
|
+
top: '50%',
|
|
2722
|
+
transform: 'translateY(-50%)',
|
|
2723
|
+
width: '60px',
|
|
2724
|
+
height: '400px',
|
|
2725
|
+
backgroundColor: 'white',
|
|
2726
|
+
borderRadius: '8px',
|
|
2727
|
+
boxShadow: '0 4px 16px rgba(0,0,0,0.15)',
|
|
2728
|
+
zIndex: 10002,
|
|
2729
|
+
padding: '8px',
|
|
2730
|
+
boxSizing: 'border-box',
|
|
2731
|
+
}, children: jsx("div", { style: {
|
|
2732
|
+
width: '100%',
|
|
2733
|
+
height: '100%',
|
|
2734
|
+
borderRadius: '4px',
|
|
2735
|
+
overflow: 'hidden',
|
|
2736
|
+
display: 'flex',
|
|
2737
|
+
flexDirection: 'column',
|
|
2738
|
+
}, children: zones.map((zone) => {
|
|
2739
|
+
const normalized = maxUsers > 0 ? zone.percUsers / maxUsers : 0;
|
|
2740
|
+
const color = getScrollGradientColor(normalized);
|
|
2741
|
+
return (jsx("div", { title: `${zone.label}: ${zone.percUsers.toFixed(2)}%`, style: {
|
|
2742
|
+
width: '100%',
|
|
2743
|
+
flex: `${zone.endY - zone.startY}`,
|
|
2744
|
+
backgroundColor: color,
|
|
2745
|
+
borderBottom: '1px solid rgba(255,255,255,0.2)',
|
|
2746
|
+
} }, zone.id));
|
|
2747
|
+
}) }) }));
|
|
2748
|
+
};
|
|
2749
|
+
|
|
2750
|
+
const ScrollZoneTooltip = ({ zone, position, currentScrollPercent, scrollmap, }) => {
|
|
2751
|
+
const tooltipRef = useRef(null);
|
|
2752
|
+
const currentData = useMemo(() => {
|
|
2753
|
+
if (!scrollmap || scrollmap.length === 0)
|
|
2754
|
+
return null;
|
|
2755
|
+
const roundedPercent = Math.floor(currentScrollPercent);
|
|
2756
|
+
return scrollmap.find((d) => d.scrollReachY === roundedPercent) || null;
|
|
2757
|
+
}, [scrollmap, currentScrollPercent]);
|
|
2758
|
+
return (jsxs("div", { id: "gx-hm-scrollmap-tooltip", ref: tooltipRef, style: {
|
|
2759
|
+
position: 'fixed',
|
|
2760
|
+
top: `${position.y}px`,
|
|
2761
|
+
backgroundColor: 'black',
|
|
2762
|
+
zIndex: 10001,
|
|
2763
|
+
pointerEvents: 'none',
|
|
2764
|
+
width: '100%',
|
|
2765
|
+
height: '2px',
|
|
2766
|
+
}, children: [jsxs("div", { style: {
|
|
2767
|
+
position: 'absolute',
|
|
2768
|
+
left: '50%',
|
|
2769
|
+
top: '-50%',
|
|
2770
|
+
transform: 'translate(-50%, -50%)',
|
|
2771
|
+
padding: '16px',
|
|
2772
|
+
borderRadius: '8px',
|
|
2773
|
+
boxShadow: '0 4px 16px rgba(0,0,0,0.15)',
|
|
2774
|
+
fontSize: '14px',
|
|
2775
|
+
width: 'fit-content',
|
|
2776
|
+
backgroundColor: 'white',
|
|
2777
|
+
minWidth: '230px',
|
|
2778
|
+
display: 'flex',
|
|
2779
|
+
gap: '8px',
|
|
2780
|
+
alignItems: 'center',
|
|
2781
|
+
}, children: [jsxs("p", { style: {
|
|
2782
|
+
fontWeight: 650,
|
|
2783
|
+
fontSize: '20px',
|
|
2784
|
+
lineHeight: '24px',
|
|
2785
|
+
letterSpacing: '-0.2px',
|
|
2786
|
+
verticalAlign: 'middle',
|
|
2787
|
+
fontVariantNumeric: 'tabular-nums',
|
|
2788
|
+
}, children: [currentData?.percUsers?.toFixed(2), "%", ' '] }), jsx("p", { style: { fontWeight: 450 }, children: "user scrolled this far" })] }), jsx(TooltipByZone, { zone: zone })] }));
|
|
2789
|
+
};
|
|
2790
|
+
const TooltipByZone = ({ zone }) => {
|
|
2791
|
+
const scrollType = useHeatmapConfigStore((state) => state.scrollType);
|
|
2792
|
+
if (!zone)
|
|
2793
|
+
return null;
|
|
2794
|
+
const contentMarkup = () => {
|
|
2795
|
+
switch (scrollType) {
|
|
2796
|
+
case IScrollType.Depth:
|
|
2797
|
+
return jsx(BasicTooltipContent, { zone: zone });
|
|
2798
|
+
case IScrollType.Attention:
|
|
2799
|
+
return jsx(MetricsTooltipContent, { zone: zone });
|
|
2800
|
+
default:
|
|
2801
|
+
return jsx(BasicTooltipContent, { zone: zone });
|
|
2802
|
+
}
|
|
2803
|
+
};
|
|
2804
|
+
return (jsx("div", { style: { paddingTop: '12px', borderTop: '1px solid #E5E7EB' }, children: contentMarkup() }));
|
|
2805
|
+
};
|
|
2806
|
+
const BasicTooltipContent = ({ zone }) => {
|
|
2807
|
+
if (!zone)
|
|
2808
|
+
return null;
|
|
2809
|
+
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" })] }));
|
|
2810
|
+
};
|
|
2811
|
+
const MetricsTooltipContent = ({ zone }) => {
|
|
2812
|
+
if (!zone)
|
|
2813
|
+
return null;
|
|
2814
|
+
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() }))] }))] }));
|
|
2815
|
+
};
|
|
2816
|
+
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 })] }));
|
|
2817
|
+
|
|
2818
|
+
const HoverZones = ({ iframeRef, wrapperRef, position, currentScrollPercent, }) => {
|
|
2819
|
+
const scrollmap = useHeatmapDataStore((state) => state.scrollmap);
|
|
2820
|
+
// const hoveredZone = useHeatmapVizScrollmapStore((state) => state.hoveredZone);
|
|
2821
|
+
// const setHoveredZone = useHeatmapVizScrollmapStore((state) => state.setHoveredZone);
|
|
2822
|
+
const { zones, isReady, maxUsers } = useScrollmapZones({
|
|
2823
|
+
iframeRef,
|
|
2824
|
+
wrapperRef,
|
|
2825
|
+
});
|
|
2826
|
+
if (!isReady || !zones.length)
|
|
2827
|
+
return null;
|
|
2828
|
+
if (!position)
|
|
2829
|
+
return null;
|
|
2830
|
+
return (jsxs(Fragment, { children: [jsx(ScrollZoneTooltip, { position: position, currentScrollPercent: currentScrollPercent, scrollmap: scrollmap || [] }), jsx(ScrollMapMinimap, { zones: zones, maxUsers: maxUsers })] }));
|
|
2831
|
+
};
|
|
2832
|
+
|
|
2833
|
+
const ScrollMapOverlay = ({ wrapperRef, iframeRef }) => {
|
|
2834
|
+
const overlayRef = useRef(null);
|
|
2835
|
+
const [position, setPosition] = useState();
|
|
2836
|
+
const [currentScrollPercent, setCurrentScrollPercent] = useState(0);
|
|
2837
|
+
const widthScale = useHeatmapVizStore((state) => state.scale);
|
|
2838
|
+
const iframeHeight = useHeatmapSingleStore((state) => state.iframeHeight);
|
|
2839
|
+
const handleMouseMove = (event) => {
|
|
2840
|
+
if (!iframeRef.current || !wrapperRef.current)
|
|
2841
|
+
return;
|
|
2842
|
+
const iframe = iframeRef.current;
|
|
2843
|
+
const iframeRect = iframe.getBoundingClientRect();
|
|
2844
|
+
const { x, y } = convertViewportToIframeCoords(event.clientX, event.clientY, iframeRect, widthScale);
|
|
2845
|
+
const wrapperEl = wrapperRef.current;
|
|
2846
|
+
const scrollOffset = (wrapperEl?.scrollTop || 0) / widthScale;
|
|
2847
|
+
const actualY = y + scrollOffset;
|
|
2848
|
+
const scrollPercent = Math.min(100, Math.max(0, (actualY / iframeHeight) * 100));
|
|
2849
|
+
setCurrentScrollPercent(scrollPercent);
|
|
2850
|
+
setPosition({ x, y });
|
|
2851
|
+
};
|
|
2852
|
+
const onMouseMove = useCallback((event) => {
|
|
2853
|
+
requestAnimationFrame(() => handleMouseMove(event));
|
|
2854
|
+
}, [handleMouseMove]);
|
|
2855
|
+
const onMouseLeave = () => {
|
|
2856
|
+
requestAnimationFrame(() => {
|
|
2857
|
+
setCurrentScrollPercent(0);
|
|
2858
|
+
setPosition(undefined);
|
|
2859
|
+
});
|
|
2860
|
+
};
|
|
2861
|
+
return (jsx("div", { ref: overlayRef, id: "gx-hm-scrollmap-overlay", onMouseMove: onMouseMove, onMouseLeave: onMouseLeave, style: {
|
|
2862
|
+
position: 'absolute',
|
|
2863
|
+
top: 0,
|
|
2864
|
+
left: 0,
|
|
2865
|
+
width: '100%',
|
|
2866
|
+
height: `${iframeHeight}px`,
|
|
2867
|
+
zIndex: 3,
|
|
2868
|
+
}, children: jsx(HoverZones, { position: position, currentScrollPercent: currentScrollPercent, iframeRef: iframeRef, wrapperRef: wrapperRef }) }));
|
|
2869
|
+
};
|
|
2870
|
+
|
|
2871
|
+
const SCROLL_TYPES = [IHeatmapType.Scroll];
|
|
2872
|
+
const VizScrollMap = ({ iframeRef, wrapperRef }) => {
|
|
2873
|
+
const iframeHeight = useHeatmapSingleStore((state) => state.iframeHeight);
|
|
2874
|
+
const heatmapType = useHeatmapConfigStore((state) => state.heatmapType);
|
|
2875
|
+
const isHeatmapScroll = SCROLL_TYPES.includes(heatmapType);
|
|
2876
|
+
if (!iframeHeight || !isHeatmapScroll)
|
|
2877
|
+
return null;
|
|
2878
|
+
return (jsxs("div", { style: {
|
|
2879
|
+
position: 'absolute',
|
|
2880
|
+
top: 0,
|
|
2881
|
+
left: '2px',
|
|
2882
|
+
width: `calc(100% - 4px)`,
|
|
2883
|
+
height: '100%',
|
|
2884
|
+
transform: 'translateZ(0)',
|
|
2885
|
+
}, children: [jsx(ScrollmapMarker, { iframeRef: iframeRef, wrapperRef: wrapperRef }), jsx(AverageFoldLine, { iframeRef: iframeRef, wrapperRef: wrapperRef }), jsx(ScrollMapOverlay, { wrapperRef: wrapperRef, iframeRef: iframeRef })] }));
|
|
2886
|
+
};
|
|
2887
|
+
|
|
1873
2888
|
const WrapperVisual = ({ children, visualRef, wrapperRef, scaledHeight, iframeHeight, onScroll, }) => {
|
|
1874
2889
|
const contentWidth = useHeatmapConfigStore((state) => state.width);
|
|
1875
2890
|
const widthScale = useHeatmapVizStore((state) => state.scale);
|
|
@@ -1877,7 +2892,7 @@ const WrapperVisual = ({ children, visualRef, wrapperRef, scaledHeight, iframeHe
|
|
|
1877
2892
|
? `${scaledHeight + HEATMAP_CONFIG['heightToolbar'] + HEATMAP_CONFIG['padding'] * 2}px`
|
|
1878
2893
|
: 'auto';
|
|
1879
2894
|
return (jsx("div", { ref: visualRef, className: "gx-hm-visual", onScroll: onScroll, style: {
|
|
1880
|
-
overflow: 'hidden
|
|
2895
|
+
overflow: 'hidden scroll',
|
|
1881
2896
|
display: 'flex',
|
|
1882
2897
|
position: 'relative',
|
|
1883
2898
|
justifyContent: 'center',
|
|
@@ -1904,8 +2919,9 @@ const WrapperVisual = ({ children, visualRef, wrapperRef, scaledHeight, iframeHe
|
|
|
1904
2919
|
|
|
1905
2920
|
const VizDomRenderer = ({ mode = 'heatmap' }) => {
|
|
1906
2921
|
const width = useHeatmapConfigStore((state) => state.width);
|
|
1907
|
-
const
|
|
1908
|
-
const
|
|
2922
|
+
const heatmapType = useHeatmapConfigStore((state) => state.heatmapType);
|
|
2923
|
+
const iframeHeight = useHeatmapSingleStore((state) => state.iframeHeight);
|
|
2924
|
+
const setIframeHeight = useHeatmapSingleStore((state) => state.setIframeHeight);
|
|
1909
2925
|
const setSelectedElement = useHeatmapInteractionStore((state) => state.setSelectedElement);
|
|
1910
2926
|
const wrapperRef = useRef(null);
|
|
1911
2927
|
const visualRef = useRef(null);
|
|
@@ -1915,14 +2931,13 @@ const VizDomRenderer = ({ mode = 'heatmap' }) => {
|
|
|
1915
2931
|
iframeRef,
|
|
1916
2932
|
visualRef,
|
|
1917
2933
|
iframeHeight,
|
|
1918
|
-
setIframeHeight,
|
|
1919
2934
|
});
|
|
1920
2935
|
const contentWidth = width ?? 0;
|
|
1921
2936
|
const onScroll = (e) => {
|
|
1922
2937
|
const scrollTop = e.currentTarget.scrollTop;
|
|
1923
2938
|
handleScroll(scrollTop);
|
|
1924
2939
|
};
|
|
1925
|
-
|
|
2940
|
+
useHeatmapCanvas({ iframeRef: iframeRef });
|
|
1926
2941
|
const cleanUp = () => {
|
|
1927
2942
|
setIframeHeight(0);
|
|
1928
2943
|
setSelectedElement(null);
|
|
@@ -1930,7 +2945,7 @@ const VizDomRenderer = ({ mode = 'heatmap' }) => {
|
|
|
1930
2945
|
useEffect(() => {
|
|
1931
2946
|
return cleanUp;
|
|
1932
2947
|
}, []);
|
|
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,
|
|
2948
|
+
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 })] }));
|
|
1934
2949
|
};
|
|
1935
2950
|
|
|
1936
2951
|
const VizLoading = () => {
|
|
@@ -1940,12 +2955,12 @@ const VizLoading = () => {
|
|
|
1940
2955
|
const VizDomHeatmap = () => {
|
|
1941
2956
|
const controls = useHeatmapControlStore((state) => state.controls);
|
|
1942
2957
|
const isRendering = useHeatmapDataStore((state) => state.isRendering);
|
|
1943
|
-
const iframeHeight =
|
|
1944
|
-
const setIframeHeight =
|
|
1945
|
-
const setVizRef =
|
|
2958
|
+
const iframeHeight = useHeatmapSingleStore((state) => state.iframeHeight);
|
|
2959
|
+
const setIframeHeight = useHeatmapSingleStore((state) => state.setIframeHeight);
|
|
2960
|
+
const setVizRef = useHeatmapSingleStore((state) => state.setVizRef);
|
|
1946
2961
|
useEffect(() => {
|
|
1947
2962
|
return () => {
|
|
1948
|
-
setVizRef(
|
|
2963
|
+
setVizRef(null);
|
|
1949
2964
|
setIframeHeight(0);
|
|
1950
2965
|
};
|
|
1951
2966
|
}, []);
|
|
@@ -1960,7 +2975,7 @@ const VizLiveRenderer = () => {
|
|
|
1960
2975
|
const setIframeHeight = useHeatmapLiveStore((state) => state.setIframeHeight);
|
|
1961
2976
|
const visualRef = useRef(null);
|
|
1962
2977
|
const wrapperRef = useRef(null);
|
|
1963
|
-
const { iframeRef } =
|
|
2978
|
+
const { iframeRef } = useVizLiveRender();
|
|
1964
2979
|
const { scaledHeight, handleScroll } = useHeatmapScale({
|
|
1965
2980
|
wrapperRef,
|
|
1966
2981
|
iframeRef,
|
|
@@ -1972,13 +2987,15 @@ const VizLiveRenderer = () => {
|
|
|
1972
2987
|
const scrollTop = e.currentTarget.scrollTop;
|
|
1973
2988
|
handleScroll(scrollTop);
|
|
1974
2989
|
};
|
|
1975
|
-
return (jsx(WrapperVisual, { visualRef: visualRef, wrapperRef: wrapperRef, scaledHeight: scaledHeight, iframeHeight: iframeHeight, onScroll: onScroll, children: jsx("iframe", { ref: iframeRef, ...HEATMAP_IFRAME, width: contentWidth,
|
|
2990
|
+
return (jsx(WrapperVisual, { visualRef: visualRef, wrapperRef: wrapperRef, scaledHeight: scaledHeight, iframeHeight: iframeHeight, onScroll: onScroll, children: jsx("iframe", { ref: iframeRef, ...HEATMAP_IFRAME, width: contentWidth,
|
|
2991
|
+
// height={iframeHeight}
|
|
2992
|
+
scrolling: "no", sandbox: "allow-scripts allow-same-origin" }) }));
|
|
1976
2993
|
};
|
|
1977
2994
|
|
|
1978
2995
|
const VizLiveHeatmap = () => {
|
|
1979
2996
|
const controls = useHeatmapControlStore((state) => state.controls);
|
|
1980
2997
|
const isRendering = useHeatmapDataStore((state) => state.isRendering);
|
|
1981
|
-
const iframeHeight =
|
|
2998
|
+
const iframeHeight = useHeatmapLiveStore((state) => state.iframeHeight);
|
|
1982
2999
|
const wrapperHeight = useHeatmapLiveStore((state) => state.wrapperHeight);
|
|
1983
3000
|
const setWrapperHeight = useHeatmapLiveStore((state) => state.setWrapperHeight);
|
|
1984
3001
|
const reset = useHeatmapLiveStore((state) => state.reset);
|
|
@@ -2035,10 +3052,10 @@ const WrapperLayout = () => {
|
|
|
2035
3052
|
return (jsxs(BoxStack, { id: "gx-hm-layout", flexDirection: "column", flex: "1", children: [jsx(ContentTopBar, {}), jsx(WrapperPreview, {})] }));
|
|
2036
3053
|
};
|
|
2037
3054
|
|
|
2038
|
-
const HeatmapLayout = ({ data, clickmap, controls, dataInfo, }) => {
|
|
3055
|
+
const HeatmapLayout = ({ data, clickmap, scrollmap, controls, dataInfo, }) => {
|
|
2039
3056
|
useRegisterControl(controls);
|
|
2040
3057
|
useRegisterData(data, dataInfo);
|
|
2041
|
-
useRegisterHeatmap(clickmap);
|
|
3058
|
+
useRegisterHeatmap({ clickmap, scrollmap });
|
|
2042
3059
|
useRegisterConfig();
|
|
2043
3060
|
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: {
|
|
2044
3061
|
minHeight: '100%',
|
|
@@ -2053,4 +3070,4 @@ const HeatmapLayout = ({ data, clickmap, controls, dataInfo, }) => {
|
|
|
2053
3070
|
}
|
|
2054
3071
|
};
|
|
2055
3072
|
|
|
2056
|
-
export { GraphView, HeatmapLayout, IHeatmapType, useHeatmapConfigStore, useHeatmapDataStore, useHeatmapInteractionStore, useHeatmapLiveStore };
|
|
3073
|
+
export { GraphView, HeatmapLayout, IClickType, IHeatmapType, IScrollType, useHeatmapConfigStore, useHeatmapDataStore, useHeatmapInteractionStore, useHeatmapLiveStore, useHeatmapVizStore };
|