@@ -1170,64 +1170,37 @@ export class VirtualizedViewManager {
1170
1170
span_space : [ number , number ] ,
1171
1171
text : string
1172
1172
) : [ number , number ] {
1173
- const text_left = span_space [ 0 ] > this . to_origin + this . trace_space . width * 0.8 ;
1174
- const width = this . text_measurer . measure ( text ) ;
1175
-
1176
- const has_profiles = node && node . profiles . length > 0 ;
1177
- const has_error_icons =
1178
- node &&
1179
- ( node . profiles . length > 0 ||
1180
- node . errors . size > 0 ||
1181
- node . performance_issues . size > 0 ) ;
1173
+ const TEXT_PADDING = 2 ;
1182
1174
1183
- const has_icons = has_profiles || has_error_icons ;
1175
+ const icon_width_config_space = ( 18 * this . span_to_px [ 0 ] ) / 2 ;
1176
+ const text_anchor_left =
1177
+ span_space [ 0 ] > this . to_origin + this . trace_space . width * 0.8 ;
1178
+ const text_width = this . text_measurer . measure ( text ) ;
1184
1179
1185
- const node_width = span_space [ 1 ] / this . span_to_px [ 0 ] ;
1186
- const TEXT_PADDING = 2 ;
1187
- // This is inaccurate in the case of left anchored text. In order to determine a true overlap, we would need to compute
1188
- // the distance between the min timestamp of an icon and beginning of the span. Once we determine the distance, we can compute
1189
- // the width and see if there is an actual overlap. Since this is a rare case which only happens in the case where we anchor the text
1190
- // to the left (20% of the time) and the node may have many errors, this could be computationally expensive to do on every frame.
1191
- // We'll live with the inaccuracy for now as it is purely visual and just make sure to handle a single error case as it will be easy
1192
- // to determine if there is an overlap.
1193
- const TEXT_PADDING_LEFT = text_left && has_icons ? 10 : TEXT_PADDING ;
1194
-
1195
- const TEXT_PADDING_RIGHT =
1196
- ! text_left && has_icons
1197
- ? node_width < 10
1198
- ? // If the node is too small, we need to make sure the text is anchored to the right edge of the icon.
1199
- // We take the distance from the right edge of the node to the right edge of the icon and subtract it from
1200
- // the base width (10) and the base padding when (expanded) to get the correct padding. If we take only 10px
1201
- // as our padding, the text can be anchored directly to the right edge of our icon - we want to preserve
1202
- // a min padding of 2px.
1203
- 12 - node_width
1204
- : TEXT_PADDING
1205
- : TEXT_PADDING ;
1180
+ const timestamps = getIconTimestamps ( node , span_space , icon_width_config_space ) ;
1181
+ const text_left = Math . min ( span_space [ 0 ] , timestamps [ 0 ] ) ;
1182
+ const text_right = Math . max ( span_space [ 0 ] + span_space [ 1 ] , timestamps [ 1 ] ) ;
1206
1183
1207
1184
// precompute all anchor points aot, so we make the control flow more readable.
1208
- // this wastes some cycles, but it's not a big deal as computers go brrrr when it comes to simple arithmetic.
1209
1185
/// |---| text
1210
- const right_outside =
1211
- this . computeTransformXFromTimestamp ( span_space [ 0 ] + span_space [ 1 ] ) +
1212
- TEXT_PADDING_RIGHT ;
1213
- /// text |---|
1214
- const left_outside =
1215
- this . computeTransformXFromTimestamp ( span_space [ 0 ] ) - TEXT_PADDING_LEFT - width ;
1216
-
1217
- // | text|
1186
+ const right_outside = this . computeTransformXFromTimestamp ( text_right ) + TEXT_PADDING ;
1187
+ // |---text|
1218
1188
const right_inside =
1219
1189
this . computeTransformXFromTimestamp ( span_space [ 0 ] + span_space [ 1 ] ) -
1220
- width -
1190
+ text_width -
1221
1191
TEXT_PADDING ;
1222
- // |text |
1192
+ // |text--- |
1223
1193
const left_inside = this . computeTransformXFromTimestamp ( span_space [ 0 ] ) + TEXT_PADDING ;
1194
+ /// text |---|
1195
+ const left_outside =
1196
+ this . computeTransformXFromTimestamp ( text_left ) - TEXT_PADDING - text_width ;
1224
1197
1225
1198
// Right edge of the window (when span extends beyond the view)
1226
1199
const window_right =
1227
1200
this . computeTransformXFromTimestamp (
1228
1201
this . to_origin + this . trace_view . left + this . trace_view . width
1229
1202
) -
1230
- width -
1203
+ text_width -
1231
1204
TEXT_PADDING ;
1232
1205
const window_left =
1233
1206
this . computeTransformXFromTimestamp ( this . to_origin + this . trace_view . left ) +
@@ -1244,22 +1217,22 @@ export class VirtualizedViewManager {
1244
1217
1245
1218
// Span is completely outside of the view on the left side
1246
1219
if ( span_right < this . trace_view . x ) {
1247
- return text_left ? [ 1 , right_inside ] : [ 0 , right_outside ] ;
1220
+ return text_anchor_left ? [ 1 , right_inside ] : [ 0 , right_outside ] ;
1248
1221
}
1249
1222
1250
1223
// Span is completely outside of the view on the right side
1251
1224
if ( span_left > this . trace_view . right ) {
1252
- return text_left ? [ 0 , left_outside ] : [ 1 , left_inside ] ;
1225
+ return text_anchor_left ? [ 0 , left_outside ] : [ 1 , left_inside ] ;
1253
1226
}
1254
1227
1255
1228
// Span "spans" the entire view
1256
1229
if ( span_left <= this . trace_view . x && span_right >= this . trace_view . right ) {
1257
- return text_left ? [ 1 , window_left ] : [ 1 , window_right ] ;
1230
+ return text_anchor_left ? [ 1 , window_left ] : [ 1 , window_right ] ;
1258
1231
}
1259
1232
1260
1233
const full_span_px_width = span_space [ 1 ] / this . span_to_px [ 0 ] ;
1261
1234
1262
- if ( text_left ) {
1235
+ if ( text_anchor_left ) {
1263
1236
// While we have space on the left, place the text there
1264
1237
if ( space_left > 0 ) {
1265
1238
return [ 0 , left_outside ] ;
@@ -1270,7 +1243,7 @@ export class VirtualizedViewManager {
1270
1243
1271
1244
// If the text fits inside the visible portion of the span, anchor it to the left
1272
1245
// side of the window so that it is visible while the user pans the view
1273
- if ( visible_width - TEXT_PADDING >= width ) {
1246
+ if ( visible_width - TEXT_PADDING >= text_width ) {
1274
1247
return [ 1 , window_left ] ;
1275
1248
}
1276
1249
@@ -1292,22 +1265,22 @@ export class VirtualizedViewManager {
1292
1265
// origin and check if it fits into the distance of space right edge - span right edge. In practice
1293
1266
// however, it seems that a magical number works just fine.
1294
1267
span_right > this . trace_space . right * 0.9 &&
1295
- space_right / this . span_to_px [ 0 ] < width
1268
+ space_right / this . span_to_px [ 0 ] < text_width
1296
1269
) {
1297
1270
return [ 1 , right_inside ] ;
1298
1271
}
1299
1272
return [ 0 , right_outside ] ;
1300
1273
}
1301
1274
1302
1275
// If text fits inside the span
1303
- if ( full_span_px_width > width ) {
1276
+ if ( full_span_px_width > text_width ) {
1304
1277
const distance = span_right - this . trace_view . right ;
1305
1278
const visible_width =
1306
1279
( span_space [ 1 ] - distance ) / this . span_to_px [ 0 ] - TEXT_PADDING ;
1307
1280
1308
1281
// If the text fits inside the visible portion of the span, anchor it to the right
1309
1282
// side of the window so that it is visible while the user pans the view
1310
- if ( visible_width - TEXT_PADDING >= width ) {
1283
+ if ( visible_width - TEXT_PADDING >= text_width ) {
1311
1284
return [ 1 , window_right ] ;
1312
1285
}
1313
1286
@@ -1704,6 +1677,50 @@ export class VirtualizedViewManager {
1704
1677
}
1705
1678
}
1706
1679
1680
+ // Computes a min and max icon timestamp. This effectively extends or reduces the hitbox
1681
+ // of the span to include the icon. We need this because when the icon is close to the edge
1682
+ // it can extend it and cause overlaps with duration labels
1683
+ function getIconTimestamps (
1684
+ node : TraceTreeNode < any > ,
1685
+ span_space : [ number , number ] ,
1686
+ icon_width : number
1687
+ ) {
1688
+ let min_icon_timestamp = span_space [ 0 ] ;
1689
+ let max_icon_timestamp = span_space [ 0 ] + span_space [ 1 ] ;
1690
+
1691
+ if ( ! node . errors . size && ! node . performance_issues . size ) {
1692
+ return [ min_icon_timestamp , max_icon_timestamp ] ;
1693
+ }
1694
+
1695
+ for ( const issue of node . performance_issues ) {
1696
+ // Perf issues render icons at the start timestamp
1697
+ if ( typeof issue . start === 'number' ) {
1698
+ min_icon_timestamp = Math . min ( min_icon_timestamp , issue . start * 1e3 - icon_width ) ;
1699
+ max_icon_timestamp = Math . max ( max_icon_timestamp , issue . start * 1e3 + icon_width ) ;
1700
+ }
1701
+ }
1702
+
1703
+ for ( const err of node . errors ) {
1704
+ if ( typeof err . timestamp === 'number' ) {
1705
+ min_icon_timestamp = Math . min ( min_icon_timestamp , err . timestamp * 1e3 - icon_width ) ;
1706
+ max_icon_timestamp = Math . max ( max_icon_timestamp , err . timestamp * 1e3 + icon_width ) ;
1707
+ }
1708
+ }
1709
+
1710
+ min_icon_timestamp = clamp (
1711
+ min_icon_timestamp ,
1712
+ span_space [ 0 ] - icon_width ,
1713
+ span_space [ 0 ] + span_space [ 1 ] + icon_width
1714
+ ) ;
1715
+ max_icon_timestamp = clamp (
1716
+ max_icon_timestamp ,
1717
+ span_space [ 0 ] - icon_width ,
1718
+ span_space [ 0 ] + span_space [ 1 ] + icon_width
1719
+ ) ;
1720
+
1721
+ return [ min_icon_timestamp , max_icon_timestamp ] ;
1722
+ }
1723
+
1707
1724
// Jest does not implement scroll updates, however since we have the
1708
1725
// middleware to handle scroll updates, we can dispatch a scroll event ourselves
1709
1726
function dispatchJestScrollUpdate ( container : HTMLElement ) {
0 commit comments