@gemx-dev/heatmap-react 3.5.47 → 3.5.49

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.
Files changed (198) hide show
  1. package/dist/esm/components/Layout/ContentToolbar.d.ts.map +1 -1
  2. package/dist/esm/components/Layout/ContentTopBar.d.ts.map +1 -1
  3. package/dist/esm/components/Layout/ContentVizByMode.d.ts.map +1 -1
  4. package/dist/esm/components/Layout/LeftSidebar.d.ts.map +1 -1
  5. package/dist/esm/components/VizCompare/CompareGrid.d.ts +1 -0
  6. package/dist/esm/components/VizCompare/CompareGrid.d.ts.map +1 -0
  7. package/dist/esm/components/VizCompare/CompareView.d.ts +1 -0
  8. package/dist/esm/components/VizCompare/CompareView.d.ts.map +1 -0
  9. package/dist/esm/components/VizCompare/CompareViewHeader.d.ts +1 -0
  10. package/dist/esm/components/VizCompare/CompareViewHeader.d.ts.map +1 -0
  11. package/dist/esm/components/VizCompare/CompareVizRenderer.d.ts +1 -0
  12. package/dist/esm/components/VizCompare/CompareVizRenderer.d.ts.map +1 -0
  13. package/dist/esm/components/VizCompare/VizCompareHeatmap.d.ts +1 -0
  14. package/dist/esm/components/VizCompare/VizCompareHeatmap.d.ts.map +1 -0
  15. package/dist/esm/components/VizCompare/index.d.ts +1 -0
  16. package/dist/esm/components/VizCompare/index.d.ts.map +1 -0
  17. package/dist/esm/components/VizDom/VizContainer.d.ts +1 -1
  18. package/dist/esm/components/VizDom/VizContainer.d.ts.map +1 -1
  19. package/dist/esm/components/VizDom/VizDomHeatmap.d.ts.map +1 -1
  20. package/dist/esm/components/VizDom/VizDomRenderer.d.ts.map +1 -1
  21. package/dist/esm/components/VizDom/WrapperVisual.d.ts.map +1 -1
  22. package/dist/esm/components/VizElement/DefaultRankBadges.d.ts.map +1 -1
  23. package/dist/esm/components/VizElement/ElementMissing.d.ts.map +1 -1
  24. package/dist/esm/components/VizElement/VizElements.d.ts.map +1 -1
  25. package/dist/esm/components/VizLive/VizLiveHeatmap.d.ts.map +1 -1
  26. package/dist/esm/components/VizLive/VizLiveRenderer.d.ts.map +1 -1
  27. package/dist/esm/components/VizScrollmap/AverageFoldLine.d.ts.map +1 -1
  28. package/dist/esm/components/VizScrollmap/HoverZones.d.ts.map +1 -1
  29. package/dist/esm/components/VizScrollmap/ScrollMapOverlay.d.ts.map +1 -1
  30. package/dist/esm/components/VizScrollmap/VizScrollMap.d.ts.map +1 -1
  31. package/dist/esm/components/VizScrollmapV2/useScrollmapOverlay.d.ts.map +1 -1
  32. package/dist/esm/contexts/CompareViewContext.d.ts +28 -0
  33. package/dist/esm/contexts/CompareViewContext.d.ts.map +1 -0
  34. package/dist/esm/contexts/index.d.ts +2 -0
  35. package/dist/esm/contexts/index.d.ts.map +1 -0
  36. package/dist/esm/hooks/compare/index.d.ts +4 -0
  37. package/dist/esm/hooks/compare/index.d.ts.map +1 -0
  38. package/dist/esm/hooks/compare/useCompareAwareConfig.d.ts +21 -0
  39. package/dist/esm/hooks/compare/useCompareAwareConfig.d.ts.map +1 -0
  40. package/dist/esm/hooks/compare/useCompareAwareData.d.ts +28 -0
  41. package/dist/esm/hooks/compare/useCompareAwareData.d.ts.map +1 -0
  42. package/dist/esm/hooks/compare/useCompareAwareViz.d.ts +34 -0
  43. package/dist/esm/hooks/compare/useCompareAwareViz.d.ts.map +1 -0
  44. package/dist/esm/hooks/index.d.ts +4 -0
  45. package/dist/esm/hooks/index.d.ts.map +1 -1
  46. package/dist/esm/hooks/register/useRegisterData.d.ts.map +1 -1
  47. package/dist/esm/hooks/register/useRegisterHeatmap.d.ts.map +1 -1
  48. package/dist/esm/hooks/useHeatmapData.d.ts +16 -0
  49. package/dist/esm/hooks/useHeatmapData.d.ts.map +1 -0
  50. package/dist/esm/hooks/useHeatmapViz.d.ts +24 -0
  51. package/dist/esm/hooks/useHeatmapViz.d.ts.map +1 -0
  52. package/dist/esm/hooks/useViewId.d.ts +15 -0
  53. package/dist/esm/hooks/useViewId.d.ts.map +1 -0
  54. package/dist/esm/hooks/viz-canvas/useAreamap.d.ts.map +1 -1
  55. package/dist/esm/hooks/viz-canvas/useClickmap.d.ts.map +1 -1
  56. package/dist/esm/hooks/viz-canvas/useScrollmap.d.ts.map +1 -1
  57. package/dist/esm/hooks/viz-elements/useClickedElement.d.ts.map +1 -1
  58. package/dist/esm/hooks/viz-elements/useElementCalloutVisible.d.ts.map +1 -1
  59. package/dist/esm/hooks/viz-elements/useHeatmapElementPosition.d.ts.map +1 -1
  60. package/dist/esm/hooks/viz-elements/useHoveredElement.d.ts.map +1 -1
  61. package/dist/esm/hooks/viz-live/useVizLiveRender.d.ts.map +1 -1
  62. package/dist/esm/hooks/viz-render/useHeatmapRender.d.ts.map +1 -1
  63. package/dist/esm/hooks/viz-render/useReplayRender.d.ts.map +1 -1
  64. package/dist/esm/hooks/viz-scale/useHeatmapScale.d.ts +1 -0
  65. package/dist/esm/hooks/viz-scale/useHeatmapScale.d.ts.map +1 -1
  66. package/dist/esm/hooks/viz-scale/useObserveIframeHeight.d.ts +1 -0
  67. package/dist/esm/hooks/viz-scale/useObserveIframeHeight.d.ts.map +1 -1
  68. package/dist/esm/hooks/viz-scale/useScaleCalculation.d.ts +5 -1
  69. package/dist/esm/hooks/viz-scale/useScaleCalculation.d.ts.map +1 -1
  70. package/dist/esm/hooks/viz-scale/useScrollSync.d.ts +2 -1
  71. package/dist/esm/hooks/viz-scale/useScrollSync.d.ts.map +1 -1
  72. package/dist/esm/hooks/viz-scale/useWrapperRefHeight.d.ts +0 -1
  73. package/dist/esm/hooks/viz-scale/useWrapperRefHeight.d.ts.map +1 -1
  74. package/dist/esm/hooks/viz-scrollmap/useScrollmapZones.d.ts.map +1 -1
  75. package/dist/esm/hooks/viz-scrollmap/useZonePositions.d.ts.map +1 -1
  76. package/dist/esm/index.d.ts +3 -1
  77. package/dist/esm/index.d.ts.map +1 -1
  78. package/dist/esm/index.js +715 -131
  79. package/dist/esm/index.mjs +715 -131
  80. package/dist/esm/stores/config.d.ts +2 -0
  81. package/dist/esm/stores/config.d.ts.map +1 -1
  82. package/dist/esm/stores/data.d.ts +11 -10
  83. package/dist/esm/stores/data.d.ts.map +1 -1
  84. package/dist/esm/stores/index.d.ts +1 -0
  85. package/dist/esm/stores/index.d.ts.map +1 -1
  86. package/dist/esm/stores/mode-compare.d.ts +33 -0
  87. package/dist/esm/stores/mode-compare.d.ts.map +1 -0
  88. package/dist/esm/stores/mode-live.d.ts +0 -4
  89. package/dist/esm/stores/mode-live.d.ts.map +1 -1
  90. package/dist/esm/stores/mode-single.d.ts +9 -4
  91. package/dist/esm/stores/mode-single.d.ts.map +1 -1
  92. package/dist/esm/stores/viz.d.ts +13 -4
  93. package/dist/esm/stores/viz.d.ts.map +1 -1
  94. package/dist/esm/types/compare.d.ts +68 -0
  95. package/dist/esm/types/compare.d.ts.map +1 -0
  96. package/dist/esm/types/control.d.ts +1 -1
  97. package/dist/esm/types/control.d.ts.map +1 -1
  98. package/dist/esm/types/index.d.ts +1 -0
  99. package/dist/esm/types/index.d.ts.map +1 -1
  100. package/dist/umd/components/Layout/ContentToolbar.d.ts.map +1 -1
  101. package/dist/umd/components/Layout/ContentTopBar.d.ts.map +1 -1
  102. package/dist/umd/components/Layout/ContentVizByMode.d.ts.map +1 -1
  103. package/dist/umd/components/Layout/LeftSidebar.d.ts.map +1 -1
  104. package/dist/umd/components/VizCompare/CompareGrid.d.ts +1 -0
  105. package/dist/umd/components/VizCompare/CompareGrid.d.ts.map +1 -0
  106. package/dist/umd/components/VizCompare/CompareView.d.ts +1 -0
  107. package/dist/umd/components/VizCompare/CompareView.d.ts.map +1 -0
  108. package/dist/umd/components/VizCompare/CompareViewHeader.d.ts +1 -0
  109. package/dist/umd/components/VizCompare/CompareViewHeader.d.ts.map +1 -0
  110. package/dist/umd/components/VizCompare/CompareVizRenderer.d.ts +1 -0
  111. package/dist/umd/components/VizCompare/CompareVizRenderer.d.ts.map +1 -0
  112. package/dist/umd/components/VizCompare/VizCompareHeatmap.d.ts +1 -0
  113. package/dist/umd/components/VizCompare/VizCompareHeatmap.d.ts.map +1 -0
  114. package/dist/umd/components/VizCompare/index.d.ts +1 -0
  115. package/dist/umd/components/VizCompare/index.d.ts.map +1 -0
  116. package/dist/umd/components/VizDom/VizContainer.d.ts +1 -1
  117. package/dist/umd/components/VizDom/VizContainer.d.ts.map +1 -1
  118. package/dist/umd/components/VizDom/VizDomHeatmap.d.ts.map +1 -1
  119. package/dist/umd/components/VizDom/VizDomRenderer.d.ts.map +1 -1
  120. package/dist/umd/components/VizDom/WrapperVisual.d.ts.map +1 -1
  121. package/dist/umd/components/VizElement/DefaultRankBadges.d.ts.map +1 -1
  122. package/dist/umd/components/VizElement/ElementMissing.d.ts.map +1 -1
  123. package/dist/umd/components/VizElement/VizElements.d.ts.map +1 -1
  124. package/dist/umd/components/VizLive/VizLiveHeatmap.d.ts.map +1 -1
  125. package/dist/umd/components/VizLive/VizLiveRenderer.d.ts.map +1 -1
  126. package/dist/umd/components/VizScrollmap/AverageFoldLine.d.ts.map +1 -1
  127. package/dist/umd/components/VizScrollmap/HoverZones.d.ts.map +1 -1
  128. package/dist/umd/components/VizScrollmap/ScrollMapOverlay.d.ts.map +1 -1
  129. package/dist/umd/components/VizScrollmap/VizScrollMap.d.ts.map +1 -1
  130. package/dist/umd/components/VizScrollmapV2/useScrollmapOverlay.d.ts.map +1 -1
  131. package/dist/umd/contexts/CompareViewContext.d.ts +28 -0
  132. package/dist/umd/contexts/CompareViewContext.d.ts.map +1 -0
  133. package/dist/umd/contexts/index.d.ts +2 -0
  134. package/dist/umd/contexts/index.d.ts.map +1 -0
  135. package/dist/umd/hooks/compare/index.d.ts +4 -0
  136. package/dist/umd/hooks/compare/index.d.ts.map +1 -0
  137. package/dist/umd/hooks/compare/useCompareAwareConfig.d.ts +21 -0
  138. package/dist/umd/hooks/compare/useCompareAwareConfig.d.ts.map +1 -0
  139. package/dist/umd/hooks/compare/useCompareAwareData.d.ts +28 -0
  140. package/dist/umd/hooks/compare/useCompareAwareData.d.ts.map +1 -0
  141. package/dist/umd/hooks/compare/useCompareAwareViz.d.ts +34 -0
  142. package/dist/umd/hooks/compare/useCompareAwareViz.d.ts.map +1 -0
  143. package/dist/umd/hooks/index.d.ts +4 -0
  144. package/dist/umd/hooks/index.d.ts.map +1 -1
  145. package/dist/umd/hooks/register/useRegisterData.d.ts.map +1 -1
  146. package/dist/umd/hooks/register/useRegisterHeatmap.d.ts.map +1 -1
  147. package/dist/umd/hooks/useHeatmapData.d.ts +16 -0
  148. package/dist/umd/hooks/useHeatmapData.d.ts.map +1 -0
  149. package/dist/umd/hooks/useHeatmapViz.d.ts +24 -0
  150. package/dist/umd/hooks/useHeatmapViz.d.ts.map +1 -0
  151. package/dist/umd/hooks/useViewId.d.ts +15 -0
  152. package/dist/umd/hooks/useViewId.d.ts.map +1 -0
  153. package/dist/umd/hooks/viz-canvas/useAreamap.d.ts.map +1 -1
  154. package/dist/umd/hooks/viz-canvas/useClickmap.d.ts.map +1 -1
  155. package/dist/umd/hooks/viz-canvas/useScrollmap.d.ts.map +1 -1
  156. package/dist/umd/hooks/viz-elements/useClickedElement.d.ts.map +1 -1
  157. package/dist/umd/hooks/viz-elements/useElementCalloutVisible.d.ts.map +1 -1
  158. package/dist/umd/hooks/viz-elements/useHeatmapElementPosition.d.ts.map +1 -1
  159. package/dist/umd/hooks/viz-elements/useHoveredElement.d.ts.map +1 -1
  160. package/dist/umd/hooks/viz-live/useVizLiveRender.d.ts.map +1 -1
  161. package/dist/umd/hooks/viz-render/useHeatmapRender.d.ts.map +1 -1
  162. package/dist/umd/hooks/viz-render/useReplayRender.d.ts.map +1 -1
  163. package/dist/umd/hooks/viz-scale/useHeatmapScale.d.ts +1 -0
  164. package/dist/umd/hooks/viz-scale/useHeatmapScale.d.ts.map +1 -1
  165. package/dist/umd/hooks/viz-scale/useObserveIframeHeight.d.ts +1 -0
  166. package/dist/umd/hooks/viz-scale/useObserveIframeHeight.d.ts.map +1 -1
  167. package/dist/umd/hooks/viz-scale/useScaleCalculation.d.ts +5 -1
  168. package/dist/umd/hooks/viz-scale/useScaleCalculation.d.ts.map +1 -1
  169. package/dist/umd/hooks/viz-scale/useScrollSync.d.ts +2 -1
  170. package/dist/umd/hooks/viz-scale/useScrollSync.d.ts.map +1 -1
  171. package/dist/umd/hooks/viz-scale/useWrapperRefHeight.d.ts +0 -1
  172. package/dist/umd/hooks/viz-scale/useWrapperRefHeight.d.ts.map +1 -1
  173. package/dist/umd/hooks/viz-scrollmap/useScrollmapZones.d.ts.map +1 -1
  174. package/dist/umd/hooks/viz-scrollmap/useZonePositions.d.ts.map +1 -1
  175. package/dist/umd/index.d.ts +3 -1
  176. package/dist/umd/index.d.ts.map +1 -1
  177. package/dist/umd/index.js +2 -2
  178. package/dist/umd/stores/config.d.ts +2 -0
  179. package/dist/umd/stores/config.d.ts.map +1 -1
  180. package/dist/umd/stores/data.d.ts +11 -10
  181. package/dist/umd/stores/data.d.ts.map +1 -1
  182. package/dist/umd/stores/index.d.ts +1 -0
  183. package/dist/umd/stores/index.d.ts.map +1 -1
  184. package/dist/umd/stores/mode-compare.d.ts +33 -0
  185. package/dist/umd/stores/mode-compare.d.ts.map +1 -0
  186. package/dist/umd/stores/mode-live.d.ts +0 -4
  187. package/dist/umd/stores/mode-live.d.ts.map +1 -1
  188. package/dist/umd/stores/mode-single.d.ts +9 -4
  189. package/dist/umd/stores/mode-single.d.ts.map +1 -1
  190. package/dist/umd/stores/viz.d.ts +13 -4
  191. package/dist/umd/stores/viz.d.ts.map +1 -1
  192. package/dist/umd/types/compare.d.ts +68 -0
  193. package/dist/umd/types/compare.d.ts.map +1 -0
  194. package/dist/umd/types/control.d.ts +1 -1
  195. package/dist/umd/types/control.d.ts.map +1 -1
  196. package/dist/umd/types/index.d.ts +1 -0
  197. package/dist/umd/types/index.d.ts.map +1 -1
  198. package/package.json +1 -1
package/dist/esm/index.js CHANGED
@@ -1,7 +1,7 @@
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, useCallback, useState, useRef, useMemo, forwardRef, Fragment as Fragment$1 } from 'react';
4
+ import { useEffect, createContext, useContext, useCallback, useState, useRef, useMemo, forwardRef, Fragment as Fragment$1 } from 'react';
5
5
  import { create } from 'zustand';
6
6
  import { decode } from '@gemx-dev/clarity-decode';
7
7
  import { Visualizer } from '@gemx-dev/clarity-visualize';
@@ -71,11 +71,11 @@ const useHeatmapControlStore = create()((set, get) => {
71
71
  return {
72
72
  controls: {
73
73
  Sidebar: null,
74
- TopBar: null,
75
74
  Toolbar: null,
76
75
  MetricBar: null,
77
76
  VizLoading: null,
78
- ElementCallout: null,
77
+ TopBar: undefined,
78
+ ElementCallout: undefined,
79
79
  },
80
80
  registerControl: (key, control) => {
81
81
  set({
@@ -117,6 +117,7 @@ const useHeatmapConfigStore = create()((set, get) => {
117
117
  heatmapType: IHeatmapType.Scroll,
118
118
  clickType: IClickType.Total,
119
119
  scrollType: IScrollType.Depth,
120
+ isRendering: true,
120
121
  setMode: (mode) => set({ mode }),
121
122
  resetMode: () => set({ mode: 'single' }),
122
123
  setWidth: (width) => set({ width }),
@@ -124,21 +125,57 @@ const useHeatmapConfigStore = create()((set, get) => {
124
125
  setHeatmapType: (heatmapType) => set({ heatmapType }),
125
126
  setClickType: (clickType) => set({ clickType }),
126
127
  setScrollType: (scrollType) => set({ scrollType }),
128
+ setIsRendering: (isRendering) => set({ isRendering }),
127
129
  };
128
130
  });
129
131
 
132
+ const DEFAULT_VIEW_ID$2 = 'default';
130
133
  const useHeatmapDataStore = create()((set, get) => {
131
134
  return {
132
- data: undefined,
133
- clickmap: undefined,
134
- dataInfo: undefined,
135
- scrollmap: undefined,
136
- isRendering: true,
137
- setIsRendering: (isRendering) => set({ isRendering }),
138
- setDataInfo: (dataInfo) => set({ dataInfo }),
139
- setData: (data) => set({ data }),
140
- setClickmap: (clickmap) => set({ clickmap }),
141
- setScrollmap: (scrollmap) => set({ scrollmap }),
135
+ data: { [DEFAULT_VIEW_ID$2]: undefined },
136
+ clickmap: { [DEFAULT_VIEW_ID$2]: undefined },
137
+ dataInfo: { [DEFAULT_VIEW_ID$2]: undefined },
138
+ scrollmap: { [DEFAULT_VIEW_ID$2]: undefined },
139
+ setDataInfo: (dataInfo, viewId = DEFAULT_VIEW_ID$2) => set((state) => ({
140
+ dataInfo: { ...state.dataInfo, [viewId]: dataInfo },
141
+ })),
142
+ setData: (data, viewId = DEFAULT_VIEW_ID$2) => set((state) => ({
143
+ data: { ...state.data, [viewId]: data },
144
+ })),
145
+ setClickmap: (clickmap, viewId = DEFAULT_VIEW_ID$2) => set((state) => ({
146
+ clickmap: { ...state.clickmap, [viewId]: clickmap },
147
+ })),
148
+ setScrollmap: (scrollmap, viewId = DEFAULT_VIEW_ID$2) => set((state) => ({
149
+ scrollmap: { ...state.scrollmap, [viewId]: scrollmap },
150
+ })),
151
+ copyView: (fromViewId, toViewId) => set((state) => ({
152
+ data: { ...state.data, [toViewId]: state.data[fromViewId] },
153
+ clickmap: { ...state.clickmap, [toViewId]: state.clickmap[fromViewId] },
154
+ dataInfo: { ...state.dataInfo, [toViewId]: state.dataInfo[fromViewId] },
155
+ scrollmap: { ...state.scrollmap, [toViewId]: state.scrollmap[fromViewId] },
156
+ })),
157
+ clearView: (viewId) => set((state) => {
158
+ const newData = { ...state.data };
159
+ const newClickmap = { ...state.clickmap };
160
+ const newDataInfo = { ...state.dataInfo };
161
+ const newScrollmap = { ...state.scrollmap };
162
+ delete newData[viewId];
163
+ delete newClickmap[viewId];
164
+ delete newDataInfo[viewId];
165
+ delete newScrollmap[viewId];
166
+ return {
167
+ data: newData,
168
+ clickmap: newClickmap,
169
+ dataInfo: newDataInfo,
170
+ scrollmap: newScrollmap,
171
+ };
172
+ }),
173
+ resetAll: () => set({
174
+ data: { [DEFAULT_VIEW_ID$2]: undefined },
175
+ clickmap: { [DEFAULT_VIEW_ID$2]: undefined },
176
+ dataInfo: { [DEFAULT_VIEW_ID$2]: undefined },
177
+ scrollmap: { [DEFAULT_VIEW_ID$2]: undefined },
178
+ }),
142
179
  };
143
180
  });
144
181
 
@@ -157,12 +194,62 @@ const useHeatmapInteractionStore = create()((set, get) => {
157
194
  };
158
195
  });
159
196
 
197
+ const DEFAULT_VIEW_ID$1 = 'default';
160
198
  const useHeatmapVizStore = create()((set, get) => {
161
199
  return {
162
- isRenderViz: false,
163
- setIsRenderViz: (isRenderViz) => set({ isRenderViz }),
164
- scale: 1,
165
- setScale: (scale) => set({ scale }),
200
+ isRenderViz: { [DEFAULT_VIEW_ID$1]: false },
201
+ zoomRatio: { [DEFAULT_VIEW_ID$1]: 100 },
202
+ minZoomRatio: { [DEFAULT_VIEW_ID$1]: 10 },
203
+ scale: { [DEFAULT_VIEW_ID$1]: 1 },
204
+ isScaledToFit: { [DEFAULT_VIEW_ID$1]: false },
205
+ setIsRenderViz: (isRenderViz, viewId = DEFAULT_VIEW_ID$1) => set((state) => ({
206
+ isRenderViz: { ...state.isRenderViz, [viewId]: isRenderViz },
207
+ })),
208
+ setZoomRatio: (zoomRatio, viewId = DEFAULT_VIEW_ID$1) => set((state) => ({
209
+ zoomRatio: { ...state.zoomRatio, [viewId]: zoomRatio },
210
+ })),
211
+ setMinZoomRatio: (minZoomRatio, viewId = DEFAULT_VIEW_ID$1) => set((state) => ({
212
+ minZoomRatio: { ...state.minZoomRatio, [viewId]: minZoomRatio },
213
+ })),
214
+ setScale: (scale, viewId = DEFAULT_VIEW_ID$1) => set((state) => ({
215
+ scale: { ...state.scale, [viewId]: scale },
216
+ })),
217
+ setIsScaledToFit: (isScaledToFit, viewId = DEFAULT_VIEW_ID$1) => set((state) => ({
218
+ isScaledToFit: { ...state.isScaledToFit, [viewId]: isScaledToFit },
219
+ })),
220
+ copyView: (fromViewId, toViewId) => set((state) => ({
221
+ isRenderViz: { ...state.isRenderViz, [toViewId]: state.isRenderViz[fromViewId] ?? false },
222
+ zoomRatio: { ...state.zoomRatio, [toViewId]: state.zoomRatio[fromViewId] ?? 100 },
223
+ minZoomRatio: { ...state.minZoomRatio, [toViewId]: state.minZoomRatio[fromViewId] ?? 10 },
224
+ scale: { ...state.scale, [toViewId]: state.scale[fromViewId] ?? 1 },
225
+ isScaledToFit: { ...state.isScaledToFit, [toViewId]: state.isScaledToFit[fromViewId] ?? false },
226
+ })),
227
+ clearView: (viewId) => set((state) => {
228
+ const newIsRenderViz = { ...state.isRenderViz };
229
+ const newZoomRatio = { ...state.zoomRatio };
230
+ const newMinZoomRatio = { ...state.minZoomRatio };
231
+ const newScale = { ...state.scale };
232
+ const newIsScaledToFit = { ...state.isScaledToFit };
233
+ delete newIsRenderViz[viewId];
234
+ delete newZoomRatio[viewId];
235
+ delete newMinZoomRatio[viewId];
236
+ delete newScale[viewId];
237
+ delete newIsScaledToFit[viewId];
238
+ return {
239
+ isRenderViz: newIsRenderViz,
240
+ zoomRatio: newZoomRatio,
241
+ minZoomRatio: newMinZoomRatio,
242
+ scale: newScale,
243
+ isScaledToFit: newIsScaledToFit,
244
+ };
245
+ }),
246
+ resetAll: () => set({
247
+ isRenderViz: { [DEFAULT_VIEW_ID$1]: false },
248
+ zoomRatio: { [DEFAULT_VIEW_ID$1]: 100 },
249
+ minZoomRatio: { [DEFAULT_VIEW_ID$1]: 10 },
250
+ scale: { [DEFAULT_VIEW_ID$1]: 1 },
251
+ isScaledToFit: { [DEFAULT_VIEW_ID$1]: false },
252
+ }),
166
253
  };
167
254
  });
168
255
 
@@ -180,8 +267,6 @@ const useHeatmapVizScrollmapStore = create()((set, get) => {
180
267
  const initialState = {
181
268
  payloads: [],
182
269
  htmlContent: '',
183
- wrapperHeight: 0,
184
- iframeHeight: 0,
185
270
  };
186
271
  const useHeatmapLiveStore = create()((set, get) => {
187
272
  return {
@@ -190,17 +275,179 @@ const useHeatmapLiveStore = create()((set, get) => {
190
275
  setPayloads: (payloads) => set({ payloads }),
191
276
  addPayload: (payload) => set((state) => ({ payloads: [...state.payloads, payload] })),
192
277
  setHtmlContent: (htmlContent) => set({ htmlContent }),
193
- setWrapperHeight: (wrapperHeight) => set({ wrapperHeight }),
194
- setIframeHeight: (iframeHeight) => set({ iframeHeight }),
195
278
  };
196
279
  });
197
280
 
281
+ const DEFAULT_VIEW_ID = 'default';
198
282
  const useHeatmapSingleStore = create()((set, get) => {
199
283
  return {
200
- vizRef: null,
201
- iframeHeight: 0,
202
- setVizRef: (vizRef) => set({ vizRef }),
203
- setIframeHeight: (iframeHeight) => set({ iframeHeight }),
284
+ vizRef: { [DEFAULT_VIEW_ID]: null },
285
+ iframeHeight: { [DEFAULT_VIEW_ID]: 0 },
286
+ wrapperHeight: { [DEFAULT_VIEW_ID]: 0 },
287
+ setVizRef: (vizRef, viewId = DEFAULT_VIEW_ID) => set((state) => ({
288
+ vizRef: { ...state.vizRef, [viewId]: vizRef },
289
+ })),
290
+ setIframeHeight: (iframeHeight, viewId = DEFAULT_VIEW_ID) => {
291
+ set((state) => ({
292
+ iframeHeight: { ...state.iframeHeight, [viewId]: iframeHeight },
293
+ }));
294
+ },
295
+ setWrapperHeight: (wrapperHeight, viewId = DEFAULT_VIEW_ID) => {
296
+ set((state) => ({
297
+ wrapperHeight: { ...state.wrapperHeight, [viewId]: wrapperHeight },
298
+ }));
299
+ },
300
+ copyView: (fromViewId, toViewId) => set((state) => ({
301
+ // Don't copy vizRef - each view needs its own visualizer instance
302
+ iframeHeight: { ...state.iframeHeight, [toViewId]: state.iframeHeight[fromViewId] ?? 0 },
303
+ wrapperHeight: { ...state.wrapperHeight, [toViewId]: state.wrapperHeight[fromViewId] ?? 0 },
304
+ })),
305
+ clearView: (viewId) => set((state) => {
306
+ const newVizRef = { ...state.vizRef };
307
+ const newIframeHeight = { ...state.iframeHeight };
308
+ const newWrapperHeight = { ...state.wrapperHeight };
309
+ delete newVizRef[viewId];
310
+ delete newIframeHeight[viewId];
311
+ delete newWrapperHeight[viewId];
312
+ return {
313
+ vizRef: newVizRef,
314
+ iframeHeight: newIframeHeight,
315
+ wrapperHeight: newWrapperHeight,
316
+ };
317
+ }),
318
+ resetAll: () => set({
319
+ vizRef: { [DEFAULT_VIEW_ID]: null },
320
+ iframeHeight: { [DEFAULT_VIEW_ID]: 0 },
321
+ wrapperHeight: { [DEFAULT_VIEW_ID]: 0 },
322
+ }),
323
+ };
324
+ });
325
+
326
+ const createDefaultView = (id, label, options) => ({
327
+ id,
328
+ label,
329
+ heatmapType: options?.heatmapType ?? IHeatmapType.Scroll,
330
+ clickType: options?.clickType ?? IClickType.Total,
331
+ scrollType: options?.scrollType ?? IScrollType.Depth,
332
+ data: options?.data,
333
+ clickmap: undefined,
334
+ scrollmap: undefined,
335
+ dataInfo: undefined,
336
+ vizRef: null,
337
+ iframeHeight: 0,
338
+ zoomRatio: 100,
339
+ scale: 1,
340
+ isScaledToFit: false,
341
+ isRendering: true,
342
+ isRenderViz: false,
343
+ });
344
+ const useHeatmapCompareStore = create()((set, get) => {
345
+ return {
346
+ views: new Map(),
347
+ viewOrder: [],
348
+ layout: 'grid-2',
349
+ syncSettings: {
350
+ zoomRatio: false,
351
+ scrolling: false,
352
+ heatmapType: false,
353
+ },
354
+ viewIdCounter: 0,
355
+ addView: (options) => {
356
+ const state = get();
357
+ const viewId = `view-${state.viewIdCounter}`;
358
+ const label = options?.label ?? `Version ${state.viewOrder.length + 1}`;
359
+ const newView = createDefaultView(viewId, label, options);
360
+ const newViews = new Map(state.views);
361
+ newViews.set(viewId, newView);
362
+ set({
363
+ views: newViews,
364
+ viewOrder: [...state.viewOrder, viewId],
365
+ viewIdCounter: state.viewIdCounter + 1,
366
+ });
367
+ return viewId;
368
+ },
369
+ removeView: (viewId) => {
370
+ const state = get();
371
+ const newViews = new Map(state.views);
372
+ newViews.delete(viewId);
373
+ set({
374
+ views: newViews,
375
+ viewOrder: state.viewOrder.filter((id) => id !== viewId),
376
+ });
377
+ },
378
+ updateView: (viewId, updates) => {
379
+ const state = get();
380
+ const view = state.views.get(viewId);
381
+ if (!view)
382
+ return;
383
+ const newViews = new Map(state.views);
384
+ newViews.set(viewId, { ...view, ...updates });
385
+ set({ views: newViews });
386
+ // Handle syncing
387
+ const { syncSettings } = state;
388
+ if (syncSettings.zoomRatio && 'zoomRatio' in updates && updates.zoomRatio !== undefined) {
389
+ get().syncProperty('zoomRatio', updates.zoomRatio);
390
+ }
391
+ if (syncSettings.heatmapType &&
392
+ 'heatmapType' in updates &&
393
+ updates.heatmapType !== undefined) {
394
+ get().syncProperty('heatmapType', updates.heatmapType);
395
+ }
396
+ },
397
+ getView: (viewId) => {
398
+ return get().views.get(viewId);
399
+ },
400
+ setLayout: (layout) => {
401
+ set({ layout });
402
+ },
403
+ setSyncSettings: (settings) => {
404
+ set({ syncSettings: { ...get().syncSettings, ...settings } });
405
+ },
406
+ initializeCompare: (count, options) => {
407
+ const viewIds = [];
408
+ const newViews = new Map();
409
+ for (let i = 0; i < count; i++) {
410
+ const viewId = `view-${i}`;
411
+ const label = options?.label ?? String.fromCharCode(65 + i); // A, B, C, D
412
+ newViews.set(viewId, createDefaultView(viewId, `Version ${label}`, options));
413
+ viewIds.push(viewId);
414
+ }
415
+ const layoutMap = {
416
+ 2: 'grid-2',
417
+ 3: 'grid-3',
418
+ 4: 'grid-4',
419
+ };
420
+ set({
421
+ views: newViews,
422
+ viewOrder: viewIds,
423
+ layout: layoutMap[count],
424
+ viewIdCounter: count,
425
+ });
426
+ },
427
+ resetCompare: () => {
428
+ set({
429
+ views: new Map(),
430
+ viewOrder: [],
431
+ layout: 'grid-2',
432
+ viewIdCounter: 0,
433
+ syncSettings: {
434
+ zoomRatio: false,
435
+ scrolling: false,
436
+ heatmapType: false,
437
+ },
438
+ });
439
+ },
440
+ syncProperty: (property, value) => {
441
+ const state = get();
442
+ const newViews = new Map(state.views);
443
+ state.viewOrder.forEach((viewId) => {
444
+ const view = newViews.get(viewId);
445
+ if (view) {
446
+ newViews.set(viewId, { ...view, [property]: value });
447
+ }
448
+ });
449
+ set({ views: newViews });
450
+ },
204
451
  };
205
452
  });
206
453
 
@@ -209,7 +456,7 @@ const useRegisterConfig = () => {
209
456
  const width = useHeatmapConfigStore((state) => state.width);
210
457
  const sidebarWidth = useHeatmapConfigStore((state) => state.sidebarWidth);
211
458
  const heatmapType = useHeatmapConfigStore((state) => state.heatmapType);
212
- const setIsRendering = useHeatmapDataStore((state) => state.setIsRendering);
459
+ const setIsRendering = useHeatmapConfigStore((state) => state.setIsRendering);
213
460
  useEffect(() => {
214
461
  setIsRendering(true);
215
462
  setTimeout(() => {
@@ -228,10 +475,54 @@ const useRegisterControl = (control) => {
228
475
  registerControl('ElementCallout', control.ElementCallout);
229
476
  };
230
477
 
231
- const useRegisterData = (data, dataInfo) => {
478
+ /**
479
+ * Context to provide viewId to components
480
+ * Used in compare mode to isolate data between views
481
+ */
482
+ const ViewIdContext = createContext(undefined);
483
+ /**
484
+ * Hook to get current viewId
485
+ * Returns 'default' if not in a ViewIdContext (single mode)
486
+ */
487
+ const useViewId = () => {
488
+ const viewId = useContext(ViewIdContext);
489
+ return viewId || 'default';
490
+ };
491
+ /**
492
+ * Hook to check if currently in compare mode
493
+ */
494
+ const useIsCompareMode = () => {
495
+ const viewId = useContext(ViewIdContext);
496
+ return viewId !== undefined && viewId !== 'default';
497
+ };
498
+
499
+ const useHeatmapData = (props) => {
500
+ const viewId = props?.viewId || useViewId();
501
+ const data = useHeatmapDataStore((state) => state.data[viewId]);
502
+ const clickmap = useHeatmapDataStore((state) => state.clickmap[viewId]);
503
+ const scrollmap = useHeatmapDataStore((state) => state.scrollmap[viewId]);
504
+ const dataInfo = useHeatmapDataStore((state) => state.dataInfo[viewId]);
232
505
  const setData = useHeatmapDataStore((state) => state.setData);
233
- const setIsRendering = useHeatmapDataStore((state) => state.setIsRendering);
506
+ const setClickmap = useHeatmapDataStore((state) => state.setClickmap);
507
+ const setScrollmap = useHeatmapDataStore((state) => state.setScrollmap);
234
508
  const setDataInfo = useHeatmapDataStore((state) => state.setDataInfo);
509
+ return {
510
+ // Data
511
+ data,
512
+ clickmap,
513
+ scrollmap,
514
+ dataInfo,
515
+ // Setters (auto-inject viewId)
516
+ setData: (newData) => setData(newData, viewId),
517
+ setClickmap: (newClickmap) => setClickmap(newClickmap, viewId),
518
+ setScrollmap: (newScrollmap) => setScrollmap(newScrollmap, viewId),
519
+ setDataInfo: (newDataInfo) => setDataInfo(newDataInfo, viewId),
520
+ };
521
+ };
522
+
523
+ const useRegisterData = (data, dataInfo) => {
524
+ const setIsRendering = useHeatmapConfigStore((state) => state.setIsRendering);
525
+ const { setData, setDataInfo } = useHeatmapData();
235
526
  const handleSetData = useCallback((data) => {
236
527
  if (!data)
237
528
  return;
@@ -252,8 +543,7 @@ const useRegisterData = (data, dataInfo) => {
252
543
  };
253
544
 
254
545
  const useRegisterHeatmap = ({ clickmap, scrollmap }) => {
255
- const setClickmap = useHeatmapDataStore((state) => state.setClickmap);
256
- const setScrollmap = useHeatmapDataStore((state) => state.setScrollmap);
546
+ const { setClickmap, setScrollmap } = useHeatmapData();
257
547
  const handleSetClickmap = useCallback((clickmap) => {
258
548
  if (!clickmap)
259
549
  return;
@@ -1127,6 +1417,48 @@ function initIframeHelperFixer(config) {
1127
1417
  return fixer;
1128
1418
  }
1129
1419
 
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
+
1130
1462
  const scrollToElementIfNeeded = (visualRef, rect, scale) => {
1131
1463
  if (!visualRef.current)
1132
1464
  return;
@@ -1145,11 +1477,11 @@ const scrollToElementIfNeeded = (visualRef, rect, scale) => {
1145
1477
  });
1146
1478
  };
1147
1479
  const useClickedElement = ({ visualRef, getRect }) => {
1148
- const heatmapInfo = useHeatmapDataStore((state) => state.dataInfo);
1149
1480
  const selectedElement = useHeatmapInteractionStore((state) => state.selectedElement);
1150
1481
  const shouldShowCallout = useHeatmapInteractionStore((state) => state.shouldShowCallout);
1151
1482
  const setShouldShowCallout = useHeatmapInteractionStore((state) => state.setShouldShowCallout);
1152
- const scale = useHeatmapVizStore((state) => state.scale);
1483
+ const { widthScale } = useHeatmapViz();
1484
+ const { dataInfo } = useHeatmapData();
1153
1485
  const [clickedElement, setClickedElement] = useState(null);
1154
1486
  const [showMissingElement, setShowMissingElement] = useState(false);
1155
1487
  const reset = () => {
@@ -1158,11 +1490,11 @@ const useClickedElement = ({ visualRef, getRect }) => {
1158
1490
  setShouldShowCallout(false);
1159
1491
  };
1160
1492
  useEffect(() => {
1161
- if (!selectedElement || !heatmapInfo?.elementMapInfo) {
1493
+ if (!selectedElement || !dataInfo?.elementMapInfo) {
1162
1494
  reset();
1163
1495
  return;
1164
1496
  }
1165
- const info = heatmapInfo.elementMapInfo[selectedElement];
1497
+ const info = dataInfo.elementMapInfo[selectedElement];
1166
1498
  if (!info) {
1167
1499
  setClickedElement(null);
1168
1500
  return;
@@ -1170,7 +1502,7 @@ const useClickedElement = ({ visualRef, getRect }) => {
1170
1502
  const hash = selectedElement;
1171
1503
  const selector = info.selector;
1172
1504
  const rect = getRect({ hash: selectedElement, selector });
1173
- const elementInfo = buildElementInfo(hash, rect, heatmapInfo);
1505
+ const elementInfo = buildElementInfo(hash, rect, dataInfo);
1174
1506
  if (!rect) {
1175
1507
  setClickedElement(elementInfo);
1176
1508
  setShowMissingElement(true);
@@ -1178,29 +1510,29 @@ const useClickedElement = ({ visualRef, getRect }) => {
1178
1510
  return;
1179
1511
  }
1180
1512
  setShowMissingElement(false);
1181
- scrollToElementIfNeeded(visualRef, rect, scale);
1513
+ scrollToElementIfNeeded(visualRef, rect, widthScale);
1182
1514
  setShouldShowCallout(true);
1183
1515
  requestAnimationFrame(() => {
1184
1516
  setClickedElement(elementInfo);
1185
1517
  });
1186
- }, [selectedElement, heatmapInfo, getRect, visualRef, scale]);
1518
+ }, [selectedElement, dataInfo, getRect, visualRef, widthScale]);
1187
1519
  return { clickedElement, showMissingElement, shouldShowCallout, setShouldShowCallout };
1188
1520
  };
1189
1521
 
1190
1522
  const useElementCalloutVisible = ({ visualRef, getRect }) => {
1191
- const scale = useHeatmapVizStore((state) => state.scale);
1192
1523
  const selectedElement = useHeatmapInteractionStore((state) => state.selectedElement);
1193
- const heatmapInfo = useHeatmapDataStore((state) => state.dataInfo);
1194
1524
  const setShouldShowCallout = useHeatmapInteractionStore((state) => state.setShouldShowCallout);
1525
+ const { widthScale } = useHeatmapViz();
1526
+ const { dataInfo } = useHeatmapData();
1195
1527
  useEffect(() => {
1196
1528
  if (!selectedElement)
1197
1529
  return;
1198
1530
  const elementIsInViewportFn = () => {
1199
- const elementInfo = heatmapInfo?.elementMapInfo?.[selectedElement];
1531
+ const elementInfo = dataInfo?.elementMapInfo?.[selectedElement];
1200
1532
  if (!elementInfo)
1201
1533
  return;
1202
1534
  const rect = getRect({ hash: selectedElement, selector: elementInfo.selector });
1203
- const isInViewport = isElementInViewport(rect, visualRef, scale);
1535
+ const isInViewport = isElementInViewport(rect, visualRef, widthScale);
1204
1536
  setShouldShowCallout(isInViewport);
1205
1537
  };
1206
1538
  elementIsInViewportFn();
@@ -1215,7 +1547,7 @@ const useElementCalloutVisible = ({ visualRef, getRect }) => {
1215
1547
  window.removeEventListener('resize', handleUpdate);
1216
1548
  visualRef?.current?.removeEventListener('scroll', handleUpdate);
1217
1549
  };
1218
- }, [selectedElement, visualRef, getRect, scale, heatmapInfo, setShouldShowCallout]);
1550
+ }, [selectedElement, visualRef, getRect, widthScale, dataInfo, setShouldShowCallout]);
1219
1551
  return {};
1220
1552
  };
1221
1553
 
@@ -1238,9 +1570,8 @@ const useHeatmapEffects = ({ isVisible, isElementSidebarOpen, setShouldShowCallo
1238
1570
  };
1239
1571
 
1240
1572
  const useHeatmapElementPosition = ({ iframeRef, wrapperRef, visualizer }) => {
1241
- const widthScale = useHeatmapVizStore((state) => state.scale);
1242
- const iframeHeight = useHeatmapSingleStore((state) => state.iframeHeight);
1243
1573
  const heatmapWidth = useHeatmapConfigStore((state) => state.width);
1574
+ const { iframeHeight, widthScale } = useHeatmapViz();
1244
1575
  return useCallback((element) => {
1245
1576
  const hash = element?.hash;
1246
1577
  if (!iframeRef.current?.contentDocument || !hash || !visualizer)
@@ -1394,8 +1725,8 @@ const useHoveredElement = ({ iframeRef, getRect }) => {
1394
1725
  const hoveredElement = useHeatmapInteractionStore((state) => state.hoveredElement);
1395
1726
  const setHoveredElement = useHeatmapInteractionStore((state) => state.setHoveredElement);
1396
1727
  const onSelect = useHeatmapInteractionStore((state) => state.setSelectedElement);
1397
- const widthScale = useHeatmapVizStore((state) => state.scale);
1398
- const heatmapInfo = useHeatmapDataStore((state) => state.dataInfo);
1728
+ const { widthScale } = useHeatmapViz();
1729
+ const { dataInfo } = useHeatmapData();
1399
1730
  const reset = useCallback(() => {
1400
1731
  setHoveredElement(null);
1401
1732
  }, [setHoveredElement]);
@@ -1403,7 +1734,7 @@ const useHoveredElement = ({ iframeRef, getRect }) => {
1403
1734
  reset();
1404
1735
  }, [reset]);
1405
1736
  const getHashFromEvent = useCallback((event) => {
1406
- if (!heatmapInfo || !isIframeReady(iframeRef, heatmapInfo)) {
1737
+ if (!dataInfo || !isIframeReady(iframeRef, dataInfo)) {
1407
1738
  reset();
1408
1739
  return;
1409
1740
  }
@@ -1411,8 +1742,8 @@ const useHoveredElement = ({ iframeRef, getRect }) => {
1411
1742
  const doc = iframe.contentDocument;
1412
1743
  const iframeRect = iframe.getBoundingClientRect();
1413
1744
  const { x, y } = convertViewportToIframeCoords(event.clientX, event.clientY, iframeRect, widthScale);
1414
- const targetElement = findTargetElement(doc, x, y, heatmapInfo);
1415
- if (!targetElement || !isValidElement(targetElement, heatmapInfo)) {
1745
+ const targetElement = findTargetElement(doc, x, y, dataInfo);
1746
+ if (!targetElement || !isValidElement(targetElement, dataInfo)) {
1416
1747
  reset();
1417
1748
  return;
1418
1749
  }
@@ -1421,9 +1752,9 @@ const useHoveredElement = ({ iframeRef, getRect }) => {
1421
1752
  return hash;
1422
1753
  reset();
1423
1754
  return;
1424
- }, [heatmapInfo, iframeRef, getRect, widthScale, reset]);
1755
+ }, [dataInfo, iframeRef, getRect, widthScale, reset]);
1425
1756
  const handleMouseMove = useCallback(debounce((event) => {
1426
- if (!heatmapInfo) {
1757
+ if (!dataInfo) {
1427
1758
  reset();
1428
1759
  return;
1429
1760
  }
@@ -1432,15 +1763,15 @@ const useHoveredElement = ({ iframeRef, getRect }) => {
1432
1763
  reset();
1433
1764
  return;
1434
1765
  }
1435
- const selector = heatmapInfo?.elementMapInfo?.[hash];
1766
+ const selector = dataInfo?.elementMapInfo?.[hash];
1436
1767
  const rect = getRect({ hash, selector });
1437
- const elementInfo = buildElementInfo(hash, rect, heatmapInfo);
1768
+ const elementInfo = buildElementInfo(hash, rect, dataInfo);
1438
1769
  if (!elementInfo) {
1439
1770
  reset();
1440
1771
  return;
1441
1772
  }
1442
1773
  setHoveredElement(elementInfo);
1443
- }, 16), [heatmapInfo, getRect, reset, getHashFromEvent]);
1774
+ }, 16), [dataInfo, getRect, reset, getHashFromEvent]);
1444
1775
  const handleClick = useCallback(() => {
1445
1776
  if (!hoveredElement?.hash)
1446
1777
  return;
@@ -1556,11 +1887,9 @@ function useVizLiveIframeMsg(options = {}) {
1556
1887
  }
1557
1888
 
1558
1889
  function useVizLiveRender() {
1559
- const wrapperHeight = useHeatmapLiveStore((state) => state.wrapperHeight);
1560
- const setIframeHeight = useHeatmapLiveStore((state) => state.setIframeHeight);
1890
+ const { setIframeHeight, wrapperHeight, setIsRenderViz } = useHeatmapViz();
1561
1891
  const contentWidth = useHeatmapConfigStore((state) => state.width);
1562
1892
  const htmlContent = useHeatmapLiveStore((state) => state.htmlContent);
1563
- const setIsRenderViz = useHeatmapVizStore((state) => state.setIsRenderViz);
1564
1893
  const { iframeRef, isReady } = useVizLiveIframeMsg();
1565
1894
  useEffect(() => {
1566
1895
  if (!htmlContent || !iframeRef.current)
@@ -1605,16 +1934,14 @@ function reset(iframe, rect, onSuccess) {
1605
1934
  fixer.enableNavigationBlocking();
1606
1935
  }
1607
1936
 
1608
- let visualizer = new Visualizer();
1609
1937
  const useHeatmapRender = () => {
1610
- const data = useHeatmapDataStore((state) => state.data);
1611
- const setVizRef = useHeatmapSingleStore((state) => state.setVizRef);
1612
- const setIsRenderViz = useHeatmapVizStore((state) => state.setIsRenderViz);
1613
- const setIframeHeight = useHeatmapSingleStore((state) => state.setIframeHeight);
1938
+ const { data } = useHeatmapData();
1939
+ const { vizRef, setVizRef, setIsRenderViz, setIframeHeight } = useHeatmapViz();
1614
1940
  const iframeRef = useRef(null);
1615
1941
  const renderHeatmap = useCallback(async (payloads) => {
1616
1942
  if (!payloads || payloads.length === 0)
1617
1943
  return;
1944
+ const visualizer = vizRef || new Visualizer();
1618
1945
  setIsRenderViz(false);
1619
1946
  const iframe = iframeRef.current;
1620
1947
  if (!iframe?.contentWindow)
@@ -1665,8 +1992,8 @@ function sortEvents(a, b) {
1665
1992
  }
1666
1993
 
1667
1994
  const useReplayRender = () => {
1668
- const data = useHeatmapDataStore((state) => state.data);
1669
1995
  const setWidth = useHeatmapConfigStore((state) => state.setWidth);
1996
+ const { data } = useHeatmapData();
1670
1997
  const visualizerRef = useRef(null);
1671
1998
  const iframeRef = useRef(null);
1672
1999
  const eventsRef = useRef([]);
@@ -1837,8 +2164,7 @@ const useContentDimensions = ({ iframeRef, }) => {
1837
2164
  };
1838
2165
 
1839
2166
  const useObserveIframeHeight = (props) => {
1840
- const { iframeRef, setIframeHeight } = props;
1841
- const isRenderViz = useHeatmapVizStore((state) => state.isRenderViz);
2167
+ const { iframeRef, setIframeHeight, isRenderViz } = props;
1842
2168
  const resizeObserverRef = useRef(null);
1843
2169
  const mutationObserverRef = useRef(null);
1844
2170
  const debounceTimerRef = useRef(null);
@@ -1963,21 +2289,51 @@ const useObserveIframeHeight = (props) => {
1963
2289
  };
1964
2290
 
1965
2291
  const useScaleCalculation = (props) => {
1966
- const scale = useHeatmapVizStore((state) => state.scale);
1967
- const setScale = useHeatmapVizStore((state) => state.setScale);
1968
- const { containerWidth, contentWidth } = props;
1969
- useEffect(() => {
1970
- if (containerWidth > 0 && contentWidth > 0) {
2292
+ const { widthScale, zoomRatio, isScaledToFit, minZoomRatio } = useHeatmapViz();
2293
+ const { setScale, setIsScaledToFit, setMinZoomRatio } = useHeatmapViz();
2294
+ const { containerWidth, containerHeight, contentWidth, contentHeight } = props;
2295
+ const calculateScaleResult = useCallback(() => {
2296
+ if (containerWidth > 0 && contentWidth > 0 && containerHeight > 0 && contentHeight > 0) {
2297
+ // 1. Calculate widthScale (base scale from width)
1971
2298
  const availableWidth = containerWidth - HEATMAP_CONFIG['padding'] * 2;
1972
- const calculatedScale = Math.min(availableWidth / contentWidth, 1);
1973
- setScale(calculatedScale);
1974
- }
1975
- }, [containerWidth, contentWidth]);
1976
- return { scale };
2299
+ const widthScale = Math.min(availableWidth / contentWidth, 1);
2300
+ // 2. Calculate available height
2301
+ const toolbarHeight = HEATMAP_CONFIG['heightToolbar'] ;
2302
+ const paddingTotal = HEATMAP_CONFIG['padding'] * 2;
2303
+ const availableHeight = containerHeight - toolbarHeight - paddingTotal; // 10px buffer to avoid scroll bar
2304
+ // 3. Calculate minZoomRatio (zoom ratio minimum to fit iframe in container)
2305
+ const roundedMinZoomRatio = (availableHeight / (contentHeight * widthScale)) * 100;
2306
+ // Limit minZoomRatio to a reasonable range (10-100)
2307
+ const finalMinZoomRatio = Math.max(10, Math.min(roundedMinZoomRatio, 100));
2308
+ // 4. Apply zoom ratio (cannot be less than minZoomRatio)
2309
+ const clampedZoomRatio = Math.max(zoomRatio, finalMinZoomRatio);
2310
+ const zoomMultiplier = clampedZoomRatio / 100;
2311
+ // 5. Calculate finalScale
2312
+ const finalScale = widthScale * zoomMultiplier;
2313
+ // 6. Check if it is currently fitted
2314
+ const isCurrentlyFitted = zoomRatio <= finalMinZoomRatio;
2315
+ // 7. Update store
2316
+ setScale(finalScale);
2317
+ setIsScaledToFit(isCurrentlyFitted);
2318
+ setMinZoomRatio(finalMinZoomRatio);
2319
+ }
2320
+ }, [
2321
+ containerWidth,
2322
+ containerHeight,
2323
+ contentWidth,
2324
+ contentHeight,
2325
+ zoomRatio,
2326
+ setScale,
2327
+ setIsScaledToFit,
2328
+ setMinZoomRatio,
2329
+ ]);
2330
+ useEffect(() => {
2331
+ calculateScaleResult();
2332
+ }, [calculateScaleResult]);
2333
+ return { widthScale, isScaledToFit, minZoomRatio };
1977
2334
  };
1978
2335
 
1979
- const useScrollSync = ({ iframeRef }) => {
1980
- const widthScale = useHeatmapVizStore((state) => state.scale);
2336
+ const useScrollSync = ({ widthScale, iframeRef, }) => {
1981
2337
  const handleScroll = useCallback((scrollTop) => {
1982
2338
  const iframe = iframeRef.current;
1983
2339
  if (!iframe || widthScale <= 0)
@@ -1998,19 +2354,24 @@ const useScrollSync = ({ iframeRef }) => {
1998
2354
  };
1999
2355
 
2000
2356
  const useHeatmapScale = (props) => {
2001
- const { wrapperRef, iframeRef, iframeHeight, setIframeHeight } = props;
2357
+ const { wrapperRef, iframeRef, iframeHeight, setIframeHeight, isRenderViz } = props;
2002
2358
  // 1. Observe container dimensions
2003
2359
  const { containerWidth, containerHeight } = useContainerDimensions({ wrapperRef });
2004
2360
  // 2. Get content dimensions from config
2005
2361
  const { contentWidth } = useContentDimensions({ iframeRef });
2006
2362
  // 3. Observe iframe height (now reacts to width changes)
2007
- useObserveIframeHeight({ iframeRef, setIframeHeight });
2363
+ useObserveIframeHeight({ iframeRef, setIframeHeight, isRenderViz });
2008
2364
  // 4. Calculate scale
2009
- const { scale } = useScaleCalculation({ containerWidth, contentWidth });
2365
+ const { widthScale } = useScaleCalculation({
2366
+ containerWidth,
2367
+ containerHeight,
2368
+ contentWidth,
2369
+ contentHeight: iframeHeight,
2370
+ });
2010
2371
  // 5. Setup scroll sync
2011
- const { handleScroll } = useScrollSync({ iframeRef });
2012
- const scaledHeight = iframeHeight * scale;
2013
- const scaledWidth = contentWidth * scale;
2372
+ const { handleScroll } = useScrollSync({ widthScale, iframeRef });
2373
+ const scaledHeight = iframeHeight * widthScale;
2374
+ const scaledWidth = contentWidth * widthScale;
2014
2375
  return {
2015
2376
  containerWidth,
2016
2377
  containerHeight,
@@ -2021,10 +2382,10 @@ const useHeatmapScale = (props) => {
2021
2382
  };
2022
2383
 
2023
2384
  const useWrapperRefHeight = (props) => {
2024
- const { isActive, wrapperRef, setWrapperHeight } = props;
2025
- const isRenderViz = useHeatmapVizStore((state) => state.isRenderViz);
2385
+ const { isActive, wrapperRef } = props;
2026
2386
  const resizeObserverRef = useRef(null);
2027
2387
  const mutationObserverRef = useRef(null);
2388
+ const { isRenderViz, setWrapperHeight } = useHeatmapViz();
2028
2389
  const updateWrapperHeight = useCallback(() => {
2029
2390
  const wrapper = wrapperRef.current;
2030
2391
  if (!wrapper)
@@ -2032,13 +2393,13 @@ const useWrapperRefHeight = (props) => {
2032
2393
  try {
2033
2394
  const wrapperHeight = wrapper.offsetHeight;
2034
2395
  if (wrapperHeight > 0) {
2035
- setWrapperHeight?.(wrapperHeight);
2396
+ setWrapperHeight(wrapperHeight);
2036
2397
  }
2037
2398
  }
2038
2399
  catch (error) {
2039
2400
  console.warn('Cannot measure iframe content:', error);
2040
2401
  }
2041
- }, [wrapperRef, setWrapperHeight]);
2402
+ }, [wrapperRef]);
2042
2403
  useEffect(() => {
2043
2404
  const wrapper = wrapperRef.current;
2044
2405
  if (!wrapper || !isRenderViz)
@@ -2090,7 +2451,7 @@ const useWrapperRefHeight = (props) => {
2090
2451
  };
2091
2452
 
2092
2453
  const useZonePositions = (options) => {
2093
- const iframeHeight = useHeatmapSingleStore((state) => state.iframeHeight);
2454
+ const { iframeHeight } = useHeatmapViz();
2094
2455
  const getZonePosition = useCallback((zone) => {
2095
2456
  if (!iframeHeight) {
2096
2457
  return null;
@@ -2116,12 +2477,13 @@ const useScrollmapZones = (options) => {
2116
2477
  const { mode = 'basic', enabled = true, iframeRef, wrapperRef } = options;
2117
2478
  const [isReady, setIsReady] = useState(false);
2118
2479
  const [zones, setZones] = useState([]);
2119
- const scrollmap = useHeatmapDataStore((state) => state.scrollmap);
2120
- const scrollMapInfo = useHeatmapDataStore((state) => state.dataInfo?.scrollMapInfo);
2480
+ const { scrollmap } = useHeatmapData();
2481
+ const { dataInfo } = useHeatmapData();
2121
2482
  const { getZonePosition } = useZonePositions();
2483
+ const scrollMapInfo = dataInfo?.scrollMapInfo;
2122
2484
  const maxUsers = useMemo(() => {
2123
2485
  if (!scrollmap || scrollmap.length === 0)
2124
- return 100;
2486
+ return 0;
2125
2487
  return Math.max(...scrollmap.map((d) => d.percUsers));
2126
2488
  }, [scrollmap]);
2127
2489
  const createZones = useCallback((data) => {
@@ -2218,6 +2580,185 @@ const getScrollGradientColor = (normalized) => {
2218
2580
  return `rgb(${r}, ${g}, ${b})`;
2219
2581
  };
2220
2582
 
2583
+ const CompareViewContext = createContext(null);
2584
+ /**
2585
+ * Hook to safely access compare view context (returns null if not in compare mode)
2586
+ */
2587
+ const useCompareViewContextSafe = () => {
2588
+ return useContext(CompareViewContext);
2589
+ };
2590
+
2591
+ /**
2592
+ * Hook that returns data from compare view context if in compare mode,
2593
+ * otherwise returns data from global store
2594
+ */
2595
+ const useCompareAwareData = () => {
2596
+ const compareContext = useCompareViewContextSafe();
2597
+ // Global store values
2598
+ const globalData = useHeatmapDataStore((state) => state.data);
2599
+ const globalClickmap = useHeatmapDataStore((state) => state.clickmap);
2600
+ const globalScrollmap = useHeatmapDataStore((state) => state.scrollmap);
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,
2609
+ };
2610
+ }
2611
+ // Otherwise use global store
2612
+ return {
2613
+ data: globalData,
2614
+ clickmap: globalClickmap,
2615
+ scrollmap: globalScrollmap,
2616
+ dataInfo: globalDataInfo,
2617
+ };
2618
+ };
2619
+ /**
2620
+ * Hook that returns setters for data
2621
+ * In compare mode, updates the view context
2622
+ * In single/live mode, updates the global store
2623
+ */
2624
+ const useCompareAwareDataSetters = () => {
2625
+ const compareContext = useCompareViewContextSafe();
2626
+ const setDataGlobal = useHeatmapDataStore((state) => state.setData);
2627
+ const setClickmapGlobal = useHeatmapDataStore((state) => state.setClickmap);
2628
+ const setScrollmapGlobal = useHeatmapDataStore((state) => state.setScrollmap);
2629
+ const setDataInfoGlobal = useHeatmapDataStore((state) => state.setDataInfo);
2630
+ if (compareContext) {
2631
+ return {
2632
+ setData: (data) => compareContext.updateView({ data }),
2633
+ setClickmap: (clickmap) => compareContext.updateView({ clickmap }),
2634
+ setScrollmap: (scrollmap) => compareContext.updateView({ scrollmap }),
2635
+ setDataInfo: (dataInfo) => compareContext.updateView({ dataInfo }),
2636
+ };
2637
+ }
2638
+ return {
2639
+ setData: setDataGlobal,
2640
+ setClickmap: setClickmapGlobal,
2641
+ setScrollmap: setScrollmapGlobal,
2642
+ setDataInfo: setDataInfoGlobal,
2643
+ };
2644
+ };
2645
+
2646
+ /**
2647
+ * Hook that returns config from compare view context if in compare mode,
2648
+ * otherwise returns config from global store
2649
+ */
2650
+ const useCompareAwareConfig = () => {
2651
+ const compareContext = useCompareViewContextSafe();
2652
+ // Global store values
2653
+ const globalHeatmapType = useHeatmapConfigStore((state) => state.heatmapType);
2654
+ const globalClickType = useHeatmapConfigStore((state) => state.clickType);
2655
+ const globalScrollType = useHeatmapConfigStore((state) => state.scrollType);
2656
+ // If in compare mode, use view context
2657
+ if (compareContext) {
2658
+ return {
2659
+ heatmapType: compareContext.view.heatmapType,
2660
+ clickType: compareContext.view.clickType,
2661
+ scrollType: compareContext.view.scrollType,
2662
+ };
2663
+ }
2664
+ // Otherwise use global store
2665
+ return {
2666
+ heatmapType: globalHeatmapType,
2667
+ clickType: globalClickType,
2668
+ scrollType: globalScrollType,
2669
+ };
2670
+ };
2671
+ /**
2672
+ * Hook that returns config setters
2673
+ * In compare mode, updates the view context
2674
+ * In single/live mode, updates the global store
2675
+ */
2676
+ const useCompareAwareConfigSetters = () => {
2677
+ const compareContext = useCompareViewContextSafe();
2678
+ const setHeatmapTypeGlobal = useHeatmapConfigStore((state) => state.setHeatmapType);
2679
+ const setClickTypeGlobal = useHeatmapConfigStore((state) => state.setClickType);
2680
+ const setScrollTypeGlobal = useHeatmapConfigStore((state) => state.setScrollType);
2681
+ if (compareContext) {
2682
+ return {
2683
+ setHeatmapType: (heatmapType) => compareContext.updateView({ heatmapType }),
2684
+ setClickType: (clickType) => compareContext.updateView({ clickType }),
2685
+ setScrollType: (scrollType) => compareContext.updateView({ scrollType }),
2686
+ };
2687
+ }
2688
+ return {
2689
+ setHeatmapType: setHeatmapTypeGlobal,
2690
+ setClickType: setClickTypeGlobal,
2691
+ setScrollType: setScrollTypeGlobal,
2692
+ };
2693
+ };
2694
+
2695
+ /**
2696
+ * Hook that returns viz state from compare view context if in compare mode,
2697
+ * otherwise returns viz state from global store
2698
+ */
2699
+ const useCompareAwareViz = () => {
2700
+ const compareContext = useCompareViewContextSafe();
2701
+ // Global store values
2702
+ const globalZoomRatio = useHeatmapVizStore((state) => state.zoomRatio);
2703
+ const globalScale = useHeatmapVizStore((state) => state.scale);
2704
+ const globalIsScaledToFit = useHeatmapVizStore((state) => state.isScaledToFit);
2705
+ const globalIsRenderViz = useHeatmapVizStore((state) => state.isRenderViz);
2706
+ const globalIframeHeight = useHeatmapSingleStore((state) => state.iframeHeight);
2707
+ const globalVizRef = useHeatmapSingleStore((state) => state.vizRef);
2708
+ // If in compare mode, use view context
2709
+ if (compareContext) {
2710
+ return {
2711
+ zoomRatio: compareContext.view.zoomRatio,
2712
+ scale: compareContext.view.scale,
2713
+ isScaledToFit: compareContext.view.isScaledToFit,
2714
+ isRenderViz: compareContext.view.isRenderViz,
2715
+ iframeHeight: compareContext.view.iframeHeight,
2716
+ vizRef: compareContext.view.vizRef,
2717
+ };
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,
2727
+ };
2728
+ };
2729
+ /**
2730
+ * Hook that returns viz setters
2731
+ * In compare mode, updates the view context
2732
+ * In single/live mode, updates the global store
2733
+ */
2734
+ const useCompareAwareVizSetters = () => {
2735
+ const compareContext = useCompareViewContextSafe();
2736
+ const setZoomRatioGlobal = useHeatmapVizStore((state) => state.setZoomRatio);
2737
+ const setScaleGlobal = useHeatmapVizStore((state) => state.setScale);
2738
+ const setIsScaledToFitGlobal = useHeatmapVizStore((state) => state.setIsScaledToFit);
2739
+ const setIsRenderVizGlobal = useHeatmapVizStore((state) => state.setIsRenderViz);
2740
+ const setIframeHeightGlobal = useHeatmapSingleStore((state) => state.setIframeHeight);
2741
+ const setVizRefGlobal = useHeatmapSingleStore((state) => state.setVizRef);
2742
+ if (compareContext) {
2743
+ return {
2744
+ setZoomRatio: (zoomRatio) => compareContext.updateView({ zoomRatio }),
2745
+ setScale: (scale) => compareContext.updateView({ scale }),
2746
+ setIsScaledToFit: (isScaledToFit) => compareContext.updateView({ isScaledToFit }),
2747
+ setIsRenderViz: (isRenderViz) => compareContext.updateView({ isRenderViz }),
2748
+ setIframeHeight: (iframeHeight) => compareContext.updateView({ iframeHeight }),
2749
+ setVizRef: (vizRef) => compareContext.updateView({ vizRef }),
2750
+ };
2751
+ }
2752
+ return {
2753
+ setZoomRatio: setZoomRatioGlobal,
2754
+ setScale: setScaleGlobal,
2755
+ setIsScaledToFit: setIsScaledToFitGlobal,
2756
+ setIsRenderViz: setIsRenderVizGlobal,
2757
+ setIframeHeight: setIframeHeightGlobal,
2758
+ setVizRef: setVizRefGlobal,
2759
+ };
2760
+ };
2761
+
2221
2762
  const BoxStack = forwardRef(({ children, ...props }, ref) => {
2222
2763
  const id = props.id;
2223
2764
  const flexDirection = props.flexDirection;
@@ -2263,7 +2804,12 @@ const BoxStack = forwardRef(({ children, ...props }, ref) => {
2263
2804
 
2264
2805
  const ContentTopBar = () => {
2265
2806
  const controls = useHeatmapControlStore((state) => state.controls);
2807
+ useHeatmapConfigStore((state) => state.mode);
2266
2808
  const TopBar = controls.TopBar;
2809
+ // In compare mode, hide individual top bars since we have a global header
2810
+ // if (mode === 'compare') {
2811
+ // return null;
2812
+ // }
2267
2813
  return (jsx(BoxStack, { id: "gx-hm-content-header", flexDirection: "row", alignItems: "center", overflow: "auto", zIndex: 1, backgroundColor: "white", style: {
2268
2814
  borderBottom: `${HEATMAP_CONFIG.borderWidth}px solid ${HEATMAP_CONFIG.borderColor}`,
2269
2815
  }, children: TopBar && jsx(TopBar, {}) }));
@@ -2279,7 +2825,6 @@ const ContentMetricBar = () => {
2279
2825
  const ContentToolbar = () => {
2280
2826
  const controls = useHeatmapControlStore((state) => state.controls);
2281
2827
  return (jsx("div", { id: "gx-hm-content-toolbar", style: {
2282
- zIndex: 2,
2283
2828
  position: 'absolute',
2284
2829
  bottom: 0,
2285
2830
  left: '8px',
@@ -2289,12 +2834,11 @@ const ContentToolbar = () => {
2289
2834
  }, children: controls.Toolbar ?? null }));
2290
2835
  };
2291
2836
 
2292
- const VizContainer = ({ children, setWrapperHeight }) => {
2837
+ const VizContainer = ({ children, isActive = false }) => {
2293
2838
  const wrapperRef = useRef(null);
2294
2839
  useWrapperRefHeight({
2295
- isActive: !!setWrapperHeight,
2840
+ isActive,
2296
2841
  wrapperRef,
2297
- setWrapperHeight,
2298
2842
  });
2299
2843
  return (jsx(BoxStack, { ref: wrapperRef, id: "gx-hm-viz-container", 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: {
2300
2844
  minWidth: '394px',
@@ -2303,8 +2847,8 @@ const VizContainer = ({ children, setWrapperHeight }) => {
2303
2847
 
2304
2848
  const useClickmap = () => {
2305
2849
  const [isInitialized, setIsInitialized] = useState(false);
2306
- const clickmap = useHeatmapDataStore((state) => state.clickmap);
2307
- const vizRef = useHeatmapSingleStore((state) => state.vizRef);
2850
+ const { clickmap } = useHeatmapData();
2851
+ const { vizRef } = useHeatmapViz();
2308
2852
  const start = useCallback(() => {
2309
2853
  if (isInitialized)
2310
2854
  return;
@@ -2323,8 +2867,8 @@ const useClickmap = () => {
2323
2867
  };
2324
2868
 
2325
2869
  const useScrollmap = () => {
2326
- const vizRef = useHeatmapSingleStore((state) => state.vizRef);
2327
- const scrollmap = useHeatmapDataStore((state) => state.scrollmap);
2870
+ const { vizRef } = useHeatmapViz();
2871
+ const { scrollmap } = useHeatmapData();
2328
2872
  const start = useCallback(() => {
2329
2873
  // if (isInitialized) return;
2330
2874
  if (!vizRef || !scrollmap || scrollmap.length === 0)
@@ -2369,9 +2913,9 @@ const RankBadge = ({ index, elementRect, widthScale, clickOnElement, }) => {
2369
2913
 
2370
2914
  const NUMBER_OF_TOP_ELEMENTS = 10;
2371
2915
  const DefaultRankBadges = ({ getRect, hidden }) => {
2372
- const heatmapInfo = useHeatmapDataStore((state) => state.dataInfo);
2373
- const widthScale = useHeatmapVizStore((state) => state.scale);
2374
- const elements = heatmapInfo?.sortedElements?.slice(0, NUMBER_OF_TOP_ELEMENTS) ?? [];
2916
+ const { dataInfo } = useHeatmapData();
2917
+ const { widthScale } = useHeatmapViz();
2918
+ const elements = dataInfo?.sortedElements?.slice(0, NUMBER_OF_TOP_ELEMENTS) ?? [];
2375
2919
  if (hidden || elements.length === 0)
2376
2920
  return null;
2377
2921
  return (jsx(Fragment, { children: elements.map((element, index) => {
@@ -2428,9 +2972,9 @@ const ElementCallout = (props) => {
2428
2972
  };
2429
2973
 
2430
2974
  const ElementMissing = ({ show = true }) => {
2975
+ const { widthScale } = useHeatmapViz();
2431
2976
  if (!show)
2432
2977
  return null;
2433
- const widthScale = useHeatmapVizStore((state) => state.scale);
2434
2978
  return (jsx("div", { className: "missingElement", style: {
2435
2979
  position: 'fixed',
2436
2980
  top: '50%',
@@ -2459,7 +3003,7 @@ const TARGET_ID_BY_TYPE = {
2459
3003
  },
2460
3004
  };
2461
3005
  const ElementOverlay = ({ type, element, onClick, isSecondary }) => {
2462
- const widthScale = useHeatmapVizStore((state) => state.scale);
3006
+ const { widthScale } = useHeatmapViz();
2463
3007
  if (!element || (element.width === 0 && element.height === 0))
2464
3008
  return null;
2465
3009
  // Iframe has border, so we need to add it to the top position
@@ -2482,7 +3026,7 @@ const ELEMENT_CALLOUT = {
2482
3026
  alignment: 'left',
2483
3027
  };
2484
3028
  const HeatmapElements = (props) => {
2485
- const iframeHeight = useHeatmapSingleStore((state) => state.iframeHeight);
3029
+ const { iframeHeight } = useHeatmapViz();
2486
3030
  const { iframeRef, wrapperRef, visualRef, visualizer, iframeDimensions, isElementSidebarOpen, isVisible = true, areDefaultRanksHidden, isSecondary, } = props;
2487
3031
  const getRect = useHeatmapElementPosition({
2488
3032
  iframeRef,
@@ -2519,9 +3063,9 @@ const HeatmapElements = (props) => {
2519
3063
  };
2520
3064
 
2521
3065
  const VizElements = ({ iframeRef, visualRef, wrapperRef }) => {
2522
- const heatmapInfo = useHeatmapDataStore((state) => state.dataInfo);
2523
3066
  const contentWidth = useHeatmapConfigStore((state) => state.width);
2524
- const vizRef = useHeatmapSingleStore((state) => state.vizRef);
3067
+ const { dataInfo } = useHeatmapData();
3068
+ const { vizRef } = useHeatmapViz();
2525
3069
  const visualizer = {
2526
3070
  get: (hash) => {
2527
3071
  if (vizRef) {
@@ -2543,7 +3087,7 @@ const VizElements = ({ iframeRef, visualRef, wrapperRef }) => {
2543
3087
  };
2544
3088
  if (!iframeRef.current)
2545
3089
  return null;
2546
- return (jsx(HeatmapElements, { visualizer: visualizer, visualRef: visualRef, iframeRef: iframeRef, wrapperRef: wrapperRef, heatmapInfo: heatmapInfo, isVisible: true, iframeDimensions: {
3090
+ return (jsx(HeatmapElements, { visualizer: visualizer, visualRef: visualRef, iframeRef: iframeRef, wrapperRef: wrapperRef, heatmapInfo: dataInfo, isVisible: true, iframeDimensions: {
2547
3091
  width: contentWidth,
2548
3092
  position: 'absolute',
2549
3093
  top: 0,
@@ -2553,8 +3097,9 @@ const VizElements = ({ iframeRef, visualRef, wrapperRef }) => {
2553
3097
  };
2554
3098
 
2555
3099
  const AverageFoldLine = ({ iframeRef, wrapperRef }) => {
2556
- const averageFold = useHeatmapDataStore((state) => state.dataInfo?.averageFold || 50);
3100
+ const { dataInfo } = useHeatmapData();
2557
3101
  const { getZonePosition } = useZonePositions();
3102
+ const averageFold = dataInfo?.averageFold || 50;
2558
3103
  const position = getZonePosition({
2559
3104
  startY: averageFold,
2560
3105
  endY: averageFold,
@@ -2589,8 +3134,8 @@ const AverageFoldLine = ({ iframeRef, wrapperRef }) => {
2589
3134
  };
2590
3135
 
2591
3136
  const ScrollmapMarker = ({ iframeRef, wrapperRef }) => {
2592
- const scrollmap = useHeatmapDataStore((state) => state.scrollmap);
2593
3137
  const scrollType = useHeatmapConfigStore((state) => state.scrollType);
3138
+ const { scrollmap } = useHeatmapData();
2594
3139
  const { getZonePosition } = useZonePositions();
2595
3140
  if (!scrollmap || scrollmap.length === 0)
2596
3141
  return null;
@@ -2770,7 +3315,7 @@ const MetricsTooltipContent = ({ zone }) => {
2770
3315
  const MetricRow = ({ label, value }) => (jsxs("div", { style: { display: 'flex', justifyContent: 'space-between' }, children: [jsxs("span", { style: { color: '#605E5C' }, children: [label, ":"] }), jsx("span", { style: { fontWeight: 600 }, children: value })] }));
2771
3316
 
2772
3317
  const HoverZones = ({ iframeRef, wrapperRef, position, currentScrollPercent, }) => {
2773
- const scrollmap = useHeatmapDataStore((state) => state.scrollmap);
3318
+ const { scrollmap } = useHeatmapData();
2774
3319
  // const hoveredZone = useHeatmapVizScrollmapStore((state) => state.hoveredZone);
2775
3320
  // const setHoveredZone = useHeatmapVizScrollmapStore((state) => state.setHoveredZone);
2776
3321
  const { zones, isReady, maxUsers } = useScrollmapZones({
@@ -2788,8 +3333,7 @@ const ScrollMapOverlay = ({ wrapperRef, iframeRef }) => {
2788
3333
  const overlayRef = useRef(null);
2789
3334
  const [position, setPosition] = useState();
2790
3335
  const [currentScrollPercent, setCurrentScrollPercent] = useState(0);
2791
- const widthScale = useHeatmapVizStore((state) => state.scale);
2792
- const iframeHeight = useHeatmapSingleStore((state) => state.iframeHeight);
3336
+ const { widthScale, iframeHeight } = useHeatmapViz();
2793
3337
  const handleMouseMove = (event) => {
2794
3338
  if (!iframeRef.current || !wrapperRef.current)
2795
3339
  return;
@@ -2824,8 +3368,8 @@ const ScrollMapOverlay = ({ wrapperRef, iframeRef }) => {
2824
3368
 
2825
3369
  const SCROLL_TYPES = [IHeatmapType.Scroll];
2826
3370
  const VizScrollMap = ({ iframeRef, wrapperRef }) => {
2827
- const iframeHeight = useHeatmapSingleStore((state) => state.iframeHeight);
2828
3371
  const heatmapType = useHeatmapConfigStore((state) => state.heatmapType);
3372
+ const { iframeHeight } = useHeatmapViz();
2829
3373
  const isHeatmapScroll = SCROLL_TYPES.includes(heatmapType);
2830
3374
  if (!iframeHeight || !isHeatmapScroll)
2831
3375
  return null;
@@ -2841,12 +3385,12 @@ const VizScrollMap = ({ iframeRef, wrapperRef }) => {
2841
3385
 
2842
3386
  const WrapperVisual = ({ children, visualRef, wrapperRef, scaledHeight, iframeHeight, onScroll, }) => {
2843
3387
  const contentWidth = useHeatmapConfigStore((state) => state.width);
2844
- const widthScale = useHeatmapVizStore((state) => state.scale);
3388
+ const { widthScale } = useHeatmapViz();
2845
3389
  const contentHeight = scaledHeight > 0
2846
3390
  ? `${scaledHeight + HEATMAP_CONFIG['heightToolbar'] + HEATMAP_CONFIG['padding'] * 2}px`
2847
3391
  : 'auto';
2848
3392
  return (jsx("div", { ref: visualRef, className: "gx-hm-visual", onScroll: onScroll, style: {
2849
- overflow: 'hidden auto',
3393
+ overflow: 'hidden scroll',
2850
3394
  display: 'flex',
2851
3395
  position: 'relative',
2852
3396
  justifyContent: 'center',
@@ -2874,9 +3418,8 @@ const WrapperVisual = ({ children, visualRef, wrapperRef, scaledHeight, iframeHe
2874
3418
  const VizDomRenderer = ({ mode = 'heatmap' }) => {
2875
3419
  const width = useHeatmapConfigStore((state) => state.width);
2876
3420
  const heatmapType = useHeatmapConfigStore((state) => state.heatmapType);
2877
- const iframeHeight = useHeatmapSingleStore((state) => state.iframeHeight);
2878
- const setIframeHeight = useHeatmapSingleStore((state) => state.setIframeHeight);
2879
3421
  const setSelectedElement = useHeatmapInteractionStore((state) => state.setSelectedElement);
3422
+ const { iframeHeight, setIframeHeight, isRenderViz } = useHeatmapViz();
2880
3423
  const wrapperRef = useRef(null);
2881
3424
  const visualRef = useRef(null);
2882
3425
  const { iframeRef } = useHeatmapVizRender(mode);
@@ -2885,6 +3428,7 @@ const VizDomRenderer = ({ mode = 'heatmap' }) => {
2885
3428
  iframeRef,
2886
3429
  visualRef,
2887
3430
  iframeHeight,
3431
+ isRenderViz,
2888
3432
  });
2889
3433
  const contentWidth = width ?? 0;
2890
3434
  const onScroll = (e) => {
@@ -2908,12 +3452,13 @@ const VizLoading = () => {
2908
3452
 
2909
3453
  const VizDomHeatmap = () => {
2910
3454
  const controls = useHeatmapControlStore((state) => state.controls);
2911
- const isRendering = useHeatmapDataStore((state) => state.isRendering);
2912
- const iframeHeight = useHeatmapSingleStore((state) => state.iframeHeight);
2913
- const setIframeHeight = useHeatmapSingleStore((state) => state.setIframeHeight);
2914
- const setVizRef = useHeatmapSingleStore((state) => state.setVizRef);
3455
+ const { isRendering } = useHeatmapData();
3456
+ console.log(`🚀 🐥 ~ VizDomHeatmap ~ isRendering:`, isRendering);
3457
+ const { iframeHeight, setIframeHeight, setVizRef } = useHeatmapViz();
3458
+ const viewId = useViewId();
2915
3459
  useEffect(() => {
2916
3460
  return () => {
3461
+ console.log(`🚀 🐥 ~ useEffect ~ return:`, viewId, iframeHeight);
2917
3462
  setVizRef(null);
2918
3463
  setIframeHeight(0);
2919
3464
  };
@@ -2925,8 +3470,7 @@ const VizDomHeatmap = () => {
2925
3470
 
2926
3471
  const VizLiveRenderer = () => {
2927
3472
  const contentWidth = useHeatmapConfigStore((state) => state.width);
2928
- const iframeHeight = useHeatmapLiveStore((state) => state.iframeHeight);
2929
- const setIframeHeight = useHeatmapLiveStore((state) => state.setIframeHeight);
3473
+ const { isRenderViz, iframeHeight, setIframeHeight } = useHeatmapViz();
2930
3474
  const visualRef = useRef(null);
2931
3475
  const wrapperRef = useRef(null);
2932
3476
  const { iframeRef } = useVizLiveRender();
@@ -2935,6 +3479,7 @@ const VizLiveRenderer = () => {
2935
3479
  iframeRef,
2936
3480
  visualRef,
2937
3481
  iframeHeight,
3482
+ isRenderViz,
2938
3483
  setIframeHeight,
2939
3484
  });
2940
3485
  const onScroll = (e) => {
@@ -2948,19 +3493,17 @@ const VizLiveRenderer = () => {
2948
3493
 
2949
3494
  const VizLiveHeatmap = () => {
2950
3495
  const controls = useHeatmapControlStore((state) => state.controls);
2951
- const isRendering = useHeatmapDataStore((state) => state.isRendering);
2952
- const iframeHeight = useHeatmapLiveStore((state) => state.iframeHeight);
2953
- const wrapperHeight = useHeatmapLiveStore((state) => state.wrapperHeight);
2954
- const setWrapperHeight = useHeatmapLiveStore((state) => state.setWrapperHeight);
3496
+ const isRendering = useHeatmapConfigStore((state) => state.isRendering);
3497
+ const { iframeHeight, wrapperHeight } = useHeatmapViz();
2955
3498
  const reset = useHeatmapLiveStore((state) => state.reset);
2956
3499
  useEffect(() => {
2957
3500
  return () => {
2958
3501
  reset();
2959
3502
  };
2960
- }, [reset]);
3503
+ }, []);
2961
3504
  if (isRendering)
2962
3505
  return controls.VizLoading ?? null;
2963
- return (jsxs(VizContainer, { setWrapperHeight: setWrapperHeight, children: [jsx(VizLiveRenderer, {}), (!iframeHeight || !wrapperHeight) && jsx(VizLoading, {})] }));
3506
+ return (jsxs(VizContainer, { isActive: true, children: [jsx(VizLiveRenderer, {}), (!iframeHeight || !wrapperHeight) && jsx(VizLoading, {})] }));
2964
3507
  };
2965
3508
 
2966
3509
  const ContentVizByMode = () => {
@@ -2968,6 +3511,8 @@ const ContentVizByMode = () => {
2968
3511
  switch (mode) {
2969
3512
  case 'live':
2970
3513
  return jsx(VizLiveHeatmap, {});
3514
+ // case 'compare':
3515
+ // return <VizCompareHeatmap />;
2971
3516
  default:
2972
3517
  return jsx(VizDomHeatmap, {});
2973
3518
  }
@@ -2977,6 +3522,45 @@ const LeftSidebar = () => {
2977
3522
  const controls = useHeatmapControlStore((state) => state.controls);
2978
3523
  const isHideSidebar = useHeatmapInteractionStore((state) => state.state.hideSidebar);
2979
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
2980
3564
  if (isHideSidebar) {
2981
3565
  return null;
2982
3566
  }
@@ -3024,4 +3608,4 @@ const HeatmapLayout = ({ data, clickmap, scrollmap, controls, dataInfo, }) => {
3024
3608
  }
3025
3609
  };
3026
3610
 
3027
- export { GraphView, HeatmapLayout, IClickType, IHeatmapType, IScrollType, useHeatmapConfigStore, useHeatmapDataStore, useHeatmapInteractionStore, useHeatmapLiveStore, useHeatmapVizStore };
3611
+ export { GraphView, HeatmapLayout, IClickType, IHeatmapType, IScrollType, ViewIdContext, convertViewportToIframeCoords, getScrollGradientColor, useClickedElement, useCompareAwareConfig, useCompareAwareConfigSetters, useCompareAwareData, useCompareAwareDataSetters, useCompareAwareViz, useCompareAwareVizSetters, useElementCalloutVisible, useHeatmapCompareStore, useHeatmapConfigStore, useHeatmapData, useHeatmapDataStore, useHeatmapEffects, useHeatmapElementPosition, useHeatmapInteractionStore, useHeatmapLiveStore, useHeatmapScale, useHeatmapSingleStore, useHeatmapViz, useHeatmapVizRender, useHeatmapVizStore, useHoveredElement, useIsCompareMode, useRegisterConfig, useRegisterControl, useRegisterData, useRegisterHeatmap, useScrollmapZones, useViewId, useVizLiveRender, useWrapperRefHeight, useZonePositions };