MCPcopy
hub / github.com/microsoft/data-formulator / ChartRenderService

Function ChartRenderService

src/views/ChartRenderService.tsx:115–326  ·  view source on GitHub ↗
()

Source from the content-addressed store, hash-verified

113}
114
115export const ChartRenderService: FC = () => {
116 const dispatch = useDispatch();
117
118 const charts = useSelector(dfSelectors.getAllCharts);
119 const tables = useSelector((state: DataFormulatorState) => state.tables);
120 const conceptShelfItems = useSelector((state: DataFormulatorState) => state.conceptShelfItems);
121 const chartSynthesisInProgress = useSelector((state: DataFormulatorState) => state.chartSynthesisInProgress);
122 const maxStretchFactor = useSelector((state: DataFormulatorState) => state.config.maxStretchFactor);
123 // Re-run when the focused canvas caches a fresh display-row sample so
124 // thumbnails can use the same richer data the main chart is rendering.
125 const displayRowsTick = useSelector((state: DataFormulatorState) => state.displayRowsTick);
126 // Read the thumbnails map via a ref so we can check current values inside
127 // the effect without adding the map to the dep list (the dispatch we
128 // issue below mutates it, and including it would re-enter the effect).
129 const chartThumbnailsRef = useRef<Record<string, string>>({});
130 chartThumbnailsRef.current = useSelector((state: DataFormulatorState) => state.chartThumbnails) || {};
131
132 // Track which charts are currently being rendered to avoid duplicates
133 const renderingRef = useRef<Set<string>>(new Set());
134
135 // Track previous chart count for cleanup
136 const prevChartIdsRef = useRef<Set<string>>(new Set());
137
138 const processChart = useCallback(async (job: RenderJob) => {
139 const { chart, table, conceptShelfItems: items, cacheKey } = job;
140
141 // Skip if already rendering this chart
142 if (renderingRef.current.has(chart.id)) return;
143 renderingRef.current.add(chart.id);
144
145 try {
146 // --- Prepare data (mirror MemoizedChartObject's pipeline) ---
147 // Prefer the same sample VisualizationView fetched for the
148 // focused canvas — for virtual tables `table.rows` is only a
149 // small preview slice, so rendering from it produces a
150 // thumbnail that doesn't match the main chart. The canvas
151 // populates `displayRowsCache` with up to 1000 server-sampled
152 // rows; reuse that when present.
153 const dispKey = computeDisplayRowsCacheKey(table, chart, items);
154 const cachedDisplay = displayRowsCache.get(dispKey);
155 let visTableRows: any[] = cachedDisplay
156 ? structuredClone(cachedDisplay.rows)
157 : structuredClone(table.rows);
158
159 // Pre-aggregate for the encoding map
160 visTableRows = prepVisTable(visTableRows, items, chart.encodingMap);
161
162 // --- Resolve the spec to render ---
163 // If a style variant is active, render its stored Vega-Lite spec so
164 // the thumbnail matches what the user sees in the focused canvas.
165 // Otherwise assemble the default spec from the encoding map.
166 // (See design-docs/28-chart-style-refinement-agent.md.)
167 const activeVariant = chart.activeVariantId
168 ? chart.styleVariants?.find(v => v.id === chart.activeVariantId)
169 : undefined;
170
171 let fullSpec: any;
172 if (activeVariant) {

Callers

nothing calls this directly

Calls 15

prepVisTableFunction · 0.90
assembleVegaChartFunction · 0.90
setCachedChartFunction · 0.90
invalidateChartFunction · 0.90
getDataTableFunction · 0.90
checkChartAvailabilityFunction · 0.90
computeCacheKeyFunction · 0.90
getCachedChartFunction · 0.90
renderHeadlessFunction · 0.85
scalePngDownFunction · 0.85

Tested by

no test coverage detected