@codebolt/litegraph 0.0.1 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +19 -19
- package/README.md +161 -161
- package/dist/css/litegraph.css +68 -22
- package/dist/litegraph.es.js +3 -3
- package/dist/litegraph.es.js.map +1 -1
- package/dist/litegraph.umd.js +1 -1
- package/dist/litegraph.umd.js.map +1 -1
- package/package.json +10 -3
package/dist/litegraph.umd.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
(function(global,factory){typeof exports==="object"&&typeof module!=="undefined"?factory(exports):typeof define==="function"&&define.amd?define(["exports"],factory):(global=typeof globalThis!=="undefined"?globalThis:global||self,factory((global.litegraph=global.litegraph||{},global.litegraph.js={})))})(this,(function(exports){"use strict";class CustomEventTarget extends EventTarget{dispatch(type,detail){const event=new CustomEvent(type,{detail,cancelable:true});return super.dispatchEvent(event)}addEventListener(type,listener,options){super.addEventListener(type,listener,options)}removeEventListener(type,listener,options){super.removeEventListener(type,listener,options)}dispatchEvent(event){return super.dispatchEvent(event)}}const SUBGRAPH_INPUT_ID=-10;const SUBGRAPH_OUTPUT_ID=-20;const constants=Object.freeze(Object.defineProperty({__proto__:null,SUBGRAPH_INPUT_ID,SUBGRAPH_OUTPUT_ID},Symbol.toStringTag,{value:"Module"}));const zeroUuid="00000000-0000-0000-0000-000000000000";const randomStorage=new Uint32Array(31);function createUuidv4(){if(typeof crypto?.randomUUID==="function")return crypto.randomUUID();if(typeof crypto?.getRandomValues==="function"){const random=crypto.getRandomValues(randomStorage);let i=0;return"10000000-1000-4000-8000-100000000000".replaceAll(/[018]/g,a=>(Number(a)^random[i++]*3725290298461914e-24>>Number(a)*.25).toString(16))}return"10000000-1000-4000-8000-100000000000".replaceAll(/[018]/g,a=>(Number(a)^Math.random()*16>>Number(a)*.25).toString(16))}class LLink{static _drawDebug=false;id;parentId;type;origin_id;origin_slot;target_id;target_slot;data;_data;_pos;_last_time;path;_centreAngle;_dragging;#color;get color(){return this.#color}set color(value){this.#color=value===""?null:value}get isFloatingOutput(){return this.origin_id===-1&&this.origin_slot===-1}get isFloatingInput(){return this.target_id===-1&&this.target_slot===-1}get isFloating(){return this.isFloatingOutput||this.isFloatingInput}get originIsIoNode(){return this.origin_id===SUBGRAPH_INPUT_ID}get targetIsIoNode(){return this.target_id===SUBGRAPH_OUTPUT_ID}constructor(id,type,origin_id,origin_slot,target_id,target_slot,parentId){this.id=id;this.type=type;this.origin_id=origin_id;this.origin_slot=origin_slot;this.target_id=target_id;this.target_slot=target_slot;this.parentId=parentId;this._data=null;this._pos=new Float32Array(2)}static createFromArray(data){return new LLink(data[0],data[5],data[1],data[2],data[3],data[4])}static create(data){return new LLink(data.id,data.type,data.origin_id,data.origin_slot,data.target_id,data.target_slot,data.parentId)}static getReroutes(network,linkSegment){if(!linkSegment.parentId)return[];return network.reroutes.get(linkSegment.parentId)?.getReroutes()??[]}static getFirstReroute(network,linkSegment){return LLink.getReroutes(network,linkSegment).at(0)}static findNextReroute(network,linkSegment,rerouteId){if(!linkSegment.parentId)return;return network.reroutes.get(linkSegment.parentId)?.findNextReroute(rerouteId)}static getOriginNode(network,linkId){const id=network.links.get(linkId)?.origin_id;return network.getNodeById(id)??void 0}static getTargetNode(network,linkId){const id=network.links.get(linkId)?.target_id;return network.getNodeById(id)??void 0}static resolve(linkId,network){return network.getLink(linkId)?.resolve(network)}static resolveMany(linkIds,network){const resolved=[];for(const id of linkIds){const r=network.getLink(id)?.resolve(network);if(r)resolved.push(r)}return resolved}resolve(network){const inputNode=this.target_id===-1?void 0:network.getNodeById(this.target_id)??void 0;const input=inputNode?.inputs[this.target_slot];const subgraphInput=this.originIsIoNode?network.inputNode?.slots[this.origin_slot]:void 0;if(subgraphInput){return{inputNode,input,subgraphInput,link:this}}const outputNode=this.origin_id===-1?void 0:network.getNodeById(this.origin_id)??void 0;const output=outputNode?.outputs[this.origin_slot];const subgraphOutput=this.targetIsIoNode?network.outputNode?.slots[this.target_slot]:void 0;if(subgraphOutput){return{outputNode,output,subgraphInput:void 0,subgraphOutput,link:this}}return{inputNode,outputNode,input,output,subgraphInput,subgraphOutput,link:this}}configure(o){if(Array.isArray(o)){this.id=o[0];this.origin_id=o[1];this.origin_slot=o[2];this.target_id=o[3];this.target_slot=o[4];this.type=o[5]}else{this.id=o.id;this.type=o.type;this.origin_id=o.origin_id;this.origin_slot=o.origin_slot;this.target_id=o.target_id;this.target_slot=o.target_slot;this.parentId=o.parentId}}hasOrigin(nodeId,outputIndex){return this.origin_id===nodeId&&this.origin_slot===outputIndex}hasTarget(nodeId,inputIndex){return this.target_id===nodeId&&this.target_slot===inputIndex}toFloating(slotType,parentId){const exported=this.asSerialisable();exported.id=-1;exported.parentId=parentId;if(slotType==="input"){exported.origin_id=-1;exported.origin_slot=-1}else{exported.target_id=-1;exported.target_slot=-1}return LLink.create(exported)}disconnect(network,keepReroutes){const reroutes=LLink.getReroutes(network,this);const lastReroute=reroutes.at(-1);const outputFloating=keepReroutes==="output"&&lastReroute?.linkIds.size===1&&lastReroute.floatingLinkIds.size===0;if(outputFloating||keepReroutes==="input"&&lastReroute){const newLink=LLink.create(this);newLink.id=-1;if(keepReroutes==="input"){newLink.origin_id=-1;newLink.origin_slot=-1;lastReroute.floating={slotType:"input"}}else{newLink.target_id=-1;newLink.target_slot=-1;lastReroute.floating={slotType:"output"}}network.addFloatingLink(newLink)}for(const reroute of reroutes){reroute.linkIds.delete(this.id);if(!keepReroutes&&!reroute.totalLinks){network.reroutes.delete(reroute.id)}}network.links.delete(this.id);if(this.originIsIoNode&&network instanceof Subgraph){const subgraphInput=network.inputs.at(this.origin_slot);if(!subgraphInput)throw new Error("Invalid link - subgraph input not found");subgraphInput.events.dispatch("input-disconnected",{input:subgraphInput})}}serialize(){return[this.id,this.origin_id,this.origin_slot,this.target_id,this.target_slot,this.type]}asSerialisable(){const copy={id:this.id,origin_id:this.origin_id,origin_slot:this.origin_slot,target_id:this.target_id,target_slot:this.target_slot,type:this.type};if(this.parentId)copy.parentId=this.parentId;return copy}}var NodeSlotType=(NodeSlotType2=>{NodeSlotType2[NodeSlotType2["INPUT"]=1]="INPUT";NodeSlotType2[NodeSlotType2["OUTPUT"]=2]="OUTPUT";return NodeSlotType2})(NodeSlotType||{});var RenderShape=(RenderShape2=>{RenderShape2[RenderShape2["BOX"]=1]="BOX";RenderShape2[RenderShape2["ROUND"]=2]="ROUND";RenderShape2[RenderShape2["CIRCLE"]=3]="CIRCLE";RenderShape2[RenderShape2["CARD"]=4]="CARD";RenderShape2[RenderShape2["ARROW"]=5]="ARROW";RenderShape2[RenderShape2["GRID"]=6]="GRID";RenderShape2[RenderShape2["HollowCircle"]=7]="HollowCircle";return RenderShape2})(RenderShape||{});var CanvasItem=(CanvasItem2=>{CanvasItem2[CanvasItem2["Nothing"]=0]="Nothing";CanvasItem2[CanvasItem2["Node"]=1]="Node";CanvasItem2[CanvasItem2["Group"]=2]="Group";CanvasItem2[CanvasItem2["Reroute"]=4]="Reroute";CanvasItem2[CanvasItem2["Link"]=8]="Link";CanvasItem2[CanvasItem2["RerouteSlot"]=32]="RerouteSlot";CanvasItem2[CanvasItem2["SubgraphIoNode"]=64]="SubgraphIoNode";CanvasItem2[CanvasItem2["SubgraphIoSlot"]=128]="SubgraphIoSlot";return CanvasItem2})(CanvasItem||{});var LinkDirection=(LinkDirection2=>{LinkDirection2[LinkDirection2["NONE"]=0]="NONE";LinkDirection2[LinkDirection2["UP"]=1]="UP";LinkDirection2[LinkDirection2["DOWN"]=2]="DOWN";LinkDirection2[LinkDirection2["LEFT"]=3]="LEFT";LinkDirection2[LinkDirection2["RIGHT"]=4]="RIGHT";LinkDirection2[LinkDirection2["CENTER"]=5]="CENTER";return LinkDirection2})(LinkDirection||{});var LinkRenderType=(LinkRenderType2=>{LinkRenderType2[LinkRenderType2["HIDDEN_LINK"]=-1]="HIDDEN_LINK";LinkRenderType2[LinkRenderType2["STRAIGHT_LINK"]=0]="STRAIGHT_LINK";LinkRenderType2[LinkRenderType2["LINEAR_LINK"]=1]="LINEAR_LINK";LinkRenderType2[LinkRenderType2["SPLINE_LINK"]=2]="SPLINE_LINK";return LinkRenderType2})(LinkRenderType||{});var LinkMarkerShape=(LinkMarkerShape2=>{LinkMarkerShape2[LinkMarkerShape2["None"]=0]="None";LinkMarkerShape2[LinkMarkerShape2["Circle"]=1]="Circle";LinkMarkerShape2[LinkMarkerShape2["Arrow"]=2]="Arrow";return LinkMarkerShape2})(LinkMarkerShape||{});var TitleMode=(TitleMode2=>{TitleMode2[TitleMode2["NORMAL_TITLE"]=0]="NORMAL_TITLE";TitleMode2[TitleMode2["NO_TITLE"]=1]="NO_TITLE";TitleMode2[TitleMode2["TRANSPARENT_TITLE"]=2]="TRANSPARENT_TITLE";TitleMode2[TitleMode2["AUTOHIDE_TITLE"]=3]="AUTOHIDE_TITLE";return TitleMode2})(TitleMode||{});var LGraphEventMode=(LGraphEventMode2=>{LGraphEventMode2[LGraphEventMode2["ALWAYS"]=0]="ALWAYS";LGraphEventMode2[LGraphEventMode2["ON_EVENT"]=1]="ON_EVENT";LGraphEventMode2[LGraphEventMode2["NEVER"]=2]="NEVER";LGraphEventMode2[LGraphEventMode2["ON_TRIGGER"]=3]="ON_TRIGGER";LGraphEventMode2[LGraphEventMode2["BYPASS"]=4]="BYPASS";return LGraphEventMode2})(LGraphEventMode||{});var EaseFunction=(EaseFunction2=>{EaseFunction2["LINEAR"]="linear";EaseFunction2["EASE_IN_QUAD"]="easeInQuad";EaseFunction2["EASE_OUT_QUAD"]="easeOutQuad";EaseFunction2["EASE_IN_OUT_QUAD"]="easeInOutQuad";return EaseFunction2})(EaseFunction||{});var Alignment=(Alignment2=>{Alignment2[Alignment2["None"]=0]="None";Alignment2[Alignment2["Top"]=1]="Top";Alignment2[Alignment2["Bottom"]=2]="Bottom";Alignment2[Alignment2["Middle"]=4]="Middle";Alignment2[Alignment2["Left"]=8]="Left";Alignment2[Alignment2["Right"]=16]="Right";Alignment2[Alignment2["Centre"]=32]="Centre";Alignment2[Alignment2["TopLeft"]=9]="TopLeft";Alignment2[Alignment2["TopCentre"]=33]="TopCentre";Alignment2[Alignment2["TopRight"]=17]="TopRight";Alignment2[Alignment2["MidLeft"]=12]="MidLeft";Alignment2[Alignment2["MidCentre"]=36]="MidCentre";Alignment2[Alignment2["MidRight"]=20]="MidRight";Alignment2[Alignment2["BottomLeft"]=10]="BottomLeft";Alignment2[Alignment2["BottomCentre"]=34]="BottomCentre";Alignment2[Alignment2["BottomRight"]=18]="BottomRight";return Alignment2})(Alignment||{});function hasFlag(flagSet,flag){return(flagSet&flag)===flag}function distance(a,b){return Math.sqrt((b[0]-a[0])*(b[0]-a[0])+(b[1]-a[1])*(b[1]-a[1]))}function dist2(x1,y1,x2,y2){return(x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)}function isInRectangle(x2,y,left,top,width2,height){return x2>=left&&x2<left+width2&&y>=top&&y<top+height}function isPointInRect(point,rect){return point[0]>=rect[0]&&point[0]<rect[0]+rect[2]&&point[1]>=rect[1]&&point[1]<rect[1]+rect[3]}function isInRect(x2,y,rect){return x2>=rect[0]&&x2<rect[0]+rect[2]&&y>=rect[1]&&y<rect[1]+rect[3]}function isInsideRectangle(x2,y,left,top,width2,height){return left<x2&&left+width2>x2&&top<y&&top+height>y}function overlapBounding(a,b){const aRight=a[0]+a[2];const aBottom=a[1]+a[3];const bRight=b[0]+b[2];const bBottom=b[1]+b[3];return a[0]>bRight||a[1]>bBottom||aRight<b[0]||aBottom<b[1]?false:true}function getCentre(rect){return[rect[0]+rect[2]*.5,rect[1]+rect[3]*.5]}function containsCentre(a,b){const centreX=b[0]+b[2]*.5;const centreY=b[1]+b[3]*.5;return isInRect(centreX,centreY,a)}function containsRect(a,b){const aRight=a[0]+a[2];const aBottom=a[1]+a[3];const bRight=b[0]+b[2];const bBottom=b[1]+b[3];const identical=a[0]===b[0]&&a[1]===b[1]&&aRight===bRight&&aBottom===bBottom;return!identical&&a[0]<=b[0]&&a[1]<=b[1]&&aRight>=bRight&&aBottom>=bBottom}function findPointOnCurve(out,a,b,controlA,controlB,t=.5){const iT=1-t;const c1=iT*iT*iT;const c2=3*(iT*iT)*t;const c3=3*iT*(t*t);const c4=t*t*t;out[0]=c1*a[0]+c2*controlA[0]+c3*controlB[0]+c4*b[0];out[1]=c1*a[1]+c2*controlA[1]+c3*controlB[1]+c4*b[1]}function createBounds(objects,padding=10){const bounds=new Float32Array([Infinity,Infinity,-Infinity,-Infinity]);for(const obj of objects){const rect=obj.boundingRect;bounds[0]=Math.min(bounds[0],rect[0]);bounds[1]=Math.min(bounds[1],rect[1]);bounds[2]=Math.max(bounds[2],rect[0]+rect[2]);bounds[3]=Math.max(bounds[3],rect[1]+rect[3])}if(!bounds.every(x2=>isFinite(x2)))return null;return[bounds[0]-padding,bounds[1]-padding,bounds[2]-bounds[0]+2*padding,bounds[3]-bounds[1]+2*padding]}function snapPoint(pos,snapTo){if(!snapTo)return false;pos[0]=snapTo*Math.round(pos[0]/snapTo);pos[1]=snapTo*Math.round(pos[1]/snapTo);return true}function alignToContainer(rect,anchors,[containerX,containerY,containerWidth,containerHeight],[insetX,insetY]=[0,0]){if(hasFlag(anchors,Alignment.Left)){rect[0]=containerX+insetX}else if(hasFlag(anchors,Alignment.Right)){rect[0]=containerX+containerWidth-insetX-rect[2]}else if(hasFlag(anchors,Alignment.Centre)){rect[0]=containerX+containerWidth*.5-rect[2]*.5}if(hasFlag(anchors,Alignment.Top)){rect[1]=containerY+insetY}else if(hasFlag(anchors,Alignment.Bottom)){rect[1]=containerY+containerHeight-insetY-rect[3]}else if(hasFlag(anchors,Alignment.Middle)){rect[1]=containerY+containerHeight*.5-rect[3]*.5}return rect}function alignOutsideContainer(rect,anchors,[otherX,otherY,otherWidth,otherHeight],[outsetX,outsetY]=[0,0]){if(hasFlag(anchors,Alignment.Left)){rect[0]=otherX-outsetX-rect[2]}else if(hasFlag(anchors,Alignment.Right)){rect[0]=otherX+otherWidth+outsetX}else if(hasFlag(anchors,Alignment.Centre)){rect[0]=otherX+otherWidth*.5-rect[2]*.5}if(hasFlag(anchors,Alignment.Top)){rect[1]=otherY-outsetY-rect[3]}else if(hasFlag(anchors,Alignment.Bottom)){rect[1]=otherY+otherHeight+outsetY}else if(hasFlag(anchors,Alignment.Middle)){rect[1]=otherY+otherHeight*.5-rect[3]*.5}return rect}function clamp(value,min,max){return value<min?min:value>max?max:value}class Rectangle extends Float64Array{#pos;#size;constructor(x2=0,y=0,width2=0,height=0){super(4);this[0]=x2;this[1]=y;this[2]=width2;this[3]=height}static from([x2,y,width2,height]){return new Rectangle(x2,y,width2,height)}static fromCentre([x2,y],width2,height=width2){const left=x2-width2*.5;const top=y-height*.5;return new Rectangle(left,top,width2,height)}static ensureRect(rect){return rect instanceof Rectangle?rect:new Rectangle(rect[0],rect[1],rect[2],rect[3])}subarray(begin=0,end){const byteOffset=begin<<3;const length=end===void 0?end:end-begin;return new Float64Array(this.buffer,byteOffset,length)}get pos(){this.#pos??=this.subarray(0,2);return this.#pos}set pos(value){this[0]=value[0];this[1]=value[1]}get size(){this.#size??=this.subarray(2,4);return this.#size}set size(value){this[2]=value[0];this[3]=value[1]}get x(){return this[0]}set x(value){this[0]=value}get y(){return this[1]}set y(value){this[1]=value}get width(){return this[2]}set width(value){this[2]=value}get height(){return this[3]}set height(value){this[3]=value}get left(){return this[0]}set left(value){this[0]=value}get top(){return this[1]}set top(value){this[1]=value}get right(){return this[0]+this[2]}set right(value){this[0]=value-this[2]}get bottom(){return this[1]+this[3]}set bottom(value){this[1]=value-this[3]}get centreX(){return this[0]+this[2]*.5}get centreY(){return this[1]+this[3]*.5}updateTo(rect){this[0]=rect[0];this[1]=rect[1];this[2]=rect[2];this[3]=rect[3]}containsXy(x2,y){const[left,top,width2,height]=this;return x2>=left&&x2<left+width2&&y>=top&&y<top+height}containsPoint([x2,y]){const[left,top,width2,height]=this;return x2>=left&&x2<left+width2&&y>=top&&y<top+height}containsRect(other){const{right,bottom}=this;const otherRight=other[0]+other[2];const otherBottom=other[1]+other[3];const identical=this.x===other[0]&&this.y===other[1]&&right===otherRight&&bottom===otherBottom;return!identical&&this.x<=other[0]&&this.y<=other[1]&&right>=otherRight&&bottom>=otherBottom}overlaps(rect){return this.x<rect[0]+rect[2]&&this.y<rect[1]+rect[3]&&this.x+this.width>rect[0]&&this.y+this.height>rect[1]}findContainingCorner(x2,y,cornerSize){if(this.isInTopLeftCorner(x2,y,cornerSize))return"NW";if(this.isInTopRightCorner(x2,y,cornerSize))return"NE";if(this.isInBottomLeftCorner(x2,y,cornerSize))return"SW";if(this.isInBottomRightCorner(x2,y,cornerSize))return"SE"}isInTopLeftCorner(x2,y,cornerSize){return isInRectangle(x2,y,this.x,this.y,cornerSize,cornerSize)}isInTopRightCorner(x2,y,cornerSize){return isInRectangle(x2,y,this.right-cornerSize,this.y,cornerSize,cornerSize)}isInBottomLeftCorner(x2,y,cornerSize){return isInRectangle(x2,y,this.x,this.bottom-cornerSize,cornerSize,cornerSize)}isInBottomRightCorner(x2,y,cornerSize){return isInRectangle(x2,y,this.right-cornerSize,this.bottom-cornerSize,cornerSize,cornerSize)}isInTopEdge(x2,y,edgeSize){return isInRectangle(x2,y,this.x,this.y,this.width,edgeSize)}isInBottomEdge(x2,y,edgeSize){return isInRectangle(x2,y,this.x,this.bottom-edgeSize,this.width,edgeSize)}isInLeftEdge(x2,y,edgeSize){return isInRectangle(x2,y,this.x,this.y,edgeSize,this.height)}isInRightEdge(x2,y,edgeSize){return isInRectangle(x2,y,this.right-edgeSize,this.y,edgeSize,this.height)}getCentre(){return[this.centreX,this.centreY]}getArea(){return this.width*this.height}getPerimeter(){return 2*(this.width+this.height)}getTopLeft(){return[this[0],this[1]]}getBottomRight(){return[this.right,this.bottom]}getSize(){return[this[2],this[3]]}getOffsetTo([x2,y]){return[x2-this[0],y-this[1]]}getOffsetFrom([x2,y]){return[this[0]-x2,this[1]-y]}resizeTopLeft(x1,y1){this[2]+=this[0]-x1;this[3]+=this[1]-y1;this[0]=x1;this[1]=y1}resizeBottomLeft(x1,y2){this[2]+=this[0]-x1;this[3]=y2-this[1];this[0]=x1}resizeTopRight(x2,y1){this[2]=x2-this[0];this[3]+=this[1]-y1;this[1]=y1}resizeBottomRight(x2,y2){this[2]=x2-this[0];this[3]=y2-this[1]}setWidthRightAnchored(width2){const currentWidth=this[2];this[2]=width2;this[0]+=currentWidth-width2}setHeightBottomAnchored(height){const currentHeight=this[3];this[3]=height;this[1]+=currentHeight-height}clone(){return new Rectangle(this[0],this[1],this[2],this[3])}toArray(){return this.export()}export(){return[this[0],this[1],this[2],this[3]]}_drawDebug(ctx,colour="red"){const{strokeStyle,lineWidth}=ctx;try{ctx.strokeStyle=colour;ctx.lineWidth=.5;ctx.beginPath();ctx.strokeRect(this[0],this[1],this[2],this[3])}finally{ctx.strokeStyle=strokeStyle;ctx.lineWidth=lineWidth}}}function getNodeInputOnPos(node2,x2,y){const{inputs}=node2;if(!inputs)return;for(const[index,input]of inputs.entries()){const pos=node2.getInputPos(index);const nameLength=input.label?.length??input.localized_name?.length??input.name?.length;const width2=20+(nameLength||3)*7;if(isInRectangle(x2,y,pos[0]-10,pos[1]-10,width2,20)){return{index,input,pos}}}}function getNodeOutputOnPos(node2,x2,y){const{outputs}=node2;if(!outputs)return;for(const[index,output]of outputs.entries()){const pos=node2.getOutputPos(index);if(isInRectangle(x2,y,pos[0]-10,pos[1]-10,40,20)){return{index,output,pos}}}}function isOverNodeInput(node2,canvasx,canvasy,slot_pos){const result=getNodeInputOnPos(node2,canvasx,canvasy);if(!result)return-1;if(slot_pos){slot_pos[0]=result.pos[0];slot_pos[1]=result.pos[1]}return result.index}function isOverNodeOutput(node2,canvasx,canvasy,slot_pos){const result=getNodeOutputOnPos(node2,canvasx,canvasy);if(!result)return-1;if(slot_pos){slot_pos[0]=result.pos[0];slot_pos[1]=result.pos[1]}return result.index}class NullGraphError extends Error{constructor(message="Attempted to access LGraph reference that was null or undefined.",cause){super(message,{cause});this.name="NullGraphError"}}class LGraphIcon{unicode;fontFamily;color;bgColor;fontSize;circlePadding;xOffset;yOffset;constructor({unicode,fontFamily="PrimeIcons",color="#e6c200",bgColor,fontSize=16,circlePadding=2,xOffset=0,yOffset=0}){this.unicode=unicode;this.fontFamily=fontFamily;this.color=color;this.bgColor=bgColor;this.fontSize=fontSize;this.circlePadding=circlePadding;this.xOffset=xOffset;this.yOffset=yOffset}draw(ctx,x2,y){x2+=this.xOffset;y+=this.yOffset;const{font,textBaseline,textAlign,fillStyle}=ctx;ctx.font=`${this.fontSize}px '${this.fontFamily}'`;ctx.textBaseline="middle";ctx.textAlign="center";const iconRadius=this.fontSize/2+this.circlePadding;if(this.bgColor){ctx.beginPath();ctx.arc(x2+iconRadius,y,iconRadius,0,2*Math.PI);ctx.fillStyle=this.bgColor;ctx.fill()}ctx.fillStyle=this.color;ctx.fillText(this.unicode,x2+iconRadius,y);ctx.font=font;ctx.textBaseline=textBaseline;ctx.textAlign=textAlign;ctx.fillStyle=fillStyle}}var BadgePosition=(BadgePosition2=>{BadgePosition2["TopLeft"]="top-left";BadgePosition2["TopRight"]="top-right";return BadgePosition2})(BadgePosition||{});class LGraphBadge{text;fgColor;bgColor;fontSize;padding;height;cornerRadius;icon;xOffset;yOffset;constructor({text,fgColor="white",bgColor="#0F1F0F",fontSize=12,padding=6,height=20,cornerRadius=5,iconOptions,xOffset=0,yOffset=0}){this.text=text;this.fgColor=fgColor;this.bgColor=bgColor;this.fontSize=fontSize;this.padding=padding;this.height=height;this.cornerRadius=cornerRadius;if(iconOptions){this.icon=new LGraphIcon(iconOptions)}this.xOffset=xOffset;this.yOffset=yOffset}get visible(){return(this.text?.length??0)>0||!!this.icon}getWidth(ctx){if(!this.visible)return 0;const{font}=ctx;let iconWidth=0;if(this.icon){ctx.font=`${this.icon.fontSize}px '${this.icon.fontFamily}'`;iconWidth=ctx.measureText(this.icon.unicode).width+this.padding}ctx.font=`${this.fontSize}px sans-serif`;const textWidth=this.text?ctx.measureText(this.text).width:0;ctx.font=font;return iconWidth+textWidth+this.padding*2}draw(ctx,x2,y){if(!this.visible)return;x2+=this.xOffset;y+=this.yOffset;const{font,fillStyle,textBaseline,textAlign}=ctx;ctx.font=`${this.fontSize}px sans-serif`;const badgeWidth=this.getWidth(ctx);const badgeX=0;ctx.fillStyle=this.bgColor;ctx.beginPath();if(ctx.roundRect){ctx.roundRect(x2+badgeX,y,badgeWidth,this.height,this.cornerRadius)}else{ctx.rect(x2+badgeX,y,badgeWidth,this.height)}ctx.fill();let drawX=x2+badgeX+this.padding;const centerY=y+this.height/2;if(this.icon){this.icon.draw(ctx,drawX,centerY);drawX+=this.icon.fontSize+this.padding/2+4}if(this.text){ctx.fillStyle=this.fgColor;ctx.textBaseline="middle";ctx.textAlign="left";ctx.fillText(this.text,drawX,centerY+1)}ctx.font=font;ctx.fillStyle=fillStyle;ctx.textBaseline=textBaseline;ctx.textAlign=textAlign}}class LGraphButton extends LGraphBadge{name;_last_area=new Rectangle;constructor(options){super(options);this.name=options.name}getWidth(ctx){if(!this.visible)return 0;const{font}=ctx;ctx.font=`${this.fontSize}px 'PrimeIcons'`;const textWidth=this.text?ctx.measureText(this.text).width:0;ctx.font=font;return textWidth}draw(ctx,x2,y){if(!this.visible){return}const width2=this.getWidth(ctx);this._last_area[0]=x2+this.xOffset;this._last_area[1]=y+this.yOffset;this._last_area[2]=width2;this._last_area[3]=this.height;const adjustedX=x2+this.xOffset;const adjustedY=y+this.yOffset;const{font,fillStyle,textBaseline,textAlign}=ctx;const titleTextColor=ctx.fillStyle||"white";ctx.font=`${this.fontSize}px 'PrimeIcons'`;ctx.fillStyle=titleTextColor;ctx.textBaseline="middle";ctx.textAlign="center";const centerX=adjustedX+width2/2;const centerY=adjustedY+this.height/2;if(this.text){ctx.fillText(this.text,centerX,centerY)}ctx.font=font;ctx.fillStyle=fillStyle;ctx.textBaseline=textBaseline;ctx.textAlign=textAlign}isPointInside(x2,y){return this._last_area.containsPoint([x2,y])}}const ELLIPSIS="…";const TWO_DOT_LEADER="‥";const ONE_DOT_LEADER="․";var SlotType=(SlotType2=>{SlotType2["Array"]="array";SlotType2[SlotType2["Event"]=-1]="Event";return SlotType2})(SlotType||{});var SlotShape=(SlotShape2=>{SlotShape2[SlotShape2["Box"]=RenderShape.BOX]="Box";SlotShape2[SlotShape2["Arrow"]=RenderShape.ARROW]="Arrow";SlotShape2[SlotShape2["Grid"]=RenderShape.GRID]="Grid";SlotShape2[SlotShape2["Circle"]=RenderShape.CIRCLE]="Circle";SlotShape2[SlotShape2["HollowCircle"]=RenderShape.HollowCircle]="HollowCircle";return SlotShape2})(SlotShape||{});var SlotDirection=(SlotDirection2=>{SlotDirection2[SlotDirection2["Up"]=LinkDirection.UP]="Up";SlotDirection2[SlotDirection2["Right"]=LinkDirection.RIGHT]="Right";SlotDirection2[SlotDirection2["Down"]=LinkDirection.DOWN]="Down";SlotDirection2[SlotDirection2["Left"]=LinkDirection.LEFT]="Left";return SlotDirection2})(SlotDirection||{});var LabelPosition=(LabelPosition2=>{LabelPosition2["Left"]="left";LabelPosition2["Right"]="right";return LabelPosition2})(LabelPosition||{});function strokeShape(ctx,area,{shape=RenderShape.BOX,round_radius,title_height,title_mode=TitleMode.NORMAL_TITLE,color,padding=6,collapsed=false,lineWidth:thickness=1}={}){round_radius??=LiteGraph.ROUND_RADIUS;color??=LiteGraph.NODE_BOX_OUTLINE_COLOR;if(title_mode===TitleMode.TRANSPARENT_TITLE){const height2=title_height??LiteGraph.NODE_TITLE_HEIGHT;area[1]-=height2;area[3]+=height2}const{lineWidth,strokeStyle}=ctx;ctx.lineWidth=thickness;ctx.globalAlpha=.8;ctx.strokeStyle=color;ctx.beginPath();const[x2,y,width2,height]=area;switch(shape){case RenderShape.BOX:{ctx.rect(x2-padding,y-padding,width2+2*padding,height+2*padding);break}case RenderShape.ROUND:case RenderShape.CARD:{const radius=round_radius+padding;const isCollapsed=shape===RenderShape.CARD&&collapsed;const cornerRadii=isCollapsed||shape===RenderShape.ROUND?[radius]:[radius,2,radius,2];ctx.roundRect(x2-padding,y-padding,width2+2*padding,height+2*padding,cornerRadii);break}case RenderShape.CIRCLE:{const centerX=x2+width2/2;const centerY=y+height/2;const radius=Math.max(width2,height)/2+padding;ctx.arc(centerX,centerY,radius,0,Math.PI*2);break}}ctx.stroke();ctx.lineWidth=lineWidth;ctx.strokeStyle=strokeStyle;ctx.globalAlpha=1}function truncateTextToWidth(ctx,text,maxWidth){if(!(maxWidth>0))return"";const fullWidth=ctx.measureText(text).width;if(fullWidth<=maxWidth)return text;const ellipsisWidth=ctx.measureText(ELLIPSIS).width*.75;if(ellipsisWidth>maxWidth){const twoDotsWidth=ctx.measureText(TWO_DOT_LEADER).width*.75;if(twoDotsWidth<maxWidth)return TWO_DOT_LEADER;const oneDotWidth=ctx.measureText(ONE_DOT_LEADER).width*.75;return oneDotWidth<maxWidth?ONE_DOT_LEADER:""}let min=0;let max=text.length;let bestLen=0;while(min<=max){const mid=Math.floor((min+max)*.5);if(mid===0){min=mid+1;continue}const sub=text.substring(0,mid);const currentWidth=ctx.measureText(sub).width+ellipsisWidth;if(currentWidth<=maxWidth){bestLen=mid;min=mid+1}else{max=mid-1}}return bestLen===0?ELLIPSIS:text.substring(0,bestLen)+ELLIPSIS}function drawTextInArea({ctx,text,area,align="left"}){const{left,right,bottom,width:width2,centreX}=area;const fullWidth=ctx.measureText(text).width;if(fullWidth<=width2){ctx.textAlign=align;const x2=align==="left"?left:align==="right"?right:centreX;ctx.fillText(text,x2,bottom);return}const truncated=truncateTextToWidth(ctx,text,width2);if(truncated.length===0)return;ctx.textAlign="left";ctx.fillText(truncated.slice(0,-1),left,bottom);ctx.rect(left,bottom,width2,1);ctx.textAlign="right";const ellipsis=truncated.at(-1);ctx.fillText(ellipsis,right,bottom,ctx.measureText(ellipsis).width*.75)}class SlotBase{name;localized_name;label;type;dir;removable;shape;color_off;color_on;locked;nameLocked;widget;_floatingLinks;hasErrors;boundingRect;constructor(name,type,boundingRect){this.name=name;this.type=type;this.boundingRect=boundingRect??new Rectangle}renderingColor(colorContext){return this.isConnected?this.color_on||colorContext.getConnectedColor(this.type):this.color_off||colorContext.getDisconnectedColor(this.type)}}class NodeSlot extends SlotBase{pos;get#centreOffset(){const nodePos=this.node.pos;const{boundingRect}=this;const diameter=boundingRect[3];return getCentre([boundingRect[0]-nodePos[0],boundingRect[1]-nodePos[1],diameter,diameter])}#node;get node(){return this.#node}get highlightColor(){return LiteGraph.NODE_TEXT_HIGHLIGHT_COLOR??LiteGraph.NODE_SELECTED_TITLE_COLOR??LiteGraph.NODE_TEXT_COLOR}constructor(slot,node2){const maybeSubgraphSlot=slot;const{boundingRect,name,type,_listenerController,...rest}=maybeSubgraphSlot;const rectangle=boundingRect?Rectangle.ensureRect(boundingRect):new Rectangle;super(name,type,rectangle);Object.assign(this,rest);this.#node=node2}get renderingLabel(){return this.label||this.localized_name||this.name||""}draw(ctx,{colorContext,labelPosition=LabelPosition.Right,lowQuality=false,highlight=false,doStroke=false}){const originalFillStyle=ctx.fillStyle;const originalStrokeStyle=ctx.strokeStyle;const originalLineWidth=ctx.lineWidth;const labelColor=highlight?this.highlightColor:LiteGraph.NODE_TEXT_COLOR;const pos=this.#centreOffset;const slot_type=this.type;const slot_shape=slot_type===SlotType.Array?SlotShape.Grid:this.shape;ctx.beginPath();let doFill=true;ctx.fillStyle=this.renderingColor(colorContext);ctx.lineWidth=1;if(slot_type===SlotType.Event||slot_shape===SlotShape.Box){ctx.rect(pos[0]-6+.5,pos[1]-5+.5,14,10)}else if(slot_shape===SlotShape.Arrow){ctx.moveTo(pos[0]+8,pos[1]+.5);ctx.lineTo(pos[0]-4,pos[1]+6+.5);ctx.lineTo(pos[0]-4,pos[1]-6+.5);ctx.closePath()}else if(slot_shape===SlotShape.Grid){const gridSize=3;const cellSize=2;const spacing=3;for(let x2=0;x2<gridSize;x2++){for(let y=0;y<gridSize;y++){ctx.rect(pos[0]-4+x2*spacing,pos[1]-4+y*spacing,cellSize,cellSize)}}doStroke=false}else{if(lowQuality){ctx.rect(pos[0]-4,pos[1]-4,8,8)}else{let radius;if(slot_shape===SlotShape.HollowCircle){doFill=false;doStroke=true;ctx.lineWidth=3;ctx.strokeStyle=ctx.fillStyle;radius=highlight?4:3}else{radius=highlight?5:4}ctx.arc(pos[0],pos[1],radius,0,Math.PI*2)}}if(doFill)ctx.fill();if(!lowQuality&&doStroke)ctx.stroke();const hideLabel=lowQuality||this.isWidgetInputSlot;if(!hideLabel){const text=this.renderingLabel;if(text){ctx.fillStyle=labelColor;if(labelPosition===LabelPosition.Right){if(this.dir==LinkDirection.UP){ctx.fillText(text,pos[0],pos[1]-10)}else{ctx.fillText(text,pos[0]+10,pos[1]+5)}}else{if(this.dir==LinkDirection.DOWN){ctx.fillText(text,pos[0],pos[1]-8)}else{ctx.fillText(text,pos[0]-10,pos[1]+5)}}}}if(this.hasErrors){ctx.lineWidth=2;ctx.strokeStyle="red";ctx.beginPath();ctx.arc(pos[0],pos[1],12,0,Math.PI*2);ctx.stroke()}ctx.fillStyle=originalFillStyle;ctx.strokeStyle=originalStrokeStyle;ctx.lineWidth=originalLineWidth}drawCollapsed(ctx){const[x2,y]=this.collapsedPos;const{fillStyle}=ctx;ctx.fillStyle="#686";ctx.beginPath();if(this.type===SlotType.Event||this.shape===RenderShape.BOX){ctx.rect(x2-7+.5,y-4,14,8)}else if(this.shape===RenderShape.ARROW){const isInput=this instanceof NodeInputSlot;if(isInput){ctx.moveTo(x2+8,y);ctx.lineTo(x2-4,y-4);ctx.lineTo(x2-4,y+4)}else{ctx.moveTo(x2+6,y);ctx.lineTo(x2-6,y-4);ctx.lineTo(x2-6,y+4)}ctx.closePath()}else{ctx.arc(x2,y,4,0,Math.PI*2)}ctx.fill();ctx.fillStyle=fillStyle}}class LGraphGroup{static minWidth=140;static minHeight=80;static resizeLength=10;static padding=4;static defaultColour="#335";id;color;title;font;font_size=LiteGraph.DEFAULT_GROUP_FONT||24;_bounding=new Float32Array([10,10,LGraphGroup.minWidth,LGraphGroup.minHeight]);_pos=this._bounding.subarray(0,2);_size=this._bounding.subarray(2,4);_nodes=[];_children=new Set;graph;flags={};selected;constructor(title,id){this.id=id??-1;this.title=title||"Group";const{pale_blue}=LGraphCanvas.node_colors;this.color=pale_blue?pale_blue.groupcolor:"#AAA"}setColorOption(colorOption){if(colorOption==null){delete this.color}else{this.color=colorOption.groupcolor}}getColorOption(){return Object.values(LGraphCanvas.node_colors).find(colorOption=>colorOption.groupcolor===this.color)??null}get pos(){return this._pos}set pos(v2){if(!v2||v2.length<2)return;this._pos[0]=v2[0];this._pos[1]=v2[1]}get size(){return this._size}set size(v2){if(!v2||v2.length<2)return;this._size[0]=Math.max(LGraphGroup.minWidth,v2[0]);this._size[1]=Math.max(LGraphGroup.minHeight,v2[1])}get boundingRect(){return this._bounding}get nodes(){return this._nodes}get titleHeight(){return this.font_size*1.4}get children(){return this._children}get pinned(){return!!this.flags.pinned}pin(value){const newState=value===void 0?!this.pinned:value;if(newState)this.flags.pinned=true;else delete this.flags.pinned}unpin(){this.pin(false)}configure(o){this.id=o.id;this.title=o.title;this._bounding.set(o.bounding);this.color=o.color;this.flags=o.flags||this.flags;if(o.font_size)this.font_size=o.font_size}serialize(){const b=this._bounding;return{id:this.id,title:this.title,bounding:[...b],color:this.color,font_size:this.font_size,flags:this.flags}}draw(graphCanvas,ctx){const{padding,resizeLength,defaultColour}=LGraphGroup;const font_size=this.font_size||LiteGraph.DEFAULT_GROUP_FONT_SIZE;const[x2,y]=this._pos;const[width2,height]=this._size;const color=this.color||defaultColour;ctx.globalAlpha=.25*graphCanvas.editor_alpha;ctx.fillStyle=color;ctx.strokeStyle=color;ctx.beginPath();ctx.rect(x2+.5,y+.5,width2,font_size*1.4);ctx.fill();ctx.fillStyle=color;ctx.strokeStyle=color;ctx.beginPath();ctx.rect(x2+.5,y+.5,width2,height);ctx.fill();ctx.globalAlpha=graphCanvas.editor_alpha;ctx.stroke();ctx.beginPath();ctx.moveTo(x2+width2,y+height);ctx.lineTo(x2+width2-resizeLength,y+height);ctx.lineTo(x2+width2,y+height-resizeLength);ctx.fill();ctx.font=`${font_size}px ${LiteGraph.GROUP_FONT}`;ctx.textAlign="left";ctx.fillText(this.title+(this.pinned?"📌":""),x2+padding,y+font_size);if(LiteGraph.highlight_selected_group&&this.selected){strokeShape(ctx,this._bounding,{title_height:this.titleHeight,padding})}}resize(width2,height){if(this.pinned)return false;this._size[0]=Math.max(LGraphGroup.minWidth,width2);this._size[1]=Math.max(LGraphGroup.minHeight,height);return true}move(deltaX,deltaY,skipChildren=false){if(this.pinned)return;this._pos[0]+=deltaX;this._pos[1]+=deltaY;if(skipChildren===true)return;for(const item of this._children){item.move(deltaX,deltaY)}}snapToGrid(snapTo){return this.pinned?false:snapPoint(this.pos,snapTo)}recomputeInsideNodes(){if(!this.graph)throw new NullGraphError;const{nodes,reroutes,groups}=this.graph;const children=this._children;this._nodes.length=0;children.clear();for(const node2 of nodes){if(containsCentre(this._bounding,node2.boundingRect)){this._nodes.push(node2);children.add(node2)}}for(const reroute of reroutes.values()){if(isPointInRect(reroute.pos,this._bounding))children.add(reroute)}for(const group of groups){if(containsRect(this._bounding,group._bounding))children.add(group)}groups.sort((a,b)=>{if(a===this){return children.has(b)?-1:0}else if(b===this){return children.has(a)?1:0}else{return 0}})}resizeTo(objects,padding=10){const boundingBox=createBounds(objects,padding);if(boundingBox===null)return;this.pos[0]=boundingBox[0];this.pos[1]=boundingBox[1]-this.titleHeight;this.size[0]=boundingBox[2];this.size[1]=boundingBox[3]+this.titleHeight}addNodes(nodes,padding=10){if(!this._nodes&&nodes.length===0)return;this.resizeTo([...this.children,...this._nodes,...nodes],padding)}getMenuOptions(){return[{content:this.pinned?"Unpin":"Pin",callback:()=>{if(this.pinned)this.unpin();else this.pin();this.setDirtyCanvas(false,true)}},null,{content:"Title",callback:LGraphCanvas.onShowPropertyEditor},{content:"Color",has_submenu:true,callback:LGraphCanvas.onMenuNodeColors},{content:"Font size",property:"font_size",type:"Number",callback:LGraphCanvas.onShowPropertyEditor},null,{content:"Remove",callback:LGraphCanvas.onMenuNodeRemove}]}isPointInTitlebar(x2,y){const b=this.boundingRect;return isInRectangle(x2,y,b[0],b[1],b[2],this.titleHeight)}isInResize(x2,y){const b=this.boundingRect;const right=b[0]+b[2];const bottom=b[1]+b[3];return x2<right&&y<bottom&&x2-right+(y-bottom)>-LGraphGroup.resizeLength}isPointInside=LGraphNode.prototype.isPointInside;setDirtyCanvas=LGraphNode.prototype.setDirtyCanvas}class Reroute{constructor(id,network,pos,parentId,linkIds,floatingLinkIds){this.id=id;this.#network=new WeakRef(network);this.parentId=parentId;if(pos)this.pos=pos;this.linkIds=new Set(linkIds);this.floatingLinkIds=new Set(floatingLinkIds)}static radius=10;static maxSplineOffset=80;static drawIdBadge=false;static slotRadius=5;static get slotOffset(){const gap=Reroute.slotRadius*.33;return Reroute.radius+gap+Reroute.slotRadius}#malloc=new Float32Array(8);#network;#parentId;get parentId(){return this.#parentId}set parentId(value){if(value===this.id)return;if(this.getReroutes()===null)return;this.#parentId=value}get parent(){return this.#network.deref()?.getReroute(this.#parentId)}floating;#pos=this.#malloc.subarray(0,2);get pos(){return this.#pos}set pos(value){if(!(value?.length>=2))throw new TypeError("Reroute.pos is an x,y point, and expects an indexable with at least two values.");this.#pos[0]=value[0];this.#pos[1]=value[1]}get boundingRect(){const{radius}=Reroute;const[x2,y]=this.#pos;return[x2-radius,y-radius,2*radius,2*radius]}get#hoverArea(){const xOffset=2*Reroute.slotOffset;const yOffset=2*Math.max(Reroute.radius,Reroute.slotRadius);const[x2,y]=this.#pos;return[x2-xOffset,y-yOffset,2*xOffset,2*yOffset]}get totalLinks(){return this.linkIds.size+this.floatingLinkIds.size}selected;linkIds;floatingLinkIds;cos=0;sin=0;controlPoint=this.#malloc.subarray(4,6);path;_centreAngle;_pos=this.#malloc.subarray(6,8);_dragging;_colour;get colour(){return this._colour??"#18184d"}#lastRenderTime=-Infinity;#inputSlot=new RerouteSlot(this,true);#outputSlot=new RerouteSlot(this,false);get isSlotHovered(){return this.isInputHovered||this.isOutputHovered}get isInputHovered(){return this.#inputSlot.hovering}get isOutputHovered(){return this.#outputSlot.hovering}get firstLink(){const linkId=this.linkIds.values().next().value;return linkId===void 0?void 0:this.#network.deref()?.links.get(linkId)}get firstFloatingLink(){const linkId=this.floatingLinkIds.values().next().value;return linkId===void 0?void 0:this.#network.deref()?.floatingLinks.get(linkId)}get origin_id(){return this.firstLink?.origin_id}get origin_slot(){return this.firstLink?.origin_slot}update(parentId,pos,linkIds,floating){this.parentId=parentId;if(pos)this.pos=pos;if(linkIds)this.linkIds=new Set(linkIds);this.floating=floating}validateLinks(links,floatingLinks){const{linkIds,floatingLinkIds}=this;for(const linkId of linkIds){if(!links.has(linkId))linkIds.delete(linkId)}for(const linkId of floatingLinkIds){if(!floatingLinks.has(linkId))floatingLinkIds.delete(linkId)}return linkIds.size>0||floatingLinkIds.size>0}getReroutes(visited=new Set){if(this.#parentId===void 0)return[this];if(visited.has(this))return null;visited.add(this);const parent=this.#network.deref()?.reroutes.get(this.#parentId);if(!parent){this.#parentId=void 0;return[this]}const reroutes=parent.getReroutes(visited);reroutes?.push(this);return reroutes}findNextReroute(withParentId,visited=new Set){if(this.#parentId===withParentId)return this;if(visited.has(this))return null;visited.add(this);if(this.#parentId===void 0)return;return this.#network.deref()?.reroutes.get(this.#parentId)?.findNextReroute(withParentId,visited)}findSourceOutput(){const link=this.firstLink??this.firstFloatingLink;if(!link)return;const node2=this.#network.deref()?.getNodeById(link.origin_id);if(!node2)return;return{node:node2,output:node2.outputs[link.origin_slot]}}findTargetInputs(){const network=this.#network.deref();if(!network)return;const results=[];addAllResults(network,this.linkIds,network.links);addAllResults(network,this.floatingLinkIds,network.floatingLinks);return results;function addAllResults(network2,linkIds,links){for(const linkId of linkIds){const link=links.get(linkId);if(!link)continue;const node2=network2.getNodeById(link.target_id);const input=node2?.inputs[link.target_slot];if(!input)continue;results.push({node:node2,input,link})}}}getFloatingLinks(from){const floatingLinks=this.#network.deref()?.floatingLinks;if(!floatingLinks)return;const idProp=from==="input"?"origin_id":"target_id";const out=[];for(const linkId of this.floatingLinkIds){const link=floatingLinks.get(linkId);if(link?.[idProp]===-1)out.push(link)}return out}setFloatingLinkOrigin(node2,output,index){const network=this.#network.deref();const floatingOutLinks=this.getFloatingLinks("output");if(!floatingOutLinks)throw new Error("[setFloatingLinkOrigin]: Invalid network.");if(!floatingOutLinks.length)return;output._floatingLinks??=new Set;for(const link of floatingOutLinks){output._floatingLinks.add(link);network?.getNodeById(link.origin_id)?.outputs[link.origin_slot]?._floatingLinks?.delete(link);link.origin_id=node2.id;link.origin_slot=index}}move(deltaX,deltaY){this.#pos[0]+=deltaX;this.#pos[1]+=deltaY}snapToGrid(snapTo){if(!snapTo)return false;const{pos}=this;pos[0]=snapTo*Math.round(pos[0]/snapTo);pos[1]=snapTo*Math.round(pos[1]/snapTo);return true}removeAllFloatingLinks(){for(const linkId of this.floatingLinkIds){this.removeFloatingLink(linkId)}}removeFloatingLink(linkId){const network=this.#network.deref();if(!network)return;const floatingLink=network.floatingLinks.get(linkId);if(!floatingLink){console.warn(`[Reroute.removeFloatingLink] Floating link not found: ${linkId}, ignoring and discarding ID.`);this.floatingLinkIds.delete(linkId);return}network.removeFloatingLink(floatingLink)}removeLink(link){const network=this.#network.deref();if(!network)return;const floatingLink=network.floatingLinks.get(link.id);if(link===floatingLink){this.floatingLinkIds.delete(link.id)}else{this.linkIds.delete(link.id)}}remove(){const network=this.#network.deref();if(!network)return;network.removeReroute(this.id)}calculateAngle(lastRenderTime,network,linkStart){if(!(lastRenderTime>this.#lastRenderTime))return;this.#lastRenderTime=lastRenderTime;const{id,pos:thisPos}=this;const angles=[];let sum=0;calculateAngles(this.linkIds,network.links);calculateAngles(this.floatingLinkIds,network.floatingLinks);if(!angles.length){this.cos=0;this.sin=0;this.controlPoint[0]=0;this.controlPoint[1]=0;return}sum/=angles.length;const originToReroute=Math.atan2(this.#pos[1]-linkStart[1],this.#pos[0]-linkStart[0]);let diff=(originToReroute-sum)*.5;if(Math.abs(diff)>Math.PI*.5)diff+=Math.PI;const dist=Math.min(Reroute.maxSplineOffset,distance(linkStart,this.#pos)*.25);const originDiff=originToReroute-diff;const cos=Math.cos(originDiff);const sin=Math.sin(originDiff);this.cos=cos;this.sin=sin;this.controlPoint[0]=dist*-cos;this.controlPoint[1]=dist*-sin;function calculateAngles(linkIds,links){for(const linkId of linkIds){const link=links.get(linkId);const pos=getNextPos(network,link,id);if(!pos)continue;const angle=getDirection(thisPos,pos);angles.push(angle);sum+=angle}}}draw(ctx,backgroundPattern){const{globalAlpha}=ctx;const{pos}=this;ctx.beginPath();ctx.arc(pos[0],pos[1],Reroute.radius,0,2*Math.PI);if(this.linkIds.size===0){ctx.fillStyle=backgroundPattern??"#797979";ctx.fill();ctx.globalAlpha=globalAlpha*.33}ctx.fillStyle=this.colour;ctx.lineWidth=Reroute.radius*.1;ctx.strokeStyle="rgb(0,0,0,0.5)";ctx.fill();ctx.stroke();ctx.fillStyle="#ffffff55";ctx.strokeStyle="rgb(0,0,0,0.3)";ctx.beginPath();ctx.arc(pos[0],pos[1],Reroute.radius*.8,0,2*Math.PI);ctx.fill();ctx.stroke();if(this.selected){ctx.strokeStyle="#fff";ctx.beginPath();ctx.arc(pos[0],pos[1],Reroute.radius*1.2,0,2*Math.PI);ctx.stroke()}if(Reroute.drawIdBadge){const idBadge=new LGraphBadge({text:this.id.toString()});const x2=pos[0]-idBadge.getWidth(ctx)*.5;const y=pos[1]-idBadge.height-Reroute.radius-2;idBadge.draw(ctx,x2,y)}ctx.globalAlpha=globalAlpha}drawSlots(ctx){this.#inputSlot.draw(ctx);this.#outputSlot.draw(ctx)}drawHighlight(ctx,colour){const{pos}=this;const{strokeStyle,lineWidth}=ctx;ctx.strokeStyle=colour;ctx.lineWidth=1;ctx.beginPath();ctx.arc(pos[0],pos[1],Reroute.radius*1.5,0,2*Math.PI);ctx.stroke();ctx.strokeStyle=strokeStyle;ctx.lineWidth=lineWidth}updateVisibility(pos){const input=this.#inputSlot;const output=this.#outputSlot;input.dirty=false;output.dirty=false;const{firstFloatingLink}=this;const hasLink=!!this.firstLink;const showInput=hasLink||firstFloatingLink?.isFloatingOutput;const showOutput=hasLink||firstFloatingLink?.isFloatingInput;const showEither=showInput||showOutput;if(showEither&&isPointInRect(pos,this.#hoverArea)){const outlineOnly=this.#contains(pos);if(showInput)input.update(pos,outlineOnly);if(showOutput)output.update(pos,outlineOnly)}else{this.hideSlots()}return input.dirty||output.dirty}hideSlots(){this.#inputSlot.hide();this.#outputSlot.hide()}containsPoint(pos){return isPointInRect(pos,this.#hoverArea)&&this.#contains(pos)}#contains(pos){return distance(this.pos,pos)<=Reroute.radius}asSerialisable(){const{id,parentId,pos,linkIds}=this;return{id,parentId,pos:[pos[0],pos[1]],linkIds:[...linkIds],floating:this.floating?{slotType:this.floating.slotType}:void 0}}}class RerouteSlot{#reroute;#offsetMultiplier;get pos(){const[x2,y]=this.#reroute.pos;return[x2+Reroute.slotOffset*this.#offsetMultiplier,y]}dirty=false;#hovering=false;get hovering(){return this.#hovering}set hovering(value){if(!Object.is(this.#hovering,value)){this.#hovering=value;this.dirty=true}}#showOutline=false;get showOutline(){return this.#showOutline}set showOutline(value){if(!Object.is(this.#showOutline,value)){this.#showOutline=value;this.dirty=true}}constructor(reroute,isInput){this.#reroute=reroute;this.#offsetMultiplier=isInput?-1:1}update(pos,outlineOnly){if(outlineOnly){this.hovering=false;this.showOutline=true}else{const dist=distance(this.pos,pos);this.hovering=dist<=2*Reroute.slotRadius;this.showOutline=dist<=5*Reroute.slotRadius}}hide(){this.hovering=false;this.showOutline=false}draw(ctx){const{fillStyle,strokeStyle,lineWidth}=ctx;const{showOutline,hovering,pos:[x2,y]}=this;if(!showOutline)return;try{ctx.fillStyle=hovering?this.#reroute.colour:"rgba(127,127,127,0.3)";ctx.strokeStyle="rgb(0,0,0,0.5)";ctx.lineWidth=1;ctx.beginPath();ctx.arc(x2,y,Reroute.slotRadius,0,2*Math.PI);ctx.fill();ctx.stroke()}finally{ctx.fillStyle=fillStyle;ctx.strokeStyle=strokeStyle;ctx.lineWidth=lineWidth}}}function getNextPos(network,link,id){if(!link)return;const linkPos=LLink.findNextReroute(network,link,id)?.pos;if(linkPos)return linkPos;if(link.target_id===-1||link.target_slot===-1)return;return network.getNodeById(link.target_id)?.getInputPos(link.target_slot)}function getDirection(fromPos,toPos){return Math.atan2(toPos[1]-fromPos[1],toPos[0]-fromPos[0])}function stringOrEmpty(value){return value==null?"":String(value)}function parseSlotTypes(type){return type==""||type=="0"?["*"]:String(type).toLowerCase().split(",")}function nextUniqueName(name,existingNames=[]){let i=1;const baseName=name;while(existingNames.includes(name)){name=`${baseName}_${i++}`}return name}class ConstrainedSize{#width=0;#height=0;#desiredWidth=0;#desiredHeight=0;minWidth=0;minHeight=0;maxWidth=Infinity;maxHeight=Infinity;get width(){return this.#width}get height(){return this.#height}get desiredWidth(){return this.#desiredWidth}set desiredWidth(value){this.#desiredWidth=value;this.#width=clamp(value,this.minWidth,this.maxWidth)}get desiredHeight(){return this.#desiredHeight}set desiredHeight(value){this.#desiredHeight=value;this.#height=clamp(value,this.minHeight,this.maxHeight)}constructor(width2,height){this.desiredWidth=width2;this.desiredHeight=height}static fromSize(size){return new ConstrainedSize(size[0],size[1])}static fromRect(rect){return new ConstrainedSize(rect[2],rect[3])}setSize(size){this.desiredWidth=size[0];this.desiredHeight=size[1]}setValues(width2,height){this.desiredWidth=width2;this.desiredHeight=height}toSize(){return[this.#width,this.#height]}}class SubgraphSlot extends SlotBase{static get defaultHeight(){return LiteGraph.NODE_SLOT_HEIGHT}#pos=new Float32Array(2);measurement=new ConstrainedSize(SubgraphSlot.defaultHeight,SubgraphSlot.defaultHeight);id;parent;type;linkIds=[];boundingRect=new Rectangle(0,0,0,SubgraphSlot.defaultHeight);get pos(){return this.#pos}set pos(value){if(!value||value.length<2)return;this.#pos[0]=value[0];this.#pos[1]=value[1]}get isConnected(){return this.linkIds.length>0}get displayName(){return this.label??this.localized_name??this.name}constructor(slot,parent){super(slot.name,slot.type);Object.assign(this,slot);this.id=slot.id??createUuidv4();this.type=slot.type;this.parent=parent}isPointerOver=false;containsPoint(point){return this.boundingRect.containsPoint(point)}onPointerMove(e2){this.isPointerOver=this.boundingRect.containsXy(e2.canvasX,e2.canvasY)}getLinks(){const links=[];const{subgraph}=this.parent;for(const id of this.linkIds){const link=subgraph.getLink(id);if(link)links.push(link)}return links}decrementSlots(inputsOrOutputs){const{links}=this.parent.subgraph;const linkProperty=inputsOrOutputs==="inputs"?"origin_slot":"target_slot";for(const linkId of this.linkIds){const link=links.get(linkId);if(link)link[linkProperty]--;else console.warn("decrementSlots: link ID not found",linkId)}}measure(){const width2=LGraphCanvas._measureText?.(this.displayName)??0;const{defaultHeight}=SubgraphSlot;this.measurement.setValues(width2+defaultHeight,defaultHeight);return this.measurement.toSize()}disconnect(){const{subgraph}=this.parent;for(const linkId of this.linkIds){subgraph.removeLink(linkId)}this.linkIds.length=0}draw({ctx,colorContext,lowQuality,fromSlot,editorAlpha=1}){const shape=this.shape;const{isPointerOver,pos:[x2,y]}=this;const isValidTarget=fromSlot?this.isValidTarget(fromSlot):true;const isValid=!fromSlot||isValidTarget;const highlight=isValid&&isPointerOver;const previousAlpha=ctx.globalAlpha;ctx.globalAlpha=isValid?editorAlpha:.4*editorAlpha;ctx.beginPath();const color=this.renderingColor(colorContext);if(lowQuality){ctx.fillStyle=color;ctx.rect(x2-4,y-4,8,8);ctx.fill()}else if(shape===SlotShape.HollowCircle){ctx.lineWidth=3;ctx.strokeStyle=color;const radius=highlight?4:3;ctx.arc(x2,y,radius,0,Math.PI*2);ctx.stroke()}else{ctx.fillStyle=color;const radius=highlight?5:4;ctx.arc(x2,y,radius,0,Math.PI*2);ctx.fill()}if(this.displayName){const[labelX,labelY]=this.labelPos;ctx.fillStyle=highlight?"white":LiteGraph.NODE_TEXT_COLOR||"#AAA";ctx.fillText(this.displayName,labelX,labelY)}ctx.globalAlpha=previousAlpha}asSerialisable(){const{id,name,type,linkIds,localized_name,label,dir,shape,color_off,color_on,pos}=this;return{id,name,type,linkIds,localized_name,label,dir,shape,color_off,color_on,pos}}}class SubgraphOutput extends SubgraphSlot{connect(slot,node2,afterRerouteId){const{subgraph}=this.parent;if(!LiteGraph.isValidConnection(slot.type,this.type))return;const outputIndex=node2.outputs.indexOf(slot);if(outputIndex===-1)throw new Error("Slot is not an output of the given node");if(node2.onConnectOutput?.(outputIndex,this.type,this,this.parent,-1)===false)return;const existingLink=this.getLinks().at(0);if(existingLink!=null){subgraph.beforeChange();existingLink.disconnect(subgraph,"input");const resolved=existingLink.resolve(subgraph);const links=resolved.output?.links;if(links)removeFromArray(links,existingLink.id)}const link=new LLink(++subgraph.state.lastLinkId,slot.type,node2.id,outputIndex,this.parent.id,this.parent.slots.indexOf(this),afterRerouteId);subgraph._links.set(link.id,link);this.linkIds[0]=link.id;slot.links??=[];slot.links.push(link.id);const reroutes=LLink.getReroutes(subgraph,link);for(const reroute of reroutes){reroute.linkIds.add(link.id);if(reroute.floating)delete reroute.floating;reroute._dragging=void 0}const lastReroute=reroutes.at(-1);if(lastReroute){for(const linkId of lastReroute.floatingLinkIds){const link2=subgraph.floatingLinks.get(linkId);if(link2?.parentId===lastReroute.id){subgraph.removeFloatingLink(link2)}}}subgraph._version++;node2.onConnectionsChange?.(NodeSlotType.OUTPUT,outputIndex,true,link,slot);subgraph.afterChange();return link}get labelPos(){const[x2,y,,height]=this.boundingRect;return[x2+height,y+height*.5]}arrange(rect){const[left,top,width2,height]=rect;const{boundingRect:b,pos}=this;b[0]=left;b[1]=top;b[2]=width2;b[3]=height;pos[0]=left+height*.5;pos[1]=top+height*.5}isValidTarget(fromSlot){if(isNodeSlot(fromSlot)){return"links"in fromSlot&&LiteGraph.isValidConnection(fromSlot.type,this.type)}if(isSubgraphInput(fromSlot)){return LiteGraph.isValidConnection(fromSlot.type,this.type)}return false}}class EmptySubgraphOutput extends SubgraphOutput{constructor(parent){super({id:zeroUuid,name:"",type:""},parent)}connect(slot,node2,afterRerouteId){const{subgraph}=this.parent;const existingNames=subgraph.outputs.map(x2=>x2.name);const name=nextUniqueName(slot.name,existingNames);const output=subgraph.addOutput(name,String(slot.type));return output.connect(slot,node2,afterRerouteId)}get labelPos(){const[x2,y,,height]=this.boundingRect;return[x2,y+height*.5]}}class SubgraphIONodeBase{constructor(subgraph){this.subgraph=subgraph}static margin=10;static minWidth=100;static roundedRadius=10;#boundingRect=new Rectangle;get boundingRect(){return this.#boundingRect}selected=false;pinned=false;removable=false;isPointerOver=false;get pos(){return this.boundingRect.pos}set pos(value){this.boundingRect.pos=value}get size(){return this.boundingRect.size}set size(value){this.boundingRect.size=value}get sideLineWidth(){return this.isPointerOver?2.5:2}get sideStrokeStyle(){return this.isPointerOver?"white":"#efefef"}move(deltaX,deltaY){this.pos[0]+=deltaX;this.pos[1]+=deltaY}snapToGrid(snapTo){return this.pinned?false:snapPoint(this.pos,snapTo)}containsPoint(point){return this.boundingRect.containsPoint(point)}onPointerMove(e2){const containsPoint=this.boundingRect.containsXy(e2.canvasX,e2.canvasY);let underPointer=containsPoint?CanvasItem.SubgraphIoNode:CanvasItem.Nothing;if(containsPoint){if(!this.isPointerOver)this.onPointerEnter();for(const slot of this.allSlots){slot.onPointerMove(e2);if(slot.isPointerOver)underPointer|=CanvasItem.SubgraphIoSlot}}else if(this.isPointerOver){this.onPointerLeave()}return underPointer}onPointerEnter(){this.isPointerOver=true}onPointerLeave(){this.isPointerOver=false;for(const slot of this.slots){slot.isPointerOver=false}}getSlotInPosition(x2,y){for(const slot of this.allSlots){if(slot.boundingRect.containsXy(x2,y)){return slot}}}showSlotContextMenu(slot,event){const options=this.#getSlotMenuOptions(slot);if(!(options.length>0))return;new LiteGraph.ContextMenu(options,{event,title:slot.name||"Subgraph Output",callback:item=>{this.#onSlotMenuAction(item,slot,event)}})}#getSlotMenuOptions(slot){const options=[];if(slot!==this.emptySlot&&slot.linkIds.length>0){options.push({content:"Disconnect Links",value:"disconnect"})}if(slot!==this.emptySlot){options.push({content:"Remove Slot",value:"remove"},{content:"Rename Slot",value:"rename"})}return options}#onSlotMenuAction(selectedItem,slot,event){switch(selectedItem.value){case"disconnect":slot.disconnect();break;case"remove":if(slot!==this.emptySlot){this.removeSlot(slot)}break;case"rename":if(slot!==this.emptySlot){this.subgraph.canvasAction(c=>c.prompt("Slot name",slot.name,newName=>{if(newName)this.renameSlot(slot,newName)},event))}break}this.subgraph.setDirtyCanvas(true)}arrange(){const{minWidth,roundedRadius}=SubgraphIONodeBase;const[,y]=this.boundingRect;const x2=this.slotAnchorX;const{size}=this;let maxWidth=minWidth;let currentY=y+roundedRadius;for(const slot of this.allSlots){const[slotWidth,slotHeight]=slot.measure();slot.arrange([x2,currentY,slotWidth,slotHeight]);currentY+=slotHeight;if(slotWidth>maxWidth)maxWidth=slotWidth}size[0]=maxWidth+2*roundedRadius;size[1]=currentY-y+roundedRadius}draw(ctx,colorContext,fromSlot,editorAlpha){const{lineWidth,strokeStyle,fillStyle,font,textBaseline}=ctx;this.drawProtected(ctx,colorContext,fromSlot,editorAlpha);Object.assign(ctx,{lineWidth,strokeStyle,fillStyle,font,textBaseline})}drawSlots(ctx,colorContext,fromSlot,editorAlpha){ctx.fillStyle="#AAA";ctx.font="12px Arial";ctx.textBaseline="middle";for(const slot of this.allSlots){slot.draw({ctx,colorContext,fromSlot,editorAlpha})}}configure(data){this.#boundingRect.set(data.bounding);this.pinned=data.pinned??false}asSerialisable(){return{id:this.id,bounding:this.boundingRect.export(),pinned:this.pinned?true:void 0}}}class SubgraphOutputNode extends SubgraphIONodeBase{id=SUBGRAPH_OUTPUT_ID;emptySlot=new EmptySubgraphOutput(this);get slots(){return this.subgraph.outputs}get allSlots(){return[...this.slots,this.emptySlot]}get slotAnchorX(){const[x2]=this.boundingRect;return x2+SubgraphIONodeBase.roundedRadius}onPointerDown(e2,pointer,linkConnector){if(e2.button===0){for(const slot of this.allSlots){const slotBounds=Rectangle.fromCentre(slot.pos,slot.boundingRect.height);if(slotBounds.containsXy(e2.canvasX,e2.canvasY)){pointer.onDragStart=()=>{linkConnector.dragNewFromSubgraphOutput(this.subgraph,this,slot)};pointer.onDragEnd=eUp=>{linkConnector.dropLinks(this.subgraph,eUp)};pointer.finally=()=>{linkConnector.reset(true)}}}}else if(e2.button===2){const slot=this.getSlotInPosition(e2.canvasX,e2.canvasY);if(slot)this.showSlotContextMenu(slot,e2)}}renameSlot(slot,name){this.subgraph.renameOutput(slot,name)}removeSlot(slot){this.subgraph.removeOutput(slot)}canConnectTo(outputNode,fromSlot,output){return outputNode.canConnectTo(this,fromSlot,output)}connectByTypeOutput(slot,target_node,target_slotType,optsIn){const outputSlot=target_node.findOutputByType(target_slotType);if(!outputSlot)return;return this.slots[slot].connect(outputSlot.slot,target_node,optsIn?.afterRerouteId)}findInputByType(type){return findFreeSlotOfType(this.slots,type,slot=>slot.linkIds.length>0)?.slot}drawProtected(ctx,colorContext,fromSlot,editorAlpha){const{roundedRadius}=SubgraphIONodeBase;const transform=ctx.getTransform();const[x2,y,,height]=this.boundingRect;ctx.translate(x2,y);ctx.strokeStyle=this.sideStrokeStyle;ctx.lineWidth=this.sideLineWidth;ctx.beginPath();ctx.arc(roundedRadius,roundedRadius,roundedRadius,Math.PI,Math.PI*1.5);ctx.moveTo(0,roundedRadius);ctx.lineTo(0,height-roundedRadius);ctx.arc(roundedRadius,height-roundedRadius,roundedRadius,Math.PI,Math.PI*.5,true);ctx.stroke();ctx.setTransform(transform);this.drawSlots(ctx,colorContext,fromSlot,editorAlpha)}}function splitPositionables(items){const nodes=new Set;const reroutes=new Set;const groups=new Set;const subgraphInputNodes=new Set;const subgraphOutputNodes=new Set;const unknown=new Set;for(const item of items){switch(true){case item instanceof LGraphNode:nodes.add(item);break;case item instanceof LGraphGroup:groups.add(item);break;case item instanceof Reroute:reroutes.add(item);break;case item instanceof SubgraphInputNode:subgraphInputNodes.add(item);break;case item instanceof SubgraphOutputNode:subgraphOutputNodes.add(item);break;default:unknown.add(item);break}}return{nodes,reroutes,groups,subgraphInputNodes,subgraphOutputNodes,unknown}}function getBoundaryLinks(graph,items){const internalLinks=[];const boundaryLinks=[];const boundaryInputLinks=[];const boundaryOutputLinks=[];const boundaryFloatingLinks=[];const visited=new WeakSet;for(const item of items){if(visited.has(item))continue;visited.add(item);if(item instanceof LGraphNode){const node2=item;if(node2.inputs){for(const input of node2.inputs){addFloatingLinks(input._floatingLinks);if(input.link==null)continue;const resolved=LLink.resolve(input.link,graph);if(!resolved){console.debug(`Failed to resolve link ID [${input.link}]`);continue}const{link,outputNode}=resolved;if(outputNode){if(!items.has(outputNode)){boundaryInputLinks.push(link)}else{internalLinks.push(link)}}else if(link.origin_id===SUBGRAPH_INPUT_ID){boundaryInputLinks.push(link)}}}if(node2.outputs){for(const output of node2.outputs){addFloatingLinks(output._floatingLinks);if(!output.links)continue;const many=LLink.resolveMany(output.links,graph);for(const{link,inputNode}of many){if(link.target_id===SUBGRAPH_OUTPUT_ID||inputNode&&!items.has(inputNode)){boundaryOutputLinks.push(link)}}}}}else if(item instanceof Reroute){const reroute=item;const results=LLink.resolveMany(reroute.linkIds,graph);for(const{link}of results){const reroutes=LLink.getReroutes(graph,link);const reroutesOutside=reroutes.filter(reroute2=>!items.has(reroute2));const{inputNode,outputNode}=link.resolve(graph);if(reroutesOutside.length||inputNode&&!items.has(inputNode)||outputNode&&!items.has(outputNode)){boundaryLinks.push(link)}}}}return{boundaryLinks,boundaryFloatingLinks,internalLinks,boundaryInputLinks,boundaryOutputLinks};function addFloatingLinks(floatingLinks){if(!floatingLinks)return;for(const link of floatingLinks){const crossesBoundary=LLink.getReroutes(graph,link).some(reroute=>!items.has(reroute));if(crossesBoundary)boundaryFloatingLinks.push(link)}}}function multiClone(nodes){const clonedNodes=[];for(const node2 of nodes){const newNode=LiteGraph.createNode(node2.type);if(!newNode){console.warn("Failed to create node",node2.type);continue}const data=LiteGraph.cloneObject(node2.serialize());newNode.configure(data);clonedNodes.push(newNode.serialize())}return clonedNodes}function groupResolvedByOutput(resolvedConnections){const groupedByOutput=new Map;for(const resolved of resolvedConnections){const groupBy=resolved.subgraphInput??resolved.output??{};const group=groupedByOutput.get(groupBy);if(group){group.push(resolved)}else{groupedByOutput.set(groupBy,[resolved])}}return groupedByOutput}function mapSubgraphInputsAndLinks(resolvedInputLinks,links){const groupedByOutput=groupResolvedByOutput(resolvedInputLinks);const inputs=[];for(const[,connections]of groupedByOutput){const inputLinks=[];for(const resolved of connections){const{link,input:input2}=resolved;if(!input2)continue;const linkData=link.asSerialisable();linkData.origin_id=SUBGRAPH_INPUT_ID;linkData.origin_slot=inputs.length;links.push(linkData);inputLinks.push(linkData)}const{input}=connections[0];if(!input)continue;const{color_off,color_on,dir,hasErrors,label,localized_name,name,shape,type}=input;const uniqueName=nextUniqueName(name,inputs.map(input2=>input2.name));const uniqueLocalizedName=localized_name?nextUniqueName(localized_name,inputs.map(input2=>input2.localized_name??"")):void 0;const inputData={id:createUuidv4(),type:String(type),linkIds:inputLinks.map(link=>link.id),name:uniqueName,color_off,color_on,dir,label,localized_name:uniqueLocalizedName,hasErrors,shape};inputs.push(inputData)}return inputs}function mapSubgraphOutputsAndLinks(resolvedOutputLinks,links){const groupedByOutput=groupResolvedByOutput(resolvedOutputLinks);const outputs=[];for(const[,connections]of groupedByOutput){const outputLinks=[];for(const resolved of connections){const{link,output:output2}=resolved;if(!output2)continue;const linkData=link.asSerialisable();linkData.target_id=SUBGRAPH_OUTPUT_ID;linkData.target_slot=outputs.length;links.push(linkData);outputLinks.push(linkData)}const{output}=connections[0];if(!output)continue;const{color_off,color_on,dir,hasErrors,label,localized_name,name,shape,type}=output;const uniqueName=nextUniqueName(name,outputs.map(output2=>output2.name));const uniqueLocalizedName=localized_name?nextUniqueName(localized_name,outputs.map(output2=>output2.localized_name??"")):void 0;const outputData={id:createUuidv4(),type:String(type),linkIds:outputLinks.map(link=>link.id),name:uniqueName,color_off,color_on,dir,label,localized_name:uniqueLocalizedName,hasErrors,shape};outputs.push(structuredClone(outputData))}return outputs}function getDirectSubgraphIds(graph){const subgraphIds=new Set;for(const node2 of graph._nodes){if(node2.isSubgraphNode()){subgraphIds.add(node2.type)}}return subgraphIds}function findUsedSubgraphIds(rootGraph,subgraphRegistry){const usedSubgraphIds=new Set;const toVisit=[rootGraph];while(toVisit.length>0){const graph=toVisit.shift();const directIds=getDirectSubgraphIds(graph);for(const id of directIds){if(!usedSubgraphIds.has(id)){usedSubgraphIds.add(id);const subgraph=subgraphRegistry.get(id);if(subgraph){toVisit.push(subgraph)}}}}return usedSubgraphIds}function isSubgraphInput(slot){return slot!=null&&typeof slot==="object"&&"parent"in slot&&slot.parent instanceof SubgraphInputNode}function isSubgraphOutput(slot){return slot!=null&&typeof slot==="object"&&"parent"in slot&&slot.parent instanceof SubgraphOutputNode}function isNodeSlot(slot){return slot!=null&&typeof slot==="object"&&("link"in slot||"links"in slot)}class NodeInputSlot extends NodeSlot{link;get isWidgetInputSlot(){return!!this.widget}#widget;get _widget(){return this.#widget?.deref()}set _widget(widget){this.#widget=widget?new WeakRef(widget):void 0}get collapsedPos(){return[0,LiteGraph.NODE_TITLE_HEIGHT*-.5]}constructor(slot,node2){super(slot,node2);this.link=slot.link}get isConnected(){return this.link!=null}isValidTarget(fromSlot){if("links"in fromSlot){return LiteGraph.isValidConnection(fromSlot.type,this.type)}if(isSubgraphInput(fromSlot)){return LiteGraph.isValidConnection(fromSlot.type,this.type)}return false}draw(ctx,options){const{textAlign}=ctx;ctx.textAlign="left";super.draw(ctx,{...options,labelPosition:LabelPosition.Right,doStroke:false});ctx.textAlign=textAlign}}class NodeOutputSlot extends NodeSlot{#node;links;_data;slot_index;get isWidgetInputSlot(){return false}get collapsedPos(){return[this.#node._collapsed_width??LiteGraph.NODE_COLLAPSED_WIDTH,LiteGraph.NODE_TITLE_HEIGHT*-.5]}constructor(slot,node2){super(slot,node2);this.links=slot.links;this._data=slot._data;this.slot_index=slot.slot_index;this.#node=node2}isValidTarget(fromSlot){if("link"in fromSlot){return LiteGraph.isValidConnection(this.type,fromSlot.type)}if(isSubgraphOutput(fromSlot)){return LiteGraph.isValidConnection(this.type,fromSlot.type)}return false}get isConnected(){return this.links!=null&&this.links.length>0}draw(ctx,options){const{textAlign,strokeStyle}=ctx;ctx.textAlign="right";ctx.strokeStyle="black";super.draw(ctx,{...options,labelPosition:LabelPosition.Left,doStroke:true});ctx.textAlign=textAlign;ctx.strokeStyle=strokeStyle}}function shallowCloneCommonProps(slot){const{color_off,color_on,dir,label,localized_name,locked,name,nameLocked,removable,shape,type}=slot;return{color_off,color_on,dir,label,localized_name,locked,name,nameLocked,removable,shape,type}}function inputAsSerialisable(slot){const{link}=slot;const widgetOrPos=slot.widget?{widget:{name:slot.widget.name}}:{pos:slot.pos};return{...shallowCloneCommonProps(slot),...widgetOrPos,link}}function outputAsSerialisable(slot){const{pos,slot_index,links,widget}=slot;const outputWidget=widget?{widget:{name:widget.name}}:null;return{...shallowCloneCommonProps(slot),...outputWidget,pos,slot_index,links}}function isINodeInputSlot(slot){return"link"in slot}function isWidgetInputSlot(slot){return!!slot.widget}const UNIQUE_MESSAGE_LIMIT=1e4;const sentWarnings=new Set;function warnDeprecated(message,source){if(!LiteGraph.alwaysRepeatWarnings){if(sentWarnings.has(message))return;if(sentWarnings.size>UNIQUE_MESSAGE_LIMIT)return;sentWarnings.add(message)}for(const callback of LiteGraph.onDeprecationWarning){callback(message,source)}}function distributeSpace(totalSpace,requests){if(requests.length===0)return[];const totalMinSize=requests.reduce((sum,req)=>sum+req.minSize,0);if(totalSpace<totalMinSize){return requests.map(req=>req.minSize)}let allocations=requests.map(req=>({computedSize:req.minSize,maxSize:req.maxSize??Infinity,remaining:(req.maxSize??Infinity)-req.minSize}));let remainingSpace=totalSpace-totalMinSize;while(remainingSpace>0&&allocations.some(alloc=>alloc.remaining>0)){const growableItems=allocations.filter(alloc=>alloc.remaining>0).length;if(growableItems===0)break;const sharePerItem=remainingSpace/growableItems;let spaceUsedThisRound=0;allocations=allocations.map(alloc=>{if(alloc.remaining<=0)return alloc;const growth=Math.min(sharePerItem,alloc.remaining);spaceUsedThisRound+=growth;return{...alloc,computedSize:alloc.computedSize+growth,remaining:alloc.remaining-growth}});remainingSpace-=spaceUsedThisRound;if(spaceUsedThisRound===0)break}return allocations.map(({computedSize})=>computedSize)}function truncateText(ctx,text,maxWidth,ellipsis="..."){const textWidth=ctx.measureText(text).width;if(textWidth<=maxWidth||maxWidth<=0){return text}const ellipsisWidth=ctx.measureText(ellipsis).width;const availableWidth=maxWidth-ellipsisWidth;if(availableWidth<=0){return ellipsis}let low=0;let high=text.length;let bestFit=0;while(low<=high){const mid=Math.floor((low+high)/2);const testText=text.substring(0,mid);const testWidth=ctx.measureText(testText).width;if(testWidth<=availableWidth){bestFit=mid;low=mid+1}else{high=mid-1}}return text.substring(0,bestFit)+ellipsis}function toClass(cls,...args){return args[0]instanceof cls?args[0]:new cls(...args)}function isColorable(obj){return typeof obj==="object"&&obj!==null&&"setColorOption"in obj&&"getColorOption"in obj}class BaseWidget{static margin=15;static arrowMargin=6;static arrowWidth=10;static minValueWidth=42;static labelValueGap=5;#node;get node(){return this.#node}linkedWidgets;name;options;label;type;y=0;last_y;width;disabled;computedDisabled;hidden;advanced;tooltip;element;#value;get value(){return this.#value}set value(value){this.#value=value}constructor(widget,node2){this.#node=node2??widget.node;this.name=widget.name;this.options=widget.options;this.type=widget.type;const{node:_,outline_color,background_color,height,text_color,secondary_text_color,disabledTextColor,displayName,displayValue,labelBaseline,...safeValues}=widget;Object.assign(this,safeValues)}get outline_color(){return this.advanced?LiteGraph.WIDGET_ADVANCED_OUTLINE_COLOR:LiteGraph.WIDGET_OUTLINE_COLOR}get background_color(){return LiteGraph.WIDGET_BGCOLOR}get height(){return LiteGraph.NODE_WIDGET_HEIGHT}get text_color(){return LiteGraph.WIDGET_TEXT_COLOR}get secondary_text_color(){return LiteGraph.WIDGET_SECONDARY_TEXT_COLOR}get disabledTextColor(){return LiteGraph.WIDGET_DISABLED_TEXT_COLOR}get displayName(){return this.label||this.name}get _displayValue(){return this.computedDisabled?"":String(this.value)}get labelBaseline(){return this.y+this.height*.7}drawWidgetShape(ctx,{width:width2,showText}){const{height,y}=this;const{margin}=BaseWidget;ctx.textAlign="left";ctx.strokeStyle=this.outline_color;ctx.fillStyle=this.background_color;ctx.beginPath();if(showText){ctx.roundRect(margin,y,width2-margin*2,height,[height*.5])}else{ctx.rect(margin,y,width2-margin*2,height)}ctx.fill();if(showText&&!this.computedDisabled)ctx.stroke()}drawTruncatingText({ctx,width:width2,leftPadding=5,rightPadding=20}){const{height,y}=this;const{margin}=BaseWidget;const{displayName,_displayValue}=this;const labelWidth=ctx.measureText(displayName).width;const valueWidth=ctx.measureText(_displayValue).width;const gap=BaseWidget.labelValueGap;const x2=margin*2+leftPadding;const totalWidth=width2-x2-2*margin-rightPadding;const requiredWidth=labelWidth+gap+valueWidth;const area=new Rectangle(x2,y,totalWidth,height*.7);ctx.fillStyle=this.secondary_text_color;if(requiredWidth<=totalWidth){drawTextInArea({ctx,text:displayName,area,align:"left"})}else if(LiteGraph.truncateWidgetTextEvenly){const scale=(totalWidth-gap)/(requiredWidth-gap);area.width=labelWidth*scale;drawTextInArea({ctx,text:displayName,area,align:"left"});area.right=x2+totalWidth;area.setWidthRightAnchored(valueWidth*scale)}else if(LiteGraph.truncateWidgetValuesFirst){const cappedLabelWidth=Math.min(labelWidth,totalWidth);area.width=cappedLabelWidth;drawTextInArea({ctx,text:displayName,area,align:"left"});area.right=x2+totalWidth;area.setWidthRightAnchored(Math.max(totalWidth-gap-cappedLabelWidth,0))}else{const cappedValueWidth=Math.min(valueWidth,totalWidth);area.width=Math.max(totalWidth-gap-cappedValueWidth,0);drawTextInArea({ctx,text:displayName,area,align:"left"});area.right=x2+totalWidth;area.setWidthRightAnchored(cappedValueWidth)}ctx.fillStyle=this.text_color;drawTextInArea({ctx,text:_displayValue,area,align:"right"})}setValue(value,{e:e2,node:node2,canvas:canvas2}){const oldValue=this.value;if(value===this.value)return;const v2=this.type==="number"?Number(value):value;this.value=v2;if(this.options?.property&&node2.properties[this.options.property]!==void 0){node2.setProperty(this.options.property,v2)}const pos=canvas2.graph_mouse;this.callback?.(this.value,canvas2,node2,pos,e2);node2.onWidgetChanged?.(this.name??"",v2,oldValue,this);if(node2.graph)node2.graph._version++}createCopyForNode(node2){const cloned=new this.constructor(this,node2);cloned.value=this.value;return cloned}}class BooleanWidget extends BaseWidget{type="toggle";drawWidget(ctx,{width:width2,showText=true}){const{height,y}=this;const{margin}=BaseWidget;this.drawWidgetShape(ctx,{width:width2,showText});ctx.fillStyle=this.value?"#89A":"#333";ctx.beginPath();ctx.arc(width2-margin*2,y+height*.5,height*.36,0,Math.PI*2);ctx.fill();if(showText){this.drawLabel(ctx,margin*2);this.drawValue(ctx,width2-40)}}drawLabel(ctx,x2){ctx.fillStyle=this.secondary_text_color;const{displayName}=this;if(displayName)ctx.fillText(displayName,x2,this.labelBaseline)}drawValue(ctx,x2){ctx.fillStyle=this.value?this.text_color:this.secondary_text_color;ctx.textAlign="right";const value=this.value?this.options.on||"true":this.options.off||"false";ctx.fillText(value,x2,this.labelBaseline)}onClick(options){this.setValue(!this.value,options)}}class ButtonWidget extends BaseWidget{type="button";clicked;constructor(widget,node2){super(widget,node2);this.clicked??=false}drawWidget(ctx,{width:width2,showText=true}){const{fillStyle,strokeStyle,textAlign}=ctx;const{height,y}=this;const{margin}=BaseWidget;ctx.fillStyle=this.background_color;if(this.clicked){ctx.fillStyle="#AAA";this.clicked=false}ctx.fillRect(margin,y,width2-margin*2,height);if(showText&&!this.computedDisabled){ctx.strokeStyle=this.outline_color;ctx.strokeRect(margin,y,width2-margin*2,height)}if(showText)this.drawLabel(ctx,width2*.5);Object.assign(ctx,{textAlign,strokeStyle,fillStyle})}drawLabel(ctx,x2){ctx.textAlign="center";ctx.fillStyle=this.text_color;ctx.fillText(this.displayName,x2,this.y+this.height*.7)}onClick({e:e2,node:node2,canvas:canvas2}){const pos=canvas2.graph_mouse;this.clicked=true;canvas2.setDirty(true);this.callback?.(this,canvas2,node2,pos,e2)}}class BaseSteppedWidget extends BaseWidget{drawArrowButtons(ctx,width2){const{height,text_color,disabledTextColor,y}=this;const{arrowMargin,arrowWidth,margin}=BaseWidget;const arrowTipX=margin+arrowMargin;const arrowInnerX=arrowTipX+arrowWidth;ctx.fillStyle=this.canDecrement()?text_color:disabledTextColor;ctx.beginPath();ctx.moveTo(arrowInnerX,y+5);ctx.lineTo(arrowTipX,y+height*.5);ctx.lineTo(arrowInnerX,y+height-5);ctx.fill();ctx.fillStyle=this.canIncrement()?text_color:disabledTextColor;ctx.beginPath();ctx.moveTo(width2-arrowInnerX,y+5);ctx.lineTo(width2-arrowTipX,y+height*.5);ctx.lineTo(width2-arrowInnerX,y+height-5);ctx.fill()}drawWidget(ctx,options){const{fillStyle,strokeStyle,textAlign}=ctx;this.drawWidgetShape(ctx,options);if(options.showText){if(!this.computedDisabled)this.drawArrowButtons(ctx,options.width);this.drawTruncatingText({ctx,width:options.width})}Object.assign(ctx,{textAlign,strokeStyle,fillStyle})}}function toArray(values){return Array.isArray(values)?values:Object.keys(values)}class ComboWidget extends BaseSteppedWidget{type="combo";get _displayValue(){if(this.computedDisabled)return"";const{values:rawValues}=this.options;if(rawValues){const values=typeof rawValues==="function"?rawValues():rawValues;if(values&&!Array.isArray(values)){return values[this.value]}}return typeof this.value==="number"?String(this.value):this.value}#getValues(node2){const{values}=this.options;if(values==null)throw new Error("[ComboWidget]: values is required");return typeof values==="function"?values(this,node2):values}#canUseButton(increment){const{values}=this.options;if(typeof values==="function")return false;const valuesArray=toArray(values);if(!(valuesArray.length>1))return false;const firstValue=valuesArray.at(0);const lastValue=valuesArray.at(-1);if(firstValue===lastValue)return true;return this.value!==(increment?lastValue:firstValue)}canIncrement(){return this.#canUseButton(true)}canDecrement(){return this.#canUseButton(false)}incrementValue(options){this.#tryChangeValue(1,options)}decrementValue(options){this.#tryChangeValue(-1,options)}#tryChangeValue(delta2,options){const values=this.#getValues(options.node);const indexedValues=toArray(values);options.canvas.last_mouseclick=0;const foundIndex=typeof values==="object"?indexedValues.indexOf(String(this.value))+delta2:indexedValues.indexOf(this.value)+delta2;const index=clamp(foundIndex,0,indexedValues.length-1);const value=Array.isArray(values)?values[index]:index;this.setValue(value,options)}onClick({e:e2,node:node2,canvas:canvas2}){const x2=e2.canvasX-node2.pos[0];const width2=this.width||node2.size[0];if(typeof this.options.values==="function"){warnDeprecated("Using a function for values is deprecated. Use an array of unique values instead.")}if(x2<40)return this.decrementValue({e:e2,node:node2,canvas:canvas2});if(x2>width2-40)return this.incrementValue({e:e2,node:node2,canvas:canvas2});const values=this.#getValues(node2);const values_list=toArray(values);const text_values=values!=values_list?Object.values(values):values;new LiteGraph.ContextMenu(text_values,{scale:Math.max(1,canvas2.ds.scale),event:e2,className:"dark",callback:value=>{this.setValue(values!=values_list?text_values.indexOf(value):value,{e:e2,node:node2,canvas:canvas2})}})}}function getWidgetStep(options){return options.step2||(options.step||10)*.1}class KnobWidget extends BaseWidget{type="knob";computeLayoutSize(){return{minHeight:60,minWidth:20,maxHeight:1e6,maxWidth:1e6}}get height(){return this.computedHeight||super.height}drawWidget(ctx,{width:width2,showText=true}){const{fillStyle,strokeStyle,textAlign}=ctx;const{y}=this;const{margin}=BaseWidget;const{gradient_stops="rgb(14, 182, 201); rgb(0, 216, 72)"}=this.options;const effective_height=this.computedHeight||this.height;const size_modifier=Math.min(this.computedHeight||this.height,this.width||20)/20;const arc_center={x:width2/2,y:effective_height/2+y};ctx.lineWidth=(Math.min(width2,effective_height)-margin*size_modifier)/6;const arc_size=(Math.min(width2,effective_height)-margin*size_modifier-ctx.lineWidth)/2;{const gradient2=ctx.createRadialGradient(arc_center.x,arc_center.y,arc_size+ctx.lineWidth,0,0,arc_size+ctx.lineWidth);gradient2.addColorStop(0,"rgb(29, 29, 29)");gradient2.addColorStop(1,"rgb(116, 116, 116)");ctx.fillStyle=gradient2}ctx.beginPath();{ctx.arc(arc_center.x,arc_center.y,arc_size+ctx.lineWidth/2,0,Math.PI*2,false);ctx.fill();ctx.closePath()}const arc={start_angle:Math.PI*.6,end_angle:Math.PI*2.4};ctx.beginPath();{const gradient2=ctx.createRadialGradient(arc_center.x,arc_center.y,arc_size+ctx.lineWidth,0,0,arc_size+ctx.lineWidth);gradient2.addColorStop(0,"rgb(99, 99, 99)");gradient2.addColorStop(1,"rgb(36, 36, 36)");ctx.strokeStyle=gradient2}ctx.arc(arc_center.x,arc_center.y,arc_size,arc.start_angle,arc.end_angle,false);ctx.stroke();ctx.closePath();const range=this.options.max-this.options.min;let nvalue=(this.value-this.options.min)/range;nvalue=clamp(nvalue,0,1);ctx.beginPath();const gradient=ctx.createConicGradient(arc.start_angle,arc_center.x,arc_center.y);const gs=gradient_stops.split(";");for(const[index,stop]of gs.entries()){gradient.addColorStop(index,stop.trim())}ctx.strokeStyle=gradient;const value_end_angle=(arc.end_angle-arc.start_angle)*nvalue+arc.start_angle;ctx.arc(arc_center.x,arc_center.y,arc_size,arc.start_angle,value_end_angle,false);ctx.stroke();ctx.closePath();if(showText&&!this.computedDisabled){ctx.strokeStyle=this.outline_color;ctx.beginPath();ctx.strokeStyle=this.outline_color;ctx.arc(arc_center.x,arc_center.y,arc_size+ctx.lineWidth/2,0,Math.PI*2,false);ctx.lineWidth=1;ctx.stroke();ctx.closePath()}if(showText){ctx.textAlign="center";ctx.fillStyle=this.text_color;const fixedValue=Number(this.value).toFixed(this.options.precision??3);ctx.fillText(`${this.label||this.name}
|
|
2
|
-
${fixedValue}`,width2*.5,y+effective_height*.5)}Object.assign(ctx,{textAlign,strokeStyle,fillStyle})}onClick(){this.current_drag_offset=0}current_drag_offset=0;onDrag(options){if(this.options.read_only)return;const{e:e2}=options;const step=getWidgetStep(this.options);const range=this.options.max-this.options.min;const range_10_percent=range/10;const range_1_percent=range/100;const step_for={shift:range_10_percent>step?range_10_percent-range_10_percent%step:step,delta_y:range_1_percent>step?range_1_percent-range_1_percent%step:step};const use_y=Math.abs(e2.movementY)>Math.abs(e2.movementX);const delta2=use_y?-e2.movementY:e2.movementX;const drag_threshold=15;this.current_drag_offset+=delta2;let adjustment=0;if(this.current_drag_offset>drag_threshold){adjustment+=1;this.current_drag_offset-=drag_threshold}else if(this.current_drag_offset<-drag_threshold){adjustment-=1;this.current_drag_offset+=drag_threshold}const step_with_shift_modifier=e2.shiftKey?step_for.shift:use_y?step_for.delta_y:step;const deltaValue=adjustment*step_with_shift_modifier;const newValue2=clamp(this.value+deltaValue,this.options.min,this.options.max);if(newValue2!==this.value){this.setValue(newValue2,options)}}}class LegacyWidget extends BaseWidget{drawWidget(ctx,options){const H=LiteGraph.NODE_WIDGET_HEIGHT;this.draw?.(ctx,this.node,options.width,this.y,H,!!options.showText)}onClick(){console.warn("Custom widget wrapper onClick was just called. Handling for third party widgets is done via LGraphCanvas - the mouse callback.")}}class NumberWidget extends BaseSteppedWidget{type="number";get _displayValue(){if(this.computedDisabled)return"";return Number(this.value).toFixed(this.options.precision!==void 0?this.options.precision:3)}canIncrement(){const{max}=this.options;return max==null||this.value<max}canDecrement(){const{min}=this.options;return min==null||this.value>min}incrementValue(options){this.setValue(this.value+getWidgetStep(this.options),options)}decrementValue(options){this.setValue(this.value-getWidgetStep(this.options),options)}setValue(value,options){let newValue2=value;if(this.options.min!=null&&newValue2<this.options.min){newValue2=this.options.min}if(this.options.max!=null&&newValue2>this.options.max){newValue2=this.options.max}super.setValue(newValue2,options)}onClick({e,node,canvas}){const x=e.canvasX-node.pos[0];const width=this.width||node.size[0];const delta=x<40?-1:x>width-40?1:0;if(delta){this.setValue(this.value+delta*getWidgetStep(this.options),{e,node,canvas});return}canvas.prompt("Value",this.value,v=>{if(/^[\d\s()*+/-]+|\d+\.\d+$/.test(v)){try{v=eval(v)}catch{}}const newValue=Number(v);if(!isNaN(newValue)){this.setValue(newValue,{e,node,canvas})}},e)}onDrag({e:e2,node:node2,canvas:canvas2}){const width2=this.width||node2.width;const x2=e2.canvasX-node2.pos[0];const delta2=x2<40?-1:x2>width2-40?1:0;if(delta2&&(x2>-3&&x2<width2+3))return;this.setValue(this.value+(e2.deltaX??0)*getWidgetStep(this.options),{e:e2,node:node2,canvas:canvas2})}}class SliderWidget extends BaseWidget{type="slider";marker;drawWidget(ctx,{width:width2,showText=true}){const{fillStyle,strokeStyle,textAlign}=ctx;const{height,y}=this;const{margin}=BaseWidget;ctx.fillStyle=this.background_color;ctx.fillRect(margin,y,width2-margin*2,height);const range=this.options.max-this.options.min;let nvalue=(this.value-this.options.min)/range;nvalue=clamp(nvalue,0,1);ctx.fillStyle=this.options.slider_color??"#678";ctx.fillRect(margin,y,nvalue*(width2-margin*2),height);if(showText&&!this.computedDisabled){ctx.strokeStyle=this.outline_color;ctx.strokeRect(margin,y,width2-margin*2,height)}if(this.marker!=null){let marker_nvalue=(this.marker-this.options.min)/range;marker_nvalue=clamp(marker_nvalue,0,1);ctx.fillStyle=this.options.marker_color??"#AA9";ctx.fillRect(margin+marker_nvalue*(width2-margin*2),y,2,height)}if(showText){ctx.textAlign="center";ctx.fillStyle=this.text_color;const fixedValue=Number(this.value).toFixed(this.options.precision??3);ctx.fillText(`${this.label||this.name} ${fixedValue}`,width2*.5,y+height*.7)}Object.assign(ctx,{textAlign,strokeStyle,fillStyle})}onClick(options){if(this.options.read_only)return;const{e:e2,node:node2}=options;const width2=this.width||node2.size[0];const x2=e2.canvasX-node2.pos[0];const slideFactor=clamp((x2-15)/(width2-30),0,1);const newValue2=this.options.min+(this.options.max-this.options.min)*slideFactor;if(newValue2!==this.value){this.setValue(newValue2,options)}}onDrag(options){if(this.options.read_only)return false;const{e:e2,node:node2}=options;const width2=this.width||node2.size[0];const x2=e2.canvasX-node2.pos[0];const slideFactor=clamp((x2-15)/(width2-30),0,1);const newValue2=this.options.min+(this.options.max-this.options.min)*slideFactor;if(newValue2!==this.value){this.setValue(newValue2,options)}}}class TextWidget extends BaseWidget{constructor(widget,node2){super(widget,node2);this.type??="string";this.value=widget.value?.toString()??""}drawWidget(ctx,{width:width2,showText=true}){const{fillStyle,strokeStyle,textAlign}=ctx;this.drawWidgetShape(ctx,{width:width2,showText});if(showText){this.drawTruncatingText({ctx,width:width2,leftPadding:0,rightPadding:0})}Object.assign(ctx,{textAlign,strokeStyle,fillStyle})}onClick({e:e2,node:node2,canvas:canvas2}){canvas2.prompt("Value",this.value,v2=>{if(v2!==null){this.setValue(v2,{e:e2,node:node2,canvas:canvas2})}},e2,this.options?.multiline??false)}}function toConcreteWidget(widget,node2,wrapLegacyWidgets=true){if(widget instanceof BaseWidget)return widget;const narrowedWidget=widget;switch(narrowedWidget.type){case"button":return toClass(ButtonWidget,narrowedWidget,node2);case"toggle":return toClass(BooleanWidget,narrowedWidget,node2);case"slider":return toClass(SliderWidget,narrowedWidget,node2);case"knob":return toClass(KnobWidget,narrowedWidget,node2);case"combo":return toClass(ComboWidget,narrowedWidget,node2);case"number":return toClass(NumberWidget,narrowedWidget,node2);case"string":return toClass(TextWidget,narrowedWidget,node2);case"text":return toClass(TextWidget,narrowedWidget,node2);default:{if(wrapLegacyWidgets)return toClass(LegacyWidget,widget,node2)}}}function isComboWidget(widget){return widget.type==="combo"}class LGraphNode{static title;static MAX_CONSOLE;static type;static category;static filter;static skip_list;static resizeHandleSize=15;static resizeEdgeSize=5;static keepAllLinksOnBypass=false;title;get titleFontStyle(){return`${LiteGraph.NODE_TEXT_SIZE}px ${LiteGraph.NODE_FONT}`}get innerFontStyle(){return`normal ${LiteGraph.NODE_SUBTEXT_SIZE}px ${LiteGraph.NODE_FONT}`}get displayType(){return this.type}graph=null;id;type="";inputs=[];outputs=[];#concreteInputs=[];#concreteOutputs=[];properties={};properties_info=[];flags={};widgets;freeWidgetSpace;locked;order=0;mode=LGraphEventMode.ALWAYS;last_serialization;serialize_widgets;color;bgcolor;boxcolor;get renderingColor(){return this.color||this.constructor.color||LiteGraph.NODE_DEFAULT_COLOR}get renderingBgColor(){return this.bgcolor||this.constructor.bgcolor||LiteGraph.NODE_DEFAULT_BGCOLOR}get renderingBoxColor(){if(this.boxcolor)return this.boxcolor;if(LiteGraph.node_box_coloured_when_on){if(this.action_triggered)return"#FFF";if(this.execute_triggered)return"#AAA"}if(LiteGraph.node_box_coloured_by_mode){const modeColour=LiteGraph.NODE_MODES_COLORS[this.mode??LGraphEventMode.ALWAYS];if(modeColour)return modeColour}return LiteGraph.NODE_DEFAULT_BOXCOLOR}setColorOption(colorOption){if(colorOption==null){delete this.color;delete this.bgcolor}else{this.color=colorOption.color;this.bgcolor=colorOption.bgcolor}}getColorOption(){return Object.values(LGraphCanvas.node_colors).find(colorOption=>colorOption.color===this.color&&colorOption.bgcolor===this.bgcolor)??null}strokeStyles;progress;exec_version;action_call;execute_triggered;action_triggered;widgets_up;widgets_start_y;lostFocusAt;gotFocusAt;badges=[];title_buttons=[];badgePosition=BadgePosition.TopLeft;_collapsed_width;console;_level;_shape;mouseOver;redraw_on_mouse;resizable;clonable;_relative_id;clip_area;ignore_remove;has_errors;removable;block_delete;selected;showAdvanced;isSubgraphNode(){return false}#renderArea=new Float32Array(4);get renderArea(){return this.#renderArea}#boundingRect=new Rectangle;get boundingRect(){return this.#boundingRect}get boundingOffset(){const{pos:[posX,posY],boundingRect:[bX,bY]}=this;return[posX-bX,posY-bY]}_posSize=new Float32Array(4);_pos=this._posSize.subarray(0,2);_size=this._posSize.subarray(2,4);get pos(){return this._pos}set pos(value){if(!value||value.length<2)return;this._pos[0]=value[0];this._pos[1]=value[1]}get size(){return this._size}set size(value){if(!value||value.length<2)return;this._size[0]=value[0];this._size[1]=value[1]}get renderingSize(){return this.flags.collapsed?[this._collapsed_width??0,0]:this._size}get shape(){return this._shape}set shape(v2){switch(v2){case"default":delete this._shape;break;case"box":this._shape=RenderShape.BOX;break;case"round":this._shape=RenderShape.ROUND;break;case"circle":this._shape=RenderShape.CIRCLE;break;case"card":this._shape=RenderShape.CARD;break;default:this._shape=v2}}get renderingShape(){return this._shape||this.constructor.shape||LiteGraph.NODE_DEFAULT_SHAPE}get is_selected(){return this.selected}set is_selected(value){this.selected=value}get title_mode(){return this.constructor.title_mode??TitleMode.NORMAL_TITLE}#getErrorStrokeStyle(){if(this.has_errors){return{padding:12,lineWidth:10,color:LiteGraph.NODE_ERROR_COLOUR}}}#getSelectedStrokeStyle(){if(this.selected){return{padding:this.has_errors?20:void 0}}}constructor(title,type){this.id=LiteGraph.use_uuids?LiteGraph.uuidv4():-1;this.title=title||"Unnamed";this.type=type??"";this.size=[LiteGraph.NODE_WIDTH,60];this.pos=[10,10];this.strokeStyles={error:this.#getErrorStrokeStyle,selected:this.#getSelectedStrokeStyle};this.onMouseDown=(e2,pos,canvas2)=>{if(this.title_buttons?.length&&!this.flags.collapsed){const nodeRelativeX=pos[0];const nodeRelativeY=pos[1];for(let i=0;i<this.title_buttons.length;i++){const button=this.title_buttons[i];if(button.visible&&button.isPointInside(nodeRelativeX,nodeRelativeY)){this.onTitleButtonClick(button,canvas2);return true}}}return false}}configure(info){if(this.graph){this.graph._version++}for(const j in info){if(j=="properties"){for(const k in info.properties){this.properties[k]=info.properties[k];this.onPropertyChanged?.(k,info.properties[k])}continue}if(info[j]==null){continue}else if(typeof info[j]=="object"){if(this[j]?.configure){this[j]?.configure(info[j])}else{this[j]=LiteGraph.cloneObject(info[j],this[j])}}else{this[j]=info[j]}}if(!info.title){this.title=this.constructor.title}this.inputs??=[];this.inputs=this.inputs.map(input=>toClass(NodeInputSlot,input,this));for(const[i,input]of this.inputs.entries()){const link=this.graph&&input.link!=null?this.graph._links.get(input.link):null;this.onConnectionsChange?.(NodeSlotType.INPUT,i,true,link,input);this.onInputAdded?.(input)}this.outputs??=[];this.outputs=this.outputs.map(output=>toClass(NodeOutputSlot,output,this));for(const[i,output]of this.outputs.entries()){if(!output.links)continue;for(const linkId of output.links){const link=this.graph?this.graph._links.get(linkId):null;this.onConnectionsChange?.(NodeSlotType.OUTPUT,i,true,link,output)}this.onOutputAdded?.(output)}this._internalConfigureAfterSlots?.();if(this.widgets){for(const w of this.widgets){if(!w)continue;if(w.options?.property&&this.properties[w.options.property]!=void 0)w.value=JSON.parse(JSON.stringify(this.properties[w.options.property]))}if(info.widgets_values){const widgetsWithValue=this.widgets.filter(w=>w.serialize!==false);for(let i=0;i<info.widgets_values.length;++i){const widget=widgetsWithValue[i];if(widget){widget.value=info.widgets_values[i]}}}}if(this.pinned)this.resizable=false;this.onConfigure?.(info)}serialize(){const o={id:this.id,type:this.type,pos:[this.pos[0],this.pos[1]],size:[this.size[0],this.size[1]],flags:LiteGraph.cloneObject(this.flags),order:this.order,mode:this.mode,showAdvanced:this.showAdvanced};if(this.constructor===LGraphNode&&this.last_serialization)return this.last_serialization;if(this.inputs)o.inputs=this.inputs.map(input=>inputAsSerialisable(input));if(this.outputs)o.outputs=this.outputs.map(output=>outputAsSerialisable(output));if(this.title&&this.title!=this.constructor.title)o.title=this.title;if(this.properties)o.properties=LiteGraph.cloneObject(this.properties);const{widgets}=this;if(widgets&&this.serialize_widgets){o.widgets_values=[];for(const[i,widget]of widgets.entries()){if(widget.serialize===false)continue;o.widgets_values[i]=widget?widget.value:null}}if(!o.type)o.type=this.constructor.type;if(this.color)o.color=this.color;if(this.bgcolor)o.bgcolor=this.bgcolor;if(this.boxcolor)o.boxcolor=this.boxcolor;if(this.shape)o.shape=this.shape;if(this.onSerialize?.(o))console.warn("node onSerialize shouldnt return anything, data should be stored in the object pass in the first parameter");return o}clone(){if(this.type==null)return null;const node2=LiteGraph.createNode(this.type);if(!node2)return null;const data=LiteGraph.cloneObject(this.serialize());const{inputs,outputs}=data;if(inputs){for(const input of inputs){input.link=null}}if(outputs){for(const{links}of outputs){if(links)links.length=0}}delete data.id;if(LiteGraph.use_uuids)data.id=LiteGraph.uuidv4();node2.configure(data);return node2}toString(){return JSON.stringify(this.serialize())}getTitle(){return this.title||this.constructor.title}setProperty(name,value){this.properties||={};if(value===this.properties[name])return;const prev_value=this.properties[name];this.properties[name]=value;if(this.onPropertyChanged?.(name,value,prev_value)===false)this.properties[name]=prev_value;if(this.widgets){for(const w of this.widgets){if(!w)continue;if(w.options.property==name){w.value=value;break}}}}setOutputData(slot,data){const{outputs}=this;if(!outputs)return;if(slot==-1||slot>=outputs.length)return;const output_info=outputs[slot];if(!output_info)return;output_info._data=data;if(!this.graph)throw new NullGraphError;const{links}=outputs[slot];if(links){for(const id of links){const link=this.graph._links.get(id);if(link)link.data=data}}}setOutputDataType(slot,type){const{outputs}=this;if(!outputs||(slot==-1||slot>=outputs.length))return;const output_info=outputs[slot];if(!output_info)return;output_info.type=type;if(!this.graph)throw new NullGraphError;const{links}=outputs[slot];if(links){for(const id of links){const link=this.graph._links.get(id);if(link)link.type=type}}}getInputData(slot,force_update){if(!this.inputs)return;if(slot>=this.inputs.length||this.inputs[slot].link==null)return;if(!this.graph)throw new NullGraphError;const link_id=this.inputs[slot].link;const link=this.graph._links.get(link_id);if(!link)return null;if(!force_update)return link.data;const node2=this.graph.getNodeById(link.origin_id);if(!node2)return link.data;if(node2.updateOutputData){node2.updateOutputData(link.origin_slot)}else{node2.onExecute?.()}return link.data}getInputDataType(slot){if(!this.inputs)return null;if(slot>=this.inputs.length||this.inputs[slot].link==null)return null;if(!this.graph)throw new NullGraphError;const link_id=this.inputs[slot].link;const link=this.graph._links.get(link_id);if(!link)return null;const node2=this.graph.getNodeById(link.origin_id);if(!node2)return link.type;const output_info=node2.outputs[link.origin_slot];return output_info?output_info.type:null}getInputDataByName(slot_name,force_update){const slot=this.findInputSlot(slot_name);return slot==-1?null:this.getInputData(slot,force_update)}isInputConnected(slot){if(!this.inputs)return false;return slot<this.inputs.length&&this.inputs[slot].link!=null}getInputInfo(slot){return!this.inputs||!(slot<this.inputs.length)?null:this.inputs[slot]}getInputLink(slot){if(!this.inputs)return null;if(slot<this.inputs.length){if(!this.graph)throw new NullGraphError;const input=this.inputs[slot];if(input.link!=null){return this.graph._links.get(input.link)??null}}return null}getInputNode(slot){if(!this.inputs)return null;if(slot>=this.inputs.length)return null;const input=this.inputs[slot];if(!input||input.link===null)return null;if(!this.graph)throw new NullGraphError;const link_info=this.graph._links.get(input.link);if(!link_info)return null;return this.graph.getNodeById(link_info.origin_id)}getInputOrProperty(name){const{inputs}=this;if(!inputs?.length){return this.properties?this.properties[name]:null}if(!this.graph)throw new NullGraphError;for(const input of inputs){if(name==input.name&&input.link!=null){const link=this.graph._links.get(input.link);if(link)return link.data}}return this.properties[name]}getOutputData(slot){if(!this.outputs)return null;if(slot>=this.outputs.length)return null;const info=this.outputs[slot];return info._data}getOutputInfo(slot){return!this.outputs||!(slot<this.outputs.length)?null:this.outputs[slot]}isOutputConnected(slot){if(!this.outputs)return false;return slot<this.outputs.length&&Number(this.outputs[slot].links?.length)>0}isAnyOutputConnected(){const{outputs}=this;if(!outputs)return false;for(const output of outputs){if(output.links?.length)return true}return false}getOutputNodes(slot){const{outputs}=this;if(!outputs||outputs.length==0)return null;if(slot>=outputs.length)return null;const{links}=outputs[slot];if(!links||links.length==0)return null;if(!this.graph)throw new NullGraphError;const r=[];for(const id of links){const link=this.graph._links.get(id);if(link){const target_node=this.graph.getNodeById(link.target_id);if(target_node){r.push(target_node)}}}return r}addOnTriggerInput(){const trigS=this.findInputSlot("onTrigger");if(trigS==-1){this.addInput("onTrigger",LiteGraph.EVENT,{nameLocked:true});return this.findInputSlot("onTrigger")}return trigS}addOnExecutedOutput(){const trigS=this.findOutputSlot("onExecuted");if(trigS==-1){this.addOutput("onExecuted",LiteGraph.ACTION,{nameLocked:true});return this.findOutputSlot("onExecuted")}return trigS}onAfterExecuteNode(param,options){const trigS=this.findOutputSlot("onExecuted");if(trigS!=-1){this.triggerSlot(trigS,param,null,options)}}changeMode(modeTo){switch(modeTo){case LGraphEventMode.ON_EVENT:break;case LGraphEventMode.ON_TRIGGER:this.addOnTriggerInput();this.addOnExecutedOutput();break;case LGraphEventMode.NEVER:break;case LGraphEventMode.ALWAYS:break;case LiteGraph.ON_REQUEST:break;default:return false}this.mode=modeTo;return true}doExecute(param,options){options=options||{};if(this.onExecute){options.action_call||=`${this.id}_exec_${Math.floor(Math.random()*9999)}`;if(!this.graph)throw new NullGraphError;this.graph.nodes_executing[this.id]=true;this.onExecute(param,options);this.graph.nodes_executing[this.id]=false;this.exec_version=this.graph.iteration;if(options?.action_call){this.action_call=options.action_call;this.graph.nodes_executedAction[this.id]=options.action_call}}this.execute_triggered=2;this.onAfterExecuteNode?.(param,options)}actionDo(action,param,options){options=options||{};if(this.onAction){options.action_call||=`${this.id}_${action||"action"}_${Math.floor(Math.random()*9999)}`;if(!this.graph)throw new NullGraphError;this.graph.nodes_actioning[this.id]=action||"actioning";this.onAction(action,param,options);this.graph.nodes_actioning[this.id]=false;if(options?.action_call){this.action_call=options.action_call;this.graph.nodes_executedAction[this.id]=options.action_call}}this.action_triggered=2;this.onAfterExecuteNode?.(param,options)}trigger(action,param,options){const{outputs}=this;if(!outputs||!outputs.length){return}if(this.graph)this.graph._last_trigger_time=LiteGraph.getTime();for(const[i,output]of outputs.entries()){if(!output||output.type!==LiteGraph.EVENT||action&&output.name!=action){continue}this.triggerSlot(i,param,null,options)}}triggerSlot(slot,param,link_id,options){options=options||{};if(!this.outputs)return;if(slot==null){console.error("slot must be a number");return}if(typeof slot!=="number")console.warn("slot must be a number, use node.trigger('name') if you want to use a string");const output=this.outputs[slot];if(!output)return;const links=output.links;if(!links||!links.length)return;if(!this.graph)throw new NullGraphError;this.graph._last_trigger_time=LiteGraph.getTime();for(const id of links){if(link_id!=null&&link_id!=id)continue;const link_info=this.graph._links.get(id);if(!link_info)continue;link_info._last_time=LiteGraph.getTime();const node2=this.graph.getNodeById(link_info.target_id);if(!node2)continue;if(node2.mode===LGraphEventMode.ON_TRIGGER){if(!options.action_call)options.action_call=`${this.id}_trigg_${Math.floor(Math.random()*9999)}`;node2.doExecute?.(param,options)}else if(node2.onAction){if(!options.action_call)options.action_call=`${this.id}_act_${Math.floor(Math.random()*9999)}`;const target_connection=node2.inputs[link_info.target_slot];node2.actionDo(target_connection.name,param,options)}}}clearTriggeredSlot(slot,link_id){if(!this.outputs)return;const output=this.outputs[slot];if(!output)return;const links=output.links;if(!links||!links.length)return;if(!this.graph)throw new NullGraphError;for(const id of links){if(link_id!=null&&link_id!=id)continue;const link_info=this.graph._links.get(id);if(!link_info)continue;link_info._last_time=0}}setSize(size){this.size=size;this.onResize?.(this.size)}expandToFitContent(){const newSize=this.computeSize();this.setSize([Math.max(this.size[0],newSize[0]),Math.max(this.size[1],newSize[1])])}addProperty(name,default_value,type,extra_info){const o={name,type,default_value};if(extra_info)Object.assign(o,extra_info);this.properties_info||=[];this.properties_info.push(o);this.properties||={};this.properties[name]=default_value;return o}addOutput(name,type,extra_info){const output=Object.assign(new NodeOutputSlot({name,type,links:null},this),extra_info);this.outputs||=[];this.outputs.push(output);this.onOutputAdded?.(output);if(LiteGraph.auto_load_slot_types)LiteGraph.registerNodeAndSlotType(this,type,true);this.expandToFitContent();this.setDirtyCanvas(true,true);return output}removeOutput(slot){this.disconnectOutput(slot);const{outputs}=this;outputs.splice(slot,1);for(let i=slot;i<outputs.length;++i){const output=outputs[i];if(!output||!output.links)continue;for(const linkId of output.links){if(!this.graph)throw new NullGraphError;const link=this.graph._links.get(linkId);if(link)link.origin_slot--}}this.onOutputRemoved?.(slot);this.setDirtyCanvas(true,true)}addInput(name,type,extra_info){type||=0;const input=Object.assign(new NodeInputSlot({name,type,link:null},this),extra_info);this.inputs||=[];this.inputs.push(input);this.expandToFitContent();this.onInputAdded?.(input);LiteGraph.registerNodeAndSlotType(this,type);this.setDirtyCanvas(true,true);return input}removeInput(slot){this.disconnectInput(slot,true);const{inputs}=this;const slot_info=inputs.splice(slot,1);for(let i=slot;i<inputs.length;++i){const input=inputs[i];if(!input?.link)continue;if(!this.graph)throw new NullGraphError;const link=this.graph._links.get(input.link);if(link)link.target_slot--}this.onInputRemoved?.(slot,slot_info[0]);this.setDirtyCanvas(true,true)}computeSize(out){const ctorSize=this.constructor.size;if(ctorSize)return[ctorSize[0],ctorSize[1]];const{inputs,outputs,widgets}=this;let rows=Math.max(inputs?inputs.filter(input=>!isWidgetInputSlot(input)).length:1,outputs?outputs.length:1);const size=out||new Float32Array([0,0]);rows=Math.max(rows,1);const font_size=LiteGraph.NODE_TEXT_SIZE;const padLeft=LiteGraph.NODE_TITLE_HEIGHT;const padRight=padLeft*.33;const title_width=padLeft+compute_text_size(this.title,this.titleFontStyle)+padRight;let input_width=0;let widgetWidth=0;let output_width=0;if(inputs){for(const input of inputs){const text=input.label||input.localized_name||input.name||"";const text_width=compute_text_size(text,this.innerFontStyle);if(isWidgetInputSlot(input)){const widget=this.getWidgetFromSlot(input);if(widget&&!this.isWidgetVisible(widget))continue;if(text_width>widgetWidth)widgetWidth=text_width}else{if(text_width>input_width)input_width=text_width}}}if(outputs){for(const output of outputs){const text=output.label||output.localized_name||output.name||"";const text_width=compute_text_size(text,this.innerFontStyle);if(output_width<text_width)output_width=text_width}}const minWidth=LiteGraph.NODE_WIDTH*(widgets?.length?1.5:1);const centrePadding=input_width&&output_width?5:0;const slotsWidth=input_width+output_width+2*LiteGraph.NODE_SLOT_HEIGHT+centrePadding;const widgetMargin=BaseWidget.margin+BaseWidget.arrowMargin+BaseWidget.arrowWidth;const widgetPadding=BaseWidget.minValueWidth+2*widgetMargin;if(widgetWidth)widgetWidth+=widgetPadding;size[0]=Math.max(slotsWidth,widgetWidth,title_width,minWidth);size[1]=(this.constructor.slot_start_y||0)+rows*LiteGraph.NODE_SLOT_HEIGHT;let widgets_height=0;if(widgets?.length){for(const widget of widgets){if(!this.isWidgetVisible(widget))continue;let widget_height=0;if(widget.computeSize){widget_height+=widget.computeSize(size[0])[1]}else if(widget.computeLayoutSize){const{minHeight,minWidth:minWidth2}=widget.computeLayoutSize(this);const widgetWidth2=minWidth2+widgetPadding;if(widgetWidth2>size[0])size[0]=widgetWidth2;widget_height+=minHeight}else{widget_height+=LiteGraph.NODE_WIDGET_HEIGHT}widgets_height+=widget_height+4}widgets_height+=8}if(this.widgets_up)size[1]=Math.max(size[1],widgets_height);else if(this.widgets_start_y!=null)size[1]=Math.max(size[1],widgets_height+this.widgets_start_y);else size[1]+=widgets_height;function compute_text_size(text,fontStyle){return LGraphCanvas._measureText?.(text,fontStyle)??font_size*(text?.length??0)*.6}if(this.constructor.min_height&&size[1]<this.constructor.min_height){size[1]=this.constructor.min_height}size[1]+=6;return size}inResizeCorner(canvasX,canvasY){const rows=this.outputs?this.outputs.length:1;const outputs_offset=(this.constructor.slot_start_y||0)+rows*LiteGraph.NODE_SLOT_HEIGHT;return isInRectangle(canvasX,canvasY,this.pos[0]+this.size[0]-15,this.pos[1]+Math.max(this.size[1]-15,outputs_offset),20,20)}findResizeDirection(canvasX,canvasY){if(this.resizable===false)return;const{boundingRect}=this;if(!boundingRect.containsXy(canvasX,canvasY))return;return boundingRect.findContainingCorner(canvasX,canvasY,LGraphNode.resizeHandleSize)}getPropertyInfo(property){let info=null;const{properties_info}=this;if(properties_info){for(const propInfo of properties_info){if(propInfo.name==property){info=propInfo;break}}}if(this.constructor[`@${property}`])info=this.constructor[`@${property}`];if(this.constructor.widgets_info?.[property])info=this.constructor.widgets_info[property];if(!info&&this.onGetPropertyInfo){info=this.onGetPropertyInfo(property)}info||={};info.type||=typeof this.properties[property];if(info.widget=="combo")info.type="enum";return info}addWidget(type,name,value,callback,options){this.widgets||=[];if(!options&&callback&&typeof callback==="object"){options=callback;callback=null}options||={};if(typeof options==="string")options={property:options};if(callback&&typeof callback==="string"){options.property=callback;callback=null}const w={type:type.toLowerCase(),name,value,callback:typeof callback!=="function"?void 0:callback,options,y:0};if(w.options.y!==void 0){w.y=w.options.y}if(!callback&&!w.options.callback&&!w.options.property){console.warn("LiteGraph addWidget(...) without a callback or property assigned")}if(type=="combo"&&!w.options.values){throw"LiteGraph addWidget('combo',...) requires to pass values in options: { values:['red','blue'] }"}const widget=this.addCustomWidget(w);this.expandToFitContent();return widget}addCustomWidget(custom_widget){this.widgets||=[];const widget=toConcreteWidget(custom_widget,this,false)??custom_widget;this.widgets.push(widget);return widget}addTitleButton(options){this.title_buttons||=[];const button=new LGraphButton(options);this.title_buttons.push(button);return button}onTitleButtonClick(button,canvas2){canvas2.dispatch("litegraph:node-title-button-clicked",{node:this,button})}removeWidgetByName(name){const widget=this.widgets?.find(x2=>x2.name===name);if(widget)this.removeWidget(widget)}removeWidget(widget){if(!this.widgets)throw new Error("removeWidget called on node without widgets");const widgetIndex=this.widgets.indexOf(widget);if(widgetIndex===-1)throw new Error("Widget not found on this node");if(this.inputs){for(const input of this.inputs){if(input._widget===widget){input._widget=void 0;delete input.widget}}}this.widgets.splice(widgetIndex,1)}ensureWidgetRemoved(widget){try{this.removeWidget(widget)}catch(error){console.debug("Failed to remove widget",error)}}move(deltaX,deltaY){if(this.pinned)return;this.pos[0]+=deltaX;this.pos[1]+=deltaY}measure(out,ctx){const titleMode=this.title_mode;const renderTitle=titleMode!=TitleMode.TRANSPARENT_TITLE&&titleMode!=TitleMode.NO_TITLE;const titleHeight=renderTitle?LiteGraph.NODE_TITLE_HEIGHT:0;out[0]=this.pos[0];out[1]=this.pos[1]+-titleHeight;if(!this.flags?.collapsed){out[2]=this.size[0];out[3]=this.size[1]+titleHeight}else{ctx.font=this.innerFontStyle;this._collapsed_width=Math.min(this.size[0],ctx.measureText(this.getTitle()??"").width+LiteGraph.NODE_TITLE_HEIGHT*2);out[2]=this._collapsed_width||LiteGraph.NODE_COLLAPSED_WIDTH;out[3]=LiteGraph.NODE_TITLE_HEIGHT}}getBounding(out,includeExternal){out||=new Float32Array(4);const rect=includeExternal?this.renderArea:this.boundingRect;out[0]=rect[0];out[1]=rect[1];out[2]=rect[2];out[3]=rect[3];return out}updateArea(ctx){const bounds=this.#boundingRect;this.measure(bounds,ctx);this.onBounding?.(bounds);const renderArea=this.#renderArea;renderArea.set(bounds);renderArea[0]-=4;renderArea[1]-=4;renderArea[2]+=6+4;renderArea[3]+=5+4}isPointInside(x2,y){return isInRect(x2,y,this.boundingRect)}isPointInCollapse(x2,y){const squareLength=LiteGraph.NODE_TITLE_HEIGHT;return isInRectangle(x2,y,this.pos[0],this.pos[1]-squareLength,squareLength,squareLength)}getInputOnPos(pos){return getNodeInputOnPos(this,pos[0],pos[1])?.input}getOutputOnPos(pos){return getNodeOutputOnPos(this,pos[0],pos[1])?.output}getSlotOnPos(pos){if(!isPointInRect(pos,this.boundingRect))return;return this.getInputOnPos(pos)??this.getOutputOnPos(pos)}getSlotInPosition(x2,y){const{inputs,outputs}=this;if(inputs){for(const[i,input]of inputs.entries()){const pos=this.getInputPos(i);if(isInRectangle(x2,y,pos[0]-10,pos[1]-10,20,20)){return{input,slot:i,link_pos:pos}}}}if(outputs){for(const[i,output]of outputs.entries()){const pos=this.getOutputPos(i);if(isInRectangle(x2,y,pos[0]-10,pos[1]-10,20,20)){return{output,slot:i,link_pos:pos}}}}return null}getWidgetOnPos(canvasX,canvasY,includeDisabled=false){const{widgets,pos,size}=this;if(!widgets?.length)return;const x2=canvasX-pos[0];const y=canvasY-pos[1];const nodeWidth=size[0];for(const widget of widgets){if(widget.computedDisabled&&!includeDisabled||!this.isWidgetVisible(widget)){continue}const h=widget.computedHeight??widget.computeSize?.(nodeWidth)[1]??LiteGraph.NODE_WIDGET_HEIGHT;const w=widget.width||nodeWidth;if(widget.last_y!==void 0&&isInRectangle(x2,y,6,widget.last_y,w-12,h)){return widget}}}findInputSlot(name,returnObj=false){const{inputs}=this;if(!inputs)return-1;for(const[i,input]of inputs.entries()){if(name==input.name){return!returnObj?i:input}}return-1}findOutputSlot(name,returnObj=false){const{outputs}=this;if(!outputs)return-1;for(const[i,output]of outputs.entries()){if(name==output.name){return!returnObj?i:output}}return-1}findInputSlotFree(optsIn){return this.#findFreeSlot(this.inputs,optsIn)}findOutputSlotFree(optsIn){return this.#findFreeSlot(this.outputs,optsIn)}#findFreeSlot(slots,options){const defaults={returnObj:false,typesNotAccepted:[]};const opts=Object.assign(defaults,options||{});const length=slots?.length;if(!(length>0))return-1;for(let i=0;i<length;++i){const slot=slots[i];if(!slot||slot.link||slot.links?.length)continue;if(opts.typesNotAccepted?.includes?.(slot.type))continue;return!opts.returnObj?i:slot}return-1}findInputSlotByType(type,returnObj,preferFreeSlot,doNotUseOccupied){return this.#findSlotByType(this.inputs,type,returnObj,preferFreeSlot,doNotUseOccupied)}findOutputSlotByType(type,returnObj,preferFreeSlot,doNotUseOccupied){return this.#findSlotByType(this.outputs,type,returnObj,preferFreeSlot,doNotUseOccupied)}findSlotByType(input,type,returnObj,preferFreeSlot,doNotUseOccupied){return input?this.#findSlotByType(this.inputs,type,returnObj,preferFreeSlot,doNotUseOccupied):this.#findSlotByType(this.outputs,type,returnObj,preferFreeSlot,doNotUseOccupied)}#findSlotByType(slots,type,returnObj,preferFreeSlot,doNotUseOccupied){const length=slots?.length;if(!length)return-1;if(type==""||type=="*")type=0;const sourceTypes=String(type).toLowerCase().split(",");let occupiedSlot=null;for(let i=0;i<length;++i){const slot=slots[i];const destTypes=slot.type=="0"||slot.type=="*"?["0"]:String(slot.type).toLowerCase().split(",");for(const sourceType of sourceTypes){const source=sourceType=="_event_"?LiteGraph.EVENT:sourceType;for(const destType of destTypes){const dest=destType=="_event_"?LiteGraph.EVENT:destType;if(source==dest||source==="*"||dest==="*"){if(preferFreeSlot&&(slot.links?.length||slot.link!=null)){occupiedSlot??=returnObj?slot:i;continue}return returnObj?slot:i}}}}return doNotUseOccupied?-1:occupiedSlot??-1}findConnectByTypeSlot(findInputs,node2,slotType,options){if(options&&typeof options==="object"){if("firstFreeIfInputGeneralInCase"in options)options.wildcardToTyped=!!options.firstFreeIfInputGeneralInCase;if("firstFreeIfOutputGeneralInCase"in options)options.wildcardToTyped=!!options.firstFreeIfOutputGeneralInCase;if("generalTypeInCase"in options)options.typedToWildcard=!!options.generalTypeInCase}const optsDef={createEventInCase:true,wildcardToTyped:true,typedToWildcard:true};const opts=Object.assign(optsDef,options);if(!this.graph)throw new NullGraphError;if(node2&&typeof node2==="number"){const nodeById=this.graph.getNodeById(node2);if(!nodeById)return;node2=nodeById}const slot=node2.findSlotByType(findInputs,slotType,false,true);if(slot>=0&&slot!==null)return slot;if(opts.createEventInCase&&slotType==LiteGraph.EVENT){if(findInputs)return-1;if(LiteGraph.do_add_triggers_slots)return node2.addOnExecutedOutput()}if(opts.typedToWildcard){const generalSlot=node2.findSlotByType(findInputs,0,false,true,true);if(generalSlot>=0)return generalSlot}if(opts.wildcardToTyped&&(slotType==0||slotType=="*"||slotType=="")){const opt={typesNotAccepted:[LiteGraph.EVENT]};const nonEventSlot=findInputs?node2.findInputSlotFree(opt):node2.findOutputSlotFree(opt);if(nonEventSlot>=0)return nonEventSlot}}findOutputByType(type){return findFreeSlotOfType(this.outputs,type,output=>!output.links?.length)}findInputByType(type){return findFreeSlotOfType(this.inputs,type,input=>input.link==null)}connectByType(slot,target_node,target_slotType,optsIn){const slotIndex=this.findConnectByTypeSlot(true,target_node,target_slotType,optsIn);if(slotIndex!==void 0)return this.connect(slot,target_node,slotIndex,optsIn?.afterRerouteId);console.debug("[connectByType]: no way to connect type:",target_slotType,"to node:",target_node);return null}connectByTypeOutput(slot,source_node,source_slotType,optsIn){if(typeof optsIn==="object"){if("firstFreeIfInputGeneralInCase"in optsIn)optsIn.wildcardToTyped=!!optsIn.firstFreeIfInputGeneralInCase;if("generalTypeInCase"in optsIn)optsIn.typedToWildcard=!!optsIn.generalTypeInCase}const slotIndex=this.findConnectByTypeSlot(false,source_node,source_slotType,optsIn);if(slotIndex!==void 0)return source_node.connect(slotIndex,this,slot,optsIn?.afterRerouteId);console.debug("[connectByType]: no way to connect type:",source_slotType,"to node:",source_node);return null}canConnectTo(node2,toSlot,fromSlot){return this.id!==node2.id&&LiteGraph.isValidConnection(fromSlot.type,toSlot.type)}connect(slot,target_node,target_slot,afterRerouteId){let targetIndex;const{graph,outputs}=this;if(!graph){console.log("Connect: Error, node doesn't belong to any graph. Nodes must be added first to a graph before connecting them.");return null}if(typeof slot==="string"){slot=this.findOutputSlot(slot);if(slot==-1){if(LiteGraph.debug)console.log(`Connect: Error, no slot of name ${slot}`);return null}}else if(!outputs||slot>=outputs.length){if(LiteGraph.debug)console.log("Connect: Error, slot number not found");return null}if(target_node&&typeof target_node==="number"){const nodeById=graph.getNodeById(target_node);if(!nodeById)throw"target node is null";target_node=nodeById}if(!target_node)throw"target node is null";if(target_node==this)return null;if(typeof target_slot==="string"){targetIndex=target_node.findInputSlot(target_slot);if(targetIndex==-1){if(LiteGraph.debug)console.log(`Connect: Error, no slot of name ${targetIndex}`);return null}}else if(target_slot===LiteGraph.EVENT){if(LiteGraph.do_add_triggers_slots){target_node.changeMode(LGraphEventMode.ON_TRIGGER);targetIndex=target_node.findInputSlot("onTrigger")}else{return null}}else if(typeof target_slot==="number"){targetIndex=target_slot}else{targetIndex=0}if(target_node.onBeforeConnectInput){const requestedIndex=target_node.onBeforeConnectInput(targetIndex,target_slot);targetIndex=typeof requestedIndex==="number"?requestedIndex:null}if(targetIndex===null||!target_node.inputs||targetIndex>=target_node.inputs.length){if(LiteGraph.debug)console.log("Connect: Error, slot number not found");return null}const input=target_node.inputs[targetIndex];const output=outputs[slot];if(!output)return null;if(output.links?.length){if(output.type===LiteGraph.EVENT&&!LiteGraph.allow_multi_output_for_events){graph.beforeChange();this.disconnectOutput(slot,false,{doProcessChange:false})}}const link=this.connectSlots(output,target_node,input,afterRerouteId);return link??null}connectSlots(output,inputNode,input,afterRerouteId){const{graph}=this;if(!graph)throw new NullGraphError;const outputIndex=this.outputs.indexOf(output);if(outputIndex===-1){console.warn("connectSlots: output not found");return}const inputIndex=inputNode.inputs.indexOf(input);if(inputIndex===-1){console.warn("connectSlots: input not found");return}if(!LiteGraph.isValidConnection(output.type,input.type)){this.setDirtyCanvas(false,true);return null}if(inputNode.onConnectInput?.(inputIndex,output.type,output,this,outputIndex)===false)return null;if(this.onConnectOutput?.(outputIndex,input.type,input,inputNode,inputIndex)===false)return null;if(inputNode.inputs[inputIndex]?.link!=null){graph.beforeChange();inputNode.disconnectInput(inputIndex,true)}const link=new LLink(++graph.state.lastLinkId,input.type||output.type,this.id,outputIndex,inputNode.id,inputIndex,afterRerouteId);graph._links.set(link.id,link);output.links??=[];output.links.push(link.id);inputNode.inputs[inputIndex].link=link.id;const reroutes=LLink.getReroutes(graph,link);for(const reroute of reroutes){reroute.linkIds.add(link.id);if(reroute.floating)delete reroute.floating;reroute._dragging=void 0}const lastReroute=reroutes.at(-1);if(lastReroute){for(const linkId of lastReroute.floatingLinkIds){const link2=graph.floatingLinks.get(linkId);if(link2?.parentId===lastReroute.id){graph.removeFloatingLink(link2)}}}graph._version++;this.onConnectionsChange?.(NodeSlotType.OUTPUT,outputIndex,true,link,output);inputNode.onConnectionsChange?.(NodeSlotType.INPUT,inputIndex,true,link,input);this.setDirtyCanvas(false,true);graph.afterChange();return link}connectFloatingReroute(pos,slot,afterRerouteId){const{graph,id}=this;if(!graph)throw new NullGraphError;const inputIndex=this.inputs.indexOf(slot);const outputIndex=this.outputs.indexOf(slot);if(inputIndex===-1&&outputIndex===-1)throw new Error("Invalid slot");const slotType=outputIndex===-1?"input":"output";const reroute=graph.setReroute({pos,parentId:afterRerouteId,linkIds:[],floating:{slotType}});const parentReroute=graph.getReroute(afterRerouteId);const fromLastFloatingReroute=parentReroute?.floating?.slotType==="output";if(afterRerouteId==null||!fromLastFloatingReroute){const link2=new LLink(-1,slot.type,outputIndex===-1?-1:id,outputIndex,inputIndex===-1?-1:id,inputIndex);link2.parentId=reroute.id;graph.addFloatingLink(link2);return reroute}if(!parentReroute)throw new Error("[connectFloatingReroute] Parent reroute not found");const link=parentReroute.getFloatingLinks("output")?.[0];if(!link)throw new Error("[connectFloatingReroute] Floating link not found");reroute.floatingLinkIds.add(link.id);link.parentId=reroute.id;delete parentReroute.floating;return reroute}disconnectOutput(slot,target_node){if(typeof slot==="string"){slot=this.findOutputSlot(slot);if(slot==-1){if(LiteGraph.debug)console.log(`Connect: Error, no slot of name ${slot}`);return false}}else if(!this.outputs||slot>=this.outputs.length){if(LiteGraph.debug)console.log("Connect: Error, slot number not found");return false}const output=this.outputs[slot];if(!output)return false;if(output._floatingLinks){for(const link of output._floatingLinks){if(link.hasOrigin(this.id,slot)){this.graph?.removeFloatingLink(link)}}}if(!output.links||output.links.length==0)return false;const{links}=output;const graph=this.graph;if(!graph)throw new NullGraphError;if(target_node){const target=typeof target_node==="number"?graph.getNodeById(target_node):target_node;if(!target)throw"Target Node not found";for(const[i,link_id]of links.entries()){const link_info=graph._links.get(link_id);if(link_info?.target_id!=target.id)continue;links.splice(i,1);const input=target.inputs[link_info.target_slot];input.link=null;link_info.disconnect(graph,"input");graph._version++;target.onConnectionsChange?.(NodeSlotType.INPUT,link_info.target_slot,false,link_info,input);this.onConnectionsChange?.(NodeSlotType.OUTPUT,slot,false,link_info,output);break}}else{for(const link_id of links){const link_info=graph._links.get(link_id);if(!link_info)continue;const target=graph.getNodeById(link_info.target_id);graph._version++;if(target){const input=target.inputs[link_info.target_slot];input.link=null;target.onConnectionsChange?.(NodeSlotType.INPUT,link_info.target_slot,false,link_info,input)}link_info.disconnect(graph,"input");this.onConnectionsChange?.(NodeSlotType.OUTPUT,slot,false,link_info,output)}output.links=null}this.setDirtyCanvas(false,true);return true}disconnectInput(slot,keepReroutes){if(typeof slot==="string"){slot=this.findInputSlot(slot);if(slot==-1){if(LiteGraph.debug)console.log(`Connect: Error, no slot of name ${slot}`);return false}}else if(!this.inputs||slot>=this.inputs.length){if(LiteGraph.debug){console.log("Connect: Error, slot number not found")}return false}const input=this.inputs[slot];if(!input){console.debug("disconnectInput: input not found",slot,this.inputs);return false}const{graph}=this;if(!graph)throw new NullGraphError;if(input._floatingLinks?.size){for(const link of input._floatingLinks){graph.removeFloatingLink(link)}}const link_id=this.inputs[slot].link;if(link_id!=null){this.inputs[slot].link=null;const link_info=graph._links.get(link_id);if(link_info){if(link_info.origin_id===-10&&"inputNode"in graph){graph.inputNode._disconnectNodeInput(this,input,link_info);return true}const target_node=graph.getNodeById(link_info.origin_id);if(!target_node){console.debug("disconnectInput: target node not found",link_info.origin_id);return false}const output=target_node.outputs[link_info.origin_slot];if(!output?.links?.length){console.debug("disconnectInput: output not found",link_info.origin_slot);return false}let i=0;for(const l=output.links.length;i<l;i++){if(output.links[i]==link_id){output.links.splice(i,1);break}}link_info.disconnect(graph,keepReroutes?"output":void 0);if(graph)graph._version++;this.onConnectionsChange?.(NodeSlotType.INPUT,slot,false,link_info,input);target_node.onConnectionsChange?.(NodeSlotType.OUTPUT,i,false,link_info,output)}}this.setDirtyCanvas(false,true);return true}getConnectionPos(is_input,slot_number,out){out||=new Float32Array(2);const{pos:[nodeX,nodeY],inputs,outputs}=this;if(this.flags.collapsed){const w=this._collapsed_width||LiteGraph.NODE_COLLAPSED_WIDTH;out[0]=is_input?nodeX:nodeX+w;out[1]=nodeY-LiteGraph.NODE_TITLE_HEIGHT*.5;return out}if(is_input&&slot_number==-1){out[0]=nodeX+LiteGraph.NODE_TITLE_HEIGHT*.5;out[1]=nodeY+LiteGraph.NODE_TITLE_HEIGHT*.5;return out}const inputPos=inputs?.[slot_number]?.pos;const outputPos=outputs?.[slot_number]?.pos;if(is_input&&inputPos){out[0]=nodeX+inputPos[0];out[1]=nodeY+inputPos[1];return out}else if(!is_input&&outputPos){out[0]=nodeX+outputPos[0];out[1]=nodeY+outputPos[1];return out}const offset=LiteGraph.NODE_SLOT_HEIGHT*.5;const slotIndex=is_input?this.#defaultVerticalInputs.indexOf(this.inputs[slot_number]):this.#defaultVerticalOutputs.indexOf(this.outputs[slot_number]);out[0]=is_input?nodeX+offset:nodeX+this.size[0]+1-offset;out[1]=nodeY+(slotIndex+.7)*LiteGraph.NODE_SLOT_HEIGHT+(this.constructor.slot_start_y||0);return out}get#defaultVerticalInputs(){return this.inputs.filter(slot=>!slot.pos&&!(this.widgets?.length&&isWidgetInputSlot(slot)))}get#defaultVerticalOutputs(){return this.outputs.filter(slot=>!slot.pos)}getInputPos(slot){return this.getInputSlotPos(this.inputs[slot])}getInputSlotPos(input){const{pos:[nodeX,nodeY]}=this;if(this.flags.collapsed){const halfTitle=LiteGraph.NODE_TITLE_HEIGHT*.5;return[nodeX,nodeY-halfTitle]}const{pos}=input;if(pos)return[nodeX+pos[0],nodeY+pos[1]];const offsetX=LiteGraph.NODE_SLOT_HEIGHT*.5;const nodeOffsetY=this.constructor.slot_start_y||0;const slotIndex=this.#defaultVerticalInputs.indexOf(input);const slotY=(slotIndex+.7)*LiteGraph.NODE_SLOT_HEIGHT;return[nodeX+offsetX,nodeY+slotY+nodeOffsetY]}getOutputPos(slot){const{pos:[nodeX,nodeY],outputs,size:[width2]}=this;if(this.flags.collapsed){const width22=this._collapsed_width||LiteGraph.NODE_COLLAPSED_WIDTH;const halfTitle=LiteGraph.NODE_TITLE_HEIGHT*.5;return[nodeX+width22,nodeY-halfTitle]}const outputPos=outputs?.[slot]?.pos;if(outputPos)return[nodeX+outputPos[0],nodeY+outputPos[1]];const offsetX=LiteGraph.NODE_SLOT_HEIGHT*.5;const nodeOffsetY=this.constructor.slot_start_y||0;const slotIndex=this.#defaultVerticalOutputs.indexOf(this.outputs[slot]);const slotY=(slotIndex+.7)*LiteGraph.NODE_SLOT_HEIGHT;return[nodeX+width2+1-offsetX,nodeY+slotY+nodeOffsetY]}snapToGrid(snapTo){return this.pinned?false:snapPoint(this.pos,snapTo)}alignToGrid(){this.snapToGrid(LiteGraph.CANVAS_GRID_SIZE)}trace(msg){this.console||=[];this.console.push(msg);if(this.console.length>LGraphNode.MAX_CONSOLE)this.console.shift()}setDirtyCanvas(dirty_foreground,dirty_background){this.graph?.canvasAction(c=>c.setDirty(dirty_foreground,dirty_background))}loadImage(url){const img=new Image;img.src=LiteGraph.node_images_path+url;img.ready=false;const dirty=()=>this.setDirtyCanvas(true);img.addEventListener("load",function(){this.ready=true;dirty()});return img}captureInput(v2){warnDeprecated("[DEPRECATED] captureInput will be removed in a future version. Please use LGraphCanvas.pointer (CanvasPointer) instead.");if(!this.graph||!this.graph.list_of_graphcanvas)return;const list=this.graph.list_of_graphcanvas;for(const c of list){if(!v2&&c.node_capturing_input!=this)continue;c.node_capturing_input=v2?this:null}}get collapsed(){return!!this.flags.collapsed}get collapsible(){return!this.pinned&&this.constructor.collapsable!==false}collapse(force){if(!this.collapsible&&!force)return;if(!this.graph)throw new NullGraphError;this.graph._version++;this.flags.collapsed=!this.flags.collapsed;this.setDirtyCanvas(true,true)}toggleAdvanced(){if(!this.widgets?.some(w=>w.advanced))return;if(!this.graph)throw new NullGraphError;this.graph._version++;this.showAdvanced=!this.showAdvanced;this.expandToFitContent();this.setDirtyCanvas(true,true)}get pinned(){return!!this.flags.pinned}pin(v2){if(!this.graph)throw new NullGraphError;this.graph._version++;this.flags.pinned=v2??!this.flags.pinned;this.resizable=!this.pinned;if(!this.pinned)delete this.flags.pinned}unpin(){this.pin(false)}localToScreen(x2,y,dragAndScale){return[(x2+this.pos[0])*dragAndScale.scale+dragAndScale.offset[0],(y+this.pos[1])*dragAndScale.scale+dragAndScale.offset[1]]}get width(){return this.collapsed?this._collapsed_width||LiteGraph.NODE_COLLAPSED_WIDTH:this.size[0]}get height(){return LiteGraph.NODE_TITLE_HEIGHT+this.bodyHeight}get bodyHeight(){return this.collapsed?0:this.size[1]}drawBadges(ctx,{gap=2}={}){const badgeInstances=this.badges.map(badge=>badge instanceof LGraphBadge?badge:badge());const isLeftAligned=this.badgePosition===BadgePosition.TopLeft;let currentX=isLeftAligned?0:this.width-badgeInstances.reduce((acc,badge)=>acc+badge.getWidth(ctx)+gap,0);const y=-(LiteGraph.NODE_TITLE_HEIGHT+gap);for(const badge of badgeInstances){badge.draw(ctx,currentX,y-badge.height);currentX+=badge.getWidth(ctx)+gap}}drawTitleBarBackground(ctx,{scale,title_height=LiteGraph.NODE_TITLE_HEIGHT,low_quality=false}){const fgcolor=this.renderingColor;const shape=this.renderingShape;const size=this.renderingSize;if(this.onDrawTitleBar){this.onDrawTitleBar(ctx,title_height,size,scale,fgcolor);return}if(this.title_mode===TitleMode.TRANSPARENT_TITLE){return}if(this.collapsed){ctx.shadowColor=LiteGraph.DEFAULT_SHADOW_COLOR}ctx.fillStyle=this.constructor.title_color||fgcolor;ctx.beginPath();if(shape==RenderShape.BOX||low_quality){ctx.rect(0,-title_height,size[0],title_height)}else if(shape==RenderShape.ROUND||shape==RenderShape.CARD){ctx.roundRect(0,-title_height,size[0],title_height,this.collapsed?[LiteGraph.ROUND_RADIUS]:[LiteGraph.ROUND_RADIUS,LiteGraph.ROUND_RADIUS,0,0])}ctx.fill();ctx.shadowColor="transparent"}drawTitleBox(ctx,{scale,low_quality=false,title_height=LiteGraph.NODE_TITLE_HEIGHT,box_size=10}){const size=this.renderingSize;const shape=this.renderingShape;if(this.onDrawTitleBox){this.onDrawTitleBox(ctx,title_height,size,scale);return}if([RenderShape.ROUND,RenderShape.CIRCLE,RenderShape.CARD].includes(shape)){if(low_quality){ctx.fillStyle="black";ctx.beginPath();ctx.arc(title_height*.5,title_height*-.5,box_size*.5+1,0,Math.PI*2);ctx.fill()}ctx.fillStyle=this.renderingBoxColor;if(low_quality){ctx.fillRect(title_height*.5-box_size*.5,title_height*-.5-box_size*.5,box_size,box_size)}else{ctx.beginPath();ctx.arc(title_height*.5,title_height*-.5,box_size*.5,0,Math.PI*2);ctx.fill()}}else{if(low_quality){ctx.fillStyle="black";ctx.fillRect((title_height-box_size)*.5-1,(title_height+box_size)*-.5-1,box_size+2,box_size+2)}ctx.fillStyle=this.renderingBoxColor;ctx.fillRect((title_height-box_size)*.5,(title_height+box_size)*-.5,box_size,box_size)}}drawTitleText(ctx,{scale,default_title_color,low_quality=false,title_height=LiteGraph.NODE_TITLE_HEIGHT}){const size=this.renderingSize;const selected=this.selected;if(this.onDrawTitleText){this.onDrawTitleText(ctx,title_height,size,scale,this.titleFontStyle,selected);return}if(low_quality){return}ctx.font=this.titleFontStyle;const rawTitle=this.getTitle()??`❌ ${this.type}`;const title=String(rawTitle)+(this.pinned?"📌":"");if(title){if(selected){ctx.fillStyle=LiteGraph.NODE_SELECTED_TITLE_COLOR}else{ctx.fillStyle=this.constructor.title_text_color||default_title_color}let availableWidth=size[0]-title_height*2;if(this.title_buttons?.length>0){let buttonsWidth=0;const savedFont=ctx.font;for(const button of this.title_buttons){if(button.visible){buttonsWidth+=button.getWidth(ctx)+2}}ctx.font=savedFont;if(buttonsWidth>0){buttonsWidth+=10;availableWidth-=buttonsWidth}}let displayTitle=title;if(this.collapsed){displayTitle=title.substr(0,20)}else if(availableWidth>0){displayTitle=truncateText(ctx,title,availableWidth)}ctx.textAlign="left";ctx.fillText(displayTitle,title_height,LiteGraph.NODE_TITLE_TEXT_Y-title_height)}}connectInputToOutput(){const{inputs,outputs,graph}=this;if(!inputs||!outputs)return;if(!graph)throw new NullGraphError;const{_links}=graph;let madeAnyConnections=false;for(const[index,input]of inputs.entries()){if(input.link==null)continue;const output=outputs[index];if(!output||!LiteGraph.isValidConnection(input.type,output.type))continue;const inLink=_links.get(input.link);if(!inLink)continue;const inNode=graph.getNodeById(inLink?.origin_id);if(!inNode)continue;bypassAllLinks(output,inNode,inLink,graph)}if(!(this.flags.keepAllLinksOnBypass??LGraphNode.keepAllLinksOnBypass))return madeAnyConnections;for(const input of inputs){if(input.link==null)continue;const inLink=_links.get(input.link);if(!inLink)continue;const inNode=graph.getNodeById(inLink?.origin_id);if(!inNode)continue;for(const output of outputs){if(!LiteGraph.isValidConnection(input.type,output.type))continue;bypassAllLinks(output,inNode,inLink,graph);break}}return madeAnyConnections;function bypassAllLinks(output,inNode,inLink,graph2){const outLinks=output.links?.map(x2=>_links.get(x2)).filter(x2=>!!x2);if(!outLinks?.length)return;for(const outLink of outLinks){const outNode=graph2.getNodeById(outLink.target_id);if(!outNode)continue;const result=inNode.connect(inLink.origin_slot,outNode,outLink.target_slot,inLink.parentId);madeAnyConnections||=!!result}}}isWidgetVisible(widget){const isHidden=this.collapsed||widget.hidden||widget.advanced&&!this.showAdvanced;return!isHidden}drawWidgets(ctx,{lowQuality=false,editorAlpha=1}){if(!this.widgets)return;const nodeWidth=this.size[0];const{widgets}=this;const H=LiteGraph.NODE_WIDGET_HEIGHT;const showText=!lowQuality;ctx.save();ctx.globalAlpha=editorAlpha;for(const widget of widgets){if(!this.isWidgetVisible(widget))continue;const{y}=widget;const outlineColour=widget.advanced?LiteGraph.WIDGET_ADVANCED_OUTLINE_COLOR:LiteGraph.WIDGET_OUTLINE_COLOR;widget.last_y=y;widget.computedDisabled=widget.disabled||this.getSlotFromWidget(widget)?.link!=null;ctx.strokeStyle=outlineColour;ctx.fillStyle="#222";ctx.textAlign="left";if(widget.computedDisabled)ctx.globalAlpha*=.5;const width2=widget.width||nodeWidth;if(typeof widget.draw==="function"){widget.draw(ctx,this,width2,y,H,lowQuality)}else{toConcreteWidget(widget,this,false)?.drawWidget(ctx,{width:width2,showText})}ctx.globalAlpha=editorAlpha}ctx.restore()}drawCollapsedSlots(ctx){for(const slot of this.#concreteInputs){if(slot.link!=null){slot.drawCollapsed(ctx);break}}for(const slot of this.#concreteOutputs){if(slot.links?.length){slot.drawCollapsed(ctx);break}}}get slots(){return[...this.inputs,...this.outputs]}#measureSlot(slot,slotIndex,isInput){const pos=isInput?this.getInputPos(slotIndex):this.getOutputPos(slotIndex);slot.boundingRect[0]=pos[0]-LiteGraph.NODE_SLOT_HEIGHT*.5;slot.boundingRect[1]=pos[1]-LiteGraph.NODE_SLOT_HEIGHT*.5;slot.boundingRect[2]=slot.isWidgetInputSlot?BaseWidget.margin:LiteGraph.NODE_SLOT_HEIGHT;slot.boundingRect[3]=LiteGraph.NODE_SLOT_HEIGHT}#measureSlots(){const slots=[];for(const[slotIndex,slot]of this.#concreteInputs.entries()){if(this.widgets?.length&&isWidgetInputSlot(slot))continue;this.#measureSlot(slot,slotIndex,true);slots.push(slot)}for(const[slotIndex,slot]of this.#concreteOutputs.entries()){this.#measureSlot(slot,slotIndex,false);slots.push(slot)}return slots.length?createBounds(slots,0):null}#getMouseOverSlot(slot){const isInput=isINodeInputSlot(slot);const mouseOverId=this.mouseOver?.[isInput?"inputId":"outputId"]??-1;if(mouseOverId===-1){return null}return isInput?this.inputs[mouseOverId]:this.outputs[mouseOverId]}#isMouseOverSlot(slot){return this.#getMouseOverSlot(slot)===slot}#isMouseOverWidget(widget){if(!widget)return false;return this.mouseOver?.overWidget===widget}getSlotFromWidget(widget){if(widget)return this.inputs.find(slot=>isWidgetInputSlot(slot)&&slot.widget.name===widget.name)}getWidgetFromSlot(slot){if(!isWidgetInputSlot(slot))return;return this.widgets?.find(w=>w.name===slot.widget.name)}drawSlots(ctx,{fromSlot,colorContext,editorAlpha,lowQuality}){for(const slot of[...this.#concreteInputs,...this.#concreteOutputs]){const isValidTarget=fromSlot&&slot.isValidTarget(fromSlot);const isMouseOverSlot=this.#isMouseOverSlot(slot);const isValid=!fromSlot||isValidTarget;const highlight=isValid&&isMouseOverSlot;if(isMouseOverSlot||isValidTarget||!slot.isWidgetInputSlot||this.#isMouseOverWidget(this.getWidgetFromSlot(slot))||slot.isConnected){ctx.globalAlpha=isValid?editorAlpha:.4*editorAlpha;slot.draw(ctx,{colorContext,lowQuality,highlight})}}}#arrangeWidgets(widgetStartY){if(!this.widgets||!this.widgets.length)return;const bodyHeight=this.bodyHeight;const startY=this.widgets_start_y??(this.widgets_up?0:widgetStartY)+2;let freeSpace=bodyHeight-startY;let fixedWidgetHeight=0;const growableWidgets=[];for(const w of this.widgets){if(w.computeSize){const height=w.computeSize()[1]+4;w.computedHeight=height;fixedWidgetHeight+=height}else if(w.computeLayoutSize){const{minHeight,maxHeight}=w.computeLayoutSize(this);growableWidgets.push({minHeight,prefHeight:maxHeight,w})}else{const height=LiteGraph.NODE_WIDGET_HEIGHT+4;w.computedHeight=height;fixedWidgetHeight+=height}}freeSpace-=fixedWidgetHeight;this.freeWidgetSpace=freeSpace;const spaceRequests=growableWidgets.map(d=>({minSize:d.minHeight,maxSize:d.prefHeight}));const allocations=distributeSpace(Math.max(0,freeSpace),spaceRequests);for(const[i,d]of growableWidgets.entries()){d.w.computedHeight=allocations[i]}let y=startY;for(const w of this.widgets){w.y=y;y+=w.computedHeight??0}if(!this.graph)throw new NullGraphError;if(y>bodyHeight){this.setSize([this.size[0],y]);this.graph.setDirtyCanvas(false,true)}}#arrangeWidgetInputSlots(){if(!this.widgets)return;const slotByWidgetName=new Map;for(const[i,slot]of this.inputs.entries()){if(!isWidgetInputSlot(slot))continue;slotByWidgetName.set(slot.widget.name,{...slot,index:i})}if(!slotByWidgetName.size)return;for(const widget of this.widgets){const slot=slotByWidgetName.get(widget.name);if(!slot)continue;const actualSlot=this.#concreteInputs[slot.index];const offset=LiteGraph.NODE_SLOT_HEIGHT*.5;actualSlot.pos=[offset,widget.y+offset];this.#measureSlot(actualSlot,slot.index,true)}}_setConcreteSlots(){this.#concreteInputs=this.inputs.map(slot=>toClass(NodeInputSlot,slot,this));this.#concreteOutputs=this.outputs.map(slot=>toClass(NodeOutputSlot,slot,this))}arrange(){const slotsBounds=this.#measureSlots();const widgetStartY=slotsBounds?slotsBounds[1]+slotsBounds[3]-this.pos[1]:0;this.#arrangeWidgets(widgetStartY);this.#arrangeWidgetInputSlots()}drawProgressBar(ctx){if(!this.progress)return;const originalFillStyle=ctx.fillStyle;ctx.fillStyle="green";ctx.fillRect(0,0,this.width*this.progress,6);ctx.fillStyle=originalFillStyle}}function getAllNestedItems(items){const allItems=new Set;if(items){for(const item of items)addRecursively(item,allItems)}return allItems;function addRecursively(item,flatSet){if(flatSet.has(item)||item.pinned)return;flatSet.add(item);if(item.children){for(const child of item.children)addRecursively(child,flatSet)}}}function findFirstNode(items){for(const item of items){if(item instanceof LGraphNode)return item}}function findFreeSlotOfType(slots,type,hasNoLinks){if(!slots?.length)return;let occupiedSlot;let wildSlot;let occupiedWildSlot;const validTypes=parseSlotTypes(type);for(const[index,slot]of slots.entries()){const slotTypes=parseSlotTypes(slot.type);for(const validType of validTypes){for(const slotType of slotTypes){if(slotType===validType){if(hasNoLinks(slot)){return{index,slot}}occupiedSlot??={index,slot}}else if(!wildSlot&&(validType==="*"||slotType==="*")){if(hasNoLinks(slot)){wildSlot={index,slot}}else{occupiedWildSlot??={index,slot}}}}}}return wildSlot??occupiedSlot??occupiedWildSlot}function removeFromArray(array,value){const index=array.indexOf(value);const found=index!==-1;if(found)array.splice(index,1);return found}class SubgraphInput extends SubgraphSlot{events=new CustomEventTarget;#widgetRef;get _widget(){return this.#widgetRef?.deref()}set _widget(widget){this.#widgetRef=widget?new WeakRef(widget):void 0}connect(slot,node2,afterRerouteId){const{subgraph}=this.parent;const inputIndex=node2.inputs.indexOf(slot);if(node2.onConnectInput?.(inputIndex,this.type,this,this.parent,-1)===false)return;if(slot.link!=null){subgraph.beforeChange();const link2=subgraph.getLink(slot.link);this.parent._disconnectNodeInput(node2,slot,link2)}const inputWidget=node2.getWidgetFromSlot(slot);if(inputWidget){if(!this.matchesWidget(inputWidget)){console.warn("Target input has invalid widget.",slot,node2);return}this._widget??=inputWidget;this.events.dispatch("input-connected",{input:slot,widget:inputWidget})}const link=new LLink(++subgraph.state.lastLinkId,slot.type,this.parent.id,this.parent.slots.indexOf(this),node2.id,inputIndex,afterRerouteId);subgraph._links.set(link.id,link);this.linkIds.push(link.id);slot.link=link.id;const reroutes=LLink.getReroutes(subgraph,link);for(const reroute of reroutes){reroute.linkIds.add(link.id);if(reroute.floating)delete reroute.floating;reroute._dragging=void 0}const lastReroute=reroutes.at(-1);if(lastReroute){for(const linkId of lastReroute.floatingLinkIds){const link2=subgraph.floatingLinks.get(linkId);if(link2?.parentId===lastReroute.id){subgraph.removeFloatingLink(link2)}}}subgraph._version++;node2.onConnectionsChange?.(NodeSlotType.INPUT,inputIndex,true,link,slot);subgraph.afterChange();return link}get labelPos(){const[x2,y,,height]=this.boundingRect;return[x2,y+height*.5]}getConnectedWidgets(){const{subgraph}=this.parent;const widgets=[];for(const linkId of this.linkIds){const link=subgraph.getLink(linkId);if(!link){console.error("Link not found",linkId);continue}const resolved=link.resolve(subgraph);if(resolved.input&&resolved.inputNode?.widgets){const widgetNamePojo=resolved.input.widget;if(!widgetNamePojo)continue;if(!widgetNamePojo.name){console.warn("Invalid widget name",widgetNamePojo);continue}const widget=resolved.inputNode.widgets.find(w=>w.name===widgetNamePojo.name);if(!widget){console.warn("Widget not found",widgetNamePojo);continue}widgets.push(widget)}else{console.debug("No input found on link id",linkId,link)}}return widgets}matchesWidget(otherWidget){const widget=this.#widgetRef?.deref();if(!widget)return true;if(otherWidget.type!==widget.type||otherWidget.options.min!==widget.options.min||otherWidget.options.max!==widget.options.max||otherWidget.options.step!==widget.options.step||otherWidget.options.step2!==widget.options.step2||otherWidget.options.precision!==widget.options.precision){return false}return true}disconnect(){super.disconnect();this.events.dispatch("input-disconnected",{input:this})}arrange(rect){const[right,top,width2,height]=rect;const{boundingRect:b,pos}=this;b[0]=right-width2;b[1]=top;b[2]=width2;b[3]=height;pos[0]=right-height*.5;pos[1]=top+height*.5}isValidTarget(fromSlot){if(isNodeSlot(fromSlot)){return"link"in fromSlot&&LiteGraph.isValidConnection(this.type,fromSlot.type)}if(isSubgraphOutput(fromSlot)){return LiteGraph.isValidConnection(this.type,fromSlot.type)}return false}}class EmptySubgraphInput extends SubgraphInput{constructor(parent){super({id:zeroUuid,name:"",type:""},parent)}connect(slot,node2,afterRerouteId){const{subgraph}=this.parent;const existingNames=subgraph.inputs.map(x2=>x2.name);const name=nextUniqueName(slot.name,existingNames);const input=subgraph.addInput(name,String(slot.type));return input.connect(slot,node2,afterRerouteId)}get labelPos(){const[x2,y,,height]=this.boundingRect;return[x2,y+height*.5]}}class SubgraphInputNode extends SubgraphIONodeBase{id=SUBGRAPH_INPUT_ID;emptySlot=new EmptySubgraphInput(this);get slots(){return this.subgraph.inputs}get allSlots(){return[...this.slots,this.emptySlot]}get slotAnchorX(){const[x2,,width2]=this.boundingRect;return x2+width2-SubgraphIONodeBase.roundedRadius}onPointerDown(e2,pointer,linkConnector){if(e2.button===0){for(const slot of this.allSlots){const slotBounds=Rectangle.fromCentre(slot.pos,slot.boundingRect.height);if(slotBounds.containsXy(e2.canvasX,e2.canvasY)){pointer.onDragStart=()=>{linkConnector.dragNewFromSubgraphInput(this.subgraph,this,slot)};pointer.onDragEnd=eUp=>{linkConnector.dropLinks(this.subgraph,eUp)};pointer.finally=()=>{linkConnector.reset(true)}}}}else if(e2.button===2){const slot=this.getSlotInPosition(e2.canvasX,e2.canvasY);if(slot)this.showSlotContextMenu(slot,e2)}}renameSlot(slot,name){this.subgraph.renameInput(slot,name)}removeSlot(slot){this.subgraph.removeInput(slot)}canConnectTo(inputNode,input,fromSlot){return inputNode.canConnectTo(this,input,fromSlot)}connectSlots(fromSlot,inputNode,input,afterRerouteId){const{subgraph}=this;const outputIndex=this.slots.indexOf(fromSlot);const inputIndex=inputNode.inputs.indexOf(input);if(outputIndex===-1||inputIndex===-1)throw new Error("Invalid slot indices.");return new LLink(++subgraph.state.lastLinkId,input.type||fromSlot.type,this.id,outputIndex,inputNode.id,inputIndex,afterRerouteId)}connectByType(slot,target_node,target_slotType,optsIn){const inputSlot=target_node.findInputByType(target_slotType);if(!inputSlot)return;if(slot===-1){const newSubgraphInput=this.subgraph.addInput(inputSlot.slot.name,String(inputSlot.slot.type??""));const newSlotIndex=this.slots.indexOf(newSubgraphInput);if(newSlotIndex===-1){console.error("Could not find newly created subgraph input slot.");return}slot=newSlotIndex}return this.slots[slot].connect(inputSlot.slot,target_node,optsIn?.afterRerouteId)}findOutputSlot(name){return this.slots.find(output=>output.name===name)}findOutputByType(type){return findFreeSlotOfType(this.slots,type,slot=>slot.linkIds.length>0)?.slot}_disconnectNodeInput(node2,input,link){const{subgraph}=this;if(input._floatingLinks?.size){for(const link2 of input._floatingLinks){subgraph.removeFloatingLink(link2)}}input.link=null;subgraph.setDirtyCanvas(false,true);if(!link)return;const subgraphInputIndex=link.origin_slot;link.disconnect(subgraph,"output");subgraph._version++;const subgraphInput=this.slots.at(subgraphInputIndex);if(!subgraphInput){console.debug("disconnectNodeInput: subgraphInput not found",this,subgraphInputIndex);return}const index=subgraphInput.linkIds.indexOf(link.id);if(index!==-1){subgraphInput.linkIds.splice(index,1)}else{console.debug("disconnectNodeInput: link ID not found in subgraphInput linkIds",link.id)}node2.onConnectionsChange?.(NodeSlotType.OUTPUT,index,false,link,subgraphInput)}drawProtected(ctx,colorContext,fromSlot,editorAlpha){const{roundedRadius}=SubgraphIONodeBase;const transform=ctx.getTransform();const[x2,y,width2,height]=this.boundingRect;ctx.translate(x2,y);ctx.strokeStyle=this.sideStrokeStyle;ctx.lineWidth=this.sideLineWidth;ctx.beginPath();ctx.arc(width2-roundedRadius,roundedRadius,roundedRadius,Math.PI*1.5,0);ctx.moveTo(width2,roundedRadius);ctx.lineTo(width2,height-roundedRadius);ctx.arc(width2-roundedRadius,height-roundedRadius,roundedRadius,0,Math.PI*.5);ctx.stroke();ctx.setTransform(transform);this.drawSlots(ctx,colorContext,fromSlot,editorAlpha)}}class FloatingRenderLink{constructor(network,link,toType,fromReroute,dragDirection=LinkDirection.CENTER){this.network=network;this.link=link;this.toType=toType;this.fromReroute=fromReroute;this.dragDirection=dragDirection;const{origin_id:outputNodeId,target_id:inputNodeId,origin_slot:outputIndex,target_slot:inputIndex}=link;if(outputNodeId!==-1){const outputNode=network.getNodeById(outputNodeId)??void 0;if(!outputNode)throw new Error(`Creating DraggingRenderLink for link [${link.id}] failed: Output node [${outputNodeId}] not found.`);const outputSlot=outputNode?.outputs.at(outputIndex);if(!outputSlot)throw new Error(`Creating DraggingRenderLink for link [${link.id}] failed: Output slot [${outputIndex}] not found.`);this.outputNodeId=outputNodeId;this.outputNode=outputNode;this.outputSlot=outputSlot;this.outputIndex=outputIndex;this.outputPos=outputNode.getOutputPos(outputIndex);this.node=outputNode;this.fromSlot=outputSlot;this.fromPos=fromReroute?.pos??this.outputPos;this.fromDirection=LinkDirection.LEFT;this.dragDirection=LinkDirection.RIGHT;this.fromSlotIndex=outputIndex}else{const inputNode=network.getNodeById(inputNodeId)??void 0;if(!inputNode)throw new Error(`Creating DraggingRenderLink for link [${link.id}] failed: Input node [${inputNodeId}] not found.`);const inputSlot=inputNode?.inputs.at(inputIndex);if(!inputSlot)throw new Error(`Creating DraggingRenderLink for link [${link.id}] failed: Input slot [${inputIndex}] not found.`);this.inputNodeId=inputNodeId;this.inputNode=inputNode;this.inputSlot=inputSlot;this.inputIndex=inputIndex;this.inputPos=inputNode.getInputPos(inputIndex);this.node=inputNode;this.fromSlot=inputSlot;this.fromDirection=LinkDirection.RIGHT;this.fromSlotIndex=inputIndex}this.fromPos=fromReroute.pos}node;fromSlot;fromPos;fromDirection;fromSlotIndex;outputNodeId=-1;outputNode;outputSlot;outputIndex=-1;outputPos;inputNodeId=-1;inputNode;inputSlot;inputIndex=-1;inputPos;canConnectToInput(){return this.toType==="input"}canConnectToOutput(){return this.toType==="output"}canConnectToReroute(reroute){if(this.toType==="input"){if(reroute.origin_id===this.inputNode?.id)return false}else{if(reroute.origin_id===this.outputNode?.id)return false}return true}connectToInput(node2,input,_events){const floatingLink=this.link;floatingLink.target_id=node2.id;floatingLink.target_slot=node2.inputs.indexOf(input);node2.disconnectInput(node2.inputs.indexOf(input));this.fromSlot._floatingLinks?.delete(floatingLink);input._floatingLinks??=new Set;input._floatingLinks.add(floatingLink)}connectToOutput(node2,output,_events){const floatingLink=this.link;floatingLink.origin_id=node2.id;floatingLink.origin_slot=node2.outputs.indexOf(output);this.fromSlot._floatingLinks?.delete(floatingLink);output._floatingLinks??=new Set;output._floatingLinks.add(floatingLink)}connectToSubgraphInput(input,_events){const floatingLink=this.link;floatingLink.origin_id=SUBGRAPH_INPUT_ID;floatingLink.origin_slot=input.parent.slots.indexOf(input);this.fromSlot._floatingLinks?.delete(floatingLink);input._floatingLinks??=new Set;input._floatingLinks.add(floatingLink)}connectToSubgraphOutput(output,_events){const floatingLink=this.link;floatingLink.origin_id=SUBGRAPH_OUTPUT_ID;floatingLink.origin_slot=output.parent.slots.indexOf(output);this.fromSlot._floatingLinks?.delete(floatingLink);output._floatingLinks??=new Set;output._floatingLinks.add(floatingLink)}connectToRerouteInput(reroute,{node:inputNode,input},events){const floatingLink=this.link;floatingLink.target_id=inputNode.id;floatingLink.target_slot=inputNode.inputs.indexOf(input);this.fromSlot._floatingLinks?.delete(floatingLink);input._floatingLinks??=new Set;input._floatingLinks.add(floatingLink);events.dispatch("input-moved",this)}connectToRerouteOutput(reroute,outputNode,output,events){const floatingLink=this.link;floatingLink.origin_id=outputNode.id;floatingLink.origin_slot=outputNode.outputs.indexOf(output);this.fromSlot._floatingLinks?.delete(floatingLink);output._floatingLinks??=new Set;output._floatingLinks.add(floatingLink);events.dispatch("output-moved",this)}}class MovingLinkBase{constructor(network,link,toType,fromReroute,dragDirection=LinkDirection.CENTER){this.network=network;this.link=link;this.toType=toType;this.fromReroute=fromReroute;this.dragDirection=dragDirection;const{origin_id:outputNodeId,target_id:inputNodeId,origin_slot:outputIndex,target_slot:inputIndex}=link;const outputNode=network.getNodeById(outputNodeId)??void 0;if(!outputNode)throw new Error(`Creating MovingRenderLink for link [${link.id}] failed: Output node [${outputNodeId}] not found.`);const outputSlot=outputNode.outputs.at(outputIndex);if(!outputSlot)throw new Error(`Creating MovingRenderLink for link [${link.id}] failed: Output slot [${outputIndex}] not found.`);this.outputNodeId=outputNodeId;this.outputNode=outputNode;this.outputSlot=outputSlot;this.outputIndex=outputIndex;this.outputPos=outputNode.getOutputPos(outputIndex);const inputNode=network.getNodeById(inputNodeId)??void 0;if(!inputNode)throw new Error(`Creating DraggingRenderLink for link [${link.id}] failed: Input node [${inputNodeId}] not found.`);const inputSlot=inputNode.inputs.at(inputIndex);if(!inputSlot)throw new Error(`Creating DraggingRenderLink for link [${link.id}] failed: Input slot [${inputIndex}] not found.`);this.inputNodeId=inputNodeId;this.inputNode=inputNode;this.inputSlot=inputSlot;this.inputIndex=inputIndex;this.inputPos=inputNode.getInputPos(inputIndex)}outputNodeId;outputNode;outputSlot;outputIndex;outputPos;inputNodeId;inputNode;inputSlot;inputIndex;inputPos}class MovingInputLink extends MovingLinkBase{toType="input";node;fromSlot;fromPos;fromDirection;fromSlotIndex;constructor(network,link,fromReroute,dragDirection=LinkDirection.CENTER){super(network,link,"input",fromReroute,dragDirection);this.node=this.outputNode;this.fromSlot=this.outputSlot;this.fromPos=fromReroute?.pos??this.outputPos;this.fromDirection=LinkDirection.NONE;this.fromSlotIndex=this.outputIndex}canConnectToInput(inputNode,input){return this.node.canConnectTo(inputNode,input,this.outputSlot)}canConnectToOutput(){return false}canConnectToReroute(reroute){return reroute.origin_id!==this.inputNode.id}connectToInput(inputNode,input,events){if(input===this.inputSlot)return;this.inputNode.disconnectInput(this.inputIndex,true);const link=this.outputNode.connectSlots(this.outputSlot,inputNode,input,this.fromReroute?.id);if(link)events.dispatch("input-moved",this);return link}connectToOutput(){throw new Error("MovingInputLink cannot connect to an output.")}connectToSubgraphInput(){throw new Error("MovingInputLink cannot connect to a subgraph input.")}connectToSubgraphOutput(output,events){const newLink=output.connect(this.fromSlot,this.node,this.fromReroute?.id);events?.dispatch("link-created",newLink)}connectToRerouteInput(reroute,{node:inputNode,input,link:existingLink},events,originalReroutes){const{outputNode,outputSlot,fromReroute}=this;for(const reroute2 of originalReroutes){if(reroute2.id===this.link.parentId)break;if(reroute2.totalLinks===1)reroute2.remove()}reroute.parentId=fromReroute?.id;const newLink=outputNode.connectSlots(outputSlot,inputNode,input,existingLink.parentId);if(newLink)events.dispatch("input-moved",this)}connectToRerouteOutput(){throw new Error("MovingInputLink cannot connect to an output.")}disconnect(){return this.inputNode.disconnectInput(this.inputIndex,true)}}class MovingOutputLink extends MovingLinkBase{toType="output";node;fromSlot;fromPos;fromDirection;fromSlotIndex;constructor(network,link,fromReroute,dragDirection=LinkDirection.CENTER){super(network,link,"output",fromReroute,dragDirection);this.node=this.inputNode;this.fromSlot=this.inputSlot;this.fromPos=fromReroute?.pos??this.inputPos;this.fromDirection=LinkDirection.LEFT;this.fromSlotIndex=this.inputIndex}canConnectToInput(){return false}canConnectToOutput(outputNode,output){return outputNode.canConnectTo(this.node,this.inputSlot,output)}canConnectToReroute(reroute){return reroute.origin_id!==this.outputNode.id}connectToInput(){throw new Error("MovingOutputLink cannot connect to an input.")}connectToOutput(outputNode,output,events){if(output===this.outputSlot)return;const link=outputNode.connectSlots(output,this.inputNode,this.inputSlot,this.link.parentId);if(link)events.dispatch("output-moved",this);return link}connectToSubgraphInput(input,events){const newLink=input.connect(this.fromSlot,this.node,this.fromReroute?.id);events?.dispatch("link-created",newLink)}connectToSubgraphOutput(){throw new Error("MovingOutputLink cannot connect to a subgraph output.")}connectToRerouteInput(){throw new Error("MovingOutputLink cannot connect to an input.")}connectToRerouteOutput(reroute,outputNode,output,events){const{inputNode,inputSlot,fromReroute}=this;const floatingTerminus=reroute?.floating?.slotType==="output";if(fromReroute){fromReroute.parentId=reroute.id}else{this.link.parentId=reroute.id}outputNode.connectSlots(output,inputNode,inputSlot,this.link.parentId);if(floatingTerminus)reroute.removeAllFloatingLinks();events.dispatch("output-moved",this)}disconnect(){return this.outputNode.disconnectOutput(this.outputIndex,this.inputNode)}}class ToInputFromIoNodeLink{constructor(network,node2,fromSlot,fromReroute,dragDirection=LinkDirection.CENTER,existingLink){this.network=network;this.node=node2;this.fromSlot=fromSlot;this.fromReroute=fromReroute;this.dragDirection=dragDirection;const outputIndex=node2.slots.indexOf(fromSlot);if(outputIndex===-1&&fromSlot!==node2.emptySlot){throw new Error(`Creating render link for node [${this.node.id}] failed: Slot index not found.`)}this.fromSlotIndex=outputIndex;this.fromPos=fromReroute?fromReroute.pos:fromSlot.pos;this.existingLink=existingLink}toType="input";fromSlotIndex;fromPos;fromDirection=LinkDirection.RIGHT;existingLink;canConnectToInput(inputNode,input){return this.node.canConnectTo(inputNode,input,this.fromSlot)}canConnectToOutput(){return false}connectToInput(node2,input,events){const{fromSlot,fromReroute,existingLink}=this;const newLink=fromSlot.connect(input,node2,fromReroute?.id);if(existingLink){events.dispatch("input-moved",this)}else{events.dispatch("link-created",newLink)}}connectToSubgraphOutput(){throw new Error("Not implemented")}connectToRerouteInput(reroute,{node:inputNode,input,link},events,originalReroutes){const{fromSlot,fromReroute}=this;const floatingTerminus=fromReroute?.floating?.slotType==="output";reroute.parentId=fromReroute?.id;const newLink=fromSlot.connect(input,inputNode,link.parentId);if(floatingTerminus)fromReroute.removeAllFloatingLinks();for(const reroute2 of originalReroutes){if(reroute2.id===fromReroute?.id)break;reroute2.removeLink(link);if(reroute2.totalLinks===0){if(link.isFloating){reroute2.remove()}else{const cl=link.toFloating("output",reroute2.id);this.network.addFloatingLink(cl);reroute2.floating={slotType:"output"}}}}if(this.existingLink){events.dispatch("input-moved",this)}else{events.dispatch("link-created",newLink)}}connectToOutput(){throw new Error("ToInputRenderLink cannot connect to an output.")}connectToSubgraphInput(){throw new Error("ToInputRenderLink cannot connect to a subgraph input.")}connectToRerouteOutput(){throw new Error("ToInputRenderLink cannot connect to an output.")}}class ToInputRenderLink{constructor(network,node2,fromSlot,fromReroute,dragDirection=LinkDirection.CENTER){this.network=network;this.node=node2;this.fromSlot=fromSlot;this.fromReroute=fromReroute;this.dragDirection=dragDirection;const outputIndex=node2.outputs.indexOf(fromSlot);if(outputIndex===-1)throw new Error(`Creating render link for node [${this.node.id}] failed: Slot index not found.`);this.fromSlotIndex=outputIndex;this.fromPos=fromReroute?fromReroute.pos:this.node.getOutputPos(outputIndex)}toType="input";fromPos;fromSlotIndex;fromDirection=LinkDirection.RIGHT;canConnectToInput(inputNode,input){return this.node.canConnectTo(inputNode,input,this.fromSlot)}canConnectToOutput(){return false}connectToInput(node2,input,events){const{node:outputNode,fromSlot,fromReroute}=this;if(node2===outputNode)return;const newLink=outputNode.connectSlots(fromSlot,node2,input,fromReroute?.id);events.dispatch("link-created",newLink)}connectToSubgraphOutput(output,events){const newLink=output.connect(this.fromSlot,this.node,this.fromReroute?.id);events.dispatch("link-created",newLink)}connectToRerouteInput(reroute,{node:inputNode,input,link},events,originalReroutes){const{node:outputNode,fromSlot,fromReroute}=this;const floatingTerminus=fromReroute?.floating?.slotType==="output";reroute.parentId=fromReroute?.id;const newLink=outputNode.connectSlots(fromSlot,inputNode,input,link.parentId);if(floatingTerminus)fromReroute.removeAllFloatingLinks();for(const reroute2 of originalReroutes){if(reroute2.id===fromReroute?.id)break;reroute2.removeLink(link);if(reroute2.totalLinks===0){if(link.isFloating){reroute2.remove()}else{const cl=link.toFloating("output",reroute2.id);this.network.addFloatingLink(cl);reroute2.floating={slotType:"output"}}}}events.dispatch("link-created",newLink)}connectToOutput(){throw new Error("ToInputRenderLink cannot connect to an output.")}connectToSubgraphInput(){throw new Error("ToInputRenderLink cannot connect to a subgraph input.")}connectToRerouteOutput(){throw new Error("ToInputRenderLink cannot connect to an output.")}}class ToOutputFromIoNodeLink{constructor(network,node2,fromSlot,fromReroute,dragDirection=LinkDirection.CENTER){this.network=network;this.node=node2;this.fromSlot=fromSlot;this.fromReroute=fromReroute;this.dragDirection=dragDirection;const inputIndex=node2.slots.indexOf(fromSlot);if(inputIndex===-1&&fromSlot!==node2.emptySlot){throw new Error(`Creating render link for node [${this.node.id}] failed: Slot index not found.`)}this.fromSlotIndex=inputIndex;this.fromPos=fromReroute?fromReroute.pos:fromSlot.pos}toType="output";fromPos;fromSlotIndex;fromDirection=LinkDirection.LEFT;canConnectToInput(){return false}canConnectToOutput(outputNode,output){return this.node.canConnectTo(outputNode,this.fromSlot,output)}canConnectToReroute(reroute){if(reroute.origin_id===this.node.id)return false;return true}connectToOutput(node2,output,events){const{fromSlot,fromReroute}=this;const newLink=fromSlot.connect(output,node2,fromReroute?.id);events.dispatch("link-created",newLink)}connectToSubgraphInput(){throw new Error("Not implemented")}connectToRerouteOutput(reroute,outputNode,output,events){const{fromSlot}=this;const newLink=fromSlot.connect(output,outputNode,reroute?.id);events.dispatch("link-created",newLink)}connectToInput(){throw new Error("ToOutputRenderLink cannot connect to an input.")}connectToSubgraphOutput(){throw new Error("ToOutputRenderLink cannot connect to a subgraph output.")}connectToRerouteInput(){throw new Error("ToOutputRenderLink cannot connect to an input.")}}class ToOutputRenderLink{constructor(network,node2,fromSlot,fromReroute,dragDirection=LinkDirection.CENTER){this.network=network;this.node=node2;this.fromSlot=fromSlot;this.fromReroute=fromReroute;this.dragDirection=dragDirection;const inputIndex=node2.inputs.indexOf(fromSlot);if(inputIndex===-1)throw new Error(`Creating render link for node [${this.node.id}] failed: Slot index not found.`);this.fromSlotIndex=inputIndex;this.fromPos=fromReroute?fromReroute.pos:this.node.getInputPos(inputIndex)}toType="output";fromPos;fromSlotIndex;fromDirection=LinkDirection.LEFT;canConnectToInput(){return false}canConnectToOutput(outputNode,output){return this.node.canConnectTo(outputNode,this.fromSlot,output)}canConnectToReroute(reroute){if(reroute.origin_id===this.node.id)return false;return true}connectToOutput(node2,output,events){const{node:inputNode,fromSlot,fromReroute}=this;if(!inputNode)return;const newLink=node2.connectSlots(output,inputNode,fromSlot,fromReroute?.id);events.dispatch("link-created",newLink)}connectToSubgraphInput(input,events){const newLink=input.connect(this.fromSlot,this.node,this.fromReroute?.id);events?.dispatch("link-created",newLink)}connectToRerouteOutput(reroute,outputNode,output,events){const{node:inputNode,fromSlot}=this;const newLink=outputNode.connectSlots(output,inputNode,fromSlot,reroute?.id);events.dispatch("link-created",newLink)}connectToInput(){throw new Error("ToOutputRenderLink cannot connect to an input.")}connectToSubgraphOutput(){throw new Error("ToOutputRenderLink cannot connect to a subgraph output.")}connectToRerouteInput(){throw new Error("ToOutputRenderLink cannot connect to an input.")}}class ToOutputFromRerouteLink extends ToOutputRenderLink{constructor(network,node2,fromSlot,fromReroute,linkConnector){super(network,node2,fromSlot,fromReroute);this.fromReroute=fromReroute;this.linkConnector=linkConnector}canConnectToReroute(){return false}connectToOutput(node2,output){const nuRenderLink=new ToInputRenderLink(this.network,node2,output);this.linkConnector._connectOutputToReroute(this.fromReroute,nuRenderLink)}}class LinkConnector{state={connectingTo:void 0,multi:false,draggingExistingLinks:false,snapLinksPos:void 0};events=new CustomEventTarget;renderLinks=[];inputLinks=[];outputLinks=[];floatingLinks=[];hiddenReroutes=new Set;overWidget;overWidgetType;overReroute;#setConnectingLinks;constructor(setConnectingLinks){this.#setConnectingLinks=setConnectingLinks}get isConnecting(){return this.state.connectingTo!==void 0}get draggingExistingLinks(){return this.state.draggingExistingLinks}moveInputLink(network,input){if(this.isConnecting)throw new Error("Already dragging links.");const{state,inputLinks,renderLinks}=this;const linkId=input.link;if(linkId==null){const floatingLink=input._floatingLinks?.values().next().value;if(floatingLink?.parentId==null)return;try{const reroute=network.reroutes.get(floatingLink.parentId);if(!reroute)throw new Error(`Invalid reroute id: [${floatingLink.parentId}] for floating link id: [${floatingLink.id}].`);const renderLink=new FloatingRenderLink(network,floatingLink,"input",reroute);const mayContinue=this.events.dispatch("before-move-input",renderLink);if(mayContinue===false)return;renderLinks.push(renderLink)}catch(error){console.warn(`Could not create render link for link id: [${floatingLink.id}].`,floatingLink,error)}floatingLink._dragging=true;this.floatingLinks.push(floatingLink)}else{const link=network.links.get(linkId);if(!link)return;if(link.origin_id===SUBGRAPH_INPUT_ID){const subgraphInput=network.inputNode?.slots[link.origin_slot];if(!subgraphInput){console.warn(`Could not find subgraph input for slot [${link.origin_slot}]`);return}try{const reroute=network.getReroute(link.parentId);const renderLink=new ToInputFromIoNodeLink(network,network.inputNode,subgraphInput,reroute,LinkDirection.CENTER,link);renderLinks.push(renderLink);this.listenUntilReset("input-moved",()=>{link.disconnect(network,"input")})}catch(error){console.warn(`Could not create render link for subgraph input link id: [${link.id}].`,link,error);return}link._dragging=true;inputLinks.push(link)}else{try{const reroute=network.getReroute(link.parentId);const renderLink=new MovingInputLink(network,link,reroute);const mayContinue=this.events.dispatch("before-move-input",renderLink);if(mayContinue===false)return;renderLinks.push(renderLink);this.listenUntilReset("input-moved",e2=>{if("link"in e2.detail&&e2.detail.link){e2.detail.link.disconnect(network,"output")}})}catch(error){console.warn(`Could not create render link for link id: [${link.id}].`,link,error);return}link._dragging=true;inputLinks.push(link)}}state.connectingTo="input";state.draggingExistingLinks=true;this.#setLegacyLinks(false)}moveOutputLink(network,output){if(this.isConnecting)throw new Error("Already dragging links.");const{state,renderLinks}=this;if(output._floatingLinks?.size){for(const floatingLink of output._floatingLinks.values()){try{const reroute=LLink.getFirstReroute(network,floatingLink);if(!reroute)throw new Error(`Invalid reroute id: [${floatingLink.parentId}] for floating link id: [${floatingLink.id}].`);const renderLink=new FloatingRenderLink(network,floatingLink,"output",reroute);const mayContinue=this.events.dispatch("before-move-output",renderLink);if(mayContinue===false)continue;renderLinks.push(renderLink);this.floatingLinks.push(floatingLink)}catch(error){console.warn(`Could not create render link for link id: [${floatingLink.id}].`,floatingLink,error)}}}if(output.links?.length){for(const linkId of output.links){const link=network.links.get(linkId);if(!link)continue;const firstReroute=LLink.getFirstReroute(network,link);if(firstReroute){firstReroute._dragging=true;this.hiddenReroutes.add(firstReroute)}else{link._dragging=true}this.outputLinks.push(link);try{const renderLink=new MovingOutputLink(network,link,firstReroute,LinkDirection.RIGHT);const mayContinue=this.events.dispatch("before-move-output",renderLink);if(mayContinue===false)continue;renderLinks.push(renderLink)}catch(error){console.warn(`Could not create render link for link id: [${link.id}].`,link,error);continue}}}if(renderLinks.length===0)return;state.draggingExistingLinks=true;state.multi=true;state.connectingTo="output";this.#setLegacyLinks(true)}dragNewFromOutput(network,node2,output,fromReroute){if(this.isConnecting)throw new Error("Already dragging links.");const{state}=this;const renderLink=new ToInputRenderLink(network,node2,output,fromReroute);this.renderLinks.push(renderLink);state.connectingTo="input";this.#setLegacyLinks(false)}dragNewFromInput(network,node2,input,fromReroute){if(this.isConnecting)throw new Error("Already dragging links.");const{state}=this;const renderLink=new ToOutputRenderLink(network,node2,input,fromReroute);this.renderLinks.push(renderLink);state.connectingTo="output";this.#setLegacyLinks(true)}dragNewFromSubgraphInput(network,inputNode,input,fromReroute){if(this.isConnecting)throw new Error("Already dragging links.");const renderLink=new ToInputFromIoNodeLink(network,inputNode,input,fromReroute);this.renderLinks.push(renderLink);this.state.connectingTo="input";this.#setLegacyLinks(false)}dragNewFromSubgraphOutput(network,outputNode,output,fromReroute){if(this.isConnecting)throw new Error("Already dragging links.");const renderLink=new ToOutputFromIoNodeLink(network,outputNode,output,fromReroute);this.renderLinks.push(renderLink);this.state.connectingTo="output";this.#setLegacyLinks(true)}dragFromReroute(network,reroute){if(this.isConnecting)throw new Error("Already dragging links.");const link=reroute.firstLink??reroute.firstFloatingLink;if(!link){console.warn("No link found for reroute.");return}if(link.origin_id===SUBGRAPH_INPUT_ID){if(!(network instanceof Subgraph)){console.warn("Subgraph input link found in non-subgraph network.");return}const input=network.inputs.at(link.origin_slot);if(!input)throw new Error("No subgraph input found for link.");const renderLink2=new ToInputFromIoNodeLink(network,network.inputNode,input,reroute);renderLink2.fromDirection=LinkDirection.NONE;this.renderLinks.push(renderLink2);this.state.connectingTo="input";this.#setLegacyLinks(false);return}const outputNode=network.getNodeById(link.origin_id);if(!outputNode){console.warn("No output node found for link.",link);return}const outputSlot=outputNode.outputs.at(link.origin_slot);if(!outputSlot){console.warn("No output slot found for link.",link);return}const renderLink=new ToInputRenderLink(network,outputNode,outputSlot,reroute);renderLink.fromDirection=LinkDirection.NONE;this.renderLinks.push(renderLink);this.state.connectingTo="input";this.#setLegacyLinks(false)}dragFromRerouteToOutput(network,reroute){if(this.isConnecting)throw new Error("Already dragging links.");const link=reroute.firstLink??reroute.firstFloatingLink;if(!link){console.warn("No link found for reroute.");return}if(link.target_id===SUBGRAPH_OUTPUT_ID){if(!(network instanceof Subgraph)){console.warn("Subgraph output link found in non-subgraph network.");return}const output=network.outputs.at(link.target_slot);if(!output)throw new Error("No subgraph output found for link.");const renderLink2=new ToOutputFromIoNodeLink(network,network.outputNode,output,reroute);renderLink2.fromDirection=LinkDirection.NONE;this.renderLinks.push(renderLink2);this.state.connectingTo="output";this.#setLegacyLinks(false);return}const inputNode=network.getNodeById(link.target_id);if(!inputNode){console.warn("No input node found for link.",link);return}const inputSlot=inputNode.inputs.at(link.target_slot);if(!inputSlot){console.warn("No input slot found for link.",link);return}const renderLink=new ToOutputFromRerouteLink(network,inputNode,inputSlot,reroute,this);renderLink.fromDirection=LinkDirection.LEFT;this.renderLinks.push(renderLink);this.state.connectingTo="output";this.#setLegacyLinks(true)}dragFromLinkSegment(network,linkSegment){if(this.isConnecting)throw new Error("Already dragging links.");const{state}=this;if(linkSegment.origin_id==null||linkSegment.origin_slot==null)return;const node2=network.getNodeById(linkSegment.origin_id);if(!node2)return;const slot=node2.outputs.at(linkSegment.origin_slot);if(!slot)return;const reroute=network.getReroute(linkSegment.parentId);const renderLink=new ToInputRenderLink(network,node2,slot,reroute);renderLink.fromDirection=LinkDirection.NONE;this.renderLinks.push(renderLink);state.connectingTo="input";this.#setLegacyLinks(false)}dropLinks(locator,event){if(!this.isConnecting){const mayContinue=this.events.dispatch("before-drop-links",{renderLinks:this.renderLinks,event});if(mayContinue===false)return}try{const{canvasX,canvasY}=event;const ioNode=locator.getIoNodeOnPos?.(canvasX,canvasY);if(ioNode){this.dropOnIoNode(ioNode,event);return}const node2=locator.getNodeOnPos(canvasX,canvasY)??void 0;if(node2){this.dropOnNode(node2,event)}else{const reroute=locator.getRerouteOnPos(canvasX,canvasY);if(reroute&&this.isRerouteValidDrop(reroute)){this.dropOnReroute(reroute,event)}else{this.dropOnNothing(event)}}}finally{this.events.dispatch("after-drop-links",{renderLinks:this.renderLinks,event})}}dropOnIoNode(ioNode,event){const{renderLinks,state}=this;const{connectingTo}=state;const{canvasX,canvasY}=event;if(connectingTo==="input"&&ioNode instanceof SubgraphOutputNode){const output=ioNode.getSlotInPosition(canvasX,canvasY);if(!output)throw new Error("No output slot found for link.");for(const link of renderLinks){link.connectToSubgraphOutput(output,this.events)}}else if(connectingTo==="output"&&ioNode instanceof SubgraphInputNode){const input=ioNode.getSlotInPosition(canvasX,canvasY);if(!input)throw new Error("No input slot found for link.");for(const link of renderLinks){link.connectToSubgraphInput(input,this.events)}}else{console.error("Invalid connectingTo state &/ ioNode",connectingTo,ioNode)}}dropOnNode(node2,event){const{renderLinks,state}=this;const{connectingTo}=state;const{canvasX,canvasY}=event;if(renderLinks.every(link=>link.node===node2))return;if(connectingTo==="output"){const output=node2.getOutputOnPos([canvasX,canvasY]);if(output){this.#dropOnOutput(node2,output)}else{this.connectToNode(node2,event)}}else if(connectingTo==="input"){const input=node2.getInputOnPos([canvasX,canvasY]);const inputOrSocket=input??node2.getSlotFromWidget(this.overWidget);if(inputOrSocket){this.#dropOnInput(node2,inputOrSocket)}else{this.connectToNode(node2,event)}}}dropOnReroute(reroute,event){const mayContinue=this.events.dispatch("dropped-on-reroute",{reroute,event});if(mayContinue===false)return;if(this.state.connectingTo==="input"){if(this.renderLinks.length!==1)throw new Error(`Attempted to connect ${this.renderLinks.length} input links to a reroute.`);const renderLink=this.renderLinks[0];this._connectOutputToReroute(reroute,renderLink);return}for(const link of this.renderLinks){if(link.toType!=="output")continue;const result=reroute.findSourceOutput();if(!result)continue;const{node:node2,output}=result;if(!link.canConnectToOutput(node2,output))continue;link.connectToRerouteOutput(reroute,node2,output,this.events)}}_connectOutputToReroute(reroute,renderLink){const results=reroute.findTargetInputs();if(!results?.length)return;const maybeReroutes=reroute.getReroutes();if(maybeReroutes===null)throw new Error("Reroute loop detected.");const originalReroutes=maybeReroutes.slice(0,-1).reverse();if(renderLink instanceof ToInputRenderLink){const{node:node2,fromSlot,fromSlotIndex,fromReroute}=renderLink;reroute.setFloatingLinkOrigin(node2,fromSlot,fromSlotIndex);if(fromReroute!=null){for(const originalReroute of originalReroutes){if(originalReroute.id===fromReroute.id)break;for(const linkId of reroute.floatingLinkIds){originalReroute.floatingLinkIds.delete(linkId)}}}}const filtered=results.filter(result=>renderLink.toType==="input"&&canConnectInputLinkToReroute(renderLink,result.node,result.input,reroute));for(const result of filtered){renderLink.connectToRerouteInput(reroute,result,this.events,originalReroutes)}return}dropOnNothing(event){const mayContinue=this.events.dispatch("dropped-on-canvas",event);if(mayContinue===false)return;this.disconnectLinks()}disconnectLinks(){for(const link of this.renderLinks){if(link instanceof MovingLinkBase){link.disconnect()}}}connectToNode(node2,event){const{state:{connectingTo}}=this;const mayContinue=this.events.dispatch("dropped-on-node",{node:node2,event});if(mayContinue===false)return;const firstLink=this.renderLinks[0];if(!firstLink)return;if(connectingTo==="output"){const output=node2.findOutputByType(firstLink.fromSlot.type)?.slot;console.debug("out",node2,output,firstLink.fromSlot);if(output===void 0){console.warn(`Could not find slot for link type: [${firstLink.fromSlot.type}].`);return}this.#dropOnOutput(node2,output)}else if(connectingTo==="input"){const input=node2.findInputByType(firstLink.fromSlot.type)?.slot;console.debug("in",node2,input,firstLink.fromSlot);if(input===void 0){console.warn(`Could not find slot for link type: [${firstLink.fromSlot.type}].`);return}this.#dropOnInput(node2,input)}}#dropOnInput(node2,input){for(const link of this.renderLinks){if(!link.canConnectToInput(node2,input))continue;link.connectToInput(node2,input,this.events)}}#dropOnOutput(node2,output){for(const link of this.renderLinks){if(!link.canConnectToOutput(node2,output)){if(link instanceof MovingOutputLink&&link.link.parentId!==void 0){link.outputNode.connectSlots(link.outputSlot,link.inputNode,link.inputSlot,void 0)}continue}link.connectToOutput(node2,output,this.events)}}isInputValidDrop(node2,input){return this.renderLinks.some(link=>link.canConnectToInput(node2,input))}isNodeValidDrop(node2){if(this.state.connectingTo==="output"){return node2.outputs.some(output=>this.renderLinks.some(link=>link.canConnectToOutput(node2,output)))}return node2.inputs.some(input=>this.renderLinks.some(link=>link.canConnectToInput(node2,input)))}isRerouteValidDrop(reroute){if(this.state.connectingTo==="input"){const results=reroute.findTargetInputs();if(!results?.length)return false;for(const{node:node2,input}of results){for(const renderLink of this.renderLinks){if(renderLink.toType!=="input")continue;if(canConnectInputLinkToReroute(renderLink,node2,input,reroute))return true}}}else{const result=reroute.findSourceOutput();if(!result)return false;const{node:node2,output}=result;for(const renderLink of this.renderLinks){if(renderLink.toType!=="output")continue;if(!renderLink.canConnectToReroute(reroute))continue;if(renderLink.canConnectToOutput(node2,output))return true}}return false}#setLegacyLinks(fromSlotIsInput){const links=this.renderLinks.map(link=>{const input=fromSlotIsInput?link.fromSlot:null;const output=fromSlotIsInput?null:link.fromSlot;const afterRerouteId=link instanceof MovingLinkBase?link.link?.parentId:link.fromReroute?.id;return{node:link.node,slot:link.fromSlotIndex,input,output,pos:link.fromPos,afterRerouteId}});this.#setConnectingLinks(links)}export(network){return{renderLinks:[...this.renderLinks],inputLinks:[...this.inputLinks],outputLinks:[...this.outputLinks],floatingLinks:[...this.floatingLinks],state:{...this.state},network}}listenUntilReset(eventName,listener,options){this.events.addEventListener(eventName,listener,options);this.events.addEventListener("reset",()=>this.events.removeEventListener(eventName,listener),{once:true})}reset(force=false){const mayContinue=this.events.dispatch("reset",force);if(mayContinue===false)return;const{state,outputLinks,inputLinks,hiddenReroutes,renderLinks,floatingLinks}=this;if(!force&&state.connectingTo===void 0)return;state.connectingTo=void 0;for(const link of outputLinks)delete link._dragging;for(const link of inputLinks)delete link._dragging;for(const link of floatingLinks)delete link._dragging;for(const reroute of hiddenReroutes)delete reroute._dragging;renderLinks.length=0;inputLinks.length=0;outputLinks.length=0;floatingLinks.length=0;hiddenReroutes.clear();state.multi=false;state.draggingExistingLinks=false;state.snapLinksPos=void 0}}function canConnectInputLinkToReroute(link,inputNode,input,reroute){const{fromReroute}=link;if(!link.canConnectToInput(inputNode,input)||fromReroute?.id===reroute.id||fromReroute?.getReroutes()?.includes(reroute)){return false}if(link instanceof ToInputRenderLink){if(reroute.parentId==null){if(reroute.firstLink?.hasOrigin(link.node.id,link.fromSlotIndex))return false}else if(link.fromReroute?.id===reroute.parentId){return false}}return true}class CanvasPointer{static bufferTime=150;static doubleClickTime=300;static get maxClickDrift(){return this.#maxClickDrift}static set maxClickDrift(value){this.#maxClickDrift=value;this.#maxClickDrift2=value*value}static#maxClickDrift=6;static#maxClickDrift2=this.#maxClickDrift**2;element;pointerId;dragStarted=false;eLastDown;isDouble=false;isDown=false;resizeDirection;clearEventsOnReset=true;eDown;eMove;eUp;get finally(){return this.#finally}set finally(value){try{this.#finally?.()}finally{this.#finally=value}}#finally;constructor(element){this.element=element}down(e2){this.reset();this.eDown=e2;this.pointerId=e2.pointerId;this.element.setPointerCapture(e2.pointerId)}move(e2){const{eDown}=this;if(!eDown)return;if(!e2.buttons){this.reset();return}if(!(e2.buttons&eDown.buttons)){this.#completeClick(e2);this.reset();return}this.eMove=e2;this.onDrag?.(e2);if(this.dragStarted)return;const longerThanBufferTime=e2.timeStamp-eDown.timeStamp>CanvasPointer.bufferTime;if(longerThanBufferTime||!this.#hasSamePosition(e2,eDown)){this.#setDragStarted(e2)}}up(e2){if(e2.button!==this.eDown?.button)return false;this.#completeClick(e2);const{dragStarted}=this;this.reset();return!dragStarted}#completeClick(e2){const{eDown}=this;if(!eDown)return;this.eUp=e2;if(this.dragStarted){this.onDragEnd?.(e2)}else if(!this.#hasSamePosition(e2,eDown)){this.#setDragStarted();this.onDragEnd?.(e2)}else if(this.onDoubleClick&&this.#isDoubleClick()){this.onDoubleClick(e2);this.eLastDown=void 0}else{this.onClick?.(e2);this.eLastDown=eDown}}#hasSamePosition(a,b,tolerance2=CanvasPointer.#maxClickDrift2){const drift=dist2(a.clientX,a.clientY,b.clientX,b.clientY);return drift<=tolerance2}#isDoubleClick(){const{eDown,eLastDown}=this;if(!eDown||!eLastDown)return false;const tolerance2=(3*CanvasPointer.#maxClickDrift)**2;const diff=eDown.timeStamp-eLastDown.timeStamp;return diff>0&&diff<CanvasPointer.doubleClickTime&&this.#hasSamePosition(eDown,eLastDown,tolerance2)}#setDragStarted(eMove){this.dragStarted=true;this.onDragStart?.(this,eMove);delete this.onDragStart}reset(){this.finally=void 0;delete this.onClick;delete this.onDoubleClick;delete this.onDragStart;delete this.onDrag;delete this.onDragEnd;this.isDown=false;this.isDouble=false;this.dragStarted=false;this.resizeDirection=void 0;if(this.clearEventsOnReset){this.eDown=void 0;this.eMove=void 0;this.eUp=void 0}const{element,pointerId}=this;this.pointerId=void 0;if(typeof pointerId==="number"&&element.hasPointerCapture(pointerId)){element.releasePointerCapture(pointerId)}}}class DragAndScale{state;lastState={offset:[0,0],scale:0};max_scale;min_scale;enabled;last_mouse;element;visible_area;dragging;viewport;get offset(){return this.state.offset}set offset(value){this.state.offset[0]=value[0];this.state.offset[1]=value[1]}get scale(){return this.state.scale}set scale(value){this.state.scale=value}constructor(element){this.state={offset:[0,0],scale:1};this.max_scale=10;this.min_scale=.1;this.enabled=true;this.last_mouse=[0,0];this.visible_area=new Rectangle;this.element=element}#stateHasChanged(){const current=this.state;const previous=this.lastState;return current.scale!==previous.scale||current.offset[0]!==previous.offset[0]||current.offset[1]!==previous.offset[1]}computeVisibleArea(viewport){const{scale,offset,visible_area}=this;if(this.#stateHasChanged()){this.onChanged?.(scale,offset);copyState(this.state,this.lastState)}if(!this.element){visible_area[0]=visible_area[1]=visible_area[2]=visible_area[3]=0;return}let{width:width2,height}=this.element;let startx=-offset[0];let starty=-offset[1];if(viewport){startx+=viewport[0]/scale;starty+=viewport[1]/scale;width2=viewport[2];height=viewport[3]}const endx=startx+width2/scale;const endy=starty+height/scale;visible_area[0]=startx;visible_area[1]=starty;visible_area.resizeBottomRight(endx,endy)}toCanvasContext(ctx){ctx.scale(this.scale,this.scale);ctx.translate(this.offset[0],this.offset[1])}convertOffsetToCanvas(pos){return[(pos[0]+this.offset[0])*this.scale,(pos[1]+this.offset[1])*this.scale]}convertCanvasToOffset(pos,out){out=out||[0,0];out[0]=pos[0]/this.scale-this.offset[0];out[1]=pos[1]/this.scale-this.offset[1];return out}mouseDrag(x2,y){this.offset[0]+=x2/this.scale;this.offset[1]+=y/this.scale;this.onredraw?.(this)}changeScale(value,zooming_center,roundToScaleOne=true){if(value<this.min_scale){value=this.min_scale}else if(value>this.max_scale){value=this.max_scale}if(value==this.scale)return;const rect=this.element.getBoundingClientRect();if(!rect)return;zooming_center=zooming_center??[rect.width*.5,rect.height*.5];const normalizedCenter=[zooming_center[0]-rect.x,zooming_center[1]-rect.y];const center=this.convertCanvasToOffset(normalizedCenter);this.scale=value;if(roundToScaleOne&&Math.abs(this.scale-1)<.01)this.scale=1;const new_center=this.convertCanvasToOffset(normalizedCenter);const delta_offset=[new_center[0]-center[0],new_center[1]-center[1]];this.offset[0]+=delta_offset[0];this.offset[1]+=delta_offset[1];this.onredraw?.(this)}changeDeltaScale(value,zooming_center){this.changeScale(this.scale*value,zooming_center)}fitToBounds(bounds,{zoom=.75}={}){const cw=this.element.width/window.devicePixelRatio;const ch=this.element.height/window.devicePixelRatio;let targetScale=this.scale;if(zoom>0){const targetScaleX=zoom*cw/Math.max(bounds[2],300);const targetScaleY=zoom*ch/Math.max(bounds[3],300);targetScale=Math.min(targetScaleX,targetScaleY,this.max_scale)}const scaledWidth=cw/targetScale;const scaledHeight=ch/targetScale;const targetX=-bounds[0]-bounds[2]*.5+scaledWidth*.5;const targetY=-bounds[1]-bounds[3]*.5+scaledHeight*.5;this.offset[0]=targetX;this.offset[1]=targetY;this.scale=targetScale}animateToBounds(bounds,setDirty,{duration=350,zoom=.75,easing=EaseFunction.EASE_IN_OUT_QUAD}={}){if(!(duration>0))throw new RangeError("Duration must be greater than 0");const easeFunctions={linear:t=>t,easeInQuad:t=>t*t,easeOutQuad:t=>t*(2-t),easeInOutQuad:t=>t<.5?2*t*t:-1+(4-2*t)*t};const easeFunction=easeFunctions[easing]??easeFunctions.linear;const startTimestamp=performance.now();const cw=this.element.width/window.devicePixelRatio;const ch=this.element.height/window.devicePixelRatio;const startX=this.offset[0];const startY=this.offset[1];const startX2=startX-cw/this.scale;const startY2=startY-ch/this.scale;const startScale=this.scale;let targetScale=startScale;if(zoom>0){const targetScaleX=zoom*cw/Math.max(bounds[2],300);const targetScaleY=zoom*ch/Math.max(bounds[3],300);targetScale=Math.min(targetScaleX,targetScaleY,this.max_scale)}const scaledWidth=cw/targetScale;const scaledHeight=ch/targetScale;const targetX=-bounds[0]-bounds[2]*.5+scaledWidth*.5;const targetY=-bounds[1]-bounds[3]*.5+scaledHeight*.5;const targetX2=targetX-scaledWidth;const targetY2=targetY-scaledHeight;const animate=timestamp=>{const elapsed=timestamp-startTimestamp;const progress=Math.min(elapsed/duration,1);const easedProgress=easeFunction(progress);const currentX=startX+(targetX-startX)*easedProgress;const currentY=startY+(targetY-startY)*easedProgress;this.offset[0]=currentX;this.offset[1]=currentY;if(zoom>0){const currentX2=startX2+(targetX2-startX2)*easedProgress;const currentY2=startY2+(targetY2-startY2)*easedProgress;const currentWidth=Math.abs(currentX2-currentX);const currentHeight=Math.abs(currentY2-currentY);this.scale=Math.min(cw/currentWidth,ch/currentHeight)}setDirty();if(progress<1){animationId=requestAnimationFrame(animate)}else{cancelAnimationFrame(animationId)}};let animationId=requestAnimationFrame(animate)}reset(){this.scale=1;this.offset[0]=0;this.offset[1]=0}}function copyState(from,to){to.scale=from.scale;to.offset[0]=from.offset[0];to.offset[1]=from.offset[1]}function getBoundaryNodes(nodes){const valid=nodes?.find(x2=>x2);if(!valid)return null;let top=valid;let right=valid;let bottom=valid;let left=valid;for(const node2 of nodes){if(!node2)continue;const[x2,y]=node2.pos;const[width2,height]=node2.size;if(y<top.pos[1])top=node2;if(x2+width2>right.pos[0]+right.size[0])right=node2;if(y+height>bottom.pos[1]+bottom.size[1])bottom=node2;if(x2<left.pos[0])left=node2}return{top,right,bottom,left}}function distributeNodes(nodes,horizontal){const nodeCount=nodes?.length;if(!(nodeCount>1))return;const index=horizontal?0:1;let total=0;let highest=-Infinity;for(const node2 of nodes){total+=node2.size[index];const high=node2.pos[index]+node2.size[index];if(high>highest)highest=high}const sorted=[...nodes].sort((a,b)=>a.pos[index]-b.pos[index]);const lowest=sorted[0].pos[index];const gap=(highest-lowest-total)/(nodeCount-1);let startAt=lowest;for(let i=0;i<nodeCount;i++){const node2=sorted[i];node2.pos[index]=startAt+gap*i;startAt+=node2.size[index]}}function alignNodes(nodes,direction,align_to){if(!nodes)return;const boundary=align_to===void 0?getBoundaryNodes(nodes):{top:align_to,right:align_to,bottom:align_to,left:align_to};if(boundary===null)return;for(const node2 of nodes){switch(direction){case"right":node2.pos[0]=boundary.right.pos[0]+boundary.right.size[0]-node2.size[0];break;case"left":node2.pos[0]=boundary.left.pos[0];break;case"top":node2.pos[1]=boundary.top.pos[1];break;case"bottom":node2.pos[1]=boundary.bottom.pos[1]+boundary.bottom.size[1]-node2.size[1];break}}}const cursors={NE:"nesw-resize",SE:"nwse-resize",SW:"nesw-resize",NW:"nwse-resize"};class LGraphCanvas{static#temp=new Float32Array(4);static#temp_vec2=new Float32Array(2);static#tmp_area=new Float32Array(4);static#margin_area=new Float32Array(4);static#link_bounding=new Float32Array(4);static#lTempA=new Float32Array(2);static#lTempB=new Float32Array(2);static#lTempC=new Float32Array(2);static DEFAULT_BACKGROUND_IMAGE="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAIAAAD/gAIDAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAQBJREFUeNrs1rEKwjAUhlETUkj3vP9rdmr1Ysammk2w5wdxuLgcMHyptfawuZX4pJSWZTnfnu/lnIe/jNNxHHGNn//HNbbv+4dr6V+11uF527arU7+u63qfa/bnmh8sWLBgwYJlqRf8MEptXPBXJXa37BSl3ixYsGDBMliwFLyCV/DeLIMFCxYsWLBMwSt4Be/NggXLYMGCBUvBK3iNruC9WbBgwYJlsGApeAWv4L1ZBgsWLFiwYJmCV/AK3psFC5bBggULloJX8BpdwXuzYMGCBctgwVLwCl7Be7MMFixYsGDBsu8FH1FaSmExVfAxBa/gvVmwYMGCZbBg/W4vAQYA5tRF9QYlv/QAAAAASUVORK5CYII=";static DEFAULT_EVENT_LINK_COLOR="#A86";static link_type_colors={"-1":LGraphCanvas.DEFAULT_EVENT_LINK_COLOR,"number":"#AAA","node":"#DCA"};static gradients={};static search_limit=-1;static node_colors={red:{color:"#322",bgcolor:"#533",groupcolor:"#A88"},brown:{color:"#332922",bgcolor:"#593930",groupcolor:"#b06634"},green:{color:"#232",bgcolor:"#353",groupcolor:"#8A8"},blue:{color:"#223",bgcolor:"#335",groupcolor:"#88A"},pale_blue:{color:"#2a363b",bgcolor:"#3f5159",groupcolor:"#3f789e"},cyan:{color:"#233",bgcolor:"#355",groupcolor:"#8AA"},purple:{color:"#323",bgcolor:"#535",groupcolor:"#a1309b"},yellow:{color:"#432",bgcolor:"#653",groupcolor:"#b58b2a"},black:{color:"#222",bgcolor:"#000",groupcolor:"#444"}};static _measureText;state={draggingItems:false,draggingCanvas:false,readOnly:false,hoveringOver:CanvasItem.Nothing,shouldSetCursor:true,selectionChanged:false};#subgraph;get subgraph(){return this.#subgraph}set subgraph(value){if(value!==this.#subgraph){this.#subgraph=value;if(value)this.dispatch("litegraph:set-graph",{oldGraph:this.#subgraph,newGraph:value})}}dispatch(type,detail){const event=new CustomEvent(type,{detail,bubbles:true});return this.canvas.dispatchEvent(event)}dispatchEvent(type,detail){this.canvas.dispatchEvent(new CustomEvent(type,{detail}))}#updateCursorStyle(){if(!this.state.shouldSetCursor)return;const crosshairItems=CanvasItem.Node|CanvasItem.RerouteSlot|CanvasItem.SubgraphIoNode|CanvasItem.SubgraphIoSlot;let cursor="default";if(this.state.draggingCanvas){cursor="grabbing"}else if(this.state.readOnly){cursor="grab"}else if(this.pointer.resizeDirection){cursor=cursors[this.pointer.resizeDirection]??cursors.SE}else if(this.state.hoveringOver&crosshairItems){cursor="crosshair"}else if(this.state.hoveringOver&CanvasItem.Reroute){cursor="grab"}this.canvas.style.cursor=cursor}_previously_dragging_canvas=null;get read_only(){return this.state.readOnly}set read_only(value){this.state.readOnly=value;this.#updateCursorStyle()}get isDragging(){return this.state.draggingItems}set isDragging(value){this.state.draggingItems=value}get hoveringOver(){return this.state.hoveringOver}set hoveringOver(value){this.state.hoveringOver=value;this.#updateCursorStyle()}get pointer_is_down(){return this.pointer.isDown}get pointer_is_double(){return this.pointer.isDouble}get dragging_canvas(){return this.state.draggingCanvas}set dragging_canvas(value){this.state.draggingCanvas=value;this.#updateCursorStyle()}get title_text_font(){return`${LiteGraph.NODE_TEXT_SIZE}px ${LiteGraph.NODE_FONT}`}get inner_text_font(){return`normal ${LiteGraph.NODE_SUBTEXT_SIZE}px ${LiteGraph.NODE_FONT}`}#maximumFrameGap=0;get maximumFps(){return this.#maximumFrameGap>Number.EPSILON?this.#maximumFrameGap/1e3:0}set maximumFps(value){this.#maximumFrameGap=value>Number.EPSILON?1e3/value:0}get round_radius(){return LiteGraph.ROUND_RADIUS}set round_radius(value){LiteGraph.ROUND_RADIUS=value}get low_quality(){return this.ds.scale<this.low_quality_zoom_threshold}options;background_image;ds;pointer;zoom_modify_alpha;zoom_speed;node_title_color;default_link_color;default_connection_color;default_connection_color_byType;default_connection_color_byTypeOff;colourGetter={getConnectedColor:type=>this.default_connection_color_byType[type]||this.default_connection_color.output_on,getDisconnectedColor:type=>this.default_connection_color_byTypeOff[type]||this.default_connection_color_byType[type]||this.default_connection_color.output_off};highquality_render;use_gradients;editor_alpha;pause_rendering;clear_background;clear_background_color;render_only_selected;show_info;allow_dragcanvas;allow_dragnodes;allow_interaction;multi_select;allow_searchbox;allow_reconnect_links;align_to_grid;drag_mode;dragging_rectangle;filter;set_canvas_dirty_on_mouse_event;always_render_background;render_shadows;render_canvas_border;render_connections_shadows;render_connections_border;render_curved_connections;render_connection_arrows;render_collapsed_slots;render_execution_order;render_link_tooltip;linkMarkerShape=LinkMarkerShape.Circle;links_render_mode;low_quality_zoom_threshold=.6;mouse;graph_mouse;canvas_mouse;onSearchBox;onSearchBoxSelection;onMouse;onDrawBackground;onDrawForeground;connections_width;current_node;node_widget;over_link_center;last_mouse_position;visible_area;renderedPaths=new Set;visible_links=[];connecting_links;linkConnector=new LinkConnector(links=>this.connecting_links=links);viewport;autoresize;static active_canvas;frame=0;last_draw_time=0;render_time=0;fps=0;selected_nodes={};selectedItems=new Set;resizingGroup=null;selected_group=null;visible_nodes=[];#visible_node_ids=new Set;node_over;node_capturing_input;highlighted_links={};#visibleReroutes=new Set;dirty_canvas=true;dirty_bgcanvas=true;dirty_nodes=new Map;dirty_area;node_in_panel;last_mouse=[0,0];last_mouseclick=0;graph;get _graph(){if(!this.graph)throw new NullGraphError;return this.graph}canvas;bgcanvas;ctx;_events_binded;bgctx;is_rendering;block_click;last_click_position;resizing_node;selected_group_resizing;last_mouse_dragging;onMouseDown;_highlight_pos;_highlight_input;node_panel;options_panel;_bg_img;_pattern;_pattern_img;prompt_box;search_box;SELECTED_NODE;NODEPANEL_IS_OPEN;#snapToGrid;#shiftDown=false;dragZoomEnabled=false;#dragZoomStart=null;static active_node;onClear;onNodeMoved;onSelectionChange;onDrawLinkTooltip;onDrawOverlay;onRenderBackground;onNodeDblClicked;onShowNodePanel;onNodeSelected;onNodeDeselected;onRender;constructor(canvas2,graph,options){options||={};this.options=options;this.background_image=LGraphCanvas.DEFAULT_BACKGROUND_IMAGE;this.ds=new DragAndScale(canvas2);this.pointer=new CanvasPointer(canvas2);this.linkConnector.events.addEventListener("link-created",()=>this.#dirty());this.linkConnector.events.addEventListener("reset",()=>{this.connecting_links=null;this.dirty_bgcanvas=true});this.linkConnector.events.addEventListener("dropped-on-canvas",customEvent=>{if(!this.connecting_links)return;const e2=customEvent.detail;this.emitEvent({subType:"empty-release",originalEvent:e2,linkReleaseContext:{links:this.connecting_links}});const firstLink=this.linkConnector.renderLinks[0];if(LiteGraph.release_link_on_empty_shows_menu){const linkReleaseContext=this.linkConnector.state.connectingTo==="input"?{node_from:firstLink.node,slot_from:firstLink.fromSlot,type_filter_in:firstLink.fromSlot.type}:{node_to:firstLink.node,slot_to:firstLink.fromSlot,type_filter_out:firstLink.fromSlot.type};const afterRerouteId=firstLink.fromReroute?.id;if("shiftKey"in e2&&e2.shiftKey){if(this.allow_searchbox){this.showSearchBox(e2,linkReleaseContext)}}else if(this.linkConnector.state.connectingTo==="input"){this.showConnectionMenu({nodeFrom:firstLink.node,slotFrom:firstLink.fromSlot,e:e2,afterRerouteId})}else{this.showConnectionMenu({nodeTo:firstLink.node,slotTo:firstLink.fromSlot,e:e2,afterRerouteId})}}});this.zoom_modify_alpha=true;this.zoom_speed=1.1;this.node_title_color=LiteGraph.NODE_TITLE_COLOR;this.default_link_color=LiteGraph.LINK_COLOR;this.default_connection_color={input_off:"#778",input_on:"#7F7",output_off:"#778",output_on:"#7F7"};this.default_connection_color_byType={};this.default_connection_color_byTypeOff={};this.highquality_render=true;this.use_gradients=false;this.editor_alpha=1;this.pause_rendering=false;this.clear_background=true;this.clear_background_color="#222";this.render_only_selected=true;this.show_info=true;this.allow_dragcanvas=true;this.allow_dragnodes=true;this.allow_interaction=true;this.multi_select=false;this.allow_searchbox=true;this.allow_reconnect_links=true;this.align_to_grid=false;this.drag_mode=false;this.dragging_rectangle=null;this.filter=null;this.set_canvas_dirty_on_mouse_event=true;this.always_render_background=false;this.render_shadows=true;this.render_canvas_border=true;this.render_connections_shadows=false;this.render_connections_border=true;this.render_curved_connections=false;this.render_connection_arrows=false;this.render_collapsed_slots=true;this.render_execution_order=false;this.render_link_tooltip=true;this.links_render_mode=LinkRenderType.SPLINE_LINK;this.mouse=[0,0];this.graph_mouse=[0,0];this.canvas_mouse=this.graph_mouse;this.connections_width=3;this.current_node=null;this.node_widget=null;this.last_mouse_position=[0,0];this.visible_area=this.ds.visible_area;this.connecting_links=null;this.viewport=options.viewport||null;this.graph=graph;graph?.attachCanvas(this);this.canvas=void 0;this.bgcanvas=void 0;this.ctx=void 0;this.setCanvas(canvas2,options.skip_events);this.clear();LGraphCanvas._measureText=(text,fontStyle=this.inner_text_font)=>{const{ctx}=this;const{font}=ctx;try{ctx.font=fontStyle;return ctx.measureText(text).width}finally{ctx.font=font}};if(!options.skip_render){this.startRendering()}this.autoresize=options.autoresize}static onGroupAdd(info,entry,mouse_event){const canvas2=LGraphCanvas.active_canvas;const group=new LiteGraph.LGraphGroup;group.pos=canvas2.convertEventToCanvasOffset(mouse_event);if(!canvas2.graph)throw new NullGraphError;canvas2.graph.add(group)}static getBoundaryNodes(nodes){const _nodes=Array.isArray(nodes)?nodes:Object.values(nodes);return getBoundaryNodes(_nodes)??{top:null,right:null,bottom:null,left:null}}static alignNodes(nodes,direction,align_to){alignNodes(Object.values(nodes),direction,align_to);LGraphCanvas.active_canvas.setDirty(true,true)}static onNodeAlign(value,options,event,prev_menu,node2){new LiteGraph.ContextMenu(["Top","Bottom","Left","Right"],{event,callback:inner_clicked,parentMenu:prev_menu});function inner_clicked(value2){alignNodes(Object.values(LGraphCanvas.active_canvas.selected_nodes),value2.toLowerCase(),node2);LGraphCanvas.active_canvas.setDirty(true,true)}}static onGroupAlign(value,options,event,prev_menu){new LiteGraph.ContextMenu(["Top","Bottom","Left","Right"],{event,callback:inner_clicked,parentMenu:prev_menu});function inner_clicked(value2){alignNodes(Object.values(LGraphCanvas.active_canvas.selected_nodes),value2.toLowerCase());LGraphCanvas.active_canvas.setDirty(true,true)}}static createDistributeMenu(value,options,event,prev_menu){new LiteGraph.ContextMenu(["Vertically","Horizontally"],{event,callback:inner_clicked,parentMenu:prev_menu});function inner_clicked(value2){const canvas2=LGraphCanvas.active_canvas;distributeNodes(Object.values(canvas2.selected_nodes),value2==="Horizontally");canvas2.setDirty(true,true)}}static onMenuAdd(value,options,e2,prev_menu,callback){const canvas2=LGraphCanvas.active_canvas;const ref_window=canvas2.getCanvasWindow();const{graph}=canvas2;if(!graph)return;inner_onMenuAdded("",prev_menu);return false;function inner_onMenuAdded(base_category,prev_menu2){if(!graph)return;const categories=LiteGraph.getNodeTypesCategories(canvas2.filter||graph.filter).filter(category=>category.startsWith(base_category));const entries=[];for(const category of categories){if(!category)continue;const base_category_regex=new RegExp(`^(${base_category})`);const category_name=category.replace(base_category_regex,"").split("/",1)[0];const category_path=base_category===""?`${category_name}/`:`${base_category}${category_name}/`;let name=category_name;if(name.includes("::"))name=name.split("::",2)[1];const index=entries.findIndex(entry=>entry.value===category_path);if(index===-1){entries.push({value:category_path,content:name,has_submenu:true,callback:function(value2,event,mouseEvent,contextMenu){inner_onMenuAdded(value2.value,contextMenu)}})}}const nodes=LiteGraph.getNodeTypesInCategory(base_category.slice(0,-1),canvas2.filter||graph.filter);for(const node2 of nodes){if(node2.skip_list)continue;const entry={value:node2.type,content:node2.title,has_submenu:false,callback:function(value2,event,mouseEvent,contextMenu){if(!canvas2.graph)throw new NullGraphError;const first_event=contextMenu.getFirstEvent();canvas2.graph.beforeChange();const node22=LiteGraph.createNode(value2.value);if(node22){if(!first_event)throw new TypeError("Context menu event was null. This should not occur in normal usage.");node22.pos=canvas2.convertEventToCanvasOffset(first_event);canvas2.graph.add(node22)}else{console.warn("Failed to create node of type:",value2.value)}callback?.(node22);canvas2.graph.afterChange()}};entries.push(entry)}new LiteGraph.ContextMenu(entries,{event:e2,parentMenu:prev_menu2},ref_window)}}static onMenuCollapseAll(){}static onMenuNodeEdit(){}static showMenuNodeOptionalOutputs(v2,_options,e2,prev_menu,node2){if(!node2)return;const canvas2=LGraphCanvas.active_canvas;let entries=[];if(LiteGraph.do_add_triggers_slots&&node2.findOutputSlot("onExecuted")==-1){entries.push({content:"On Executed",value:["onExecuted",LiteGraph.EVENT,{nameLocked:true}],className:"event"})}const retEntries=node2.onMenuNodeOutputs?.(entries);if(retEntries)entries=retEntries;if(!entries.length)return;new LiteGraph.ContextMenu(entries,{event:e2,callback:inner_clicked,parentMenu:prev_menu,node:node2});function inner_clicked(v22,e22,prev){if(!node2)return;if(v22.callback)v22.callback.call(this,node2,v22,e22,prev);if(!v22.value)return;const value=v22.value[1];if(value&&(typeof value==="object"||Array.isArray(value))){const entries2=[];for(const i in value){entries2.push({content:i,value:value[i]})}new LiteGraph.ContextMenu(entries2,{event:e22,callback:inner_clicked,parentMenu:prev_menu,node:node2});return false}const{graph}=node2;if(!graph)throw new NullGraphError;graph.beforeChange();node2.addOutput(v22.value[0],v22.value[1],v22.value[2]);node2.onNodeOutputAdd?.(v22.value);canvas2.setDirty(true,true);graph.afterChange()}return false}static onShowMenuNodeProperties(value,options,e2,prev_menu,node2){if(!node2||!node2.properties)return;const canvas2=LGraphCanvas.active_canvas;const ref_window=canvas2.getCanvasWindow();const entries=[];for(const i in node2.properties){value=node2.properties[i]!==void 0?node2.properties[i]:" ";if(typeof value=="object")value=JSON.stringify(value);const info=node2.getPropertyInfo(i);if(info.type=="enum"||info.type=="combo")value=LGraphCanvas.getPropertyPrintableValue(value,info.values);value=LGraphCanvas.decodeHTML(stringOrEmpty(value));entries.push({content:`<span class='property_name'>${info.label||i}</span><span class='property_value'>${value}</span>`,value:i})}if(!entries.length){return}new LiteGraph.ContextMenu(entries,{event:e2,callback:inner_clicked,parentMenu:prev_menu,allow_html:true,node:node2},ref_window);function inner_clicked(v2){if(!node2)return;const rect=this.getBoundingClientRect();canvas2.showEditPropertyValue(node2,v2.value,{position:[rect.left,rect.top]})}return false}static decodeHTML(str){const e2=document.createElement("div");e2.textContent=str;return e2.innerHTML}static onMenuResizeNode(value,options,e2,menu,node2){if(!node2)return;const fApplyMultiNode=function(node22){node22.setSize(node22.computeSize())};const canvas2=LGraphCanvas.active_canvas;if(!canvas2.selected_nodes||Object.keys(canvas2.selected_nodes).length<=1){fApplyMultiNode(node2)}else{for(const i in canvas2.selected_nodes){fApplyMultiNode(canvas2.selected_nodes[i])}}canvas2.setDirty(true,true)}static onShowPropertyEditor(item,options,e2,menu,node2){const property=item.property||"title";const value=node2[property];const title=document.createElement("span");title.className="name";title.textContent=property;const input=document.createElement("input");Object.assign(input,{type:"text",className:"value",autofocus:true});const button=document.createElement("button");button.textContent="OK";const dialog=Object.assign(document.createElement("div"),{is_modified:false,className:"graphdialog",close:()=>dialog.remove()});dialog.append(title,input,button);input.value=String(value);input.addEventListener("blur",function(){this.focus()});input.addEventListener("keydown",e22=>{dialog.is_modified=true;if(e22.key=="Escape"){dialog.close()}else if(e22.key=="Enter"){inner()}else if(!e22.target||!("localName"in e22.target)||e22.target.localName!="textarea"){return}e22.preventDefault();e22.stopPropagation()});const canvas2=LGraphCanvas.active_canvas;const canvasEl=canvas2.canvas;const rect=canvasEl.getBoundingClientRect();const offsetx=rect?-20-rect.left:-20;const offsety=rect?-20-rect.top:-20;if(e2){dialog.style.left=`${e2.clientX+offsetx}px`;dialog.style.top=`${e2.clientY+offsety}px`}else{dialog.style.left=`${canvasEl.width*.5+offsetx}px`;dialog.style.top=`${canvasEl.height*.5+offsety}px`}button.addEventListener("click",inner);if(canvasEl.parentNode==null)throw new TypeError("canvasEl.parentNode was null");canvasEl.parentNode.append(dialog);input.focus();let dialogCloseTimer;dialog.addEventListener("mouseleave",function(){if(LiteGraph.dialog_close_on_mouse_leave){if(!dialog.is_modified&&LiteGraph.dialog_close_on_mouse_leave){dialogCloseTimer=setTimeout(dialog.close,LiteGraph.dialog_close_on_mouse_leave_delay)}}});dialog.addEventListener("mouseenter",function(){if(LiteGraph.dialog_close_on_mouse_leave){if(dialogCloseTimer)clearTimeout(dialogCloseTimer)}});function inner(){if(input)setValue(input.value)}function setValue(value2){if(item.type=="Number"){value2=Number(value2)}else if(item.type=="Boolean"){value2=Boolean(value2)}node2[property]=value2;dialog.remove();canvas2.setDirty(true,true)}}static getPropertyPrintableValue(value,values){if(!values)return String(value);if(Array.isArray(values)){return String(value)}if(typeof values==="object"){let desc_value="";for(const k in values){if(values[k]!=value)continue;desc_value=k;break}return`${String(value)} (${desc_value})`}}static onMenuNodeCollapse(value,options,e2,menu,node2){if(!node2.graph)throw new NullGraphError;node2.graph.beforeChange();const fApplyMultiNode=function(node22){node22.collapse()};const graphcanvas=LGraphCanvas.active_canvas;if(!graphcanvas.selected_nodes||Object.keys(graphcanvas.selected_nodes).length<=1){fApplyMultiNode(node2)}else{for(const i in graphcanvas.selected_nodes){fApplyMultiNode(graphcanvas.selected_nodes[i])}}node2.graph.afterChange()}static onMenuToggleAdvanced(value,options,e2,menu,node2){if(!node2.graph)throw new NullGraphError;node2.graph.beforeChange();const fApplyMultiNode=function(node22){node22.toggleAdvanced()};const graphcanvas=LGraphCanvas.active_canvas;if(!graphcanvas.selected_nodes||Object.keys(graphcanvas.selected_nodes).length<=1){fApplyMultiNode(node2)}else{for(const i in graphcanvas.selected_nodes){fApplyMultiNode(graphcanvas.selected_nodes[i])}}node2.graph.afterChange()}static onMenuNodeMode(value,options,e2,menu,node2){new LiteGraph.ContextMenu(LiteGraph.NODE_MODES,{event:e2,callback:inner_clicked,parentMenu:menu,node:node2});function inner_clicked(v2){if(!node2)return;const kV=Object.values(LiteGraph.NODE_MODES).indexOf(v2);const fApplyMultiNode=function(node22){if(kV!==-1&&LiteGraph.NODE_MODES[kV]){node22.changeMode(kV)}else{console.warn(`unexpected mode: ${v2}`);node22.changeMode(LGraphEventMode.ALWAYS)}};const graphcanvas=LGraphCanvas.active_canvas;if(!graphcanvas.selected_nodes||Object.keys(graphcanvas.selected_nodes).length<=1){fApplyMultiNode(node2)}else{for(const i in graphcanvas.selected_nodes){fApplyMultiNode(graphcanvas.selected_nodes[i])}}}return false}static onMenuNodeColors(value,options,e2,menu,node2){if(!node2)throw"no node for color";const values=[];values.push({value:null,content:"<span style='display: block; padding-left: 4px;'>No color</span>"});for(const i in LGraphCanvas.node_colors){const color=LGraphCanvas.node_colors[i];value={value:i,content:`<span style='display: block; color: #999; padding-left: 4px; border-left: 8px solid ${color.color}; background-color:${color.bgcolor}'>${i}</span>`};values.push(value)}new LiteGraph.ContextMenu(values,{event:e2,callback:inner_clicked,parentMenu:menu,node:node2});function inner_clicked(v2){if(!node2)return;const fApplyColor=function(item){const colorOption=v2.value?LGraphCanvas.node_colors[v2.value]:null;item.setColorOption(colorOption)};const canvas2=LGraphCanvas.active_canvas;if(!canvas2.selected_nodes||Object.keys(canvas2.selected_nodes).length<=1){fApplyColor(node2)}else{for(const i in canvas2.selected_nodes){fApplyColor(canvas2.selected_nodes[i])}}canvas2.setDirty(true,true)}return false}static onMenuNodeShapes(value,options,e2,menu,node2){if(!node2)throw"no node passed";new LiteGraph.ContextMenu(LiteGraph.VALID_SHAPES,{event:e2,callback:inner_clicked,parentMenu:menu,node:node2});function inner_clicked(v2){if(!node2)return;if(!node2.graph)throw new NullGraphError;node2.graph.beforeChange();const fApplyMultiNode=function(node22){node22.shape=v2};const canvas2=LGraphCanvas.active_canvas;if(!canvas2.selected_nodes||Object.keys(canvas2.selected_nodes).length<=1){fApplyMultiNode(node2)}else{for(const i in canvas2.selected_nodes){fApplyMultiNode(canvas2.selected_nodes[i])}}node2.graph.afterChange();canvas2.setDirty(true)}return false}static onMenuNodeRemove(){LGraphCanvas.active_canvas.deleteSelected()}static onMenuNodeClone(value,options,e2,menu,node2){const{graph}=node2;if(!graph)throw new NullGraphError;graph.beforeChange();const newSelected=new Set;const fApplyMultiNode=function(node22,newNodes){if(node22.clonable===false)return;const newnode=node22.clone();if(!newnode)return;newnode.pos=[node22.pos[0]+5,node22.pos[1]+5];if(!node22.graph)throw new NullGraphError;node22.graph.add(newnode);newNodes.add(newnode)};const canvas2=LGraphCanvas.active_canvas;if(!canvas2.selected_nodes||Object.keys(canvas2.selected_nodes).length<=1){fApplyMultiNode(node2,newSelected)}else{for(const i in canvas2.selected_nodes){fApplyMultiNode(canvas2.selected_nodes[i],newSelected)}}if(newSelected.size){canvas2.selectNodes([...newSelected])}graph.afterChange();canvas2.setDirty(true,true)}clear(){this.frame=0;this.last_draw_time=0;this.render_time=0;this.fps=0;this.dragging_rectangle=null;this.selected_nodes={};this.selected_group=null;this.selectedItems.clear();this.state.selectionChanged=true;this.onSelectionChange?.(this.selected_nodes);this.visible_nodes=[];this.node_over=void 0;this.node_capturing_input=null;this.connecting_links=null;this.highlighted_links={};this.dragging_canvas=false;this.#dirty();this.dirty_area=null;this.node_in_panel=null;this.node_widget=null;this.last_mouse=[0,0];this.last_mouseclick=0;this.pointer.reset();this.visible_area.set([0,0,0,0]);this.onClear?.()}setGraph(newGraph){const{graph}=this;if(newGraph===graph)return;this.clear();newGraph.attachCanvas(this);this.dispatch("litegraph:set-graph",{newGraph,oldGraph:graph});this.#dirty()}openSubgraph(subgraph){const{graph}=this;if(!graph)throw new NullGraphError;const options={bubbles:true,detail:{subgraph,closingGraph:graph},cancelable:true};const mayContinue=this.canvas.dispatchEvent(new CustomEvent("subgraph-opening",options));if(!mayContinue)return;this.clear();this.subgraph=subgraph;this.setGraph(subgraph);this.canvas.dispatchEvent(new CustomEvent("subgraph-opened",options))}getCurrentGraph(){return this.graph}#validateCanvas(canvas2){if(typeof canvas2==="string"){const el=document.getElementById(canvas2);if(!(el instanceof HTMLCanvasElement))throw"Error validating LiteGraph canvas: Canvas element not found";return el}return canvas2}setCanvas(canvas2,skip_events){const element=this.#validateCanvas(canvas2);if(element===this.canvas)return;if(!element&&this.canvas&&!skip_events)this.unbindEvents();this.canvas=element;this.ds.element=element;this.pointer.element=element;if(!element)return;element.className+=" lgraphcanvas";element.data=this;this.bgcanvas=document.createElement("canvas");this.bgcanvas.width=this.canvas.width;this.bgcanvas.height=this.canvas.height;const ctx=element.getContext?.("2d");if(ctx==null){if(element.localName!="canvas"){throw`Element supplied for LGraphCanvas must be a <canvas> element, you passed a ${element.localName}`}throw"This browser doesn't support Canvas"}this.ctx=ctx;if(!skip_events)this.bindEvents()}_doNothing(e2){e2.preventDefault();return false}_doReturnTrue(e2){e2.preventDefault();return true}bindEvents(){if(this._events_binded){console.warn("LGraphCanvas: events already bound");return}const{canvas:canvas2}=this;const{document:document2}=this.getCanvasWindow();this._mousedown_callback=this.processMouseDown.bind(this);this._mousewheel_callback=this.processMouseWheel.bind(this);this._mousemove_callback=this.processMouseMove.bind(this);this._mouseup_callback=this.processMouseUp.bind(this);this._mouseout_callback=this.processMouseOut.bind(this);this._mousecancel_callback=this.processMouseCancel.bind(this);canvas2.addEventListener("pointerdown",this._mousedown_callback,true);canvas2.addEventListener("wheel",this._mousewheel_callback,false);canvas2.addEventListener("pointerup",this._mouseup_callback,true);canvas2.addEventListener("pointermove",this._mousemove_callback);canvas2.addEventListener("pointerout",this._mouseout_callback);canvas2.addEventListener("pointercancel",this._mousecancel_callback,true);canvas2.addEventListener("contextmenu",this._doNothing);this._key_callback=this.processKey.bind(this);canvas2.addEventListener("keydown",this._key_callback,true);document2.addEventListener("keyup",this._key_callback,true);canvas2.addEventListener("dragover",this._doNothing,false);canvas2.addEventListener("dragend",this._doNothing,false);canvas2.addEventListener("dragenter",this._doReturnTrue,false);this._events_binded=true}unbindEvents(){if(!this._events_binded){console.warn("LGraphCanvas: no events bound");return}const{document:document2}=this.getCanvasWindow();const{canvas:canvas2}=this;canvas2.removeEventListener("pointercancel",this._mousecancel_callback);canvas2.removeEventListener("pointerout",this._mouseout_callback);canvas2.removeEventListener("pointermove",this._mousemove_callback);canvas2.removeEventListener("pointerup",this._mouseup_callback);canvas2.removeEventListener("pointerdown",this._mousedown_callback);canvas2.removeEventListener("wheel",this._mousewheel_callback);canvas2.removeEventListener("keydown",this._key_callback);document2.removeEventListener("keyup",this._key_callback);canvas2.removeEventListener("contextmenu",this._doNothing);canvas2.removeEventListener("dragenter",this._doReturnTrue);this._mousedown_callback=void 0;this._mousewheel_callback=void 0;this._key_callback=void 0;this._events_binded=false}setDirty(fgcanvas,bgcanvas){if(fgcanvas)this.dirty_canvas=true;if(bgcanvas)this.dirty_bgcanvas=true}#dirty(){this.dirty_canvas=true;this.dirty_bgcanvas=true}#linkConnectorDrop(){const{graph,linkConnector,pointer}=this;if(!graph)throw new NullGraphError;pointer.onDragEnd=upEvent=>linkConnector.dropLinks(graph,upEvent);pointer.finally=()=>this.linkConnector.reset(true)}getCanvasWindow(){if(!this.canvas)return window;const doc=this.canvas.ownerDocument;return doc.defaultView||doc.parentWindow}startRendering(){if(this.is_rendering)return;this.is_rendering=true;renderFrame.call(this);function renderFrame(){if(!this.pause_rendering){this.draw()}const window2=this.getCanvasWindow();if(this.is_rendering){if(this.#maximumFrameGap>0){const gap=this.#maximumFrameGap-(LiteGraph.getTime()-this.last_draw_time);setTimeout(renderFrame.bind(this),Math.max(1,gap))}else{window2.requestAnimationFrame(renderFrame.bind(this))}}}}stopRendering(){this.is_rendering=false}blockClick(){this.block_click=true;this.last_mouseclick=0}getWidgetAtCursor(node2){node2??=this.node_over;return node2?.getWidgetOnPos(this.graph_mouse[0],this.graph_mouse[1],true)}updateMouseOverNodes(node2,e2){if(!this.graph)throw new NullGraphError;const{pointer}=this;const nodes=this.graph._nodes;for(const otherNode of nodes){if(otherNode.mouseOver&&node2!=otherNode){if(!pointer.eDown)pointer.resizeDirection=void 0;otherNode.mouseOver=void 0;this._highlight_input=void 0;this._highlight_pos=void 0;this.linkConnector.overWidget=void 0;otherNode.lostFocusAt=LiteGraph.getTime();this.node_over?.onMouseLeave?.(e2);this.node_over=void 0;this.dirty_canvas=true}}}processMouseDown(e2){if(this.dragZoomEnabled&&e2.ctrlKey&&e2.shiftKey&&!e2.altKey&&e2.buttons){this.#dragZoomStart={pos:[e2.x,e2.y],scale:this.ds.scale};return}const{graph,pointer}=this;this.adjustMouseEvent(e2);if(e2.isPrimary)pointer.down(e2);if(this.set_canvas_dirty_on_mouse_event)this.dirty_canvas=true;if(!graph)return;const ref_window=this.getCanvasWindow();LGraphCanvas.active_canvas=this;const x2=e2.clientX;const y=e2.clientY;this.ds.viewport=this.viewport;const is_inside=!this.viewport||isInRect(x2,y,this.viewport);if(!is_inside)return;const node2=graph.getNodeOnPos(e2.canvasX,e2.canvasY,this.visible_nodes)??void 0;this.mouse[0]=x2;this.mouse[1]=y;this.graph_mouse[0]=e2.canvasX;this.graph_mouse[1]=e2.canvasY;this.last_click_position=[this.mouse[0],this.mouse[1]];pointer.isDouble=pointer.isDown&&e2.isPrimary;pointer.isDown=true;this.canvas.focus();LiteGraph.closeAllContextMenus(ref_window);if(this.onMouse?.(e2)==true)return;if(e2.button===0&&!pointer.isDouble){this.#processPrimaryButton(e2,node2)}else if(e2.button===1){this.#processMiddleButton(e2,node2)}else if((e2.button===2||pointer.isDouble)&&this.allow_interaction&&!this.read_only){const{linkConnector,subgraph}=this;if(subgraph?.inputNode.containsPoint(this.graph_mouse)){this.processSelect(subgraph.inputNode,e2,true);subgraph.inputNode.onPointerDown(e2,pointer,linkConnector)}else if(subgraph?.outputNode.containsPoint(this.graph_mouse)){this.processSelect(subgraph.outputNode,e2,true);subgraph.outputNode.onPointerDown(e2,pointer,linkConnector)}else{if(node2){this.processSelect(node2,e2,true)}else if(this.links_render_mode!==LinkRenderType.HIDDEN_LINK){const reroute=graph.getRerouteOnPos(e2.canvasX,e2.canvasY,this.#visibleReroutes);if(reroute){if(e2.altKey){pointer.onClick=upEvent=>{if(upEvent.altKey){if(reroute.selected){this.deselect(reroute);this.onSelectionChange?.(this.selected_nodes)}reroute.remove()}}}else{this.processSelect(reroute,e2,true)}}}pointer.onClick??=()=>this.processContextMenu(node2,e2)}}this.last_mouse=[x2,y];this.last_mouseclick=LiteGraph.getTime();this.last_mouse_dragging=true;graph.change();if(!ref_window.document.activeElement||ref_window.document.activeElement.nodeName.toLowerCase()!="input"&&ref_window.document.activeElement.nodeName.toLowerCase()!="textarea"){e2.preventDefault()}e2.stopPropagation();this.onMouseDown?.(e2)}#getPositionableOnPos(x2,y){const ioNode=this.subgraph?.getIoNodeOnPos(x2,y);if(ioNode)return ioNode;for(const reroute of this.#visibleReroutes){if(reroute.containsPoint([x2,y]))return reroute}return this.graph?.getGroupTitlebarOnPos(x2,y)}#processPrimaryButton(e2,node2){const{pointer,graph,linkConnector,subgraph}=this;if(!graph)throw new NullGraphError;const x2=e2.canvasX;const y=e2.canvasY;const ctrlOrMeta=e2.ctrlKey||e2.metaKey;if(ctrlOrMeta&&!e2.altKey&&LiteGraph.canvasNavigationMode==="legacy"){this.#setupNodeSelectionDrag(e2,pointer,node2);return}if(this.read_only){pointer.finally=()=>this.dragging_canvas=false;this.dragging_canvas=true;return}if(LiteGraph.alt_drag_do_clone_nodes&&e2.altKey&&!e2.ctrlKey&&node2&&this.allow_interaction){let newType=node2.type;if(node2 instanceof SubgraphNode){const cloned=node2.subgraph.clone().asSerialisable();const subgraph2=graph.createSubgraph(cloned);subgraph2.configure(cloned);newType=subgraph2.id}const node_data=node2.clone()?.serialize();if(node_data?.type!=null){const cloned=LiteGraph.createNode(newType);if(cloned){cloned.configure(node_data);cloned.pos[0]+=5;cloned.pos[1]+=5;if(this.allow_dragnodes){pointer.onDragStart=pointer2=>{graph.add(cloned,false);this.#startDraggingItems(cloned,pointer2)};pointer.onDragEnd=e22=>this.#processDraggedItems(e22)}else{graph.beforeChange();graph.add(cloned,false);graph.afterChange()}return}}}if(node2&&(this.allow_interaction||node2.flags.allow_interaction)){this.#processNodeClick(e2,ctrlOrMeta,node2)}else{if(subgraph){let processSubgraphIONode=function(canvas2,ioNode){if(!ioNode.containsPoint([x2,y]))return false;ioNode.onPointerDown(e2,pointer,linkConnector);pointer.onClick??=()=>canvas2.processSelect(ioNode,e2);pointer.onDragStart??=()=>canvas2.#startDraggingItems(ioNode,pointer,true);pointer.onDragEnd??=eUp=>canvas2.#processDraggedItems(eUp);return true};const{inputNode,outputNode}=subgraph;if(processSubgraphIONode(this,inputNode))return;if(processSubgraphIONode(this,outputNode))return}if(this.links_render_mode!==LinkRenderType.HIDDEN_LINK){for(const reroute of this.#visibleReroutes){const overReroute=reroute.containsPoint([x2,y]);if(!reroute.isSlotHovered&&!overReroute)continue;if(overReroute){pointer.onClick=()=>this.processSelect(reroute,e2);if(!e2.shiftKey){pointer.onDragStart=pointer2=>this.#startDraggingItems(reroute,pointer2,true);pointer.onDragEnd=e22=>this.#processDraggedItems(e22)}}if(reroute.isOutputHovered||overReroute&&e2.shiftKey){linkConnector.dragFromReroute(graph,reroute);this.#linkConnectorDrop()}if(reroute.isInputHovered){linkConnector.dragFromRerouteToOutput(graph,reroute);this.#linkConnectorDrop()}reroute.hideSlots();this.dirty_bgcanvas=true;return}}const{lineWidth}=this.ctx;this.ctx.lineWidth=this.connections_width+7;const dpi=window?.devicePixelRatio||1;for(const linkSegment of this.renderedPaths){const centre=linkSegment._pos;if(!centre)continue;if((e2.shiftKey||e2.altKey)&&linkSegment.path&&this.ctx.isPointInStroke(linkSegment.path,x2*dpi,y*dpi)){this.ctx.lineWidth=lineWidth;if(e2.shiftKey&&!e2.altKey){linkConnector.dragFromLinkSegment(graph,linkSegment);this.#linkConnectorDrop();return}else if(e2.altKey&&!e2.shiftKey){const newReroute=graph.createReroute([x2,y],linkSegment);pointer.onDragStart=pointer2=>this.#startDraggingItems(newReroute,pointer2);pointer.onDragEnd=e22=>this.#processDraggedItems(e22);return}}else if(isInRectangle(x2,y,centre[0]-4,centre[1]-4,8,8)){this.ctx.lineWidth=lineWidth;pointer.onClick=()=>this.showLinkMenu(linkSegment,e2);pointer.onDragStart=()=>this.dragging_canvas=true;pointer.finally=()=>this.dragging_canvas=false;this.over_link_center=void 0;return}}this.ctx.lineWidth=lineWidth;const group=graph.getGroupOnPos(x2,y);this.selected_group=group??null;if(group){if(group.isInResize(x2,y)){const b=group.boundingRect;const offsetX=x2-(b[0]+b[2]);const offsetY=y-(b[1]+b[3]);pointer.onDragStart=()=>this.resizingGroup=group;pointer.onDrag=eMove=>{if(this.read_only)return;const pos=[eMove.canvasX-group.pos[0]-offsetX,eMove.canvasY-group.pos[1]-offsetY];if(this.#snapToGrid)snapPoint(pos,this.#snapToGrid);const resized=group.resize(pos[0],pos[1]);if(resized)this.dirty_bgcanvas=true};pointer.finally=()=>this.resizingGroup=null}else{const f=group.font_size||LiteGraph.DEFAULT_GROUP_FONT_SIZE;const headerHeight=f*1.4;if(isInRectangle(x2,y,group.pos[0],group.pos[1],group.size[0],headerHeight)){pointer.onClick=()=>this.processSelect(group,e2);pointer.onDragStart=pointer2=>{group.recomputeInsideNodes();this.#startDraggingItems(group,pointer2,true)};pointer.onDragEnd=e22=>this.#processDraggedItems(e22)}}pointer.onDoubleClick=()=>{this.emitEvent({subType:"group-double-click",originalEvent:e2,group})}}else{pointer.onDoubleClick=()=>{if(this.allow_searchbox){this.showSearchBox(e2);e2.preventDefault()}this.emitEvent({subType:"empty-double-click",originalEvent:e2})}}}if(!pointer.onDragStart&&!pointer.onClick&&!pointer.onDrag&&this.allow_dragcanvas){if(LiteGraph.canvasNavigationMode!=="standard"||this.read_only){pointer.onClick=()=>this.processSelect(null,e2);pointer.finally=()=>this.dragging_canvas=false;this.dragging_canvas=true}else{this.#setupNodeSelectionDrag(e2,pointer)}}}#setupNodeSelectionDrag(e2,pointer,node2){const dragRect=new Float32Array(4);dragRect[0]=e2.canvasX;dragRect[1]=e2.canvasY;dragRect[2]=1;dragRect[3]=1;pointer.onClick=eUp=>{const clickedItem=node2??this.#getPositionableOnPos(eUp.canvasX,eUp.canvasY);this.processSelect(clickedItem,eUp)};pointer.onDragStart=()=>this.dragging_rectangle=dragRect;pointer.onDragEnd=upEvent=>this.#handleMultiSelect(upEvent,dragRect);pointer.finally=()=>this.dragging_rectangle=null}#processNodeClick(e2,ctrlOrMeta,node2){const{pointer,graph,linkConnector}=this;if(!graph)throw new NullGraphError;const x2=e2.canvasX;const y=e2.canvasY;pointer.onClick=()=>this.processSelect(node2,e2);if(!node2.flags.pinned){this.bringToFront(node2)}const inCollapse=node2.isPointInCollapse(x2,y);if(inCollapse){pointer.onClick=()=>{node2.collapse();this.setDirty(true,true)}}else if(!node2.flags.collapsed){const{inputs,outputs}=node2;if(outputs){for(const[i,output]of outputs.entries()){const link_pos=node2.getOutputPos(i);if(isInRectangle(x2,y,link_pos[0]-15,link_pos[1]-10,30,20)){if(e2.shiftKey&&(output.links?.length||output._floatingLinks?.size)){linkConnector.moveOutputLink(graph,output);this.#linkConnectorDrop();return}linkConnector.dragNewFromOutput(graph,node2,output);this.#linkConnectorDrop();if(LiteGraph.shift_click_do_break_link_from){if(e2.shiftKey){node2.disconnectOutput(i)}}else if(LiteGraph.ctrl_alt_click_do_break_link){if(ctrlOrMeta&&e2.altKey&&!e2.shiftKey){node2.disconnectOutput(i)}}pointer.onDoubleClick=()=>node2.onOutputDblClick?.(i,e2);pointer.onClick=()=>node2.onOutputClick?.(i,e2);return}}}if(inputs){for(const[i,input]of inputs.entries()){const link_pos=node2.getInputPos(i);const isInSlot=input instanceof NodeInputSlot?isInRect(x2,y,input.boundingRect):isInRectangle(x2,y,link_pos[0]-15,link_pos[1]-10,30,20);if(isInSlot){pointer.onDoubleClick=()=>node2.onInputDblClick?.(i,e2);pointer.onClick=()=>node2.onInputClick?.(i,e2);const shouldBreakLink=LiteGraph.ctrl_alt_click_do_break_link&&ctrlOrMeta&&e2.altKey&&!e2.shiftKey;if(input.link!==null||input._floatingLinks?.size){if(shouldBreakLink||LiteGraph.click_do_break_link_to){node2.disconnectInput(i,true)}else if(e2.shiftKey||this.allow_reconnect_links){linkConnector.moveInputLink(graph,input)}}if(!linkConnector.isConnecting){linkConnector.dragNewFromInput(graph,node2,input)}this.#linkConnectorDrop();this.dirty_bgcanvas=true;return}}}}const pos=[x2-node2.pos[0],y-node2.pos[1]];const widget=node2.getWidgetOnPos(x2,y);if(widget){this.#processWidgetClick(e2,node2,widget);this.node_widget=[node2,widget]}else{pointer.onDoubleClick=()=>{if(pos[1]<0&&!inCollapse){node2.onNodeTitleDblClick?.(e2,pos,this)}else if(node2 instanceof SubgraphNode){this.openSubgraph(node2.subgraph)}node2.onDblClick?.(e2,pos,this);this.emitEvent({subType:"node-double-click",originalEvent:e2,node:node2});this.processNodeDblClicked(node2)};if(node2.onMouseDown?.(e2,pos,this)){pointer.onClick=()=>{};return}if(!this.allow_dragnodes)return;if(!node2.flags.collapsed){const resizeDirection=node2.findResizeDirection(x2,y);if(resizeDirection){pointer.resizeDirection=resizeDirection;const startBounds=new Rectangle(node2.pos[0],node2.pos[1],node2.size[0],node2.size[1]);pointer.onDragStart=()=>{graph.beforeChange();this.resizing_node=node2};pointer.onDrag=eMove=>{if(this.read_only)return;const deltaX=eMove.canvasX-x2;const deltaY=eMove.canvasY-y;const newBounds=new Rectangle(startBounds.x,startBounds.y,startBounds.width,startBounds.height);switch(resizeDirection){case"NE":newBounds.y=startBounds.y+deltaY;newBounds.width=startBounds.width+deltaX;newBounds.height=startBounds.height-deltaY;break;case"SE":newBounds.width=startBounds.width+deltaX;newBounds.height=startBounds.height+deltaY;break;case"SW":newBounds.x=startBounds.x+deltaX;newBounds.width=startBounds.width-deltaX;newBounds.height=startBounds.height+deltaY;break;case"NW":newBounds.x=startBounds.x+deltaX;newBounds.y=startBounds.y+deltaY;newBounds.width=startBounds.width-deltaX;newBounds.height=startBounds.height-deltaY;break}if(this.#snapToGrid){if(resizeDirection.includes("N")||resizeDirection.includes("W")){const originalX=newBounds.x;const originalY=newBounds.y;snapPoint(newBounds.pos,this.#snapToGrid);if(resizeDirection.includes("N")){newBounds.height+=originalY-newBounds.y}if(resizeDirection.includes("W")){newBounds.width+=originalX-newBounds.x}}snapPoint(newBounds.size,this.#snapToGrid)}const min=node2.computeSize();if(newBounds.width<min[0]){if(resizeDirection.includes("W")){newBounds.x=startBounds.x+startBounds.width-min[0]}newBounds.width=min[0]}if(newBounds.height<min[1]){if(resizeDirection.includes("N")){newBounds.y=startBounds.y+startBounds.height-min[1]}newBounds.height=min[1]}node2.pos=newBounds.pos;node2.setSize(newBounds.size);this.#dirty()};pointer.onDragEnd=()=>{this.#dirty();graph.afterChange(node2)};pointer.finally=()=>{this.resizing_node=null;pointer.resizeDirection=void 0};this.canvas.style.cursor=cursors[resizeDirection];return}}pointer.onDragStart=pointer2=>this.#startDraggingItems(node2,pointer2,true);pointer.onDragEnd=e22=>this.#processDraggedItems(e22)}this.dirty_canvas=true}#processWidgetClick(e2,node2,widget){const{pointer}=this;if(typeof widget.onPointerDown==="function"){const handled=widget.onPointerDown(pointer,node2,this);if(handled)return}const oldValue=widget.value;const pos=this.graph_mouse;const x2=pos[0]-node2.pos[0];const y=pos[1]-node2.pos[1];const widgetInstance=toConcreteWidget(widget,node2,false);if(widgetInstance){pointer.onClick=()=>widgetInstance.onClick({e:e2,node:node2,canvas:this});pointer.onDrag=eMove=>widgetInstance.onDrag?.({e:eMove,node:node2,canvas:this})}else if(widget.mouse){const result=widget.mouse(e2,[x2,y],node2);if(result!=null)this.dirty_canvas=result}if(oldValue!=widget.value){node2.onWidgetChanged?.(widget.name,widget.value,oldValue,widget);if(!node2.graph)throw new NullGraphError;node2.graph._version++}pointer.finally=()=>{if(widget.mouse){const{eUp}=pointer;if(!eUp)return;const{canvasX,canvasY}=eUp;widget.mouse(eUp,[canvasX-node2.pos[0],canvasY-node2.pos[1]],node2)}this.node_widget=null}}#processMiddleButton(e2,node2){const{pointer}=this;if(LiteGraph.middle_click_slot_add_default_node&&node2&&this.allow_interaction&&!this.read_only&&!this.connecting_links&&!node2.flags.collapsed){let mClikSlot=false;let mClikSlot_index=false;let mClikSlot_isOut=false;const{inputs,outputs}=node2;if(outputs){for(const[i,output]of outputs.entries()){const link_pos=node2.getOutputPos(i);if(isInRectangle(e2.canvasX,e2.canvasY,link_pos[0]-15,link_pos[1]-10,30,20)){mClikSlot=output;mClikSlot_index=i;mClikSlot_isOut=true;break}}}if(inputs){for(const[i,input]of inputs.entries()){const link_pos=node2.getInputPos(i);if(isInRectangle(e2.canvasX,e2.canvasY,link_pos[0]-15,link_pos[1]-10,30,20)){mClikSlot=input;mClikSlot_index=i;mClikSlot_isOut=false;break}}}if(mClikSlot&&mClikSlot_index!==false){const alphaPosY=.5-(mClikSlot_index+1)/(mClikSlot_isOut?outputs.length:inputs.length);const node_bounding=node2.getBounding();const posRef=[!mClikSlot_isOut?node_bounding[0]:node_bounding[0]+node_bounding[2],e2.canvasY-80];pointer.onClick=()=>this.createDefaultNodeForSlot({nodeFrom:!mClikSlot_isOut?null:node2,slotFrom:!mClikSlot_isOut?null:mClikSlot_index,nodeTo:!mClikSlot_isOut?node2:null,slotTo:!mClikSlot_isOut?mClikSlot_index:null,position:posRef,nodeType:"AUTO",posAdd:[!mClikSlot_isOut?-30:30,-alphaPosY*130],posSizeFix:[!mClikSlot_isOut?-1:0,0]})}}if(this.allow_dragcanvas){pointer.onDragStart=()=>this.dragging_canvas=true;pointer.finally=()=>this.dragging_canvas=false}}#processDragZoom(e2){if(!e2.buttons){this.#dragZoomStart=null;return}const start=this.#dragZoomStart;if(!start)throw new TypeError("Drag-zoom state object was null");if(!this.graph)throw new NullGraphError;const deltaY=e2.y-start.pos[1];const startScale=start.scale;const scale=startScale-deltaY/100;this.ds.changeScale(scale,start.pos);this.graph.change()}processMouseMove(e2){if(this.dragZoomEnabled&&e2.ctrlKey&&e2.shiftKey&&this.#dragZoomStart){this.#processDragZoom(e2);return}if(this.autoresize)this.resize();if(this.set_canvas_dirty_on_mouse_event)this.dirty_canvas=true;const{graph,resizingGroup,linkConnector,pointer,subgraph}=this;if(!graph)return;LGraphCanvas.active_canvas=this;this.adjustMouseEvent(e2);const mouse=[e2.clientX,e2.clientY];this.mouse[0]=mouse[0];this.mouse[1]=mouse[1];const delta2=[mouse[0]-this.last_mouse[0],mouse[1]-this.last_mouse[1]];this.last_mouse=mouse;const{canvasX:x2,canvasY:y}=e2;this.graph_mouse[0]=x2;this.graph_mouse[1]=y;if(e2.isPrimary)pointer.move(e2);let underPointer=CanvasItem.Nothing;if(subgraph){underPointer|=subgraph.inputNode.onPointerMove(e2);underPointer|=subgraph.outputNode.onPointerMove(e2)}if(this.block_click){e2.preventDefault();return}e2.dragging=this.last_mouse_dragging;if(this.node_widget){const[node22,widget]=this.node_widget;if(widget?.mouse){const relativeX=x2-node22.pos[0];const relativeY=y-node22.pos[1];const result=widget.mouse(e2,[relativeX,relativeY],node22);if(result!=null)this.dirty_canvas=result}}const node2=graph.getNodeOnPos(x2,y,this.visible_nodes);const dragRect=this.dragging_rectangle;if(dragRect){dragRect[2]=x2-dragRect[0];dragRect[3]=y-dragRect[1];this.dirty_canvas=true}else if(resizingGroup){underPointer|=CanvasItem.Group;pointer.resizeDirection="SE"}else if(this.dragging_canvas){this.ds.offset[0]+=delta2[0]/this.ds.scale;this.ds.offset[1]+=delta2[1]/this.ds.scale;this.#dirty()}else if((this.allow_interaction||node2?.flags.allow_interaction)&&!this.read_only){if(linkConnector.isConnecting)this.dirty_canvas=true;this.updateMouseOverNodes(node2,e2);if(node2){underPointer|=CanvasItem.Node;if(node2.redraw_on_mouse)this.dirty_canvas=true;const pos=[0,0];const inputId=isOverNodeInput(node2,x2,y,pos);const outputId=isOverNodeOutput(node2,x2,y,pos);const overWidget=node2.getWidgetOnPos(x2,y,true)??void 0;if(!node2.mouseOver){node2.mouseOver={};this.node_over=node2;this.dirty_canvas=true;for(const reroute of this.#visibleReroutes){reroute.hideSlots();this.dirty_bgcanvas=true}node2.onMouseEnter?.(e2)}node2.onMouseMove?.(e2,[x2-node2.pos[0],y-node2.pos[1]],this);const{mouseOver}=node2;if(mouseOver.inputId!==inputId||mouseOver.outputId!==outputId||mouseOver.overWidget!==overWidget){mouseOver.inputId=inputId;mouseOver.outputId=outputId;mouseOver.overWidget=overWidget;linkConnector.overWidget=void 0;if(linkConnector.isConnecting){const firstLink=linkConnector.renderLinks.at(0);let highlightPos;let highlightInput;if(!firstLink||!linkConnector.isNodeValidDrop(node2));else if(linkConnector.state.connectingTo==="input"){if(overWidget){const slot=node2.getSlotFromWidget(overWidget);if(slot&&linkConnector.isInputValidDrop(node2,slot)){highlightInput=slot;highlightPos=node2.getInputSlotPos(slot);linkConnector.overWidget=overWidget}}if(!linkConnector.overWidget){if(inputId===-1&&outputId===-1){const result=node2.findInputByType(firstLink.fromSlot.type);if(result){highlightInput=result.slot;highlightPos=node2.getInputSlotPos(result.slot)}}else if(inputId!=-1&&node2.inputs[inputId]&&LiteGraph.isValidConnection(firstLink.fromSlot.type,node2.inputs[inputId].type)){highlightPos=pos;highlightInput=node2.inputs[inputId]}if(highlightInput){const widget=node2.getWidgetFromSlot(highlightInput);if(widget)linkConnector.overWidget=widget}}}else if(linkConnector.state.connectingTo==="output"){if(inputId===-1&&outputId===-1){const result=node2.findOutputByType(firstLink.fromSlot.type);if(result){highlightPos=node2.getOutputPos(result.index)}}else{if(outputId!=-1&&node2.outputs[outputId]&&LiteGraph.isValidConnection(firstLink.fromSlot.type,node2.outputs[outputId].type)){highlightPos=pos}}}this._highlight_pos=highlightPos;this._highlight_input=highlightInput}this.dirty_canvas=true}if(!pointer.eDown){if(inputId===-1&&outputId===-1&&!overWidget){pointer.resizeDirection=node2.findResizeDirection(x2,y)}else{pointer.resizeDirection&&=void 0}}}else{underPointer=this.#updateReroutes(underPointer);const segment=this.#getLinkCentreOnPos(e2);if(this.over_link_center!==segment){underPointer|=CanvasItem.Link;this.over_link_center=segment;this.dirty_bgcanvas=true}if(this.canvas){const group=graph.getGroupOnPos(x2,y);if(group&&!e2.ctrlKey&&!this.read_only&&group.isInResize(x2,y)){pointer.resizeDirection="SE"}else{pointer.resizeDirection&&=void 0}}}if(this.node_capturing_input&&this.node_capturing_input!=node2){this.node_capturing_input.onMouseMove?.(e2,[x2-this.node_capturing_input.pos[0],y-this.node_capturing_input.pos[1]],this)}if(this.isDragging){const selected=this.selectedItems;const allItems=e2.ctrlKey?selected:getAllNestedItems(selected);const deltaX=delta2[0]/this.ds.scale;const deltaY=delta2[1]/this.ds.scale;for(const item of allItems){item.move(deltaX,deltaY,true)}this.#dirty()}}this.hoveringOver=underPointer;e2.preventDefault();return}#updateReroutes(underPointer){const{graph,pointer,linkConnector}=this;if(!graph)throw new NullGraphError;if(!pointer.isDown){let anyChanges=false;for(const reroute of this.#visibleReroutes){anyChanges||=reroute.updateVisibility(this.graph_mouse);if(reroute.isSlotHovered)underPointer|=CanvasItem.RerouteSlot}if(anyChanges)this.dirty_bgcanvas=true}else if(linkConnector.isConnecting){for(const reroute of this.#visibleReroutes){if(reroute.containsPoint(this.graph_mouse)){if(linkConnector.isRerouteValidDrop(reroute)){linkConnector.overReroute=reroute;this._highlight_pos=reroute.pos}return underPointer|=CanvasItem.RerouteSlot}}}this._highlight_pos&&=void 0;linkConnector.overReroute&&=void 0;return underPointer}#startDraggingItems(item,pointer,sticky=false){this.emitBeforeChange();this.graph?.beforeChange();pointer.finally=()=>{this.isDragging=false;this.graph?.afterChange();this.emitAfterChange()};this.processSelect(item,pointer.eDown,sticky);this.isDragging=true}#processDraggedItems(e2){const{graph}=this;if(e2.shiftKey||LiteGraph.alwaysSnapToGrid)graph?.snapToGrid(this.selectedItems);this.dirty_canvas=true;this.dirty_bgcanvas=true;this.onNodeMoved?.(findFirstNode(this.selectedItems))}processMouseUp(e2){if(e2.isPrimary===false)return;const{graph,pointer}=this;if(!graph)return;LGraphCanvas.active_canvas=this;this.adjustMouseEvent(e2);const now=LiteGraph.getTime();e2.click_time=now-this.last_mouseclick;const isClick=pointer.up(e2);if(isClick===true){pointer.isDown=false;pointer.isDouble=false;this.connecting_links=null;this.dragging_canvas=false;graph.change();e2.stopPropagation();e2.preventDefault();return}this.last_mouse_dragging=false;this.last_click_position=null;this.block_click&&=false;if(e2.button===0){this.selected_group=null;this.isDragging=false;const x2=e2.canvasX;const y=e2.canvasY;if(!this.linkConnector.isConnecting){this.dirty_canvas=true;this.node_over?.onMouseUp?.(e2,[x2-this.node_over.pos[0],y-this.node_over.pos[1]],this);this.node_capturing_input?.onMouseUp?.(e2,[x2-this.node_capturing_input.pos[0],y-this.node_capturing_input.pos[1]])}}else if(e2.button===1){this.dirty_canvas=true;this.dragging_canvas=false}else if(e2.button===2){this.dirty_canvas=true}pointer.isDown=false;pointer.isDouble=false;graph.change();e2.stopPropagation();e2.preventDefault();return}processMouseOut(e2){this.adjustMouseEvent(e2);this.updateMouseOverNodes(null,e2)}processMouseCancel(){console.warn("Pointer cancel!");this.pointer.reset()}processMouseWheel(e2){if(!this.graph||!this.allow_dragcanvas)return;const delta2=e2.wheelDeltaY??e2.detail*-60;this.adjustMouseEvent(e2);const pos=[e2.clientX,e2.clientY];if(this.viewport&&!isPointInRect(pos,this.viewport))return;let{scale}=this.ds;if(LiteGraph.canvasNavigationMode==="legacy"||LiteGraph.canvasNavigationMode==="standard"&&e2.ctrlKey){if(delta2>0){scale*=this.zoom_speed}else if(delta2<0){scale*=1/this.zoom_speed}this.ds.changeScale(scale,[e2.clientX,e2.clientY])}else if(LiteGraph.macTrackpadGestures&&(!LiteGraph.macGesturesRequireMac||navigator.userAgent.includes("Mac"))){if(e2.metaKey&&!e2.ctrlKey&&!e2.shiftKey&&!e2.altKey){if(e2.deltaY>0){scale*=1/this.zoom_speed}else if(e2.deltaY<0){scale*=this.zoom_speed}this.ds.changeScale(scale,[e2.clientX,e2.clientY])}else if(e2.ctrlKey){scale*=1+e2.deltaY*(1-this.zoom_speed)*.18;this.ds.changeScale(scale,[e2.clientX,e2.clientY],false)}else if(e2.shiftKey){this.ds.offset[0]-=e2.deltaY*1.18*(1/scale)}else{this.ds.offset[0]-=e2.deltaX*1.18*(1/scale);this.ds.offset[1]-=e2.deltaY*1.18*(1/scale)}}this.graph.change();e2.preventDefault();return}#noItemsSelected(){const event=new CustomEvent("litegraph:no-items-selected",{bubbles:true});this.canvas.dispatchEvent(event)}processKey(e2){this.#shiftDown=e2.shiftKey;const{graph}=this;if(!graph)return;let block_default=false;if(e2.target.localName=="input")return;if(e2.type=="keydown"){if(e2.key===" "){this.read_only=true;if(this._previously_dragging_canvas===null){this._previously_dragging_canvas=this.dragging_canvas}this.dragging_canvas=this.pointer.isDown;block_default=true}else if(e2.key==="Escape"){if(this.linkConnector.isConnecting){this.linkConnector.reset();e2.preventDefault();return}this.node_panel?.close();this.options_panel?.close();if(this.node_panel||this.options_panel)block_default=true}else if(e2.keyCode===65&&e2.ctrlKey){this.selectItems();block_default=true}else if(e2.keyCode===67&&(e2.metaKey||e2.ctrlKey)&&!e2.shiftKey){if(this.selected_nodes){this.copyToClipboard();block_default=true}}else if(e2.keyCode===86&&(e2.metaKey||e2.ctrlKey)){this.pasteFromClipboard({connectInputs:e2.shiftKey})}else if(e2.key==="Delete"||e2.key==="Backspace"){if(e2.target.localName!="input"&&e2.target.localName!="textarea"){if(this.selectedItems.size===0){this.#noItemsSelected();return}this.deleteSelected();block_default=true}}for(const node2 of Object.values(this.selected_nodes)){node2.onKeyDown?.(e2)}}else if(e2.type=="keyup"){if(e2.key===" "){this.read_only=false;this.dragging_canvas=(this._previously_dragging_canvas??false)&&this.pointer.isDown;this._previously_dragging_canvas=null}for(const node2 of Object.values(this.selected_nodes)){node2.onKeyUp?.(e2)}}graph.change();if(block_default){e2.preventDefault();e2.stopImmediatePropagation()}}copyToClipboard(items){const serialisable={nodes:[],groups:[],reroutes:[],links:[],subgraphs:[]};const subgraphs=new Set;for(const item of items??this.selectedItems){if(item instanceof LGraphNode){if(item.clonable===false)continue;const cloned=item.clone()?.serialize();if(!cloned)continue;cloned.id=item.id;serialisable.nodes.push(cloned);if(item.inputs){for(const{link:linkId}of item.inputs){if(linkId==null)continue;const link=this.graph?._links.get(linkId)?.asSerialisable();if(link)serialisable.links.push(link)}}if(item instanceof SubgraphNode){subgraphs.add(item.subgraph)}}else if(item instanceof LGraphGroup){serialisable.groups.push(item.serialize())}else if(item instanceof Reroute){serialisable.reroutes.push(item.asSerialisable())}}for(const subgraph of subgraphs){const cloned=subgraph.clone(true).asSerialisable();serialisable.subgraphs.push(cloned)}localStorage.setItem("litegrapheditor_clipboard",JSON.stringify(serialisable))}emitEvent(detail){this.canvas.dispatchEvent(new CustomEvent("litegraph:canvas",{bubbles:true,detail}))}emitBeforeChange(){this.emitEvent({subType:"before-change"})}emitAfterChange(){this.emitEvent({subType:"after-change"})}_pasteFromClipboard(options={}){const{connectInputs=false,position=this.graph_mouse}=options;if(!LiteGraph.ctrl_shift_v_paste_connect_unselected_outputs&&connectInputs)return;const data=localStorage.getItem("litegrapheditor_clipboard");if(!data)return;const{graph}=this;if(!graph)throw new NullGraphError;graph.beforeChange();const parsed=JSON.parse(data);parsed.nodes??=[];parsed.groups??=[];parsed.reroutes??=[];parsed.links??=[];parsed.subgraphs??=[];let offsetX=Infinity;let offsetY=Infinity;for(const item of[...parsed.nodes,...parsed.reroutes]){if(item.pos==null)throw new TypeError("Invalid node encounterd on paste. `pos` was null.");if(item.pos[0]<offsetX)offsetX=item.pos[0];if(item.pos[1]<offsetY)offsetY=item.pos[1]}if(parsed.groups){for(const group of parsed.groups){if(group.bounding[0]<offsetX)offsetX=group.bounding[0];if(group.bounding[1]<offsetY)offsetY=group.bounding[1]}}const results={created:[],nodes:new Map,links:new Map,reroutes:new Map,subgraphs:new Map};const{created,nodes,links,reroutes}=results;for(const info of parsed.subgraphs){const originalId=info.id;info.id=createUuidv4();const subgraph=graph.createSubgraph(info);subgraph.configure(info);results.subgraphs.set(originalId,subgraph)}for(const info of parsed.groups){info.id=-1;const group=new LGraphGroup;group.configure(info);graph.add(group);created.push(group)}for(const info of parsed.nodes){const subgraph=results.subgraphs.get(info.type);if(subgraph)info.type=subgraph.id;const node2=info.type==null?null:LiteGraph.createNode(info.type);if(!node2){continue}nodes.set(info.id,node2);info.id=-1;node2.configure(info);graph.add(node2);created.push(node2)}for(const info of parsed.reroutes){const{id,...rerouteInfo}=info;const reroute=graph.setReroute(rerouteInfo);created.push(reroute);reroutes.set(id,reroute)}for(const reroute of reroutes.values()){if(reroute.parentId==null)continue;const mapped=reroutes.get(reroute.parentId);if(mapped)reroute.parentId=mapped.id}for(const info of parsed.links){let outNode=nodes.get(info.origin_id);let afterRerouteId;if(info.parentId!=null)afterRerouteId=reroutes.get(info.parentId)?.id;if(connectInputs&&LiteGraph.ctrl_shift_v_paste_connect_unselected_outputs){outNode??=graph.getNodeById(info.origin_id);afterRerouteId??=info.parentId}const inNode=nodes.get(info.target_id);if(inNode){const link=outNode?.connect(info.origin_slot,inNode,info.target_slot,afterRerouteId);if(link)links.set(info.id,link)}}for(const reroute of reroutes.values()){const ids=[...reroute.linkIds].map(x2=>links.get(x2)?.id??x2);reroute.update(reroute.parentId,void 0,ids,reroute.floating);if(!reroute.validateLinks(graph.links,graph.floatingLinks)){graph.removeReroute(reroute.id)}}for(const item of created){item.pos[0]+=position[0]-offsetX;item.pos[1]+=position[1]-offsetY}this.selectItems(created);graph.afterChange();return results}pasteFromClipboard(options={}){this.emitBeforeChange();try{this._pasteFromClipboard(options)}finally{this.emitAfterChange()}}processNodeDblClicked(n){this.onShowNodePanel?.(n);this.onNodeDblClicked?.(n);this.setDirty(true)}#handleMultiSelect(e2,dragRect){const{graph,selectedItems,subgraph}=this;if(!graph)throw new NullGraphError;const w=Math.abs(dragRect[2]);const h=Math.abs(dragRect[3]);if(dragRect[2]<0)dragRect[0]-=w;if(dragRect[3]<0)dragRect[1]-=h;dragRect[2]=w;dragRect[3]=h;const isSelected=new Set;const notSelected=[];if(subgraph){const{inputNode,outputNode}=subgraph;if(overlapBounding(dragRect,inputNode.boundingRect)){addPositionable(inputNode)}if(overlapBounding(dragRect,outputNode.boundingRect)){addPositionable(outputNode)}}for(const nodeX of graph._nodes){if(overlapBounding(dragRect,nodeX.boundingRect)){addPositionable(nodeX)}}for(const group of graph.groups){if(!containsRect(dragRect,group._bounding))continue;group.recomputeInsideNodes();addPositionable(group)}for(const reroute of graph.reroutes.values()){if(!isPointInRect(reroute.pos,dragRect))continue;selectedItems.add(reroute);reroute.selected=true;addPositionable(reroute)}if(e2.shiftKey){for(const item of notSelected)this.select(item)}else if(e2.altKey){for(const item of isSelected)this.deselect(item)}else{for(const item of selectedItems.values()){if(!isSelected.has(item))this.deselect(item)}for(const item of notSelected)this.select(item)}this.onSelectionChange?.(this.selected_nodes);function addPositionable(item){if(!item.selected||!selectedItems.has(item))notSelected.push(item);else isSelected.add(item)}}processSelect(item,e2,sticky=false){const addModifier=e2?.shiftKey;const subtractModifier=e2!=null&&(e2.metaKey||e2.ctrlKey);const eitherModifier=addModifier||subtractModifier;const modifySelection=eitherModifier||this.multi_select;if(!item){if(!eitherModifier||this.multi_select)this.deselectAll()}else if(!item.selected||!this.selectedItems.has(item)){if(!modifySelection)this.deselectAll(item);this.select(item)}else if(modifySelection&&!sticky){this.deselect(item)}else if(!sticky){this.deselectAll(item)}else{return}this.onSelectionChange?.(this.selected_nodes);this.setDirty(true)}select(item){if(item.selected&&this.selectedItems.has(item))return;item.selected=true;this.selectedItems.add(item);this.state.selectionChanged=true;if(!(item instanceof LGraphNode))return;item.onSelected?.();this.selected_nodes[item.id]=item;this.onNodeSelected?.(item);if(item.inputs){for(const input of item.inputs){if(input.link==null)continue;this.highlighted_links[input.link]=true}}if(item.outputs){for(const id of item.outputs.flatMap(x2=>x2.links)){if(id==null)continue;this.highlighted_links[id]=true}}}deselect(item){if(!item.selected&&!this.selectedItems.has(item))return;item.selected=false;this.selectedItems.delete(item);this.state.selectionChanged=true;if(!(item instanceof LGraphNode))return;item.onDeselected?.();delete this.selected_nodes[item.id];this.onNodeDeselected?.(item);const{graph}=this;if(!graph)return;if(item.inputs){for(const input of item.inputs){if(input.link==null)continue;const node2=LLink.getOriginNode(graph,input.link);if(node2&&this.selectedItems.has(node2))continue;delete this.highlighted_links[input.link]}}if(item.outputs){for(const id of item.outputs.flatMap(x2=>x2.links)){if(id==null)continue;const node2=LLink.getTargetNode(graph,id);if(node2&&this.selectedItems.has(node2))continue;delete this.highlighted_links[id]}}}processNodeSelected(item,e2){this.processSelect(item,e2,e2&&(e2.shiftKey||e2.metaKey||e2.ctrlKey||this.multi_select))}selectNode(node2,add_to_current_selection){if(node2==null){this.deselectAll()}else{this.selectNodes([node2],add_to_current_selection)}}get empty(){if(!this.graph)throw new NullGraphError;return this.graph.empty}get positionableItems(){if(!this.graph)throw new NullGraphError;return this.graph.positionableItems()}selectItems(items,add_to_current_selection){const itemsToSelect=items??this.positionableItems;if(!add_to_current_selection)this.deselectAll();for(const item of itemsToSelect)this.select(item);this.onSelectionChange?.(this.selected_nodes);this.setDirty(true)}selectNodes(nodes,add_to_current_selection){this.selectItems(nodes,add_to_current_selection)}deselectNode(node2){this.deselect(node2)}deselectAll(keepSelected){if(!this.graph)return;const selected=this.selectedItems;if(!selected.size)return;let wasSelected;for(const sel of selected){if(sel===keepSelected){wasSelected=sel;continue}sel.onDeselected?.();sel.selected=false}selected.clear();if(wasSelected)selected.add(wasSelected);this.setDirty(true);const oldNode=keepSelected?.id==null?null:this.selected_nodes[keepSelected.id];this.selected_nodes={};this.current_node=null;this.highlighted_links={};if(keepSelected instanceof LGraphNode){if(oldNode)this.selected_nodes[oldNode.id]=oldNode;if(keepSelected.inputs){for(const input of keepSelected.inputs){if(input.link==null)continue;this.highlighted_links[input.link]=true}}if(keepSelected.outputs){for(const id of keepSelected.outputs.flatMap(x2=>x2.links)){if(id==null)continue;this.highlighted_links[id]=true}}}this.state.selectionChanged=true;this.onSelectionChange?.(this.selected_nodes)}deselectAllNodes(){this.deselectAll()}deleteSelected(){const{graph}=this;if(!graph)throw new NullGraphError;this.emitBeforeChange();graph.beforeChange();for(const item of this.selectedItems){if(item instanceof LGraphNode){const node2=item;if(node2.block_delete)continue;node2.connectInputToOutput();graph.remove(node2);this.onNodeDeselected?.(node2)}else if(item instanceof LGraphGroup){graph.remove(item)}else if(item instanceof Reroute){graph.removeReroute(item.id)}}this.selected_nodes={};this.selectedItems.clear();this.current_node=null;this.highlighted_links={};this.state.selectionChanged=true;this.onSelectionChange?.(this.selected_nodes);this.setDirty(true);graph.afterChange();this.emitAfterChange()}deleteSelectedNodes(){this.deleteSelected()}centerOnNode(node2){const dpi=window?.devicePixelRatio||1;this.ds.offset[0]=-node2.pos[0]-node2.size[0]*.5+this.canvas.width*.5/(this.ds.scale*dpi);this.ds.offset[1]=-node2.pos[1]-node2.size[1]*.5+this.canvas.height*.5/(this.ds.scale*dpi);this.setDirty(true,true)}adjustMouseEvent(e2){let clientX_rel=e2.clientX;let clientY_rel=e2.clientY;if(this.canvas){const b=this.canvas.getBoundingClientRect();clientX_rel-=b.left;clientY_rel-=b.top}e2.safeOffsetX=clientX_rel;e2.safeOffsetY=clientY_rel;if(e2.deltaX===void 0)e2.deltaX=clientX_rel-this.last_mouse_position[0];if(e2.deltaY===void 0)e2.deltaY=clientY_rel-this.last_mouse_position[1];this.last_mouse_position[0]=clientX_rel;this.last_mouse_position[1]=clientY_rel;e2.canvasX=clientX_rel/this.ds.scale-this.ds.offset[0];e2.canvasY=clientY_rel/this.ds.scale-this.ds.offset[1]}setZoom(value,zooming_center){this.ds.changeScale(value,zooming_center);this.#dirty()}convertOffsetToCanvas(pos,out){return this.ds.convertOffsetToCanvas(pos,out)}convertCanvasToOffset(pos,out){return this.ds.convertCanvasToOffset(pos,out)}convertEventToCanvasOffset(e2){const rect=this.canvas.getBoundingClientRect();return this.convertCanvasToOffset([e2.clientX-rect.left,e2.clientY-rect.top])}bringToFront(node2){const{graph}=this;if(!graph)throw new NullGraphError;const i=graph._nodes.indexOf(node2);if(i==-1)return;graph._nodes.splice(i,1);graph._nodes.push(node2)}sendToBack(node2){const{graph}=this;if(!graph)throw new NullGraphError;const i=graph._nodes.indexOf(node2);if(i==-1)return;graph._nodes.splice(i,1);graph._nodes.unshift(node2)}computeVisibleNodes(nodes,out){const visible_nodes=out||[];visible_nodes.length=0;if(!this.graph)throw new NullGraphError;const _nodes=nodes||this.graph._nodes;for(const node2 of _nodes){node2.updateArea(this.ctx);if(!overlapBounding(this.visible_area,node2.renderArea))continue;visible_nodes.push(node2)}return visible_nodes}isNodeVisible(node2){return this.#visible_node_ids.has(node2.id)}draw(force_canvas,force_bgcanvas){if(!this.canvas||this.canvas.width==0||this.canvas.height==0)return;const now=LiteGraph.getTime();this.render_time=(now-this.last_draw_time)*.001;this.last_draw_time=now;if(this.graph)this.ds.computeVisibleArea(this.viewport);if(this.dirty_canvas||force_canvas){this.computeVisibleNodes(void 0,this.visible_nodes);this.#visible_node_ids=new Set(this.visible_nodes.map(node2=>node2.id));const{subgraph}=this;if(subgraph){subgraph.inputNode.arrange();subgraph.outputNode.arrange()}}if(this.dirty_bgcanvas||force_bgcanvas||this.always_render_background||this.graph?._last_trigger_time&&now-this.graph._last_trigger_time<1e3){this.drawBackCanvas()}if(this.dirty_canvas||force_canvas)this.drawFrontCanvas();this.fps=this.render_time?1/this.render_time:0;this.frame++}drawFrontCanvas(){this.dirty_canvas=false;const{ctx,canvas:canvas2,graph,linkConnector}=this;if(ctx.start2D&&!this.viewport){ctx.start2D();ctx.restore();ctx.setTransform(1,0,0,1,0,0)}const area=this.viewport||this.dirty_area;if(area){ctx.save();ctx.beginPath();ctx.rect(area[0],area[1],area[2],area[3]);ctx.clip()}this.#snapToGrid=this.#shiftDown||LiteGraph.alwaysSnapToGrid?this.graph?.getSnapToGridSize():void 0;if(this.clear_background){if(area)ctx.clearRect(area[0],area[1],area[2],area[3]);else ctx.clearRect(0,0,canvas2.width,canvas2.height)}if(this.bgcanvas==this.canvas){this.drawBackCanvas()}else{const scale=window.devicePixelRatio;ctx.drawImage(this.bgcanvas,0,0,this.bgcanvas.width/scale,this.bgcanvas.height/scale)}this.onRender?.(canvas2,ctx);if(this.show_info){this.renderInfo(ctx,area?area[0]:0,area?area[1]:0)}if(graph){ctx.save();this.ds.toCanvasContext(ctx);const{visible_nodes}=this;const drawSnapGuides=this.#snapToGrid&&this.isDragging;for(const node2 of visible_nodes){ctx.save();if(drawSnapGuides&&this.selectedItems.has(node2))this.drawSnapGuide(ctx,node2);ctx.translate(node2.pos[0],node2.pos[1]);this.drawNode(node2,ctx);ctx.restore()}this.subgraph?.draw(ctx,this.colourGetter,this.linkConnector.renderLinks[0]?.fromSlot,this.editor_alpha);if(this.render_execution_order){this.drawExecutionOrder(ctx)}if(graph.config.links_ontop){this.drawConnections(ctx)}if(linkConnector.isConnecting){const{renderLinks}=linkConnector;const highlightPos=this.#getHighlightPosition();ctx.lineWidth=this.connections_width;for(const renderLink of renderLinks){const{fromSlot,fromPos:pos,fromDirection,dragDirection}=renderLink;const connShape=fromSlot.shape;const connType=fromSlot.type;const colour=connType===LiteGraph.EVENT?LiteGraph.EVENT_LINK_COLOR:LiteGraph.CONNECTING_LINK_COLOR;this.renderLink(ctx,pos,highlightPos,null,false,null,colour,fromDirection,dragDirection);ctx.beginPath();if(connType===LiteGraph.EVENT||connShape===RenderShape.BOX){ctx.rect(pos[0]-6+.5,pos[1]-5+.5,14,10);ctx.rect(highlightPos[0]-6+.5,highlightPos[1]-5+.5,14,10)}else if(connShape===RenderShape.ARROW){ctx.moveTo(pos[0]+8,pos[1]+.5);ctx.lineTo(pos[0]-4,pos[1]+6+.5);ctx.lineTo(pos[0]-4,pos[1]-6+.5);ctx.closePath()}else{ctx.arc(pos[0],pos[1],4,0,Math.PI*2);ctx.arc(highlightPos[0],highlightPos[1],4,0,Math.PI*2)}ctx.fill()}this.#renderSnapHighlight(ctx,highlightPos)}if(this.dragging_rectangle){const{eDown,eMove}=this.pointer;ctx.strokeStyle="#FFF";if(eDown&&eMove){const transform=ctx.getTransform();const ratio=Math.max(1,window.devicePixelRatio);ctx.setTransform(ratio,0,0,ratio,0,0);const x2=eDown.safeOffsetX;const y=eDown.safeOffsetY;ctx.strokeRect(x2,y,eMove.safeOffsetX-x2,eMove.safeOffsetY-y);ctx.setTransform(transform)}else{const[x2,y,w,h]=this.dragging_rectangle;ctx.strokeRect(x2,y,w,h)}}if(!this.isDragging&&this.over_link_center&&this.render_link_tooltip){this.drawLinkTooltip(ctx,this.over_link_center)}else{this.onDrawLinkTooltip?.(ctx,null)}this.onDrawForeground?.(ctx,this.visible_area);ctx.restore()}this.onDrawOverlay?.(ctx);if(area)ctx.restore()}#getLinkCentreOnPos(e2){for(const linkSegment of this.renderedPaths){const centre=linkSegment._pos;if(!centre)continue;if(isInRectangle(e2.canvasX,e2.canvasY,centre[0]-4,centre[1]-4,8,8)){return linkSegment}}}#getHighlightPosition(){return LiteGraph.snaps_for_comfy?this.linkConnector.state.snapLinksPos??this._highlight_pos??this.graph_mouse:this.graph_mouse}#renderSnapHighlight(ctx,highlightPos){const linkConnectorSnap=!!this.linkConnector.state.snapLinksPos;if(!this._highlight_pos&&!linkConnectorSnap)return;ctx.fillStyle="#ffcc00";ctx.beginPath();const shape=this._highlight_input?.shape;if(shape===RenderShape.ARROW){ctx.moveTo(highlightPos[0]+8,highlightPos[1]+.5);ctx.lineTo(highlightPos[0]-4,highlightPos[1]+6+.5);ctx.lineTo(highlightPos[0]-4,highlightPos[1]-6+.5);ctx.closePath()}else{ctx.arc(highlightPos[0],highlightPos[1],6,0,Math.PI*2)}ctx.fill();const{linkConnector}=this;const{overReroute,overWidget}=linkConnector;if(!LiteGraph.snap_highlights_node||!linkConnector.isConnecting||linkConnectorSnap)return;overReroute?.drawHighlight(ctx,"#ffcc00aa");const node2=this.node_over;if(!node2)return;const{strokeStyle,lineWidth}=ctx;const area=node2.boundingRect;const gap=3;const radius=LiteGraph.ROUND_RADIUS+gap;const x2=area[0]-gap;const y=area[1]-gap;const width2=area[2]+gap*2;const height=area[3]+gap*2;ctx.beginPath();ctx.roundRect(x2,y,width2,height,radius);const start=linkConnector.state.connectingTo==="output"?0:1;const inverter=start?-1:1;const hx=highlightPos[0];const hy=highlightPos[1];const gRadius=width2<height?width2:width2*Math.max(height/width2,.5);const gradient=ctx.createRadialGradient(hx,hy,0,hx,hy,gRadius);gradient.addColorStop(1,"#00000000");gradient.addColorStop(0,"#ffcc00aa");const linearGradient=ctx.createLinearGradient(x2,y,x2+width2,y);linearGradient.addColorStop(.5,"#00000000");linearGradient.addColorStop(start+.67*inverter,"#ddeeff33");linearGradient.addColorStop(start+inverter,"#ffcc0055");ctx.setLineDash([radius,radius*.001]);ctx.lineWidth=1;ctx.strokeStyle=linearGradient;ctx.stroke();if(overWidget){const{computedHeight}=overWidget;ctx.beginPath();const{pos:[nodeX,nodeY]}=node2;const height2=LiteGraph.NODE_WIDGET_HEIGHT;if(overWidget.type.startsWith("custom")&&computedHeight!=null&&computedHeight>height2*2){ctx.rect(nodeX+9,nodeY+overWidget.y+9,(overWidget.width??area[2])-18,computedHeight-18)}else{ctx.roundRect(nodeX+BaseWidget.margin,nodeY+overWidget.y,overWidget.width??area[2],height2,height2*.5)}ctx.stroke()}ctx.strokeStyle=gradient;ctx.stroke();ctx.setLineDash([]);ctx.lineWidth=lineWidth;ctx.strokeStyle=strokeStyle}renderInfo(ctx,x2,y){x2=x2||10;y=y||this.canvas.offsetHeight-80;ctx.save();ctx.translate(x2,y);ctx.font=`10px ${LiteGraph.DEFAULT_FONT}`;ctx.fillStyle="#888";ctx.textAlign="left";if(this.graph){ctx.fillText(`T: ${this.graph.globaltime.toFixed(2)}s`,5,13*1);ctx.fillText(`I: ${this.graph.iteration}`,5,13*2);ctx.fillText(`N: ${this.graph._nodes.length} [${this.visible_nodes.length}]`,5,13*3);ctx.fillText(`V: ${this.graph._version}`,5,13*4);ctx.fillText(`FPS:${this.fps.toFixed(2)}`,5,13*5)}else{ctx.fillText("No graph selected",5,13*1)}ctx.restore()}drawBackCanvas(){const canvas2=this.bgcanvas;if(canvas2.width!=this.canvas.width||canvas2.height!=this.canvas.height){canvas2.width=this.canvas.width;canvas2.height=this.canvas.height}if(!this.bgctx){this.bgctx=this.bgcanvas.getContext("2d")}const ctx=this.bgctx;if(!ctx)throw new TypeError("Background canvas context was null.");const viewport=this.viewport||[0,0,ctx.canvas.width,ctx.canvas.height];if(this.clear_background){ctx.clearRect(viewport[0],viewport[1],viewport[2],viewport[3])}const bg_already_painted=this.onRenderBackground?this.onRenderBackground(canvas2,ctx):false;if(!this.viewport){const scale=window.devicePixelRatio;ctx.restore();ctx.setTransform(scale,0,0,scale,0,0)}if(this.graph){ctx.save();this.ds.toCanvasContext(ctx);if(this.ds.scale<1.5&&!bg_already_painted&&this.clear_background_color){ctx.fillStyle=this.clear_background_color;ctx.fillRect(this.visible_area[0],this.visible_area[1],this.visible_area[2],this.visible_area[3])}if(this.background_image&&this.ds.scale>.5&&!bg_already_painted){if(this.zoom_modify_alpha){ctx.globalAlpha=(1-.5/this.ds.scale)*this.editor_alpha}else{ctx.globalAlpha=this.editor_alpha}ctx.imageSmoothingEnabled=false;if(!this._bg_img||this._bg_img.name!=this.background_image){this._bg_img=new Image;this._bg_img.name=this.background_image;this._bg_img.src=this.background_image;const that=this;this._bg_img.addEventListener("load",function(){that.draw(true,true)})}let pattern=this._pattern;if(pattern==null&&this._bg_img.width>0){pattern=ctx.createPattern(this._bg_img,"repeat")??void 0;this._pattern_img=this._bg_img;this._pattern=pattern}if(pattern){ctx.fillStyle=pattern;ctx.fillRect(this.visible_area[0],this.visible_area[1],this.visible_area[2],this.visible_area[3]);ctx.fillStyle="transparent"}ctx.globalAlpha=1;ctx.imageSmoothingEnabled=true}if(this.graph._groups.length){this.drawGroups(canvas2,ctx)}this.onDrawBackground?.(ctx,this.visible_area);if(this.render_canvas_border){ctx.strokeStyle="#235";ctx.strokeRect(0,0,canvas2.width,canvas2.height)}if(this.render_connections_shadows){ctx.shadowColor="#000";ctx.shadowOffsetX=0;ctx.shadowOffsetY=0;ctx.shadowBlur=6}else{ctx.shadowColor="rgba(0,0,0,0)"}this.drawConnections(ctx);ctx.shadowColor="rgba(0,0,0,0)";ctx.restore()}this.dirty_bgcanvas=false;this.dirty_canvas=true}drawNode(node2,ctx){this.current_node=node2;const color=node2.renderingColor;const bgcolor=node2.renderingBgColor;const{low_quality,editor_alpha}=this;ctx.globalAlpha=editor_alpha;if(this.render_shadows&&!low_quality){ctx.shadowColor=LiteGraph.DEFAULT_SHADOW_COLOR;ctx.shadowOffsetX=2*this.ds.scale;ctx.shadowOffsetY=2*this.ds.scale;ctx.shadowBlur=3*this.ds.scale}else{ctx.shadowColor="transparent"}if(node2.flags.collapsed&&node2.onDrawCollapsed?.(ctx,this)==true)return;const shape=node2._shape||RenderShape.BOX;const size=LGraphCanvas.#temp_vec2;size.set(node2.renderingSize);if(node2.collapsed){ctx.font=this.inner_text_font}if(node2.clip_area){ctx.save();ctx.beginPath();if(shape==RenderShape.BOX){ctx.rect(0,0,size[0],size[1])}else if(shape==RenderShape.ROUND){ctx.roundRect(0,0,size[0],size[1],[10])}else if(shape==RenderShape.CIRCLE){ctx.arc(size[0]*.5,size[1]*.5,size[0]*.5,0,Math.PI*2)}ctx.clip()}this.drawNodeShape(node2,ctx,size,color,bgcolor,!!node2.selected);if(node2.title_buttons&&!node2.flags.collapsed){const title_height=LiteGraph.NODE_TITLE_HEIGHT;let current_x=size[0];for(let i=0;i<node2.title_buttons.length;i++){const button=node2.title_buttons[i];if(!button.visible){continue}const button_width=button.getWidth(ctx);current_x-=button_width;const button_y=-title_height+(title_height-button.height)/2;button.draw(ctx,current_x,button_y);current_x-=2}}if(!low_quality){node2.drawBadges(ctx)}ctx.shadowColor="transparent";ctx.strokeStyle=LiteGraph.NODE_BOX_OUTLINE_COLOR;node2.onDrawForeground?.(ctx,this,this.canvas);ctx.font=this.inner_text_font;node2._setConcreteSlots();if(!node2.collapsed){node2.arrange();node2.drawSlots(ctx,{fromSlot:this.linkConnector.renderLinks[0]?.fromSlot,colorContext:this.colourGetter,editorAlpha:this.editor_alpha,lowQuality:this.low_quality});ctx.textAlign="left";ctx.globalAlpha=1;this.drawNodeWidgets(node2,null,ctx)}else if(this.render_collapsed_slots){node2.drawCollapsedSlots(ctx)}if(node2.clip_area){ctx.restore()}ctx.globalAlpha=1}drawLinkTooltip(ctx,link){const pos=link._pos;ctx.fillStyle="black";ctx.beginPath();if(this.linkMarkerShape===LinkMarkerShape.Arrow){const transform=ctx.getTransform();ctx.translate(pos[0],pos[1]);if(Number.isFinite(link._centreAngle))ctx.rotate(link._centreAngle);ctx.moveTo(-2,-3);ctx.lineTo(4,0);ctx.lineTo(-2,3);ctx.setTransform(transform)}else if(this.linkMarkerShape==null||this.linkMarkerShape===LinkMarkerShape.Circle){ctx.arc(pos[0],pos[1],3,0,Math.PI*2)}ctx.fill();const{data}=link;if(data==null)return;if(this.onDrawLinkTooltip?.(ctx,link,this)==true)return;let text=null;if(typeof data==="number")text=data.toFixed(2);else if(typeof data==="string")text=`"${data}"`;else if(typeof data==="boolean")text=String(data);else if(data.toToolTip)text=data.toToolTip();else text=`[${data.constructor.name}]`;if(text==null)return;text=text.substring(0,30);ctx.font="14px Courier New";const info=ctx.measureText(text);const w=info.width+20;const h=24;ctx.shadowColor="black";ctx.shadowOffsetX=2;ctx.shadowOffsetY=2;ctx.shadowBlur=3;ctx.fillStyle="#454";ctx.beginPath();ctx.roundRect(pos[0]-w*.5,pos[1]-15-h,w,h,[3]);ctx.moveTo(pos[0]-10,pos[1]-15);ctx.lineTo(pos[0]+10,pos[1]-15);ctx.lineTo(pos[0],pos[1]-5);ctx.fill();ctx.shadowColor="transparent";ctx.textAlign="center";ctx.fillStyle="#CEC";ctx.fillText(text,pos[0],pos[1]-15-h*.3)}drawNodeShape(node2,ctx,size,fgcolor,bgcolor,_selected){ctx.strokeStyle=fgcolor;ctx.fillStyle=bgcolor;const title_height=LiteGraph.NODE_TITLE_HEIGHT;const{low_quality}=this;const{collapsed}=node2.flags;const shape=node2.renderingShape;const{title_mode}=node2;const render_title=title_mode==TitleMode.TRANSPARENT_TITLE||title_mode==TitleMode.NO_TITLE?false:true;const area=LGraphCanvas.#tmp_area;area.set(node2.boundingRect);area[0]-=node2.pos[0];area[1]-=node2.pos[1];const old_alpha=ctx.globalAlpha;ctx.beginPath();if(shape==RenderShape.BOX||low_quality){ctx.rect(area[0],area[1],area[2],area[3])}else if(shape==RenderShape.ROUND||shape==RenderShape.CARD){ctx.roundRect(area[0],area[1],area[2],area[3],shape==RenderShape.CARD?[LiteGraph.ROUND_RADIUS,LiteGraph.ROUND_RADIUS,0,0]:[LiteGraph.ROUND_RADIUS])}else if(shape==RenderShape.CIRCLE){ctx.arc(size[0]*.5,size[1]*.5,size[0]*.5,0,Math.PI*2)}ctx.fill();if(!collapsed&&render_title){ctx.shadowColor="transparent";ctx.fillStyle="rgba(0,0,0,0.2)";ctx.fillRect(0,-1,area[2],2)}ctx.shadowColor="transparent";node2.onDrawBackground?.(ctx);if(render_title||title_mode==TitleMode.TRANSPARENT_TITLE){node2.drawTitleBarBackground(ctx,{scale:this.ds.scale,low_quality});node2.drawTitleBox(ctx,{scale:this.ds.scale,low_quality,box_size:10});ctx.globalAlpha=old_alpha;node2.drawTitleText(ctx,{scale:this.ds.scale,default_title_color:this.node_title_color,low_quality});node2.onDrawTitle?.(ctx)}for(const getStyle of Object.values(node2.strokeStyles)){const strokeStyle=getStyle.call(node2);if(strokeStyle){strokeShape(ctx,area,{shape,title_height,title_mode,collapsed,...strokeStyle})}}node2.drawProgressBar(ctx);if(node2.execute_triggered!=null&&node2.execute_triggered>0)node2.execute_triggered--;if(node2.action_triggered!=null&&node2.action_triggered>0)node2.action_triggered--}drawSnapGuide(ctx,item,shape=RenderShape.ROUND){const snapGuide=LGraphCanvas.#temp;snapGuide.set(item.boundingRect);const{pos}=item;const offsetX=pos[0]-snapGuide[0];const offsetY=pos[1]-snapGuide[1];snapGuide[0]+=offsetX;snapGuide[1]+=offsetY;if(this.#snapToGrid)snapPoint(snapGuide,this.#snapToGrid);snapGuide[0]-=offsetX;snapGuide[1]-=offsetY;const{globalAlpha}=ctx;ctx.globalAlpha=1;ctx.beginPath();const[x2,y,w,h]=snapGuide;if(shape===RenderShape.CIRCLE){const midX=x2+w*.5;const midY=y+h*.5;const radius=Math.min(w*.5,h*.5);ctx.arc(midX,midY,radius,0,Math.PI*2)}else{ctx.rect(x2,y,w,h)}ctx.lineWidth=.5;ctx.strokeStyle="#FFFFFF66";ctx.fillStyle="#FFFFFF22";ctx.fill();ctx.stroke();ctx.globalAlpha=globalAlpha}drawConnections(ctx){this.renderedPaths.clear();if(this.links_render_mode===LinkRenderType.HIDDEN_LINK)return;const{graph,subgraph}=this;if(!graph)throw new NullGraphError;const visibleReroutes=[];const now=LiteGraph.getTime();const{visible_area}=this;LGraphCanvas.#margin_area[0]=visible_area[0]-20;LGraphCanvas.#margin_area[1]=visible_area[1]-20;LGraphCanvas.#margin_area[2]=visible_area[2]+40;LGraphCanvas.#margin_area[3]=visible_area[3]+40;ctx.lineWidth=this.connections_width;ctx.fillStyle="#AAA";ctx.strokeStyle="#AAA";ctx.globalAlpha=this.editor_alpha;const nodes=graph._nodes;for(const node2 of nodes){const{inputs}=node2;if(!inputs?.length)continue;for(const[i,input]of inputs.entries()){if(!input||input.link==null)continue;const link_id=input.link;const link=graph._links.get(link_id);if(!link)continue;const endPos=node2.getInputPos(i);const start_node=graph.getNodeById(link.origin_id);if(start_node==null)continue;const outputId=link.origin_slot;const startPos=outputId===-1?[start_node.pos[0]+10,start_node.pos[1]+10]:start_node.getOutputPos(outputId);const output=start_node.outputs[outputId];if(!output)continue;this.#renderAllLinkSegments(ctx,link,startPos,endPos,visibleReroutes,now,output.dir,input.dir)}}if(subgraph){for(const output of subgraph.inputNode.slots){if(!output.linkIds.length)continue;for(const linkId of output.linkIds){const resolved=LLink.resolve(linkId,graph);if(!resolved)continue;const{link,inputNode,input}=resolved;if(!inputNode||!input)continue;const endPos=inputNode.getInputPos(link.target_slot);this.#renderAllLinkSegments(ctx,link,output.pos,endPos,visibleReroutes,now,input.dir,input.dir)}}for(const input of subgraph.outputNode.slots){if(!input.linkIds.length)continue;const resolved=LLink.resolve(input.linkIds[0],graph);if(!resolved)continue;const{link,outputNode,output}=resolved;if(!outputNode||!output)continue;const startPos=outputNode.getOutputPos(link.origin_slot);this.#renderAllLinkSegments(ctx,link,startPos,input.pos,visibleReroutes,now,output.dir,input.dir)}}if(graph.floatingLinks.size>0){this.#renderFloatingLinks(ctx,graph,visibleReroutes,now)}const rerouteSet=this.#visibleReroutes;rerouteSet.clear();visibleReroutes.sort((a,b)=>a.linkIds.size-b.linkIds.size);for(const reroute of visibleReroutes){rerouteSet.add(reroute);if(this.#snapToGrid&&this.isDragging&&this.selectedItems.has(reroute)){this.drawSnapGuide(ctx,reroute,RenderShape.CIRCLE)}reroute.draw(ctx,this._pattern);if(!this.pointer.isDown)reroute.drawSlots(ctx)}ctx.globalAlpha=1}#renderFloatingLinks(ctx,graph,visibleReroutes,now){const{globalAlpha}=ctx;ctx.globalAlpha=globalAlpha*.33;for(const link of graph.floatingLinks.values()){const reroutes=LLink.getReroutes(graph,link);const firstReroute=reroutes[0];const reroute=reroutes.at(-1);if(!firstReroute||!reroute?.floating)continue;if(reroute.floating.slotType==="input"){const node2=graph.getNodeById(link.target_id);if(!node2)continue;const startPos=firstReroute.pos;const endPos=node2.getInputPos(link.target_slot);const endDirection=node2.inputs[link.target_slot]?.dir;firstReroute._dragging=true;this.#renderAllLinkSegments(ctx,link,startPos,endPos,visibleReroutes,now,LinkDirection.CENTER,endDirection,true)}else{const node2=graph.getNodeById(link.origin_id);if(!node2)continue;const startPos=node2.getOutputPos(link.origin_slot);const endPos=reroute.pos;const startDirection=node2.outputs[link.origin_slot]?.dir;link._dragging=true;this.#renderAllLinkSegments(ctx,link,startPos,endPos,visibleReroutes,now,startDirection,LinkDirection.CENTER,true)}}ctx.globalAlpha=globalAlpha}#renderAllLinkSegments(ctx,link,startPos,endPos,visibleReroutes,now,startDirection,endDirection,disabled=false){const{graph,renderedPaths}=this;if(!graph)return;const reroutes=LLink.getReroutes(graph,link);const points=[startPos,...reroutes.map(x2=>x2.pos),endPos];const pointsX=points.map(x2=>x2[0]);const pointsY=points.map(x2=>x2[1]);LGraphCanvas.#link_bounding[0]=Math.min(...pointsX);LGraphCanvas.#link_bounding[1]=Math.min(...pointsY);LGraphCanvas.#link_bounding[2]=Math.max(...pointsX)-LGraphCanvas.#link_bounding[0];LGraphCanvas.#link_bounding[3]=Math.max(...pointsY)-LGraphCanvas.#link_bounding[1];if(!overlapBounding(LGraphCanvas.#link_bounding,LGraphCanvas.#margin_area))return;const start_dir=startDirection||LinkDirection.RIGHT;const end_dir=endDirection||LinkDirection.LEFT;if(reroutes.length){let startControl;const l=reroutes.length;for(let j=0;j<l;j++){const reroute=reroutes[j];if(!renderedPaths.has(reroute)){renderedPaths.add(reroute);visibleReroutes.push(reroute);reroute._colour=link.color||LGraphCanvas.link_type_colors[link.type]||this.default_link_color;const prevReroute=graph.getReroute(reroute.parentId);const rerouteStartPos=prevReroute?.pos??startPos;reroute.calculateAngle(this.last_draw_time,graph,rerouteStartPos);if(!reroute._dragging){this.renderLink(ctx,rerouteStartPos,reroute.pos,link,false,0,null,startControl===void 0?start_dir:LinkDirection.CENTER,LinkDirection.CENTER,{startControl,endControl:reroute.controlPoint,reroute,disabled})}}if(!startControl&&reroutes.at(-1)?.floating?.slotType==="input"){startControl=[0,0]}else{const nextPos=reroutes[j+1]?.pos??endPos;const dist=Math.min(Reroute.maxSplineOffset,distance(reroute.pos,nextPos)*.25);startControl=[dist*reroute.cos,dist*reroute.sin]}}if(link._dragging)return;const segmentStartPos=points.at(-2)??startPos;this.renderLink(ctx,segmentStartPos,endPos,link,false,0,null,LinkDirection.CENTER,end_dir,{startControl,disabled})}else if(!link._dragging){this.renderLink(ctx,startPos,endPos,link,false,0,null,start_dir,end_dir)}renderedPaths.add(link);if(link?._last_time&&now-link._last_time<1e3){const f=2-(now-link._last_time)*.002;const tmp=ctx.globalAlpha;ctx.globalAlpha=tmp*f;this.renderLink(ctx,startPos,endPos,link,true,f,"white",start_dir,end_dir);ctx.globalAlpha=tmp}}renderLink(ctx,a,b,link,skip_border,flow,color,start_dir,end_dir,{startControl,endControl,reroute,num_sublines=1,disabled=false}={}){const linkColour=link!=null&&this.highlighted_links[link.id]?"#FFF":color||link?.color||link?.type!=null&&LGraphCanvas.link_type_colors[link.type]||this.default_link_color;const startDir=start_dir||LinkDirection.RIGHT;const endDir=end_dir||LinkDirection.LEFT;const dist=this.links_render_mode==LinkRenderType.SPLINE_LINK&&(!endControl||!startControl)?distance(a,b):0;if(this.render_connections_border&&!this.low_quality){ctx.lineWidth=this.connections_width+4}ctx.lineJoin="round";num_sublines||=1;if(num_sublines>1)ctx.lineWidth=.5;const path=new Path2D;const linkSegment=reroute??link;if(linkSegment)linkSegment.path=path;const innerA=LGraphCanvas.#lTempA;const innerB=LGraphCanvas.#lTempB;const pos=linkSegment?._pos??[0,0];for(let i=0;i<num_sublines;i++){const offsety=(i-(num_sublines-1)*.5)*5;innerA[0]=a[0];innerA[1]=a[1];innerB[0]=b[0];innerB[1]=b[1];if(this.links_render_mode==LinkRenderType.SPLINE_LINK){if(endControl){innerB[0]=b[0]+endControl[0];innerB[1]=b[1]+endControl[1]}else{this.#addSplineOffset(innerB,endDir,dist)}if(startControl){innerA[0]=a[0]+startControl[0];innerA[1]=a[1]+startControl[1]}else{this.#addSplineOffset(innerA,startDir,dist)}path.moveTo(a[0],a[1]+offsety);path.bezierCurveTo(innerA[0],innerA[1]+offsety,innerB[0],innerB[1]+offsety,b[0],b[1]+offsety);findPointOnCurve(pos,a,b,innerA,innerB,.5);if(linkSegment&&this.linkMarkerShape===LinkMarkerShape.Arrow){const justPastCentre=LGraphCanvas.#lTempC;findPointOnCurve(justPastCentre,a,b,innerA,innerB,.51);linkSegment._centreAngle=Math.atan2(justPastCentre[1]-pos[1],justPastCentre[0]-pos[0])}}else{const l=this.links_render_mode==LinkRenderType.LINEAR_LINK?15:10;switch(startDir){case LinkDirection.LEFT:innerA[0]+=-l;break;case LinkDirection.RIGHT:innerA[0]+=l;break;case LinkDirection.UP:innerA[1]+=-l;break;case LinkDirection.DOWN:innerA[1]+=l;break}switch(endDir){case LinkDirection.LEFT:innerB[0]+=-l;break;case LinkDirection.RIGHT:innerB[0]+=l;break;case LinkDirection.UP:innerB[1]+=-l;break;case LinkDirection.DOWN:innerB[1]+=l;break}if(this.links_render_mode==LinkRenderType.LINEAR_LINK){path.moveTo(a[0],a[1]+offsety);path.lineTo(innerA[0],innerA[1]+offsety);path.lineTo(innerB[0],innerB[1]+offsety);path.lineTo(b[0],b[1]+offsety);pos[0]=(innerA[0]+innerB[0])*.5;pos[1]=(innerA[1]+innerB[1])*.5;if(linkSegment&&this.linkMarkerShape===LinkMarkerShape.Arrow){linkSegment._centreAngle=Math.atan2(innerB[1]-innerA[1],innerB[0]-innerA[0])}}else if(this.links_render_mode==LinkRenderType.STRAIGHT_LINK){const midX=(innerA[0]+innerB[0])*.5;path.moveTo(a[0],a[1]);path.lineTo(innerA[0],innerA[1]);path.lineTo(midX,innerA[1]);path.lineTo(midX,innerB[1]);path.lineTo(innerB[0],innerB[1]);path.lineTo(b[0],b[1]);pos[0]=midX;pos[1]=(innerA[1]+innerB[1])*.5;if(linkSegment&&this.linkMarkerShape===LinkMarkerShape.Arrow){const diff=innerB[1]-innerA[1];if(Math.abs(diff)<4)linkSegment._centreAngle=0;else if(diff>0)linkSegment._centreAngle=Math.PI*.5;else linkSegment._centreAngle=-(Math.PI*.5)}}else{return}}}if(this.render_connections_border&&!this.low_quality&&!skip_border){ctx.strokeStyle="rgba(0,0,0,0.5)";ctx.stroke(path)}ctx.lineWidth=this.connections_width;ctx.fillStyle=ctx.strokeStyle=linkColour;ctx.stroke(path);if(this.ds.scale>=.6&&this.highquality_render&&linkSegment){if(this.render_connection_arrows){const posA=this.computeConnectionPoint(a,b,.25,startDir,endDir);const posB=this.computeConnectionPoint(a,b,.26,startDir,endDir);const posC=this.computeConnectionPoint(a,b,.75,startDir,endDir);const posD=this.computeConnectionPoint(a,b,.76,startDir,endDir);let angleA=0;let angleB=0;if(this.render_curved_connections){angleA=-Math.atan2(posB[0]-posA[0],posB[1]-posA[1]);angleB=-Math.atan2(posD[0]-posC[0],posD[1]-posC[1])}else{angleB=angleA=b[1]>a[1]?0:Math.PI}const transform=ctx.getTransform();ctx.translate(posA[0],posA[1]);ctx.rotate(angleA);ctx.beginPath();ctx.moveTo(-5,-3);ctx.lineTo(0,7);ctx.lineTo(5,-3);ctx.fill();ctx.setTransform(transform);ctx.translate(posC[0],posC[1]);ctx.rotate(angleB);ctx.beginPath();ctx.moveTo(-5,-3);ctx.lineTo(0,7);ctx.lineTo(5,-3);ctx.fill();ctx.setTransform(transform)}ctx.beginPath();if(this.linkMarkerShape===LinkMarkerShape.Arrow){const transform=ctx.getTransform();ctx.translate(pos[0],pos[1]);if(linkSegment._centreAngle)ctx.rotate(linkSegment._centreAngle);ctx.moveTo(-3.2,-5);ctx.lineTo(7,0);ctx.lineTo(-3.2,5);ctx.setTransform(transform)}else if(this.linkMarkerShape==null||this.linkMarkerShape===LinkMarkerShape.Circle){ctx.arc(pos[0],pos[1],5,0,Math.PI*2)}if(disabled){const{fillStyle,globalAlpha}=ctx;ctx.fillStyle=this._pattern??"#797979";ctx.globalAlpha=.75;ctx.fill();ctx.globalAlpha=globalAlpha;ctx.fillStyle=fillStyle}ctx.fill();if(LLink._drawDebug){const{fillStyle,font,globalAlpha,lineWidth,strokeStyle}=ctx;ctx.globalAlpha=1;ctx.lineWidth=4;ctx.fillStyle="white";ctx.strokeStyle="black";ctx.font="16px Arial";const text=String(linkSegment.id);const{width:width2,actualBoundingBoxAscent}=ctx.measureText(text);const x2=pos[0]-width2*.5;const y=pos[1]+actualBoundingBoxAscent*.5;ctx.strokeText(text,x2,y);ctx.fillText(text,x2,y);ctx.font=font;ctx.globalAlpha=globalAlpha;ctx.lineWidth=lineWidth;ctx.fillStyle=fillStyle;ctx.strokeStyle=strokeStyle}}if(flow){ctx.fillStyle=linkColour;for(let i=0;i<5;++i){const f=(LiteGraph.getTime()*.001+i*.2)%1;const flowPos=this.computeConnectionPoint(a,b,f,startDir,endDir);ctx.beginPath();ctx.arc(flowPos[0],flowPos[1],5,0,2*Math.PI);ctx.fill()}}}computeConnectionPoint(a,b,t,start_dir,end_dir){start_dir||=LinkDirection.RIGHT;end_dir||=LinkDirection.LEFT;const dist=distance(a,b);const pa=[a[0],a[1]];const pb=[b[0],b[1]];this.#addSplineOffset(pa,start_dir,dist);this.#addSplineOffset(pb,end_dir,dist);const c1=(1-t)*(1-t)*(1-t);const c2=3*((1-t)*(1-t))*t;const c3=3*(1-t)*(t*t);const c4=t*t*t;const x2=c1*a[0]+c2*pa[0]+c3*pb[0]+c4*b[0];const y=c1*a[1]+c2*pa[1]+c3*pb[1]+c4*b[1];return[x2,y]}#addSplineOffset(point,direction,dist,factor=.25){switch(direction){case LinkDirection.LEFT:point[0]+=dist*-factor;break;case LinkDirection.RIGHT:point[0]+=dist*factor;break;case LinkDirection.UP:point[1]+=dist*-factor;break;case LinkDirection.DOWN:point[1]+=dist*factor;break}}drawExecutionOrder(ctx){ctx.shadowColor="transparent";ctx.globalAlpha=.25;ctx.textAlign="center";ctx.strokeStyle="white";ctx.globalAlpha=.75;const{visible_nodes}=this;for(const node2 of visible_nodes){ctx.fillStyle="black";ctx.fillRect(node2.pos[0]-LiteGraph.NODE_TITLE_HEIGHT,node2.pos[1]-LiteGraph.NODE_TITLE_HEIGHT,LiteGraph.NODE_TITLE_HEIGHT,LiteGraph.NODE_TITLE_HEIGHT);if(node2.order==0){ctx.strokeRect(node2.pos[0]-LiteGraph.NODE_TITLE_HEIGHT+.5,node2.pos[1]-LiteGraph.NODE_TITLE_HEIGHT+.5,LiteGraph.NODE_TITLE_HEIGHT,LiteGraph.NODE_TITLE_HEIGHT)}ctx.fillStyle="#FFF";ctx.fillText(stringOrEmpty(node2.order),node2.pos[0]+LiteGraph.NODE_TITLE_HEIGHT*-.5,node2.pos[1]-6)}ctx.globalAlpha=1}drawNodeWidgets(node2,_posY,ctx){node2.drawWidgets(ctx,{lowQuality:this.low_quality,editorAlpha:this.editor_alpha})}drawGroups(canvas2,ctx){if(!this.graph)return;const groups=this.graph._groups;ctx.save();ctx.globalAlpha=.5*this.editor_alpha;const drawSnapGuides=this.#snapToGrid&&this.isDragging;for(const group of groups){if(!overlapBounding(this.visible_area,group._bounding)){continue}if(drawSnapGuides&&this.selectedItems.has(group))this.drawSnapGuide(ctx,group);group.draw(this,ctx)}ctx.restore()}resize(width2,height){if(!width2&&!height){const parent=this.canvas.parentElement;if(!parent)throw new TypeError("Attempted to resize canvas, but parent element was null.");width2=parent.offsetWidth;height=parent.offsetHeight}if(this.canvas.width==width2&&this.canvas.height==height)return;this.canvas.width=width2??0;this.canvas.height=height??0;this.bgcanvas.width=this.canvas.width;this.bgcanvas.height=this.canvas.height;this.setDirty(true,true)}onNodeSelectionChange(){}boundaryNodesForSelection(){return LGraphCanvas.getBoundaryNodes(this.selected_nodes)}showLinkMenu(segment,e2){const{graph}=this;if(!graph)throw new NullGraphError;const title="data"in segment&&segment.data!=null?segment.data.constructor.name:void 0;const{origin_id,origin_slot}=segment;if(origin_id==null||origin_slot==null){new LiteGraph.ContextMenu(["Link has no origin"],{event:e2,title});return false}const node_left=graph.getNodeById(origin_id);const fromType=node_left?.outputs?.[origin_slot]?.type;const options=["Add Node","Add Reroute",null,"Delete",null];const menu=new LiteGraph.ContextMenu(options,{event:e2,title,callback:inner_clicked.bind(this)});return false;function inner_clicked(v2,options2,e22){if(!graph)throw new NullGraphError;switch(v2){case"Add Node":LGraphCanvas.onMenuAdd(null,null,e22,menu,node2=>{if(!node2?.inputs?.length||!node2?.outputs?.length||origin_slot==null)return;const options3={afterRerouteId:segment.parentId};if(node_left?.connectByType(origin_slot,node2,fromType??"*",options3)){node2.pos[0]-=node2.size[0]*.5}});break;case"Add Reroute":{try{this.emitBeforeChange();this.adjustMouseEvent(e22);graph.createReroute(segment._pos,segment);this.setDirty(false,true)}catch(error){console.error(error)}finally{this.emitAfterChange()}break}case"Delete":graph.removeLink(segment.id);break}}}createDefaultNodeForSlot(optPass){const opts=Object.assign({nodeFrom:null,slotFrom:null,nodeTo:null,slotTo:null,position:[0,0],nodeType:void 0,posAdd:[0,0],posSizeFix:[0,0]},optPass);const{afterRerouteId}=opts;const isFrom=opts.nodeFrom&&opts.slotFrom!==null;const isTo=!isFrom&&opts.nodeTo&&opts.slotTo!==null;if(!isFrom&&!isTo){console.warn(`No data passed to createDefaultNodeForSlot`,opts.nodeFrom,opts.slotFrom,opts.nodeTo,opts.slotTo);return false}if(!opts.nodeType){console.warn("No type to createDefaultNodeForSlot");return false}const nodeX=isFrom?opts.nodeFrom:opts.nodeTo;if(!nodeX)throw new TypeError("nodeX was null when creating default node for slot.");let slotX=isFrom?opts.slotFrom:opts.slotTo;let iSlotConn=false;if(nodeX instanceof SubgraphIONodeBase){if(typeof slotX!=="object"||!slotX){console.warn("Cant get slot information",slotX);return false}const{name}=slotX;iSlotConn=nodeX.slots.findIndex(s=>s.name===name);slotX=nodeX.slots[iSlotConn];if(!slotX){console.warn("Cant get slot information",slotX);return false}}else{switch(typeof slotX){case"string":iSlotConn=isFrom?nodeX.findOutputSlot(slotX,false):nodeX.findInputSlot(slotX,false);slotX=isFrom?nodeX.outputs[slotX]:nodeX.inputs[slotX];break;case"object":if(slotX===null){console.warn("Cant get slot information",slotX);return false}iSlotConn=isFrom?nodeX.findOutputSlot(slotX.name):nodeX.findInputSlot(slotX.name);break;case"number":iSlotConn=slotX;slotX=isFrom?nodeX.outputs[slotX]:nodeX.inputs[slotX];break;case"undefined":default:console.warn("Cant get slot information",slotX);return false}}const fromSlotType=slotX.type==LiteGraph.EVENT?"_event_":slotX.type;const slotTypesDefault=isFrom?LiteGraph.slot_types_default_out:LiteGraph.slot_types_default_in;if(slotTypesDefault?.[fromSlotType]){let nodeNewType=false;if(typeof slotTypesDefault[fromSlotType]=="object"){for(const typeX in slotTypesDefault[fromSlotType]){if(opts.nodeType==slotTypesDefault[fromSlotType][typeX]||opts.nodeType=="AUTO"){nodeNewType=slotTypesDefault[fromSlotType][typeX];break}}}else if(opts.nodeType==slotTypesDefault[fromSlotType]||opts.nodeType=="AUTO"){nodeNewType=slotTypesDefault[fromSlotType]}if(nodeNewType){let nodeNewOpts=false;if(typeof nodeNewType=="object"&&nodeNewType.node){nodeNewOpts=nodeNewType;nodeNewType=nodeNewType.node}const newNode=LiteGraph.createNode(nodeNewType);if(newNode){if(nodeNewOpts){if(nodeNewOpts.properties){for(const i in nodeNewOpts.properties){newNode.addProperty(i,nodeNewOpts.properties[i])}}if(nodeNewOpts.inputs){newNode.inputs=[];for(const i in nodeNewOpts.inputs){newNode.addOutput(nodeNewOpts.inputs[i][0],nodeNewOpts.inputs[i][1])}}if(nodeNewOpts.outputs){newNode.outputs=[];for(const i in nodeNewOpts.outputs){newNode.addOutput(nodeNewOpts.outputs[i][0],nodeNewOpts.outputs[i][1])}}if(nodeNewOpts.title){newNode.title=nodeNewOpts.title}if(nodeNewOpts.json){newNode.configure(nodeNewOpts.json)}}if(!this.graph)throw new NullGraphError;this.graph.add(newNode);newNode.pos=[opts.position[0]+opts.posAdd[0]+(opts.posSizeFix[0]?opts.posSizeFix[0]*newNode.size[0]:0),opts.position[1]+opts.posAdd[1]+(opts.posSizeFix[1]?opts.posSizeFix[1]*newNode.size[1]:0)];const detail={node:newNode,opts};const mayConnectLinks=this.canvas.dispatchEvent(new CustomEvent("connect-new-default-node",{detail,cancelable:true}));if(!mayConnectLinks)return true;if(isFrom){if(!opts.nodeFrom)throw new TypeError("createDefaultNodeForSlot - nodeFrom was null");opts.nodeFrom.connectByType(iSlotConn,newNode,fromSlotType,{afterRerouteId})}else{if(!opts.nodeTo)throw new TypeError("createDefaultNodeForSlot - nodeTo was null");opts.nodeTo.connectByTypeOutput(iSlotConn,newNode,fromSlotType,{afterRerouteId})}return true}console.log(`failed creating ${nodeNewType}`)}}return false}showConnectionMenu(optPass){const opts=Object.assign({nodeFrom:null,slotFrom:null,nodeTo:null,slotTo:null,e:void 0,allow_searchbox:this.allow_searchbox,showSearchBox:this.showSearchBox},optPass||{});const dirty=()=>this.#dirty();const that=this;const{graph}=this;const{afterRerouteId}=opts;const isFrom=opts.nodeFrom&&opts.slotFrom;const isTo=!isFrom&&opts.nodeTo&&opts.slotTo;if(!isFrom&&!isTo){console.warn("No data passed to showConnectionMenu");return}const nodeX=isFrom?opts.nodeFrom:opts.nodeTo;if(!nodeX)throw new TypeError("nodeX was null when creating default node for slot.");let slotX=isFrom?opts.slotFrom:opts.slotTo;let iSlotConn;if(nodeX instanceof SubgraphIONodeBase){if(typeof slotX!=="object"||!slotX){console.warn("Cant get slot information",slotX);return}const{name}=slotX;iSlotConn=nodeX.slots.findIndex(s=>s.name===name);if(iSlotConn!==-1){slotX=nodeX.slots[iSlotConn]}if(!slotX){console.warn("Cant get slot information",slotX);return}}else{switch(typeof slotX){case"string":iSlotConn=isFrom?nodeX.findOutputSlot(slotX,false):nodeX.findInputSlot(slotX,false);slotX=isFrom?nodeX.outputs[slotX]:nodeX.inputs[slotX];break;case"object":if(slotX===null){console.warn("Cant get slot information",slotX);return}iSlotConn=isFrom?nodeX.findOutputSlot(slotX.name):nodeX.findInputSlot(slotX.name);break;case"number":iSlotConn=slotX;slotX=isFrom?nodeX.outputs[slotX]:nodeX.inputs[slotX];break;default:console.warn("Cant get slot information",slotX);return}}const options=["Add Node","Add Reroute",null];if(opts.allow_searchbox){options.push("Search",null)}const fromSlotType=slotX.type==LiteGraph.EVENT?"_event_":slotX.type;const slotTypesDefault=isFrom?LiteGraph.slot_types_default_out:LiteGraph.slot_types_default_in;if(slotTypesDefault?.[fromSlotType]){if(typeof slotTypesDefault[fromSlotType]=="object"){for(const typeX in slotTypesDefault[fromSlotType]){options.push(slotTypesDefault[fromSlotType][typeX])}}else{options.push(slotTypesDefault[fromSlotType])}}const menu=new LiteGraph.ContextMenu(options,{event:opts.e,extra:slotX,title:(slotX&&slotX.name!=""?slotX.name+(fromSlotType?" | ":""):"")+(slotX&&fromSlotType?fromSlotType:""),callback:inner_clicked});return menu;function inner_clicked(v2,options2,e2){switch(v2){case"Add Node":LGraphCanvas.onMenuAdd(null,null,e2,menu,function(node2){if(!node2)return;if(isFrom){if(!opts.nodeFrom)throw new TypeError("Cannot add node to SubgraphInputNode: nodeFrom was null");const slot=opts.nodeFrom.connectByType(iSlotConn,node2,fromSlotType,{afterRerouteId});if(!slot)console.warn("Failed to make new connection.")}else{if(!opts.nodeTo)throw new TypeError("Cannot add node to SubgraphInputNode: nodeTo was null");opts.nodeTo.connectByTypeOutput(iSlotConn,node2,fromSlotType,{afterRerouteId})}});break;case"Add Reroute":{const node2=isFrom?opts.nodeFrom:opts.nodeTo;const slot=options2.extra;if(!graph)throw new NullGraphError;if(!node2)throw new TypeError("Cannot add reroute: node was null");if(!slot)throw new TypeError("Cannot add reroute: slot was null");if(!opts.e)throw new TypeError("Cannot add reroute: CanvasPointerEvent was null");if(node2 instanceof SubgraphIONodeBase){throw new TypeError("Cannot add floating reroute to Subgraph IO Nodes")}else{const reroute=node2.connectFloatingReroute([opts.e.canvasX,opts.e.canvasY],slot,afterRerouteId);if(!reroute)throw new Error("Failed to create reroute")}dirty();break}case"Search":if(isFrom){opts.showSearchBox(e2,{node_from:opts.nodeFrom,slot_from:slotX,type_filter_in:fromSlotType})}else{opts.showSearchBox(e2,{node_to:opts.nodeTo,slot_from:slotX,type_filter_out:fromSlotType})}break;default:{const customProps={position:[opts.e?.canvasX??0,opts.e?.canvasY??0],nodeType:v2,afterRerouteId};const options3=Object.assign(opts,customProps);if(!that.createDefaultNodeForSlot(options3))break}}}}prompt(title,value,callback,event,multiline){const that=this;title=title||"";const customProperties={is_modified:false,className:"graphdialog rounded",innerHTML:multiline?"<span class='name'></span> <textarea autofocus class='value'></textarea><button class='rounded'>OK</button>":"<span class='name'></span> <input autofocus type='text' class='value'/><button class='rounded'>OK</button>",close(){that.prompt_box=null;if(dialog.parentNode){dialog.remove()}}};const div=document.createElement("div");const dialog=Object.assign(div,customProperties);const graphcanvas=LGraphCanvas.active_canvas;const{canvas:canvas2}=graphcanvas;if(!canvas2.parentNode)throw new TypeError("canvas element parentNode was null when opening a prompt.");canvas2.parentNode.append(dialog);if(this.ds.scale>1)dialog.style.transform=`scale(${this.ds.scale})`;let dialogCloseTimer;let prevent_timeout=0;LiteGraph.pointerListenerAdd(dialog,"leave",function(){if(prevent_timeout)return;if(LiteGraph.dialog_close_on_mouse_leave){if(!dialog.is_modified&&LiteGraph.dialog_close_on_mouse_leave){dialogCloseTimer=setTimeout(dialog.close,LiteGraph.dialog_close_on_mouse_leave_delay)}}});LiteGraph.pointerListenerAdd(dialog,"enter",function(){if(LiteGraph.dialog_close_on_mouse_leave&&dialogCloseTimer)clearTimeout(dialogCloseTimer)});const selInDia=dialog.querySelectorAll("select");if(selInDia){for(const selIn of selInDia){selIn.addEventListener("click",function(){prevent_timeout++});selIn.addEventListener("blur",function(){prevent_timeout=0});selIn.addEventListener("change",function(){prevent_timeout=-1})}}this.prompt_box?.close();this.prompt_box=dialog;const name_element=dialog.querySelector(".name");if(!name_element)throw new TypeError("name_element was null");name_element.textContent=title;const value_element=dialog.querySelector(".value");if(!value_element)throw new TypeError("value_element was null");value_element.value=value;value_element.select();const input=value_element;input.addEventListener("keydown",function(e2){dialog.is_modified=true;if(e2.key=="Escape"){dialog.close()}else if(e2.key=="Enter"&&e2.target.localName!="textarea"){if(callback){callback(this.value)}dialog.close()}else{return}e2.preventDefault();e2.stopPropagation()});const button=dialog.querySelector("button");if(!button)throw new TypeError("button was null when opening prompt");button.addEventListener("click",function(){callback?.(input.value);that.setDirty(true);dialog.close()});const rect=canvas2.getBoundingClientRect();let offsetx=-20;let offsety=-20;if(rect){offsetx-=rect.left;offsety-=rect.top}if(event){dialog.style.left=`${event.clientX+offsetx}px`;dialog.style.top=`${event.clientY+offsety}px`}else{dialog.style.left=`${canvas2.width*.5+offsetx}px`;dialog.style.top=`${canvas2.height*.5+offsety}px`}setTimeout(function(){input.focus();const clickTime=Date.now();function handleOutsideClick(e2){if(e2.target===canvas2&&Date.now()-clickTime>256){dialog.close();canvas2.parentElement?.removeEventListener("click",handleOutsideClick);canvas2.parentElement?.removeEventListener("touchend",handleOutsideClick)}}canvas2.parentElement?.addEventListener("click",handleOutsideClick);canvas2.parentElement?.addEventListener("touchend",handleOutsideClick)},10);return dialog}showSearchBox(event,searchOptions){const options={slot_from:null,node_from:null,node_to:null,do_type_filter:LiteGraph.search_filter_enabled,type_filter_in:false,type_filter_out:false,show_general_if_none_on_typefilter:true,show_general_after_typefiltered:true,hide_on_mouse_leave:LiteGraph.search_hide_on_mouse_leave,show_all_if_empty:true,show_all_on_open:LiteGraph.search_show_all_on_open};Object.assign(options,searchOptions);const that=this;const graphcanvas=LGraphCanvas.active_canvas;const{canvas:canvas2}=graphcanvas;const root_document=canvas2.ownerDocument||document;const div=document.createElement("div");const dialog=Object.assign(div,{close(){that.search_box=void 0;this.blur();canvas2.focus();root_document.body.style.overflow="";setTimeout(()=>canvas2.focus(),20);dialog.remove()}});dialog.className="litegraph litesearchbox graphdialog rounded";dialog.innerHTML="<span class='name'>Search</span> <input autofocus type='text' class='value rounded'/>";if(options.do_type_filter){dialog.innerHTML+="<select class='slot_in_type_filter'><option value=''></option></select>";dialog.innerHTML+="<select class='slot_out_type_filter'><option value=''></option></select>"}const helper=document.createElement("div");helper.className="helper";dialog.append(helper);if(root_document.fullscreenElement){root_document.fullscreenElement.append(dialog)}else{root_document.body.append(dialog);root_document.body.style.overflow="hidden"}let selIn;let selOut;if(options.do_type_filter){selIn=dialog.querySelector(".slot_in_type_filter");selOut=dialog.querySelector(".slot_out_type_filter")}if(this.ds.scale>1){dialog.style.transform=`scale(${this.ds.scale})`}if(options.hide_on_mouse_leave){let prevent_timeout=false;let timeout_close=null;LiteGraph.pointerListenerAdd(dialog,"enter",function(){if(timeout_close){clearTimeout(timeout_close);timeout_close=null}});dialog.addEventListener("pointerleave",function(){if(prevent_timeout)return;const hideDelay=options.hide_on_mouse_leave;const delay=typeof hideDelay==="number"?hideDelay:500;timeout_close=setTimeout(dialog.close,delay)});if(options.do_type_filter){if(!selIn)throw new TypeError("selIn was null when showing search box");if(!selOut)throw new TypeError("selOut was null when showing search box");selIn.addEventListener("click",function(){prevent_timeout++});selIn.addEventListener("blur",function(){prevent_timeout=0});selIn.addEventListener("change",function(){prevent_timeout=-1});selOut.addEventListener("click",function(){prevent_timeout++});selOut.addEventListener("blur",function(){prevent_timeout=0});selOut.addEventListener("change",function(){prevent_timeout=-1})}}that.search_box?.close();that.search_box=dialog;let first=null;let timeout=null;let selected=null;const maybeInput=dialog.querySelector("input");if(!maybeInput)throw new TypeError("Could not create search input box.");const input=maybeInput;if(input){input.addEventListener("blur",function(){this.focus()});input.addEventListener("keydown",function(e2){if(e2.key=="ArrowUp"){changeSelection(false)}else if(e2.key=="ArrowDown"){changeSelection(true)}else if(e2.key=="Escape"){dialog.close()}else if(e2.key=="Enter"){if(selected instanceof HTMLElement){select(unescape(String(selected.dataset["type"])))}else if(first){select(first)}else{dialog.close()}}else{if(timeout){clearInterval(timeout)}timeout=setTimeout(refreshHelper,10);return}e2.preventDefault();e2.stopPropagation();e2.stopImmediatePropagation();return true})}if(options.do_type_filter){if(selIn){const aSlots=LiteGraph.slot_types_in;const nSlots=aSlots.length;if(options.type_filter_in==LiteGraph.EVENT||options.type_filter_in==LiteGraph.ACTION){options.type_filter_in="_event_"}for(let iK=0;iK<nSlots;iK++){const opt=document.createElement("option");opt.value=aSlots[iK];opt.innerHTML=aSlots[iK];selIn.append(opt);if(options.type_filter_in!==false&&String(options.type_filter_in).toLowerCase()==String(aSlots[iK]).toLowerCase()){opt.selected=true}}selIn.addEventListener("change",function(){refreshHelper()})}if(selOut){const aSlots=LiteGraph.slot_types_out;if(options.type_filter_out==LiteGraph.EVENT||options.type_filter_out==LiteGraph.ACTION){options.type_filter_out="_event_"}for(const aSlot of aSlots){const opt=document.createElement("option");opt.value=aSlot;opt.innerHTML=aSlot;selOut.append(opt);if(options.type_filter_out!==false&&String(options.type_filter_out).toLowerCase()==String(aSlot).toLowerCase()){opt.selected=true}}selOut.addEventListener("change",function(){refreshHelper()})}}const rect=canvas2.getBoundingClientRect();const left=(event?event.clientX:rect.left+rect.width*.5)-80;const top=(event?event.clientY:rect.top+rect.height*.5)-20;dialog.style.left=`${left}px`;dialog.style.top=`${top}px`;if(event.layerY>rect.height-200){helper.style.maxHeight=`${rect.height-event.layerY-20}px`}requestAnimationFrame(function(){input.focus()});if(options.show_all_on_open)refreshHelper();function select(name){if(name){if(that.onSearchBoxSelection){that.onSearchBoxSelection(name,event,graphcanvas)}else{if(!graphcanvas.graph)throw new NullGraphError;graphcanvas.graph.beforeChange();const node2=LiteGraph.createNode(name);if(node2){node2.pos=graphcanvas.convertEventToCanvasOffset(event);graphcanvas.graph.add(node2,false)}if(options.node_from){let iS=false;switch(typeof options.slot_from){case"string":iS=options.node_from.findOutputSlot(options.slot_from);break;case"object":if(options.slot_from==null)throw new TypeError("options.slot_from was null when showing search box");iS=options.slot_from.name?options.node_from.findOutputSlot(options.slot_from.name):-1;if(iS==-1&&options.slot_from.slot_index!==void 0)iS=options.slot_from.slot_index;break;case"number":iS=options.slot_from;break;default:iS=0}if(options.node_from.outputs[iS]!==void 0){if(iS!==false&&iS>-1){if(node2==null)throw new TypeError("options.slot_from was null when showing search box");options.node_from.connectByType(iS,node2,options.node_from.outputs[iS].type)}}}if(options.node_to){let iS=false;switch(typeof options.slot_from){case"string":iS=options.node_to.findInputSlot(options.slot_from);break;case"object":if(options.slot_from==null)throw new TypeError("options.slot_from was null when showing search box");iS=options.slot_from.name?options.node_to.findInputSlot(options.slot_from.name):-1;if(iS==-1&&options.slot_from.slot_index!==void 0)iS=options.slot_from.slot_index;break;case"number":iS=options.slot_from;break;default:iS=0}if(options.node_to.inputs[iS]!==void 0){if(iS!==false&&iS>-1){if(node2==null)throw new TypeError("options.slot_from was null when showing search box");options.node_to.connectByTypeOutput(iS,node2,options.node_to.inputs[iS].type)}}}graphcanvas.graph.afterChange()}}dialog.close()}function changeSelection(forward){const prev=selected;if(!selected){selected=forward?helper.childNodes[0]:helper.childNodes[helper.childNodes.length]}else if(selected instanceof Element){selected.classList.remove("selected");selected=forward?selected.nextSibling:selected.previousSibling;selected||=prev}if(selected instanceof Element){selected.classList.add("selected");selected.scrollIntoView({block:"end",behavior:"smooth"})}}function refreshHelper(){timeout=null;let str=input.value;first=null;helper.innerHTML="";if(!str&&!options.show_all_if_empty)return;if(that.onSearchBox){const list=that.onSearchBox(helper,str,graphcanvas);if(list){for(const item of list){addResult(item)}}}else{let inner_test_filter=function(type,optsIn){optsIn=optsIn||{};const optsDef={skipFilter:false,inTypeOverride:false,outTypeOverride:false};const opts=Object.assign(optsDef,optsIn);const ctor=LiteGraph.registered_node_types[type];if(filter&&ctor.filter!=filter)return false;if((!options.show_all_if_empty||str)&&!type.toLowerCase().includes(str)&&(!ctor.title||!ctor.title.toLowerCase().includes(str))){return false}if(options.do_type_filter&&!opts.skipFilter){const sType=type;let sV=opts.inTypeOverride!==false?opts.inTypeOverride:sIn.value;if(sIn&&sV&&LiteGraph.registered_slot_in_types[sV]?.nodes){const doesInc=LiteGraph.registered_slot_in_types[sV].nodes.includes(sType);if(doesInc===false)return false}sV=sOut.value;if(opts.outTypeOverride!==false)sV=opts.outTypeOverride;if(sOut&&sV&&LiteGraph.registered_slot_out_types[sV]?.nodes){const doesInc=LiteGraph.registered_slot_out_types[sV].nodes.includes(sType);if(doesInc===false)return false}}return true};let c=0;str=str.toLowerCase();if(!graphcanvas.graph)throw new NullGraphError;const filter=graphcanvas.filter||graphcanvas.graph.filter;let sIn=false;let sOut=false;if(options.do_type_filter&&that.search_box){sIn=that.search_box.querySelector(".slot_in_type_filter");sOut=that.search_box.querySelector(".slot_out_type_filter")}const keys=Object.keys(LiteGraph.registered_node_types);const filtered=keys.filter(x2=>inner_test_filter(x2));for(const item of filtered){addResult(item);if(LGraphCanvas.search_limit!==-1&&c++>LGraphCanvas.search_limit)break}if(options.show_general_after_typefiltered&&(sIn.value||sOut.value)){filtered_extra=[];for(const i in LiteGraph.registered_node_types){if(inner_test_filter(i,{inTypeOverride:sIn&&sIn.value?"*":false,outTypeOverride:sOut&&sOut.value?"*":false})){filtered_extra.push(i)}}for(const extraItem of filtered_extra){addResult(extraItem,"generic_type");if(LGraphCanvas.search_limit!==-1&&c++>LGraphCanvas.search_limit)break}}if((sIn.value||sOut.value)&&helper.childNodes.length==0&&options.show_general_if_none_on_typefilter){filtered_extra=[];for(const i in LiteGraph.registered_node_types){if(inner_test_filter(i,{skipFilter:true}))filtered_extra.push(i)}for(const extraItem of filtered_extra){addResult(extraItem,"not_in_filter");if(LGraphCanvas.search_limit!==-1&&c++>LGraphCanvas.search_limit)break}}}function addResult(type,className){const help=document.createElement("div");first||=type;const nodeType=LiteGraph.registered_node_types[type];if(nodeType?.title){help.textContent=nodeType?.title;const typeEl=document.createElement("span");typeEl.className="litegraph lite-search-item-type";typeEl.textContent=type;help.append(typeEl)}else{help.textContent=type}help.dataset["type"]=escape(type);help.className="litegraph lite-search-item";if(className){help.className+=` ${className}`}help.addEventListener("click",function(){select(unescape(String(this.dataset["type"])))});helper.append(help)}}return dialog}showEditPropertyValue(node2,property,options){if(!node2||node2.properties[property]===void 0)return;options=options||{};const info=node2.getPropertyInfo(property);const{type}=info;let input_html="";if(type=="string"||type=="number"||type=="array"||type=="object"){input_html="<input autofocus type='text' class='value'/>"}else if((type=="enum"||type=="combo")&&info.values){input_html="<select autofocus type='text' class='value'>";for(const i in info.values){const v2=Array.isArray(info.values)?info.values[i]:i;const selected=v2==node2.properties[property]?"selected":"";input_html+=`<option value='${v2}' ${selected}>${info.values[i]}</option>`}input_html+="</select>"}else if(type=="boolean"||type=="toggle"){const checked=node2.properties[property]?"checked":"";input_html=`<input autofocus type='checkbox' class='value' ${checked}/>`}else{console.warn(`unknown type: ${type}`);return}const dialog=this.createDialog(`<span class='name'>${info.label||property}</span>${input_html}<button>OK</button>`,options);let input;if((type=="enum"||type=="combo")&&info.values){input=dialog.querySelector("select");input?.addEventListener("change",function(e2){dialog.modified();setValue(e2.target?.value)})}else if(type=="boolean"||type=="toggle"){input=dialog.querySelector("input");input?.addEventListener("click",function(){dialog.modified();setValue(!!input.checked)})}else{input=dialog.querySelector("input");if(input){input.addEventListener("blur",function(){this.focus()});let v2=node2.properties[property]!==void 0?node2.properties[property]:"";if(type!=="string"){v2=JSON.stringify(v2)}input.value=v2;input.addEventListener("keydown",function(e2){if(e2.key=="Escape"){dialog.close()}else if(e2.key=="Enter"){inner()}else{dialog.modified();return}e2.preventDefault();e2.stopPropagation()})}}input?.focus();const button=dialog.querySelector("button");if(!button)throw new TypeError("Show edit property value button was null.");button.addEventListener("click",inner);function inner(){setValue(input?.value)}const dirty=()=>this.#dirty();function setValue(value){if(info?.values&&typeof info.values==="object"&&info.values[value]!=void 0){value=info.values[value]}if(typeof node2.properties[property]=="number"){value=Number(value)}if(type=="array"||type=="object"){value=JSON.parse(value)}node2.properties[property]=value;if(node2.graph){node2.graph._version++}node2.onPropertyChanged?.(property,value);options.onclose?.();dialog.close();dirty()}return dialog}createDialog(html,options){const def_options={checkForInput:false,closeOnLeave:true,closeOnLeave_checkModified:true};options=Object.assign(def_options,options||{});const customProperties={className:"graphdialog",innerHTML:html,is_modified:false,modified(){this.is_modified=true},close(){this.remove()}};const div=document.createElement("div");const dialog=Object.assign(div,customProperties);const rect=this.canvas.getBoundingClientRect();let offsetx=-20;let offsety=-20;if(rect){offsetx-=rect.left;offsety-=rect.top}if(options.position){offsetx+=options.position[0];offsety+=options.position[1]}else if(options.event){offsetx+=options.event.clientX;offsety+=options.event.clientY}else{offsetx+=this.canvas.width*.5;offsety+=this.canvas.height*.5}dialog.style.left=`${offsetx}px`;dialog.style.top=`${offsety}px`;if(!this.canvas.parentNode)throw new TypeError("Canvas parent element was null.");this.canvas.parentNode.append(dialog);if(options.checkForInput){const aI=dialog.querySelectorAll("input");if(aI){for(const iX of aI){iX.addEventListener("keydown",function(e2){dialog.modified();if(e2.key=="Escape"){dialog.close()}else if(e2.key!="Enter"){return}e2.preventDefault();e2.stopPropagation()});iX.focus()}}}let dialogCloseTimer;let prevent_timeout=0;dialog.addEventListener("mouseleave",function(){if(prevent_timeout)return;if(!dialog.is_modified&&LiteGraph.dialog_close_on_mouse_leave){dialogCloseTimer=setTimeout(dialog.close,LiteGraph.dialog_close_on_mouse_leave_delay)}});dialog.addEventListener("mouseenter",function(){if(options.closeOnLeave||LiteGraph.dialog_close_on_mouse_leave){if(dialogCloseTimer)clearTimeout(dialogCloseTimer)}});const selInDia=dialog.querySelectorAll("select");if(selInDia){for(const selIn of selInDia){selIn.addEventListener("click",function(){prevent_timeout++});selIn.addEventListener("blur",function(){prevent_timeout=0});selIn.addEventListener("change",function(){prevent_timeout=-1})}}return dialog}createPanel(title,options){options=options||{};const ref_window=options.window||window;const root=document.createElement("div");root.className="litegraph dialog";root.innerHTML="<div class='dialog-header'><span class='dialog-title'></span></div><div class='dialog-content'></div><div style='display:none;' class='dialog-alt-content'></div><div class='dialog-footer'></div>";root.header=root.querySelector(".dialog-header");if(options.width)root.style.width=options.width+(typeof options.width==="number"?"px":"");if(options.height)root.style.height=options.height+(typeof options.height==="number"?"px":"");if(options.closable){const close=document.createElement("span");close.innerHTML="✕";close.classList.add("close");close.addEventListener("click",function(){root.close()});root.header.append(close)}root.title_element=root.querySelector(".dialog-title");root.title_element.textContent=title;root.content=root.querySelector(".dialog-content");root.alt_content=root.querySelector(".dialog-alt-content");root.footer=root.querySelector(".dialog-footer");root.close=function(){if(typeof root.onClose=="function")root.onClose();root.remove();this.remove()};root.toggleAltContent=function(force){let vTo;let vAlt;if(force!==void 0){vTo=force?"block":"none";vAlt=force?"none":"block"}else{vTo=root.alt_content.style.display!="block"?"block":"none";vAlt=root.alt_content.style.display!="block"?"none":"block"}root.alt_content.style.display=vTo;root.content.style.display=vAlt};root.toggleFooterVisibility=function(force){let vTo;if(force!==void 0){vTo=force?"block":"none"}else{vTo=root.footer.style.display!="block"?"block":"none"}root.footer.style.display=vTo};root.clear=function(){this.content.innerHTML=""};root.addHTML=function(code,classname,on_footer){const elem=document.createElement("div");if(classname)elem.className=classname;elem.innerHTML=code;if(on_footer)root.footer.append(elem);else root.content.append(elem);return elem};root.addButton=function(name,callback,options2){const elem=document.createElement("button");elem.textContent=name;elem.options=options2;elem.classList.add("btn");elem.addEventListener("click",callback);root.footer.append(elem);return elem};root.addSeparator=function(){const elem=document.createElement("div");elem.className="separator";root.content.append(elem)};root.addWidget=function(type,name,value,options2,callback){options2=options2||{};let str_value=String(value);type=type.toLowerCase();if(type=="number"&&typeof value==="number")str_value=value.toFixed(3);const elem=document.createElement("div");elem.className="property";elem.innerHTML="<span class='property_name'></span><span class='property_value'></span>";const nameSpan=elem.querySelector(".property_name");if(!nameSpan)throw new TypeError("Property name element was null.");nameSpan.textContent=options2.label||name;const value_element=elem.querySelector(".property_value");if(!value_element)throw new TypeError("Property name element was null.");value_element.textContent=str_value;elem.dataset["property"]=name;elem.dataset["type"]=options2.type||type;elem.options=options2;elem.value=value;if(type=="code"){elem.addEventListener("click",function(){root.inner_showCodePad(this.dataset["property"])})}else if(type=="boolean"){elem.classList.add("boolean");if(value)elem.classList.add("bool-on");elem.addEventListener("click",()=>{const propname=elem.dataset["property"];elem.value=!elem.value;elem.classList.toggle("bool-on");if(!value_element)throw new TypeError("Property name element was null.");value_element.textContent=elem.value?"true":"false";innerChange(propname,elem.value)})}else if(type=="string"||type=="number"){if(!value_element)throw new TypeError("Property name element was null.");value_element.setAttribute("contenteditable","true");value_element.addEventListener("keydown",function(e2){if(e2.code=="Enter"&&(type!="string"||!e2.shiftKey)){e2.preventDefault();this.blur()}});value_element.addEventListener("blur",function(){let v2=this.textContent;const propname=this.parentElement?.dataset["property"];const proptype=this.parentElement?.dataset["type"];if(proptype=="number")v2=Number(v2);innerChange(propname,v2)})}else if(type=="enum"||type=="combo"){const str_value2=LGraphCanvas.getPropertyPrintableValue(value,options2.values);if(!value_element)throw new TypeError("Property name element was null.");value_element.textContent=str_value2??"";value_element.addEventListener("click",function(event){const values=options2.values||[];const propname=this.parentElement?.dataset["property"];const inner_clicked=v2=>{this.textContent=v2;innerChange(propname,v2);return false};new LiteGraph.ContextMenu(values,{event,className:"dark",callback:inner_clicked},ref_window)})}root.content.append(elem);function innerChange(name2,value2){options2.callback?.(name2,value2,options2);callback?.(name2,value2,options2)}return elem};if(typeof root.onOpen=="function")root.onOpen();return root}closePanels(){document.querySelector("#node-panel")?.close?.();document.querySelector("#option-panel")?.close?.()}showShowNodePanel(node2){this.SELECTED_NODE=node2;this.closePanels();const ref_window=this.getCanvasWindow();const panel=this.createPanel(node2.title||"",{closable:true,window:ref_window,onOpen:()=>{this.NODEPANEL_IS_OPEN=true},onClose:()=>{this.NODEPANEL_IS_OPEN=false;this.node_panel=null}});this.node_panel=panel;panel.id="node-panel";panel.node=node2;panel.classList.add("settings");const inner_refresh=()=>{panel.content.innerHTML="";panel.addHTML(`<span class='node_type'>${node2.type}</span><span class='node_desc'>${node2.constructor.desc||""}</span><span class='separator'></span>`);panel.addHTML("<h3>Properties</h3>");const fUpdate=(name,value)=>{if(!this.graph)throw new NullGraphError;this.graph.beforeChange(node2);switch(name){case"Title":if(typeof value!=="string")throw new TypeError("Attempting to set title to non-string value.");node2.title=value;break;case"Mode":{if(typeof value!=="string")throw new TypeError("Attempting to set mode to non-string value.");const kV=Object.values(LiteGraph.NODE_MODES).indexOf(value);if(kV!==-1&&LiteGraph.NODE_MODES[kV]){node2.changeMode(kV)}else{console.warn(`unexpected mode: ${value}`)}break}case"Color":if(typeof value!=="string")throw new TypeError("Attempting to set colour to non-string value.");if(LGraphCanvas.node_colors[value]){node2.color=LGraphCanvas.node_colors[value].color;node2.bgcolor=LGraphCanvas.node_colors[value].bgcolor}else{console.warn(`unexpected color: ${value}`)}break;default:node2.setProperty(name,value);break}this.graph.afterChange();this.dirty_canvas=true};panel.addWidget("string","Title",node2.title,{},fUpdate);const mode=node2.mode==null?void 0:LiteGraph.NODE_MODES[node2.mode];panel.addWidget("combo","Mode",mode,{values:LiteGraph.NODE_MODES},fUpdate);const nodeCol=node2.color!==void 0?Object.keys(LGraphCanvas.node_colors).filter(function(nK){return LGraphCanvas.node_colors[nK].color==node2.color}):"";panel.addWidget("combo","Color",nodeCol,{values:Object.keys(LGraphCanvas.node_colors)},fUpdate);for(const pName in node2.properties){const value=node2.properties[pName];const info=node2.getPropertyInfo(pName);if(node2.onAddPropertyToPanel?.(pName,panel))continue;panel.addWidget(info.widget||info.type,pName,value,info,fUpdate)}panel.addSeparator();node2.onShowCustomPanelInfo?.(panel);panel.footer.innerHTML="";panel.addButton("Delete",function(){if(node2.block_delete)return;if(!node2.graph)throw new NullGraphError;node2.graph.remove(node2);panel.close()}).classList.add("delete")};panel.inner_showCodePad=function(propname){panel.classList.remove("settings");panel.classList.add("centered");panel.alt_content.innerHTML="<textarea class='code'></textarea>";const textarea=panel.alt_content.querySelector("textarea");const fDoneWith=function(){panel.toggleAltContent(false);panel.toggleFooterVisibility(true);textarea.remove();panel.classList.add("settings");panel.classList.remove("centered");inner_refresh()};textarea.value=String(node2.properties[propname]);textarea.addEventListener("keydown",function(e2){if(e2.code=="Enter"&&e2.ctrlKey){node2.setProperty(propname,textarea.value);fDoneWith()}});panel.toggleAltContent(true);panel.toggleFooterVisibility(false);textarea.style.height="calc(100% - 40px)";const assign=panel.addButton("Assign",function(){node2.setProperty(propname,textarea.value);fDoneWith()});panel.alt_content.append(assign);const button=panel.addButton("Close",fDoneWith);button.style.float="right";panel.alt_content.append(button)};inner_refresh();if(!this.canvas.parentNode)throw new TypeError("showNodePanel - this.canvas.parentNode was null");this.canvas.parentNode.append(panel)}checkPanels(){if(!this.canvas)return;if(!this.canvas.parentNode)throw new TypeError("checkPanels - this.canvas.parentNode was null");const panels=this.canvas.parentNode.querySelectorAll(".litegraph.dialog");for(const panel of panels){if(!panel.node)continue;if(!panel.node.graph||panel.graph!=this.graph)panel.close()}}getCanvasMenuOptions(){let options;if(this.getMenuOptions){options=this.getMenuOptions()}else{options=[{content:"Add Node",has_submenu:true,callback:LGraphCanvas.onMenuAdd},{content:"Add Group",callback:LGraphCanvas.onGroupAdd}];if(Object.keys(this.selected_nodes).length>1){options.push({content:"Convert to Subgraph 🆕",callback:()=>{if(!this.selectedItems.size)throw new Error("Convert to Subgraph: Nothing selected.");this._graph.convertToSubgraph(this.selectedItems)}},{content:"Align",has_submenu:true,callback:LGraphCanvas.onGroupAlign})}}const extra=this.getExtraMenuOptions?.(this,options);return Array.isArray(extra)?options.concat(extra):options}getNodeMenuOptions(node2){let options;if(node2.getMenuOptions){options=node2.getMenuOptions(this)}else{options=[{content:"Inputs",has_submenu:true,disabled:true},{content:"Outputs",has_submenu:true,disabled:true,callback:LGraphCanvas.showMenuNodeOptionalOutputs},null,{content:"Convert to Subgraph 🆕",callback:()=>{if(!this.selectedItems.size)throw new Error("Convert to Subgraph: Nothing selected.");this._graph.convertToSubgraph(this.selectedItems)}},{content:"Properties",has_submenu:true,callback:LGraphCanvas.onShowMenuNodeProperties},{content:"Properties Panel",callback:function(item,options2,e2,menu,node22){LGraphCanvas.active_canvas.showShowNodePanel(node22)}},null,{content:"Title",callback:LGraphCanvas.onShowPropertyEditor},{content:"Mode",has_submenu:true,callback:LGraphCanvas.onMenuNodeMode}];if(node2.resizable!==false){options.push({content:"Resize",callback:LGraphCanvas.onMenuResizeNode})}if(node2.collapsible){options.push({content:node2.collapsed?"Expand":"Collapse",callback:LGraphCanvas.onMenuNodeCollapse})}if(node2.widgets?.some(w=>w.advanced)){options.push({content:node2.showAdvanced?"Hide Advanced":"Show Advanced",callback:LGraphCanvas.onMenuToggleAdvanced})}options.push({content:node2.pinned?"Unpin":"Pin",callback:()=>{for(const i in this.selected_nodes){const node22=this.selected_nodes[i];node22.pin()}this.setDirty(true,true)}},{content:"Colors",has_submenu:true,callback:LGraphCanvas.onMenuNodeColors},{content:"Shapes",has_submenu:true,callback:LGraphCanvas.onMenuNodeShapes},null)}const extra=node2.getExtraMenuOptions?.(this,options);if(Array.isArray(extra)&&extra.length>0){extra.push(null);options=extra.concat(options)}if(node2.clonable!==false){options.push({content:"Clone",callback:LGraphCanvas.onMenuNodeClone})}if(Object.keys(this.selected_nodes).length>1){options.push({content:"Align Selected To",has_submenu:true,callback:LGraphCanvas.onNodeAlign},{content:"Distribute Nodes",has_submenu:true,callback:LGraphCanvas.createDistributeMenu})}options.push(null,{content:"Remove",disabled:!(node2.removable!==false&&!node2.block_delete),callback:LGraphCanvas.onMenuNodeRemove});node2.graph?.onGetNodeMenuOptions?.(options,node2);return options}getGroupMenuOptions(group){console.warn("LGraphCanvas.getGroupMenuOptions is deprecated, use LGraphGroup.getMenuOptions instead");return group.getMenuOptions()}processContextMenu(node2,event){const canvas2=LGraphCanvas.active_canvas;const ref_window=canvas2.getCanvasWindow();let menu_info;const options={event,callback:inner_option_clicked,extra:node2};if(node2){options.title=node2.displayType??node2.type??void 0;LGraphCanvas.active_node=node2;const slot=node2.getSlotInPosition(event.canvasX,event.canvasY);if(slot){menu_info=[];if(node2.getSlotMenuOptions){menu_info=node2.getSlotMenuOptions(slot)}else{if(slot.output?.links?.length||slot.input?.link!=null){menu_info.push({content:"Disconnect Links",slot})}const _slot=slot.input||slot.output;if(!_slot)throw new TypeError("Both in put and output slots were null when processing context menu.");if(_slot.removable){menu_info.push(_slot.locked?"Cannot remove":{content:"Remove Slot",slot})}if(!_slot.nameLocked&&!("link"in _slot&&_slot.widget)){menu_info.push({content:"Rename Slot",slot})}if(node2.getExtraSlotMenuOptions){menu_info.push(...node2.getExtraSlotMenuOptions(slot))}}options.title=(slot.input?slot.input.type:slot.output.type)||"*";if(slot.input&&slot.input.type==LiteGraph.ACTION)options.title="Action";if(slot.output&&slot.output.type==LiteGraph.EVENT)options.title="Event"}else{menu_info=this.getNodeMenuOptions(node2)}}else{menu_info=this.getCanvasMenuOptions();if(!this.graph)throw new NullGraphError;if(this.links_render_mode!==LinkRenderType.HIDDEN_LINK){const reroute=this.graph.getRerouteOnPos(event.canvasX,event.canvasY,this.#visibleReroutes);if(reroute){menu_info.unshift({content:"Delete Reroute",callback:()=>{if(!this.graph)throw new NullGraphError;this.graph.removeReroute(reroute.id)}},null)}}const group=this.graph.getGroupOnPos(event.canvasX,event.canvasY);if(group){menu_info.push(null,{content:"Edit Group",has_submenu:true,submenu:{title:"Group",extra:group,options:group.getMenuOptions()}})}}if(!menu_info)return;new LiteGraph.ContextMenu(menu_info,options,ref_window);const createDialog=options2=>this.createDialog("<span class='name'>Name</span><input autofocus type='text'/><button>OK</button>",options2);const setDirty=()=>this.setDirty(true);function inner_option_clicked(v2,options2){if(!v2)return;if(v2.content=="Remove Slot"){if(!node2?.graph)throw new NullGraphError;const info=v2.slot;if(!info)throw new TypeError("Found-slot info was null when processing context menu.");node2.graph.beforeChange();if(info.input){node2.removeInput(info.slot)}else if(info.output){node2.removeOutput(info.slot)}node2.graph.afterChange();return}else if(v2.content=="Disconnect Links"){if(!node2?.graph)throw new NullGraphError;const info=v2.slot;if(!info)throw new TypeError("Found-slot info was null when processing context menu.");node2.graph.beforeChange();if(info.output){node2.disconnectOutput(info.slot)}else if(info.input){node2.disconnectInput(info.slot,true)}node2.graph.afterChange();return}else if(v2.content=="Rename Slot"){if(!node2)throw new TypeError("`node` was null when processing the context menu.");const info=v2.slot;if(!info)throw new TypeError("Found-slot info was null when processing context menu.");const slot_info=info.input?node2.getInputInfo(info.slot):node2.getOutputInfo(info.slot);const dialog=createDialog(options2);const input=dialog.querySelector("input");if(input&&slot_info){input.value=slot_info.label||""}const inner=function(){if(!node2.graph)throw new NullGraphError;node2.graph.beforeChange();if(input?.value){if(slot_info){slot_info.label=input.value}setDirty()}dialog.close();node2.graph.afterChange()};dialog.querySelector("button")?.addEventListener("click",inner);if(!input)throw new TypeError("Input element was null when processing context menu.");input.addEventListener("keydown",function(e2){dialog.is_modified=true;if(e2.key=="Escape"){dialog.close()}else if(e2.key=="Enter"){inner()}else if(e2.target.localName!="textarea"){return}e2.preventDefault();e2.stopPropagation()});input.focus()}}}animateToBounds(bounds,options={}){const setDirty=()=>this.setDirty(true,true);this.ds.animateToBounds(bounds,setDirty,options)}fitViewToSelectionAnimated(options={}){const items=this.selectedItems.size?Array.from(this.selectedItems):this.positionableItems;const bounds=createBounds(items);if(!bounds)throw new TypeError("Attempted to fit to view but could not calculate bounds.");const setDirty=()=>this.setDirty(true,true);this.ds.animateToBounds(bounds,setDirty,options)}}class MapProxyHandler{getOwnPropertyDescriptor(target,p){const value=this.get(target,p);if(value){return{configurable:true,enumerable:true,value}}}has(target,p){if(typeof p==="symbol")return false;const int=parseInt(p,10);return target.has(!isNaN(int)?int:p)}ownKeys(target){return[...target.keys()].map(String)}get(target,p){if(p in target)return Reflect.get(target,p,target);if(typeof p==="symbol")return;const int=parseInt(p,10);return target.get(!isNaN(int)?int:p)}set(target,p,newValue2){if(typeof p==="symbol")return false;const int=parseInt(p,10);target.set(!isNaN(int)?int:p,newValue2);return true}deleteProperty(target,p){return target.delete(p)}static bindAllMethods(map){map.clear=map.clear.bind(map);map.delete=map.delete.bind(map);map.forEach=map.forEach.bind(map);map.get=map.get.bind(map);map.has=map.has.bind(map);map.set=map.set.bind(map);map.entries=map.entries.bind(map);map.keys=map.keys.bind(map);map.values=map.values.bind(map);map[Symbol.iterator]=map[Symbol.iterator].bind(map)}}class LGraph{static serialisedSchemaVersion=1;static STATUS_STOPPED=1;static STATUS_RUNNING=2;static ConfigureProperties=new Set(["nodes","groups","links","state","reroutes","floatingLinks","id","subgraphs","definitions","inputs","outputs","widgets","inputNode","outputNode","extra"]);id=zeroUuid;revision=0;_version=-1;_links=new Map;links;list_of_graphcanvas;status=LGraph.STATUS_STOPPED;state={lastGroupId:0,lastNodeId:0,lastLinkId:0,lastRerouteId:0};events=new CustomEventTarget;_subgraphs=new Map;_nodes=[];_nodes_by_id={};_nodes_in_order=[];_nodes_executable=null;_groups=[];iteration=0;globaltime=0;runningtime=0;fixedtime=0;fixedtime_lapse=.01;elapsed_time=.01;last_update_time=0;starttime=0;catch_errors=true;execution_timer_id;errors_in_execution;execution_time;_last_trigger_time;filter;config={};vars={};nodes_executing=[];nodes_actioning=[];nodes_executedAction=[];extra={};version;get empty(){return this._nodes.length+this._groups.length+this.reroutes.size===0}*positionableItems(){for(const node2 of this._nodes)yield node2;for(const group of this._groups)yield group;for(const reroute of this.reroutes.values())yield reroute;return}#lastFloatingLinkId=0;#floatingLinks=new Map;get floatingLinks(){return this.#floatingLinks}#reroutes=new Map;get reroutes(){return this.#reroutes}get rootGraph(){return this}get isRootGraph(){return this.rootGraph===this}get last_node_id(){return this.state.lastNodeId}set last_node_id(value){this.state.lastNodeId=value}get last_link_id(){return this.state.lastLinkId}set last_link_id(value){this.state.lastLinkId=value}_input_nodes;constructor(o){if(LiteGraph.debug)console.log("Graph created");const links=this._links;MapProxyHandler.bindAllMethods(links);const handler=new MapProxyHandler;this.links=new Proxy(links,handler);this.list_of_graphcanvas=null;this.clear();if(o)this.configure(o)}clear(){this.stop();this.status=LGraph.STATUS_STOPPED;this.id=zeroUuid;this.revision=0;this.state={lastGroupId:0,lastNodeId:0,lastLinkId:0,lastRerouteId:0};this._version=-1;this._subgraphs.clear();if(this._nodes){for(const _node of this._nodes){_node.onRemoved?.()}}this._nodes=[];this._nodes_by_id={};this._nodes_in_order=[];this._nodes_executable=null;this._links.clear();this.reroutes.clear();this.#floatingLinks.clear();this.#lastFloatingLinkId=0;this._groups=[];this.iteration=0;this.config={};this.vars={};this.extra={};this.globaltime=0;this.runningtime=0;this.fixedtime=0;this.fixedtime_lapse=.01;this.elapsed_time=.01;this.last_update_time=0;this.starttime=0;this.catch_errors=true;this.nodes_executing=[];this.nodes_actioning=[];this.nodes_executedAction=[];this.change();this.canvasAction(c=>c.clear())}get subgraphs(){return this.rootGraph._subgraphs}get nodes(){return this._nodes}get groups(){return this._groups}attachCanvas(canvas2){if(!(canvas2 instanceof LGraphCanvas)){throw new TypeError("attachCanvas expects an LGraphCanvas instance")}this.primaryCanvas=canvas2;this.list_of_graphcanvas??=[];if(!this.list_of_graphcanvas.includes(canvas2)){this.list_of_graphcanvas.push(canvas2)}if(canvas2.graph===this)return;canvas2.graph?.detachCanvas(canvas2);canvas2.graph=this;canvas2.subgraph=void 0}detachCanvas(canvas2){canvas2.graph=null;const canvases=this.list_of_graphcanvas;if(canvases){const pos=canvases.indexOf(canvas2);if(pos!==-1)canvases.splice(pos,1)}}start(interval){if(this.status==LGraph.STATUS_RUNNING)return;this.status=LGraph.STATUS_RUNNING;this.onPlayEvent?.();this.sendEventToAllNodes("onStart");this.starttime=LiteGraph.getTime();this.last_update_time=this.starttime;interval||=0;if(interval==0&&typeof window!="undefined"&&window.requestAnimationFrame){const on_frame=()=>{if(this.execution_timer_id!=-1)return;window.requestAnimationFrame(on_frame);this.onBeforeStep?.();this.runStep(1,!this.catch_errors);this.onAfterStep?.()};this.execution_timer_id=-1;on_frame()}else{this.execution_timer_id=setInterval(()=>{this.onBeforeStep?.();this.runStep(1,!this.catch_errors);this.onAfterStep?.()},interval)}}stop(){if(this.status==LGraph.STATUS_STOPPED)return;this.status=LGraph.STATUS_STOPPED;this.onStopEvent?.();if(this.execution_timer_id!=null){if(this.execution_timer_id!=-1){clearInterval(this.execution_timer_id)}this.execution_timer_id=null}this.sendEventToAllNodes("onStop")}runStep(num,do_not_catch_errors,limit){num=num||1;const start=LiteGraph.getTime();this.globaltime=.001*(start-this.starttime);const nodes=this._nodes_executable||this._nodes;if(!nodes)return;limit=limit||nodes.length;if(do_not_catch_errors){for(let i=0;i<num;i++){for(let j=0;j<limit;++j){const node2=nodes[j];if(node2.mode==LGraphEventMode.ALWAYS&&node2.onExecute){node2.doExecute?.()}}this.fixedtime+=this.fixedtime_lapse;this.onExecuteStep?.()}this.onAfterExecute?.()}else{try{for(let i=0;i<num;i++){for(let j=0;j<limit;++j){const node2=nodes[j];if(node2.mode==LGraphEventMode.ALWAYS){node2.onExecute?.()}}this.fixedtime+=this.fixedtime_lapse;this.onExecuteStep?.()}this.onAfterExecute?.();this.errors_in_execution=false}catch(error){this.errors_in_execution=true;if(LiteGraph.throw_errors)throw error;if(LiteGraph.debug)console.log("Error during execution:",error);this.stop()}}const now=LiteGraph.getTime();let elapsed=now-start;if(elapsed==0)elapsed=1;this.execution_time=.001*elapsed;this.globaltime+=.001*elapsed;this.iteration+=1;this.elapsed_time=(now-this.last_update_time)*.001;this.last_update_time=now;this.nodes_executing=[];this.nodes_actioning=[];this.nodes_executedAction=[]}updateExecutionOrder(){this._nodes_in_order=this.computeExecutionOrder(false);this._nodes_executable=[];for(const node2 of this._nodes_in_order){if(node2.onExecute){this._nodes_executable.push(node2)}}}computeExecutionOrder(only_onExecute,set_level){const L=[];const S=[];const M={};const visited_links={};const remaining_links={};for(const node2 of this._nodes){if(only_onExecute&&!node2.onExecute){continue}M[node2.id]=node2;let num=0;if(node2.inputs){for(const input of node2.inputs){if(input?.link!=null){num+=1}}}if(num==0){S.push(node2);if(set_level)node2._level=1}else{if(set_level)node2._level=0;remaining_links[node2.id]=num}}while(true){const node2=S.shift();if(node2===void 0)break;L.push(node2);delete M[node2.id];if(!node2.outputs)continue;for(const output of node2.outputs){if(output?.links==null||output.links.length==0)continue;for(const link_id of output.links){const link=this._links.get(link_id);if(!link)continue;if(visited_links[link.id])continue;const target_node=this.getNodeById(link.target_id);if(target_node==null){visited_links[link.id]=true;continue}if(set_level){node2._level??=0;if(!target_node._level||target_node._level<=node2._level){target_node._level=node2._level+1}}visited_links[link.id]=true;remaining_links[target_node.id]-=1;if(remaining_links[target_node.id]==0)S.push(target_node)}}}for(const i in M){L.push(M[i])}if(L.length!=this._nodes.length&&LiteGraph.debug)console.warn("something went wrong, nodes missing");function setOrder(nodes){const l=nodes.length;for(let i=0;i<l;++i){nodes[i].order=i}}setOrder(L);L.sort(function(A,B){const Ap=A.constructor.priority||A.priority||0;const Bp=B.constructor.priority||B.priority||0;return Ap==Bp?A.order-B.order:Ap-Bp});setOrder(L);return L}arrange(margin,layout){margin=margin||100;const nodes=this.computeExecutionOrder(false,true);const columns=[];for(const node2 of nodes){const col=node2._level||1;columns[col]||=[];columns[col].push(node2)}let x2=margin;for(const column of columns){if(!column)continue;let max_size=100;let y=margin+LiteGraph.NODE_TITLE_HEIGHT;for(const node2 of column){node2.pos[0]=layout==LiteGraph.VERTICAL_LAYOUT?y:x2;node2.pos[1]=layout==LiteGraph.VERTICAL_LAYOUT?x2:y;const max_size_index=layout==LiteGraph.VERTICAL_LAYOUT?1:0;if(node2.size[max_size_index]>max_size){max_size=node2.size[max_size_index]}const node_size_index=layout==LiteGraph.VERTICAL_LAYOUT?0:1;y+=node2.size[node_size_index]+margin+LiteGraph.NODE_TITLE_HEIGHT}x2+=max_size+margin}this.setDirtyCanvas(true,true)}getTime(){return this.globaltime}getFixedTime(){return this.fixedtime}getElapsedTime(){return this.elapsed_time}sendEventToAllNodes(eventname,params,mode){mode=mode||LGraphEventMode.ALWAYS;const nodes=this._nodes_in_order||this._nodes;if(!nodes)return;for(const node2 of nodes){if(!node2[eventname]||node2.mode!=mode)continue;if(params===void 0){node2[eventname]()}else if(params&¶ms.constructor===Array){node2[eventname].apply(node2,params)}else{node2[eventname](params)}}}canvasAction(action){const canvases=this.list_of_graphcanvas;if(!canvases)return;for(const canvas2 of canvases)action(canvas2)}sendActionToCanvas(action,params){const{list_of_graphcanvas}=this;if(!list_of_graphcanvas)return;for(const c of list_of_graphcanvas){c[action]?.apply(c,params)}}add(node2,skip_compute_order){if(!node2)return;const{state}=this;if(LiteGraph.alwaysSnapToGrid){const snapTo=this.getSnapToGridSize();if(snapTo)node2.snapToGrid(snapTo)}if(node2 instanceof LGraphGroup){if(node2.id==null||node2.id===-1)node2.id=++state.lastGroupId;if(node2.id>state.lastGroupId)state.lastGroupId=node2.id;this._groups.push(node2);this.setDirtyCanvas(true);this.change();node2.graph=this;this._version++;return}if(node2.id!=-1&&this._nodes_by_id[node2.id]!=null){console.warn("LiteGraph: there is already a node with this ID, changing it");node2.id=LiteGraph.use_uuids?LiteGraph.uuidv4():++state.lastNodeId}if(this._nodes.length>=LiteGraph.MAX_NUMBER_OF_NODES){throw"LiteGraph: max number of nodes in a graph reached"}if(LiteGraph.use_uuids){if(node2.id==null||node2.id==-1)node2.id=LiteGraph.uuidv4()}else{if(node2.id==null||node2.id==-1){node2.id=++state.lastNodeId}else if(typeof node2.id==="number"&&state.lastNodeId<node2.id){state.lastNodeId=node2.id}}node2.graph=this;this._version++;this._nodes.push(node2);this._nodes_by_id[node2.id]=node2;node2.onAdded?.(this);if(this.config.align_to_grid)node2.alignToGrid();if(!skip_compute_order)this.updateExecutionOrder();this.onNodeAdded?.(node2);this.setDirtyCanvas(true);this.change();return node2}remove(node2){if(node2 instanceof LGraphGroup){this.canvasAction(c=>c.deselect(node2));const index=this._groups.indexOf(node2);if(index!=-1){this._groups.splice(index,1)}node2.graph=void 0;this._version++;this.setDirtyCanvas(true,true);this.change();return}if(this._nodes_by_id[node2.id]==null){console.warn("LiteGraph: node not found",node2);return}if(node2.ignore_remove){console.warn("LiteGraph: node cannot be removed",node2);return}this.beforeChange();const{inputs,outputs}=node2;if(inputs){for(const[i,slot]of inputs.entries()){if(slot.link!=null)node2.disconnectInput(i,true)}}if(outputs){for(const[i,slot]of outputs.entries()){if(slot.links?.length)node2.disconnectOutput(i)}}for(const link of this.floatingLinks.values()){if(link.origin_id===node2.id||link.target_id===node2.id){this.removeFloatingLink(link)}}node2.onRemoved?.();node2.graph=null;this._version++;const{list_of_graphcanvas}=this;if(list_of_graphcanvas){for(const canvas2 of list_of_graphcanvas){if(canvas2.selected_nodes[node2.id])delete canvas2.selected_nodes[node2.id];canvas2.deselect(node2)}}const pos=this._nodes.indexOf(node2);if(pos!=-1)this._nodes.splice(pos,1);delete this._nodes_by_id[node2.id];this.onNodeRemoved?.(node2);this.canvasAction(c=>c.checkPanels());this.setDirtyCanvas(true,true);this.afterChange();this.change();this.updateExecutionOrder()}getNodeById(id){return id!=null?this._nodes_by_id[id]:null}findNodesByClass(classObject,result){result=result||[];result.length=0;const{_nodes}=this;for(const node2 of _nodes){if(node2.constructor===classObject)result.push(node2)}return result}findNodesByType(type,result){const matchType=type.toLowerCase();result=result||[];result.length=0;const{_nodes}=this;for(const node2 of _nodes){if(node2.type?.toLowerCase()==matchType)result.push(node2)}return result}findNodeByTitle(title){const{_nodes}=this;for(const node2 of _nodes){if(node2.title==title)return node2}return null}findNodesByTitle(title){const result=[];const{_nodes}=this;for(const node2 of _nodes){if(node2.title==title)result.push(node2)}return result}getNodeOnPos(x2,y,nodeList){const nodes=nodeList||this._nodes;let i=nodes.length;while(--i>=0){const node2=nodes[i];if(node2.isPointInside(x2,y))return node2}return null}getGroupOnPos(x2,y){return this._groups.toReversed().find(g=>g.isPointInside(x2,y))}getGroupTitlebarOnPos(x2,y){return this._groups.toReversed().find(g=>g.isPointInTitlebar(x2,y))}getRerouteOnPos(x2,y,reroutes){for(const reroute of reroutes??this.reroutes.values()){if(reroute.containsPoint([x2,y]))return reroute}}snapToGrid(items){const snapTo=this.getSnapToGridSize();if(!snapTo)return;for(const item of getAllNestedItems(items)){if(!item.pinned)item.snapToGrid(snapTo)}}getSnapToGridSize(){return LiteGraph.alwaysSnapToGrid?LiteGraph.CANVAS_GRID_SIZE||1:LiteGraph.CANVAS_GRID_SIZE}checkNodeTypes(){const{_nodes}=this;for(const[i,node2]of _nodes.entries()){const ctor=LiteGraph.registered_node_types[node2.type];if(node2.constructor==ctor)continue;console.log("node being replaced by newer version:",node2.type);const newnode=LiteGraph.createNode(node2.type);if(!newnode)continue;_nodes[i]=newnode;newnode.configure(node2.serialize());newnode.graph=this;this._nodes_by_id[newnode.id]=newnode;if(node2.inputs)newnode.inputs=[...node2.inputs];if(node2.outputs)newnode.outputs=[...node2.outputs]}this.updateExecutionOrder()}trigger(action,param){this.onTrigger?.(action,param)}triggerInput(name,value){const nodes=this.findNodesByTitle(name);for(const node2 of nodes){node2.onTrigger(value)}}setCallback(name,func){const nodes=this.findNodesByTitle(name);for(const node2 of nodes){node2.setTrigger(func)}}beforeChange(info){this.onBeforeChange?.(this,info);this.canvasAction(c=>c.onBeforeChange?.(this))}afterChange(info){this.onAfterChange?.(this,info);this.canvasAction(c=>c.onAfterChange?.(this))}clearTriggeredSlots(){for(const link_info of this._links.values()){if(!link_info)continue;if(link_info._last_time)link_info._last_time=0}}change(){if(LiteGraph.debug){console.log("Graph changed")}this.canvasAction(c=>c.setDirty(true,true));this.on_change?.(this)}setDirtyCanvas(fg,bg){this.canvasAction(c=>c.setDirty(fg,bg))}addFloatingLink(link){if(link.id===-1){link.id=++this.#lastFloatingLinkId}this.#floatingLinks.set(link.id,link);const slot=link.target_id!==-1?this.getNodeById(link.target_id)?.inputs?.[link.target_slot]:this.getNodeById(link.origin_id)?.outputs?.[link.origin_slot];if(slot){slot._floatingLinks??=new Set;slot._floatingLinks.add(link)}else{console.warn(`Adding invalid floating link: target/slot: [${link.target_id}/${link.target_slot}] origin/slot: [${link.origin_id}/${link.origin_slot}]`)}const reroutes=LLink.getReroutes(this,link);for(const reroute of reroutes){reroute.floatingLinkIds.add(link.id)}return link}removeFloatingLink(link){this.#floatingLinks.delete(link.id);const slot=link.target_id!==-1?this.getNodeById(link.target_id)?.inputs?.[link.target_slot]:this.getNodeById(link.origin_id)?.outputs?.[link.origin_slot];if(slot){slot._floatingLinks?.delete(link)}const reroutes=LLink.getReroutes(this,link);for(const reroute of reroutes){reroute.floatingLinkIds.delete(link.id);if(reroute.floatingLinkIds.size===0){delete reroute.floating}if(reroute.totalLinks===0)this.removeReroute(reroute.id)}}getLink(id){return id==null?void 0:this._links.get(id)}getReroute(id){return id==null?void 0:this.reroutes.get(id)}setReroute({id,parentId,pos,linkIds,floating}){id??=++this.state.lastRerouteId;if(id>this.state.lastRerouteId)this.state.lastRerouteId=id;const reroute=this.reroutes.get(id)??new Reroute(id,this);reroute.update(parentId,pos,linkIds,floating);this.reroutes.set(id,reroute);return reroute}createReroute(pos,before){const rerouteId=++this.state.lastRerouteId;const linkIds=before instanceof Reroute?before.linkIds:[before.id];const floatingLinkIds=before instanceof Reroute?before.floatingLinkIds:[before.id];const reroute=new Reroute(rerouteId,this,pos,before.parentId,linkIds,floatingLinkIds);this.reroutes.set(rerouteId,reroute);for(const linkId of linkIds){const link=this._links.get(linkId);if(!link)continue;if(link.parentId===before.parentId)link.parentId=rerouteId;const reroutes=LLink.getReroutes(this,link);for(const x2 of reroutes.filter(x22=>x22.parentId===before.parentId)){x2.parentId=rerouteId}}for(const linkId of floatingLinkIds){const link=this.floatingLinks.get(linkId);if(!link)continue;if(link.parentId===before.parentId)link.parentId=rerouteId;const reroutes=LLink.getReroutes(this,link);for(const x2 of reroutes.filter(x22=>x22.parentId===before.parentId)){x2.parentId=rerouteId}}return reroute}removeReroute(id){const{reroutes}=this;const reroute=reroutes.get(id);if(!reroute)return;this.canvasAction(c=>c.deselect(reroute));const{parentId,linkIds,floatingLinkIds}=reroute;for(const reroute2 of reroutes.values()){if(reroute2.parentId===id)reroute2.parentId=parentId}for(const linkId of linkIds){const link=this._links.get(linkId);if(link&&link.parentId===id)link.parentId=parentId}for(const linkId of floatingLinkIds){const link=this.floatingLinks.get(linkId);if(!link){console.warn(`Removed reroute had floating link ID that did not exist [${linkId}]`);continue}const floatingReroutes=LLink.getReroutes(this,link);const lastReroute=floatingReroutes.at(-1);const secondLastReroute=floatingReroutes.at(-2);if(reroute!==lastReroute){continue}else if(secondLastReroute?.totalLinks!==1){this.removeFloatingLink(link)}else if(link.parentId===id){link.parentId=parentId;secondLastReroute.floating=reroute.floating}}reroutes.delete(id);this.setDirtyCanvas(false,true)}removeLink(link_id){const link=this._links.get(link_id);if(!link)return;const node2=this.getNodeById(link.target_id);node2?.disconnectInput(link.target_slot,false);link.disconnect(this)}createSubgraph(data){const{id}=data;const subgraph=new Subgraph(this.rootGraph,data);this.subgraphs.set(id,subgraph);this.rootGraph.events.dispatch("subgraph-created",{subgraph,data});return subgraph}convertToSubgraph(items){if(items.size===0)throw new Error("Cannot convert to subgraph: nothing to convert");const{state,revision,config}=this;const{boundaryLinks,boundaryFloatingLinks,internalLinks,boundaryInputLinks,boundaryOutputLinks}=getBoundaryLinks(this,items);const{nodes,reroutes,groups}=splitPositionables(items);const boundingRect=createBounds(items);if(!boundingRect)throw new Error("Failed to create bounding rect for subgraph");const resolvedInputLinks=boundaryInputLinks.map(x2=>x2.resolve(this));const resolvedOutputLinks=boundaryOutputLinks.map(x2=>x2.resolve(this));const clonedNodes=multiClone(nodes);const links=internalLinks.map(x2=>x2.asSerialisable());const inputs=mapSubgraphInputsAndLinks(resolvedInputLinks,links);const outputs=mapSubgraphOutputsAndLinks(resolvedOutputLinks,links);const data={id:createUuidv4(),name:"New Subgraph",inputNode:{id:SUBGRAPH_INPUT_ID,bounding:[0,0,75,100]},outputNode:{id:SUBGRAPH_OUTPUT_ID,bounding:[0,0,75,100]},inputs,outputs,widgets:[],version:LGraph.serialisedSchemaVersion,state,revision,config,links,nodes:clonedNodes,reroutes:structuredClone([...reroutes].map(reroute=>reroute.asSerialisable())),groups:structuredClone([...groups].map(group=>group.serialize()))};const subgraph=this.createSubgraph(data);subgraph.configure(data);subgraph.inputNode.arrange();subgraph.outputNode.arrange();const{boundingRect:inputRect}=subgraph.inputNode;const{boundingRect:outputRect}=subgraph.outputNode;alignOutsideContainer(inputRect,Alignment.MidLeft,boundingRect,[50,0]);alignOutsideContainer(outputRect,Alignment.MidRight,boundingRect,[50,0]);for(const resolved of resolvedInputLinks)resolved.inputNode?.disconnectInput(resolved.inputNode.inputs.indexOf(resolved.input),true);for(const resolved of resolvedOutputLinks)resolved.outputNode?.disconnectOutput(resolved.outputNode.outputs.indexOf(resolved.output),resolved.inputNode);for(const node2 of nodes)this.remove(node2);for(const reroute of reroutes)this.removeReroute(reroute.id);for(const group of groups)this.remove(group);this.rootGraph.events.dispatch("convert-to-subgraph",{subgraph,bounds:boundingRect,exportedSubgraph:data,boundaryLinks,resolvedInputLinks,resolvedOutputLinks,boundaryFloatingLinks,internalLinks});const subgraphNode=LiteGraph.createNode(subgraph.id,subgraph.name,{inputs:structuredClone(inputs),outputs:structuredClone(outputs)});if(!subgraphNode)throw new Error("Failed to create subgraph node");subgraphNode.setSize(subgraphNode.computeSize());alignToContainer(subgraphNode._posSize,Alignment.Centre|Alignment.Middle,boundingRect);this.add(subgraphNode);const groupedByOutput=groupResolvedByOutput(resolvedInputLinks);let i=0;for(const[,connections]of groupedByOutput.entries()){const[firstResolved,...others]=connections;const{output,outputNode,link,subgraphInput}=firstResolved;i++;if(link.origin_id===SUBGRAPH_INPUT_ID){link.target_id=subgraphNode.id;link.target_slot=i-1;if(subgraphInput instanceof SubgraphInput){subgraphInput.connect(subgraphNode.findInputSlotByType(link.type,true,true),subgraphNode,link.parentId)}else{throw new TypeError("Subgraph input node is not a SubgraphInput")}console.debug("Reconnect input links in parent graph",{...link},this.links.get(link.id),this.links.get(link.id)===link);for(const resolved of others){resolved.link.disconnect(this)}continue}if(!output||!outputNode){console.warn("Convert to Subgraph reconnect: Failed to resolve input link",connections[0]);continue}const input=subgraphNode.findInputSlotByType(link.type,true,true);outputNode.connectSlots(output,subgraphNode,input,link.parentId)}const outputsGroupedByOutput=groupResolvedByOutput(resolvedOutputLinks);i=0;for(const[,connections]of outputsGroupedByOutput.entries()){i++;for(const connection of connections){const{input,inputNode,link,subgraphOutput}=connection;if(link.target_id===SUBGRAPH_OUTPUT_ID){link.origin_id=subgraphNode.id;link.origin_slot=i-1;this.links.set(link.id,link);if(subgraphOutput instanceof SubgraphOutput){subgraphOutput.connect(subgraphNode.findOutputSlotByType(link.type,true,true),subgraphNode,link.parentId)}else{throw new TypeError("Subgraph input node is not a SubgraphInput")}continue}if(!input||!inputNode){console.warn("Convert to Subgraph reconnect: Failed to resolve output link",connection);continue}const output=subgraphNode.outputs[i-1];subgraphNode.connectSlots(output,inputNode,input,link.parentId)}}return{subgraph,node:subgraphNode}}resolveSubgraphIdPath(nodeIds){const result=[];let currentGraph=this.rootGraph;for(const nodeId of nodeIds){const node2=currentGraph.getNodeById(nodeId);if(!node2)throw new Error(`Node [${nodeId}] not found. ID Path: ${nodeIds.join(":")}`);if(!node2.isSubgraphNode())throw new Error(`Node [${nodeId}] is not a SubgraphNode. ID Path: ${nodeIds.join(":")}`);result.push(node2);currentGraph=node2.subgraph}return result}serialize(option){const{config,state,groups,nodes,reroutes,extra,floatingLinks,definitions}=this.asSerialisable(option);const linkArray=[...this._links.values()];const links=linkArray.map(x2=>x2.serialize());if(reroutes?.length){extra.linkExtensions=linkArray.filter(x2=>x2.parentId!==void 0).map(x2=>({id:x2.id,parentId:x2.parentId}))}extra.reroutes=reroutes?.length?reroutes:void 0;return{id:this.id,revision:this.revision,last_node_id:state.lastNodeId,last_link_id:state.lastLinkId,nodes,links,floatingLinks,groups,definitions,config,extra,version:LiteGraph.VERSION}}#getDragAndScale(){const ds=this.list_of_graphcanvas?.at(0)?.ds;if(ds)return{scale:ds.scale,offset:ds.offset}}asSerialisable(options){const{id,revision,config,state}=this;const nodeList=!LiteGraph.use_uuids&&options?.sortNodes?[...this._nodes].sort((a,b)=>a.id-b.id):this._nodes;const nodes=nodeList.map(node2=>node2.serialize());const groups=this._groups.map(x2=>x2.serialize());const links=this._links.size?[...this._links.values()].map(x2=>x2.asSerialisable()):void 0;const floatingLinks=this.floatingLinks.size?[...this.floatingLinks.values()].map(x2=>x2.asSerialisable()):void 0;const reroutes=this.reroutes.size?[...this.reroutes.values()].map(x2=>x2.asSerialisable()):void 0;const extra={...this.extra};if(LiteGraph.saveViewportWithGraph)extra.ds=this.#getDragAndScale();if(!extra.ds)delete extra.ds;const data={id,revision,version:LGraph.serialisedSchemaVersion,config,state,groups,nodes,links,floatingLinks,reroutes,extra};if(this.isRootGraph&&this._subgraphs.size){const usedSubgraphIds=findUsedSubgraphIds(this,this._subgraphs);const usedSubgraphs=[...this._subgraphs.values()].filter(subgraph=>usedSubgraphIds.has(subgraph.id)).map(x2=>x2.asSerialisable());if(usedSubgraphs.length>0){data.definitions={subgraphs:usedSubgraphs}}}this.onSerialize?.(data);return data}_configureBase(data){const{id,extra}=data;if(id){this.id=id}else if(this.id===zeroUuid){this.id=createUuidv4()}this.extra=extra?structuredClone(extra):{};delete this.extra.linkExtensions}configure(data,keep_old){const options={data,clearGraph:!keep_old};const mayContinue=this.events.dispatch("configuring",options);if(!mayContinue)return;try{if(!data)return;if(options.clearGraph)this.clear();this._configureBase(data);let reroutes;if(data.version===.4){const{extra}=data;if(Array.isArray(data.links)){for(const linkData of data.links){const link=LLink.createFromArray(linkData);this._links.set(link.id,link)}}if(Array.isArray(extra?.linkExtensions)){for(const linkEx of extra.linkExtensions){const link=this._links.get(linkEx.id);if(link)link.parentId=linkEx.parentId}}reroutes=extra?.reroutes}else{if(data.state){const{lastGroupId,lastLinkId,lastNodeId,lastRerouteId}=data.state;const{state}=this;if(lastGroupId!=null)state.lastGroupId=lastGroupId;if(lastLinkId!=null)state.lastLinkId=lastLinkId;if(lastNodeId!=null)state.lastNodeId=lastNodeId;if(lastRerouteId!=null)state.lastRerouteId=lastRerouteId}if(Array.isArray(data.links)){for(const linkData of data.links){const link=LLink.create(linkData);this._links.set(link.id,link)}}reroutes=data.reroutes}if(Array.isArray(reroutes)){for(const rerouteData of reroutes){this.setReroute(rerouteData)}}const nodesData=data.nodes;for(const i in data){if(LGraph.ConfigureProperties.has(i))continue;this[i]=data[i]}const subgraphs=data.definitions?.subgraphs;if(subgraphs){for(const subgraph of subgraphs)this.createSubgraph(subgraph);for(const subgraph of subgraphs)this.subgraphs.get(subgraph.id)?.configure(subgraph)}let error=false;const nodeDataMap=new Map;this._nodes=[];if(nodesData){for(const n_info of nodesData){let node2=LiteGraph.createNode(String(n_info.type),n_info.title);if(!node2){if(LiteGraph.debug)console.log("Node not found or has errors:",n_info.type);node2=new LGraphNode("");node2.last_serialization=n_info;node2.has_errors=true;error=true}node2.id=n_info.id;this.add(node2,true);nodeDataMap.set(node2.id,n_info)}for(const[id,nodeData]of nodeDataMap){this.getNodeById(id)?.configure(nodeData)}}if(Array.isArray(data.floatingLinks)){for(const linkData of data.floatingLinks){const floatingLink=LLink.create(linkData);this.addFloatingLink(floatingLink);if(floatingLink.id>this.#lastFloatingLinkId)this.#lastFloatingLinkId=floatingLink.id}}for(const reroute of this.reroutes.values()){if(!reroute.validateLinks(this._links,this.floatingLinks)){this.reroutes.delete(reroute.id)}}this._groups.length=0;const groupData=data.groups;if(groupData){for(const data2 of groupData){const group=new LiteGraph.LGraphGroup;group.configure(data2);this.add(group)}}this.updateExecutionOrder();this.onConfigure?.(data);this._version++;const{primaryCanvas}=this;const subgraphId=primaryCanvas?.subgraph?.id;if(subgraphId){const subgraph=this.subgraphs.get(subgraphId);if(subgraph){primaryCanvas.setGraph(subgraph)}else{primaryCanvas.setGraph(this)}}this.setDirtyCanvas(true,true);return error}finally{this.events.dispatch("configured")}}#canvas;get primaryCanvas(){return this.rootGraph.#canvas}set primaryCanvas(canvas2){this.rootGraph.#canvas=canvas2}load(url,callback){const that=this;if(url instanceof Blob||url instanceof File){const reader=new FileReader;reader.addEventListener("load",function(event){const result=stringOrEmpty(event.target?.result);const data=JSON.parse(result);that.configure(data);callback?.()});reader.readAsText(url);return}const req=new XMLHttpRequest;req.open("GET",url,true);req.send(null);req.addEventListener("load",function(){if(req.status!==200){console.error("Error loading graph:",req.status,req.response);return}const data=JSON.parse(req.response);that.configure(data);callback?.()});req.addEventListener("error",err=>{console.error("Error loading graph:",err)})}}class Subgraph extends LGraph{static MAX_NESTED_SUBGRAPHS=1e3;name="Unnamed Subgraph";inputNode=new SubgraphInputNode(this);outputNode=new SubgraphOutputNode(this);inputs=[];outputs=[];widgets=[];#rootGraph;get rootGraph(){return this.#rootGraph}constructor(rootGraph,data){if(!rootGraph)throw new Error("Root graph is required");super();this.#rootGraph=rootGraph;const cloned=structuredClone(data);this._configureBase(cloned);this.#configureSubgraph(cloned)}getIoNodeOnPos(x2,y){const{inputNode,outputNode}=this;if(inputNode.containsPoint([x2,y]))return inputNode;if(outputNode.containsPoint([x2,y]))return outputNode}#configureSubgraph(data){const{name,inputs,outputs,widgets}=data;this.name=name;if(inputs){this.inputs.length=0;for(const input of inputs){const subgraphInput=new SubgraphInput(input,this.inputNode);this.inputs.push(subgraphInput);this.events.dispatch("input-added",{input:subgraphInput})}}if(outputs){this.outputs.length=0;for(const output of outputs){this.outputs.push(new SubgraphOutput(output,this.outputNode))}}if(widgets){this.widgets.length=0;for(const widget of widgets){this.widgets.push(widget)}}this.inputNode.configure(data.inputNode);this.outputNode.configure(data.outputNode)}configure(data,keep_old){const r=super.configure(data,keep_old);this.#configureSubgraph(data);return r}attachCanvas(canvas2){super.attachCanvas(canvas2);canvas2.subgraph=this}addInput(name,type){this.events.dispatch("adding-input",{name,type});const input=new SubgraphInput({id:createUuidv4(),name,type},this.inputNode);this.inputs.push(input);this.events.dispatch("input-added",{input});return input}addOutput(name,type){this.events.dispatch("adding-output",{name,type});const output=new SubgraphOutput({id:createUuidv4(),name,type},this.outputNode);this.outputs.push(output);this.events.dispatch("output-added",{output});return output}renameInput(input,name){const index=this.inputs.indexOf(input);if(index===-1)throw new Error("Input not found");const oldName=input.displayName;this.events.dispatch("renaming-input",{input,index,oldName,newName:name});input.label=name}renameOutput(output,name){const index=this.outputs.indexOf(output);if(index===-1)throw new Error("Output not found");const oldName=output.displayName;this.events.dispatch("renaming-output",{output,index,oldName,newName:name});output.label=name}removeInput(input){input.disconnect();const index=this.inputs.indexOf(input);if(index===-1)throw new Error("Input not found");const mayContinue=this.events.dispatch("removing-input",{input,index});if(!mayContinue)return;this.inputs.splice(index,1);const{length}=this.inputs;for(let i=index;i<length;i++){this.inputs[i].decrementSlots("inputs")}}removeOutput(output){output.disconnect();const index=this.outputs.indexOf(output);if(index===-1)throw new Error("Output not found");const mayContinue=this.events.dispatch("removing-output",{output,index});if(!mayContinue)return;this.outputs.splice(index,1);const{length}=this.outputs;for(let i=index;i<length;i++){this.outputs[i].decrementSlots("outputs")}}draw(ctx,colorContext,fromSlot,editorAlpha){this.inputNode.draw(ctx,colorContext,fromSlot,editorAlpha);this.outputNode.draw(ctx,colorContext,fromSlot,editorAlpha)}clone(keepId=false){const exported=this.asSerialisable();if(!keepId)exported.id=createUuidv4();const subgraph=new Subgraph(this.rootGraph,exported);subgraph.configure(exported);return subgraph}asSerialisable(){return{id:this.id,version:LGraph.serialisedSchemaVersion,state:this.state,revision:this.revision,config:this.config,name:this.name,inputNode:this.inputNode.asSerialisable(),outputNode:this.outputNode.asSerialisable(),inputs:this.inputs.map(x2=>x2.asSerialisable()),outputs:this.outputs.map(x2=>x2.asSerialisable()),widgets:[...this.widgets],nodes:this.nodes.map(node2=>node2.serialize()),groups:this.groups.map(group=>group.serialize()),links:[...this.links.values()].map(x2=>x2.asSerialisable()),extra:this.extra}}}class InputIndicators{constructor(canvas2){this.canvas=canvas2;this.controller=new AbortController;const{signal}=this.controller;const element=canvas2.canvas;const options={capture:true,signal};element.addEventListener("pointerdown",this.#onPointerDownOrMove,options);element.addEventListener("pointermove",this.#onPointerDownOrMove,options);element.addEventListener("pointerup",this.#onPointerUp,options);element.addEventListener("keydown",this.#onKeyDownOrUp,options);document.addEventListener("keyup",this.#onKeyDownOrUp,options);const origDrawFrontCanvas=canvas2.drawFrontCanvas.bind(canvas2);signal.addEventListener("abort",()=>{canvas2.drawFrontCanvas=origDrawFrontCanvas});canvas2.drawFrontCanvas=()=>{origDrawFrontCanvas();this.draw()}}radius=8;startAngle=0;endAngle=Math.PI*2;inactiveColour="#ffffff10";colour1="#ff5f00";colour2="#00ff7c";colour3="#dea7ff";fontString="bold 12px Arial";enabled=true;shiftDown=false;undoDown=false;redoDown=false;ctrlDown=false;altDown=false;mouse0Down=false;mouse1Down=false;mouse2Down=false;x=0;y=0;controller;#onPointerDownOrMove=this.onPointerDownOrMove.bind(this);onPointerDownOrMove(e2){this.mouse0Down=(e2.buttons&1)===1;this.mouse1Down=(e2.buttons&4)===4;this.mouse2Down=(e2.buttons&2)===2;this.x=e2.clientX;this.y=e2.clientY;this.canvas.setDirty(true)}#onPointerUp=this.onPointerUp.bind(this);onPointerUp(){this.mouse0Down=false;this.mouse1Down=false;this.mouse2Down=false}#onKeyDownOrUp=this.onKeyDownOrUp.bind(this);onKeyDownOrUp(e2){this.ctrlDown=e2.ctrlKey;this.altDown=e2.altKey;this.shiftDown=e2.shiftKey;this.undoDown=e2.ctrlKey&&e2.code==="KeyZ"&&e2.type==="keydown";this.redoDown=e2.ctrlKey&&e2.code==="KeyY"&&e2.type==="keydown"}draw(){const{canvas:{ctx},radius,startAngle,endAngle,x:x2,y,inactiveColour,colour1,colour2,colour3,fontString}=this;const{fillStyle,font}=ctx;const mouseDotX=x2;const mouseDotY=y-80;const textX=mouseDotX;const textY=mouseDotY-15;ctx.font=fontString;textMarker(textX+0,textY,"Shift",this.shiftDown?colour1:inactiveColour);textMarker(textX+45,textY+20,"Alt",this.altDown?colour2:inactiveColour);textMarker(textX+30,textY,"Control",this.ctrlDown?colour3:inactiveColour);textMarker(textX-30,textY,"↩️",this.undoDown?"#000":"transparent");textMarker(textX+45,textY,"↪️",this.redoDown?"#000":"transparent");ctx.beginPath();drawDot(mouseDotX,mouseDotY);drawDot(mouseDotX+15,mouseDotY);drawDot(mouseDotX+30,mouseDotY);ctx.fillStyle=inactiveColour;ctx.fill();const leftButtonColour=this.mouse0Down?colour1:inactiveColour;const middleButtonColour=this.mouse1Down?colour2:inactiveColour;const rightButtonColour=this.mouse2Down?colour3:inactiveColour;if(this.mouse0Down)mouseMarker(mouseDotX,mouseDotY,leftButtonColour);if(this.mouse1Down)mouseMarker(mouseDotX+15,mouseDotY,middleButtonColour);if(this.mouse2Down)mouseMarker(mouseDotX+30,mouseDotY,rightButtonColour);ctx.fillStyle=fillStyle;ctx.font=font;function textMarker(x22,y2,text,colour){ctx.fillStyle=colour;ctx.fillText(text,x22,y2)}function mouseMarker(x22,y2,colour){ctx.beginPath();ctx.fillStyle=colour;drawDot(x22,y2);ctx.fill()}function drawDot(x22,y2){ctx.arc(x22,y2,radius,startAngle,endAngle)}}dispose(){this.controller?.abort();this.controller=void 0}[Symbol.dispose](){this.dispose()}}class ContextMenu{options;parentMenu;root;current_submenu;lock;controller=new AbortController;constructor(values,options){options||={};this.options=options;const parent=options.parentMenu;if(parent){if(!(parent instanceof ContextMenu)){console.error("parentMenu must be of class ContextMenu, ignoring it");options.parentMenu=void 0}else{this.parentMenu=parent;this.parentMenu.lock=true;this.parentMenu.current_submenu=this}if(parent.options?.className==="dark"){options.className="dark"}}const eventClass=options.event?options.event.constructor.name:null;if(eventClass!=="MouseEvent"&&eventClass!=="CustomEvent"&&eventClass!=="PointerEvent"){console.error(`Event passed to ContextMenu is not of type MouseEvent or CustomEvent. Ignoring it. (${eventClass})`);options.event=void 0}const root=document.createElement("div");let classes="litegraph litecontextmenu litemenubar-panel";if(options.className)classes+=` ${options.className}`;root.className=classes;root.style.minWidth="100";root.style.minHeight="100";const{signal}=this.controller;const eventOptions={capture:true,signal};if(!this.parentMenu){document.addEventListener("pointerdown",e2=>{if(e2.target instanceof Node&&!this.containsNode(e2.target)){this.close()}},eventOptions)}root.addEventListener("pointerup",e2=>e2.preventDefault(),eventOptions);root.addEventListener("contextmenu",e2=>{if(e2.button===2)e2.preventDefault()},eventOptions);root.addEventListener("pointerdown",e2=>{if(e2.button==2){this.close();e2.preventDefault()}},eventOptions);this.root=root;if(options.title){const element=document.createElement("div");element.className="litemenu-title";element.innerHTML=options.title;root.append(element)}for(let i=0;i<values.length;i++){const value=values[i];let name=Array.isArray(values)?value:String(i);if(typeof name!=="string"){name=name!=null?name.content===void 0?String(name):name.content:name}this.addItem(name,value,options)}const ownerDocument=options.event?.target?.ownerDocument;const root_document=ownerDocument||document;if(root_document.fullscreenElement)root_document.fullscreenElement.append(root);else root_document.body.append(root);let left=options.left||0;let top=options.top||0;if(options.event){left=options.event.clientX-10;top=options.event.clientY-10;if(options.title)top-=20;if(parent){const rect=parent.root.getBoundingClientRect();left=rect.left+rect.width}const body_rect=document.body.getBoundingClientRect();const root_rect=root.getBoundingClientRect();if(body_rect.height==0)console.error("document.body height is 0. That is dangerous, set html,body { height: 100%; }");if(body_rect.width&&left>body_rect.width-root_rect.width-10)left=body_rect.width-root_rect.width-10;if(body_rect.height&&top>body_rect.height-root_rect.height-10)top=body_rect.height-root_rect.height-10}root.style.left=`${left}px`;root.style.top=`${top}px`;if(LiteGraph.context_menu_scaling&&options.scale){root.style.transform=`scale(${Math.round(options.scale*4)*.25})`}}containsNode(node2,visited=new Set){if(visited.has(this))return false;visited.add(this);return this.current_submenu?.containsNode(node2,visited)||this.root.contains(node2)}addItem(name,value,options){options||={};const element=document.createElement("div");element.className="litemenu-entry submenu";let disabled=false;if(value===null){element.classList.add("separator")}else{const innerHtml=name===null?"":String(name);if(typeof value==="string"){element.innerHTML=innerHtml}else{element.innerHTML=value?.title??innerHtml;if(value.disabled){disabled=true;element.classList.add("disabled");element.setAttribute("aria-disabled","true")}if(value.submenu||value.has_submenu){element.classList.add("has_submenu");element.setAttribute("aria-haspopup","true");element.setAttribute("aria-expanded","false")}if(value.className)element.className+=` ${value.className}`}element.value=value;element.setAttribute("role","menuitem");if(typeof value==="function"){element.dataset["value"]=String(name);element.onclick_callback=value}else{element.dataset["value"]=String(value)}}this.root.append(element);if(!disabled)element.addEventListener("click",inner_onclick);if(!disabled&&options.autoopen)element.addEventListener("pointerenter",inner_over);const setAriaExpanded=()=>{const entries=this.root.querySelectorAll("div.litemenu-entry.has_submenu");if(entries){for(const entry of entries){entry.setAttribute("aria-expanded","false")}}element.setAttribute("aria-expanded","true")};function inner_over(e2){const value2=this.value;if(!value2||!value2.has_submenu)return;inner_onclick.call(this,e2);setAriaExpanded()}const that=this;function inner_onclick(e2){const value2=this.value;let close_parent=true;that.current_submenu?.close(e2);if(value2?.has_submenu||value2?.submenu){setAriaExpanded()}if(options.callback){const r=options.callback.call(this,value2,options,e2,that,options.node);if(r===true)close_parent=false}if(typeof value2==="object"){if(value2.callback&&!options.ignore_item_callbacks&&value2.disabled!==true){const r=value2.callback.call(this,value2,options,e2,that,options.extra);if(r===true)close_parent=false}if(value2.submenu){if(!value2.submenu.options)throw"ContextMenu submenu needs options";new that.constructor(value2.submenu.options,{callback:value2.submenu.callback,event:e2,parentMenu:that,ignore_item_callbacks:value2.submenu.ignore_item_callbacks,title:value2.submenu.title,extra:value2.submenu.extra,autoopen:options.autoopen});close_parent=false}}if(close_parent&&!that.lock)that.close()}return element}close(e2,ignore_parent_menu){this.controller.abort();this.root.remove();if(this.parentMenu&&!ignore_parent_menu){this.parentMenu.lock=false;this.parentMenu.current_submenu=void 0;if(e2===void 0){this.parentMenu.close()}else if(e2&&!ContextMenu.isCursorOverElement(e2,this.parentMenu.root)){ContextMenu.trigger(this.parentMenu.root,`${LiteGraph.pointerevents_method}leave`,e2)}}this.current_submenu?.close(e2,true)}static trigger(element,event_name,params){const evt=document.createEvent("CustomEvent");evt.initCustomEvent(event_name,true,true,params);if(element.dispatchEvent)element.dispatchEvent(evt);return evt}getTopMenu(){return this.options.parentMenu?this.options.parentMenu.getTopMenu():this}getFirstEvent(){return this.options.parentMenu?this.options.parentMenu.getFirstEvent():this.options.event}static isCursorOverElement(event,element){const left=event.clientX;const top=event.clientY;const rect=element.getBoundingClientRect();if(!rect)return false;if(top>rect.top&&top<rect.top+rect.height&&left>rect.left&&left<rect.left+rect.width){return true}return false}}class CurveEditor{points;selected;nearest;size;must_update;margin;_nearest;constructor(points){this.points=points;this.selected=-1;this.nearest=-1;this.size=null;this.must_update=true;this.margin=5}static sampleCurve(f,points){if(!points)return;for(let i=0;i<points.length-1;++i){const p=points[i];const pn=points[i+1];if(pn[0]<f)continue;const r=pn[0]-p[0];if(Math.abs(r)<1e-5)return p[1];const local_f=(f-p[0])/r;return p[1]*(1-local_f)+pn[1]*local_f}return 0}draw(ctx,size,graphcanvas,background_color,line_color,inactive=false){const points=this.points;if(!points)return;this.size=size;const w=size[0]-this.margin*2;const h=size[1]-this.margin*2;line_color=line_color||"#666";ctx.save();ctx.translate(this.margin,this.margin);if(background_color){ctx.fillStyle="#111";ctx.fillRect(0,0,w,h);ctx.fillStyle="#222";ctx.fillRect(w*.5,0,1,h);ctx.strokeStyle="#333";ctx.strokeRect(0,0,w,h)}ctx.strokeStyle=line_color;if(inactive)ctx.globalAlpha=.5;ctx.beginPath();for(const p of points){ctx.lineTo(p[0]*w,(1-p[1])*h)}ctx.stroke();ctx.globalAlpha=1;if(!inactive){for(const[i,p]of points.entries()){ctx.fillStyle=this.selected==i?"#FFF":this.nearest==i?"#DDD":"#AAA";ctx.beginPath();ctx.arc(p[0]*w,(1-p[1])*h,2,0,Math.PI*2);ctx.fill()}}ctx.restore()}onMouseDown(localpos,graphcanvas){const points=this.points;if(!points)return;if(localpos[1]<0)return;if(this.size==null)throw new Error("CurveEditor.size was null or undefined.");const w=this.size[0]-this.margin*2;const h=this.size[1]-this.margin*2;const x2=localpos[0]-this.margin;const y=localpos[1]-this.margin;const pos=[x2,y];const max_dist=30/graphcanvas.ds.scale;this.selected=this.getCloserPoint(pos,max_dist);if(this.selected==-1){const point=[x2/w,1-y/h];points.push(point);points.sort(function(a,b){return a[0]-b[0]});this.selected=points.indexOf(point);this.must_update=true}if(this.selected!=-1)return true}onMouseMove(localpos,graphcanvas){const points=this.points;if(!points)return;const s=this.selected;if(s<0)return;if(this.size==null)throw new Error("CurveEditor.size was null or undefined.");const x2=(localpos[0]-this.margin)/(this.size[0]-this.margin*2);const y=(localpos[1]-this.margin)/(this.size[1]-this.margin*2);const curvepos=[localpos[0]-this.margin,localpos[1]-this.margin];const max_dist=30/graphcanvas.ds.scale;this._nearest=this.getCloserPoint(curvepos,max_dist);const point=points[s];if(point){const is_edge_point=s==0||s==points.length-1;if(!is_edge_point&&(localpos[0]<-10||localpos[0]>this.size[0]+10||localpos[1]<-10||localpos[1]>this.size[1]+10)){points.splice(s,1);this.selected=-1;return}if(!is_edge_point)point[0]=clamp(x2,0,1);else point[0]=s==0?0:1;point[1]=1-clamp(y,0,1);points.sort(function(a,b){return a[0]-b[0]});this.selected=points.indexOf(point);this.must_update=true}}onMouseUp(){this.selected=-1;return false}getCloserPoint(pos,max_dist){const points=this.points;if(!points)return-1;max_dist=max_dist||30;if(this.size==null)throw new Error("CurveEditor.size was null or undefined.");const w=this.size[0]-this.margin*2;const h=this.size[1]-this.margin*2;const num=points.length;const p2=[0,0];let min_dist=1e6;let closest=-1;for(let i=0;i<num;++i){const p=points[i];p2[0]=p[0]*w;p2[1]=(1-p[1])*h;const dist=distance(pos,p2);if(dist>min_dist||dist>max_dist)continue;closest=i;min_dist=dist}return closest}}class LiteGraphGlobal{SlotShape=SlotShape;SlotDirection=SlotDirection;SlotType=SlotType;LabelPosition=LabelPosition;VERSION=.4;CANVAS_GRID_SIZE=10;NODE_TITLE_HEIGHT=30;NODE_TITLE_TEXT_Y=20;NODE_SLOT_HEIGHT=20;NODE_WIDGET_HEIGHT=20;NODE_WIDTH=140;NODE_MIN_WIDTH=50;NODE_COLLAPSED_RADIUS=10;NODE_COLLAPSED_WIDTH=80;NODE_TITLE_COLOR="#999";NODE_SELECTED_TITLE_COLOR="#FFF";NODE_TEXT_SIZE=14;NODE_TEXT_COLOR="#AAA";NODE_TEXT_HIGHLIGHT_COLOR="#EEE";NODE_SUBTEXT_SIZE=12;NODE_DEFAULT_COLOR="#333";NODE_DEFAULT_BGCOLOR="#353535";NODE_DEFAULT_BOXCOLOR="#666";NODE_DEFAULT_SHAPE=RenderShape.ROUND;NODE_BOX_OUTLINE_COLOR="#FFF";NODE_ERROR_COLOUR="#E00";NODE_FONT="Arial";DEFAULT_FONT="Arial";DEFAULT_SHADOW_COLOR="rgba(0,0,0,0.5)";DEFAULT_GROUP_FONT=24;DEFAULT_GROUP_FONT_SIZE;GROUP_FONT="Arial";WIDGET_BGCOLOR="#222";WIDGET_OUTLINE_COLOR="#666";WIDGET_ADVANCED_OUTLINE_COLOR="rgba(56, 139, 253, 0.8)";WIDGET_TEXT_COLOR="#DDD";WIDGET_SECONDARY_TEXT_COLOR="#999";WIDGET_DISABLED_TEXT_COLOR="#666";LINK_COLOR="#9A9";EVENT_LINK_COLOR="#A86";CONNECTING_LINK_COLOR="#AFA";MAX_NUMBER_OF_NODES=1e4;DEFAULT_POSITION=[100,100];VALID_SHAPES=["default","box","round","card"];ROUND_RADIUS=8;BOX_SHAPE=RenderShape.BOX;ROUND_SHAPE=RenderShape.ROUND;CIRCLE_SHAPE=RenderShape.CIRCLE;CARD_SHAPE=RenderShape.CARD;ARROW_SHAPE=RenderShape.ARROW;GRID_SHAPE=RenderShape.GRID;INPUT=NodeSlotType.INPUT;OUTPUT=NodeSlotType.OUTPUT;EVENT=-1;ACTION=-1;NODE_MODES=["Always","On Event","Never","On Trigger"];NODE_MODES_COLORS=["#666","#422","#333","#224","#626"];ALWAYS=LGraphEventMode.ALWAYS;ON_EVENT=LGraphEventMode.ON_EVENT;NEVER=LGraphEventMode.NEVER;ON_TRIGGER=LGraphEventMode.ON_TRIGGER;UP=LinkDirection.UP;DOWN=LinkDirection.DOWN;LEFT=LinkDirection.LEFT;RIGHT=LinkDirection.RIGHT;CENTER=LinkDirection.CENTER;LINK_RENDER_MODES=["Straight","Linear","Spline"];HIDDEN_LINK=LinkRenderType.HIDDEN_LINK;STRAIGHT_LINK=LinkRenderType.STRAIGHT_LINK;LINEAR_LINK=LinkRenderType.LINEAR_LINK;SPLINE_LINK=LinkRenderType.SPLINE_LINK;NORMAL_TITLE=TitleMode.NORMAL_TITLE;NO_TITLE=TitleMode.NO_TITLE;TRANSPARENT_TITLE=TitleMode.TRANSPARENT_TITLE;AUTOHIDE_TITLE=TitleMode.AUTOHIDE_TITLE;VERTICAL_LAYOUT="vertical";proxy=null;node_images_path="";debug=false;catch_exceptions=true;throw_errors=true;allow_scripts=false;registered_node_types={};node_types_by_file_extension={};Nodes={};Globals={};searchbox_extras={};node_box_coloured_when_on=false;node_box_coloured_by_mode=false;dialog_close_on_mouse_leave=false;dialog_close_on_mouse_leave_delay=500;shift_click_do_break_link_from=false;click_do_break_link_to=false;ctrl_alt_click_do_break_link=true;snaps_for_comfy=true;snap_highlights_node=true;alwaysSnapToGrid;snapToGrid;search_hide_on_mouse_leave=true;search_filter_enabled=false;search_show_all_on_open=true;auto_load_slot_types=false;registered_slot_in_types={};registered_slot_out_types={};slot_types_in=[];slot_types_out=[];slot_types_default_in={};slot_types_default_out={};alt_drag_do_clone_nodes=false;do_add_triggers_slots=false;allow_multi_output_for_events=true;middle_click_slot_add_default_node=false;release_link_on_empty_shows_menu=false;pointerevents_method="pointer";ctrl_shift_v_paste_connect_unselected_outputs=true;use_uuids=false;highlight_selected_group=true;context_menu_scaling=false;alwaysRepeatWarnings=false;onDeprecationWarning=[console.warn];macTrackpadGestures=false;macGesturesRequireMac=true;canvasNavigationMode="legacy";truncateWidgetTextEvenly=false;truncateWidgetValuesFirst=false;saveViewportWithGraph=true;LGraph=LGraph;LLink=LLink;LGraphNode=LGraphNode;LGraphGroup=LGraphGroup;DragAndScale=DragAndScale;LGraphCanvas=LGraphCanvas;ContextMenu=ContextMenu;CurveEditor=CurveEditor;Reroute=Reroute;constructor(){Object.defineProperty(this,"Classes",{writable:false})}Classes={get SubgraphSlot(){return SubgraphSlot},get SubgraphIONodeBase(){return SubgraphIONodeBase},get Rectangle(){return Rectangle},get InputIndicators(){return InputIndicators}};registerNodeType(type,base_class){if(!base_class.prototype)throw"Cannot register a simple object, it must be a class with a prototype";base_class.type=type;if(this.debug)console.log("Node registered:",type);const classname=base_class.name;const pos=type.lastIndexOf("/");base_class.category=type.substring(0,pos);base_class.title||=classname;for(const i in LGraphNode.prototype){base_class.prototype[i]||=LGraphNode.prototype[i]}const prev=this.registered_node_types[type];if(prev&&this.debug){console.log("replacing node type:",type)}this.registered_node_types[type]=base_class;if(base_class.constructor.name)this.Nodes[classname]=base_class;this.onNodeTypeRegistered?.(type,base_class);if(prev)this.onNodeTypeReplaced?.(type,base_class,prev);if(base_class.prototype.onPropertyChange)console.warn(`LiteGraph node class ${type} has onPropertyChange method, it must be called onPropertyChanged with d at the end`);if(this.auto_load_slot_types)new base_class(base_class.title||"tmpnode")}unregisterNodeType(type){const base_class=typeof type==="string"?this.registered_node_types[type]:type;if(!base_class)throw`node type not found: ${String(type)}`;delete this.registered_node_types[String(base_class.type)];const name=base_class.constructor.name;if(name)delete this.Nodes[name]}registerNodeAndSlotType(type,slot_type,out){out||=false;const base_class=typeof type==="string"&&this.registered_node_types[type]!=="anonymous"?this.registered_node_types[type]:type;const class_type=base_class.constructor.type;let allTypes=[];if(typeof slot_type==="string"){allTypes=slot_type.split(",")}else if(slot_type==this.EVENT||slot_type==this.ACTION){allTypes=["_event_"]}else{allTypes=["*"]}for(let slotType of allTypes){if(slotType==="")slotType="*";const register=out?this.registered_slot_out_types:this.registered_slot_in_types;register[slotType]??={nodes:[]};const{nodes}=register[slotType];if(!nodes.includes(class_type))nodes.push(class_type);const types=out?this.slot_types_out:this.slot_types_in;const type2=slotType.toLowerCase();if(!types.includes(type2)){types.push(type2);types.sort()}}}clearRegisteredTypes(){this.registered_node_types={};this.node_types_by_file_extension={};this.Nodes={};this.searchbox_extras={}}createNode(type,title,options){const base_class=this.registered_node_types[type];if(!base_class){if(this.debug)console.log(`GraphNode type "${type}" not registered.`);return null}title=title||base_class.title||type;let node2=null;if(this.catch_exceptions){try{node2=new base_class(title)}catch(error){console.error(error);return null}}else{node2=new base_class(title)}node2.type=type;if(!node2.title&&title)node2.title=title;node2.properties||={};node2.properties_info||=[];node2.flags||={};node2.size||=node2.computeSize();node2.pos||=[this.DEFAULT_POSITION[0],this.DEFAULT_POSITION[1]];node2.mode||=LGraphEventMode.ALWAYS;if(options){for(const i in options){node2[i]=options[i]}}node2.onNodeCreated?.();return node2}getNodeType(type){return this.registered_node_types[type]}getNodeTypesInCategory(category,filter){const r=[];for(const i in this.registered_node_types){const type=this.registered_node_types[i];if(type.filter!=filter)continue;if(category==""){if(type.category==null)r.push(type)}else if(type.category==category){r.push(type)}}return r}getNodeTypesCategories(filter){const categories={"":1};for(const i in this.registered_node_types){const type=this.registered_node_types[i];if(type.category&&!type.skip_list){if(type.filter!=filter)continue;categories[type.category]=1}}const result=[];for(const i in categories){result.push(i)}return result}reloadNodes(folder_wildcard){const tmp=document.getElementsByTagName("script");const script_files=[];for(const element of tmp){script_files.push(element)}const docHeadObj=document.getElementsByTagName("head")[0];folder_wildcard=document.location.href+folder_wildcard;for(const script_file of script_files){const src=script_file.src;if(!src||src.substr(0,folder_wildcard.length)!=folder_wildcard)continue;try{if(this.debug)console.log("Reloading:",src);const dynamicScript=document.createElement("script");dynamicScript.type="text/javascript";dynamicScript.src=src;docHeadObj.append(dynamicScript);script_file.remove()}catch(error){if(this.throw_errors)throw error;if(this.debug)console.log("Error while reloading",src)}}if(this.debug)console.log("Nodes reloaded")}cloneObject(obj,target){if(obj==null)return null;const r=JSON.parse(JSON.stringify(obj));if(!target)return r;for(const i in r){target[i]=r[i]}return target}uuidv4=createUuidv4;isValidConnection(type_a,type_b){if(type_a==""||type_a==="*")type_a=0;if(type_b==""||type_b==="*")type_b=0;if(!type_a||!type_b||type_a==type_b||type_a==this.EVENT&&type_b==this.ACTION){return true}type_a=String(type_a);type_b=String(type_b);type_a=type_a.toLowerCase();type_b=type_b.toLowerCase();if(!type_a.includes(",")&&!type_b.includes(","))return type_a==type_b;const supported_types_a=type_a.split(",");const supported_types_b=type_b.split(",");for(const a of supported_types_a){for(const b of supported_types_b){if(this.isValidConnection(a,b))return true}}return false}getParameterNames(func){return String(func).replaceAll(/\/\/.*$/gm,"").replaceAll(/\s+/g,"").replaceAll(/\/\*[^*/]*\*\//g,"").split("){",1)[0].replace(/^[^(]*\(/,"").replaceAll(/=[^,]+/g,"").split(",").filter(Boolean)}pointerListenerAdd(oDOM,sEvIn,fCall,capture=false){if(!oDOM||!oDOM.addEventListener||!sEvIn||typeof fCall!=="function")return;let sMethod=this.pointerevents_method;let sEvent=sEvIn;if(sMethod=="pointer"&&!window.PointerEvent){console.warn("sMethod=='pointer' && !window.PointerEvent");console.log(`Converting pointer[${sEvent}] : down move up cancel enter TO touchstart touchmove touchend, etc ..`);switch(sEvent){case"down":{sMethod="touch";sEvent="start";break}case"move":{sMethod="touch";break}case"up":{sMethod="touch";sEvent="end";break}case"cancel":{sMethod="touch";break}case"enter":{console.log("debug: Should I send a move event?");break}default:{console.warn(`PointerEvent not available in this browser ? The event ${sEvent} would not be called`)}}}switch(sEvent){case"down":case"up":case"move":case"over":case"out":case"enter":{oDOM.addEventListener(sMethod+sEvent,fCall,capture)}case"leave":case"cancel":case"gotpointercapture":case"lostpointercapture":{if(sMethod!="mouse"){return oDOM.addEventListener(sMethod+sEvent,fCall,capture)}}default:return oDOM.addEventListener(sEvent,fCall,capture)}}pointerListenerRemove(oDOM,sEvent,fCall,capture=false){if(!oDOM||!oDOM.removeEventListener||!sEvent||typeof fCall!=="function")return;switch(sEvent){case"down":case"up":case"move":case"over":case"out":case"enter":{if(this.pointerevents_method=="pointer"||this.pointerevents_method=="mouse"){oDOM.removeEventListener(this.pointerevents_method+sEvent,fCall,capture)}}case"leave":case"cancel":case"gotpointercapture":case"lostpointercapture":{if(this.pointerevents_method=="pointer"){return oDOM.removeEventListener(this.pointerevents_method+sEvent,fCall,capture)}}default:return oDOM.removeEventListener(sEvent,fCall,capture)}}getTime(){return performance.now()}distance=distance;colorToString(c){return`rgba(${Math.round(c[0]*255).toFixed()},${Math.round(c[1]*255).toFixed()},${Math.round(c[2]*255).toFixed()},${c.length==4?c[3].toFixed(2):"1.0"})`}isInsideRectangle=isInsideRectangle;growBounding(bounding,x2,y){if(x2<bounding[0]){bounding[0]=x2}else if(x2>bounding[2]){bounding[2]=x2}if(y<bounding[1]){bounding[1]=y}else if(y>bounding[3]){bounding[3]=y}}overlapBounding=overlapBounding;isInsideBounding(p,bb){if(p[0]<bb[0][0]||p[1]<bb[0][1]||p[0]>bb[1][0]||p[1]>bb[1][1]){return false}return true}hex2num(hex){if(hex.charAt(0)=="#"){hex=hex.slice(1)}hex=hex.toUpperCase();const hex_alphabets="0123456789ABCDEF";const value=new Array(3);let k=0;let int1,int2;for(let i=0;i<6;i+=2){int1=hex_alphabets.indexOf(hex.charAt(i));int2=hex_alphabets.indexOf(hex.charAt(i+1));value[k]=int1*16+int2;k++}return value}num2hex(triplet){const hex_alphabets="0123456789ABCDEF";let hex="#";let int1,int2;for(let i=0;i<3;i++){int1=triplet[i]/16;int2=triplet[i]%16;hex+=hex_alphabets.charAt(int1)+hex_alphabets.charAt(int2)}return hex}closeAllContextMenus(ref_window=window){const elements=[...ref_window.document.querySelectorAll(".litecontextmenu")];if(!elements.length)return;for(const element of elements){if("close"in element&&typeof element.close==="function"){element.close()}else{element.remove()}}}extendClass(target,origin){for(const i in origin){if(target.hasOwnProperty(i))continue;target[i]=origin[i]}if(origin.prototype){for(const i in origin.prototype){if(!origin.prototype.hasOwnProperty(i))continue;if(target.prototype.hasOwnProperty(i))continue;if(origin.prototype.__lookupGetter__(i)){target.prototype.__defineGetter__(i,origin.prototype.__lookupGetter__(i))}else{target.prototype[i]=origin.prototype[i]}if(origin.prototype.__lookupSetter__(i)){target.prototype.__defineSetter__(i,origin.prototype.__lookupSetter__(i))}}}}}Symbol.dispose??=Symbol("Symbol.dispose");Symbol.asyncDispose??=Symbol("Symbol.asyncDispose");function loadPolyfills(){if(typeof window!="undefined"&&window.CanvasRenderingContext2D&&!window.CanvasRenderingContext2D.prototype.roundRect){window.CanvasRenderingContext2D.prototype.roundRect=function(x2,y,w,h,radius,radius_low){let top_left_radius=0;let top_right_radius=0;let bottom_left_radius=0;let bottom_right_radius=0;if(radius===0){this.rect(x2,y,w,h);return}if(radius_low===void 0)radius_low=radius;if(Array.isArray(radius)){if(radius.length==1){top_left_radius=top_right_radius=bottom_left_radius=bottom_right_radius=radius[0]}else if(radius.length==2){top_left_radius=bottom_right_radius=radius[0];top_right_radius=bottom_left_radius=radius[1]}else if(radius.length==4){top_left_radius=radius[0];top_right_radius=radius[1];bottom_left_radius=radius[2];bottom_right_radius=radius[3]}else{return}}else{top_left_radius=radius||0;top_right_radius=radius||0;const low=!Array.isArray(radius_low)&&radius_low?radius_low:0;bottom_left_radius=low;bottom_right_radius=low}this.moveTo(x2+top_left_radius,y);this.lineTo(x2+w-top_right_radius,y);this.quadraticCurveTo(x2+w,y,x2+w,y+top_right_radius);this.lineTo(x2+w,y+h-bottom_right_radius);this.quadraticCurveTo(x2+w,y+h,x2+w-bottom_right_radius,y+h);this.lineTo(x2+bottom_right_radius,y+h);this.quadraticCurveTo(x2,y+h,x2,y+h-bottom_left_radius);this.lineTo(x2,y+bottom_left_radius);this.quadraticCurveTo(x2,y,x2+top_left_radius,y)}}if(typeof window!="undefined"&&!window["requestAnimationFrame"]){window.requestAnimationFrame=window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||function(callback){window.setTimeout(callback,1e3/60)}}}class InvalidLinkError extends Error{constructor(message="Attempted to access a link that was invalid.",cause){super(message,{cause});this.name="InvalidLinkError"}}class RecursionError extends Error{constructor(subject){super(subject);this.name="RecursionError"}}class SlotIndexError extends Error{constructor(message="Attempted to access a slot that was out of bounds.",cause){super(message,{cause});this.name="SlotIndexError"}}class ExecutableNodeDTO{constructor(node2,subgraphNodePath,nodesByExecutionId,subgraphNode){this.node=node2;this.subgraphNodePath=subgraphNodePath;this.nodesByExecutionId=nodesByExecutionId;this.subgraphNode=subgraphNode;if(!node2.graph)throw new NullGraphError;this.#id=[...this.subgraphNodePath,this.node.id].join(":");this.graph=node2.graph;this.inputs=this.node.inputs.map(x2=>({linkId:x2.link,name:x2.name,type:x2.type}));if(this.node.applyToGraph){this.applyToGraph=(...args)=>this.node.applyToGraph?.(...args)}}graph;inputs;#id;get id(){return this.#id}get type(){return this.node.type}get title(){return this.node.title}get mode(){return this.node.mode}get comfyClass(){return this.node.comfyClass}get isVirtualNode(){return this.node.isVirtualNode}get widgets(){return this.node.widgets}get subgraphId(){return this.subgraphNode?.subgraph.id}getInnerNodes(){return this.node.isSubgraphNode()?this.node.getInnerNodes(this.nodesByExecutionId,this.subgraphNodePath):[this]}resolveInput(slot,visited=new Set){const uniqueId=`${this.subgraphNode?.subgraph.id}:${this.node.id}[I]${slot}`;if(visited.has(uniqueId)){const nodeInfo=`${this.node.id}${this.node.title?` (${this.node.title})`:""}`;const pathInfo=this.subgraphNodePath.length>0?` at path ${this.subgraphNodePath.join(":")}`:"";throw new RecursionError(`Circular reference detected while resolving input ${slot} of node ${nodeInfo}${pathInfo}. This creates an infinite loop in link resolution. UniqueID: [${uniqueId}]`)}visited.add(uniqueId);const input=this.inputs.at(slot);if(!input)throw new SlotIndexError(`No input found for flattened id [${this.id}] slot [${slot}]`);if(input.linkId==null)return;const link=this.graph.getLink(input.linkId);if(!link)throw new InvalidLinkError(`No link found in parent graph for id [${this.id}] slot [${slot}] ${input.name}`);const{subgraphNode}=this;if(subgraphNode&&link.originIsIoNode){const subgraphNodeInput=subgraphNode.inputs.at(link.origin_slot);if(!subgraphNodeInput)throw new SlotIndexError(`No input found for slot [${link.origin_slot}] ${input.name}`);const linkId=subgraphNodeInput.link;if(linkId==null){const widget=subgraphNode.getWidgetFromSlot(subgraphNodeInput);if(!widget)return;return{node:this,origin_id:this.id,origin_slot:-1,widgetInfo:{value:widget.value}}}const outerLink=subgraphNode.graph.getLink(linkId);if(!outerLink)throw new InvalidLinkError(`No outer link found for slot [${link.origin_slot}] ${input.name}`);const subgraphNodeExecutionId=this.subgraphNodePath.join(":");const subgraphNodeDto=this.nodesByExecutionId.get(subgraphNodeExecutionId);if(!subgraphNodeDto)throw new Error(`No subgraph node DTO found for id [${subgraphNodeExecutionId}]`);return subgraphNodeDto.resolveInput(outerLink.target_slot,visited)}const outputNode=this.graph.getNodeById(link.origin_id);if(!outputNode)throw new InvalidLinkError(`No input node found for id [${this.id}] slot [${slot}] ${input.name}`);const outputNodeExecutionId=[...this.subgraphNodePath,outputNode.id].join(":");const outputNodeDto=this.nodesByExecutionId.get(outputNodeExecutionId);if(!outputNodeDto)throw new Error(`No output node DTO found for id [${outputNodeExecutionId}]`);return outputNodeDto.resolveOutput(link.origin_slot,input.type,visited)}resolveOutput(slot,type,visited){const uniqueId=`${this.subgraphNode?.subgraph.id}:${this.node.id}[O]${slot}`;if(visited.has(uniqueId)){const nodeInfo=`${this.node.id}${this.node.title?` (${this.node.title})`:""}`;const pathInfo=this.subgraphNodePath.length>0?` at path ${this.subgraphNodePath.join(":")}`:"";throw new RecursionError(`Circular reference detected while resolving output ${slot} of node ${nodeInfo}${pathInfo}. This creates an infinite loop in link resolution. UniqueID: [${uniqueId}]`)}visited.add(uniqueId);if(this.mode===LGraphEventMode.BYPASS){const{inputs}=this;const parentInputIndexes=Object.keys(inputs).map(Number);const indexes=[slot,...parentInputIndexes];const matchingIndex=indexes.find(i=>inputs[i]?.type===type);if(matchingIndex===void 0){console.debug(`[ExecutableNodeDTO.resolveOutput] No input types match type [${type}] for id [${this.id}] slot [${slot}]`,this);return}return this.resolveInput(matchingIndex,visited)}const{node:node2}=this;if(node2.isSubgraphNode())return this.#resolveSubgraphOutput(slot,type,visited);if(node2.isVirtualNode){if(this.inputs.at(slot))return this.resolveInput(slot,visited);const virtualLink=this.node.getInputLink(slot);if(virtualLink){const outputNode=this.graph.getNodeById(virtualLink.origin_id);if(!outputNode)throw new InvalidLinkError(`Virtual node failed to resolve parent [${this.id}] slot [${slot}]`);const outputNodeExecutionId=[...this.subgraphNodePath,outputNode.id].join(":");const outputNodeDto=this.nodesByExecutionId.get(outputNodeExecutionId);if(!outputNodeDto)throw new Error(`No output node DTO found for id [${outputNode.id}]`);return outputNodeDto.resolveOutput(virtualLink.origin_slot,type,visited)}return}return{node:this,origin_id:this.id,origin_slot:slot}}#resolveSubgraphOutput(slot,type,visited){const{node:node2}=this;const output=node2.outputs.at(slot);if(!output)throw new SlotIndexError(`No output found for flattened id [${this.id}] slot [${slot}]`);if(!node2.isSubgraphNode())throw new TypeError(`Node is not a subgraph node: ${node2.id}`);const innerResolved=node2.resolveSubgraphOutputLink(slot);if(!innerResolved)return;const innerNode=innerResolved.outputNode;if(!innerNode)throw new Error(`No output node found for id [${this.id}] slot [${slot}] ${output.name}`);const innerNodeExecutionId=[...this.subgraphNodePath,node2.id,innerNode.id].join(":");const innerNodeDto=this.nodesByExecutionId.get(innerNodeExecutionId);if(!innerNodeDto)throw new Error(`No inner node DTO found for id [${innerNodeExecutionId}]`);return innerNodeDto.resolveOutput(innerResolved.link.origin_slot,type,visited)}}class SubgraphNode extends LGraphNode{constructor(graph,subgraph,instanceData){super(subgraph.name,subgraph.id);this.graph=graph;this.subgraph=subgraph;const subgraphEvents=this.subgraph.events;const{signal}=this.#eventAbortController;subgraphEvents.addEventListener("input-added",e2=>{const subgraphInput=e2.detail.input;const{name,type}=subgraphInput;if(this.inputs.some(i=>i.name==name))return;const input=this.addInput(name,type);this.#addSubgraphInputListeners(subgraphInput,input)},{signal});subgraphEvents.addEventListener("removing-input",e2=>{const widget=e2.detail.input._widget;if(widget)this.ensureWidgetRemoved(widget);this.removeInput(e2.detail.index);this.setDirtyCanvas(true,true)},{signal});subgraphEvents.addEventListener("output-added",e2=>{const{name,type}=e2.detail.output;this.addOutput(name,type)},{signal});subgraphEvents.addEventListener("removing-output",e2=>{this.removeOutput(e2.detail.index);this.setDirtyCanvas(true,true)},{signal});subgraphEvents.addEventListener("renaming-input",e2=>{const{index,newName}=e2.detail;const input=this.inputs.at(index);if(!input)throw new Error("Subgraph input not found");input.label=newName},{signal});subgraphEvents.addEventListener("renaming-output",e2=>{const{index,newName}=e2.detail;const output=this.outputs.at(index);if(!output)throw new Error("Subgraph output not found");output.label=newName},{signal});this.type=subgraph.id;this.configure(instanceData);this.addTitleButton({name:"enter_subgraph",text:"",yOffset:0,xOffset:-10,fontSize:16})}type;isVirtualNode=true;get rootGraph(){return this.graph.rootGraph}get displayType(){return"Subgraph node"}isSubgraphNode(){return true}widgets=[];#eventAbortController=new AbortController;onTitleButtonClick(button,canvas2){if(button.name==="enter_subgraph"){canvas2.openSubgraph(this.subgraph)}else{super.onTitleButtonClick(button,canvas2)}}#addSubgraphInputListeners(subgraphInput,input){input._listenerController?.abort();input._listenerController=new AbortController;const{signal}=input._listenerController;subgraphInput.events.addEventListener("input-connected",()=>{if(input._widget)return;const widget=subgraphInput._widget;if(!widget)return;this.#setWidget(subgraphInput,input,widget)},{signal});subgraphInput.events.addEventListener("input-disconnected",()=>{const connectedWidgets=subgraphInput.getConnectedWidgets();if(connectedWidgets.length>0)return;this.removeWidgetByName(input.name);delete input.pos;delete input.widget;input._widget=void 0},{signal})}configure(info){for(const input of this.inputs){input._listenerController?.abort()}this.inputs.length=0;this.inputs.push(...this.subgraph.inputNode.slots.map(slot=>new NodeInputSlot({name:slot.name,localized_name:slot.localized_name,label:slot.label,type:slot.type,link:null},this)));this.outputs.length=0;this.outputs.push(...this.subgraph.outputNode.slots.map(slot=>new NodeOutputSlot({name:slot.name,localized_name:slot.localized_name,label:slot.label,type:slot.type,links:null},this)));super.configure(info)}_internalConfigureAfterSlots(){this.widgets.length=0;for(const input of this.inputs){const subgraphInput=this.subgraph.inputNode.slots.find(slot=>slot.name===input.name);if(!subgraphInput)throw new Error(`[SubgraphNode.configure] No subgraph input found for input ${input.name}`);this.#addSubgraphInputListeners(subgraphInput,input);for(const linkId of subgraphInput.linkIds){const link=this.subgraph.getLink(linkId);if(!link){console.warn(`[SubgraphNode.configure] No link found for link ID ${linkId}`,this);continue}const resolved=link.resolve(this.subgraph);if(!resolved.input||!resolved.inputNode){console.warn("Invalid resolved link",resolved,this);continue}const widget=resolved.inputNode.getWidgetFromSlot(resolved.input);if(!widget)continue;this.#setWidget(subgraphInput,input,widget);break}}}#setWidget(subgraphInput,input,widget){const promotedWidget=toConcreteWidget(widget,this).createCopyForNode(this);Object.assign(promotedWidget,{get name(){return subgraphInput.name},set name(value){console.warn("Promoted widget: setting name is not allowed",this,value)},get localized_name(){return subgraphInput.localized_name},set localized_name(value){console.warn("Promoted widget: setting localized_name is not allowed",this,value)},get label(){return subgraphInput.label},set label(value){console.warn("Promoted widget: setting label is not allowed",this,value)},get tooltip(){return widget.tooltip},set tooltip(value){console.warn("Promoted widget: setting tooltip is not allowed",this,value)}});this.widgets.push(promotedWidget);this.subgraph.events.dispatch("widget-promoted",{widget:promotedWidget,subgraphNode:this});input.widget={name:subgraphInput.name};input._widget=promotedWidget}addInput(name,type,inputProperties={}){return super.addInput(name,type,inputProperties)}getInputLink(slot){const innerLink=this.subgraph.outputNode.slots[slot].getLinks().at(0);if(!innerLink){console.warn(`SubgraphNode.getInputLink: no inner link found for slot ${slot}`);return null}const newLink=LLink.create(innerLink);newLink.origin_id=`${this.id}:${innerLink.origin_id}`;newLink.origin_slot=innerLink.origin_slot;return newLink}resolveSubgraphInputLinks(slot){const inputSlot=this.subgraph.inputNode.slots[slot];const innerLinks=inputSlot.getLinks();if(innerLinks.length===0){console.debug(`[SubgraphNode.resolveSubgraphInputLinks] No inner links found for input slot [${slot}] ${inputSlot.name}`,this);return[]}return innerLinks.map(link=>link.resolve(this.subgraph))}resolveSubgraphOutputLink(slot){const outputSlot=this.subgraph.outputNode.slots[slot];const innerLink=outputSlot.getLinks().at(0);if(innerLink)return innerLink.resolve(this.subgraph);console.debug(`[SubgraphNode.resolveSubgraphOutputLink] No inner link found for output slot [${slot}] ${outputSlot.name}`,this)}getInnerNodes(executableNodes,subgraphNodePath=[],nodes=[],visited=new Set){if(visited.has(this)){const nodeInfo=`${this.id}${this.title?` (${this.title})`:""}`;const subgraphInfo=`'${this.subgraph.name||"Unnamed Subgraph"}'`;const depth=subgraphNodePath.length;throw new RecursionError(`Circular reference detected at depth ${depth} in node ${nodeInfo} of subgraph ${subgraphInfo}. This creates an infinite loop in the subgraph hierarchy.`)}visited.add(this);const subgraphInstanceIdPath=[...subgraphNodePath,this.id];const parentSubgraphNode=this.graph.rootGraph.resolveSubgraphIdPath(subgraphNodePath).at(-1);const subgraphNodeDto=new ExecutableNodeDTO(this,subgraphNodePath,executableNodes,parentSubgraphNode);executableNodes.set(subgraphNodeDto.id,subgraphNodeDto);for(const node2 of this.subgraph.nodes){if("getInnerNodes"in node2){node2.getInnerNodes(executableNodes,subgraphInstanceIdPath,nodes,new Set(visited))}else{const aVeryRealNode=new ExecutableNodeDTO(node2,subgraphInstanceIdPath,executableNodes,this);executableNodes.set(aVeryRealNode.id,aVeryRealNode);nodes.push(aVeryRealNode)}}return nodes}removeWidgetByName(name){const widget=this.widgets.find(w=>w.name===name);if(widget){this.subgraph.events.dispatch("widget-demoted",{widget,subgraphNode:this})}super.removeWidgetByName(name)}ensureWidgetRemoved(widget){if(this.widgets.includes(widget)){this.subgraph.events.dispatch("widget-demoted",{widget,subgraphNode:this})}super.ensureWidgetRemoved(widget)}onRemoved(){this.#eventAbortController.abort();for(const widget of this.widgets){this.subgraph.events.dispatch("widget-demoted",{widget,subgraphNode:this})}for(const input of this.inputs){input._listenerController?.abort()}}}const LiteGraph=new LiteGraphGlobal;loadPolyfills();exports.BadgePosition=BadgePosition;exports.BaseSteppedWidget=BaseSteppedWidget;exports.BaseWidget=BaseWidget;exports.BooleanWidget=BooleanWidget;exports.ButtonWidget=ButtonWidget;exports.CanvasItem=CanvasItem;exports.CanvasPointer=CanvasPointer;exports.ComboWidget=ComboWidget;exports.Constants=constants;exports.ContextMenu=ContextMenu;exports.CurveEditor=CurveEditor;exports.DragAndScale=DragAndScale;exports.EaseFunction=EaseFunction;exports.ExecutableNodeDTO=ExecutableNodeDTO;exports.InputIndicators=InputIndicators;exports.KnobWidget=KnobWidget;exports.LGraph=LGraph;exports.LGraphBadge=LGraphBadge;exports.LGraphCanvas=LGraphCanvas;exports.LGraphEventMode=LGraphEventMode;exports.LGraphGroup=LGraphGroup;exports.LGraphNode=LGraphNode;exports.LLink=LLink;exports.LabelPosition=LabelPosition;exports.LegacyWidget=LegacyWidget;exports.LinkConnector=LinkConnector;exports.LinkMarkerShape=LinkMarkerShape;exports.LiteGraph=LiteGraph;exports.NumberWidget=NumberWidget;exports.Rectangle=Rectangle;exports.RenderShape=RenderShape;exports.Reroute=Reroute;exports.SliderWidget=SliderWidget;exports.SlotDirection=SlotDirection;exports.SlotShape=SlotShape;exports.SlotType=SlotType;exports.Subgraph=Subgraph;exports.SubgraphNode=SubgraphNode;exports.TextWidget=TextWidget;exports.TitleMode=TitleMode;exports.clamp=clamp;exports.createBounds=createBounds;exports.createUuidv4=createUuidv4;exports.isColorable=isColorable;exports.isComboWidget=isComboWidget;exports.isOverNodeInput=isOverNodeInput;exports.isOverNodeOutput=isOverNodeOutput;exports.strokeShape=strokeShape;Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"})}));
|
|
2
|
+
${fixedValue}`,width2*.5,y+effective_height*.5)}Object.assign(ctx,{textAlign,strokeStyle,fillStyle})}onClick(){this.current_drag_offset=0}current_drag_offset=0;onDrag(options){if(this.options.read_only)return;const{e:e2}=options;const step=getWidgetStep(this.options);const range=this.options.max-this.options.min;const range_10_percent=range/10;const range_1_percent=range/100;const step_for={shift:range_10_percent>step?range_10_percent-range_10_percent%step:step,delta_y:range_1_percent>step?range_1_percent-range_1_percent%step:step};const use_y=Math.abs(e2.movementY)>Math.abs(e2.movementX);const delta2=use_y?-e2.movementY:e2.movementX;const drag_threshold=15;this.current_drag_offset+=delta2;let adjustment=0;if(this.current_drag_offset>drag_threshold){adjustment+=1;this.current_drag_offset-=drag_threshold}else if(this.current_drag_offset<-drag_threshold){adjustment-=1;this.current_drag_offset+=drag_threshold}const step_with_shift_modifier=e2.shiftKey?step_for.shift:use_y?step_for.delta_y:step;const deltaValue=adjustment*step_with_shift_modifier;const newValue2=clamp(this.value+deltaValue,this.options.min,this.options.max);if(newValue2!==this.value){this.setValue(newValue2,options)}}}class LegacyWidget extends BaseWidget{drawWidget(ctx,options){const H=LiteGraph.NODE_WIDGET_HEIGHT;this.draw?.(ctx,this.node,options.width,this.y,H,!!options.showText)}onClick(){console.warn("Custom widget wrapper onClick was just called. Handling for third party widgets is done via LGraphCanvas - the mouse callback.")}}class NumberWidget extends BaseSteppedWidget{type="number";get _displayValue(){if(this.computedDisabled)return"";return Number(this.value).toFixed(this.options.precision!==void 0?this.options.precision:3)}canIncrement(){const{max}=this.options;return max==null||this.value<max}canDecrement(){const{min}=this.options;return min==null||this.value>min}incrementValue(options){this.setValue(this.value+getWidgetStep(this.options),options)}decrementValue(options){this.setValue(this.value-getWidgetStep(this.options),options)}setValue(value,options){let newValue2=value;if(this.options.min!=null&&newValue2<this.options.min){newValue2=this.options.min}if(this.options.max!=null&&newValue2>this.options.max){newValue2=this.options.max}super.setValue(newValue2,options)}onClick({e,node,canvas}){const x=e.canvasX-node.pos[0];const width=this.width||node.size[0];const delta=x<40?-1:x>width-40?1:0;if(delta){this.setValue(this.value+delta*getWidgetStep(this.options),{e,node,canvas});return}canvas.prompt("Value",this.value,v=>{if(/^[\d\s()*+/-]+|\d+\.\d+$/.test(v)){try{v=eval(v)}catch{}}const newValue=Number(v);if(!isNaN(newValue)){this.setValue(newValue,{e,node,canvas})}},e)}onDrag({e:e2,node:node2,canvas:canvas2}){const width2=this.width||node2.width;const x2=e2.canvasX-node2.pos[0];const delta2=x2<40?-1:x2>width2-40?1:0;if(delta2&&(x2>-3&&x2<width2+3))return;this.setValue(this.value+(e2.deltaX??0)*getWidgetStep(this.options),{e:e2,node:node2,canvas:canvas2})}}class SliderWidget extends BaseWidget{type="slider";marker;drawWidget(ctx,{width:width2,showText=true}){const{fillStyle,strokeStyle,textAlign}=ctx;const{height,y}=this;const{margin}=BaseWidget;ctx.fillStyle=this.background_color;ctx.fillRect(margin,y,width2-margin*2,height);const range=this.options.max-this.options.min;let nvalue=(this.value-this.options.min)/range;nvalue=clamp(nvalue,0,1);ctx.fillStyle=this.options.slider_color??"#678";ctx.fillRect(margin,y,nvalue*(width2-margin*2),height);if(showText&&!this.computedDisabled){ctx.strokeStyle=this.outline_color;ctx.strokeRect(margin,y,width2-margin*2,height)}if(this.marker!=null){let marker_nvalue=(this.marker-this.options.min)/range;marker_nvalue=clamp(marker_nvalue,0,1);ctx.fillStyle=this.options.marker_color??"#AA9";ctx.fillRect(margin+marker_nvalue*(width2-margin*2),y,2,height)}if(showText){ctx.textAlign="center";ctx.fillStyle=this.text_color;const fixedValue=Number(this.value).toFixed(this.options.precision??3);ctx.fillText(`${this.label||this.name} ${fixedValue}`,width2*.5,y+height*.7)}Object.assign(ctx,{textAlign,strokeStyle,fillStyle})}onClick(options){if(this.options.read_only)return;const{e:e2,node:node2}=options;const width2=this.width||node2.size[0];const x2=e2.canvasX-node2.pos[0];const slideFactor=clamp((x2-15)/(width2-30),0,1);const newValue2=this.options.min+(this.options.max-this.options.min)*slideFactor;if(newValue2!==this.value){this.setValue(newValue2,options)}}onDrag(options){if(this.options.read_only)return false;const{e:e2,node:node2}=options;const width2=this.width||node2.size[0];const x2=e2.canvasX-node2.pos[0];const slideFactor=clamp((x2-15)/(width2-30),0,1);const newValue2=this.options.min+(this.options.max-this.options.min)*slideFactor;if(newValue2!==this.value){this.setValue(newValue2,options)}}}class TextWidget extends BaseWidget{constructor(widget,node2){super(widget,node2);this.type??="string";this.value=widget.value?.toString()??""}drawWidget(ctx,{width:width2,showText=true}){const{fillStyle,strokeStyle,textAlign}=ctx;this.drawWidgetShape(ctx,{width:width2,showText});if(showText){this.drawTruncatingText({ctx,width:width2,leftPadding:0,rightPadding:0})}Object.assign(ctx,{textAlign,strokeStyle,fillStyle})}onClick({e:e2,node:node2,canvas:canvas2}){canvas2.prompt("Value",this.value,v2=>{if(v2!==null){this.setValue(v2,{e:e2,node:node2,canvas:canvas2})}},e2,this.options?.multiline??false)}}function toConcreteWidget(widget,node2,wrapLegacyWidgets=true){if(widget instanceof BaseWidget)return widget;const narrowedWidget=widget;switch(narrowedWidget.type){case"button":return toClass(ButtonWidget,narrowedWidget,node2);case"toggle":return toClass(BooleanWidget,narrowedWidget,node2);case"slider":return toClass(SliderWidget,narrowedWidget,node2);case"knob":return toClass(KnobWidget,narrowedWidget,node2);case"combo":return toClass(ComboWidget,narrowedWidget,node2);case"number":return toClass(NumberWidget,narrowedWidget,node2);case"string":return toClass(TextWidget,narrowedWidget,node2);case"text":return toClass(TextWidget,narrowedWidget,node2);default:{if(wrapLegacyWidgets)return toClass(LegacyWidget,widget,node2)}}}function isComboWidget(widget){return widget.type==="combo"}class LGraphNode{static title;static MAX_CONSOLE;static type;static category;static filter;static skip_list;static resizeHandleSize=15;static resizeEdgeSize=5;static keepAllLinksOnBypass=false;title;get titleFontStyle(){return`${LiteGraph.NODE_TEXT_SIZE}px ${LiteGraph.NODE_FONT}`}get innerFontStyle(){return`normal ${LiteGraph.NODE_SUBTEXT_SIZE}px ${LiteGraph.NODE_FONT}`}get displayType(){return this.type}graph=null;id;type="";inputs=[];outputs=[];#concreteInputs=[];#concreteOutputs=[];properties={};properties_info=[];flags={};widgets;freeWidgetSpace;locked;order=0;mode=LGraphEventMode.ALWAYS;last_serialization;serialize_widgets;color;bgcolor;boxcolor;get renderingColor(){return this.color||this.constructor.color||LiteGraph.NODE_DEFAULT_COLOR}get renderingBgColor(){return this.bgcolor||this.constructor.bgcolor||LiteGraph.NODE_DEFAULT_BGCOLOR}get renderingBoxColor(){if(this.boxcolor)return this.boxcolor;if(LiteGraph.node_box_coloured_when_on){if(this.action_triggered)return"#FFF";if(this.execute_triggered)return"#AAA"}if(LiteGraph.node_box_coloured_by_mode){const modeColour=LiteGraph.NODE_MODES_COLORS[this.mode??LGraphEventMode.ALWAYS];if(modeColour)return modeColour}return LiteGraph.NODE_DEFAULT_BOXCOLOR}setColorOption(colorOption){if(colorOption==null){delete this.color;delete this.bgcolor}else{this.color=colorOption.color;this.bgcolor=colorOption.bgcolor}}getColorOption(){return Object.values(LGraphCanvas.node_colors).find(colorOption=>colorOption.color===this.color&&colorOption.bgcolor===this.bgcolor)??null}strokeStyles;progress;exec_version;action_call;execute_triggered;action_triggered;widgets_up;widgets_start_y;lostFocusAt;gotFocusAt;badges=[];title_buttons=[];badgePosition=BadgePosition.TopLeft;_collapsed_width;console;_level;_shape;mouseOver;redraw_on_mouse;resizable;clonable;_relative_id;clip_area;ignore_remove;has_errors;removable;block_delete;selected;showAdvanced;isSubgraphNode(){return false}#renderArea=new Float32Array(4);get renderArea(){return this.#renderArea}#boundingRect=new Rectangle;get boundingRect(){return this.#boundingRect}get boundingOffset(){const{pos:[posX,posY],boundingRect:[bX,bY]}=this;return[posX-bX,posY-bY]}_posSize=new Float32Array(4);_pos=this._posSize.subarray(0,2);_size=this._posSize.subarray(2,4);get pos(){return this._pos}set pos(value){if(!value||value.length<2)return;this._pos[0]=value[0];this._pos[1]=value[1]}get size(){return this._size}set size(value){if(!value||value.length<2)return;this._size[0]=value[0];this._size[1]=value[1]}get renderingSize(){return this.flags.collapsed?[this._collapsed_width??0,0]:this._size}get shape(){return this._shape}set shape(v2){switch(v2){case"default":delete this._shape;break;case"box":this._shape=RenderShape.BOX;break;case"round":this._shape=RenderShape.ROUND;break;case"circle":this._shape=RenderShape.CIRCLE;break;case"card":this._shape=RenderShape.CARD;break;default:this._shape=v2}}get renderingShape(){return this._shape||this.constructor.shape||LiteGraph.NODE_DEFAULT_SHAPE}get is_selected(){return this.selected}set is_selected(value){this.selected=value}get title_mode(){return this.constructor.title_mode??TitleMode.NORMAL_TITLE}#getErrorStrokeStyle(){if(this.has_errors){return{padding:12,lineWidth:10,color:LiteGraph.NODE_ERROR_COLOUR}}}#getSelectedStrokeStyle(){if(this.selected){return{padding:this.has_errors?20:void 0}}}constructor(title,type){this.id=LiteGraph.use_uuids?LiteGraph.uuidv4():-1;this.title=title||"Unnamed";this.type=type??"";this.size=[LiteGraph.NODE_WIDTH,60];this.pos=[10,10];this.strokeStyles={error:this.#getErrorStrokeStyle,selected:this.#getSelectedStrokeStyle};this.onMouseDown=(e2,pos,canvas2)=>{if(this.title_buttons?.length&&!this.flags.collapsed){const nodeRelativeX=pos[0];const nodeRelativeY=pos[1];for(let i=0;i<this.title_buttons.length;i++){const button=this.title_buttons[i];if(button.visible&&button.isPointInside(nodeRelativeX,nodeRelativeY)){this.onTitleButtonClick(button,canvas2);return true}}}return false}}configure(info){if(this.graph){this.graph._version++}for(const j in info){if(j=="properties"){for(const k in info.properties){this.properties[k]=info.properties[k];this.onPropertyChanged?.(k,info.properties[k])}continue}if(info[j]==null){continue}else if(typeof info[j]=="object"){if(this[j]?.configure){this[j]?.configure(info[j])}else{this[j]=LiteGraph.cloneObject(info[j],this[j])}}else{this[j]=info[j]}}if(!info.title){this.title=this.constructor.title}this.inputs??=[];this.inputs=this.inputs.map(input=>toClass(NodeInputSlot,input,this));for(const[i,input]of this.inputs.entries()){const link=this.graph&&input.link!=null?this.graph._links.get(input.link):null;this.onConnectionsChange?.(NodeSlotType.INPUT,i,true,link,input);this.onInputAdded?.(input)}this.outputs??=[];this.outputs=this.outputs.map(output=>toClass(NodeOutputSlot,output,this));for(const[i,output]of this.outputs.entries()){if(!output.links)continue;for(const linkId of output.links){const link=this.graph?this.graph._links.get(linkId):null;this.onConnectionsChange?.(NodeSlotType.OUTPUT,i,true,link,output)}this.onOutputAdded?.(output)}this._internalConfigureAfterSlots?.();if(this.widgets){for(const w of this.widgets){if(!w)continue;if(w.options?.property&&this.properties[w.options.property]!=void 0)w.value=JSON.parse(JSON.stringify(this.properties[w.options.property]))}if(info.widgets_values){const widgetsWithValue=this.widgets.filter(w=>w.serialize!==false);for(let i=0;i<info.widgets_values.length;++i){const widget=widgetsWithValue[i];if(widget){widget.value=info.widgets_values[i]}}}}if(this.pinned)this.resizable=false;this.onConfigure?.(info)}serialize(){const o={id:this.id,type:this.type,pos:[this.pos[0],this.pos[1]],size:[this.size[0],this.size[1]],flags:LiteGraph.cloneObject(this.flags),order:this.order,mode:this.mode,showAdvanced:this.showAdvanced};if(this.constructor===LGraphNode&&this.last_serialization)return this.last_serialization;if(this.inputs)o.inputs=this.inputs.map(input=>inputAsSerialisable(input));if(this.outputs)o.outputs=this.outputs.map(output=>outputAsSerialisable(output));if(this.title&&this.title!=this.constructor.title)o.title=this.title;if(this.properties)o.properties=LiteGraph.cloneObject(this.properties);const{widgets}=this;if(widgets&&this.serialize_widgets){o.widgets_values=[];for(const[i,widget]of widgets.entries()){if(widget.serialize===false)continue;o.widgets_values[i]=widget?widget.value:null}}if(!o.type)o.type=this.constructor.type;if(this.color)o.color=this.color;if(this.bgcolor)o.bgcolor=this.bgcolor;if(this.boxcolor)o.boxcolor=this.boxcolor;if(this.shape)o.shape=this.shape;if(this.onSerialize?.(o))console.warn("node onSerialize shouldnt return anything, data should be stored in the object pass in the first parameter");return o}clone(){if(this.type==null)return null;const node2=LiteGraph.createNode(this.type);if(!node2)return null;const data=LiteGraph.cloneObject(this.serialize());const{inputs,outputs}=data;if(inputs){for(const input of inputs){input.link=null}}if(outputs){for(const{links}of outputs){if(links)links.length=0}}delete data.id;if(LiteGraph.use_uuids)data.id=LiteGraph.uuidv4();node2.configure(data);return node2}toString(){return JSON.stringify(this.serialize())}getTitle(){return this.title||this.constructor.title}setProperty(name,value){this.properties||={};if(value===this.properties[name])return;const prev_value=this.properties[name];this.properties[name]=value;if(this.onPropertyChanged?.(name,value,prev_value)===false)this.properties[name]=prev_value;if(this.widgets){for(const w of this.widgets){if(!w)continue;if(w.options.property==name){w.value=value;break}}}}setOutputData(slot,data){const{outputs}=this;if(!outputs)return;if(slot==-1||slot>=outputs.length)return;const output_info=outputs[slot];if(!output_info)return;output_info._data=data;if(!this.graph)throw new NullGraphError;const{links}=outputs[slot];if(links){for(const id of links){const link=this.graph._links.get(id);if(link)link.data=data}}}setOutputDataType(slot,type){const{outputs}=this;if(!outputs||(slot==-1||slot>=outputs.length))return;const output_info=outputs[slot];if(!output_info)return;output_info.type=type;if(!this.graph)throw new NullGraphError;const{links}=outputs[slot];if(links){for(const id of links){const link=this.graph._links.get(id);if(link)link.type=type}}}getInputData(slot,force_update){if(!this.inputs)return;if(slot>=this.inputs.length||this.inputs[slot].link==null)return;if(!this.graph)throw new NullGraphError;const link_id=this.inputs[slot].link;const link=this.graph._links.get(link_id);if(!link)return null;if(!force_update)return link.data;const node2=this.graph.getNodeById(link.origin_id);if(!node2)return link.data;if(node2.updateOutputData){node2.updateOutputData(link.origin_slot)}else{node2.onExecute?.()}return link.data}getInputDataType(slot){if(!this.inputs)return null;if(slot>=this.inputs.length||this.inputs[slot].link==null)return null;if(!this.graph)throw new NullGraphError;const link_id=this.inputs[slot].link;const link=this.graph._links.get(link_id);if(!link)return null;const node2=this.graph.getNodeById(link.origin_id);if(!node2)return link.type;const output_info=node2.outputs[link.origin_slot];return output_info?output_info.type:null}getInputDataByName(slot_name,force_update){const slot=this.findInputSlot(slot_name);return slot==-1?null:this.getInputData(slot,force_update)}isInputConnected(slot){if(!this.inputs)return false;return slot<this.inputs.length&&this.inputs[slot].link!=null}getInputInfo(slot){return!this.inputs||!(slot<this.inputs.length)?null:this.inputs[slot]}getInputLink(slot){if(!this.inputs)return null;if(slot<this.inputs.length){if(!this.graph)throw new NullGraphError;const input=this.inputs[slot];if(input.link!=null){return this.graph._links.get(input.link)??null}}return null}getInputNode(slot){if(!this.inputs)return null;if(slot>=this.inputs.length)return null;const input=this.inputs[slot];if(!input||input.link===null)return null;if(!this.graph)throw new NullGraphError;const link_info=this.graph._links.get(input.link);if(!link_info)return null;return this.graph.getNodeById(link_info.origin_id)}getInputOrProperty(name){const{inputs}=this;if(!inputs?.length){return this.properties?this.properties[name]:null}if(!this.graph)throw new NullGraphError;for(const input of inputs){if(name==input.name&&input.link!=null){const link=this.graph._links.get(input.link);if(link)return link.data}}return this.properties[name]}getOutputData(slot){if(!this.outputs)return null;if(slot>=this.outputs.length)return null;const info=this.outputs[slot];return info._data}getOutputInfo(slot){return!this.outputs||!(slot<this.outputs.length)?null:this.outputs[slot]}isOutputConnected(slot){if(!this.outputs)return false;return slot<this.outputs.length&&Number(this.outputs[slot].links?.length)>0}isAnyOutputConnected(){const{outputs}=this;if(!outputs)return false;for(const output of outputs){if(output.links?.length)return true}return false}getOutputNodes(slot){const{outputs}=this;if(!outputs||outputs.length==0)return null;if(slot>=outputs.length)return null;const{links}=outputs[slot];if(!links||links.length==0)return null;if(!this.graph)throw new NullGraphError;const r=[];for(const id of links){const link=this.graph._links.get(id);if(link){const target_node=this.graph.getNodeById(link.target_id);if(target_node){r.push(target_node)}}}return r}addOnTriggerInput(){const trigS=this.findInputSlot("onTrigger");if(trigS==-1){this.addInput("onTrigger",LiteGraph.EVENT,{nameLocked:true});return this.findInputSlot("onTrigger")}return trigS}addOnExecutedOutput(){const trigS=this.findOutputSlot("onExecuted");if(trigS==-1){this.addOutput("onExecuted",LiteGraph.ACTION,{nameLocked:true});return this.findOutputSlot("onExecuted")}return trigS}onAfterExecuteNode(param,options){const trigS=this.findOutputSlot("onExecuted");if(trigS!=-1){this.triggerSlot(trigS,param,null,options)}}changeMode(modeTo){switch(modeTo){case LGraphEventMode.ON_EVENT:break;case LGraphEventMode.ON_TRIGGER:this.addOnTriggerInput();this.addOnExecutedOutput();break;case LGraphEventMode.NEVER:break;case LGraphEventMode.ALWAYS:break;case LiteGraph.ON_REQUEST:break;default:return false}this.mode=modeTo;return true}doExecute(param,options){options=options||{};if(this.onExecute){options.action_call||=`${this.id}_exec_${Math.floor(Math.random()*9999)}`;if(!this.graph)throw new NullGraphError;this.graph.nodes_executing[this.id]=true;this.onExecute(param,options);this.graph.nodes_executing[this.id]=false;this.exec_version=this.graph.iteration;if(options?.action_call){this.action_call=options.action_call;this.graph.nodes_executedAction[this.id]=options.action_call}}this.execute_triggered=2;this.onAfterExecuteNode?.(param,options)}actionDo(action,param,options){options=options||{};if(this.onAction){options.action_call||=`${this.id}_${action||"action"}_${Math.floor(Math.random()*9999)}`;if(!this.graph)throw new NullGraphError;this.graph.nodes_actioning[this.id]=action||"actioning";this.onAction(action,param,options);this.graph.nodes_actioning[this.id]=false;if(options?.action_call){this.action_call=options.action_call;this.graph.nodes_executedAction[this.id]=options.action_call}}this.action_triggered=2;this.onAfterExecuteNode?.(param,options)}trigger(action,param,options){const{outputs}=this;if(!outputs||!outputs.length){return}if(this.graph)this.graph._last_trigger_time=LiteGraph.getTime();for(const[i,output]of outputs.entries()){if(!output||output.type!==LiteGraph.EVENT||action&&output.name!=action){continue}this.triggerSlot(i,param,null,options)}}triggerSlot(slot,param,link_id,options){options=options||{};if(!this.outputs)return;if(slot==null){console.error("slot must be a number");return}if(typeof slot!=="number")console.warn("slot must be a number, use node.trigger('name') if you want to use a string");const output=this.outputs[slot];if(!output)return;const links=output.links;if(!links||!links.length)return;if(!this.graph)throw new NullGraphError;this.graph._last_trigger_time=LiteGraph.getTime();for(const id of links){if(link_id!=null&&link_id!=id)continue;const link_info=this.graph._links.get(id);if(!link_info)continue;link_info._last_time=LiteGraph.getTime();const node2=this.graph.getNodeById(link_info.target_id);if(!node2)continue;if(node2.mode===LGraphEventMode.ON_TRIGGER){if(!options.action_call)options.action_call=`${this.id}_trigg_${Math.floor(Math.random()*9999)}`;node2.doExecute?.(param,options)}else if(node2.onAction){if(!options.action_call)options.action_call=`${this.id}_act_${Math.floor(Math.random()*9999)}`;const target_connection=node2.inputs[link_info.target_slot];node2.actionDo(target_connection.name,param,options)}}}clearTriggeredSlot(slot,link_id){if(!this.outputs)return;const output=this.outputs[slot];if(!output)return;const links=output.links;if(!links||!links.length)return;if(!this.graph)throw new NullGraphError;for(const id of links){if(link_id!=null&&link_id!=id)continue;const link_info=this.graph._links.get(id);if(!link_info)continue;link_info._last_time=0}}setSize(size){this.size=size;this.onResize?.(this.size)}expandToFitContent(){const newSize=this.computeSize();this.setSize([Math.max(this.size[0],newSize[0]),Math.max(this.size[1],newSize[1])])}addProperty(name,default_value,type,extra_info){const o={name,type,default_value};if(extra_info)Object.assign(o,extra_info);this.properties_info||=[];this.properties_info.push(o);this.properties||={};this.properties[name]=default_value;return o}addOutput(name,type,extra_info){const output=Object.assign(new NodeOutputSlot({name,type,links:null},this),extra_info);this.outputs||=[];this.outputs.push(output);this.onOutputAdded?.(output);if(LiteGraph.auto_load_slot_types)LiteGraph.registerNodeAndSlotType(this,type,true);this.expandToFitContent();this.setDirtyCanvas(true,true);return output}removeOutput(slot){this.disconnectOutput(slot);const{outputs}=this;outputs.splice(slot,1);for(let i=slot;i<outputs.length;++i){const output=outputs[i];if(!output||!output.links)continue;for(const linkId of output.links){if(!this.graph)throw new NullGraphError;const link=this.graph._links.get(linkId);if(link)link.origin_slot--}}this.onOutputRemoved?.(slot);this.setDirtyCanvas(true,true)}addInput(name,type,extra_info){type||=0;const input=Object.assign(new NodeInputSlot({name,type,link:null},this),extra_info);this.inputs||=[];this.inputs.push(input);this.expandToFitContent();this.onInputAdded?.(input);LiteGraph.registerNodeAndSlotType(this,type);this.setDirtyCanvas(true,true);return input}removeInput(slot){this.disconnectInput(slot,true);const{inputs}=this;const slot_info=inputs.splice(slot,1);for(let i=slot;i<inputs.length;++i){const input=inputs[i];if(!input?.link)continue;if(!this.graph)throw new NullGraphError;const link=this.graph._links.get(input.link);if(link)link.target_slot--}this.onInputRemoved?.(slot,slot_info[0]);this.setDirtyCanvas(true,true)}computeSize(out){const ctorSize=this.constructor.size;if(ctorSize)return[ctorSize[0],ctorSize[1]];const{inputs,outputs,widgets}=this;let rows=Math.max(inputs?inputs.filter(input=>!isWidgetInputSlot(input)).length:1,outputs?outputs.length:1);const size=out||new Float32Array([0,0]);rows=Math.max(rows,1);const font_size=LiteGraph.NODE_TEXT_SIZE;const padLeft=LiteGraph.NODE_TITLE_HEIGHT;const padRight=padLeft*.33;const title_width=padLeft+compute_text_size(this.title,this.titleFontStyle)+padRight;let input_width=0;let widgetWidth=0;let output_width=0;if(inputs){for(const input of inputs){const text=input.label||input.localized_name||input.name||"";const text_width=compute_text_size(text,this.innerFontStyle);if(isWidgetInputSlot(input)){const widget=this.getWidgetFromSlot(input);if(widget&&!this.isWidgetVisible(widget))continue;if(text_width>widgetWidth)widgetWidth=text_width}else{if(text_width>input_width)input_width=text_width}}}if(outputs){for(const output of outputs){const text=output.label||output.localized_name||output.name||"";const text_width=compute_text_size(text,this.innerFontStyle);if(output_width<text_width)output_width=text_width}}const minWidth=LiteGraph.NODE_WIDTH*(widgets?.length?1.5:1);const centrePadding=input_width&&output_width?5:0;const slotsWidth=input_width+output_width+2*LiteGraph.NODE_SLOT_HEIGHT+centrePadding;const widgetMargin=BaseWidget.margin+BaseWidget.arrowMargin+BaseWidget.arrowWidth;const widgetPadding=BaseWidget.minValueWidth+2*widgetMargin;if(widgetWidth)widgetWidth+=widgetPadding;size[0]=Math.max(slotsWidth,widgetWidth,title_width,minWidth);size[1]=(this.constructor.slot_start_y||0)+rows*LiteGraph.NODE_SLOT_HEIGHT;let widgets_height=0;if(widgets?.length){for(const widget of widgets){if(!this.isWidgetVisible(widget))continue;let widget_height=0;if(widget.computeSize){widget_height+=widget.computeSize(size[0])[1]}else if(widget.computeLayoutSize){const{minHeight,minWidth:minWidth2}=widget.computeLayoutSize(this);const widgetWidth2=minWidth2+widgetPadding;if(widgetWidth2>size[0])size[0]=widgetWidth2;widget_height+=minHeight}else{widget_height+=LiteGraph.NODE_WIDGET_HEIGHT}widgets_height+=widget_height+4}widgets_height+=8}if(this.widgets_up)size[1]=Math.max(size[1],widgets_height);else if(this.widgets_start_y!=null)size[1]=Math.max(size[1],widgets_height+this.widgets_start_y);else size[1]+=widgets_height;function compute_text_size(text,fontStyle){return LGraphCanvas._measureText?.(text,fontStyle)??font_size*(text?.length??0)*.6}if(this.constructor.min_height&&size[1]<this.constructor.min_height){size[1]=this.constructor.min_height}size[1]+=6;return size}inResizeCorner(canvasX,canvasY){const rows=this.outputs?this.outputs.length:1;const outputs_offset=(this.constructor.slot_start_y||0)+rows*LiteGraph.NODE_SLOT_HEIGHT;return isInRectangle(canvasX,canvasY,this.pos[0]+this.size[0]-15,this.pos[1]+Math.max(this.size[1]-15,outputs_offset),20,20)}findResizeDirection(canvasX,canvasY){if(this.resizable===false)return;const{boundingRect}=this;if(!boundingRect.containsXy(canvasX,canvasY))return;return boundingRect.findContainingCorner(canvasX,canvasY,LGraphNode.resizeHandleSize)}getPropertyInfo(property){let info=null;const{properties_info}=this;if(properties_info){for(const propInfo of properties_info){if(propInfo.name==property){info=propInfo;break}}}if(this.constructor[`@${property}`])info=this.constructor[`@${property}`];if(this.constructor.widgets_info?.[property])info=this.constructor.widgets_info[property];if(!info&&this.onGetPropertyInfo){info=this.onGetPropertyInfo(property)}info||={};info.type||=typeof this.properties[property];if(info.widget=="combo")info.type="enum";return info}addWidget(type,name,value,callback,options){this.widgets||=[];if(!options&&callback&&typeof callback==="object"){options=callback;callback=null}options||={};if(typeof options==="string")options={property:options};if(callback&&typeof callback==="string"){options.property=callback;callback=null}const w={type:type.toLowerCase(),name,value,callback:typeof callback!=="function"?void 0:callback,options,y:0};if(w.options.y!==void 0){w.y=w.options.y}if(!callback&&!w.options.callback&&!w.options.property){console.warn("LiteGraph addWidget(...) without a callback or property assigned")}if(type=="combo"&&!w.options.values){throw"LiteGraph addWidget('combo',...) requires to pass values in options: { values:['red','blue'] }"}const widget=this.addCustomWidget(w);this.expandToFitContent();return widget}addCustomWidget(custom_widget){this.widgets||=[];const widget=toConcreteWidget(custom_widget,this,false)??custom_widget;this.widgets.push(widget);return widget}addTitleButton(options){this.title_buttons||=[];const button=new LGraphButton(options);this.title_buttons.push(button);return button}onTitleButtonClick(button,canvas2){canvas2.dispatch("litegraph:node-title-button-clicked",{node:this,button})}removeWidgetByName(name){const widget=this.widgets?.find(x2=>x2.name===name);if(widget)this.removeWidget(widget)}removeWidget(widget){if(!this.widgets)throw new Error("removeWidget called on node without widgets");const widgetIndex=this.widgets.indexOf(widget);if(widgetIndex===-1)throw new Error("Widget not found on this node");if(this.inputs){for(const input of this.inputs){if(input._widget===widget){input._widget=void 0;delete input.widget}}}this.widgets.splice(widgetIndex,1)}ensureWidgetRemoved(widget){try{this.removeWidget(widget)}catch(error){console.debug("Failed to remove widget",error)}}move(deltaX,deltaY){if(this.pinned)return;this.pos[0]+=deltaX;this.pos[1]+=deltaY}measure(out,ctx){const titleMode=this.title_mode;const renderTitle=titleMode!=TitleMode.TRANSPARENT_TITLE&&titleMode!=TitleMode.NO_TITLE;const titleHeight=renderTitle?LiteGraph.NODE_TITLE_HEIGHT:0;out[0]=this.pos[0];out[1]=this.pos[1]+-titleHeight;if(!this.flags?.collapsed){out[2]=this.size[0];out[3]=this.size[1]+titleHeight}else{ctx.font=this.innerFontStyle;this._collapsed_width=Math.min(this.size[0],ctx.measureText(this.getTitle()??"").width+LiteGraph.NODE_TITLE_HEIGHT*2);out[2]=this._collapsed_width||LiteGraph.NODE_COLLAPSED_WIDTH;out[3]=LiteGraph.NODE_TITLE_HEIGHT}}getBounding(out,includeExternal){out||=new Float32Array(4);const rect=includeExternal?this.renderArea:this.boundingRect;out[0]=rect[0];out[1]=rect[1];out[2]=rect[2];out[3]=rect[3];return out}updateArea(ctx){const bounds=this.#boundingRect;this.measure(bounds,ctx);this.onBounding?.(bounds);const renderArea=this.#renderArea;renderArea.set(bounds);renderArea[0]-=4;renderArea[1]-=4;renderArea[2]+=6+4;renderArea[3]+=5+4}isPointInside(x2,y){return isInRect(x2,y,this.boundingRect)}isPointInCollapse(x2,y){const squareLength=LiteGraph.NODE_TITLE_HEIGHT;return isInRectangle(x2,y,this.pos[0],this.pos[1]-squareLength,squareLength,squareLength)}getInputOnPos(pos){return getNodeInputOnPos(this,pos[0],pos[1])?.input}getOutputOnPos(pos){return getNodeOutputOnPos(this,pos[0],pos[1])?.output}getSlotOnPos(pos){if(!isPointInRect(pos,this.boundingRect))return;return this.getInputOnPos(pos)??this.getOutputOnPos(pos)}getSlotInPosition(x2,y){const{inputs,outputs}=this;if(inputs){for(const[i,input]of inputs.entries()){const pos=this.getInputPos(i);if(isInRectangle(x2,y,pos[0]-10,pos[1]-10,20,20)){return{input,slot:i,link_pos:pos}}}}if(outputs){for(const[i,output]of outputs.entries()){const pos=this.getOutputPos(i);if(isInRectangle(x2,y,pos[0]-10,pos[1]-10,20,20)){return{output,slot:i,link_pos:pos}}}}return null}getWidgetOnPos(canvasX,canvasY,includeDisabled=false){const{widgets,pos,size}=this;if(!widgets?.length)return;const x2=canvasX-pos[0];const y=canvasY-pos[1];const nodeWidth=size[0];for(const widget of widgets){if(widget.computedDisabled&&!includeDisabled||!this.isWidgetVisible(widget)){continue}const h=widget.computedHeight??widget.computeSize?.(nodeWidth)[1]??LiteGraph.NODE_WIDGET_HEIGHT;const w=widget.width||nodeWidth;if(widget.last_y!==void 0&&isInRectangle(x2,y,6,widget.last_y,w-12,h)){return widget}}}findInputSlot(name,returnObj=false){const{inputs}=this;if(!inputs)return-1;for(const[i,input]of inputs.entries()){if(name==input.name){return!returnObj?i:input}}return-1}findOutputSlot(name,returnObj=false){const{outputs}=this;if(!outputs)return-1;for(const[i,output]of outputs.entries()){if(name==output.name){return!returnObj?i:output}}return-1}findInputSlotFree(optsIn){return this.#findFreeSlot(this.inputs,optsIn)}findOutputSlotFree(optsIn){return this.#findFreeSlot(this.outputs,optsIn)}#findFreeSlot(slots,options){const defaults={returnObj:false,typesNotAccepted:[]};const opts=Object.assign(defaults,options||{});const length=slots?.length;if(!(length>0))return-1;for(let i=0;i<length;++i){const slot=slots[i];if(!slot||slot.link||slot.links?.length)continue;if(opts.typesNotAccepted?.includes?.(slot.type))continue;return!opts.returnObj?i:slot}return-1}findInputSlotByType(type,returnObj,preferFreeSlot,doNotUseOccupied){return this.#findSlotByType(this.inputs,type,returnObj,preferFreeSlot,doNotUseOccupied)}findOutputSlotByType(type,returnObj,preferFreeSlot,doNotUseOccupied){return this.#findSlotByType(this.outputs,type,returnObj,preferFreeSlot,doNotUseOccupied)}findSlotByType(input,type,returnObj,preferFreeSlot,doNotUseOccupied){return input?this.#findSlotByType(this.inputs,type,returnObj,preferFreeSlot,doNotUseOccupied):this.#findSlotByType(this.outputs,type,returnObj,preferFreeSlot,doNotUseOccupied)}#findSlotByType(slots,type,returnObj,preferFreeSlot,doNotUseOccupied){const length=slots?.length;if(!length)return-1;if(type==""||type=="*")type=0;const sourceTypes=String(type).toLowerCase().split(",");let occupiedSlot=null;for(let i=0;i<length;++i){const slot=slots[i];const destTypes=slot.type=="0"||slot.type=="*"?["0"]:String(slot.type).toLowerCase().split(",");for(const sourceType of sourceTypes){const source=sourceType=="_event_"?LiteGraph.EVENT:sourceType;for(const destType of destTypes){const dest=destType=="_event_"?LiteGraph.EVENT:destType;if(source==dest||source==="*"||dest==="*"){if(preferFreeSlot&&(slot.links?.length||slot.link!=null)){occupiedSlot??=returnObj?slot:i;continue}return returnObj?slot:i}}}}return doNotUseOccupied?-1:occupiedSlot??-1}findConnectByTypeSlot(findInputs,node2,slotType,options){if(options&&typeof options==="object"){if("firstFreeIfInputGeneralInCase"in options)options.wildcardToTyped=!!options.firstFreeIfInputGeneralInCase;if("firstFreeIfOutputGeneralInCase"in options)options.wildcardToTyped=!!options.firstFreeIfOutputGeneralInCase;if("generalTypeInCase"in options)options.typedToWildcard=!!options.generalTypeInCase}const optsDef={createEventInCase:true,wildcardToTyped:true,typedToWildcard:true};const opts=Object.assign(optsDef,options);if(!this.graph)throw new NullGraphError;if(node2&&typeof node2==="number"){const nodeById=this.graph.getNodeById(node2);if(!nodeById)return;node2=nodeById}const slot=node2.findSlotByType(findInputs,slotType,false,true);if(slot>=0&&slot!==null)return slot;if(opts.createEventInCase&&slotType==LiteGraph.EVENT){if(findInputs)return-1;if(LiteGraph.do_add_triggers_slots)return node2.addOnExecutedOutput()}if(opts.typedToWildcard){const generalSlot=node2.findSlotByType(findInputs,0,false,true,true);if(generalSlot>=0)return generalSlot}if(opts.wildcardToTyped&&(slotType==0||slotType=="*"||slotType=="")){const opt={typesNotAccepted:[LiteGraph.EVENT]};const nonEventSlot=findInputs?node2.findInputSlotFree(opt):node2.findOutputSlotFree(opt);if(nonEventSlot>=0)return nonEventSlot}}findOutputByType(type){return findFreeSlotOfType(this.outputs,type,output=>!output.links?.length)}findInputByType(type){return findFreeSlotOfType(this.inputs,type,input=>input.link==null)}connectByType(slot,target_node,target_slotType,optsIn){const slotIndex=this.findConnectByTypeSlot(true,target_node,target_slotType,optsIn);if(slotIndex!==void 0)return this.connect(slot,target_node,slotIndex,optsIn?.afterRerouteId);console.debug("[connectByType]: no way to connect type:",target_slotType,"to node:",target_node);return null}connectByTypeOutput(slot,source_node,source_slotType,optsIn){if(typeof optsIn==="object"){if("firstFreeIfInputGeneralInCase"in optsIn)optsIn.wildcardToTyped=!!optsIn.firstFreeIfInputGeneralInCase;if("generalTypeInCase"in optsIn)optsIn.typedToWildcard=!!optsIn.generalTypeInCase}const slotIndex=this.findConnectByTypeSlot(false,source_node,source_slotType,optsIn);if(slotIndex!==void 0)return source_node.connect(slotIndex,this,slot,optsIn?.afterRerouteId);console.debug("[connectByType]: no way to connect type:",source_slotType,"to node:",source_node);return null}canConnectTo(node2,toSlot,fromSlot){return this.id!==node2.id&&LiteGraph.isValidConnection(fromSlot.type,toSlot.type)}connect(slot,target_node,target_slot,afterRerouteId){let targetIndex;const{graph,outputs}=this;if(!graph){console.log("Connect: Error, node doesn't belong to any graph. Nodes must be added first to a graph before connecting them.");return null}if(typeof slot==="string"){slot=this.findOutputSlot(slot);if(slot==-1){if(LiteGraph.debug)console.log(`Connect: Error, no slot of name ${slot}`);return null}}else if(!outputs||slot>=outputs.length){if(LiteGraph.debug)console.log("Connect: Error, slot number not found");return null}if(target_node&&typeof target_node==="number"){const nodeById=graph.getNodeById(target_node);if(!nodeById)throw"target node is null";target_node=nodeById}if(!target_node)throw"target node is null";if(target_node==this)return null;if(typeof target_slot==="string"){targetIndex=target_node.findInputSlot(target_slot);if(targetIndex==-1){if(LiteGraph.debug)console.log(`Connect: Error, no slot of name ${targetIndex}`);return null}}else if(target_slot===LiteGraph.EVENT){if(LiteGraph.do_add_triggers_slots){target_node.changeMode(LGraphEventMode.ON_TRIGGER);targetIndex=target_node.findInputSlot("onTrigger")}else{return null}}else if(typeof target_slot==="number"){targetIndex=target_slot}else{targetIndex=0}if(target_node.onBeforeConnectInput){const requestedIndex=target_node.onBeforeConnectInput(targetIndex,target_slot);targetIndex=typeof requestedIndex==="number"?requestedIndex:null}if(targetIndex===null||!target_node.inputs||targetIndex>=target_node.inputs.length){if(LiteGraph.debug)console.log("Connect: Error, slot number not found");return null}const input=target_node.inputs[targetIndex];const output=outputs[slot];if(!output)return null;if(output.links?.length){if(output.type===LiteGraph.EVENT&&!LiteGraph.allow_multi_output_for_events){graph.beforeChange();this.disconnectOutput(slot,false,{doProcessChange:false})}}const link=this.connectSlots(output,target_node,input,afterRerouteId);return link??null}connectSlots(output,inputNode,input,afterRerouteId){const{graph}=this;if(!graph)throw new NullGraphError;const outputIndex=this.outputs.indexOf(output);if(outputIndex===-1){console.warn("connectSlots: output not found");return}const inputIndex=inputNode.inputs.indexOf(input);if(inputIndex===-1){console.warn("connectSlots: input not found");return}if(!LiteGraph.isValidConnection(output.type,input.type)){this.setDirtyCanvas(false,true);return null}if(inputNode.onConnectInput?.(inputIndex,output.type,output,this,outputIndex)===false)return null;if(this.onConnectOutput?.(outputIndex,input.type,input,inputNode,inputIndex)===false)return null;if(inputNode.inputs[inputIndex]?.link!=null){graph.beforeChange();inputNode.disconnectInput(inputIndex,true)}const link=new LLink(++graph.state.lastLinkId,input.type||output.type,this.id,outputIndex,inputNode.id,inputIndex,afterRerouteId);graph._links.set(link.id,link);output.links??=[];output.links.push(link.id);inputNode.inputs[inputIndex].link=link.id;const reroutes=LLink.getReroutes(graph,link);for(const reroute of reroutes){reroute.linkIds.add(link.id);if(reroute.floating)delete reroute.floating;reroute._dragging=void 0}const lastReroute=reroutes.at(-1);if(lastReroute){for(const linkId of lastReroute.floatingLinkIds){const link2=graph.floatingLinks.get(linkId);if(link2?.parentId===lastReroute.id){graph.removeFloatingLink(link2)}}}graph._version++;this.onConnectionsChange?.(NodeSlotType.OUTPUT,outputIndex,true,link,output);inputNode.onConnectionsChange?.(NodeSlotType.INPUT,inputIndex,true,link,input);this.setDirtyCanvas(false,true);graph.afterChange();return link}connectFloatingReroute(pos,slot,afterRerouteId){const{graph,id}=this;if(!graph)throw new NullGraphError;const inputIndex=this.inputs.indexOf(slot);const outputIndex=this.outputs.indexOf(slot);if(inputIndex===-1&&outputIndex===-1)throw new Error("Invalid slot");const slotType=outputIndex===-1?"input":"output";const reroute=graph.setReroute({pos,parentId:afterRerouteId,linkIds:[],floating:{slotType}});const parentReroute=graph.getReroute(afterRerouteId);const fromLastFloatingReroute=parentReroute?.floating?.slotType==="output";if(afterRerouteId==null||!fromLastFloatingReroute){const link2=new LLink(-1,slot.type,outputIndex===-1?-1:id,outputIndex,inputIndex===-1?-1:id,inputIndex);link2.parentId=reroute.id;graph.addFloatingLink(link2);return reroute}if(!parentReroute)throw new Error("[connectFloatingReroute] Parent reroute not found");const link=parentReroute.getFloatingLinks("output")?.[0];if(!link)throw new Error("[connectFloatingReroute] Floating link not found");reroute.floatingLinkIds.add(link.id);link.parentId=reroute.id;delete parentReroute.floating;return reroute}disconnectOutput(slot,target_node){if(typeof slot==="string"){slot=this.findOutputSlot(slot);if(slot==-1){if(LiteGraph.debug)console.log(`Connect: Error, no slot of name ${slot}`);return false}}else if(!this.outputs||slot>=this.outputs.length){if(LiteGraph.debug)console.log("Connect: Error, slot number not found");return false}const output=this.outputs[slot];if(!output)return false;if(output._floatingLinks){for(const link of output._floatingLinks){if(link.hasOrigin(this.id,slot)){this.graph?.removeFloatingLink(link)}}}if(!output.links||output.links.length==0)return false;const{links}=output;const graph=this.graph;if(!graph)throw new NullGraphError;if(target_node){const target=typeof target_node==="number"?graph.getNodeById(target_node):target_node;if(!target)throw"Target Node not found";for(const[i,link_id]of links.entries()){const link_info=graph._links.get(link_id);if(link_info?.target_id!=target.id)continue;links.splice(i,1);const input=target.inputs[link_info.target_slot];input.link=null;link_info.disconnect(graph,"input");graph._version++;target.onConnectionsChange?.(NodeSlotType.INPUT,link_info.target_slot,false,link_info,input);this.onConnectionsChange?.(NodeSlotType.OUTPUT,slot,false,link_info,output);break}}else{for(const link_id of links){const link_info=graph._links.get(link_id);if(!link_info)continue;const target=graph.getNodeById(link_info.target_id);graph._version++;if(target){const input=target.inputs[link_info.target_slot];input.link=null;target.onConnectionsChange?.(NodeSlotType.INPUT,link_info.target_slot,false,link_info,input)}link_info.disconnect(graph,"input");this.onConnectionsChange?.(NodeSlotType.OUTPUT,slot,false,link_info,output)}output.links=null}this.setDirtyCanvas(false,true);return true}disconnectInput(slot,keepReroutes){if(typeof slot==="string"){slot=this.findInputSlot(slot);if(slot==-1){if(LiteGraph.debug)console.log(`Connect: Error, no slot of name ${slot}`);return false}}else if(!this.inputs||slot>=this.inputs.length){if(LiteGraph.debug){console.log("Connect: Error, slot number not found")}return false}const input=this.inputs[slot];if(!input){console.debug("disconnectInput: input not found",slot,this.inputs);return false}const{graph}=this;if(!graph)throw new NullGraphError;if(input._floatingLinks?.size){for(const link of input._floatingLinks){graph.removeFloatingLink(link)}}const link_id=this.inputs[slot].link;if(link_id!=null){this.inputs[slot].link=null;const link_info=graph._links.get(link_id);if(link_info){if(link_info.origin_id===-10&&"inputNode"in graph){graph.inputNode._disconnectNodeInput(this,input,link_info);return true}const target_node=graph.getNodeById(link_info.origin_id);if(!target_node){console.debug("disconnectInput: target node not found",link_info.origin_id);return false}const output=target_node.outputs[link_info.origin_slot];if(!output?.links?.length){console.debug("disconnectInput: output not found",link_info.origin_slot);return false}let i=0;for(const l=output.links.length;i<l;i++){if(output.links[i]==link_id){output.links.splice(i,1);break}}link_info.disconnect(graph,keepReroutes?"output":void 0);if(graph)graph._version++;this.onConnectionsChange?.(NodeSlotType.INPUT,slot,false,link_info,input);target_node.onConnectionsChange?.(NodeSlotType.OUTPUT,i,false,link_info,output)}}this.setDirtyCanvas(false,true);return true}getConnectionPos(is_input,slot_number,out){out||=new Float32Array(2);const{pos:[nodeX,nodeY],inputs,outputs}=this;if(this.flags.collapsed){const w=this._collapsed_width||LiteGraph.NODE_COLLAPSED_WIDTH;out[0]=is_input?nodeX:nodeX+w;out[1]=nodeY-LiteGraph.NODE_TITLE_HEIGHT*.5;return out}if(is_input&&slot_number==-1){out[0]=nodeX+LiteGraph.NODE_TITLE_HEIGHT*.5;out[1]=nodeY+LiteGraph.NODE_TITLE_HEIGHT*.5;return out}const inputPos=inputs?.[slot_number]?.pos;const outputPos=outputs?.[slot_number]?.pos;if(is_input&&inputPos){out[0]=nodeX+inputPos[0];out[1]=nodeY+inputPos[1];return out}else if(!is_input&&outputPos){out[0]=nodeX+outputPos[0];out[1]=nodeY+outputPos[1];return out}const offset=LiteGraph.NODE_SLOT_HEIGHT*.5;const slotIndex=is_input?this.#defaultVerticalInputs.indexOf(this.inputs[slot_number]):this.#defaultVerticalOutputs.indexOf(this.outputs[slot_number]);out[0]=is_input?nodeX+offset:nodeX+this.size[0]+1-offset;out[1]=nodeY+(slotIndex+.7)*LiteGraph.NODE_SLOT_HEIGHT+(this.constructor.slot_start_y||0);return out}get#defaultVerticalInputs(){return this.inputs.filter(slot=>!slot.pos&&!(this.widgets?.length&&isWidgetInputSlot(slot)))}get#defaultVerticalOutputs(){return this.outputs.filter(slot=>!slot.pos)}getInputPos(slot){return this.getInputSlotPos(this.inputs[slot])}getInputSlotPos(input){const{pos:[nodeX,nodeY]}=this;if(this.flags.collapsed){const halfTitle=LiteGraph.NODE_TITLE_HEIGHT*.5;return[nodeX,nodeY-halfTitle]}const{pos}=input;if(pos)return[nodeX+pos[0],nodeY+pos[1]];const offsetX=LiteGraph.NODE_SLOT_HEIGHT*.5;const nodeOffsetY=this.constructor.slot_start_y||0;const slotIndex=this.#defaultVerticalInputs.indexOf(input);const slotY=(slotIndex+.7)*LiteGraph.NODE_SLOT_HEIGHT;return[nodeX+offsetX,nodeY+slotY+nodeOffsetY]}getOutputPos(slot){const{pos:[nodeX,nodeY],outputs,size:[width2]}=this;if(this.flags.collapsed){const width22=this._collapsed_width||LiteGraph.NODE_COLLAPSED_WIDTH;const halfTitle=LiteGraph.NODE_TITLE_HEIGHT*.5;return[nodeX+width22,nodeY-halfTitle]}const outputPos=outputs?.[slot]?.pos;if(outputPos)return[nodeX+outputPos[0],nodeY+outputPos[1]];const offsetX=LiteGraph.NODE_SLOT_HEIGHT*.5;const nodeOffsetY=this.constructor.slot_start_y||0;const slotIndex=this.#defaultVerticalOutputs.indexOf(this.outputs[slot]);const slotY=(slotIndex+.7)*LiteGraph.NODE_SLOT_HEIGHT;return[nodeX+width2+1-offsetX,nodeY+slotY+nodeOffsetY]}snapToGrid(snapTo){return this.pinned?false:snapPoint(this.pos,snapTo)}alignToGrid(){this.snapToGrid(LiteGraph.CANVAS_GRID_SIZE)}trace(msg){this.console||=[];this.console.push(msg);if(this.console.length>LGraphNode.MAX_CONSOLE)this.console.shift()}setDirtyCanvas(dirty_foreground,dirty_background){this.graph?.canvasAction(c=>c.setDirty(dirty_foreground,dirty_background))}loadImage(url){const img=new Image;img.src=LiteGraph.node_images_path+url;img.ready=false;const dirty=()=>this.setDirtyCanvas(true);img.addEventListener("load",function(){this.ready=true;dirty()});return img}captureInput(v2){warnDeprecated("[DEPRECATED] captureInput will be removed in a future version. Please use LGraphCanvas.pointer (CanvasPointer) instead.");if(!this.graph||!this.graph.list_of_graphcanvas)return;const list=this.graph.list_of_graphcanvas;for(const c of list){if(!v2&&c.node_capturing_input!=this)continue;c.node_capturing_input=v2?this:null}}get collapsed(){return!!this.flags.collapsed}get collapsible(){return!this.pinned&&this.constructor.collapsable!==false}collapse(force){if(!this.collapsible&&!force)return;if(!this.graph)throw new NullGraphError;this.graph._version++;this.flags.collapsed=!this.flags.collapsed;this.setDirtyCanvas(true,true)}toggleAdvanced(){if(!this.widgets?.some(w=>w.advanced))return;if(!this.graph)throw new NullGraphError;this.graph._version++;this.showAdvanced=!this.showAdvanced;this.expandToFitContent();this.setDirtyCanvas(true,true)}get pinned(){return!!this.flags.pinned}pin(v2){if(!this.graph)throw new NullGraphError;this.graph._version++;this.flags.pinned=v2??!this.flags.pinned;this.resizable=!this.pinned;if(!this.pinned)delete this.flags.pinned}unpin(){this.pin(false)}localToScreen(x2,y,dragAndScale){return[(x2+this.pos[0])*dragAndScale.scale+dragAndScale.offset[0],(y+this.pos[1])*dragAndScale.scale+dragAndScale.offset[1]]}get width(){return this.collapsed?this._collapsed_width||LiteGraph.NODE_COLLAPSED_WIDTH:this.size[0]}get height(){return LiteGraph.NODE_TITLE_HEIGHT+this.bodyHeight}get bodyHeight(){return this.collapsed?0:this.size[1]}drawBadges(ctx,{gap=2}={}){const badgeInstances=this.badges.map(badge=>badge instanceof LGraphBadge?badge:badge());const isLeftAligned=this.badgePosition===BadgePosition.TopLeft;let currentX=isLeftAligned?0:this.width-badgeInstances.reduce((acc,badge)=>acc+badge.getWidth(ctx)+gap,0);const y=-(LiteGraph.NODE_TITLE_HEIGHT+gap);for(const badge of badgeInstances){badge.draw(ctx,currentX,y-badge.height);currentX+=badge.getWidth(ctx)+gap}}drawTitleBarBackground(ctx,{scale,title_height=LiteGraph.NODE_TITLE_HEIGHT,low_quality=false}){const fgcolor=this.renderingColor;const shape=this.renderingShape;const size=this.renderingSize;if(this.onDrawTitleBar){this.onDrawTitleBar(ctx,title_height,size,scale,fgcolor);return}if(this.title_mode===TitleMode.TRANSPARENT_TITLE){return}if(this.collapsed){ctx.shadowColor=LiteGraph.DEFAULT_SHADOW_COLOR}ctx.fillStyle=this.constructor.title_color||fgcolor;ctx.beginPath();if(shape==RenderShape.BOX||low_quality){ctx.rect(0,-title_height,size[0],title_height)}else if(shape==RenderShape.ROUND||shape==RenderShape.CARD){ctx.roundRect(0,-title_height,size[0],title_height,this.collapsed?[LiteGraph.ROUND_RADIUS]:[LiteGraph.ROUND_RADIUS,LiteGraph.ROUND_RADIUS,0,0])}ctx.fill();ctx.shadowColor="transparent"}drawTitleBox(ctx,{scale,low_quality=false,title_height=LiteGraph.NODE_TITLE_HEIGHT,box_size=10}){const size=this.renderingSize;const shape=this.renderingShape;if(this.onDrawTitleBox){this.onDrawTitleBox(ctx,title_height,size,scale);return}if([RenderShape.ROUND,RenderShape.CIRCLE,RenderShape.CARD].includes(shape)){if(low_quality){ctx.fillStyle="black";ctx.beginPath();ctx.arc(title_height*.5,title_height*-.5,box_size*.5+1,0,Math.PI*2);ctx.fill()}ctx.fillStyle=this.renderingBoxColor;if(low_quality){ctx.fillRect(title_height*.5-box_size*.5,title_height*-.5-box_size*.5,box_size,box_size)}else{ctx.beginPath();ctx.arc(title_height*.5,title_height*-.5,box_size*.5,0,Math.PI*2);ctx.fill()}}else{if(low_quality){ctx.fillStyle="black";ctx.fillRect((title_height-box_size)*.5-1,(title_height+box_size)*-.5-1,box_size+2,box_size+2)}ctx.fillStyle=this.renderingBoxColor;ctx.fillRect((title_height-box_size)*.5,(title_height+box_size)*-.5,box_size,box_size)}}drawTitleText(ctx,{scale,default_title_color,low_quality=false,title_height=LiteGraph.NODE_TITLE_HEIGHT}){const size=this.renderingSize;const selected=this.selected;if(this.onDrawTitleText){this.onDrawTitleText(ctx,title_height,size,scale,this.titleFontStyle,selected);return}if(low_quality){return}ctx.font=this.titleFontStyle;const rawTitle=this.getTitle()??`❌ ${this.type}`;const title=String(rawTitle)+(this.pinned?"📌":"");if(title){if(selected){ctx.fillStyle=LiteGraph.NODE_SELECTED_TITLE_COLOR}else{ctx.fillStyle=this.constructor.title_text_color||default_title_color}let availableWidth=size[0]-title_height*2;if(this.title_buttons?.length>0){let buttonsWidth=0;const savedFont=ctx.font;for(const button of this.title_buttons){if(button.visible){buttonsWidth+=button.getWidth(ctx)+2}}ctx.font=savedFont;if(buttonsWidth>0){buttonsWidth+=10;availableWidth-=buttonsWidth}}let displayTitle=title;if(this.collapsed){displayTitle=title.substr(0,20)}else if(availableWidth>0){displayTitle=truncateText(ctx,title,availableWidth)}ctx.textAlign="left";ctx.fillText(displayTitle,title_height,LiteGraph.NODE_TITLE_TEXT_Y-title_height)}}connectInputToOutput(){const{inputs,outputs,graph}=this;if(!inputs||!outputs)return;if(!graph)throw new NullGraphError;const{_links}=graph;let madeAnyConnections=false;for(const[index,input]of inputs.entries()){if(input.link==null)continue;const output=outputs[index];if(!output||!LiteGraph.isValidConnection(input.type,output.type))continue;const inLink=_links.get(input.link);if(!inLink)continue;const inNode=graph.getNodeById(inLink?.origin_id);if(!inNode)continue;bypassAllLinks(output,inNode,inLink,graph)}if(!(this.flags.keepAllLinksOnBypass??LGraphNode.keepAllLinksOnBypass))return madeAnyConnections;for(const input of inputs){if(input.link==null)continue;const inLink=_links.get(input.link);if(!inLink)continue;const inNode=graph.getNodeById(inLink?.origin_id);if(!inNode)continue;for(const output of outputs){if(!LiteGraph.isValidConnection(input.type,output.type))continue;bypassAllLinks(output,inNode,inLink,graph);break}}return madeAnyConnections;function bypassAllLinks(output,inNode,inLink,graph2){const outLinks=output.links?.map(x2=>_links.get(x2)).filter(x2=>!!x2);if(!outLinks?.length)return;for(const outLink of outLinks){const outNode=graph2.getNodeById(outLink.target_id);if(!outNode)continue;const result=inNode.connect(inLink.origin_slot,outNode,outLink.target_slot,inLink.parentId);madeAnyConnections||=!!result}}}isWidgetVisible(widget){const isHidden=this.collapsed||widget.hidden||widget.advanced&&!this.showAdvanced;return!isHidden}drawWidgets(ctx,{lowQuality=false,editorAlpha=1}){if(!this.widgets)return;const nodeWidth=this.size[0];const{widgets}=this;const H=LiteGraph.NODE_WIDGET_HEIGHT;const showText=!lowQuality;ctx.save();ctx.globalAlpha=editorAlpha;for(const widget of widgets){if(!this.isWidgetVisible(widget))continue;const{y}=widget;const outlineColour=widget.advanced?LiteGraph.WIDGET_ADVANCED_OUTLINE_COLOR:LiteGraph.WIDGET_OUTLINE_COLOR;widget.last_y=y;widget.computedDisabled=widget.disabled||this.getSlotFromWidget(widget)?.link!=null;ctx.strokeStyle=outlineColour;ctx.fillStyle="#222";ctx.textAlign="left";if(widget.computedDisabled)ctx.globalAlpha*=.5;const width2=widget.width||nodeWidth;if(typeof widget.draw==="function"){widget.draw(ctx,this,width2,y,H,lowQuality)}else{toConcreteWidget(widget,this,false)?.drawWidget(ctx,{width:width2,showText})}ctx.globalAlpha=editorAlpha}ctx.restore()}drawCollapsedSlots(ctx){for(const slot of this.#concreteInputs){if(slot.link!=null){slot.drawCollapsed(ctx);break}}for(const slot of this.#concreteOutputs){if(slot.links?.length){slot.drawCollapsed(ctx);break}}}get slots(){return[...this.inputs,...this.outputs]}#measureSlot(slot,slotIndex,isInput){const pos=isInput?this.getInputPos(slotIndex):this.getOutputPos(slotIndex);slot.boundingRect[0]=pos[0]-LiteGraph.NODE_SLOT_HEIGHT*.5;slot.boundingRect[1]=pos[1]-LiteGraph.NODE_SLOT_HEIGHT*.5;slot.boundingRect[2]=slot.isWidgetInputSlot?BaseWidget.margin:LiteGraph.NODE_SLOT_HEIGHT;slot.boundingRect[3]=LiteGraph.NODE_SLOT_HEIGHT}#measureSlots(){const slots=[];for(const[slotIndex,slot]of this.#concreteInputs.entries()){if(this.widgets?.length&&isWidgetInputSlot(slot))continue;this.#measureSlot(slot,slotIndex,true);slots.push(slot)}for(const[slotIndex,slot]of this.#concreteOutputs.entries()){this.#measureSlot(slot,slotIndex,false);slots.push(slot)}return slots.length?createBounds(slots,0):null}#getMouseOverSlot(slot){const isInput=isINodeInputSlot(slot);const mouseOverId=this.mouseOver?.[isInput?"inputId":"outputId"]??-1;if(mouseOverId===-1){return null}return isInput?this.inputs[mouseOverId]:this.outputs[mouseOverId]}#isMouseOverSlot(slot){return this.#getMouseOverSlot(slot)===slot}#isMouseOverWidget(widget){if(!widget)return false;return this.mouseOver?.overWidget===widget}getSlotFromWidget(widget){if(widget)return this.inputs.find(slot=>isWidgetInputSlot(slot)&&slot.widget.name===widget.name)}getWidgetFromSlot(slot){if(!isWidgetInputSlot(slot))return;return this.widgets?.find(w=>w.name===slot.widget.name)}drawSlots(ctx,{fromSlot,colorContext,editorAlpha,lowQuality}){for(const slot of[...this.#concreteInputs,...this.#concreteOutputs]){const isValidTarget=fromSlot&&slot.isValidTarget(fromSlot);const isMouseOverSlot=this.#isMouseOverSlot(slot);const isValid=!fromSlot||isValidTarget;const highlight=isValid&&isMouseOverSlot;if(isMouseOverSlot||isValidTarget||!slot.isWidgetInputSlot||this.#isMouseOverWidget(this.getWidgetFromSlot(slot))||slot.isConnected){ctx.globalAlpha=isValid?editorAlpha:.4*editorAlpha;slot.draw(ctx,{colorContext,lowQuality,highlight})}}}#arrangeWidgets(widgetStartY){if(!this.widgets||!this.widgets.length)return;const bodyHeight=this.bodyHeight;const startY=this.widgets_start_y??(this.widgets_up?0:widgetStartY)+2;let freeSpace=bodyHeight-startY;let fixedWidgetHeight=0;const growableWidgets=[];for(const w of this.widgets){if(w.computeSize){const height=w.computeSize()[1]+4;w.computedHeight=height;fixedWidgetHeight+=height}else if(w.computeLayoutSize){const{minHeight,maxHeight}=w.computeLayoutSize(this);growableWidgets.push({minHeight,prefHeight:maxHeight,w})}else{const height=LiteGraph.NODE_WIDGET_HEIGHT+4;w.computedHeight=height;fixedWidgetHeight+=height}}freeSpace-=fixedWidgetHeight;this.freeWidgetSpace=freeSpace;const spaceRequests=growableWidgets.map(d=>({minSize:d.minHeight,maxSize:d.prefHeight}));const allocations=distributeSpace(Math.max(0,freeSpace),spaceRequests);for(const[i,d]of growableWidgets.entries()){d.w.computedHeight=allocations[i]}let y=startY;for(const w of this.widgets){w.y=y;y+=w.computedHeight??0}if(!this.graph)throw new NullGraphError;if(y>bodyHeight){this.setSize([this.size[0],y]);this.graph.setDirtyCanvas(false,true)}}#arrangeWidgetInputSlots(){if(!this.widgets)return;const slotByWidgetName=new Map;for(const[i,slot]of this.inputs.entries()){if(!isWidgetInputSlot(slot))continue;slotByWidgetName.set(slot.widget.name,{...slot,index:i})}if(!slotByWidgetName.size)return;for(const widget of this.widgets){const slot=slotByWidgetName.get(widget.name);if(!slot)continue;const actualSlot=this.#concreteInputs[slot.index];const offset=LiteGraph.NODE_SLOT_HEIGHT*.5;actualSlot.pos=[offset,widget.y+offset];this.#measureSlot(actualSlot,slot.index,true)}}_setConcreteSlots(){this.#concreteInputs=this.inputs.map(slot=>toClass(NodeInputSlot,slot,this));this.#concreteOutputs=this.outputs.map(slot=>toClass(NodeOutputSlot,slot,this))}arrange(){const slotsBounds=this.#measureSlots();const widgetStartY=slotsBounds?slotsBounds[1]+slotsBounds[3]-this.pos[1]:0;this.#arrangeWidgets(widgetStartY);this.#arrangeWidgetInputSlots()}drawProgressBar(ctx){if(!this.progress)return;const originalFillStyle=ctx.fillStyle;ctx.fillStyle="green";ctx.fillRect(0,0,this.width*this.progress,6);ctx.fillStyle=originalFillStyle}}function getAllNestedItems(items){const allItems=new Set;if(items){for(const item of items)addRecursively(item,allItems)}return allItems;function addRecursively(item,flatSet){if(flatSet.has(item)||item.pinned)return;flatSet.add(item);if(item.children){for(const child of item.children)addRecursively(child,flatSet)}}}function findFirstNode(items){for(const item of items){if(item instanceof LGraphNode)return item}}function findFreeSlotOfType(slots,type,hasNoLinks){if(!slots?.length)return;let occupiedSlot;let wildSlot;let occupiedWildSlot;const validTypes=parseSlotTypes(type);for(const[index,slot]of slots.entries()){const slotTypes=parseSlotTypes(slot.type);for(const validType of validTypes){for(const slotType of slotTypes){if(slotType===validType){if(hasNoLinks(slot)){return{index,slot}}occupiedSlot??={index,slot}}else if(!wildSlot&&(validType==="*"||slotType==="*")){if(hasNoLinks(slot)){wildSlot={index,slot}}else{occupiedWildSlot??={index,slot}}}}}}return wildSlot??occupiedSlot??occupiedWildSlot}function removeFromArray(array,value){const index=array.indexOf(value);const found=index!==-1;if(found)array.splice(index,1);return found}class SubgraphInput extends SubgraphSlot{events=new CustomEventTarget;#widgetRef;get _widget(){return this.#widgetRef?.deref()}set _widget(widget){this.#widgetRef=widget?new WeakRef(widget):void 0}connect(slot,node2,afterRerouteId){const{subgraph}=this.parent;const inputIndex=node2.inputs.indexOf(slot);if(node2.onConnectInput?.(inputIndex,this.type,this,this.parent,-1)===false)return;if(slot.link!=null){subgraph.beforeChange();const link2=subgraph.getLink(slot.link);this.parent._disconnectNodeInput(node2,slot,link2)}const inputWidget=node2.getWidgetFromSlot(slot);if(inputWidget){if(!this.matchesWidget(inputWidget)){console.warn("Target input has invalid widget.",slot,node2);return}this._widget??=inputWidget;this.events.dispatch("input-connected",{input:slot,widget:inputWidget})}const link=new LLink(++subgraph.state.lastLinkId,slot.type,this.parent.id,this.parent.slots.indexOf(this),node2.id,inputIndex,afterRerouteId);subgraph._links.set(link.id,link);this.linkIds.push(link.id);slot.link=link.id;const reroutes=LLink.getReroutes(subgraph,link);for(const reroute of reroutes){reroute.linkIds.add(link.id);if(reroute.floating)delete reroute.floating;reroute._dragging=void 0}const lastReroute=reroutes.at(-1);if(lastReroute){for(const linkId of lastReroute.floatingLinkIds){const link2=subgraph.floatingLinks.get(linkId);if(link2?.parentId===lastReroute.id){subgraph.removeFloatingLink(link2)}}}subgraph._version++;node2.onConnectionsChange?.(NodeSlotType.INPUT,inputIndex,true,link,slot);subgraph.afterChange();return link}get labelPos(){const[x2,y,,height]=this.boundingRect;return[x2,y+height*.5]}getConnectedWidgets(){const{subgraph}=this.parent;const widgets=[];for(const linkId of this.linkIds){const link=subgraph.getLink(linkId);if(!link){console.error("Link not found",linkId);continue}const resolved=link.resolve(subgraph);if(resolved.input&&resolved.inputNode?.widgets){const widgetNamePojo=resolved.input.widget;if(!widgetNamePojo)continue;if(!widgetNamePojo.name){console.warn("Invalid widget name",widgetNamePojo);continue}const widget=resolved.inputNode.widgets.find(w=>w.name===widgetNamePojo.name);if(!widget){console.warn("Widget not found",widgetNamePojo);continue}widgets.push(widget)}else{console.debug("No input found on link id",linkId,link)}}return widgets}matchesWidget(otherWidget){const widget=this.#widgetRef?.deref();if(!widget)return true;if(otherWidget.type!==widget.type||otherWidget.options.min!==widget.options.min||otherWidget.options.max!==widget.options.max||otherWidget.options.step!==widget.options.step||otherWidget.options.step2!==widget.options.step2||otherWidget.options.precision!==widget.options.precision){return false}return true}disconnect(){super.disconnect();this.events.dispatch("input-disconnected",{input:this})}arrange(rect){const[right,top,width2,height]=rect;const{boundingRect:b,pos}=this;b[0]=right-width2;b[1]=top;b[2]=width2;b[3]=height;pos[0]=right-height*.5;pos[1]=top+height*.5}isValidTarget(fromSlot){if(isNodeSlot(fromSlot)){return"link"in fromSlot&&LiteGraph.isValidConnection(this.type,fromSlot.type)}if(isSubgraphOutput(fromSlot)){return LiteGraph.isValidConnection(this.type,fromSlot.type)}return false}}class EmptySubgraphInput extends SubgraphInput{constructor(parent){super({id:zeroUuid,name:"",type:""},parent)}connect(slot,node2,afterRerouteId){const{subgraph}=this.parent;const existingNames=subgraph.inputs.map(x2=>x2.name);const name=nextUniqueName(slot.name,existingNames);const input=subgraph.addInput(name,String(slot.type));return input.connect(slot,node2,afterRerouteId)}get labelPos(){const[x2,y,,height]=this.boundingRect;return[x2,y+height*.5]}}class SubgraphInputNode extends SubgraphIONodeBase{id=SUBGRAPH_INPUT_ID;emptySlot=new EmptySubgraphInput(this);get slots(){return this.subgraph.inputs}get allSlots(){return[...this.slots,this.emptySlot]}get slotAnchorX(){const[x2,,width2]=this.boundingRect;return x2+width2-SubgraphIONodeBase.roundedRadius}onPointerDown(e2,pointer,linkConnector){if(e2.button===0){for(const slot of this.allSlots){const slotBounds=Rectangle.fromCentre(slot.pos,slot.boundingRect.height);if(slotBounds.containsXy(e2.canvasX,e2.canvasY)){pointer.onDragStart=()=>{linkConnector.dragNewFromSubgraphInput(this.subgraph,this,slot)};pointer.onDragEnd=eUp=>{linkConnector.dropLinks(this.subgraph,eUp)};pointer.finally=()=>{linkConnector.reset(true)}}}}else if(e2.button===2){const slot=this.getSlotInPosition(e2.canvasX,e2.canvasY);if(slot)this.showSlotContextMenu(slot,e2)}}renameSlot(slot,name){this.subgraph.renameInput(slot,name)}removeSlot(slot){this.subgraph.removeInput(slot)}canConnectTo(inputNode,input,fromSlot){return inputNode.canConnectTo(this,input,fromSlot)}connectSlots(fromSlot,inputNode,input,afterRerouteId){const{subgraph}=this;const outputIndex=this.slots.indexOf(fromSlot);const inputIndex=inputNode.inputs.indexOf(input);if(outputIndex===-1||inputIndex===-1)throw new Error("Invalid slot indices.");return new LLink(++subgraph.state.lastLinkId,input.type||fromSlot.type,this.id,outputIndex,inputNode.id,inputIndex,afterRerouteId)}connectByType(slot,target_node,target_slotType,optsIn){const inputSlot=target_node.findInputByType(target_slotType);if(!inputSlot)return;if(slot===-1){const newSubgraphInput=this.subgraph.addInput(inputSlot.slot.name,String(inputSlot.slot.type??""));const newSlotIndex=this.slots.indexOf(newSubgraphInput);if(newSlotIndex===-1){console.error("Could not find newly created subgraph input slot.");return}slot=newSlotIndex}return this.slots[slot].connect(inputSlot.slot,target_node,optsIn?.afterRerouteId)}findOutputSlot(name){return this.slots.find(output=>output.name===name)}findOutputByType(type){return findFreeSlotOfType(this.slots,type,slot=>slot.linkIds.length>0)?.slot}_disconnectNodeInput(node2,input,link){const{subgraph}=this;if(input._floatingLinks?.size){for(const link2 of input._floatingLinks){subgraph.removeFloatingLink(link2)}}input.link=null;subgraph.setDirtyCanvas(false,true);if(!link)return;const subgraphInputIndex=link.origin_slot;link.disconnect(subgraph,"output");subgraph._version++;const subgraphInput=this.slots.at(subgraphInputIndex);if(!subgraphInput){console.debug("disconnectNodeInput: subgraphInput not found",this,subgraphInputIndex);return}const index=subgraphInput.linkIds.indexOf(link.id);if(index!==-1){subgraphInput.linkIds.splice(index,1)}else{console.debug("disconnectNodeInput: link ID not found in subgraphInput linkIds",link.id)}node2.onConnectionsChange?.(NodeSlotType.OUTPUT,index,false,link,subgraphInput)}drawProtected(ctx,colorContext,fromSlot,editorAlpha){const{roundedRadius}=SubgraphIONodeBase;const transform=ctx.getTransform();const[x2,y,width2,height]=this.boundingRect;ctx.translate(x2,y);ctx.strokeStyle=this.sideStrokeStyle;ctx.lineWidth=this.sideLineWidth;ctx.beginPath();ctx.arc(width2-roundedRadius,roundedRadius,roundedRadius,Math.PI*1.5,0);ctx.moveTo(width2,roundedRadius);ctx.lineTo(width2,height-roundedRadius);ctx.arc(width2-roundedRadius,height-roundedRadius,roundedRadius,0,Math.PI*.5);ctx.stroke();ctx.setTransform(transform);this.drawSlots(ctx,colorContext,fromSlot,editorAlpha)}}class FloatingRenderLink{constructor(network,link,toType,fromReroute,dragDirection=LinkDirection.CENTER){this.network=network;this.link=link;this.toType=toType;this.fromReroute=fromReroute;this.dragDirection=dragDirection;const{origin_id:outputNodeId,target_id:inputNodeId,origin_slot:outputIndex,target_slot:inputIndex}=link;if(outputNodeId!==-1){const outputNode=network.getNodeById(outputNodeId)??void 0;if(!outputNode)throw new Error(`Creating DraggingRenderLink for link [${link.id}] failed: Output node [${outputNodeId}] not found.`);const outputSlot=outputNode?.outputs.at(outputIndex);if(!outputSlot)throw new Error(`Creating DraggingRenderLink for link [${link.id}] failed: Output slot [${outputIndex}] not found.`);this.outputNodeId=outputNodeId;this.outputNode=outputNode;this.outputSlot=outputSlot;this.outputIndex=outputIndex;this.outputPos=outputNode.getOutputPos(outputIndex);this.node=outputNode;this.fromSlot=outputSlot;this.fromPos=fromReroute?.pos??this.outputPos;this.fromDirection=LinkDirection.LEFT;this.dragDirection=LinkDirection.RIGHT;this.fromSlotIndex=outputIndex}else{const inputNode=network.getNodeById(inputNodeId)??void 0;if(!inputNode)throw new Error(`Creating DraggingRenderLink for link [${link.id}] failed: Input node [${inputNodeId}] not found.`);const inputSlot=inputNode?.inputs.at(inputIndex);if(!inputSlot)throw new Error(`Creating DraggingRenderLink for link [${link.id}] failed: Input slot [${inputIndex}] not found.`);this.inputNodeId=inputNodeId;this.inputNode=inputNode;this.inputSlot=inputSlot;this.inputIndex=inputIndex;this.inputPos=inputNode.getInputPos(inputIndex);this.node=inputNode;this.fromSlot=inputSlot;this.fromDirection=LinkDirection.RIGHT;this.fromSlotIndex=inputIndex}this.fromPos=fromReroute.pos}node;fromSlot;fromPos;fromDirection;fromSlotIndex;outputNodeId=-1;outputNode;outputSlot;outputIndex=-1;outputPos;inputNodeId=-1;inputNode;inputSlot;inputIndex=-1;inputPos;canConnectToInput(){return this.toType==="input"}canConnectToOutput(){return this.toType==="output"}canConnectToReroute(reroute){if(this.toType==="input"){if(reroute.origin_id===this.inputNode?.id)return false}else{if(reroute.origin_id===this.outputNode?.id)return false}return true}connectToInput(node2,input,_events){const floatingLink=this.link;floatingLink.target_id=node2.id;floatingLink.target_slot=node2.inputs.indexOf(input);node2.disconnectInput(node2.inputs.indexOf(input));this.fromSlot._floatingLinks?.delete(floatingLink);input._floatingLinks??=new Set;input._floatingLinks.add(floatingLink)}connectToOutput(node2,output,_events){const floatingLink=this.link;floatingLink.origin_id=node2.id;floatingLink.origin_slot=node2.outputs.indexOf(output);this.fromSlot._floatingLinks?.delete(floatingLink);output._floatingLinks??=new Set;output._floatingLinks.add(floatingLink)}connectToSubgraphInput(input,_events){const floatingLink=this.link;floatingLink.origin_id=SUBGRAPH_INPUT_ID;floatingLink.origin_slot=input.parent.slots.indexOf(input);this.fromSlot._floatingLinks?.delete(floatingLink);input._floatingLinks??=new Set;input._floatingLinks.add(floatingLink)}connectToSubgraphOutput(output,_events){const floatingLink=this.link;floatingLink.origin_id=SUBGRAPH_OUTPUT_ID;floatingLink.origin_slot=output.parent.slots.indexOf(output);this.fromSlot._floatingLinks?.delete(floatingLink);output._floatingLinks??=new Set;output._floatingLinks.add(floatingLink)}connectToRerouteInput(reroute,{node:inputNode,input},events){const floatingLink=this.link;floatingLink.target_id=inputNode.id;floatingLink.target_slot=inputNode.inputs.indexOf(input);this.fromSlot._floatingLinks?.delete(floatingLink);input._floatingLinks??=new Set;input._floatingLinks.add(floatingLink);events.dispatch("input-moved",this)}connectToRerouteOutput(reroute,outputNode,output,events){const floatingLink=this.link;floatingLink.origin_id=outputNode.id;floatingLink.origin_slot=outputNode.outputs.indexOf(output);this.fromSlot._floatingLinks?.delete(floatingLink);output._floatingLinks??=new Set;output._floatingLinks.add(floatingLink);events.dispatch("output-moved",this)}}class MovingLinkBase{constructor(network,link,toType,fromReroute,dragDirection=LinkDirection.CENTER){this.network=network;this.link=link;this.toType=toType;this.fromReroute=fromReroute;this.dragDirection=dragDirection;const{origin_id:outputNodeId,target_id:inputNodeId,origin_slot:outputIndex,target_slot:inputIndex}=link;const outputNode=network.getNodeById(outputNodeId)??void 0;if(!outputNode)throw new Error(`Creating MovingRenderLink for link [${link.id}] failed: Output node [${outputNodeId}] not found.`);const outputSlot=outputNode.outputs.at(outputIndex);if(!outputSlot)throw new Error(`Creating MovingRenderLink for link [${link.id}] failed: Output slot [${outputIndex}] not found.`);this.outputNodeId=outputNodeId;this.outputNode=outputNode;this.outputSlot=outputSlot;this.outputIndex=outputIndex;this.outputPos=outputNode.getOutputPos(outputIndex);const inputNode=network.getNodeById(inputNodeId)??void 0;if(!inputNode)throw new Error(`Creating DraggingRenderLink for link [${link.id}] failed: Input node [${inputNodeId}] not found.`);const inputSlot=inputNode.inputs.at(inputIndex);if(!inputSlot)throw new Error(`Creating DraggingRenderLink for link [${link.id}] failed: Input slot [${inputIndex}] not found.`);this.inputNodeId=inputNodeId;this.inputNode=inputNode;this.inputSlot=inputSlot;this.inputIndex=inputIndex;this.inputPos=inputNode.getInputPos(inputIndex)}outputNodeId;outputNode;outputSlot;outputIndex;outputPos;inputNodeId;inputNode;inputSlot;inputIndex;inputPos}class MovingInputLink extends MovingLinkBase{toType="input";node;fromSlot;fromPos;fromDirection;fromSlotIndex;constructor(network,link,fromReroute,dragDirection=LinkDirection.CENTER){super(network,link,"input",fromReroute,dragDirection);this.node=this.outputNode;this.fromSlot=this.outputSlot;this.fromPos=fromReroute?.pos??this.outputPos;this.fromDirection=LinkDirection.NONE;this.fromSlotIndex=this.outputIndex}canConnectToInput(inputNode,input){return this.node.canConnectTo(inputNode,input,this.outputSlot)}canConnectToOutput(){return false}canConnectToReroute(reroute){return reroute.origin_id!==this.inputNode.id}connectToInput(inputNode,input,events){if(input===this.inputSlot)return;this.inputNode.disconnectInput(this.inputIndex,true);const link=this.outputNode.connectSlots(this.outputSlot,inputNode,input,this.fromReroute?.id);if(link)events.dispatch("input-moved",this);return link}connectToOutput(){throw new Error("MovingInputLink cannot connect to an output.")}connectToSubgraphInput(){throw new Error("MovingInputLink cannot connect to a subgraph input.")}connectToSubgraphOutput(output,events){const newLink=output.connect(this.fromSlot,this.node,this.fromReroute?.id);events?.dispatch("link-created",newLink)}connectToRerouteInput(reroute,{node:inputNode,input,link:existingLink},events,originalReroutes){const{outputNode,outputSlot,fromReroute}=this;for(const reroute2 of originalReroutes){if(reroute2.id===this.link.parentId)break;if(reroute2.totalLinks===1)reroute2.remove()}reroute.parentId=fromReroute?.id;const newLink=outputNode.connectSlots(outputSlot,inputNode,input,existingLink.parentId);if(newLink)events.dispatch("input-moved",this)}connectToRerouteOutput(){throw new Error("MovingInputLink cannot connect to an output.")}disconnect(){return this.inputNode.disconnectInput(this.inputIndex,true)}}class MovingOutputLink extends MovingLinkBase{toType="output";node;fromSlot;fromPos;fromDirection;fromSlotIndex;constructor(network,link,fromReroute,dragDirection=LinkDirection.CENTER){super(network,link,"output",fromReroute,dragDirection);this.node=this.inputNode;this.fromSlot=this.inputSlot;this.fromPos=fromReroute?.pos??this.inputPos;this.fromDirection=LinkDirection.LEFT;this.fromSlotIndex=this.inputIndex}canConnectToInput(){return false}canConnectToOutput(outputNode,output){return outputNode.canConnectTo(this.node,this.inputSlot,output)}canConnectToReroute(reroute){return reroute.origin_id!==this.outputNode.id}connectToInput(){throw new Error("MovingOutputLink cannot connect to an input.")}connectToOutput(outputNode,output,events){if(output===this.outputSlot)return;const link=outputNode.connectSlots(output,this.inputNode,this.inputSlot,this.link.parentId);if(link)events.dispatch("output-moved",this);return link}connectToSubgraphInput(input,events){const newLink=input.connect(this.fromSlot,this.node,this.fromReroute?.id);events?.dispatch("link-created",newLink)}connectToSubgraphOutput(){throw new Error("MovingOutputLink cannot connect to a subgraph output.")}connectToRerouteInput(){throw new Error("MovingOutputLink cannot connect to an input.")}connectToRerouteOutput(reroute,outputNode,output,events){const{inputNode,inputSlot,fromReroute}=this;const floatingTerminus=reroute?.floating?.slotType==="output";if(fromReroute){fromReroute.parentId=reroute.id}else{this.link.parentId=reroute.id}outputNode.connectSlots(output,inputNode,inputSlot,this.link.parentId);if(floatingTerminus)reroute.removeAllFloatingLinks();events.dispatch("output-moved",this)}disconnect(){return this.outputNode.disconnectOutput(this.outputIndex,this.inputNode)}}class ToInputFromIoNodeLink{constructor(network,node2,fromSlot,fromReroute,dragDirection=LinkDirection.CENTER,existingLink){this.network=network;this.node=node2;this.fromSlot=fromSlot;this.fromReroute=fromReroute;this.dragDirection=dragDirection;const outputIndex=node2.slots.indexOf(fromSlot);if(outputIndex===-1&&fromSlot!==node2.emptySlot){throw new Error(`Creating render link for node [${this.node.id}] failed: Slot index not found.`)}this.fromSlotIndex=outputIndex;this.fromPos=fromReroute?fromReroute.pos:fromSlot.pos;this.existingLink=existingLink}toType="input";fromSlotIndex;fromPos;fromDirection=LinkDirection.RIGHT;existingLink;canConnectToInput(inputNode,input){return this.node.canConnectTo(inputNode,input,this.fromSlot)}canConnectToOutput(){return false}connectToInput(node2,input,events){const{fromSlot,fromReroute,existingLink}=this;const newLink=fromSlot.connect(input,node2,fromReroute?.id);if(existingLink){events.dispatch("input-moved",this)}else{events.dispatch("link-created",newLink)}}connectToSubgraphOutput(){throw new Error("Not implemented")}connectToRerouteInput(reroute,{node:inputNode,input,link},events,originalReroutes){const{fromSlot,fromReroute}=this;const floatingTerminus=fromReroute?.floating?.slotType==="output";reroute.parentId=fromReroute?.id;const newLink=fromSlot.connect(input,inputNode,link.parentId);if(floatingTerminus)fromReroute.removeAllFloatingLinks();for(const reroute2 of originalReroutes){if(reroute2.id===fromReroute?.id)break;reroute2.removeLink(link);if(reroute2.totalLinks===0){if(link.isFloating){reroute2.remove()}else{const cl=link.toFloating("output",reroute2.id);this.network.addFloatingLink(cl);reroute2.floating={slotType:"output"}}}}if(this.existingLink){events.dispatch("input-moved",this)}else{events.dispatch("link-created",newLink)}}connectToOutput(){throw new Error("ToInputRenderLink cannot connect to an output.")}connectToSubgraphInput(){throw new Error("ToInputRenderLink cannot connect to a subgraph input.")}connectToRerouteOutput(){throw new Error("ToInputRenderLink cannot connect to an output.")}}class ToInputRenderLink{constructor(network,node2,fromSlot,fromReroute,dragDirection=LinkDirection.CENTER){this.network=network;this.node=node2;this.fromSlot=fromSlot;this.fromReroute=fromReroute;this.dragDirection=dragDirection;const outputIndex=node2.outputs.indexOf(fromSlot);if(outputIndex===-1)throw new Error(`Creating render link for node [${this.node.id}] failed: Slot index not found.`);this.fromSlotIndex=outputIndex;this.fromPos=fromReroute?fromReroute.pos:this.node.getOutputPos(outputIndex)}toType="input";fromPos;fromSlotIndex;fromDirection=LinkDirection.RIGHT;canConnectToInput(inputNode,input){return this.node.canConnectTo(inputNode,input,this.fromSlot)}canConnectToOutput(){return false}connectToInput(node2,input,events){const{node:outputNode,fromSlot,fromReroute}=this;if(node2===outputNode)return;const newLink=outputNode.connectSlots(fromSlot,node2,input,fromReroute?.id);events.dispatch("link-created",newLink)}connectToSubgraphOutput(output,events){const newLink=output.connect(this.fromSlot,this.node,this.fromReroute?.id);events.dispatch("link-created",newLink)}connectToRerouteInput(reroute,{node:inputNode,input,link},events,originalReroutes){const{node:outputNode,fromSlot,fromReroute}=this;const floatingTerminus=fromReroute?.floating?.slotType==="output";reroute.parentId=fromReroute?.id;const newLink=outputNode.connectSlots(fromSlot,inputNode,input,link.parentId);if(floatingTerminus)fromReroute.removeAllFloatingLinks();for(const reroute2 of originalReroutes){if(reroute2.id===fromReroute?.id)break;reroute2.removeLink(link);if(reroute2.totalLinks===0){if(link.isFloating){reroute2.remove()}else{const cl=link.toFloating("output",reroute2.id);this.network.addFloatingLink(cl);reroute2.floating={slotType:"output"}}}}events.dispatch("link-created",newLink)}connectToOutput(){throw new Error("ToInputRenderLink cannot connect to an output.")}connectToSubgraphInput(){throw new Error("ToInputRenderLink cannot connect to a subgraph input.")}connectToRerouteOutput(){throw new Error("ToInputRenderLink cannot connect to an output.")}}class ToOutputFromIoNodeLink{constructor(network,node2,fromSlot,fromReroute,dragDirection=LinkDirection.CENTER){this.network=network;this.node=node2;this.fromSlot=fromSlot;this.fromReroute=fromReroute;this.dragDirection=dragDirection;const inputIndex=node2.slots.indexOf(fromSlot);if(inputIndex===-1&&fromSlot!==node2.emptySlot){throw new Error(`Creating render link for node [${this.node.id}] failed: Slot index not found.`)}this.fromSlotIndex=inputIndex;this.fromPos=fromReroute?fromReroute.pos:fromSlot.pos}toType="output";fromPos;fromSlotIndex;fromDirection=LinkDirection.LEFT;canConnectToInput(){return false}canConnectToOutput(outputNode,output){return this.node.canConnectTo(outputNode,this.fromSlot,output)}canConnectToReroute(reroute){if(reroute.origin_id===this.node.id)return false;return true}connectToOutput(node2,output,events){const{fromSlot,fromReroute}=this;const newLink=fromSlot.connect(output,node2,fromReroute?.id);events.dispatch("link-created",newLink)}connectToSubgraphInput(){throw new Error("Not implemented")}connectToRerouteOutput(reroute,outputNode,output,events){const{fromSlot}=this;const newLink=fromSlot.connect(output,outputNode,reroute?.id);events.dispatch("link-created",newLink)}connectToInput(){throw new Error("ToOutputRenderLink cannot connect to an input.")}connectToSubgraphOutput(){throw new Error("ToOutputRenderLink cannot connect to a subgraph output.")}connectToRerouteInput(){throw new Error("ToOutputRenderLink cannot connect to an input.")}}class ToOutputRenderLink{constructor(network,node2,fromSlot,fromReroute,dragDirection=LinkDirection.CENTER){this.network=network;this.node=node2;this.fromSlot=fromSlot;this.fromReroute=fromReroute;this.dragDirection=dragDirection;const inputIndex=node2.inputs.indexOf(fromSlot);if(inputIndex===-1)throw new Error(`Creating render link for node [${this.node.id}] failed: Slot index not found.`);this.fromSlotIndex=inputIndex;this.fromPos=fromReroute?fromReroute.pos:this.node.getInputPos(inputIndex)}toType="output";fromPos;fromSlotIndex;fromDirection=LinkDirection.LEFT;canConnectToInput(){return false}canConnectToOutput(outputNode,output){return this.node.canConnectTo(outputNode,this.fromSlot,output)}canConnectToReroute(reroute){if(reroute.origin_id===this.node.id)return false;return true}connectToOutput(node2,output,events){const{node:inputNode,fromSlot,fromReroute}=this;if(!inputNode)return;const newLink=node2.connectSlots(output,inputNode,fromSlot,fromReroute?.id);events.dispatch("link-created",newLink)}connectToSubgraphInput(input,events){const newLink=input.connect(this.fromSlot,this.node,this.fromReroute?.id);events?.dispatch("link-created",newLink)}connectToRerouteOutput(reroute,outputNode,output,events){const{node:inputNode,fromSlot}=this;const newLink=outputNode.connectSlots(output,inputNode,fromSlot,reroute?.id);events.dispatch("link-created",newLink)}connectToInput(){throw new Error("ToOutputRenderLink cannot connect to an input.")}connectToSubgraphOutput(){throw new Error("ToOutputRenderLink cannot connect to a subgraph output.")}connectToRerouteInput(){throw new Error("ToOutputRenderLink cannot connect to an input.")}}class ToOutputFromRerouteLink extends ToOutputRenderLink{constructor(network,node2,fromSlot,fromReroute,linkConnector){super(network,node2,fromSlot,fromReroute);this.fromReroute=fromReroute;this.linkConnector=linkConnector}canConnectToReroute(){return false}connectToOutput(node2,output){const nuRenderLink=new ToInputRenderLink(this.network,node2,output);this.linkConnector._connectOutputToReroute(this.fromReroute,nuRenderLink)}}class LinkConnector{state={connectingTo:void 0,multi:false,draggingExistingLinks:false,snapLinksPos:void 0};events=new CustomEventTarget;renderLinks=[];inputLinks=[];outputLinks=[];floatingLinks=[];hiddenReroutes=new Set;overWidget;overWidgetType;overReroute;#setConnectingLinks;constructor(setConnectingLinks){this.#setConnectingLinks=setConnectingLinks}get isConnecting(){return this.state.connectingTo!==void 0}get draggingExistingLinks(){return this.state.draggingExistingLinks}moveInputLink(network,input){if(this.isConnecting)throw new Error("Already dragging links.");const{state,inputLinks,renderLinks}=this;const linkId=input.link;if(linkId==null){const floatingLink=input._floatingLinks?.values().next().value;if(floatingLink?.parentId==null)return;try{const reroute=network.reroutes.get(floatingLink.parentId);if(!reroute)throw new Error(`Invalid reroute id: [${floatingLink.parentId}] for floating link id: [${floatingLink.id}].`);const renderLink=new FloatingRenderLink(network,floatingLink,"input",reroute);const mayContinue=this.events.dispatch("before-move-input",renderLink);if(mayContinue===false)return;renderLinks.push(renderLink)}catch(error){console.warn(`Could not create render link for link id: [${floatingLink.id}].`,floatingLink,error)}floatingLink._dragging=true;this.floatingLinks.push(floatingLink)}else{const link=network.links.get(linkId);if(!link)return;if(link.origin_id===SUBGRAPH_INPUT_ID){const subgraphInput=network.inputNode?.slots[link.origin_slot];if(!subgraphInput){console.warn(`Could not find subgraph input for slot [${link.origin_slot}]`);return}try{const reroute=network.getReroute(link.parentId);const renderLink=new ToInputFromIoNodeLink(network,network.inputNode,subgraphInput,reroute,LinkDirection.CENTER,link);renderLinks.push(renderLink);this.listenUntilReset("input-moved",()=>{link.disconnect(network,"input")})}catch(error){console.warn(`Could not create render link for subgraph input link id: [${link.id}].`,link,error);return}link._dragging=true;inputLinks.push(link)}else{try{const reroute=network.getReroute(link.parentId);const renderLink=new MovingInputLink(network,link,reroute);const mayContinue=this.events.dispatch("before-move-input",renderLink);if(mayContinue===false)return;renderLinks.push(renderLink);this.listenUntilReset("input-moved",e2=>{if("link"in e2.detail&&e2.detail.link){e2.detail.link.disconnect(network,"output")}})}catch(error){console.warn(`Could not create render link for link id: [${link.id}].`,link,error);return}link._dragging=true;inputLinks.push(link)}}state.connectingTo="input";state.draggingExistingLinks=true;this.#setLegacyLinks(false)}moveOutputLink(network,output){if(this.isConnecting)throw new Error("Already dragging links.");const{state,renderLinks}=this;if(output._floatingLinks?.size){for(const floatingLink of output._floatingLinks.values()){try{const reroute=LLink.getFirstReroute(network,floatingLink);if(!reroute)throw new Error(`Invalid reroute id: [${floatingLink.parentId}] for floating link id: [${floatingLink.id}].`);const renderLink=new FloatingRenderLink(network,floatingLink,"output",reroute);const mayContinue=this.events.dispatch("before-move-output",renderLink);if(mayContinue===false)continue;renderLinks.push(renderLink);this.floatingLinks.push(floatingLink)}catch(error){console.warn(`Could not create render link for link id: [${floatingLink.id}].`,floatingLink,error)}}}if(output.links?.length){for(const linkId of output.links){const link=network.links.get(linkId);if(!link)continue;const firstReroute=LLink.getFirstReroute(network,link);if(firstReroute){firstReroute._dragging=true;this.hiddenReroutes.add(firstReroute)}else{link._dragging=true}this.outputLinks.push(link);try{const renderLink=new MovingOutputLink(network,link,firstReroute,LinkDirection.RIGHT);const mayContinue=this.events.dispatch("before-move-output",renderLink);if(mayContinue===false)continue;renderLinks.push(renderLink)}catch(error){console.warn(`Could not create render link for link id: [${link.id}].`,link,error);continue}}}if(renderLinks.length===0)return;state.draggingExistingLinks=true;state.multi=true;state.connectingTo="output";this.#setLegacyLinks(true)}dragNewFromOutput(network,node2,output,fromReroute){if(this.isConnecting)throw new Error("Already dragging links.");const{state}=this;const renderLink=new ToInputRenderLink(network,node2,output,fromReroute);this.renderLinks.push(renderLink);state.connectingTo="input";this.#setLegacyLinks(false)}dragNewFromInput(network,node2,input,fromReroute){if(this.isConnecting)throw new Error("Already dragging links.");const{state}=this;const renderLink=new ToOutputRenderLink(network,node2,input,fromReroute);this.renderLinks.push(renderLink);state.connectingTo="output";this.#setLegacyLinks(true)}dragNewFromSubgraphInput(network,inputNode,input,fromReroute){if(this.isConnecting)throw new Error("Already dragging links.");const renderLink=new ToInputFromIoNodeLink(network,inputNode,input,fromReroute);this.renderLinks.push(renderLink);this.state.connectingTo="input";this.#setLegacyLinks(false)}dragNewFromSubgraphOutput(network,outputNode,output,fromReroute){if(this.isConnecting)throw new Error("Already dragging links.");const renderLink=new ToOutputFromIoNodeLink(network,outputNode,output,fromReroute);this.renderLinks.push(renderLink);this.state.connectingTo="output";this.#setLegacyLinks(true)}dragFromReroute(network,reroute){if(this.isConnecting)throw new Error("Already dragging links.");const link=reroute.firstLink??reroute.firstFloatingLink;if(!link){console.warn("No link found for reroute.");return}if(link.origin_id===SUBGRAPH_INPUT_ID){if(!(network instanceof Subgraph)){console.warn("Subgraph input link found in non-subgraph network.");return}const input=network.inputs.at(link.origin_slot);if(!input)throw new Error("No subgraph input found for link.");const renderLink2=new ToInputFromIoNodeLink(network,network.inputNode,input,reroute);renderLink2.fromDirection=LinkDirection.NONE;this.renderLinks.push(renderLink2);this.state.connectingTo="input";this.#setLegacyLinks(false);return}const outputNode=network.getNodeById(link.origin_id);if(!outputNode){console.warn("No output node found for link.",link);return}const outputSlot=outputNode.outputs.at(link.origin_slot);if(!outputSlot){console.warn("No output slot found for link.",link);return}const renderLink=new ToInputRenderLink(network,outputNode,outputSlot,reroute);renderLink.fromDirection=LinkDirection.NONE;this.renderLinks.push(renderLink);this.state.connectingTo="input";this.#setLegacyLinks(false)}dragFromRerouteToOutput(network,reroute){if(this.isConnecting)throw new Error("Already dragging links.");const link=reroute.firstLink??reroute.firstFloatingLink;if(!link){console.warn("No link found for reroute.");return}if(link.target_id===SUBGRAPH_OUTPUT_ID){if(!(network instanceof Subgraph)){console.warn("Subgraph output link found in non-subgraph network.");return}const output=network.outputs.at(link.target_slot);if(!output)throw new Error("No subgraph output found for link.");const renderLink2=new ToOutputFromIoNodeLink(network,network.outputNode,output,reroute);renderLink2.fromDirection=LinkDirection.NONE;this.renderLinks.push(renderLink2);this.state.connectingTo="output";this.#setLegacyLinks(false);return}const inputNode=network.getNodeById(link.target_id);if(!inputNode){console.warn("No input node found for link.",link);return}const inputSlot=inputNode.inputs.at(link.target_slot);if(!inputSlot){console.warn("No input slot found for link.",link);return}const renderLink=new ToOutputFromRerouteLink(network,inputNode,inputSlot,reroute,this);renderLink.fromDirection=LinkDirection.LEFT;this.renderLinks.push(renderLink);this.state.connectingTo="output";this.#setLegacyLinks(true)}dragFromLinkSegment(network,linkSegment){if(this.isConnecting)throw new Error("Already dragging links.");const{state}=this;if(linkSegment.origin_id==null||linkSegment.origin_slot==null)return;const node2=network.getNodeById(linkSegment.origin_id);if(!node2)return;const slot=node2.outputs.at(linkSegment.origin_slot);if(!slot)return;const reroute=network.getReroute(linkSegment.parentId);const renderLink=new ToInputRenderLink(network,node2,slot,reroute);renderLink.fromDirection=LinkDirection.NONE;this.renderLinks.push(renderLink);state.connectingTo="input";this.#setLegacyLinks(false)}dropLinks(locator,event){if(!this.isConnecting){const mayContinue=this.events.dispatch("before-drop-links",{renderLinks:this.renderLinks,event});if(mayContinue===false)return}try{const{canvasX,canvasY}=event;const ioNode=locator.getIoNodeOnPos?.(canvasX,canvasY);if(ioNode){this.dropOnIoNode(ioNode,event);return}const node2=locator.getNodeOnPos(canvasX,canvasY)??void 0;if(node2){this.dropOnNode(node2,event)}else{const reroute=locator.getRerouteOnPos(canvasX,canvasY);if(reroute&&this.isRerouteValidDrop(reroute)){this.dropOnReroute(reroute,event)}else{this.dropOnNothing(event)}}}finally{this.events.dispatch("after-drop-links",{renderLinks:this.renderLinks,event})}}dropOnIoNode(ioNode,event){const{renderLinks,state}=this;const{connectingTo}=state;const{canvasX,canvasY}=event;if(connectingTo==="input"&&ioNode instanceof SubgraphOutputNode){const output=ioNode.getSlotInPosition(canvasX,canvasY);if(!output)throw new Error("No output slot found for link.");for(const link of renderLinks){link.connectToSubgraphOutput(output,this.events)}}else if(connectingTo==="output"&&ioNode instanceof SubgraphInputNode){const input=ioNode.getSlotInPosition(canvasX,canvasY);if(!input)throw new Error("No input slot found for link.");for(const link of renderLinks){link.connectToSubgraphInput(input,this.events)}}else{console.error("Invalid connectingTo state &/ ioNode",connectingTo,ioNode)}}dropOnNode(node2,event){const{renderLinks,state}=this;const{connectingTo}=state;const{canvasX,canvasY}=event;if(renderLinks.every(link=>link.node===node2))return;if(connectingTo==="output"){const output=node2.getOutputOnPos([canvasX,canvasY]);if(output){this.#dropOnOutput(node2,output)}else{this.connectToNode(node2,event)}}else if(connectingTo==="input"){const input=node2.getInputOnPos([canvasX,canvasY]);const inputOrSocket=input??node2.getSlotFromWidget(this.overWidget);if(inputOrSocket){this.#dropOnInput(node2,inputOrSocket)}else{this.connectToNode(node2,event)}}}dropOnReroute(reroute,event){const mayContinue=this.events.dispatch("dropped-on-reroute",{reroute,event});if(mayContinue===false)return;if(this.state.connectingTo==="input"){if(this.renderLinks.length!==1)throw new Error(`Attempted to connect ${this.renderLinks.length} input links to a reroute.`);const renderLink=this.renderLinks[0];this._connectOutputToReroute(reroute,renderLink);return}for(const link of this.renderLinks){if(link.toType!=="output")continue;const result=reroute.findSourceOutput();if(!result)continue;const{node:node2,output}=result;if(!link.canConnectToOutput(node2,output))continue;link.connectToRerouteOutput(reroute,node2,output,this.events)}}_connectOutputToReroute(reroute,renderLink){const results=reroute.findTargetInputs();if(!results?.length)return;const maybeReroutes=reroute.getReroutes();if(maybeReroutes===null)throw new Error("Reroute loop detected.");const originalReroutes=maybeReroutes.slice(0,-1).reverse();if(renderLink instanceof ToInputRenderLink){const{node:node2,fromSlot,fromSlotIndex,fromReroute}=renderLink;reroute.setFloatingLinkOrigin(node2,fromSlot,fromSlotIndex);if(fromReroute!=null){for(const originalReroute of originalReroutes){if(originalReroute.id===fromReroute.id)break;for(const linkId of reroute.floatingLinkIds){originalReroute.floatingLinkIds.delete(linkId)}}}}const filtered=results.filter(result=>renderLink.toType==="input"&&canConnectInputLinkToReroute(renderLink,result.node,result.input,reroute));for(const result of filtered){renderLink.connectToRerouteInput(reroute,result,this.events,originalReroutes)}return}dropOnNothing(event){const mayContinue=this.events.dispatch("dropped-on-canvas",event);if(mayContinue===false)return;this.disconnectLinks()}disconnectLinks(){for(const link of this.renderLinks){if(link instanceof MovingLinkBase){link.disconnect()}}}connectToNode(node2,event){const{state:{connectingTo}}=this;const mayContinue=this.events.dispatch("dropped-on-node",{node:node2,event});if(mayContinue===false)return;const firstLink=this.renderLinks[0];if(!firstLink)return;if(connectingTo==="output"){const output=node2.findOutputByType(firstLink.fromSlot.type)?.slot;console.debug("out",node2,output,firstLink.fromSlot);if(output===void 0){console.warn(`Could not find slot for link type: [${firstLink.fromSlot.type}].`);return}this.#dropOnOutput(node2,output)}else if(connectingTo==="input"){const input=node2.findInputByType(firstLink.fromSlot.type)?.slot;console.debug("in",node2,input,firstLink.fromSlot);if(input===void 0){console.warn(`Could not find slot for link type: [${firstLink.fromSlot.type}].`);return}this.#dropOnInput(node2,input)}}#dropOnInput(node2,input){for(const link of this.renderLinks){if(!link.canConnectToInput(node2,input))continue;link.connectToInput(node2,input,this.events)}}#dropOnOutput(node2,output){for(const link of this.renderLinks){if(!link.canConnectToOutput(node2,output)){if(link instanceof MovingOutputLink&&link.link.parentId!==void 0){link.outputNode.connectSlots(link.outputSlot,link.inputNode,link.inputSlot,void 0)}continue}link.connectToOutput(node2,output,this.events)}}isInputValidDrop(node2,input){return this.renderLinks.some(link=>link.canConnectToInput(node2,input))}isNodeValidDrop(node2){if(this.state.connectingTo==="output"){return node2.outputs.some(output=>this.renderLinks.some(link=>link.canConnectToOutput(node2,output)))}return node2.inputs.some(input=>this.renderLinks.some(link=>link.canConnectToInput(node2,input)))}isRerouteValidDrop(reroute){if(this.state.connectingTo==="input"){const results=reroute.findTargetInputs();if(!results?.length)return false;for(const{node:node2,input}of results){for(const renderLink of this.renderLinks){if(renderLink.toType!=="input")continue;if(canConnectInputLinkToReroute(renderLink,node2,input,reroute))return true}}}else{const result=reroute.findSourceOutput();if(!result)return false;const{node:node2,output}=result;for(const renderLink of this.renderLinks){if(renderLink.toType!=="output")continue;if(!renderLink.canConnectToReroute(reroute))continue;if(renderLink.canConnectToOutput(node2,output))return true}}return false}#setLegacyLinks(fromSlotIsInput){const links=this.renderLinks.map(link=>{const input=fromSlotIsInput?link.fromSlot:null;const output=fromSlotIsInput?null:link.fromSlot;const afterRerouteId=link instanceof MovingLinkBase?link.link?.parentId:link.fromReroute?.id;return{node:link.node,slot:link.fromSlotIndex,input,output,pos:link.fromPos,afterRerouteId}});this.#setConnectingLinks(links)}export(network){return{renderLinks:[...this.renderLinks],inputLinks:[...this.inputLinks],outputLinks:[...this.outputLinks],floatingLinks:[...this.floatingLinks],state:{...this.state},network}}listenUntilReset(eventName,listener,options){this.events.addEventListener(eventName,listener,options);this.events.addEventListener("reset",()=>this.events.removeEventListener(eventName,listener),{once:true})}reset(force=false){const mayContinue=this.events.dispatch("reset",force);if(mayContinue===false)return;const{state,outputLinks,inputLinks,hiddenReroutes,renderLinks,floatingLinks}=this;if(!force&&state.connectingTo===void 0)return;state.connectingTo=void 0;for(const link of outputLinks)delete link._dragging;for(const link of inputLinks)delete link._dragging;for(const link of floatingLinks)delete link._dragging;for(const reroute of hiddenReroutes)delete reroute._dragging;renderLinks.length=0;inputLinks.length=0;outputLinks.length=0;floatingLinks.length=0;hiddenReroutes.clear();state.multi=false;state.draggingExistingLinks=false;state.snapLinksPos=void 0}}function canConnectInputLinkToReroute(link,inputNode,input,reroute){const{fromReroute}=link;if(!link.canConnectToInput(inputNode,input)||fromReroute?.id===reroute.id||fromReroute?.getReroutes()?.includes(reroute)){return false}if(link instanceof ToInputRenderLink){if(reroute.parentId==null){if(reroute.firstLink?.hasOrigin(link.node.id,link.fromSlotIndex))return false}else if(link.fromReroute?.id===reroute.parentId){return false}}return true}class CanvasPointer{static bufferTime=150;static doubleClickTime=300;static get maxClickDrift(){return this.#maxClickDrift}static set maxClickDrift(value){this.#maxClickDrift=value;this.#maxClickDrift2=value*value}static#maxClickDrift=6;static#maxClickDrift2=this.#maxClickDrift**2;element;pointerId;dragStarted=false;eLastDown;isDouble=false;isDown=false;resizeDirection;clearEventsOnReset=true;eDown;eMove;eUp;get finally(){return this.#finally}set finally(value){try{this.#finally?.()}finally{this.#finally=value}}#finally;constructor(element){this.element=element}down(e2){this.reset();this.eDown=e2;this.pointerId=e2.pointerId;this.element.setPointerCapture(e2.pointerId)}move(e2){const{eDown}=this;if(!eDown)return;if(!e2.buttons){this.reset();return}if(!(e2.buttons&eDown.buttons)){this.#completeClick(e2);this.reset();return}this.eMove=e2;this.onDrag?.(e2);if(this.dragStarted)return;const longerThanBufferTime=e2.timeStamp-eDown.timeStamp>CanvasPointer.bufferTime;if(longerThanBufferTime||!this.#hasSamePosition(e2,eDown)){this.#setDragStarted(e2)}}up(e2){if(e2.button!==this.eDown?.button)return false;this.#completeClick(e2);const{dragStarted}=this;this.reset();return!dragStarted}#completeClick(e2){const{eDown}=this;if(!eDown)return;this.eUp=e2;if(this.dragStarted){this.onDragEnd?.(e2)}else if(!this.#hasSamePosition(e2,eDown)){this.#setDragStarted();this.onDragEnd?.(e2)}else if(this.onDoubleClick&&this.#isDoubleClick()){this.onDoubleClick(e2);this.eLastDown=void 0}else{this.onClick?.(e2);this.eLastDown=eDown}}#hasSamePosition(a,b,tolerance2=CanvasPointer.#maxClickDrift2){const drift=dist2(a.clientX,a.clientY,b.clientX,b.clientY);return drift<=tolerance2}#isDoubleClick(){const{eDown,eLastDown}=this;if(!eDown||!eLastDown)return false;const tolerance2=(3*CanvasPointer.#maxClickDrift)**2;const diff=eDown.timeStamp-eLastDown.timeStamp;return diff>0&&diff<CanvasPointer.doubleClickTime&&this.#hasSamePosition(eDown,eLastDown,tolerance2)}#setDragStarted(eMove){this.dragStarted=true;this.onDragStart?.(this,eMove);delete this.onDragStart}reset(){this.finally=void 0;delete this.onClick;delete this.onDoubleClick;delete this.onDragStart;delete this.onDrag;delete this.onDragEnd;this.isDown=false;this.isDouble=false;this.dragStarted=false;this.resizeDirection=void 0;if(this.clearEventsOnReset){this.eDown=void 0;this.eMove=void 0;this.eUp=void 0}const{element,pointerId}=this;this.pointerId=void 0;if(typeof pointerId==="number"&&element.hasPointerCapture(pointerId)){element.releasePointerCapture(pointerId)}}}class DragAndScale{state;lastState={offset:[0,0],scale:0};max_scale;min_scale;enabled;last_mouse;element;visible_area;dragging;viewport;get offset(){return this.state.offset}set offset(value){this.state.offset[0]=value[0];this.state.offset[1]=value[1]}get scale(){return this.state.scale}set scale(value){this.state.scale=value}constructor(element){this.state={offset:[0,0],scale:1};this.max_scale=10;this.min_scale=.1;this.enabled=true;this.last_mouse=[0,0];this.visible_area=new Rectangle;this.element=element}#stateHasChanged(){const current=this.state;const previous=this.lastState;return current.scale!==previous.scale||current.offset[0]!==previous.offset[0]||current.offset[1]!==previous.offset[1]}computeVisibleArea(viewport){const{scale,offset,visible_area}=this;if(this.#stateHasChanged()){this.onChanged?.(scale,offset);copyState(this.state,this.lastState)}if(!this.element){visible_area[0]=visible_area[1]=visible_area[2]=visible_area[3]=0;return}let{width:width2,height}=this.element;let startx=-offset[0];let starty=-offset[1];if(viewport){startx+=viewport[0]/scale;starty+=viewport[1]/scale;width2=viewport[2];height=viewport[3]}const endx=startx+width2/scale;const endy=starty+height/scale;visible_area[0]=startx;visible_area[1]=starty;visible_area.resizeBottomRight(endx,endy)}toCanvasContext(ctx){ctx.scale(this.scale,this.scale);ctx.translate(this.offset[0],this.offset[1])}convertOffsetToCanvas(pos){return[(pos[0]+this.offset[0])*this.scale,(pos[1]+this.offset[1])*this.scale]}convertCanvasToOffset(pos,out){out=out||[0,0];out[0]=pos[0]/this.scale-this.offset[0];out[1]=pos[1]/this.scale-this.offset[1];return out}mouseDrag(x2,y){this.offset[0]+=x2/this.scale;this.offset[1]+=y/this.scale;this.onredraw?.(this)}changeScale(value,zooming_center,roundToScaleOne=true){if(value<this.min_scale){value=this.min_scale}else if(value>this.max_scale){value=this.max_scale}if(value==this.scale)return;const rect=this.element.getBoundingClientRect();if(!rect)return;zooming_center=zooming_center??[rect.width*.5,rect.height*.5];const normalizedCenter=[zooming_center[0]-rect.x,zooming_center[1]-rect.y];const center=this.convertCanvasToOffset(normalizedCenter);this.scale=value;if(roundToScaleOne&&Math.abs(this.scale-1)<.01)this.scale=1;const new_center=this.convertCanvasToOffset(normalizedCenter);const delta_offset=[new_center[0]-center[0],new_center[1]-center[1]];this.offset[0]+=delta_offset[0];this.offset[1]+=delta_offset[1];this.onredraw?.(this)}changeDeltaScale(value,zooming_center){this.changeScale(this.scale*value,zooming_center)}fitToBounds(bounds,{zoom=.75}={}){const cw=this.element.width/window.devicePixelRatio;const ch=this.element.height/window.devicePixelRatio;let targetScale=this.scale;if(zoom>0){const targetScaleX=zoom*cw/Math.max(bounds[2],300);const targetScaleY=zoom*ch/Math.max(bounds[3],300);targetScale=Math.min(targetScaleX,targetScaleY,this.max_scale)}const scaledWidth=cw/targetScale;const scaledHeight=ch/targetScale;const targetX=-bounds[0]-bounds[2]*.5+scaledWidth*.5;const targetY=-bounds[1]-bounds[3]*.5+scaledHeight*.5;this.offset[0]=targetX;this.offset[1]=targetY;this.scale=targetScale}animateToBounds(bounds,setDirty,{duration=350,zoom=.75,easing=EaseFunction.EASE_IN_OUT_QUAD}={}){if(!(duration>0))throw new RangeError("Duration must be greater than 0");const easeFunctions={linear:t=>t,easeInQuad:t=>t*t,easeOutQuad:t=>t*(2-t),easeInOutQuad:t=>t<.5?2*t*t:-1+(4-2*t)*t};const easeFunction=easeFunctions[easing]??easeFunctions.linear;const startTimestamp=performance.now();const cw=this.element.width/window.devicePixelRatio;const ch=this.element.height/window.devicePixelRatio;const startX=this.offset[0];const startY=this.offset[1];const startX2=startX-cw/this.scale;const startY2=startY-ch/this.scale;const startScale=this.scale;let targetScale=startScale;if(zoom>0){const targetScaleX=zoom*cw/Math.max(bounds[2],300);const targetScaleY=zoom*ch/Math.max(bounds[3],300);targetScale=Math.min(targetScaleX,targetScaleY,this.max_scale)}const scaledWidth=cw/targetScale;const scaledHeight=ch/targetScale;const targetX=-bounds[0]-bounds[2]*.5+scaledWidth*.5;const targetY=-bounds[1]-bounds[3]*.5+scaledHeight*.5;const targetX2=targetX-scaledWidth;const targetY2=targetY-scaledHeight;const animate=timestamp=>{const elapsed=timestamp-startTimestamp;const progress=Math.min(elapsed/duration,1);const easedProgress=easeFunction(progress);const currentX=startX+(targetX-startX)*easedProgress;const currentY=startY+(targetY-startY)*easedProgress;this.offset[0]=currentX;this.offset[1]=currentY;if(zoom>0){const currentX2=startX2+(targetX2-startX2)*easedProgress;const currentY2=startY2+(targetY2-startY2)*easedProgress;const currentWidth=Math.abs(currentX2-currentX);const currentHeight=Math.abs(currentY2-currentY);this.scale=Math.min(cw/currentWidth,ch/currentHeight)}setDirty();if(progress<1){animationId=requestAnimationFrame(animate)}else{cancelAnimationFrame(animationId)}};let animationId=requestAnimationFrame(animate)}reset(){this.scale=1;this.offset[0]=0;this.offset[1]=0}}function copyState(from,to){to.scale=from.scale;to.offset[0]=from.offset[0];to.offset[1]=from.offset[1]}function getBoundaryNodes(nodes){const valid=nodes?.find(x2=>x2);if(!valid)return null;let top=valid;let right=valid;let bottom=valid;let left=valid;for(const node2 of nodes){if(!node2)continue;const[x2,y]=node2.pos;const[width2,height]=node2.size;if(y<top.pos[1])top=node2;if(x2+width2>right.pos[0]+right.size[0])right=node2;if(y+height>bottom.pos[1]+bottom.size[1])bottom=node2;if(x2<left.pos[0])left=node2}return{top,right,bottom,left}}function distributeNodes(nodes,horizontal){const nodeCount=nodes?.length;if(!(nodeCount>1))return;const index=horizontal?0:1;let total=0;let highest=-Infinity;for(const node2 of nodes){total+=node2.size[index];const high=node2.pos[index]+node2.size[index];if(high>highest)highest=high}const sorted=[...nodes].sort((a,b)=>a.pos[index]-b.pos[index]);const lowest=sorted[0].pos[index];const gap=(highest-lowest-total)/(nodeCount-1);let startAt=lowest;for(let i=0;i<nodeCount;i++){const node2=sorted[i];node2.pos[index]=startAt+gap*i;startAt+=node2.size[index]}}function alignNodes(nodes,direction,align_to){if(!nodes)return;const boundary=align_to===void 0?getBoundaryNodes(nodes):{top:align_to,right:align_to,bottom:align_to,left:align_to};if(boundary===null)return;for(const node2 of nodes){switch(direction){case"right":node2.pos[0]=boundary.right.pos[0]+boundary.right.size[0]-node2.size[0];break;case"left":node2.pos[0]=boundary.left.pos[0];break;case"top":node2.pos[1]=boundary.top.pos[1];break;case"bottom":node2.pos[1]=boundary.bottom.pos[1]+boundary.bottom.size[1]-node2.size[1];break}}}const cursors={NE:"nesw-resize",SE:"nwse-resize",SW:"nesw-resize",NW:"nwse-resize"};class LGraphCanvas{static#temp=new Float32Array(4);static#temp_vec2=new Float32Array(2);static#tmp_area=new Float32Array(4);static#margin_area=new Float32Array(4);static#link_bounding=new Float32Array(4);static#lTempA=new Float32Array(2);static#lTempB=new Float32Array(2);static#lTempC=new Float32Array(2);static DEFAULT_BACKGROUND_IMAGE="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAIAAAD/gAIDAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAQBJREFUeNrs1rEKwjAUhlETUkj3vP9rdmr1Ysammk2w5wdxuLgcMHyptfawuZX4pJSWZTnfnu/lnIe/jNNxHHGNn//HNbbv+4dr6V+11uF527arU7+u63qfa/bnmh8sWLBgwYJlqRf8MEptXPBXJXa37BSl3ixYsGDBMliwFLyCV/DeLIMFCxYsWLBMwSt4Be/NggXLYMGCBUvBK3iNruC9WbBgwYJlsGApeAWv4L1ZBgsWLFiwYJmCV/AK3psFC5bBggULloJX8BpdwXuzYMGCBctgwVLwCl7Be7MMFixYsGDBsu8FH1FaSmExVfAxBa/gvVmwYMGCZbBg/W4vAQYA5tRF9QYlv/QAAAAASUVORK5CYII=";static DEFAULT_EVENT_LINK_COLOR="#A86";static link_type_colors={"-1":LGraphCanvas.DEFAULT_EVENT_LINK_COLOR,"number":"#AAA","node":"#DCA"};static gradients={};static search_limit=-1;static node_colors={red:{color:"#322",bgcolor:"#533",groupcolor:"#A88"},brown:{color:"#332922",bgcolor:"#593930",groupcolor:"#b06634"},green:{color:"#232",bgcolor:"#353",groupcolor:"#8A8"},blue:{color:"#223",bgcolor:"#335",groupcolor:"#88A"},pale_blue:{color:"#2a363b",bgcolor:"#3f5159",groupcolor:"#3f789e"},cyan:{color:"#233",bgcolor:"#355",groupcolor:"#8AA"},purple:{color:"#323",bgcolor:"#535",groupcolor:"#a1309b"},yellow:{color:"#432",bgcolor:"#653",groupcolor:"#b58b2a"},black:{color:"#222",bgcolor:"#000",groupcolor:"#444"}};static _measureText;state={draggingItems:false,draggingCanvas:false,readOnly:false,hoveringOver:CanvasItem.Nothing,shouldSetCursor:true,selectionChanged:false};#subgraph;get subgraph(){return this.#subgraph}set subgraph(value){if(value!==this.#subgraph){this.#subgraph=value;if(value)this.dispatch("litegraph:set-graph",{oldGraph:this.#subgraph,newGraph:value})}}dispatch(type,detail){const event=new CustomEvent(type,{detail,bubbles:true});return this.canvas.dispatchEvent(event)}dispatchEvent(type,detail){this.canvas.dispatchEvent(new CustomEvent(type,{detail}))}#updateCursorStyle(){if(!this.state.shouldSetCursor)return;const crosshairItems=CanvasItem.Node|CanvasItem.RerouteSlot|CanvasItem.SubgraphIoNode|CanvasItem.SubgraphIoSlot;let cursor="default";if(this.state.draggingCanvas){cursor="grabbing"}else if(this.state.readOnly){cursor="grab"}else if(this.pointer.resizeDirection){cursor=cursors[this.pointer.resizeDirection]??cursors.SE}else if(this.state.hoveringOver&crosshairItems){cursor="crosshair"}else if(this.state.hoveringOver&CanvasItem.Reroute){cursor="grab"}this.canvas.style.cursor=cursor}_previously_dragging_canvas=null;get read_only(){return this.state.readOnly}set read_only(value){this.state.readOnly=value;this.#updateCursorStyle()}get isDragging(){return this.state.draggingItems}set isDragging(value){this.state.draggingItems=value}get hoveringOver(){return this.state.hoveringOver}set hoveringOver(value){this.state.hoveringOver=value;this.#updateCursorStyle()}get pointer_is_down(){return this.pointer.isDown}get pointer_is_double(){return this.pointer.isDouble}get dragging_canvas(){return this.state.draggingCanvas}set dragging_canvas(value){this.state.draggingCanvas=value;this.#updateCursorStyle()}get title_text_font(){return`${LiteGraph.NODE_TEXT_SIZE}px ${LiteGraph.NODE_FONT}`}get inner_text_font(){return`normal ${LiteGraph.NODE_SUBTEXT_SIZE}px ${LiteGraph.NODE_FONT}`}#maximumFrameGap=0;get maximumFps(){return this.#maximumFrameGap>Number.EPSILON?this.#maximumFrameGap/1e3:0}set maximumFps(value){this.#maximumFrameGap=value>Number.EPSILON?1e3/value:0}get round_radius(){return LiteGraph.ROUND_RADIUS}set round_radius(value){LiteGraph.ROUND_RADIUS=value}get low_quality(){return this.ds.scale<this.low_quality_zoom_threshold}options;background_image;ds;pointer;zoom_modify_alpha;zoom_speed;node_title_color;default_link_color;default_connection_color;default_connection_color_byType;default_connection_color_byTypeOff;colourGetter={getConnectedColor:type=>this.default_connection_color_byType[type]||this.default_connection_color.output_on,getDisconnectedColor:type=>this.default_connection_color_byTypeOff[type]||this.default_connection_color_byType[type]||this.default_connection_color.output_off};highquality_render;use_gradients;editor_alpha;pause_rendering;clear_background;clear_background_color;render_only_selected;show_info;allow_dragcanvas;allow_dragnodes;allow_interaction;multi_select;allow_searchbox;allow_reconnect_links;align_to_grid;drag_mode;dragging_rectangle;filter;set_canvas_dirty_on_mouse_event;always_render_background;render_shadows;render_canvas_border;render_connections_shadows;render_connections_border;render_curved_connections;render_connection_arrows;render_collapsed_slots;render_execution_order;render_link_tooltip;linkMarkerShape=LinkMarkerShape.Circle;links_render_mode;low_quality_zoom_threshold=.6;mouse;graph_mouse;canvas_mouse;onSearchBox;onSearchBoxSelection;onMouse;onDrawBackground;onDrawForeground;connections_width;current_node;node_widget;over_link_center;last_mouse_position;visible_area;renderedPaths=new Set;visible_links=[];connecting_links;linkConnector=new LinkConnector(links=>this.connecting_links=links);viewport;autoresize;static active_canvas;frame=0;last_draw_time=0;render_time=0;fps=0;selected_nodes={};selectedItems=new Set;resizingGroup=null;selected_group=null;visible_nodes=[];#visible_node_ids=new Set;node_over;node_capturing_input;highlighted_links={};#visibleReroutes=new Set;dirty_canvas=true;dirty_bgcanvas=true;dirty_nodes=new Map;dirty_area;node_in_panel;last_mouse=[0,0];last_mouseclick=0;graph;get _graph(){if(!this.graph)throw new NullGraphError;return this.graph}canvas;bgcanvas;ctx;_events_binded;bgctx;is_rendering;block_click;last_click_position;resizing_node;selected_group_resizing;last_mouse_dragging;onMouseDown;_highlight_pos;_highlight_input;node_panel;options_panel;_bg_img;_pattern;_pattern_img;prompt_box;search_box;SELECTED_NODE;NODEPANEL_IS_OPEN;#snapToGrid;#shiftDown=false;dragZoomEnabled=false;#dragZoomStart=null;static active_node;onClear;onNodeMoved;onSelectionChange;onDrawLinkTooltip;onDrawOverlay;onRenderBackground;onNodeDblClicked;onShowNodePanel;onNodeSelected;onNodeDeselected;onRender;constructor(canvas2,graph,options){options||={};this.options=options;this.background_image=LGraphCanvas.DEFAULT_BACKGROUND_IMAGE;this.ds=new DragAndScale(canvas2);this.pointer=new CanvasPointer(canvas2);this.linkConnector.events.addEventListener("link-created",()=>this.#dirty());this.linkConnector.events.addEventListener("reset",()=>{this.connecting_links=null;this.dirty_bgcanvas=true});this.linkConnector.events.addEventListener("dropped-on-canvas",customEvent=>{if(!this.connecting_links)return;const e2=customEvent.detail;this.emitEvent({subType:"empty-release",originalEvent:e2,linkReleaseContext:{links:this.connecting_links}});const firstLink=this.linkConnector.renderLinks[0];if(LiteGraph.release_link_on_empty_shows_menu){const linkReleaseContext=this.linkConnector.state.connectingTo==="input"?{node_from:firstLink.node,slot_from:firstLink.fromSlot,type_filter_in:firstLink.fromSlot.type}:{node_to:firstLink.node,slot_to:firstLink.fromSlot,type_filter_out:firstLink.fromSlot.type};const afterRerouteId=firstLink.fromReroute?.id;if("shiftKey"in e2&&e2.shiftKey){if(this.allow_searchbox){this.showSearchBox(e2,linkReleaseContext)}}else if(this.linkConnector.state.connectingTo==="input"){this.showConnectionMenu({nodeFrom:firstLink.node,slotFrom:firstLink.fromSlot,e:e2,afterRerouteId})}else{this.showConnectionMenu({nodeTo:firstLink.node,slotTo:firstLink.fromSlot,e:e2,afterRerouteId})}}});this.zoom_modify_alpha=true;this.zoom_speed=1.1;this.node_title_color=LiteGraph.NODE_TITLE_COLOR;this.default_link_color=LiteGraph.LINK_COLOR;this.default_connection_color={input_off:"#778",input_on:"#7F7",output_off:"#778",output_on:"#7F7"};this.default_connection_color_byType={};this.default_connection_color_byTypeOff={};this.highquality_render=true;this.use_gradients=false;this.editor_alpha=1;this.pause_rendering=false;this.clear_background=true;this.clear_background_color="#222";this.render_only_selected=true;this.show_info=true;this.allow_dragcanvas=true;this.allow_dragnodes=true;this.allow_interaction=true;this.multi_select=false;this.allow_searchbox=true;this.allow_reconnect_links=true;this.align_to_grid=false;this.drag_mode=false;this.dragging_rectangle=null;this.filter=null;this.set_canvas_dirty_on_mouse_event=true;this.always_render_background=false;this.render_shadows=true;this.render_canvas_border=true;this.render_connections_shadows=false;this.render_connections_border=true;this.render_curved_connections=false;this.render_connection_arrows=false;this.render_collapsed_slots=true;this.render_execution_order=false;this.render_link_tooltip=true;this.links_render_mode=LinkRenderType.SPLINE_LINK;this.mouse=[0,0];this.graph_mouse=[0,0];this.canvas_mouse=this.graph_mouse;this.connections_width=3;this.current_node=null;this.node_widget=null;this.last_mouse_position=[0,0];this.visible_area=this.ds.visible_area;this.connecting_links=null;this.viewport=options.viewport||null;this.graph=graph;graph?.attachCanvas(this);this.canvas=void 0;this.bgcanvas=void 0;this.ctx=void 0;this.setCanvas(canvas2,options.skip_events);this.clear();LGraphCanvas._measureText=(text,fontStyle=this.inner_text_font)=>{const{ctx}=this;const{font}=ctx;try{ctx.font=fontStyle;return ctx.measureText(text).width}finally{ctx.font=font}};if(!options.skip_render){this.startRendering()}this.autoresize=options.autoresize}static onGroupAdd(info,entry,mouse_event){const canvas2=LGraphCanvas.active_canvas;const group=new LiteGraph.LGraphGroup;group.pos=canvas2.convertEventToCanvasOffset(mouse_event);if(!canvas2.graph)throw new NullGraphError;canvas2.graph.add(group)}static getBoundaryNodes(nodes){const _nodes=Array.isArray(nodes)?nodes:Object.values(nodes);return getBoundaryNodes(_nodes)??{top:null,right:null,bottom:null,left:null}}static alignNodes(nodes,direction,align_to){alignNodes(Object.values(nodes),direction,align_to);LGraphCanvas.active_canvas.setDirty(true,true)}static onNodeAlign(value,options,event,prev_menu,node2){new LiteGraph.ContextMenu(["Top","Bottom","Left","Right"],{event,callback:inner_clicked,parentMenu:prev_menu});function inner_clicked(value2){alignNodes(Object.values(LGraphCanvas.active_canvas.selected_nodes),value2.toLowerCase(),node2);LGraphCanvas.active_canvas.setDirty(true,true)}}static onGroupAlign(value,options,event,prev_menu){new LiteGraph.ContextMenu(["Top","Bottom","Left","Right"],{event,callback:inner_clicked,parentMenu:prev_menu});function inner_clicked(value2){alignNodes(Object.values(LGraphCanvas.active_canvas.selected_nodes),value2.toLowerCase());LGraphCanvas.active_canvas.setDirty(true,true)}}static createDistributeMenu(value,options,event,prev_menu){new LiteGraph.ContextMenu(["Vertically","Horizontally"],{event,callback:inner_clicked,parentMenu:prev_menu});function inner_clicked(value2){const canvas2=LGraphCanvas.active_canvas;distributeNodes(Object.values(canvas2.selected_nodes),value2==="Horizontally");canvas2.setDirty(true,true)}}static onMenuAdd(value,options,e2,prev_menu,callback){const canvas2=LGraphCanvas.active_canvas;const ref_window=canvas2.getCanvasWindow();const{graph}=canvas2;if(!graph)return;inner_onMenuAdded("",prev_menu);return false;function inner_onMenuAdded(base_category,prev_menu2){if(!graph)return;const categories=LiteGraph.getNodeTypesCategories(canvas2.filter||graph.filter).filter(category=>category.startsWith(base_category));const entries=[];for(const category of categories){if(!category)continue;const base_category_regex=new RegExp(`^(${base_category})`);const category_name=category.replace(base_category_regex,"").split("/",1)[0];const category_path=base_category===""?`${category_name}/`:`${base_category}${category_name}/`;let name=category_name;if(name.includes("::"))name=name.split("::",2)[1];const index=entries.findIndex(entry=>entry.value===category_path);if(index===-1){entries.push({value:category_path,content:name,has_submenu:true,callback:function(value2,event,mouseEvent,contextMenu){inner_onMenuAdded(value2.value,contextMenu)}})}}const nodes=LiteGraph.getNodeTypesInCategory(base_category.slice(0,-1),canvas2.filter||graph.filter);for(const node2 of nodes){if(node2.skip_list)continue;const entry={value:node2.type,content:node2.title,has_submenu:false,callback:function(value2,event,mouseEvent,contextMenu){if(!canvas2.graph)throw new NullGraphError;const first_event=contextMenu.getFirstEvent();canvas2.graph.beforeChange();const node22=LiteGraph.createNode(value2.value);if(node22){if(!first_event)throw new TypeError("Context menu event was null. This should not occur in normal usage.");node22.pos=canvas2.convertEventToCanvasOffset(first_event);canvas2.graph.add(node22)}else{console.warn("Failed to create node of type:",value2.value)}callback?.(node22);canvas2.graph.afterChange()}};entries.push(entry)}new LiteGraph.ContextMenu(entries,{event:e2,parentMenu:prev_menu2},ref_window)}}static onMenuCollapseAll(){}static onMenuNodeEdit(){}static showMenuNodeOptionalOutputs(v2,_options,e2,prev_menu,node2){if(!node2)return;const canvas2=LGraphCanvas.active_canvas;let entries=[];if(LiteGraph.do_add_triggers_slots&&node2.findOutputSlot("onExecuted")==-1){entries.push({content:"On Executed",value:["onExecuted",LiteGraph.EVENT,{nameLocked:true}],className:"event"})}const retEntries=node2.onMenuNodeOutputs?.(entries);if(retEntries)entries=retEntries;if(!entries.length)return;new LiteGraph.ContextMenu(entries,{event:e2,callback:inner_clicked,parentMenu:prev_menu,node:node2});function inner_clicked(v22,e22,prev){if(!node2)return;if(v22.callback)v22.callback.call(this,node2,v22,e22,prev);if(!v22.value)return;const value=v22.value[1];if(value&&(typeof value==="object"||Array.isArray(value))){const entries2=[];for(const i in value){entries2.push({content:i,value:value[i]})}new LiteGraph.ContextMenu(entries2,{event:e22,callback:inner_clicked,parentMenu:prev_menu,node:node2});return false}const{graph}=node2;if(!graph)throw new NullGraphError;graph.beforeChange();node2.addOutput(v22.value[0],v22.value[1],v22.value[2]);node2.onNodeOutputAdd?.(v22.value);canvas2.setDirty(true,true);graph.afterChange()}return false}static onShowMenuNodeProperties(value,options,e2,prev_menu,node2){if(!node2||!node2.properties)return;const canvas2=LGraphCanvas.active_canvas;const ref_window=canvas2.getCanvasWindow();const entries=[];for(const i in node2.properties){value=node2.properties[i]!==void 0?node2.properties[i]:" ";if(typeof value=="object")value=JSON.stringify(value);const info=node2.getPropertyInfo(i);if(info.type=="enum"||info.type=="combo")value=LGraphCanvas.getPropertyPrintableValue(value,info.values);value=LGraphCanvas.decodeHTML(stringOrEmpty(value));entries.push({content:`<span class='property_name'>${info.label||i}</span><span class='property_value'>${value}</span>`,value:i})}if(!entries.length){return}new LiteGraph.ContextMenu(entries,{event:e2,callback:inner_clicked,parentMenu:prev_menu,allow_html:true,node:node2},ref_window);function inner_clicked(v2){if(!node2)return;const rect=this.getBoundingClientRect();canvas2.showEditPropertyValue(node2,v2.value,{position:[rect.left,rect.top]})}return false}static decodeHTML(str){const e2=document.createElement("div");e2.textContent=str;return e2.innerHTML}static onMenuResizeNode(value,options,e2,menu,node2){if(!node2)return;const fApplyMultiNode=function(node22){node22.setSize(node22.computeSize())};const canvas2=LGraphCanvas.active_canvas;if(!canvas2.selected_nodes||Object.keys(canvas2.selected_nodes).length<=1){fApplyMultiNode(node2)}else{for(const i in canvas2.selected_nodes){fApplyMultiNode(canvas2.selected_nodes[i])}}canvas2.setDirty(true,true)}static onShowPropertyEditor(item,options,e2,menu,node2){const property=item.property||"title";const value=node2[property];const title=document.createElement("span");title.className="name";title.textContent=property;const input=document.createElement("input");Object.assign(input,{type:"text",className:"value",autofocus:true});const button=document.createElement("button");button.textContent="OK";const dialog=Object.assign(document.createElement("div"),{is_modified:false,className:"graphdialog",close:()=>dialog.remove()});dialog.append(title,input,button);input.value=String(value);input.addEventListener("blur",function(){this.focus()});input.addEventListener("keydown",e22=>{dialog.is_modified=true;if(e22.key=="Escape"){dialog.close()}else if(e22.key=="Enter"){inner()}else if(!e22.target||!("localName"in e22.target)||e22.target.localName!="textarea"){return}e22.preventDefault();e22.stopPropagation()});const canvas2=LGraphCanvas.active_canvas;const canvasEl=canvas2.canvas;const rect=canvasEl.getBoundingClientRect();const offsetx=rect?-20-rect.left:-20;const offsety=rect?-20-rect.top:-20;if(e2){dialog.style.left=`${e2.clientX+offsetx}px`;dialog.style.top=`${e2.clientY+offsety}px`}else{dialog.style.left=`${canvasEl.width*.5+offsetx}px`;dialog.style.top=`${canvasEl.height*.5+offsety}px`}button.addEventListener("click",inner);if(canvasEl.parentNode==null)throw new TypeError("canvasEl.parentNode was null");canvasEl.parentNode.append(dialog);input.focus();let dialogCloseTimer;dialog.addEventListener("mouseleave",function(){if(LiteGraph.dialog_close_on_mouse_leave){if(!dialog.is_modified&&LiteGraph.dialog_close_on_mouse_leave){dialogCloseTimer=setTimeout(dialog.close,LiteGraph.dialog_close_on_mouse_leave_delay)}}});dialog.addEventListener("mouseenter",function(){if(LiteGraph.dialog_close_on_mouse_leave){if(dialogCloseTimer)clearTimeout(dialogCloseTimer)}});function inner(){if(input)setValue(input.value)}function setValue(value2){if(item.type=="Number"){value2=Number(value2)}else if(item.type=="Boolean"){value2=Boolean(value2)}node2[property]=value2;dialog.remove();canvas2.setDirty(true,true)}}static getPropertyPrintableValue(value,values){if(!values)return String(value);if(Array.isArray(values)){return String(value)}if(typeof values==="object"){let desc_value="";for(const k in values){if(values[k]!=value)continue;desc_value=k;break}return`${String(value)} (${desc_value})`}}static onMenuNodeCollapse(value,options,e2,menu,node2){if(!node2.graph)throw new NullGraphError;node2.graph.beforeChange();const fApplyMultiNode=function(node22){node22.collapse()};const graphcanvas=LGraphCanvas.active_canvas;if(!graphcanvas.selected_nodes||Object.keys(graphcanvas.selected_nodes).length<=1){fApplyMultiNode(node2)}else{for(const i in graphcanvas.selected_nodes){fApplyMultiNode(graphcanvas.selected_nodes[i])}}node2.graph.afterChange()}static onMenuToggleAdvanced(value,options,e2,menu,node2){if(!node2.graph)throw new NullGraphError;node2.graph.beforeChange();const fApplyMultiNode=function(node22){node22.toggleAdvanced()};const graphcanvas=LGraphCanvas.active_canvas;if(!graphcanvas.selected_nodes||Object.keys(graphcanvas.selected_nodes).length<=1){fApplyMultiNode(node2)}else{for(const i in graphcanvas.selected_nodes){fApplyMultiNode(graphcanvas.selected_nodes[i])}}node2.graph.afterChange()}static onMenuNodeMode(value,options,e2,menu,node2){new LiteGraph.ContextMenu(LiteGraph.NODE_MODES,{event:e2,callback:inner_clicked,parentMenu:menu,node:node2});function inner_clicked(v2){if(!node2)return;const kV=Object.values(LiteGraph.NODE_MODES).indexOf(v2);const fApplyMultiNode=function(node22){if(kV!==-1&&LiteGraph.NODE_MODES[kV]){node22.changeMode(kV)}else{console.warn(`unexpected mode: ${v2}`);node22.changeMode(LGraphEventMode.ALWAYS)}};const graphcanvas=LGraphCanvas.active_canvas;if(!graphcanvas.selected_nodes||Object.keys(graphcanvas.selected_nodes).length<=1){fApplyMultiNode(node2)}else{for(const i in graphcanvas.selected_nodes){fApplyMultiNode(graphcanvas.selected_nodes[i])}}}return false}static onMenuNodeColors(value,options,e2,menu,node2){if(!node2)throw"no node for color";const values=[];values.push({value:null,content:"<span style='display: block; padding-left: 4px;'>No color</span>"});for(const i in LGraphCanvas.node_colors){const color=LGraphCanvas.node_colors[i];value={value:i,content:`<span style='display: block; color: #999; padding-left: 4px; border-left: 8px solid ${color.color}; background-color:${color.bgcolor}'>${i}</span>`};values.push(value)}new LiteGraph.ContextMenu(values,{event:e2,callback:inner_clicked,parentMenu:menu,node:node2});function inner_clicked(v2){if(!node2)return;const fApplyColor=function(item){const colorOption=v2.value?LGraphCanvas.node_colors[v2.value]:null;item.setColorOption(colorOption)};const canvas2=LGraphCanvas.active_canvas;if(!canvas2.selected_nodes||Object.keys(canvas2.selected_nodes).length<=1){fApplyColor(node2)}else{for(const i in canvas2.selected_nodes){fApplyColor(canvas2.selected_nodes[i])}}canvas2.setDirty(true,true)}return false}static onMenuNodeShapes(value,options,e2,menu,node2){if(!node2)throw"no node passed";new LiteGraph.ContextMenu(LiteGraph.VALID_SHAPES,{event:e2,callback:inner_clicked,parentMenu:menu,node:node2});function inner_clicked(v2){if(!node2)return;if(!node2.graph)throw new NullGraphError;node2.graph.beforeChange();const fApplyMultiNode=function(node22){node22.shape=v2};const canvas2=LGraphCanvas.active_canvas;if(!canvas2.selected_nodes||Object.keys(canvas2.selected_nodes).length<=1){fApplyMultiNode(node2)}else{for(const i in canvas2.selected_nodes){fApplyMultiNode(canvas2.selected_nodes[i])}}node2.graph.afterChange();canvas2.setDirty(true)}return false}static onMenuNodeRemove(){LGraphCanvas.active_canvas.deleteSelected()}static onMenuNodeClone(value,options,e2,menu,node2){const{graph}=node2;if(!graph)throw new NullGraphError;graph.beforeChange();const newSelected=new Set;const fApplyMultiNode=function(node22,newNodes){if(node22.clonable===false)return;const newnode=node22.clone();if(!newnode)return;newnode.pos=[node22.pos[0]+5,node22.pos[1]+5];if(!node22.graph)throw new NullGraphError;node22.graph.add(newnode);newNodes.add(newnode)};const canvas2=LGraphCanvas.active_canvas;if(!canvas2.selected_nodes||Object.keys(canvas2.selected_nodes).length<=1){fApplyMultiNode(node2,newSelected)}else{for(const i in canvas2.selected_nodes){fApplyMultiNode(canvas2.selected_nodes[i],newSelected)}}if(newSelected.size){canvas2.selectNodes([...newSelected])}graph.afterChange();canvas2.setDirty(true,true)}clear(){this.frame=0;this.last_draw_time=0;this.render_time=0;this.fps=0;this.dragging_rectangle=null;this.selected_nodes={};this.selected_group=null;this.selectedItems.clear();this.state.selectionChanged=true;this.onSelectionChange?.(this.selected_nodes);this.visible_nodes=[];this.node_over=void 0;this.node_capturing_input=null;this.connecting_links=null;this.highlighted_links={};this.dragging_canvas=false;this.#dirty();this.dirty_area=null;this.node_in_panel=null;this.node_widget=null;this.last_mouse=[0,0];this.last_mouseclick=0;this.pointer.reset();this.visible_area.set([0,0,0,0]);this.onClear?.()}setGraph(newGraph){const{graph}=this;if(newGraph===graph)return;this.clear();newGraph.attachCanvas(this);this.dispatch("litegraph:set-graph",{newGraph,oldGraph:graph});this.#dirty()}openSubgraph(subgraph){const{graph}=this;if(!graph)throw new NullGraphError;const options={bubbles:true,detail:{subgraph,closingGraph:graph},cancelable:true};const mayContinue=this.canvas.dispatchEvent(new CustomEvent("subgraph-opening",options));if(!mayContinue)return;this.clear();this.subgraph=subgraph;this.setGraph(subgraph);this.canvas.dispatchEvent(new CustomEvent("subgraph-opened",options))}getCurrentGraph(){return this.graph}#validateCanvas(canvas2){if(typeof canvas2==="string"){const el=document.getElementById(canvas2);if(!(el instanceof HTMLCanvasElement))throw"Error validating LiteGraph canvas: Canvas element not found";return el}return canvas2}setCanvas(canvas2,skip_events){const element=this.#validateCanvas(canvas2);if(element===this.canvas)return;if(!element&&this.canvas&&!skip_events)this.unbindEvents();this.canvas=element;this.ds.element=element;this.pointer.element=element;if(!element)return;element.className+=" lgraphcanvas";element.data=this;this.bgcanvas=document.createElement("canvas");this.bgcanvas.width=this.canvas.width;this.bgcanvas.height=this.canvas.height;const ctx=element.getContext?.("2d");if(ctx==null){if(element.localName!="canvas"){throw`Element supplied for LGraphCanvas must be a <canvas> element, you passed a ${element.localName}`}throw"This browser doesn't support Canvas"}this.ctx=ctx;if(!skip_events)this.bindEvents()}_doNothing(e2){e2.preventDefault();return false}_doReturnTrue(e2){e2.preventDefault();return true}bindEvents(){if(this._events_binded){console.warn("LGraphCanvas: events already bound");return}const{canvas:canvas2}=this;const{document:document2}=this.getCanvasWindow();this._mousedown_callback=this.processMouseDown.bind(this);this._mousewheel_callback=this.processMouseWheel.bind(this);this._mousemove_callback=this.processMouseMove.bind(this);this._mouseup_callback=this.processMouseUp.bind(this);this._mouseout_callback=this.processMouseOut.bind(this);this._mousecancel_callback=this.processMouseCancel.bind(this);canvas2.addEventListener("pointerdown",this._mousedown_callback,true);canvas2.addEventListener("wheel",this._mousewheel_callback,false);canvas2.addEventListener("pointerup",this._mouseup_callback,true);canvas2.addEventListener("pointermove",this._mousemove_callback);canvas2.addEventListener("pointerout",this._mouseout_callback);canvas2.addEventListener("pointercancel",this._mousecancel_callback,true);canvas2.addEventListener("contextmenu",this._doNothing);this._key_callback=this.processKey.bind(this);canvas2.addEventListener("keydown",this._key_callback,true);document2.addEventListener("keyup",this._key_callback,true);canvas2.addEventListener("dragover",this._doNothing,false);canvas2.addEventListener("dragend",this._doNothing,false);canvas2.addEventListener("dragenter",this._doReturnTrue,false);this._events_binded=true}unbindEvents(){if(!this._events_binded){console.warn("LGraphCanvas: no events bound");return}const{document:document2}=this.getCanvasWindow();const{canvas:canvas2}=this;canvas2.removeEventListener("pointercancel",this._mousecancel_callback);canvas2.removeEventListener("pointerout",this._mouseout_callback);canvas2.removeEventListener("pointermove",this._mousemove_callback);canvas2.removeEventListener("pointerup",this._mouseup_callback);canvas2.removeEventListener("pointerdown",this._mousedown_callback);canvas2.removeEventListener("wheel",this._mousewheel_callback);canvas2.removeEventListener("keydown",this._key_callback);document2.removeEventListener("keyup",this._key_callback);canvas2.removeEventListener("contextmenu",this._doNothing);canvas2.removeEventListener("dragenter",this._doReturnTrue);this._mousedown_callback=void 0;this._mousewheel_callback=void 0;this._key_callback=void 0;this._events_binded=false}setDirty(fgcanvas,bgcanvas){if(fgcanvas)this.dirty_canvas=true;if(bgcanvas)this.dirty_bgcanvas=true}#dirty(){this.dirty_canvas=true;this.dirty_bgcanvas=true}#linkConnectorDrop(){const{graph,linkConnector,pointer}=this;if(!graph)throw new NullGraphError;pointer.onDragEnd=upEvent=>linkConnector.dropLinks(graph,upEvent);pointer.finally=()=>this.linkConnector.reset(true)}getCanvasWindow(){if(!this.canvas)return window;const doc=this.canvas.ownerDocument;return doc.defaultView||doc.parentWindow}startRendering(){if(this.is_rendering)return;this.is_rendering=true;renderFrame.call(this);function renderFrame(){if(!this.pause_rendering){this.draw()}const window2=this.getCanvasWindow();if(this.is_rendering){if(this.#maximumFrameGap>0){const gap=this.#maximumFrameGap-(LiteGraph.getTime()-this.last_draw_time);setTimeout(renderFrame.bind(this),Math.max(1,gap))}else{window2.requestAnimationFrame(renderFrame.bind(this))}}}}stopRendering(){this.is_rendering=false}blockClick(){this.block_click=true;this.last_mouseclick=0}getWidgetAtCursor(node2){node2??=this.node_over;return node2?.getWidgetOnPos(this.graph_mouse[0],this.graph_mouse[1],true)}updateMouseOverNodes(node2,e2){if(!this.graph)throw new NullGraphError;const{pointer}=this;const nodes=this.graph._nodes;for(const otherNode of nodes){if(otherNode.mouseOver&&node2!=otherNode){if(!pointer.eDown)pointer.resizeDirection=void 0;otherNode.mouseOver=void 0;this._highlight_input=void 0;this._highlight_pos=void 0;this.linkConnector.overWidget=void 0;otherNode.lostFocusAt=LiteGraph.getTime();this.node_over?.onMouseLeave?.(e2);this.node_over=void 0;this.dirty_canvas=true}}}processMouseDown(e2){if(this.dragZoomEnabled&&e2.ctrlKey&&e2.shiftKey&&!e2.altKey&&e2.buttons){this.#dragZoomStart={pos:[e2.x,e2.y],scale:this.ds.scale};return}const{graph,pointer}=this;this.adjustMouseEvent(e2);if(e2.isPrimary)pointer.down(e2);if(this.set_canvas_dirty_on_mouse_event)this.dirty_canvas=true;if(!graph)return;const ref_window=this.getCanvasWindow();LGraphCanvas.active_canvas=this;const x2=e2.clientX;const y=e2.clientY;this.ds.viewport=this.viewport;const is_inside=!this.viewport||isInRect(x2,y,this.viewport);if(!is_inside)return;const node2=graph.getNodeOnPos(e2.canvasX,e2.canvasY,this.visible_nodes)??void 0;this.mouse[0]=x2;this.mouse[1]=y;this.graph_mouse[0]=e2.canvasX;this.graph_mouse[1]=e2.canvasY;this.last_click_position=[this.mouse[0],this.mouse[1]];pointer.isDouble=pointer.isDown&&e2.isPrimary;pointer.isDown=true;this.canvas.focus();LiteGraph.closeAllContextMenus(ref_window);if(this.onMouse?.(e2)==true)return;if(e2.button===0&&!pointer.isDouble){this.#processPrimaryButton(e2,node2)}else if(e2.button===1){this.#processMiddleButton(e2,node2)}else if((e2.button===2||pointer.isDouble)&&this.allow_interaction&&!this.read_only){const{linkConnector,subgraph}=this;if(subgraph?.inputNode.containsPoint(this.graph_mouse)){this.processSelect(subgraph.inputNode,e2,true);subgraph.inputNode.onPointerDown(e2,pointer,linkConnector)}else if(subgraph?.outputNode.containsPoint(this.graph_mouse)){this.processSelect(subgraph.outputNode,e2,true);subgraph.outputNode.onPointerDown(e2,pointer,linkConnector)}else{if(node2){this.processSelect(node2,e2,true)}else if(this.links_render_mode!==LinkRenderType.HIDDEN_LINK){const reroute=graph.getRerouteOnPos(e2.canvasX,e2.canvasY,this.#visibleReroutes);if(reroute){if(e2.altKey){pointer.onClick=upEvent=>{if(upEvent.altKey){if(reroute.selected){this.deselect(reroute);this.onSelectionChange?.(this.selected_nodes)}reroute.remove()}}}else{this.processSelect(reroute,e2,true)}}}pointer.onClick??=()=>this.processContextMenu(node2,e2)}}this.last_mouse=[x2,y];this.last_mouseclick=LiteGraph.getTime();this.last_mouse_dragging=true;graph.change();if(!ref_window.document.activeElement||ref_window.document.activeElement.nodeName.toLowerCase()!="input"&&ref_window.document.activeElement.nodeName.toLowerCase()!="textarea"){e2.preventDefault()}e2.stopPropagation();this.onMouseDown?.(e2)}#getPositionableOnPos(x2,y){const ioNode=this.subgraph?.getIoNodeOnPos(x2,y);if(ioNode)return ioNode;for(const reroute of this.#visibleReroutes){if(reroute.containsPoint([x2,y]))return reroute}return this.graph?.getGroupTitlebarOnPos(x2,y)}#processPrimaryButton(e2,node2){const{pointer,graph,linkConnector,subgraph}=this;if(!graph)throw new NullGraphError;const x2=e2.canvasX;const y=e2.canvasY;const ctrlOrMeta=e2.ctrlKey||e2.metaKey;if(ctrlOrMeta&&!e2.altKey&&LiteGraph.canvasNavigationMode==="legacy"){this.#setupNodeSelectionDrag(e2,pointer,node2);return}if(this.read_only){pointer.finally=()=>this.dragging_canvas=false;this.dragging_canvas=true;return}if(LiteGraph.alt_drag_do_clone_nodes&&e2.altKey&&!e2.ctrlKey&&node2&&this.allow_interaction){let newType=node2.type;if(node2 instanceof SubgraphNode){const cloned=node2.subgraph.clone().asSerialisable();const subgraph2=graph.createSubgraph(cloned);subgraph2.configure(cloned);newType=subgraph2.id}const node_data=node2.clone()?.serialize();if(node_data?.type!=null){const cloned=LiteGraph.createNode(newType);if(cloned){cloned.configure(node_data);cloned.pos[0]+=5;cloned.pos[1]+=5;if(this.allow_dragnodes){pointer.onDragStart=pointer2=>{graph.add(cloned,false);this.#startDraggingItems(cloned,pointer2)};pointer.onDragEnd=e22=>this.#processDraggedItems(e22)}else{graph.beforeChange();graph.add(cloned,false);graph.afterChange()}return}}}if(node2&&(this.allow_interaction||node2.flags.allow_interaction)){this.#processNodeClick(e2,ctrlOrMeta,node2)}else{if(subgraph){let processSubgraphIONode=function(canvas2,ioNode){if(!ioNode.containsPoint([x2,y]))return false;ioNode.onPointerDown(e2,pointer,linkConnector);pointer.onClick??=()=>canvas2.processSelect(ioNode,e2);pointer.onDragStart??=()=>canvas2.#startDraggingItems(ioNode,pointer,true);pointer.onDragEnd??=eUp=>canvas2.#processDraggedItems(eUp);return true};const{inputNode,outputNode}=subgraph;if(processSubgraphIONode(this,inputNode))return;if(processSubgraphIONode(this,outputNode))return}if(this.links_render_mode!==LinkRenderType.HIDDEN_LINK){for(const reroute of this.#visibleReroutes){const overReroute=reroute.containsPoint([x2,y]);if(!reroute.isSlotHovered&&!overReroute)continue;if(overReroute){pointer.onClick=()=>this.processSelect(reroute,e2);if(!e2.shiftKey){pointer.onDragStart=pointer2=>this.#startDraggingItems(reroute,pointer2,true);pointer.onDragEnd=e22=>this.#processDraggedItems(e22)}}if(reroute.isOutputHovered||overReroute&&e2.shiftKey){linkConnector.dragFromReroute(graph,reroute);this.#linkConnectorDrop()}if(reroute.isInputHovered){linkConnector.dragFromRerouteToOutput(graph,reroute);this.#linkConnectorDrop()}reroute.hideSlots();this.dirty_bgcanvas=true;return}}const{lineWidth}=this.ctx;this.ctx.lineWidth=this.connections_width+7;const dpi=window?.devicePixelRatio||1;for(const linkSegment of this.renderedPaths){const centre=linkSegment._pos;if(!centre)continue;if((e2.shiftKey||e2.altKey)&&linkSegment.path&&this.ctx.isPointInStroke(linkSegment.path,x2*dpi,y*dpi)){this.ctx.lineWidth=lineWidth;if(e2.shiftKey&&!e2.altKey){linkConnector.dragFromLinkSegment(graph,linkSegment);this.#linkConnectorDrop();return}else if(e2.altKey&&!e2.shiftKey){const newReroute=graph.createReroute([x2,y],linkSegment);pointer.onDragStart=pointer2=>this.#startDraggingItems(newReroute,pointer2);pointer.onDragEnd=e22=>this.#processDraggedItems(e22);return}}else if(isInRectangle(x2,y,centre[0]-4,centre[1]-4,8,8)){this.ctx.lineWidth=lineWidth;pointer.onClick=()=>this.showLinkMenu(linkSegment,e2);pointer.onDragStart=()=>this.dragging_canvas=true;pointer.finally=()=>this.dragging_canvas=false;this.over_link_center=void 0;return}}this.ctx.lineWidth=lineWidth;const group=graph.getGroupOnPos(x2,y);this.selected_group=group??null;if(group){if(group.isInResize(x2,y)){const b=group.boundingRect;const offsetX=x2-(b[0]+b[2]);const offsetY=y-(b[1]+b[3]);pointer.onDragStart=()=>this.resizingGroup=group;pointer.onDrag=eMove=>{if(this.read_only)return;const pos=[eMove.canvasX-group.pos[0]-offsetX,eMove.canvasY-group.pos[1]-offsetY];if(this.#snapToGrid)snapPoint(pos,this.#snapToGrid);const resized=group.resize(pos[0],pos[1]);if(resized)this.dirty_bgcanvas=true};pointer.finally=()=>this.resizingGroup=null}else{const f=group.font_size||LiteGraph.DEFAULT_GROUP_FONT_SIZE;const headerHeight=f*1.4;if(isInRectangle(x2,y,group.pos[0],group.pos[1],group.size[0],headerHeight)){pointer.onClick=()=>this.processSelect(group,e2);pointer.onDragStart=pointer2=>{group.recomputeInsideNodes();this.#startDraggingItems(group,pointer2,true)};pointer.onDragEnd=e22=>this.#processDraggedItems(e22)}}pointer.onDoubleClick=()=>{this.emitEvent({subType:"group-double-click",originalEvent:e2,group})}}else{pointer.onDoubleClick=()=>{if(this.allow_searchbox){this.showSearchBox(e2);e2.preventDefault()}this.emitEvent({subType:"empty-double-click",originalEvent:e2})}}}if(!pointer.onDragStart&&!pointer.onClick&&!pointer.onDrag&&this.allow_dragcanvas){if(LiteGraph.canvasNavigationMode!=="standard"||this.read_only){pointer.onClick=()=>this.processSelect(null,e2);pointer.finally=()=>this.dragging_canvas=false;this.dragging_canvas=true}else{this.#setupNodeSelectionDrag(e2,pointer)}}}#setupNodeSelectionDrag(e2,pointer,node2){const dragRect=new Float32Array(4);dragRect[0]=e2.canvasX;dragRect[1]=e2.canvasY;dragRect[2]=1;dragRect[3]=1;pointer.onClick=eUp=>{const clickedItem=node2??this.#getPositionableOnPos(eUp.canvasX,eUp.canvasY);this.processSelect(clickedItem,eUp)};pointer.onDragStart=()=>this.dragging_rectangle=dragRect;pointer.onDragEnd=upEvent=>this.#handleMultiSelect(upEvent,dragRect);pointer.finally=()=>this.dragging_rectangle=null}#processNodeClick(e2,ctrlOrMeta,node2){const{pointer,graph,linkConnector}=this;if(!graph)throw new NullGraphError;const x2=e2.canvasX;const y=e2.canvasY;pointer.onClick=()=>this.processSelect(node2,e2);if(!node2.flags.pinned){this.bringToFront(node2)}const inCollapse=node2.isPointInCollapse(x2,y);if(inCollapse){pointer.onClick=()=>{node2.collapse();this.setDirty(true,true)}}else if(!node2.flags.collapsed){const{inputs,outputs}=node2;if(outputs){for(const[i,output]of outputs.entries()){const link_pos=node2.getOutputPos(i);if(isInRectangle(x2,y,link_pos[0]-15,link_pos[1]-10,30,20)){if(e2.shiftKey&&(output.links?.length||output._floatingLinks?.size)){linkConnector.moveOutputLink(graph,output);this.#linkConnectorDrop();return}linkConnector.dragNewFromOutput(graph,node2,output);this.#linkConnectorDrop();if(LiteGraph.shift_click_do_break_link_from){if(e2.shiftKey){node2.disconnectOutput(i)}}else if(LiteGraph.ctrl_alt_click_do_break_link){if(ctrlOrMeta&&e2.altKey&&!e2.shiftKey){node2.disconnectOutput(i)}}pointer.onDoubleClick=()=>node2.onOutputDblClick?.(i,e2);pointer.onClick=()=>node2.onOutputClick?.(i,e2);return}}}if(inputs){for(const[i,input]of inputs.entries()){const link_pos=node2.getInputPos(i);const isInSlot=input instanceof NodeInputSlot?isInRect(x2,y,input.boundingRect):isInRectangle(x2,y,link_pos[0]-15,link_pos[1]-10,30,20);if(isInSlot){pointer.onDoubleClick=()=>node2.onInputDblClick?.(i,e2);pointer.onClick=()=>node2.onInputClick?.(i,e2);const shouldBreakLink=LiteGraph.ctrl_alt_click_do_break_link&&ctrlOrMeta&&e2.altKey&&!e2.shiftKey;if(input.link!==null||input._floatingLinks?.size){if(shouldBreakLink||LiteGraph.click_do_break_link_to){node2.disconnectInput(i,true)}else if(e2.shiftKey||this.allow_reconnect_links){linkConnector.moveInputLink(graph,input)}}if(!linkConnector.isConnecting){linkConnector.dragNewFromInput(graph,node2,input)}this.#linkConnectorDrop();this.dirty_bgcanvas=true;return}}}}const pos=[x2-node2.pos[0],y-node2.pos[1]];const widget=node2.getWidgetOnPos(x2,y);if(widget){this.#processWidgetClick(e2,node2,widget);this.node_widget=[node2,widget]}else{pointer.onDoubleClick=()=>{if(pos[1]<0&&!inCollapse){node2.onNodeTitleDblClick?.(e2,pos,this)}else if(node2 instanceof SubgraphNode){this.openSubgraph(node2.subgraph)}node2.onDblClick?.(e2,pos,this);this.emitEvent({subType:"node-double-click",originalEvent:e2,node:node2});this.processNodeDblClicked(node2)};if(node2.onMouseDown?.(e2,pos,this)){pointer.onClick=()=>{};return}if(!this.allow_dragnodes)return;if(!node2.flags.collapsed){const resizeDirection=node2.findResizeDirection(x2,y);if(resizeDirection){pointer.resizeDirection=resizeDirection;const startBounds=new Rectangle(node2.pos[0],node2.pos[1],node2.size[0],node2.size[1]);pointer.onDragStart=()=>{graph.beforeChange();this.resizing_node=node2};pointer.onDrag=eMove=>{if(this.read_only)return;const deltaX=eMove.canvasX-x2;const deltaY=eMove.canvasY-y;const newBounds=new Rectangle(startBounds.x,startBounds.y,startBounds.width,startBounds.height);switch(resizeDirection){case"NE":newBounds.y=startBounds.y+deltaY;newBounds.width=startBounds.width+deltaX;newBounds.height=startBounds.height-deltaY;break;case"SE":newBounds.width=startBounds.width+deltaX;newBounds.height=startBounds.height+deltaY;break;case"SW":newBounds.x=startBounds.x+deltaX;newBounds.width=startBounds.width-deltaX;newBounds.height=startBounds.height+deltaY;break;case"NW":newBounds.x=startBounds.x+deltaX;newBounds.y=startBounds.y+deltaY;newBounds.width=startBounds.width-deltaX;newBounds.height=startBounds.height-deltaY;break}if(this.#snapToGrid){if(resizeDirection.includes("N")||resizeDirection.includes("W")){const originalX=newBounds.x;const originalY=newBounds.y;snapPoint(newBounds.pos,this.#snapToGrid);if(resizeDirection.includes("N")){newBounds.height+=originalY-newBounds.y}if(resizeDirection.includes("W")){newBounds.width+=originalX-newBounds.x}}snapPoint(newBounds.size,this.#snapToGrid)}const min=node2.computeSize();if(newBounds.width<min[0]){if(resizeDirection.includes("W")){newBounds.x=startBounds.x+startBounds.width-min[0]}newBounds.width=min[0]}if(newBounds.height<min[1]){if(resizeDirection.includes("N")){newBounds.y=startBounds.y+startBounds.height-min[1]}newBounds.height=min[1]}node2.pos=newBounds.pos;node2.setSize(newBounds.size);this.#dirty()};pointer.onDragEnd=()=>{this.#dirty();graph.afterChange(node2)};pointer.finally=()=>{this.resizing_node=null;pointer.resizeDirection=void 0};this.canvas.style.cursor=cursors[resizeDirection];return}}pointer.onDragStart=pointer2=>this.#startDraggingItems(node2,pointer2,true);pointer.onDragEnd=e22=>this.#processDraggedItems(e22)}this.dirty_canvas=true}#processWidgetClick(e2,node2,widget){const{pointer}=this;if(typeof widget.onPointerDown==="function"){const handled=widget.onPointerDown(pointer,node2,this);if(handled)return}const oldValue=widget.value;const pos=this.graph_mouse;const x2=pos[0]-node2.pos[0];const y=pos[1]-node2.pos[1];const widgetInstance=toConcreteWidget(widget,node2,false);if(widgetInstance){pointer.onClick=()=>widgetInstance.onClick({e:e2,node:node2,canvas:this});pointer.onDrag=eMove=>widgetInstance.onDrag?.({e:eMove,node:node2,canvas:this})}else if(widget.mouse){const result=widget.mouse(e2,[x2,y],node2);if(result!=null)this.dirty_canvas=result}if(oldValue!=widget.value){node2.onWidgetChanged?.(widget.name,widget.value,oldValue,widget);if(!node2.graph)throw new NullGraphError;node2.graph._version++}pointer.finally=()=>{if(widget.mouse){const{eUp}=pointer;if(!eUp)return;const{canvasX,canvasY}=eUp;widget.mouse(eUp,[canvasX-node2.pos[0],canvasY-node2.pos[1]],node2)}this.node_widget=null}}#processMiddleButton(e2,node2){const{pointer}=this;if(LiteGraph.middle_click_slot_add_default_node&&node2&&this.allow_interaction&&!this.read_only&&!this.connecting_links&&!node2.flags.collapsed){let mClikSlot=false;let mClikSlot_index=false;let mClikSlot_isOut=false;const{inputs,outputs}=node2;if(outputs){for(const[i,output]of outputs.entries()){const link_pos=node2.getOutputPos(i);if(isInRectangle(e2.canvasX,e2.canvasY,link_pos[0]-15,link_pos[1]-10,30,20)){mClikSlot=output;mClikSlot_index=i;mClikSlot_isOut=true;break}}}if(inputs){for(const[i,input]of inputs.entries()){const link_pos=node2.getInputPos(i);if(isInRectangle(e2.canvasX,e2.canvasY,link_pos[0]-15,link_pos[1]-10,30,20)){mClikSlot=input;mClikSlot_index=i;mClikSlot_isOut=false;break}}}if(mClikSlot&&mClikSlot_index!==false){const alphaPosY=.5-(mClikSlot_index+1)/(mClikSlot_isOut?outputs.length:inputs.length);const node_bounding=node2.getBounding();const posRef=[!mClikSlot_isOut?node_bounding[0]:node_bounding[0]+node_bounding[2],e2.canvasY-80];pointer.onClick=()=>this.createDefaultNodeForSlot({nodeFrom:!mClikSlot_isOut?null:node2,slotFrom:!mClikSlot_isOut?null:mClikSlot_index,nodeTo:!mClikSlot_isOut?node2:null,slotTo:!mClikSlot_isOut?mClikSlot_index:null,position:posRef,nodeType:"AUTO",posAdd:[!mClikSlot_isOut?-30:30,-alphaPosY*130],posSizeFix:[!mClikSlot_isOut?-1:0,0]})}}if(this.allow_dragcanvas){pointer.onDragStart=()=>this.dragging_canvas=true;pointer.finally=()=>this.dragging_canvas=false}}#processDragZoom(e2){if(!e2.buttons){this.#dragZoomStart=null;return}const start=this.#dragZoomStart;if(!start)throw new TypeError("Drag-zoom state object was null");if(!this.graph)throw new NullGraphError;const deltaY=e2.y-start.pos[1];const startScale=start.scale;const scale=startScale-deltaY/100;this.ds.changeScale(scale,start.pos);this.graph.change()}processMouseMove(e2){if(this.dragZoomEnabled&&e2.ctrlKey&&e2.shiftKey&&this.#dragZoomStart){this.#processDragZoom(e2);return}if(this.autoresize)this.resize();if(this.set_canvas_dirty_on_mouse_event)this.dirty_canvas=true;const{graph,resizingGroup,linkConnector,pointer,subgraph}=this;if(!graph)return;LGraphCanvas.active_canvas=this;this.adjustMouseEvent(e2);const mouse=[e2.clientX,e2.clientY];this.mouse[0]=mouse[0];this.mouse[1]=mouse[1];const delta2=[mouse[0]-this.last_mouse[0],mouse[1]-this.last_mouse[1]];this.last_mouse=mouse;const{canvasX:x2,canvasY:y}=e2;this.graph_mouse[0]=x2;this.graph_mouse[1]=y;if(e2.isPrimary)pointer.move(e2);let underPointer=CanvasItem.Nothing;if(subgraph){underPointer|=subgraph.inputNode.onPointerMove(e2);underPointer|=subgraph.outputNode.onPointerMove(e2)}if(this.block_click){e2.preventDefault();return}e2.dragging=this.last_mouse_dragging;if(this.node_widget){const[node22,widget]=this.node_widget;if(widget?.mouse){const relativeX=x2-node22.pos[0];const relativeY=y-node22.pos[1];const result=widget.mouse(e2,[relativeX,relativeY],node22);if(result!=null)this.dirty_canvas=result}}const node2=graph.getNodeOnPos(x2,y,this.visible_nodes);const dragRect=this.dragging_rectangle;if(dragRect){dragRect[2]=x2-dragRect[0];dragRect[3]=y-dragRect[1];this.dirty_canvas=true}else if(resizingGroup){underPointer|=CanvasItem.Group;pointer.resizeDirection="SE"}else if(this.dragging_canvas){this.ds.offset[0]+=delta2[0]/this.ds.scale;this.ds.offset[1]+=delta2[1]/this.ds.scale;this.#dirty()}else if((this.allow_interaction||node2?.flags.allow_interaction)&&!this.read_only){if(linkConnector.isConnecting)this.dirty_canvas=true;this.updateMouseOverNodes(node2,e2);if(node2){underPointer|=CanvasItem.Node;if(node2.redraw_on_mouse)this.dirty_canvas=true;const pos=[0,0];const inputId=isOverNodeInput(node2,x2,y,pos);const outputId=isOverNodeOutput(node2,x2,y,pos);const overWidget=node2.getWidgetOnPos(x2,y,true)??void 0;if(!node2.mouseOver){node2.mouseOver={};this.node_over=node2;this.dirty_canvas=true;for(const reroute of this.#visibleReroutes){reroute.hideSlots();this.dirty_bgcanvas=true}node2.onMouseEnter?.(e2)}node2.onMouseMove?.(e2,[x2-node2.pos[0],y-node2.pos[1]],this);const{mouseOver}=node2;if(mouseOver.inputId!==inputId||mouseOver.outputId!==outputId||mouseOver.overWidget!==overWidget){mouseOver.inputId=inputId;mouseOver.outputId=outputId;mouseOver.overWidget=overWidget;linkConnector.overWidget=void 0;if(linkConnector.isConnecting){const firstLink=linkConnector.renderLinks.at(0);let highlightPos;let highlightInput;if(!firstLink||!linkConnector.isNodeValidDrop(node2));else if(linkConnector.state.connectingTo==="input"){if(overWidget){const slot=node2.getSlotFromWidget(overWidget);if(slot&&linkConnector.isInputValidDrop(node2,slot)){highlightInput=slot;highlightPos=node2.getInputSlotPos(slot);linkConnector.overWidget=overWidget}}if(!linkConnector.overWidget){if(inputId===-1&&outputId===-1){const result=node2.findInputByType(firstLink.fromSlot.type);if(result){highlightInput=result.slot;highlightPos=node2.getInputSlotPos(result.slot)}}else if(inputId!=-1&&node2.inputs[inputId]&&LiteGraph.isValidConnection(firstLink.fromSlot.type,node2.inputs[inputId].type)){highlightPos=pos;highlightInput=node2.inputs[inputId]}if(highlightInput){const widget=node2.getWidgetFromSlot(highlightInput);if(widget)linkConnector.overWidget=widget}}}else if(linkConnector.state.connectingTo==="output"){if(inputId===-1&&outputId===-1){const result=node2.findOutputByType(firstLink.fromSlot.type);if(result){highlightPos=node2.getOutputPos(result.index)}}else{if(outputId!=-1&&node2.outputs[outputId]&&LiteGraph.isValidConnection(firstLink.fromSlot.type,node2.outputs[outputId].type)){highlightPos=pos}}}this._highlight_pos=highlightPos;this._highlight_input=highlightInput}this.dirty_canvas=true}if(!pointer.eDown){if(inputId===-1&&outputId===-1&&!overWidget){pointer.resizeDirection=node2.findResizeDirection(x2,y)}else{pointer.resizeDirection&&=void 0}}}else{underPointer=this.#updateReroutes(underPointer);const segment=this.#getLinkCentreOnPos(e2);if(this.over_link_center!==segment){underPointer|=CanvasItem.Link;this.over_link_center=segment;this.dirty_bgcanvas=true}if(this.canvas){const group=graph.getGroupOnPos(x2,y);if(group&&!e2.ctrlKey&&!this.read_only&&group.isInResize(x2,y)){pointer.resizeDirection="SE"}else{pointer.resizeDirection&&=void 0}}}if(this.node_capturing_input&&this.node_capturing_input!=node2){this.node_capturing_input.onMouseMove?.(e2,[x2-this.node_capturing_input.pos[0],y-this.node_capturing_input.pos[1]],this)}if(this.isDragging){const selected=this.selectedItems;const allItems=e2.ctrlKey?selected:getAllNestedItems(selected);const deltaX=delta2[0]/this.ds.scale;const deltaY=delta2[1]/this.ds.scale;for(const item of allItems){item.move(deltaX,deltaY,true)}this.#dirty()}}this.hoveringOver=underPointer;e2.preventDefault();return}#updateReroutes(underPointer){const{graph,pointer,linkConnector}=this;if(!graph)throw new NullGraphError;if(!pointer.isDown){let anyChanges=false;for(const reroute of this.#visibleReroutes){anyChanges||=reroute.updateVisibility(this.graph_mouse);if(reroute.isSlotHovered)underPointer|=CanvasItem.RerouteSlot}if(anyChanges)this.dirty_bgcanvas=true}else if(linkConnector.isConnecting){for(const reroute of this.#visibleReroutes){if(reroute.containsPoint(this.graph_mouse)){if(linkConnector.isRerouteValidDrop(reroute)){linkConnector.overReroute=reroute;this._highlight_pos=reroute.pos}return underPointer|=CanvasItem.RerouteSlot}}}this._highlight_pos&&=void 0;linkConnector.overReroute&&=void 0;return underPointer}#startDraggingItems(item,pointer,sticky=false){this.emitBeforeChange();this.graph?.beforeChange();pointer.finally=()=>{this.isDragging=false;this.graph?.afterChange();this.emitAfterChange()};this.processSelect(item,pointer.eDown,sticky);this.isDragging=true}#processDraggedItems(e2){const{graph}=this;if(e2.shiftKey||LiteGraph.alwaysSnapToGrid)graph?.snapToGrid(this.selectedItems);this.dirty_canvas=true;this.dirty_bgcanvas=true;this.onNodeMoved?.(findFirstNode(this.selectedItems))}processMouseUp(e2){if(e2.isPrimary===false)return;const{graph,pointer}=this;if(!graph)return;LGraphCanvas.active_canvas=this;this.adjustMouseEvent(e2);const now=LiteGraph.getTime();e2.click_time=now-this.last_mouseclick;const isClick=pointer.up(e2);if(isClick===true){pointer.isDown=false;pointer.isDouble=false;this.connecting_links=null;this.dragging_canvas=false;graph.change();e2.stopPropagation();e2.preventDefault();return}this.last_mouse_dragging=false;this.last_click_position=null;this.block_click&&=false;if(e2.button===0){this.selected_group=null;this.isDragging=false;const x2=e2.canvasX;const y=e2.canvasY;if(!this.linkConnector.isConnecting){this.dirty_canvas=true;this.node_over?.onMouseUp?.(e2,[x2-this.node_over.pos[0],y-this.node_over.pos[1]],this);this.node_capturing_input?.onMouseUp?.(e2,[x2-this.node_capturing_input.pos[0],y-this.node_capturing_input.pos[1]])}}else if(e2.button===1){this.dirty_canvas=true;this.dragging_canvas=false}else if(e2.button===2){this.dirty_canvas=true}pointer.isDown=false;pointer.isDouble=false;graph.change();e2.stopPropagation();e2.preventDefault();return}processMouseOut(e2){this.adjustMouseEvent(e2);this.updateMouseOverNodes(null,e2)}processMouseCancel(){console.warn("Pointer cancel!");this.pointer.reset()}processMouseWheel(e2){if(!this.graph||!this.allow_dragcanvas)return;const delta2=e2.wheelDeltaY??e2.detail*-60;this.adjustMouseEvent(e2);const pos=[e2.clientX,e2.clientY];if(this.viewport&&!isPointInRect(pos,this.viewport))return;let{scale}=this.ds;if(LiteGraph.canvasNavigationMode==="legacy"||LiteGraph.canvasNavigationMode==="standard"&&e2.ctrlKey){if(delta2>0){scale*=this.zoom_speed}else if(delta2<0){scale*=1/this.zoom_speed}this.ds.changeScale(scale,[e2.clientX,e2.clientY])}else if(LiteGraph.macTrackpadGestures&&(!LiteGraph.macGesturesRequireMac||navigator.userAgent.includes("Mac"))){if(e2.metaKey&&!e2.ctrlKey&&!e2.shiftKey&&!e2.altKey){if(e2.deltaY>0){scale*=1/this.zoom_speed}else if(e2.deltaY<0){scale*=this.zoom_speed}this.ds.changeScale(scale,[e2.clientX,e2.clientY])}else if(e2.ctrlKey){scale*=1+e2.deltaY*(1-this.zoom_speed)*.18;this.ds.changeScale(scale,[e2.clientX,e2.clientY],false)}else if(e2.shiftKey){this.ds.offset[0]-=e2.deltaY*1.18*(1/scale)}else{this.ds.offset[0]-=e2.deltaX*1.18*(1/scale);this.ds.offset[1]-=e2.deltaY*1.18*(1/scale)}}this.graph.change();e2.preventDefault();return}#noItemsSelected(){const event=new CustomEvent("litegraph:no-items-selected",{bubbles:true});this.canvas.dispatchEvent(event)}processKey(e2){this.#shiftDown=e2.shiftKey;const{graph}=this;if(!graph)return;let block_default=false;if(e2.target.localName=="input")return;if(e2.type=="keydown"){if(e2.key===" "){this.read_only=true;if(this._previously_dragging_canvas===null){this._previously_dragging_canvas=this.dragging_canvas}this.dragging_canvas=this.pointer.isDown;block_default=true}else if(e2.key==="Escape"){if(this.linkConnector.isConnecting){this.linkConnector.reset();e2.preventDefault();return}this.node_panel?.close();this.options_panel?.close();if(this.node_panel||this.options_panel)block_default=true}else if(e2.keyCode===65&&e2.ctrlKey){this.selectItems();block_default=true}else if(e2.keyCode===67&&(e2.metaKey||e2.ctrlKey)&&!e2.shiftKey){if(this.selected_nodes){this.copyToClipboard();block_default=true}}else if(e2.keyCode===86&&(e2.metaKey||e2.ctrlKey)){this.pasteFromClipboard({connectInputs:e2.shiftKey})}else if(e2.key==="Delete"||e2.key==="Backspace"){if(e2.target.localName!="input"&&e2.target.localName!="textarea"){if(this.selectedItems.size===0){this.#noItemsSelected();return}this.deleteSelected();block_default=true}}for(const node2 of Object.values(this.selected_nodes)){node2.onKeyDown?.(e2)}}else if(e2.type=="keyup"){if(e2.key===" "){this.read_only=false;this.dragging_canvas=(this._previously_dragging_canvas??false)&&this.pointer.isDown;this._previously_dragging_canvas=null}for(const node2 of Object.values(this.selected_nodes)){node2.onKeyUp?.(e2)}}graph.change();if(block_default){e2.preventDefault();e2.stopImmediatePropagation()}}copyToClipboard(items){const serialisable={nodes:[],groups:[],reroutes:[],links:[],subgraphs:[]};const subgraphs=new Set;for(const item of items??this.selectedItems){if(item instanceof LGraphNode){if(item.clonable===false)continue;const cloned=item.clone()?.serialize();if(!cloned)continue;cloned.id=item.id;serialisable.nodes.push(cloned);if(item.inputs){for(const{link:linkId}of item.inputs){if(linkId==null)continue;const link=this.graph?._links.get(linkId)?.asSerialisable();if(link)serialisable.links.push(link)}}if(item instanceof SubgraphNode){subgraphs.add(item.subgraph)}}else if(item instanceof LGraphGroup){serialisable.groups.push(item.serialize())}else if(item instanceof Reroute){serialisable.reroutes.push(item.asSerialisable())}}for(const subgraph of subgraphs){const cloned=subgraph.clone(true).asSerialisable();serialisable.subgraphs.push(cloned)}localStorage.setItem("litegrapheditor_clipboard",JSON.stringify(serialisable))}emitEvent(detail){this.canvas.dispatchEvent(new CustomEvent("litegraph:canvas",{bubbles:true,detail}))}emitBeforeChange(){this.emitEvent({subType:"before-change"})}emitAfterChange(){this.emitEvent({subType:"after-change"})}_pasteFromClipboard(options={}){const{connectInputs=false,position=this.graph_mouse}=options;if(!LiteGraph.ctrl_shift_v_paste_connect_unselected_outputs&&connectInputs)return;const data=localStorage.getItem("litegrapheditor_clipboard");if(!data)return;const{graph}=this;if(!graph)throw new NullGraphError;graph.beforeChange();const parsed=JSON.parse(data);parsed.nodes??=[];parsed.groups??=[];parsed.reroutes??=[];parsed.links??=[];parsed.subgraphs??=[];let offsetX=Infinity;let offsetY=Infinity;for(const item of[...parsed.nodes,...parsed.reroutes]){if(item.pos==null)throw new TypeError("Invalid node encounterd on paste. `pos` was null.");if(item.pos[0]<offsetX)offsetX=item.pos[0];if(item.pos[1]<offsetY)offsetY=item.pos[1]}if(parsed.groups){for(const group of parsed.groups){if(group.bounding[0]<offsetX)offsetX=group.bounding[0];if(group.bounding[1]<offsetY)offsetY=group.bounding[1]}}const results={created:[],nodes:new Map,links:new Map,reroutes:new Map,subgraphs:new Map};const{created,nodes,links,reroutes}=results;for(const info of parsed.subgraphs){const originalId=info.id;info.id=createUuidv4();const subgraph=graph.createSubgraph(info);subgraph.configure(info);results.subgraphs.set(originalId,subgraph)}for(const info of parsed.groups){info.id=-1;const group=new LGraphGroup;group.configure(info);graph.add(group);created.push(group)}for(const info of parsed.nodes){const subgraph=results.subgraphs.get(info.type);if(subgraph)info.type=subgraph.id;const node2=info.type==null?null:LiteGraph.createNode(info.type);if(!node2){continue}nodes.set(info.id,node2);info.id=-1;node2.configure(info);graph.add(node2);created.push(node2)}for(const info of parsed.reroutes){const{id,...rerouteInfo}=info;const reroute=graph.setReroute(rerouteInfo);created.push(reroute);reroutes.set(id,reroute)}for(const reroute of reroutes.values()){if(reroute.parentId==null)continue;const mapped=reroutes.get(reroute.parentId);if(mapped)reroute.parentId=mapped.id}for(const info of parsed.links){let outNode=nodes.get(info.origin_id);let afterRerouteId;if(info.parentId!=null)afterRerouteId=reroutes.get(info.parentId)?.id;if(connectInputs&&LiteGraph.ctrl_shift_v_paste_connect_unselected_outputs){outNode??=graph.getNodeById(info.origin_id);afterRerouteId??=info.parentId}const inNode=nodes.get(info.target_id);if(inNode){const link=outNode?.connect(info.origin_slot,inNode,info.target_slot,afterRerouteId);if(link)links.set(info.id,link)}}for(const reroute of reroutes.values()){const ids=[...reroute.linkIds].map(x2=>links.get(x2)?.id??x2);reroute.update(reroute.parentId,void 0,ids,reroute.floating);if(!reroute.validateLinks(graph.links,graph.floatingLinks)){graph.removeReroute(reroute.id)}}for(const item of created){item.pos[0]+=position[0]-offsetX;item.pos[1]+=position[1]-offsetY}this.selectItems(created);graph.afterChange();return results}pasteFromClipboard(options={}){this.emitBeforeChange();try{this._pasteFromClipboard(options)}finally{this.emitAfterChange()}}processNodeDblClicked(n){this.onShowNodePanel?.(n);this.onNodeDblClicked?.(n);this.setDirty(true)}#handleMultiSelect(e2,dragRect){const{graph,selectedItems,subgraph}=this;if(!graph)throw new NullGraphError;const w=Math.abs(dragRect[2]);const h=Math.abs(dragRect[3]);if(dragRect[2]<0)dragRect[0]-=w;if(dragRect[3]<0)dragRect[1]-=h;dragRect[2]=w;dragRect[3]=h;const isSelected=new Set;const notSelected=[];if(subgraph){const{inputNode,outputNode}=subgraph;if(overlapBounding(dragRect,inputNode.boundingRect)){addPositionable(inputNode)}if(overlapBounding(dragRect,outputNode.boundingRect)){addPositionable(outputNode)}}for(const nodeX of graph._nodes){if(overlapBounding(dragRect,nodeX.boundingRect)){addPositionable(nodeX)}}for(const group of graph.groups){if(!containsRect(dragRect,group._bounding))continue;group.recomputeInsideNodes();addPositionable(group)}for(const reroute of graph.reroutes.values()){if(!isPointInRect(reroute.pos,dragRect))continue;selectedItems.add(reroute);reroute.selected=true;addPositionable(reroute)}if(e2.shiftKey){for(const item of notSelected)this.select(item)}else if(e2.altKey){for(const item of isSelected)this.deselect(item)}else{for(const item of selectedItems.values()){if(!isSelected.has(item))this.deselect(item)}for(const item of notSelected)this.select(item)}this.onSelectionChange?.(this.selected_nodes);function addPositionable(item){if(!item.selected||!selectedItems.has(item))notSelected.push(item);else isSelected.add(item)}}processSelect(item,e2,sticky=false){const addModifier=e2?.shiftKey;const subtractModifier=e2!=null&&(e2.metaKey||e2.ctrlKey);const eitherModifier=addModifier||subtractModifier;const modifySelection=eitherModifier||this.multi_select;if(!item){if(!eitherModifier||this.multi_select)this.deselectAll()}else if(!item.selected||!this.selectedItems.has(item)){if(!modifySelection)this.deselectAll(item);this.select(item)}else if(modifySelection&&!sticky){this.deselect(item)}else if(!sticky){this.deselectAll(item)}else{return}this.onSelectionChange?.(this.selected_nodes);this.setDirty(true)}select(item){if(item.selected&&this.selectedItems.has(item))return;item.selected=true;this.selectedItems.add(item);this.state.selectionChanged=true;if(!(item instanceof LGraphNode))return;item.onSelected?.();this.selected_nodes[item.id]=item;this.onNodeSelected?.(item);if(item.inputs){for(const input of item.inputs){if(input.link==null)continue;this.highlighted_links[input.link]=true}}if(item.outputs){for(const id of item.outputs.flatMap(x2=>x2.links)){if(id==null)continue;this.highlighted_links[id]=true}}}deselect(item){if(!item.selected&&!this.selectedItems.has(item))return;item.selected=false;this.selectedItems.delete(item);this.state.selectionChanged=true;if(!(item instanceof LGraphNode))return;item.onDeselected?.();delete this.selected_nodes[item.id];this.onNodeDeselected?.(item);const{graph}=this;if(!graph)return;if(item.inputs){for(const input of item.inputs){if(input.link==null)continue;const node2=LLink.getOriginNode(graph,input.link);if(node2&&this.selectedItems.has(node2))continue;delete this.highlighted_links[input.link]}}if(item.outputs){for(const id of item.outputs.flatMap(x2=>x2.links)){if(id==null)continue;const node2=LLink.getTargetNode(graph,id);if(node2&&this.selectedItems.has(node2))continue;delete this.highlighted_links[id]}}}processNodeSelected(item,e2){this.processSelect(item,e2,e2&&(e2.shiftKey||e2.metaKey||e2.ctrlKey||this.multi_select))}selectNode(node2,add_to_current_selection){if(node2==null){this.deselectAll()}else{this.selectNodes([node2],add_to_current_selection)}}get empty(){if(!this.graph)throw new NullGraphError;return this.graph.empty}get positionableItems(){if(!this.graph)throw new NullGraphError;return this.graph.positionableItems()}selectItems(items,add_to_current_selection){const itemsToSelect=items??this.positionableItems;if(!add_to_current_selection)this.deselectAll();for(const item of itemsToSelect)this.select(item);this.onSelectionChange?.(this.selected_nodes);this.setDirty(true)}selectNodes(nodes,add_to_current_selection){this.selectItems(nodes,add_to_current_selection)}deselectNode(node2){this.deselect(node2)}deselectAll(keepSelected){if(!this.graph)return;const selected=this.selectedItems;if(!selected.size)return;let wasSelected;for(const sel of selected){if(sel===keepSelected){wasSelected=sel;continue}sel.onDeselected?.();sel.selected=false}selected.clear();if(wasSelected)selected.add(wasSelected);this.setDirty(true);const oldNode=keepSelected?.id==null?null:this.selected_nodes[keepSelected.id];this.selected_nodes={};this.current_node=null;this.highlighted_links={};if(keepSelected instanceof LGraphNode){if(oldNode)this.selected_nodes[oldNode.id]=oldNode;if(keepSelected.inputs){for(const input of keepSelected.inputs){if(input.link==null)continue;this.highlighted_links[input.link]=true}}if(keepSelected.outputs){for(const id of keepSelected.outputs.flatMap(x2=>x2.links)){if(id==null)continue;this.highlighted_links[id]=true}}}this.state.selectionChanged=true;this.onSelectionChange?.(this.selected_nodes)}deselectAllNodes(){this.deselectAll()}deleteSelected(){const{graph}=this;if(!graph)throw new NullGraphError;this.emitBeforeChange();graph.beforeChange();for(const item of this.selectedItems){if(item instanceof LGraphNode){const node2=item;if(node2.block_delete)continue;node2.connectInputToOutput();graph.remove(node2);this.onNodeDeselected?.(node2)}else if(item instanceof LGraphGroup){graph.remove(item)}else if(item instanceof Reroute){graph.removeReroute(item.id)}}this.selected_nodes={};this.selectedItems.clear();this.current_node=null;this.highlighted_links={};this.state.selectionChanged=true;this.onSelectionChange?.(this.selected_nodes);this.setDirty(true);graph.afterChange();this.emitAfterChange()}deleteSelectedNodes(){this.deleteSelected()}centerOnNode(node2){const dpi=window?.devicePixelRatio||1;this.ds.offset[0]=-node2.pos[0]-node2.size[0]*.5+this.canvas.width*.5/(this.ds.scale*dpi);this.ds.offset[1]=-node2.pos[1]-node2.size[1]*.5+this.canvas.height*.5/(this.ds.scale*dpi);this.setDirty(true,true)}adjustMouseEvent(e2){let clientX_rel=e2.clientX;let clientY_rel=e2.clientY;if(this.canvas){const b=this.canvas.getBoundingClientRect();clientX_rel-=b.left;clientY_rel-=b.top}e2.safeOffsetX=clientX_rel;e2.safeOffsetY=clientY_rel;if(e2.deltaX===void 0)e2.deltaX=clientX_rel-this.last_mouse_position[0];if(e2.deltaY===void 0)e2.deltaY=clientY_rel-this.last_mouse_position[1];this.last_mouse_position[0]=clientX_rel;this.last_mouse_position[1]=clientY_rel;e2.canvasX=clientX_rel/this.ds.scale-this.ds.offset[0];e2.canvasY=clientY_rel/this.ds.scale-this.ds.offset[1]}setZoom(value,zooming_center){this.ds.changeScale(value,zooming_center);this.#dirty()}convertOffsetToCanvas(pos,out){return this.ds.convertOffsetToCanvas(pos,out)}convertCanvasToOffset(pos,out){return this.ds.convertCanvasToOffset(pos,out)}convertEventToCanvasOffset(e2){const rect=this.canvas.getBoundingClientRect();return this.convertCanvasToOffset([e2.clientX-rect.left,e2.clientY-rect.top])}bringToFront(node2){const{graph}=this;if(!graph)throw new NullGraphError;const i=graph._nodes.indexOf(node2);if(i==-1)return;graph._nodes.splice(i,1);graph._nodes.push(node2)}sendToBack(node2){const{graph}=this;if(!graph)throw new NullGraphError;const i=graph._nodes.indexOf(node2);if(i==-1)return;graph._nodes.splice(i,1);graph._nodes.unshift(node2)}computeVisibleNodes(nodes,out){const visible_nodes=out||[];visible_nodes.length=0;if(!this.graph)throw new NullGraphError;const _nodes=nodes||this.graph._nodes;for(const node2 of _nodes){node2.updateArea(this.ctx);if(!overlapBounding(this.visible_area,node2.renderArea))continue;visible_nodes.push(node2)}return visible_nodes}isNodeVisible(node2){return this.#visible_node_ids.has(node2.id)}draw(force_canvas,force_bgcanvas){if(!this.canvas||this.canvas.width==0||this.canvas.height==0)return;const now=LiteGraph.getTime();this.render_time=(now-this.last_draw_time)*.001;this.last_draw_time=now;if(this.graph)this.ds.computeVisibleArea(this.viewport);if(this.dirty_canvas||force_canvas){this.computeVisibleNodes(void 0,this.visible_nodes);this.#visible_node_ids=new Set(this.visible_nodes.map(node2=>node2.id));const{subgraph}=this;if(subgraph){subgraph.inputNode.arrange();subgraph.outputNode.arrange()}}if(this.dirty_bgcanvas||force_bgcanvas||this.always_render_background||this.graph?._last_trigger_time&&now-this.graph._last_trigger_time<1e3){this.drawBackCanvas()}if(this.dirty_canvas||force_canvas)this.drawFrontCanvas();this.fps=this.render_time?1/this.render_time:0;this.frame++}drawFrontCanvas(){this.dirty_canvas=false;const{ctx,canvas:canvas2,graph,linkConnector}=this;if(ctx.start2D&&!this.viewport){ctx.start2D();ctx.restore();ctx.setTransform(1,0,0,1,0,0)}const area=this.viewport||this.dirty_area;if(area){ctx.save();ctx.beginPath();ctx.rect(area[0],area[1],area[2],area[3]);ctx.clip()}this.#snapToGrid=this.#shiftDown||LiteGraph.alwaysSnapToGrid?this.graph?.getSnapToGridSize():void 0;if(this.clear_background){if(area)ctx.clearRect(area[0],area[1],area[2],area[3]);else ctx.clearRect(0,0,canvas2.width,canvas2.height)}if(this.bgcanvas==this.canvas){this.drawBackCanvas()}else{const scale=1;ctx.drawImage(this.bgcanvas,0,0,this.bgcanvas.width/scale,this.bgcanvas.height/scale)}this.onRender?.(canvas2,ctx);if(this.show_info){this.renderInfo(ctx,area?area[0]:0,area?area[1]:0)}if(graph){ctx.save();this.ds.toCanvasContext(ctx);const{visible_nodes}=this;const drawSnapGuides=this.#snapToGrid&&this.isDragging;for(const node2 of visible_nodes){ctx.save();if(drawSnapGuides&&this.selectedItems.has(node2))this.drawSnapGuide(ctx,node2);ctx.translate(node2.pos[0],node2.pos[1]);this.drawNode(node2,ctx);ctx.restore()}this.subgraph?.draw(ctx,this.colourGetter,this.linkConnector.renderLinks[0]?.fromSlot,this.editor_alpha);if(this.render_execution_order){this.drawExecutionOrder(ctx)}if(graph.config.links_ontop){this.drawConnections(ctx)}if(linkConnector.isConnecting){const{renderLinks}=linkConnector;const highlightPos=this.#getHighlightPosition();ctx.lineWidth=this.connections_width;for(const renderLink of renderLinks){const{fromSlot,fromPos:pos,fromDirection,dragDirection}=renderLink;const connShape=fromSlot.shape;const connType=fromSlot.type;const colour=connType===LiteGraph.EVENT?LiteGraph.EVENT_LINK_COLOR:LiteGraph.CONNECTING_LINK_COLOR;this.renderLink(ctx,pos,highlightPos,null,false,null,colour,fromDirection,dragDirection);ctx.beginPath();if(connType===LiteGraph.EVENT||connShape===RenderShape.BOX){ctx.rect(pos[0]-6+.5,pos[1]-5+.5,14,10);ctx.rect(highlightPos[0]-6+.5,highlightPos[1]-5+.5,14,10)}else if(connShape===RenderShape.ARROW){ctx.moveTo(pos[0]+8,pos[1]+.5);ctx.lineTo(pos[0]-4,pos[1]+6+.5);ctx.lineTo(pos[0]-4,pos[1]-6+.5);ctx.closePath()}else{ctx.arc(pos[0],pos[1],4,0,Math.PI*2);ctx.arc(highlightPos[0],highlightPos[1],4,0,Math.PI*2)}ctx.fill()}this.#renderSnapHighlight(ctx,highlightPos)}if(this.dragging_rectangle){const{eDown,eMove}=this.pointer;ctx.strokeStyle="#FFF";if(eDown&&eMove){const transform=ctx.getTransform();const ratio=1;ctx.setTransform(ratio,0,0,ratio,0,0);const x2=eDown.safeOffsetX;const y=eDown.safeOffsetY;ctx.strokeRect(x2,y,eMove.safeOffsetX-x2,eMove.safeOffsetY-y);ctx.setTransform(transform)}else{const[x2,y,w,h]=this.dragging_rectangle;ctx.strokeRect(x2,y,w,h)}}if(!this.isDragging&&this.over_link_center&&this.render_link_tooltip){this.drawLinkTooltip(ctx,this.over_link_center)}else{this.onDrawLinkTooltip?.(ctx,null)}this.onDrawForeground?.(ctx,this.visible_area);ctx.restore()}this.onDrawOverlay?.(ctx);if(area)ctx.restore()}#getLinkCentreOnPos(e2){for(const linkSegment of this.renderedPaths){const centre=linkSegment._pos;if(!centre)continue;if(isInRectangle(e2.canvasX,e2.canvasY,centre[0]-4,centre[1]-4,8,8)){return linkSegment}}}#getHighlightPosition(){return LiteGraph.snaps_for_comfy?this.linkConnector.state.snapLinksPos??this._highlight_pos??this.graph_mouse:this.graph_mouse}#renderSnapHighlight(ctx,highlightPos){const linkConnectorSnap=!!this.linkConnector.state.snapLinksPos;if(!this._highlight_pos&&!linkConnectorSnap)return;ctx.fillStyle="#ffcc00";ctx.beginPath();const shape=this._highlight_input?.shape;if(shape===RenderShape.ARROW){ctx.moveTo(highlightPos[0]+8,highlightPos[1]+.5);ctx.lineTo(highlightPos[0]-4,highlightPos[1]+6+.5);ctx.lineTo(highlightPos[0]-4,highlightPos[1]-6+.5);ctx.closePath()}else{ctx.arc(highlightPos[0],highlightPos[1],6,0,Math.PI*2)}ctx.fill();const{linkConnector}=this;const{overReroute,overWidget}=linkConnector;if(!LiteGraph.snap_highlights_node||!linkConnector.isConnecting||linkConnectorSnap)return;overReroute?.drawHighlight(ctx,"#ffcc00aa");const node2=this.node_over;if(!node2)return;const{strokeStyle,lineWidth}=ctx;const area=node2.boundingRect;const gap=3;const radius=LiteGraph.ROUND_RADIUS+gap;const x2=area[0]-gap;const y=area[1]-gap;const width2=area[2]+gap*2;const height=area[3]+gap*2;ctx.beginPath();ctx.roundRect(x2,y,width2,height,radius);const start=linkConnector.state.connectingTo==="output"?0:1;const inverter=start?-1:1;const hx=highlightPos[0];const hy=highlightPos[1];const gRadius=width2<height?width2:width2*Math.max(height/width2,.5);const gradient=ctx.createRadialGradient(hx,hy,0,hx,hy,gRadius);gradient.addColorStop(1,"#00000000");gradient.addColorStop(0,"#ffcc00aa");const linearGradient=ctx.createLinearGradient(x2,y,x2+width2,y);linearGradient.addColorStop(.5,"#00000000");linearGradient.addColorStop(start+.67*inverter,"#ddeeff33");linearGradient.addColorStop(start+inverter,"#ffcc0055");ctx.setLineDash([radius,radius*.001]);ctx.lineWidth=1;ctx.strokeStyle=linearGradient;ctx.stroke();if(overWidget){const{computedHeight}=overWidget;ctx.beginPath();const{pos:[nodeX,nodeY]}=node2;const height2=LiteGraph.NODE_WIDGET_HEIGHT;if(overWidget.type.startsWith("custom")&&computedHeight!=null&&computedHeight>height2*2){ctx.rect(nodeX+9,nodeY+overWidget.y+9,(overWidget.width??area[2])-18,computedHeight-18)}else{ctx.roundRect(nodeX+BaseWidget.margin,nodeY+overWidget.y,overWidget.width??area[2],height2,height2*.5)}ctx.stroke()}ctx.strokeStyle=gradient;ctx.stroke();ctx.setLineDash([]);ctx.lineWidth=lineWidth;ctx.strokeStyle=strokeStyle}renderInfo(ctx,x2,y){x2=x2||10;y=y||this.canvas.offsetHeight-80;ctx.save();ctx.translate(x2,y);ctx.font=`10px ${LiteGraph.DEFAULT_FONT}`;ctx.fillStyle="#888";ctx.textAlign="left";if(this.graph){ctx.fillText(`T: ${this.graph.globaltime.toFixed(2)}s`,5,13*1);ctx.fillText(`I: ${this.graph.iteration}`,5,13*2);ctx.fillText(`N: ${this.graph._nodes.length} [${this.visible_nodes.length}]`,5,13*3);ctx.fillText(`V: ${this.graph._version}`,5,13*4);ctx.fillText(`FPS:${this.fps.toFixed(2)}`,5,13*5)}else{ctx.fillText("No graph selected",5,13*1)}ctx.restore()}drawBackCanvas(){const canvas2=this.bgcanvas;if(canvas2.width!=this.canvas.width||canvas2.height!=this.canvas.height){canvas2.width=this.canvas.width;canvas2.height=this.canvas.height}if(!this.bgctx){this.bgctx=this.bgcanvas.getContext("2d")}const ctx=this.bgctx;if(!ctx)throw new TypeError("Background canvas context was null.");const viewport=this.viewport||[0,0,ctx.canvas.width,ctx.canvas.height];if(this.clear_background){ctx.clearRect(viewport[0],viewport[1],viewport[2],viewport[3])}const bg_already_painted=this.onRenderBackground?this.onRenderBackground(canvas2,ctx):false;if(!this.viewport){const scale=1;ctx.restore();ctx.setTransform(scale,0,0,scale,0,0)}if(this.graph){ctx.save();this.ds.toCanvasContext(ctx);if(this.ds.scale<1.5&&!bg_already_painted&&this.clear_background_color){ctx.fillStyle=this.clear_background_color;ctx.fillRect(this.visible_area[0],this.visible_area[1],this.visible_area[2],this.visible_area[3])}if(this.background_image&&this.ds.scale>.5&&!bg_already_painted){if(this.zoom_modify_alpha){ctx.globalAlpha=(1-.5/this.ds.scale)*this.editor_alpha}else{ctx.globalAlpha=this.editor_alpha}ctx.imageSmoothingEnabled=false;if(!this._bg_img||this._bg_img.name!=this.background_image){this._bg_img=new Image;this._bg_img.name=this.background_image;this._bg_img.src=this.background_image;const that=this;this._bg_img.addEventListener("load",function(){that.draw(true,true)})}let pattern=this._pattern;if(pattern==null&&this._bg_img.width>0){pattern=ctx.createPattern(this._bg_img,"repeat")??void 0;this._pattern_img=this._bg_img;this._pattern=pattern}if(pattern){ctx.fillStyle=pattern;ctx.fillRect(this.visible_area[0],this.visible_area[1],this.visible_area[2],this.visible_area[3]);ctx.fillStyle="transparent"}ctx.globalAlpha=1;ctx.imageSmoothingEnabled=true}if(this.graph._groups.length){this.drawGroups(canvas2,ctx)}this.onDrawBackground?.(ctx,this.visible_area);if(this.render_canvas_border){ctx.strokeStyle="#235";ctx.strokeRect(0,0,canvas2.width,canvas2.height)}if(this.render_connections_shadows){ctx.shadowColor="#000";ctx.shadowOffsetX=0;ctx.shadowOffsetY=0;ctx.shadowBlur=6}else{ctx.shadowColor="rgba(0,0,0,0)"}this.drawConnections(ctx);ctx.shadowColor="rgba(0,0,0,0)";ctx.restore()}this.dirty_bgcanvas=false;this.dirty_canvas=true}drawNode(node2,ctx){this.current_node=node2;const color=node2.renderingColor;const bgcolor=node2.renderingBgColor;const{low_quality,editor_alpha}=this;ctx.globalAlpha=editor_alpha;if(this.render_shadows&&!low_quality){ctx.shadowColor=LiteGraph.DEFAULT_SHADOW_COLOR;ctx.shadowOffsetX=2*this.ds.scale;ctx.shadowOffsetY=2*this.ds.scale;ctx.shadowBlur=3*this.ds.scale}else{ctx.shadowColor="transparent"}if(node2.flags.collapsed&&node2.onDrawCollapsed?.(ctx,this)==true)return;const shape=node2._shape||RenderShape.BOX;const size=LGraphCanvas.#temp_vec2;size.set(node2.renderingSize);if(node2.collapsed){ctx.font=this.inner_text_font}if(node2.clip_area){ctx.save();ctx.beginPath();if(shape==RenderShape.BOX){ctx.rect(0,0,size[0],size[1])}else if(shape==RenderShape.ROUND){ctx.roundRect(0,0,size[0],size[1],[10])}else if(shape==RenderShape.CIRCLE){ctx.arc(size[0]*.5,size[1]*.5,size[0]*.5,0,Math.PI*2)}ctx.clip()}this.drawNodeShape(node2,ctx,size,color,bgcolor,!!node2.selected);if(node2.title_buttons&&!node2.flags.collapsed){const title_height=LiteGraph.NODE_TITLE_HEIGHT;let current_x=size[0];for(let i=0;i<node2.title_buttons.length;i++){const button=node2.title_buttons[i];if(!button.visible){continue}const button_width=button.getWidth(ctx);current_x-=button_width;const button_y=-title_height+(title_height-button.height)/2;button.draw(ctx,current_x,button_y);current_x-=2}}if(!low_quality){node2.drawBadges(ctx)}ctx.shadowColor="transparent";ctx.strokeStyle=LiteGraph.NODE_BOX_OUTLINE_COLOR;node2.onDrawForeground?.(ctx,this,this.canvas);ctx.font=this.inner_text_font;node2._setConcreteSlots();if(!node2.collapsed){node2.arrange();node2.drawSlots(ctx,{fromSlot:this.linkConnector.renderLinks[0]?.fromSlot,colorContext:this.colourGetter,editorAlpha:this.editor_alpha,lowQuality:this.low_quality});ctx.textAlign="left";ctx.globalAlpha=1;this.drawNodeWidgets(node2,null,ctx)}else if(this.render_collapsed_slots){node2.drawCollapsedSlots(ctx)}if(node2.clip_area){ctx.restore()}ctx.globalAlpha=1}drawLinkTooltip(ctx,link){const pos=link._pos;ctx.fillStyle="black";ctx.beginPath();if(this.linkMarkerShape===LinkMarkerShape.Arrow){const transform=ctx.getTransform();ctx.translate(pos[0],pos[1]);if(Number.isFinite(link._centreAngle))ctx.rotate(link._centreAngle);ctx.moveTo(-2,-3);ctx.lineTo(4,0);ctx.lineTo(-2,3);ctx.setTransform(transform)}else if(this.linkMarkerShape==null||this.linkMarkerShape===LinkMarkerShape.Circle){ctx.arc(pos[0],pos[1],3,0,Math.PI*2)}ctx.fill();const{data}=link;if(data==null)return;if(this.onDrawLinkTooltip?.(ctx,link,this)==true)return;let text=null;if(typeof data==="number")text=data.toFixed(2);else if(typeof data==="string")text=`"${data}"`;else if(typeof data==="boolean")text=String(data);else if(data.toToolTip)text=data.toToolTip();else text=`[${data.constructor.name}]`;if(text==null)return;text=text.substring(0,30);ctx.font="14px Courier New";const info=ctx.measureText(text);const w=info.width+20;const h=24;ctx.shadowColor="black";ctx.shadowOffsetX=2;ctx.shadowOffsetY=2;ctx.shadowBlur=3;ctx.fillStyle="#454";ctx.beginPath();ctx.roundRect(pos[0]-w*.5,pos[1]-15-h,w,h,[3]);ctx.moveTo(pos[0]-10,pos[1]-15);ctx.lineTo(pos[0]+10,pos[1]-15);ctx.lineTo(pos[0],pos[1]-5);ctx.fill();ctx.shadowColor="transparent";ctx.textAlign="center";ctx.fillStyle="#CEC";ctx.fillText(text,pos[0],pos[1]-15-h*.3)}drawNodeShape(node2,ctx,size,fgcolor,bgcolor,_selected){ctx.strokeStyle=fgcolor;ctx.fillStyle=bgcolor;const title_height=LiteGraph.NODE_TITLE_HEIGHT;const{low_quality}=this;const{collapsed}=node2.flags;const shape=node2.renderingShape;const{title_mode}=node2;const render_title=title_mode==TitleMode.TRANSPARENT_TITLE||title_mode==TitleMode.NO_TITLE?false:true;const area=LGraphCanvas.#tmp_area;area.set(node2.boundingRect);area[0]-=node2.pos[0];area[1]-=node2.pos[1];const old_alpha=ctx.globalAlpha;ctx.beginPath();if(shape==RenderShape.BOX||low_quality){ctx.rect(area[0],area[1],area[2],area[3])}else if(shape==RenderShape.ROUND||shape==RenderShape.CARD){ctx.roundRect(area[0],area[1],area[2],area[3],shape==RenderShape.CARD?[LiteGraph.ROUND_RADIUS,LiteGraph.ROUND_RADIUS,0,0]:[LiteGraph.ROUND_RADIUS])}else if(shape==RenderShape.CIRCLE){ctx.arc(size[0]*.5,size[1]*.5,size[0]*.5,0,Math.PI*2)}ctx.fill();if(!collapsed&&render_title){ctx.shadowColor="transparent";ctx.fillStyle="rgba(0,0,0,0.2)";ctx.fillRect(0,-1,area[2],2)}ctx.shadowColor="transparent";node2.onDrawBackground?.(ctx);if(render_title||title_mode==TitleMode.TRANSPARENT_TITLE){node2.drawTitleBarBackground(ctx,{scale:this.ds.scale,low_quality});node2.drawTitleBox(ctx,{scale:this.ds.scale,low_quality,box_size:10});ctx.globalAlpha=old_alpha;node2.drawTitleText(ctx,{scale:this.ds.scale,default_title_color:this.node_title_color,low_quality});node2.onDrawTitle?.(ctx)}for(const getStyle of Object.values(node2.strokeStyles)){const strokeStyle=getStyle.call(node2);if(strokeStyle){strokeShape(ctx,area,{shape,title_height,title_mode,collapsed,...strokeStyle})}}node2.drawProgressBar(ctx);if(node2.execute_triggered!=null&&node2.execute_triggered>0)node2.execute_triggered--;if(node2.action_triggered!=null&&node2.action_triggered>0)node2.action_triggered--}drawSnapGuide(ctx,item,shape=RenderShape.ROUND){const snapGuide=LGraphCanvas.#temp;snapGuide.set(item.boundingRect);const{pos}=item;const offsetX=pos[0]-snapGuide[0];const offsetY=pos[1]-snapGuide[1];snapGuide[0]+=offsetX;snapGuide[1]+=offsetY;if(this.#snapToGrid)snapPoint(snapGuide,this.#snapToGrid);snapGuide[0]-=offsetX;snapGuide[1]-=offsetY;const{globalAlpha}=ctx;ctx.globalAlpha=1;ctx.beginPath();const[x2,y,w,h]=snapGuide;if(shape===RenderShape.CIRCLE){const midX=x2+w*.5;const midY=y+h*.5;const radius=Math.min(w*.5,h*.5);ctx.arc(midX,midY,radius,0,Math.PI*2)}else{ctx.rect(x2,y,w,h)}ctx.lineWidth=.5;ctx.strokeStyle="#FFFFFF66";ctx.fillStyle="#FFFFFF22";ctx.fill();ctx.stroke();ctx.globalAlpha=globalAlpha}drawConnections(ctx){this.renderedPaths.clear();if(this.links_render_mode===LinkRenderType.HIDDEN_LINK)return;const{graph,subgraph}=this;if(!graph)throw new NullGraphError;const visibleReroutes=[];const now=LiteGraph.getTime();const{visible_area}=this;LGraphCanvas.#margin_area[0]=visible_area[0]-20;LGraphCanvas.#margin_area[1]=visible_area[1]-20;LGraphCanvas.#margin_area[2]=visible_area[2]+40;LGraphCanvas.#margin_area[3]=visible_area[3]+40;ctx.lineWidth=this.connections_width;ctx.fillStyle="#AAA";ctx.strokeStyle="#AAA";ctx.globalAlpha=this.editor_alpha;const nodes=graph._nodes;for(const node2 of nodes){const{inputs}=node2;if(!inputs?.length)continue;for(const[i,input]of inputs.entries()){if(!input||input.link==null)continue;const link_id=input.link;const link=graph._links.get(link_id);if(!link)continue;const endPos=node2.getInputPos(i);const start_node=graph.getNodeById(link.origin_id);if(start_node==null)continue;const outputId=link.origin_slot;const startPos=outputId===-1?[start_node.pos[0]+10,start_node.pos[1]+10]:start_node.getOutputPos(outputId);const output=start_node.outputs[outputId];if(!output)continue;this.#renderAllLinkSegments(ctx,link,startPos,endPos,visibleReroutes,now,output.dir,input.dir)}}if(subgraph){for(const output of subgraph.inputNode.slots){if(!output.linkIds.length)continue;for(const linkId of output.linkIds){const resolved=LLink.resolve(linkId,graph);if(!resolved)continue;const{link,inputNode,input}=resolved;if(!inputNode||!input)continue;const endPos=inputNode.getInputPos(link.target_slot);this.#renderAllLinkSegments(ctx,link,output.pos,endPos,visibleReroutes,now,input.dir,input.dir)}}for(const input of subgraph.outputNode.slots){if(!input.linkIds.length)continue;const resolved=LLink.resolve(input.linkIds[0],graph);if(!resolved)continue;const{link,outputNode,output}=resolved;if(!outputNode||!output)continue;const startPos=outputNode.getOutputPos(link.origin_slot);this.#renderAllLinkSegments(ctx,link,startPos,input.pos,visibleReroutes,now,output.dir,input.dir)}}if(graph.floatingLinks.size>0){this.#renderFloatingLinks(ctx,graph,visibleReroutes,now)}const rerouteSet=this.#visibleReroutes;rerouteSet.clear();visibleReroutes.sort((a,b)=>a.linkIds.size-b.linkIds.size);for(const reroute of visibleReroutes){rerouteSet.add(reroute);if(this.#snapToGrid&&this.isDragging&&this.selectedItems.has(reroute)){this.drawSnapGuide(ctx,reroute,RenderShape.CIRCLE)}reroute.draw(ctx,this._pattern);if(!this.pointer.isDown)reroute.drawSlots(ctx)}ctx.globalAlpha=1}#renderFloatingLinks(ctx,graph,visibleReroutes,now){const{globalAlpha}=ctx;ctx.globalAlpha=globalAlpha*.33;for(const link of graph.floatingLinks.values()){const reroutes=LLink.getReroutes(graph,link);const firstReroute=reroutes[0];const reroute=reroutes.at(-1);if(!firstReroute||!reroute?.floating)continue;if(reroute.floating.slotType==="input"){const node2=graph.getNodeById(link.target_id);if(!node2)continue;const startPos=firstReroute.pos;const endPos=node2.getInputPos(link.target_slot);const endDirection=node2.inputs[link.target_slot]?.dir;firstReroute._dragging=true;this.#renderAllLinkSegments(ctx,link,startPos,endPos,visibleReroutes,now,LinkDirection.CENTER,endDirection,true)}else{const node2=graph.getNodeById(link.origin_id);if(!node2)continue;const startPos=node2.getOutputPos(link.origin_slot);const endPos=reroute.pos;const startDirection=node2.outputs[link.origin_slot]?.dir;link._dragging=true;this.#renderAllLinkSegments(ctx,link,startPos,endPos,visibleReroutes,now,startDirection,LinkDirection.CENTER,true)}}ctx.globalAlpha=globalAlpha}#renderAllLinkSegments(ctx,link,startPos,endPos,visibleReroutes,now,startDirection,endDirection,disabled=false){const{graph,renderedPaths}=this;if(!graph)return;const reroutes=LLink.getReroutes(graph,link);const points=[startPos,...reroutes.map(x2=>x2.pos),endPos];const pointsX=points.map(x2=>x2[0]);const pointsY=points.map(x2=>x2[1]);LGraphCanvas.#link_bounding[0]=Math.min(...pointsX);LGraphCanvas.#link_bounding[1]=Math.min(...pointsY);LGraphCanvas.#link_bounding[2]=Math.max(...pointsX)-LGraphCanvas.#link_bounding[0];LGraphCanvas.#link_bounding[3]=Math.max(...pointsY)-LGraphCanvas.#link_bounding[1];if(!overlapBounding(LGraphCanvas.#link_bounding,LGraphCanvas.#margin_area))return;const start_dir=startDirection||LinkDirection.RIGHT;const end_dir=endDirection||LinkDirection.LEFT;if(reroutes.length){let startControl;const l=reroutes.length;for(let j=0;j<l;j++){const reroute=reroutes[j];if(!renderedPaths.has(reroute)){renderedPaths.add(reroute);visibleReroutes.push(reroute);reroute._colour=link.color||LGraphCanvas.link_type_colors[link.type]||this.default_link_color;const prevReroute=graph.getReroute(reroute.parentId);const rerouteStartPos=prevReroute?.pos??startPos;reroute.calculateAngle(this.last_draw_time,graph,rerouteStartPos);if(!reroute._dragging){this.renderLink(ctx,rerouteStartPos,reroute.pos,link,false,0,null,startControl===void 0?start_dir:LinkDirection.CENTER,LinkDirection.CENTER,{startControl,endControl:reroute.controlPoint,reroute,disabled})}}if(!startControl&&reroutes.at(-1)?.floating?.slotType==="input"){startControl=[0,0]}else{const nextPos=reroutes[j+1]?.pos??endPos;const dist=Math.min(Reroute.maxSplineOffset,distance(reroute.pos,nextPos)*.25);startControl=[dist*reroute.cos,dist*reroute.sin]}}if(link._dragging)return;const segmentStartPos=points.at(-2)??startPos;this.renderLink(ctx,segmentStartPos,endPos,link,false,0,null,LinkDirection.CENTER,end_dir,{startControl,disabled})}else if(!link._dragging){this.renderLink(ctx,startPos,endPos,link,false,0,null,start_dir,end_dir)}renderedPaths.add(link);if(link?._last_time&&now-link._last_time<1e3){const f=2-(now-link._last_time)*.002;const tmp=ctx.globalAlpha;ctx.globalAlpha=tmp*f;this.renderLink(ctx,startPos,endPos,link,true,f,"white",start_dir,end_dir);ctx.globalAlpha=tmp}}renderLink(ctx,a,b,link,skip_border,flow,color,start_dir,end_dir,{startControl,endControl,reroute,num_sublines=1,disabled=false}={}){const linkColour=link!=null&&this.highlighted_links[link.id]?"#FFF":color||link?.color||link?.type!=null&&LGraphCanvas.link_type_colors[link.type]||this.default_link_color;const startDir=start_dir||LinkDirection.RIGHT;const endDir=end_dir||LinkDirection.LEFT;const dist=this.links_render_mode==LinkRenderType.SPLINE_LINK&&(!endControl||!startControl)?distance(a,b):0;if(this.render_connections_border&&!this.low_quality){ctx.lineWidth=this.connections_width+4}ctx.lineJoin="round";num_sublines||=1;if(num_sublines>1)ctx.lineWidth=.5;const path=new Path2D;const linkSegment=reroute??link;if(linkSegment)linkSegment.path=path;const innerA=LGraphCanvas.#lTempA;const innerB=LGraphCanvas.#lTempB;const pos=linkSegment?._pos??[0,0];for(let i=0;i<num_sublines;i++){const offsety=(i-(num_sublines-1)*.5)*5;innerA[0]=a[0];innerA[1]=a[1];innerB[0]=b[0];innerB[1]=b[1];if(this.links_render_mode==LinkRenderType.SPLINE_LINK){if(endControl){innerB[0]=b[0]+endControl[0];innerB[1]=b[1]+endControl[1]}else{this.#addSplineOffset(innerB,endDir,dist)}if(startControl){innerA[0]=a[0]+startControl[0];innerA[1]=a[1]+startControl[1]}else{this.#addSplineOffset(innerA,startDir,dist)}path.moveTo(a[0],a[1]+offsety);path.bezierCurveTo(innerA[0],innerA[1]+offsety,innerB[0],innerB[1]+offsety,b[0],b[1]+offsety);findPointOnCurve(pos,a,b,innerA,innerB,.5);if(linkSegment&&this.linkMarkerShape===LinkMarkerShape.Arrow){const justPastCentre=LGraphCanvas.#lTempC;findPointOnCurve(justPastCentre,a,b,innerA,innerB,.51);linkSegment._centreAngle=Math.atan2(justPastCentre[1]-pos[1],justPastCentre[0]-pos[0])}}else{const l=this.links_render_mode==LinkRenderType.LINEAR_LINK?15:10;switch(startDir){case LinkDirection.LEFT:innerA[0]+=-l;break;case LinkDirection.RIGHT:innerA[0]+=l;break;case LinkDirection.UP:innerA[1]+=-l;break;case LinkDirection.DOWN:innerA[1]+=l;break}switch(endDir){case LinkDirection.LEFT:innerB[0]+=-l;break;case LinkDirection.RIGHT:innerB[0]+=l;break;case LinkDirection.UP:innerB[1]+=-l;break;case LinkDirection.DOWN:innerB[1]+=l;break}if(this.links_render_mode==LinkRenderType.LINEAR_LINK){path.moveTo(a[0],a[1]+offsety);path.lineTo(innerA[0],innerA[1]+offsety);path.lineTo(innerB[0],innerB[1]+offsety);path.lineTo(b[0],b[1]+offsety);pos[0]=(innerA[0]+innerB[0])*.5;pos[1]=(innerA[1]+innerB[1])*.5;if(linkSegment&&this.linkMarkerShape===LinkMarkerShape.Arrow){linkSegment._centreAngle=Math.atan2(innerB[1]-innerA[1],innerB[0]-innerA[0])}}else if(this.links_render_mode==LinkRenderType.STRAIGHT_LINK){const midX=(innerA[0]+innerB[0])*.5;path.moveTo(a[0],a[1]);path.lineTo(innerA[0],innerA[1]);path.lineTo(midX,innerA[1]);path.lineTo(midX,innerB[1]);path.lineTo(innerB[0],innerB[1]);path.lineTo(b[0],b[1]);pos[0]=midX;pos[1]=(innerA[1]+innerB[1])*.5;if(linkSegment&&this.linkMarkerShape===LinkMarkerShape.Arrow){const diff=innerB[1]-innerA[1];if(Math.abs(diff)<4)linkSegment._centreAngle=0;else if(diff>0)linkSegment._centreAngle=Math.PI*.5;else linkSegment._centreAngle=-(Math.PI*.5)}}else{return}}}if(this.render_connections_border&&!this.low_quality&&!skip_border){ctx.strokeStyle="rgba(0,0,0,0.5)";ctx.stroke(path)}ctx.lineWidth=this.connections_width;ctx.fillStyle=ctx.strokeStyle=linkColour;ctx.stroke(path);if(this.ds.scale>=.6&&this.highquality_render&&linkSegment){if(this.render_connection_arrows){const posA=this.computeConnectionPoint(a,b,.25,startDir,endDir);const posB=this.computeConnectionPoint(a,b,.26,startDir,endDir);const posC=this.computeConnectionPoint(a,b,.75,startDir,endDir);const posD=this.computeConnectionPoint(a,b,.76,startDir,endDir);let angleA=0;let angleB=0;if(this.render_curved_connections){angleA=-Math.atan2(posB[0]-posA[0],posB[1]-posA[1]);angleB=-Math.atan2(posD[0]-posC[0],posD[1]-posC[1])}else{angleB=angleA=b[1]>a[1]?0:Math.PI}const transform=ctx.getTransform();ctx.translate(posA[0],posA[1]);ctx.rotate(angleA);ctx.beginPath();ctx.moveTo(-5,-3);ctx.lineTo(0,7);ctx.lineTo(5,-3);ctx.fill();ctx.setTransform(transform);ctx.translate(posC[0],posC[1]);ctx.rotate(angleB);ctx.beginPath();ctx.moveTo(-5,-3);ctx.lineTo(0,7);ctx.lineTo(5,-3);ctx.fill();ctx.setTransform(transform)}ctx.beginPath();if(this.linkMarkerShape===LinkMarkerShape.Arrow){const transform=ctx.getTransform();ctx.translate(pos[0],pos[1]);if(linkSegment._centreAngle)ctx.rotate(linkSegment._centreAngle);ctx.moveTo(-3.2,-5);ctx.lineTo(7,0);ctx.lineTo(-3.2,5);ctx.setTransform(transform)}else if(this.linkMarkerShape==null||this.linkMarkerShape===LinkMarkerShape.Circle){ctx.arc(pos[0],pos[1],5,0,Math.PI*2)}if(disabled){const{fillStyle,globalAlpha}=ctx;ctx.fillStyle=this._pattern??"#797979";ctx.globalAlpha=.75;ctx.fill();ctx.globalAlpha=globalAlpha;ctx.fillStyle=fillStyle}ctx.fill();if(LLink._drawDebug){const{fillStyle,font,globalAlpha,lineWidth,strokeStyle}=ctx;ctx.globalAlpha=1;ctx.lineWidth=4;ctx.fillStyle="white";ctx.strokeStyle="black";ctx.font="16px Arial";const text=String(linkSegment.id);const{width:width2,actualBoundingBoxAscent}=ctx.measureText(text);const x2=pos[0]-width2*.5;const y=pos[1]+actualBoundingBoxAscent*.5;ctx.strokeText(text,x2,y);ctx.fillText(text,x2,y);ctx.font=font;ctx.globalAlpha=globalAlpha;ctx.lineWidth=lineWidth;ctx.fillStyle=fillStyle;ctx.strokeStyle=strokeStyle}}if(flow){ctx.fillStyle=linkColour;for(let i=0;i<5;++i){const f=(LiteGraph.getTime()*.001+i*.2)%1;const flowPos=this.computeConnectionPoint(a,b,f,startDir,endDir);ctx.beginPath();ctx.arc(flowPos[0],flowPos[1],5,0,2*Math.PI);ctx.fill()}}}computeConnectionPoint(a,b,t,start_dir,end_dir){start_dir||=LinkDirection.RIGHT;end_dir||=LinkDirection.LEFT;const dist=distance(a,b);const pa=[a[0],a[1]];const pb=[b[0],b[1]];this.#addSplineOffset(pa,start_dir,dist);this.#addSplineOffset(pb,end_dir,dist);const c1=(1-t)*(1-t)*(1-t);const c2=3*((1-t)*(1-t))*t;const c3=3*(1-t)*(t*t);const c4=t*t*t;const x2=c1*a[0]+c2*pa[0]+c3*pb[0]+c4*b[0];const y=c1*a[1]+c2*pa[1]+c3*pb[1]+c4*b[1];return[x2,y]}#addSplineOffset(point,direction,dist,factor=.25){switch(direction){case LinkDirection.LEFT:point[0]+=dist*-factor;break;case LinkDirection.RIGHT:point[0]+=dist*factor;break;case LinkDirection.UP:point[1]+=dist*-factor;break;case LinkDirection.DOWN:point[1]+=dist*factor;break}}drawExecutionOrder(ctx){ctx.shadowColor="transparent";ctx.globalAlpha=.25;ctx.textAlign="center";ctx.strokeStyle="white";ctx.globalAlpha=.75;const{visible_nodes}=this;for(const node2 of visible_nodes){ctx.fillStyle="black";ctx.fillRect(node2.pos[0]-LiteGraph.NODE_TITLE_HEIGHT,node2.pos[1]-LiteGraph.NODE_TITLE_HEIGHT,LiteGraph.NODE_TITLE_HEIGHT,LiteGraph.NODE_TITLE_HEIGHT);if(node2.order==0){ctx.strokeRect(node2.pos[0]-LiteGraph.NODE_TITLE_HEIGHT+.5,node2.pos[1]-LiteGraph.NODE_TITLE_HEIGHT+.5,LiteGraph.NODE_TITLE_HEIGHT,LiteGraph.NODE_TITLE_HEIGHT)}ctx.fillStyle="#FFF";ctx.fillText(stringOrEmpty(node2.order),node2.pos[0]+LiteGraph.NODE_TITLE_HEIGHT*-.5,node2.pos[1]-6)}ctx.globalAlpha=1}drawNodeWidgets(node2,_posY,ctx){node2.drawWidgets(ctx,{lowQuality:this.low_quality,editorAlpha:this.editor_alpha})}drawGroups(canvas2,ctx){if(!this.graph)return;const groups=this.graph._groups;ctx.save();ctx.globalAlpha=.5*this.editor_alpha;const drawSnapGuides=this.#snapToGrid&&this.isDragging;for(const group of groups){if(!overlapBounding(this.visible_area,group._bounding)){continue}if(drawSnapGuides&&this.selectedItems.has(group))this.drawSnapGuide(ctx,group);group.draw(this,ctx)}ctx.restore()}resize(width2,height){if(!width2&&!height){const parent=this.canvas.parentElement;if(!parent)throw new TypeError("Attempted to resize canvas, but parent element was null.");width2=parent.offsetWidth;height=parent.offsetHeight}if(this.canvas.width==width2&&this.canvas.height==height)return;this.canvas.width=width2??0;this.canvas.height=height??0;this.bgcanvas.width=this.canvas.width;this.bgcanvas.height=this.canvas.height;this.setDirty(true,true)}onNodeSelectionChange(){}boundaryNodesForSelection(){return LGraphCanvas.getBoundaryNodes(this.selected_nodes)}showLinkMenu(segment,e2){const{graph}=this;if(!graph)throw new NullGraphError;const title="data"in segment&&segment.data!=null?segment.data.constructor.name:void 0;const{origin_id,origin_slot}=segment;if(origin_id==null||origin_slot==null){new LiteGraph.ContextMenu(["Link has no origin"],{event:e2,title});return false}const node_left=graph.getNodeById(origin_id);const fromType=node_left?.outputs?.[origin_slot]?.type;const options=["Add Node","Add Reroute",null,"Delete",null];const menu=new LiteGraph.ContextMenu(options,{event:e2,title,callback:inner_clicked.bind(this)});return false;function inner_clicked(v2,options2,e22){if(!graph)throw new NullGraphError;switch(v2){case"Add Node":LGraphCanvas.onMenuAdd(null,null,e22,menu,node2=>{if(!node2?.inputs?.length||!node2?.outputs?.length||origin_slot==null)return;const options3={afterRerouteId:segment.parentId};if(node_left?.connectByType(origin_slot,node2,fromType??"*",options3)){node2.pos[0]-=node2.size[0]*.5}});break;case"Add Reroute":{try{this.emitBeforeChange();this.adjustMouseEvent(e22);graph.createReroute(segment._pos,segment);this.setDirty(false,true)}catch(error){console.error(error)}finally{this.emitAfterChange()}break}case"Delete":graph.removeLink(segment.id);break}}}createDefaultNodeForSlot(optPass){const opts=Object.assign({nodeFrom:null,slotFrom:null,nodeTo:null,slotTo:null,position:[0,0],nodeType:void 0,posAdd:[0,0],posSizeFix:[0,0]},optPass);const{afterRerouteId}=opts;const isFrom=opts.nodeFrom&&opts.slotFrom!==null;const isTo=!isFrom&&opts.nodeTo&&opts.slotTo!==null;if(!isFrom&&!isTo){console.warn(`No data passed to createDefaultNodeForSlot`,opts.nodeFrom,opts.slotFrom,opts.nodeTo,opts.slotTo);return false}if(!opts.nodeType){console.warn("No type to createDefaultNodeForSlot");return false}const nodeX=isFrom?opts.nodeFrom:opts.nodeTo;if(!nodeX)throw new TypeError("nodeX was null when creating default node for slot.");let slotX=isFrom?opts.slotFrom:opts.slotTo;let iSlotConn=false;if(nodeX instanceof SubgraphIONodeBase){if(typeof slotX!=="object"||!slotX){console.warn("Cant get slot information",slotX);return false}const{name}=slotX;iSlotConn=nodeX.slots.findIndex(s=>s.name===name);slotX=nodeX.slots[iSlotConn];if(!slotX){console.warn("Cant get slot information",slotX);return false}}else{switch(typeof slotX){case"string":iSlotConn=isFrom?nodeX.findOutputSlot(slotX,false):nodeX.findInputSlot(slotX,false);slotX=isFrom?nodeX.outputs[slotX]:nodeX.inputs[slotX];break;case"object":if(slotX===null){console.warn("Cant get slot information",slotX);return false}iSlotConn=isFrom?nodeX.findOutputSlot(slotX.name):nodeX.findInputSlot(slotX.name);break;case"number":iSlotConn=slotX;slotX=isFrom?nodeX.outputs[slotX]:nodeX.inputs[slotX];break;case"undefined":default:console.warn("Cant get slot information",slotX);return false}}const fromSlotType=slotX.type==LiteGraph.EVENT?"_event_":slotX.type;const slotTypesDefault=isFrom?LiteGraph.slot_types_default_out:LiteGraph.slot_types_default_in;if(slotTypesDefault?.[fromSlotType]){let nodeNewType=false;if(typeof slotTypesDefault[fromSlotType]=="object"){for(const typeX in slotTypesDefault[fromSlotType]){if(opts.nodeType==slotTypesDefault[fromSlotType][typeX]||opts.nodeType=="AUTO"){nodeNewType=slotTypesDefault[fromSlotType][typeX];break}}}else if(opts.nodeType==slotTypesDefault[fromSlotType]||opts.nodeType=="AUTO"){nodeNewType=slotTypesDefault[fromSlotType]}if(nodeNewType){let nodeNewOpts=false;if(typeof nodeNewType=="object"&&nodeNewType.node){nodeNewOpts=nodeNewType;nodeNewType=nodeNewType.node}const newNode=LiteGraph.createNode(nodeNewType);if(newNode){if(nodeNewOpts){if(nodeNewOpts.properties){for(const i in nodeNewOpts.properties){newNode.addProperty(i,nodeNewOpts.properties[i])}}if(nodeNewOpts.inputs){newNode.inputs=[];for(const i in nodeNewOpts.inputs){newNode.addOutput(nodeNewOpts.inputs[i][0],nodeNewOpts.inputs[i][1])}}if(nodeNewOpts.outputs){newNode.outputs=[];for(const i in nodeNewOpts.outputs){newNode.addOutput(nodeNewOpts.outputs[i][0],nodeNewOpts.outputs[i][1])}}if(nodeNewOpts.title){newNode.title=nodeNewOpts.title}if(nodeNewOpts.json){newNode.configure(nodeNewOpts.json)}}if(!this.graph)throw new NullGraphError;this.graph.add(newNode);newNode.pos=[opts.position[0]+opts.posAdd[0]+(opts.posSizeFix[0]?opts.posSizeFix[0]*newNode.size[0]:0),opts.position[1]+opts.posAdd[1]+(opts.posSizeFix[1]?opts.posSizeFix[1]*newNode.size[1]:0)];const detail={node:newNode,opts};const mayConnectLinks=this.canvas.dispatchEvent(new CustomEvent("connect-new-default-node",{detail,cancelable:true}));if(!mayConnectLinks)return true;if(isFrom){if(!opts.nodeFrom)throw new TypeError("createDefaultNodeForSlot - nodeFrom was null");opts.nodeFrom.connectByType(iSlotConn,newNode,fromSlotType,{afterRerouteId})}else{if(!opts.nodeTo)throw new TypeError("createDefaultNodeForSlot - nodeTo was null");opts.nodeTo.connectByTypeOutput(iSlotConn,newNode,fromSlotType,{afterRerouteId})}return true}console.log(`failed creating ${nodeNewType}`)}}return false}showConnectionMenu(optPass){const opts=Object.assign({nodeFrom:null,slotFrom:null,nodeTo:null,slotTo:null,e:void 0,allow_searchbox:this.allow_searchbox,showSearchBox:this.showSearchBox},optPass||{});const dirty=()=>this.#dirty();const that=this;const{graph}=this;const{afterRerouteId}=opts;const isFrom=opts.nodeFrom&&opts.slotFrom;const isTo=!isFrom&&opts.nodeTo&&opts.slotTo;if(!isFrom&&!isTo){console.warn("No data passed to showConnectionMenu");return}const nodeX=isFrom?opts.nodeFrom:opts.nodeTo;if(!nodeX)throw new TypeError("nodeX was null when creating default node for slot.");let slotX=isFrom?opts.slotFrom:opts.slotTo;let iSlotConn;if(nodeX instanceof SubgraphIONodeBase){if(typeof slotX!=="object"||!slotX){console.warn("Cant get slot information",slotX);return}const{name}=slotX;iSlotConn=nodeX.slots.findIndex(s=>s.name===name);if(iSlotConn!==-1){slotX=nodeX.slots[iSlotConn]}if(!slotX){console.warn("Cant get slot information",slotX);return}}else{switch(typeof slotX){case"string":iSlotConn=isFrom?nodeX.findOutputSlot(slotX,false):nodeX.findInputSlot(slotX,false);slotX=isFrom?nodeX.outputs[slotX]:nodeX.inputs[slotX];break;case"object":if(slotX===null){console.warn("Cant get slot information",slotX);return}iSlotConn=isFrom?nodeX.findOutputSlot(slotX.name):nodeX.findInputSlot(slotX.name);break;case"number":iSlotConn=slotX;slotX=isFrom?nodeX.outputs[slotX]:nodeX.inputs[slotX];break;default:console.warn("Cant get slot information",slotX);return}}const options=["Add Node","Add Reroute",null];if(opts.allow_searchbox){options.push("Search",null)}const fromSlotType=slotX.type==LiteGraph.EVENT?"_event_":slotX.type;const slotTypesDefault=isFrom?LiteGraph.slot_types_default_out:LiteGraph.slot_types_default_in;if(slotTypesDefault?.[fromSlotType]){if(typeof slotTypesDefault[fromSlotType]=="object"){for(const typeX in slotTypesDefault[fromSlotType]){options.push(slotTypesDefault[fromSlotType][typeX])}}else{options.push(slotTypesDefault[fromSlotType])}}const menu=new LiteGraph.ContextMenu(options,{event:opts.e,extra:slotX,title:(slotX&&slotX.name!=""?slotX.name+(fromSlotType?" | ":""):"")+(slotX&&fromSlotType?fromSlotType:""),callback:inner_clicked});return menu;function inner_clicked(v2,options2,e2){switch(v2){case"Add Node":LGraphCanvas.onMenuAdd(null,null,e2,menu,function(node2){if(!node2)return;if(isFrom){if(!opts.nodeFrom)throw new TypeError("Cannot add node to SubgraphInputNode: nodeFrom was null");const slot=opts.nodeFrom.connectByType(iSlotConn,node2,fromSlotType,{afterRerouteId});if(!slot)console.warn("Failed to make new connection.")}else{if(!opts.nodeTo)throw new TypeError("Cannot add node to SubgraphInputNode: nodeTo was null");opts.nodeTo.connectByTypeOutput(iSlotConn,node2,fromSlotType,{afterRerouteId})}});break;case"Add Reroute":{const node2=isFrom?opts.nodeFrom:opts.nodeTo;const slot=options2.extra;if(!graph)throw new NullGraphError;if(!node2)throw new TypeError("Cannot add reroute: node was null");if(!slot)throw new TypeError("Cannot add reroute: slot was null");if(!opts.e)throw new TypeError("Cannot add reroute: CanvasPointerEvent was null");if(node2 instanceof SubgraphIONodeBase){throw new TypeError("Cannot add floating reroute to Subgraph IO Nodes")}else{const reroute=node2.connectFloatingReroute([opts.e.canvasX,opts.e.canvasY],slot,afterRerouteId);if(!reroute)throw new Error("Failed to create reroute")}dirty();break}case"Search":if(isFrom){opts.showSearchBox(e2,{node_from:opts.nodeFrom,slot_from:slotX,type_filter_in:fromSlotType})}else{opts.showSearchBox(e2,{node_to:opts.nodeTo,slot_from:slotX,type_filter_out:fromSlotType})}break;default:{const customProps={position:[opts.e?.canvasX??0,opts.e?.canvasY??0],nodeType:v2,afterRerouteId};const options3=Object.assign(opts,customProps);if(!that.createDefaultNodeForSlot(options3))break}}}}prompt(title,value,callback,event,multiline){const that=this;title=title||"";const customProperties={is_modified:false,className:"graphdialog rounded",innerHTML:multiline?"<span class='name'></span> <textarea autofocus class='value'></textarea><button class='rounded'>OK</button>":"<span class='name'></span> <input autofocus type='text' class='value'/><button class='rounded'>OK</button>",close(){that.prompt_box=null;if(dialog.parentNode){dialog.remove()}}};const div=document.createElement("div");const dialog=Object.assign(div,customProperties);const graphcanvas=LGraphCanvas.active_canvas;const{canvas:canvas2}=graphcanvas;if(!canvas2.parentNode)throw new TypeError("canvas element parentNode was null when opening a prompt.");canvas2.parentNode.append(dialog);if(this.ds.scale>1)dialog.style.transform=`scale(${this.ds.scale})`;let dialogCloseTimer;let prevent_timeout=0;LiteGraph.pointerListenerAdd(dialog,"leave",function(){if(prevent_timeout)return;if(LiteGraph.dialog_close_on_mouse_leave){if(!dialog.is_modified&&LiteGraph.dialog_close_on_mouse_leave){dialogCloseTimer=setTimeout(dialog.close,LiteGraph.dialog_close_on_mouse_leave_delay)}}});LiteGraph.pointerListenerAdd(dialog,"enter",function(){if(LiteGraph.dialog_close_on_mouse_leave&&dialogCloseTimer)clearTimeout(dialogCloseTimer)});const selInDia=dialog.querySelectorAll("select");if(selInDia){for(const selIn of selInDia){selIn.addEventListener("click",function(){prevent_timeout++});selIn.addEventListener("blur",function(){prevent_timeout=0});selIn.addEventListener("change",function(){prevent_timeout=-1})}}this.prompt_box?.close();this.prompt_box=dialog;const name_element=dialog.querySelector(".name");if(!name_element)throw new TypeError("name_element was null");name_element.textContent=title;const value_element=dialog.querySelector(".value");if(!value_element)throw new TypeError("value_element was null");value_element.value=value;value_element.select();const input=value_element;input.addEventListener("keydown",function(e2){dialog.is_modified=true;if(e2.key=="Escape"){dialog.close()}else if(e2.key=="Enter"&&e2.target.localName!="textarea"){if(callback){callback(this.value)}dialog.close()}else{return}e2.preventDefault();e2.stopPropagation()});const button=dialog.querySelector("button");if(!button)throw new TypeError("button was null when opening prompt");button.addEventListener("click",function(){callback?.(input.value);that.setDirty(true);dialog.close()});const rect=canvas2.getBoundingClientRect();let offsetx=-20;let offsety=-20;if(rect){offsetx-=rect.left;offsety-=rect.top}if(event){dialog.style.left=`${event.clientX+offsetx}px`;dialog.style.top=`${event.clientY+offsety}px`}else{dialog.style.left=`${canvas2.width*.5+offsetx}px`;dialog.style.top=`${canvas2.height*.5+offsety}px`}setTimeout(function(){input.focus();const clickTime=Date.now();function handleOutsideClick(e2){if(e2.target===canvas2&&Date.now()-clickTime>256){dialog.close();canvas2.parentElement?.removeEventListener("click",handleOutsideClick);canvas2.parentElement?.removeEventListener("touchend",handleOutsideClick)}}canvas2.parentElement?.addEventListener("click",handleOutsideClick);canvas2.parentElement?.addEventListener("touchend",handleOutsideClick)},10);return dialog}showSearchBox(event,searchOptions){const options={slot_from:null,node_from:null,node_to:null,do_type_filter:LiteGraph.search_filter_enabled,type_filter_in:false,type_filter_out:false,show_general_if_none_on_typefilter:true,show_general_after_typefiltered:true,hide_on_mouse_leave:LiteGraph.search_hide_on_mouse_leave,show_all_if_empty:true,show_all_on_open:LiteGraph.search_show_all_on_open};Object.assign(options,searchOptions);const that=this;const graphcanvas=LGraphCanvas.active_canvas;const{canvas:canvas2}=graphcanvas;const root_document=canvas2.ownerDocument||document;const div=document.createElement("div");const dialog=Object.assign(div,{close(){that.search_box=void 0;this.blur();canvas2.focus();root_document.body.style.overflow="";setTimeout(()=>canvas2.focus(),20);dialog.remove()}});dialog.className="litegraph litesearchbox graphdialog rounded";dialog.innerHTML="<span class='name'>Search</span> <input autofocus type='text' class='value rounded'/>";if(options.do_type_filter){dialog.innerHTML+="<select class='slot_in_type_filter'><option value=''></option></select>";dialog.innerHTML+="<select class='slot_out_type_filter'><option value=''></option></select>"}const helper=document.createElement("div");helper.className="helper";dialog.append(helper);if(root_document.fullscreenElement){root_document.fullscreenElement.append(dialog)}else{root_document.body.append(dialog);root_document.body.style.overflow="hidden"}let selIn;let selOut;if(options.do_type_filter){selIn=dialog.querySelector(".slot_in_type_filter");selOut=dialog.querySelector(".slot_out_type_filter")}if(this.ds.scale>1){dialog.style.transform=`scale(${this.ds.scale})`}if(options.hide_on_mouse_leave){let prevent_timeout=false;let timeout_close=null;LiteGraph.pointerListenerAdd(dialog,"enter",function(){if(timeout_close){clearTimeout(timeout_close);timeout_close=null}});dialog.addEventListener("pointerleave",function(){if(prevent_timeout)return;const hideDelay=options.hide_on_mouse_leave;const delay=typeof hideDelay==="number"?hideDelay:500;timeout_close=setTimeout(dialog.close,delay)});if(options.do_type_filter){if(!selIn)throw new TypeError("selIn was null when showing search box");if(!selOut)throw new TypeError("selOut was null when showing search box");selIn.addEventListener("click",function(){prevent_timeout++});selIn.addEventListener("blur",function(){prevent_timeout=0});selIn.addEventListener("change",function(){prevent_timeout=-1});selOut.addEventListener("click",function(){prevent_timeout++});selOut.addEventListener("blur",function(){prevent_timeout=0});selOut.addEventListener("change",function(){prevent_timeout=-1})}}that.search_box?.close();that.search_box=dialog;let first=null;let timeout=null;let selected=null;const maybeInput=dialog.querySelector("input");if(!maybeInput)throw new TypeError("Could not create search input box.");const input=maybeInput;if(input){input.addEventListener("blur",function(){this.focus()});input.addEventListener("keydown",function(e2){if(e2.key=="ArrowUp"){changeSelection(false)}else if(e2.key=="ArrowDown"){changeSelection(true)}else if(e2.key=="Escape"){dialog.close()}else if(e2.key=="Enter"){if(selected instanceof HTMLElement){select(unescape(String(selected.dataset["type"])))}else if(first){select(first)}else{dialog.close()}}else{if(timeout){clearInterval(timeout)}timeout=setTimeout(refreshHelper,10);return}e2.preventDefault();e2.stopPropagation();e2.stopImmediatePropagation();return true})}if(options.do_type_filter){if(selIn){const aSlots=LiteGraph.slot_types_in;const nSlots=aSlots.length;if(options.type_filter_in==LiteGraph.EVENT||options.type_filter_in==LiteGraph.ACTION){options.type_filter_in="_event_"}for(let iK=0;iK<nSlots;iK++){const opt=document.createElement("option");opt.value=aSlots[iK];opt.innerHTML=aSlots[iK];selIn.append(opt);if(options.type_filter_in!==false&&String(options.type_filter_in).toLowerCase()==String(aSlots[iK]).toLowerCase()){opt.selected=true}}selIn.addEventListener("change",function(){refreshHelper()})}if(selOut){const aSlots=LiteGraph.slot_types_out;if(options.type_filter_out==LiteGraph.EVENT||options.type_filter_out==LiteGraph.ACTION){options.type_filter_out="_event_"}for(const aSlot of aSlots){const opt=document.createElement("option");opt.value=aSlot;opt.innerHTML=aSlot;selOut.append(opt);if(options.type_filter_out!==false&&String(options.type_filter_out).toLowerCase()==String(aSlot).toLowerCase()){opt.selected=true}}selOut.addEventListener("change",function(){refreshHelper()})}}const rect=canvas2.getBoundingClientRect();const left=(event?event.clientX:rect.left+rect.width*.5)-80;const top=(event?event.clientY:rect.top+rect.height*.5)-20;dialog.style.left=`${left}px`;dialog.style.top=`${top}px`;if(event.layerY>rect.height-200){helper.style.maxHeight=`${rect.height-event.layerY-20}px`}requestAnimationFrame(function(){input.focus()});if(options.show_all_on_open)refreshHelper();function select(name){if(name){if(that.onSearchBoxSelection){that.onSearchBoxSelection(name,event,graphcanvas)}else{if(!graphcanvas.graph)throw new NullGraphError;graphcanvas.graph.beforeChange();const node2=LiteGraph.createNode(name);if(node2){node2.pos=graphcanvas.convertEventToCanvasOffset(event);graphcanvas.graph.add(node2,false)}if(options.node_from){let iS=false;switch(typeof options.slot_from){case"string":iS=options.node_from.findOutputSlot(options.slot_from);break;case"object":if(options.slot_from==null)throw new TypeError("options.slot_from was null when showing search box");iS=options.slot_from.name?options.node_from.findOutputSlot(options.slot_from.name):-1;if(iS==-1&&options.slot_from.slot_index!==void 0)iS=options.slot_from.slot_index;break;case"number":iS=options.slot_from;break;default:iS=0}if(options.node_from.outputs[iS]!==void 0){if(iS!==false&&iS>-1){if(node2==null)throw new TypeError("options.slot_from was null when showing search box");options.node_from.connectByType(iS,node2,options.node_from.outputs[iS].type)}}}if(options.node_to){let iS=false;switch(typeof options.slot_from){case"string":iS=options.node_to.findInputSlot(options.slot_from);break;case"object":if(options.slot_from==null)throw new TypeError("options.slot_from was null when showing search box");iS=options.slot_from.name?options.node_to.findInputSlot(options.slot_from.name):-1;if(iS==-1&&options.slot_from.slot_index!==void 0)iS=options.slot_from.slot_index;break;case"number":iS=options.slot_from;break;default:iS=0}if(options.node_to.inputs[iS]!==void 0){if(iS!==false&&iS>-1){if(node2==null)throw new TypeError("options.slot_from was null when showing search box");options.node_to.connectByTypeOutput(iS,node2,options.node_to.inputs[iS].type)}}}graphcanvas.graph.afterChange()}}dialog.close()}function changeSelection(forward){const prev=selected;if(!selected){selected=forward?helper.childNodes[0]:helper.childNodes[helper.childNodes.length]}else if(selected instanceof Element){selected.classList.remove("selected");selected=forward?selected.nextSibling:selected.previousSibling;selected||=prev}if(selected instanceof Element){selected.classList.add("selected");selected.scrollIntoView({block:"end",behavior:"smooth"})}}function refreshHelper(){timeout=null;let str=input.value;first=null;helper.innerHTML="";if(!str&&!options.show_all_if_empty)return;if(that.onSearchBox){const list=that.onSearchBox(helper,str,graphcanvas);if(list){for(const item of list){addResult(item)}}}else{let inner_test_filter=function(type,optsIn){optsIn=optsIn||{};const optsDef={skipFilter:false,inTypeOverride:false,outTypeOverride:false};const opts=Object.assign(optsDef,optsIn);const ctor=LiteGraph.registered_node_types[type];if(filter&&ctor.filter!=filter)return false;if((!options.show_all_if_empty||str)&&!type.toLowerCase().includes(str)&&(!ctor.title||!ctor.title.toLowerCase().includes(str))){return false}if(options.do_type_filter&&!opts.skipFilter){const sType=type;let sV=opts.inTypeOverride!==false?opts.inTypeOverride:sIn.value;if(sIn&&sV&&LiteGraph.registered_slot_in_types[sV]?.nodes){const doesInc=LiteGraph.registered_slot_in_types[sV].nodes.includes(sType);if(doesInc===false)return false}sV=sOut.value;if(opts.outTypeOverride!==false)sV=opts.outTypeOverride;if(sOut&&sV&&LiteGraph.registered_slot_out_types[sV]?.nodes){const doesInc=LiteGraph.registered_slot_out_types[sV].nodes.includes(sType);if(doesInc===false)return false}}return true};let c=0;str=str.toLowerCase();if(!graphcanvas.graph)throw new NullGraphError;const filter=graphcanvas.filter||graphcanvas.graph.filter;let sIn=false;let sOut=false;if(options.do_type_filter&&that.search_box){sIn=that.search_box.querySelector(".slot_in_type_filter");sOut=that.search_box.querySelector(".slot_out_type_filter")}const keys=Object.keys(LiteGraph.registered_node_types);const filtered=keys.filter(x2=>inner_test_filter(x2));for(const item of filtered){addResult(item);if(LGraphCanvas.search_limit!==-1&&c++>LGraphCanvas.search_limit)break}if(options.show_general_after_typefiltered&&(sIn.value||sOut.value)){filtered_extra=[];for(const i in LiteGraph.registered_node_types){if(inner_test_filter(i,{inTypeOverride:sIn&&sIn.value?"*":false,outTypeOverride:sOut&&sOut.value?"*":false})){filtered_extra.push(i)}}for(const extraItem of filtered_extra){addResult(extraItem,"generic_type");if(LGraphCanvas.search_limit!==-1&&c++>LGraphCanvas.search_limit)break}}if((sIn.value||sOut.value)&&helper.childNodes.length==0&&options.show_general_if_none_on_typefilter){filtered_extra=[];for(const i in LiteGraph.registered_node_types){if(inner_test_filter(i,{skipFilter:true}))filtered_extra.push(i)}for(const extraItem of filtered_extra){addResult(extraItem,"not_in_filter");if(LGraphCanvas.search_limit!==-1&&c++>LGraphCanvas.search_limit)break}}}function addResult(type,className){const help=document.createElement("div");first||=type;const nodeType=LiteGraph.registered_node_types[type];if(nodeType?.title){help.textContent=nodeType?.title;const typeEl=document.createElement("span");typeEl.className="litegraph lite-search-item-type";typeEl.textContent=type;help.append(typeEl)}else{help.textContent=type}help.dataset["type"]=escape(type);help.className="litegraph lite-search-item";if(className){help.className+=` ${className}`}help.addEventListener("click",function(){select(unescape(String(this.dataset["type"])))});helper.append(help)}}return dialog}showEditPropertyValue(node2,property,options){if(!node2||node2.properties[property]===void 0)return;options=options||{};const info=node2.getPropertyInfo(property);const{type}=info;let input_html="";if(type=="string"||type=="number"||type=="array"||type=="object"){input_html="<input autofocus type='text' class='value'/>"}else if((type=="enum"||type=="combo")&&info.values){input_html="<select autofocus type='text' class='value'>";for(const i in info.values){const v2=Array.isArray(info.values)?info.values[i]:i;const selected=v2==node2.properties[property]?"selected":"";input_html+=`<option value='${v2}' ${selected}>${info.values[i]}</option>`}input_html+="</select>"}else if(type=="boolean"||type=="toggle"){const checked=node2.properties[property]?"checked":"";input_html=`<input autofocus type='checkbox' class='value' ${checked}/>`}else{console.warn(`unknown type: ${type}`);return}const dialog=this.createDialog(`<span class='name'>${info.label||property}</span>${input_html}<button>OK</button>`,options);let input;if((type=="enum"||type=="combo")&&info.values){input=dialog.querySelector("select");input?.addEventListener("change",function(e2){dialog.modified();setValue(e2.target?.value)})}else if(type=="boolean"||type=="toggle"){input=dialog.querySelector("input");input?.addEventListener("click",function(){dialog.modified();setValue(!!input.checked)})}else{input=dialog.querySelector("input");if(input){input.addEventListener("blur",function(){this.focus()});let v2=node2.properties[property]!==void 0?node2.properties[property]:"";if(type!=="string"){v2=JSON.stringify(v2)}input.value=v2;input.addEventListener("keydown",function(e2){if(e2.key=="Escape"){dialog.close()}else if(e2.key=="Enter"){inner()}else{dialog.modified();return}e2.preventDefault();e2.stopPropagation()})}}input?.focus();const button=dialog.querySelector("button");if(!button)throw new TypeError("Show edit property value button was null.");button.addEventListener("click",inner);function inner(){setValue(input?.value)}const dirty=()=>this.#dirty();function setValue(value){if(info?.values&&typeof info.values==="object"&&info.values[value]!=void 0){value=info.values[value]}if(typeof node2.properties[property]=="number"){value=Number(value)}if(type=="array"||type=="object"){value=JSON.parse(value)}node2.properties[property]=value;if(node2.graph){node2.graph._version++}node2.onPropertyChanged?.(property,value);options.onclose?.();dialog.close();dirty()}return dialog}createDialog(html,options){const def_options={checkForInput:false,closeOnLeave:true,closeOnLeave_checkModified:true};options=Object.assign(def_options,options||{});const customProperties={className:"graphdialog",innerHTML:html,is_modified:false,modified(){this.is_modified=true},close(){this.remove()}};const div=document.createElement("div");const dialog=Object.assign(div,customProperties);const rect=this.canvas.getBoundingClientRect();let offsetx=-20;let offsety=-20;if(rect){offsetx-=rect.left;offsety-=rect.top}if(options.position){offsetx+=options.position[0];offsety+=options.position[1]}else if(options.event){offsetx+=options.event.clientX;offsety+=options.event.clientY}else{offsetx+=this.canvas.width*.5;offsety+=this.canvas.height*.5}dialog.style.left=`${offsetx}px`;dialog.style.top=`${offsety}px`;if(!this.canvas.parentNode)throw new TypeError("Canvas parent element was null.");this.canvas.parentNode.append(dialog);if(options.checkForInput){const aI=dialog.querySelectorAll("input");if(aI){for(const iX of aI){iX.addEventListener("keydown",function(e2){dialog.modified();if(e2.key=="Escape"){dialog.close()}else if(e2.key!="Enter"){return}e2.preventDefault();e2.stopPropagation()});iX.focus()}}}let dialogCloseTimer;let prevent_timeout=0;dialog.addEventListener("mouseleave",function(){if(prevent_timeout)return;if(!dialog.is_modified&&LiteGraph.dialog_close_on_mouse_leave){dialogCloseTimer=setTimeout(dialog.close,LiteGraph.dialog_close_on_mouse_leave_delay)}});dialog.addEventListener("mouseenter",function(){if(options.closeOnLeave||LiteGraph.dialog_close_on_mouse_leave){if(dialogCloseTimer)clearTimeout(dialogCloseTimer)}});const selInDia=dialog.querySelectorAll("select");if(selInDia){for(const selIn of selInDia){selIn.addEventListener("click",function(){prevent_timeout++});selIn.addEventListener("blur",function(){prevent_timeout=0});selIn.addEventListener("change",function(){prevent_timeout=-1})}}return dialog}createPanel(title,options){options=options||{};const ref_window=options.window||window;const root=document.createElement("div");root.className="litegraph dialog";root.innerHTML="<div class='dialog-header'><span class='dialog-title'></span></div><div class='dialog-content'></div><div style='display:none;' class='dialog-alt-content'></div><div class='dialog-footer'></div>";root.header=root.querySelector(".dialog-header");if(options.width)root.style.width=options.width+(typeof options.width==="number"?"px":"");if(options.height)root.style.height=options.height+(typeof options.height==="number"?"px":"");if(options.closable){const close=document.createElement("span");close.innerHTML="✕";close.classList.add("close");close.addEventListener("click",function(){root.close()});root.header.append(close)}root.title_element=root.querySelector(".dialog-title");root.title_element.textContent=title;root.content=root.querySelector(".dialog-content");root.alt_content=root.querySelector(".dialog-alt-content");root.footer=root.querySelector(".dialog-footer");root.close=function(){if(typeof root.onClose=="function")root.onClose();root.remove();this.remove()};root.toggleAltContent=function(force){let vTo;let vAlt;if(force!==void 0){vTo=force?"block":"none";vAlt=force?"none":"block"}else{vTo=root.alt_content.style.display!="block"?"block":"none";vAlt=root.alt_content.style.display!="block"?"none":"block"}root.alt_content.style.display=vTo;root.content.style.display=vAlt};root.toggleFooterVisibility=function(force){let vTo;if(force!==void 0){vTo=force?"block":"none"}else{vTo=root.footer.style.display!="block"?"block":"none"}root.footer.style.display=vTo};root.clear=function(){this.content.innerHTML=""};root.addHTML=function(code,classname,on_footer){const elem=document.createElement("div");if(classname)elem.className=classname;elem.innerHTML=code;if(on_footer)root.footer.append(elem);else root.content.append(elem);return elem};root.addButton=function(name,callback,options2){const elem=document.createElement("button");elem.textContent=name;elem.options=options2;elem.classList.add("btn");elem.addEventListener("click",callback);root.footer.append(elem);return elem};root.addSeparator=function(){const elem=document.createElement("div");elem.className="separator";root.content.append(elem)};root.addWidget=function(type,name,value,options2,callback){options2=options2||{};let str_value=String(value);type=type.toLowerCase();if(type=="number"&&typeof value==="number")str_value=value.toFixed(3);const elem=document.createElement("div");elem.className="property";elem.innerHTML="<span class='property_name'></span><span class='property_value'></span>";const nameSpan=elem.querySelector(".property_name");if(!nameSpan)throw new TypeError("Property name element was null.");nameSpan.textContent=options2.label||name;const value_element=elem.querySelector(".property_value");if(!value_element)throw new TypeError("Property name element was null.");value_element.textContent=str_value;elem.dataset["property"]=name;elem.dataset["type"]=options2.type||type;elem.options=options2;elem.value=value;if(type=="code"){elem.addEventListener("click",function(){root.inner_showCodePad(this.dataset["property"])})}else if(type=="boolean"){elem.classList.add("boolean");if(value)elem.classList.add("bool-on");elem.addEventListener("click",()=>{const propname=elem.dataset["property"];elem.value=!elem.value;elem.classList.toggle("bool-on");if(!value_element)throw new TypeError("Property name element was null.");value_element.textContent=elem.value?"true":"false";innerChange(propname,elem.value)})}else if(type=="string"||type=="number"){if(!value_element)throw new TypeError("Property name element was null.");value_element.setAttribute("contenteditable","true");value_element.addEventListener("keydown",function(e2){if(e2.code=="Enter"&&(type!="string"||!e2.shiftKey)){e2.preventDefault();this.blur()}});value_element.addEventListener("blur",function(){let v2=this.textContent;const propname=this.parentElement?.dataset["property"];const proptype=this.parentElement?.dataset["type"];if(proptype=="number")v2=Number(v2);innerChange(propname,v2)})}else if(type=="enum"||type=="combo"){const str_value2=LGraphCanvas.getPropertyPrintableValue(value,options2.values);if(!value_element)throw new TypeError("Property name element was null.");value_element.textContent=str_value2??"";value_element.addEventListener("click",function(event){const values=options2.values||[];const propname=this.parentElement?.dataset["property"];const inner_clicked=v2=>{this.textContent=v2;innerChange(propname,v2);return false};new LiteGraph.ContextMenu(values,{event,className:"dark",callback:inner_clicked},ref_window)})}root.content.append(elem);function innerChange(name2,value2){options2.callback?.(name2,value2,options2);callback?.(name2,value2,options2)}return elem};if(typeof root.onOpen=="function")root.onOpen();return root}closePanels(){document.querySelector("#node-panel")?.close?.();document.querySelector("#option-panel")?.close?.()}showShowNodePanel(node2){this.SELECTED_NODE=node2;this.closePanels();const ref_window=this.getCanvasWindow();const panel=this.createPanel(node2.title||"",{closable:true,window:ref_window,onOpen:()=>{this.NODEPANEL_IS_OPEN=true},onClose:()=>{this.NODEPANEL_IS_OPEN=false;this.node_panel=null}});this.node_panel=panel;panel.id="node-panel";panel.node=node2;panel.classList.add("settings");const inner_refresh=()=>{panel.content.innerHTML="";panel.addHTML(`<span class='node_type'>${node2.type}</span><span class='node_desc'>${node2.constructor.desc||""}</span><span class='separator'></span>`);panel.addHTML("<h3>Properties</h3>");const fUpdate=(name,value)=>{if(!this.graph)throw new NullGraphError;this.graph.beforeChange(node2);switch(name){case"Title":if(typeof value!=="string")throw new TypeError("Attempting to set title to non-string value.");node2.title=value;break;case"Mode":{if(typeof value!=="string")throw new TypeError("Attempting to set mode to non-string value.");const kV=Object.values(LiteGraph.NODE_MODES).indexOf(value);if(kV!==-1&&LiteGraph.NODE_MODES[kV]){node2.changeMode(kV)}else{console.warn(`unexpected mode: ${value}`)}break}case"Color":if(typeof value!=="string")throw new TypeError("Attempting to set colour to non-string value.");if(LGraphCanvas.node_colors[value]){node2.color=LGraphCanvas.node_colors[value].color;node2.bgcolor=LGraphCanvas.node_colors[value].bgcolor}else{console.warn(`unexpected color: ${value}`)}break;default:node2.setProperty(name,value);break}this.graph.afterChange();this.dirty_canvas=true};panel.addWidget("string","Title",node2.title,{},fUpdate);const mode=node2.mode==null?void 0:LiteGraph.NODE_MODES[node2.mode];panel.addWidget("combo","Mode",mode,{values:LiteGraph.NODE_MODES},fUpdate);const nodeCol=node2.color!==void 0?Object.keys(LGraphCanvas.node_colors).filter(function(nK){return LGraphCanvas.node_colors[nK].color==node2.color}):"";panel.addWidget("combo","Color",nodeCol,{values:Object.keys(LGraphCanvas.node_colors)},fUpdate);for(const pName in node2.properties){const value=node2.properties[pName];const info=node2.getPropertyInfo(pName);if(node2.onAddPropertyToPanel?.(pName,panel))continue;panel.addWidget(info.widget||info.type,pName,value,info,fUpdate)}panel.addSeparator();node2.onShowCustomPanelInfo?.(panel);panel.footer.innerHTML="";panel.addButton("Delete",function(){if(node2.block_delete)return;if(!node2.graph)throw new NullGraphError;node2.graph.remove(node2);panel.close()}).classList.add("delete")};panel.inner_showCodePad=function(propname){panel.classList.remove("settings");panel.classList.add("centered");panel.alt_content.innerHTML="<textarea class='code'></textarea>";const textarea=panel.alt_content.querySelector("textarea");const fDoneWith=function(){panel.toggleAltContent(false);panel.toggleFooterVisibility(true);textarea.remove();panel.classList.add("settings");panel.classList.remove("centered");inner_refresh()};textarea.value=String(node2.properties[propname]);textarea.addEventListener("keydown",function(e2){if(e2.code=="Enter"&&e2.ctrlKey){node2.setProperty(propname,textarea.value);fDoneWith()}});panel.toggleAltContent(true);panel.toggleFooterVisibility(false);textarea.style.height="calc(100% - 40px)";const assign=panel.addButton("Assign",function(){node2.setProperty(propname,textarea.value);fDoneWith()});panel.alt_content.append(assign);const button=panel.addButton("Close",fDoneWith);button.style.float="right";panel.alt_content.append(button)};inner_refresh();if(!this.canvas.parentNode)throw new TypeError("showNodePanel - this.canvas.parentNode was null");this.canvas.parentNode.append(panel)}checkPanels(){if(!this.canvas)return;if(!this.canvas.parentNode)throw new TypeError("checkPanels - this.canvas.parentNode was null");const panels=this.canvas.parentNode.querySelectorAll(".litegraph.dialog");for(const panel of panels){if(!panel.node)continue;if(!panel.node.graph||panel.graph!=this.graph)panel.close()}}getCanvasMenuOptions(){let options;if(this.getMenuOptions){options=this.getMenuOptions()}else{options=[{content:"Add Node",has_submenu:true,callback:LGraphCanvas.onMenuAdd},{content:"Add Group",callback:LGraphCanvas.onGroupAdd}];if(Object.keys(this.selected_nodes).length>1){options.push({content:"Convert to Subgraph 🆕",callback:()=>{if(!this.selectedItems.size)throw new Error("Convert to Subgraph: Nothing selected.");this._graph.convertToSubgraph(this.selectedItems)}},{content:"Align",has_submenu:true,callback:LGraphCanvas.onGroupAlign})}}const extra=this.getExtraMenuOptions?.(this,options);return Array.isArray(extra)?options.concat(extra):options}getNodeMenuOptions(node2){let options;if(node2.getMenuOptions){options=node2.getMenuOptions(this)}else{options=[{content:"Inputs",has_submenu:true,disabled:true},{content:"Outputs",has_submenu:true,disabled:true,callback:LGraphCanvas.showMenuNodeOptionalOutputs},null,{content:"Convert to Subgraph 🆕",callback:()=>{if(!this.selectedItems.size)throw new Error("Convert to Subgraph: Nothing selected.");this._graph.convertToSubgraph(this.selectedItems)}},{content:"Properties",has_submenu:true,callback:LGraphCanvas.onShowMenuNodeProperties},{content:"Properties Panel",callback:function(item,options2,e2,menu,node22){LGraphCanvas.active_canvas.showShowNodePanel(node22)}},null,{content:"Title",callback:LGraphCanvas.onShowPropertyEditor},{content:"Mode",has_submenu:true,callback:LGraphCanvas.onMenuNodeMode}];if(node2.resizable!==false){options.push({content:"Resize",callback:LGraphCanvas.onMenuResizeNode})}if(node2.collapsible){options.push({content:node2.collapsed?"Expand":"Collapse",callback:LGraphCanvas.onMenuNodeCollapse})}if(node2.widgets?.some(w=>w.advanced)){options.push({content:node2.showAdvanced?"Hide Advanced":"Show Advanced",callback:LGraphCanvas.onMenuToggleAdvanced})}options.push({content:node2.pinned?"Unpin":"Pin",callback:()=>{for(const i in this.selected_nodes){const node22=this.selected_nodes[i];node22.pin()}this.setDirty(true,true)}},{content:"Colors",has_submenu:true,callback:LGraphCanvas.onMenuNodeColors},{content:"Shapes",has_submenu:true,callback:LGraphCanvas.onMenuNodeShapes},null)}const extra=node2.getExtraMenuOptions?.(this,options);if(Array.isArray(extra)&&extra.length>0){extra.push(null);options=extra.concat(options)}if(node2.clonable!==false){options.push({content:"Clone",callback:LGraphCanvas.onMenuNodeClone})}if(Object.keys(this.selected_nodes).length>1){options.push({content:"Align Selected To",has_submenu:true,callback:LGraphCanvas.onNodeAlign},{content:"Distribute Nodes",has_submenu:true,callback:LGraphCanvas.createDistributeMenu})}options.push(null,{content:"Remove",disabled:!(node2.removable!==false&&!node2.block_delete),callback:LGraphCanvas.onMenuNodeRemove});node2.graph?.onGetNodeMenuOptions?.(options,node2);return options}getGroupMenuOptions(group){console.warn("LGraphCanvas.getGroupMenuOptions is deprecated, use LGraphGroup.getMenuOptions instead");return group.getMenuOptions()}processContextMenu(node2,event){const canvas2=LGraphCanvas.active_canvas;const ref_window=canvas2.getCanvasWindow();let menu_info;const options={event,callback:inner_option_clicked,extra:node2};if(node2){options.title=node2.displayType??node2.type??void 0;LGraphCanvas.active_node=node2;const slot=node2.getSlotInPosition(event.canvasX,event.canvasY);if(slot){menu_info=[];if(node2.getSlotMenuOptions){menu_info=node2.getSlotMenuOptions(slot)}else{if(slot.output?.links?.length||slot.input?.link!=null){menu_info.push({content:"Disconnect Links",slot})}const _slot=slot.input||slot.output;if(!_slot)throw new TypeError("Both in put and output slots were null when processing context menu.");if(_slot.removable){menu_info.push(_slot.locked?"Cannot remove":{content:"Remove Slot",slot})}if(!_slot.nameLocked&&!("link"in _slot&&_slot.widget)){menu_info.push({content:"Rename Slot",slot})}if(node2.getExtraSlotMenuOptions){menu_info.push(...node2.getExtraSlotMenuOptions(slot))}}options.title=(slot.input?slot.input.type:slot.output.type)||"*";if(slot.input&&slot.input.type==LiteGraph.ACTION)options.title="Action";if(slot.output&&slot.output.type==LiteGraph.EVENT)options.title="Event"}else{menu_info=this.getNodeMenuOptions(node2)}}else{menu_info=this.getCanvasMenuOptions();if(!this.graph)throw new NullGraphError;if(this.links_render_mode!==LinkRenderType.HIDDEN_LINK){const reroute=this.graph.getRerouteOnPos(event.canvasX,event.canvasY,this.#visibleReroutes);if(reroute){menu_info.unshift({content:"Delete Reroute",callback:()=>{if(!this.graph)throw new NullGraphError;this.graph.removeReroute(reroute.id)}},null)}}const group=this.graph.getGroupOnPos(event.canvasX,event.canvasY);if(group){menu_info.push(null,{content:"Edit Group",has_submenu:true,submenu:{title:"Group",extra:group,options:group.getMenuOptions()}})}}if(!menu_info)return;new LiteGraph.ContextMenu(menu_info,options,ref_window);const createDialog=options2=>this.createDialog("<span class='name'>Name</span><input autofocus type='text'/><button>OK</button>",options2);const setDirty=()=>this.setDirty(true);function inner_option_clicked(v2,options2){if(!v2)return;if(v2.content=="Remove Slot"){if(!node2?.graph)throw new NullGraphError;const info=v2.slot;if(!info)throw new TypeError("Found-slot info was null when processing context menu.");node2.graph.beforeChange();if(info.input){node2.removeInput(info.slot)}else if(info.output){node2.removeOutput(info.slot)}node2.graph.afterChange();return}else if(v2.content=="Disconnect Links"){if(!node2?.graph)throw new NullGraphError;const info=v2.slot;if(!info)throw new TypeError("Found-slot info was null when processing context menu.");node2.graph.beforeChange();if(info.output){node2.disconnectOutput(info.slot)}else if(info.input){node2.disconnectInput(info.slot,true)}node2.graph.afterChange();return}else if(v2.content=="Rename Slot"){if(!node2)throw new TypeError("`node` was null when processing the context menu.");const info=v2.slot;if(!info)throw new TypeError("Found-slot info was null when processing context menu.");const slot_info=info.input?node2.getInputInfo(info.slot):node2.getOutputInfo(info.slot);const dialog=createDialog(options2);const input=dialog.querySelector("input");if(input&&slot_info){input.value=slot_info.label||""}const inner=function(){if(!node2.graph)throw new NullGraphError;node2.graph.beforeChange();if(input?.value){if(slot_info){slot_info.label=input.value}setDirty()}dialog.close();node2.graph.afterChange()};dialog.querySelector("button")?.addEventListener("click",inner);if(!input)throw new TypeError("Input element was null when processing context menu.");input.addEventListener("keydown",function(e2){dialog.is_modified=true;if(e2.key=="Escape"){dialog.close()}else if(e2.key=="Enter"){inner()}else if(e2.target.localName!="textarea"){return}e2.preventDefault();e2.stopPropagation()});input.focus()}}}animateToBounds(bounds,options={}){const setDirty=()=>this.setDirty(true,true);this.ds.animateToBounds(bounds,setDirty,options)}fitViewToSelectionAnimated(options={}){const items=this.selectedItems.size?Array.from(this.selectedItems):this.positionableItems;const bounds=createBounds(items);if(!bounds)throw new TypeError("Attempted to fit to view but could not calculate bounds.");const setDirty=()=>this.setDirty(true,true);this.ds.animateToBounds(bounds,setDirty,options)}}class MapProxyHandler{getOwnPropertyDescriptor(target,p){const value=this.get(target,p);if(value){return{configurable:true,enumerable:true,value}}}has(target,p){if(typeof p==="symbol")return false;const int=parseInt(p,10);return target.has(!isNaN(int)?int:p)}ownKeys(target){return[...target.keys()].map(String)}get(target,p){if(p in target)return Reflect.get(target,p,target);if(typeof p==="symbol")return;const int=parseInt(p,10);return target.get(!isNaN(int)?int:p)}set(target,p,newValue2){if(typeof p==="symbol")return false;const int=parseInt(p,10);target.set(!isNaN(int)?int:p,newValue2);return true}deleteProperty(target,p){return target.delete(p)}static bindAllMethods(map){map.clear=map.clear.bind(map);map.delete=map.delete.bind(map);map.forEach=map.forEach.bind(map);map.get=map.get.bind(map);map.has=map.has.bind(map);map.set=map.set.bind(map);map.entries=map.entries.bind(map);map.keys=map.keys.bind(map);map.values=map.values.bind(map);map[Symbol.iterator]=map[Symbol.iterator].bind(map)}}class LGraph{static serialisedSchemaVersion=1;static STATUS_STOPPED=1;static STATUS_RUNNING=2;static ConfigureProperties=new Set(["nodes","groups","links","state","reroutes","floatingLinks","id","subgraphs","definitions","inputs","outputs","widgets","inputNode","outputNode","extra"]);id=zeroUuid;revision=0;_version=-1;_links=new Map;links;list_of_graphcanvas;status=LGraph.STATUS_STOPPED;state={lastGroupId:0,lastNodeId:0,lastLinkId:0,lastRerouteId:0};events=new CustomEventTarget;_subgraphs=new Map;_nodes=[];_nodes_by_id={};_nodes_in_order=[];_nodes_executable=null;_groups=[];iteration=0;globaltime=0;runningtime=0;fixedtime=0;fixedtime_lapse=.01;elapsed_time=.01;last_update_time=0;starttime=0;catch_errors=true;execution_timer_id;errors_in_execution;execution_time;_last_trigger_time;filter;config={};vars={};nodes_executing=[];nodes_actioning=[];nodes_executedAction=[];extra={};version;get empty(){return this._nodes.length+this._groups.length+this.reroutes.size===0}*positionableItems(){for(const node2 of this._nodes)yield node2;for(const group of this._groups)yield group;for(const reroute of this.reroutes.values())yield reroute;return}#lastFloatingLinkId=0;#floatingLinks=new Map;get floatingLinks(){return this.#floatingLinks}#reroutes=new Map;get reroutes(){return this.#reroutes}get rootGraph(){return this}get isRootGraph(){return this.rootGraph===this}get last_node_id(){return this.state.lastNodeId}set last_node_id(value){this.state.lastNodeId=value}get last_link_id(){return this.state.lastLinkId}set last_link_id(value){this.state.lastLinkId=value}_input_nodes;constructor(o){if(LiteGraph.debug)console.log("Graph created");const links=this._links;MapProxyHandler.bindAllMethods(links);const handler=new MapProxyHandler;this.links=new Proxy(links,handler);this.list_of_graphcanvas=null;this.clear();if(o)this.configure(o)}clear(){this.stop();this.status=LGraph.STATUS_STOPPED;this.id=zeroUuid;this.revision=0;this.state={lastGroupId:0,lastNodeId:0,lastLinkId:0,lastRerouteId:0};this._version=-1;this._subgraphs.clear();if(this._nodes){for(const _node of this._nodes){_node.onRemoved?.()}}this._nodes=[];this._nodes_by_id={};this._nodes_in_order=[];this._nodes_executable=null;this._links.clear();this.reroutes.clear();this.#floatingLinks.clear();this.#lastFloatingLinkId=0;this._groups=[];this.iteration=0;this.config={};this.vars={};this.extra={};this.globaltime=0;this.runningtime=0;this.fixedtime=0;this.fixedtime_lapse=.01;this.elapsed_time=.01;this.last_update_time=0;this.starttime=0;this.catch_errors=true;this.nodes_executing=[];this.nodes_actioning=[];this.nodes_executedAction=[];this.change();this.canvasAction(c=>c.clear())}get subgraphs(){return this.rootGraph._subgraphs}get nodes(){return this._nodes}get groups(){return this._groups}attachCanvas(canvas2){if(!(canvas2 instanceof LGraphCanvas)){throw new TypeError("attachCanvas expects an LGraphCanvas instance")}this.primaryCanvas=canvas2;this.list_of_graphcanvas??=[];if(!this.list_of_graphcanvas.includes(canvas2)){this.list_of_graphcanvas.push(canvas2)}if(canvas2.graph===this)return;canvas2.graph?.detachCanvas(canvas2);canvas2.graph=this;canvas2.subgraph=void 0}detachCanvas(canvas2){canvas2.graph=null;const canvases=this.list_of_graphcanvas;if(canvases){const pos=canvases.indexOf(canvas2);if(pos!==-1)canvases.splice(pos,1)}}start(interval){if(this.status==LGraph.STATUS_RUNNING)return;this.status=LGraph.STATUS_RUNNING;this.onPlayEvent?.();this.sendEventToAllNodes("onStart");this.starttime=LiteGraph.getTime();this.last_update_time=this.starttime;interval||=0;if(interval==0&&typeof window!="undefined"&&window.requestAnimationFrame){const on_frame=()=>{if(this.execution_timer_id!=-1)return;window.requestAnimationFrame(on_frame);this.onBeforeStep?.();this.runStep(1,!this.catch_errors);this.onAfterStep?.()};this.execution_timer_id=-1;on_frame()}else{this.execution_timer_id=setInterval(()=>{this.onBeforeStep?.();this.runStep(1,!this.catch_errors);this.onAfterStep?.()},interval)}}stop(){if(this.status==LGraph.STATUS_STOPPED)return;this.status=LGraph.STATUS_STOPPED;this.onStopEvent?.();if(this.execution_timer_id!=null){if(this.execution_timer_id!=-1){clearInterval(this.execution_timer_id)}this.execution_timer_id=null}this.sendEventToAllNodes("onStop")}runStep(num,do_not_catch_errors,limit){num=num||1;const start=LiteGraph.getTime();this.globaltime=.001*(start-this.starttime);const nodes=this._nodes_executable||this._nodes;if(!nodes)return;limit=limit||nodes.length;if(do_not_catch_errors){for(let i=0;i<num;i++){for(let j=0;j<limit;++j){const node2=nodes[j];if(node2.mode==LGraphEventMode.ALWAYS&&node2.onExecute){node2.doExecute?.()}}this.fixedtime+=this.fixedtime_lapse;this.onExecuteStep?.()}this.onAfterExecute?.()}else{try{for(let i=0;i<num;i++){for(let j=0;j<limit;++j){const node2=nodes[j];if(node2.mode==LGraphEventMode.ALWAYS){node2.onExecute?.()}}this.fixedtime+=this.fixedtime_lapse;this.onExecuteStep?.()}this.onAfterExecute?.();this.errors_in_execution=false}catch(error){this.errors_in_execution=true;if(LiteGraph.throw_errors)throw error;if(LiteGraph.debug)console.log("Error during execution:",error);this.stop()}}const now=LiteGraph.getTime();let elapsed=now-start;if(elapsed==0)elapsed=1;this.execution_time=.001*elapsed;this.globaltime+=.001*elapsed;this.iteration+=1;this.elapsed_time=(now-this.last_update_time)*.001;this.last_update_time=now;this.nodes_executing=[];this.nodes_actioning=[];this.nodes_executedAction=[]}updateExecutionOrder(){this._nodes_in_order=this.computeExecutionOrder(false);this._nodes_executable=[];for(const node2 of this._nodes_in_order){if(node2.onExecute){this._nodes_executable.push(node2)}}}computeExecutionOrder(only_onExecute,set_level){const L=[];const S=[];const M={};const visited_links={};const remaining_links={};for(const node2 of this._nodes){if(only_onExecute&&!node2.onExecute){continue}M[node2.id]=node2;let num=0;if(node2.inputs){for(const input of node2.inputs){if(input?.link!=null){num+=1}}}if(num==0){S.push(node2);if(set_level)node2._level=1}else{if(set_level)node2._level=0;remaining_links[node2.id]=num}}while(true){const node2=S.shift();if(node2===void 0)break;L.push(node2);delete M[node2.id];if(!node2.outputs)continue;for(const output of node2.outputs){if(output?.links==null||output.links.length==0)continue;for(const link_id of output.links){const link=this._links.get(link_id);if(!link)continue;if(visited_links[link.id])continue;const target_node=this.getNodeById(link.target_id);if(target_node==null){visited_links[link.id]=true;continue}if(set_level){node2._level??=0;if(!target_node._level||target_node._level<=node2._level){target_node._level=node2._level+1}}visited_links[link.id]=true;remaining_links[target_node.id]-=1;if(remaining_links[target_node.id]==0)S.push(target_node)}}}for(const i in M){L.push(M[i])}if(L.length!=this._nodes.length&&LiteGraph.debug)console.warn("something went wrong, nodes missing");function setOrder(nodes){const l=nodes.length;for(let i=0;i<l;++i){nodes[i].order=i}}setOrder(L);L.sort(function(A,B){const Ap=A.constructor.priority||A.priority||0;const Bp=B.constructor.priority||B.priority||0;return Ap==Bp?A.order-B.order:Ap-Bp});setOrder(L);return L}arrange(margin,layout){margin=margin||100;const nodes=this.computeExecutionOrder(false,true);const columns=[];for(const node2 of nodes){const col=node2._level||1;columns[col]||=[];columns[col].push(node2)}let x2=margin;for(const column of columns){if(!column)continue;let max_size=100;let y=margin+LiteGraph.NODE_TITLE_HEIGHT;for(const node2 of column){node2.pos[0]=layout==LiteGraph.VERTICAL_LAYOUT?y:x2;node2.pos[1]=layout==LiteGraph.VERTICAL_LAYOUT?x2:y;const max_size_index=layout==LiteGraph.VERTICAL_LAYOUT?1:0;if(node2.size[max_size_index]>max_size){max_size=node2.size[max_size_index]}const node_size_index=layout==LiteGraph.VERTICAL_LAYOUT?0:1;y+=node2.size[node_size_index]+margin+LiteGraph.NODE_TITLE_HEIGHT}x2+=max_size+margin}this.setDirtyCanvas(true,true)}getTime(){return this.globaltime}getFixedTime(){return this.fixedtime}getElapsedTime(){return this.elapsed_time}sendEventToAllNodes(eventname,params,mode){mode=mode||LGraphEventMode.ALWAYS;const nodes=this._nodes_in_order||this._nodes;if(!nodes)return;for(const node2 of nodes){if(!node2[eventname]||node2.mode!=mode)continue;if(params===void 0){node2[eventname]()}else if(params&¶ms.constructor===Array){node2[eventname].apply(node2,params)}else{node2[eventname](params)}}}canvasAction(action){const canvases=this.list_of_graphcanvas;if(!canvases)return;for(const canvas2 of canvases)action(canvas2)}sendActionToCanvas(action,params){const{list_of_graphcanvas}=this;if(!list_of_graphcanvas)return;for(const c of list_of_graphcanvas){c[action]?.apply(c,params)}}add(node2,skip_compute_order){if(!node2)return;const{state}=this;if(LiteGraph.alwaysSnapToGrid){const snapTo=this.getSnapToGridSize();if(snapTo)node2.snapToGrid(snapTo)}if(node2 instanceof LGraphGroup){if(node2.id==null||node2.id===-1)node2.id=++state.lastGroupId;if(node2.id>state.lastGroupId)state.lastGroupId=node2.id;this._groups.push(node2);this.setDirtyCanvas(true);this.change();node2.graph=this;this._version++;return}if(node2.id!=-1&&this._nodes_by_id[node2.id]!=null){console.warn("LiteGraph: there is already a node with this ID, changing it");node2.id=LiteGraph.use_uuids?LiteGraph.uuidv4():++state.lastNodeId}if(this._nodes.length>=LiteGraph.MAX_NUMBER_OF_NODES){throw"LiteGraph: max number of nodes in a graph reached"}if(LiteGraph.use_uuids){if(node2.id==null||node2.id==-1)node2.id=LiteGraph.uuidv4()}else{if(node2.id==null||node2.id==-1){node2.id=++state.lastNodeId}else if(typeof node2.id==="number"&&state.lastNodeId<node2.id){state.lastNodeId=node2.id}}node2.graph=this;this._version++;this._nodes.push(node2);this._nodes_by_id[node2.id]=node2;node2.onAdded?.(this);if(this.config.align_to_grid)node2.alignToGrid();if(!skip_compute_order)this.updateExecutionOrder();this.onNodeAdded?.(node2);this.setDirtyCanvas(true);this.change();return node2}remove(node2){if(node2 instanceof LGraphGroup){this.canvasAction(c=>c.deselect(node2));const index=this._groups.indexOf(node2);if(index!=-1){this._groups.splice(index,1)}node2.graph=void 0;this._version++;this.setDirtyCanvas(true,true);this.change();return}if(this._nodes_by_id[node2.id]==null){console.warn("LiteGraph: node not found",node2);return}if(node2.ignore_remove){console.warn("LiteGraph: node cannot be removed",node2);return}this.beforeChange();const{inputs,outputs}=node2;if(inputs){for(const[i,slot]of inputs.entries()){if(slot.link!=null)node2.disconnectInput(i,true)}}if(outputs){for(const[i,slot]of outputs.entries()){if(slot.links?.length)node2.disconnectOutput(i)}}for(const link of this.floatingLinks.values()){if(link.origin_id===node2.id||link.target_id===node2.id){this.removeFloatingLink(link)}}node2.onRemoved?.();node2.graph=null;this._version++;const{list_of_graphcanvas}=this;if(list_of_graphcanvas){for(const canvas2 of list_of_graphcanvas){if(canvas2.selected_nodes[node2.id])delete canvas2.selected_nodes[node2.id];canvas2.deselect(node2)}}const pos=this._nodes.indexOf(node2);if(pos!=-1)this._nodes.splice(pos,1);delete this._nodes_by_id[node2.id];this.onNodeRemoved?.(node2);this.canvasAction(c=>c.checkPanels());this.setDirtyCanvas(true,true);this.afterChange();this.change();this.updateExecutionOrder()}getNodeById(id){return id!=null?this._nodes_by_id[id]:null}findNodesByClass(classObject,result){result=result||[];result.length=0;const{_nodes}=this;for(const node2 of _nodes){if(node2.constructor===classObject)result.push(node2)}return result}findNodesByType(type,result){const matchType=type.toLowerCase();result=result||[];result.length=0;const{_nodes}=this;for(const node2 of _nodes){if(node2.type?.toLowerCase()==matchType)result.push(node2)}return result}findNodeByTitle(title){const{_nodes}=this;for(const node2 of _nodes){if(node2.title==title)return node2}return null}findNodesByTitle(title){const result=[];const{_nodes}=this;for(const node2 of _nodes){if(node2.title==title)result.push(node2)}return result}getNodeOnPos(x2,y,nodeList){const nodes=nodeList||this._nodes;let i=nodes.length;while(--i>=0){const node2=nodes[i];if(node2.isPointInside(x2,y))return node2}return null}getGroupOnPos(x2,y){return this._groups.toReversed().find(g=>g.isPointInside(x2,y))}getGroupTitlebarOnPos(x2,y){return this._groups.toReversed().find(g=>g.isPointInTitlebar(x2,y))}getRerouteOnPos(x2,y,reroutes){for(const reroute of reroutes??this.reroutes.values()){if(reroute.containsPoint([x2,y]))return reroute}}snapToGrid(items){const snapTo=this.getSnapToGridSize();if(!snapTo)return;for(const item of getAllNestedItems(items)){if(!item.pinned)item.snapToGrid(snapTo)}}getSnapToGridSize(){return LiteGraph.alwaysSnapToGrid?LiteGraph.CANVAS_GRID_SIZE||1:LiteGraph.CANVAS_GRID_SIZE}checkNodeTypes(){const{_nodes}=this;for(const[i,node2]of _nodes.entries()){const ctor=LiteGraph.registered_node_types[node2.type];if(node2.constructor==ctor)continue;console.log("node being replaced by newer version:",node2.type);const newnode=LiteGraph.createNode(node2.type);if(!newnode)continue;_nodes[i]=newnode;newnode.configure(node2.serialize());newnode.graph=this;this._nodes_by_id[newnode.id]=newnode;if(node2.inputs)newnode.inputs=[...node2.inputs];if(node2.outputs)newnode.outputs=[...node2.outputs]}this.updateExecutionOrder()}trigger(action,param){this.onTrigger?.(action,param)}triggerInput(name,value){const nodes=this.findNodesByTitle(name);for(const node2 of nodes){node2.onTrigger(value)}}setCallback(name,func){const nodes=this.findNodesByTitle(name);for(const node2 of nodes){node2.setTrigger(func)}}beforeChange(info){this.onBeforeChange?.(this,info);this.canvasAction(c=>c.onBeforeChange?.(this))}afterChange(info){this.onAfterChange?.(this,info);this.canvasAction(c=>c.onAfterChange?.(this))}clearTriggeredSlots(){for(const link_info of this._links.values()){if(!link_info)continue;if(link_info._last_time)link_info._last_time=0}}change(){if(LiteGraph.debug){console.log("Graph changed")}this.canvasAction(c=>c.setDirty(true,true));this.on_change?.(this)}setDirtyCanvas(fg,bg){this.canvasAction(c=>c.setDirty(fg,bg))}addFloatingLink(link){if(link.id===-1){link.id=++this.#lastFloatingLinkId}this.#floatingLinks.set(link.id,link);const slot=link.target_id!==-1?this.getNodeById(link.target_id)?.inputs?.[link.target_slot]:this.getNodeById(link.origin_id)?.outputs?.[link.origin_slot];if(slot){slot._floatingLinks??=new Set;slot._floatingLinks.add(link)}else{console.warn(`Adding invalid floating link: target/slot: [${link.target_id}/${link.target_slot}] origin/slot: [${link.origin_id}/${link.origin_slot}]`)}const reroutes=LLink.getReroutes(this,link);for(const reroute of reroutes){reroute.floatingLinkIds.add(link.id)}return link}removeFloatingLink(link){this.#floatingLinks.delete(link.id);const slot=link.target_id!==-1?this.getNodeById(link.target_id)?.inputs?.[link.target_slot]:this.getNodeById(link.origin_id)?.outputs?.[link.origin_slot];if(slot){slot._floatingLinks?.delete(link)}const reroutes=LLink.getReroutes(this,link);for(const reroute of reroutes){reroute.floatingLinkIds.delete(link.id);if(reroute.floatingLinkIds.size===0){delete reroute.floating}if(reroute.totalLinks===0)this.removeReroute(reroute.id)}}getLink(id){return id==null?void 0:this._links.get(id)}getReroute(id){return id==null?void 0:this.reroutes.get(id)}setReroute({id,parentId,pos,linkIds,floating}){id??=++this.state.lastRerouteId;if(id>this.state.lastRerouteId)this.state.lastRerouteId=id;const reroute=this.reroutes.get(id)??new Reroute(id,this);reroute.update(parentId,pos,linkIds,floating);this.reroutes.set(id,reroute);return reroute}createReroute(pos,before){const rerouteId=++this.state.lastRerouteId;const linkIds=before instanceof Reroute?before.linkIds:[before.id];const floatingLinkIds=before instanceof Reroute?before.floatingLinkIds:[before.id];const reroute=new Reroute(rerouteId,this,pos,before.parentId,linkIds,floatingLinkIds);this.reroutes.set(rerouteId,reroute);for(const linkId of linkIds){const link=this._links.get(linkId);if(!link)continue;if(link.parentId===before.parentId)link.parentId=rerouteId;const reroutes=LLink.getReroutes(this,link);for(const x2 of reroutes.filter(x22=>x22.parentId===before.parentId)){x2.parentId=rerouteId}}for(const linkId of floatingLinkIds){const link=this.floatingLinks.get(linkId);if(!link)continue;if(link.parentId===before.parentId)link.parentId=rerouteId;const reroutes=LLink.getReroutes(this,link);for(const x2 of reroutes.filter(x22=>x22.parentId===before.parentId)){x2.parentId=rerouteId}}return reroute}removeReroute(id){const{reroutes}=this;const reroute=reroutes.get(id);if(!reroute)return;this.canvasAction(c=>c.deselect(reroute));const{parentId,linkIds,floatingLinkIds}=reroute;for(const reroute2 of reroutes.values()){if(reroute2.parentId===id)reroute2.parentId=parentId}for(const linkId of linkIds){const link=this._links.get(linkId);if(link&&link.parentId===id)link.parentId=parentId}for(const linkId of floatingLinkIds){const link=this.floatingLinks.get(linkId);if(!link){console.warn(`Removed reroute had floating link ID that did not exist [${linkId}]`);continue}const floatingReroutes=LLink.getReroutes(this,link);const lastReroute=floatingReroutes.at(-1);const secondLastReroute=floatingReroutes.at(-2);if(reroute!==lastReroute){continue}else if(secondLastReroute?.totalLinks!==1){this.removeFloatingLink(link)}else if(link.parentId===id){link.parentId=parentId;secondLastReroute.floating=reroute.floating}}reroutes.delete(id);this.setDirtyCanvas(false,true)}removeLink(link_id){const link=this._links.get(link_id);if(!link)return;const node2=this.getNodeById(link.target_id);node2?.disconnectInput(link.target_slot,false);link.disconnect(this)}createSubgraph(data){const{id}=data;const subgraph=new Subgraph(this.rootGraph,data);this.subgraphs.set(id,subgraph);this.rootGraph.events.dispatch("subgraph-created",{subgraph,data});return subgraph}convertToSubgraph(items){if(items.size===0)throw new Error("Cannot convert to subgraph: nothing to convert");const{state,revision,config}=this;const{boundaryLinks,boundaryFloatingLinks,internalLinks,boundaryInputLinks,boundaryOutputLinks}=getBoundaryLinks(this,items);const{nodes,reroutes,groups}=splitPositionables(items);const boundingRect=createBounds(items);if(!boundingRect)throw new Error("Failed to create bounding rect for subgraph");const resolvedInputLinks=boundaryInputLinks.map(x2=>x2.resolve(this));const resolvedOutputLinks=boundaryOutputLinks.map(x2=>x2.resolve(this));const clonedNodes=multiClone(nodes);const links=internalLinks.map(x2=>x2.asSerialisable());const inputs=mapSubgraphInputsAndLinks(resolvedInputLinks,links);const outputs=mapSubgraphOutputsAndLinks(resolvedOutputLinks,links);const data={id:createUuidv4(),name:"New Subgraph",inputNode:{id:SUBGRAPH_INPUT_ID,bounding:[0,0,75,100]},outputNode:{id:SUBGRAPH_OUTPUT_ID,bounding:[0,0,75,100]},inputs,outputs,widgets:[],version:LGraph.serialisedSchemaVersion,state,revision,config,links,nodes:clonedNodes,reroutes:structuredClone([...reroutes].map(reroute=>reroute.asSerialisable())),groups:structuredClone([...groups].map(group=>group.serialize()))};const subgraph=this.createSubgraph(data);subgraph.configure(data);subgraph.inputNode.arrange();subgraph.outputNode.arrange();const{boundingRect:inputRect}=subgraph.inputNode;const{boundingRect:outputRect}=subgraph.outputNode;alignOutsideContainer(inputRect,Alignment.MidLeft,boundingRect,[50,0]);alignOutsideContainer(outputRect,Alignment.MidRight,boundingRect,[50,0]);for(const resolved of resolvedInputLinks)resolved.inputNode?.disconnectInput(resolved.inputNode.inputs.indexOf(resolved.input),true);for(const resolved of resolvedOutputLinks)resolved.outputNode?.disconnectOutput(resolved.outputNode.outputs.indexOf(resolved.output),resolved.inputNode);for(const node2 of nodes)this.remove(node2);for(const reroute of reroutes)this.removeReroute(reroute.id);for(const group of groups)this.remove(group);this.rootGraph.events.dispatch("convert-to-subgraph",{subgraph,bounds:boundingRect,exportedSubgraph:data,boundaryLinks,resolvedInputLinks,resolvedOutputLinks,boundaryFloatingLinks,internalLinks});const subgraphNode=LiteGraph.createNode(subgraph.id,subgraph.name,{inputs:structuredClone(inputs),outputs:structuredClone(outputs)});if(!subgraphNode)throw new Error("Failed to create subgraph node");subgraphNode.setSize(subgraphNode.computeSize());alignToContainer(subgraphNode._posSize,Alignment.Centre|Alignment.Middle,boundingRect);this.add(subgraphNode);const groupedByOutput=groupResolvedByOutput(resolvedInputLinks);let i=0;for(const[,connections]of groupedByOutput.entries()){const[firstResolved,...others]=connections;const{output,outputNode,link,subgraphInput}=firstResolved;i++;if(link.origin_id===SUBGRAPH_INPUT_ID){link.target_id=subgraphNode.id;link.target_slot=i-1;if(subgraphInput instanceof SubgraphInput){subgraphInput.connect(subgraphNode.findInputSlotByType(link.type,true,true),subgraphNode,link.parentId)}else{throw new TypeError("Subgraph input node is not a SubgraphInput")}console.debug("Reconnect input links in parent graph",{...link},this.links.get(link.id),this.links.get(link.id)===link);for(const resolved of others){resolved.link.disconnect(this)}continue}if(!output||!outputNode){console.warn("Convert to Subgraph reconnect: Failed to resolve input link",connections[0]);continue}const input=subgraphNode.findInputSlotByType(link.type,true,true);outputNode.connectSlots(output,subgraphNode,input,link.parentId)}const outputsGroupedByOutput=groupResolvedByOutput(resolvedOutputLinks);i=0;for(const[,connections]of outputsGroupedByOutput.entries()){i++;for(const connection of connections){const{input,inputNode,link,subgraphOutput}=connection;if(link.target_id===SUBGRAPH_OUTPUT_ID){link.origin_id=subgraphNode.id;link.origin_slot=i-1;this.links.set(link.id,link);if(subgraphOutput instanceof SubgraphOutput){subgraphOutput.connect(subgraphNode.findOutputSlotByType(link.type,true,true),subgraphNode,link.parentId)}else{throw new TypeError("Subgraph input node is not a SubgraphInput")}continue}if(!input||!inputNode){console.warn("Convert to Subgraph reconnect: Failed to resolve output link",connection);continue}const output=subgraphNode.outputs[i-1];subgraphNode.connectSlots(output,inputNode,input,link.parentId)}}return{subgraph,node:subgraphNode}}resolveSubgraphIdPath(nodeIds){const result=[];let currentGraph=this.rootGraph;for(const nodeId of nodeIds){const node2=currentGraph.getNodeById(nodeId);if(!node2)throw new Error(`Node [${nodeId}] not found. ID Path: ${nodeIds.join(":")}`);if(!node2.isSubgraphNode())throw new Error(`Node [${nodeId}] is not a SubgraphNode. ID Path: ${nodeIds.join(":")}`);result.push(node2);currentGraph=node2.subgraph}return result}serialize(option){const{config,state,groups,nodes,reroutes,extra,floatingLinks,definitions}=this.asSerialisable(option);const linkArray=[...this._links.values()];const links=linkArray.map(x2=>x2.serialize());if(reroutes?.length){extra.linkExtensions=linkArray.filter(x2=>x2.parentId!==void 0).map(x2=>({id:x2.id,parentId:x2.parentId}))}extra.reroutes=reroutes?.length?reroutes:void 0;return{id:this.id,revision:this.revision,last_node_id:state.lastNodeId,last_link_id:state.lastLinkId,nodes,links,floatingLinks,groups,definitions,config,extra,version:LiteGraph.VERSION}}#getDragAndScale(){const ds=this.list_of_graphcanvas?.at(0)?.ds;if(ds)return{scale:ds.scale,offset:ds.offset}}asSerialisable(options){const{id,revision,config,state}=this;const nodeList=!LiteGraph.use_uuids&&options?.sortNodes?[...this._nodes].sort((a,b)=>a.id-b.id):this._nodes;const nodes=nodeList.map(node2=>node2.serialize());const groups=this._groups.map(x2=>x2.serialize());const links=this._links.size?[...this._links.values()].map(x2=>x2.asSerialisable()):void 0;const floatingLinks=this.floatingLinks.size?[...this.floatingLinks.values()].map(x2=>x2.asSerialisable()):void 0;const reroutes=this.reroutes.size?[...this.reroutes.values()].map(x2=>x2.asSerialisable()):void 0;const extra={...this.extra};if(LiteGraph.saveViewportWithGraph)extra.ds=this.#getDragAndScale();if(!extra.ds)delete extra.ds;const data={id,revision,version:LGraph.serialisedSchemaVersion,config,state,groups,nodes,links,floatingLinks,reroutes,extra};if(this.isRootGraph&&this._subgraphs.size){const usedSubgraphIds=findUsedSubgraphIds(this,this._subgraphs);const usedSubgraphs=[...this._subgraphs.values()].filter(subgraph=>usedSubgraphIds.has(subgraph.id)).map(x2=>x2.asSerialisable());if(usedSubgraphs.length>0){data.definitions={subgraphs:usedSubgraphs}}}this.onSerialize?.(data);return data}_configureBase(data){const{id,extra}=data;if(id){this.id=id}else if(this.id===zeroUuid){this.id=createUuidv4()}this.extra=extra?structuredClone(extra):{};delete this.extra.linkExtensions}configure(data,keep_old){const options={data,clearGraph:!keep_old};const mayContinue=this.events.dispatch("configuring",options);if(!mayContinue)return;try{if(!data)return;if(options.clearGraph)this.clear();this._configureBase(data);let reroutes;if(data.version===.4){const{extra}=data;if(Array.isArray(data.links)){for(const linkData of data.links){const link=LLink.createFromArray(linkData);this._links.set(link.id,link)}}if(Array.isArray(extra?.linkExtensions)){for(const linkEx of extra.linkExtensions){const link=this._links.get(linkEx.id);if(link)link.parentId=linkEx.parentId}}reroutes=extra?.reroutes}else{if(data.state){const{lastGroupId,lastLinkId,lastNodeId,lastRerouteId}=data.state;const{state}=this;if(lastGroupId!=null)state.lastGroupId=lastGroupId;if(lastLinkId!=null)state.lastLinkId=lastLinkId;if(lastNodeId!=null)state.lastNodeId=lastNodeId;if(lastRerouteId!=null)state.lastRerouteId=lastRerouteId}if(Array.isArray(data.links)){for(const linkData of data.links){const link=LLink.create(linkData);this._links.set(link.id,link)}}reroutes=data.reroutes}if(Array.isArray(reroutes)){for(const rerouteData of reroutes){this.setReroute(rerouteData)}}const nodesData=data.nodes;for(const i in data){if(LGraph.ConfigureProperties.has(i))continue;this[i]=data[i]}const subgraphs=data.definitions?.subgraphs;if(subgraphs){for(const subgraph of subgraphs)this.createSubgraph(subgraph);for(const subgraph of subgraphs)this.subgraphs.get(subgraph.id)?.configure(subgraph)}let error=false;const nodeDataMap=new Map;this._nodes=[];if(nodesData){for(const n_info of nodesData){let node2=LiteGraph.createNode(String(n_info.type),n_info.title);if(!node2){if(LiteGraph.debug)console.log("Node not found or has errors:",n_info.type);node2=new LGraphNode("");node2.last_serialization=n_info;node2.has_errors=true;error=true}node2.id=n_info.id;this.add(node2,true);nodeDataMap.set(node2.id,n_info)}for(const[id,nodeData]of nodeDataMap){this.getNodeById(id)?.configure(nodeData)}}if(Array.isArray(data.floatingLinks)){for(const linkData of data.floatingLinks){const floatingLink=LLink.create(linkData);this.addFloatingLink(floatingLink);if(floatingLink.id>this.#lastFloatingLinkId)this.#lastFloatingLinkId=floatingLink.id}}for(const reroute of this.reroutes.values()){if(!reroute.validateLinks(this._links,this.floatingLinks)){this.reroutes.delete(reroute.id)}}this._groups.length=0;const groupData=data.groups;if(groupData){for(const data2 of groupData){const group=new LiteGraph.LGraphGroup;group.configure(data2);this.add(group)}}this.updateExecutionOrder();this.onConfigure?.(data);this._version++;const{primaryCanvas}=this;const subgraphId=primaryCanvas?.subgraph?.id;if(subgraphId){const subgraph=this.subgraphs.get(subgraphId);if(subgraph){primaryCanvas.setGraph(subgraph)}else{primaryCanvas.setGraph(this)}}this.setDirtyCanvas(true,true);return error}finally{this.events.dispatch("configured")}}#canvas;get primaryCanvas(){return this.rootGraph.#canvas}set primaryCanvas(canvas2){this.rootGraph.#canvas=canvas2}load(url,callback){const that=this;if(url instanceof Blob||url instanceof File){const reader=new FileReader;reader.addEventListener("load",function(event){const result=stringOrEmpty(event.target?.result);const data=JSON.parse(result);that.configure(data);callback?.()});reader.readAsText(url);return}const req=new XMLHttpRequest;req.open("GET",url,true);req.send(null);req.addEventListener("load",function(){if(req.status!==200){console.error("Error loading graph:",req.status,req.response);return}const data=JSON.parse(req.response);that.configure(data);callback?.()});req.addEventListener("error",err=>{console.error("Error loading graph:",err)})}}class Subgraph extends LGraph{static MAX_NESTED_SUBGRAPHS=1e3;name="Unnamed Subgraph";inputNode=new SubgraphInputNode(this);outputNode=new SubgraphOutputNode(this);inputs=[];outputs=[];widgets=[];#rootGraph;get rootGraph(){return this.#rootGraph}constructor(rootGraph,data){if(!rootGraph)throw new Error("Root graph is required");super();this.#rootGraph=rootGraph;const cloned=structuredClone(data);this._configureBase(cloned);this.#configureSubgraph(cloned)}getIoNodeOnPos(x2,y){const{inputNode,outputNode}=this;if(inputNode.containsPoint([x2,y]))return inputNode;if(outputNode.containsPoint([x2,y]))return outputNode}#configureSubgraph(data){const{name,inputs,outputs,widgets}=data;this.name=name;if(inputs){this.inputs.length=0;for(const input of inputs){const subgraphInput=new SubgraphInput(input,this.inputNode);this.inputs.push(subgraphInput);this.events.dispatch("input-added",{input:subgraphInput})}}if(outputs){this.outputs.length=0;for(const output of outputs){this.outputs.push(new SubgraphOutput(output,this.outputNode))}}if(widgets){this.widgets.length=0;for(const widget of widgets){this.widgets.push(widget)}}this.inputNode.configure(data.inputNode);this.outputNode.configure(data.outputNode)}configure(data,keep_old){const r=super.configure(data,keep_old);this.#configureSubgraph(data);return r}attachCanvas(canvas2){super.attachCanvas(canvas2);canvas2.subgraph=this}addInput(name,type){this.events.dispatch("adding-input",{name,type});const input=new SubgraphInput({id:createUuidv4(),name,type},this.inputNode);this.inputs.push(input);this.events.dispatch("input-added",{input});return input}addOutput(name,type){this.events.dispatch("adding-output",{name,type});const output=new SubgraphOutput({id:createUuidv4(),name,type},this.outputNode);this.outputs.push(output);this.events.dispatch("output-added",{output});return output}renameInput(input,name){const index=this.inputs.indexOf(input);if(index===-1)throw new Error("Input not found");const oldName=input.displayName;this.events.dispatch("renaming-input",{input,index,oldName,newName:name});input.label=name}renameOutput(output,name){const index=this.outputs.indexOf(output);if(index===-1)throw new Error("Output not found");const oldName=output.displayName;this.events.dispatch("renaming-output",{output,index,oldName,newName:name});output.label=name}removeInput(input){input.disconnect();const index=this.inputs.indexOf(input);if(index===-1)throw new Error("Input not found");const mayContinue=this.events.dispatch("removing-input",{input,index});if(!mayContinue)return;this.inputs.splice(index,1);const{length}=this.inputs;for(let i=index;i<length;i++){this.inputs[i].decrementSlots("inputs")}}removeOutput(output){output.disconnect();const index=this.outputs.indexOf(output);if(index===-1)throw new Error("Output not found");const mayContinue=this.events.dispatch("removing-output",{output,index});if(!mayContinue)return;this.outputs.splice(index,1);const{length}=this.outputs;for(let i=index;i<length;i++){this.outputs[i].decrementSlots("outputs")}}draw(ctx,colorContext,fromSlot,editorAlpha){this.inputNode.draw(ctx,colorContext,fromSlot,editorAlpha);this.outputNode.draw(ctx,colorContext,fromSlot,editorAlpha)}clone(keepId=false){const exported=this.asSerialisable();if(!keepId)exported.id=createUuidv4();const subgraph=new Subgraph(this.rootGraph,exported);subgraph.configure(exported);return subgraph}asSerialisable(){return{id:this.id,version:LGraph.serialisedSchemaVersion,state:this.state,revision:this.revision,config:this.config,name:this.name,inputNode:this.inputNode.asSerialisable(),outputNode:this.outputNode.asSerialisable(),inputs:this.inputs.map(x2=>x2.asSerialisable()),outputs:this.outputs.map(x2=>x2.asSerialisable()),widgets:[...this.widgets],nodes:this.nodes.map(node2=>node2.serialize()),groups:this.groups.map(group=>group.serialize()),links:[...this.links.values()].map(x2=>x2.asSerialisable()),extra:this.extra}}}class InputIndicators{constructor(canvas2){this.canvas=canvas2;this.controller=new AbortController;const{signal}=this.controller;const element=canvas2.canvas;const options={capture:true,signal};element.addEventListener("pointerdown",this.#onPointerDownOrMove,options);element.addEventListener("pointermove",this.#onPointerDownOrMove,options);element.addEventListener("pointerup",this.#onPointerUp,options);element.addEventListener("keydown",this.#onKeyDownOrUp,options);document.addEventListener("keyup",this.#onKeyDownOrUp,options);const origDrawFrontCanvas=canvas2.drawFrontCanvas.bind(canvas2);signal.addEventListener("abort",()=>{canvas2.drawFrontCanvas=origDrawFrontCanvas});canvas2.drawFrontCanvas=()=>{origDrawFrontCanvas();this.draw()}}radius=8;startAngle=0;endAngle=Math.PI*2;inactiveColour="#ffffff10";colour1="#ff5f00";colour2="#00ff7c";colour3="#dea7ff";fontString="bold 12px Arial";enabled=true;shiftDown=false;undoDown=false;redoDown=false;ctrlDown=false;altDown=false;mouse0Down=false;mouse1Down=false;mouse2Down=false;x=0;y=0;controller;#onPointerDownOrMove=this.onPointerDownOrMove.bind(this);onPointerDownOrMove(e2){this.mouse0Down=(e2.buttons&1)===1;this.mouse1Down=(e2.buttons&4)===4;this.mouse2Down=(e2.buttons&2)===2;this.x=e2.clientX;this.y=e2.clientY;this.canvas.setDirty(true)}#onPointerUp=this.onPointerUp.bind(this);onPointerUp(){this.mouse0Down=false;this.mouse1Down=false;this.mouse2Down=false}#onKeyDownOrUp=this.onKeyDownOrUp.bind(this);onKeyDownOrUp(e2){this.ctrlDown=e2.ctrlKey;this.altDown=e2.altKey;this.shiftDown=e2.shiftKey;this.undoDown=e2.ctrlKey&&e2.code==="KeyZ"&&e2.type==="keydown";this.redoDown=e2.ctrlKey&&e2.code==="KeyY"&&e2.type==="keydown"}draw(){const{canvas:{ctx},radius,startAngle,endAngle,x:x2,y,inactiveColour,colour1,colour2,colour3,fontString}=this;const{fillStyle,font}=ctx;const mouseDotX=x2;const mouseDotY=y-80;const textX=mouseDotX;const textY=mouseDotY-15;ctx.font=fontString;textMarker(textX+0,textY,"Shift",this.shiftDown?colour1:inactiveColour);textMarker(textX+45,textY+20,"Alt",this.altDown?colour2:inactiveColour);textMarker(textX+30,textY,"Control",this.ctrlDown?colour3:inactiveColour);textMarker(textX-30,textY,"↩️",this.undoDown?"#000":"transparent");textMarker(textX+45,textY,"↪️",this.redoDown?"#000":"transparent");ctx.beginPath();drawDot(mouseDotX,mouseDotY);drawDot(mouseDotX+15,mouseDotY);drawDot(mouseDotX+30,mouseDotY);ctx.fillStyle=inactiveColour;ctx.fill();const leftButtonColour=this.mouse0Down?colour1:inactiveColour;const middleButtonColour=this.mouse1Down?colour2:inactiveColour;const rightButtonColour=this.mouse2Down?colour3:inactiveColour;if(this.mouse0Down)mouseMarker(mouseDotX,mouseDotY,leftButtonColour);if(this.mouse1Down)mouseMarker(mouseDotX+15,mouseDotY,middleButtonColour);if(this.mouse2Down)mouseMarker(mouseDotX+30,mouseDotY,rightButtonColour);ctx.fillStyle=fillStyle;ctx.font=font;function textMarker(x22,y2,text,colour){ctx.fillStyle=colour;ctx.fillText(text,x22,y2)}function mouseMarker(x22,y2,colour){ctx.beginPath();ctx.fillStyle=colour;drawDot(x22,y2);ctx.fill()}function drawDot(x22,y2){ctx.arc(x22,y2,radius,startAngle,endAngle)}}dispose(){this.controller?.abort();this.controller=void 0}[Symbol.dispose](){this.dispose()}}class ContextMenu{options;parentMenu;root;current_submenu;lock;controller=new AbortController;constructor(values,options){options||={};this.options=options;const parent=options.parentMenu;if(parent){if(!(parent instanceof ContextMenu)){console.error("parentMenu must be of class ContextMenu, ignoring it");options.parentMenu=void 0}else{this.parentMenu=parent;this.parentMenu.lock=true;this.parentMenu.current_submenu=this}if(parent.options?.className==="dark"){options.className="dark"}}const eventClass=options.event?options.event.constructor.name:null;if(eventClass!=="MouseEvent"&&eventClass!=="CustomEvent"&&eventClass!=="PointerEvent"){console.error(`Event passed to ContextMenu is not of type MouseEvent or CustomEvent. Ignoring it. (${eventClass})`);options.event=void 0}const root=document.createElement("div");let classes="litegraph litecontextmenu litemenubar-panel";if(options.className)classes+=` ${options.className}`;root.className=classes;root.style.minWidth="100";root.style.minHeight="100";const{signal}=this.controller;const eventOptions={capture:true,signal};if(!this.parentMenu){document.addEventListener("pointerdown",e2=>{if(e2.target instanceof Node&&!this.containsNode(e2.target)){this.close()}},eventOptions)}root.addEventListener("pointerup",e2=>e2.preventDefault(),eventOptions);root.addEventListener("contextmenu",e2=>{if(e2.button===2)e2.preventDefault()},eventOptions);root.addEventListener("pointerdown",e2=>{if(e2.button==2){this.close();e2.preventDefault()}},eventOptions);this.root=root;if(options.title){const element=document.createElement("div");element.className="litemenu-title";element.innerHTML=options.title;root.append(element)}for(let i=0;i<values.length;i++){const value=values[i];let name=Array.isArray(values)?value:String(i);if(typeof name!=="string"){name=name!=null?name.content===void 0?String(name):name.content:name}this.addItem(name,value,options)}const ownerDocument=options.event?.target?.ownerDocument;const root_document=ownerDocument||document;if(root_document.fullscreenElement)root_document.fullscreenElement.append(root);else root_document.body.append(root);let left=options.left||0;let top=options.top||0;if(options.event){left=options.event.clientX-10;top=options.event.clientY-10;if(options.title)top-=20;if(parent){const rect=parent.root.getBoundingClientRect();left=rect.left+rect.width}const body_rect=document.body.getBoundingClientRect();const root_rect=root.getBoundingClientRect();if(body_rect.height==0)console.error("document.body height is 0. That is dangerous, set html,body { height: 100%; }");if(body_rect.width&&left>body_rect.width-root_rect.width-10)left=body_rect.width-root_rect.width-10;if(body_rect.height&&top>body_rect.height-root_rect.height-10)top=body_rect.height-root_rect.height-10}root.style.left=`${left}px`;root.style.top=`${top}px`;if(LiteGraph.context_menu_scaling&&options.scale){root.style.transform=`scale(${Math.round(options.scale*4)*.25})`}}containsNode(node2,visited=new Set){if(visited.has(this))return false;visited.add(this);return this.current_submenu?.containsNode(node2,visited)||this.root.contains(node2)}addItem(name,value,options){options||={};const element=document.createElement("div");element.className="litemenu-entry submenu";let disabled=false;if(value===null){element.classList.add("separator")}else{const innerHtml=name===null?"":String(name);if(typeof value==="string"){element.innerHTML=innerHtml}else{element.innerHTML=value?.title??innerHtml;if(value.disabled){disabled=true;element.classList.add("disabled");element.setAttribute("aria-disabled","true")}if(value.submenu||value.has_submenu){element.classList.add("has_submenu");element.setAttribute("aria-haspopup","true");element.setAttribute("aria-expanded","false")}if(value.className)element.className+=` ${value.className}`}element.value=value;element.setAttribute("role","menuitem");if(typeof value==="function"){element.dataset["value"]=String(name);element.onclick_callback=value}else{element.dataset["value"]=String(value)}}this.root.append(element);if(!disabled)element.addEventListener("click",inner_onclick);if(!disabled&&options.autoopen)element.addEventListener("pointerenter",inner_over);const setAriaExpanded=()=>{const entries=this.root.querySelectorAll("div.litemenu-entry.has_submenu");if(entries){for(const entry of entries){entry.setAttribute("aria-expanded","false")}}element.setAttribute("aria-expanded","true")};function inner_over(e2){const value2=this.value;if(!value2||!value2.has_submenu)return;inner_onclick.call(this,e2);setAriaExpanded()}const that=this;function inner_onclick(e2){const value2=this.value;let close_parent=true;that.current_submenu?.close(e2);if(value2?.has_submenu||value2?.submenu){setAriaExpanded()}if(options.callback){const r=options.callback.call(this,value2,options,e2,that,options.node);if(r===true)close_parent=false}if(typeof value2==="object"){if(value2.callback&&!options.ignore_item_callbacks&&value2.disabled!==true){const r=value2.callback.call(this,value2,options,e2,that,options.extra);if(r===true)close_parent=false}if(value2.submenu){if(!value2.submenu.options)throw"ContextMenu submenu needs options";new that.constructor(value2.submenu.options,{callback:value2.submenu.callback,event:e2,parentMenu:that,ignore_item_callbacks:value2.submenu.ignore_item_callbacks,title:value2.submenu.title,extra:value2.submenu.extra,autoopen:options.autoopen});close_parent=false}}if(close_parent&&!that.lock)that.close()}return element}close(e2,ignore_parent_menu){this.controller.abort();this.root.remove();if(this.parentMenu&&!ignore_parent_menu){this.parentMenu.lock=false;this.parentMenu.current_submenu=void 0;if(e2===void 0){this.parentMenu.close()}else if(e2&&!ContextMenu.isCursorOverElement(e2,this.parentMenu.root)){ContextMenu.trigger(this.parentMenu.root,`${LiteGraph.pointerevents_method}leave`,e2)}}this.current_submenu?.close(e2,true)}static trigger(element,event_name,params){const evt=document.createEvent("CustomEvent");evt.initCustomEvent(event_name,true,true,params);if(element.dispatchEvent)element.dispatchEvent(evt);return evt}getTopMenu(){return this.options.parentMenu?this.options.parentMenu.getTopMenu():this}getFirstEvent(){return this.options.parentMenu?this.options.parentMenu.getFirstEvent():this.options.event}static isCursorOverElement(event,element){const left=event.clientX;const top=event.clientY;const rect=element.getBoundingClientRect();if(!rect)return false;if(top>rect.top&&top<rect.top+rect.height&&left>rect.left&&left<rect.left+rect.width){return true}return false}}class CurveEditor{points;selected;nearest;size;must_update;margin;_nearest;constructor(points){this.points=points;this.selected=-1;this.nearest=-1;this.size=null;this.must_update=true;this.margin=5}static sampleCurve(f,points){if(!points)return;for(let i=0;i<points.length-1;++i){const p=points[i];const pn=points[i+1];if(pn[0]<f)continue;const r=pn[0]-p[0];if(Math.abs(r)<1e-5)return p[1];const local_f=(f-p[0])/r;return p[1]*(1-local_f)+pn[1]*local_f}return 0}draw(ctx,size,graphcanvas,background_color,line_color,inactive=false){const points=this.points;if(!points)return;this.size=size;const w=size[0]-this.margin*2;const h=size[1]-this.margin*2;line_color=line_color||"#666";ctx.save();ctx.translate(this.margin,this.margin);if(background_color){ctx.fillStyle="#111";ctx.fillRect(0,0,w,h);ctx.fillStyle="#222";ctx.fillRect(w*.5,0,1,h);ctx.strokeStyle="#333";ctx.strokeRect(0,0,w,h)}ctx.strokeStyle=line_color;if(inactive)ctx.globalAlpha=.5;ctx.beginPath();for(const p of points){ctx.lineTo(p[0]*w,(1-p[1])*h)}ctx.stroke();ctx.globalAlpha=1;if(!inactive){for(const[i,p]of points.entries()){ctx.fillStyle=this.selected==i?"#FFF":this.nearest==i?"#DDD":"#AAA";ctx.beginPath();ctx.arc(p[0]*w,(1-p[1])*h,2,0,Math.PI*2);ctx.fill()}}ctx.restore()}onMouseDown(localpos,graphcanvas){const points=this.points;if(!points)return;if(localpos[1]<0)return;if(this.size==null)throw new Error("CurveEditor.size was null or undefined.");const w=this.size[0]-this.margin*2;const h=this.size[1]-this.margin*2;const x2=localpos[0]-this.margin;const y=localpos[1]-this.margin;const pos=[x2,y];const max_dist=30/graphcanvas.ds.scale;this.selected=this.getCloserPoint(pos,max_dist);if(this.selected==-1){const point=[x2/w,1-y/h];points.push(point);points.sort(function(a,b){return a[0]-b[0]});this.selected=points.indexOf(point);this.must_update=true}if(this.selected!=-1)return true}onMouseMove(localpos,graphcanvas){const points=this.points;if(!points)return;const s=this.selected;if(s<0)return;if(this.size==null)throw new Error("CurveEditor.size was null or undefined.");const x2=(localpos[0]-this.margin)/(this.size[0]-this.margin*2);const y=(localpos[1]-this.margin)/(this.size[1]-this.margin*2);const curvepos=[localpos[0]-this.margin,localpos[1]-this.margin];const max_dist=30/graphcanvas.ds.scale;this._nearest=this.getCloserPoint(curvepos,max_dist);const point=points[s];if(point){const is_edge_point=s==0||s==points.length-1;if(!is_edge_point&&(localpos[0]<-10||localpos[0]>this.size[0]+10||localpos[1]<-10||localpos[1]>this.size[1]+10)){points.splice(s,1);this.selected=-1;return}if(!is_edge_point)point[0]=clamp(x2,0,1);else point[0]=s==0?0:1;point[1]=1-clamp(y,0,1);points.sort(function(a,b){return a[0]-b[0]});this.selected=points.indexOf(point);this.must_update=true}}onMouseUp(){this.selected=-1;return false}getCloserPoint(pos,max_dist){const points=this.points;if(!points)return-1;max_dist=max_dist||30;if(this.size==null)throw new Error("CurveEditor.size was null or undefined.");const w=this.size[0]-this.margin*2;const h=this.size[1]-this.margin*2;const num=points.length;const p2=[0,0];let min_dist=1e6;let closest=-1;for(let i=0;i<num;++i){const p=points[i];p2[0]=p[0]*w;p2[1]=(1-p[1])*h;const dist=distance(pos,p2);if(dist>min_dist||dist>max_dist)continue;closest=i;min_dist=dist}return closest}}class LiteGraphGlobal{SlotShape=SlotShape;SlotDirection=SlotDirection;SlotType=SlotType;LabelPosition=LabelPosition;VERSION=.4;CANVAS_GRID_SIZE=10;NODE_TITLE_HEIGHT=30;NODE_TITLE_TEXT_Y=20;NODE_SLOT_HEIGHT=20;NODE_WIDGET_HEIGHT=20;NODE_WIDTH=140;NODE_MIN_WIDTH=50;NODE_COLLAPSED_RADIUS=10;NODE_COLLAPSED_WIDTH=80;NODE_TITLE_COLOR="#999";NODE_SELECTED_TITLE_COLOR="#FFF";NODE_TEXT_SIZE=14;NODE_TEXT_COLOR="#AAA";NODE_TEXT_HIGHLIGHT_COLOR="#EEE";NODE_SUBTEXT_SIZE=12;NODE_DEFAULT_COLOR="#333";NODE_DEFAULT_BGCOLOR="#353535";NODE_DEFAULT_BOXCOLOR="#666";NODE_DEFAULT_SHAPE=RenderShape.ROUND;NODE_BOX_OUTLINE_COLOR="#FFF";NODE_ERROR_COLOUR="#E00";NODE_FONT="Arial";DEFAULT_FONT="Arial";DEFAULT_SHADOW_COLOR="rgba(0,0,0,0.5)";DEFAULT_GROUP_FONT=24;DEFAULT_GROUP_FONT_SIZE;GROUP_FONT="Arial";WIDGET_BGCOLOR="#222";WIDGET_OUTLINE_COLOR="#666";WIDGET_ADVANCED_OUTLINE_COLOR="rgba(56, 139, 253, 0.8)";WIDGET_TEXT_COLOR="#DDD";WIDGET_SECONDARY_TEXT_COLOR="#999";WIDGET_DISABLED_TEXT_COLOR="#666";LINK_COLOR="#9A9";EVENT_LINK_COLOR="#A86";CONNECTING_LINK_COLOR="#AFA";MAX_NUMBER_OF_NODES=1e4;DEFAULT_POSITION=[100,100];VALID_SHAPES=["default","box","round","card"];ROUND_RADIUS=8;BOX_SHAPE=RenderShape.BOX;ROUND_SHAPE=RenderShape.ROUND;CIRCLE_SHAPE=RenderShape.CIRCLE;CARD_SHAPE=RenderShape.CARD;ARROW_SHAPE=RenderShape.ARROW;GRID_SHAPE=RenderShape.GRID;INPUT=NodeSlotType.INPUT;OUTPUT=NodeSlotType.OUTPUT;EVENT=-1;ACTION=-1;NODE_MODES=["Always","On Event","Never","On Trigger"];NODE_MODES_COLORS=["#666","#422","#333","#224","#626"];ALWAYS=LGraphEventMode.ALWAYS;ON_EVENT=LGraphEventMode.ON_EVENT;NEVER=LGraphEventMode.NEVER;ON_TRIGGER=LGraphEventMode.ON_TRIGGER;UP=LinkDirection.UP;DOWN=LinkDirection.DOWN;LEFT=LinkDirection.LEFT;RIGHT=LinkDirection.RIGHT;CENTER=LinkDirection.CENTER;LINK_RENDER_MODES=["Straight","Linear","Spline"];HIDDEN_LINK=LinkRenderType.HIDDEN_LINK;STRAIGHT_LINK=LinkRenderType.STRAIGHT_LINK;LINEAR_LINK=LinkRenderType.LINEAR_LINK;SPLINE_LINK=LinkRenderType.SPLINE_LINK;NORMAL_TITLE=TitleMode.NORMAL_TITLE;NO_TITLE=TitleMode.NO_TITLE;TRANSPARENT_TITLE=TitleMode.TRANSPARENT_TITLE;AUTOHIDE_TITLE=TitleMode.AUTOHIDE_TITLE;VERTICAL_LAYOUT="vertical";proxy=null;node_images_path="";debug=false;catch_exceptions=true;throw_errors=true;allow_scripts=false;registered_node_types={};node_types_by_file_extension={};Nodes={};Globals={};searchbox_extras={};node_box_coloured_when_on=false;node_box_coloured_by_mode=false;dialog_close_on_mouse_leave=false;dialog_close_on_mouse_leave_delay=500;shift_click_do_break_link_from=false;click_do_break_link_to=false;ctrl_alt_click_do_break_link=true;snaps_for_comfy=true;snap_highlights_node=true;alwaysSnapToGrid;snapToGrid;search_hide_on_mouse_leave=true;search_filter_enabled=false;search_show_all_on_open=true;auto_load_slot_types=false;registered_slot_in_types={};registered_slot_out_types={};slot_types_in=[];slot_types_out=[];slot_types_default_in={};slot_types_default_out={};alt_drag_do_clone_nodes=false;do_add_triggers_slots=false;allow_multi_output_for_events=true;middle_click_slot_add_default_node=false;release_link_on_empty_shows_menu=false;pointerevents_method="pointer";ctrl_shift_v_paste_connect_unselected_outputs=true;use_uuids=false;highlight_selected_group=true;context_menu_scaling=false;alwaysRepeatWarnings=false;onDeprecationWarning=[console.warn];macTrackpadGestures=false;macGesturesRequireMac=true;canvasNavigationMode="legacy";truncateWidgetTextEvenly=false;truncateWidgetValuesFirst=false;saveViewportWithGraph=true;LGraph=LGraph;LLink=LLink;LGraphNode=LGraphNode;LGraphGroup=LGraphGroup;DragAndScale=DragAndScale;LGraphCanvas=LGraphCanvas;ContextMenu=ContextMenu;CurveEditor=CurveEditor;Reroute=Reroute;constructor(){Object.defineProperty(this,"Classes",{writable:false})}Classes={get SubgraphSlot(){return SubgraphSlot},get SubgraphIONodeBase(){return SubgraphIONodeBase},get Rectangle(){return Rectangle},get InputIndicators(){return InputIndicators}};registerNodeType(type,base_class){if(!base_class.prototype)throw"Cannot register a simple object, it must be a class with a prototype";base_class.type=type;if(this.debug)console.log("Node registered:",type);const classname=base_class.name;const pos=type.lastIndexOf("/");base_class.category=type.substring(0,pos);base_class.title||=classname;for(const i in LGraphNode.prototype){base_class.prototype[i]||=LGraphNode.prototype[i]}const prev=this.registered_node_types[type];if(prev&&this.debug){console.log("replacing node type:",type)}this.registered_node_types[type]=base_class;if(base_class.constructor.name)this.Nodes[classname]=base_class;this.onNodeTypeRegistered?.(type,base_class);if(prev)this.onNodeTypeReplaced?.(type,base_class,prev);if(base_class.prototype.onPropertyChange)console.warn(`LiteGraph node class ${type} has onPropertyChange method, it must be called onPropertyChanged with d at the end`);if(this.auto_load_slot_types)new base_class(base_class.title||"tmpnode")}unregisterNodeType(type){const base_class=typeof type==="string"?this.registered_node_types[type]:type;if(!base_class)throw`node type not found: ${String(type)}`;delete this.registered_node_types[String(base_class.type)];const name=base_class.constructor.name;if(name)delete this.Nodes[name]}registerNodeAndSlotType(type,slot_type,out){out||=false;const base_class=typeof type==="string"&&this.registered_node_types[type]!=="anonymous"?this.registered_node_types[type]:type;const class_type=base_class.constructor.type;let allTypes=[];if(typeof slot_type==="string"){allTypes=slot_type.split(",")}else if(slot_type==this.EVENT||slot_type==this.ACTION){allTypes=["_event_"]}else{allTypes=["*"]}for(let slotType of allTypes){if(slotType==="")slotType="*";const register=out?this.registered_slot_out_types:this.registered_slot_in_types;register[slotType]??={nodes:[]};const{nodes}=register[slotType];if(!nodes.includes(class_type))nodes.push(class_type);const types=out?this.slot_types_out:this.slot_types_in;const type2=slotType.toLowerCase();if(!types.includes(type2)){types.push(type2);types.sort()}}}clearRegisteredTypes(){this.registered_node_types={};this.node_types_by_file_extension={};this.Nodes={};this.searchbox_extras={}}createNode(type,title,options){const base_class=this.registered_node_types[type];if(!base_class){if(this.debug)console.log(`GraphNode type "${type}" not registered.`);return null}title=title||base_class.title||type;let node2=null;if(this.catch_exceptions){try{node2=new base_class(title)}catch(error){console.error(error);return null}}else{node2=new base_class(title)}node2.type=type;if(!node2.title&&title)node2.title=title;node2.properties||={};node2.properties_info||=[];node2.flags||={};node2.size||=node2.computeSize();node2.pos||=[this.DEFAULT_POSITION[0],this.DEFAULT_POSITION[1]];node2.mode||=LGraphEventMode.ALWAYS;if(options){for(const i in options){node2[i]=options[i]}}node2.onNodeCreated?.();return node2}getNodeType(type){return this.registered_node_types[type]}getNodeTypesInCategory(category,filter){const r=[];for(const i in this.registered_node_types){const type=this.registered_node_types[i];if(type.filter!=filter)continue;if(category==""){if(type.category==null)r.push(type)}else if(type.category==category){r.push(type)}}return r}getNodeTypesCategories(filter){const categories={"":1};for(const i in this.registered_node_types){const type=this.registered_node_types[i];if(type.category&&!type.skip_list){if(type.filter!=filter)continue;categories[type.category]=1}}const result=[];for(const i in categories){result.push(i)}return result}reloadNodes(folder_wildcard){const tmp=document.getElementsByTagName("script");const script_files=[];for(const element of tmp){script_files.push(element)}const docHeadObj=document.getElementsByTagName("head")[0];folder_wildcard=document.location.href+folder_wildcard;for(const script_file of script_files){const src=script_file.src;if(!src||src.substr(0,folder_wildcard.length)!=folder_wildcard)continue;try{if(this.debug)console.log("Reloading:",src);const dynamicScript=document.createElement("script");dynamicScript.type="text/javascript";dynamicScript.src=src;docHeadObj.append(dynamicScript);script_file.remove()}catch(error){if(this.throw_errors)throw error;if(this.debug)console.log("Error while reloading",src)}}if(this.debug)console.log("Nodes reloaded")}cloneObject(obj,target){if(obj==null)return null;const r=JSON.parse(JSON.stringify(obj));if(!target)return r;for(const i in r){target[i]=r[i]}return target}uuidv4=createUuidv4;isValidConnection(type_a,type_b){if(type_a==""||type_a==="*")type_a=0;if(type_b==""||type_b==="*")type_b=0;if(!type_a||!type_b||type_a==type_b||type_a==this.EVENT&&type_b==this.ACTION){return true}type_a=String(type_a);type_b=String(type_b);type_a=type_a.toLowerCase();type_b=type_b.toLowerCase();if(!type_a.includes(",")&&!type_b.includes(","))return type_a==type_b;const supported_types_a=type_a.split(",");const supported_types_b=type_b.split(",");for(const a of supported_types_a){for(const b of supported_types_b){if(this.isValidConnection(a,b))return true}}return false}getParameterNames(func){return String(func).replaceAll(/\/\/.*$/gm,"").replaceAll(/\s+/g,"").replaceAll(/\/\*[^*/]*\*\//g,"").split("){",1)[0].replace(/^[^(]*\(/,"").replaceAll(/=[^,]+/g,"").split(",").filter(Boolean)}pointerListenerAdd(oDOM,sEvIn,fCall,capture=false){if(!oDOM||!oDOM.addEventListener||!sEvIn||typeof fCall!=="function")return;let sMethod=this.pointerevents_method;let sEvent=sEvIn;if(sMethod=="pointer"&&!window.PointerEvent){console.warn("sMethod=='pointer' && !window.PointerEvent");console.log(`Converting pointer[${sEvent}] : down move up cancel enter TO touchstart touchmove touchend, etc ..`);switch(sEvent){case"down":{sMethod="touch";sEvent="start";break}case"move":{sMethod="touch";break}case"up":{sMethod="touch";sEvent="end";break}case"cancel":{sMethod="touch";break}case"enter":{console.log("debug: Should I send a move event?");break}default:{console.warn(`PointerEvent not available in this browser ? The event ${sEvent} would not be called`)}}}switch(sEvent){case"down":case"up":case"move":case"over":case"out":case"enter":{oDOM.addEventListener(sMethod+sEvent,fCall,capture)}case"leave":case"cancel":case"gotpointercapture":case"lostpointercapture":{if(sMethod!="mouse"){return oDOM.addEventListener(sMethod+sEvent,fCall,capture)}}default:return oDOM.addEventListener(sEvent,fCall,capture)}}pointerListenerRemove(oDOM,sEvent,fCall,capture=false){if(!oDOM||!oDOM.removeEventListener||!sEvent||typeof fCall!=="function")return;switch(sEvent){case"down":case"up":case"move":case"over":case"out":case"enter":{if(this.pointerevents_method=="pointer"||this.pointerevents_method=="mouse"){oDOM.removeEventListener(this.pointerevents_method+sEvent,fCall,capture)}}case"leave":case"cancel":case"gotpointercapture":case"lostpointercapture":{if(this.pointerevents_method=="pointer"){return oDOM.removeEventListener(this.pointerevents_method+sEvent,fCall,capture)}}default:return oDOM.removeEventListener(sEvent,fCall,capture)}}getTime(){return performance.now()}distance=distance;colorToString(c){return`rgba(${Math.round(c[0]*255).toFixed()},${Math.round(c[1]*255).toFixed()},${Math.round(c[2]*255).toFixed()},${c.length==4?c[3].toFixed(2):"1.0"})`}isInsideRectangle=isInsideRectangle;growBounding(bounding,x2,y){if(x2<bounding[0]){bounding[0]=x2}else if(x2>bounding[2]){bounding[2]=x2}if(y<bounding[1]){bounding[1]=y}else if(y>bounding[3]){bounding[3]=y}}overlapBounding=overlapBounding;isInsideBounding(p,bb){if(p[0]<bb[0][0]||p[1]<bb[0][1]||p[0]>bb[1][0]||p[1]>bb[1][1]){return false}return true}hex2num(hex){if(hex.charAt(0)=="#"){hex=hex.slice(1)}hex=hex.toUpperCase();const hex_alphabets="0123456789ABCDEF";const value=new Array(3);let k=0;let int1,int2;for(let i=0;i<6;i+=2){int1=hex_alphabets.indexOf(hex.charAt(i));int2=hex_alphabets.indexOf(hex.charAt(i+1));value[k]=int1*16+int2;k++}return value}num2hex(triplet){const hex_alphabets="0123456789ABCDEF";let hex="#";let int1,int2;for(let i=0;i<3;i++){int1=triplet[i]/16;int2=triplet[i]%16;hex+=hex_alphabets.charAt(int1)+hex_alphabets.charAt(int2)}return hex}closeAllContextMenus(ref_window=window){const elements=[...ref_window.document.querySelectorAll(".litecontextmenu")];if(!elements.length)return;for(const element of elements){if("close"in element&&typeof element.close==="function"){element.close()}else{element.remove()}}}extendClass(target,origin){for(const i in origin){if(target.hasOwnProperty(i))continue;target[i]=origin[i]}if(origin.prototype){for(const i in origin.prototype){if(!origin.prototype.hasOwnProperty(i))continue;if(target.prototype.hasOwnProperty(i))continue;if(origin.prototype.__lookupGetter__(i)){target.prototype.__defineGetter__(i,origin.prototype.__lookupGetter__(i))}else{target.prototype[i]=origin.prototype[i]}if(origin.prototype.__lookupSetter__(i)){target.prototype.__defineSetter__(i,origin.prototype.__lookupSetter__(i))}}}}}Symbol.dispose??=Symbol("Symbol.dispose");Symbol.asyncDispose??=Symbol("Symbol.asyncDispose");function loadPolyfills(){if(typeof window!="undefined"&&window.CanvasRenderingContext2D&&!window.CanvasRenderingContext2D.prototype.roundRect){window.CanvasRenderingContext2D.prototype.roundRect=function(x2,y,w,h,radius,radius_low){let top_left_radius=0;let top_right_radius=0;let bottom_left_radius=0;let bottom_right_radius=0;if(radius===0){this.rect(x2,y,w,h);return}if(radius_low===void 0)radius_low=radius;if(Array.isArray(radius)){if(radius.length==1){top_left_radius=top_right_radius=bottom_left_radius=bottom_right_radius=radius[0]}else if(radius.length==2){top_left_radius=bottom_right_radius=radius[0];top_right_radius=bottom_left_radius=radius[1]}else if(radius.length==4){top_left_radius=radius[0];top_right_radius=radius[1];bottom_left_radius=radius[2];bottom_right_radius=radius[3]}else{return}}else{top_left_radius=radius||0;top_right_radius=radius||0;const low=!Array.isArray(radius_low)&&radius_low?radius_low:0;bottom_left_radius=low;bottom_right_radius=low}this.moveTo(x2+top_left_radius,y);this.lineTo(x2+w-top_right_radius,y);this.quadraticCurveTo(x2+w,y,x2+w,y+top_right_radius);this.lineTo(x2+w,y+h-bottom_right_radius);this.quadraticCurveTo(x2+w,y+h,x2+w-bottom_right_radius,y+h);this.lineTo(x2+bottom_right_radius,y+h);this.quadraticCurveTo(x2,y+h,x2,y+h-bottom_left_radius);this.lineTo(x2,y+bottom_left_radius);this.quadraticCurveTo(x2,y,x2+top_left_radius,y)}}if(typeof window!="undefined"&&!window["requestAnimationFrame"]){window.requestAnimationFrame=window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||function(callback){window.setTimeout(callback,1e3/60)}}}class InvalidLinkError extends Error{constructor(message="Attempted to access a link that was invalid.",cause){super(message,{cause});this.name="InvalidLinkError"}}class RecursionError extends Error{constructor(subject){super(subject);this.name="RecursionError"}}class SlotIndexError extends Error{constructor(message="Attempted to access a slot that was out of bounds.",cause){super(message,{cause});this.name="SlotIndexError"}}class ExecutableNodeDTO{constructor(node2,subgraphNodePath,nodesByExecutionId,subgraphNode){this.node=node2;this.subgraphNodePath=subgraphNodePath;this.nodesByExecutionId=nodesByExecutionId;this.subgraphNode=subgraphNode;if(!node2.graph)throw new NullGraphError;this.#id=[...this.subgraphNodePath,this.node.id].join(":");this.graph=node2.graph;this.inputs=this.node.inputs.map(x2=>({linkId:x2.link,name:x2.name,type:x2.type}));if(this.node.applyToGraph){this.applyToGraph=(...args)=>this.node.applyToGraph?.(...args)}}graph;inputs;#id;get id(){return this.#id}get type(){return this.node.type}get title(){return this.node.title}get mode(){return this.node.mode}get comfyClass(){return this.node.comfyClass}get isVirtualNode(){return this.node.isVirtualNode}get widgets(){return this.node.widgets}get subgraphId(){return this.subgraphNode?.subgraph.id}getInnerNodes(){return this.node.isSubgraphNode()?this.node.getInnerNodes(this.nodesByExecutionId,this.subgraphNodePath):[this]}resolveInput(slot,visited=new Set){const uniqueId=`${this.subgraphNode?.subgraph.id}:${this.node.id}[I]${slot}`;if(visited.has(uniqueId)){const nodeInfo=`${this.node.id}${this.node.title?` (${this.node.title})`:""}`;const pathInfo=this.subgraphNodePath.length>0?` at path ${this.subgraphNodePath.join(":")}`:"";throw new RecursionError(`Circular reference detected while resolving input ${slot} of node ${nodeInfo}${pathInfo}. This creates an infinite loop in link resolution. UniqueID: [${uniqueId}]`)}visited.add(uniqueId);const input=this.inputs.at(slot);if(!input)throw new SlotIndexError(`No input found for flattened id [${this.id}] slot [${slot}]`);if(input.linkId==null)return;const link=this.graph.getLink(input.linkId);if(!link)throw new InvalidLinkError(`No link found in parent graph for id [${this.id}] slot [${slot}] ${input.name}`);const{subgraphNode}=this;if(subgraphNode&&link.originIsIoNode){const subgraphNodeInput=subgraphNode.inputs.at(link.origin_slot);if(!subgraphNodeInput)throw new SlotIndexError(`No input found for slot [${link.origin_slot}] ${input.name}`);const linkId=subgraphNodeInput.link;if(linkId==null){const widget=subgraphNode.getWidgetFromSlot(subgraphNodeInput);if(!widget)return;return{node:this,origin_id:this.id,origin_slot:-1,widgetInfo:{value:widget.value}}}const outerLink=subgraphNode.graph.getLink(linkId);if(!outerLink)throw new InvalidLinkError(`No outer link found for slot [${link.origin_slot}] ${input.name}`);const subgraphNodeExecutionId=this.subgraphNodePath.join(":");const subgraphNodeDto=this.nodesByExecutionId.get(subgraphNodeExecutionId);if(!subgraphNodeDto)throw new Error(`No subgraph node DTO found for id [${subgraphNodeExecutionId}]`);return subgraphNodeDto.resolveInput(outerLink.target_slot,visited)}const outputNode=this.graph.getNodeById(link.origin_id);if(!outputNode)throw new InvalidLinkError(`No input node found for id [${this.id}] slot [${slot}] ${input.name}`);const outputNodeExecutionId=[...this.subgraphNodePath,outputNode.id].join(":");const outputNodeDto=this.nodesByExecutionId.get(outputNodeExecutionId);if(!outputNodeDto)throw new Error(`No output node DTO found for id [${outputNodeExecutionId}]`);return outputNodeDto.resolveOutput(link.origin_slot,input.type,visited)}resolveOutput(slot,type,visited){const uniqueId=`${this.subgraphNode?.subgraph.id}:${this.node.id}[O]${slot}`;if(visited.has(uniqueId)){const nodeInfo=`${this.node.id}${this.node.title?` (${this.node.title})`:""}`;const pathInfo=this.subgraphNodePath.length>0?` at path ${this.subgraphNodePath.join(":")}`:"";throw new RecursionError(`Circular reference detected while resolving output ${slot} of node ${nodeInfo}${pathInfo}. This creates an infinite loop in link resolution. UniqueID: [${uniqueId}]`)}visited.add(uniqueId);if(this.mode===LGraphEventMode.BYPASS){const{inputs}=this;const parentInputIndexes=Object.keys(inputs).map(Number);const indexes=[slot,...parentInputIndexes];const matchingIndex=indexes.find(i=>inputs[i]?.type===type);if(matchingIndex===void 0){console.debug(`[ExecutableNodeDTO.resolveOutput] No input types match type [${type}] for id [${this.id}] slot [${slot}]`,this);return}return this.resolveInput(matchingIndex,visited)}const{node:node2}=this;if(node2.isSubgraphNode())return this.#resolveSubgraphOutput(slot,type,visited);if(node2.isVirtualNode){if(this.inputs.at(slot))return this.resolveInput(slot,visited);const virtualLink=this.node.getInputLink(slot);if(virtualLink){const outputNode=this.graph.getNodeById(virtualLink.origin_id);if(!outputNode)throw new InvalidLinkError(`Virtual node failed to resolve parent [${this.id}] slot [${slot}]`);const outputNodeExecutionId=[...this.subgraphNodePath,outputNode.id].join(":");const outputNodeDto=this.nodesByExecutionId.get(outputNodeExecutionId);if(!outputNodeDto)throw new Error(`No output node DTO found for id [${outputNode.id}]`);return outputNodeDto.resolveOutput(virtualLink.origin_slot,type,visited)}return}return{node:this,origin_id:this.id,origin_slot:slot}}#resolveSubgraphOutput(slot,type,visited){const{node:node2}=this;const output=node2.outputs.at(slot);if(!output)throw new SlotIndexError(`No output found for flattened id [${this.id}] slot [${slot}]`);if(!node2.isSubgraphNode())throw new TypeError(`Node is not a subgraph node: ${node2.id}`);const innerResolved=node2.resolveSubgraphOutputLink(slot);if(!innerResolved)return;const innerNode=innerResolved.outputNode;if(!innerNode)throw new Error(`No output node found for id [${this.id}] slot [${slot}] ${output.name}`);const innerNodeExecutionId=[...this.subgraphNodePath,node2.id,innerNode.id].join(":");const innerNodeDto=this.nodesByExecutionId.get(innerNodeExecutionId);if(!innerNodeDto)throw new Error(`No inner node DTO found for id [${innerNodeExecutionId}]`);return innerNodeDto.resolveOutput(innerResolved.link.origin_slot,type,visited)}}class SubgraphNode extends LGraphNode{constructor(graph,subgraph,instanceData){super(subgraph.name,subgraph.id);this.graph=graph;this.subgraph=subgraph;const subgraphEvents=this.subgraph.events;const{signal}=this.#eventAbortController;subgraphEvents.addEventListener("input-added",e2=>{const subgraphInput=e2.detail.input;const{name,type}=subgraphInput;if(this.inputs.some(i=>i.name==name))return;const input=this.addInput(name,type);this.#addSubgraphInputListeners(subgraphInput,input)},{signal});subgraphEvents.addEventListener("removing-input",e2=>{const widget=e2.detail.input._widget;if(widget)this.ensureWidgetRemoved(widget);this.removeInput(e2.detail.index);this.setDirtyCanvas(true,true)},{signal});subgraphEvents.addEventListener("output-added",e2=>{const{name,type}=e2.detail.output;this.addOutput(name,type)},{signal});subgraphEvents.addEventListener("removing-output",e2=>{this.removeOutput(e2.detail.index);this.setDirtyCanvas(true,true)},{signal});subgraphEvents.addEventListener("renaming-input",e2=>{const{index,newName}=e2.detail;const input=this.inputs.at(index);if(!input)throw new Error("Subgraph input not found");input.label=newName},{signal});subgraphEvents.addEventListener("renaming-output",e2=>{const{index,newName}=e2.detail;const output=this.outputs.at(index);if(!output)throw new Error("Subgraph output not found");output.label=newName},{signal});this.type=subgraph.id;this.configure(instanceData);this.addTitleButton({name:"enter_subgraph",text:"",yOffset:0,xOffset:-10,fontSize:16})}type;isVirtualNode=true;get rootGraph(){return this.graph.rootGraph}get displayType(){return"Subgraph node"}isSubgraphNode(){return true}widgets=[];#eventAbortController=new AbortController;onTitleButtonClick(button,canvas2){if(button.name==="enter_subgraph"){canvas2.openSubgraph(this.subgraph)}else{super.onTitleButtonClick(button,canvas2)}}#addSubgraphInputListeners(subgraphInput,input){input._listenerController?.abort();input._listenerController=new AbortController;const{signal}=input._listenerController;subgraphInput.events.addEventListener("input-connected",()=>{if(input._widget)return;const widget=subgraphInput._widget;if(!widget)return;this.#setWidget(subgraphInput,input,widget)},{signal});subgraphInput.events.addEventListener("input-disconnected",()=>{const connectedWidgets=subgraphInput.getConnectedWidgets();if(connectedWidgets.length>0)return;this.removeWidgetByName(input.name);delete input.pos;delete input.widget;input._widget=void 0},{signal})}configure(info){for(const input of this.inputs){input._listenerController?.abort()}this.inputs.length=0;this.inputs.push(...this.subgraph.inputNode.slots.map(slot=>new NodeInputSlot({name:slot.name,localized_name:slot.localized_name,label:slot.label,type:slot.type,link:null},this)));this.outputs.length=0;this.outputs.push(...this.subgraph.outputNode.slots.map(slot=>new NodeOutputSlot({name:slot.name,localized_name:slot.localized_name,label:slot.label,type:slot.type,links:null},this)));super.configure(info)}_internalConfigureAfterSlots(){this.widgets.length=0;for(const input of this.inputs){const subgraphInput=this.subgraph.inputNode.slots.find(slot=>slot.name===input.name);if(!subgraphInput)throw new Error(`[SubgraphNode.configure] No subgraph input found for input ${input.name}`);this.#addSubgraphInputListeners(subgraphInput,input);for(const linkId of subgraphInput.linkIds){const link=this.subgraph.getLink(linkId);if(!link){console.warn(`[SubgraphNode.configure] No link found for link ID ${linkId}`,this);continue}const resolved=link.resolve(this.subgraph);if(!resolved.input||!resolved.inputNode){console.warn("Invalid resolved link",resolved,this);continue}const widget=resolved.inputNode.getWidgetFromSlot(resolved.input);if(!widget)continue;this.#setWidget(subgraphInput,input,widget);break}}}#setWidget(subgraphInput,input,widget){const promotedWidget=toConcreteWidget(widget,this).createCopyForNode(this);Object.assign(promotedWidget,{get name(){return subgraphInput.name},set name(value){console.warn("Promoted widget: setting name is not allowed",this,value)},get localized_name(){return subgraphInput.localized_name},set localized_name(value){console.warn("Promoted widget: setting localized_name is not allowed",this,value)},get label(){return subgraphInput.label},set label(value){console.warn("Promoted widget: setting label is not allowed",this,value)},get tooltip(){return widget.tooltip},set tooltip(value){console.warn("Promoted widget: setting tooltip is not allowed",this,value)}});this.widgets.push(promotedWidget);this.subgraph.events.dispatch("widget-promoted",{widget:promotedWidget,subgraphNode:this});input.widget={name:subgraphInput.name};input._widget=promotedWidget}addInput(name,type,inputProperties={}){return super.addInput(name,type,inputProperties)}getInputLink(slot){const innerLink=this.subgraph.outputNode.slots[slot].getLinks().at(0);if(!innerLink){console.warn(`SubgraphNode.getInputLink: no inner link found for slot ${slot}`);return null}const newLink=LLink.create(innerLink);newLink.origin_id=`${this.id}:${innerLink.origin_id}`;newLink.origin_slot=innerLink.origin_slot;return newLink}resolveSubgraphInputLinks(slot){const inputSlot=this.subgraph.inputNode.slots[slot];const innerLinks=inputSlot.getLinks();if(innerLinks.length===0){console.debug(`[SubgraphNode.resolveSubgraphInputLinks] No inner links found for input slot [${slot}] ${inputSlot.name}`,this);return[]}return innerLinks.map(link=>link.resolve(this.subgraph))}resolveSubgraphOutputLink(slot){const outputSlot=this.subgraph.outputNode.slots[slot];const innerLink=outputSlot.getLinks().at(0);if(innerLink)return innerLink.resolve(this.subgraph);console.debug(`[SubgraphNode.resolveSubgraphOutputLink] No inner link found for output slot [${slot}] ${outputSlot.name}`,this)}getInnerNodes(executableNodes,subgraphNodePath=[],nodes=[],visited=new Set){if(visited.has(this)){const nodeInfo=`${this.id}${this.title?` (${this.title})`:""}`;const subgraphInfo=`'${this.subgraph.name||"Unnamed Subgraph"}'`;const depth=subgraphNodePath.length;throw new RecursionError(`Circular reference detected at depth ${depth} in node ${nodeInfo} of subgraph ${subgraphInfo}. This creates an infinite loop in the subgraph hierarchy.`)}visited.add(this);const subgraphInstanceIdPath=[...subgraphNodePath,this.id];const parentSubgraphNode=this.graph.rootGraph.resolveSubgraphIdPath(subgraphNodePath).at(-1);const subgraphNodeDto=new ExecutableNodeDTO(this,subgraphNodePath,executableNodes,parentSubgraphNode);executableNodes.set(subgraphNodeDto.id,subgraphNodeDto);for(const node2 of this.subgraph.nodes){if("getInnerNodes"in node2){node2.getInnerNodes(executableNodes,subgraphInstanceIdPath,nodes,new Set(visited))}else{const aVeryRealNode=new ExecutableNodeDTO(node2,subgraphInstanceIdPath,executableNodes,this);executableNodes.set(aVeryRealNode.id,aVeryRealNode);nodes.push(aVeryRealNode)}}return nodes}removeWidgetByName(name){const widget=this.widgets.find(w=>w.name===name);if(widget){this.subgraph.events.dispatch("widget-demoted",{widget,subgraphNode:this})}super.removeWidgetByName(name)}ensureWidgetRemoved(widget){if(this.widgets.includes(widget)){this.subgraph.events.dispatch("widget-demoted",{widget,subgraphNode:this})}super.ensureWidgetRemoved(widget)}onRemoved(){this.#eventAbortController.abort();for(const widget of this.widgets){this.subgraph.events.dispatch("widget-demoted",{widget,subgraphNode:this})}for(const input of this.inputs){input._listenerController?.abort()}}}const LiteGraph=new LiteGraphGlobal;loadPolyfills();exports.BadgePosition=BadgePosition;exports.BaseSteppedWidget=BaseSteppedWidget;exports.BaseWidget=BaseWidget;exports.BooleanWidget=BooleanWidget;exports.ButtonWidget=ButtonWidget;exports.CanvasItem=CanvasItem;exports.CanvasPointer=CanvasPointer;exports.ComboWidget=ComboWidget;exports.Constants=constants;exports.ContextMenu=ContextMenu;exports.CurveEditor=CurveEditor;exports.DragAndScale=DragAndScale;exports.EaseFunction=EaseFunction;exports.ExecutableNodeDTO=ExecutableNodeDTO;exports.InputIndicators=InputIndicators;exports.KnobWidget=KnobWidget;exports.LGraph=LGraph;exports.LGraphBadge=LGraphBadge;exports.LGraphCanvas=LGraphCanvas;exports.LGraphEventMode=LGraphEventMode;exports.LGraphGroup=LGraphGroup;exports.LGraphNode=LGraphNode;exports.LLink=LLink;exports.LabelPosition=LabelPosition;exports.LegacyWidget=LegacyWidget;exports.LinkConnector=LinkConnector;exports.LinkMarkerShape=LinkMarkerShape;exports.LiteGraph=LiteGraph;exports.NumberWidget=NumberWidget;exports.Rectangle=Rectangle;exports.RenderShape=RenderShape;exports.Reroute=Reroute;exports.SliderWidget=SliderWidget;exports.SlotDirection=SlotDirection;exports.SlotShape=SlotShape;exports.SlotType=SlotType;exports.Subgraph=Subgraph;exports.SubgraphNode=SubgraphNode;exports.TextWidget=TextWidget;exports.TitleMode=TitleMode;exports.clamp=clamp;exports.createBounds=createBounds;exports.createUuidv4=createUuidv4;exports.isColorable=isColorable;exports.isComboWidget=isComboWidget;exports.isOverNodeInput=isOverNodeInput;exports.isOverNodeOutput=isOverNodeOutput;exports.strokeShape=strokeShape;Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"})}));
|
|
3
3
|
//# sourceMappingURL=litegraph.umd.js.map
|