@@ -86,7 +86,11 @@ import {
8686 RenderShape ,
8787 TitleMode
8888} from './types/globalEnums'
89- import type { ClipboardItems , SubgraphIO } from './types/serialisation'
89+ import type {
90+ ClipboardItems ,
91+ ISerialisedNode ,
92+ SubgraphIO
93+ } from './types/serialisation'
9094import type { NeverNever , PickNevers } from './types/utility'
9195import type { IBaseWidget } from './types/widgets'
9296import { alignNodes , distributeNodes , getBoundaryNodes } from './utils/arrange'
@@ -1772,47 +1776,24 @@ export class LGraphCanvas
17721776 menu : ContextMenu ,
17731777 node : LGraphNode
17741778 ) : void {
1775- const { graph } = node
1776- if ( ! graph ) throw new NullGraphError ( )
1777- graph . beforeChange ( )
1778-
1779- const newSelected = new Set < LGraphNode > ( )
1780-
1781- const fApplyMultiNode = function (
1782- node : LGraphNode ,
1783- newNodes : Set < LGraphNode >
1784- ) : void {
1785- if ( node . clonable === false ) return
1786-
1787- const newnode = node . clone ( )
1788- if ( ! newnode ) return
1789-
1790- newnode . pos = [ node . pos [ 0 ] + 5 , node . pos [ 1 ] + 5 ]
1791- if ( ! node . graph ) throw new NullGraphError ( )
1792-
1793- node . graph . add ( newnode )
1794- newNodes . add ( newnode )
1795- }
1796-
17971779 const canvas = LGraphCanvas . active_canvas
1798- if (
1799- ! canvas . selected_nodes ||
1800- Object . keys ( canvas . selected_nodes ) . length <= 1
1801- ) {
1802- fApplyMultiNode ( node , newSelected )
1803- } else {
1804- for ( const i in canvas . selected_nodes ) {
1805- fApplyMultiNode ( canvas . selected_nodes [ i ] , newSelected )
1806- }
1807- }
1780+ const nodes = canvas . selectedItems . size ? canvas . selectedItems : [ node ]
18081781
1809- if ( newSelected . size ) {
1810- canvas . selectNodes ( [ ...newSelected ] )
1782+ // Find top-left-most boundary
1783+ let offsetX = Infinity
1784+ let offsetY = Infinity
1785+ for ( const item of nodes ) {
1786+ if ( item . pos == null )
1787+ throw new TypeError (
1788+ 'Invalid node encountered on clone. `pos` was null.'
1789+ )
1790+ if ( item . pos [ 0 ] < offsetX ) offsetX = item . pos [ 0 ]
1791+ if ( item . pos [ 1 ] < offsetY ) offsetY = item . pos [ 1 ]
18111792 }
18121793
1813- graph . afterChange ( )
1814-
1815- canvas . setDirty ( true , true )
1794+ canvas . _deserializeItems ( canvas . _serializeItems ( nodes ) , {
1795+ position : [ offsetX + 5 , offsetY + 5 ]
1796+ } )
18161797 }
18171798
18181799 /**
@@ -2384,42 +2365,22 @@ export class LGraphCanvas
23842365 node &&
23852366 this . allow_interaction
23862367 ) {
2387- let newType = node . type
2388-
2389- if ( node instanceof SubgraphNode ) {
2390- const cloned = node . subgraph . clone ( ) . asSerialisable ( )
2391-
2392- const subgraph = graph . createSubgraph ( cloned )
2393- subgraph . configure ( cloned )
2394- newType = subgraph . id
2395- }
2396-
2397- const node_data = node . clone ( ) ?. serialize ( )
2398- if ( node_data ?. type != null ) {
2399- // Ensure the cloned node is configured against the correct type (especially for SubgraphNodes)
2400- node_data . type = newType
2401- const cloned = LiteGraph . createNode ( newType )
2402- if ( cloned ) {
2403- cloned . configure ( node_data )
2404- cloned . pos [ 0 ] += 5
2405- cloned . pos [ 1 ] += 5
2368+ const items = this . _deserializeItems ( this . _serializeItems ( [ node ] ) , {
2369+ position : node . pos
2370+ } )
2371+ const cloned = items ?. created [ 0 ] as LGraphNode | undefined
2372+ if ( ! cloned ) return
24062373
2407- if ( this . allow_dragnodes ) {
2408- pointer . onDragStart = ( pointer ) => {
2409- graph . add ( cloned , false )
2410- this . #startDraggingItems( cloned , pointer )
2411- }
2412- pointer . onDragEnd = ( e ) => this . #processDraggedItems( e )
2413- } else {
2414- // TODO: Check if before/after change are necessary here.
2415- graph . beforeChange ( )
2416- graph . add ( cloned , false )
2417- graph . afterChange ( )
2418- }
2374+ cloned . pos [ 0 ] += 5
2375+ cloned . pos [ 1 ] += 5
24192376
2420- return
2377+ if ( this . allow_dragnodes ) {
2378+ pointer . onDragStart = ( pointer ) => {
2379+ this . #startDraggingItems( cloned , pointer )
24212380 }
2381+ pointer . onDragEnd = ( e ) => this . #processDraggedItems( e )
24222382 }
2383+ return
24232384 }
24242385
24252386 // Node clicked
@@ -3963,17 +3924,26 @@ export class LGraphCanvas
39633924 const { created, nodes, links, reroutes } = results
39643925
39653926 // const failedNodes: ISerialisedNode[] = []
3927+ const subgraphIdMap : Record < string , string > = { }
3928+ // SubgraphV2: Remove always-clone behaviour
3929+ //Update subgraph ids
3930+ for ( const subgraphInfo of parsed . subgraphs )
3931+ subgraphInfo . id = subgraphIdMap [ subgraphInfo . id ] = createUuidv4 ( )
3932+ const allNodeInfo : ISerialisedNode [ ] = [
3933+ parsed . nodes ? [ parsed . nodes ] : [ ] ,
3934+ parsed . subgraphs ? parsed . subgraphs . map ( ( s ) => s . nodes ?? [ ] ) : [ ]
3935+ ] . flat ( 2 )
3936+ for ( const nodeInfo of allNodeInfo )
3937+ if ( nodeInfo . type in subgraphIdMap )
3938+ nodeInfo . type = subgraphIdMap [ nodeInfo . type ]
39663939
39673940 // Subgraphs
39683941 for ( const info of parsed . subgraphs ) {
3969- // SubgraphV2: Remove always-clone behaviour
3970- const originalId = info . id
3971- info . id = createUuidv4 ( )
3972-
39733942 const subgraph = graph . createSubgraph ( info )
3974- subgraph . configure ( info )
3975- results . subgraphs . set ( originalId , subgraph )
3943+ results . subgraphs . set ( info . id , subgraph )
39763944 }
3945+ for ( const info of parsed . subgraphs )
3946+ results . subgraphs . get ( info . id ) ?. configure ( info )
39773947
39783948 // Groups
39793949 for ( const info of parsed . groups ) {
@@ -3985,17 +3955,6 @@ export class LGraphCanvas
39853955 created . push ( group )
39863956 }
39873957
3988- // Update subgraph ids with nesting
3989- function updateSubgraphIds ( nodes : { type : string } [ ] ) {
3990- for ( const info of nodes ) {
3991- const subgraph = results . subgraphs . get ( info . type )
3992- if ( ! subgraph ) continue
3993- info . type = subgraph . id
3994- updateSubgraphIds ( subgraph . nodes )
3995- }
3996- }
3997- updateSubgraphIds ( parsed . nodes )
3998-
39993958 // Nodes
40003959 for ( const info of parsed . nodes ) {
40013960 const node = info . type == null ? null : LiteGraph . createNode ( info . type )
0 commit comments