@gemx-dev/heatmap-react 3.5.41 → 3.5.43
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/VizDom/VizDomRenderer.d.ts.map +1 -1
- package/dist/esm/components/VizElement/HeatmapElements.d.ts.map +1 -1
- package/dist/esm/components/VizLive/VizLiveHeatmap.d.ts.map +1 -1
- package/dist/esm/components/VizLive/VizLiveRenderer.d.ts.map +1 -1
- package/dist/esm/configs/style.d.ts +2 -0
- package/dist/esm/configs/style.d.ts.map +1 -1
- package/dist/esm/helpers/viewport-fixer.d.ts +5 -3
- package/dist/esm/helpers/viewport-fixer.d.ts.map +1 -1
- package/dist/esm/helpers/viewport-replacer.d.ts +12 -12
- package/dist/esm/helpers/viewport-replacer.d.ts.map +1 -1
- package/dist/esm/hooks/vix-elements/useHeatmapMouseHandler.d.ts +34 -0
- package/dist/esm/hooks/vix-elements/useHeatmapMouseHandler.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 +3 -1
- 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 +3 -1
- 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/{useIframeMessage.d.ts → useVizLiveIframeMsg.d.ts} +2 -5
- package/dist/esm/hooks/viz-live/useVizLiveIframeMsg.d.ts.map +1 -0
- package/dist/esm/hooks/viz-live/useVizLiveRender.d.ts +4 -0
- package/dist/esm/hooks/viz-live/useVizLiveRender.d.ts.map +1 -0
- package/dist/esm/hooks/viz-render/useHeatmapRender.d.ts.map +1 -1
- package/dist/esm/hooks/viz-scale/useContainerDimensions.d.ts.map +1 -1
- package/dist/esm/hooks/viz-scale/useHeatmapScale.d.ts +1 -1
- package/dist/esm/hooks/viz-scale/useHeatmapScale.d.ts.map +1 -1
- package/dist/esm/hooks/viz-scale/useObserveIframeHeight.d.ts +10 -0
- package/dist/esm/hooks/viz-scale/useObserveIframeHeight.d.ts.map +1 -0
- package/dist/esm/index.js +582 -194
- package/dist/esm/index.mjs +582 -194
- package/dist/esm/stores/index.d.ts +1 -0
- package/dist/esm/stores/index.d.ts.map +1 -1
- package/dist/esm/stores/interaction.d.ts.map +1 -1
- package/dist/esm/stores/mode-single.d.ts +9 -0
- package/dist/esm/stores/mode-single.d.ts.map +1 -0
- package/dist/esm/stores/viz.d.ts +0 -5
- package/dist/esm/stores/viz.d.ts.map +1 -1
- package/dist/esm/types/viewport-fixer.d.ts +9 -8
- package/dist/esm/types/viewport-fixer.d.ts.map +1 -1
- package/dist/umd/components/VizDom/VizDomRenderer.d.ts.map +1 -1
- package/dist/umd/components/VizElement/HeatmapElements.d.ts.map +1 -1
- package/dist/umd/components/VizLive/VizLiveHeatmap.d.ts.map +1 -1
- package/dist/umd/components/VizLive/VizLiveRenderer.d.ts.map +1 -1
- package/dist/umd/configs/style.d.ts +2 -0
- package/dist/umd/configs/style.d.ts.map +1 -1
- package/dist/umd/helpers/viewport-fixer.d.ts +5 -3
- package/dist/umd/helpers/viewport-fixer.d.ts.map +1 -1
- package/dist/umd/helpers/viewport-replacer.d.ts +12 -12
- package/dist/umd/helpers/viewport-replacer.d.ts.map +1 -1
- package/dist/umd/hooks/vix-elements/useHeatmapMouseHandler.d.ts +34 -0
- package/dist/umd/hooks/vix-elements/useHeatmapMouseHandler.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 +3 -1
- 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 +3 -1
- 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/{useIframeMessage.d.ts → useVizLiveIframeMsg.d.ts} +2 -5
- package/dist/umd/hooks/viz-live/useVizLiveIframeMsg.d.ts.map +1 -0
- package/dist/umd/hooks/viz-live/useVizLiveRender.d.ts +4 -0
- package/dist/umd/hooks/viz-live/useVizLiveRender.d.ts.map +1 -0
- package/dist/umd/hooks/viz-render/useHeatmapRender.d.ts.map +1 -1
- package/dist/umd/hooks/viz-scale/useContainerDimensions.d.ts.map +1 -1
- package/dist/umd/hooks/viz-scale/useHeatmapScale.d.ts +1 -1
- package/dist/umd/hooks/viz-scale/useHeatmapScale.d.ts.map +1 -1
- package/dist/umd/hooks/viz-scale/useObserveIframeHeight.d.ts +10 -0
- package/dist/umd/hooks/viz-scale/useObserveIframeHeight.d.ts.map +1 -0
- package/dist/umd/index.js +2 -2
- package/dist/umd/stores/index.d.ts +1 -0
- package/dist/umd/stores/index.d.ts.map +1 -1
- package/dist/umd/stores/interaction.d.ts.map +1 -1
- package/dist/umd/stores/mode-single.d.ts +9 -0
- package/dist/umd/stores/mode-single.d.ts.map +1 -0
- package/dist/umd/stores/viz.d.ts +0 -5
- package/dist/umd/stores/viz.d.ts.map +1 -1
- package/dist/umd/types/viewport-fixer.d.ts +9 -8
- package/dist/umd/types/viewport-fixer.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/esm/hooks/viz-live/useIframeMessage.d.ts.map +0 -1
- package/dist/esm/hooks/viz-scale/useIframeHeight.d.ts +0 -10
- package/dist/esm/hooks/viz-scale/useIframeHeight.d.ts.map +0 -1
- package/dist/umd/hooks/viz-live/useIframeMessage.d.ts.map +0 -1
- package/dist/umd/hooks/viz-scale/useIframeHeight.d.ts +0 -10
- package/dist/umd/hooks/viz-scale/useIframeHeight.d.ts.map +0 -1
package/dist/esm/index.mjs
CHANGED
|
@@ -61,6 +61,8 @@ const HEATMAP_STYLE = {
|
|
|
61
61
|
},
|
|
62
62
|
wrapper: {
|
|
63
63
|
padding: `${HEATMAP_CONFIG.padding}px 0`,
|
|
64
|
+
paddingBlock: `${HEATMAP_CONFIG.padding}px`,
|
|
65
|
+
paddingInline: `${HEATMAP_CONFIG.padding}px`,
|
|
64
66
|
},
|
|
65
67
|
};
|
|
66
68
|
const DEFAULT_SIDEBAR_WIDTH = 260;
|
|
@@ -139,11 +141,7 @@ const useHeatmapVizStore = create()((set, get) => {
|
|
|
139
141
|
isRenderViz: false,
|
|
140
142
|
setIsRenderViz: (isRenderViz) => set({ isRenderViz }),
|
|
141
143
|
scale: 1,
|
|
142
|
-
vizRef: null,
|
|
143
|
-
iframeHeight: 0,
|
|
144
144
|
setScale: (scale) => set({ scale }),
|
|
145
|
-
setVizRef: (vizRef) => set({ vizRef }),
|
|
146
|
-
setIframeHeight: (iframeHeight) => set({ iframeHeight }),
|
|
147
145
|
};
|
|
148
146
|
});
|
|
149
147
|
|
|
@@ -165,6 +163,15 @@ const useHeatmapLiveStore = create()((set, get) => {
|
|
|
165
163
|
};
|
|
166
164
|
});
|
|
167
165
|
|
|
166
|
+
const useHeatmapSingleStore = create()((set, get) => {
|
|
167
|
+
return {
|
|
168
|
+
vizRef: null,
|
|
169
|
+
iframeHeight: 0,
|
|
170
|
+
setVizRef: (vizRef) => set({ vizRef }),
|
|
171
|
+
setIframeHeight: (iframeHeight) => set({ iframeHeight }),
|
|
172
|
+
};
|
|
173
|
+
});
|
|
174
|
+
|
|
168
175
|
const useRegisterConfig = () => {
|
|
169
176
|
const mode = useHeatmapConfigStore((state) => state.mode);
|
|
170
177
|
const width = useHeatmapConfigStore((state) => state.width);
|
|
@@ -504,85 +511,18 @@ function isElementInViewport(elementRect, visualRef, scale) {
|
|
|
504
511
|
return elementBottom > viewportTop && elementTop < viewportBottom;
|
|
505
512
|
}
|
|
506
513
|
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
const classCode = ActualClass.toString();
|
|
511
|
-
const classInstantiateCode = ActualClass.name;
|
|
512
|
-
const scriptCode = `
|
|
513
|
-
(function() {
|
|
514
|
-
'use strict';
|
|
515
|
-
${classCode}
|
|
516
|
-
const replacer = new ${classInstantiateCode}();
|
|
517
|
-
replacer.init();
|
|
518
|
-
})();
|
|
519
|
-
`;
|
|
520
|
-
return scriptCode;
|
|
521
|
-
};
|
|
522
|
-
class ViewportUnitsFixer {
|
|
523
|
-
iframe = null;
|
|
514
|
+
class ViewportUnitsReplacer {
|
|
515
|
+
doc;
|
|
516
|
+
win;
|
|
524
517
|
config;
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
}
|
|
530
|
-
async init() {
|
|
531
|
-
if (!this.iframe) {
|
|
532
|
-
console.error('[Parent] Required elements not found');
|
|
533
|
-
return;
|
|
534
|
-
}
|
|
535
|
-
// this.injectScriptContent = await generateIframeInjectScript();
|
|
536
|
-
window.addEventListener('message', this.handleMessage.bind(this));
|
|
537
|
-
if (this.iframe.contentDocument?.readyState === 'complete') {
|
|
538
|
-
await this.injectScript();
|
|
539
|
-
}
|
|
540
|
-
else {
|
|
541
|
-
this.iframe.addEventListener('load', () => this.injectScript());
|
|
542
|
-
}
|
|
543
|
-
}
|
|
544
|
-
async injectScript() {
|
|
545
|
-
if (!this.iframe?.contentWindow || !this.iframe.contentDocument)
|
|
546
|
-
return;
|
|
547
|
-
const doc = this.iframe.contentDocument;
|
|
548
|
-
const win = this.iframe.contentWindow;
|
|
549
|
-
try {
|
|
550
|
-
win.__viewportConfig = this.config;
|
|
551
|
-
const script = doc.createElement('script');
|
|
552
|
-
const scriptCode = await getScriptInjectCode();
|
|
553
|
-
script.textContent = scriptCode;
|
|
554
|
-
doc.head.appendChild(script);
|
|
555
|
-
}
|
|
556
|
-
catch (error) {
|
|
557
|
-
console.error('[Parent] Failed to inject script', error);
|
|
518
|
+
regex = /([-.\d]+)(vh|svh|lvh|dvh|vw|svw|lvw|dvw)/gi;
|
|
519
|
+
constructor(iframe, config) {
|
|
520
|
+
if (!iframe.contentDocument || !iframe.contentWindow) {
|
|
521
|
+
throw new Error('Iframe document or window not accessible');
|
|
558
522
|
}
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
if (!data || data.type !== 'IFRAME_HEIGHT_CALCULATED')
|
|
563
|
-
return;
|
|
564
|
-
this.config.onSuccess?.(data);
|
|
565
|
-
}
|
|
566
|
-
recalculate() {
|
|
567
|
-
this.injectScript();
|
|
568
|
-
}
|
|
569
|
-
}
|
|
570
|
-
function initViewportFixer(config) {
|
|
571
|
-
const fixer = new ViewportUnitsFixer(config);
|
|
572
|
-
window.viewportFixer = fixer;
|
|
573
|
-
window.addEventListener('iframe-dimensions-applied', ((e) => {
|
|
574
|
-
const ev = e;
|
|
575
|
-
console.log('Iframe dimensions finalized:', ev.detail);
|
|
576
|
-
}));
|
|
577
|
-
return fixer;
|
|
578
|
-
}
|
|
579
|
-
|
|
580
|
-
class ViewportUnitsReplacer {
|
|
581
|
-
regex() {
|
|
582
|
-
return /([-.\d]+)(vh|svh|lvh|dvh|vw|svw|lvw|dvw)/gi;
|
|
583
|
-
}
|
|
584
|
-
config() {
|
|
585
|
-
return window.__viewportConfig;
|
|
523
|
+
this.doc = iframe.contentDocument;
|
|
524
|
+
this.win = iframe.contentWindow;
|
|
525
|
+
this.config = config;
|
|
586
526
|
}
|
|
587
527
|
px(value) {
|
|
588
528
|
return `${value.toFixed(2)}px`;
|
|
@@ -592,42 +532,44 @@ class ViewportUnitsReplacer {
|
|
|
592
532
|
if (isNaN(num))
|
|
593
533
|
return value;
|
|
594
534
|
const map = {
|
|
595
|
-
vh: this.config
|
|
596
|
-
svh: this.config
|
|
597
|
-
lvh: this.config
|
|
598
|
-
dvh: this.config
|
|
599
|
-
vw: this.config
|
|
600
|
-
svw: this.config
|
|
601
|
-
lvw: this.config
|
|
602
|
-
dvw: this.config
|
|
535
|
+
vh: this.config.targetHeight,
|
|
536
|
+
svh: this.config.targetHeight,
|
|
537
|
+
lvh: this.config.targetHeight,
|
|
538
|
+
dvh: this.config.targetHeight,
|
|
539
|
+
vw: this.config.targetWidth,
|
|
540
|
+
svw: this.config.targetWidth,
|
|
541
|
+
lvw: this.config.targetWidth,
|
|
542
|
+
dvw: this.config.targetWidth,
|
|
603
543
|
};
|
|
604
544
|
return this.px((num / 100) * (map[unit.toLowerCase()] || 0));
|
|
605
545
|
}
|
|
606
546
|
replaceInText(cssText) {
|
|
607
|
-
return cssText.replace(this.regex
|
|
547
|
+
return cssText.replace(this.regex, (_, value, unit) => this.convert(value, unit));
|
|
608
548
|
}
|
|
609
549
|
processInlineStyles() {
|
|
610
550
|
let count = 0;
|
|
611
|
-
|
|
551
|
+
this.doc.querySelectorAll('[style]').forEach((el) => {
|
|
612
552
|
const style = el.getAttribute('style');
|
|
613
|
-
if (style && this.regex
|
|
553
|
+
if (style && this.regex.test(style)) {
|
|
554
|
+
this.regex.lastIndex = 0;
|
|
614
555
|
el.setAttribute('style', this.replaceInText(style));
|
|
615
556
|
count++;
|
|
616
557
|
}
|
|
617
558
|
});
|
|
618
|
-
console.log(`[
|
|
559
|
+
console.log(`[ViewportReplacer] Replaced ${count} inline style elements`);
|
|
619
560
|
return count;
|
|
620
561
|
}
|
|
621
562
|
processStyleTags() {
|
|
622
563
|
let count = 0;
|
|
623
|
-
|
|
564
|
+
this.doc.querySelectorAll('style').forEach((tag) => {
|
|
624
565
|
const css = tag.textContent || '';
|
|
625
|
-
if (this.regex
|
|
566
|
+
if (this.regex.test(css)) {
|
|
567
|
+
this.regex.lastIndex = 0;
|
|
626
568
|
tag.textContent = this.replaceInText(css);
|
|
627
569
|
count++;
|
|
628
570
|
}
|
|
629
571
|
});
|
|
630
|
-
console.log(`[
|
|
572
|
+
console.log(`[ViewportReplacer] Replaced ${count} <style> tags`);
|
|
631
573
|
return count;
|
|
632
574
|
}
|
|
633
575
|
processRule(rule) {
|
|
@@ -637,7 +579,8 @@ class ViewportUnitsReplacer {
|
|
|
637
579
|
for (let i = 0; i < style.length; i++) {
|
|
638
580
|
const prop = style[i];
|
|
639
581
|
const value = style.getPropertyValue(prop);
|
|
640
|
-
if (value && this.regex
|
|
582
|
+
if (value && this.regex.test(value)) {
|
|
583
|
+
this.regex.lastIndex = 0;
|
|
641
584
|
style.setProperty(prop, this.replaceInText(value), style.getPropertyPriority(prop));
|
|
642
585
|
count++;
|
|
643
586
|
}
|
|
@@ -653,11 +596,11 @@ class ViewportUnitsReplacer {
|
|
|
653
596
|
}
|
|
654
597
|
processStylesheets() {
|
|
655
598
|
let total = 0;
|
|
656
|
-
Array.from(
|
|
599
|
+
Array.from(this.doc.styleSheets).forEach((sheet) => {
|
|
657
600
|
try {
|
|
658
601
|
// Bỏ qua external CSS (cross-origin)
|
|
659
|
-
if (sheet.href && !sheet.href.startsWith(location.origin)) {
|
|
660
|
-
console.log('[
|
|
602
|
+
if (sheet.href && !sheet.href.startsWith(this.win.location.origin)) {
|
|
603
|
+
console.log('[ViewportReplacer] Skipping external CSS:', sheet.href);
|
|
661
604
|
return;
|
|
662
605
|
}
|
|
663
606
|
const rules = sheet.cssRules || sheet.rules;
|
|
@@ -668,26 +611,27 @@ class ViewportUnitsReplacer {
|
|
|
668
611
|
}
|
|
669
612
|
}
|
|
670
613
|
catch (e) {
|
|
671
|
-
console.warn('[
|
|
614
|
+
console.warn('[ViewportReplacer] Cannot read stylesheet (CORS?):', e.message);
|
|
672
615
|
}
|
|
673
616
|
});
|
|
674
|
-
console.log(`[
|
|
617
|
+
console.log(`[ViewportReplacer] Replaced ${total} rules in stylesheets`);
|
|
675
618
|
return total;
|
|
676
619
|
}
|
|
677
620
|
async processLinkedStylesheets() {
|
|
678
|
-
const links =
|
|
621
|
+
const links = this.doc.querySelectorAll('link[rel="stylesheet"]');
|
|
679
622
|
let count = 0;
|
|
680
623
|
for (const link of Array.from(links)) {
|
|
681
|
-
if (!link.href.startsWith(location.origin)) {
|
|
682
|
-
console.log('[
|
|
624
|
+
if (!link.href.startsWith(this.win.location.origin)) {
|
|
625
|
+
console.log('[ViewportReplacer] Skipping external CSS:', link.href);
|
|
683
626
|
continue;
|
|
684
627
|
}
|
|
685
628
|
try {
|
|
686
629
|
const res = await fetch(link.href);
|
|
687
630
|
let css = await res.text();
|
|
688
|
-
if (this.regex
|
|
631
|
+
if (this.regex.test(css)) {
|
|
632
|
+
this.regex.lastIndex = 0;
|
|
689
633
|
css = this.replaceInText(css);
|
|
690
|
-
const style =
|
|
634
|
+
const style = this.doc.createElement('style');
|
|
691
635
|
style.textContent = css;
|
|
692
636
|
style.dataset.originalHref = link.href;
|
|
693
637
|
link.parentNode?.insertBefore(style, link);
|
|
@@ -696,30 +640,25 @@ class ViewportUnitsReplacer {
|
|
|
696
640
|
}
|
|
697
641
|
}
|
|
698
642
|
catch (e) {
|
|
699
|
-
console.warn('[
|
|
643
|
+
console.warn('[ViewportReplacer] Cannot load CSS:', link.href, e);
|
|
700
644
|
}
|
|
701
645
|
}
|
|
702
|
-
console.log(`[
|
|
646
|
+
console.log(`[ViewportReplacer] Replaced ${count} linked CSS files`);
|
|
703
647
|
return count;
|
|
704
648
|
}
|
|
705
649
|
getFinalHeight() {
|
|
706
650
|
// Trigger reflow
|
|
707
|
-
void
|
|
708
|
-
return Math.max(
|
|
651
|
+
void this.doc.body.offsetHeight;
|
|
652
|
+
return Math.max(this.doc.body.scrollHeight, this.doc.body.offsetHeight, this.doc.documentElement.scrollHeight, this.doc.documentElement.offsetHeight, this.doc.documentElement.clientHeight);
|
|
709
653
|
}
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
type: 'IFRAME_HEIGHT_CALCULATED',
|
|
713
|
-
height,
|
|
714
|
-
width: document.body.scrollWidth,
|
|
715
|
-
}, '*');
|
|
716
|
-
console.log('[Iframe] Sent height to parent:', height);
|
|
654
|
+
getFinalWidth() {
|
|
655
|
+
return Math.max(this.doc.body.scrollWidth, this.doc.body.offsetWidth, this.doc.documentElement.scrollWidth, this.doc.documentElement.offsetWidth, this.doc.documentElement.clientWidth);
|
|
717
656
|
}
|
|
718
657
|
async waitForResources() {
|
|
719
|
-
if ('fonts' in
|
|
720
|
-
await
|
|
658
|
+
if ('fonts' in this.doc) {
|
|
659
|
+
await this.doc.fonts.ready;
|
|
721
660
|
}
|
|
722
|
-
const images = Array.from(
|
|
661
|
+
const images = Array.from(this.doc.images).filter((img) => !img.complete);
|
|
723
662
|
if (images.length > 0) {
|
|
724
663
|
await Promise.all(images.map((img) => new Promise((resolve) => {
|
|
725
664
|
img.onload = img.onerror = resolve;
|
|
@@ -728,37 +667,104 @@ class ViewportUnitsReplacer {
|
|
|
728
667
|
}
|
|
729
668
|
async run() {
|
|
730
669
|
try {
|
|
670
|
+
console.log('[ViewportReplacer] Starting viewport units replacement...');
|
|
731
671
|
this.processInlineStyles();
|
|
732
672
|
this.processStyleTags();
|
|
733
673
|
this.processStylesheets();
|
|
734
674
|
await this.processLinkedStylesheets();
|
|
735
675
|
// await this.waitForResources();
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
676
|
+
return await new Promise((resolve) => {
|
|
677
|
+
requestAnimationFrame(() => {
|
|
678
|
+
const height = this.getFinalHeight();
|
|
679
|
+
const width = this.getFinalWidth();
|
|
680
|
+
console.log('[ViewportReplacer] Calculated dimensions:', { height, width });
|
|
681
|
+
resolve({ height, width });
|
|
682
|
+
});
|
|
739
683
|
});
|
|
740
684
|
}
|
|
741
685
|
catch (err) {
|
|
742
|
-
console.error('[
|
|
743
|
-
|
|
686
|
+
console.error('[ViewportReplacer] Critical error:', err);
|
|
687
|
+
return {
|
|
688
|
+
height: this.doc.body.scrollHeight || 1000,
|
|
689
|
+
width: this.doc.body.scrollWidth || 1000,
|
|
690
|
+
};
|
|
744
691
|
}
|
|
745
692
|
}
|
|
746
|
-
|
|
747
|
-
|
|
693
|
+
updateConfig(config) {
|
|
694
|
+
this.config = { ...this.config, ...config };
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
class ViewportUnitsFixer {
|
|
699
|
+
iframe;
|
|
700
|
+
config;
|
|
701
|
+
replacer = null;
|
|
702
|
+
constructor(config) {
|
|
703
|
+
this.config = config;
|
|
704
|
+
this.iframe = config.iframe;
|
|
705
|
+
this.init();
|
|
706
|
+
}
|
|
707
|
+
async init() {
|
|
708
|
+
if (!this.iframe) {
|
|
709
|
+
console.error('[ViewportFixer] iframe not found');
|
|
710
|
+
this.config.onError?.(new Error('iframe not found'));
|
|
748
711
|
return;
|
|
749
|
-
|
|
750
|
-
|
|
712
|
+
}
|
|
713
|
+
if (this.iframe.contentDocument?.readyState === 'complete') {
|
|
714
|
+
await this.process();
|
|
751
715
|
}
|
|
752
716
|
else {
|
|
753
|
-
this.
|
|
717
|
+
this.iframe.addEventListener('load', () => this.process());
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
async process() {
|
|
721
|
+
if (!this.iframe.contentDocument || !this.iframe.contentWindow) {
|
|
722
|
+
console.error('[ViewportFixer] Cannot access iframe document');
|
|
723
|
+
this.config.onError?.(new Error('Cannot access iframe document'));
|
|
724
|
+
return;
|
|
725
|
+
}
|
|
726
|
+
try {
|
|
727
|
+
console.log('[ViewportFixer] Processing viewport units...');
|
|
728
|
+
// Tạo replacer instance với iframe và config
|
|
729
|
+
this.replacer = new ViewportUnitsReplacer(this.iframe, this.config);
|
|
730
|
+
// Chạy replacement
|
|
731
|
+
const result = await this.replacer.run();
|
|
732
|
+
console.log('[ViewportFixer] Process completed:', result);
|
|
733
|
+
// Trigger success callback
|
|
734
|
+
this.config.onSuccess?.(result);
|
|
735
|
+
// Dispatch custom event
|
|
736
|
+
window.dispatchEvent(new CustomEvent('iframe-dimensions-applied', {
|
|
737
|
+
detail: result,
|
|
738
|
+
}));
|
|
739
|
+
}
|
|
740
|
+
catch (error) {
|
|
741
|
+
console.error('[ViewportFixer] Failed to process:', error);
|
|
742
|
+
this.config.onError?.(error);
|
|
754
743
|
}
|
|
755
744
|
}
|
|
745
|
+
async recalculate() {
|
|
746
|
+
console.log('[ViewportFixer] Recalculating...');
|
|
747
|
+
await this.process();
|
|
748
|
+
}
|
|
749
|
+
updateConfig(config) {
|
|
750
|
+
this.config = { ...this.config, ...config };
|
|
751
|
+
if (this.replacer) {
|
|
752
|
+
this.replacer.updateConfig(config);
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
destroy() {
|
|
756
|
+
this.replacer = null;
|
|
757
|
+
console.log('[ViewportFixer] Destroyed');
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
function initViewportFixer(config) {
|
|
761
|
+
const fixer = new ViewportUnitsFixer(config);
|
|
762
|
+
window.addEventListener('iframe-dimensions-applied', ((e) => {
|
|
763
|
+
const ev = e;
|
|
764
|
+
console.log('[ViewportFixer] Iframe dimensions finalized:', ev.detail);
|
|
765
|
+
}));
|
|
766
|
+
return fixer;
|
|
756
767
|
}
|
|
757
|
-
|
|
758
|
-
var viewportReplacer = /*#__PURE__*/Object.freeze({
|
|
759
|
-
__proto__: null,
|
|
760
|
-
default: ViewportUnitsReplacer
|
|
761
|
-
});
|
|
762
768
|
|
|
763
769
|
const scrollToElementIfNeeded = (visualRef, rect, scale) => {
|
|
764
770
|
if (!visualRef.current)
|
|
@@ -872,7 +878,7 @@ const useHeatmapEffects = ({ isVisible, isElementSidebarOpen, setShouldShowCallo
|
|
|
872
878
|
|
|
873
879
|
const useHeatmapElementPosition = ({ iframeRef, wrapperRef, visualizer }) => {
|
|
874
880
|
const widthScale = useHeatmapVizStore((state) => state.scale);
|
|
875
|
-
const iframeHeight =
|
|
881
|
+
const iframeHeight = useHeatmapSingleStore((state) => state.iframeHeight);
|
|
876
882
|
const heatmapWidth = useHeatmapConfigStore((state) => state.width);
|
|
877
883
|
return useCallback((element) => {
|
|
878
884
|
const hash = element?.hash;
|
|
@@ -920,6 +926,179 @@ const debounce = (fn, delay) => {
|
|
|
920
926
|
};
|
|
921
927
|
};
|
|
922
928
|
|
|
929
|
+
// ===================== CONSTANTS =====================
|
|
930
|
+
const HEATMAP_ELEMENT_ATTRIBUTE = 'data-clarity-hashalpha'; // Hoặc attribute bạn đang dùng
|
|
931
|
+
// ===================== UTILITY FUNCTIONS =====================
|
|
932
|
+
/**
|
|
933
|
+
* Lấy bounding box tuyệt đối của element (relative to document)
|
|
934
|
+
*/
|
|
935
|
+
function getBoundingBox(element) {
|
|
936
|
+
if (typeof element.getBoundingClientRect !== 'function') {
|
|
937
|
+
return null;
|
|
938
|
+
}
|
|
939
|
+
const rect = element.getBoundingClientRect();
|
|
940
|
+
// Lấy scroll offset (hỗ trợ cả cách cũ và mới)
|
|
941
|
+
const scrollLeft = 'pageXOffset' in window ? window.pageXOffset : document.documentElement.scrollLeft;
|
|
942
|
+
const scrollTop = 'pageYOffset' in window ? window.pageYOffset : document.documentElement.scrollTop;
|
|
943
|
+
// Kiểm tra element có kích thước hợp lệ
|
|
944
|
+
if (!rect || (rect.height === 0 && rect.width === 0)) {
|
|
945
|
+
return null;
|
|
946
|
+
}
|
|
947
|
+
// Trả về vị trí tuyệt đối
|
|
948
|
+
return {
|
|
949
|
+
left: Math.floor(rect.left + scrollLeft),
|
|
950
|
+
top: Math.floor(rect.top + scrollTop),
|
|
951
|
+
width: Math.floor(rect.width),
|
|
952
|
+
height: Math.floor(rect.height),
|
|
953
|
+
};
|
|
954
|
+
}
|
|
955
|
+
/**
|
|
956
|
+
* Lấy tất cả elements tại tọa độ (x, y), hỗ trợ Shadow DOM
|
|
957
|
+
*/
|
|
958
|
+
function getElementsAtPoint(documentOrShadowRoot, x, y, filterFunction, visitedShadowRoots = new Set()) {
|
|
959
|
+
// Lấy tất cả elements tại vị trí
|
|
960
|
+
const elementsAtPoint = documentOrShadowRoot.elementsFromPoint(x, y);
|
|
961
|
+
if (!filterFunction) {
|
|
962
|
+
return elementsAtPoint;
|
|
963
|
+
}
|
|
964
|
+
// Tìm element đầu tiên match với filter
|
|
965
|
+
const matchedElement = elementsAtPoint.find(filterFunction);
|
|
966
|
+
// Nếu element có Shadow DOM và chưa visit -> đệ quy vào
|
|
967
|
+
if (matchedElement?.shadowRoot && !visitedShadowRoots.has(matchedElement.shadowRoot)) {
|
|
968
|
+
visitedShadowRoots.add(matchedElement.shadowRoot);
|
|
969
|
+
return getElementsAtPoint(matchedElement.shadowRoot, x, y, filterFunction, visitedShadowRoots);
|
|
970
|
+
}
|
|
971
|
+
return elementsAtPoint;
|
|
972
|
+
}
|
|
973
|
+
// ===================== MAIN HOOK =====================
|
|
974
|
+
function useHeatmapMouseHandler(props) {
|
|
975
|
+
const { heatmapWrapperRef, iframeRef, parentRef, heatmapInfo, scaleRatio, onElementHover } = props;
|
|
976
|
+
const handleMouseMove = useCallback((event) => {
|
|
977
|
+
// Kiểm tra tất cả refs và data cần thiết
|
|
978
|
+
if (!heatmapWrapperRef?.current ||
|
|
979
|
+
!iframeRef?.current ||
|
|
980
|
+
!iframeRef.current.contentDocument ||
|
|
981
|
+
!heatmapInfo?.elementMapInfo ||
|
|
982
|
+
!parentRef?.current) {
|
|
983
|
+
return;
|
|
984
|
+
}
|
|
985
|
+
try {
|
|
986
|
+
// Tính toán scroll position (đã scale)
|
|
987
|
+
const scrollTop = parentRef.current.scrollTop / scaleRatio;
|
|
988
|
+
console.log(`🚀 🐥 ~ useHeatmapMouseHandler ~ scrollTop:`, scrollTop);
|
|
989
|
+
// Lấy vị trí của heatmap wrapper
|
|
990
|
+
const wrapperRect = heatmapWrapperRef.current.getBoundingClientRect();
|
|
991
|
+
// Tính toán tọa độ chuột trong iframe (đã scale)
|
|
992
|
+
const mouseX = (event.clientX - wrapperRect.left) / scaleRatio;
|
|
993
|
+
const mouseY = (event.clientY - wrapperRect.top) / scaleRatio - scrollTop;
|
|
994
|
+
// Tìm elements tại vị trí chuột
|
|
995
|
+
const elementsAtPoint = getElementsAtPoint(iframeRef.current.contentDocument, Math.round(mouseX), Math.round(mouseY),
|
|
996
|
+
// Filter: chỉ lấy elements có heatmap attribute
|
|
997
|
+
(element) => element.hasAttribute(HEATMAP_ELEMENT_ATTRIBUTE));
|
|
998
|
+
if (!elementsAtPoint || elementsAtPoint.length === 0) {
|
|
999
|
+
return;
|
|
1000
|
+
}
|
|
1001
|
+
// Duyệt qua các elements tìm được
|
|
1002
|
+
for (let i = 0; i < elementsAtPoint.length; i++) {
|
|
1003
|
+
const element = elementsAtPoint[i];
|
|
1004
|
+
// Lấy hash/id của element
|
|
1005
|
+
const elementHash = element.getAttribute(HEATMAP_ELEMENT_ATTRIBUTE);
|
|
1006
|
+
// Kiểm tra element có data trong heatmapInfo không
|
|
1007
|
+
if (elementHash && heatmapInfo.elementMapInfo[elementHash]) {
|
|
1008
|
+
const elementData = heatmapInfo.elementMapInfo[elementHash];
|
|
1009
|
+
// Lấy bounding box của element
|
|
1010
|
+
const boundingBox = getBoundingBox(element);
|
|
1011
|
+
if (boundingBox) {
|
|
1012
|
+
// Tính rank của element
|
|
1013
|
+
const rank = Array.isArray(heatmapInfo.sortedElements) && elementData
|
|
1014
|
+
? heatmapInfo.sortedElements.indexOf(elementData) + 1
|
|
1015
|
+
: NaN;
|
|
1016
|
+
// Callback với thông tin element
|
|
1017
|
+
onElementHover({
|
|
1018
|
+
...boundingBox,
|
|
1019
|
+
// Giới hạn width không vượt quá width của heatmap
|
|
1020
|
+
width: Math.min(boundingBox.width, heatmapInfo.width || 0),
|
|
1021
|
+
// Adjust top position với scroll
|
|
1022
|
+
top: boundingBox.top + scrollTop,
|
|
1023
|
+
// Metadata
|
|
1024
|
+
hash: elementHash,
|
|
1025
|
+
clicks: elementData.totalclicks,
|
|
1026
|
+
rank: rank,
|
|
1027
|
+
selector: elementData.selector || '',
|
|
1028
|
+
});
|
|
1029
|
+
// Dừng loop khi tìm thấy element hợp lệ đầu tiên
|
|
1030
|
+
break;
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
catch (error) {
|
|
1036
|
+
console.warn('Error handling mouse move on heatmap:', error);
|
|
1037
|
+
}
|
|
1038
|
+
}, [heatmapWrapperRef, iframeRef, parentRef, heatmapInfo, scaleRatio, onElementHover]);
|
|
1039
|
+
return { handleMouseMove };
|
|
1040
|
+
}
|
|
1041
|
+
// ===================== EXAMPLE USAGE =====================
|
|
1042
|
+
/*
|
|
1043
|
+
import { useRef, useState } from 'react';
|
|
1044
|
+
|
|
1045
|
+
function HeatmapComponent() {
|
|
1046
|
+
const heatmapWrapperRef = useRef<HTMLDivElement>(null);
|
|
1047
|
+
const iframeRef = useRef<HTMLIFrameElement>(null);
|
|
1048
|
+
const parentRef = useRef<HTMLDivElement>(null);
|
|
1049
|
+
|
|
1050
|
+
const [hoveredElement, setHoveredElement] = useState<HoveredElementInfo | null>(null);
|
|
1051
|
+
|
|
1052
|
+
const heatmapInfo = {
|
|
1053
|
+
width: 1920,
|
|
1054
|
+
elementMapInfo: {
|
|
1055
|
+
'hash123': {
|
|
1056
|
+
totalclicks: 45,
|
|
1057
|
+
selector: 'button.submit'
|
|
1058
|
+
}
|
|
1059
|
+
},
|
|
1060
|
+
sortedElements: [...]
|
|
1061
|
+
};
|
|
1062
|
+
|
|
1063
|
+
const { handleMouseMove } = useHeatmapMouseHandler({
|
|
1064
|
+
heatmapWrapperRef,
|
|
1065
|
+
iframeRef,
|
|
1066
|
+
parentRef,
|
|
1067
|
+
heatmapInfo,
|
|
1068
|
+
scaleRatio: 0.8, // 80% zoom
|
|
1069
|
+
onElementHover: (info) => {
|
|
1070
|
+
setHoveredElement(info);
|
|
1071
|
+
console.log('Hovered element:', info);
|
|
1072
|
+
}
|
|
1073
|
+
});
|
|
1074
|
+
|
|
1075
|
+
return (
|
|
1076
|
+
<div ref={parentRef}>
|
|
1077
|
+
<div
|
|
1078
|
+
ref={heatmapWrapperRef}
|
|
1079
|
+
onMouseMove={handleMouseMove}
|
|
1080
|
+
>
|
|
1081
|
+
<iframe ref={iframeRef} />
|
|
1082
|
+
|
|
1083
|
+
{hoveredElement && (
|
|
1084
|
+
<div className="tooltip" style={{
|
|
1085
|
+
position: 'absolute',
|
|
1086
|
+
left: hoveredElement.left,
|
|
1087
|
+
top: hoveredElement.top
|
|
1088
|
+
}}>
|
|
1089
|
+
Clicks: {hoveredElement.clicks}
|
|
1090
|
+
<br />
|
|
1091
|
+
Rank: #{hoveredElement.rank}
|
|
1092
|
+
<br />
|
|
1093
|
+
Selector: {hoveredElement.selector}
|
|
1094
|
+
</div>
|
|
1095
|
+
)}
|
|
1096
|
+
</div>
|
|
1097
|
+
</div>
|
|
1098
|
+
);
|
|
1099
|
+
}
|
|
1100
|
+
*/
|
|
1101
|
+
|
|
923
1102
|
const useHoveredElement = ({ iframeRef, getRect }) => {
|
|
924
1103
|
const hoveredElement = useHeatmapInteractionStore((state) => state.hoveredElement);
|
|
925
1104
|
const setHoveredElement = useHeatmapInteractionStore((state) => state.setHoveredElement);
|
|
@@ -941,7 +1120,7 @@ const useHoveredElement = ({ iframeRef, getRect }) => {
|
|
|
941
1120
|
const doc = iframe.contentDocument;
|
|
942
1121
|
const iframeRect = iframe.getBoundingClientRect();
|
|
943
1122
|
const { x, y } = convertViewportToIframeCoords(event.clientX, event.clientY, iframeRect, widthScale);
|
|
944
|
-
const targetElement = findTargetElement(doc, x, y);
|
|
1123
|
+
const targetElement = findTargetElement(doc, x, y, heatmapInfo);
|
|
945
1124
|
if (!targetElement || !isValidElement(targetElement, heatmapInfo)) {
|
|
946
1125
|
reset();
|
|
947
1126
|
return;
|
|
@@ -992,7 +1171,25 @@ const convertViewportToIframeCoords = (clientX, clientY, iframeRect, scale) => {
|
|
|
992
1171
|
}
|
|
993
1172
|
return { x, y };
|
|
994
1173
|
};
|
|
995
|
-
const findTargetElement = (doc, x, y) => {
|
|
1174
|
+
const findTargetElement = (doc, x, y, heatmapInfo) => {
|
|
1175
|
+
const HEATMAP_ELEMENT_ATTRIBUTE = 'data-clarity-hashalpha';
|
|
1176
|
+
const elementsAtPoint = getElementsAtPoint(doc, Math.round(x), Math.round(y), (element) => element.hasAttribute(HEATMAP_ELEMENT_ATTRIBUTE));
|
|
1177
|
+
let dataElement = null;
|
|
1178
|
+
for (let i = 0; i < elementsAtPoint.length; i++) {
|
|
1179
|
+
const element = elementsAtPoint[i];
|
|
1180
|
+
const elementHash = element.getAttribute(HEATMAP_ELEMENT_ATTRIBUTE);
|
|
1181
|
+
if (elementHash && heatmapInfo.elementMapInfo?.[elementHash]) {
|
|
1182
|
+
heatmapInfo.elementMapInfo[elementHash];
|
|
1183
|
+
const boundingBox = getBoundingBox(element);
|
|
1184
|
+
if (boundingBox) {
|
|
1185
|
+
dataElement = element;
|
|
1186
|
+
break;
|
|
1187
|
+
}
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
if (!!dataElement) {
|
|
1191
|
+
return dataElement;
|
|
1192
|
+
}
|
|
996
1193
|
let targetElement = getElementAtPoint(doc, x, y);
|
|
997
1194
|
if (!targetElement) {
|
|
998
1195
|
targetElement = doc.elementFromPoint(x, y);
|
|
@@ -1016,7 +1213,7 @@ var MessageType;
|
|
|
1016
1213
|
MessageType["GX_DOM_TRACKING_PAYLOAD"] = "GX_DOM_TRACKING_PAYLOAD";
|
|
1017
1214
|
MessageType["CLARITY_READY"] = "CLARITY_READY";
|
|
1018
1215
|
})(MessageType || (MessageType = {}));
|
|
1019
|
-
function
|
|
1216
|
+
function useVizLiveIframeMsg(options = {}) {
|
|
1020
1217
|
const { trustedOrigins = [], onMessage } = options;
|
|
1021
1218
|
const addPayload = useHeatmapLiveStore((state) => state.addPayload);
|
|
1022
1219
|
const [isReady, setIsReady] = useState(false);
|
|
@@ -1066,13 +1263,14 @@ function useIframeMessage(options = {}) {
|
|
|
1066
1263
|
isReady,
|
|
1067
1264
|
};
|
|
1068
1265
|
}
|
|
1069
|
-
|
|
1266
|
+
|
|
1267
|
+
function useVizLiveRender() {
|
|
1070
1268
|
const wrapperHeight = useHeatmapLiveStore((state) => state.wrapperHeight);
|
|
1269
|
+
const setIframeHeight = useHeatmapLiveStore((state) => state.setIframeHeight);
|
|
1071
1270
|
const contentWidth = useHeatmapConfigStore((state) => state.width);
|
|
1072
|
-
const setIframeHeight = useHeatmapVizStore((state) => state.setIframeHeight);
|
|
1073
1271
|
const htmlContent = useHeatmapLiveStore((state) => state.htmlContent);
|
|
1074
1272
|
const setIsRenderViz = useHeatmapVizStore((state) => state.setIsRenderViz);
|
|
1075
|
-
const { iframeRef, isReady } =
|
|
1273
|
+
const { iframeRef, isReady } = useVizLiveIframeMsg();
|
|
1076
1274
|
useEffect(() => {
|
|
1077
1275
|
if (!htmlContent || !iframeRef.current)
|
|
1078
1276
|
return;
|
|
@@ -1119,9 +1317,9 @@ function reset$1(iframe, rect, onSuccess) {
|
|
|
1119
1317
|
let visualizer = new Visualizer();
|
|
1120
1318
|
const useHeatmapRender = () => {
|
|
1121
1319
|
const data = useHeatmapDataStore((state) => state.data);
|
|
1122
|
-
const setVizRef =
|
|
1320
|
+
const setVizRef = useHeatmapSingleStore((state) => state.setVizRef);
|
|
1123
1321
|
const setIsRenderViz = useHeatmapVizStore((state) => state.setIsRenderViz);
|
|
1124
|
-
const setIframeHeight =
|
|
1322
|
+
const setIframeHeight = useHeatmapSingleStore((state) => state.setIframeHeight);
|
|
1125
1323
|
const iframeRef = useRef(null);
|
|
1126
1324
|
const renderHeatmap = useCallback(async (payloads) => {
|
|
1127
1325
|
if (!payloads || payloads.length === 0)
|
|
@@ -1131,8 +1329,6 @@ const useHeatmapRender = () => {
|
|
|
1131
1329
|
if (!iframe?.contentWindow)
|
|
1132
1330
|
return;
|
|
1133
1331
|
await visualizer.html(payloads, iframe.contentWindow);
|
|
1134
|
-
const element = visualizer.get('3w0uppvjw');
|
|
1135
|
-
console.log(`🚀 🐥 ~ useHeatmapRender ~ element:`, element);
|
|
1136
1332
|
reset(iframe, payloads, (height) => {
|
|
1137
1333
|
height && setIframeHeight(height);
|
|
1138
1334
|
setIsRenderViz(true);
|
|
@@ -1160,8 +1356,8 @@ function reset(iframe, payloads, onSuccess) {
|
|
|
1160
1356
|
targetHeight: docHeight,
|
|
1161
1357
|
iframe: iframe,
|
|
1162
1358
|
onSuccess: (data) => {
|
|
1163
|
-
onSuccess(data.height);
|
|
1164
1359
|
iframe.height = `${data.height}px`;
|
|
1360
|
+
onSuccess(data.height);
|
|
1165
1361
|
},
|
|
1166
1362
|
});
|
|
1167
1363
|
viewportFixer.recalculate();
|
|
@@ -1350,30 +1546,64 @@ const useContentDimensions = ({ iframeRef, }) => {
|
|
|
1350
1546
|
return { contentWidth };
|
|
1351
1547
|
};
|
|
1352
1548
|
|
|
1353
|
-
const
|
|
1549
|
+
const useObserveIframeHeight = (props) => {
|
|
1354
1550
|
const { iframeRef, setIframeHeight } = props;
|
|
1355
1551
|
const isRenderViz = useHeatmapVizStore((state) => state.isRenderViz);
|
|
1356
1552
|
const resizeObserverRef = useRef(null);
|
|
1357
1553
|
const mutationObserverRef = useRef(null);
|
|
1554
|
+
const debounceTimerRef = useRef(null);
|
|
1555
|
+
const lastHeightRef = useRef(0);
|
|
1556
|
+
const animationFrameRef = useRef(null);
|
|
1358
1557
|
const updateIframeHeight = useCallback(() => {
|
|
1359
1558
|
const iframe = iframeRef.current;
|
|
1360
|
-
if (!iframe)
|
|
1559
|
+
if (!iframe || !setIframeHeight)
|
|
1361
1560
|
return;
|
|
1362
1561
|
try {
|
|
1363
1562
|
const iframeDocument = iframe.contentDocument;
|
|
1364
1563
|
const iframeBody = iframeDocument?.body;
|
|
1365
|
-
|
|
1564
|
+
const iframeDocumentElement = iframeDocument?.documentElement;
|
|
1565
|
+
if (!iframeBody || !iframeDocumentElement)
|
|
1366
1566
|
return;
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1567
|
+
iframe.style.height = 'auto';
|
|
1568
|
+
requestAnimationFrame(() => {
|
|
1569
|
+
const bodyHeight = Math.max(iframeBody.scrollHeight, iframeBody.offsetHeight, iframeBody.clientHeight);
|
|
1570
|
+
const documentHeight = Math.max(iframeDocumentElement.scrollHeight, iframeDocumentElement.offsetHeight, iframeDocumentElement.clientHeight);
|
|
1571
|
+
const actualHeight = Math.max(bodyHeight, documentHeight);
|
|
1572
|
+
if (actualHeight > 0) {
|
|
1573
|
+
lastHeightRef.current = actualHeight;
|
|
1574
|
+
iframe.height = `${actualHeight}px`;
|
|
1575
|
+
iframe.style.height = `${actualHeight}px`;
|
|
1576
|
+
setIframeHeight(actualHeight);
|
|
1577
|
+
}
|
|
1578
|
+
});
|
|
1372
1579
|
}
|
|
1373
1580
|
catch (error) {
|
|
1374
1581
|
console.warn('Cannot measure iframe content:', error);
|
|
1375
1582
|
}
|
|
1376
1583
|
}, [iframeRef, setIframeHeight]);
|
|
1584
|
+
const debouncedUpdate = useCallback(() => {
|
|
1585
|
+
// Cancel pending updates
|
|
1586
|
+
if (debounceTimerRef.current) {
|
|
1587
|
+
clearTimeout(debounceTimerRef.current);
|
|
1588
|
+
}
|
|
1589
|
+
if (animationFrameRef.current) {
|
|
1590
|
+
cancelAnimationFrame(animationFrameRef.current);
|
|
1591
|
+
}
|
|
1592
|
+
debounceTimerRef.current = setTimeout(() => {
|
|
1593
|
+
animationFrameRef.current = requestAnimationFrame(() => {
|
|
1594
|
+
updateIframeHeight();
|
|
1595
|
+
});
|
|
1596
|
+
}, 50);
|
|
1597
|
+
}, [updateIframeHeight]);
|
|
1598
|
+
// Immediate update không debounce (cho ResizeObserver)
|
|
1599
|
+
const immediateUpdate = useCallback(() => {
|
|
1600
|
+
if (animationFrameRef.current) {
|
|
1601
|
+
cancelAnimationFrame(animationFrameRef.current);
|
|
1602
|
+
}
|
|
1603
|
+
animationFrameRef.current = requestAnimationFrame(() => {
|
|
1604
|
+
updateIframeHeight();
|
|
1605
|
+
});
|
|
1606
|
+
}, [updateIframeHeight]);
|
|
1377
1607
|
useEffect(() => {
|
|
1378
1608
|
const iframe = iframeRef.current;
|
|
1379
1609
|
if (!iframe || !isRenderViz)
|
|
@@ -1391,22 +1621,24 @@ const useIframeHeight = (props) => {
|
|
|
1391
1621
|
if (mutationObserverRef.current) {
|
|
1392
1622
|
mutationObserverRef.current.disconnect();
|
|
1393
1623
|
}
|
|
1394
|
-
// ResizeObserver for size changes
|
|
1395
1624
|
if (typeof window.ResizeObserver !== 'undefined') {
|
|
1396
|
-
resizeObserverRef.current = new ResizeObserver(
|
|
1625
|
+
resizeObserverRef.current = new ResizeObserver(immediateUpdate);
|
|
1397
1626
|
resizeObserverRef.current.observe(iframeBody);
|
|
1627
|
+
const iframeDocumentElement = iframeDocument?.documentElement;
|
|
1628
|
+
if (iframeDocumentElement) {
|
|
1629
|
+
resizeObserverRef.current.observe(iframeDocumentElement);
|
|
1630
|
+
}
|
|
1398
1631
|
}
|
|
1399
|
-
// MutationObserver for DOM changes
|
|
1400
1632
|
if (typeof window.MutationObserver !== 'undefined') {
|
|
1401
|
-
mutationObserverRef.current = new MutationObserver(
|
|
1633
|
+
mutationObserverRef.current = new MutationObserver(immediateUpdate);
|
|
1402
1634
|
mutationObserverRef.current.observe(iframeBody, {
|
|
1403
1635
|
childList: true,
|
|
1404
1636
|
subtree: true,
|
|
1405
1637
|
attributes: true,
|
|
1406
|
-
|
|
1638
|
+
attributeFilter: ['style', 'class'],
|
|
1639
|
+
characterData: false,
|
|
1407
1640
|
});
|
|
1408
1641
|
}
|
|
1409
|
-
// Initial measurement
|
|
1410
1642
|
updateIframeHeight();
|
|
1411
1643
|
}
|
|
1412
1644
|
catch (error) {
|
|
@@ -1420,15 +1652,23 @@ const useIframeHeight = (props) => {
|
|
|
1420
1652
|
iframe.addEventListener('load', setupObservers, { once: true });
|
|
1421
1653
|
}
|
|
1422
1654
|
return () => {
|
|
1655
|
+
// Cleanup observers
|
|
1423
1656
|
if (resizeObserverRef.current) {
|
|
1424
1657
|
resizeObserverRef.current.disconnect();
|
|
1425
1658
|
}
|
|
1426
1659
|
if (mutationObserverRef.current) {
|
|
1427
1660
|
mutationObserverRef.current.disconnect();
|
|
1428
1661
|
}
|
|
1662
|
+
// Cleanup timers
|
|
1663
|
+
if (debounceTimerRef.current) {
|
|
1664
|
+
clearTimeout(debounceTimerRef.current);
|
|
1665
|
+
}
|
|
1666
|
+
if (animationFrameRef.current) {
|
|
1667
|
+
cancelAnimationFrame(animationFrameRef.current);
|
|
1668
|
+
}
|
|
1429
1669
|
iframe.removeEventListener('load', setupObservers);
|
|
1430
1670
|
};
|
|
1431
|
-
}, [iframeRef, isRenderViz, updateIframeHeight]);
|
|
1671
|
+
}, [iframeRef, isRenderViz, updateIframeHeight, debouncedUpdate, immediateUpdate]);
|
|
1432
1672
|
return {};
|
|
1433
1673
|
};
|
|
1434
1674
|
|
|
@@ -1474,7 +1714,7 @@ const useHeatmapScale = (props) => {
|
|
|
1474
1714
|
// 2. Get content dimensions from config
|
|
1475
1715
|
const { contentWidth } = useContentDimensions({ iframeRef });
|
|
1476
1716
|
// 3. Observe iframe height (now reacts to width changes)
|
|
1477
|
-
|
|
1717
|
+
useObserveIframeHeight({ iframeRef, setIframeHeight });
|
|
1478
1718
|
// 4. Calculate scale
|
|
1479
1719
|
const { scale } = useScaleCalculation({ containerWidth, contentWidth });
|
|
1480
1720
|
// 5. Setup scroll sync
|
|
@@ -1645,37 +1885,159 @@ const VizContainer = ({ children, setWrapperHeight }) => {
|
|
|
1645
1885
|
const useClickmap = () => {
|
|
1646
1886
|
const [isInitialized, setIsInitialized] = useState(false);
|
|
1647
1887
|
const clickmap = useHeatmapDataStore((state) => state.clickmap);
|
|
1648
|
-
const vizRef =
|
|
1649
|
-
|
|
1888
|
+
const vizRef = useHeatmapSingleStore((state) => state.vizRef);
|
|
1889
|
+
const start = useCallback(() => {
|
|
1650
1890
|
if (isInitialized)
|
|
1651
1891
|
return;
|
|
1652
1892
|
if (!vizRef || !clickmap || clickmap.length === 0)
|
|
1653
1893
|
return;
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1894
|
+
try {
|
|
1895
|
+
vizRef?.clearmap?.();
|
|
1896
|
+
vizRef?.clickmap?.(clickmap);
|
|
1897
|
+
setIsInitialized(true);
|
|
1898
|
+
}
|
|
1899
|
+
catch (error) {
|
|
1900
|
+
console.error(`🚀 🐥 ~ useClickmap ~ error:`, error);
|
|
1901
|
+
}
|
|
1659
1902
|
}, [vizRef, clickmap]);
|
|
1660
|
-
return {};
|
|
1903
|
+
return { start };
|
|
1661
1904
|
};
|
|
1662
1905
|
|
|
1906
|
+
const DATA_SCROLLMAP = [
|
|
1907
|
+
{
|
|
1908
|
+
scrollReachY: 5,
|
|
1909
|
+
cumulativeSum: 0,
|
|
1910
|
+
percUsers: 0,
|
|
1911
|
+
},
|
|
1912
|
+
{
|
|
1913
|
+
scrollReachY: 10,
|
|
1914
|
+
cumulativeSum: 0,
|
|
1915
|
+
percUsers: 0,
|
|
1916
|
+
},
|
|
1917
|
+
{
|
|
1918
|
+
scrollReachY: 15,
|
|
1919
|
+
cumulativeSum: 0,
|
|
1920
|
+
percUsers: 0,
|
|
1921
|
+
},
|
|
1922
|
+
{
|
|
1923
|
+
scrollReachY: 20,
|
|
1924
|
+
cumulativeSum: 0,
|
|
1925
|
+
percUsers: 0,
|
|
1926
|
+
},
|
|
1927
|
+
{
|
|
1928
|
+
scrollReachY: 25,
|
|
1929
|
+
cumulativeSum: 0,
|
|
1930
|
+
percUsers: 0,
|
|
1931
|
+
},
|
|
1932
|
+
{
|
|
1933
|
+
scrollReachY: 30,
|
|
1934
|
+
cumulativeSum: 0,
|
|
1935
|
+
percUsers: 0,
|
|
1936
|
+
},
|
|
1937
|
+
{
|
|
1938
|
+
scrollReachY: 35,
|
|
1939
|
+
cumulativeSum: 0,
|
|
1940
|
+
percUsers: 0,
|
|
1941
|
+
},
|
|
1942
|
+
{
|
|
1943
|
+
scrollReachY: 40,
|
|
1944
|
+
cumulativeSum: 0,
|
|
1945
|
+
percUsers: 0,
|
|
1946
|
+
},
|
|
1947
|
+
{
|
|
1948
|
+
scrollReachY: 45,
|
|
1949
|
+
cumulativeSum: 0,
|
|
1950
|
+
percUsers: 0,
|
|
1951
|
+
},
|
|
1952
|
+
{
|
|
1953
|
+
scrollReachY: 50,
|
|
1954
|
+
cumulativeSum: 0,
|
|
1955
|
+
percUsers: 0,
|
|
1956
|
+
},
|
|
1957
|
+
{
|
|
1958
|
+
scrollReachY: 55,
|
|
1959
|
+
cumulativeSum: 0,
|
|
1960
|
+
percUsers: 0,
|
|
1961
|
+
},
|
|
1962
|
+
{
|
|
1963
|
+
scrollReachY: 60,
|
|
1964
|
+
cumulativeSum: 0,
|
|
1965
|
+
percUsers: 0,
|
|
1966
|
+
},
|
|
1967
|
+
{
|
|
1968
|
+
scrollReachY: 65,
|
|
1969
|
+
cumulativeSum: 0,
|
|
1970
|
+
percUsers: 0,
|
|
1971
|
+
},
|
|
1972
|
+
{
|
|
1973
|
+
scrollReachY: 70,
|
|
1974
|
+
cumulativeSum: 0,
|
|
1975
|
+
percUsers: 0,
|
|
1976
|
+
},
|
|
1977
|
+
{
|
|
1978
|
+
scrollReachY: 75,
|
|
1979
|
+
cumulativeSum: 0,
|
|
1980
|
+
percUsers: 0,
|
|
1981
|
+
},
|
|
1982
|
+
{
|
|
1983
|
+
scrollReachY: 80,
|
|
1984
|
+
cumulativeSum: 0,
|
|
1985
|
+
percUsers: 0,
|
|
1986
|
+
},
|
|
1987
|
+
{
|
|
1988
|
+
scrollReachY: 85,
|
|
1989
|
+
cumulativeSum: 0,
|
|
1990
|
+
percUsers: 0,
|
|
1991
|
+
},
|
|
1992
|
+
{
|
|
1993
|
+
scrollReachY: 90,
|
|
1994
|
+
cumulativeSum: 0,
|
|
1995
|
+
percUsers: 0,
|
|
1996
|
+
},
|
|
1997
|
+
{
|
|
1998
|
+
scrollReachY: 95,
|
|
1999
|
+
cumulativeSum: 0,
|
|
2000
|
+
percUsers: 0,
|
|
2001
|
+
},
|
|
2002
|
+
{
|
|
2003
|
+
scrollReachY: 100,
|
|
2004
|
+
cumulativeSum: 0,
|
|
2005
|
+
percUsers: 0,
|
|
2006
|
+
},
|
|
2007
|
+
];
|
|
1663
2008
|
const useScrollmap = () => {
|
|
1664
|
-
|
|
1665
|
-
|
|
2009
|
+
const vizRef = useHeatmapSingleStore((state) => state.vizRef);
|
|
2010
|
+
const start = useCallback(() => {
|
|
2011
|
+
// if (isInitialized) return;
|
|
2012
|
+
const scrollmap = DATA_SCROLLMAP;
|
|
2013
|
+
if (!vizRef || !scrollmap || scrollmap.length === 0)
|
|
2014
|
+
return;
|
|
2015
|
+
try {
|
|
2016
|
+
vizRef?.clearmap?.();
|
|
2017
|
+
vizRef?.scrollmap?.(scrollmap);
|
|
2018
|
+
// setIsInitialized(true);
|
|
2019
|
+
}
|
|
2020
|
+
catch (error) {
|
|
2021
|
+
console.error(`🚀 🐥 ~ useScrollmap ~ error:`, error);
|
|
2022
|
+
}
|
|
2023
|
+
}, [vizRef]);
|
|
2024
|
+
return { start };
|
|
1666
2025
|
};
|
|
1667
2026
|
|
|
1668
2027
|
const useHeatmapVizCanvas = () => {
|
|
1669
2028
|
const heatmapType = useHeatmapConfigStore((state) => state.heatmapType);
|
|
1670
|
-
const
|
|
2029
|
+
const { start: startClickmap } = useClickmap();
|
|
2030
|
+
const { start: startScrollmap } = useScrollmap();
|
|
2031
|
+
useEffect(() => {
|
|
1671
2032
|
switch (heatmapType) {
|
|
1672
2033
|
case IHeatmapType.Click:
|
|
1673
|
-
|
|
2034
|
+
startClickmap();
|
|
2035
|
+
break;
|
|
1674
2036
|
case IHeatmapType.Scroll:
|
|
1675
|
-
|
|
2037
|
+
startClickmap();
|
|
2038
|
+
break;
|
|
1676
2039
|
}
|
|
1677
|
-
}, [heatmapType]);
|
|
1678
|
-
return heatmapRender?.();
|
|
2040
|
+
}, [heatmapType, startClickmap, startScrollmap]);
|
|
1679
2041
|
};
|
|
1680
2042
|
|
|
1681
2043
|
const CLICKED_ELEMENT_ID = 'gx-hm-clicked-element';
|
|
@@ -1738,7 +2100,7 @@ const ElementCallout = (props) => {
|
|
|
1738
2100
|
window.removeEventListener('resize', handleUpdate);
|
|
1739
2101
|
visualRef?.current?.removeEventListener('scroll', handleUpdate);
|
|
1740
2102
|
};
|
|
1741
|
-
}, [target, visualRef, hozOffset, alignment]);
|
|
2103
|
+
}, [element, target, visualRef, hozOffset, alignment]);
|
|
1742
2104
|
const calloutContent = (jsx("div", { ref: calloutRef, className: `clarity-callout clarity-callout--${position.placement} clarity-callout--align-${position.horizontalAlign}`, style: {
|
|
1743
2105
|
position: 'fixed',
|
|
1744
2106
|
top: position.top,
|
|
@@ -1803,7 +2165,8 @@ const ELEMENT_CALLOUT = {
|
|
|
1803
2165
|
alignment: 'left',
|
|
1804
2166
|
};
|
|
1805
2167
|
const HeatmapElements = (props) => {
|
|
1806
|
-
const
|
|
2168
|
+
const iframeHeight = useHeatmapSingleStore((state) => state.iframeHeight);
|
|
2169
|
+
const setHoveredElement = useHeatmapInteractionStore((state) => state.setHoveredElement);
|
|
1807
2170
|
const { iframeRef, wrapperRef, visualRef, visualizer, iframeDimensions, isElementSidebarOpen, isVisible = true, areDefaultRanksHidden, isSecondary, ...rest } = props;
|
|
1808
2171
|
const getRect = useHeatmapElementPosition({
|
|
1809
2172
|
iframeRef,
|
|
@@ -1818,6 +2181,27 @@ const HeatmapElements = (props) => {
|
|
|
1818
2181
|
iframeRef,
|
|
1819
2182
|
getRect,
|
|
1820
2183
|
});
|
|
2184
|
+
const heatmapInfo = useHeatmapDataStore((state) => state.dataInfo);
|
|
2185
|
+
useHeatmapMouseHandler({
|
|
2186
|
+
heatmapWrapperRef: wrapperRef,
|
|
2187
|
+
iframeRef,
|
|
2188
|
+
parentRef: visualRef,
|
|
2189
|
+
heatmapInfo: heatmapInfo || {},
|
|
2190
|
+
scaleRatio: 0.8, // 80% zoom
|
|
2191
|
+
onElementHover: (info) => {
|
|
2192
|
+
setHoveredElement({
|
|
2193
|
+
hash: info.hash,
|
|
2194
|
+
clicks: info.clicks,
|
|
2195
|
+
rank: info.rank,
|
|
2196
|
+
selector: info.selector,
|
|
2197
|
+
top: info.top,
|
|
2198
|
+
left: info.left,
|
|
2199
|
+
width: info.width,
|
|
2200
|
+
height: info.height,
|
|
2201
|
+
});
|
|
2202
|
+
console.log(`🚀 🐥 ~ HeatmapElements ~ info:`, info);
|
|
2203
|
+
},
|
|
2204
|
+
});
|
|
1821
2205
|
useElementCalloutVisible({
|
|
1822
2206
|
visualRef,
|
|
1823
2207
|
getRect,
|
|
@@ -1833,13 +2217,16 @@ const HeatmapElements = (props) => {
|
|
|
1833
2217
|
});
|
|
1834
2218
|
if (!isVisible)
|
|
1835
2219
|
return null;
|
|
1836
|
-
return (jsxs("div", { onMouseMove:
|
|
2220
|
+
return (jsxs("div", { onMouseMove: (event) => {
|
|
2221
|
+
handleMouseMove(event);
|
|
2222
|
+
// handleMouseMove2(event as any);
|
|
2223
|
+
}, onMouseLeave: handleMouseLeave, className: "gx-hm-elements", style: { ...iframeDimensions, height: `${iframeHeight}px` }, children: [jsx(ElementMissing, { show: showMissingElement }), jsx(DefaultRankBadges, { getRect: getRect, hidden: areDefaultRanksHidden }), jsx(ElementOverlay, { type: "clicked", element: clickedElement, isSecondary: isSecondary }), jsx(ElementOverlay, { type: "hovered", element: hoveredElement, isSecondary: isSecondary, onClick: handleClick }), hoveredElement?.hash !== clickedElement?.hash && hoveredElement && (jsx(ElementCallout, { element: hoveredElement, target: `#${HOVERED_ELEMENT_ID}`, visualRef: visualRef, ...ELEMENT_CALLOUT })), shouldShowCallout && clickedElement && (jsx(ElementCallout, { element: clickedElement, target: `#${CLICKED_ELEMENT_ID}`, visualRef: visualRef, ...ELEMENT_CALLOUT }))] }));
|
|
1837
2224
|
};
|
|
1838
2225
|
|
|
1839
2226
|
const VizElements = ({ iframeRef, visualRef, wrapperRef }) => {
|
|
1840
2227
|
const heatmapInfo = useHeatmapDataStore((state) => state.dataInfo);
|
|
1841
2228
|
const contentWidth = useHeatmapConfigStore((state) => state.width);
|
|
1842
|
-
const vizRef =
|
|
2229
|
+
const vizRef = useHeatmapSingleStore((state) => state.vizRef);
|
|
1843
2230
|
const visualizer = {
|
|
1844
2231
|
get: (hash) => {
|
|
1845
2232
|
if (vizRef) {
|
|
@@ -1904,8 +2291,8 @@ const WrapperVisual = ({ children, visualRef, wrapperRef, scaledHeight, iframeHe
|
|
|
1904
2291
|
|
|
1905
2292
|
const VizDomRenderer = ({ mode = 'heatmap' }) => {
|
|
1906
2293
|
const width = useHeatmapConfigStore((state) => state.width);
|
|
1907
|
-
const iframeHeight =
|
|
1908
|
-
const setIframeHeight =
|
|
2294
|
+
const iframeHeight = useHeatmapSingleStore((state) => state.iframeHeight);
|
|
2295
|
+
const setIframeHeight = useHeatmapSingleStore((state) => state.setIframeHeight);
|
|
1909
2296
|
const setSelectedElement = useHeatmapInteractionStore((state) => state.setSelectedElement);
|
|
1910
2297
|
const wrapperRef = useRef(null);
|
|
1911
2298
|
const visualRef = useRef(null);
|
|
@@ -1915,7 +2302,6 @@ const VizDomRenderer = ({ mode = 'heatmap' }) => {
|
|
|
1915
2302
|
iframeRef,
|
|
1916
2303
|
visualRef,
|
|
1917
2304
|
iframeHeight,
|
|
1918
|
-
setIframeHeight,
|
|
1919
2305
|
});
|
|
1920
2306
|
const contentWidth = width ?? 0;
|
|
1921
2307
|
const onScroll = (e) => {
|
|
@@ -1930,7 +2316,7 @@ const VizDomRenderer = ({ mode = 'heatmap' }) => {
|
|
|
1930
2316
|
useEffect(() => {
|
|
1931
2317
|
return cleanUp;
|
|
1932
2318
|
}, []);
|
|
1933
|
-
return (jsxs(WrapperVisual, { visualRef: visualRef, wrapperRef: wrapperRef, scaledHeight: scaledHeight, onScroll: onScroll, iframeHeight: iframeHeight, children: [jsx(VizElements, { iframeRef: iframeRef, visualRef: visualRef, wrapperRef: wrapperRef }), jsx("iframe", { ref: iframeRef, ...HEATMAP_IFRAME, width: contentWidth,
|
|
2319
|
+
return (jsxs(WrapperVisual, { visualRef: visualRef, wrapperRef: wrapperRef, scaledHeight: scaledHeight, onScroll: onScroll, iframeHeight: iframeHeight, children: [jsx(VizElements, { iframeRef: iframeRef, visualRef: visualRef, wrapperRef: wrapperRef }), jsx("iframe", { ref: iframeRef, ...HEATMAP_IFRAME, width: contentWidth, scrolling: "no" })] }));
|
|
1934
2320
|
};
|
|
1935
2321
|
|
|
1936
2322
|
const VizLoading = () => {
|
|
@@ -1940,12 +2326,12 @@ const VizLoading = () => {
|
|
|
1940
2326
|
const VizDomHeatmap = () => {
|
|
1941
2327
|
const controls = useHeatmapControlStore((state) => state.controls);
|
|
1942
2328
|
const isRendering = useHeatmapDataStore((state) => state.isRendering);
|
|
1943
|
-
const iframeHeight =
|
|
1944
|
-
const setIframeHeight =
|
|
1945
|
-
const setVizRef =
|
|
2329
|
+
const iframeHeight = useHeatmapSingleStore((state) => state.iframeHeight);
|
|
2330
|
+
const setIframeHeight = useHeatmapSingleStore((state) => state.setIframeHeight);
|
|
2331
|
+
const setVizRef = useHeatmapSingleStore((state) => state.setVizRef);
|
|
1946
2332
|
useEffect(() => {
|
|
1947
2333
|
return () => {
|
|
1948
|
-
setVizRef(
|
|
2334
|
+
setVizRef(null);
|
|
1949
2335
|
setIframeHeight(0);
|
|
1950
2336
|
};
|
|
1951
2337
|
}, []);
|
|
@@ -1960,7 +2346,7 @@ const VizLiveRenderer = () => {
|
|
|
1960
2346
|
const setIframeHeight = useHeatmapLiveStore((state) => state.setIframeHeight);
|
|
1961
2347
|
const visualRef = useRef(null);
|
|
1962
2348
|
const wrapperRef = useRef(null);
|
|
1963
|
-
const { iframeRef } =
|
|
2349
|
+
const { iframeRef } = useVizLiveRender();
|
|
1964
2350
|
const { scaledHeight, handleScroll } = useHeatmapScale({
|
|
1965
2351
|
wrapperRef,
|
|
1966
2352
|
iframeRef,
|
|
@@ -1972,13 +2358,15 @@ const VizLiveRenderer = () => {
|
|
|
1972
2358
|
const scrollTop = e.currentTarget.scrollTop;
|
|
1973
2359
|
handleScroll(scrollTop);
|
|
1974
2360
|
};
|
|
1975
|
-
return (jsx(WrapperVisual, { visualRef: visualRef, wrapperRef: wrapperRef, scaledHeight: scaledHeight, iframeHeight: iframeHeight, onScroll: onScroll, children: jsx("iframe", { ref: iframeRef, ...HEATMAP_IFRAME, width: contentWidth,
|
|
2361
|
+
return (jsx(WrapperVisual, { visualRef: visualRef, wrapperRef: wrapperRef, scaledHeight: scaledHeight, iframeHeight: iframeHeight, onScroll: onScroll, children: jsx("iframe", { ref: iframeRef, ...HEATMAP_IFRAME, width: contentWidth,
|
|
2362
|
+
// height={iframeHeight}
|
|
2363
|
+
scrolling: "no", sandbox: "allow-scripts allow-same-origin" }) }));
|
|
1976
2364
|
};
|
|
1977
2365
|
|
|
1978
2366
|
const VizLiveHeatmap = () => {
|
|
1979
2367
|
const controls = useHeatmapControlStore((state) => state.controls);
|
|
1980
2368
|
const isRendering = useHeatmapDataStore((state) => state.isRendering);
|
|
1981
|
-
const iframeHeight =
|
|
2369
|
+
const iframeHeight = useHeatmapLiveStore((state) => state.iframeHeight);
|
|
1982
2370
|
const wrapperHeight = useHeatmapLiveStore((state) => state.wrapperHeight);
|
|
1983
2371
|
const setWrapperHeight = useHeatmapLiveStore((state) => state.setWrapperHeight);
|
|
1984
2372
|
const reset = useHeatmapLiveStore((state) => state.reset);
|