import { SocketGraphicsItem , SocketType } from "./socketgraphicsitem" ; import { ImageCanvas } from "../designer/imagecanvas" ; import { GraphicsItem , MouseDownEvent , MouseMoveEvent , MouseUpEvent } from "./graphicsitem" ; import { NodeScene } from "../scene" ; import { Vector2 } from "./view" ; import { MoveItemsAction } from "../actions/moveItemsaction" ; import { UndoStack } from "../undostack" ; export class NodeGraphicsItemRenderState { hovered = false ; selected = false ; } export class NodeGraphicsItem extends GraphicsItem { id ! : string ; sockets : SocketGraphicsItem [ ] = [ ] ; public title : string ; thumbnail ! : HTMLImageElement ; imageCanvas : ImageCanvas ; processingTime : number ; hit : boolean ; textureChannel : string ; dragStartPos : Vector2 ; constructor ( title ) { super ( ) ; this . width = 100 ; this . height = 100 ; this . title = title ; this . imageCanvas = new ImageCanvas ( ) ; this . processingTime = 0 ; this . hit = false ; } public setScene ( scene ) { this . scene = scene ; for ( const sock of this . sockets ) sock . setScene ( scene ) ; } public setTextureChannel ( name ) { this . textureChannel = name ; } public clearTextureChannel ( ) { this . textureChannel = null ; } public setThumbnail ( thumbnail ) { this . thumbnail = thumbnail ; } public move ( dx , dy ) { this . x += dx ; this . y += dy ; for ( const sock of this . sockets ) { sock . move ( dx , dy ) ; } } draw ( ctx , renderData ) { const renderState = < NodeGraphicsItemRenderState > renderData ; if ( renderState . selected ) { ctx . strokeStyle = "rgb(255, 255, 255)" ; ctx . beginPath ( ) ; ctx . lineWidth = 8 ; this . roundRect ( ctx , this . x , this . y , this . width , this . height , 2 ) ; ctx . stroke ( ) ; } ctx . beginPath ( ) ; ctx . fillStyle = "rgb(0, 0, 0)" ; ctx . rect ( this . x , this . y , this . width , this . height ) ; ctx . fill ( ) ; if ( this . thumbnail ) { } ctx . drawImage ( this . imageCanvas . canvas , this . x , this . y , this . width , this . height ) ; if ( ! renderState . hovered ) { ctx . beginPath ( ) ; ctx . fillStyle = "rgb(0,0,0)" ; ctx . rect ( this . x , this . y , this . width , 20 ) ; ctx . fill ( ) ; ctx . beginPath ( ) ; ctx . font = "bold 9px 'Open Sans'" ; ctx . fillStyle = "rgb(255,255,255)" ; const size = ctx . measureText ( this . title ) ; const textX = this . centerX ( ) - size . width / 2 ; const textY = this . y + 14 ; ctx . fillText ( this . title , textX , textY ) ; } ctx . beginPath ( ) ; ctx . lineWidth = 4 ; ctx . strokeStyle = "rgb(0, 0, 0)" ; this . roundRect ( ctx , this . x , this . y , this . width , this . height , 2 ) ; ctx . stroke ( ) ; for ( const sock of this . sockets ) { sock . draw ( ctx , renderState ) ; } ctx . beginPath ( ) ; let procTime = "calculating.." ; if ( this . processingTime >= 0 ) procTime = this . processingTime + "ms" ; ctx . font = "bold 9px 'Open Sans'" ; ctx . fillStyle = "rgb(255,255,255)" ; const size = ctx . measureText ( procTime ) ; const textX = this . centerX ( ) - size . width / 2 ; const textY = this . y + this . height + 14 ; ctx . fillText ( procTime , textX , textY ) ; if ( this . textureChannel ) { ctx . beginPath ( ) ; ctx . font = "12px 'Open Sans'" ; ctx . fillStyle = "rgb(200, 255, 200)" ; const size = ctx . measureText ( this . textureChannel . toUpperCase ( ) ) ; const textX = this . centerX ( ) - size . width / 2 ; const textY = this . y - 12 ; ctx . fillText ( this . textureChannel . toUpperCase ( ) , textX , textY ) ; } } public setPos ( x , y ) { super . setPos ( x , y ) ; this . sortSockets ( ) ; } public setCenter ( x , y ) { super . setCenter ( x , y ) ; this . sortSockets ( ) ; } public sortSockets ( ) { let socks = this . getInSockets ( ) ; const pad = socks . length < 5 ? 10 : 0 ; let incr = ( this . height - pad * 2 ) / socks . length ; let mid = incr / 2.0 ; let i = 0 ; for ( const sock of socks ) { const y = pad + i * incr + mid ; const x = this . x ; sock . setCenter ( x , this . y + y ) ; i ++ ; } socks = this . getOutSockets ( ) ; incr = ( this . height - pad * 2 ) / socks . length ; mid = incr / 2.0 ; i = 0 ; for ( const sock of socks ) { const y = pad + i * incr + mid ; const x = this . x + this . width ; sock . setCenter ( x , this . y + y ) ; i ++ ; } } getInSockets ( ) { const array = [ ] ; for ( const sock of this . sockets ) { if ( sock . socketType == SocketType . In ) array . push ( sock ) ; } return array ; } getInSocketByName ( name ) { for ( const sock of this . sockets ) { if ( sock . socketType == SocketType . In ) if ( sock . title == name ) return sock ; } return null ; } getOutSockets ( ) { const array = [ ] ; for ( const sock of this . sockets ) { if ( sock . socketType == SocketType . Out ) array . push ( sock ) ; } return array ; } getOutSocketByName ( name ) { if ( ! name ) { const socks = this . getOutSockets ( ) ; if ( socks . length > 0 ) return socks [ 0 ] ; else { console . log ( "[warning] attempting to get  output socket from node with no output sockets" ) ; return null ; } } for ( const sock of this . sockets ) { if ( sock . socketType == SocketType . Out ) if ( sock . title == name ) return sock ; } return null ; } public addSocket ( name , id , type ) { const sock = new SocketGraphicsItem ( ) ; sock . id = id ; sock . title = name ; sock . node = this ; sock . socketType = type ; this . sockets . push ( sock ) ; this . sortSockets ( ) ; } public mouseDown ( evt ) { this . hit = true ; this . dragStartPos = new Vector2 ( this . x , this . y ) ; } public mouseMove ( evt ) { if ( this . hit ) { this . move ( evt . deltaX , evt . deltaY ) ; } } public mouseUp ( evt ) { this . hit = false ; const newPos = new Vector2 ( this . x , this . y ) ; if ( newPos . x != this . dragStartPos . x || newPos . y != this . dragStartPos . y ) { const action = new MoveItemsAction ( [ this ] , [ this . dragStartPos . clone ( ) ] , [ newPos ] ) ; UndoStack . current . push ( action ) ; } } }