@@ -146,7 +146,6 @@ function graphplot_card(app, session)
146
146
Stress (; pin)
147
147
end
148
148
149
- small_hover_text = Observable {String} (" " )
150
149
fig, ax = with_theme (apptheme ()) do
151
150
fig = Figure (; figure_padding= 0 )
152
151
ax = Axis (fig[1 ,1 ])
@@ -156,11 +155,6 @@ function graphplot_card(app, session)
156
155
157
156
hidespines! (ax)
158
157
hidedecorations! (ax)
159
-
160
- fig[1 ,1 ] = Label (fig, small_hover_text,
161
- tellwidth= false , tellheight= false ,
162
- justification= :left , halign= :left , valign= :bottom )
163
-
164
158
fig, ax
165
159
end
166
160
xratio = Ref {Float64} (1.0 )
@@ -174,33 +168,65 @@ function graphplot_card(app, session)
174
168
# ###
175
169
# ### Interactions
176
170
# ###
177
- hoverstate = Observable ( false )
171
+ tooltip_text = Observable {String} ( " " )
178
172
179
173
js = js """
180
174
const gpcard = document .querySelector (" .graphplot-card" );
181
- $ (hoverstate).on ((state ) => {
182
- if (state) {
175
+
176
+ // Create tooltip element
177
+ const tooltip = document .createElement (" div" );
178
+ tooltip .classList .add (" tooltip" ); // Apply styles from CSS
179
+ document .body .appendChild (tooltip);
180
+
181
+ // let tooltipTimeout; // Store timeout reference
182
+ let latestX = 0 , latestY = 0 ; // Store latest cursor position
183
+ let isUpdating = false ;
184
+
185
+ gpcard .addEventListener (" mousemove" , (event ) => {
186
+ latestX = event .clientX ;
187
+ latestY = event .clientY ;
188
+
189
+ if (! isUpdating && tooltip .style .display === " block" ) {
190
+ isUpdating = true ;
191
+ requestAnimationFrame (() => {
192
+ tooltip .style .left = ` ${ latestX} px` ;
193
+ tooltip .style .top = ` ${ latestY} px` ;
194
+ isUpdating = false ;
195
+ });
196
+ }
197
+ });
198
+
199
+ // Show tooltip after delay when idx > 0
200
+ $ (tooltip_text).on ((text ) => {
201
+ // clearTimeout(tooltipTimeout); // Prevent multiple pending tooltips
202
+
203
+ if (text .length > 0 ) {
183
204
gpcard .style .cursor = " pointer" ;
205
+
206
+ // tooltipTimeout = setTimeout(() => { // Delay tooltip display
207
+ tooltip .textContent = text;
208
+ tooltip .style .display = " block" ;
209
+ tooltip .style .left = ` ${ latestX} px` ;
210
+ tooltip .style .top = ` ${ latestY} px` ;
211
+ // }, 300); // 0.3s delay
184
212
} else {
185
213
gpcard .style .cursor = " default" ;
214
+ tooltip .style .display = " none" ; // Hide tooltip immediately
215
+ // clearTimeout(tooltipTimeout); // Cancel any pending tooltip show
186
216
}
187
217
});
188
218
"""
189
219
evaljs (session, js)
190
220
191
221
nhh = NodeHoverHandler () do hstate, idx, event, axis
192
- hoverstate [] = hstate
222
+ tooltip_text [] = hstate ? _sidx_to_str ( VIndex (idx), app) : " "
193
223
app. graphplot. _hoverel[] = hstate ? VIndex (idx) : nothing
194
224
end
195
225
ehh = EdgeHoverHandler () do hstate, idx, event, axis
196
- hoverstate [] = hstate
226
+ tooltip_text [] = hstate ? _sidx_to_str ( EIndex (idx), app) : " "
197
227
app. graphplot. _hoverel[] = hstate ? EIndex (idx) : nothing
198
228
end
199
229
200
- on (app. graphplot. _hoverel) do el
201
- small_hover_text[] = isnothing (el) ? " " : repr (el)
202
- end
203
-
204
230
# interactions
205
231
clickaction = (i, type) -> begin
206
232
idx = type == :vertex ? VIndex (i) : EIndex (i)
@@ -259,7 +285,6 @@ function adapt_xy_scaling!(xratio, yratio, ax)
259
285
resize = potential_x_factor > potential_y_factor ? :x : :y
260
286
@warn " No valid scaling factor found, chose $resize "
261
287
end
262
- @info " Resizing $resize "
263
288
264
289
if resize == :x
265
290
xratio[] = potential_x_factor
@@ -475,7 +500,7 @@ function timeseries_card(app, key, session)
475
500
comp_sel = MultiSelect (comp_options, tsplot. selcomp;
476
501
placeholder= " Select components" ,
477
502
multi= true ,
478
- option_to_string= _sidx_to_str,
503
+ option_to_string= s -> _sidx_to_str (s, app) ,
479
504
T= SymbolicIndex,
480
505
id= gendomid (" compsel" ))
481
506
# comp_sel_dom = Grid(DOM.span("Components"), comp_sel; columns = "70px 1fr", align_items = "center")
@@ -531,7 +556,7 @@ function timeseries_card(app, key, session)
531
556
i = _smallest_free (color_cache)
532
557
color_cache[new] = i
533
558
end
534
- colorpairs[] = [(; title= _sidx_to_str (k),
559
+ colorpairs[] = [(; title= _sidx_to_str (k, app ),
535
560
color= " #" * Colors. hex (getcycled (COLORS, v)))
536
561
for (k,v) in color_cache]
537
562
nothing
@@ -766,8 +791,15 @@ function timeseries_card(app, key, session)
766
791
767
792
return card
768
793
end
769
- function _sidx_to_str (s)
770
- (s isa VIndex ? " v" : " e" ) * string (s. compidx)
794
+
795
+ function _sidx_to_str (s, app)
796
+ if s isa VIndex
797
+ " v$(s. compidx) "
798
+ else
799
+ edge = extract_nw (app. sol[]). im. edgevec[s. compidx]
800
+ src, dst = edge. src, edge. dst
801
+ " e$(s. compidx) : $src →$dst "
802
+ end
771
803
end
772
804
function _smallest_free (d:: Dict )
773
805
vals = values (d)
0 commit comments