super-three 0.133.2 → 0.135.0

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.
Files changed (246) hide show
  1. package/build/three.js +619 -538
  2. package/build/three.min.js +1 -1
  3. package/build/three.module.js +763 -616
  4. package/examples/fonts/open-sans/open-sans-v15-cyrillic-ext_greek_greek-ext_cyrillic_latin_latin-ext_vietnamese-regular.woff +0 -0
  5. package/examples/fonts/open-sans/open-sans-v15-cyrillic-ext_greek_greek-ext_cyrillic_latin_latin-ext_vietnamese-regular.woff2 +0 -0
  6. package/examples/fonts/open-sans/open-sans.css +9 -0
  7. package/examples/fonts/tabler-icons/fonts/tabler-icons.eot +0 -0
  8. package/examples/fonts/tabler-icons/fonts/tabler-icons.ttf +0 -0
  9. package/examples/fonts/tabler-icons/fonts/tabler-icons.woff +0 -0
  10. package/examples/fonts/tabler-icons/fonts/tabler-icons.woff2 +0 -0
  11. package/examples/fonts/tabler-icons/tabler-icons.min.css +4 -0
  12. package/examples/js/controls/ArcballControls.js +68 -27
  13. package/examples/js/controls/DragControls.js +7 -0
  14. package/examples/js/controls/OrbitControls.js +5 -36
  15. package/examples/js/controls/TrackballControls.js +3 -2
  16. package/examples/js/csm/CSM.js +2 -2
  17. package/examples/js/csm/CSMFrustum.js +133 -0
  18. package/examples/js/exporters/GLTFExporter.js +147 -63
  19. package/examples/js/exporters/USDZExporter.js +45 -26
  20. package/examples/js/lines/LineMaterial.js +58 -20
  21. package/examples/js/lines/LineSegments2.js +29 -24
  22. package/examples/js/loaders/3DMLoader.js +24 -11
  23. package/examples/js/loaders/3MFLoader.js +2 -2
  24. package/examples/js/loaders/ColladaLoader.js +61 -3
  25. package/examples/js/loaders/FBXLoader.js +1 -1
  26. package/examples/js/loaders/GLTFLoader.js +94 -31
  27. package/examples/js/loaders/KTX2Loader.js +12 -0
  28. package/examples/js/loaders/LWOLoader.js +8 -6
  29. package/examples/js/loaders/LogLuvLoader.js +766 -0
  30. package/examples/js/loaders/PLYLoader.js +32 -7
  31. package/examples/js/loaders/RGBELoader.js +2 -1
  32. package/examples/js/loaders/SVGLoader.js +7 -3
  33. package/examples/js/loaders/TDSLoader.js +237 -271
  34. package/examples/js/loaders/lwo/LWO2Parser.js +1 -0
  35. package/examples/js/loaders/lwo/LWO3Parser.js +4 -2
  36. package/examples/js/objects/MarchingCubes.js +42 -128
  37. package/examples/js/renderers/CSS2DRenderer.js +4 -4
  38. package/examples/js/renderers/CSS3DRenderer.js +4 -4
  39. package/examples/js/utils/RoughnessMipmapper.js +1 -0
  40. package/examples/jsm/controls/ArcballControls.js +61 -29
  41. package/examples/jsm/controls/DragControls.js +7 -0
  42. package/examples/jsm/controls/OrbitControls.js +9 -51
  43. package/examples/jsm/controls/TrackballControls.js +1 -1
  44. package/examples/jsm/csm/CSM.js +3 -3
  45. package/examples/jsm/csm/{Frustum.js → CSMFrustum.js} +3 -3
  46. package/examples/jsm/exporters/GLTFExporter.js +160 -74
  47. package/examples/jsm/exporters/USDZExporter.js +47 -26
  48. package/examples/jsm/libs/flow.module.js +3218 -0
  49. package/examples/jsm/libs/lil-gui.module.min.js +8 -0
  50. package/examples/jsm/libs/rhino3dm/rhino3dm.wasm +0 -0
  51. package/examples/jsm/lines/LineMaterial.js +59 -23
  52. package/examples/jsm/lines/LineSegments2.js +22 -18
  53. package/examples/jsm/loaders/3DMLoader.js +18 -12
  54. package/examples/jsm/loaders/3MFLoader.js +2 -2
  55. package/examples/jsm/loaders/ColladaLoader.js +61 -3
  56. package/examples/jsm/loaders/FBXLoader.js +1 -1
  57. package/examples/jsm/loaders/GLTFLoader.js +99 -35
  58. package/examples/jsm/loaders/KTX2Loader.js +19 -0
  59. package/examples/jsm/loaders/LWOLoader.js +8 -6
  60. package/examples/jsm/loaders/LogLuvLoader.js +606 -0
  61. package/examples/jsm/loaders/PLYLoader.js +33 -7
  62. package/examples/jsm/loaders/SVGLoader.js +7 -4
  63. package/examples/jsm/loaders/TDSLoader.js +225 -285
  64. package/examples/jsm/loaders/lwo/LWO2Parser.js +1 -0
  65. package/examples/jsm/loaders/lwo/LWO3Parser.js +2 -2
  66. package/examples/jsm/node-editor/NodeEditor.js +455 -0
  67. package/examples/jsm/node-editor/accessors/NormalEditor.js +30 -0
  68. package/examples/jsm/node-editor/accessors/PositionEditor.js +30 -0
  69. package/examples/jsm/node-editor/accessors/UVEditor.js +26 -0
  70. package/examples/jsm/node-editor/display/BlendEditor.js +43 -0
  71. package/examples/jsm/node-editor/examples/animate-uv.json +1 -0
  72. package/examples/jsm/node-editor/examples/fake-top-light.json +1 -0
  73. package/examples/jsm/node-editor/examples/oscillator-color.json +1 -0
  74. package/examples/jsm/node-editor/examples/rim.json +1 -0
  75. package/examples/jsm/node-editor/inputs/ColorEditor.js +91 -0
  76. package/examples/jsm/node-editor/inputs/FloatEditor.js +24 -0
  77. package/examples/jsm/node-editor/inputs/SliderEditor.js +68 -0
  78. package/examples/jsm/node-editor/inputs/Vector2Editor.js +28 -0
  79. package/examples/jsm/node-editor/inputs/Vector3Editor.js +30 -0
  80. package/examples/jsm/node-editor/inputs/Vector4Editor.js +37 -0
  81. package/examples/jsm/node-editor/materials/StandardMaterialEditor.js +69 -0
  82. package/examples/jsm/node-editor/math/DotEditor.js +36 -0
  83. package/examples/jsm/node-editor/math/InvertEditor.js +38 -0
  84. package/examples/jsm/node-editor/math/LimiterEditor.js +48 -0
  85. package/examples/jsm/node-editor/math/NormalizeEditor.js +26 -0
  86. package/examples/jsm/node-editor/math/OperatorEditor.js +50 -0
  87. package/examples/jsm/node-editor/math/PowerEditor.js +34 -0
  88. package/examples/jsm/node-editor/math/TrigonometryEditor.js +39 -0
  89. package/examples/jsm/node-editor/procedural/CheckerEditor.js +26 -0
  90. package/examples/jsm/node-editor/utils/OscillatorEditor.js +42 -0
  91. package/examples/jsm/node-editor/utils/TimerEditor.js +57 -0
  92. package/examples/jsm/nodes/materials/StandardNodeMaterial.js +1 -1
  93. package/examples/jsm/nodes/materials/nodes/StandardNode.js +6 -6
  94. package/examples/jsm/nodes/utils/ColorSpaceNode.js +1 -49
  95. package/examples/jsm/objects/MarchingCubes.js +46 -152
  96. package/examples/jsm/postprocessing/AdaptiveToneMappingPass.js +1 -1
  97. package/examples/jsm/postprocessing/AfterimagePass.js +1 -1
  98. package/examples/jsm/postprocessing/BloomPass.js +1 -1
  99. package/examples/jsm/postprocessing/BokehPass.js +1 -1
  100. package/examples/jsm/postprocessing/ClearPass.js +1 -1
  101. package/examples/jsm/postprocessing/CubeTexturePass.js +1 -1
  102. package/examples/jsm/postprocessing/DotScreenPass.js +1 -1
  103. package/examples/jsm/postprocessing/EffectComposer.js +3 -3
  104. package/examples/jsm/postprocessing/FilmPass.js +1 -1
  105. package/examples/jsm/postprocessing/GlitchPass.js +1 -1
  106. package/examples/jsm/postprocessing/HalftonePass.js +1 -1
  107. package/examples/jsm/postprocessing/MaskPass.js +1 -1
  108. package/examples/jsm/postprocessing/OutlinePass.js +1 -1
  109. package/examples/jsm/postprocessing/RenderPass.js +1 -1
  110. package/examples/jsm/postprocessing/SAOPass.js +1 -1
  111. package/examples/jsm/postprocessing/SMAAPass.js +1 -1
  112. package/examples/jsm/postprocessing/SSAARenderPass.js +1 -1
  113. package/examples/jsm/postprocessing/SSAOPass.js +1 -1
  114. package/examples/jsm/postprocessing/SSRPass.js +1 -1
  115. package/examples/jsm/postprocessing/SSRrPass.js +1 -1
  116. package/examples/jsm/postprocessing/SavePass.js +1 -1
  117. package/examples/jsm/postprocessing/ShaderPass.js +1 -1
  118. package/examples/jsm/postprocessing/TAARenderPass.js +1 -1
  119. package/examples/jsm/postprocessing/TexturePass.js +1 -1
  120. package/examples/jsm/postprocessing/UnrealBloomPass.js +1 -1
  121. package/examples/jsm/renderers/CSS2DRenderer.js +5 -4
  122. package/examples/jsm/renderers/CSS3DRenderer.js +5 -4
  123. package/examples/jsm/renderers/nodes/Nodes.js +14 -13
  124. package/examples/jsm/renderers/nodes/ShaderNode.js +193 -41
  125. package/examples/jsm/renderers/nodes/accessors/MaterialNode.js +6 -6
  126. package/examples/jsm/renderers/nodes/accessors/ModelViewProjectionNode.js +5 -5
  127. package/examples/jsm/renderers/nodes/accessors/NormalNode.js +14 -3
  128. package/examples/jsm/renderers/nodes/accessors/PointUVNode.js +3 -3
  129. package/examples/jsm/renderers/nodes/accessors/PositionNode.js +15 -5
  130. package/examples/jsm/renderers/nodes/accessors/SkinningNode.js +107 -0
  131. package/examples/jsm/renderers/nodes/accessors/UVNode.js +7 -5
  132. package/examples/jsm/renderers/nodes/core/ArrayInputNode.js +3 -3
  133. package/examples/jsm/renderers/nodes/core/AttributeNode.js +6 -0
  134. package/examples/jsm/renderers/nodes/core/BypassNode.js +38 -0
  135. package/examples/jsm/renderers/nodes/core/CodeNode.js +3 -3
  136. package/examples/jsm/renderers/nodes/core/ContextNode.js +4 -19
  137. package/examples/jsm/renderers/nodes/core/ExpressionNode.js +13 -2
  138. package/examples/jsm/renderers/nodes/core/FunctionNode.js +19 -132
  139. package/examples/jsm/renderers/nodes/core/InputNode.js +13 -3
  140. package/examples/jsm/renderers/nodes/core/Node.js +32 -10
  141. package/examples/jsm/renderers/nodes/core/NodeBuilder.js +146 -128
  142. package/examples/jsm/renderers/nodes/core/NodeFunction.js +22 -0
  143. package/examples/jsm/renderers/nodes/core/NodeFunctionInput.js +4 -4
  144. package/examples/jsm/renderers/nodes/core/NodeKeywords.js +18 -179
  145. package/examples/jsm/renderers/nodes/core/NodeParser.js +11 -0
  146. package/examples/jsm/renderers/nodes/core/NodeVar.js +2 -2
  147. package/examples/jsm/renderers/nodes/core/PropertyNode.js +14 -2
  148. package/examples/jsm/renderers/nodes/core/TempNode.js +10 -13
  149. package/examples/jsm/renderers/nodes/core/VarNode.js +12 -7
  150. package/examples/jsm/renderers/nodes/core/VaryNode.js +23 -8
  151. package/examples/jsm/renderers/nodes/core/constants.js +2 -0
  152. package/examples/jsm/renderers/nodes/display/ColorSpaceNode.js +47 -25
  153. package/examples/jsm/renderers/nodes/display/NormalMapNode.js +21 -22
  154. package/examples/jsm/renderers/nodes/functions/BSDFs.js +64 -101
  155. package/examples/jsm/renderers/nodes/inputs/BufferNode.js +25 -0
  156. package/examples/jsm/renderers/nodes/inputs/IntNode.js +17 -0
  157. package/examples/jsm/renderers/nodes/inputs/TextureNode.js +10 -2
  158. package/examples/jsm/renderers/nodes/lights/LightContextNode.js +20 -14
  159. package/examples/jsm/renderers/nodes/lights/LightNode.js +32 -36
  160. package/examples/jsm/renderers/nodes/math/CondNode.js +60 -0
  161. package/examples/jsm/renderers/nodes/math/MathNode.js +87 -36
  162. package/examples/jsm/renderers/nodes/math/OperatorNode.js +124 -31
  163. package/examples/jsm/renderers/nodes/parsers/GLSLNodeFunction.js +137 -0
  164. package/examples/jsm/renderers/nodes/parsers/GLSLNodeParser.js +14 -0
  165. package/examples/jsm/renderers/nodes/parsers/WGSLNodeFunction.js +89 -0
  166. package/examples/jsm/renderers/nodes/parsers/WGSLNodeParser.js +14 -0
  167. package/examples/jsm/renderers/nodes/procedural/CheckerNode.js +7 -9
  168. package/examples/jsm/renderers/nodes/utils/ArrayElementNode.js +31 -0
  169. package/examples/jsm/renderers/nodes/utils/ConvertNode.js +33 -0
  170. package/examples/jsm/renderers/nodes/utils/JoinNode.js +7 -7
  171. package/examples/jsm/renderers/nodes/utils/OscNode.js +58 -0
  172. package/examples/jsm/renderers/nodes/utils/SplitNode.js +18 -8
  173. package/examples/jsm/renderers/nodes/utils/SpriteSheetUVNode.js +7 -7
  174. package/examples/jsm/renderers/webgl/nodes/SlotNode.js +22 -0
  175. package/examples/jsm/renderers/webgl/nodes/WebGLNodeBuilder.js +191 -94
  176. package/examples/jsm/renderers/webgl/nodes/WebGLNodes.js +2 -2
  177. package/examples/jsm/renderers/webgl/nodes/WebGLPhysicalContextNode.js +2 -2
  178. package/examples/jsm/renderers/webgpu/WebGPUBackground.js +1 -1
  179. package/examples/jsm/renderers/webgpu/WebGPUBindings.js +3 -3
  180. package/examples/jsm/renderers/webgpu/WebGPUComputePipelines.js +2 -4
  181. package/examples/jsm/renderers/webgpu/WebGPUProgrammableStage.js +2 -4
  182. package/examples/jsm/renderers/webgpu/WebGPURenderPipeline.js +15 -23
  183. package/examples/jsm/renderers/webgpu/WebGPURenderPipelines.js +3 -5
  184. package/examples/jsm/renderers/webgpu/WebGPURenderer.js +11 -27
  185. package/examples/jsm/renderers/webgpu/WebGPUTextureUtils.js +62 -28
  186. package/examples/jsm/renderers/webgpu/WebGPUTextures.js +34 -27
  187. package/examples/jsm/renderers/webgpu/constants.js +2 -2
  188. package/examples/jsm/renderers/webgpu/nodes/WebGPUNodeBuilder.js +430 -98
  189. package/examples/jsm/renderers/webgpu/nodes/WebGPUNodes.js +1 -1
  190. package/examples/jsm/utils/RoughnessMipmapper.js +1 -0
  191. package/examples/jsm/webxr/OculusHandPointerModel.js +6 -6
  192. package/package.json +10 -10
  193. package/src/Three.Legacy.js +6 -0
  194. package/src/Three.js +0 -1
  195. package/src/cameras/StereoCamera.js +8 -7
  196. package/src/constants.js +1 -2
  197. package/src/core/Layers.js +7 -1
  198. package/src/core/Object3D.js +2 -0
  199. package/src/extras/PMREMGenerator.js +11 -6
  200. package/src/loaders/FileLoader.js +89 -152
  201. package/src/loaders/ImageLoader.js +9 -4
  202. package/src/loaders/LoaderUtils.js +26 -0
  203. package/src/loaders/MaterialLoader.js +7 -4
  204. package/src/loaders/ObjectLoader.js +2 -0
  205. package/src/materials/Material.js +4 -4
  206. package/src/materials/MeshPhysicalMaterial.js +20 -14
  207. package/src/math/MathUtils.js +5 -16
  208. package/src/renderers/WebGLMultisampleRenderTarget.js +7 -1
  209. package/src/renderers/WebGLRenderer.js +83 -117
  210. package/src/renderers/shaders/ShaderChunk/bsdfs.glsl.js +2 -2
  211. package/src/renderers/shaders/ShaderChunk/encodings_pars_fragment.glsl.js +0 -27
  212. package/src/renderers/shaders/ShaderChunk/envmap_common_pars_fragment.glsl.js +0 -1
  213. package/src/renderers/shaders/ShaderChunk/lights_physical_fragment.glsl.js +19 -6
  214. package/src/renderers/shaders/ShaderChunk/lights_physical_pars_fragment.glsl.js +2 -2
  215. package/src/renderers/shaders/ShaderChunk/transmission_fragment.glsl.js +1 -1
  216. package/src/renderers/shaders/ShaderChunk/transmission_pars_fragment.glsl.js +1 -1
  217. package/src/renderers/shaders/ShaderLib/meshphysical.glsl.js +13 -5
  218. package/src/renderers/shaders/ShaderLib/vsm.glsl.js +2 -1
  219. package/src/renderers/shaders/ShaderLib.js +6 -4
  220. package/src/renderers/shaders/UniformsLib.js +1 -2
  221. package/src/renderers/webgl/WebGLExtensions.js +1 -0
  222. package/src/renderers/webgl/WebGLMaterials.js +27 -15
  223. package/src/renderers/webgl/WebGLProgram.js +10 -6
  224. package/src/renderers/webgl/WebGLPrograms.js +17 -12
  225. package/src/renderers/webgl/WebGLShadowMap.js +14 -5
  226. package/src/renderers/webgl/WebGLState.js +31 -17
  227. package/src/renderers/webgl/WebGLTextures.js +188 -51
  228. package/src/renderers/webgl/WebGLUniforms.js +45 -1
  229. package/src/renderers/webxr/WebXRManager.js +71 -110
  230. package/src/textures/Texture.js +6 -0
  231. package/src/utils.js +37 -1
  232. package/examples/js/controls/DeviceOrientationControls.js +0 -147
  233. package/examples/js/libs/dat.gui.min.js +0 -14
  234. package/examples/jsm/controls/DeviceOrientationControls.js +0 -153
  235. package/examples/jsm/libs/dat.gui.module.js +0 -3575
  236. package/examples/jsm/libs/glslang.js +0 -78
  237. package/examples/jsm/libs/glslang.wasm +0 -0
  238. package/examples/jsm/renderers/nodes/consts/MathConsts.js +0 -7
  239. package/examples/jsm/renderers/nodes/core/ConstNode.js +0 -39
  240. package/examples/jsm/renderers/nodes/core/NodeSlot.js +0 -13
  241. package/examples/jsm/renderers/nodes/core/StructNode.js +0 -80
  242. package/examples/jsm/renderers/nodes/core/StructVarNode.js +0 -75
  243. package/examples/jsm/renderers/nodes/functions/EncodingFunctions.js +0 -99
  244. package/examples/jsm/renderers/nodes/functions/MathFunctions.js +0 -47
  245. package/examples/jsm/renderers/webgpu/nodes/ShaderLib.js +0 -152
  246. package/src/extras/objects/ImmediateRenderObject.js +0 -31
@@ -0,0 +1,3218 @@
1
+ /**
2
+ * https://github.com/sunag/flow
3
+ */
4
+
5
+ function __flow__addCSS( css ) {
6
+
7
+ try {
8
+
9
+ const style = document.createElement( 'style' );
10
+
11
+ style.setAttribute( 'type', 'text/css' );
12
+ style.innerHTML = css;
13
+ document.head.appendChild( style );
14
+
15
+ } catch( e ) {}
16
+
17
+ }
18
+
19
+ __flow__addCSS( `f-canvas,f-canvas canvas { position: absolute; top: 0; left: 0; margin: 0; padding: 0; width: 100%; height: 100%; -webkit-touch-callout: none; }f-canvas { overflow: auto; cursor: grab;}f-canvas canvas.front { z-index: 10;}body.dragging f-canvas,body.connecting f-canvas { overflow: hidden !important;}body.dragging *:not(.drag) { pointer-events: none !important;}f-canvas.grabbing * { cursor: grabbing; user-select: none;}f-canvas canvas { position: fixed; overflow: hidden; pointer-events: none;}f-canvas::-webkit-scrollbar { width: 8px; height: 8px;}f-canvas::-webkit-scrollbar-thumb:hover{ background: #014fc5;}f-canvas::-webkit-scrollbar-track { background: #363636;}f-canvas::-webkit-scrollbar-thumb { background-color: #666666; border-radius: 10px; border: 0;}f-canvas f-content,f-canvas f-area { position: absolute; display: block;}f-node { position: absolute; margin: 0; padding: 0; user-select: none; width: 320px; z-index: 1; cursor: auto; filter: drop-shadow(0 0 10px #00000061); backdrop-filter: blur(4px);}f-node.selected { z-index: 2;}f-node.selected,f-canvas.dragging-rio f-node:hover,f-canvas.dragging-lio f-node:hover { filter: drop-shadow(0 0 10px #00000061) drop-shadow(0 0 8px #4444dd);}f-node.closed f-element:not(:first-child) { display: none;}f-node.center { top: 50%; left: 50%; transform: translate( -50%, -50% );}f-node.top-right { top: 0; right: 0;}f-node.top-center { top: 0; left: 50%; transform: translateX( -50% );}f-node.top-left { top: 0; left: 0;}f-node { transition: filter 0.2s ease;}@keyframes f-open { 0% { transform: scale(.5); filter: blur(30px); } 100% { transform: scale(1); filter: unset }}f-node { animation: .2s f-open 1 alternate ease-out;}f-menu,f-menu button,f-element,f-element input,f-element select,f-element button,f-element textarea { font-family: 'Open Sans', sans-serif; font-size: 13px; text-transform: capitalize; color: #eeeeee; outline: solid 0px #000; letter-spacing: .2px; margin: 0; padding: 0; border: 0; user-select: none; -webkit-tap-highlight-color: transparent; transition: background 0.2s ease;}f-element input { transition: background 0.1s ease;}f-element input,f-element select,f-element button,f-element textarea { background-color: #242427;}f-element { position: relative; width: calc( 100% - 14px ); background: rgba(45, 45, 48, 0.95); pointer-events: auto; border-bottom: 2px solid #232323; display: flex; padding-left: 7px; padding-right: 7px; padding-top: 2px; padding-bottom: 2px;}f-element { height: 24px;}f-element input { margin-top: 2px; margin-bottom: 2px; box-shadow: inset 0px 1px 1px rgb(0 0 0 / 20%), 0px 1px 0px rgb(255 255 255 / 5%); margin-left: 2px; margin-right: 2px; width: 100%; padding-left: 4px; padding-right: 4px;}f-element input.number { cursor: col-resize;}f-element input:focus[type='text'], f-element input:focus[type='range'], f-element input:focus[type='color'] { background: rgba( 0, 0, 0, 0.6 ); outline: solid 1px rgba( 0, 80, 200, 0.98 );}f-element input[type='color'] { appearance: none; padding: 0; margin-left: 2px; margin-right: 2px; height: calc( 100% - 4px ); margin-top: 2px; border: none; }f-element input[type='color']::-webkit-color-swatch-wrapper { padding: 2px;}f-element input[type='color']::-webkit-color-swatch { border: none; cursor: alias;}f-element input[type='range'] { appearance: none; width: 100%; overflow: hidden; padding: 0; cursor: ew-resize;}f-element input[type='range']::-webkit-slider-runnable-track { appearance: none; height: 10px; color: #13bba4; margin: 0;}f-element input[type='range']::-webkit-slider-thumb { appearance: none; width: 0; background: #434343; box-shadow: -500px 0 0 500px rgba( 0, 120, 255, 0.98 ); border-radius: 50%; border: 0 !important;}f-element input[type='range']::-webkit-slider-runnable-track { margin-left: -4px; margin-right: -5px;}f-element input[type='checkbox'] { appearance: none; cursor: pointer;}f-element input[type='checkbox'].toggle { height: 20px; width: 45px; border-radius: 16px; display: inline-block; position: relative; margin: 0; margin-top: 2px; background: linear-gradient( 0deg, #292929 0%, #0a0a0ac2 100% ); transition: all 0.2s ease;}f-element input[type='checkbox'].toggle:after { content: ""; position: absolute; top: 2px; left: 2px; width: 16px; height: 16px; border-radius: 50%; background: white; box-shadow: 0 1px 2px rgba(44, 44, 44, 0.2); transition: all 0.2s cubic-bezier(0.5, 0.1, 0.75, 1.35);}f-element input[type='checkbox'].toggle:checked { background: linear-gradient( 0deg, #0177fb 0%, #0177fb 100% );}f-element input[type='checkbox'].toggle:checked:after { transform: translatex(25px);}f-element.auto-height { display: table;}f-element textarea { width: calc( 100% - 18px ); padding-top: 1px; padding-bottom: 3px; padding-left: 3px; padding-right: 8px; margin-top: 2px; margin-left: 2px; height: calc( 100% - 8px ); max-height: 300px; border-radius: 2px; resize: none; box-shadow: inset 0px 1px 1px rgb(0 0 0 / 20%), 0px 1px 0px rgb(255 255 255 / 5%);}f-element.auto-height textarea { resize: auto;}f-element select { width: 100%; margin-top: 2px; margin-bottom: 2px; margin-left: 2px; margin-right: 2px; padding-left: 5px; cursor: pointer; box-shadow: inset 0px 1px 1px rgb(0 0 0 / 20%), 0px 1px 0px rgb(255 255 255 / 5%);}f-element f-toolbar { position: absolute; display: flex; top: 0; width: 100%; height: 100%; align-content: space-around;}f-element.output-right f-toolbar { right: 7px; float: right; justify-content: end;}f-element f-toolbar { margin-top: auto; margin-bottom: auto; margin-left: 3px; margin-right: 3px; font-size: 18px; line-height: 18px;}f-element f-toolbar button { opacity: .7; cursor: pointer; font-size: 14px; width: unset; height: unset; border-radius: unset; border: unset; outline: 0; background-color: unset; box-shadow: unset;}f-element f-toolbar button:hover,f-element f-toolbar button:active { opacity: 1; border: 0; background-color: unset;}f-element input.range-value { width: 60px; text-align: center;}f-menu.context button,f-element button { width: 100%; height: calc( 100% - 4px ); margin-left: 2px; margin-right: 2px; margin-top: 2px; border-radius: 3px; cursor: pointer;}f-element button { box-shadow: inset 1px 1px 1px 0 rgb(255 255 255 / 17%), inset -2px -2px 2px 0 rgb(0 0 0 / 26%);}f-element button:hover { color: #fff; background-color: #2a2a2a;}f-element button:active { border: 1px solid rgba( 0, 120, 255, 0.98 );}f-element f-inputs,f-element f-subinputs { display: flex; width: 100%;}f-element f-inputs { left: 100px; top: 50%; transform: translateY(-50%); position: absolute; width: calc( 100% - 106px ); height: calc( 100% - 4px ); z-index: 1;}f-element f-label,f-element span { margin: auto; text-shadow: 1px 1px 0px #0007;}f-element f-label { padding-left: 4px; white-space: nowrap; position: absolute; top: 50%; transform: translateY(-50%); width: calc( 100% - 20px );}f-element.right f-label { text-align: right;}f-element f-label i { float: left; font-size: 18px; margin-right: 6px;}f-element f-label.center { width: 100%; text-align: center; display: block;}f-element.title { height: 29px; background-color: #3a3a3ab0; background-color: #3b3b43ed; cursor: all-scroll; border-top-left-radius: 6px; border-top-right-radius: 6px;}f-element.blue { background-color: #014fc5;}f-element.red { background-color: #bd0b0b;}f-element.green { background-color: #148d05;}f-element.yellow { background-color: #d6b100;}f-element.title.left { text-align: left; display: inline-grid; justify-content: start;}f-element.title span { text-align: center; font-size: 15px; padding-top: 2px;}f-element.title i { font-size: 18px; position: absolute; right: 10px; top: 50%; transform: translateY(-50%); opacity: .5;}f-element.output-right.title i { left: 10px; right: unset;}f-element.title.left span { text-align: left;}f-element f-io { border: 2px solid #dadada; width: 7px; height: 7px; position: absolute; background: #242427; border-radius: 8px; float: left; left: -7px; top: calc( 50% - 5px ); cursor: alias; box-shadow: 0 0 3px 2px #0000005e; z-index: 1;}f-element f-io.connect,f-canvas.dragging-rio f-element:hover f-io.lio,f-canvas.dragging-lio f-element:hover f-io.rio { border: 2px solid #0177fb; zoom: 1.4;}f-node.io-connect f-io:not(.connect) { border: 2px solid #dadada !important; zoom: 1 !important;}f-element f-io.rio { float: right; right: -7px; left: unset;}f-element f-disconnect { position: absolute; left: -35px; top: 50%; font-size: 22px; transform: translateY( -50% ); filter: drop-shadow(0 0 5px #000); text-shadow: 0px 0px 5px black; cursor: pointer;}f-element.output-right f-disconnect { right: -35px; left: unset;}f-element f-disconnect:hover { color: #ff3300;}f-element textarea::-webkit-scrollbar { width: 6px;}f-element textarea::-webkit-scrollbar-track { background: #111; } f-element textarea::-webkit-scrollbar-thumb { background: #0177fb; }f-element textarea::-webkit-scrollbar-thumb:hover { background: #1187ff; }f-element.small { height: 18px;}f-element.large { height: 36px;}body.connecting f-node:not(.io-connect) f-element:hover,f-element.select { background-color: rgba(61, 70, 82, 0.98);}f-tooltip { pointer-events: none;}f-tooltip { position: absolute; left: 0; top: 0; background: rgba(0,0,0,.8); backdrop-filter: blur(4px); font-size: 14px; padding: 7px; border-radius: 10px; top: 50%; transform: translateY(-50%); visibility: hidden; pointer-events: none; opacity: 0; transition: all 0.3s ease; z-index: 150; white-space: nowrap;}f-menu.context { position: absolute; width: 170px; padding: 2px; margin: 0; background: #17171794; z-index: 110; font-size: 12px; border-radius: 6px; backdrop-filter: blur(6px); border: 1px solid #7e7e7e45; box-shadow: 3px 3px 6px rgba(0,0,0,.2); transition: opacity 0.2s ease, transform 0.1s ease;}f-menu.context.hidden { visibility: hidden; opacity: 0;}f-menu.context f-item { display: block; position: relative; margin: 0; padding: 0; white-space: nowrap;}f-menu.context f-item.submenu::after { content: ""; position: absolute; right: 6px; top: 50%; -webkit-transform: translateY(-50%); transform: translateY(-50%); border: 5px solid transparent; border-left-color: #808080;}f-menu.context f-item:hover > f-menu,f-menu.context f-item.active > f-menu { visibility: unset; transform: unset; opacity: unset;}f-menu.context f-menu { top: 0px; left: calc( 100% - 4px );}f-menu.context f-item button { overflow: visible; display: block; width: calc( 100% - 6px ); text-align: left; cursor: pointer; white-space: nowrap; padding: 6px 8px; border-radius: 3px; background: #2d2d32; border: 0; color: #ddd; margin: 3px; text-shadow: 1px 1px 0px #0007;}f-menu.context f-item button i { float: left; font-size: 16px;}f-menu.context f-item button span { margin-left: 6px;}f-menu.context f-item:hover > button,f-menu.context f-item.active > button { color: #fff; background: #313136;}f-menu.context f-item button:active { outline: solid 1px rgba( 0, 80, 200, 0.98 );}f-menu.context f-item f-tooltip { margin-left: 120px;}f-menu.circle { position: absolute; left: 30px; top: 30px; z-index: 100;}f-menu.circle f-item { display: flex; justify-content: end; align-content: space-around; margin-bottom: 12px;}f-menu.circle f-item button { width: 50px; height: 50px; font-size: 26px; background: #17171794; border-radius: 50%; backdrop-filter: blur(6px); border: 1px solid #7e7e7e45; line-height: 100%; cursor: pointer; box-shadow: 3px 3px 6px rgba(0,0,0,.2);}f-menu.circle f-item f-tooltip { margin-left: 50px;}.f-rounded f-node f-element,.f-rounded f-node f-element.title.left { border-radius: 10px 5px 10px 5px;}.f-rounded f-node f-element input, .f-rounded f-node f-element select,.f-rounded f-node f-element button,.f-rounded f-node f-element textarea,.f-rounded f-node f-element input[type='checkbox'].toggle,.f-rounded f-node f-element input[type='checkbox'].toggle:after { border-radius: 20px 10px;}.f-rounded f-node f-element input { padding-left: 7px; padding-right: 7px;}.f-rounded f-menu.context,.f-rounded f-menu.context f-item button { border-radius: 20px 10px;}@media (hover: hover) and (pointer: fine) { f-element f-io:hover { border: 2px solid #0177fb; zoom: 1.4; } f-menu.circle f-item button:hover { background-color: #2a2a2a; } f-menu.circle f-item button:hover > f-tooltip, f-menu.context f-item button:hover > f-tooltip { visibility: visible; transform: translate(10px, -50%); opacity: 1; } f-menu.circle f-item button:focus > f-tooltip, f-menu.context f-item button:focus > f-tooltip { visibility: hidden; opacity: 0; }}f-canvas { will-change: top, left;}f-node { will-change: transform !important;}` );
20
+
21
+ const REVISION = '1';
22
+
23
+ let _id = 0;
24
+
25
+ class Serializer extends EventTarget {
26
+
27
+ constructor() {
28
+
29
+ super();
30
+
31
+ this._id = _id ++;
32
+
33
+ this._serializable = true;
34
+
35
+ }
36
+
37
+ get id() {
38
+
39
+ return this._id;
40
+
41
+ }
42
+
43
+ setSerializable( value ) {
44
+
45
+ this._serializable = value;
46
+
47
+ return this;
48
+
49
+ }
50
+
51
+ getSerializable() {
52
+
53
+ return this._serializable;
54
+
55
+ }
56
+
57
+ serialize( /*data*/ ) {
58
+
59
+ console.warn( 'Serializer: Abstract function.' );
60
+
61
+ }
62
+
63
+ deserialize( /*data*/ ) {
64
+
65
+ console.warn( 'Serializer: Abstract function.' );
66
+
67
+ }
68
+
69
+ toJSON( data = null ) {
70
+
71
+ let object = null;
72
+
73
+ const id = this.id;
74
+
75
+ if ( data !== null ) {
76
+
77
+ const objects = data.objects;
78
+
79
+ object = objects[ id ];
80
+
81
+ if ( object === undefined ) {
82
+
83
+ object = { objects };
84
+
85
+ this.serialize( object );
86
+
87
+ delete object.objects;
88
+
89
+ objects[ id ] = object;
90
+
91
+ }
92
+
93
+ } else {
94
+
95
+ object = { objects: {} };
96
+
97
+ this.serialize( object );
98
+
99
+ }
100
+
101
+ object.id = id;
102
+ object.type = this.constructor.name;
103
+
104
+ return object;
105
+
106
+ }
107
+
108
+ }
109
+
110
+ const draggableDOM = ( dom, callback = null, className = 'dragging' ) => {
111
+
112
+ let dragData = null;
113
+
114
+ const getZoom = () => {
115
+
116
+ let zoomDOM = dom;
117
+
118
+ while ( zoomDOM && zoomDOM !== document ) {
119
+
120
+ const zoom = zoomDOM.style.zoom;
121
+
122
+ if ( zoom ) {
123
+
124
+ return Number( zoom );
125
+
126
+ }
127
+
128
+ zoomDOM = zoomDOM.parentNode;
129
+
130
+ }
131
+
132
+ return 1;
133
+
134
+ };
135
+
136
+ const onMouseDown = ( e ) => {
137
+
138
+ const event = e.touches ? e.touches[ 0 ] : e;
139
+
140
+ e.stopImmediatePropagation();
141
+
142
+ dragData = {
143
+ client: { x: event.clientX, y: event.clientY },
144
+ delta: { x: 0, y: 0 },
145
+ start: { x: dom.offsetLeft, y: dom.offsetTop },
146
+ dragging: false,
147
+ isTouch: !! e.touches
148
+ };
149
+
150
+ window.addEventListener( 'mousemove', onGlobalMouseMove );
151
+ window.addEventListener( 'mouseup', onGlobalMouseUp );
152
+
153
+ window.addEventListener( 'touchmove', onGlobalMouseMove );
154
+ window.addEventListener( 'touchend', onGlobalMouseUp );
155
+
156
+ };
157
+
158
+ const onGlobalMouseMove = ( e ) => {
159
+
160
+ const { start, delta, client } = dragData;
161
+
162
+ const event = e.touches ? e.touches[ 0 ] : e;
163
+
164
+ const zoom = getZoom();
165
+
166
+ delta.x = ( event.clientX - client.x ) / zoom;
167
+ delta.y = ( event.clientY - client.y ) / zoom;
168
+
169
+ dragData.x = start.x + delta.x;
170
+ dragData.y = start.y + delta.y;
171
+
172
+ if ( dragData.dragging === true ) {
173
+
174
+ if ( callback !== null ) {
175
+
176
+ callback( dragData );
177
+
178
+ } else {
179
+
180
+ dom.style.cssText += `; left: ${ dragData.x }px; top: ${ dragData.y }px;`;
181
+
182
+ }
183
+
184
+ e.stopImmediatePropagation();
185
+
186
+ } else {
187
+
188
+ if ( Math.abs( delta.x ) > 2 || Math.abs( delta.y ) > 2 ) {
189
+
190
+ dragData.dragging = true;
191
+
192
+ dom.classList.add( 'drag' );
193
+
194
+ if ( className ) document.body.classList.add( className );
195
+
196
+ e.stopImmediatePropagation();
197
+
198
+ }
199
+
200
+ }
201
+
202
+ };
203
+
204
+ const onGlobalMouseUp = ( e ) => {
205
+
206
+ e.stopImmediatePropagation();
207
+
208
+ dom.classList.remove( 'drag' );
209
+
210
+ if ( className ) document.body.classList.remove( className );
211
+
212
+ window.removeEventListener( 'mousemove', onGlobalMouseMove );
213
+ window.removeEventListener( 'mouseup', onGlobalMouseUp );
214
+
215
+ window.removeEventListener( 'touchmove', onGlobalMouseMove );
216
+ window.removeEventListener( 'touchend', onGlobalMouseUp );
217
+
218
+ if ( callback === null ) {
219
+
220
+ dom.removeEventListener( 'mousedown', onMouseDown );
221
+ dom.removeEventListener( 'touchstart', onMouseDown );
222
+
223
+ }
224
+
225
+ dragData.dragging = false;
226
+
227
+ if ( callback !== null ) {
228
+
229
+ callback( dragData );
230
+
231
+ }
232
+
233
+ };
234
+
235
+ if ( dom instanceof Event ) {
236
+
237
+ const e = dom;
238
+ dom = e.target;
239
+
240
+ onMouseDown( e );
241
+
242
+ } else {
243
+
244
+ dom.addEventListener( 'mousedown', onMouseDown );
245
+ dom.addEventListener( 'touchstart', onMouseDown );
246
+
247
+ }
248
+
249
+ };
250
+
251
+ const dispatchEventList = ( list, ...params ) => {
252
+
253
+ for ( const callback of list ) {
254
+
255
+ callback( ...params );
256
+
257
+ }
258
+
259
+ };
260
+
261
+ const toPX = ( val ) => {
262
+
263
+ if ( isNaN( val ) === false ) {
264
+
265
+ val = `${ val }px`;
266
+
267
+ }
268
+
269
+ return val;
270
+
271
+ };
272
+
273
+ const toHex = ( val ) => {
274
+
275
+ if ( isNaN( val ) === false ) {
276
+
277
+ val = `#${ val.toString( 16 ).padStart( 6, '0' ) }`;
278
+
279
+ }
280
+
281
+ return val;
282
+
283
+ };
284
+
285
+ var Utils = /*#__PURE__*/Object.freeze({
286
+ __proto__: null,
287
+ draggableDOM: draggableDOM,
288
+ dispatchEventList: dispatchEventList,
289
+ toPX: toPX,
290
+ toHex: toHex
291
+ });
292
+
293
+ class Link {
294
+
295
+ constructor( inputElement = null, outputElement = null ) {
296
+
297
+ this.inputElement = inputElement;
298
+ this.outputElement = outputElement;
299
+
300
+ }
301
+
302
+ get lioElement() {
303
+
304
+ if ( Link.InputDirection === 'left' ) {
305
+
306
+ return this.outputElement;
307
+
308
+ } else {
309
+
310
+ return this.inputElement;
311
+
312
+ }
313
+
314
+ }
315
+
316
+ get rioElement() {
317
+
318
+ if ( Link.InputDirection === 'left' ) {
319
+
320
+ return this.inputElement;
321
+
322
+ } else {
323
+
324
+ return this.outputElement;
325
+
326
+ }
327
+
328
+ }
329
+
330
+ }
331
+
332
+ //Link.InputDirection = 'right';
333
+ Link.InputDirection = 'left';
334
+
335
+ let selected = null;
336
+
337
+ class Element extends Serializer {
338
+
339
+ constructor( draggable = false ) {
340
+
341
+ super();
342
+
343
+ const dom = document.createElement( 'f-element' );
344
+ dom.element = this;
345
+
346
+ const onSelect = ( e ) => {
347
+
348
+ let element = this;
349
+
350
+ if ( e.changedTouches && e.changedTouches.length > 0 ) {
351
+
352
+ const touch = e.changedTouches[ 0 ];
353
+
354
+ let overDOM = document.elementFromPoint( touch.clientX, touch.clientY );
355
+
356
+ while ( overDOM && ( ! overDOM.element || ! overDOM.element.isElement ) ) {
357
+
358
+ overDOM = overDOM.parentNode;
359
+
360
+ }
361
+
362
+ element = overDOM ? overDOM.element : null;
363
+
364
+ }
365
+
366
+ selected = element;
367
+
368
+ };
369
+
370
+ if ( draggable === false ) {
371
+
372
+ dom.ontouchstart = dom.onmousedown = ( e ) => {
373
+
374
+ e.stopPropagation();
375
+
376
+ };
377
+
378
+ }
379
+
380
+ dom.addEventListener( 'mouseup', onSelect, true );
381
+ dom.addEventListener( 'touchend', onSelect );
382
+
383
+ this.inputs = [];
384
+
385
+ this.links = [];
386
+
387
+ this.dom = dom;
388
+
389
+ this.lioLength = 0;
390
+ this.rioLength = 0;
391
+
392
+ this.events = {
393
+ 'connect': [],
394
+ 'connectChildren': []
395
+ };
396
+
397
+ this.node = null;
398
+
399
+ this.style = '';
400
+
401
+ this.extra = null;
402
+
403
+ this.visible = true;
404
+
405
+ this.inputsDOM = dom;
406
+
407
+ this.disconnectDOM = null;
408
+
409
+ this.lioDOM = this._createIO( 'lio' );
410
+ this.rioDOM = this._createIO( 'rio' );
411
+
412
+ this.dom.classList.add( `output-${ Link.InputDirection }` );
413
+
414
+ this.dom.appendChild( this.lioDOM );
415
+ this.dom.appendChild( this.rioDOM );
416
+
417
+ this.addEventListener( 'connect', ( ) => {
418
+
419
+ dispatchEventList( this.events.connect, this );
420
+
421
+ } );
422
+
423
+ this.addEventListener( 'connectChildren', ( ) => {
424
+
425
+ dispatchEventList( this.events.connectChildren, this );
426
+
427
+ } );
428
+
429
+ }
430
+
431
+ onConnect( callback, childrens = false ) {
432
+
433
+ this.events.connect.push( callback );
434
+
435
+ if ( childrens ) {
436
+
437
+ this.events.connectChildren.push( callback );
438
+
439
+ }
440
+
441
+ return this;
442
+
443
+ }
444
+
445
+ setExtra( value ) {
446
+
447
+ this.extra = value;
448
+
449
+ return this;
450
+
451
+ }
452
+
453
+ getExtra() {
454
+
455
+ return this.extra;
456
+
457
+ }
458
+
459
+ setVisible( value ) {
460
+
461
+ this.visible = value;
462
+
463
+ this.dom.style.display = value ? '' : 'none';
464
+
465
+ return this;
466
+
467
+ }
468
+
469
+ getVisible() {
470
+
471
+ return this.visible;
472
+
473
+ }
474
+
475
+ setStyle( style ) {
476
+
477
+ const dom = this.dom;
478
+
479
+ if ( this.style ) dom.classList.remove( this.style );
480
+
481
+ if ( style ) dom.classList.add( style );
482
+
483
+ this.style = style;
484
+
485
+ return this;
486
+
487
+ }
488
+
489
+ setInput( length ) {
490
+
491
+ if ( Link.InputDirection === 'left' ) {
492
+
493
+ return this.setLIO( length );
494
+
495
+ } else {
496
+
497
+ return this.setRIO( length );
498
+
499
+ }
500
+
501
+ }
502
+
503
+ setOutput( length ) {
504
+
505
+ if ( Link.InputDirection === 'left' ) {
506
+
507
+ return this.setRIO( length );
508
+
509
+ } else {
510
+
511
+ return this.setLIO( length );
512
+
513
+ }
514
+
515
+ }
516
+
517
+ get inputLength() {
518
+
519
+ if ( Link.InputDirection === 'left' ) {
520
+
521
+ return this.lioLength;
522
+
523
+ } else {
524
+
525
+ return this.rioLength;
526
+
527
+ }
528
+
529
+ }
530
+
531
+ get outputLength() {
532
+
533
+ if ( Link.InputDirection === 'left' ) {
534
+
535
+ return this.rioLength;
536
+
537
+ } else {
538
+
539
+ return this.lioLength;
540
+
541
+ }
542
+
543
+ }
544
+
545
+ setLIO( length ) {
546
+
547
+ this.lioLength = length;
548
+
549
+ this.lioDOM.style.visibility = length > 0 ? '' : 'hidden';
550
+
551
+ return this;
552
+
553
+ }
554
+
555
+ setRIO( length ) {
556
+
557
+ this.rioLength = length;
558
+
559
+ this.rioDOM.style.visibility = length > 0 ? '' : 'hidden';
560
+
561
+ return this;
562
+
563
+ }
564
+
565
+ add( input ) {
566
+
567
+ this.inputs.push( input );
568
+
569
+ input.element = this;
570
+
571
+ this.inputsDOM.appendChild( input.dom );
572
+
573
+ return this;
574
+
575
+ }
576
+
577
+ setHeight( val ) {
578
+
579
+ this.dom.style.height = toPX( val );
580
+
581
+ return this;
582
+
583
+ }
584
+
585
+ getHeight() {
586
+
587
+ return this.dom.style.height;
588
+
589
+ }
590
+
591
+ connect( element = null ) {
592
+
593
+ if ( this.disconnectDOM !== null ) {
594
+
595
+ // remove the current input
596
+
597
+ this.disconnectDOM.dispatchEvent( new Event( 'disconnect' ) );
598
+
599
+ }
600
+
601
+ if ( element !== null ) {
602
+
603
+ const link = new Link( this, element );
604
+
605
+ this.links.push( link );
606
+
607
+ if ( this.disconnectDOM === null ) {
608
+
609
+ this.disconnectDOM = document.createElement( 'f-disconnect' );
610
+ this.disconnectDOM.innerText = '✖';
611
+ this.dom.appendChild( this.disconnectDOM );
612
+
613
+ const onDisconnect = () => {
614
+
615
+ this.links = [];
616
+ this.dom.removeChild( this.disconnectDOM );
617
+
618
+ this.disconnectDOM.removeEventListener( 'mousedown', onClick, true );
619
+ this.disconnectDOM.removeEventListener( 'touchstart', onClick, true );
620
+ this.disconnectDOM.removeEventListener( 'disconnect', onDisconnect, true );
621
+ element.removeEventListener( 'connect', onConnect );
622
+ element.removeEventListener( 'connectChildren', onConnect );
623
+ element.removeEventListener( 'nodeConnect', onConnect );
624
+ element.removeEventListener( 'nodeConnectChildren', onConnect );
625
+ element.removeEventListener( 'dispose', onDispose );
626
+
627
+ this.disconnectDOM = null;
628
+
629
+ };
630
+
631
+ const onConnect = ( e ) => {
632
+
633
+ this.dispatchEvent( new Event( 'connectChildren' ) );
634
+
635
+ };
636
+
637
+ const onDispose = () => {
638
+
639
+ this.connect();
640
+
641
+ };
642
+
643
+ const onClick = ( e ) => {
644
+
645
+ e.stopPropagation();
646
+
647
+ this.connect();
648
+
649
+ };
650
+
651
+ this.disconnectDOM.addEventListener( 'mousedown', onClick, true );
652
+ this.disconnectDOM.addEventListener( 'touchstart', onClick, true );
653
+ this.disconnectDOM.addEventListener( 'disconnect', onDisconnect, true );
654
+ element.addEventListener( 'connect', onConnect );
655
+ element.addEventListener( 'connectChildren', onConnect );
656
+ element.addEventListener( 'nodeConnect', onConnect );
657
+ element.addEventListener( 'nodeConnectChildren', onConnect );
658
+ element.addEventListener( 'dispose', onDispose );
659
+
660
+ }
661
+
662
+ }
663
+
664
+ this.dispatchEvent( new Event( 'connect' ) );
665
+
666
+ return this;
667
+
668
+ }
669
+
670
+ dispose() {
671
+
672
+ this.dispatchEvent( new Event( 'dispose' ) );
673
+
674
+ }
675
+
676
+ serialize( data ) {
677
+
678
+ const height = this.getHeight();
679
+
680
+ const inputs = [];
681
+ const links = [];
682
+
683
+ for ( const input of this.inputs ) {
684
+
685
+ inputs.push( input.toJSON( data ).id );
686
+
687
+ }
688
+
689
+ for ( const link of this.links ) {
690
+
691
+ if ( link.inputElement !== null && link.outputElement !== null ) {
692
+
693
+ links.push( link.outputElement.toJSON( data ).id );
694
+
695
+ }
696
+
697
+ }
698
+
699
+ if ( this.inputLength > 0 ) data.inputLength = this.inputLength;
700
+ if ( this.outputLength > 0 ) data.outputLength = this.outputLength;
701
+
702
+ if ( inputs.length > 0 ) data.inputs = inputs;
703
+ if ( links.length > 0 ) data.links = links;
704
+
705
+ if ( this.style !== '' ) {
706
+
707
+ data.style = this.style;
708
+
709
+ }
710
+
711
+ if ( height !== '' ) {
712
+
713
+ data.height = height;
714
+
715
+ }
716
+
717
+ }
718
+
719
+ deserialize( data ) {
720
+
721
+ if ( data.inputLength !== undefined ) this.setInput( data.inputLength );
722
+ if ( data.outputLength !== undefined ) this.setOutput( data.outputLength );
723
+
724
+ if ( data.inputs !== undefined ) {
725
+
726
+ const inputs = this.inputs;
727
+
728
+ if ( inputs.length > 0 ) {
729
+
730
+ let index = 0;
731
+
732
+ for ( const id of data.inputs ) {
733
+
734
+ data.objects[ id ] = inputs[ index ++ ];
735
+
736
+ }
737
+
738
+ } else {
739
+
740
+ for ( const id of data.inputs ) {
741
+
742
+ this.add( data.objects[ id ] );
743
+
744
+ }
745
+
746
+ }
747
+
748
+ }
749
+
750
+ if ( data.links !== undefined ) {
751
+
752
+ for ( const id of data.links ) {
753
+
754
+ this.connect( data.objects[ id ] );
755
+
756
+ }
757
+
758
+ }
759
+
760
+ if ( data.style !== undefined ) {
761
+
762
+ this.setStyle( data.style );
763
+
764
+ }
765
+
766
+ if ( data.height !== undefined ) {
767
+
768
+ this.setHeight( data.height );
769
+
770
+ }
771
+
772
+ }
773
+
774
+ get linkedExtra() {
775
+
776
+ const linkedElement = this.linkedElement;
777
+
778
+ return linkedElement ? linkedElement.getExtra() : null;
779
+
780
+ }
781
+
782
+ get linkedElement() {
783
+
784
+ const link = this.link;
785
+
786
+ return link ? link.outputElement : null;
787
+
788
+ }
789
+
790
+ get link() {
791
+
792
+ return this.links[ 0 ];
793
+
794
+ }
795
+
796
+ _createIO( type ) {
797
+
798
+ const { dom } = this;
799
+
800
+ const ioDOM = document.createElement( 'f-io' );
801
+ ioDOM.style.visibility = 'hidden';
802
+ ioDOM.className = type;
803
+
804
+ const onConnectEvent = ( e ) => {
805
+
806
+ e.preventDefault();
807
+
808
+ e.stopPropagation();
809
+
810
+ selected = null;
811
+
812
+ const nodeDOM = this.node.dom;
813
+
814
+ nodeDOM.classList.add( 'io-connect' );
815
+
816
+ ioDOM.classList.add( 'connect' );
817
+ dom.classList.add( 'select' );
818
+
819
+ const defaultOutput = Link.InputDirection === 'left' ? 'lio' : 'rio';
820
+
821
+ const link = type === defaultOutput ? new Link( this ) : new Link( null, this );
822
+
823
+ this.links.push( link );
824
+
825
+ draggableDOM( e, ( data ) => {
826
+
827
+ if ( data.dragging === false ) {
828
+
829
+ nodeDOM.classList.remove( 'io-connect' );
830
+
831
+ ioDOM.classList.remove( 'connect' );
832
+ dom.classList.remove( 'select' );
833
+
834
+ this.links.splice( this.links.indexOf( link ), 1 );
835
+
836
+ if ( selected !== null ) {
837
+
838
+ if ( type === defaultOutput ) {
839
+
840
+ link.outputElement = selected;
841
+
842
+ } else {
843
+
844
+ link.inputElement = selected;
845
+
846
+ }
847
+
848
+ // check if is an is circular link
849
+
850
+ if ( link.outputElement.node.isCircular( link.inputElement.node ) ) {
851
+
852
+ return;
853
+
854
+ }
855
+
856
+ //
857
+
858
+ if ( link.inputElement.inputLength > 0 && link.outputElement.outputLength > 0 ) {
859
+
860
+ link.inputElement.connect( link.outputElement );
861
+
862
+ }
863
+
864
+ }
865
+
866
+ }
867
+
868
+ }, 'connecting' );
869
+
870
+ };
871
+
872
+ ioDOM.addEventListener( 'mousedown', onConnectEvent, true );
873
+ ioDOM.addEventListener( 'touchstart', onConnectEvent, true );
874
+
875
+ return ioDOM;
876
+
877
+ }
878
+
879
+ }
880
+
881
+ Element.prototype.isElement = true;
882
+
883
+ class Input extends Serializer {
884
+
885
+ constructor( dom ) {
886
+
887
+ super();
888
+
889
+ this.dom = dom;
890
+
891
+ this.element = null;
892
+
893
+ this.extra = null;
894
+
895
+ this.events = {
896
+ 'change': [],
897
+ 'click': []
898
+ };
899
+
900
+ this.addEventListener( 'change', ( ) => {
901
+
902
+ dispatchEventList( this.events.change, this );
903
+
904
+ } );
905
+
906
+ this.addEventListener( 'click', ( ) => {
907
+
908
+ dispatchEventList( this.events.click, this );
909
+
910
+ } );
911
+
912
+ }
913
+
914
+ setExtra( value ) {
915
+
916
+ this.extra = value;
917
+
918
+ return this;
919
+
920
+ }
921
+
922
+ getExtra() {
923
+
924
+ return this.extra;
925
+
926
+ }
927
+
928
+ setToolTip( text ) {
929
+
930
+ const div = document.createElement( 'f-tooltip' );
931
+ div.innerText = text;
932
+
933
+ this.dom.appendChild( div );
934
+
935
+ return this;
936
+
937
+ }
938
+
939
+ onChange( callback ) {
940
+
941
+ this.events.change.push( callback );
942
+
943
+ return this;
944
+
945
+ }
946
+
947
+ onClick( callback ) {
948
+
949
+ this.events.click.push( callback );
950
+
951
+ return this;
952
+
953
+ }
954
+
955
+ setValue( value, dispatch = true ) {
956
+
957
+ this.dom.value = value;
958
+
959
+ if ( dispatch ) this.dispatchEvent( new Event( 'change' ) );
960
+
961
+ return this;
962
+
963
+ }
964
+
965
+ getValue() {
966
+
967
+ return this.dom.value;
968
+
969
+ }
970
+
971
+ serialize( data ) {
972
+
973
+ data.value = this.getValue();
974
+
975
+ }
976
+
977
+ deserialize( data ) {
978
+
979
+ this.setValue( data.value );
980
+
981
+ }
982
+
983
+ }
984
+
985
+ Input.prototype.isInput = true;
986
+
987
+ class Node extends Serializer {
988
+
989
+ constructor() {
990
+
991
+ super();
992
+
993
+ const dom = document.createElement( 'f-node' );
994
+
995
+ const onDown = () => {
996
+
997
+ const canvas = this.canvas;
998
+
999
+ if ( canvas !== null ) {
1000
+
1001
+ canvas.select( this );
1002
+
1003
+ }
1004
+
1005
+ };
1006
+
1007
+ dom.addEventListener( 'mousedown', onDown, true );
1008
+ dom.addEventListener( 'touchstart', onDown, true );
1009
+
1010
+ this._onConnect = ( e ) => {
1011
+
1012
+ const { target } = e;
1013
+
1014
+ for ( const element of this.elements ) {
1015
+
1016
+ if ( element !== target ) {
1017
+
1018
+ element.dispatchEvent( new Event( 'nodeConnect' ) );
1019
+
1020
+ }
1021
+
1022
+ }
1023
+
1024
+ };
1025
+
1026
+ this._onConnectChildren = ( e ) => {
1027
+
1028
+ const { target } = e;
1029
+
1030
+ for ( const element of this.elements ) {
1031
+
1032
+ if ( element !== target ) {
1033
+
1034
+ element.dispatchEvent( new Event( 'nodeConnectChildren' ) );
1035
+
1036
+ }
1037
+
1038
+ }
1039
+
1040
+ };
1041
+
1042
+ this.dom = dom;
1043
+
1044
+ this.style = '';
1045
+
1046
+ this.canvas = null;
1047
+
1048
+ this.elements = [];
1049
+
1050
+ this.events = {
1051
+ 'focus': [],
1052
+ 'blur': []
1053
+ };
1054
+
1055
+ this.setPosition( 0, 0 );
1056
+
1057
+ }
1058
+
1059
+ onFocus( callback ) {
1060
+
1061
+ this.events.focus.push( callback );
1062
+
1063
+ return this;
1064
+
1065
+ }
1066
+
1067
+ onBlur( callback ) {
1068
+
1069
+ this.events.blur.push( callback );
1070
+
1071
+ return this;
1072
+
1073
+ }
1074
+
1075
+ setStyle( style ) {
1076
+
1077
+ const dom = this.dom;
1078
+
1079
+ if ( this.style ) dom.classList.remove( this.style );
1080
+
1081
+ if ( style ) dom.classList.add( style );
1082
+
1083
+ this.style = style;
1084
+
1085
+ return this;
1086
+
1087
+ }
1088
+
1089
+ setPosition( x, y ) {
1090
+
1091
+ const dom = this.dom;
1092
+
1093
+ dom.style.left = toPX( x );
1094
+ dom.style.top = toPX( y );
1095
+
1096
+ return this;
1097
+
1098
+ }
1099
+
1100
+ getPosition() {
1101
+
1102
+ const dom = this.dom;
1103
+
1104
+ return {
1105
+ x: parseInt( dom.style.left ),
1106
+ y: parseInt( dom.style.top )
1107
+ };
1108
+
1109
+ }
1110
+
1111
+ setWidth( val ) {
1112
+
1113
+ this.dom.style.width = toPX( val );
1114
+
1115
+ return this;
1116
+
1117
+ }
1118
+
1119
+ getWidth() {
1120
+
1121
+ return this.dom.style.width;
1122
+
1123
+ }
1124
+
1125
+ add( element ) {
1126
+
1127
+ this.elements.push( element );
1128
+
1129
+ element.node = this;
1130
+ element.addEventListener( 'connect', this._onConnect );
1131
+ element.addEventListener( 'connectChildren', this._onConnectChildren );
1132
+
1133
+ this.dom.appendChild( element.dom );
1134
+
1135
+ return this;
1136
+
1137
+ }
1138
+
1139
+ remove( element ) {
1140
+
1141
+ this.elements.splice( this.elements.indexOf( element ), 1 );
1142
+
1143
+ element.node = null;
1144
+ element.removeEventListener( 'connect', this._onConnect );
1145
+ element.removeEventListener( 'connectChildren', this._onConnectChildren );
1146
+
1147
+ this.dom.removeChild( element.dom );
1148
+
1149
+ return this;
1150
+
1151
+ }
1152
+
1153
+ dispose() {
1154
+
1155
+ const canvas = this.canvas;
1156
+
1157
+ if ( canvas !== null ) canvas.remove( this );
1158
+
1159
+ for ( const element of this.elements ) {
1160
+
1161
+ element.dispose();
1162
+
1163
+ }
1164
+
1165
+ this.dispatchEvent( new Event( 'dispose' ) );
1166
+
1167
+ }
1168
+
1169
+ isCircular( node ) {
1170
+
1171
+ if ( node === this ) return true;
1172
+
1173
+ const links = this.getLinks();
1174
+
1175
+ for ( const link of links ) {
1176
+
1177
+ if ( link.outputElement.node.isCircular( node ) ) {
1178
+
1179
+ return true;
1180
+
1181
+ }
1182
+
1183
+ }
1184
+
1185
+ return false;
1186
+
1187
+ }
1188
+
1189
+ getLinks() {
1190
+
1191
+ const links = [];
1192
+
1193
+ for ( const element of this.elements ) {
1194
+
1195
+ links.push( ...element.links );
1196
+
1197
+ }
1198
+
1199
+ return links;
1200
+
1201
+ }
1202
+
1203
+ serialize( data ) {
1204
+
1205
+ const { x, y, style } = this.getPosition();
1206
+
1207
+ const elements = [];
1208
+
1209
+ for ( const element of this.elements ) {
1210
+
1211
+ elements.push( element.toJSON( data ).id );
1212
+
1213
+ }
1214
+
1215
+ data.x = x;
1216
+ data.y = y;
1217
+ data.width = this.getWidth();
1218
+ data.elements = elements;
1219
+
1220
+ if ( style !== '' ) {
1221
+
1222
+ data.style = style;
1223
+
1224
+ }
1225
+
1226
+ }
1227
+
1228
+ deserialize( data ) {
1229
+
1230
+ this.setPosition( data.x, data.y );
1231
+ this.setWidth( data.width );
1232
+
1233
+ if ( data.style !== undefined ) {
1234
+
1235
+ this.setStyle( data.style );
1236
+
1237
+ }
1238
+
1239
+ const elements = this.elements;
1240
+
1241
+ if ( elements.length > 0 ) {
1242
+
1243
+ let index = 0;
1244
+
1245
+ for ( const id of data.elements ) {
1246
+
1247
+ data.objects[ id ] = elements[ index ++ ];
1248
+
1249
+ }
1250
+
1251
+ } else {
1252
+
1253
+ for ( const id of data.elements ) {
1254
+
1255
+ this.add( data.objects[ id ] );
1256
+
1257
+ }
1258
+
1259
+ }
1260
+
1261
+ }
1262
+
1263
+ }
1264
+
1265
+ Node.prototype.isNode = true;
1266
+
1267
+ const drawLine = ( p1x, p1y, p2x, p2y, invert, size, color, ctx ) => {
1268
+
1269
+ const offset = 100 * ( invert ? - 1 : 1 );
1270
+
1271
+ ctx.beginPath();
1272
+
1273
+ ctx.moveTo( p1x, p1y );
1274
+
1275
+ ctx.bezierCurveTo(
1276
+ p1x + offset, p1y,
1277
+ p2x - offset, p2y,
1278
+ p2x, p2y
1279
+ );
1280
+
1281
+ ctx.lineWidth = size;
1282
+ ctx.strokeStyle = color;
1283
+ ctx.stroke();
1284
+
1285
+ };
1286
+
1287
+ const colors = [
1288
+ '#ff4444',
1289
+ '#44ff44',
1290
+ '#4444ff'
1291
+ ];
1292
+
1293
+ class Canvas extends Serializer {
1294
+
1295
+ constructor() {
1296
+
1297
+ super();
1298
+
1299
+ const dom = document.createElement( 'f-canvas' );
1300
+ const contentDOM = document.createElement( 'f-content' );
1301
+ const areaDOM = document.createElement( 'f-area' );
1302
+ const canvas = document.createElement( 'canvas' );
1303
+ const frontCanvas = document.createElement( 'canvas' );
1304
+
1305
+ const context = canvas.getContext( '2d' );
1306
+ const frontContext = frontCanvas.getContext( '2d' );
1307
+
1308
+ this.dom = dom;
1309
+
1310
+ this.contentDOM = contentDOM;
1311
+ this.areaDOM = areaDOM;
1312
+
1313
+ this.canvas = canvas;
1314
+ this.frontCanvas = frontCanvas;
1315
+
1316
+ this.context = context;
1317
+ this.frontContext = frontContext;
1318
+
1319
+ this.width = 10000;
1320
+ this.height = 10000;
1321
+
1322
+ this.clientX = 0;
1323
+ this.clientY = 0;
1324
+
1325
+ this.relativeClientX = 0;
1326
+ this.relativeClientY = 0;
1327
+
1328
+ this.zoom = 1;
1329
+
1330
+ this.nodes = [];
1331
+
1332
+ this.selected = null;
1333
+
1334
+ this.updating = false;
1335
+
1336
+ frontCanvas.className = 'front';
1337
+
1338
+ contentDOM.style.left = toPX( this.centerX );
1339
+ contentDOM.style.top = toPX( this.centerY );
1340
+
1341
+ areaDOM.style.width = `calc( 100% + ${ this.width }px )`;
1342
+ areaDOM.style.height = `calc( 100% + ${ this.height }px )`;
1343
+
1344
+ dom.appendChild( canvas );
1345
+ dom.appendChild( frontCanvas );
1346
+ dom.appendChild( contentDOM );
1347
+ dom.appendChild( areaDOM );
1348
+ /*
1349
+ let zoomTouchData = null;
1350
+
1351
+ const onZoomStart = () => {
1352
+
1353
+ zoomTouchData = null;
1354
+
1355
+ };
1356
+ */
1357
+ const onZoom = ( e ) => {
1358
+
1359
+ if ( e.touches ) {
1360
+
1361
+ if ( e.touches.length === 2 ) {
1362
+
1363
+ e.preventDefault();
1364
+
1365
+ e.stopImmediatePropagation();
1366
+ /*
1367
+ const clientX = ( e.touches[ 0 ].clientX + e.touches[ 1 ].clientX ) / 2;
1368
+ const clientY = ( e.touches[ 0 ].clientY + e.touches[ 1 ].clientY ) / 2;
1369
+
1370
+ const distance = Math.hypot(
1371
+ e.touches[ 0 ].clientX - e.touches[ 1 ].clientX,
1372
+ e.touches[ 0 ].clientY - e.touches[ 1 ].clientY
1373
+ );
1374
+
1375
+ if ( zoomTouchData === null ) {
1376
+
1377
+ zoomTouchData = {
1378
+ distance
1379
+ };
1380
+
1381
+ }
1382
+
1383
+ const delta = ( zoomTouchData.distance - distance );
1384
+ zoomTouchData.distance = distance;
1385
+
1386
+ let zoom = Math.min( Math.max( this.zoom - delta * .01, .5 ), 1.2 );
1387
+
1388
+ if ( zoom < .52 ) zoom = .5;
1389
+ else if ( zoom > .98 ) zoom = 1;
1390
+
1391
+ contentDOM.style.left = toPX( this.centerX / zoom );
1392
+ contentDOM.style.top = toPX( this.centerY / zoom );
1393
+ contentDOM.style.zoom = this.zoom = zoom;
1394
+ */
1395
+
1396
+ }
1397
+
1398
+ } else {
1399
+
1400
+ e.preventDefault();
1401
+
1402
+ e.stopImmediatePropagation();
1403
+ /*
1404
+ const delta = e.deltaY / 100;
1405
+ const zoom = Math.min( Math.max( this.zoom - delta * .1, .5 ), 1 );
1406
+
1407
+ contentDOM.style.left = toPX( this.centerX / zoom );
1408
+ contentDOM.style.top = toPX( this.centerY / zoom );
1409
+ contentDOM.style.zoom = this.zoom = zoom;
1410
+ */
1411
+
1412
+ }
1413
+
1414
+ };
1415
+
1416
+ dom.addEventListener( 'wheel', onZoom );
1417
+ dom.addEventListener( 'touchmove', onZoom );
1418
+ //dom.addEventListener( 'touchstart', onZoomStart );
1419
+
1420
+ draggableDOM( dom, ( data ) => {
1421
+
1422
+ const { delta, isTouch } = data;
1423
+
1424
+ if ( ! isTouch ) {
1425
+
1426
+ if ( data.scrollTop === undefined ) {
1427
+
1428
+ data.scrollLeft = dom.scrollLeft;
1429
+ data.scrollTop = dom.scrollTop;
1430
+
1431
+ }
1432
+
1433
+ dom.scrollLeft = data.scrollLeft - delta.x;
1434
+ dom.scrollTop = data.scrollTop - delta.y;
1435
+
1436
+ }
1437
+
1438
+ if ( data.dragging ) {
1439
+
1440
+ dom.classList.add( 'grabbing' );
1441
+
1442
+ } else {
1443
+
1444
+ dom.classList.remove( 'grabbing' );
1445
+
1446
+ }
1447
+
1448
+ }, 'dragging-canvas' );
1449
+
1450
+ this._onMoveEvent = ( e ) => {
1451
+
1452
+ const event = e.touches ? e.touches[ 0 ] : e;
1453
+ const { zoom, rect } = this;
1454
+
1455
+ this.clientX = event.clientX;
1456
+ this.clientY = event.clientY;
1457
+
1458
+ this.relativeClientX = ( ( ( dom.scrollLeft - this.centerX ) + event.clientX ) - rect.left ) / zoom;
1459
+ this.relativeClientY = ( ( ( dom.scrollTop - this.centerY ) + event.clientY ) - rect.top ) / zoom;
1460
+
1461
+ };
1462
+
1463
+ this._onContentLoaded = () => {
1464
+
1465
+ this.centralize();
1466
+
1467
+ };
1468
+
1469
+ this._onUpdate = () => {
1470
+
1471
+ this.update();
1472
+
1473
+ };
1474
+
1475
+ this.start();
1476
+
1477
+ }
1478
+
1479
+ get rect() {
1480
+
1481
+ return this.dom.getBoundingClientRect();
1482
+
1483
+ }
1484
+
1485
+ get relativeX() {
1486
+
1487
+ return this.dom.scrollLeft - this.centerX;
1488
+
1489
+ }
1490
+
1491
+ get relativeY() {
1492
+
1493
+ return this.dom.scrollTop - this.centerY;
1494
+
1495
+ }
1496
+
1497
+ get centerX() {
1498
+
1499
+ return this.width / 2;
1500
+
1501
+ }
1502
+
1503
+ get centerY() {
1504
+
1505
+ return this.height / 2;
1506
+
1507
+ }
1508
+
1509
+ start() {
1510
+
1511
+ this.updating = true;
1512
+
1513
+ document.addEventListener( 'wheel', this._onMoveEvent, true );
1514
+
1515
+ document.addEventListener( 'mousedown', this._onMoveEvent, true );
1516
+ document.addEventListener( 'touchstart', this._onMoveEvent, true );
1517
+
1518
+ document.addEventListener( 'mousemove', this._onMoveEvent, true );
1519
+ document.addEventListener( 'touchmove', this._onMoveEvent, true );
1520
+
1521
+ document.addEventListener( 'DOMContentLoaded', this._onContentLoaded );
1522
+
1523
+ requestAnimationFrame( this._onUpdate );
1524
+
1525
+ }
1526
+
1527
+ stop() {
1528
+
1529
+ this.updating = false;
1530
+
1531
+ document.removeEventListener( 'wheel', this._onMoveEvent, true );
1532
+
1533
+ document.removeEventListener( 'mousedown', this._onMoveEvent, true );
1534
+ document.removeEventListener( 'touchstart', this._onMoveEvent, true );
1535
+
1536
+ document.removeEventListener( 'mousemove', this._onMoveEvent, true );
1537
+ document.removeEventListener( 'touchmove', this._onMoveEvent, true );
1538
+
1539
+ document.removeEventListener( 'DOMContentLoaded', this._onContentLoaded );
1540
+
1541
+ }
1542
+
1543
+ add( node ) {
1544
+
1545
+ this.nodes.push( node );
1546
+
1547
+ node.canvas = this;
1548
+
1549
+ this.contentDOM.appendChild( node.dom );
1550
+
1551
+ return this;
1552
+
1553
+ }
1554
+
1555
+ remove( node ) {
1556
+
1557
+ if ( node === this.selected ) {
1558
+
1559
+ this.select();
1560
+
1561
+ }
1562
+
1563
+ this.unlink( node );
1564
+
1565
+ const nodes = this.nodes;
1566
+
1567
+ nodes.splice( nodes.indexOf( node ), 1 );
1568
+
1569
+ node.canvas = null;
1570
+
1571
+ this.contentDOM.removeChild( node.dom );
1572
+
1573
+ return this;
1574
+
1575
+ }
1576
+
1577
+ clear() {
1578
+
1579
+ const nodes = this.nodes;
1580
+
1581
+ while ( nodes.length > 0 ) {
1582
+
1583
+ this.remove( nodes[ 0 ] );
1584
+
1585
+ }
1586
+
1587
+ return this;
1588
+
1589
+ }
1590
+
1591
+ unlink( node ) {
1592
+
1593
+ const links = this.getLinks();
1594
+
1595
+ for ( const link of links ) {
1596
+
1597
+ if ( link.outputElement && link.outputElement.node === node ) {
1598
+
1599
+ link.inputElement.connect();
1600
+
1601
+ }
1602
+
1603
+ }
1604
+
1605
+ }
1606
+
1607
+ getLinks() {
1608
+
1609
+ const links = [];
1610
+
1611
+ for ( const node of this.nodes ) {
1612
+
1613
+ links.push( ...node.getLinks() );
1614
+
1615
+ }
1616
+
1617
+ return links;
1618
+
1619
+ }
1620
+
1621
+ centralize() {
1622
+
1623
+ this.dom.scroll( this.centerX, this.centerY );
1624
+
1625
+ return this;
1626
+
1627
+ }
1628
+
1629
+ select( node = null ) {
1630
+
1631
+ if ( node === this.selected ) return;
1632
+
1633
+ const previousNode = this.selected;
1634
+
1635
+ if ( previousNode !== null ) {
1636
+
1637
+ previousNode.dom.classList.remove( 'selected' );
1638
+
1639
+ this.selected = null;
1640
+
1641
+ dispatchEventList( previousNode.events.blur, previousNode );
1642
+
1643
+ }
1644
+
1645
+ if ( node !== null ) {
1646
+
1647
+ node.dom.classList.add( 'selected' );
1648
+
1649
+ this.selected = node;
1650
+
1651
+ dispatchEventList( node.events.focus, node );
1652
+
1653
+ }
1654
+
1655
+ }
1656
+
1657
+ update() {
1658
+
1659
+ if ( this.updating === false ) return;
1660
+
1661
+ requestAnimationFrame( this._onUpdate );
1662
+
1663
+ const { dom, zoom, canvas, frontCanvas, frontContext, context } = this;
1664
+
1665
+ const width = window.innerWidth;
1666
+ const height = window.innerHeight;
1667
+
1668
+ const domRect = this.rect;
1669
+
1670
+ if ( canvas.width !== width || canvas.height !== height ) {
1671
+
1672
+ canvas.width = width;
1673
+ canvas.height = height;
1674
+
1675
+ frontCanvas.width = width;
1676
+ frontCanvas.height = height;
1677
+
1678
+ }
1679
+
1680
+ context.clearRect( 0, 0, width, height );
1681
+ frontContext.clearRect( 0, 0, width, height );
1682
+
1683
+ context.globalCompositeOperation = 'lighter';
1684
+ frontContext.globalCompositeOperation = 'source-over';
1685
+
1686
+ const links = this.getLinks();
1687
+
1688
+ const aPos = { x: 0, y: 0 };
1689
+ const bPos = { x: 0, y: 0 };
1690
+
1691
+ const offsetIORadius = 10;
1692
+
1693
+ let dragging = '';
1694
+
1695
+ for ( const link of links ) {
1696
+
1697
+ const { lioElement, rioElement } = link;
1698
+
1699
+ let draggingLink = '';
1700
+ let length = 0;
1701
+
1702
+ if ( lioElement !== null ) {
1703
+
1704
+ const rect = lioElement.dom.getBoundingClientRect();
1705
+
1706
+ length = Math.max( length, lioElement.rioLength );
1707
+
1708
+ aPos.x = rect.x + rect.width;
1709
+ aPos.y = rect.y + ( rect.height / 2 );
1710
+
1711
+ } else {
1712
+
1713
+ aPos.x = this.clientX;
1714
+ aPos.y = this.clientY;
1715
+
1716
+ draggingLink = 'lio';
1717
+
1718
+ }
1719
+
1720
+ if ( rioElement !== null ) {
1721
+
1722
+ const rect = rioElement.dom.getBoundingClientRect();
1723
+
1724
+ length = Math.max( length, rioElement.lioLength );
1725
+
1726
+ bPos.x = rect.x;
1727
+ bPos.y = rect.y + ( rect.height / 2 );
1728
+
1729
+ } else {
1730
+
1731
+ bPos.x = this.clientX;
1732
+ bPos.y = this.clientY;
1733
+
1734
+ draggingLink = 'rio';
1735
+
1736
+ }
1737
+
1738
+ dragging = dragging || draggingLink;
1739
+
1740
+ const drawContext = draggingLink ? frontContext : context;
1741
+
1742
+ if ( draggingLink || length === 1 ) {
1743
+
1744
+ if ( draggingLink === 'rio' ) {
1745
+
1746
+ aPos.x += offsetIORadius;
1747
+ bPos.x /= zoom;
1748
+ bPos.y /= zoom;
1749
+
1750
+ } else if ( draggingLink === 'lio' ) {
1751
+
1752
+ bPos.x -= offsetIORadius;
1753
+ aPos.x /= zoom;
1754
+ aPos.y /= zoom;
1755
+
1756
+ }
1757
+
1758
+ drawLine(
1759
+ aPos.x * zoom, aPos.y * zoom,
1760
+ bPos.x * zoom, bPos.y * zoom,
1761
+ false, 2, '#ffffff', drawContext
1762
+ );
1763
+
1764
+ } else {
1765
+
1766
+ length = Math.min( length, 4 );
1767
+
1768
+ for ( let i = 0; i < length; i ++ ) {
1769
+
1770
+ const color = colors[ i ] || '#ffffff';
1771
+
1772
+ const marginY = 4;
1773
+
1774
+ const rioLength = Math.min( lioElement.rioLength, length );
1775
+ const lioLength = Math.min( rioElement.lioLength, length );
1776
+
1777
+ const aCenterY = ( ( rioLength * marginY ) * .5 ) - ( marginY / 2 );
1778
+ const bCenterY = ( ( lioLength * marginY ) * .5 ) - ( marginY / 2 );
1779
+
1780
+ const aIndex = Math.min( i, rioLength - 1 );
1781
+ const bIndex = Math.min( i, lioLength - 1 );
1782
+
1783
+ const aPosY = aIndex * marginY;
1784
+ const bPosY = bIndex * marginY;
1785
+
1786
+ drawLine(
1787
+ aPos.x * zoom, ( ( aPos.y + aPosY ) - aCenterY ) * zoom,
1788
+ bPos.x * zoom, ( ( bPos.y + bPosY ) - bCenterY ) * zoom,
1789
+ false, 2, color, drawContext
1790
+ );
1791
+
1792
+ }
1793
+
1794
+ }
1795
+
1796
+ }
1797
+
1798
+ context.globalCompositeOperation = 'destination-in';
1799
+
1800
+ context.fillRect( domRect.x, domRect.y, domRect.width, domRect.height );
1801
+
1802
+ if ( dragging !== '' ) {
1803
+
1804
+ dom.classList.add( 'dragging-' + dragging );
1805
+
1806
+ } else {
1807
+
1808
+ dom.classList.remove( 'dragging-lio' );
1809
+ dom.classList.remove( 'dragging-rio' );
1810
+
1811
+ }
1812
+
1813
+ }
1814
+
1815
+ serialize( data ) {
1816
+
1817
+ const nodes = [];
1818
+
1819
+ for ( const node of this.nodes ) {
1820
+
1821
+ nodes.push( node.toJSON( data ).id );
1822
+
1823
+ }
1824
+
1825
+ data.nodes = nodes;
1826
+
1827
+ }
1828
+
1829
+ deserialize( data ) {
1830
+
1831
+ for ( const id of data.nodes ) {
1832
+
1833
+ this.add( data.objects[ id ] );
1834
+
1835
+ }
1836
+
1837
+ }
1838
+
1839
+ }
1840
+
1841
+ class ButtonInput extends Input {
1842
+
1843
+ constructor( innterText = '' ) {
1844
+
1845
+ const dom = document.createElement( 'button' );
1846
+
1847
+ const spanDOM = document.createElement( 'span' );
1848
+ dom.appendChild( spanDOM );
1849
+
1850
+ const iconDOM = document.createElement( 'i' );
1851
+ dom.appendChild( iconDOM );
1852
+
1853
+ super( dom );
1854
+
1855
+ this.spanDOM = spanDOM;
1856
+ this.iconDOM = iconDOM;
1857
+
1858
+ spanDOM.innerText = innterText;
1859
+
1860
+ dom.onmouseover = () => {
1861
+
1862
+ this.dispatchEvent( new Event( 'mouseover' ) );
1863
+
1864
+ };
1865
+
1866
+ dom.onclick = dom.ontouchstart = ( e ) => {
1867
+
1868
+ e.preventDefault();
1869
+
1870
+ e.stopPropagation();
1871
+
1872
+ this.dispatchEvent( new Event( 'click' ) );
1873
+
1874
+ };
1875
+
1876
+ }
1877
+
1878
+ setIcon( className ) {
1879
+
1880
+ this.iconDOM.className = className;
1881
+
1882
+ return this;
1883
+
1884
+ }
1885
+
1886
+ setValue( val ) {
1887
+
1888
+ this.spanDOM.innerText = val;
1889
+
1890
+ return this;
1891
+
1892
+ }
1893
+
1894
+ getValue() {
1895
+
1896
+ return this.spanDOM.innerText;
1897
+
1898
+ }
1899
+
1900
+ }
1901
+
1902
+ class DraggableElement extends Element {
1903
+
1904
+ constructor( draggable = true ) {
1905
+
1906
+ super( true );
1907
+
1908
+ this.draggable = draggable;
1909
+
1910
+ const onDrag = ( e ) => {
1911
+
1912
+ e.preventDefault();
1913
+
1914
+ if ( this.draggable === true ) {
1915
+
1916
+ draggableDOM( this.node.dom );
1917
+
1918
+ }
1919
+
1920
+ };
1921
+
1922
+ const { dom } = this;
1923
+
1924
+ dom.addEventListener( 'mousedown', onDrag, true );
1925
+ dom.addEventListener( 'touchstart', onDrag, true );
1926
+
1927
+ }
1928
+
1929
+ }
1930
+
1931
+ class TitleElement extends DraggableElement {
1932
+
1933
+ constructor( title, draggable = true ) {
1934
+
1935
+ super( draggable );
1936
+
1937
+ const { dom } = this;
1938
+
1939
+ dom.className = 'title';
1940
+
1941
+ const spanDOM = document.createElement( 'span' );
1942
+ spanDOM.innerText = title;
1943
+
1944
+ const iconDOM = document.createElement( 'i' );
1945
+
1946
+ const toolbarDOM = document.createElement( 'f-toolbar' );
1947
+
1948
+ this.buttons = [];
1949
+
1950
+ this.spanDOM = spanDOM;
1951
+ this.iconDOM = iconDOM;
1952
+ this.toolbarDOM = toolbarDOM;
1953
+
1954
+ dom.appendChild( spanDOM );
1955
+ dom.appendChild( iconDOM );
1956
+ dom.appendChild( toolbarDOM );
1957
+
1958
+ }
1959
+
1960
+ setIcon( value ) {
1961
+
1962
+ this.iconDOM.className = value;
1963
+
1964
+ return this;
1965
+
1966
+ }
1967
+
1968
+ getIcon() {
1969
+
1970
+ return this.iconDOM.className;
1971
+
1972
+ }
1973
+
1974
+ setTitle( value ) {
1975
+
1976
+ this.spanDOM.innerText = value;
1977
+
1978
+ return this;
1979
+
1980
+ }
1981
+
1982
+ getTitle() {
1983
+
1984
+ return this.spanDOM.innerText;
1985
+
1986
+ }
1987
+
1988
+ addButton( button ) {
1989
+
1990
+ this.buttons.push( button );
1991
+
1992
+ this.toolbarDOM.appendChild( button.dom );
1993
+
1994
+ return this;
1995
+
1996
+ }
1997
+
1998
+ serialize( data ) {
1999
+
2000
+ super.serialize( data );
2001
+
2002
+ const title = this.getTitle();
2003
+ const icon = this.getIcon();
2004
+
2005
+ data.title = title;
2006
+
2007
+ if ( icon !== '' ) {
2008
+
2009
+ data.icon = icon;
2010
+
2011
+ }
2012
+
2013
+ }
2014
+
2015
+ deserialize( data ) {
2016
+
2017
+ super.deserialize( data );
2018
+
2019
+ this.setTitle( data.title );
2020
+
2021
+ if ( data.icon !== undefined ) {
2022
+
2023
+ this.setIcon( data.icon );
2024
+
2025
+ }
2026
+
2027
+ }
2028
+
2029
+ }
2030
+
2031
+ class ObjectNode extends Node {
2032
+
2033
+ constructor( name, inputLength, extra = null, width = 300 ) {
2034
+
2035
+ super();
2036
+
2037
+ this.setWidth( width );
2038
+
2039
+ const title = new TitleElement( name )
2040
+ .setExtra( extra )
2041
+ .setOutput( inputLength );
2042
+
2043
+ const closeButton = new ButtonInput( '✖' ).onClick( () => {
2044
+
2045
+ this.dispose();
2046
+
2047
+ } );
2048
+
2049
+ title.addButton( closeButton );
2050
+
2051
+ this.add( title );
2052
+
2053
+ this.title = title;
2054
+ this.closeButton = closeButton;
2055
+
2056
+ }
2057
+
2058
+ setExtra( value ) {
2059
+
2060
+ this.title.setExtra( value );
2061
+
2062
+ return this;
2063
+
2064
+ }
2065
+
2066
+ getExtra( value ) {
2067
+
2068
+ return this.title.getExtra();
2069
+
2070
+ }
2071
+
2072
+ invalidate() {
2073
+
2074
+ this.title.dispatchEvent( new Event( 'connect' ) );
2075
+
2076
+ }
2077
+
2078
+ }
2079
+
2080
+ const ENTER_KEY$1 = 13;
2081
+
2082
+ class StringInput extends Input {
2083
+
2084
+ constructor( value = '' ) {
2085
+
2086
+ const dom = document.createElement( 'input' );
2087
+ super( dom );
2088
+
2089
+ dom.type = 'text';
2090
+ dom.value = value;
2091
+ dom.spellcheck = false;
2092
+ dom.autocomplete = 'off';
2093
+
2094
+ dom.onblur = () => {
2095
+
2096
+ this.dispatchEvent( new Event( 'blur' ) );
2097
+
2098
+ };
2099
+
2100
+ dom.onchange = () => {
2101
+
2102
+ this.dispatchEvent( new Event( 'change' ) );
2103
+
2104
+ };
2105
+
2106
+ dom.onkeyup = ( e ) => {
2107
+
2108
+ if ( e.keyCode === ENTER_KEY$1 ) {
2109
+
2110
+ e.target.blur();
2111
+
2112
+ }
2113
+
2114
+ e.stopPropagation();
2115
+
2116
+ this.dispatchEvent( new Event( 'change' ) );
2117
+
2118
+ };
2119
+
2120
+ }
2121
+
2122
+ }
2123
+
2124
+ const ENTER_KEY = 13;
2125
+
2126
+ class NumberInput extends Input {
2127
+
2128
+ constructor( value = 0, min = - Infinity, max = Infinity, step = .01 ) {
2129
+
2130
+ const dom = document.createElement( 'input' );
2131
+ super( dom );
2132
+
2133
+ this.min = min;
2134
+ this.max = max;
2135
+ this.step = step;
2136
+
2137
+ this.integer = false;
2138
+
2139
+ dom.type = 'text';
2140
+ dom.className = 'number';
2141
+ dom.value = this._getString( value );
2142
+ dom.spellcheck = false;
2143
+ dom.autocomplete = 'off';
2144
+
2145
+ dom.ondragstart = dom.oncontextmenu = ( e ) => {
2146
+
2147
+ e.preventDefault();
2148
+
2149
+ e.stopPropagation();
2150
+
2151
+ };
2152
+
2153
+ dom.onfocus = dom.onclick = () => {
2154
+
2155
+ dom.select();
2156
+
2157
+ };
2158
+
2159
+ dom.onblur = () => {
2160
+
2161
+ this.dispatchEvent( new Event( 'blur' ) );
2162
+
2163
+ };
2164
+
2165
+ dom.onchange = () => {
2166
+
2167
+ this.dispatchEvent( new Event( 'change' ) );
2168
+
2169
+ };
2170
+
2171
+ dom.onkeydown = ( e ) => {
2172
+
2173
+ if ( e.key.length === 1 && /\d|\./.test( e.key ) !== true ) {
2174
+
2175
+ return false;
2176
+
2177
+ }
2178
+
2179
+ if ( e.keyCode === ENTER_KEY ) {
2180
+
2181
+ e.target.blur();
2182
+
2183
+ }
2184
+
2185
+ e.stopPropagation();
2186
+
2187
+ };
2188
+
2189
+ draggableDOM( dom, ( data ) => {
2190
+
2191
+ const { delta } = data;
2192
+
2193
+ if ( data.value === undefined ) {
2194
+
2195
+ data.value = this.getValue();
2196
+
2197
+ }
2198
+
2199
+ const diff = delta.x - delta.y;
2200
+
2201
+ const value = data.value + ( diff * this.step );
2202
+
2203
+ this.dom.value = this._getString( value.toFixed( this.precision ) );
2204
+
2205
+ this.dispatchEvent( new Event( 'change' ) );
2206
+
2207
+ } );
2208
+
2209
+ }
2210
+
2211
+ setRange( min, max, step ) {
2212
+
2213
+ this.min = min;
2214
+ this.max = max;
2215
+ this.step = step;
2216
+
2217
+ this.dispatchEvent( new Event( 'range' ) );
2218
+
2219
+ return this.setValue( this.getValue() );
2220
+
2221
+ }
2222
+
2223
+ get precision() {
2224
+
2225
+ if ( this.integer === true ) return 0;
2226
+
2227
+ const fract = this.step % 1;
2228
+
2229
+ return fract !== 0 ? fract.toString().split( '.' )[ 1 ].length : 1;
2230
+
2231
+ }
2232
+
2233
+ setValue( val, dispatch = true ) {
2234
+
2235
+ return super.setValue( this._getString( val ), dispatch );
2236
+
2237
+ }
2238
+
2239
+ getValue() {
2240
+
2241
+ return Number( this.dom.value );
2242
+
2243
+ }
2244
+
2245
+ serialize( data ) {
2246
+
2247
+ const { min, max } = this;
2248
+
2249
+ if ( min !== - Infinity && max !== Infinity ) {
2250
+
2251
+ data.min = this.min;
2252
+ data.max = this.max;
2253
+ data.step = this.step;
2254
+
2255
+ }
2256
+
2257
+ super.serialize( data );
2258
+
2259
+ }
2260
+
2261
+ deserialize( data ) {
2262
+
2263
+ if ( data.min !== undefined ) {
2264
+
2265
+ const { min, max, step } = this;
2266
+
2267
+ this.setRange( min, max, step );
2268
+
2269
+ }
2270
+
2271
+ super.deserialize( data );
2272
+
2273
+ }
2274
+
2275
+ _getString( value ) {
2276
+
2277
+ let num = Math.min( Math.max( Number( value ), this.min ), this.max );
2278
+
2279
+ if ( this.integer === true ) {
2280
+
2281
+ return Math.floor( num );
2282
+
2283
+ } else {
2284
+
2285
+ return num + ( num % 1 ? '' : '.0' );
2286
+
2287
+ }
2288
+
2289
+ }
2290
+
2291
+ }
2292
+
2293
+ const getStep = ( min, max ) => {
2294
+
2295
+ const sensibility = .001;
2296
+
2297
+ return ( max - min ) * sensibility;
2298
+
2299
+ };
2300
+
2301
+ class SliderInput extends Input {
2302
+
2303
+ constructor( value = 0, min = 0, max = 100 ) {
2304
+
2305
+ const dom = document.createElement( 'f-subinputs' );
2306
+ super( dom );
2307
+
2308
+ value = Math.min( Math.max( value, min ), max );
2309
+
2310
+ const step = getStep( min, max );
2311
+
2312
+ const rangeDOM = document.createElement( 'input' );
2313
+ rangeDOM.type = 'range';
2314
+ rangeDOM.min = min;
2315
+ rangeDOM.max = max;
2316
+ rangeDOM.step = step;
2317
+ rangeDOM.value = value;
2318
+
2319
+ const field = new NumberInput( value, min, max, step );
2320
+ field.dom.className = 'range-value';
2321
+ field.onChange( () => {
2322
+
2323
+ rangeDOM.value = field.getValue();
2324
+
2325
+ } );
2326
+
2327
+ field.addEventListener( 'range', () => {
2328
+
2329
+ rangeDOM.min = field.min;
2330
+ rangeDOM.max = field.max;
2331
+ rangeDOM.step = field.step;
2332
+ rangeDOM.value = field.getValue();
2333
+
2334
+ } );
2335
+
2336
+ dom.appendChild( rangeDOM );
2337
+ dom.appendChild( field.dom );
2338
+
2339
+ this.rangeDOM = rangeDOM;
2340
+ this.field = field;
2341
+
2342
+ const updateRangeValue = () => {
2343
+
2344
+ let value = Number( rangeDOM.value );
2345
+
2346
+ if ( value !== this.max && value + this.step >= this.max ) {
2347
+
2348
+ // fix not end range fraction
2349
+
2350
+ rangeDOM.value = value = this.max;
2351
+
2352
+ }
2353
+
2354
+ this.field.setValue( value );
2355
+
2356
+ };
2357
+
2358
+ draggableDOM( rangeDOM, () => {
2359
+
2360
+ updateRangeValue();
2361
+
2362
+ this.dispatchEvent( new Event( 'change' ) );
2363
+
2364
+ }, '' );
2365
+
2366
+ }
2367
+
2368
+ get min() {
2369
+
2370
+ return this.field.min;
2371
+
2372
+ }
2373
+
2374
+ get max() {
2375
+
2376
+ return this.field.max;
2377
+
2378
+ }
2379
+
2380
+ get step() {
2381
+
2382
+ return this.field.step;
2383
+
2384
+ }
2385
+
2386
+ setRange( min, max ) {
2387
+
2388
+ this.field.setRange( min, max, getStep( min, max ) );
2389
+
2390
+ this.dispatchEvent( new Event( 'range' ) );
2391
+ this.dispatchEvent( new Event( 'change' ) );
2392
+
2393
+ return this;
2394
+
2395
+ }
2396
+
2397
+ setValue( val, dispatch = true ) {
2398
+
2399
+ this.field.setValue( val );
2400
+ this.rangeDOM.value = val;
2401
+
2402
+ if ( dispatch ) this.dispatchEvent( new Event( 'change' ) );
2403
+
2404
+ return this;
2405
+
2406
+ }
2407
+
2408
+ getValue() {
2409
+
2410
+ return this.field.getValue();
2411
+
2412
+ }
2413
+
2414
+ serialize( data ) {
2415
+
2416
+ data.min = this.min;
2417
+ data.max = this.max;
2418
+
2419
+ super.serialize( data );
2420
+
2421
+ }
2422
+
2423
+ deserialize( data ) {
2424
+
2425
+ const { min, max } = data;
2426
+
2427
+ this.setRange( min, max );
2428
+
2429
+ super.deserialize( data );
2430
+
2431
+ }
2432
+
2433
+ }
2434
+
2435
+ class ColorInput extends Input {
2436
+
2437
+ constructor( value = 0x0099ff ) {
2438
+
2439
+ const dom = document.createElement( 'input' );
2440
+ super( dom );
2441
+
2442
+ dom.type = 'color';
2443
+ dom.value = toHex( value );
2444
+
2445
+ dom.oninput = () => {
2446
+
2447
+ this.dispatchEvent( new Event( 'change' ) );
2448
+
2449
+ };
2450
+
2451
+ }
2452
+
2453
+ setValue( value, dispatch = true ) {
2454
+
2455
+ return super.setValue( toHex( value ), dispatch );
2456
+
2457
+ }
2458
+
2459
+ getValue() {
2460
+
2461
+ return parseInt( super.getValue().substr( 1 ), 16 );
2462
+
2463
+ }
2464
+
2465
+ }
2466
+
2467
+ class TextInput extends Input {
2468
+
2469
+ constructor( innerText = '' ) {
2470
+
2471
+ const dom = document.createElement( 'textarea' );
2472
+ super( dom );
2473
+
2474
+ dom.innerText = innerText;
2475
+
2476
+ }
2477
+
2478
+ setValue( val ) {
2479
+
2480
+ this.dom.innerText = val;
2481
+
2482
+ return this;
2483
+
2484
+ }
2485
+
2486
+ getValue() {
2487
+
2488
+ return this.dom.innerText;
2489
+
2490
+ }
2491
+
2492
+ }
2493
+
2494
+ class LabelElement extends Element {
2495
+
2496
+ constructor( label = '', align = '' ) {
2497
+
2498
+ super();
2499
+
2500
+ this.labelDOM = document.createElement( 'f-label' );
2501
+ this.inputsDOM = document.createElement( 'f-inputs' );
2502
+
2503
+ const spanDOM = document.createElement( 'span' );
2504
+ const iconDOM = document.createElement( 'i' );
2505
+
2506
+ this.spanDOM = spanDOM;
2507
+ this.iconDOM = iconDOM;
2508
+
2509
+ this.labelDOM.appendChild( this.spanDOM );
2510
+ this.labelDOM.appendChild( this.iconDOM );
2511
+
2512
+ this.dom.appendChild( this.labelDOM );
2513
+ this.dom.appendChild( this.inputsDOM );
2514
+
2515
+ this.setLabel( label );
2516
+ this.setAlign( align );
2517
+
2518
+ }
2519
+
2520
+ setIcon( value ) {
2521
+
2522
+ this.iconDOM.className = value;
2523
+
2524
+ return this;
2525
+
2526
+ }
2527
+
2528
+ getIcon() {
2529
+
2530
+ return this.iconDOM.className;
2531
+
2532
+ }
2533
+
2534
+ setAlign( align ) {
2535
+
2536
+ this.labelDOM.className = align;
2537
+
2538
+ }
2539
+
2540
+ setLabel( val ) {
2541
+
2542
+ this.spanDOM.innerText = val;
2543
+
2544
+ }
2545
+
2546
+ getLabel() {
2547
+
2548
+ return this.spanDOM.innerText;
2549
+
2550
+ }
2551
+
2552
+ serialize( data ) {
2553
+
2554
+ super.serialize( data );
2555
+
2556
+ const label = this.getLabel();
2557
+ const icon = this.getIcon();
2558
+
2559
+ data.label = label;
2560
+
2561
+ if ( icon !== '' ) {
2562
+
2563
+ data.icon = icon;
2564
+
2565
+ }
2566
+
2567
+ }
2568
+
2569
+ deserialize( data ) {
2570
+
2571
+ super.deserialize( data );
2572
+
2573
+ this.setLabel( data.label );
2574
+
2575
+ if ( data.icon !== undefined ) {
2576
+
2577
+ this.setIcon( data.icon );
2578
+
2579
+ }
2580
+
2581
+ }
2582
+
2583
+ }
2584
+
2585
+ class PanelNode extends Node {
2586
+
2587
+ constructor( title = 'Panel', align = 'top-right' ) {
2588
+
2589
+ super();
2590
+
2591
+ const titleElement = new TitleElement( title );
2592
+ this.add( titleElement );
2593
+
2594
+ const collapseButton = new ButtonInput( '🗕' );
2595
+ collapseButton.onClick( () => {
2596
+
2597
+ this.setCollapse( ! this.collapsed );
2598
+
2599
+ } );
2600
+
2601
+ titleElement.addButton( collapseButton );
2602
+
2603
+ this.collapseButton = collapseButton;
2604
+ this.titleElement = titleElement;
2605
+ this.align = align;
2606
+ this.collapsed = false;
2607
+
2608
+ this.setAlign( align );
2609
+ this.setStyle( 'rouded' );
2610
+
2611
+ }
2612
+
2613
+ setCollapse( value ) {
2614
+
2615
+ const cssClass = 'closed';
2616
+
2617
+ this.dom.classList.remove( cssClass );
2618
+
2619
+ this.collapsed = value;
2620
+
2621
+ this.collapseButton.value = value ? '🗖' : '🗕';
2622
+
2623
+ if ( value === true ) {
2624
+
2625
+ this.dom.classList.add( cssClass );
2626
+
2627
+ }
2628
+
2629
+ return this;
2630
+
2631
+ }
2632
+
2633
+ setAlign( align ) {
2634
+
2635
+ if ( this.align ) this.dom.classList.remove( this.align );
2636
+ this.dom.classList.add( align );
2637
+
2638
+ this.align = align;
2639
+
2640
+ return this;
2641
+
2642
+ }
2643
+
2644
+ addInput( inputClass, object, property, ...params ) {
2645
+
2646
+ const value = object[ property ];
2647
+
2648
+ const input = new inputClass( value, ...params );
2649
+ input.onChange( () => {
2650
+
2651
+ object[ property ] = input.value;
2652
+
2653
+ } );
2654
+
2655
+ this.add( new LabelElement( property ).add( input ) );
2656
+
2657
+ return input;
2658
+
2659
+ }
2660
+
2661
+ addSlider( object, property, min, max ) {
2662
+
2663
+ return this.addInput( SliderInput, object, property, min, max );
2664
+
2665
+ }
2666
+
2667
+ addNumber( object, property ) {
2668
+
2669
+ return this.addInput( NumberInput, object, property );
2670
+
2671
+ }
2672
+
2673
+ addColor( object, property ) {
2674
+
2675
+ return this.addInput( ColorInput, object, property );
2676
+
2677
+ }
2678
+
2679
+ addString( object, property ) {
2680
+
2681
+ return this.addInput( StringInput, object, property );
2682
+
2683
+ }
2684
+
2685
+ addText( object, property ) {
2686
+
2687
+ const input = this.addInput( TextInput, object, property );
2688
+ input.element.setHeight( 70 );
2689
+
2690
+ return input;
2691
+
2692
+ }
2693
+
2694
+ addButton( name ) {
2695
+
2696
+ const input = new ButtonInput( name );
2697
+
2698
+ this.add( new Element().setHeight( 34 ).add( input ) );
2699
+
2700
+ return input;
2701
+
2702
+ }
2703
+
2704
+ }
2705
+
2706
+ class Menu extends EventTarget {
2707
+
2708
+ constructor( className, target = null ) {
2709
+
2710
+ super();
2711
+
2712
+ const dom = document.createElement( 'f-menu' );
2713
+ dom.className = className + ' hidden';
2714
+
2715
+ this.dom = dom;
2716
+
2717
+ this.visible = false;
2718
+
2719
+ this.subMenus = new WeakMap();
2720
+ this.domButtons = new WeakMap();
2721
+
2722
+ this.events = {
2723
+ 'context': []
2724
+ };
2725
+
2726
+ this.addEventListener( 'context', ( ) => {
2727
+
2728
+ dispatchEventList( this.events.context, this );
2729
+
2730
+ } );
2731
+
2732
+ this._lastButtonClick = null;
2733
+
2734
+ this._onButtonClick = ( e = null ) => {
2735
+
2736
+ const button = e ? e.target : null;
2737
+
2738
+ if ( this._lastButtonClick ) {
2739
+
2740
+ this._lastButtonClick.dom.parentElement.classList.remove( 'active' );
2741
+
2742
+ }
2743
+
2744
+ this._lastButtonClick = button;
2745
+
2746
+ if ( button ) {
2747
+
2748
+ if ( this.subMenus.has( button ) ) {
2749
+
2750
+ this.subMenus.get( button )._onButtonClick();
2751
+
2752
+ }
2753
+
2754
+ button.dom.parentElement.classList.add( 'active' );
2755
+
2756
+ }
2757
+
2758
+ };
2759
+
2760
+ this._onButtonMouseOver = ( e ) => {
2761
+
2762
+ const button = e.target;
2763
+
2764
+ if ( this.subMenus.has( button ) && this._lastButtonClick !== button ) {
2765
+
2766
+ this._onButtonClick();
2767
+
2768
+ }
2769
+
2770
+ };
2771
+
2772
+ this.setTarget( target );
2773
+
2774
+ }
2775
+
2776
+ onContext( callback ) {
2777
+
2778
+ this.events.context.push( callback );
2779
+
2780
+ return this;
2781
+
2782
+ }
2783
+
2784
+ show( x = null, y = null ) {
2785
+
2786
+ this._onButtonClick();
2787
+
2788
+ if ( x !== null && y !== null ) {
2789
+
2790
+ this.setPosition( x, y );
2791
+
2792
+ }
2793
+
2794
+ this.dom.classList.remove( 'hidden' );
2795
+
2796
+ this.visible = true;
2797
+
2798
+ this.dispatchEvent( new Event( 'show' ) );
2799
+
2800
+ return this;
2801
+
2802
+ }
2803
+
2804
+ hide() {
2805
+
2806
+ this.dom.classList.add( 'hidden' );
2807
+
2808
+ this.dispatchEvent( new Event( 'hide' ) );
2809
+
2810
+ this.visible = false;
2811
+
2812
+ }
2813
+
2814
+ setTarget( target = null ) {
2815
+
2816
+ if ( target !== null ) {
2817
+
2818
+ const onContextMenu = ( e ) => {
2819
+
2820
+ e.preventDefault();
2821
+
2822
+ if ( e.pointerType !== 'mouse' || ( e.pageX === 0 && e.pageY === 0 ) ) return;
2823
+
2824
+ const rect = this.target.getBoundingClientRect();
2825
+
2826
+ this.dispatchEvent( new Event( 'context' ) );
2827
+
2828
+ this.show( e.pageX - rect.left, e.pageY - rect.top );
2829
+
2830
+ };
2831
+
2832
+ const onDown = ( e ) => {
2833
+
2834
+ if ( this.visible === true && e.target.closest( 'f-menu' ) === null ) {
2835
+
2836
+ this.hide();
2837
+
2838
+ }
2839
+
2840
+ };
2841
+
2842
+ this.target = target;
2843
+
2844
+ target.addEventListener( 'mousedown', onDown, true );
2845
+ target.addEventListener( 'touchstart', onDown, true );
2846
+
2847
+ target.addEventListener( 'contextmenu', onContextMenu, false );
2848
+
2849
+ target.appendChild( this.dom );
2850
+
2851
+ }
2852
+
2853
+ return this;
2854
+
2855
+ }
2856
+
2857
+ add( button, submenu = null ) {
2858
+
2859
+ const liDOM = document.createElement( 'f-item' );
2860
+
2861
+ if ( submenu !== null ) {
2862
+
2863
+ liDOM.classList.add( 'submenu' );
2864
+
2865
+ liDOM.appendChild( submenu.dom );
2866
+
2867
+ this.subMenus.set( button, submenu );
2868
+
2869
+ }
2870
+
2871
+ liDOM.appendChild( button.dom );
2872
+
2873
+ button.addEventListener( 'click', this._onButtonClick );
2874
+ button.addEventListener( 'mouseover', this._onButtonMouseOver );
2875
+
2876
+ this.dom.appendChild( liDOM );
2877
+
2878
+ this.domButtons.set( liDOM, button );
2879
+
2880
+ return this;
2881
+
2882
+ }
2883
+
2884
+ setPosition( x, y ) {
2885
+
2886
+ const dom = this.dom;
2887
+
2888
+ dom.style.left = toPX( x );
2889
+ dom.style.top = toPX( y );
2890
+
2891
+ return this;
2892
+
2893
+ }
2894
+
2895
+ }
2896
+
2897
+ let lastContext = null;
2898
+
2899
+ class ContextMenu extends Menu {
2900
+
2901
+ constructor( target = null ) {
2902
+
2903
+ super( 'context', target );
2904
+
2905
+ }
2906
+
2907
+ show( x, y ) {
2908
+
2909
+ if ( lastContext !== null ) {
2910
+
2911
+ lastContext.hide();
2912
+
2913
+ }
2914
+
2915
+ lastContext = this;
2916
+
2917
+ return super.show( x, y );
2918
+
2919
+ }
2920
+
2921
+ hide() {
2922
+
2923
+ if ( lastContext === this ) {
2924
+
2925
+ lastContext = null;
2926
+
2927
+ }
2928
+
2929
+ return super.hide();
2930
+
2931
+ }
2932
+
2933
+ }
2934
+
2935
+ class CircleMenu extends Menu {
2936
+
2937
+ constructor( target = null ) {
2938
+
2939
+ super( 'circle', target );
2940
+
2941
+ }
2942
+
2943
+ }
2944
+
2945
+ class SelectInput extends Input {
2946
+
2947
+ constructor( options = [] ) {
2948
+
2949
+ const dom = document.createElement( 'select' );
2950
+ super( dom );
2951
+
2952
+ dom.onchange = () => {
2953
+
2954
+ this.dispatchEvent( new Event( 'change' ) );
2955
+
2956
+ };
2957
+
2958
+ this.setOptions( options );
2959
+
2960
+ }
2961
+
2962
+ setOptions( options ) {
2963
+
2964
+ const dom = this.dom;
2965
+
2966
+ this.options = options;
2967
+
2968
+ dom.innerHTML = '';
2969
+
2970
+ for ( let index = 0; index < options.length; index ++ ) {
2971
+
2972
+ let opt = options[ index ];
2973
+
2974
+ if ( typeof opt === 'string' ) {
2975
+
2976
+ opt = { name: opt, value: index };
2977
+
2978
+ }
2979
+
2980
+ const option = document.createElement( 'option' );
2981
+ option.innerText = opt.name;
2982
+ option.value = opt.value;
2983
+
2984
+ dom.appendChild( option );
2985
+
2986
+ }
2987
+
2988
+ return this;
2989
+
2990
+ }
2991
+
2992
+ getOptions() {
2993
+
2994
+ return this._options;
2995
+
2996
+ }
2997
+
2998
+ serialize( data ) {
2999
+
3000
+ data.options = [ ...this.options ];
3001
+
3002
+ super.serialize( data );
3003
+
3004
+ }
3005
+
3006
+ deserialize( data ) {
3007
+
3008
+ const currentOptions = this.options;
3009
+
3010
+ if ( currentOptions.length > 0 ) {
3011
+
3012
+ this.setOptions( data.options );
3013
+
3014
+ }
3015
+
3016
+ super.deserialize( data );
3017
+
3018
+ }
3019
+
3020
+ }
3021
+
3022
+ class ToggleInput extends Input {
3023
+
3024
+ constructor( value = false ) {
3025
+
3026
+ const dom = document.createElement( 'input' );
3027
+ super( dom );
3028
+
3029
+ dom.type = 'checkbox';
3030
+ dom.className = 'toggle';
3031
+ dom.checked = value;
3032
+
3033
+ }
3034
+
3035
+ setValue( val ) {
3036
+
3037
+ this.dom.checked = val;
3038
+
3039
+ this.dispatchEvent( new Event( 'change' ) );
3040
+
3041
+ return this;
3042
+
3043
+ }
3044
+
3045
+ getValue() {
3046
+
3047
+ return this.dom.checked;
3048
+
3049
+ }
3050
+
3051
+ }
3052
+
3053
+ var Flow = /*#__PURE__*/Object.freeze({
3054
+ __proto__: null,
3055
+ Element: Element,
3056
+ Input: Input,
3057
+ Node: Node,
3058
+ Canvas: Canvas,
3059
+ Serializer: Serializer,
3060
+ ObjectNode: ObjectNode,
3061
+ PanelNode: PanelNode,
3062
+ Menu: Menu,
3063
+ ContextMenu: ContextMenu,
3064
+ CircleMenu: CircleMenu,
3065
+ DraggableElement: DraggableElement,
3066
+ LabelElement: LabelElement,
3067
+ TitleElement: TitleElement,
3068
+ ButtonInput: ButtonInput,
3069
+ ColorInput: ColorInput,
3070
+ NumberInput: NumberInput,
3071
+ SelectInput: SelectInput,
3072
+ SliderInput: SliderInput,
3073
+ StringInput: StringInput,
3074
+ TextInput: TextInput,
3075
+ ToggleInput: ToggleInput
3076
+ });
3077
+
3078
+ class Loader extends EventTarget {
3079
+
3080
+ constructor( parseType = Loader.DEFAULT ) {
3081
+
3082
+ super();
3083
+
3084
+ this.parseType = parseType;
3085
+
3086
+ this.events = {
3087
+ 'load': []
3088
+ };
3089
+
3090
+ }
3091
+
3092
+ setParseType( type ) {
3093
+
3094
+ this.parseType = type;
3095
+
3096
+ return this;
3097
+
3098
+ }
3099
+
3100
+ getParseType() {
3101
+
3102
+ return this.parseType;
3103
+
3104
+ }
3105
+
3106
+ onLoad( callback ) {
3107
+
3108
+ this.events.load.push( callback );
3109
+
3110
+ return this;
3111
+
3112
+ }
3113
+
3114
+ async load( url, lib = null ) {
3115
+
3116
+ return await fetch( url )
3117
+ .then( response => response.json() )
3118
+ .then( result => {
3119
+
3120
+ this.data = this.parse( result, lib );
3121
+
3122
+ dispatchEventList( this.events.load, this );
3123
+
3124
+ return this.data;
3125
+
3126
+ } )
3127
+ .catch( err => {
3128
+
3129
+ console.error( 'Loader:', err );
3130
+
3131
+ } );
3132
+
3133
+ }
3134
+
3135
+ parse( json, lib = null ) {
3136
+
3137
+ json = this._parseObjects( json, lib );
3138
+
3139
+ const parseType = this.parseType;
3140
+
3141
+ if ( parseType === Loader.DEFAULT ) {
3142
+
3143
+ const flowObj = new Flow[ json.type ]();
3144
+
3145
+ if ( flowObj.getSerializable() ) {
3146
+
3147
+ flowObj.deserialize( json );
3148
+
3149
+ }
3150
+
3151
+ return flowObj;
3152
+
3153
+ } else if ( parseType === Loader.OBJECTS ) {
3154
+
3155
+ return json;
3156
+
3157
+ }
3158
+
3159
+ }
3160
+
3161
+ _parseObjects( json, lib = null ) {
3162
+
3163
+ json = { ...json };
3164
+
3165
+ const objects = {};
3166
+
3167
+ for ( const id in json.objects ) {
3168
+
3169
+ const obj = json.objects[ id ];
3170
+ obj.objects = objects;
3171
+
3172
+ const Class = lib && lib[ obj.type ] ? lib[ obj.type ] : Flow[ obj.type ];
3173
+
3174
+ objects[ id ] = new Class();
3175
+
3176
+ }
3177
+
3178
+ const ref = new WeakMap();
3179
+
3180
+ const deserializePass = ( prop = null ) => {
3181
+
3182
+ for ( const id in json.objects ) {
3183
+
3184
+ const newObject = objects[ id ];
3185
+
3186
+ if ( ref.has( newObject ) === false && ( prop === null || newObject[ prop ] === true ) ) {
3187
+
3188
+ ref.set( newObject, true );
3189
+
3190
+ if ( newObject.getSerializable() ) {
3191
+
3192
+ newObject.deserialize( json.objects[ id ] );
3193
+
3194
+ }
3195
+
3196
+ }
3197
+
3198
+ }
3199
+
3200
+ };
3201
+
3202
+ deserializePass( 'isNode' );
3203
+ deserializePass( 'isElement' );
3204
+ deserializePass( 'isInput' );
3205
+ deserializePass();
3206
+
3207
+ json.objects = objects;
3208
+
3209
+ return json;
3210
+
3211
+ }
3212
+
3213
+ }
3214
+
3215
+ Loader.DEFAULT = 'default';
3216
+ Loader.OBJECTS = 'objects';
3217
+
3218
+ export { ButtonInput, Canvas, CircleMenu, ColorInput, ContextMenu, DraggableElement, Element, Input, LabelElement, Loader, Menu, Node, NumberInput, ObjectNode, PanelNode, REVISION, SelectInput, Serializer, SliderInput, StringInput, TextInput, TitleElement, ToggleInput, Utils };