import { IData , IGlob , INode } from "lib/types" ; import inputs from "lib/inputs" ; import * as vec from "lib/vec" ; import { pointInRect } from "lib/utils" ; const MIN_SPEED = 5 , SNAP_DISTANCE = 4 ; type SnapResult = { id : string ; from : number [ ] ; to : number [ ] ; } ; export default function getNodeSnapper ( node , nodes ) { const iPoint = [ ... node . point ] ; const r = node . radius ; const iNodes = nodes . filter ( ( { id } ) => id !== node . id ) . map ( ( { id , point , radius } ) => ( { id , point : [ ... point ] , radius , } ) ) ; return function getSnap ( delta , camera , document ) : { delta : number [ ] ; point : number [ ] ; snaps : SnapResult [ ] ; } { const next = vec . add ( iPoint , delta ) ; const results = [ ] ; let d , dx = SNAP_DISTANCE , dy = SNAP_DISTANCE , sx = next [ 0 ] , sy = next [ 1 ] ; if ( vec . len ( inputs . pointer . delta ) > MIN_SPEED ) return { delta : vec . vec ( iPoint , next ) , point : next , snaps : [ ] } ; const minX = document . point [ 0 ] - document . size [ 0 ] * 0.25 , minY = document . point [ 1 ] - document . size [ 1 ] * 0.25 , maxX = minX + document . size [ 0 ] * 1.5 , maxY = minY + document . size [ 1 ] * 1.5 ; const nodesToCheck = iNodes . filter ( ( { point } ) => pointInRect ( point , minX , minY , maxX , maxY ) ) ; for ( const n of nodesToCheck ) { d = vec . dist ( n . point , next ) * camera . zoom ; if ( d < dx ) { dx = d ; sx = n . point [ 0 ] ; sy = n . point [ 1 ] ; results [ 0 ] = { id : n . id , from : n . point , to : [ 0 , 0 ] , } ; } } if ( ! results [ 0 ] ) { for ( const n of nodesToCheck ) { d = Math . abs ( next [ 0 ] - n . point [ 0 ] ) * camera . zoom ; if ( d < dx ) { dx = d ; sx = n . point [ 0 ] ; results [ 0 ] = { id : n . id , from : n . point , to : [ 0 , 0 ] , } ; } d = Math . abs ( next [ 1 ] - n . point [ 1 ] ) * camera . zoom ; if ( d < dy ) { dy = d ; sy = n . point [ 1 ] ; results [ 1 ] = { id : n . id , from : n . point , to : [ 0 , 0 ] , } ; } } if ( ! ( results [ 0 ] && results [ 1 ] ) ) { for ( const n of nodesToCheck ) { if ( ! results [ 0 ] ) { d = Math . abs ( next [ 0 ] - ( n . point [ 0 ] - n . radius ) ) * camera . zoom ; if ( d < dx ) { dx = d ; sx = n . point [ 0 ] - n . radius ; results [ 0 ] = { id : n . id , from : vec . sub ( n . point , [ n . radius , 0 ] ) , to : [ 0 , 0 ] , } ; } d = Math . abs ( next [ 0 ] - ( n . point [ 0 ] + n . radius ) ) * camera . zoom ; if ( d < dx ) { dx = d ; sx = n . point [ 0 ] + n . radius ; results [ 0 ] = { id : n . id , from : vec . add ( n . point , [ n . radius , 0 ] ) , to : [ 0 , 0 ] , } ; } } if ( ! results [ 1 ] ) { d = Math . abs ( next [ 1 ] - ( n . point [ 1 ] - n . radius ) ) * camera . zoom ; if ( d < dy ) { dy = d ; sy = n . point [ 1 ] - n . radius ; results [ 1 ] = { id : n . id , from : vec . sub ( n . point , [ 0 , n . radius ] ) , to : [ 0 , 0 ] , } ; } d = Math . abs ( next [ 1 ] - ( n . point [ 1 ] + n . radius ) ) * camera . zoom ; if ( d < dy ) { dy = d ; sy = n . point [ 1 ] + n . radius ; results [ 1 ] = { id : n . id , from : vec . add ( n . point , [ 0 , n . radius ] ) , to : [ 0 , 0 ] , } ; } } } } if ( ! ( results [ 0 ] && results [ 1 ] ) ) { for ( const n of nodesToCheck ) { if ( ! results [ 0 ] ) { d = Math . abs ( next [ 0 ] - r - n . point [ 0 ] ) * camera . zoom ; if ( d < dx ) { dx = d ; sx = n . point [ 0 ] + r ; results [ 0 ] = { id : n . id , from : n . point , to : [ - r , 0 ] , } ; } d = Math . abs ( next [ 0 ] - r - ( n . point [ 0 ] - n . radius ) ) * camera . zoom ; if ( d < dx ) { dx = d ; sx = n . point [ 0 ] - n . radius + r ; results [ 0 ] = { id : n . id , from : vec . sub ( n . point , [ n . radius , 0 ] ) , to : [ - r , 0 ] , } ; } d = Math . abs ( next [ 0 ] - r - ( n . point [ 0 ] + n . radius ) ) * camera . zoom ; if ( d < dx ) { dx = d ; sx = n . point [ 0 ] + n . radius + r ; results [ 0 ] = { id : n . id , from : vec . add ( n . point , [ n . radius , 0 ] ) , to : [ - r , 0 ] , } ; } d = Math . abs ( next [ 0 ] + r - n . point [ 0 ] ) * camera . zoom ; if ( d < dx ) { dx = d ; sx = n . point [ 0 ] - r ; results [ 0 ] = { id : n . id , from : n . point , to : [ r , 0 ] , } ; } d = Math . abs ( next [ 0 ] + r - ( n . point [ 0 ] - n . radius ) ) * camera . zoom ; if ( d < dx ) { dx = d ; sx = n . point [ 0 ] - n . radius - r ; results [ 0 ] = { id : n . id , from : vec . sub ( n . point , [ n . radius , 0 ] ) , to : [ r , 0 ] , } ; } d = Math . abs ( next [ 0 ] + r - ( n . point [ 0 ] + n . radius ) ) * camera . zoom ; if ( d < dx ) { dx = d ; sx = n . point [ 0 ] + n . radius - r ; results [ 0 ] = { id : n . id , from : vec . add ( n . point , [ n . radius , 0 ] ) , to : [ r , 0 ] , } ; } } if ( ! results [ 1 ] ) { d = Math . abs ( next [ 1 ] - r - n . point [ 1 ] ) * camera . zoom ; if ( d < dy ) { dy = d ; sy = n . point [ 1 ] + r ; results [ 1 ] = { id : n . id , from : n . point , to : [ 0 , - r ] , } ; } d = Math . abs ( next [ 1 ] - r - ( n . point [ 1 ] - n . radius ) ) * camera . zoom ; if ( d < dy ) { dy = d ; sy = n . point [ 1 ] - n . radius + r ; results [ 1 ] = { id : n . id , from : vec . sub ( n . point , [ 0 , n . radius ] ) , to : [ 0 , - r ] , } ; } d = Math . abs ( next [ 1 ] - r - ( n . point [ 1 ] + n . radius ) ) * camera . zoom ; if ( d < dy ) { dy = d ; sy = n . point [ 1 ] + n . radius + r ; results [ 1 ] = { id : n . id , from : vec . add ( n . point , [ 0 , n . radius ] ) , to : [ 0 , - r ] , } ; } d = Math . abs ( next [ 1 ] + r - n . point [ 1 ] ) * camera . zoom ; if ( d < dy ) { dy = d ; sy = n . point [ 1 ] - r ; results [ 1 ] = { id : n . id , from : n . point , to : [ 0 , r ] , } ; } d = Math . abs ( next [ 1 ] + r - ( n . point [ 1 ] - n . radius ) ) * camera . zoom ; if ( d < dy ) { dy = d ; sy = n . point [ 1 ] - n . radius - r ; results [ 1 ] = { id : n . id , from : vec . sub ( n . point , [ 0 , n . radius ] ) , to : [ 0 , r ] , } ; } d = Math . abs ( next [ 1 ] + r - ( n . point [ 1 ] + n . radius ) ) * camera . zoom ; if ( d < dy ) { dy = d ; sy = n . point [ 1 ] + n . radius - r ; results [ 1 ] = { id : n . id , from : vec . add ( n . point , [ 0 , n . radius ] ) , to : [ 0 , r ] , } ; } } } } } return { delta : vec . vec ( iPoint , [ sx , sy ] ) , point : [ sx , sy ] , snaps : results . map ( ( r ) => ( { ... r , to : vec . add ( r . to , [ sx , sy ] ) , } ) ) , } ; } ; } export type NodeSnapper = ReturnType < typeof getNodeSnapper > ;