@@ -43,8 +43,8 @@ export class EntriesLinkOverlay extends HTMLElement {
4343 #connector: SVGLineElement | null = null ;
4444 #entryFromWrapper: HTMLElement | null = null ;
4545 #entryToWrapper: HTMLElement | null = null ;
46- #entryFromConnector : SVGCircleElement | null = null ;
47- #entryToConnector : SVGCircleElement | null = null ;
46+ #entryFromCirleConnector : SVGCircleElement | null = null ;
47+ #entryToCircleConnector : SVGCircleElement | null = null ;
4848 #entryFromVisible = true ;
4949 #entryToVisible = true ;
5050 #canvasRect: DOMRect | null = null ;
@@ -73,8 +73,8 @@ export class EntriesLinkOverlay extends HTMLElement {
7373 this . #connector = this . #connectorLineContainer?. querySelector ( 'line' ) ?? null ;
7474 this . #entryFromWrapper = this . #shadow. querySelector ( '.from-highlight-wrapper' ) ?? null ;
7575 this . #entryToWrapper = this . #shadow. querySelector ( '.to-highlight-wrapper' ) ?? null ;
76- this . #entryFromConnector = this . #connectorLineContainer?. querySelector ( '.entryFromConnector' ) ?? null ;
77- this . #entryToConnector = this . #connectorLineContainer?. querySelector ( '.entryToConnector' ) ?? null ;
76+ this . #entryFromCirleConnector = this . #connectorLineContainer?. querySelector ( '.entryFromConnector' ) ?? null ;
77+ this . #entryToCircleConnector = this . #connectorLineContainer?. querySelector ( '.entryToConnector' ) ?? null ;
7878 this . #linkState = linkCreationNotStartedState ;
7979 this . #render( ) ;
8080 }
@@ -117,13 +117,13 @@ export class EntriesLinkOverlay extends HTMLElement {
117117 this . #coordinateFrom = { x : fromEntryParams . x , y : fromEntryParams . y } ;
118118 this . #fromEntryDimensions = { width : fromEntryParams . length , height : fromEntryParams . height } ;
119119 this . #updateCreateLinkBox( ) ;
120- this . #redrawConnectionArrow ( ) ;
120+ this . #redrawAllEntriesLinkParts ( ) ;
121121 }
122122
123123 set entriesVisibility ( entriesVisibility : { fromEntryVisibility : boolean , toEntryVisibility : boolean } ) {
124124 this . #entryFromVisible = entriesVisibility . fromEntryVisibility ;
125125 this . #entryToVisible = entriesVisibility . toEntryVisibility ;
126- this . #redrawConnectionArrow ( ) ;
126+ this . #redrawAllEntriesLinkParts ( ) ;
127127 }
128128
129129 // The arrow might be pointing either to an entry or an empty space.
@@ -137,7 +137,7 @@ export class EntriesLinkOverlay extends HTMLElement {
137137 }
138138
139139 this . #updateCreateLinkBox( ) ;
140- this . #redrawConnectionArrow ( ) ;
140+ this . #redrawAllEntriesLinkParts ( ) ;
141141 }
142142
143143 set fromEntryIsSource ( x : boolean ) {
@@ -156,97 +156,121 @@ export class EntriesLinkOverlay extends HTMLElement {
156156 this . #render( ) ;
157157 }
158158
159- #redrawConnectionArrow( ) : void {
160- if ( ! this . #connector || ! this . #entryFromWrapper || ! this . #entryToWrapper || ! this . #entryFromConnector ||
161- ! this . #entryToConnector) {
162- console . error ( '`connector` element is missing.' ) ;
159+ /*
160+ Redraw all parts of the EntriesLink overlay
161+ _________
162+ |__entry__|o\ <-- 'from 'entry wrapper and the circle connector next to it
163+ \
164+ \ <-- Arrow Connector
165+ \ ________________
166+ ➘ o|_____entry______| <-- 'to' entry wrapper and the circle connector next to it
167+ */
168+ #redrawAllEntriesLinkParts( ) : void {
169+ if ( ! this . #connector || ! this . #entryFromWrapper || ! this . #entryToWrapper || ! this . #entryFromCirleConnector ||
170+ ! this . #entryToCircleConnector) {
171+ console . error ( 'one of the required Entries Link elements is missing.' ) ;
163172 return ;
164173 }
165174
166175 if ( this . #linkState === Trace . Types . File . EntriesLinkState . CREATION_NOT_STARTED ) {
167- this . #entryFromConnector. setAttribute ( 'visibility' , 'hidden' ) ;
168- this . #entryToConnector. setAttribute ( 'visibility' , 'hidden' ) ;
176+ this . #entryFromCirleConnector. setAttribute ( 'visibility' , 'hidden' ) ;
177+ this . #entryToCircleConnector. setAttribute ( 'visibility' , 'hidden' ) ;
178+ this . #connector. style . display = 'none' ;
169179 return ;
170180 }
171181
182+ this . #setEntriesWrappersVisibility( ) ;
183+ this . #setConnectorCirclesVisibility( ) ;
184+ this . #setArrowConnectorStyle( ) ;
185+ this . #positionConnectorLineAndCircles( ) ;
186+
187+ this . #render( ) ;
188+ }
189+
190+ // Only draw the entry wrapper if that entry is visible
191+ #setEntriesWrappersVisibility( ) : void {
192+ if ( ! this . #entryFromWrapper || ! this . #entryToWrapper) {
193+ return ;
194+ }
195+ this . #entryFromWrapper. style . visibility = this . #entryFromVisible ? 'visible' : 'hidden' ;
196+ this . #entryToWrapper. style . visibility = this . #entryToVisible ? 'visible' : 'hidden' ;
197+ }
198+
199+ // Draw the entry connector circles:
200+ // - The entry the arrow is connecting to is the connection source
201+ // - That entry currently is visible
202+ // - There is enough space for the connector circle
203+ #setConnectorCirclesVisibility( ) : void {
204+ if ( ! this . #toEntryDimensions || ! this . #entryFromCirleConnector || ! this . #entryToCircleConnector) {
205+ return ;
206+ }
172207 // If the user is zoomed out, the connector circles can be as large as the
173208 // event itself. So if the rectangle for this entry is too small, we
174209 // don't draw the circles.
175210 const minWidthToDrawConnectorCircles = 8 ;
176-
177- // We do not draw the connectors if the entry is not visible, or if the
178- // entry we are connecting to isn't the actual source entry.
179- // We also don't draw them if an entry is completely hidden, in which case
180- // we aren't drawing the arrows, so it doesn't make sense to draw the
181- // connectors.
182211 const drawFromEntryConnectorCircle = this . #entryFromVisible && ! this . #arrowHidden && this . #fromEntryIsSource &&
183212 this . #fromEntryDimensions. width >= minWidthToDrawConnectorCircles ;
184-
185- const widthOfToEntry = this . #toEntryDimensions?. width ?? 0 ;
186213 const drawToEntryConnectorCircle = ! this . #arrowHidden && this . #entryToVisible && this . #toEntryIsSource &&
187- widthOfToEntry >= minWidthToDrawConnectorCircles && ! this . #arrowHidden;
214+ this . #toEntryDimensions?. width >= minWidthToDrawConnectorCircles && ! this . #arrowHidden;
215+
216+ this . #entryFromCirleConnector. setAttribute ( 'visibility' , drawFromEntryConnectorCircle ? 'visible' : 'hidden' ) ;
217+ this . #entryToCircleConnector. setAttribute ( 'visibility' , drawToEntryConnectorCircle ? 'visible' : 'hidden' ) ;
218+ }
219+
220+ #setArrowConnectorStyle( ) : void {
221+ if ( ! this . #connector) {
222+ return ;
223+ }
224+
225+ // If neither entry is visible, do not display the connector
226+ this . #connector. style . display = ( this . #entryFromVisible || this . #entryToVisible) ? 'block' : 'none' ;
227+ this . #connector. setAttribute ( 'stroke-width' , '2' ) ;
228+
229+ const arrowColor = ThemeSupport . ThemeSupport . instance ( ) . getComputedValue ( '--color-text-primary' ) ;
230+
231+ // Use a solid stroke if the 'to' entry's dimensions are unknown (during link creation) or if both entries are visible.
232+ if ( ! this . #toEntryDimensions || ( this . #entryFromVisible && this . #entryToVisible) ) {
233+ this . #connector. setAttribute ( 'stroke' , arrowColor ) ;
234+ return ;
235+ }
188236
189- this . #entryFromConnector. setAttribute ( 'visibility' , drawFromEntryConnectorCircle ? 'visible' : 'hidden' ) ;
190- this . #entryToConnector. setAttribute ( 'visibility' , drawToEntryConnectorCircle ? 'visible' : 'hidden' ) ;
237+ // If one entry is not visible and one is, fade the arrow.
238+ if ( this . #entryFromVisible && ! this . #entryToVisible) {
239+ this . #connector. setAttribute ( 'stroke' , 'url(#fromVisibleLineGradient)' ) ;
240+ } else if ( this . #entryToVisible && ! this . #entryFromVisible) {
241+ this . #connector. setAttribute ( 'stroke' , 'url(#toVisibleLineGradient)' ) ;
242+ }
243+ }
244+
245+ #positionConnectorLineAndCircles( ) : void {
246+ if ( ! this . #connector || ! this . #entryFromCirleConnector || ! this . #entryToCircleConnector) {
247+ return ;
248+ }
191249
192250 // If the entry is visible, the entry arrow starts from the middle of the right edge of the entry (end on the X axis and middle of the Y axis).
193251 // If not, draw it to the y coordinate of the entry and the edge of the timeline so it is pointing in the direction of the entry.
194252 const halfFromEntryHeight = this . #fromEntryDimensions. height / 2 ;
195- if ( this . #entryFromVisible) {
196- const endConnectionPointX = String ( this . #coordinateFrom. x + this . #fromEntryDimensions. width ) ;
197- const endConnectionPointY = String ( this . #coordinateFrom. y + halfFromEntryHeight ) ;
253+ const fromX = this . #coordinateFrom. x + this . #fromEntryDimensions. width ;
254+ const fromY = this . #coordinateFrom. y + halfFromEntryHeight ;
198255
199- this . #connector. setAttribute ( 'x1' , endConnectionPointX ) ;
200- this . #connector. setAttribute ( 'y1' , endConnectionPointY ) ;
256+ this . #connector. setAttribute ( 'x1' , fromX . toString ( ) ) ;
257+ this . #connector. setAttribute ( 'y1' , fromY . toString ( ) ) ;
201258
202- this . #entryFromConnector. setAttribute ( 'cx' , endConnectionPointX ) ;
203- this . #entryFromConnector. setAttribute ( 'cy' , endConnectionPointY ) ;
204- this . #entryFromWrapper. style . visibility = 'visible' ;
205- } else {
206- this . #connector. setAttribute ( 'x1' , ( this . #coordinateFrom. x + this . #fromEntryDimensions. width ) . toString ( ) ) ;
207- this . #connector. setAttribute ( 'y1' , String ( this . #coordinateFrom. y + halfFromEntryHeight ) ) ;
208- this . #entryFromWrapper. style . visibility = 'hidden' ;
209- }
259+ this . #entryFromCirleConnector. setAttribute ( 'cx' , fromX . toString ( ) ) ;
260+ this . #entryFromCirleConnector. setAttribute ( 'cy' , fromY . toString ( ) ) ;
210261
211262 // If the arrow is pointing to the entry and that entry is visible, point it to the middle of the entry.
212263 // If the entry is not visible, point the arrow to the edge of the screen towards the entry.
213264 // Otherwise, the arrow is following the mouse so we assign it to the provided coordinates.
214- if ( this . #toEntryDimensions && this . #entryToVisible) {
215- const connectionPointX = String ( this . #coordinateTo. x ) ;
216- const connectionPointY = String ( this . #coordinateTo. y + this . #toEntryDimensions. height / 2 ) ;
217-
218- this . #connector. setAttribute ( 'x2' , connectionPointX ) ;
219- this . #connector. setAttribute ( 'y2' , connectionPointY ) ;
265+ const toX = this . #coordinateTo. x ;
266+ const toY = this . #toEntryDimensions ? this . #coordinateTo. y + ( this . #toEntryDimensions?. height ?? 0 ) / 2 :
267+ this . #coordinateTo. y ;
220268
221- this . #entryToConnector . setAttribute ( 'cx ' , connectionPointX ) ;
222- this . #entryToConnector . setAttribute ( 'cy ' , connectionPointY ) ;
269+ this . #connector . setAttribute ( 'x2 ' , toX . toString ( ) ) ;
270+ this . #connector . setAttribute ( 'y2 ' , toY . toString ( ) ) ;
223271
224- this . #entryToWrapper. style . visibility = 'visible' ;
225- } else {
226- this . #entryToWrapper. style . visibility = 'hidden' ;
227- this . #connector. setAttribute ( 'x2' , this . #coordinateTo. x . toString ( ) ) ;
228- // If `toEntryDimensions` exist, the arrow points to the entry and we need to take its height into account.
229- // Otherwise, it is following the mouse.
230- if ( this . #toEntryDimensions) {
231- const halfToEntryHeight = this . #toEntryDimensions. height / 2 ;
232- this . #connector. setAttribute ( 'y2' , String ( this . #coordinateTo. y + halfToEntryHeight ) ) ;
233- } else {
234- this . #connector. setAttribute ( 'y2' , ( this . #coordinateTo. y ) . toString ( ) ) ;
235- }
236- }
237-
238- this . #connector. setAttribute ( 'stroke-width' , '2' ) ;
239-
240- if ( this . #toEntryDimensions && this . #entryFromVisible && ! this . #entryToVisible) {
241- this . #connector. setAttribute ( 'stroke' , 'url(#fromVisibleLineGradient)' ) ;
242- } else if ( this . #toEntryDimensions && this . #entryToVisible && ! this . #entryFromVisible) {
243- this . #connector. setAttribute ( 'stroke' , 'url(#toVisibleLineGradient)' ) ;
244- } else {
245- const arrowColor = ThemeSupport . ThemeSupport . instance ( ) . getComputedValue ( '--color-text-primary' ) ;
246- this . #connector. setAttribute ( 'stroke' , arrowColor ) ;
247- }
248-
249- this . #render( ) ;
272+ this . #entryToCircleConnector. setAttribute ( 'cx' , toX . toString ( ) ) ;
273+ this . #entryToCircleConnector. setAttribute ( 'cy' , toY . toString ( ) ) ;
250274 }
251275
252276 /*
0 commit comments