66 TextStyle ,
77 Text ,
88 Container ,
9+ Ticker ,
910} from "pixi.js" ;
1011import { ViewGraph } from "../graphs/viewgraph" ;
1112import {
@@ -15,7 +16,7 @@ import {
1516 urManager ,
1617} from "../viewportManager" ;
1718import { RightBar } from "../../graphics/right_bar" ;
18- import { Colors , ZIndexLevels } from "../../utils/utils" ;
19+ import { Colors , createDeviceIcon , ZIndexLevels } from "../../utils/utils" ;
1920import { Position } from "../common" ;
2021import { DeviceInfo } from "../../graphics/renderables/device_info" ;
2122import {
@@ -68,6 +69,8 @@ export abstract class ViewDevice extends Container {
6869 private circleGraphic ?: Graphics ;
6970 private idLabel ?: Text ;
7071 private isVisibleFlag = true ; // Flag to track visibility
72+ private deviceIcons : Record < string , Text | undefined > = { } ;
73+ private deviceTooltips : Record < string , Text | undefined > = { } ;
7174
7275 readonly id : DeviceId ;
7376 readonly viewgraph : ViewGraph ;
@@ -190,6 +193,9 @@ export abstract class ViewDevice extends Container {
190193
191194 updateDevicesAspect ( ) {
192195 if ( ! this . isVisibleFlag ) {
196+ for ( const iconKey in this . deviceIcons ) {
197+ this . hideDeviceIcon ( iconKey ) ;
198+ }
193199 const edges = this . viewgraph
194200 . getConnections ( this . id )
195201 . filter ( ( e ) => e . isVisible ( ) ) ;
@@ -400,6 +406,90 @@ export abstract class ViewDevice extends Container {
400406 RightBar . getInstance ( ) . renderInfo ( new DeviceInfo ( this ) ) ;
401407 }
402408
409+ private repositionDeviceIcons ( ) {
410+ const icons = Object . values ( this . deviceIcons ) . filter ( Boolean ) as Text [ ] ;
411+ if ( icons . length === 0 ) return ;
412+
413+ const spacing = 28 ;
414+ const baseY = - this . height / 2 - 5 ;
415+
416+ const totalWidth = ( icons . length - 1 ) * spacing ;
417+ icons . forEach ( ( icon , idx ) => {
418+ icon . x = - totalWidth / 2 + idx * spacing ;
419+ icon . y = baseY ;
420+ } ) ;
421+ }
422+
423+ showDeviceIconFor (
424+ iconKey : string ,
425+ emoji : string ,
426+ tooltipText : string | undefined ,
427+ durationMs = 2000 ,
428+ visibleFromLayer ?: Layer ,
429+ ) {
430+ this . showDeviceIcon ( iconKey , emoji , tooltipText , visibleFromLayer ) ;
431+ let progress = 0 ;
432+ const tick = ( ticker : Ticker ) => {
433+ progress += ticker . elapsedMS * this . ctx . getCurrentSpeed ( ) ;
434+ if ( progress >= durationMs ) {
435+ Ticker . shared . remove ( tick , this ) ;
436+ this . hideDeviceIcon ( iconKey ) ;
437+ }
438+ } ;
439+ Ticker . shared . add ( tick , this ) ;
440+ }
441+
442+ showDeviceIcon (
443+ iconKey : string ,
444+ emoji : string ,
445+ tooltipText ?: string ,
446+ visibleFromLayer ?: Layer ,
447+ ) {
448+ if (
449+ visibleFromLayer !== undefined &&
450+ this . viewgraph . getLayer ( ) > visibleFromLayer
451+ ) {
452+ return ;
453+ }
454+ if ( ! this . isVisible ( ) ) return ;
455+ if ( this . deviceIcons [ iconKey ] ) return ;
456+ const icon = createDeviceIcon ( emoji , 0 ) ;
457+ this . deviceIcons [ iconKey ] = icon ;
458+
459+ if ( tooltipText ) {
460+ icon . on ( "pointerover" , ( ) => {
461+ this . deviceTooltips [ iconKey ] = showTooltip (
462+ this ,
463+ tooltipText ,
464+ 0 ,
465+ icon . y - 30 ,
466+ this . deviceTooltips [ iconKey ] ,
467+ ) ;
468+ } ) ;
469+ icon . on ( "pointerout" , ( ) => {
470+ hideTooltip ( this . deviceTooltips [ iconKey ] ) ;
471+ } ) ;
472+ }
473+
474+ this . addChild ( icon ) ;
475+ this . repositionDeviceIcons ( ) ;
476+ }
477+
478+ hideDeviceIcon ( iconKey : string ) {
479+ const icon = this . deviceIcons [ iconKey ] ;
480+ if ( icon ) {
481+ this . removeChild ( icon ) ;
482+ icon . destroy ( ) ;
483+ this . deviceIcons [ iconKey ] = undefined ;
484+ this . repositionDeviceIcons ( ) ;
485+ }
486+ const tooltip = this . deviceTooltips [ iconKey ] ;
487+ if ( tooltip ) {
488+ removeTooltip ( this , tooltip ) ;
489+ this . deviceTooltips [ iconKey ] = undefined ;
490+ }
491+ }
492+
403493 select ( ) {
404494 if ( this . isDragCircle ) return ;
405495 this . highlight ( ) ; // Calls highlight on select
0 commit comments