@gemx-dev/heatmap-react 3.5.49 → 3.5.51
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/ContentMetricBar.d.ts.map +1 -1
- package/dist/esm/components/Layout/ContentVizByMode.d.ts.map +1 -1
- package/dist/esm/components/Layout/HeatmapLayout.d.ts +2 -2
- package/dist/esm/components/Layout/HeatmapLayout.d.ts.map +1 -1
- package/dist/esm/components/Layout/Sidebar/ContentSidebar.d.ts +2 -0
- package/dist/esm/components/Layout/Sidebar/ContentSidebar.d.ts.map +1 -0
- package/dist/esm/components/Layout/Sidebar/PopoverSidebar.d.ts +2 -0
- package/dist/esm/components/Layout/Sidebar/PopoverSidebar.d.ts.map +1 -0
- package/dist/esm/components/Layout/Sidebar/index.d.ts +3 -0
- package/dist/esm/components/Layout/Sidebar/index.d.ts.map +1 -0
- package/dist/esm/components/Layout/WrapperLayout.d.ts.map +1 -1
- package/dist/esm/components/Layout/WrapperPreview.d.ts.map +1 -1
- package/dist/esm/components/VizDom/VizContainer.d.ts.map +1 -1
- package/dist/esm/components/VizDom/VizDomHeatmap.d.ts.map +1 -1
- package/dist/esm/components/VizDom/VizDomRenderer.d.ts.map +1 -1
- package/dist/esm/components/VizDom/WrapperVisual.d.ts.map +1 -1
- package/dist/esm/components/VizElement/DefaultRankBadges.d.ts.map +1 -1
- package/dist/esm/components/VizElement/ElementCallout.d.ts.map +1 -1
- package/dist/esm/components/VizElement/ElementOverlay.d.ts +1 -0
- package/dist/esm/components/VizElement/ElementOverlay.d.ts.map +1 -1
- package/dist/esm/components/VizElement/HeatmapElements.d.ts +0 -1
- package/dist/esm/components/VizElement/HeatmapElements.d.ts.map +1 -1
- 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/HoverZones.d.ts +1 -1
- package/dist/esm/components/VizScrollmap/HoverZones.d.ts.map +1 -1
- package/dist/esm/components/VizScrollmap/ScrollMapMinimap.d.ts +1 -1
- package/dist/esm/components/VizScrollmap/ScrollMapMinimap.d.ts.map +1 -1
- package/dist/esm/components/VizScrollmap/ScrollMapOverlay.d.ts.map +1 -1
- package/dist/esm/components/VizScrollmap/ScrollZoneHoverArea.d.ts +1 -2
- package/dist/esm/components/VizScrollmap/ScrollZoneHoverArea.d.ts.map +1 -1
- package/dist/esm/components/VizScrollmap/ScrollZoneTooltip.d.ts +1 -1
- package/dist/esm/components/VizScrollmap/ScrollZoneTooltip.d.ts.map +1 -1
- package/dist/esm/components/VizScrollmap/VizScrollMap.d.ts.map +1 -1
- package/dist/esm/components/VizScrollmapV2/ScrollmapOverlayV2.d.ts +1 -2
- package/dist/esm/components/VizScrollmapV2/ScrollmapOverlayV2.d.ts.map +1 -1
- package/dist/esm/components/VizScrollmapV2/useScrollmapOverlay.d.ts +1 -1
- package/dist/esm/components/VizScrollmapV2/useScrollmapOverlay.d.ts.map +1 -1
- package/dist/esm/configs/index.d.ts +2 -0
- package/dist/esm/configs/index.d.ts.map +1 -1
- package/dist/esm/configs/viewId.d.ts +21 -0
- package/dist/esm/configs/viewId.d.ts.map +1 -0
- package/dist/esm/configs/z-index.d.ts +8 -0
- package/dist/esm/configs/z-index.d.ts.map +1 -0
- package/dist/esm/constants/index.d.ts +13 -4
- package/dist/esm/constants/index.d.ts.map +1 -1
- package/dist/esm/contexts/CompareViewContext.d.ts +1 -1
- package/dist/esm/contexts/CompareViewContext.d.ts.map +1 -1
- package/dist/esm/helpers/iframe-helper/fixer.d.ts +1 -1
- package/dist/esm/helpers/iframe-helper/fixer.d.ts.map +1 -1
- package/dist/esm/helpers/iframe-helper/init.d.ts +1 -1
- package/dist/esm/helpers/iframe-helper/init.d.ts.map +1 -1
- package/dist/esm/helpers/iframe-helper/style-replacer.d.ts.map +1 -1
- package/dist/esm/helpers/iframe.d.ts +1 -1
- package/dist/esm/helpers/iframe.d.ts.map +1 -1
- package/dist/esm/helpers/index.d.ts +2 -3
- package/dist/esm/helpers/index.d.ts.map +1 -1
- package/dist/esm/helpers/viz-canvas/area-clustering.d.ts +1 -1
- package/dist/esm/helpers/viz-canvas/area-clustering.d.ts.map +1 -1
- package/dist/esm/helpers/viz-canvas/area-overlay-manager-v2.d.ts +2 -2
- package/dist/esm/helpers/viz-canvas/area-overlay-manager-v2.d.ts.map +1 -1
- package/dist/esm/helpers/viz-canvas/area-overlay-manager.d.ts +1 -1
- package/dist/esm/helpers/viz-canvas/area-overlay-manager.d.ts.map +1 -1
- package/dist/esm/helpers/viz-canvas/hierarchical-area-clustering.d.ts +1 -1
- package/dist/esm/helpers/viz-canvas/hierarchical-area-clustering.d.ts.map +1 -1
- package/dist/esm/helpers/viz-elm-callout/constants.d.ts +4 -0
- package/dist/esm/helpers/viz-elm-callout/constants.d.ts.map +1 -0
- package/dist/esm/helpers/viz-elm-callout/dimensions.d.ts +4 -0
- package/dist/esm/helpers/viz-elm-callout/dimensions.d.ts.map +1 -0
- package/dist/esm/helpers/{elm-getter.d.ts → viz-elm-callout/getter.d.ts} +2 -2
- package/dist/esm/helpers/viz-elm-callout/getter.d.ts.map +1 -0
- package/dist/esm/helpers/viz-elm-callout/index.d.ts +3 -0
- package/dist/esm/helpers/viz-elm-callout/index.d.ts.map +1 -0
- package/dist/esm/helpers/viz-elm-callout/position-calculator.d.ts +14 -0
- package/dist/esm/helpers/viz-elm-callout/position-calculator.d.ts.map +1 -0
- package/dist/esm/helpers/viz-elm-callout/position-candidates.d.ts +6 -0
- package/dist/esm/helpers/viz-elm-callout/position-candidates.d.ts.map +1 -0
- package/dist/esm/helpers/viz-elm-callout/position-selector.d.ts +10 -0
- package/dist/esm/helpers/viz-elm-callout/position-selector.d.ts.map +1 -0
- package/dist/esm/helpers/viz-elm-callout/position-validator.d.ts +4 -0
- package/dist/esm/helpers/viz-elm-callout/position-validator.d.ts.map +1 -0
- package/dist/esm/helpers/viz-elm-callout/types.d.ts +17 -0
- package/dist/esm/helpers/viz-elm-callout/types.d.ts.map +1 -0
- package/dist/esm/helpers/{elm-callout.d.ts → viz-elm-callout/viz-elm.d.ts} +4 -3
- package/dist/esm/helpers/viz-elm-callout/viz-elm.d.ts.map +1 -0
- package/dist/esm/helpers/{viz-elements.d.ts → viz-elm.d.ts} +1 -1
- package/dist/esm/helpers/viz-elm.d.ts.map +1 -0
- package/dist/esm/hooks/common/index.d.ts +2 -0
- package/dist/esm/hooks/common/index.d.ts.map +1 -0
- package/dist/esm/hooks/common/useDebounceCallback.d.ts +17 -0
- package/dist/esm/hooks/common/useDebounceCallback.d.ts.map +1 -0
- package/dist/esm/hooks/index.d.ts +3 -5
- package/dist/esm/hooks/index.d.ts.map +1 -1
- package/dist/esm/hooks/register/useRegisterControl.d.ts +1 -1
- package/dist/esm/hooks/register/useRegisterControl.d.ts.map +1 -1
- package/dist/esm/hooks/register/useRegisterData.d.ts +1 -1
- package/dist/esm/hooks/register/useRegisterData.d.ts.map +1 -1
- package/dist/esm/hooks/register/useRegisterHeatmap.d.ts +1 -1
- package/dist/esm/hooks/register/useRegisterHeatmap.d.ts.map +1 -1
- package/dist/esm/hooks/view-context/index.d.ts +7 -0
- package/dist/esm/hooks/view-context/index.d.ts.map +1 -0
- package/dist/esm/hooks/view-context/useHeatmapCopyView.d.ts +33 -0
- package/dist/esm/hooks/view-context/useHeatmapCopyView.d.ts.map +1 -0
- package/dist/esm/hooks/{useHeatmapData.d.ts → view-context/useHeatmapData.d.ts} +1 -1
- package/dist/esm/hooks/view-context/useHeatmapData.d.ts.map +1 -0
- package/dist/esm/hooks/view-context/useHeatmapInteraction.d.ts +16 -0
- package/dist/esm/hooks/view-context/useHeatmapInteraction.d.ts.map +1 -0
- package/dist/{umd/hooks → esm/hooks/view-context}/useHeatmapViz.d.ts +3 -1
- package/dist/esm/hooks/view-context/useHeatmapViz.d.ts.map +1 -0
- package/dist/esm/hooks/view-context/useHeatmapVizScrollmap.d.ts +13 -0
- package/dist/esm/hooks/view-context/useHeatmapVizScrollmap.d.ts.map +1 -0
- package/dist/esm/hooks/{useViewId.d.ts → view-context/useViewId.d.ts} +1 -1
- package/dist/esm/hooks/view-context/useViewId.d.ts.map +1 -0
- package/dist/esm/hooks/viz-area/useAreaHeatmap.d.ts +1 -1
- package/dist/esm/hooks/viz-area/useAreaHeatmap.d.ts.map +1 -1
- package/dist/esm/hooks/viz-area/useAreaHeatmapManager.d.ts.map +1 -1
- package/dist/esm/hooks/viz-canvas/useAreamap.d.ts +1 -1
- package/dist/esm/hooks/viz-canvas/useAreamap.d.ts.map +1 -1
- package/dist/esm/hooks/viz-canvas/useClickmap.d.ts.map +1 -1
- package/dist/esm/hooks/viz-canvas/useHeatmapCanvas.d.ts +1 -3
- package/dist/esm/hooks/viz-canvas/useHeatmapCanvas.d.ts.map +1 -1
- package/dist/esm/hooks/viz-canvas/useScrollmap.d.ts.map +1 -1
- package/dist/esm/hooks/viz-elm/index.d.ts.map +1 -0
- package/dist/esm/hooks/{viz-elements → viz-elm}/useClickedElement.d.ts +0 -1
- package/dist/esm/hooks/viz-elm/useClickedElement.d.ts.map +1 -0
- package/dist/esm/hooks/viz-elm/useElementCalloutVisible.d.ts.map +1 -0
- package/dist/esm/hooks/viz-elm/useHeatmapEffects.d.ts +4 -0
- package/dist/esm/hooks/viz-elm/useHeatmapEffects.d.ts.map +1 -0
- package/dist/esm/hooks/viz-elm/useHeatmapElementPosition.d.ts.map +1 -0
- package/dist/{umd/hooks/viz-elements → esm/hooks/viz-elm}/useHeatmapMouseHandler.d.ts +1 -1
- package/dist/esm/hooks/{viz-elements → viz-elm}/useHeatmapMouseHandler.d.ts.map +1 -1
- package/dist/esm/hooks/viz-elm/useHoveredElement.d.ts.map +1 -0
- package/dist/esm/hooks/viz-live/useVizLiveRender.d.ts.map +1 -1
- package/dist/esm/hooks/viz-render/useHeatmapRender.d.ts.map +1 -1
- package/dist/esm/hooks/viz-render/useReplayRender.d.ts.map +1 -1
- package/dist/esm/hooks/viz-scale/useHeatmapScale.d.ts +0 -1
- package/dist/esm/hooks/viz-scale/useHeatmapScale.d.ts.map +1 -1
- package/dist/esm/hooks/viz-scale/useObserveIframeHeight.d.ts +0 -1
- package/dist/esm/hooks/viz-scale/useObserveIframeHeight.d.ts.map +1 -1
- package/dist/esm/hooks/viz-scale/useWrapperRefHeight.d.ts.map +1 -1
- package/dist/esm/hooks/viz-scrollmap/useScrollmapZones.d.ts +1 -1
- package/dist/esm/hooks/viz-scrollmap/useScrollmapZones.d.ts.map +1 -1
- package/dist/esm/hooks/viz-scrollmap/useZonePositions.d.ts +2 -2
- package/dist/esm/hooks/viz-scrollmap/useZonePositions.d.ts.map +1 -1
- package/dist/esm/index.d.ts +3 -2
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +1280 -635
- package/dist/esm/index.mjs +1280 -635
- package/dist/esm/performance/hooks.d.ts +28 -0
- package/dist/esm/performance/hooks.d.ts.map +1 -0
- package/dist/esm/performance/index.d.ts +7 -0
- package/dist/esm/performance/index.d.ts.map +1 -0
- package/dist/esm/performance/performance-logger.d.ts +22 -0
- package/dist/esm/performance/performance-logger.d.ts.map +1 -0
- package/dist/esm/performance/storeTracker.d.ts +10 -0
- package/dist/esm/performance/storeTracker.d.ts.map +1 -0
- package/dist/esm/performance/types.d.ts +79 -0
- package/dist/esm/performance/types.d.ts.map +1 -0
- package/dist/esm/performance/utils.d.ts +24 -0
- package/dist/esm/performance/utils.d.ts.map +1 -0
- package/dist/esm/performance/withPerformanceTracking.d.ts +14 -0
- package/dist/esm/performance/withPerformanceTracking.d.ts.map +1 -0
- package/dist/esm/stores/comp.d.ts +1 -1
- package/dist/esm/stores/comp.d.ts.map +1 -1
- package/dist/esm/stores/data.d.ts +10 -2
- package/dist/esm/stores/data.d.ts.map +1 -1
- package/dist/esm/stores/interaction.d.ts +21 -10
- package/dist/esm/stores/interaction.d.ts.map +1 -1
- package/dist/esm/stores/mode-compare.d.ts +1 -1
- package/dist/esm/stores/mode-compare.d.ts.map +1 -1
- package/dist/esm/stores/mode-live.d.ts +1 -1
- package/dist/esm/stores/mode-live.d.ts.map +1 -1
- package/dist/esm/stores/mode-single.d.ts +12 -2
- package/dist/esm/stores/mode-single.d.ts.map +1 -1
- package/dist/esm/stores/viz-scrollmap.d.ts +19 -8
- package/dist/esm/stores/viz-scrollmap.d.ts.map +1 -1
- package/dist/esm/stores/viz.d.ts +9 -1
- package/dist/esm/stores/viz.d.ts.map +1 -1
- package/dist/esm/types/control.d.ts +9 -1
- package/dist/esm/types/control.d.ts.map +1 -1
- package/dist/esm/types/heatmap-info.d.ts +2 -2
- package/dist/esm/types/heatmap-info.d.ts.map +1 -1
- package/dist/esm/types/index.d.ts +3 -2
- package/dist/esm/types/index.d.ts.map +1 -1
- package/dist/{umd/types/elm-callout.d.ts → esm/types/viz-elm-callout.d.ts} +1 -1
- package/dist/esm/types/viz-elm-callout.d.ts.map +1 -0
- package/dist/esm/types/{viz-element.d.ts → viz-elm.d.ts} +1 -1
- package/dist/esm/types/viz-elm.d.ts.map +1 -0
- package/dist/esm/utils/sort.d.ts +1 -1
- package/dist/esm/utils/sort.d.ts.map +1 -1
- package/dist/style.css +7 -1
- package/dist/umd/components/Layout/ContentMetricBar.d.ts.map +1 -1
- package/dist/umd/components/Layout/ContentVizByMode.d.ts.map +1 -1
- package/dist/umd/components/Layout/HeatmapLayout.d.ts +2 -2
- package/dist/umd/components/Layout/HeatmapLayout.d.ts.map +1 -1
- package/dist/umd/components/Layout/Sidebar/ContentSidebar.d.ts +2 -0
- package/dist/umd/components/Layout/Sidebar/ContentSidebar.d.ts.map +1 -0
- package/dist/umd/components/Layout/Sidebar/PopoverSidebar.d.ts +2 -0
- package/dist/umd/components/Layout/Sidebar/PopoverSidebar.d.ts.map +1 -0
- package/dist/umd/components/Layout/Sidebar/index.d.ts +3 -0
- package/dist/umd/components/Layout/Sidebar/index.d.ts.map +1 -0
- package/dist/umd/components/Layout/WrapperLayout.d.ts.map +1 -1
- package/dist/umd/components/Layout/WrapperPreview.d.ts.map +1 -1
- package/dist/umd/components/VizDom/VizContainer.d.ts.map +1 -1
- package/dist/umd/components/VizDom/VizDomHeatmap.d.ts.map +1 -1
- package/dist/umd/components/VizDom/VizDomRenderer.d.ts.map +1 -1
- package/dist/umd/components/VizDom/WrapperVisual.d.ts.map +1 -1
- package/dist/umd/components/VizElement/DefaultRankBadges.d.ts.map +1 -1
- package/dist/umd/components/VizElement/ElementCallout.d.ts.map +1 -1
- package/dist/umd/components/VizElement/ElementOverlay.d.ts +1 -0
- package/dist/umd/components/VizElement/ElementOverlay.d.ts.map +1 -1
- package/dist/umd/components/VizElement/HeatmapElements.d.ts +0 -1
- package/dist/umd/components/VizElement/HeatmapElements.d.ts.map +1 -1
- 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/HoverZones.d.ts +1 -1
- package/dist/umd/components/VizScrollmap/HoverZones.d.ts.map +1 -1
- package/dist/umd/components/VizScrollmap/ScrollMapMinimap.d.ts +1 -1
- package/dist/umd/components/VizScrollmap/ScrollMapMinimap.d.ts.map +1 -1
- package/dist/umd/components/VizScrollmap/ScrollMapOverlay.d.ts.map +1 -1
- package/dist/umd/components/VizScrollmap/ScrollZoneHoverArea.d.ts +1 -2
- package/dist/umd/components/VizScrollmap/ScrollZoneHoverArea.d.ts.map +1 -1
- package/dist/umd/components/VizScrollmap/ScrollZoneTooltip.d.ts +1 -1
- package/dist/umd/components/VizScrollmap/ScrollZoneTooltip.d.ts.map +1 -1
- package/dist/umd/components/VizScrollmap/VizScrollMap.d.ts.map +1 -1
- package/dist/umd/components/VizScrollmapV2/ScrollmapOverlayV2.d.ts +1 -2
- package/dist/umd/components/VizScrollmapV2/ScrollmapOverlayV2.d.ts.map +1 -1
- package/dist/umd/components/VizScrollmapV2/useScrollmapOverlay.d.ts +1 -1
- package/dist/umd/components/VizScrollmapV2/useScrollmapOverlay.d.ts.map +1 -1
- package/dist/umd/configs/index.d.ts +2 -0
- package/dist/umd/configs/index.d.ts.map +1 -1
- package/dist/umd/configs/viewId.d.ts +21 -0
- package/dist/umd/configs/viewId.d.ts.map +1 -0
- package/dist/umd/configs/z-index.d.ts +8 -0
- package/dist/umd/configs/z-index.d.ts.map +1 -0
- package/dist/umd/constants/index.d.ts +13 -4
- package/dist/umd/constants/index.d.ts.map +1 -1
- package/dist/umd/contexts/CompareViewContext.d.ts +1 -1
- package/dist/umd/contexts/CompareViewContext.d.ts.map +1 -1
- package/dist/umd/helpers/iframe-helper/fixer.d.ts +1 -1
- package/dist/umd/helpers/iframe-helper/fixer.d.ts.map +1 -1
- package/dist/umd/helpers/iframe-helper/init.d.ts +1 -1
- package/dist/umd/helpers/iframe-helper/init.d.ts.map +1 -1
- package/dist/umd/helpers/iframe-helper/style-replacer.d.ts.map +1 -1
- package/dist/umd/helpers/iframe.d.ts +1 -1
- package/dist/umd/helpers/iframe.d.ts.map +1 -1
- package/dist/umd/helpers/index.d.ts +2 -3
- package/dist/umd/helpers/index.d.ts.map +1 -1
- package/dist/umd/helpers/viz-canvas/area-clustering.d.ts +1 -1
- package/dist/umd/helpers/viz-canvas/area-clustering.d.ts.map +1 -1
- package/dist/umd/helpers/viz-canvas/area-overlay-manager-v2.d.ts +2 -2
- package/dist/umd/helpers/viz-canvas/area-overlay-manager-v2.d.ts.map +1 -1
- package/dist/umd/helpers/viz-canvas/area-overlay-manager.d.ts +1 -1
- package/dist/umd/helpers/viz-canvas/area-overlay-manager.d.ts.map +1 -1
- package/dist/umd/helpers/viz-canvas/hierarchical-area-clustering.d.ts +1 -1
- package/dist/umd/helpers/viz-canvas/hierarchical-area-clustering.d.ts.map +1 -1
- package/dist/umd/helpers/viz-elm-callout/constants.d.ts +4 -0
- package/dist/umd/helpers/viz-elm-callout/constants.d.ts.map +1 -0
- package/dist/umd/helpers/viz-elm-callout/dimensions.d.ts +4 -0
- package/dist/umd/helpers/viz-elm-callout/dimensions.d.ts.map +1 -0
- package/dist/umd/helpers/{elm-getter.d.ts → viz-elm-callout/getter.d.ts} +2 -2
- package/dist/umd/helpers/viz-elm-callout/getter.d.ts.map +1 -0
- package/dist/umd/helpers/viz-elm-callout/index.d.ts +3 -0
- package/dist/umd/helpers/viz-elm-callout/index.d.ts.map +1 -0
- package/dist/umd/helpers/viz-elm-callout/position-calculator.d.ts +14 -0
- package/dist/umd/helpers/viz-elm-callout/position-calculator.d.ts.map +1 -0
- package/dist/umd/helpers/viz-elm-callout/position-candidates.d.ts +6 -0
- package/dist/umd/helpers/viz-elm-callout/position-candidates.d.ts.map +1 -0
- package/dist/umd/helpers/viz-elm-callout/position-selector.d.ts +10 -0
- package/dist/umd/helpers/viz-elm-callout/position-selector.d.ts.map +1 -0
- package/dist/umd/helpers/viz-elm-callout/position-validator.d.ts +4 -0
- package/dist/umd/helpers/viz-elm-callout/position-validator.d.ts.map +1 -0
- package/dist/umd/helpers/viz-elm-callout/types.d.ts +17 -0
- package/dist/umd/helpers/viz-elm-callout/types.d.ts.map +1 -0
- package/dist/umd/helpers/{elm-callout.d.ts → viz-elm-callout/viz-elm.d.ts} +4 -3
- package/dist/umd/helpers/viz-elm-callout/viz-elm.d.ts.map +1 -0
- package/dist/umd/helpers/{viz-elements.d.ts → viz-elm.d.ts} +1 -1
- package/dist/umd/helpers/viz-elm.d.ts.map +1 -0
- package/dist/umd/hooks/common/index.d.ts +2 -0
- package/dist/umd/hooks/common/index.d.ts.map +1 -0
- package/dist/umd/hooks/common/useDebounceCallback.d.ts +17 -0
- package/dist/umd/hooks/common/useDebounceCallback.d.ts.map +1 -0
- package/dist/umd/hooks/index.d.ts +3 -5
- package/dist/umd/hooks/index.d.ts.map +1 -1
- package/dist/umd/hooks/register/useRegisterControl.d.ts +1 -1
- package/dist/umd/hooks/register/useRegisterControl.d.ts.map +1 -1
- package/dist/umd/hooks/register/useRegisterData.d.ts +1 -1
- package/dist/umd/hooks/register/useRegisterData.d.ts.map +1 -1
- package/dist/umd/hooks/register/useRegisterHeatmap.d.ts +1 -1
- package/dist/umd/hooks/register/useRegisterHeatmap.d.ts.map +1 -1
- package/dist/umd/hooks/view-context/index.d.ts +7 -0
- package/dist/umd/hooks/view-context/index.d.ts.map +1 -0
- package/dist/umd/hooks/view-context/useHeatmapCopyView.d.ts +33 -0
- package/dist/umd/hooks/view-context/useHeatmapCopyView.d.ts.map +1 -0
- package/dist/umd/hooks/{useHeatmapData.d.ts → view-context/useHeatmapData.d.ts} +1 -1
- package/dist/umd/hooks/view-context/useHeatmapData.d.ts.map +1 -0
- package/dist/umd/hooks/view-context/useHeatmapInteraction.d.ts +16 -0
- package/dist/umd/hooks/view-context/useHeatmapInteraction.d.ts.map +1 -0
- package/dist/{esm/hooks → umd/hooks/view-context}/useHeatmapViz.d.ts +3 -1
- package/dist/umd/hooks/view-context/useHeatmapViz.d.ts.map +1 -0
- package/dist/umd/hooks/view-context/useHeatmapVizScrollmap.d.ts +13 -0
- package/dist/umd/hooks/view-context/useHeatmapVizScrollmap.d.ts.map +1 -0
- package/dist/umd/hooks/{useViewId.d.ts → view-context/useViewId.d.ts} +1 -1
- package/dist/umd/hooks/view-context/useViewId.d.ts.map +1 -0
- package/dist/umd/hooks/viz-area/useAreaHeatmap.d.ts +1 -1
- package/dist/umd/hooks/viz-area/useAreaHeatmap.d.ts.map +1 -1
- package/dist/umd/hooks/viz-area/useAreaHeatmapManager.d.ts.map +1 -1
- package/dist/umd/hooks/viz-canvas/useAreamap.d.ts +1 -1
- package/dist/umd/hooks/viz-canvas/useAreamap.d.ts.map +1 -1
- package/dist/umd/hooks/viz-canvas/useClickmap.d.ts.map +1 -1
- package/dist/umd/hooks/viz-canvas/useHeatmapCanvas.d.ts +1 -3
- package/dist/umd/hooks/viz-canvas/useHeatmapCanvas.d.ts.map +1 -1
- package/dist/umd/hooks/viz-canvas/useScrollmap.d.ts.map +1 -1
- package/dist/umd/hooks/viz-elm/index.d.ts.map +1 -0
- package/dist/umd/hooks/{viz-elements → viz-elm}/useClickedElement.d.ts +0 -1
- package/dist/umd/hooks/viz-elm/useClickedElement.d.ts.map +1 -0
- package/dist/umd/hooks/viz-elm/useElementCalloutVisible.d.ts.map +1 -0
- package/dist/umd/hooks/viz-elm/useHeatmapEffects.d.ts +4 -0
- package/dist/umd/hooks/viz-elm/useHeatmapEffects.d.ts.map +1 -0
- package/dist/umd/hooks/viz-elm/useHeatmapElementPosition.d.ts.map +1 -0
- package/dist/{esm/hooks/viz-elements → umd/hooks/viz-elm}/useHeatmapMouseHandler.d.ts +1 -1
- package/dist/umd/hooks/{viz-elements → viz-elm}/useHeatmapMouseHandler.d.ts.map +1 -1
- package/dist/umd/hooks/viz-elm/useHoveredElement.d.ts.map +1 -0
- package/dist/umd/hooks/viz-live/useVizLiveRender.d.ts.map +1 -1
- package/dist/umd/hooks/viz-render/useHeatmapRender.d.ts.map +1 -1
- package/dist/umd/hooks/viz-render/useReplayRender.d.ts.map +1 -1
- package/dist/umd/hooks/viz-scale/useHeatmapScale.d.ts +0 -1
- package/dist/umd/hooks/viz-scale/useHeatmapScale.d.ts.map +1 -1
- package/dist/umd/hooks/viz-scale/useObserveIframeHeight.d.ts +0 -1
- package/dist/umd/hooks/viz-scale/useObserveIframeHeight.d.ts.map +1 -1
- package/dist/umd/hooks/viz-scale/useWrapperRefHeight.d.ts.map +1 -1
- package/dist/umd/hooks/viz-scrollmap/useScrollmapZones.d.ts +1 -1
- package/dist/umd/hooks/viz-scrollmap/useScrollmapZones.d.ts.map +1 -1
- package/dist/umd/hooks/viz-scrollmap/useZonePositions.d.ts +2 -2
- package/dist/umd/hooks/viz-scrollmap/useZonePositions.d.ts.map +1 -1
- package/dist/umd/index.d.ts +3 -2
- package/dist/umd/index.d.ts.map +1 -1
- package/dist/umd/index.js +2 -2
- package/dist/umd/performance/hooks.d.ts +28 -0
- package/dist/umd/performance/hooks.d.ts.map +1 -0
- package/dist/umd/performance/index.d.ts +7 -0
- package/dist/umd/performance/index.d.ts.map +1 -0
- package/dist/umd/performance/performance-logger.d.ts +22 -0
- package/dist/umd/performance/performance-logger.d.ts.map +1 -0
- package/dist/umd/performance/storeTracker.d.ts +10 -0
- package/dist/umd/performance/storeTracker.d.ts.map +1 -0
- package/dist/umd/performance/types.d.ts +79 -0
- package/dist/umd/performance/types.d.ts.map +1 -0
- package/dist/umd/performance/utils.d.ts +24 -0
- package/dist/umd/performance/utils.d.ts.map +1 -0
- package/dist/umd/performance/withPerformanceTracking.d.ts +14 -0
- package/dist/umd/performance/withPerformanceTracking.d.ts.map +1 -0
- package/dist/umd/stores/comp.d.ts +1 -1
- package/dist/umd/stores/comp.d.ts.map +1 -1
- package/dist/umd/stores/data.d.ts +10 -2
- package/dist/umd/stores/data.d.ts.map +1 -1
- package/dist/umd/stores/interaction.d.ts +21 -10
- package/dist/umd/stores/interaction.d.ts.map +1 -1
- package/dist/umd/stores/mode-compare.d.ts +1 -1
- package/dist/umd/stores/mode-compare.d.ts.map +1 -1
- package/dist/umd/stores/mode-live.d.ts +1 -1
- package/dist/umd/stores/mode-live.d.ts.map +1 -1
- package/dist/umd/stores/mode-single.d.ts +12 -2
- package/dist/umd/stores/mode-single.d.ts.map +1 -1
- package/dist/umd/stores/viz-scrollmap.d.ts +19 -8
- package/dist/umd/stores/viz-scrollmap.d.ts.map +1 -1
- package/dist/umd/stores/viz.d.ts +9 -1
- package/dist/umd/stores/viz.d.ts.map +1 -1
- package/dist/umd/types/control.d.ts +9 -1
- package/dist/umd/types/control.d.ts.map +1 -1
- package/dist/umd/types/heatmap-info.d.ts +2 -2
- package/dist/umd/types/heatmap-info.d.ts.map +1 -1
- package/dist/umd/types/index.d.ts +3 -2
- package/dist/umd/types/index.d.ts.map +1 -1
- package/dist/{esm/types/elm-callout.d.ts → umd/types/viz-elm-callout.d.ts} +1 -1
- package/dist/umd/types/viz-elm-callout.d.ts.map +1 -0
- package/dist/umd/types/{viz-element.d.ts → viz-elm.d.ts} +1 -1
- package/dist/umd/types/viz-elm.d.ts.map +1 -0
- package/dist/umd/utils/sort.d.ts +1 -1
- package/dist/umd/utils/sort.d.ts.map +1 -1
- package/package.json +4 -1
- package/dist/esm/components/Layout/LeftSidebar.d.ts +0 -2
- package/dist/esm/components/Layout/LeftSidebar.d.ts.map +0 -1
- package/dist/esm/components/VizElement/HeatmapExample.d.ts +0 -2
- package/dist/esm/components/VizElement/HeatmapExample.d.ts.map +0 -1
- package/dist/esm/helpers/elm-callout.d.ts.map +0 -1
- package/dist/esm/helpers/elm-getter.d.ts.map +0 -1
- package/dist/esm/helpers/viz-elements.d.ts.map +0 -1
- package/dist/esm/hooks/compare/index.d.ts +0 -4
- package/dist/esm/hooks/compare/index.d.ts.map +0 -1
- package/dist/esm/hooks/compare/useCompareAwareConfig.d.ts +0 -21
- package/dist/esm/hooks/compare/useCompareAwareConfig.d.ts.map +0 -1
- package/dist/esm/hooks/compare/useCompareAwareData.d.ts +0 -28
- package/dist/esm/hooks/compare/useCompareAwareData.d.ts.map +0 -1
- package/dist/esm/hooks/compare/useCompareAwareViz.d.ts +0 -34
- package/dist/esm/hooks/compare/useCompareAwareViz.d.ts.map +0 -1
- package/dist/esm/hooks/useHeatmapData.d.ts.map +0 -1
- package/dist/esm/hooks/useHeatmapViz.d.ts.map +0 -1
- package/dist/esm/hooks/useViewId.d.ts.map +0 -1
- package/dist/esm/hooks/viz-elements/index.d.ts.map +0 -1
- package/dist/esm/hooks/viz-elements/useClickedElement.d.ts.map +0 -1
- package/dist/esm/hooks/viz-elements/useElementCalloutVisible.d.ts.map +0 -1
- package/dist/esm/hooks/viz-elements/useHeatmapEffects.d.ts +0 -7
- package/dist/esm/hooks/viz-elements/useHeatmapEffects.d.ts.map +0 -1
- package/dist/esm/hooks/viz-elements/useHeatmapElementPosition.d.ts.map +0 -1
- package/dist/esm/hooks/viz-elements/useHoveredElement.d.ts.map +0 -1
- package/dist/esm/types/elm-callout.d.ts.map +0 -1
- package/dist/esm/types/viz-element.d.ts.map +0 -1
- package/dist/umd/components/Layout/LeftSidebar.d.ts +0 -2
- package/dist/umd/components/Layout/LeftSidebar.d.ts.map +0 -1
- package/dist/umd/components/VizElement/HeatmapExample.d.ts +0 -2
- package/dist/umd/components/VizElement/HeatmapExample.d.ts.map +0 -1
- package/dist/umd/helpers/elm-callout.d.ts.map +0 -1
- package/dist/umd/helpers/elm-getter.d.ts.map +0 -1
- package/dist/umd/helpers/viz-elements.d.ts.map +0 -1
- package/dist/umd/hooks/compare/index.d.ts +0 -4
- package/dist/umd/hooks/compare/index.d.ts.map +0 -1
- package/dist/umd/hooks/compare/useCompareAwareConfig.d.ts +0 -21
- package/dist/umd/hooks/compare/useCompareAwareConfig.d.ts.map +0 -1
- package/dist/umd/hooks/compare/useCompareAwareData.d.ts +0 -28
- package/dist/umd/hooks/compare/useCompareAwareData.d.ts.map +0 -1
- package/dist/umd/hooks/compare/useCompareAwareViz.d.ts +0 -34
- package/dist/umd/hooks/compare/useCompareAwareViz.d.ts.map +0 -1
- package/dist/umd/hooks/useHeatmapData.d.ts.map +0 -1
- package/dist/umd/hooks/useHeatmapViz.d.ts.map +0 -1
- package/dist/umd/hooks/useViewId.d.ts.map +0 -1
- package/dist/umd/hooks/viz-elements/index.d.ts.map +0 -1
- package/dist/umd/hooks/viz-elements/useClickedElement.d.ts.map +0 -1
- package/dist/umd/hooks/viz-elements/useElementCalloutVisible.d.ts.map +0 -1
- package/dist/umd/hooks/viz-elements/useHeatmapEffects.d.ts +0 -7
- package/dist/umd/hooks/viz-elements/useHeatmapEffects.d.ts.map +0 -1
- package/dist/umd/hooks/viz-elements/useHeatmapElementPosition.d.ts.map +0 -1
- package/dist/umd/hooks/viz-elements/useHoveredElement.d.ts.map +0 -1
- package/dist/umd/types/elm-callout.d.ts.map +0 -1
- package/dist/umd/types/viz-element.d.ts.map +0 -1
- /package/dist/esm/hooks/{viz-elements → viz-elm}/index.d.ts +0 -0
- /package/dist/esm/hooks/{viz-elements → viz-elm}/useElementCalloutVisible.d.ts +0 -0
- /package/dist/esm/hooks/{viz-elements → viz-elm}/useHeatmapElementPosition.d.ts +0 -0
- /package/dist/esm/hooks/{viz-elements → viz-elm}/useHoveredElement.d.ts +0 -0
- /package/dist/umd/hooks/{viz-elements → viz-elm}/index.d.ts +0 -0
- /package/dist/umd/hooks/{viz-elements → viz-elm}/useElementCalloutVisible.d.ts +0 -0
- /package/dist/umd/hooks/{viz-elements → viz-elm}/useHeatmapElementPosition.d.ts +0 -0
- /package/dist/umd/hooks/{viz-elements → viz-elm}/useHoveredElement.d.ts +0 -0
package/dist/esm/index.mjs
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
3
3
|
import { useNodesState, ReactFlow, Controls, Background } from '@xyflow/react';
|
|
4
|
-
import { useEffect,
|
|
4
|
+
import { useEffect, useRef, useCallback, createContext, useContext, useMemo, useState, forwardRef, Fragment as Fragment$1 } from 'react';
|
|
5
5
|
import { create } from 'zustand';
|
|
6
|
+
import { subscribeWithSelector } from 'zustand/middleware';
|
|
6
7
|
import { decode } from '@gemx-dev/clarity-decode';
|
|
7
8
|
import { Visualizer } from '@gemx-dev/clarity-visualize';
|
|
8
9
|
import { createPortal } from 'react-dom';
|
|
@@ -67,10 +68,75 @@ const HEATMAP_STYLE = {
|
|
|
67
68
|
};
|
|
68
69
|
const DEFAULT_SIDEBAR_WIDTH = 260;
|
|
69
70
|
|
|
71
|
+
/**
|
|
72
|
+
* Default view ID for single mode
|
|
73
|
+
*/
|
|
74
|
+
const DEFAULT_VIEW_ID = 'default';
|
|
75
|
+
/**
|
|
76
|
+
* Generate compare view ID
|
|
77
|
+
* @param index - Zero-based index (0, 1, 2, 3)
|
|
78
|
+
* @returns View ID string like 'view-0', 'view-1', etc.
|
|
79
|
+
*/
|
|
80
|
+
const getCompareViewId = (index) => `view-${index}`;
|
|
81
|
+
/**
|
|
82
|
+
* Check if a view ID is a compare view
|
|
83
|
+
*/
|
|
84
|
+
const isCompareViewId = (viewId) => viewId.startsWith('view-');
|
|
85
|
+
/**
|
|
86
|
+
* Extract index from compare view ID
|
|
87
|
+
* @param viewId - View ID like 'view-0'
|
|
88
|
+
* @returns Index number or -1 if invalid
|
|
89
|
+
*/
|
|
90
|
+
const getCompareViewIndex = (viewId) => {
|
|
91
|
+
if (!isCompareViewId(viewId))
|
|
92
|
+
return -1;
|
|
93
|
+
const match = viewId.match(/^view-(\d+)$/);
|
|
94
|
+
return match ? parseInt(match[1], 10) : -1;
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const Z_INDEX = {
|
|
98
|
+
ELEMENTS: 1000,
|
|
99
|
+
CALLOUT: 2000,
|
|
100
|
+
MINIMAP: 3000,
|
|
101
|
+
SIDEBAR: 4000,
|
|
102
|
+
SIDEBAR_POPOVER: 4001,
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Creates a debounced version of a callback that delays invoking until after
|
|
107
|
+
* wait milliseconds have elapsed since the last time it was invoked.
|
|
108
|
+
*
|
|
109
|
+
* @param callback - The function to debounce
|
|
110
|
+
* @param delay - The number of milliseconds to delay
|
|
111
|
+
* @returns A debounced version of the callback
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* ```tsx
|
|
115
|
+
* const handleSearch = useDebounceCallback((query: string) => {
|
|
116
|
+
* searchAPI(query);
|
|
117
|
+
* }, 300);
|
|
118
|
+
* ```
|
|
119
|
+
*/
|
|
120
|
+
function useDebounceCallback(callback, delay) {
|
|
121
|
+
const timeoutRef = useRef();
|
|
122
|
+
const callbackRef = useRef(callback);
|
|
123
|
+
// Update callback ref when callback changes
|
|
124
|
+
callbackRef.current = callback;
|
|
125
|
+
return useCallback((...args) => {
|
|
126
|
+
if (timeoutRef.current) {
|
|
127
|
+
clearTimeout(timeoutRef.current);
|
|
128
|
+
}
|
|
129
|
+
timeoutRef.current = setTimeout(() => {
|
|
130
|
+
callbackRef.current(...args);
|
|
131
|
+
}, delay);
|
|
132
|
+
}, [delay]);
|
|
133
|
+
}
|
|
134
|
+
|
|
70
135
|
const useHeatmapControlStore = create()((set, get) => {
|
|
71
136
|
return {
|
|
72
137
|
controls: {
|
|
73
|
-
Sidebar:
|
|
138
|
+
Sidebar: undefined,
|
|
139
|
+
SidebarActivator: undefined,
|
|
74
140
|
Toolbar: null,
|
|
75
141
|
MetricBar: null,
|
|
76
142
|
VizLoading: null,
|
|
@@ -109,12 +175,12 @@ var IScrollType;
|
|
|
109
175
|
IScrollType["Revenue"] = "revenue-scroll";
|
|
110
176
|
})(IScrollType || (IScrollType = {}));
|
|
111
177
|
|
|
112
|
-
const useHeatmapConfigStore = create()((set
|
|
178
|
+
const useHeatmapConfigStore = create()((set) => {
|
|
113
179
|
return {
|
|
114
180
|
mode: 'single',
|
|
115
181
|
width: 1440,
|
|
116
182
|
sidebarWidth: DEFAULT_SIDEBAR_WIDTH,
|
|
117
|
-
heatmapType: IHeatmapType.
|
|
183
|
+
heatmapType: IHeatmapType.Click,
|
|
118
184
|
clickType: IClickType.Total,
|
|
119
185
|
scrollType: IScrollType.Depth,
|
|
120
186
|
isRendering: true,
|
|
@@ -129,23 +195,22 @@ const useHeatmapConfigStore = create()((set, get) => {
|
|
|
129
195
|
};
|
|
130
196
|
});
|
|
131
197
|
|
|
132
|
-
const
|
|
133
|
-
const useHeatmapDataStore = create()((set, get) => {
|
|
198
|
+
const useHeatmapDataStore = create()(subscribeWithSelector((set) => {
|
|
134
199
|
return {
|
|
135
|
-
data: { [DEFAULT_VIEW_ID
|
|
136
|
-
clickmap: { [DEFAULT_VIEW_ID
|
|
137
|
-
dataInfo: { [DEFAULT_VIEW_ID
|
|
138
|
-
scrollmap: { [DEFAULT_VIEW_ID
|
|
139
|
-
setDataInfo: (dataInfo, viewId = DEFAULT_VIEW_ID
|
|
200
|
+
data: { [DEFAULT_VIEW_ID]: undefined },
|
|
201
|
+
clickmap: { [DEFAULT_VIEW_ID]: undefined },
|
|
202
|
+
dataInfo: { [DEFAULT_VIEW_ID]: undefined },
|
|
203
|
+
scrollmap: { [DEFAULT_VIEW_ID]: undefined },
|
|
204
|
+
setDataInfo: (dataInfo, viewId = DEFAULT_VIEW_ID) => set((state) => ({
|
|
140
205
|
dataInfo: { ...state.dataInfo, [viewId]: dataInfo },
|
|
141
206
|
})),
|
|
142
|
-
setData: (data, viewId = DEFAULT_VIEW_ID
|
|
207
|
+
setData: (data, viewId = DEFAULT_VIEW_ID) => set((state) => ({
|
|
143
208
|
data: { ...state.data, [viewId]: data },
|
|
144
209
|
})),
|
|
145
|
-
setClickmap: (clickmap, viewId = DEFAULT_VIEW_ID
|
|
210
|
+
setClickmap: (clickmap, viewId = DEFAULT_VIEW_ID) => set((state) => ({
|
|
146
211
|
clickmap: { ...state.clickmap, [viewId]: clickmap },
|
|
147
212
|
})),
|
|
148
|
-
setScrollmap: (scrollmap, viewId = DEFAULT_VIEW_ID
|
|
213
|
+
setScrollmap: (scrollmap, viewId = DEFAULT_VIEW_ID) => set((state) => ({
|
|
149
214
|
scrollmap: { ...state.scrollmap, [viewId]: scrollmap },
|
|
150
215
|
})),
|
|
151
216
|
copyView: (fromViewId, toViewId) => set((state) => ({
|
|
@@ -171,50 +236,98 @@ const useHeatmapDataStore = create()((set, get) => {
|
|
|
171
236
|
};
|
|
172
237
|
}),
|
|
173
238
|
resetAll: () => set({
|
|
174
|
-
data: { [DEFAULT_VIEW_ID
|
|
175
|
-
clickmap: { [DEFAULT_VIEW_ID
|
|
176
|
-
dataInfo: { [DEFAULT_VIEW_ID
|
|
177
|
-
scrollmap: { [DEFAULT_VIEW_ID
|
|
239
|
+
data: { [DEFAULT_VIEW_ID]: undefined },
|
|
240
|
+
clickmap: { [DEFAULT_VIEW_ID]: undefined },
|
|
241
|
+
dataInfo: { [DEFAULT_VIEW_ID]: undefined },
|
|
242
|
+
scrollmap: { [DEFAULT_VIEW_ID]: undefined },
|
|
178
243
|
}),
|
|
179
244
|
};
|
|
180
|
-
});
|
|
245
|
+
}));
|
|
181
246
|
|
|
182
|
-
const
|
|
247
|
+
const DEFAULT_STATE = {
|
|
248
|
+
hideSidebar: false,
|
|
249
|
+
};
|
|
250
|
+
const useHeatmapInteractionStore = create()(subscribeWithSelector((set) => {
|
|
183
251
|
return {
|
|
184
|
-
state: {
|
|
185
|
-
|
|
186
|
-
},
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
252
|
+
state: { [DEFAULT_VIEW_ID]: DEFAULT_STATE },
|
|
253
|
+
selectedElement: { [DEFAULT_VIEW_ID]: null },
|
|
254
|
+
hoveredElement: { [DEFAULT_VIEW_ID]: null },
|
|
255
|
+
shouldShowCallout: { [DEFAULT_VIEW_ID]: false },
|
|
256
|
+
setState: (state, viewId = DEFAULT_VIEW_ID) => set((prev) => ({
|
|
257
|
+
state: { ...prev.state, [viewId]: state },
|
|
258
|
+
})),
|
|
259
|
+
setSelectedElement: (selectedElement, viewId = DEFAULT_VIEW_ID) => set((prev) => ({
|
|
260
|
+
selectedElement: { ...prev.selectedElement, [viewId]: selectedElement },
|
|
261
|
+
})),
|
|
262
|
+
setHoveredElement: (hoveredElement, viewId = DEFAULT_VIEW_ID) => set((prev) => ({
|
|
263
|
+
hoveredElement: { ...prev.hoveredElement, [viewId]: hoveredElement },
|
|
264
|
+
})),
|
|
265
|
+
setShouldShowCallout: (shouldShowCallout, viewId = DEFAULT_VIEW_ID) => set((prev) => ({
|
|
266
|
+
shouldShowCallout: { ...prev.shouldShowCallout, [viewId]: shouldShowCallout },
|
|
267
|
+
})),
|
|
268
|
+
copyView: (fromViewId, toViewId) => set((state) => ({
|
|
269
|
+
state: {
|
|
270
|
+
...state.state,
|
|
271
|
+
[toViewId]: state.state[fromViewId] ?? DEFAULT_STATE,
|
|
272
|
+
},
|
|
273
|
+
selectedElement: {
|
|
274
|
+
...state.selectedElement,
|
|
275
|
+
[toViewId]: state.selectedElement[fromViewId] ?? null,
|
|
276
|
+
},
|
|
277
|
+
hoveredElement: {
|
|
278
|
+
...state.hoveredElement,
|
|
279
|
+
[toViewId]: state.hoveredElement[fromViewId] ?? null,
|
|
280
|
+
},
|
|
281
|
+
shouldShowCallout: {
|
|
282
|
+
...state.shouldShowCallout,
|
|
283
|
+
[toViewId]: state.shouldShowCallout[fromViewId] ?? false,
|
|
284
|
+
},
|
|
285
|
+
})),
|
|
286
|
+
clearView: (viewId) => set((state) => {
|
|
287
|
+
const newState = { ...state.state };
|
|
288
|
+
const newSelectedElement = { ...state.selectedElement };
|
|
289
|
+
const newHoveredElement = { ...state.hoveredElement };
|
|
290
|
+
const newShouldShowCallout = { ...state.shouldShowCallout };
|
|
291
|
+
delete newState[viewId];
|
|
292
|
+
delete newSelectedElement[viewId];
|
|
293
|
+
delete newHoveredElement[viewId];
|
|
294
|
+
delete newShouldShowCallout[viewId];
|
|
295
|
+
return {
|
|
296
|
+
state: newState,
|
|
297
|
+
selectedElement: newSelectedElement,
|
|
298
|
+
hoveredElement: newHoveredElement,
|
|
299
|
+
shouldShowCallout: newShouldShowCallout,
|
|
300
|
+
};
|
|
301
|
+
}),
|
|
302
|
+
resetAll: () => set({
|
|
303
|
+
state: { default: DEFAULT_STATE },
|
|
304
|
+
selectedElement: { default: null },
|
|
305
|
+
hoveredElement: { default: null },
|
|
306
|
+
shouldShowCallout: { default: false },
|
|
307
|
+
}),
|
|
194
308
|
};
|
|
195
|
-
});
|
|
309
|
+
}));
|
|
196
310
|
|
|
197
|
-
const
|
|
198
|
-
const useHeatmapVizStore = create()((set, get) => {
|
|
311
|
+
const useHeatmapVizStore = create()(subscribeWithSelector((set) => {
|
|
199
312
|
return {
|
|
200
|
-
isRenderViz: { [DEFAULT_VIEW_ID
|
|
201
|
-
zoomRatio: { [DEFAULT_VIEW_ID
|
|
202
|
-
minZoomRatio: { [DEFAULT_VIEW_ID
|
|
203
|
-
scale: { [DEFAULT_VIEW_ID
|
|
204
|
-
isScaledToFit: { [DEFAULT_VIEW_ID
|
|
205
|
-
setIsRenderViz: (isRenderViz, viewId = DEFAULT_VIEW_ID
|
|
313
|
+
isRenderViz: { [DEFAULT_VIEW_ID]: false },
|
|
314
|
+
zoomRatio: { [DEFAULT_VIEW_ID]: 100 },
|
|
315
|
+
minZoomRatio: { [DEFAULT_VIEW_ID]: 10 },
|
|
316
|
+
scale: { [DEFAULT_VIEW_ID]: 1 },
|
|
317
|
+
isScaledToFit: { [DEFAULT_VIEW_ID]: false },
|
|
318
|
+
setIsRenderViz: (isRenderViz, viewId = DEFAULT_VIEW_ID) => set((state) => ({
|
|
206
319
|
isRenderViz: { ...state.isRenderViz, [viewId]: isRenderViz },
|
|
207
320
|
})),
|
|
208
|
-
setZoomRatio: (zoomRatio, viewId = DEFAULT_VIEW_ID
|
|
321
|
+
setZoomRatio: (zoomRatio, viewId = DEFAULT_VIEW_ID) => set((state) => ({
|
|
209
322
|
zoomRatio: { ...state.zoomRatio, [viewId]: zoomRatio },
|
|
210
323
|
})),
|
|
211
|
-
setMinZoomRatio: (minZoomRatio, viewId = DEFAULT_VIEW_ID
|
|
324
|
+
setMinZoomRatio: (minZoomRatio, viewId = DEFAULT_VIEW_ID) => set((state) => ({
|
|
212
325
|
minZoomRatio: { ...state.minZoomRatio, [viewId]: minZoomRatio },
|
|
213
326
|
})),
|
|
214
|
-
setScale: (scale, viewId = DEFAULT_VIEW_ID
|
|
327
|
+
setScale: (scale, viewId = DEFAULT_VIEW_ID) => set((state) => ({
|
|
215
328
|
scale: { ...state.scale, [viewId]: scale },
|
|
216
329
|
})),
|
|
217
|
-
setIsScaledToFit: (isScaledToFit, viewId = DEFAULT_VIEW_ID
|
|
330
|
+
setIsScaledToFit: (isScaledToFit, viewId = DEFAULT_VIEW_ID) => set((state) => ({
|
|
218
331
|
isScaledToFit: { ...state.isScaledToFit, [viewId]: isScaledToFit },
|
|
219
332
|
})),
|
|
220
333
|
copyView: (fromViewId, toViewId) => set((state) => ({
|
|
@@ -222,7 +335,10 @@ const useHeatmapVizStore = create()((set, get) => {
|
|
|
222
335
|
zoomRatio: { ...state.zoomRatio, [toViewId]: state.zoomRatio[fromViewId] ?? 100 },
|
|
223
336
|
minZoomRatio: { ...state.minZoomRatio, [toViewId]: state.minZoomRatio[fromViewId] ?? 10 },
|
|
224
337
|
scale: { ...state.scale, [toViewId]: state.scale[fromViewId] ?? 1 },
|
|
225
|
-
isScaledToFit: {
|
|
338
|
+
isScaledToFit: {
|
|
339
|
+
...state.isScaledToFit,
|
|
340
|
+
[toViewId]: state.isScaledToFit[fromViewId] ?? false,
|
|
341
|
+
},
|
|
226
342
|
})),
|
|
227
343
|
clearView: (viewId) => set((state) => {
|
|
228
344
|
const newIsRenderViz = { ...state.isRenderViz };
|
|
@@ -244,31 +360,69 @@ const useHeatmapVizStore = create()((set, get) => {
|
|
|
244
360
|
};
|
|
245
361
|
}),
|
|
246
362
|
resetAll: () => set({
|
|
247
|
-
isRenderViz: { [DEFAULT_VIEW_ID
|
|
248
|
-
zoomRatio: { [DEFAULT_VIEW_ID
|
|
249
|
-
minZoomRatio: { [DEFAULT_VIEW_ID
|
|
250
|
-
scale: { [DEFAULT_VIEW_ID
|
|
251
|
-
isScaledToFit: { [DEFAULT_VIEW_ID
|
|
363
|
+
isRenderViz: { [DEFAULT_VIEW_ID]: false },
|
|
364
|
+
zoomRatio: { [DEFAULT_VIEW_ID]: 100 },
|
|
365
|
+
minZoomRatio: { [DEFAULT_VIEW_ID]: 10 },
|
|
366
|
+
scale: { [DEFAULT_VIEW_ID]: 1 },
|
|
367
|
+
isScaledToFit: { [DEFAULT_VIEW_ID]: false },
|
|
252
368
|
}),
|
|
253
369
|
};
|
|
254
|
-
});
|
|
370
|
+
}));
|
|
255
371
|
|
|
256
|
-
const useHeatmapVizScrollmapStore = create()((set
|
|
372
|
+
const useHeatmapVizScrollmapStore = create()(subscribeWithSelector((set) => {
|
|
257
373
|
return {
|
|
258
|
-
zones: [],
|
|
259
|
-
hoveredZone: null,
|
|
260
|
-
showMinimap: true,
|
|
261
|
-
setZones: (zones) => set(
|
|
262
|
-
|
|
263
|
-
|
|
374
|
+
zones: { [DEFAULT_VIEW_ID]: [] },
|
|
375
|
+
hoveredZone: { [DEFAULT_VIEW_ID]: null },
|
|
376
|
+
showMinimap: { [DEFAULT_VIEW_ID]: true },
|
|
377
|
+
setZones: (zones, viewId = DEFAULT_VIEW_ID) => set((prev) => ({
|
|
378
|
+
zones: { ...prev.zones, [viewId]: zones },
|
|
379
|
+
})),
|
|
380
|
+
setHoveredZone: (hoveredZone, viewId = DEFAULT_VIEW_ID) => set((prev) => ({
|
|
381
|
+
hoveredZone: { ...prev.hoveredZone, [viewId]: hoveredZone },
|
|
382
|
+
})),
|
|
383
|
+
setShowMinimap: (showMinimap, viewId = DEFAULT_VIEW_ID) => set((prev) => ({
|
|
384
|
+
showMinimap: { ...prev.showMinimap, [viewId]: showMinimap },
|
|
385
|
+
})),
|
|
386
|
+
copyView: (fromViewId, toViewId) => set((state) => ({
|
|
387
|
+
zones: {
|
|
388
|
+
...state.zones,
|
|
389
|
+
[toViewId]: state.zones[fromViewId] ?? [],
|
|
390
|
+
},
|
|
391
|
+
hoveredZone: {
|
|
392
|
+
...state.hoveredZone,
|
|
393
|
+
[toViewId]: state.hoveredZone[fromViewId] ?? null,
|
|
394
|
+
},
|
|
395
|
+
showMinimap: {
|
|
396
|
+
...state.showMinimap,
|
|
397
|
+
[toViewId]: state.showMinimap[fromViewId] ?? true,
|
|
398
|
+
},
|
|
399
|
+
})),
|
|
400
|
+
clearView: (viewId) => set((state) => {
|
|
401
|
+
const newZones = { ...state.zones };
|
|
402
|
+
const newHoveredZone = { ...state.hoveredZone };
|
|
403
|
+
const newShowMinimap = { ...state.showMinimap };
|
|
404
|
+
delete newZones[viewId];
|
|
405
|
+
delete newHoveredZone[viewId];
|
|
406
|
+
delete newShowMinimap[viewId];
|
|
407
|
+
return {
|
|
408
|
+
zones: newZones,
|
|
409
|
+
hoveredZone: newHoveredZone,
|
|
410
|
+
showMinimap: newShowMinimap,
|
|
411
|
+
};
|
|
412
|
+
}),
|
|
413
|
+
resetAll: () => set({
|
|
414
|
+
zones: { default: [] },
|
|
415
|
+
hoveredZone: { default: null },
|
|
416
|
+
showMinimap: { default: true },
|
|
417
|
+
}),
|
|
264
418
|
};
|
|
265
|
-
});
|
|
419
|
+
}));
|
|
266
420
|
|
|
267
421
|
const initialState = {
|
|
268
422
|
payloads: [],
|
|
269
423
|
htmlContent: '',
|
|
270
424
|
};
|
|
271
|
-
const useHeatmapLiveStore = create()((set
|
|
425
|
+
const useHeatmapLiveStore = create()((set) => {
|
|
272
426
|
return {
|
|
273
427
|
...initialState,
|
|
274
428
|
reset: () => set(initialState),
|
|
@@ -278,12 +432,12 @@ const useHeatmapLiveStore = create()((set, get) => {
|
|
|
278
432
|
};
|
|
279
433
|
});
|
|
280
434
|
|
|
281
|
-
const
|
|
282
|
-
const useHeatmapSingleStore = create()((set, get) => {
|
|
435
|
+
const useHeatmapSingleStore = create()(subscribeWithSelector((set) => {
|
|
283
436
|
return {
|
|
284
437
|
vizRef: { [DEFAULT_VIEW_ID]: null },
|
|
285
438
|
iframeHeight: { [DEFAULT_VIEW_ID]: 0 },
|
|
286
439
|
wrapperHeight: { [DEFAULT_VIEW_ID]: 0 },
|
|
440
|
+
wrapperWidth: { [DEFAULT_VIEW_ID]: 0 },
|
|
287
441
|
setVizRef: (vizRef, viewId = DEFAULT_VIEW_ID) => set((state) => ({
|
|
288
442
|
vizRef: { ...state.vizRef, [viewId]: vizRef },
|
|
289
443
|
})),
|
|
@@ -297,31 +451,43 @@ const useHeatmapSingleStore = create()((set, get) => {
|
|
|
297
451
|
wrapperHeight: { ...state.wrapperHeight, [viewId]: wrapperHeight },
|
|
298
452
|
}));
|
|
299
453
|
},
|
|
454
|
+
setWrapperWidth: (wrapperWidth, viewId = DEFAULT_VIEW_ID) => {
|
|
455
|
+
set((state) => ({
|
|
456
|
+
wrapperWidth: { ...state.wrapperWidth, [viewId]: wrapperWidth },
|
|
457
|
+
}));
|
|
458
|
+
},
|
|
300
459
|
copyView: (fromViewId, toViewId) => set((state) => ({
|
|
301
460
|
// Don't copy vizRef - each view needs its own visualizer instance
|
|
302
461
|
iframeHeight: { ...state.iframeHeight, [toViewId]: state.iframeHeight[fromViewId] ?? 0 },
|
|
303
|
-
wrapperHeight: {
|
|
462
|
+
wrapperHeight: {
|
|
463
|
+
...state.wrapperHeight,
|
|
464
|
+
[toViewId]: state.wrapperHeight[fromViewId] ?? 0,
|
|
465
|
+
},
|
|
304
466
|
})),
|
|
305
467
|
clearView: (viewId) => set((state) => {
|
|
306
468
|
const newVizRef = { ...state.vizRef };
|
|
307
469
|
const newIframeHeight = { ...state.iframeHeight };
|
|
308
470
|
const newWrapperHeight = { ...state.wrapperHeight };
|
|
471
|
+
const newWrapperWidth = { ...state.wrapperWidth };
|
|
309
472
|
delete newVizRef[viewId];
|
|
310
473
|
delete newIframeHeight[viewId];
|
|
311
474
|
delete newWrapperHeight[viewId];
|
|
475
|
+
delete newWrapperWidth[viewId];
|
|
312
476
|
return {
|
|
313
477
|
vizRef: newVizRef,
|
|
314
478
|
iframeHeight: newIframeHeight,
|
|
315
479
|
wrapperHeight: newWrapperHeight,
|
|
480
|
+
wrapperWidth: newWrapperWidth,
|
|
316
481
|
};
|
|
317
482
|
}),
|
|
318
483
|
resetAll: () => set({
|
|
319
484
|
vizRef: { [DEFAULT_VIEW_ID]: null },
|
|
320
485
|
iframeHeight: { [DEFAULT_VIEW_ID]: 0 },
|
|
321
486
|
wrapperHeight: { [DEFAULT_VIEW_ID]: 0 },
|
|
487
|
+
wrapperWidth: { [DEFAULT_VIEW_ID]: 0 },
|
|
322
488
|
}),
|
|
323
489
|
};
|
|
324
|
-
});
|
|
490
|
+
}));
|
|
325
491
|
|
|
326
492
|
const createDefaultView = (id, label, options) => ({
|
|
327
493
|
id,
|
|
@@ -468,6 +634,7 @@ const useRegisterConfig = () => {
|
|
|
468
634
|
const useRegisterControl = (control) => {
|
|
469
635
|
const registerControl = useHeatmapControlStore((state) => state.registerControl);
|
|
470
636
|
registerControl('Sidebar', control.Sidebar);
|
|
637
|
+
registerControl('SidebarActivator', control.SidebarActivator);
|
|
471
638
|
registerControl('TopBar', control.TopBar);
|
|
472
639
|
registerControl('Toolbar', control.Toolbar);
|
|
473
640
|
registerControl('MetricBar', control.MetricBar);
|
|
@@ -482,18 +649,18 @@ const useRegisterControl = (control) => {
|
|
|
482
649
|
const ViewIdContext = createContext(undefined);
|
|
483
650
|
/**
|
|
484
651
|
* Hook to get current viewId
|
|
485
|
-
* Returns
|
|
652
|
+
* Returns DEFAULT_VIEW_ID if not in a ViewIdContext (single mode)
|
|
486
653
|
*/
|
|
487
654
|
const useViewId = () => {
|
|
488
655
|
const viewId = useContext(ViewIdContext);
|
|
489
|
-
return viewId ||
|
|
656
|
+
return viewId || DEFAULT_VIEW_ID;
|
|
490
657
|
};
|
|
491
658
|
/**
|
|
492
659
|
* Hook to check if currently in compare mode
|
|
493
660
|
*/
|
|
494
661
|
const useIsCompareMode = () => {
|
|
495
662
|
const viewId = useContext(ViewIdContext);
|
|
496
|
-
return viewId !== undefined && viewId !==
|
|
663
|
+
return viewId !== undefined && viewId !== DEFAULT_VIEW_ID;
|
|
497
664
|
};
|
|
498
665
|
|
|
499
666
|
const useHeatmapData = (props) => {
|
|
@@ -506,17 +673,191 @@ const useHeatmapData = (props) => {
|
|
|
506
673
|
const setClickmap = useHeatmapDataStore((state) => state.setClickmap);
|
|
507
674
|
const setScrollmap = useHeatmapDataStore((state) => state.setScrollmap);
|
|
508
675
|
const setDataInfo = useHeatmapDataStore((state) => state.setDataInfo);
|
|
676
|
+
const memoizedSetters = useMemo(() => ({
|
|
677
|
+
setData: (newData) => setData(newData, viewId),
|
|
678
|
+
setClickmap: (newClickmap) => setClickmap(newClickmap, viewId),
|
|
679
|
+
setScrollmap: (newScrollmap) => setScrollmap(newScrollmap, viewId),
|
|
680
|
+
setDataInfo: (newDataInfo) => setDataInfo(newDataInfo, viewId),
|
|
681
|
+
}), [setData, setClickmap, setScrollmap, setDataInfo, viewId]);
|
|
509
682
|
return {
|
|
510
|
-
// Data
|
|
511
683
|
data,
|
|
512
684
|
clickmap,
|
|
513
685
|
scrollmap,
|
|
514
686
|
dataInfo,
|
|
515
687
|
// Setters (auto-inject viewId)
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
688
|
+
...memoizedSetters,
|
|
689
|
+
};
|
|
690
|
+
};
|
|
691
|
+
|
|
692
|
+
const useHeatmapInteraction = (props) => {
|
|
693
|
+
const viewId = props?.viewId || useViewId();
|
|
694
|
+
const state = useHeatmapInteractionStore((store) => store.state[viewId] ?? { hideSidebar: false });
|
|
695
|
+
const selectedElement = useHeatmapInteractionStore((store) => store.selectedElement[viewId] ?? null);
|
|
696
|
+
const hoveredElement = useHeatmapInteractionStore((store) => store.hoveredElement[viewId] ?? null);
|
|
697
|
+
const shouldShowCallout = useHeatmapInteractionStore((store) => store.shouldShowCallout[viewId] ?? false);
|
|
698
|
+
const setStateStore = useHeatmapInteractionStore((store) => store.setState);
|
|
699
|
+
const setSelectedElementStore = useHeatmapInteractionStore((store) => store.setSelectedElement);
|
|
700
|
+
const setHoveredElementStore = useHeatmapInteractionStore((store) => store.setHoveredElement);
|
|
701
|
+
const setShouldShowCalloutStore = useHeatmapInteractionStore((store) => store.setShouldShowCallout);
|
|
702
|
+
const memoizedSetters = useMemo(() => ({
|
|
703
|
+
setState: (newState) => setStateStore(newState, viewId),
|
|
704
|
+
setSelectedElement: (element) => setSelectedElementStore(element, viewId),
|
|
705
|
+
setHoveredElement: (element) => setHoveredElementStore(element, viewId),
|
|
706
|
+
setShouldShowCallout: (value) => setShouldShowCalloutStore(value, viewId),
|
|
707
|
+
}), [
|
|
708
|
+
setStateStore,
|
|
709
|
+
setSelectedElementStore,
|
|
710
|
+
setHoveredElementStore,
|
|
711
|
+
setShouldShowCalloutStore,
|
|
712
|
+
viewId,
|
|
713
|
+
]);
|
|
714
|
+
return {
|
|
715
|
+
state,
|
|
716
|
+
selectedElement,
|
|
717
|
+
hoveredElement,
|
|
718
|
+
shouldShowCallout,
|
|
719
|
+
// Setters (auto-inject viewId)
|
|
720
|
+
...memoizedSetters,
|
|
721
|
+
};
|
|
722
|
+
};
|
|
723
|
+
|
|
724
|
+
const useHeatmapViz = (props) => {
|
|
725
|
+
const viewId = props?.viewId || useViewId();
|
|
726
|
+
// Viz store
|
|
727
|
+
const isRenderViz = useHeatmapVizStore((state) => state.isRenderViz[viewId] ?? false);
|
|
728
|
+
const zoomRatio = useHeatmapVizStore((state) => state.zoomRatio[viewId] ?? 100);
|
|
729
|
+
const minZoomRatio = useHeatmapVizStore((state) => state.minZoomRatio[viewId] ?? 10);
|
|
730
|
+
const widthScale = useHeatmapVizStore((state) => state.scale[viewId] ?? 1);
|
|
731
|
+
const isScaledToFit = useHeatmapVizStore((state) => state.isScaledToFit[viewId] ?? false);
|
|
732
|
+
const setIsRenderViz = useHeatmapVizStore((state) => state.setIsRenderViz);
|
|
733
|
+
const setZoomRatio = useHeatmapVizStore((state) => state.setZoomRatio);
|
|
734
|
+
const setMinZoomRatio = useHeatmapVizStore((state) => state.setMinZoomRatio);
|
|
735
|
+
const setScale = useHeatmapVizStore((state) => state.setScale);
|
|
736
|
+
const setIsScaledToFit = useHeatmapVizStore((state) => state.setIsScaledToFit);
|
|
737
|
+
// Single store
|
|
738
|
+
const vizRef = useHeatmapSingleStore((state) => state.vizRef[viewId] ?? null);
|
|
739
|
+
const iframeHeight = useHeatmapSingleStore((state) => state.iframeHeight[viewId] ?? 0);
|
|
740
|
+
const wrapperHeight = useHeatmapSingleStore((state) => state.wrapperHeight[viewId] ?? 0);
|
|
741
|
+
const wrapperWidth = useHeatmapSingleStore((state) => state.wrapperWidth[viewId] ?? 0);
|
|
742
|
+
const setVizRef = useHeatmapSingleStore((state) => state.setVizRef);
|
|
743
|
+
const setIframeHeight = useHeatmapSingleStore((state) => state.setIframeHeight);
|
|
744
|
+
const setWrapperHeight = useHeatmapSingleStore((state) => state.setWrapperHeight);
|
|
745
|
+
const setWrapperWidth = useHeatmapSingleStore((state) => state.setWrapperWidth);
|
|
746
|
+
const memoizedSetters = useMemo(() => ({
|
|
747
|
+
setIsRenderViz: (value) => setIsRenderViz(value, viewId),
|
|
748
|
+
setZoomRatio: (value) => setZoomRatio(value, viewId),
|
|
749
|
+
setMinZoomRatio: (value) => setMinZoomRatio(value, viewId),
|
|
750
|
+
setScale: (value) => setScale(value, viewId),
|
|
751
|
+
setIsScaledToFit: (value) => setIsScaledToFit(value, viewId),
|
|
752
|
+
setVizRef: (value) => setVizRef(value, viewId),
|
|
753
|
+
setIframeHeight: (value) => setIframeHeight(value, viewId),
|
|
754
|
+
setWrapperHeight: (value) => setWrapperHeight(value, viewId),
|
|
755
|
+
setWrapperWidth: (value) => setWrapperWidth(value, viewId),
|
|
756
|
+
}), [
|
|
757
|
+
setIsRenderViz,
|
|
758
|
+
setZoomRatio,
|
|
759
|
+
setMinZoomRatio,
|
|
760
|
+
setScale,
|
|
761
|
+
setIsScaledToFit,
|
|
762
|
+
setVizRef,
|
|
763
|
+
setIframeHeight,
|
|
764
|
+
setWrapperHeight,
|
|
765
|
+
setWrapperWidth,
|
|
766
|
+
viewId,
|
|
767
|
+
]);
|
|
768
|
+
return {
|
|
769
|
+
isRenderViz,
|
|
770
|
+
zoomRatio,
|
|
771
|
+
minZoomRatio,
|
|
772
|
+
widthScale,
|
|
773
|
+
isScaledToFit,
|
|
774
|
+
vizRef,
|
|
775
|
+
iframeHeight,
|
|
776
|
+
wrapperHeight,
|
|
777
|
+
wrapperWidth,
|
|
778
|
+
// Setters (auto-inject viewId)
|
|
779
|
+
...memoizedSetters,
|
|
780
|
+
};
|
|
781
|
+
};
|
|
782
|
+
|
|
783
|
+
const useHeatmapVizScrollmap = (props) => {
|
|
784
|
+
const viewId = props?.viewId || useViewId();
|
|
785
|
+
const zones = useHeatmapVizScrollmapStore((store) => store.zones[viewId] ?? []);
|
|
786
|
+
const hoveredZone = useHeatmapVizScrollmapStore((store) => store.hoveredZone[viewId] ?? null);
|
|
787
|
+
const showMinimap = useHeatmapVizScrollmapStore((store) => store.showMinimap[viewId] ?? true);
|
|
788
|
+
const setZonesStore = useHeatmapVizScrollmapStore((store) => store.setZones);
|
|
789
|
+
const setHoveredZoneStore = useHeatmapVizScrollmapStore((store) => store.setHoveredZone);
|
|
790
|
+
const setShowMinimapStore = useHeatmapVizScrollmapStore((store) => store.setShowMinimap);
|
|
791
|
+
const memoizedSetters = useMemo(() => ({
|
|
792
|
+
setZones: (newZones) => setZonesStore(newZones, viewId),
|
|
793
|
+
setHoveredZone: (zone) => setHoveredZoneStore(zone, viewId),
|
|
794
|
+
setShowMinimap: (value) => setShowMinimapStore(value, viewId),
|
|
795
|
+
}), [setZonesStore, setHoveredZoneStore, setShowMinimapStore, viewId]);
|
|
796
|
+
return {
|
|
797
|
+
zones,
|
|
798
|
+
hoveredZone,
|
|
799
|
+
showMinimap,
|
|
800
|
+
// Setters (auto-inject viewId)
|
|
801
|
+
...memoizedSetters,
|
|
802
|
+
};
|
|
803
|
+
};
|
|
804
|
+
|
|
805
|
+
/**
|
|
806
|
+
* Hook to handle copying and clearing view data across all stores
|
|
807
|
+
*/
|
|
808
|
+
const useHeatmapCopyView = () => {
|
|
809
|
+
const copyDataView = useHeatmapDataStore((state) => state.copyView);
|
|
810
|
+
const copyVizView = useHeatmapVizStore((state) => state.copyView);
|
|
811
|
+
const copySingleView = useHeatmapSingleStore((state) => state.copyView);
|
|
812
|
+
const copyInteractionView = useHeatmapInteractionStore((state) => state.copyView);
|
|
813
|
+
const copyVizScrollmapView = useHeatmapVizScrollmapStore((state) => state.copyView);
|
|
814
|
+
const clearDataView = useHeatmapDataStore((state) => state.clearView);
|
|
815
|
+
const clearVizView = useHeatmapVizStore((state) => state.clearView);
|
|
816
|
+
const clearSingleView = useHeatmapSingleStore((state) => state.clearView);
|
|
817
|
+
const clearInteractionView = useHeatmapInteractionStore((state) => state.clearView);
|
|
818
|
+
const clearVizScrollmapView = useHeatmapVizScrollmapStore((state) => state.clearView);
|
|
819
|
+
const resetDataAll = useHeatmapDataStore((state) => state.resetAll);
|
|
820
|
+
const resetVizAll = useHeatmapVizStore((state) => state.resetAll);
|
|
821
|
+
const resetSingleAll = useHeatmapSingleStore((state) => state.resetAll);
|
|
822
|
+
const resetInteractionAll = useHeatmapInteractionStore((state) => state.resetAll);
|
|
823
|
+
const resetVizScrollmapAll = useHeatmapVizScrollmapStore((state) => state.resetAll);
|
|
824
|
+
const copyView = (fromViewId, toViewId) => {
|
|
825
|
+
copyDataView(fromViewId, toViewId);
|
|
826
|
+
copyVizView(fromViewId, toViewId);
|
|
827
|
+
copySingleView(fromViewId, toViewId);
|
|
828
|
+
copyInteractionView(fromViewId, toViewId);
|
|
829
|
+
copyVizScrollmapView(fromViewId, toViewId);
|
|
830
|
+
};
|
|
831
|
+
const copyViewToMultiple = (fromViewId, toViewIds) => {
|
|
832
|
+
toViewIds.forEach((toViewId) => {
|
|
833
|
+
copyView(fromViewId, toViewId);
|
|
834
|
+
});
|
|
835
|
+
};
|
|
836
|
+
const clearView = (viewId) => {
|
|
837
|
+
clearDataView(viewId);
|
|
838
|
+
clearVizView(viewId);
|
|
839
|
+
clearSingleView(viewId);
|
|
840
|
+
clearInteractionView(viewId);
|
|
841
|
+
clearVizScrollmapView(viewId);
|
|
842
|
+
};
|
|
843
|
+
const clearMultipleViews = (viewIds) => {
|
|
844
|
+
viewIds.forEach((viewId) => {
|
|
845
|
+
clearView(viewId);
|
|
846
|
+
});
|
|
847
|
+
};
|
|
848
|
+
const resetAll = () => {
|
|
849
|
+
resetDataAll();
|
|
850
|
+
resetVizAll();
|
|
851
|
+
resetSingleAll();
|
|
852
|
+
resetInteractionAll();
|
|
853
|
+
resetVizScrollmapAll();
|
|
854
|
+
};
|
|
855
|
+
return {
|
|
856
|
+
copyView,
|
|
857
|
+
copyViewToMultiple,
|
|
858
|
+
clearView,
|
|
859
|
+
clearMultipleViews,
|
|
860
|
+
resetAll,
|
|
520
861
|
};
|
|
521
862
|
};
|
|
522
863
|
|
|
@@ -562,23 +903,146 @@ const useRegisterHeatmap = ({ clickmap, scrollmap }) => {
|
|
|
562
903
|
}, [scrollmap]);
|
|
563
904
|
};
|
|
564
905
|
|
|
906
|
+
function findLastSizeOfDom(data) {
|
|
907
|
+
const listDocs = data
|
|
908
|
+
.filter((item) => item.doc?.find((doc) => doc.data.width && doc.data.height))
|
|
909
|
+
.flatMap((item) => item.doc?.flatMap((doc) => doc.data));
|
|
910
|
+
const lastDoc = listDocs?.[listDocs.length - 1];
|
|
911
|
+
const docSize = {
|
|
912
|
+
width: lastDoc?.width,
|
|
913
|
+
height: lastDoc?.height,
|
|
914
|
+
};
|
|
915
|
+
const listResizes = data.filter((item) => !!item.resize).flatMap((item) => item.resize);
|
|
916
|
+
const lastResizeEvent = listResizes?.[listResizes.length - 1];
|
|
917
|
+
const resize = {
|
|
918
|
+
width: lastResizeEvent?.data.width,
|
|
919
|
+
height: lastResizeEvent?.data.height,
|
|
920
|
+
};
|
|
921
|
+
return {
|
|
922
|
+
doc: docSize,
|
|
923
|
+
resize: resize,
|
|
924
|
+
size: {
|
|
925
|
+
width: resize.width || docSize.width,
|
|
926
|
+
height: resize.height || docSize.height,
|
|
927
|
+
},
|
|
928
|
+
};
|
|
929
|
+
}
|
|
930
|
+
function decodePayloads(payload) {
|
|
931
|
+
try {
|
|
932
|
+
return decode(payload);
|
|
933
|
+
}
|
|
934
|
+
catch (error) {
|
|
935
|
+
return null;
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
function calculateRankPosition(rect, widthScale) {
|
|
940
|
+
const top = rect.top <= 18 ? rect.top + 3 : rect.top - 18;
|
|
941
|
+
const left = rect.left <= 18 ? rect.left + 3 : rect.left - 18;
|
|
942
|
+
return {
|
|
943
|
+
transform: `scale(${1.2 * widthScale})`,
|
|
944
|
+
top: Number.isNaN(top) ? undefined : top,
|
|
945
|
+
left: Number.isNaN(left) ? undefined : left,
|
|
946
|
+
};
|
|
947
|
+
}
|
|
948
|
+
function isElementInViewport(elementRect, visualRef, scale) {
|
|
949
|
+
if (!elementRect)
|
|
950
|
+
return false;
|
|
951
|
+
const visualRect = visualRef.current?.getBoundingClientRect();
|
|
952
|
+
if (!visualRect)
|
|
953
|
+
return false;
|
|
954
|
+
// Element position relative to the document (or container's content)
|
|
955
|
+
const elementTop = elementRect.top * scale;
|
|
956
|
+
const elementBottom = (elementRect.top + elementRect.height) * scale;
|
|
957
|
+
// Current scroll position
|
|
958
|
+
const scrollTop = visualRef.current?.scrollTop || 0;
|
|
959
|
+
const viewportHeight = visualRect.height;
|
|
960
|
+
// Visible viewport range in the scrollable content
|
|
961
|
+
const viewportTop = scrollTop;
|
|
962
|
+
const viewportBottom = scrollTop + viewportHeight;
|
|
963
|
+
// Check if element is within the visible viewport
|
|
964
|
+
// Element is visible if it overlaps with the viewport
|
|
965
|
+
return elementBottom > viewportTop && elementTop < viewportBottom;
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
function getElementLayout(element) {
|
|
969
|
+
if (!element?.getBoundingClientRect)
|
|
970
|
+
return null;
|
|
971
|
+
const rect = element.getBoundingClientRect();
|
|
972
|
+
if (rect.width === 0 && rect.height === 0)
|
|
973
|
+
return null;
|
|
974
|
+
return {
|
|
975
|
+
top: rect.top,
|
|
976
|
+
left: rect.left,
|
|
977
|
+
width: rect.width,
|
|
978
|
+
height: rect.height,
|
|
979
|
+
};
|
|
980
|
+
}
|
|
981
|
+
const getElementAtPoint = (doc, x, y) => {
|
|
982
|
+
let el = null;
|
|
983
|
+
if ('caretPositionFromPoint' in doc) {
|
|
984
|
+
el = doc.caretPositionFromPoint(x, y)?.offsetNode ?? null;
|
|
985
|
+
}
|
|
986
|
+
el = el ?? doc.elementFromPoint(x, y);
|
|
987
|
+
let element = el;
|
|
988
|
+
while (element && element.nodeType === Node.TEXT_NODE) {
|
|
989
|
+
element = element.parentElement;
|
|
990
|
+
}
|
|
991
|
+
return element;
|
|
992
|
+
};
|
|
993
|
+
function getElementHash(element) {
|
|
994
|
+
return (element.getAttribute('data-clarity-hash') ||
|
|
995
|
+
element.getAttribute('data-clarity-hashalpha') ||
|
|
996
|
+
element.getAttribute('data-clarity-hashbeta'));
|
|
997
|
+
}
|
|
998
|
+
const getElementRank = (hash, elements) => {
|
|
999
|
+
if (!elements)
|
|
1000
|
+
return 0;
|
|
1001
|
+
return elements.findIndex((e) => e.hash === hash) + 1;
|
|
1002
|
+
};
|
|
1003
|
+
const buildElementInfo = (hash, rect, heatmapInfo) => {
|
|
1004
|
+
if (!rect || !heatmapInfo)
|
|
1005
|
+
return null;
|
|
1006
|
+
const info = heatmapInfo.elementMapInfo?.[hash];
|
|
1007
|
+
if (!info)
|
|
1008
|
+
return null;
|
|
1009
|
+
const rank = getElementRank(hash, heatmapInfo.sortedElements);
|
|
1010
|
+
const clicks = info.totalclicks ?? 0;
|
|
1011
|
+
const selector = info.selector ?? '';
|
|
1012
|
+
const baseInfo = {
|
|
1013
|
+
hash,
|
|
1014
|
+
clicks,
|
|
1015
|
+
rank,
|
|
1016
|
+
selector,
|
|
1017
|
+
};
|
|
1018
|
+
return {
|
|
1019
|
+
...baseInfo,
|
|
1020
|
+
...rect,
|
|
1021
|
+
};
|
|
1022
|
+
};
|
|
1023
|
+
|
|
565
1024
|
const PADDING = 0;
|
|
566
1025
|
const ARROW_SIZE = 8;
|
|
567
1026
|
const HORIZONTAL_OFFSET = 0;
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
const
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
1027
|
+
|
|
1028
|
+
const getViewportDimensions = (containerElm) => {
|
|
1029
|
+
if (containerElm) {
|
|
1030
|
+
const containerRect = containerElm.getBoundingClientRect();
|
|
1031
|
+
return {
|
|
1032
|
+
width: containerRect.width,
|
|
1033
|
+
height: containerRect.height,
|
|
1034
|
+
};
|
|
1035
|
+
}
|
|
1036
|
+
return {
|
|
1037
|
+
width: window.innerWidth,
|
|
1038
|
+
height: window.innerHeight,
|
|
1039
|
+
};
|
|
1040
|
+
};
|
|
575
1041
|
const getElementDimensions = (targetElm, calloutElm) => ({
|
|
576
1042
|
targetRect: targetElm.getBoundingClientRect(),
|
|
577
1043
|
calloutRect: calloutElm.getBoundingClientRect(),
|
|
578
1044
|
});
|
|
579
|
-
|
|
580
|
-
// Alignment Order
|
|
581
|
-
// ============================================================================
|
|
1045
|
+
|
|
582
1046
|
const getAlignmentOrder = (alignment) => {
|
|
583
1047
|
switch (alignment) {
|
|
584
1048
|
case 'center':
|
|
@@ -589,9 +1053,6 @@ const getAlignmentOrder = (alignment) => {
|
|
|
589
1053
|
return ['right', 'center', 'left'];
|
|
590
1054
|
}
|
|
591
1055
|
};
|
|
592
|
-
// ============================================================================
|
|
593
|
-
// Position Calculation
|
|
594
|
-
// ============================================================================
|
|
595
1056
|
const calculateLeftPosition = ({ targetRect, calloutRect, hozOffset, align, }) => {
|
|
596
1057
|
switch (align) {
|
|
597
1058
|
case 'left':
|
|
@@ -615,31 +1076,40 @@ const calculateHorizontalPlacementPosition = (targetRect, calloutRect, placement
|
|
|
615
1076
|
: targetRect.left - calloutRect.width - padding - arrowSize;
|
|
616
1077
|
return { top, left };
|
|
617
1078
|
};
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
1079
|
+
|
|
1080
|
+
const isLeftPositionValid = (leftPos, calloutWidth, viewportWidth, padding, containerRect) => {
|
|
1081
|
+
if (containerRect) {
|
|
1082
|
+
return leftPos >= containerRect.left + padding && leftPos + calloutWidth <= containerRect.right - padding;
|
|
1083
|
+
}
|
|
622
1084
|
return leftPos >= padding && leftPos + calloutWidth <= viewportWidth - padding;
|
|
623
1085
|
};
|
|
624
|
-
const isVerticalPositionValid = (targetRect, calloutRect, placement, viewportHeight, padding, arrowSize) => {
|
|
1086
|
+
const isVerticalPositionValid = (targetRect, calloutRect, placement, viewportHeight, padding, arrowSize, containerRect) => {
|
|
1087
|
+
if (containerRect) {
|
|
1088
|
+
return placement === 'top'
|
|
1089
|
+
? targetRect.top - calloutRect.height - padding - arrowSize >= containerRect.top
|
|
1090
|
+
: targetRect.bottom + calloutRect.height + padding + arrowSize <= containerRect.bottom;
|
|
1091
|
+
}
|
|
625
1092
|
return placement === 'top'
|
|
626
1093
|
? targetRect.top - calloutRect.height - padding - arrowSize > 0
|
|
627
1094
|
: targetRect.bottom + calloutRect.height + padding + arrowSize < viewportHeight;
|
|
628
1095
|
};
|
|
629
|
-
const isHorizontalPlacementValid = (targetRect, calloutRect, placement, viewportWidth, padding, arrowSize) => {
|
|
1096
|
+
const isHorizontalPlacementValid = (targetRect, calloutRect, placement, viewportWidth, padding, arrowSize, containerRect) => {
|
|
1097
|
+
if (containerRect) {
|
|
1098
|
+
return placement === 'right'
|
|
1099
|
+
? targetRect.right + calloutRect.width + padding + arrowSize <= containerRect.right
|
|
1100
|
+
: targetRect.left - calloutRect.width - padding - arrowSize >= containerRect.left;
|
|
1101
|
+
}
|
|
630
1102
|
return placement === 'right'
|
|
631
1103
|
? targetRect.right + calloutRect.width + padding + arrowSize < viewportWidth
|
|
632
1104
|
: targetRect.left - calloutRect.width - padding - arrowSize > 0;
|
|
633
1105
|
};
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
// ============================================================================
|
|
637
|
-
const generateVerticalPositionCandidates = (targetRect, calloutRect, viewportHeight, viewportWidth, alignment, hozOffset, padding, arrowSize) => {
|
|
1106
|
+
|
|
1107
|
+
const generateVerticalPositionCandidates = (targetRect, calloutRect, viewportHeight, viewportWidth, alignment, hozOffset, padding, arrowSize, containerRect) => {
|
|
638
1108
|
const candidates = [];
|
|
639
1109
|
const placements = ['top', 'bottom'];
|
|
640
1110
|
placements.forEach((placement) => {
|
|
641
1111
|
const verticalPos = calculateVerticalPosition(targetRect, calloutRect, placement, padding, arrowSize);
|
|
642
|
-
const verticalValid = isVerticalPositionValid(targetRect, calloutRect, placement, viewportHeight, padding, arrowSize);
|
|
1112
|
+
const verticalValid = isVerticalPositionValid(targetRect, calloutRect, placement, viewportHeight, padding, arrowSize, containerRect);
|
|
643
1113
|
const alignmentOrder = getAlignmentOrder(alignment);
|
|
644
1114
|
alignmentOrder.forEach((align) => {
|
|
645
1115
|
const horizontalPos = calculateLeftPosition({
|
|
@@ -654,13 +1124,13 @@ const generateVerticalPositionCandidates = (targetRect, calloutRect, viewportHei
|
|
|
654
1124
|
left: horizontalPos,
|
|
655
1125
|
horizontalAlign: align,
|
|
656
1126
|
valid: verticalValid &&
|
|
657
|
-
isLeftPositionValid(horizontalPos, calloutRect.width, viewportWidth, padding),
|
|
1127
|
+
isLeftPositionValid(horizontalPos, calloutRect.width, viewportWidth, padding, containerRect),
|
|
658
1128
|
});
|
|
659
1129
|
});
|
|
660
1130
|
});
|
|
661
1131
|
return candidates;
|
|
662
1132
|
};
|
|
663
|
-
const generateHorizontalPositionCandidates = (targetRect, calloutRect, viewportWidth, padding, arrowSize) => {
|
|
1133
|
+
const generateHorizontalPositionCandidates = (targetRect, calloutRect, viewportWidth, padding, arrowSize, containerRect) => {
|
|
664
1134
|
const placements = ['left', 'right'];
|
|
665
1135
|
return placements.map((placement) => {
|
|
666
1136
|
const { top, left } = calculateHorizontalPlacementPosition(targetRect, calloutRect, placement, padding, arrowSize);
|
|
@@ -669,46 +1139,45 @@ const generateHorizontalPositionCandidates = (targetRect, calloutRect, viewportW
|
|
|
669
1139
|
top,
|
|
670
1140
|
left,
|
|
671
1141
|
horizontalAlign: 'center',
|
|
672
|
-
valid: isHorizontalPlacementValid(targetRect, calloutRect, placement, viewportWidth, padding, arrowSize),
|
|
1142
|
+
valid: isHorizontalPlacementValid(targetRect, calloutRect, placement, viewportWidth, padding, arrowSize, containerRect),
|
|
673
1143
|
};
|
|
674
1144
|
});
|
|
675
1145
|
};
|
|
676
|
-
const generateAllPositionCandidates = (rectDimensions, viewport, alignment, hozOffset, padding, arrowSize) => {
|
|
1146
|
+
const generateAllPositionCandidates = (rectDimensions, viewport, alignment, hozOffset, padding, arrowSize, containerRect) => {
|
|
677
1147
|
const { targetRect, calloutRect } = rectDimensions;
|
|
678
|
-
const verticalCandidates = generateVerticalPositionCandidates(targetRect, calloutRect, viewport.height, viewport.width, alignment, hozOffset, padding, arrowSize);
|
|
679
|
-
const horizontalCandidates = generateHorizontalPositionCandidates(targetRect, calloutRect, viewport.width, padding, arrowSize);
|
|
1148
|
+
const verticalCandidates = generateVerticalPositionCandidates(targetRect, calloutRect, viewport.height, viewport.width, alignment, hozOffset, padding, arrowSize, containerRect);
|
|
1149
|
+
const horizontalCandidates = generateHorizontalPositionCandidates(targetRect, calloutRect, viewport.width, padding, arrowSize, containerRect);
|
|
680
1150
|
return [...verticalCandidates, ...horizontalCandidates];
|
|
681
1151
|
};
|
|
682
|
-
|
|
683
|
-
// Position Selection
|
|
684
|
-
// ============================================================================
|
|
1152
|
+
|
|
685
1153
|
const selectBestPosition = (candidates) => {
|
|
686
1154
|
return candidates.find((p) => p.valid) || candidates[0];
|
|
687
1155
|
};
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
const
|
|
1156
|
+
const constrainToViewport = (position, calloutRect, viewport, padding, containerRect) => {
|
|
1157
|
+
if (containerRect) {
|
|
1158
|
+
const left = Math.max(containerRect.left + padding, Math.min(position.left, containerRect.right - calloutRect.width - padding));
|
|
1159
|
+
const top = Math.max(containerRect.top + padding, Math.min(position.top, containerRect.bottom - calloutRect.height - padding));
|
|
1160
|
+
return { top, left };
|
|
1161
|
+
}
|
|
692
1162
|
const left = Math.max(padding, Math.min(position.left, viewport.width - calloutRect.width - padding));
|
|
693
1163
|
const top = Math.max(padding, Math.min(position.top, viewport.height - calloutRect.height - padding));
|
|
694
1164
|
return { top, left };
|
|
695
1165
|
};
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
// ============================================================================
|
|
699
|
-
const calcCalloutPosition = ({ targetElm, calloutElm, setPosition, hozOffset = HORIZONTAL_OFFSET, alignment = 'center', }) => {
|
|
1166
|
+
|
|
1167
|
+
const calcCalloutPosition = ({ targetElm, calloutElm, setPosition, hozOffset = HORIZONTAL_OFFSET, alignment = 'center', containerElm, }) => {
|
|
700
1168
|
return () => {
|
|
701
1169
|
// 1. Get dimensions
|
|
702
1170
|
const rectDimensions = getElementDimensions(targetElm, calloutElm);
|
|
703
|
-
const viewport = getViewportDimensions();
|
|
1171
|
+
const viewport = getViewportDimensions(containerElm);
|
|
1172
|
+
const containerRect = containerElm?.getBoundingClientRect();
|
|
704
1173
|
const padding = PADDING;
|
|
705
1174
|
const arrowSize = ARROW_SIZE;
|
|
706
1175
|
// 2. Generate all position candidates
|
|
707
|
-
const candidates = generateAllPositionCandidates(rectDimensions, viewport, alignment, hozOffset, padding, arrowSize);
|
|
1176
|
+
const candidates = generateAllPositionCandidates(rectDimensions, viewport, alignment, hozOffset, padding, arrowSize, containerRect);
|
|
708
1177
|
// 3. Select best position
|
|
709
1178
|
const bestPosition = selectBestPosition(candidates);
|
|
710
1179
|
// 4. Constrain to viewport
|
|
711
|
-
const constrainedPosition = constrainToViewport({ top: bestPosition.top, left: bestPosition.left }, rectDimensions.calloutRect, viewport, padding);
|
|
1180
|
+
const constrainedPosition = constrainToViewport({ top: bestPosition.top, left: bestPosition.left }, rectDimensions.calloutRect, viewport, padding, containerRect);
|
|
712
1181
|
// 5. Create final position object
|
|
713
1182
|
const finalPosition = {
|
|
714
1183
|
top: constrainedPosition.top,
|
|
@@ -720,128 +1189,6 @@ const calcCalloutPosition = ({ targetElm, calloutElm, setPosition, hozOffset = H
|
|
|
720
1189
|
};
|
|
721
1190
|
};
|
|
722
1191
|
|
|
723
|
-
function getElementLayout(element) {
|
|
724
|
-
if (!element?.getBoundingClientRect)
|
|
725
|
-
return null;
|
|
726
|
-
const rect = element.getBoundingClientRect();
|
|
727
|
-
if (rect.width === 0 && rect.height === 0)
|
|
728
|
-
return null;
|
|
729
|
-
return {
|
|
730
|
-
top: rect.top,
|
|
731
|
-
left: rect.left,
|
|
732
|
-
width: rect.width,
|
|
733
|
-
height: rect.height,
|
|
734
|
-
};
|
|
735
|
-
}
|
|
736
|
-
const getElementAtPoint = (doc, x, y) => {
|
|
737
|
-
let el = null;
|
|
738
|
-
if ('caretPositionFromPoint' in doc) {
|
|
739
|
-
el = doc.caretPositionFromPoint(x, y)?.offsetNode ?? null;
|
|
740
|
-
}
|
|
741
|
-
el = el ?? doc.elementFromPoint(x, y);
|
|
742
|
-
let element = el;
|
|
743
|
-
while (element && element.nodeType === Node.TEXT_NODE) {
|
|
744
|
-
element = element.parentElement;
|
|
745
|
-
}
|
|
746
|
-
return element;
|
|
747
|
-
};
|
|
748
|
-
function getElementHash(element) {
|
|
749
|
-
return (element.getAttribute('data-clarity-hash') ||
|
|
750
|
-
element.getAttribute('data-clarity-hashalpha') ||
|
|
751
|
-
element.getAttribute('data-clarity-hashbeta'));
|
|
752
|
-
}
|
|
753
|
-
const getElementRank = (hash, elements) => {
|
|
754
|
-
if (!elements)
|
|
755
|
-
return 0;
|
|
756
|
-
return elements.findIndex((e) => e.hash === hash) + 1;
|
|
757
|
-
};
|
|
758
|
-
const buildElementInfo = (hash, rect, heatmapInfo) => {
|
|
759
|
-
if (!rect || !heatmapInfo)
|
|
760
|
-
return null;
|
|
761
|
-
const info = heatmapInfo.elementMapInfo?.[hash];
|
|
762
|
-
if (!info)
|
|
763
|
-
return null;
|
|
764
|
-
const rank = getElementRank(hash, heatmapInfo.sortedElements);
|
|
765
|
-
const clicks = info.totalclicks ?? 0;
|
|
766
|
-
const selector = info.selector ?? '';
|
|
767
|
-
const baseInfo = {
|
|
768
|
-
hash,
|
|
769
|
-
clicks,
|
|
770
|
-
rank,
|
|
771
|
-
selector,
|
|
772
|
-
};
|
|
773
|
-
return {
|
|
774
|
-
...baseInfo,
|
|
775
|
-
...rect,
|
|
776
|
-
};
|
|
777
|
-
};
|
|
778
|
-
|
|
779
|
-
function findLastSizeOfDom(data) {
|
|
780
|
-
const firstDoc = data.find((item) => item.envelope.sequence === 1)?.doc;
|
|
781
|
-
const docSorted = firstDoc?.sort(sort);
|
|
782
|
-
const firstEvent = docSorted?.[0];
|
|
783
|
-
const docSize = {
|
|
784
|
-
width: firstEvent?.data.width,
|
|
785
|
-
height: firstEvent?.data.height,
|
|
786
|
-
};
|
|
787
|
-
const newData = JSON.parse(JSON.stringify(data));
|
|
788
|
-
const reversedData = newData.reverse();
|
|
789
|
-
const lastResizeEvent = reversedData.find((item) => !!item.resize);
|
|
790
|
-
const firstEventResize = lastResizeEvent?.resize?.[0];
|
|
791
|
-
const resize = {
|
|
792
|
-
width: firstEventResize?.data.width,
|
|
793
|
-
height: firstEventResize?.data.height,
|
|
794
|
-
};
|
|
795
|
-
return {
|
|
796
|
-
doc: docSize,
|
|
797
|
-
resize: resize,
|
|
798
|
-
size: {
|
|
799
|
-
width: resize.width ?? docSize.width,
|
|
800
|
-
height: resize.height ?? docSize.height,
|
|
801
|
-
},
|
|
802
|
-
};
|
|
803
|
-
}
|
|
804
|
-
function sort(a, b) {
|
|
805
|
-
return a.time - b.time;
|
|
806
|
-
}
|
|
807
|
-
function decodePayloads(payload) {
|
|
808
|
-
try {
|
|
809
|
-
return decode(payload);
|
|
810
|
-
}
|
|
811
|
-
catch (error) {
|
|
812
|
-
return null;
|
|
813
|
-
}
|
|
814
|
-
}
|
|
815
|
-
|
|
816
|
-
function calculateRankPosition(rect, widthScale) {
|
|
817
|
-
const top = rect.top <= 18 ? rect.top + 3 : rect.top - 18;
|
|
818
|
-
const left = rect.left <= 18 ? rect.left + 3 : rect.left - 18;
|
|
819
|
-
return {
|
|
820
|
-
transform: `scale(${1.2 * widthScale})`,
|
|
821
|
-
top: Number.isNaN(top) ? undefined : top,
|
|
822
|
-
left: Number.isNaN(left) ? undefined : left,
|
|
823
|
-
};
|
|
824
|
-
}
|
|
825
|
-
function isElementInViewport(elementRect, visualRef, scale) {
|
|
826
|
-
if (!elementRect)
|
|
827
|
-
return false;
|
|
828
|
-
const visualRect = visualRef.current?.getBoundingClientRect();
|
|
829
|
-
if (!visualRect)
|
|
830
|
-
return false;
|
|
831
|
-
// Element position relative to the document (or container's content)
|
|
832
|
-
const elementTop = elementRect.top * scale;
|
|
833
|
-
const elementBottom = (elementRect.top + elementRect.height) * scale;
|
|
834
|
-
// Current scroll position
|
|
835
|
-
const scrollTop = visualRef.current?.scrollTop || 0;
|
|
836
|
-
const viewportHeight = visualRect.height;
|
|
837
|
-
// Visible viewport range in the scrollable content
|
|
838
|
-
const viewportTop = scrollTop;
|
|
839
|
-
const viewportBottom = scrollTop + viewportHeight;
|
|
840
|
-
// Check if element is within the visible viewport
|
|
841
|
-
// Element is visible if it overlaps with the viewport
|
|
842
|
-
return elementBottom > viewportTop && elementTop < viewportBottom;
|
|
843
|
-
}
|
|
844
|
-
|
|
845
1192
|
class IframeNavigationBlockerV2 {
|
|
846
1193
|
doc;
|
|
847
1194
|
win;
|
|
@@ -1139,7 +1486,7 @@ class IframeStyleReplacer {
|
|
|
1139
1486
|
doc;
|
|
1140
1487
|
win;
|
|
1141
1488
|
config;
|
|
1142
|
-
regex = /([-.\d]+)(vh|svh|lvh|dvh
|
|
1489
|
+
regex = /([-.\d]+)(vh|svh|lvh|dvh)/gi; //vw|svw|lvw|dvw
|
|
1143
1490
|
constructor(iframe, config) {
|
|
1144
1491
|
if (!iframe.contentDocument || !iframe.contentWindow) {
|
|
1145
1492
|
throw new Error('Iframe document or window not accessible');
|
|
@@ -1417,48 +1764,6 @@ function initIframeHelperFixer(config) {
|
|
|
1417
1764
|
return fixer;
|
|
1418
1765
|
}
|
|
1419
1766
|
|
|
1420
|
-
const useHeatmapViz = (props) => {
|
|
1421
|
-
const viewId = props?.viewId || useViewId();
|
|
1422
|
-
// Viz store
|
|
1423
|
-
const isRenderViz = useHeatmapVizStore((state) => state.isRenderViz[viewId] ?? false);
|
|
1424
|
-
const zoomRatio = useHeatmapVizStore((state) => state.zoomRatio[viewId] ?? 100);
|
|
1425
|
-
const minZoomRatio = useHeatmapVizStore((state) => state.minZoomRatio[viewId] ?? 10);
|
|
1426
|
-
const widthScale = useHeatmapVizStore((state) => state.scale[viewId] ?? 1);
|
|
1427
|
-
const isScaledToFit = useHeatmapVizStore((state) => state.isScaledToFit[viewId] ?? false);
|
|
1428
|
-
const setIsRenderViz = useHeatmapVizStore((state) => state.setIsRenderViz);
|
|
1429
|
-
const setZoomRatio = useHeatmapVizStore((state) => state.setZoomRatio);
|
|
1430
|
-
const setMinZoomRatio = useHeatmapVizStore((state) => state.setMinZoomRatio);
|
|
1431
|
-
const setScale = useHeatmapVizStore((state) => state.setScale);
|
|
1432
|
-
const setIsScaledToFit = useHeatmapVizStore((state) => state.setIsScaledToFit);
|
|
1433
|
-
// Single store
|
|
1434
|
-
const vizRef = useHeatmapSingleStore((state) => state.vizRef[viewId] ?? null);
|
|
1435
|
-
const iframeHeight = useHeatmapSingleStore((state) => state.iframeHeight[viewId] ?? 0);
|
|
1436
|
-
const wrapperHeight = useHeatmapSingleStore((state) => state.wrapperHeight[viewId] ?? 0);
|
|
1437
|
-
const setVizRef = useHeatmapSingleStore((state) => state.setVizRef);
|
|
1438
|
-
const setIframeHeight = useHeatmapSingleStore((state) => state.setIframeHeight);
|
|
1439
|
-
const setWrapperHeight = useHeatmapSingleStore((state) => state.setWrapperHeight);
|
|
1440
|
-
return {
|
|
1441
|
-
// State
|
|
1442
|
-
isRenderViz,
|
|
1443
|
-
zoomRatio,
|
|
1444
|
-
minZoomRatio,
|
|
1445
|
-
widthScale,
|
|
1446
|
-
isScaledToFit,
|
|
1447
|
-
vizRef,
|
|
1448
|
-
iframeHeight,
|
|
1449
|
-
wrapperHeight,
|
|
1450
|
-
// Setters (auto-inject viewId)
|
|
1451
|
-
setIsRenderViz: (value) => setIsRenderViz(value, viewId),
|
|
1452
|
-
setZoomRatio: (value) => setZoomRatio(value, viewId),
|
|
1453
|
-
setMinZoomRatio: (value) => setMinZoomRatio(value, viewId),
|
|
1454
|
-
setScale: (value) => setScale(value, viewId),
|
|
1455
|
-
setIsScaledToFit: (value) => setIsScaledToFit(value, viewId),
|
|
1456
|
-
setVizRef: (value) => setVizRef(value, viewId),
|
|
1457
|
-
setIframeHeight: (value) => setIframeHeight(value, viewId),
|
|
1458
|
-
setWrapperHeight: (value) => setWrapperHeight(value, viewId),
|
|
1459
|
-
};
|
|
1460
|
-
};
|
|
1461
|
-
|
|
1462
1767
|
const scrollToElementIfNeeded = (visualRef, rect, scale) => {
|
|
1463
1768
|
if (!visualRef.current)
|
|
1464
1769
|
return;
|
|
@@ -1477,9 +1782,7 @@ const scrollToElementIfNeeded = (visualRef, rect, scale) => {
|
|
|
1477
1782
|
});
|
|
1478
1783
|
};
|
|
1479
1784
|
const useClickedElement = ({ visualRef, getRect }) => {
|
|
1480
|
-
const selectedElement =
|
|
1481
|
-
const shouldShowCallout = useHeatmapInteractionStore((state) => state.shouldShowCallout);
|
|
1482
|
-
const setShouldShowCallout = useHeatmapInteractionStore((state) => state.setShouldShowCallout);
|
|
1785
|
+
const { selectedElement, shouldShowCallout, setShouldShowCallout } = useHeatmapInteraction();
|
|
1483
1786
|
const { widthScale } = useHeatmapViz();
|
|
1484
1787
|
const { dataInfo } = useHeatmapData();
|
|
1485
1788
|
const [clickedElement, setClickedElement] = useState(null);
|
|
@@ -1490,6 +1793,8 @@ const useClickedElement = ({ visualRef, getRect }) => {
|
|
|
1490
1793
|
setShouldShowCallout(false);
|
|
1491
1794
|
};
|
|
1492
1795
|
useEffect(() => {
|
|
1796
|
+
if (selectedElement === clickedElement?.hash)
|
|
1797
|
+
return;
|
|
1493
1798
|
if (!selectedElement || !dataInfo?.elementMapInfo) {
|
|
1494
1799
|
reset();
|
|
1495
1800
|
return;
|
|
@@ -1515,13 +1820,12 @@ const useClickedElement = ({ visualRef, getRect }) => {
|
|
|
1515
1820
|
requestAnimationFrame(() => {
|
|
1516
1821
|
setClickedElement(elementInfo);
|
|
1517
1822
|
});
|
|
1518
|
-
}, [selectedElement, dataInfo,
|
|
1519
|
-
return { clickedElement, showMissingElement, shouldShowCallout
|
|
1823
|
+
}, [selectedElement, dataInfo, visualRef, widthScale]);
|
|
1824
|
+
return { clickedElement, showMissingElement, shouldShowCallout };
|
|
1520
1825
|
};
|
|
1521
1826
|
|
|
1522
1827
|
const useElementCalloutVisible = ({ visualRef, getRect }) => {
|
|
1523
|
-
const selectedElement =
|
|
1524
|
-
const setShouldShowCallout = useHeatmapInteractionStore((state) => state.setShouldShowCallout);
|
|
1828
|
+
const { selectedElement, setShouldShowCallout } = useHeatmapInteraction();
|
|
1525
1829
|
const { widthScale } = useHeatmapViz();
|
|
1526
1830
|
const { dataInfo } = useHeatmapData();
|
|
1527
1831
|
useEffect(() => {
|
|
@@ -1547,26 +1851,26 @@ const useElementCalloutVisible = ({ visualRef, getRect }) => {
|
|
|
1547
1851
|
window.removeEventListener('resize', handleUpdate);
|
|
1548
1852
|
visualRef?.current?.removeEventListener('scroll', handleUpdate);
|
|
1549
1853
|
};
|
|
1550
|
-
}, [selectedElement, visualRef,
|
|
1854
|
+
}, [selectedElement, visualRef, widthScale, dataInfo]);
|
|
1551
1855
|
return {};
|
|
1552
1856
|
};
|
|
1553
1857
|
|
|
1554
|
-
const useHeatmapEffects = ({ isVisible
|
|
1555
|
-
|
|
1858
|
+
const useHeatmapEffects = ({ isVisible }) => {
|
|
1859
|
+
useHeatmapInteraction();
|
|
1860
|
+
const resetAll = () => {
|
|
1861
|
+
// setShouldShowCallout(false);
|
|
1862
|
+
};
|
|
1556
1863
|
// Reset khi ẩn
|
|
1557
1864
|
useEffect(() => {
|
|
1558
|
-
if (!isVisible)
|
|
1559
|
-
resetAll();
|
|
1560
1865
|
}, [isVisible, resetAll]);
|
|
1561
1866
|
// Ẩn callout khi sidebar mở
|
|
1562
|
-
useEffect(() => {
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
}, [isElementSidebarOpen, selectedElement, setShouldShowCallout]);
|
|
1867
|
+
// useEffect(() => {
|
|
1868
|
+
// if (isElementSidebarOpen && selectedElement) {
|
|
1869
|
+
// setShouldShowCallout(false);
|
|
1870
|
+
// } else if (!isElementSidebarOpen && selectedElement) {
|
|
1871
|
+
// setShouldShowCallout(true);
|
|
1872
|
+
// }
|
|
1873
|
+
// }, [isElementSidebarOpen, selectedElement]);
|
|
1570
1874
|
};
|
|
1571
1875
|
|
|
1572
1876
|
const useHeatmapElementPosition = ({ iframeRef, wrapperRef, visualizer }) => {
|
|
@@ -1722,9 +2026,7 @@ function HeatmapComponent() {
|
|
|
1722
2026
|
*/
|
|
1723
2027
|
|
|
1724
2028
|
const useHoveredElement = ({ iframeRef, getRect }) => {
|
|
1725
|
-
const hoveredElement =
|
|
1726
|
-
const setHoveredElement = useHeatmapInteractionStore((state) => state.setHoveredElement);
|
|
1727
|
-
const onSelect = useHeatmapInteractionStore((state) => state.setSelectedElement);
|
|
2029
|
+
const { hoveredElement, setHoveredElement, setSelectedElement } = useHeatmapInteraction();
|
|
1728
2030
|
const { widthScale } = useHeatmapViz();
|
|
1729
2031
|
const { dataInfo } = useHeatmapData();
|
|
1730
2032
|
const reset = useCallback(() => {
|
|
@@ -1739,7 +2041,15 @@ const useHoveredElement = ({ iframeRef, getRect }) => {
|
|
|
1739
2041
|
return;
|
|
1740
2042
|
}
|
|
1741
2043
|
const iframe = iframeRef.current;
|
|
2044
|
+
if (!iframe) {
|
|
2045
|
+
reset();
|
|
2046
|
+
return;
|
|
2047
|
+
}
|
|
1742
2048
|
const doc = iframe.contentDocument;
|
|
2049
|
+
if (!doc) {
|
|
2050
|
+
reset();
|
|
2051
|
+
return;
|
|
2052
|
+
}
|
|
1743
2053
|
const iframeRect = iframe.getBoundingClientRect();
|
|
1744
2054
|
const { x, y } = convertViewportToIframeCoords(event.clientX, event.clientY, iframeRect, widthScale);
|
|
1745
2055
|
const targetElement = findTargetElement(doc, x, y, dataInfo);
|
|
@@ -1748,11 +2058,12 @@ const useHoveredElement = ({ iframeRef, getRect }) => {
|
|
|
1748
2058
|
return;
|
|
1749
2059
|
}
|
|
1750
2060
|
const hash = getElementHash(targetElement);
|
|
1751
|
-
if (
|
|
2061
|
+
if (hash)
|
|
1752
2062
|
return hash;
|
|
1753
2063
|
reset();
|
|
1754
2064
|
return;
|
|
1755
|
-
}, [dataInfo, iframeRef,
|
|
2065
|
+
}, [dataInfo, iframeRef, widthScale, reset]);
|
|
2066
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1756
2067
|
const handleMouseMove = useCallback(debounce((event) => {
|
|
1757
2068
|
if (!dataInfo) {
|
|
1758
2069
|
reset();
|
|
@@ -1775,7 +2086,8 @@ const useHoveredElement = ({ iframeRef, getRect }) => {
|
|
|
1775
2086
|
const handleClick = useCallback(() => {
|
|
1776
2087
|
if (!hoveredElement?.hash)
|
|
1777
2088
|
return;
|
|
1778
|
-
|
|
2089
|
+
setSelectedElement(hoveredElement.hash);
|
|
2090
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1779
2091
|
}, [hoveredElement?.hash]);
|
|
1780
2092
|
return {
|
|
1781
2093
|
hoveredElement,
|
|
@@ -1801,7 +2113,6 @@ const findTargetElement = (doc, x, y, heatmapInfo) => {
|
|
|
1801
2113
|
const element = elementsAtPoint[i];
|
|
1802
2114
|
const elementHash = element.getAttribute(HEATMAP_ELEMENT_ATTRIBUTE);
|
|
1803
2115
|
if (elementHash && heatmapInfo.elementMapInfo?.[elementHash]) {
|
|
1804
|
-
heatmapInfo.elementMapInfo[elementHash];
|
|
1805
2116
|
const boundingBox = getBoundingBox(element);
|
|
1806
2117
|
if (boundingBox) {
|
|
1807
2118
|
dataElement = element;
|
|
@@ -1809,7 +2120,7 @@ const findTargetElement = (doc, x, y, heatmapInfo) => {
|
|
|
1809
2120
|
}
|
|
1810
2121
|
}
|
|
1811
2122
|
}
|
|
1812
|
-
if (
|
|
2123
|
+
if (dataElement) {
|
|
1813
2124
|
return dataElement;
|
|
1814
2125
|
}
|
|
1815
2126
|
let targetElement = getElementAtPoint(doc, x, y);
|
|
@@ -1887,7 +2198,7 @@ function useVizLiveIframeMsg(options = {}) {
|
|
|
1887
2198
|
}
|
|
1888
2199
|
|
|
1889
2200
|
function useVizLiveRender() {
|
|
1890
|
-
const { setIframeHeight, wrapperHeight, setIsRenderViz } = useHeatmapViz();
|
|
2201
|
+
const { setIframeHeight, wrapperHeight, setIsRenderViz, wrapperWidth } = useHeatmapViz();
|
|
1891
2202
|
const contentWidth = useHeatmapConfigStore((state) => state.width);
|
|
1892
2203
|
const htmlContent = useHeatmapLiveStore((state) => state.htmlContent);
|
|
1893
2204
|
const { iframeRef, isReady } = useVizLiveIframeMsg();
|
|
@@ -1905,17 +2216,20 @@ function useVizLiveRender() {
|
|
|
1905
2216
|
useEffect(() => {
|
|
1906
2217
|
if (!isReady)
|
|
1907
2218
|
return;
|
|
2219
|
+
if (!wrapperHeight)
|
|
2220
|
+
return;
|
|
1908
2221
|
if (!iframeRef.current)
|
|
1909
2222
|
return;
|
|
2223
|
+
console.log(`🚀 🐥 ~ useVizLiveRender ~ wrapperHeight:`, wrapperHeight);
|
|
1910
2224
|
const iframe = iframeRef.current;
|
|
1911
2225
|
if (!iframe || !htmlContent)
|
|
1912
2226
|
return;
|
|
1913
2227
|
setIsRenderViz(false);
|
|
1914
|
-
reset(iframe, { width:
|
|
2228
|
+
reset(iframe, { width: wrapperWidth, height: wrapperHeight }, (height) => {
|
|
1915
2229
|
height && setIframeHeight(height);
|
|
1916
2230
|
setIsRenderViz(true);
|
|
1917
2231
|
});
|
|
1918
|
-
}, [isReady, contentWidth, wrapperHeight]);
|
|
2232
|
+
}, [isReady, contentWidth, wrapperHeight, wrapperWidth]);
|
|
1919
2233
|
return {
|
|
1920
2234
|
iframeRef,
|
|
1921
2235
|
};
|
|
@@ -1936,12 +2250,17 @@ function reset(iframe, rect, onSuccess) {
|
|
|
1936
2250
|
|
|
1937
2251
|
const useHeatmapRender = () => {
|
|
1938
2252
|
const { data } = useHeatmapData();
|
|
1939
|
-
const { vizRef, setVizRef, setIsRenderViz, setIframeHeight } = useHeatmapViz();
|
|
2253
|
+
const { vizRef, setVizRef, setIsRenderViz, setIframeHeight, wrapperHeight, wrapperWidth } = useHeatmapViz();
|
|
2254
|
+
console.log(`🚀 🐥 ~ useHeatmapRender ~ wrapperHeight:`, wrapperHeight);
|
|
1940
2255
|
const iframeRef = useRef(null);
|
|
1941
2256
|
const renderHeatmap = useCallback(async (payloads) => {
|
|
1942
2257
|
if (!payloads || payloads.length === 0)
|
|
1943
2258
|
return;
|
|
1944
|
-
|
|
2259
|
+
let visualizer = vizRef;
|
|
2260
|
+
if (!visualizer) {
|
|
2261
|
+
visualizer = new Visualizer();
|
|
2262
|
+
setVizRef(visualizer);
|
|
2263
|
+
}
|
|
1945
2264
|
setIsRenderViz(false);
|
|
1946
2265
|
const iframe = iframeRef.current;
|
|
1947
2266
|
if (!iframe?.contentWindow)
|
|
@@ -1950,7 +2269,6 @@ const useHeatmapRender = () => {
|
|
|
1950
2269
|
initIframe(iframe, payloads, (height) => {
|
|
1951
2270
|
height && setIframeHeight(height);
|
|
1952
2271
|
setIsRenderViz(true);
|
|
1953
|
-
setVizRef(visualizer);
|
|
1954
2272
|
});
|
|
1955
2273
|
}, []);
|
|
1956
2274
|
useEffect(() => {
|
|
@@ -1965,7 +2283,9 @@ const useHeatmapRender = () => {
|
|
|
1965
2283
|
iframeRef,
|
|
1966
2284
|
};
|
|
1967
2285
|
};
|
|
1968
|
-
function initIframe(iframe,
|
|
2286
|
+
function initIframe(iframe,
|
|
2287
|
+
// size: { width: number; height: number },
|
|
2288
|
+
payloads, onSuccess) {
|
|
1969
2289
|
const { size } = findLastSizeOfDom(payloads);
|
|
1970
2290
|
const docWidth = size.width ?? 0;
|
|
1971
2291
|
const docHeight = size.height ?? 0;
|
|
@@ -2164,7 +2484,8 @@ const useContentDimensions = ({ iframeRef, }) => {
|
|
|
2164
2484
|
};
|
|
2165
2485
|
|
|
2166
2486
|
const useObserveIframeHeight = (props) => {
|
|
2167
|
-
const { iframeRef,
|
|
2487
|
+
const { iframeRef, isRenderViz } = props;
|
|
2488
|
+
const { setIframeHeight } = useHeatmapViz();
|
|
2168
2489
|
const resizeObserverRef = useRef(null);
|
|
2169
2490
|
const mutationObserverRef = useRef(null);
|
|
2170
2491
|
const debounceTimerRef = useRef(null);
|
|
@@ -2172,7 +2493,7 @@ const useObserveIframeHeight = (props) => {
|
|
|
2172
2493
|
const animationFrameRef = useRef(null);
|
|
2173
2494
|
const updateIframeHeight = useCallback(() => {
|
|
2174
2495
|
const iframe = iframeRef.current;
|
|
2175
|
-
if (!iframe
|
|
2496
|
+
if (!iframe)
|
|
2176
2497
|
return;
|
|
2177
2498
|
try {
|
|
2178
2499
|
const iframeDocument = iframe.contentDocument;
|
|
@@ -2180,7 +2501,7 @@ const useObserveIframeHeight = (props) => {
|
|
|
2180
2501
|
const iframeDocumentElement = iframeDocument?.documentElement;
|
|
2181
2502
|
if (!iframeBody || !iframeDocumentElement)
|
|
2182
2503
|
return;
|
|
2183
|
-
iframe.style.height = 'auto';
|
|
2504
|
+
// iframe.style.height = 'auto'; // TODO: check if this is needed
|
|
2184
2505
|
requestAnimationFrame(() => {
|
|
2185
2506
|
const bodyHeight = Math.max(iframeBody.scrollHeight, iframeBody.offsetHeight, iframeBody.clientHeight);
|
|
2186
2507
|
const documentHeight = Math.max(iframeDocumentElement.scrollHeight, iframeDocumentElement.offsetHeight, iframeDocumentElement.clientHeight);
|
|
@@ -2196,7 +2517,7 @@ const useObserveIframeHeight = (props) => {
|
|
|
2196
2517
|
catch (error) {
|
|
2197
2518
|
console.warn('Cannot measure iframe content:', error);
|
|
2198
2519
|
}
|
|
2199
|
-
}, [iframeRef
|
|
2520
|
+
}, [iframeRef]);
|
|
2200
2521
|
const debouncedUpdate = useCallback(() => {
|
|
2201
2522
|
// Cancel pending updates
|
|
2202
2523
|
if (debounceTimerRef.current) {
|
|
@@ -2298,7 +2619,7 @@ const useScaleCalculation = (props) => {
|
|
|
2298
2619
|
const availableWidth = containerWidth - HEATMAP_CONFIG['padding'] * 2;
|
|
2299
2620
|
const widthScale = Math.min(availableWidth / contentWidth, 1);
|
|
2300
2621
|
// 2. Calculate available height
|
|
2301
|
-
const toolbarHeight = HEATMAP_CONFIG['heightToolbar'] ;
|
|
2622
|
+
const toolbarHeight = HEATMAP_CONFIG['heightToolbar'] || 0;
|
|
2302
2623
|
const paddingTotal = HEATMAP_CONFIG['padding'] * 2;
|
|
2303
2624
|
const availableHeight = containerHeight - toolbarHeight - paddingTotal; // 10px buffer to avoid scroll bar
|
|
2304
2625
|
// 3. Calculate minZoomRatio (zoom ratio minimum to fit iframe in container)
|
|
@@ -2354,13 +2675,13 @@ const useScrollSync = ({ widthScale, iframeRef, }) => {
|
|
|
2354
2675
|
};
|
|
2355
2676
|
|
|
2356
2677
|
const useHeatmapScale = (props) => {
|
|
2357
|
-
const { wrapperRef, iframeRef, iframeHeight,
|
|
2678
|
+
const { wrapperRef, iframeRef, iframeHeight, isRenderViz } = props;
|
|
2358
2679
|
// 1. Observe container dimensions
|
|
2359
2680
|
const { containerWidth, containerHeight } = useContainerDimensions({ wrapperRef });
|
|
2360
2681
|
// 2. Get content dimensions from config
|
|
2361
2682
|
const { contentWidth } = useContentDimensions({ iframeRef });
|
|
2362
2683
|
// 3. Observe iframe height (now reacts to width changes)
|
|
2363
|
-
useObserveIframeHeight({ iframeRef,
|
|
2684
|
+
useObserveIframeHeight({ iframeRef, isRenderViz });
|
|
2364
2685
|
// 4. Calculate scale
|
|
2365
2686
|
const { widthScale } = useScaleCalculation({
|
|
2366
2687
|
containerWidth,
|
|
@@ -2385,15 +2706,17 @@ const useWrapperRefHeight = (props) => {
|
|
|
2385
2706
|
const { isActive, wrapperRef } = props;
|
|
2386
2707
|
const resizeObserverRef = useRef(null);
|
|
2387
2708
|
const mutationObserverRef = useRef(null);
|
|
2388
|
-
const {
|
|
2709
|
+
const { setWrapperHeight, setWrapperWidth } = useHeatmapViz();
|
|
2389
2710
|
const updateWrapperHeight = useCallback(() => {
|
|
2390
2711
|
const wrapper = wrapperRef.current;
|
|
2391
2712
|
if (!wrapper)
|
|
2392
2713
|
return;
|
|
2393
2714
|
try {
|
|
2394
2715
|
const wrapperHeight = wrapper.offsetHeight;
|
|
2716
|
+
const wrapperWidth = wrapper.offsetWidth;
|
|
2395
2717
|
if (wrapperHeight > 0) {
|
|
2396
2718
|
setWrapperHeight(wrapperHeight);
|
|
2719
|
+
setWrapperWidth(wrapperWidth);
|
|
2397
2720
|
}
|
|
2398
2721
|
}
|
|
2399
2722
|
catch (error) {
|
|
@@ -2402,7 +2725,7 @@ const useWrapperRefHeight = (props) => {
|
|
|
2402
2725
|
}, [wrapperRef]);
|
|
2403
2726
|
useEffect(() => {
|
|
2404
2727
|
const wrapper = wrapperRef.current;
|
|
2405
|
-
if (!wrapper
|
|
2728
|
+
if (!wrapper)
|
|
2406
2729
|
return;
|
|
2407
2730
|
const setupObservers = () => {
|
|
2408
2731
|
try {
|
|
@@ -2432,6 +2755,7 @@ const useWrapperRefHeight = (props) => {
|
|
|
2432
2755
|
updateWrapperHeight();
|
|
2433
2756
|
}
|
|
2434
2757
|
catch (error) {
|
|
2758
|
+
console.log(`🚀 🐥 ~ setupObservers ~ error:`, error);
|
|
2435
2759
|
console.warn('Cannot access wrapper content:', error);
|
|
2436
2760
|
}
|
|
2437
2761
|
};
|
|
@@ -2446,11 +2770,11 @@ const useWrapperRefHeight = (props) => {
|
|
|
2446
2770
|
mutationObserverRef.current.disconnect();
|
|
2447
2771
|
}
|
|
2448
2772
|
};
|
|
2449
|
-
}, [wrapperRef,
|
|
2773
|
+
}, [wrapperRef, updateWrapperHeight, isActive]);
|
|
2450
2774
|
return {};
|
|
2451
2775
|
};
|
|
2452
2776
|
|
|
2453
|
-
const useZonePositions = (
|
|
2777
|
+
const useZonePositions = (_options) => {
|
|
2454
2778
|
const { iframeHeight } = useHeatmapViz();
|
|
2455
2779
|
const getZonePosition = useCallback((zone) => {
|
|
2456
2780
|
if (!iframeHeight) {
|
|
@@ -2580,184 +2904,509 @@ const getScrollGradientColor = (normalized) => {
|
|
|
2580
2904
|
return `rgb(${r}, ${g}, ${b})`;
|
|
2581
2905
|
};
|
|
2582
2906
|
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
const globalDataInfo = useHeatmapDataStore((state) => state.dataInfo);
|
|
2602
|
-
// If in compare mode, use view context
|
|
2603
|
-
if (compareContext) {
|
|
2604
|
-
return {
|
|
2605
|
-
data: compareContext.view.data,
|
|
2606
|
-
clickmap: compareContext.view.clickmap,
|
|
2607
|
-
scrollmap: compareContext.view.scrollmap,
|
|
2608
|
-
dataInfo: compareContext.view.dataInfo,
|
|
2907
|
+
class PerformanceLogger {
|
|
2908
|
+
static instance;
|
|
2909
|
+
metrics = [];
|
|
2910
|
+
sessionId;
|
|
2911
|
+
sessionStartTime;
|
|
2912
|
+
config;
|
|
2913
|
+
constructor() {
|
|
2914
|
+
this.sessionId = `session-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
2915
|
+
this.sessionStartTime = Date.now();
|
|
2916
|
+
this.config = {
|
|
2917
|
+
enabled: false,
|
|
2918
|
+
logToConsole: false,
|
|
2919
|
+
logLevel: 'normal',
|
|
2920
|
+
thresholds: {
|
|
2921
|
+
slowRenderMs: 16, // > 16ms = slower than 60fps
|
|
2922
|
+
slowHookMs: 5,
|
|
2923
|
+
excessiveRenderCount: 10,
|
|
2924
|
+
},
|
|
2609
2925
|
};
|
|
2610
2926
|
}
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
};
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2927
|
+
static getInstance() {
|
|
2928
|
+
if (!PerformanceLogger.instance) {
|
|
2929
|
+
PerformanceLogger.instance = new PerformanceLogger();
|
|
2930
|
+
}
|
|
2931
|
+
return PerformanceLogger.instance;
|
|
2932
|
+
}
|
|
2933
|
+
configure(config) {
|
|
2934
|
+
this.config = { ...this.config, ...config };
|
|
2935
|
+
if (this.config.enabled && this.config.logToConsole) {
|
|
2936
|
+
console.log('[Performance Monitor] Enabled', {
|
|
2937
|
+
sessionId: this.sessionId,
|
|
2938
|
+
config: this.config,
|
|
2939
|
+
});
|
|
2940
|
+
}
|
|
2941
|
+
}
|
|
2942
|
+
log(metric) {
|
|
2943
|
+
if (!this.config.enabled)
|
|
2944
|
+
return;
|
|
2945
|
+
this.metrics.push(metric);
|
|
2946
|
+
// Log to console based on level
|
|
2947
|
+
if (this.config.logToConsole) {
|
|
2948
|
+
this.logToConsole(metric);
|
|
2949
|
+
}
|
|
2950
|
+
// Send to external logger if configured
|
|
2951
|
+
if (this.config.externalLogger) {
|
|
2952
|
+
this.config.externalLogger(metric);
|
|
2953
|
+
}
|
|
2954
|
+
// Check thresholds and warn
|
|
2955
|
+
this.checkThresholds(metric);
|
|
2956
|
+
}
|
|
2957
|
+
logToConsole(metric) {
|
|
2958
|
+
const { logLevel } = this.config;
|
|
2959
|
+
if (logLevel === 'minimal') {
|
|
2960
|
+
// Only log warnings
|
|
2961
|
+
return;
|
|
2962
|
+
}
|
|
2963
|
+
const style = this.getConsoleStyle(metric.type);
|
|
2964
|
+
const label = `[${metric.type.toUpperCase()}] ${metric.name}`;
|
|
2965
|
+
if (logLevel === 'verbose') {
|
|
2966
|
+
console.log(`%c${label}`, style, metric);
|
|
2967
|
+
}
|
|
2968
|
+
else {
|
|
2969
|
+
// Normal: Log compact info
|
|
2970
|
+
const info = { name: metric.name };
|
|
2971
|
+
if (metric.duration)
|
|
2972
|
+
info.duration = `${metric.duration.toFixed(2)}ms`;
|
|
2973
|
+
if ('viewId' in metric && metric.viewId)
|
|
2974
|
+
info.viewId = metric.viewId;
|
|
2975
|
+
if ('renderCount' in metric)
|
|
2976
|
+
info.renderCount = metric.renderCount;
|
|
2977
|
+
console.log(`%c${label}`, style, info);
|
|
2978
|
+
}
|
|
2979
|
+
}
|
|
2980
|
+
getConsoleStyle(type) {
|
|
2981
|
+
const styles = {
|
|
2982
|
+
render: 'color: #61dafb; font-weight: bold',
|
|
2983
|
+
hook: 'color: #ffa500; font-weight: bold',
|
|
2984
|
+
store: 'color: #9c27b0; font-weight: bold',
|
|
2985
|
+
function: 'color: #4caf50; font-weight: bold',
|
|
2986
|
+
};
|
|
2987
|
+
return styles[type] || '';
|
|
2988
|
+
}
|
|
2989
|
+
checkThresholds(metric) {
|
|
2990
|
+
const { thresholds } = this.config;
|
|
2991
|
+
// Check slow render
|
|
2992
|
+
if (metric.type === 'render' && metric.duration && metric.duration > thresholds.slowRenderMs) {
|
|
2993
|
+
console.warn(`[Performance] Slow render detected: ${metric.name} took ${metric.duration.toFixed(2)}ms`, metric);
|
|
2994
|
+
}
|
|
2995
|
+
// Check slow hook
|
|
2996
|
+
if (metric.type === 'hook' && metric.duration && metric.duration > thresholds.slowHookMs) {
|
|
2997
|
+
console.warn(`[Performance] Slow hook detected: ${metric.name} took ${metric.duration.toFixed(2)}ms`, metric);
|
|
2998
|
+
}
|
|
2999
|
+
// Check excessive renders
|
|
3000
|
+
if (metric.type === 'render' && 'renderCount' in metric) {
|
|
3001
|
+
const renderMetric = metric;
|
|
3002
|
+
if (renderMetric.renderCount > thresholds.excessiveRenderCount) {
|
|
3003
|
+
console.warn(`[Performance] Excessive renders: ${metric.name} has rendered ${renderMetric.renderCount} times`, metric);
|
|
3004
|
+
}
|
|
3005
|
+
}
|
|
3006
|
+
}
|
|
3007
|
+
generateReport() {
|
|
3008
|
+
const now = Date.now();
|
|
3009
|
+
const duration = now - this.sessionStartTime;
|
|
3010
|
+
// Calculate summary
|
|
3011
|
+
const renderMetrics = this.metrics.filter((m) => m.type === 'render');
|
|
3012
|
+
const hookMetrics = this.metrics.filter((m) => m.type === 'hook');
|
|
3013
|
+
const storeMetrics = this.metrics.filter((m) => m.type === 'store');
|
|
3014
|
+
const totalRenders = renderMetrics.length;
|
|
3015
|
+
const totalHookCalls = hookMetrics.length;
|
|
3016
|
+
const totalStoreUpdates = storeMetrics.length;
|
|
3017
|
+
const renderDurations = renderMetrics
|
|
3018
|
+
.filter((m) => m.duration)
|
|
3019
|
+
.map((m) => m.duration);
|
|
3020
|
+
const averageRenderTime = renderDurations.length > 0
|
|
3021
|
+
? renderDurations.reduce((a, b) => a + b, 0) / renderDurations.length
|
|
3022
|
+
: 0;
|
|
3023
|
+
// View-specific metrics
|
|
3024
|
+
const viewMetrics = {};
|
|
3025
|
+
this.metrics.forEach((metric) => {
|
|
3026
|
+
const viewId = 'viewId' in metric && metric.viewId ? metric.viewId : DEFAULT_VIEW_ID;
|
|
3027
|
+
if (!viewMetrics[viewId]) {
|
|
3028
|
+
viewMetrics[viewId] = { renders: 0, hookCalls: 0, storeUpdates: 0 };
|
|
3029
|
+
}
|
|
3030
|
+
if (metric.type === 'render')
|
|
3031
|
+
viewMetrics[viewId].renders++;
|
|
3032
|
+
if (metric.type === 'hook')
|
|
3033
|
+
viewMetrics[viewId].hookCalls++;
|
|
3034
|
+
if (metric.type === 'store')
|
|
3035
|
+
viewMetrics[viewId].storeUpdates++;
|
|
3036
|
+
});
|
|
3037
|
+
// Find warnings
|
|
3038
|
+
const renderCounts = new Map();
|
|
3039
|
+
renderMetrics.forEach((m) => {
|
|
3040
|
+
const key = `${m.name}-${'viewId' in m ? m.viewId : DEFAULT_VIEW_ID}`;
|
|
3041
|
+
renderCounts.set(key, (renderCounts.get(key) || 0) + 1);
|
|
3042
|
+
});
|
|
3043
|
+
const excessiveRenders = Array.from(renderCounts.entries())
|
|
3044
|
+
.filter(([, count]) => count > this.config.thresholds.excessiveRenderCount)
|
|
3045
|
+
.map(([key, count]) => {
|
|
3046
|
+
const [component, viewId] = key.split('-');
|
|
3047
|
+
return { component, count, viewId: viewId !== DEFAULT_VIEW_ID ? viewId : undefined };
|
|
3048
|
+
});
|
|
3049
|
+
const slowOperations = this.metrics
|
|
3050
|
+
.filter((m) => m.duration &&
|
|
3051
|
+
((m.type === 'render' && m.duration > this.config.thresholds.slowRenderMs) ||
|
|
3052
|
+
(m.type === 'hook' && m.duration > this.config.thresholds.slowHookMs)))
|
|
3053
|
+
.map((m) => ({
|
|
3054
|
+
name: m.name,
|
|
3055
|
+
duration: m.duration,
|
|
3056
|
+
type: m.type,
|
|
3057
|
+
}));
|
|
2631
3058
|
return {
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
3059
|
+
session: {
|
|
3060
|
+
id: this.sessionId,
|
|
3061
|
+
startTime: this.sessionStartTime,
|
|
3062
|
+
endTime: now,
|
|
3063
|
+
duration,
|
|
3064
|
+
},
|
|
3065
|
+
summary: {
|
|
3066
|
+
totalRenders,
|
|
3067
|
+
totalHookCalls,
|
|
3068
|
+
totalStoreUpdates,
|
|
3069
|
+
averageRenderTime,
|
|
3070
|
+
viewMetrics,
|
|
3071
|
+
},
|
|
3072
|
+
metrics: this.metrics,
|
|
3073
|
+
warnings: {
|
|
3074
|
+
excessiveRenders,
|
|
3075
|
+
slowOperations,
|
|
3076
|
+
},
|
|
2636
3077
|
};
|
|
2637
3078
|
}
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
3079
|
+
clearMetrics() {
|
|
3080
|
+
this.metrics = [];
|
|
3081
|
+
this.sessionId = `session-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
3082
|
+
this.sessionStartTime = Date.now();
|
|
3083
|
+
}
|
|
3084
|
+
getMetrics() {
|
|
3085
|
+
return [...this.metrics];
|
|
3086
|
+
}
|
|
3087
|
+
isEnabled() {
|
|
3088
|
+
return this.config.enabled;
|
|
3089
|
+
}
|
|
3090
|
+
}
|
|
3091
|
+
const performanceLogger = PerformanceLogger.getInstance();
|
|
2645
3092
|
|
|
2646
3093
|
/**
|
|
2647
|
-
* Hook
|
|
2648
|
-
*
|
|
3094
|
+
* Hook to track render count of a component
|
|
3095
|
+
* @param componentName - Name of the component
|
|
3096
|
+
* @param viewId - Optional viewId for compare mode
|
|
2649
3097
|
*/
|
|
2650
|
-
|
|
2651
|
-
const
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
|
|
3098
|
+
function useRenderCount(componentName, viewId) {
|
|
3099
|
+
const renderCount = useRef(0);
|
|
3100
|
+
const startTime = useRef(0);
|
|
3101
|
+
// Increment before render
|
|
3102
|
+
renderCount.current += 1;
|
|
3103
|
+
startTime.current = performance.now();
|
|
3104
|
+
useEffect(() => {
|
|
3105
|
+
const duration = performance.now() - startTime.current;
|
|
3106
|
+
const metric = {
|
|
3107
|
+
id: `render-${componentName}-${Date.now()}`,
|
|
3108
|
+
type: 'render',
|
|
3109
|
+
name: componentName,
|
|
3110
|
+
componentName,
|
|
3111
|
+
renderCount: renderCount.current,
|
|
3112
|
+
timestamp: Date.now(),
|
|
3113
|
+
duration,
|
|
3114
|
+
viewId,
|
|
2662
3115
|
};
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
return
|
|
2666
|
-
|
|
2667
|
-
clickType: globalClickType,
|
|
2668
|
-
scrollType: globalScrollType,
|
|
2669
|
-
};
|
|
2670
|
-
};
|
|
3116
|
+
performanceLogger.log(metric);
|
|
3117
|
+
});
|
|
3118
|
+
return renderCount.current;
|
|
3119
|
+
}
|
|
2671
3120
|
/**
|
|
2672
|
-
* Hook
|
|
2673
|
-
*
|
|
2674
|
-
*
|
|
3121
|
+
* Hook to detect why a component re-rendered (which props changed)
|
|
3122
|
+
* @param componentName - Name of the component
|
|
3123
|
+
* @param props - Props object to track
|
|
3124
|
+
* @param viewId - Optional viewId
|
|
2675
3125
|
*/
|
|
2676
|
-
|
|
2677
|
-
const
|
|
2678
|
-
const
|
|
2679
|
-
const
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
|
|
3126
|
+
function useWhyDidYouUpdate(componentName, props, viewId) {
|
|
3127
|
+
const previousProps = useRef();
|
|
3128
|
+
const renderCount = useRef(0);
|
|
3129
|
+
const startTime = useRef(0);
|
|
3130
|
+
renderCount.current += 1;
|
|
3131
|
+
startTime.current = performance.now();
|
|
3132
|
+
useEffect(() => {
|
|
3133
|
+
if (previousProps.current) {
|
|
3134
|
+
const duration = performance.now() - startTime.current;
|
|
3135
|
+
const allKeys = Object.keys({ ...previousProps.current, ...props });
|
|
3136
|
+
const changedProps = [];
|
|
3137
|
+
allKeys.forEach((key) => {
|
|
3138
|
+
if (previousProps.current[key] !== props[key]) {
|
|
3139
|
+
changedProps.push(key);
|
|
3140
|
+
}
|
|
3141
|
+
});
|
|
3142
|
+
if (changedProps.length > 0) {
|
|
3143
|
+
const metric = {
|
|
3144
|
+
id: `render-${componentName}-${Date.now()}`,
|
|
3145
|
+
type: 'render',
|
|
3146
|
+
name: componentName,
|
|
3147
|
+
componentName,
|
|
3148
|
+
renderCount: renderCount.current,
|
|
3149
|
+
timestamp: Date.now(),
|
|
3150
|
+
duration,
|
|
3151
|
+
viewId,
|
|
3152
|
+
reason: 'Props changed',
|
|
3153
|
+
propsChanged: changedProps,
|
|
3154
|
+
metadata: {
|
|
3155
|
+
changes: changedProps.reduce((acc, key) => {
|
|
3156
|
+
acc[key] = {
|
|
3157
|
+
from: previousProps.current[key],
|
|
3158
|
+
to: props[key],
|
|
3159
|
+
};
|
|
3160
|
+
return acc;
|
|
3161
|
+
}, {}),
|
|
3162
|
+
},
|
|
3163
|
+
};
|
|
3164
|
+
performanceLogger.log(metric);
|
|
3165
|
+
}
|
|
3166
|
+
}
|
|
3167
|
+
previousProps.current = props;
|
|
3168
|
+
});
|
|
3169
|
+
}
|
|
3170
|
+
/**
|
|
3171
|
+
* Hook to measure execution time of a function
|
|
3172
|
+
* @param functionName - Name of the function
|
|
3173
|
+
* @param fn - Function to measure
|
|
3174
|
+
* @param viewId - Optional viewId
|
|
3175
|
+
*/
|
|
3176
|
+
function useMeasureFunction(functionName, fn, viewId) {
|
|
3177
|
+
const measuredFn = ((...args) => {
|
|
3178
|
+
const startTime = performance.now();
|
|
3179
|
+
const result = fn(...args);
|
|
3180
|
+
const duration = performance.now() - startTime;
|
|
3181
|
+
performanceLogger.log({
|
|
3182
|
+
id: `function-${functionName}-${Date.now()}`,
|
|
3183
|
+
type: 'function',
|
|
3184
|
+
name: functionName,
|
|
3185
|
+
functionName,
|
|
3186
|
+
timestamp: Date.now(),
|
|
3187
|
+
duration,
|
|
3188
|
+
viewId,
|
|
3189
|
+
metadata: {
|
|
3190
|
+
args: args.length,
|
|
3191
|
+
},
|
|
3192
|
+
});
|
|
3193
|
+
return result;
|
|
3194
|
+
});
|
|
3195
|
+
return measuredFn;
|
|
3196
|
+
}
|
|
3197
|
+
/**
|
|
3198
|
+
* Hook to track when a hook is called
|
|
3199
|
+
* @param hookName - Name of the hook
|
|
3200
|
+
* @param viewId - Optional viewId
|
|
3201
|
+
* @param storeSlice - Optional store slice being accessed
|
|
3202
|
+
*/
|
|
3203
|
+
function useTrackHookCall(hookName, viewId, storeSlice) {
|
|
3204
|
+
const startTime = useRef(0);
|
|
3205
|
+
startTime.current = performance.now();
|
|
3206
|
+
useEffect(() => {
|
|
3207
|
+
const duration = performance.now() - startTime.current;
|
|
3208
|
+
performanceLogger.log({
|
|
3209
|
+
id: `hook-${hookName}-${Date.now()}`,
|
|
3210
|
+
type: 'hook',
|
|
3211
|
+
name: hookName,
|
|
3212
|
+
hookName,
|
|
3213
|
+
timestamp: Date.now(),
|
|
3214
|
+
duration,
|
|
3215
|
+
viewId,
|
|
3216
|
+
storeSlice,
|
|
3217
|
+
});
|
|
3218
|
+
});
|
|
3219
|
+
}
|
|
3220
|
+
|
|
3221
|
+
/**
|
|
3222
|
+
* HOC to track component performance
|
|
3223
|
+
* @param Component - Component to wrap
|
|
3224
|
+
* @param options - Tracking options
|
|
3225
|
+
*/
|
|
3226
|
+
function withPerformanceTracking(Component, options = {}) {
|
|
3227
|
+
const { trackProps = true, componentName, viewIdProp = 'viewId' } = options;
|
|
3228
|
+
const WrappedComponent = (props) => {
|
|
3229
|
+
const name = componentName || Component.displayName || Component.name || 'Unknown';
|
|
3230
|
+
const viewId = viewIdProp in props ? props[viewIdProp] : undefined;
|
|
3231
|
+
if (trackProps) {
|
|
3232
|
+
useWhyDidYouUpdate(name, props, viewId); // eslint-disable-line react-hooks/rules-of-hooks
|
|
3233
|
+
}
|
|
3234
|
+
return jsx(Component, { ...props });
|
|
2692
3235
|
};
|
|
2693
|
-
}
|
|
3236
|
+
WrappedComponent.displayName = `withPerformanceTracking(${componentName || Component.displayName || Component.name})`;
|
|
3237
|
+
return WrappedComponent;
|
|
3238
|
+
}
|
|
2694
3239
|
|
|
2695
3240
|
/**
|
|
2696
|
-
*
|
|
2697
|
-
* otherwise returns viz state from global store
|
|
3241
|
+
* Middleware để track store updates
|
|
2698
3242
|
*/
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
3243
|
+
function createStorePerformanceTracker(storeName) {
|
|
3244
|
+
return (config) => (set, get, api) => {
|
|
3245
|
+
const wrappedSet = (partial, replace) => {
|
|
3246
|
+
const startTime = performance.now();
|
|
3247
|
+
const prevState = get();
|
|
3248
|
+
// Call original set
|
|
3249
|
+
set(partial, replace);
|
|
3250
|
+
const duration = performance.now() - startTime;
|
|
3251
|
+
const nextState = get();
|
|
3252
|
+
// Detect which viewIds were affected
|
|
3253
|
+
const affectedViews = new Set();
|
|
3254
|
+
// Check Record<string, any> properties for viewId keys
|
|
3255
|
+
Object.keys(nextState).forEach((key) => {
|
|
3256
|
+
if (typeof prevState[key] === 'object' &&
|
|
3257
|
+
typeof nextState[key] === 'object' &&
|
|
3258
|
+
prevState[key] !== nextState[key]) {
|
|
3259
|
+
// Check if this is a Record<viewId, value> structure
|
|
3260
|
+
const prevKeys = Object.keys(prevState[key] || {});
|
|
3261
|
+
const nextKeys = Object.keys(nextState[key] || {});
|
|
3262
|
+
const allKeys = new Set([...prevKeys, ...nextKeys]);
|
|
3263
|
+
allKeys.forEach((viewId) => {
|
|
3264
|
+
if (prevState[key]?.[viewId] !== nextState[key]?.[viewId]) {
|
|
3265
|
+
affectedViews.add(viewId);
|
|
3266
|
+
}
|
|
3267
|
+
});
|
|
3268
|
+
}
|
|
3269
|
+
});
|
|
3270
|
+
const metric = {
|
|
3271
|
+
id: `store-${storeName}-${Date.now()}`,
|
|
3272
|
+
type: 'store',
|
|
3273
|
+
name: `${storeName} update`,
|
|
3274
|
+
storeName,
|
|
3275
|
+
action: typeof partial === 'function' ? 'function update' : 'direct update',
|
|
3276
|
+
timestamp: Date.now(),
|
|
3277
|
+
duration,
|
|
3278
|
+
affectedViews: Array.from(affectedViews),
|
|
3279
|
+
metadata: {
|
|
3280
|
+
stateKeys: Object.keys(nextState),
|
|
3281
|
+
},
|
|
3282
|
+
};
|
|
3283
|
+
performanceLogger.log(metric);
|
|
2717
3284
|
};
|
|
2718
|
-
|
|
2719
|
-
// Otherwise use global store
|
|
2720
|
-
return {
|
|
2721
|
-
zoomRatio: globalZoomRatio,
|
|
2722
|
-
scale: globalScale,
|
|
2723
|
-
isScaledToFit: globalIsScaledToFit,
|
|
2724
|
-
isRenderViz: globalIsRenderViz,
|
|
2725
|
-
iframeHeight: globalIframeHeight,
|
|
2726
|
-
vizRef: globalVizRef,
|
|
3285
|
+
return config(wrappedSet, get, api);
|
|
2727
3286
|
};
|
|
2728
|
-
}
|
|
3287
|
+
}
|
|
2729
3288
|
/**
|
|
2730
|
-
*
|
|
2731
|
-
* In compare mode, updates the view context
|
|
2732
|
-
* In single/live mode, updates the global store
|
|
3289
|
+
* Track specific store action
|
|
2733
3290
|
*/
|
|
2734
|
-
|
|
2735
|
-
const
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
3291
|
+
function trackStoreAction(storeName, action, viewId, metadata) {
|
|
3292
|
+
const metric = {
|
|
3293
|
+
id: `store-${storeName}-${action}-${Date.now()}`,
|
|
3294
|
+
type: 'store',
|
|
3295
|
+
name: `${storeName}.${action}`,
|
|
3296
|
+
storeName,
|
|
3297
|
+
action,
|
|
3298
|
+
timestamp: Date.now(),
|
|
3299
|
+
viewId,
|
|
3300
|
+
metadata,
|
|
3301
|
+
};
|
|
3302
|
+
performanceLogger.log(metric);
|
|
3303
|
+
}
|
|
3304
|
+
|
|
3305
|
+
function getPerformanceReportJSON() {
|
|
3306
|
+
const report = performanceLogger.generateReport();
|
|
3307
|
+
return JSON.stringify(report, null, 2);
|
|
3308
|
+
}
|
|
3309
|
+
function downloadPerformanceReport(filename = 'heatmap-performance-report.json') {
|
|
3310
|
+
const report = performanceLogger.generateReport();
|
|
3311
|
+
const blob = new Blob([JSON.stringify(report, null, 2)], { type: 'application/json' });
|
|
3312
|
+
const url = URL.createObjectURL(blob);
|
|
3313
|
+
const link = document.createElement('a');
|
|
3314
|
+
link.href = url;
|
|
3315
|
+
link.download = filename;
|
|
3316
|
+
link.click();
|
|
3317
|
+
URL.revokeObjectURL(url);
|
|
3318
|
+
}
|
|
3319
|
+
async function sendPerformanceReport(endpoint) {
|
|
3320
|
+
const report = performanceLogger.generateReport();
|
|
3321
|
+
try {
|
|
3322
|
+
const response = await fetch(endpoint, {
|
|
3323
|
+
method: 'POST',
|
|
3324
|
+
headers: {
|
|
3325
|
+
'Content-Type': 'application/json',
|
|
3326
|
+
},
|
|
3327
|
+
body: JSON.stringify(report),
|
|
3328
|
+
});
|
|
3329
|
+
if (!response.ok) {
|
|
3330
|
+
throw new Error(`Failed to send report: ${response.statusText}`);
|
|
3331
|
+
}
|
|
3332
|
+
}
|
|
3333
|
+
catch (error) {
|
|
3334
|
+
console.error('[Performance] Failed to send report:', error);
|
|
3335
|
+
throw error;
|
|
3336
|
+
}
|
|
3337
|
+
}
|
|
3338
|
+
function printPerformanceSummary() {
|
|
3339
|
+
const report = performanceLogger.generateReport();
|
|
3340
|
+
console.group('📊 Performance Summary');
|
|
3341
|
+
console.log('Session:', report.session);
|
|
3342
|
+
console.log('Total Renders:', report.summary.totalRenders);
|
|
3343
|
+
console.log('Total Hook Calls:', report.summary.totalHookCalls);
|
|
3344
|
+
console.log('Total Store Updates:', report.summary.totalStoreUpdates);
|
|
3345
|
+
console.log('Average Render Time:', `${report.summary.averageRenderTime.toFixed(2)}ms`);
|
|
3346
|
+
console.log('View Metrics:', report.summary.viewMetrics);
|
|
3347
|
+
if (report.warnings.excessiveRenders.length > 0) {
|
|
3348
|
+
console.group('⚠️ Excessive Renders');
|
|
3349
|
+
report.warnings.excessiveRenders.forEach((warning) => {
|
|
3350
|
+
console.warn(`${warning.component}${warning.viewId ? ` (${warning.viewId})` : ''}: ${warning.count} renders`);
|
|
3351
|
+
});
|
|
3352
|
+
console.groupEnd();
|
|
3353
|
+
}
|
|
3354
|
+
if (report.warnings.slowOperations.length > 0) {
|
|
3355
|
+
console.group('🐌 Slow Operations');
|
|
3356
|
+
report.warnings.slowOperations.forEach((warning) => {
|
|
3357
|
+
console.warn(`${warning.name} (${warning.type}): ${warning.duration.toFixed(2)}ms`);
|
|
3358
|
+
});
|
|
3359
|
+
console.groupEnd();
|
|
2751
3360
|
}
|
|
3361
|
+
console.groupEnd();
|
|
3362
|
+
}
|
|
3363
|
+
function getMetricsByViewId(viewId) {
|
|
3364
|
+
const allMetrics = performanceLogger.getMetrics();
|
|
3365
|
+
const filteredMetrics = allMetrics.filter((m) => {
|
|
3366
|
+
return 'viewId' in m && m.viewId === viewId;
|
|
3367
|
+
});
|
|
3368
|
+
const report = performanceLogger.generateReport();
|
|
2752
3369
|
return {
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
3370
|
+
...report,
|
|
3371
|
+
metrics: filteredMetrics,
|
|
3372
|
+
summary: {
|
|
3373
|
+
...report.summary,
|
|
3374
|
+
totalRenders: filteredMetrics.filter((m) => m.type === 'render').length,
|
|
3375
|
+
totalHookCalls: filteredMetrics.filter((m) => m.type === 'hook').length,
|
|
3376
|
+
totalStoreUpdates: filteredMetrics.filter((m) => m.type === 'store').length,
|
|
3377
|
+
averageRenderTime: 0, // Recalculate if needed
|
|
3378
|
+
viewMetrics: {
|
|
3379
|
+
[viewId]: report.summary.viewMetrics[viewId] || {
|
|
3380
|
+
renders: 0,
|
|
3381
|
+
hookCalls: 0,
|
|
3382
|
+
storeUpdates: 0,
|
|
3383
|
+
},
|
|
3384
|
+
},
|
|
3385
|
+
},
|
|
2759
3386
|
};
|
|
2760
|
-
}
|
|
3387
|
+
}
|
|
3388
|
+
function compareViewPerformance(viewId1, viewId2) {
|
|
3389
|
+
const report = performanceLogger.generateReport();
|
|
3390
|
+
const view1Metrics = report.summary.viewMetrics[viewId1] || {
|
|
3391
|
+
renders: 0,
|
|
3392
|
+
hookCalls: 0,
|
|
3393
|
+
storeUpdates: 0,
|
|
3394
|
+
};
|
|
3395
|
+
const view2Metrics = report.summary.viewMetrics[viewId2] || {
|
|
3396
|
+
renders: 0,
|
|
3397
|
+
hookCalls: 0,
|
|
3398
|
+
storeUpdates: 0,
|
|
3399
|
+
};
|
|
3400
|
+
return {
|
|
3401
|
+
view1: view1Metrics,
|
|
3402
|
+
view2: view2Metrics,
|
|
3403
|
+
difference: {
|
|
3404
|
+
renders: view1Metrics.renders - view2Metrics.renders,
|
|
3405
|
+
hookCalls: view1Metrics.hookCalls - view2Metrics.hookCalls,
|
|
3406
|
+
storeUpdates: view1Metrics.storeUpdates - view2Metrics.storeUpdates,
|
|
3407
|
+
},
|
|
3408
|
+
};
|
|
3409
|
+
}
|
|
2761
3410
|
|
|
2762
3411
|
const BoxStack = forwardRef(({ children, ...props }, ref) => {
|
|
2763
3412
|
const id = props.id;
|
|
@@ -2770,7 +3419,7 @@ const BoxStack = forwardRef(({ children, ...props }, ref) => {
|
|
|
2770
3419
|
const style = props.style || {};
|
|
2771
3420
|
const gap = props.gap || 0;
|
|
2772
3421
|
const height = props.height || 'auto';
|
|
2773
|
-
const isZIndexDefined = typeof props.zIndex !== undefined;
|
|
3422
|
+
const isZIndexDefined = typeof props.zIndex !== 'undefined';
|
|
2774
3423
|
const zIndex = props.zIndex;
|
|
2775
3424
|
const backgroundColor = props.backgroundColor || 'transparent';
|
|
2776
3425
|
const styleGap = useMemo(() => {
|
|
@@ -2801,6 +3450,7 @@ const BoxStack = forwardRef(({ children, ...props }, ref) => {
|
|
|
2801
3450
|
};
|
|
2802
3451
|
return (jsx("div", { id: id, style: styleProps, ref: ref, children: children }));
|
|
2803
3452
|
});
|
|
3453
|
+
BoxStack.displayName = 'BoxStack';
|
|
2804
3454
|
|
|
2805
3455
|
const ContentTopBar = () => {
|
|
2806
3456
|
const controls = useHeatmapControlStore((state) => state.controls);
|
|
@@ -2817,8 +3467,9 @@ const ContentTopBar = () => {
|
|
|
2817
3467
|
|
|
2818
3468
|
const ContentMetricBar = () => {
|
|
2819
3469
|
const controls = useHeatmapControlStore((state) => state.controls);
|
|
3470
|
+
const borderBottom = `${HEATMAP_CONFIG.borderWidth}px solid ${HEATMAP_CONFIG.borderColor}`;
|
|
2820
3471
|
return (jsx(BoxStack, { id: "gx-hm-content-metric-bar", flexDirection: "row", alignItems: "center", overflow: "auto", zIndex: 1, backgroundColor: "white", style: {
|
|
2821
|
-
borderBottom
|
|
3472
|
+
borderBottom,
|
|
2822
3473
|
}, children: controls.MetricBar ?? null }));
|
|
2823
3474
|
};
|
|
2824
3475
|
|
|
@@ -2834,30 +3485,88 @@ const ContentToolbar = () => {
|
|
|
2834
3485
|
}, children: controls.Toolbar ?? null }));
|
|
2835
3486
|
};
|
|
2836
3487
|
|
|
3488
|
+
const ContentSidebar = () => {
|
|
3489
|
+
const controls = useHeatmapControlStore((state) => state.controls);
|
|
3490
|
+
const { state } = useHeatmapInteraction();
|
|
3491
|
+
const isHideSidebar = state.hideSidebar;
|
|
3492
|
+
const sidebarWidth = useHeatmapConfigStore((state) => state.sidebarWidth);
|
|
3493
|
+
const mode = useHeatmapConfigStore((state) => state.mode);
|
|
3494
|
+
const SidebarComponent = controls.Sidebar ?? null;
|
|
3495
|
+
const isCompareMode = mode === 'compare';
|
|
3496
|
+
if (isCompareMode)
|
|
3497
|
+
return null;
|
|
3498
|
+
if (!SidebarComponent)
|
|
3499
|
+
return null;
|
|
3500
|
+
return (jsx("div", { className: "gx-hm-sidebar", style: {
|
|
3501
|
+
height: '100%',
|
|
3502
|
+
display: 'flex',
|
|
3503
|
+
zIndex: 1,
|
|
3504
|
+
...(isHideSidebar
|
|
3505
|
+
? {
|
|
3506
|
+
width: '0',
|
|
3507
|
+
transform: 'translateX(-100%)',
|
|
3508
|
+
visibility: 'hidden',
|
|
3509
|
+
}
|
|
3510
|
+
: { width: `${sidebarWidth}px + ${HEATMAP_CONFIG.borderWidth}px` }),
|
|
3511
|
+
}, children: jsx("div", { className: "gx-hm-sidebar-wrapper", style: {
|
|
3512
|
+
height: '100%',
|
|
3513
|
+
width: `calc(${sidebarWidth}px + ${HEATMAP_CONFIG.borderWidth}px)`,
|
|
3514
|
+
borderRight: `${HEATMAP_CONFIG.borderWidth}px solid ${HEATMAP_CONFIG.borderColor}`,
|
|
3515
|
+
}, children: jsx(SidebarComponent, {}) }) }));
|
|
3516
|
+
};
|
|
3517
|
+
|
|
3518
|
+
const PopoverSidebar = () => {
|
|
3519
|
+
const mode = useHeatmapConfigStore((state) => state.mode);
|
|
3520
|
+
const CompSidebar = useHeatmapControlStore((state) => state.controls.Sidebar);
|
|
3521
|
+
const CompSidebarActivator = useHeatmapControlStore((state) => state.controls.SidebarActivator);
|
|
3522
|
+
const sidebarWidth = useHeatmapConfigStore((state) => state.sidebarWidth);
|
|
3523
|
+
const [isPopoverOpen, setIsPopoverOpen] = useState(false);
|
|
3524
|
+
const { state } = useHeatmapInteraction();
|
|
3525
|
+
const isCompareMode = mode === 'compare';
|
|
3526
|
+
const isHideSidebar = state.hideSidebar;
|
|
3527
|
+
const stylePopover = {
|
|
3528
|
+
position: 'absolute',
|
|
3529
|
+
top: '24px',
|
|
3530
|
+
left: '24px',
|
|
3531
|
+
zIndex: Z_INDEX.SIDEBAR_POPOVER,
|
|
3532
|
+
height: `calc(100% - ${HEATMAP_CONFIG.heightToolbar}px - ${HEATMAP_CONFIG.padding}px - 24px)`,
|
|
3533
|
+
width: `calc(${sidebarWidth}px + ${HEATMAP_CONFIG.borderWidth}px)`,
|
|
3534
|
+
};
|
|
3535
|
+
if (isHideSidebar || !isCompareMode)
|
|
3536
|
+
return null;
|
|
3537
|
+
if (!CompSidebar || !CompSidebarActivator)
|
|
3538
|
+
return null;
|
|
3539
|
+
return (jsxs("div", { children: [!isPopoverOpen && (jsx("div", { style: { ...stylePopover, width: 'auto', height: 'auto' }, children: jsx(CompSidebarActivator, { onClick: () => setIsPopoverOpen(true) }) })), isPopoverOpen && (jsx(Fragment, { children: jsx("div", { className: "gx-hm-sidebar-popover", style: {
|
|
3540
|
+
...stylePopover,
|
|
3541
|
+
backgroundColor: '#fff',
|
|
3542
|
+
borderRight: `${HEATMAP_CONFIG.borderWidth}px solid ${HEATMAP_CONFIG.borderColor}`,
|
|
3543
|
+
borderRadius: '8px',
|
|
3544
|
+
boxShadow: '4px 0 12px rgba(0, 0, 0, 0.15)',
|
|
3545
|
+
overflow: 'auto',
|
|
3546
|
+
}, children: jsx(CompSidebar, { closeAction: { onClick: () => setIsPopoverOpen(false) } }) }) }))] }));
|
|
3547
|
+
};
|
|
3548
|
+
|
|
2837
3549
|
const VizContainer = ({ children, isActive = false }) => {
|
|
2838
3550
|
const wrapperRef = useRef(null);
|
|
3551
|
+
const viewId = useViewId();
|
|
2839
3552
|
useWrapperRefHeight({
|
|
2840
3553
|
isActive,
|
|
2841
3554
|
wrapperRef,
|
|
2842
3555
|
});
|
|
2843
|
-
return (
|
|
2844
|
-
|
|
2845
|
-
|
|
3556
|
+
return (jsxs(BoxStack, { ref: wrapperRef, id: `gx-hm-viz-container-${viewId}`, flexDirection: "column", flex: "1 1 auto", overflow: "auto", zIndex: 1, children: [jsx(BoxStack, { id: "gx-hm-content", flexDirection: "column", flex: "1 1 auto", overflow: "hidden", style: {
|
|
3557
|
+
minWidth: '394px',
|
|
3558
|
+
}, children: children }), jsx(PopoverSidebar, {})] }));
|
|
2846
3559
|
};
|
|
2847
3560
|
|
|
2848
3561
|
const useClickmap = () => {
|
|
2849
|
-
const [isInitialized, setIsInitialized] = useState(false);
|
|
2850
|
-
const { clickmap } = useHeatmapData();
|
|
2851
3562
|
const { vizRef } = useHeatmapViz();
|
|
3563
|
+
const { clickmap } = useHeatmapData();
|
|
2852
3564
|
const start = useCallback(() => {
|
|
2853
|
-
if (isInitialized)
|
|
2854
|
-
return;
|
|
2855
3565
|
if (!vizRef || !clickmap || clickmap.length === 0)
|
|
2856
3566
|
return;
|
|
2857
3567
|
try {
|
|
2858
3568
|
vizRef?.clearmap?.();
|
|
2859
3569
|
vizRef?.clickmap?.(clickmap);
|
|
2860
|
-
setIsInitialized(true);
|
|
2861
3570
|
}
|
|
2862
3571
|
catch (error) {
|
|
2863
3572
|
console.error(`🚀 🐥 ~ useClickmap ~ error:`, error);
|
|
@@ -2885,7 +3594,7 @@ const useScrollmap = () => {
|
|
|
2885
3594
|
return { start };
|
|
2886
3595
|
};
|
|
2887
3596
|
|
|
2888
|
-
const useHeatmapCanvas = (
|
|
3597
|
+
const useHeatmapCanvas = () => {
|
|
2889
3598
|
const heatmapType = useHeatmapConfigStore((state) => state.heatmapType);
|
|
2890
3599
|
const { start: startClickmap } = useClickmap();
|
|
2891
3600
|
const { start: startScrollmap } = useScrollmap();
|
|
@@ -2901,10 +3610,28 @@ const useHeatmapCanvas = ({ iframeRef, }) => {
|
|
|
2901
3610
|
}, [heatmapType, startClickmap, startScrollmap]);
|
|
2902
3611
|
};
|
|
2903
3612
|
|
|
2904
|
-
|
|
2905
|
-
const
|
|
2906
|
-
const
|
|
2907
|
-
const
|
|
3613
|
+
// Base IDs for elements (without viewId suffix)
|
|
3614
|
+
const CLICKED_ELEMENT_ID_BASE = 'gx-hm-clicked-element';
|
|
3615
|
+
const SECONDARY_CLICKED_ELEMENT_ID_BASE = 'gx-hm-secondary-clicked-element';
|
|
3616
|
+
const HOVERED_ELEMENT_ID_BASE = 'gx-hm-hovered-element';
|
|
3617
|
+
const SECONDARY_HOVERED_ELEMENT_ID_BASE = 'gx-hm-secondary-hovered-element';
|
|
3618
|
+
/**
|
|
3619
|
+
* Generate unique element ID for a specific view
|
|
3620
|
+
* @param baseId - Base element ID
|
|
3621
|
+
* @param viewId - View ID
|
|
3622
|
+
* @returns Unique element ID (e.g., 'gx-hm-clicked-element-view-0')
|
|
3623
|
+
*/
|
|
3624
|
+
const getElementId = (baseId, viewId) => {
|
|
3625
|
+
return `${baseId}-${viewId}`;
|
|
3626
|
+
};
|
|
3627
|
+
const getClickedElementId = (viewId, isSecondary = false) => {
|
|
3628
|
+
const baseId = isSecondary ? SECONDARY_CLICKED_ELEMENT_ID_BASE : CLICKED_ELEMENT_ID_BASE;
|
|
3629
|
+
return getElementId(baseId, viewId);
|
|
3630
|
+
};
|
|
3631
|
+
const getHoveredElementId = (viewId, isSecondary = false) => {
|
|
3632
|
+
const baseId = isSecondary ? SECONDARY_HOVERED_ELEMENT_ID_BASE : HOVERED_ELEMENT_ID_BASE;
|
|
3633
|
+
return getElementId(baseId, viewId);
|
|
3634
|
+
};
|
|
2908
3635
|
|
|
2909
3636
|
const RankBadge = ({ index, elementRect, widthScale, clickOnElement, }) => {
|
|
2910
3637
|
const style = calculateRankPosition(elementRect, widthScale);
|
|
@@ -2934,6 +3661,7 @@ const DEFAULT_POSITION = {
|
|
|
2934
3661
|
};
|
|
2935
3662
|
const ElementCallout = (props) => {
|
|
2936
3663
|
const CompElementCallout = useHeatmapControlStore((state) => state.controls.ElementCallout);
|
|
3664
|
+
const viewId = useViewId();
|
|
2937
3665
|
const { element, target, visualRef, hozOffset, alignment = 'left' } = props;
|
|
2938
3666
|
const calloutRef = useRef(null);
|
|
2939
3667
|
const [position, setPosition] = useState(DEFAULT_POSITION);
|
|
@@ -2948,6 +3676,7 @@ const ElementCallout = (props) => {
|
|
|
2948
3676
|
setPosition,
|
|
2949
3677
|
hozOffset,
|
|
2950
3678
|
alignment,
|
|
3679
|
+
containerElm: visualRef?.current,
|
|
2951
3680
|
});
|
|
2952
3681
|
positionFn();
|
|
2953
3682
|
const handleUpdate = () => {
|
|
@@ -2966,9 +3695,9 @@ const ElementCallout = (props) => {
|
|
|
2966
3695
|
position: 'fixed',
|
|
2967
3696
|
top: position.top,
|
|
2968
3697
|
left: position.left,
|
|
2969
|
-
zIndex:
|
|
3698
|
+
zIndex: Z_INDEX.CALLOUT,
|
|
2970
3699
|
}, "aria-live": "assertive", role: "tooltip", children: CompElementCallout && jsx(CompElementCallout, { elementHash: element.hash }) }));
|
|
2971
|
-
return createPortal(calloutContent, document.getElementById(
|
|
3700
|
+
return createPortal(calloutContent, document.getElementById(`gx-hm-viz-container-${viewId}`));
|
|
2972
3701
|
};
|
|
2973
3702
|
|
|
2974
3703
|
const ElementMissing = ({ show = true }) => {
|
|
@@ -2992,17 +3721,8 @@ const ElementMissing = ({ show = true }) => {
|
|
|
2992
3721
|
}, "aria-live": "assertive", children: "Element not visible on current screen" }));
|
|
2993
3722
|
};
|
|
2994
3723
|
|
|
2995
|
-
const
|
|
2996
|
-
|
|
2997
|
-
default: HOVERED_ELEMENT_ID,
|
|
2998
|
-
secondary: SECONDARY_HOVERED_ELEMENT_ID,
|
|
2999
|
-
},
|
|
3000
|
-
clicked: {
|
|
3001
|
-
default: CLICKED_ELEMENT_ID,
|
|
3002
|
-
secondary: SECONDARY_CLICKED_ELEMENT_ID,
|
|
3003
|
-
},
|
|
3004
|
-
};
|
|
3005
|
-
const ElementOverlay = ({ type, element, onClick, isSecondary }) => {
|
|
3724
|
+
const ElementOverlay = ({ type, element, onClick, isSecondary, elementId, }) => {
|
|
3725
|
+
// useRenderCount('ElementOverlay');
|
|
3006
3726
|
const { widthScale } = useHeatmapViz();
|
|
3007
3727
|
if (!element || (element.width === 0 && element.height === 0))
|
|
3008
3728
|
return null;
|
|
@@ -3011,8 +3731,7 @@ const ElementOverlay = ({ type, element, onClick, isSecondary }) => {
|
|
|
3011
3731
|
const left = element.left + HEATMAP_CONFIG['borderWidthIframe'];
|
|
3012
3732
|
const width = element.width;
|
|
3013
3733
|
const height = element.height;
|
|
3014
|
-
|
|
3015
|
-
return (jsxs(Fragment$1, { children: [jsx("div", { onClick: onClick, className: "heatmapElement", id: targetId, style: {
|
|
3734
|
+
return (jsxs(Fragment$1, { children: [jsx("div", { onClick: onClick, className: "heatmapElement", id: elementId, style: {
|
|
3016
3735
|
top,
|
|
3017
3736
|
left,
|
|
3018
3737
|
width,
|
|
@@ -3026,14 +3745,17 @@ const ELEMENT_CALLOUT = {
|
|
|
3026
3745
|
alignment: 'left',
|
|
3027
3746
|
};
|
|
3028
3747
|
const HeatmapElements = (props) => {
|
|
3748
|
+
const viewId = useViewId();
|
|
3029
3749
|
const { iframeHeight } = useHeatmapViz();
|
|
3030
|
-
const
|
|
3750
|
+
const clickedElementId = getClickedElementId(viewId, props.isSecondary);
|
|
3751
|
+
const hoveredElementId = getHoveredElementId(viewId, props.isSecondary);
|
|
3752
|
+
const { iframeRef, wrapperRef, visualRef, visualizer, iframeDimensions, isVisible = true, areDefaultRanksHidden, isSecondary, } = props;
|
|
3031
3753
|
const getRect = useHeatmapElementPosition({
|
|
3032
3754
|
iframeRef,
|
|
3033
3755
|
wrapperRef,
|
|
3034
3756
|
visualizer,
|
|
3035
3757
|
});
|
|
3036
|
-
const { clickedElement, showMissingElement, shouldShowCallout
|
|
3758
|
+
const { clickedElement, showMissingElement, shouldShowCallout } = useClickedElement({
|
|
3037
3759
|
visualRef,
|
|
3038
3760
|
getRect,
|
|
3039
3761
|
});
|
|
@@ -3041,25 +3763,12 @@ const HeatmapElements = (props) => {
|
|
|
3041
3763
|
iframeRef,
|
|
3042
3764
|
getRect,
|
|
3043
3765
|
});
|
|
3044
|
-
useElementCalloutVisible({
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
});
|
|
3048
|
-
const resetAll = () => {
|
|
3049
|
-
// setShouldShowCallout(false);
|
|
3050
|
-
};
|
|
3051
|
-
useHeatmapEffects({
|
|
3052
|
-
isVisible,
|
|
3053
|
-
isElementSidebarOpen,
|
|
3054
|
-
setShouldShowCallout,
|
|
3055
|
-
resetAll,
|
|
3056
|
-
});
|
|
3766
|
+
useElementCalloutVisible({ visualRef, getRect });
|
|
3767
|
+
useHeatmapEffects({ isVisible });
|
|
3768
|
+
useRenderCount('HeatmapElements');
|
|
3057
3769
|
if (!isVisible)
|
|
3058
3770
|
return null;
|
|
3059
|
-
return (jsxs("div", { onMouseMove: (
|
|
3060
|
-
handleMouseMove(event);
|
|
3061
|
-
// handleMouseMove2(event as any);
|
|
3062
|
-
}, 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 }))] }));
|
|
3771
|
+
return (jsxs("div", { onMouseMove: handleMouseMove, onMouseLeave: handleMouseLeave, className: "gx-hm-elements", style: { ...iframeDimensions, height: `${iframeHeight}px` }, children: [jsx(ElementMissing, { show: showMissingElement }), jsx(DefaultRankBadges, { getRect: getRect, hidden: areDefaultRanksHidden }), jsx(ElementOverlay, { type: "clicked", element: clickedElement, isSecondary: isSecondary, elementId: clickedElementId }), jsx(ElementOverlay, { type: "hovered", element: hoveredElement, isSecondary: isSecondary, onClick: handleClick, elementId: hoveredElementId }), hoveredElement?.hash !== clickedElement?.hash && hoveredElement && (jsx(ElementCallout, { element: hoveredElement, target: `#${hoveredElementId}`, visualRef: visualRef, ...ELEMENT_CALLOUT })), shouldShowCallout && clickedElement && (jsx(ElementCallout, { element: clickedElement, target: `#${clickedElementId}`, visualRef: visualRef, ...ELEMENT_CALLOUT }))] }));
|
|
3063
3772
|
};
|
|
3064
3773
|
|
|
3065
3774
|
const VizElements = ({ iframeRef, visualRef, wrapperRef }) => {
|
|
@@ -3068,23 +3777,12 @@ const VizElements = ({ iframeRef, visualRef, wrapperRef }) => {
|
|
|
3068
3777
|
const { vizRef } = useHeatmapViz();
|
|
3069
3778
|
const visualizer = {
|
|
3070
3779
|
get: (hash) => {
|
|
3071
|
-
if (vizRef)
|
|
3072
|
-
return vizRef.get(hash);
|
|
3073
|
-
}
|
|
3074
|
-
const doc = iframeRef.current?.contentDocument;
|
|
3075
|
-
if (!doc)
|
|
3780
|
+
if (!vizRef)
|
|
3076
3781
|
return null;
|
|
3077
|
-
|
|
3078
|
-
if (elmHashAlpha) {
|
|
3079
|
-
return elmHashAlpha;
|
|
3080
|
-
}
|
|
3081
|
-
const elmHash = doc.querySelector(`[data-clarity-hash="${hash}"]`);
|
|
3082
|
-
if (elmHash) {
|
|
3083
|
-
return elmHash;
|
|
3084
|
-
}
|
|
3085
|
-
return null;
|
|
3782
|
+
return vizRef.get(hash);
|
|
3086
3783
|
},
|
|
3087
3784
|
};
|
|
3785
|
+
// useRenderCount('VizElements');
|
|
3088
3786
|
if (!iframeRef.current)
|
|
3089
3787
|
return null;
|
|
3090
3788
|
return (jsx(HeatmapElements, { visualizer: visualizer, visualRef: visualRef, iframeRef: iframeRef, wrapperRef: wrapperRef, heatmapInfo: dataInfo, isVisible: true, iframeDimensions: {
|
|
@@ -3209,8 +3907,8 @@ const ScrollmapMarker = ({ iframeRef, wrapperRef }) => {
|
|
|
3209
3907
|
};
|
|
3210
3908
|
|
|
3211
3909
|
const ScrollMapMinimap = ({ zones, maxUsers }) => {
|
|
3212
|
-
const showMinimap = useHeatmapVizScrollmapStore((state) => state.showMinimap);
|
|
3213
3910
|
const scrollType = useHeatmapConfigStore((state) => state.scrollType);
|
|
3911
|
+
const { showMinimap } = useHeatmapVizScrollmap();
|
|
3214
3912
|
const isScrollType = [IScrollType.Attention].includes(scrollType);
|
|
3215
3913
|
if (!showMinimap || !isScrollType)
|
|
3216
3914
|
return null;
|
|
@@ -3370,6 +4068,7 @@ const SCROLL_TYPES = [IHeatmapType.Scroll];
|
|
|
3370
4068
|
const VizScrollMap = ({ iframeRef, wrapperRef }) => {
|
|
3371
4069
|
const heatmapType = useHeatmapConfigStore((state) => state.heatmapType);
|
|
3372
4070
|
const { iframeHeight } = useHeatmapViz();
|
|
4071
|
+
// useRenderCount('VizScrollMap');
|
|
3373
4072
|
const isHeatmapScroll = SCROLL_TYPES.includes(heatmapType);
|
|
3374
4073
|
if (!iframeHeight || !isHeatmapScroll)
|
|
3375
4074
|
return null;
|
|
@@ -3386,9 +4085,7 @@ const VizScrollMap = ({ iframeRef, wrapperRef }) => {
|
|
|
3386
4085
|
const WrapperVisual = ({ children, visualRef, wrapperRef, scaledHeight, iframeHeight, onScroll, }) => {
|
|
3387
4086
|
const contentWidth = useHeatmapConfigStore((state) => state.width);
|
|
3388
4087
|
const { widthScale } = useHeatmapViz();
|
|
3389
|
-
const contentHeight =
|
|
3390
|
-
? `${scaledHeight + HEATMAP_CONFIG['heightToolbar'] + HEATMAP_CONFIG['padding'] * 2}px`
|
|
3391
|
-
: 'auto';
|
|
4088
|
+
const contentHeight = calcContentHeight();
|
|
3392
4089
|
return (jsx("div", { ref: visualRef, className: "gx-hm-visual", onScroll: onScroll, style: {
|
|
3393
4090
|
overflow: 'hidden scroll',
|
|
3394
4091
|
display: 'flex',
|
|
@@ -3413,15 +4110,20 @@ const WrapperVisual = ({ children, visualRef, wrapperRef, scaledHeight, iframeHe
|
|
|
3413
4110
|
transformOrigin: 'top center',
|
|
3414
4111
|
paddingBlockEnd: '0',
|
|
3415
4112
|
}, children: children }) }) }));
|
|
4113
|
+
function calcContentHeight() {
|
|
4114
|
+
return scaledHeight > 0
|
|
4115
|
+
? `${scaledHeight + HEATMAP_CONFIG['heightToolbar'] + HEATMAP_CONFIG['padding'] * 2}px`
|
|
4116
|
+
: 'auto';
|
|
4117
|
+
}
|
|
3416
4118
|
};
|
|
3417
4119
|
|
|
3418
4120
|
const VizDomRenderer = ({ mode = 'heatmap' }) => {
|
|
3419
|
-
const
|
|
4121
|
+
const contentWidth = useHeatmapConfigStore((state) => state.width || 0);
|
|
3420
4122
|
const heatmapType = useHeatmapConfigStore((state) => state.heatmapType);
|
|
3421
|
-
const setSelectedElement = useHeatmapInteractionStore((state) => state.setSelectedElement);
|
|
3422
|
-
const { iframeHeight, setIframeHeight, isRenderViz } = useHeatmapViz();
|
|
3423
4123
|
const wrapperRef = useRef(null);
|
|
3424
4124
|
const visualRef = useRef(null);
|
|
4125
|
+
const { setSelectedElement } = useHeatmapInteraction();
|
|
4126
|
+
const { iframeHeight, setIframeHeight, isRenderViz } = useHeatmapViz();
|
|
3425
4127
|
const { iframeRef } = useHeatmapVizRender(mode);
|
|
3426
4128
|
const { scaledHeight, handleScroll } = useHeatmapScale({
|
|
3427
4129
|
wrapperRef,
|
|
@@ -3430,12 +4132,12 @@ const VizDomRenderer = ({ mode = 'heatmap' }) => {
|
|
|
3430
4132
|
iframeHeight,
|
|
3431
4133
|
isRenderViz,
|
|
3432
4134
|
});
|
|
3433
|
-
|
|
4135
|
+
useHeatmapCanvas();
|
|
4136
|
+
useRenderCount('VizDomRenderer');
|
|
3434
4137
|
const onScroll = (e) => {
|
|
3435
4138
|
const scrollTop = e.currentTarget.scrollTop;
|
|
3436
4139
|
handleScroll(scrollTop);
|
|
3437
4140
|
};
|
|
3438
|
-
useHeatmapCanvas({ iframeRef: iframeRef });
|
|
3439
4141
|
const cleanUp = () => {
|
|
3440
4142
|
setIframeHeight(0);
|
|
3441
4143
|
setSelectedElement(null);
|
|
@@ -3451,21 +4153,15 @@ const VizLoading = () => {
|
|
|
3451
4153
|
};
|
|
3452
4154
|
|
|
3453
4155
|
const VizDomHeatmap = () => {
|
|
3454
|
-
const
|
|
3455
|
-
|
|
3456
|
-
console.log(`🚀 🐥 ~ VizDomHeatmap ~ isRendering:`, isRendering);
|
|
3457
|
-
const { iframeHeight, setIframeHeight, setVizRef } = useHeatmapViz();
|
|
3458
|
-
const viewId = useViewId();
|
|
4156
|
+
const { iframeHeight, setIframeHeight } = useHeatmapViz();
|
|
4157
|
+
useRenderCount('VizDomHeatmap');
|
|
3459
4158
|
useEffect(() => {
|
|
3460
4159
|
return () => {
|
|
3461
|
-
console.log(
|
|
3462
|
-
setVizRef(null);
|
|
4160
|
+
console.log('🚀 🐥 ~ useEffect ~ return:');
|
|
3463
4161
|
setIframeHeight(0);
|
|
3464
4162
|
};
|
|
3465
4163
|
}, []);
|
|
3466
|
-
|
|
3467
|
-
return controls.VizLoading ?? null;
|
|
3468
|
-
return (jsxs(VizContainer, { children: [jsx(VizDomRenderer, {}), iframeHeight === 0 && jsx(VizLoading, {})] }));
|
|
4164
|
+
return (jsxs(VizContainer, { isActive: true, children: [jsx(VizDomRenderer, {}), iframeHeight === 0 && jsx(VizLoading, {})] }));
|
|
3469
4165
|
};
|
|
3470
4166
|
|
|
3471
4167
|
const VizLiveRenderer = () => {
|
|
@@ -3480,7 +4176,6 @@ const VizLiveRenderer = () => {
|
|
|
3480
4176
|
visualRef,
|
|
3481
4177
|
iframeHeight,
|
|
3482
4178
|
isRenderViz,
|
|
3483
|
-
setIframeHeight,
|
|
3484
4179
|
});
|
|
3485
4180
|
const onScroll = (e) => {
|
|
3486
4181
|
const scrollTop = e.currentTarget.scrollTop;
|
|
@@ -3492,8 +4187,6 @@ const VizLiveRenderer = () => {
|
|
|
3492
4187
|
};
|
|
3493
4188
|
|
|
3494
4189
|
const VizLiveHeatmap = () => {
|
|
3495
|
-
const controls = useHeatmapControlStore((state) => state.controls);
|
|
3496
|
-
const isRendering = useHeatmapConfigStore((state) => state.isRendering);
|
|
3497
4190
|
const { iframeHeight, wrapperHeight } = useHeatmapViz();
|
|
3498
4191
|
const reset = useHeatmapLiveStore((state) => state.reset);
|
|
3499
4192
|
useEffect(() => {
|
|
@@ -3501,13 +4194,15 @@ const VizLiveHeatmap = () => {
|
|
|
3501
4194
|
reset();
|
|
3502
4195
|
};
|
|
3503
4196
|
}, []);
|
|
3504
|
-
if (isRendering)
|
|
3505
|
-
return controls.VizLoading ?? null;
|
|
3506
4197
|
return (jsxs(VizContainer, { isActive: true, children: [jsx(VizLiveRenderer, {}), (!iframeHeight || !wrapperHeight) && jsx(VizLoading, {})] }));
|
|
3507
4198
|
};
|
|
3508
4199
|
|
|
3509
4200
|
const ContentVizByMode = () => {
|
|
3510
4201
|
const mode = useHeatmapConfigStore((state) => state.mode);
|
|
4202
|
+
const isRendering = useHeatmapConfigStore((state) => state.isRendering);
|
|
4203
|
+
const controls = useHeatmapControlStore((state) => state.controls);
|
|
4204
|
+
if (isRendering)
|
|
4205
|
+
return controls.VizLoading ?? null;
|
|
3511
4206
|
switch (mode) {
|
|
3512
4207
|
case 'live':
|
|
3513
4208
|
return jsx(VizLiveHeatmap, {});
|
|
@@ -3518,75 +4213,12 @@ const ContentVizByMode = () => {
|
|
|
3518
4213
|
}
|
|
3519
4214
|
};
|
|
3520
4215
|
|
|
3521
|
-
const LeftSidebar = () => {
|
|
3522
|
-
const controls = useHeatmapControlStore((state) => state.controls);
|
|
3523
|
-
const isHideSidebar = useHeatmapInteractionStore((state) => state.state.hideSidebar);
|
|
3524
|
-
const sidebarWidth = useHeatmapConfigStore((state) => state.sidebarWidth);
|
|
3525
|
-
const mode = useHeatmapConfigStore((state) => state.mode);
|
|
3526
|
-
const [isPopoverOpen, setIsPopoverOpen] = useState(false);
|
|
3527
|
-
// In compare mode, render as popover
|
|
3528
|
-
if (mode === 'compare') {
|
|
3529
|
-
return (jsxs("div", { style: { position: 'relative', zIndex: 10 }, children: [jsx("button", { onClick: () => setIsPopoverOpen(!isPopoverOpen), style: {
|
|
3530
|
-
position: 'absolute',
|
|
3531
|
-
top: '8px',
|
|
3532
|
-
left: '8px',
|
|
3533
|
-
padding: '8px 16px',
|
|
3534
|
-
backgroundColor: '#fff',
|
|
3535
|
-
border: '1px solid #c9cccf',
|
|
3536
|
-
borderRadius: '8px',
|
|
3537
|
-
cursor: 'pointer',
|
|
3538
|
-
fontSize: '14px',
|
|
3539
|
-
fontWeight: 500,
|
|
3540
|
-
zIndex: 11,
|
|
3541
|
-
boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)',
|
|
3542
|
-
}, children: "Click data" }), isPopoverOpen && (jsxs(Fragment, { children: [jsx("div", { onClick: () => setIsPopoverOpen(false), style: {
|
|
3543
|
-
position: 'fixed',
|
|
3544
|
-
top: 0,
|
|
3545
|
-
left: 0,
|
|
3546
|
-
right: 0,
|
|
3547
|
-
bottom: 0,
|
|
3548
|
-
backgroundColor: 'rgba(0, 0, 0, 0.3)',
|
|
3549
|
-
zIndex: 12,
|
|
3550
|
-
} }), jsx("div", { className: "gx-hm-sidebar-popover", style: {
|
|
3551
|
-
position: 'fixed',
|
|
3552
|
-
top: 0,
|
|
3553
|
-
left: 0,
|
|
3554
|
-
height: '100vh',
|
|
3555
|
-
width: `calc(${sidebarWidth}px + ${HEATMAP_CONFIG.borderWidth}px)`,
|
|
3556
|
-
backgroundColor: '#fff',
|
|
3557
|
-
borderRight: `${HEATMAP_CONFIG.borderWidth}px solid ${HEATMAP_CONFIG.borderColor}`,
|
|
3558
|
-
zIndex: 13,
|
|
3559
|
-
boxShadow: '4px 0 12px rgba(0, 0, 0, 0.15)',
|
|
3560
|
-
overflow: 'auto',
|
|
3561
|
-
}, children: controls.Sidebar ?? null })] }))] }));
|
|
3562
|
-
}
|
|
3563
|
-
// Normal sidebar rendering for single mode
|
|
3564
|
-
if (isHideSidebar) {
|
|
3565
|
-
return null;
|
|
3566
|
-
}
|
|
3567
|
-
return (jsx("div", { className: "gx-hm-sidebar", style: {
|
|
3568
|
-
height: '100%',
|
|
3569
|
-
display: 'flex',
|
|
3570
|
-
zIndex: 1,
|
|
3571
|
-
...(isHideSidebar
|
|
3572
|
-
? {
|
|
3573
|
-
width: '0',
|
|
3574
|
-
transform: 'translateX(-100%)',
|
|
3575
|
-
visibility: 'hidden',
|
|
3576
|
-
}
|
|
3577
|
-
: { width: `${sidebarWidth}px + ${HEATMAP_CONFIG.borderWidth}px` }),
|
|
3578
|
-
}, children: jsx("div", { className: "gx-hm-sidebar-wrapper", style: {
|
|
3579
|
-
height: '100%',
|
|
3580
|
-
width: `calc(${sidebarWidth}px + ${HEATMAP_CONFIG.borderWidth}px)`,
|
|
3581
|
-
borderRight: `${HEATMAP_CONFIG.borderWidth}px solid ${HEATMAP_CONFIG.borderColor}`,
|
|
3582
|
-
}, children: controls.Sidebar ?? null }) }));
|
|
3583
|
-
};
|
|
3584
|
-
|
|
3585
4216
|
const WrapperPreview = () => {
|
|
3586
|
-
return (jsxs(BoxStack, { id: "gx-hm-container", flexDirection: "row", overflow: "hidden", flex: "1", position: "relative", children: [jsx(
|
|
4217
|
+
return (jsxs(BoxStack, { id: "gx-hm-container", flexDirection: "row", overflow: "hidden", flex: "1", position: "relative", children: [jsx(ContentSidebar, {}), jsxs(BoxStack, { flexDirection: "column", flex: "1", children: [jsx(ContentMetricBar, {}), jsx(ContentVizByMode, {}), jsx(ContentToolbar, {})] })] }));
|
|
3587
4218
|
};
|
|
3588
4219
|
|
|
3589
4220
|
const WrapperLayout = () => {
|
|
4221
|
+
useRenderCount('WrapperLayout');
|
|
3590
4222
|
return (jsxs(BoxStack, { id: "gx-hm-layout", flexDirection: "column", flex: "1", children: [jsx(ContentTopBar, {}), jsx(WrapperPreview, {})] }));
|
|
3591
4223
|
};
|
|
3592
4224
|
|
|
@@ -3595,6 +4227,19 @@ const HeatmapLayout = ({ data, clickmap, scrollmap, controls, dataInfo, }) => {
|
|
|
3595
4227
|
useRegisterData(data, dataInfo);
|
|
3596
4228
|
useRegisterHeatmap({ clickmap, scrollmap });
|
|
3597
4229
|
useRegisterConfig();
|
|
4230
|
+
performanceLogger.configure({
|
|
4231
|
+
enabled: true,
|
|
4232
|
+
logToConsole: false,
|
|
4233
|
+
logLevel: 'normal', // 'verbose' | 'normal' | 'minimal'
|
|
4234
|
+
thresholds: {
|
|
4235
|
+
slowRenderMs: 16, // Warn if render > 16ms (60fps)
|
|
4236
|
+
slowHookMs: 5, // Warn if hook > 5ms
|
|
4237
|
+
excessiveRenderCount: 10, // Warn if component renders > 10 times
|
|
4238
|
+
},
|
|
4239
|
+
externalLogger: (metric) => {
|
|
4240
|
+
if (metric.name === 'VizDomRenderer') ;
|
|
4241
|
+
},
|
|
4242
|
+
});
|
|
3598
4243
|
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: {
|
|
3599
4244
|
minHeight: '100%',
|
|
3600
4245
|
display: 'flex',
|
|
@@ -3608,4 +4253,4 @@ const HeatmapLayout = ({ data, clickmap, scrollmap, controls, dataInfo, }) => {
|
|
|
3608
4253
|
}
|
|
3609
4254
|
};
|
|
3610
4255
|
|
|
3611
|
-
export { GraphView, HeatmapLayout, IClickType, IHeatmapType, IScrollType, ViewIdContext, convertViewportToIframeCoords, getScrollGradientColor,
|
|
4256
|
+
export { DEFAULT_SIDEBAR_WIDTH, DEFAULT_VIEW_ID, GraphView, HEATMAP_CONFIG, HEATMAP_IFRAME, HEATMAP_STYLE, HeatmapLayout, IClickType, IHeatmapType, IScrollType, ViewIdContext, Z_INDEX, compareViewPerformance, convertViewportToIframeCoords, createStorePerformanceTracker, downloadPerformanceReport, getCompareViewId, getCompareViewIndex, getMetricsByViewId, getPerformanceReportJSON, getScrollGradientColor, isCompareViewId, performanceLogger, printPerformanceSummary, sendPerformanceReport, trackStoreAction, useClickedElement, useDebounceCallback, useElementCalloutVisible, useHeatmapCompareStore, useHeatmapConfigStore, useHeatmapCopyView, useHeatmapData, useHeatmapDataStore, useHeatmapEffects, useHeatmapElementPosition, useHeatmapInteraction, useHeatmapInteractionStore, useHeatmapLiveStore, useHeatmapScale, useHeatmapSingleStore, useHeatmapViz, useHeatmapVizRender, useHeatmapVizScrollmap, useHeatmapVizScrollmapStore, useHeatmapVizStore, useHoveredElement, useIsCompareMode, useMeasureFunction, useRegisterConfig, useRegisterControl, useRegisterData, useRegisterHeatmap, useRenderCount, useScrollmapZones, useTrackHookCall, useViewId, useVizLiveRender, useWhyDidYouUpdate, useWrapperRefHeight, useZonePositions, withPerformanceTracking };
|