import React, { useMemo } from "react"; import { useCurrentFrame, useVideoConfig, interpolate } from "remotion"; import type { CashFlowData } from "./CashFlowChart"; import { CashFlowChart } from "./CashFlowChart"; import { LifePlanChart } from "./LifePlanChart"; import type { YearlySnapshot } from "./types"; import { UnifiedHUD } from "./UnifiedHUD"; interface DualChartViewProps { absoluteFrame?: number; chartStartFrame?: number; chartEndFrame?: number; cashflowData?: { timeline: Array< CashFlowData & { totalExpense: number; netCashFlow: number; assetBalance: number; } >; meta: { currencyUnit: string; }; }; } export const DualChartView: React.FC = ({ absoluteFrame, chartStartFrame, chartEndFrame, cashflowData = { timeline: [], meta: { currencyUnit: "万円" } }, }) => { const frame = useCurrentFrame(); const { fps } = useVideoConfig(); // durationInFrames removed since we use chartEndFrame // Use absolute frame if provided to maintain animation continuity across segments const currentFrame = absoluteFrame !== undefined ? absoluteFrame : frame; // --- Unified Animation Logic (Both charts sync) --- // Animation should start at chartStartFrame and end at chartEndFrame const start = chartStartFrame !== undefined ? chartStartFrame : 0; // Fallback to absolute video end if no specific end frame provided const end = chartEndFrame !== undefined ? chartEndFrame : 300 * fps; const exactProgress = interpolate( currentFrame, [start, end], [0, cashflowData.timeline.length - 1], { extrapolateRight: "clamp", extrapolateLeft: "clamp" }, ); const dataEndIndex = Math.floor(exactProgress); const yearProgress = exactProgress - dataEndIndex; // Current data for HUD const currentData = cashflowData.timeline[dataEndIndex] || cashflowData.timeline[0]; // --- Convert cashflow data to LifePlanChart format --- // useMemo prevents re-creating this array every frame, which causes chart flickering const lifePlanTimeline: YearlySnapshot[] = useMemo( () => cashflowData.timeline.map((item) => ({ year: item.year, ages: { rep: item.age, spouse: undefined, // No spouse data in cashflow }, financials: { income: item.income.total, expenditure: item.totalExpense, assetBalance: item.assetBalance, }, events: [], isCritical: item.assetBalance < 0, })), [cashflowData.timeline], ); // Memoize meta object to prevent re-creating it every frame const lifePlanMeta = useMemo( () => ({ currencyUnit: cashflowData.meta.currencyUnit, startYear: cashflowData.timeline[0].year, }), [cashflowData.meta.currencyUnit, cashflowData.timeline], ); return (
{/* --- Upper Chart: LifePlan (Asset Balance Trend) --- */}

資産残高推移

{/* --- Lower Chart: CashFlow (Income vs Expenses) --- */}

収支明細

); };