@gemx-dev/heatmap-react 3.5.44 → 3.5.46
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/components/Layout/ContentHeader.d.ts +4 -0
- package/dist/esm/components/Layout/ContentHeader.d.ts.map +1 -0
- package/dist/esm/components/Layout/VizMode.d.ts +2 -0
- package/dist/esm/components/Layout/VizMode.d.ts.map +1 -0
- package/dist/esm/components/Test.d.ts +121 -0
- package/dist/esm/components/Test.d.ts.map +1 -0
- package/dist/esm/components/VizDom/VizDomContainer.d.ts +6 -0
- package/dist/esm/components/VizDom/VizDomContainer.d.ts.map +1 -0
- package/dist/esm/components/VizDom/VizDomRenderer.d.ts.map +1 -1
- package/dist/esm/components/VizElement/ClickedElementOverlay.d.ts +17 -0
- package/dist/esm/components/VizElement/ClickedElementOverlay.d.ts.map +1 -0
- package/dist/esm/components/VizElement/HeatmapElements.d.ts.map +1 -1
- package/dist/esm/components/VizElement/HoveredElementOverlay.d.ts +12 -0
- package/dist/esm/components/VizElement/HoveredElementOverlay.d.ts.map +1 -0
- package/dist/esm/components/VizElement/MissingElementMessage.d.ts +7 -0
- package/dist/esm/components/VizElement/MissingElementMessage.d.ts.map +1 -0
- package/dist/esm/components/VizElement/VizElements.d.ts.map +1 -1
- package/dist/esm/components/VizElement/temp/ClarityVisualizer.d.ts +150 -0
- package/dist/esm/components/VizElement/temp/ClarityVisualizer.d.ts.map +1 -0
- package/dist/esm/components/VizElement/temp/VizElementRank.d.ts +74 -0
- package/dist/esm/components/VizElement/temp/VizElementRank.d.ts.map +1 -0
- package/dist/esm/components/VizLive/VizLive.d.ts +2 -0
- package/dist/esm/components/VizLive/VizLive.d.ts.map +1 -0
- package/dist/esm/components/VizLive/VizLiveHeatmap.d.ts.map +1 -1
- package/dist/esm/components/VizLive/VizLiveRenderer.d.ts.map +1 -1
- package/dist/esm/configs/style.d.ts +0 -2
- package/dist/esm/configs/style.d.ts.map +1 -1
- package/dist/esm/helpers/index.d.ts +2 -1
- package/dist/esm/helpers/index.d.ts.map +1 -1
- package/dist/esm/helpers/viewport-fixer.d.ts +13 -0
- package/dist/esm/helpers/viewport-fixer.d.ts.map +1 -0
- package/dist/esm/helpers/viewport-replacer.d.ts +26 -0
- package/dist/esm/helpers/viewport-replacer.d.ts.map +1 -0
- package/dist/esm/hooks/vix-elements/useHoveredElement.d.ts.map +1 -1
- package/dist/esm/hooks/viz-canvas/useClickmap.d.ts +1 -3
- package/dist/esm/hooks/viz-canvas/useClickmap.d.ts.map +1 -1
- package/dist/esm/hooks/viz-canvas/useHeatmapVizCanvas.d.ts +1 -1
- package/dist/esm/hooks/viz-canvas/useHeatmapVizCanvas.d.ts.map +1 -1
- package/dist/esm/hooks/viz-canvas/useScrollmap.d.ts +1 -3
- package/dist/esm/hooks/viz-canvas/useScrollmap.d.ts.map +1 -1
- package/dist/esm/hooks/viz-live/index.d.ts +1 -1
- package/dist/esm/hooks/viz-live/{useVizLiveIframeMsg.d.ts → useIframeMessage.d.ts} +10 -2
- package/dist/esm/hooks/viz-live/useIframeMessage.d.ts.map +1 -0
- package/dist/esm/hooks/viz-render/useHeatmapRender.d.ts.map +1 -1
- package/dist/esm/hooks/viz-scale/useContainerDimensions.d.ts.map +1 -1
- package/dist/esm/hooks/viz-scale/useHeatmapScale.d.ts +1 -1
- package/dist/esm/hooks/viz-scale/useHeatmapScale.d.ts.map +1 -1
- package/dist/esm/hooks/viz-scale/useIframeHeight.d.ts +10 -0
- package/dist/esm/hooks/viz-scale/useIframeHeight.d.ts.map +1 -0
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +203 -910
- package/dist/esm/index.mjs +203 -910
- package/dist/esm/stores/index.d.ts +0 -1
- package/dist/esm/stores/index.d.ts.map +1 -1
- package/dist/esm/stores/interaction.d.ts.map +1 -1
- package/dist/esm/stores/mode-live.d.ts +0 -4
- package/dist/esm/stores/mode-live.d.ts.map +1 -1
- package/dist/esm/stores/viz.d.ts +4 -0
- package/dist/esm/stores/viz.d.ts.map +1 -1
- package/dist/esm/types/index.d.ts +1 -1
- package/dist/esm/types/index.d.ts.map +1 -1
- package/dist/esm/types/viewport-fixer.d.ts +31 -0
- package/dist/esm/types/viewport-fixer.d.ts.map +1 -0
- package/dist/umd/components/Layout/ContentHeader.d.ts +4 -0
- package/dist/umd/components/Layout/ContentHeader.d.ts.map +1 -0
- package/dist/umd/components/Test.d.ts +121 -0
- package/dist/umd/components/Test.d.ts.map +1 -0
- package/dist/umd/components/VizDom/VizDomContainer.d.ts +2 -0
- package/dist/umd/components/VizDom/VizDomContainer.d.ts.map +1 -0
- package/dist/umd/components/VizDom/VizDomRenderer.d.ts.map +1 -1
- package/dist/umd/components/VizElement/ClickedElementOverlay.d.ts +17 -0
- package/dist/umd/components/VizElement/ClickedElementOverlay.d.ts.map +1 -0
- package/dist/umd/components/VizElement/HeatmapElements.d.ts.map +1 -1
- package/dist/umd/components/VizElement/HoveredElementOverlay.d.ts +12 -0
- package/dist/umd/components/VizElement/HoveredElementOverlay.d.ts.map +1 -0
- package/dist/umd/components/VizElement/MissingElementMessage.d.ts +7 -0
- package/dist/umd/components/VizElement/MissingElementMessage.d.ts.map +1 -0
- package/dist/umd/components/VizElement/VizElements.d.ts.map +1 -1
- package/dist/umd/components/VizElement/temp/ClarityVisualizer.d.ts +150 -0
- package/dist/umd/components/VizElement/temp/ClarityVisualizer.d.ts.map +1 -0
- package/dist/umd/components/VizElement/temp/VizElementRank.d.ts +74 -0
- package/dist/umd/components/VizElement/temp/VizElementRank.d.ts.map +1 -0
- package/dist/umd/components/VizLive/VizLiveHeatmap.d.ts.map +1 -1
- package/dist/umd/components/VizLive/VizLiveRenderer.d.ts.map +1 -1
- package/dist/umd/configs/style.d.ts +0 -2
- package/dist/umd/configs/style.d.ts.map +1 -1
- package/dist/umd/helpers/index.d.ts +2 -1
- package/dist/umd/helpers/index.d.ts.map +1 -1
- package/dist/umd/helpers/viewport-fixer.d.ts +13 -0
- package/dist/umd/helpers/viewport-fixer.d.ts.map +1 -0
- package/dist/umd/helpers/viewport-replacer.d.ts +26 -0
- package/dist/umd/helpers/viewport-replacer.d.ts.map +1 -0
- package/dist/umd/hooks/vix-elements/useHoveredElement.d.ts.map +1 -1
- package/dist/umd/hooks/viz-canvas/useClickmap.d.ts +1 -3
- package/dist/umd/hooks/viz-canvas/useClickmap.d.ts.map +1 -1
- package/dist/umd/hooks/viz-canvas/useHeatmapVizCanvas.d.ts +1 -1
- package/dist/umd/hooks/viz-canvas/useHeatmapVizCanvas.d.ts.map +1 -1
- package/dist/umd/hooks/viz-canvas/useScrollmap.d.ts +1 -3
- package/dist/umd/hooks/viz-canvas/useScrollmap.d.ts.map +1 -1
- package/dist/umd/hooks/viz-live/index.d.ts +1 -1
- package/dist/umd/hooks/viz-live/{useVizLiveIframeMsg.d.ts → useIframeMessage.d.ts} +10 -2
- package/dist/umd/hooks/viz-live/useIframeMessage.d.ts.map +1 -0
- package/dist/umd/hooks/viz-render/useHeatmapRender.d.ts.map +1 -1
- package/dist/umd/hooks/viz-scale/useContainerDimensions.d.ts.map +1 -1
- package/dist/umd/hooks/viz-scale/useHeatmapScale.d.ts +1 -1
- package/dist/umd/hooks/viz-scale/useHeatmapScale.d.ts.map +1 -1
- package/dist/umd/hooks/viz-scale/useIframeHeight.d.ts +10 -0
- package/dist/umd/hooks/viz-scale/useIframeHeight.d.ts.map +1 -0
- package/dist/umd/index.d.ts +1 -1
- package/dist/umd/index.d.ts.map +1 -1
- package/dist/umd/index.js +2 -2
- package/dist/umd/stores/index.d.ts +0 -1
- package/dist/umd/stores/index.d.ts.map +1 -1
- package/dist/umd/stores/interaction.d.ts.map +1 -1
- package/dist/umd/stores/mode-live.d.ts +0 -4
- package/dist/umd/stores/mode-live.d.ts.map +1 -1
- package/dist/umd/stores/viz.d.ts +4 -0
- package/dist/umd/stores/viz.d.ts.map +1 -1
- package/dist/umd/types/index.d.ts +1 -1
- package/dist/umd/types/index.d.ts.map +1 -1
- package/dist/umd/types/viewport-fixer.d.ts +31 -0
- package/dist/umd/types/viewport-fixer.d.ts.map +1 -0
- package/package.json +13 -15
- package/src/components/GraphView.tsx +58 -0
- package/src/components/Layout/ContentMetricBar.tsx +23 -0
- package/src/components/Layout/ContentToolbar.tsx +22 -0
- package/src/components/Layout/ContentTopBar.tsx +24 -0
- package/src/components/Layout/ContentVizByMode.tsx +14 -0
- package/src/components/Layout/HeatmapLayout.tsx +60 -0
- package/src/components/Layout/LeftSidebar.tsx +44 -0
- package/src/components/Layout/WrapperLayout.tsx +12 -0
- package/src/components/Layout/WrapperPreview.tsx +24 -0
- package/src/components/Layout/index.ts +1 -0
- package/src/components/VizDom/ReplayControls.tsx +48 -0
- package/src/components/VizDom/VizContainer.tsx +40 -0
- package/src/components/VizDom/VizDomHeatmap.tsx +28 -0
- package/src/components/VizDom/VizDomRenderer.tsx +82 -0
- package/src/components/VizDom/VizLoading.tsx +8 -0
- package/src/components/VizDom/WrapperVisual.tsx +73 -0
- package/src/components/VizDom/index.ts +5 -0
- package/src/components/VizElement/DefaultRankBadges.tsx +36 -0
- package/src/components/VizElement/ElementCallout.tsx +82 -0
- package/src/components/VizElement/ElementMissing.tsx +35 -0
- package/src/components/VizElement/ElementOverlay.tsx +66 -0
- package/src/components/VizElement/HeatmapElements.tsx +127 -0
- package/src/components/VizElement/HeatmapExample.tsx +70 -0
- package/src/components/VizElement/RankBadge.tsx +25 -0
- package/src/components/VizElement/VizElements.tsx +57 -0
- package/src/components/VizElement/index.ts +1 -0
- package/src/components/VizLive/VizLiveHeatmap.tsx +27 -0
- package/src/components/VizLive/VizLiveRenderer.tsx +47 -0
- package/src/components/VizLive/index.ts +1 -0
- package/src/components/VizScrollmap/AverageFoldLine.tsx +57 -0
- package/src/components/VizScrollmap/HoverZones.tsx +58 -0
- package/src/components/VizScrollmap/MetricRow.tsx +0 -0
- package/src/components/VizScrollmap/ScrollMapMinimap.tsx +64 -0
- package/src/components/VizScrollmap/ScrollMapOverlay.tsx +79 -0
- package/src/components/VizScrollmap/ScrollZoneHoverArea.tsx +35 -0
- package/src/components/VizScrollmap/ScrollZoneTooltip.tsx +146 -0
- package/src/components/VizScrollmap/ScrollmapMarker.tsx +106 -0
- package/src/components/VizScrollmap/VizScrollMap.tsx +36 -0
- package/src/components/VizScrollmap/index.ts +1 -0
- package/src/components/VizScrollmapV2/ScrollmapOverlay.css +94 -0
- package/src/components/VizScrollmapV2/ScrollmapOverlayV2.tsx +130 -0
- package/src/components/VizScrollmapV2/index.ts +1 -0
- package/src/components/VizScrollmapV2/scrollmap.types.ts +21 -0
- package/src/components/VizScrollmapV2/useScrollmapOverlay.ts +187 -0
- package/src/components/index.tsx +2 -0
- package/src/configs/iframe.ts +15 -0
- package/src/configs/index.ts +2 -0
- package/src/configs/style.ts +21 -0
- package/src/constants/index.ts +4 -0
- package/src/global.d.ts +5 -0
- package/src/helpers/elm-callout.ts +347 -0
- package/src/helpers/elm-getter.ts +70 -0
- package/src/helpers/iframe-helper/fixer.ts +100 -0
- package/src/helpers/iframe-helper/index.ts +1 -0
- package/src/helpers/iframe-helper/init.ts +56 -0
- package/src/helpers/iframe-helper/navigation-blocker-v2.ts +371 -0
- package/src/helpers/iframe-helper/navigation-blocker.ts +367 -0
- package/src/helpers/iframe-helper/style-replacer.ts +231 -0
- package/src/helpers/iframe.ts +42 -0
- package/src/helpers/index.ts +8 -0
- package/src/helpers/viz-canvas/area-clustering.ts +234 -0
- package/src/helpers/viz-canvas/area-overlay-manager-v2.ts +176 -0
- package/src/helpers/viz-canvas/area-overlay-manager.ts +273 -0
- package/src/helpers/viz-canvas/hierarchical-area-clustering.ts +420 -0
- package/src/helpers/viz-canvas/index.ts +2 -0
- package/src/helpers/viz-elements.ts +43 -0
- package/src/hooks/index.ts +8 -0
- package/src/hooks/register/index.ts +4 -0
- package/src/hooks/register/useRegisterConfig.ts +17 -0
- package/src/hooks/register/useRegisterControl.ts +13 -0
- package/src/hooks/register/useRegisterData.ts +36 -0
- package/src/hooks/register/useRegisterHeatmap.ts +38 -0
- package/src/hooks/viz-area/useAreaHeatmap.ts +336 -0
- package/src/hooks/viz-area/useAreaHeatmapManager.ts +692 -0
- package/src/hooks/viz-canvas/index.ts +1 -0
- package/src/hooks/viz-canvas/useAreamap.ts +162 -0
- package/src/hooks/viz-canvas/useClickmap.ts +24 -0
- package/src/hooks/viz-canvas/useHeatmapCanvas.ts +27 -0
- package/src/hooks/viz-canvas/useScrollmap.ts +22 -0
- package/src/hooks/viz-elements/index.ts +5 -0
- package/src/hooks/viz-elements/useClickedElement.ts +86 -0
- package/src/hooks/viz-elements/useElementCalloutVisible.ts +45 -0
- package/src/hooks/viz-elements/useHeatmapEffects.ts +30 -0
- package/src/hooks/viz-elements/useHeatmapElementPosition.ts +60 -0
- package/src/hooks/viz-elements/useHeatmapMouseHandler.ts +255 -0
- package/src/hooks/viz-elements/useHoveredElement.ts +170 -0
- package/src/hooks/viz-live/index.ts +1 -0
- package/src/hooks/viz-live/useVizLiveIframeMsg.ts +88 -0
- package/src/hooks/viz-live/useVizLiveRender.ts +67 -0
- package/src/hooks/viz-render/index.ts +1 -0
- package/src/hooks/viz-render/useHeatmapRender.ts +71 -0
- package/src/hooks/viz-render/useHeatmapVizRender.ts +20 -0
- package/src/hooks/viz-render/useReplayRender.ts +160 -0
- package/src/hooks/viz-scale/index.ts +2 -0
- package/src/hooks/viz-scale/useContainerDimensions.ts +48 -0
- package/src/hooks/viz-scale/useContentDimensions.ts +25 -0
- package/src/hooks/viz-scale/useHeatmapScale.ts +52 -0
- package/src/hooks/viz-scale/useObserveIframeHeight.ts +162 -0
- package/src/hooks/viz-scale/useScaleCalculation.ts +31 -0
- package/src/hooks/viz-scale/useScrollSync.ts +36 -0
- package/src/hooks/viz-scale/useWrapperRefHeight.ts +91 -0
- package/src/hooks/viz-scrollmap/index.ts +2 -0
- package/src/hooks/viz-scrollmap/useScrollmapZones.ts +165 -0
- package/src/hooks/viz-scrollmap/useZonePositions.ts +38 -0
- package/src/index.ts +10 -0
- package/src/stores/comp.ts +31 -0
- package/src/stores/config.ts +37 -0
- package/src/stores/data.ts +30 -0
- package/src/stores/index.ts +10 -0
- package/src/stores/interaction.ts +32 -0
- package/src/stores/mode-live.ts +38 -0
- package/src/stores/mode-single.ts +18 -0
- package/src/stores/viz-scrollmap.ts +22 -0
- package/src/stores/viz.ts +17 -0
- package/src/styles/base.css +1 -0
- package/src/styles/style.css +137 -0
- package/src/types/clarity.ts +45 -0
- package/src/types/control.ts +10 -0
- package/src/types/elm-callout.ts +9 -0
- package/src/types/heatmap-info.ts +11 -0
- package/src/types/heatmap.ts +25 -0
- package/src/types/iframe-helper.ts +18 -0
- package/src/types/index.ts +12 -0
- package/src/types/viz-canvas.ts +20 -0
- package/src/types/viz-element.ts +34 -0
- package/src/types/viz-scrollmap.ts +28 -0
- package/src/ui/BoxStack/BoxStack.tsx +136 -0
- package/src/ui/BoxStack/index.ts +1 -0
- package/src/ui/index.ts +1 -0
- package/src/utils/debounce.ts +10 -0
- package/src/utils/device.ts +7 -0
- package/src/utils/retry.ts +20 -0
- package/src/utils/sort.ts +5 -0
- package/dist/esm/helpers/iframe-helper/fixer.d.ts +0 -18
- package/dist/esm/helpers/iframe-helper/fixer.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/index.d.ts +0 -2
- package/dist/esm/helpers/iframe-helper/index.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/init.d.ts +0 -5
- package/dist/esm/helpers/iframe-helper/init.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/navigation-blocker-v2.d.ts +0 -28
- package/dist/esm/helpers/iframe-helper/navigation-blocker-v2.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/navigation-blocker.d.ts +0 -20
- package/dist/esm/helpers/iframe-helper/navigation-blocker.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/style-replacer.d.ts +0 -25
- package/dist/esm/helpers/iframe-helper/style-replacer.d.ts.map +0 -1
- package/dist/esm/hooks/vix-elements/useHeatmapMouseHandler.d.ts +0 -34
- package/dist/esm/hooks/vix-elements/useHeatmapMouseHandler.d.ts.map +0 -1
- package/dist/esm/hooks/viz-live/useVizLiveIframeMsg.d.ts.map +0 -1
- package/dist/esm/hooks/viz-live/useVizLiveRender.d.ts +0 -4
- package/dist/esm/hooks/viz-live/useVizLiveRender.d.ts.map +0 -1
- package/dist/esm/hooks/viz-scale/useObserveIframeHeight.d.ts +0 -10
- package/dist/esm/hooks/viz-scale/useObserveIframeHeight.d.ts.map +0 -1
- package/dist/esm/stores/mode-single.d.ts +0 -9
- package/dist/esm/stores/mode-single.d.ts.map +0 -1
- package/dist/esm/types/iframe-helper.d.ts +0 -20
- package/dist/esm/types/iframe-helper.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/fixer.d.ts +0 -18
- package/dist/umd/helpers/iframe-helper/fixer.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/index.d.ts +0 -2
- package/dist/umd/helpers/iframe-helper/index.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/init.d.ts +0 -5
- package/dist/umd/helpers/iframe-helper/init.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/navigation-blocker-v2.d.ts +0 -28
- package/dist/umd/helpers/iframe-helper/navigation-blocker-v2.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/navigation-blocker.d.ts +0 -20
- package/dist/umd/helpers/iframe-helper/navigation-blocker.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/style-replacer.d.ts +0 -25
- package/dist/umd/helpers/iframe-helper/style-replacer.d.ts.map +0 -1
- package/dist/umd/hooks/vix-elements/useHeatmapMouseHandler.d.ts +0 -34
- package/dist/umd/hooks/vix-elements/useHeatmapMouseHandler.d.ts.map +0 -1
- package/dist/umd/hooks/viz-live/useVizLiveIframeMsg.d.ts.map +0 -1
- package/dist/umd/hooks/viz-live/useVizLiveRender.d.ts +0 -4
- package/dist/umd/hooks/viz-live/useVizLiveRender.d.ts.map +0 -1
- package/dist/umd/hooks/viz-scale/useObserveIframeHeight.d.ts +0 -10
- package/dist/umd/hooks/viz-scale/useObserveIframeHeight.d.ts.map +0 -1
- package/dist/umd/stores/mode-single.d.ts +0 -9
- package/dist/umd/stores/mode-single.d.ts.map +0 -1
- package/dist/umd/types/iframe-helper.d.ts +0 -20
- package/dist/umd/types/iframe-helper.d.ts.map +0 -1
|
@@ -0,0 +1,420 @@
|
|
|
1
|
+
import { ClickMapPoint, IClusterArea } from '../../types';
|
|
2
|
+
|
|
3
|
+
export interface HierarchicalCluster extends IClusterArea {
|
|
4
|
+
parentHash: string | null; // Hash của parent chung
|
|
5
|
+
level: number; // Level trong DOM tree
|
|
6
|
+
children: Set<string>; // IDs của child clusters
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
interface ClickElement {
|
|
10
|
+
hash: string;
|
|
11
|
+
element: HTMLElement;
|
|
12
|
+
rect: Rect;
|
|
13
|
+
totalclicks: number;
|
|
14
|
+
level: number;
|
|
15
|
+
parents: string[]; // Danh sách hash của parents
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const HEATMAP_GRADIENT_COLORS: [number, number, number][] = [
|
|
19
|
+
[0, 0, 255], // Blue
|
|
20
|
+
[0, 255, 255], // Cyan
|
|
21
|
+
[0, 255, 0], // Green
|
|
22
|
+
[255, 255, 0], // Yellow
|
|
23
|
+
[255, 0, 0], // Red
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
const GRADIENT_COLOR_COUNT = HEATMAP_GRADIENT_COLORS.length - 1;
|
|
27
|
+
|
|
28
|
+
const CLUSTERING_CONFIG = {
|
|
29
|
+
maxDistance: 150, // Max distance để coi là cùng nhóm
|
|
30
|
+
minElements: 1, // Min elements trong cluster
|
|
31
|
+
maxClusterSize: 0.8, // Max 80% viewport size
|
|
32
|
+
minClusterSize: 30, // Min 30px
|
|
33
|
+
excludeTags: ['BODY', 'HTML', 'MAIN', 'SECTION', 'ARTICLE', 'DIV'], // Tags không nên làm parent trừ khi specific
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export class HierarchicalAreaClusteringEngine {
|
|
37
|
+
/**
|
|
38
|
+
* Cluster areas với hierarchical logic
|
|
39
|
+
*/
|
|
40
|
+
public clusterAreas(
|
|
41
|
+
clickData: ClickMapPoint[],
|
|
42
|
+
iframeDoc: Document,
|
|
43
|
+
totalClicks: number,
|
|
44
|
+
): HierarchicalCluster[] {
|
|
45
|
+
// 1. Build click elements với hierarchy info
|
|
46
|
+
const clickElements = this.buildClickElements(clickData, iframeDoc);
|
|
47
|
+
if (clickElements.length === 0) return [];
|
|
48
|
+
|
|
49
|
+
console.log(`[HierarchicalClustering] Processing ${clickElements.length} elements`);
|
|
50
|
+
|
|
51
|
+
// 2. Group by common parent
|
|
52
|
+
const parentGroups = this.groupByCommonParent(clickElements);
|
|
53
|
+
|
|
54
|
+
console.log(`[HierarchicalClustering] Found ${parentGroups.size} parent groups`);
|
|
55
|
+
|
|
56
|
+
// 3. Create clusters from groups
|
|
57
|
+
let clusters = this.createClustersFromGroups(parentGroups, totalClicks, iframeDoc);
|
|
58
|
+
|
|
59
|
+
// 4. Remove nested clusters (child inside parent)
|
|
60
|
+
clusters = this.removeNestedClusters(clusters);
|
|
61
|
+
|
|
62
|
+
// 5. Filter out too large clusters
|
|
63
|
+
clusters = this.filterLargeClusters(clusters, iframeDoc);
|
|
64
|
+
|
|
65
|
+
// 6. Sort by click percentage
|
|
66
|
+
clusters.sort((a, b) => b.clickPercentage - a.clickPercentage);
|
|
67
|
+
|
|
68
|
+
console.log(`[HierarchicalClustering] Final: ${clusters.length} clusters`);
|
|
69
|
+
|
|
70
|
+
return clusters;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Build click elements với hierarchy info
|
|
75
|
+
*/
|
|
76
|
+
private buildClickElements(clickData: ClickMapPoint[], iframeDoc: Document): ClickElement[] {
|
|
77
|
+
const elements: ClickElement[] = [];
|
|
78
|
+
|
|
79
|
+
clickData.forEach((item) => {
|
|
80
|
+
const element = iframeDoc.querySelector(
|
|
81
|
+
`[data-clarity-hashalpha="${item.hash}"]`,
|
|
82
|
+
) as HTMLElement;
|
|
83
|
+
|
|
84
|
+
if (!element || item.totalclicks === 0) return;
|
|
85
|
+
|
|
86
|
+
const rect = this.getElementRect(element);
|
|
87
|
+
|
|
88
|
+
// Filter quá nhỏ
|
|
89
|
+
if (rect.width < 10 || rect.height < 10) return;
|
|
90
|
+
|
|
91
|
+
// Get DOM level
|
|
92
|
+
const level = this.getDOMLevel(element);
|
|
93
|
+
|
|
94
|
+
// Get all parent hashes
|
|
95
|
+
const parents = this.getParentHashes(element);
|
|
96
|
+
|
|
97
|
+
elements.push({
|
|
98
|
+
hash: item.hash,
|
|
99
|
+
element,
|
|
100
|
+
rect,
|
|
101
|
+
totalclicks: item.totalclicks,
|
|
102
|
+
level,
|
|
103
|
+
parents,
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
return elements;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Get DOM level (depth from body)
|
|
112
|
+
*/
|
|
113
|
+
private getDOMLevel(element: HTMLElement): number {
|
|
114
|
+
let level = 0;
|
|
115
|
+
let current: HTMLElement | null = element;
|
|
116
|
+
|
|
117
|
+
while (current && current.tagName !== 'BODY') {
|
|
118
|
+
level++;
|
|
119
|
+
current = current.parentElement;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return level;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Get all parent hashes của element
|
|
127
|
+
*/
|
|
128
|
+
private getParentHashes(element: HTMLElement): string[] {
|
|
129
|
+
const hashes: string[] = [];
|
|
130
|
+
let current: HTMLElement | null = element.parentElement;
|
|
131
|
+
|
|
132
|
+
while (current && current.tagName !== 'BODY') {
|
|
133
|
+
const hash = current.getAttribute('data-clarity-hashalpha');
|
|
134
|
+
if (hash) {
|
|
135
|
+
hashes.push(hash);
|
|
136
|
+
}
|
|
137
|
+
current = current.parentElement;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return hashes;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Group elements by common parent
|
|
145
|
+
*/
|
|
146
|
+
private groupByCommonParent(clickElements: ClickElement[]): Map<string, ClickElement[]> {
|
|
147
|
+
const groups = new Map<string, ClickElement[]>();
|
|
148
|
+
|
|
149
|
+
// Tìm common parent cho mỗi cặp elements
|
|
150
|
+
for (let i = 0; i < clickElements.length; i++) {
|
|
151
|
+
const el1 = clickElements[i];
|
|
152
|
+
let foundGroup = false;
|
|
153
|
+
|
|
154
|
+
// Check xem el1 có thuộc group nào chưa
|
|
155
|
+
for (const [parentHash, group] of groups.entries()) {
|
|
156
|
+
// Check nếu el1 share parent với group
|
|
157
|
+
const hasCommonParent = group.some((el2) => {
|
|
158
|
+
return this.hasCommonParent(el1, el2);
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
if (hasCommonParent) {
|
|
162
|
+
group.push(el1);
|
|
163
|
+
foundGroup = true;
|
|
164
|
+
break;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Nếu chưa có group, tạo group mới với parent gần nhất
|
|
169
|
+
if (!foundGroup) {
|
|
170
|
+
const parentHash = this.getBestParentHash(el1);
|
|
171
|
+
if (!groups.has(parentHash)) {
|
|
172
|
+
groups.set(parentHash, []);
|
|
173
|
+
}
|
|
174
|
+
groups.get(parentHash)!.push(el1);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
return groups;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Check if two elements have common parent
|
|
183
|
+
*/
|
|
184
|
+
private hasCommonParent(el1: ClickElement, el2: ClickElement): boolean {
|
|
185
|
+
// Check shared parents
|
|
186
|
+
const commonParents = el1.parents.filter((p) => el2.parents.includes(p));
|
|
187
|
+
|
|
188
|
+
if (commonParents.length === 0) return false;
|
|
189
|
+
|
|
190
|
+
// Cũng check khoảng cách để đảm bảo không quá xa
|
|
191
|
+
const distance = this.getDistance(el1.rect, el2.rect);
|
|
192
|
+
return distance <= CLUSTERING_CONFIG.maxDistance;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Get best parent hash (closest specific parent)
|
|
197
|
+
*/
|
|
198
|
+
private getBestParentHash(el: ClickElement): string {
|
|
199
|
+
// Ưu tiên parent có semantic tag (không phải DIV, SECTION...)
|
|
200
|
+
for (const parentHash of el.parents) {
|
|
201
|
+
const parent = el.element.ownerDocument.querySelector(
|
|
202
|
+
`[data-clarity-hashalpha="${parentHash}"]`,
|
|
203
|
+
) as HTMLElement;
|
|
204
|
+
|
|
205
|
+
if (parent && !CLUSTERING_CONFIG.excludeTags.includes(parent.tagName)) {
|
|
206
|
+
return parentHash;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Fallback: parent gần nhất
|
|
211
|
+
return el.parents[0] || `element_${el.hash}`;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Create clusters from parent groups
|
|
216
|
+
*/
|
|
217
|
+
private createClustersFromGroups(
|
|
218
|
+
groups: Map<string, ClickElement[]>,
|
|
219
|
+
totalClicks: number,
|
|
220
|
+
iframeDoc: Document,
|
|
221
|
+
): HierarchicalCluster[] {
|
|
222
|
+
const clusters: HierarchicalCluster[] = [];
|
|
223
|
+
let index = 0;
|
|
224
|
+
|
|
225
|
+
groups.forEach((elements, parentHash) => {
|
|
226
|
+
if (elements.length === 0) return;
|
|
227
|
+
|
|
228
|
+
const totalClusterClicks = elements.reduce((sum, el) => sum + el.totalclicks || 0, 0);
|
|
229
|
+
const clickPercentage = (totalClusterClicks / totalClicks) * 100;
|
|
230
|
+
|
|
231
|
+
// Calculate smart bounding rect
|
|
232
|
+
const boundingRect = this.calculateSmartBoundingRect(elements, iframeDoc);
|
|
233
|
+
|
|
234
|
+
// Get average level
|
|
235
|
+
const avgLevel = Math.round(
|
|
236
|
+
elements.reduce((sum, el) => sum + el.level, 0) / elements.length,
|
|
237
|
+
);
|
|
238
|
+
|
|
239
|
+
const cluster: HierarchicalCluster = {
|
|
240
|
+
id: `cluster_${index++}`,
|
|
241
|
+
parentHash: parentHash === `element_${elements[0].hash}` ? null : parentHash,
|
|
242
|
+
level: avgLevel,
|
|
243
|
+
elements: elements.map((e) => e.element),
|
|
244
|
+
hashes: elements.map((e) => e.hash),
|
|
245
|
+
boundingRect,
|
|
246
|
+
totalClicks: totalClusterClicks,
|
|
247
|
+
clickPercentage,
|
|
248
|
+
color: this.getHeatmapColor(clickPercentage / 100),
|
|
249
|
+
hoverColor: this.getHoverColor(clickPercentage / 100),
|
|
250
|
+
children: new Set(),
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
clusters.push(cluster);
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
return clusters;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Calculate smart bounding rect - không bao trọn toàn bộ parent
|
|
261
|
+
*/
|
|
262
|
+
private calculateSmartBoundingRect(elements: ClickElement[], iframeDoc: Document): Rect {
|
|
263
|
+
// Nếu chỉ có 1 element, dùng rect của nó
|
|
264
|
+
if (elements.length === 1) {
|
|
265
|
+
const rect = elements[0].rect;
|
|
266
|
+
return { ...rect, right: rect.left + rect.width, bottom: rect.top + rect.height };
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Calculate tight bounding box với moderate padding
|
|
270
|
+
const padding = 15;
|
|
271
|
+
|
|
272
|
+
const minLeft = Math.min(...elements.map((e) => e.rect.left)) - padding;
|
|
273
|
+
const minTop = Math.min(...elements.map((e) => e.rect.top)) - padding;
|
|
274
|
+
const maxRight = Math.max(...elements.map((e) => e.rect.left + e.rect.width)) + padding;
|
|
275
|
+
const maxBottom = Math.max(...elements.map((e) => e.rect.top + e.rect.height)) + padding;
|
|
276
|
+
|
|
277
|
+
return {
|
|
278
|
+
left: minLeft,
|
|
279
|
+
top: minTop,
|
|
280
|
+
width: maxRight - minLeft,
|
|
281
|
+
height: maxBottom - minTop,
|
|
282
|
+
right: maxRight,
|
|
283
|
+
bottom: maxBottom,
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Remove nested clusters - Loại bỏ cluster con nếu nằm trong cluster cha
|
|
289
|
+
*/
|
|
290
|
+
private removeNestedClusters(clusters: HierarchicalCluster[]): HierarchicalCluster[] {
|
|
291
|
+
const filtered: HierarchicalCluster[] = [];
|
|
292
|
+
|
|
293
|
+
// Sort by level (lower level = closer to root = parent)
|
|
294
|
+
const sorted = [...clusters].sort((a, b) => a.level - b.level);
|
|
295
|
+
|
|
296
|
+
for (const cluster of sorted) {
|
|
297
|
+
// Check if cluster is nested inside any existing filtered cluster
|
|
298
|
+
const isNested = filtered.some((parent) => {
|
|
299
|
+
return this.isClusterNested(cluster, parent);
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
if (!isNested) {
|
|
303
|
+
filtered.push(cluster);
|
|
304
|
+
} else {
|
|
305
|
+
console.log(`[HierarchicalClustering] Removed nested cluster ${cluster.id}`);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
return filtered;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Check if cluster1 is nested inside cluster2
|
|
314
|
+
*/
|
|
315
|
+
private isClusterNested(child: HierarchicalCluster, parent: HierarchicalCluster): boolean {
|
|
316
|
+
const childRect = child.boundingRect;
|
|
317
|
+
const parentRect = parent.boundingRect;
|
|
318
|
+
|
|
319
|
+
// Check bounding rect containment với threshold
|
|
320
|
+
const threshold = 0.9; // 90% overlap considered nested
|
|
321
|
+
|
|
322
|
+
const overlapArea = this.calculateOverlapArea(childRect, parentRect);
|
|
323
|
+
const childArea = childRect.width * childRect.height;
|
|
324
|
+
|
|
325
|
+
// Nếu > 90% diện tích child nằm trong parent -> nested
|
|
326
|
+
return overlapArea / childArea > threshold;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Calculate overlap area between two rects
|
|
331
|
+
*/
|
|
332
|
+
private calculateOverlapArea(rect1: Rect, rect2: Rect): number {
|
|
333
|
+
const xOverlap = Math.max(
|
|
334
|
+
0,
|
|
335
|
+
Math.min(rect1.right, rect2.right) - Math.max(rect1.left, rect2.left),
|
|
336
|
+
);
|
|
337
|
+
const yOverlap = Math.max(
|
|
338
|
+
0,
|
|
339
|
+
Math.min(rect1.bottom, rect2.bottom) - Math.max(rect1.top, rect2.top),
|
|
340
|
+
);
|
|
341
|
+
|
|
342
|
+
return xOverlap * yOverlap;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Filter out too large clusters (không bao trọn body hoặc quá lớn)
|
|
347
|
+
*/
|
|
348
|
+
private filterLargeClusters(
|
|
349
|
+
clusters: HierarchicalCluster[],
|
|
350
|
+
iframeDoc: Document,
|
|
351
|
+
): HierarchicalCluster[] {
|
|
352
|
+
const viewportWidth = iframeDoc.documentElement.clientWidth;
|
|
353
|
+
const viewportHeight = iframeDoc.documentElement.clientHeight;
|
|
354
|
+
|
|
355
|
+
const maxWidth = viewportWidth * CLUSTERING_CONFIG.maxClusterSize;
|
|
356
|
+
const maxHeight = viewportHeight * CLUSTERING_CONFIG.maxClusterSize;
|
|
357
|
+
|
|
358
|
+
return clusters.filter((cluster) => {
|
|
359
|
+
const rect = cluster.boundingRect;
|
|
360
|
+
|
|
361
|
+
// Loại bỏ clusters quá lớn
|
|
362
|
+
if (rect.width > maxWidth || rect.height > maxHeight) {
|
|
363
|
+
console.log(
|
|
364
|
+
`[HierarchicalClustering] Filtered large cluster ${cluster.id}: ${rect.width}x${rect.height}`,
|
|
365
|
+
);
|
|
366
|
+
return false;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// Loại bỏ clusters quá nhỏ
|
|
370
|
+
if (
|
|
371
|
+
rect.width < CLUSTERING_CONFIG.minClusterSize ||
|
|
372
|
+
rect.height < CLUSTERING_CONFIG.minClusterSize
|
|
373
|
+
) {
|
|
374
|
+
return false;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
return true;
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// Utility methods
|
|
382
|
+
private getElementRect(element: HTMLElement): Rect {
|
|
383
|
+
const domRect = element.getBoundingClientRect();
|
|
384
|
+
return {
|
|
385
|
+
top: domRect.top,
|
|
386
|
+
left: domRect.left,
|
|
387
|
+
width: domRect.width,
|
|
388
|
+
height: domRect.height,
|
|
389
|
+
right: domRect.right,
|
|
390
|
+
bottom: domRect.bottom,
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
private getDistance(rect1: Rect, rect2: Rect): number {
|
|
395
|
+
const horizontalDistance = Math.max(0, rect1.left - rect2.right, rect2.left - rect1.right);
|
|
396
|
+
const verticalDistance = Math.max(0, rect1.top - rect2.bottom, rect2.top - rect1.bottom);
|
|
397
|
+
return Math.sqrt(horizontalDistance ** 2 + verticalDistance ** 2);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
private getHeatmapColor(percentage: number): string {
|
|
401
|
+
const index = Math.min(Math.floor(percentage * GRADIENT_COLOR_COUNT), GRADIENT_COLOR_COUNT - 1);
|
|
402
|
+
const [r, g, b] = HEATMAP_GRADIENT_COLORS[index];
|
|
403
|
+
return `rgba(${r}, ${g}, ${b}, 0.5)`;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
private getHoverColor(percentage: number): string {
|
|
407
|
+
const index = Math.min(Math.floor(percentage * GRADIENT_COLOR_COUNT), GRADIENT_COLOR_COUNT - 1);
|
|
408
|
+
const [r, g, b] = HEATMAP_GRADIENT_COLORS[index];
|
|
409
|
+
return `rgba(${r}, ${g}, ${b}, 0.8)`;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
export interface Rect {
|
|
414
|
+
top: number;
|
|
415
|
+
left: number;
|
|
416
|
+
width: number;
|
|
417
|
+
height: number;
|
|
418
|
+
right: number;
|
|
419
|
+
bottom: number;
|
|
420
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { ElementRect } from '../types';
|
|
2
|
+
|
|
3
|
+
export function formatPercentage(value: number, decimals = 2): string {
|
|
4
|
+
return value.toFixed(decimals);
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function calculateRankPosition(rect: ElementRect, widthScale: number) {
|
|
8
|
+
const top = rect.top <= 18 ? rect.top + 3 : rect.top - 18;
|
|
9
|
+
const left = rect.left <= 18 ? rect.left + 3 : rect.left - 18;
|
|
10
|
+
|
|
11
|
+
return {
|
|
12
|
+
transform: `scale(${1.2 * widthScale})`,
|
|
13
|
+
top: Number.isNaN(top) ? undefined : top,
|
|
14
|
+
left: Number.isNaN(left) ? undefined : left,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function isElementInViewport(
|
|
19
|
+
elementRect: ElementRect,
|
|
20
|
+
visualRef: React.RefObject<HTMLDivElement>,
|
|
21
|
+
scale: number,
|
|
22
|
+
): boolean {
|
|
23
|
+
if (!elementRect) return false;
|
|
24
|
+
|
|
25
|
+
const visualRect = visualRef.current?.getBoundingClientRect();
|
|
26
|
+
if (!visualRect) return false;
|
|
27
|
+
|
|
28
|
+
// Element position relative to the document (or container's content)
|
|
29
|
+
const elementTop = elementRect.top * scale;
|
|
30
|
+
const elementBottom = (elementRect.top + elementRect.height) * scale;
|
|
31
|
+
|
|
32
|
+
// Current scroll position
|
|
33
|
+
const scrollTop = visualRef.current?.scrollTop || 0;
|
|
34
|
+
const viewportHeight = visualRect.height;
|
|
35
|
+
|
|
36
|
+
// Visible viewport range in the scrollable content
|
|
37
|
+
const viewportTop = scrollTop;
|
|
38
|
+
const viewportBottom = scrollTop + viewportHeight;
|
|
39
|
+
|
|
40
|
+
// Check if element is within the visible viewport
|
|
41
|
+
// Element is visible if it overlaps with the viewport
|
|
42
|
+
return elementBottom > viewportTop && elementTop < viewportBottom;
|
|
43
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
import { useHeatmapConfigStore, useHeatmapDataStore } from '../../stores';
|
|
3
|
+
|
|
4
|
+
export const useRegisterConfig = () => {
|
|
5
|
+
const mode = useHeatmapConfigStore((state) => state.mode);
|
|
6
|
+
const width = useHeatmapConfigStore((state) => state.width);
|
|
7
|
+
const sidebarWidth = useHeatmapConfigStore((state) => state.sidebarWidth);
|
|
8
|
+
const heatmapType = useHeatmapConfigStore((state) => state.heatmapType);
|
|
9
|
+
const setIsRendering = useHeatmapDataStore((state) => state.setIsRendering);
|
|
10
|
+
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
setIsRendering(true);
|
|
13
|
+
setTimeout(() => {
|
|
14
|
+
setIsRendering(false);
|
|
15
|
+
}, 1000);
|
|
16
|
+
}, [mode, width, sidebarWidth, heatmapType]);
|
|
17
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { useHeatmapControlStore } from '../../stores';
|
|
2
|
+
import { IHeatmapControl } from '../../types/control';
|
|
3
|
+
|
|
4
|
+
export const useRegisterControl = (control: IHeatmapControl) => {
|
|
5
|
+
const registerControl = useHeatmapControlStore((state) => state.registerControl);
|
|
6
|
+
|
|
7
|
+
registerControl('Sidebar', control.Sidebar);
|
|
8
|
+
registerControl('TopBar', control.TopBar);
|
|
9
|
+
registerControl('Toolbar', control.Toolbar);
|
|
10
|
+
registerControl('MetricBar', control.MetricBar);
|
|
11
|
+
registerControl('VizLoading', control.VizLoading);
|
|
12
|
+
registerControl('ElementCallout', control.ElementCallout);
|
|
13
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { useCallback, useEffect } from 'react';
|
|
2
|
+
import { useHeatmapDataStore } from '../../stores';
|
|
3
|
+
import { DecodedPayload, IHeatmapInfo } from '../../types';
|
|
4
|
+
|
|
5
|
+
export const useRegisterData = (data?: DecodedPayload[], dataInfo?: IHeatmapInfo) => {
|
|
6
|
+
const setData = useHeatmapDataStore((state) => state.setData);
|
|
7
|
+
const setIsRendering = useHeatmapDataStore((state) => state.setIsRendering);
|
|
8
|
+
const setDataInfo = useHeatmapDataStore((state) => state.setDataInfo);
|
|
9
|
+
|
|
10
|
+
const handleSetData = useCallback(
|
|
11
|
+
(data?: DecodedPayload[]) => {
|
|
12
|
+
if (!data) return;
|
|
13
|
+
|
|
14
|
+
setData(data);
|
|
15
|
+
setIsRendering(false);
|
|
16
|
+
},
|
|
17
|
+
[data],
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
const handleSetDataInfo = useCallback(
|
|
21
|
+
(dataInfo?: IHeatmapInfo) => {
|
|
22
|
+
if (!dataInfo) return;
|
|
23
|
+
|
|
24
|
+
setDataInfo(dataInfo);
|
|
25
|
+
},
|
|
26
|
+
[setDataInfo],
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
handleSetData(data);
|
|
31
|
+
}, [data]);
|
|
32
|
+
|
|
33
|
+
useEffect(() => {
|
|
34
|
+
handleSetDataInfo(dataInfo);
|
|
35
|
+
}, [dataInfo]);
|
|
36
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { useCallback, useEffect } from 'react';
|
|
2
|
+
import { useHeatmapDataStore } from '../../stores';
|
|
3
|
+
import { ClickMapPoint, ScrollMapPoint } from '../../types';
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
clickmap?: ClickMapPoint[];
|
|
7
|
+
scrollmap?: ScrollMapPoint[];
|
|
8
|
+
}
|
|
9
|
+
export const useRegisterHeatmap = ({ clickmap, scrollmap }: Props) => {
|
|
10
|
+
const setClickmap = useHeatmapDataStore((state) => state.setClickmap);
|
|
11
|
+
const setScrollmap = useHeatmapDataStore((state) => state.setScrollmap);
|
|
12
|
+
|
|
13
|
+
const handleSetClickmap = useCallback(
|
|
14
|
+
(clickmap?: ClickMapPoint[]) => {
|
|
15
|
+
if (!clickmap) return;
|
|
16
|
+
|
|
17
|
+
setClickmap(clickmap);
|
|
18
|
+
},
|
|
19
|
+
[clickmap],
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
const handleSetScrollmap = useCallback(
|
|
23
|
+
(scrollmap?: ScrollMapPoint[]) => {
|
|
24
|
+
if (!scrollmap) return;
|
|
25
|
+
|
|
26
|
+
setScrollmap(scrollmap);
|
|
27
|
+
},
|
|
28
|
+
[scrollmap],
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
handleSetClickmap(clickmap);
|
|
33
|
+
}, [clickmap]);
|
|
34
|
+
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
handleSetScrollmap(scrollmap);
|
|
37
|
+
}, [scrollmap]);
|
|
38
|
+
};
|