@gemx-dev/heatmap-react 3.5.35 → 3.5.38
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/components/Layout/ContentToolbar.d.ts.map +1 -1
- package/dist/esm/components/Layout/ContentTopBar.d.ts.map +1 -1
- package/dist/esm/components/Layout/LeftSidebar.d.ts.map +1 -1
- package/dist/esm/components/VizDom/VizDomContainer.d.ts.map +1 -1
- package/dist/esm/configs/iframe.d.ts +1 -1
- package/dist/esm/configs/iframe.d.ts.map +1 -1
- package/dist/esm/helpers/index.d.ts +2 -0
- package/dist/esm/helpers/index.d.ts.map +1 -1
- package/dist/esm/helpers/viewport-fixer.d.ts +13 -0
- package/dist/esm/helpers/viewport-fixer.d.ts.map +1 -0
- package/dist/esm/helpers/viewport-replacer.d.ts +26 -0
- package/dist/esm/helpers/viewport-replacer.d.ts.map +1 -0
- package/dist/esm/hooks/viz-render/useHeatmapRender.d.ts.map +1 -1
- package/dist/esm/hooks/viz-scale/useContentDimensions.d.ts +1 -1
- package/dist/esm/hooks/viz-scale/useContentDimensions.d.ts.map +1 -1
- package/dist/esm/hooks/viz-scale/useHeatmapScale.d.ts.map +1 -1
- package/dist/esm/hooks/viz-scale/useIframeHeight.d.ts +0 -1
- package/dist/esm/hooks/viz-scale/useIframeHeight.d.ts.map +1 -1
- package/dist/esm/hooks/viz-scale/useScrollSync.d.ts.map +1 -1
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +349 -33
- package/dist/esm/index.mjs +349 -33
- package/dist/esm/stores/config.d.ts +7 -0
- package/dist/esm/stores/config.d.ts.map +1 -0
- package/dist/esm/stores/index.d.ts +2 -0
- package/dist/esm/stores/index.d.ts.map +1 -1
- package/dist/esm/stores/mode-live.d.ts +6 -0
- package/dist/esm/stores/mode-live.d.ts.map +1 -0
- package/dist/esm/stores/viz.d.ts +2 -0
- package/dist/esm/stores/viz.d.ts.map +1 -1
- package/dist/esm/types/control.d.ts +1 -1
- package/dist/esm/types/control.d.ts.map +1 -1
- package/dist/esm/types/index.d.ts +1 -0
- package/dist/esm/types/index.d.ts.map +1 -1
- package/dist/esm/types/viewport-fixer.d.ts +31 -0
- package/dist/esm/types/viewport-fixer.d.ts.map +1 -0
- package/dist/esm/ui/BoxStack/BoxStack.d.ts +1 -1
- package/dist/esm/ui/BoxStack/BoxStack.d.ts.map +1 -1
- package/dist/style.css +45 -1
- package/dist/umd/components/Layout/ContentToolbar.d.ts.map +1 -1
- package/dist/umd/components/Layout/ContentTopBar.d.ts.map +1 -1
- package/dist/umd/components/Layout/LeftSidebar.d.ts.map +1 -1
- package/dist/umd/components/VizDom/VizDomContainer.d.ts.map +1 -1
- package/dist/umd/configs/iframe.d.ts +1 -1
- package/dist/umd/configs/iframe.d.ts.map +1 -1
- package/dist/umd/helpers/index.d.ts +2 -0
- package/dist/umd/helpers/index.d.ts.map +1 -1
- package/dist/umd/helpers/viewport-fixer.d.ts +13 -0
- package/dist/umd/helpers/viewport-fixer.d.ts.map +1 -0
- package/dist/umd/helpers/viewport-replacer.d.ts +26 -0
- package/dist/umd/helpers/viewport-replacer.d.ts.map +1 -0
- package/dist/umd/hooks/viz-render/useHeatmapRender.d.ts.map +1 -1
- package/dist/umd/hooks/viz-scale/useContentDimensions.d.ts +1 -1
- package/dist/umd/hooks/viz-scale/useContentDimensions.d.ts.map +1 -1
- package/dist/umd/hooks/viz-scale/useHeatmapScale.d.ts.map +1 -1
- package/dist/umd/hooks/viz-scale/useIframeHeight.d.ts +0 -1
- package/dist/umd/hooks/viz-scale/useIframeHeight.d.ts.map +1 -1
- package/dist/umd/hooks/viz-scale/useScrollSync.d.ts.map +1 -1
- package/dist/umd/index.d.ts +1 -1
- package/dist/umd/index.d.ts.map +1 -1
- package/dist/umd/index.js +2 -2
- package/dist/umd/stores/config.d.ts +7 -0
- package/dist/umd/stores/config.d.ts.map +1 -0
- package/dist/umd/stores/index.d.ts +2 -0
- package/dist/umd/stores/index.d.ts.map +1 -1
- package/dist/umd/stores/mode-live.d.ts +6 -0
- package/dist/umd/stores/mode-live.d.ts.map +1 -0
- package/dist/umd/stores/viz.d.ts +2 -0
- package/dist/umd/stores/viz.d.ts.map +1 -1
- package/dist/umd/types/control.d.ts +1 -1
- package/dist/umd/types/control.d.ts.map +1 -1
- package/dist/umd/types/index.d.ts +1 -0
- package/dist/umd/types/index.d.ts.map +1 -1
- package/dist/umd/types/viewport-fixer.d.ts +31 -0
- package/dist/umd/types/viewport-fixer.d.ts.map +1 -0
- package/dist/umd/ui/BoxStack/BoxStack.d.ts +1 -1
- package/dist/umd/ui/BoxStack/BoxStack.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/esm/index.js
CHANGED
|
@@ -85,6 +85,14 @@ const useHeatmapControlStore = create()((set, get) => {
|
|
|
85
85
|
};
|
|
86
86
|
});
|
|
87
87
|
|
|
88
|
+
const useHeatmapConfigStore = create()((set, get) => {
|
|
89
|
+
return {
|
|
90
|
+
mode: 'single',
|
|
91
|
+
setMode: (mode) => set({ mode }),
|
|
92
|
+
resetMode: () => set({ mode: 'single' }),
|
|
93
|
+
};
|
|
94
|
+
});
|
|
95
|
+
|
|
88
96
|
var IHeatmapType;
|
|
89
97
|
(function (IHeatmapType) {
|
|
90
98
|
IHeatmapType["Click"] = "click";
|
|
@@ -128,6 +136,8 @@ const useHeatmapInteractionStore = create()((set, get) => {
|
|
|
128
136
|
|
|
129
137
|
const useHeatmapVizStore = create()((set, get) => {
|
|
130
138
|
return {
|
|
139
|
+
isRenderViz: false,
|
|
140
|
+
setIsRenderViz: (isRenderViz) => set({ isRenderViz }),
|
|
131
141
|
scale: 1,
|
|
132
142
|
vizRef: undefined,
|
|
133
143
|
iframeHeight: 0,
|
|
@@ -137,6 +147,13 @@ const useHeatmapVizStore = create()((set, get) => {
|
|
|
137
147
|
};
|
|
138
148
|
});
|
|
139
149
|
|
|
150
|
+
const useHeatmapLiveStore = create()((set, get) => {
|
|
151
|
+
return {
|
|
152
|
+
htmlContent: '',
|
|
153
|
+
setHtmlContent: (htmlContent) => set({ htmlContent }),
|
|
154
|
+
};
|
|
155
|
+
});
|
|
156
|
+
|
|
140
157
|
const useRegisterConfig = () => {
|
|
141
158
|
const config = useHeatmapDataStore((state) => state.config);
|
|
142
159
|
const setIsRendering = useHeatmapDataStore((state) => state.setIsRendering);
|
|
@@ -436,6 +453,266 @@ function isElementInViewport(elementRect, visualRef, scale) {
|
|
|
436
453
|
return elementBottom > viewportTop && elementTop < viewportBottom;
|
|
437
454
|
}
|
|
438
455
|
|
|
456
|
+
const getScriptInjectCode = async () => {
|
|
457
|
+
const moduleResult = (await Promise.resolve().then(function () { return viewportReplacer; }));
|
|
458
|
+
const ActualClass = moduleResult.default;
|
|
459
|
+
const classCode = ActualClass.toString();
|
|
460
|
+
const classInstantiateCode = ActualClass.name;
|
|
461
|
+
const scriptCode = `
|
|
462
|
+
(function() {
|
|
463
|
+
'use strict';
|
|
464
|
+
${classCode}
|
|
465
|
+
new ${classInstantiateCode}()
|
|
466
|
+
})();
|
|
467
|
+
`;
|
|
468
|
+
return scriptCode;
|
|
469
|
+
};
|
|
470
|
+
class ViewportUnitsFixer {
|
|
471
|
+
iframe = null;
|
|
472
|
+
config;
|
|
473
|
+
constructor(config) {
|
|
474
|
+
this.config = config;
|
|
475
|
+
this.iframe = config.iframe;
|
|
476
|
+
this.init();
|
|
477
|
+
}
|
|
478
|
+
async init() {
|
|
479
|
+
if (!this.iframe) {
|
|
480
|
+
console.error('[Parent] Required elements not found');
|
|
481
|
+
return;
|
|
482
|
+
}
|
|
483
|
+
// this.injectScriptContent = await generateIframeInjectScript();
|
|
484
|
+
window.addEventListener('message', this.handleMessage.bind(this));
|
|
485
|
+
if (this.iframe.contentDocument?.readyState === 'complete') {
|
|
486
|
+
await this.injectScript();
|
|
487
|
+
}
|
|
488
|
+
else {
|
|
489
|
+
this.iframe.addEventListener('load', () => this.injectScript());
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
async injectScript() {
|
|
493
|
+
if (!this.iframe?.contentWindow || !this.iframe.contentDocument)
|
|
494
|
+
return;
|
|
495
|
+
const win = this.iframe.contentWindow;
|
|
496
|
+
const doc = this.iframe.contentDocument;
|
|
497
|
+
win.__viewportConfig = this.config;
|
|
498
|
+
const script = doc.createElement('script');
|
|
499
|
+
const codeInject = await getScriptInjectCode();
|
|
500
|
+
script.textContent = codeInject;
|
|
501
|
+
script.type = 'text/javascript';
|
|
502
|
+
script.id = 'viewport-replacer';
|
|
503
|
+
script.onload = () => console.log('[Parent] Viewport replacer module loaded');
|
|
504
|
+
script.onerror = () => {
|
|
505
|
+
this.config.onSuccess?.({
|
|
506
|
+
height: 1000,
|
|
507
|
+
});
|
|
508
|
+
};
|
|
509
|
+
doc.head.appendChild(script);
|
|
510
|
+
}
|
|
511
|
+
handleMessage(event) {
|
|
512
|
+
const data = event.data;
|
|
513
|
+
if (!data || data.type !== 'IFRAME_HEIGHT_CALCULATED')
|
|
514
|
+
return;
|
|
515
|
+
this.config.onSuccess?.(data);
|
|
516
|
+
}
|
|
517
|
+
recalculate() {
|
|
518
|
+
this.injectScript();
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
function initViewportFixer(config) {
|
|
522
|
+
const fixer = new ViewportUnitsFixer(config);
|
|
523
|
+
window.viewportFixer = fixer;
|
|
524
|
+
window.addEventListener('iframe-dimensions-applied', ((e) => {
|
|
525
|
+
const ev = e;
|
|
526
|
+
console.log('Iframe dimensions finalized:', ev.detail);
|
|
527
|
+
}));
|
|
528
|
+
return fixer;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
class ViewportUnitsReplacer {
|
|
532
|
+
config;
|
|
533
|
+
regex = /([-.\d]+)(vh|svh|lvh|dvh|vw|svw|lvw|dvw)/gi;
|
|
534
|
+
constructor() {
|
|
535
|
+
if (!window.__viewportConfig) {
|
|
536
|
+
throw new Error('[Iframe] Do not have viewport config');
|
|
537
|
+
}
|
|
538
|
+
this.config = window.__viewportConfig;
|
|
539
|
+
console.log('[Iframe] ViewportUnitsReplacer started with config:', this.config);
|
|
540
|
+
this.init();
|
|
541
|
+
}
|
|
542
|
+
px(value) {
|
|
543
|
+
return `${value.toFixed(2)}px`;
|
|
544
|
+
}
|
|
545
|
+
convert(value, unit) {
|
|
546
|
+
const num = parseFloat(value);
|
|
547
|
+
if (isNaN(num))
|
|
548
|
+
return value;
|
|
549
|
+
const map = {
|
|
550
|
+
vh: this.config.targetHeight,
|
|
551
|
+
svh: this.config.targetHeight,
|
|
552
|
+
lvh: this.config.targetHeight,
|
|
553
|
+
dvh: this.config.targetHeight,
|
|
554
|
+
vw: this.config.targetWidth,
|
|
555
|
+
svw: this.config.targetWidth,
|
|
556
|
+
lvw: this.config.targetWidth,
|
|
557
|
+
dvw: this.config.targetWidth,
|
|
558
|
+
};
|
|
559
|
+
return this.px((num / 100) * (map[unit.toLowerCase()] || 0));
|
|
560
|
+
}
|
|
561
|
+
replaceInText(cssText) {
|
|
562
|
+
return cssText.replace(this.regex, (_, value, unit) => this.convert(value, unit));
|
|
563
|
+
}
|
|
564
|
+
processInlineStyles() {
|
|
565
|
+
let count = 0;
|
|
566
|
+
document.querySelectorAll('[style]').forEach((el) => {
|
|
567
|
+
const style = el.getAttribute('style');
|
|
568
|
+
if (style && this.regex.test(style)) {
|
|
569
|
+
el.setAttribute('style', this.replaceInText(style));
|
|
570
|
+
count++;
|
|
571
|
+
}
|
|
572
|
+
});
|
|
573
|
+
console.log(`[Iframe] Replaced ${count} inline style elements`);
|
|
574
|
+
return count;
|
|
575
|
+
}
|
|
576
|
+
processStyleTags() {
|
|
577
|
+
let count = 0;
|
|
578
|
+
document.querySelectorAll('style').forEach((tag) => {
|
|
579
|
+
const css = tag.textContent || '';
|
|
580
|
+
if (this.regex.test(css)) {
|
|
581
|
+
tag.textContent = this.replaceInText(css);
|
|
582
|
+
count++;
|
|
583
|
+
}
|
|
584
|
+
});
|
|
585
|
+
console.log(`[Iframe] Replaced ${count} <style> tags`);
|
|
586
|
+
return count;
|
|
587
|
+
}
|
|
588
|
+
processRule(rule) {
|
|
589
|
+
let count = 0;
|
|
590
|
+
if ('style' in rule && rule.style) {
|
|
591
|
+
const style = rule.style;
|
|
592
|
+
for (let i = 0; i < style.length; i++) {
|
|
593
|
+
const prop = style[i];
|
|
594
|
+
const value = style.getPropertyValue(prop);
|
|
595
|
+
if (value && this.regex.test(value)) {
|
|
596
|
+
style.setProperty(prop, this.replaceInText(value), style.getPropertyPriority(prop));
|
|
597
|
+
count++;
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
if ('cssRules' in rule) {
|
|
602
|
+
const rules = rule;
|
|
603
|
+
for (const r of Array.from(rules.cssRules || [])) {
|
|
604
|
+
count += this.processRule(r);
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
return count;
|
|
608
|
+
}
|
|
609
|
+
processStylesheets() {
|
|
610
|
+
let total = 0;
|
|
611
|
+
Array.from(document.styleSheets).forEach((sheet) => {
|
|
612
|
+
try {
|
|
613
|
+
// Bỏ qua external CSS (cross-origin)
|
|
614
|
+
if (sheet.href && !sheet.href.startsWith(location.origin)) {
|
|
615
|
+
console.log('[Iframe] Skipping external CSS:', sheet.href);
|
|
616
|
+
return;
|
|
617
|
+
}
|
|
618
|
+
const rules = sheet.cssRules || sheet.rules;
|
|
619
|
+
if (!rules)
|
|
620
|
+
return;
|
|
621
|
+
for (const rule of Array.from(rules)) {
|
|
622
|
+
total += this.processRule(rule);
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
catch (e) {
|
|
626
|
+
console.warn('[Iframe] Cannot read stylesheet (CORS?):', e.message);
|
|
627
|
+
}
|
|
628
|
+
});
|
|
629
|
+
console.log(`[Iframe] Replaced ${total} rules in stylesheets`);
|
|
630
|
+
return total;
|
|
631
|
+
}
|
|
632
|
+
async processLinkedStylesheets() {
|
|
633
|
+
const links = document.querySelectorAll('link[rel="stylesheet"]');
|
|
634
|
+
let count = 0;
|
|
635
|
+
for (const link of Array.from(links)) {
|
|
636
|
+
if (!link.href.startsWith(location.origin)) {
|
|
637
|
+
console.log('[Iframe] Skipping external CSS:', link.href);
|
|
638
|
+
continue;
|
|
639
|
+
}
|
|
640
|
+
try {
|
|
641
|
+
const res = await fetch(link.href);
|
|
642
|
+
let css = await res.text();
|
|
643
|
+
if (this.regex.test(css)) {
|
|
644
|
+
css = this.replaceInText(css);
|
|
645
|
+
const style = document.createElement('style');
|
|
646
|
+
style.textContent = css;
|
|
647
|
+
style.dataset.originalHref = link.href;
|
|
648
|
+
link.parentNode?.insertBefore(style, link);
|
|
649
|
+
link.remove();
|
|
650
|
+
count++;
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
catch (e) {
|
|
654
|
+
console.warn('[Iframe] Cannot load CSS:', link.href, e);
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
console.log(`[Iframe] Replaced ${count} linked CSS files`);
|
|
658
|
+
return count;
|
|
659
|
+
}
|
|
660
|
+
getFinalHeight() {
|
|
661
|
+
// Trigger reflow
|
|
662
|
+
void document.body.offsetHeight;
|
|
663
|
+
return Math.max(document.body.scrollHeight, document.body.offsetHeight, document.documentElement.scrollHeight, document.documentElement.offsetHeight, document.documentElement.clientHeight);
|
|
664
|
+
}
|
|
665
|
+
notifyParent(height) {
|
|
666
|
+
window.parent.postMessage({
|
|
667
|
+
type: 'IFRAME_HEIGHT_CALCULATED',
|
|
668
|
+
height,
|
|
669
|
+
width: document.body.scrollWidth,
|
|
670
|
+
}, '*');
|
|
671
|
+
console.log('[Iframe] Sent height to parent:', height);
|
|
672
|
+
}
|
|
673
|
+
async waitForResources() {
|
|
674
|
+
if ('fonts' in document) {
|
|
675
|
+
await document.fonts.ready;
|
|
676
|
+
}
|
|
677
|
+
const images = Array.from(document.images).filter((img) => !img.complete);
|
|
678
|
+
if (images.length > 0) {
|
|
679
|
+
await Promise.all(images.map((img) => new Promise((resolve) => {
|
|
680
|
+
img.onload = img.onerror = resolve;
|
|
681
|
+
})));
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
async run() {
|
|
685
|
+
try {
|
|
686
|
+
this.processInlineStyles();
|
|
687
|
+
this.processStyleTags();
|
|
688
|
+
this.processStylesheets();
|
|
689
|
+
await this.processLinkedStylesheets();
|
|
690
|
+
// await this.waitForResources();
|
|
691
|
+
requestAnimationFrame(() => {
|
|
692
|
+
const height = this.getFinalHeight();
|
|
693
|
+
this.notifyParent(height);
|
|
694
|
+
});
|
|
695
|
+
}
|
|
696
|
+
catch (err) {
|
|
697
|
+
console.error('[Iframe] Critical error:', err);
|
|
698
|
+
this.notifyParent(document.body.scrollHeight || 1000);
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
init() {
|
|
702
|
+
if (document.readyState === 'loading') {
|
|
703
|
+
document.addEventListener('DOMContentLoaded', () => this.run());
|
|
704
|
+
}
|
|
705
|
+
else {
|
|
706
|
+
this.run();
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
var viewportReplacer = /*#__PURE__*/Object.freeze({
|
|
712
|
+
__proto__: null,
|
|
713
|
+
default: ViewportUnitsReplacer
|
|
714
|
+
});
|
|
715
|
+
|
|
439
716
|
const scrollToElementIfNeeded = (visualRef, rect, scale) => {
|
|
440
717
|
if (!visualRef.current)
|
|
441
718
|
return;
|
|
@@ -691,24 +968,22 @@ const useHeatmapRender = () => {
|
|
|
691
968
|
const data = useHeatmapDataStore((state) => state.data);
|
|
692
969
|
const config = useHeatmapDataStore((state) => state.config);
|
|
693
970
|
const setVizRef = useHeatmapVizStore((state) => state.setVizRef);
|
|
971
|
+
const setIsRenderViz = useHeatmapVizStore((state) => state.setIsRenderViz);
|
|
972
|
+
const setIframeHeight = useHeatmapVizStore((state) => state.setIframeHeight);
|
|
694
973
|
const iframeRef = useRef(null);
|
|
695
974
|
const renderHeatmap = useCallback(async (payloads) => {
|
|
696
975
|
if (!payloads || payloads.length === 0)
|
|
697
976
|
return;
|
|
977
|
+
setIsRenderViz(false);
|
|
698
978
|
const visualizer = new Visualizer();
|
|
699
979
|
const iframe = iframeRef.current;
|
|
700
980
|
if (!iframe?.contentWindow)
|
|
701
981
|
return;
|
|
702
982
|
await visualizer.html(payloads, iframe.contentWindow);
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
// const isRemove = !(isClosedEcomsendWidget || isEcomsendWidget);
|
|
708
|
-
// if (isRemove) {
|
|
709
|
-
// element.remove();
|
|
710
|
-
// }
|
|
711
|
-
// });
|
|
983
|
+
reset(iframe, payloads, (height) => {
|
|
984
|
+
height && setIframeHeight(height);
|
|
985
|
+
setIsRenderViz(true);
|
|
986
|
+
});
|
|
712
987
|
setVizRef(visualizer);
|
|
713
988
|
}, []);
|
|
714
989
|
useEffect(() => {
|
|
@@ -723,6 +998,50 @@ const useHeatmapRender = () => {
|
|
|
723
998
|
iframeRef,
|
|
724
999
|
};
|
|
725
1000
|
};
|
|
1001
|
+
function sort(a, b) {
|
|
1002
|
+
return a.time - b.time;
|
|
1003
|
+
}
|
|
1004
|
+
function findLastSizeOfDom(data) {
|
|
1005
|
+
const firstDoc = data.find((item) => item.envelope.sequence === 1)?.doc;
|
|
1006
|
+
const docSorted = firstDoc?.sort(sort);
|
|
1007
|
+
const firstEvent = docSorted?.[0];
|
|
1008
|
+
const docSize = {
|
|
1009
|
+
width: firstEvent?.data.width,
|
|
1010
|
+
height: firstEvent?.data.height,
|
|
1011
|
+
};
|
|
1012
|
+
const newData = JSON.parse(JSON.stringify(data));
|
|
1013
|
+
const reversedData = newData.reverse();
|
|
1014
|
+
const lastResizeEvent = reversedData.find((item) => !!item.resize);
|
|
1015
|
+
const firstEventResize = lastResizeEvent?.resize?.[0];
|
|
1016
|
+
const resize = {
|
|
1017
|
+
width: firstEventResize?.data.width,
|
|
1018
|
+
height: firstEventResize?.data.height,
|
|
1019
|
+
};
|
|
1020
|
+
return {
|
|
1021
|
+
doc: docSize,
|
|
1022
|
+
resize: resize,
|
|
1023
|
+
size: {
|
|
1024
|
+
width: resize.width ?? docSize.width,
|
|
1025
|
+
height: resize.height ?? docSize.height,
|
|
1026
|
+
},
|
|
1027
|
+
};
|
|
1028
|
+
}
|
|
1029
|
+
function reset(iframe, payloads, onSuccess) {
|
|
1030
|
+
const { size } = findLastSizeOfDom(payloads);
|
|
1031
|
+
const docWidth = size.width ?? 0;
|
|
1032
|
+
const docHeight = size.height ?? 0;
|
|
1033
|
+
const viewportFixer = initViewportFixer({
|
|
1034
|
+
targetWidth: docWidth,
|
|
1035
|
+
targetHeight: docHeight,
|
|
1036
|
+
iframe: iframe,
|
|
1037
|
+
onSuccess: (data) => {
|
|
1038
|
+
onSuccess(data.height);
|
|
1039
|
+
iframe.height = `${data.height}px`;
|
|
1040
|
+
},
|
|
1041
|
+
});
|
|
1042
|
+
viewportFixer.recalculate();
|
|
1043
|
+
return iframe;
|
|
1044
|
+
}
|
|
726
1045
|
|
|
727
1046
|
function isMobileDevice(userAgent) {
|
|
728
1047
|
if (!userAgent)
|
|
@@ -894,24 +1213,24 @@ const useContainerDimensions = (props) => {
|
|
|
894
1213
|
return { containerWidth, containerHeight };
|
|
895
1214
|
};
|
|
896
1215
|
|
|
897
|
-
const useContentDimensions = (
|
|
898
|
-
const
|
|
899
|
-
const
|
|
1216
|
+
const useContentDimensions = ({ iframeRef, }) => {
|
|
1217
|
+
const config = useHeatmapDataStore((state) => state.config);
|
|
1218
|
+
const contentWidth = config?.width ?? 0;
|
|
900
1219
|
useEffect(() => {
|
|
901
1220
|
if (!contentWidth)
|
|
902
1221
|
return;
|
|
903
1222
|
if (!iframeRef.current)
|
|
904
1223
|
return;
|
|
905
|
-
iframeRef.current.width = `${contentWidth}px`;
|
|
1224
|
+
// iframeRef.current.width = `${contentWidth}px`;
|
|
906
1225
|
}, [contentWidth, iframeRef]);
|
|
907
1226
|
return { contentWidth };
|
|
908
1227
|
};
|
|
909
1228
|
|
|
910
|
-
// Hook 3: Iframe Height Observer
|
|
911
1229
|
const useIframeHeight = (props) => {
|
|
912
|
-
const { iframeRef
|
|
1230
|
+
const { iframeRef } = props;
|
|
913
1231
|
const iframeHeight = useHeatmapVizStore((state) => state.iframeHeight);
|
|
914
1232
|
const setIframeHeight = useHeatmapVizStore((state) => state.setIframeHeight);
|
|
1233
|
+
const isRenderViz = useHeatmapVizStore((state) => state.isRenderViz);
|
|
915
1234
|
const resizeObserverRef = useRef(null);
|
|
916
1235
|
const mutationObserverRef = useRef(null);
|
|
917
1236
|
const updateIframeHeight = useCallback(() => {
|
|
@@ -933,17 +1252,9 @@ const useIframeHeight = (props) => {
|
|
|
933
1252
|
console.warn('Cannot measure iframe content:', error);
|
|
934
1253
|
}
|
|
935
1254
|
}, [iframeRef, setIframeHeight]);
|
|
936
|
-
useEffect(() => {
|
|
937
|
-
if (contentWidth > 0) {
|
|
938
|
-
const timeoutId = setTimeout(() => {
|
|
939
|
-
updateIframeHeight();
|
|
940
|
-
}, 100);
|
|
941
|
-
return () => clearTimeout(timeoutId);
|
|
942
|
-
}
|
|
943
|
-
}, [contentWidth]);
|
|
944
1255
|
useEffect(() => {
|
|
945
1256
|
const iframe = iframeRef.current;
|
|
946
|
-
if (!iframe)
|
|
1257
|
+
if (!iframe || !isRenderViz)
|
|
947
1258
|
return;
|
|
948
1259
|
const setupObservers = () => {
|
|
949
1260
|
try {
|
|
@@ -995,7 +1306,7 @@ const useIframeHeight = (props) => {
|
|
|
995
1306
|
}
|
|
996
1307
|
iframe.removeEventListener('load', setupObservers);
|
|
997
1308
|
};
|
|
998
|
-
}, [iframeRef, updateIframeHeight]);
|
|
1309
|
+
}, [iframeRef, isRenderViz, updateIframeHeight]);
|
|
999
1310
|
return { iframeHeight };
|
|
1000
1311
|
};
|
|
1001
1312
|
|
|
@@ -1025,7 +1336,6 @@ const useScrollSync = ({ iframeRef }) => {
|
|
|
1025
1336
|
if (iframeWindow && iframeDocument) {
|
|
1026
1337
|
const iframeScrollTop = scrollTop / widthScale;
|
|
1027
1338
|
iframe.style.top = `${iframeScrollTop}px`;
|
|
1028
|
-
// iframeWindow.scrollTo({ top: iframeScrollTop, behavior: 'smooth' });
|
|
1029
1339
|
}
|
|
1030
1340
|
}
|
|
1031
1341
|
catch (error) {
|
|
@@ -1036,13 +1346,14 @@ const useScrollSync = ({ iframeRef }) => {
|
|
|
1036
1346
|
};
|
|
1037
1347
|
|
|
1038
1348
|
const useHeatmapScale = (props) => {
|
|
1349
|
+
// const iframeHeight = useHeatmapVizStore((state) => state.iframeHeight);
|
|
1039
1350
|
const { wrapperRef, iframeRef, visualRef } = props;
|
|
1040
1351
|
// 1. Observe container dimensions
|
|
1041
1352
|
const { containerWidth, containerHeight } = useContainerDimensions({ wrapperRef });
|
|
1042
1353
|
// 2. Get content dimensions from config
|
|
1043
1354
|
const { contentWidth } = useContentDimensions({ iframeRef });
|
|
1044
1355
|
// 3. Observe iframe height (now reacts to width changes)
|
|
1045
|
-
const { iframeHeight } = useIframeHeight({ iframeRef
|
|
1356
|
+
const { iframeHeight } = useIframeHeight({ iframeRef });
|
|
1046
1357
|
// 4. Calculate scale
|
|
1047
1358
|
const { scale } = useScaleCalculation({ containerWidth, contentWidth });
|
|
1048
1359
|
// 5. Setup scroll sync
|
|
@@ -1068,7 +1379,8 @@ const BoxStack = forwardRef(({ children, ...props }, ref) => {
|
|
|
1068
1379
|
const style = props.style || {};
|
|
1069
1380
|
const gap = props.gap || 0;
|
|
1070
1381
|
const height = props.height || 'auto';
|
|
1071
|
-
const
|
|
1382
|
+
const isZIndexDefined = typeof props.zIndex !== undefined;
|
|
1383
|
+
const zIndex = props.zIndex;
|
|
1072
1384
|
const backgroundColor = props.backgroundColor || 'transparent';
|
|
1073
1385
|
const styleGap = useMemo(() => {
|
|
1074
1386
|
switch (flexDirection) {
|
|
@@ -1091,8 +1403,8 @@ const BoxStack = forwardRef(({ children, ...props }, ref) => {
|
|
|
1091
1403
|
justifyContent,
|
|
1092
1404
|
alignItems,
|
|
1093
1405
|
height,
|
|
1094
|
-
zIndex,
|
|
1095
1406
|
backgroundColor,
|
|
1407
|
+
...(isZIndexDefined ? { zIndex } : {}),
|
|
1096
1408
|
...styleGap,
|
|
1097
1409
|
...style,
|
|
1098
1410
|
};
|
|
@@ -1101,9 +1413,10 @@ const BoxStack = forwardRef(({ children, ...props }, ref) => {
|
|
|
1101
1413
|
|
|
1102
1414
|
const ContentTopBar = () => {
|
|
1103
1415
|
const controls = useHeatmapControlStore((state) => state.controls);
|
|
1416
|
+
const TopBar = controls.TopBar;
|
|
1104
1417
|
return (jsx(BoxStack, { id: "gx-hm-content-header", flexDirection: "row", alignItems: "center", overflow: "auto", zIndex: 1, backgroundColor: "white", style: {
|
|
1105
1418
|
borderBottom: `${HEATMAP_CONFIG.borderWidth}px solid ${HEATMAP_CONFIG.borderColor}`,
|
|
1106
|
-
}, children:
|
|
1419
|
+
}, children: TopBar && jsx(TopBar, {}) }));
|
|
1107
1420
|
};
|
|
1108
1421
|
|
|
1109
1422
|
const useClickmap = () => {
|
|
@@ -1414,11 +1727,12 @@ const VizDomRenderer = ({ mode = 'heatmap' }) => {
|
|
|
1414
1727
|
const VizDomContainer = () => {
|
|
1415
1728
|
const controls = useHeatmapControlStore((state) => state.controls);
|
|
1416
1729
|
const isRendering = useHeatmapDataStore((state) => state.isRendering);
|
|
1730
|
+
const iframeHeight = useHeatmapVizStore((state) => state.iframeHeight);
|
|
1417
1731
|
if (isRendering)
|
|
1418
1732
|
return controls.VizLoading ?? null;
|
|
1419
|
-
return (jsx(BoxStack, { id: "gx-hm-viz-container", flexDirection: "column", flex: "1 1 auto", overflow: "auto", children:
|
|
1733
|
+
return (jsx(BoxStack, { id: "gx-hm-viz-container", flexDirection: "column", flex: "1 1 auto", overflow: "auto", zIndex: 1, children: jsxs(BoxStack, { id: "gx-hm-content", flexDirection: "column", flex: "1 1 auto", overflow: "hidden", style: {
|
|
1420
1734
|
minWidth: '394px',
|
|
1421
|
-
}, children: jsx(VizDomRenderer, {}) }) }));
|
|
1735
|
+
}, children: [jsx(VizDomRenderer, {}), iframeHeight === 0 && (jsxs("div", { className: "gx-hm-loading", children: [jsx("div", { className: "gx-hm-loading--spinner" }), jsx("p", { className: "gx-hm-loading--text", children: "Loading visualization..." })] }))] }) }));
|
|
1422
1736
|
};
|
|
1423
1737
|
|
|
1424
1738
|
const ContentMetricBar = () => {
|
|
@@ -1431,6 +1745,7 @@ const ContentMetricBar = () => {
|
|
|
1431
1745
|
const ContentToolbar = () => {
|
|
1432
1746
|
const controls = useHeatmapControlStore((state) => state.controls);
|
|
1433
1747
|
return (jsx("div", { id: "gx-hm-content-toolbar", style: {
|
|
1748
|
+
zIndex: 2,
|
|
1434
1749
|
position: 'absolute',
|
|
1435
1750
|
bottom: 0,
|
|
1436
1751
|
left: '8px',
|
|
@@ -1451,6 +1766,7 @@ const LeftSidebar = () => {
|
|
|
1451
1766
|
return (jsx("div", { className: "gx-hm-sidebar", style: {
|
|
1452
1767
|
height: '100%',
|
|
1453
1768
|
display: 'flex',
|
|
1769
|
+
zIndex: 1,
|
|
1454
1770
|
...(isHideSidebar
|
|
1455
1771
|
? {
|
|
1456
1772
|
width: '0',
|
|
@@ -1509,4 +1825,4 @@ var ErrorType;
|
|
|
1509
1825
|
ErrorType["DataError"] = "DataError";
|
|
1510
1826
|
})(ErrorType || (ErrorType = {}));
|
|
1511
1827
|
|
|
1512
|
-
export { GraphView, HeatmapLayout, IHeatmapType, useHeatmapDataStore, useHeatmapInteractionStore };
|
|
1828
|
+
export { GraphView, HeatmapLayout, IHeatmapType, useHeatmapConfigStore, useHeatmapDataStore, useHeatmapInteractionStore, useHeatmapLiveStore };
|