@@ -694,6 +694,36 @@ const WebGLFeatureComponent = observer(function WebGLFeatureComponent({
694694
695695 const overlays : React . ReactElement [ ] = [ ]
696696
697+ // Compute the screen rect for a feature, expanded to include label area
698+ const getFeatureRect = (
699+ featureId : string ,
700+ vr : VisibleRegion ,
701+ data : WebGLFeatureDataResult ,
702+ ) => {
703+ const feature = data . flatbushItems . find ( f => f . featureId === featureId )
704+ if ( ! feature || feature . endBp < vr . start || feature . startBp > vr . end ) {
705+ return null
706+ }
707+ const blockBpPerPx =
708+ ( vr . end - vr . start ) / ( vr . screenEndPx - vr . screenStartPx )
709+ const leftPx =
710+ vr . screenStartPx + ( feature . startBp - vr . start ) / blockBpPerPx
711+ let rightPx =
712+ vr . screenStartPx + ( feature . endBp - vr . start ) / blockBpPerPx
713+ const labelData = data . floatingLabelsData [ featureId ]
714+ if ( labelData ) {
715+ for ( const label of labelData . floatingLabels ) {
716+ rightPx = Math . max ( rightPx , leftPx + measureText ( label . text , 11 ) )
717+ }
718+ }
719+ return {
720+ leftPx,
721+ width : rightPx - leftPx ,
722+ topPx : feature . topPx - scrollY ,
723+ heightPx : feature . bottomPx - feature . topPx ,
724+ }
725+ }
726+
697727 const addFeatureOverlay = (
698728 featureId : string ,
699729 color : string ,
@@ -704,44 +734,19 @@ const WebGLFeatureComponent = observer(function WebGLFeatureComponent({
704734 if ( ! data ) {
705735 continue
706736 }
707- const feature = data . flatbushItems . find ( f => f . featureId === featureId )
708- if ( ! feature ) {
737+ const rect = getFeatureRect ( featureId , vr , data )
738+ if ( ! rect ) {
709739 continue
710740 }
711-
712- if ( feature . endBp < vr . start || feature . startBp > vr . end ) {
713- continue
714- }
715-
716- const blockBpPerPx =
717- ( vr . end - vr . start ) / ( vr . screenEndPx - vr . screenStartPx )
718- const leftPx =
719- vr . screenStartPx + ( feature . startBp - vr . start ) / blockBpPerPx
720- let rightPx =
721- vr . screenStartPx + ( feature . endBp - vr . start ) / blockBpPerPx
722-
723- // Expand to include label area
724- const labelData = data . floatingLabelsData [ featureId ]
725- if ( labelData ) {
726- for ( const label of labelData . floatingLabels ) {
727- const labelWidth = measureText ( label . text , 11 )
728- rightPx = Math . max ( rightPx , leftPx + labelWidth )
729- }
730- }
731-
732- const featureWidth = rightPx - leftPx
733- const topPx = feature . topPx - scrollY
734- const heightPx = feature . bottomPx - feature . topPx
735-
736741 overlays . push (
737742 < div
738743 key = { `${ key } -${ vr . regionNumber } ` }
739744 style = { {
740745 position : 'absolute' ,
741- left : leftPx ,
742- top : topPx ,
743- width : featureWidth ,
744- height : heightPx ,
746+ left : rect . leftPx ,
747+ top : rect . topPx ,
748+ width : rect . width ,
749+ height : rect . heightPx ,
745750 backgroundColor : color ,
746751 pointerEvents : 'none' ,
747752 } }
@@ -759,26 +764,21 @@ const WebGLFeatureComponent = observer(function WebGLFeatureComponent({
759764 if ( subfeature . endBp < vr . start || subfeature . startBp > vr . end ) {
760765 continue
761766 }
762-
763767 const blockBpPerPx =
764768 ( vr . end - vr . start ) / ( vr . screenEndPx - vr . screenStartPx )
765769 const leftPx =
766770 vr . screenStartPx + ( subfeature . startBp - vr . start ) / blockBpPerPx
767771 const rightPx =
768772 vr . screenStartPx + ( subfeature . endBp - vr . start ) / blockBpPerPx
769- const featureWidth = rightPx - leftPx
770- const topPx = subfeature . topPx - scrollY
771- const heightPx = subfeature . bottomPx - subfeature . topPx
772-
773773 overlays . push (
774774 < div
775775 key = { `${ key } -${ vr . regionNumber } ` }
776776 style = { {
777777 position : 'absolute' ,
778778 left : leftPx ,
779- top : topPx ,
780- width : featureWidth ,
781- height : heightPx ,
779+ top : subfeature . topPx - scrollY ,
780+ width : rightPx - leftPx ,
781+ height : subfeature . bottomPx - subfeature . topPx ,
782782 backgroundColor : color ,
783783 pointerEvents : 'none' ,
784784 } }
@@ -798,56 +798,67 @@ const WebGLFeatureComponent = observer(function WebGLFeatureComponent({
798798 }
799799
800800 if ( model . selectedFeatureId ) {
801+ const selId = model . selectedFeatureId
802+ let found = false
801803 for ( const vr of visibleRegions ) {
802804 const data = rpcDataMap . get ( vr . regionNumber )
803805 if ( ! data ) {
804806 continue
805807 }
806- const feature = data . flatbushItems . find (
807- f => f . featureId === model . selectedFeatureId ,
808- )
809- if ( ! feature ) {
810- continue
811- }
812- if ( feature . endBp < vr . start || feature . startBp > vr . end ) {
813- continue
808+ const rect = getFeatureRect ( selId , vr , data )
809+ if ( rect ) {
810+ found = true
811+ overlays . push (
812+ < div
813+ key = { `selected-${ vr . regionNumber } ` }
814+ style = { {
815+ position : 'absolute' ,
816+ left : rect . leftPx - 2 ,
817+ top : rect . topPx - 2 ,
818+ width : rect . width + 4 ,
819+ height : rect . heightPx + 4 ,
820+ border : '2px solid rgba(0, 100, 255, 0.8)' ,
821+ borderRadius : 3 ,
822+ pointerEvents : 'none' ,
823+ } }
824+ /> ,
825+ )
814826 }
815-
816- const blockBpPerPx =
817- ( vr . end - vr . start ) / ( vr . screenEndPx - vr . screenStartPx )
818- const leftPx =
819- vr . screenStartPx + ( feature . startBp - vr . start ) / blockBpPerPx
820- let rightPx =
821- vr . screenStartPx + ( feature . endBp - vr . start ) / blockBpPerPx
822-
823- // Expand to include label area
824- const selLabelData = data . floatingLabelsData [ model . selectedFeatureId ]
825- if ( selLabelData ) {
826- for ( const label of selLabelData . floatingLabels ) {
827- const labelWidth = measureText ( label . text , 11 )
828- rightPx = Math . max ( rightPx , leftPx + labelWidth )
827+ }
828+ if ( ! found ) {
829+ for ( const vr of visibleRegions ) {
830+ const data = rpcDataMap . get ( vr . regionNumber )
831+ if ( ! data ) {
832+ continue
833+ }
834+ const sub = data . subfeatureInfos . find (
835+ s => s . featureId === selId ,
836+ )
837+ if ( sub && sub . endBp >= vr . start && sub . startBp <= vr . end ) {
838+ const blockBpPerPx =
839+ ( vr . end - vr . start ) / ( vr . screenEndPx - vr . screenStartPx )
840+ const leftPx =
841+ vr . screenStartPx + ( sub . startBp - vr . start ) / blockBpPerPx
842+ const rightPx =
843+ vr . screenStartPx + ( sub . endBp - vr . start ) / blockBpPerPx
844+ overlays . push (
845+ < div
846+ key = { `selected-${ vr . regionNumber } ` }
847+ style = { {
848+ position : 'absolute' ,
849+ left : leftPx - 2 ,
850+ top : sub . topPx - scrollY - 2 ,
851+ width : rightPx - leftPx + 4 ,
852+ height : sub . bottomPx - sub . topPx + 4 ,
853+ border : '2px solid rgba(0, 100, 255, 0.8)' ,
854+ borderRadius : 3 ,
855+ pointerEvents : 'none' ,
856+ } }
857+ /> ,
858+ )
859+ break
829860 }
830861 }
831-
832- const featureWidth = rightPx - leftPx
833- const topPx = feature . topPx - scrollY
834- const heightPx = feature . bottomPx - feature . topPx
835-
836- overlays . push (
837- < div
838- key = { `selected-${ vr . regionNumber } ` }
839- style = { {
840- position : 'absolute' ,
841- left : leftPx - 2 ,
842- top : topPx - 2 ,
843- width : featureWidth + 4 ,
844- height : heightPx + 4 ,
845- border : '2px solid rgba(0, 100, 255, 0.8)' ,
846- borderRadius : 3 ,
847- pointerEvents : 'none' ,
848- } }
849- /> ,
850- )
851862 }
852863 }
853864
0 commit comments