import React, { useEffect, useRef, useState } from 'react' import Plot from 'react-plotly.js' import Plotly from 'plotly.js-dist-min' function PlotFigure({ figure, indexedFigure = null, onRequestIndexedFigure = null, title, subtitle = '', forceHideLegend = false, className = '', lazy = false, showPointIndexToggle = false, headerActions = null, trailingHeaderActions = null, revisionKey = '', }) { const containerRef = useRef(null) const [shouldRenderPlot, setShouldRenderPlot] = useState(() => !lazy) const [showPointIndices, setShowPointIndices] = useState(false) const [loadingIndexedFigure, setLoadingIndexedFigure] = useState(false) const figureResetKey = revisionKey ? String(revisionKey) : figure useEffect(() => { if (!lazy) { setShouldRenderPlot(true) return undefined } if (shouldRenderPlot) return undefined if (typeof window === 'undefined' || !('IntersectionObserver' in window)) { setShouldRenderPlot(true) return undefined } const target = containerRef.current if (!target) return undefined const observer = new IntersectionObserver( (entries) => { const isVisible = entries.some((entry) => entry.isIntersecting || entry.intersectionRatio > 0) if (isVisible) { setShouldRenderPlot(true) observer.disconnect() } }, { rootMargin: '240px 0px', threshold: 0.01 }, ) observer.observe(target) return () => observer.disconnect() }, [lazy, shouldRenderPlot]) useEffect(() => { setShowPointIndices(false) setLoadingIndexedFigure(false) }, [figureResetKey]) if (!figure) { return
Grafico indisponivel.
} const hasIndexedFigure = Boolean(indexedFigure) const canRequestIndexedFigure = typeof onRequestIndexedFigure === 'function' const canToggleIndices = hasIndexedFigure || canRequestIndexedFigure const activeFigure = showPointIndices && hasIndexedFigure ? indexedFigure : figure const safeFigure = activeFigure || { data: [], layout: {} } const baseLayout = safeFigure.layout || {} const { width: _ignoreWidth, ...layoutNoWidth } = baseLayout const safeAnnotations = Array.isArray(baseLayout.annotations) ? baseLayout.annotations.map((annotation) => { const { ax, ay, axref, ayref, arrowhead, arrowsize, arrowwidth, arrowcolor, standoff, ...clean } = annotation || {} return { ...clean, showarrow: false } }) : baseLayout.annotations const data = (safeFigure.data || []).map((trace) => ( forceHideLegend ? { ...trace, showlegend: false } : { ...trace } )) const layout = { ...layoutNoWidth, autosize: true, annotations: Array.isArray(safeAnnotations) ? safeAnnotations : [], margin: baseLayout.margin || { t: 40, r: 20, b: 50, l: 50 }, } if (forceHideLegend) { layout.showlegend = false } const plotHeight = layout.height ? `${layout.height}px` : '100%' const plotRevision = `${showPointIndices && hasIndexedFigure ? 'indices' : 'base'}:${String(revisionKey || '')}` const cardClassName = `plot-card ${className}`.trim() async function handleToggleChange(event) { const checked = Boolean(event.target.checked) if (!checked) { setShowPointIndices(false) return } if (hasIndexedFigure) { setShowPointIndices(true) return } if (!canRequestIndexedFigure || loadingIndexedFigure) return setLoadingIndexedFigure(true) try { const loadedFigure = await onRequestIndexedFigure() setShowPointIndices(Boolean(loadedFigure)) } catch { setShowPointIndices(false) } finally { setLoadingIndexedFigure(false) } } const toggleTitle = loadingIndexedFigure ? 'Carregando INDICES dos pontos...' : hasIndexedFigure ? 'Exibir INDICES dos pontos' : canRequestIndexedFigure ? 'Carregar INDICES dos pontos sob demanda' : 'Este gráfico não trouxe uma versão com INDICES.' return (
{title || subtitle || showPointIndexToggle || headerActions || trailingHeaderActions ? (
{title ?

{title}

: null} {subtitle ?
{subtitle}
: null}
{headerActions} {showPointIndexToggle ? ( ) : null} {trailingHeaderActions}
) : null} {shouldRenderPlot ? (
) : (
Carregando gráfico...
)}
) } export default PlotFigure