diff --git a/src/app.tsx b/src/app.tsx index 3e684b7..d67a534 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -224,6 +224,8 @@ export function App() { const [data, setData] = useState(); /** Selected individual. */ const [selection, setSelection] = useState(); + /** Selected individual which should be displayed in the details pane. */ + const [detailIndi, setDetailIndi] = useState(); /** Error to display. */ const [error, setError] = useState(); /** Whether the side panel is shown. */ @@ -257,6 +259,7 @@ export function App() { selection!.generation !== newSelection.generation ) { setSelection(newSelection); + setDetailIndi(newSelection.id); } } @@ -380,6 +383,7 @@ export function App() { // Set state from URL parameters. setSourceSpec(args.sourceSpec); setSelection(args.selection); + setDetailIndi(args.selection?.id); setStandalone(args.standalone); setShowWikiTreeMenus(args.showWikiTreeMenus); setChartType(args.chartType); @@ -414,6 +418,7 @@ export function App() { const newSelection = getSelection(data.chartData, args.selection); setData(data); setSelection(newSelection); + setDetailIndi(newSelection.id); setState(AppState.SHOWING_CHART); } catch (error: any) { setState(AppState.SHOWING_CHART); @@ -456,6 +461,13 @@ export function App() { gen: selection.generation, }); } + /** + * Called when the user shift+clicks an individual box in the chart. + * Shows the individual in the details pane. + */ + function onDetailSelection(selection: IndiInfo) { + setDetailIndi(selection.id); + } function onPrint() { analyticsEvent('print'); @@ -524,6 +536,7 @@ export function App() { selection={selection} chartType={chartType} onSelection={onSelection} + onDetailSelection={onDetailSelection} freezeAnimation={freezeAnimation} colors={config.color} hideIds={config.id} @@ -550,7 +563,7 @@ export function App() { void; + onDetailSelection: (indiInfo: IndiInfo) => void; freezeAnimation?: boolean; colors?: ChartColors; hideIds?: Ids; @@ -370,7 +371,16 @@ class ChartWrapper { chartType: getChartType(props.chartType), renderer: getRendererType(props.chartType), svgSelector: '#chart', - indiCallback: (info) => props.onSelection(info), + indiCallback: (info) => { // ths is called when an individual is selected in the chart + if (info.modifiers?.shiftKey) { + // If the shift key is pressed, we just update the details tab without changing the selection in the chart. + // This allows users to quickly view details of multiple individuals without losing their place in the chart. + props.onDetailSelection(info) + } else { + // If the shift key is not pressed, we update the selection in the chart as usual. + props.onSelection(info) + } + }, colors: chartColors.get(props.colors!), animate: true, updateSvgSize: false, @@ -474,7 +484,11 @@ export function Chart(props: ChartProps) { const resetPosition = props.chartType !== prevProps?.chartType || props.data !== prevProps.data || - props.selection !== prevProps.selection; + // This does not work as the objects are always different instances. + //props.selection !== prevProps.selection; + // Therefore, compare id and generation instead. + props.selection.id !== prevProps.selection.id || + props.selection.generation !== prevProps.selection.generation; chartWrapper.current.renderChart(props, intl, { initialRender, resetPosition,