@@ -876,12 +876,14 @@ export function ResultSet() {
876876 rsu . current . setLoaderText = setLoaderText ;
877877
878878 const isDataChangedRef = useRef ( false ) ;
879- const prevRowsRef = React . useRef ( null ) ;
880- const prevColumnsRef = React . useRef ( null ) ;
881- const gvClearedForColumnsRef = useRef ( null ) ;
882879 const lastGvSelectionRef = useRef ( {
883- type : 'all' , // 'all' | 'rows' | 'columns'
884- selectedColumns : new Set ( ) ,
880+ type : 'all' , // 'all' | 'rows' | 'columns' | 'range' | 'cell'
881+ geometryColumnKey : null ,
882+ rowIndices : [ ] ,
883+ columnIndices : new Set ( ) ,
884+ rangeStartIdx : null ,
885+ rangeEndIdx : null ,
886+ cellIdx : null ,
885887 } ) ;
886888
887889 useEffect ( ( ) => {
@@ -1468,86 +1470,99 @@ export function ResultSet() {
14681470 return ( ) => eventBus . deregisterListener ( QUERY_TOOL_EVENTS . TRIGGER_ADD_ROWS , triggerAddRows ) ;
14691471 } , [ columns , selectedRows . size ] ) ;
14701472
1471- const getFilteredRowsForGeometryViewer = React . useCallback ( ( useLastGvSelection = false ) => {
1472- let selRowsData = rows ;
1473- if ( selectedRows . size != 0 ) {
1474- selRowsData = rows . filter ( ( r ) => selectedRows . has ( rowKeyGetter ( r ) ) ) ;
1475- } else if ( selectedColumns . size > 0 ) {
1476- let selectedCols = _ . filter ( columns , ( _c , i ) => selectedColumns . has ( i + 1 ) ) ;
1477- selRowsData = _ . map ( rows , ( r ) => _ . pick ( r , _ . map ( selectedCols , ( c ) => c . key ) ) ) ;
1478- } else if ( useLastGvSelection && lastGvSelectionRef . current . type === 'columns'
1479- && lastGvSelectionRef . current . selectedColumns . size > 0 ) {
1480- let selectedCols = _ . filter ( columns , ( _c , i ) => lastGvSelectionRef . current . selectedColumns . has ( i + 1 ) ) ;
1481- if ( selectedCols . length > 0 ) {
1482- selRowsData = _ . map ( rows , ( r ) => _ . pick ( r , _ . map ( selectedCols , ( c ) => c . key ) ) ) ;
1483- }
1484- } else if ( selectedRange . current ) {
1485- let [ , , startRowIdx , endRowIdx ] = getRangeIndexes ( ) ;
1486- selRowsData = rows . slice ( startRowIdx , endRowIdx + 1 ) ;
1487- } else if ( selectedCell . current ?. [ 0 ] ) {
1488- selRowsData = [ selectedCell . current [ 0 ] ] ;
1489- }
1490- return selRowsData ;
1491- } , [ rows , columns , selectedRows , selectedColumns ] ) ;
1492-
14931473 const openGeometryViewerTab = React . useCallback ( ( column , rowsData ) => {
14941474 layoutDocker . openTab ( {
14951475 id : PANELS . GEOMETRY ,
14961476 title : gettext ( 'Geometry Viewer' ) ,
1497- content : < GeometryViewer rows = { rowsData } columns = { columns } column = { column } /> ,
1477+ content : < GeometryViewer rows = { rowsData } columns = { columns } column = { column } /> ,
14981478 closable : true ,
14991479 } , PANELS . MESSAGES , 'after-tab' , true ) ;
15001480 } , [ layoutDocker , columns ] ) ;
15011481
1502- // Handle manual Geometry Viewer opening
1482+ // Handle manual Geometry Viewer opening.
1483+ // Determines which rows to plot based on the current grid selection (rows, columns,
1484+ // range, or cell) and stores the selection indices in lastGvSelectionRef so the
1485+ // auto-update effect can re-apply the same selection on subsequent query re-runs.
15031486 useEffect ( ( ) => {
15041487 const renderGeometries = ( column ) => {
1505- gvClearedForColumnsRef . current = null ;
1488+ const defaultSel = { geometryColumnKey : column ?. key , rowIndices : [ ] , columnIndices : new Set ( ) , rangeStartIdx : null , rangeEndIdx : null , cellIdx : null } ;
1489+ let selRowsData = rows ;
1490+
15061491 if ( selectedRows . size > 0 ) {
1507- lastGvSelectionRef . current = { type : 'rows' , selectedColumns : new Set ( ) } ;
1492+ // Specific rows selected in the grid — plot only those rows
1493+ const rowIndices = [ ] ;
1494+ rows . forEach ( ( r , i ) => {
1495+ if ( selectedRows . has ( rowKeyGetter ( r ) ) ) {
1496+ rowIndices . push ( i ) ;
1497+ }
1498+ } ) ;
1499+ selRowsData = rowIndices . map ( i => rows [ i ] ) ;
1500+ lastGvSelectionRef . current = { ...defaultSel , type : 'rows' , rowIndices } ;
15081501 } else if ( selectedColumns . size > 0 ) {
1509- lastGvSelectionRef . current = { type : 'columns' , selectedColumns : new Set ( selectedColumns ) } ;
1502+ // Specific columns selected — plot all rows but only with selected column data
1503+ let selectedCols = _ . filter ( columns , ( _c , i ) => selectedColumns . has ( i + 1 ) ) ;
1504+ selRowsData = _ . map ( rows , ( r ) => _ . pick ( r , _ . map ( selectedCols , ( c ) => c . key ) ) ) ;
1505+ lastGvSelectionRef . current = { ...defaultSel , type : 'columns' , columnIndices : new Set ( selectedColumns ) } ;
1506+ } else if ( selectedRange . current ) {
1507+ // Cell range selected — plot the rows within the range
1508+ let [ , , startRowIdx , endRowIdx ] = getRangeIndexes ( ) ;
1509+ selRowsData = rows . slice ( startRowIdx , endRowIdx + 1 ) ;
1510+ lastGvSelectionRef . current = { ...defaultSel , type : 'range' , rangeStartIdx : startRowIdx , rangeEndIdx : endRowIdx } ;
1511+ } else if ( selectedCell . current ?. [ 0 ] ) {
1512+ // Single cell selected — plot only that row
1513+ const cellIdx = rows . indexOf ( selectedCell . current [ 0 ] ) ;
1514+ selRowsData = [ selectedCell . current [ 0 ] ] ;
1515+ lastGvSelectionRef . current = { ...defaultSel , type : 'cell' , cellIdx : cellIdx >= 0 ? cellIdx : null } ;
15101516 } else {
1511- lastGvSelectionRef . current = { type : 'all' , selectedColumns : new Set ( ) } ;
1517+ // No selection — plot all rows
1518+ lastGvSelectionRef . current = { ...defaultSel , type : 'all' } ;
15121519 }
1513- const selRowsData = getFilteredRowsForGeometryViewer ( ) ;
1520+
15141521 openGeometryViewerTab ( column , selRowsData ) ;
15151522 } ;
15161523 eventBus . registerListener ( QUERY_TOOL_EVENTS . TRIGGER_RENDER_GEOMETRIES , renderGeometries ) ;
15171524 return ( ) => eventBus . deregisterListener ( QUERY_TOOL_EVENTS . TRIGGER_RENDER_GEOMETRIES , renderGeometries ) ;
1518- } , [ getFilteredRowsForGeometryViewer , openGeometryViewerTab , eventBus , selectedRows , selectedColumns ] ) ;
1525+ } , [ openGeometryViewerTab , eventBus , rows , columns , selectedRows , selectedColumns ] ) ;
15191526
15201527 // Auto-update Geometry Viewer when rows/columns change
15211528 useEffect ( ( ) => {
1522- const rowsChanged = prevRowsRef . current !== rows ;
1523- const columnsChanged = prevColumnsRef . current !== columns ;
1524- const currentGeometryColumn = columns . find ( col => col . cell === 'geometry' || col . cell === 'geography' ) ;
1525-
1526- if ( ( rowsChanged || columnsChanged ) && layoutDocker . isTabOpen ( PANELS . GEOMETRY ) ) {
1527-
1528- const prevColumnNames = prevColumnsRef . current ?. map ( c => c . key ) . sort ( ) . join ( ',' ) ?? '' ;
1529- const currColumnNames = columns . map ( c => c . key ) . sort ( ) . join ( ',' ) ;
1530- const columnsChanged = prevColumnNames !== currColumnNames ;
1531-
1532- if ( columnsChanged && currentGeometryColumn ) {
1533- gvClearedForColumnsRef . current = currColumnNames ;
1534- lastGvSelectionRef . current = { type : 'all' , selectedColumns : new Set ( ) } ;
1535- openGeometryViewerTab ( null , [ ] ) ;
1536- } else if ( gvClearedForColumnsRef . current === currColumnNames ) {
1537- openGeometryViewerTab ( null , [ ] ) ;
1538- } else if ( currentGeometryColumn && rowsChanged ) {
1539- const useColSelection = lastGvSelectionRef . current . type === 'columns' ;
1540- const selRowsData = getFilteredRowsForGeometryViewer ( useColSelection ) ;
1541- openGeometryViewerTab ( currentGeometryColumn , selRowsData ) ;
1529+ if ( layoutDocker . isTabOpen ( PANELS . GEOMETRY ) ) {
1530+ const lastGeomKey = lastGvSelectionRef . current . geometryColumnKey ;
1531+ const matchedGeomCol = lastGeomKey
1532+ ? columns . find ( c => c . key === lastGeomKey && ( c . cell === 'geometry' || c . cell === 'geography' ) )
1533+ : null ;
1534+
1535+ if ( matchedGeomCol ) {
1536+ // Previously plotted geometry column still exists → re-apply selection and re-render
1537+ const lastSel = lastGvSelectionRef . current ;
1538+ let selRowsData = rows ;
1539+
1540+ if ( lastSel . type === 'rows' && lastSel . rowIndices . length > 0 ) {
1541+ if ( lastSel . rowIndices . every ( idx => idx < rows . length ) ) {
1542+ selRowsData = lastSel . rowIndices . map ( idx => rows [ idx ] ) ;
1543+ }
1544+ } else if ( lastSel . type === 'columns' && lastSel . columnIndices . size > 0 ) {
1545+ let selectedCols = _ . filter ( columns , ( _c , i ) => lastSel . columnIndices . has ( i + 1 ) ) ;
1546+ if ( selectedCols . length > 0 ) {
1547+ selRowsData = _ . map ( rows , ( r ) => _ . pick ( r , _ . map ( selectedCols , ( c ) => c . key ) ) ) ;
1548+ }
1549+ } else if ( lastSel . type === 'range' && lastSel . rangeStartIdx != null ) {
1550+ if ( lastSel . rangeStartIdx < rows . length && lastSel . rangeEndIdx < rows . length ) {
1551+ selRowsData = rows . slice ( lastSel . rangeStartIdx , lastSel . rangeEndIdx + 1 ) ;
1552+ }
1553+ } else if ( lastSel . type === 'cell' && lastSel . cellIdx != null ) {
1554+ if ( lastSel . cellIdx < rows . length ) {
1555+ selRowsData = [ rows [ lastSel . cellIdx ] ] ;
1556+ }
1557+ }
1558+
1559+ openGeometryViewerTab ( matchedGeomCol , selRowsData ) ;
15421560 } else {
1543- // No geometry column
1561+ // Previously plotted geometry column not found → clear GV
15441562 openGeometryViewerTab ( null , [ ] ) ;
15451563 }
15461564 }
1547-
1548- prevRowsRef . current = rows ;
1549- prevColumnsRef . current = columns ;
1550- } , [ rows , columns , getFilteredRowsForGeometryViewer , layoutDocker ] ) ;
1565+ } , [ rows , columns , layoutDocker ] ) ;
15511566
15521567 const triggerResetScroll = ( ) => {
15531568 // Reset the scroll position to previously saved location.
0 commit comments