@@ -45,6 +45,8 @@ export const Timeline: React.FunctionComponent<{
45
45
onHighlighted : ( action : ActionTraceEvent | undefined ) => void ,
46
46
} > = ( { context, boundaries, selectedAction, highlightedAction, onSelected, onHighlighted } ) => {
47
47
const [ measure , ref ] = useMeasure < HTMLDivElement > ( ) ;
48
+ const barsRef = React . useRef < HTMLDivElement | null > ( null ) ;
49
+
48
50
const [ previewPoint , setPreviewPoint ] = React . useState < { x : number , clientY : number } | undefined > ( ) ;
49
51
const [ hoveredBarIndex , setHoveredBarIndex ] = React . useState < number | undefined > ( ) ;
50
52
@@ -58,9 +60,9 @@ export const Timeline: React.FunctionComponent<{
58
60
for ( const entry of page . actions ) {
59
61
if ( ! entry . metadata . params )
60
62
console . log ( entry ) ;
61
- let detail = entry . metadata . params . selector || '' ;
63
+ let detail = trimRight ( entry . metadata . params . selector || '' , 50 ) ;
62
64
if ( entry . metadata . method === 'goto' )
63
- detail = entry . metadata . params . url || '' ;
65
+ detail = trimRight ( entry . metadata . params . url || '' , 50 ) ;
64
66
bars . push ( {
65
67
action : entry ,
66
68
leftTime : entry . metadata . startTime ,
@@ -94,32 +96,41 @@ export const Timeline: React.FunctionComponent<{
94
96
let targetBar : TimelineBar | undefined = bars . find ( bar => bar . action === ( highlightedAction || selectedAction ) ) ;
95
97
targetBar = hoveredBar || targetBar ;
96
98
97
- const findHoveredBarIndex = ( x : number ) => {
99
+ const findHoveredBarIndex = ( x : number , y : number ) => {
98
100
const time = positionToTime ( measure . width , boundaries , x ) ;
99
101
const time1 = positionToTime ( measure . width , boundaries , x - 5 ) ;
100
102
const time2 = positionToTime ( measure . width , boundaries , x + 5 ) ;
101
103
let index : number | undefined ;
102
- let distance : number | undefined ;
104
+ let yDistance : number | undefined ;
105
+ let xDistance : number | undefined ;
103
106
for ( let i = 0 ; i < bars . length ; i ++ ) {
104
107
const bar = bars [ i ] ;
108
+ const yMiddle = kBarHeight / 2 + barTop ( bar ) ;
105
109
const left = Math . max ( bar . leftTime , time1 ) ;
106
110
const right = Math . min ( bar . rightTime , time2 ) ;
107
- const middle = ( bar . leftTime + bar . rightTime ) / 2 ;
108
- const d = Math . abs ( time - middle ) ;
109
- if ( left <= right && ( index === undefined || d < distance ! ) ) {
111
+ const xMiddle = ( bar . leftTime + bar . rightTime ) / 2 ;
112
+ const xd = Math . abs ( time - xMiddle ) ;
113
+ const yd = Math . abs ( y - yMiddle ) ;
114
+ if ( left > right )
115
+ continue ;
116
+ // Prefer closest yDistance (the same bar), among those prefer the closest xDistance.
117
+ if ( index === undefined ||
118
+ ( yd < yDistance ! ) ||
119
+ ( Math . abs ( yd - yDistance ! ) < 1e-2 && xd < xDistance ! ) ) {
110
120
index = i ;
111
- distance = d ;
121
+ xDistance = xd ;
122
+ yDistance = yd ;
112
123
}
113
124
}
114
125
return index ;
115
126
} ;
116
127
117
128
const onMouseMove = ( event : React . MouseEvent ) => {
118
- if ( ! ref . current )
129
+ if ( ! ref . current || ! barsRef . current )
119
130
return ;
120
- const bounds = ref . current . getBoundingClientRect ( ) ;
121
- const x = event . clientX - bounds . left ;
122
- const index = findHoveredBarIndex ( x ) ;
131
+ const x = event . clientX - ref . current . getBoundingClientRect ( ) . left ;
132
+ const y = event . clientY - barsRef . current . getBoundingClientRect ( ) . top ;
133
+ const index = findHoveredBarIndex ( x , y ) ;
123
134
setPreviewPoint ( { x, clientY : event . clientY } ) ;
124
135
setHoveredBarIndex ( index ) ;
125
136
if ( typeof index === 'number' )
@@ -134,10 +145,11 @@ export const Timeline: React.FunctionComponent<{
134
145
135
146
const onClick = ( event : React . MouseEvent ) => {
136
147
setPreviewPoint ( undefined ) ;
137
- if ( ! ref . current )
148
+ if ( ! ref . current || ! barsRef . current )
138
149
return ;
139
150
const x = event . clientX - ref . current . getBoundingClientRect ( ) . left ;
140
- const index = findHoveredBarIndex ( x ) ;
151
+ const y = event . clientY - barsRef . current . getBoundingClientRect ( ) . top ;
152
+ const index = findHoveredBarIndex ( x , y ) ;
141
153
if ( index === undefined )
142
154
return ;
143
155
const entry = bars [ index ] . action ;
@@ -166,13 +178,14 @@ export const Timeline: React.FunctionComponent<{
166
178
</ div > ;
167
179
} )
168
180
} </ div >
169
- < div className = 'timeline-lane timeline-bars' > {
181
+ < div className = 'timeline-lane timeline-bars' ref = { barsRef } > {
170
182
bars . map ( ( bar , index ) => {
171
183
return < div key = { index }
172
184
className = { 'timeline-bar ' + ( bar . action ? 'action ' : '' ) + ( bar . event ? 'event ' : '' ) + bar . className + ( targetBar === bar ? ' selected' : '' ) }
173
185
style = { {
174
186
left : bar . leftPosition + 'px' ,
175
187
width : Math . max ( 1 , bar . rightPosition - bar . leftPosition ) + 'px' ,
188
+ top : barTop ( bar ) + 'px' ,
176
189
} }
177
190
> </ div > ;
178
191
} )
@@ -222,3 +235,12 @@ function timeToPosition(clientWidth: number, boundaries: Boundaries, time: numbe
222
235
function positionToTime ( clientWidth : number , boundaries : Boundaries , x : number ) : number {
223
236
return x / clientWidth * ( boundaries . maximum - boundaries . minimum ) + boundaries . minimum ;
224
237
}
238
+
239
+ function trimRight ( s : string , maxLength : number ) : string {
240
+ return s . length <= maxLength ? s : s . substring ( 0 , maxLength - 1 ) + '\u2026' ;
241
+ }
242
+
243
+ const kBarHeight = 11 ;
244
+ function barTop ( bar : TimelineBar ) : number {
245
+ return bar . event ? 22 : ( bar . action ?. metadata . method === 'waitForEventInfo' ? 0 : 11 ) ;
246
+ }
0 commit comments