|
20 | 20 |
|
21 | 21 | const editor = getContext<EditorWrapper>("editor"); |
22 | 22 | const nodeGraph = getContext<NodeGraphStore>("nodeGraph"); |
| 23 | + const nodeGraphTransform = nodeGraph.transformStore; |
| 24 | + const nodeGraphImportsExports = nodeGraph.importsExportsStore; |
| 25 | + const visibleNodes = nodeGraph.visibleNodesStore; |
| 26 | + const nodeGraphWires = nodeGraph.wiresStore; |
23 | 27 | const documentState = getContext<DocumentStore>("document"); |
24 | 28 | const subscriptions = getContext<SubscriptionsRouter>("subscriptions"); |
25 | 29 |
|
26 | 30 | let graph: HTMLDivElement | undefined; |
27 | 31 |
|
28 | | - $: gridSpacing = calculateGridSpacing($nodeGraph.transform.scale); |
29 | | - $: gridDotRadius = 1 + Math.floor($nodeGraph.transform.scale - 0.5 + 0.001) / 2; |
| 32 | + $: gridSpacing = calculateGridSpacing($nodeGraphTransform.scale); |
| 33 | + $: gridDotRadius = 1 + Math.floor($nodeGraphTransform.scale - 0.5 + 0.001) / 2; |
30 | 34 |
|
31 | 35 | // Close the context menu when the graph view overlay is closed |
32 | 36 | $: if (!$documentState.graphViewOverlayOpen) closeContextMenu(); |
|
215 | 219 | } |
216 | 220 | </script> |
217 | 221 |
|
218 | | -<div |
219 | | - class="graph" |
220 | | - bind:this={graph} |
221 | | - style:--grid-spacing={`${gridSpacing}px`} |
222 | | - style:--grid-offset-x={`${$nodeGraph.transform.x}px`} |
223 | | - style:--grid-offset-y={`${$nodeGraph.transform.y}px`} |
224 | | - style:--grid-dot-radius={`${gridDotRadius}px`} |
225 | | - data-node-graph |
226 | | -> |
| 222 | +<div class="graph" bind:this={graph} data-node-graph> |
| 223 | + <div |
| 224 | + class="grid-background" |
| 225 | + style:--grid-spacing={`${gridSpacing}px`} |
| 226 | + style:--grid-offset-x={`${$nodeGraphTransform.x}px`} |
| 227 | + style:--grid-offset-y={`${$nodeGraphTransform.y}px`} |
| 228 | + style:--grid-dot-radius={`${gridDotRadius}px`} |
| 229 | + ></div> |
227 | 230 | <!-- Right click menu for adding nodes --> |
228 | 231 | {#if $nodeGraph.contextMenuInformation} |
229 | 232 | <FloatingMenu |
230 | 233 | class="context-menu" |
231 | 234 | data-context-menu |
232 | 235 | styles={{ |
233 | | - left: `${$nodeGraph.contextMenuInformation.contextMenuCoordinates[0] * $nodeGraph.transform.scale + $nodeGraph.transform.x}px`, |
234 | | - top: `${$nodeGraph.contextMenuInformation.contextMenuCoordinates[1] * $nodeGraph.transform.scale + $nodeGraph.transform.y}px`, |
| 236 | + left: `${$nodeGraph.contextMenuInformation.contextMenuCoordinates[0] * $nodeGraphTransform.scale + $nodeGraphTransform.x}px`, |
| 237 | + top: `${$nodeGraph.contextMenuInformation.contextMenuCoordinates[1] * $nodeGraphTransform.scale + $nodeGraphTransform.y}px`, |
235 | 238 | }} |
236 | 239 | open={true} |
237 | 240 | type="Popover" |
|
283 | 286 | {/if} |
284 | 287 |
|
285 | 288 | {#if $nodeGraph.error} |
286 | | - <div class="node-error-container" style:transform-origin="0 0" style:transform={`translate(${$nodeGraph.transform.x}px, ${$nodeGraph.transform.y}px) scale(${$nodeGraph.transform.scale})`}> |
| 289 | + <div class="node-error-container" style:transform-origin="0 0" style:transform={`translate(${$nodeGraphTransform.x}px, ${$nodeGraphTransform.y}px) scale(${$nodeGraphTransform.scale})`}> |
287 | 290 | <span class="node-error faded" style:left={`${$nodeGraph.error.position[0]}px`} style:top={`${$nodeGraph.error.position[1]}px`} transition:fade={FADE_TRANSITION}> |
288 | 291 | {$nodeGraph.error.error} |
289 | 292 | </span> |
|
295 | 298 |
|
296 | 299 | <!-- Click target debug visualizations --> |
297 | 300 | {#if $nodeGraph.clickTargets} |
298 | | - <div class="click-targets" style:transform-origin="0 0" style:transform={`translate(${$nodeGraph.transform.x}px, ${$nodeGraph.transform.y}px) scale(${$nodeGraph.transform.scale})`}> |
| 301 | + <div class="click-targets" style:transform-origin="0 0" style:transform={`translate(${$nodeGraphTransform.x}px, ${$nodeGraphTransform.y}px) scale(${$nodeGraphTransform.scale})`}> |
299 | 302 | <svg> |
300 | 303 | {#each $nodeGraph.clickTargets.nodeClickTargets as pathString} |
301 | 304 | <path class="node" d={pathString} /> |
|
318 | 321 | {/if} |
319 | 322 |
|
320 | 323 | <!-- Thick vertical layer connection wires --> |
321 | | - <div class="wires" style:transform-origin="0 0" style:transform={`translate(${$nodeGraph.transform.x}px, ${$nodeGraph.transform.y}px) scale(${$nodeGraph.transform.scale})`}> |
| 324 | + <div class="wires" style:transform-origin="0 0" style:transform={`translate(${$nodeGraphTransform.x}px, ${$nodeGraphTransform.y}px) scale(${$nodeGraphTransform.scale})`}> |
322 | 325 | <svg> |
323 | | - {#each $nodeGraph.wires.values() as map} |
| 326 | + {#each $nodeGraphWires.values() as map} |
324 | 327 | {#each map.values() as { pathString, dataType, thick, dashed }} |
325 | 328 | {#if thick} |
326 | 329 | <path |
|
337 | 340 | </div> |
338 | 341 |
|
339 | 342 | <!-- Import and Export connectors --> |
340 | | - <div class="imports-and-exports" style:transform-origin="0 0" style:transform={`translate(${$nodeGraph.transform.x}px, ${$nodeGraph.transform.y}px) scale(${$nodeGraph.transform.scale})`}> |
341 | | - {#if $nodeGraph.updateImportsExports} |
342 | | - {#each $nodeGraph.updateImportsExports.imports as frontendOutput, index} |
| 343 | + <div class="imports-and-exports" style:transform-origin="0 0" style:transform={`translate(${$nodeGraphTransform.x}px, ${$nodeGraphTransform.y}px) scale(${$nodeGraphTransform.scale})`}> |
| 344 | + {#if $nodeGraphImportsExports} |
| 345 | + {#each $nodeGraphImportsExports.imports as frontendOutput, index} |
343 | 346 | {#if frontendOutput} |
344 | 347 | <svg |
345 | 348 | xmlns="http://www.w3.org/2000/svg" |
|
351 | 354 | data-datatype={frontendOutput.dataType} |
352 | 355 | style:--data-color={`var(--color-data-${frontendOutput.dataType.toLowerCase()})`} |
353 | 356 | style:--data-color-dim={`var(--color-data-${frontendOutput.dataType.toLowerCase()}-dim)`} |
354 | | - style:--offset-left={($nodeGraph.updateImportsExports.importPosition[0] - 8) / 24} |
355 | | - style:--offset-top={($nodeGraph.updateImportsExports.importPosition[1] - 8) / 24 + index} |
| 357 | + style:--offset-left={($nodeGraphImportsExports.importPosition[0] - 8) / 24} |
| 358 | + style:--offset-top={($nodeGraphImportsExports.importPosition[1] - 8) / 24 + index} |
356 | 359 | > |
357 | 360 | {#if frontendOutput.connectedTo.length > 0} |
358 | 361 | <path d="M0,6.306A1.474,1.474,0,0,0,2.356,7.724L7.028,5.248c1.3-.687,1.3-1.809,0-2.5L2.356.276A1.474,1.474,0,0,0,0,1.694Z" fill="var(--data-color)" /> |
|
365 | 368 | on:pointerenter={() => (hoveringImportIndex = index)} |
366 | 369 | on:pointerleave={() => (hoveringImportIndex = undefined)} |
367 | 370 | class="edit-import-export import" |
368 | | - class:separator-bottom={index === 0 && $nodeGraph.updateImportsExports.addImportExport} |
369 | | - class:separator-top={index === 1 && $nodeGraph.updateImportsExports.addImportExport} |
370 | | - style:--offset-left={($nodeGraph.updateImportsExports.importPosition[0] - 8) / 24} |
371 | | - style:--offset-top={($nodeGraph.updateImportsExports.importPosition[1] - 8) / 24 + index} |
| 371 | + class:separator-bottom={index === 0 && $nodeGraphImportsExports.addImportExport} |
| 372 | + class:separator-top={index === 1 && $nodeGraphImportsExports.addImportExport} |
| 373 | + style:--offset-left={($nodeGraphImportsExports.importPosition[0] - 8) / 24} |
| 374 | + style:--offset-top={($nodeGraphImportsExports.importPosition[1] - 8) / 24 + index} |
372 | 375 | > |
373 | 376 | {#if editingNameImportIndex === index} |
374 | 377 | <input |
|
385 | 388 | {frontendOutput.name} |
386 | 389 | </p> |
387 | 390 | {/if} |
388 | | - {#if (hoveringImportIndex === index || editingNameImportIndex === index) && $nodeGraph.updateImportsExports.addImportExport} |
| 391 | + {#if (hoveringImportIndex === index || editingNameImportIndex === index) && $nodeGraphImportsExports.addImportExport} |
389 | 392 | <IconButton |
390 | 393 | size={16} |
391 | 394 | icon="Remove" |
|
402 | 405 | {/if} |
403 | 406 | </div> |
404 | 407 | {:else} |
405 | | - <div |
406 | | - class="plus" |
407 | | - style:--offset-top={($nodeGraph.updateImportsExports.importPosition[1] - 12) / 24} |
408 | | - style:--offset-left={($nodeGraph.updateImportsExports.importPosition[0] - 12) / 24} |
409 | | - > |
| 408 | + <div class="plus" style:--offset-top={($nodeGraphImportsExports.importPosition[1] - 12) / 24} style:--offset-left={($nodeGraphImportsExports.importPosition[0] - 12) / 24}> |
410 | 409 | <IconButton size={24} icon="Add" action={() => editor.addPrimaryImport()} /> |
411 | 410 | </div> |
412 | 411 | {/if} |
413 | 412 | {/each} |
414 | 413 |
|
415 | | - {#each $nodeGraph.updateImportsExports.exports as frontendInput, index} |
| 414 | + {#each $nodeGraphImportsExports.exports as frontendInput, index} |
416 | 415 | {#if frontendInput} |
417 | 416 | <svg |
418 | 417 | xmlns="http://www.w3.org/2000/svg" |
|
424 | 423 | data-datatype={frontendInput.dataType} |
425 | 424 | style:--data-color={`var(--color-data-${frontendInput.dataType.toLowerCase()})`} |
426 | 425 | style:--data-color-dim={`var(--color-data-${frontendInput.dataType.toLowerCase()}-dim)`} |
427 | | - style:--offset-left={($nodeGraph.updateImportsExports.exportPosition[0] - 8) / 24} |
428 | | - style:--offset-top={($nodeGraph.updateImportsExports.exportPosition[1] - 8) / 24 + index} |
| 426 | + style:--offset-left={($nodeGraphImportsExports.exportPosition[0] - 8) / 24} |
| 427 | + style:--offset-top={($nodeGraphImportsExports.exportPosition[1] - 8) / 24 + index} |
429 | 428 | > |
430 | 429 | {#if frontendInput.connectedTo !== "Connected to nothing."} |
431 | 430 | <path d="M0,6.306A1.474,1.474,0,0,0,2.356,7.724L7.028,5.248c1.3-.687,1.3-1.809,0-2.5L2.356.276A1.474,1.474,0,0,0,0,1.694Z" fill="var(--data-color)" /> |
|
437 | 436 | on:pointerenter={() => (hoveringExportIndex = index)} |
438 | 437 | on:pointerleave={() => (hoveringExportIndex = undefined)} |
439 | 438 | class="edit-import-export export" |
440 | | - class:separator-bottom={index === 0 && $nodeGraph.updateImportsExports.addImportExport} |
441 | | - class:separator-top={index === 1 && $nodeGraph.updateImportsExports.addImportExport} |
442 | | - style:--offset-left={($nodeGraph.updateImportsExports.exportPosition[0] - 8) / 24} |
443 | | - style:--offset-top={($nodeGraph.updateImportsExports.exportPosition[1] - 8) / 24 + index} |
| 439 | + class:separator-bottom={index === 0 && $nodeGraphImportsExports.addImportExport} |
| 440 | + class:separator-top={index === 1 && $nodeGraphImportsExports.addImportExport} |
| 441 | + style:--offset-left={($nodeGraphImportsExports.exportPosition[0] - 8) / 24} |
| 442 | + style:--offset-top={($nodeGraphImportsExports.exportPosition[1] - 8) / 24 + index} |
444 | 443 | > |
445 | | - {#if (hoveringExportIndex === index || editingNameExportIndex === index) && $nodeGraph.updateImportsExports.addImportExport} |
| 444 | + {#if (hoveringExportIndex === index || editingNameExportIndex === index) && $nodeGraphImportsExports.addImportExport} |
446 | 445 | {#if index > 0} |
447 | 446 | <div class="reorder-drag-grip" data-tooltip-description="Reorder this export"></div> |
448 | 447 | {/if} |
|
473 | 472 | {/if} |
474 | 473 | </div> |
475 | 474 | {:else} |
476 | | - <div |
477 | | - class="plus" |
478 | | - style:--offset-left={($nodeGraph.updateImportsExports.exportPosition[0] - 12) / 24} |
479 | | - style:--offset-top={($nodeGraph.updateImportsExports.exportPosition[1] - 12) / 24} |
480 | | - > |
| 475 | + <div class="plus" style:--offset-left={($nodeGraphImportsExports.exportPosition[0] - 12) / 24} style:--offset-top={($nodeGraphImportsExports.exportPosition[1] - 12) / 24}> |
481 | 476 | <IconButton size={24} icon="Add" action={() => editor.addPrimaryExport()} /> |
482 | 477 | </div> |
483 | 478 | {/if} |
484 | 479 | {/each} |
485 | 480 |
|
486 | | - {#if $nodeGraph.updateImportsExports.addImportExport} |
| 481 | + {#if $nodeGraphImportsExports.addImportExport} |
487 | 482 | <div |
488 | 483 | class="plus" |
489 | | - style:--offset-left={($nodeGraph.updateImportsExports.importPosition[0] - 12) / 24} |
490 | | - style:--offset-top={($nodeGraph.updateImportsExports.importPosition[1] - 12) / 24 + $nodeGraph.updateImportsExports.imports.length} |
| 484 | + style:--offset-left={($nodeGraphImportsExports.importPosition[0] - 12) / 24} |
| 485 | + style:--offset-top={($nodeGraphImportsExports.importPosition[1] - 12) / 24 + $nodeGraphImportsExports.imports.length} |
491 | 486 | > |
492 | 487 | <IconButton size={24} icon="Add" action={() => editor.addSecondaryImport()} /> |
493 | 488 | </div> |
494 | 489 | <div |
495 | 490 | class="plus" |
496 | | - style:--offset-left={($nodeGraph.updateImportsExports.exportPosition[0] - 12) / 24} |
497 | | - style:--offset-top={($nodeGraph.updateImportsExports.exportPosition[1] - 12) / 24 + $nodeGraph.updateImportsExports.exports.length} |
| 491 | + style:--offset-left={($nodeGraphImportsExports.exportPosition[0] - 12) / 24} |
| 492 | + style:--offset-top={($nodeGraphImportsExports.exportPosition[1] - 12) / 24 + $nodeGraphImportsExports.exports.length} |
498 | 493 | > |
499 | 494 | <IconButton size={24} icon="Add" action={() => editor.addSecondaryExport()} /> |
500 | 495 | </div> |
501 | 496 | {/if} |
502 | 497 |
|
503 | 498 | {#if $nodeGraph.reorderImportIndex !== undefined} |
504 | 499 | {@const position = { |
505 | | - x: Number($nodeGraph.updateImportsExports.importPosition[0]), |
506 | | - y: Number($nodeGraph.updateImportsExports.importPosition[1]) + Number($nodeGraph.reorderImportIndex) * 24, |
| 500 | + x: Number($nodeGraphImportsExports.importPosition[0]), |
| 501 | + y: Number($nodeGraphImportsExports.importPosition[1]) + Number($nodeGraph.reorderImportIndex) * 24, |
507 | 502 | }} |
508 | 503 | <div class="reorder-bar" style:--offset-left={(position.x - 48) / 24} style:--offset-top={(position.y - 12) / 24}></div> |
509 | 504 | {/if} |
510 | 505 |
|
511 | 506 | {#if $nodeGraph.reorderExportIndex !== undefined} |
512 | 507 | {@const position = { |
513 | | - x: Number($nodeGraph.updateImportsExports.exportPosition[0]), |
514 | | - y: Number($nodeGraph.updateImportsExports.exportPosition[1]) + Number($nodeGraph.reorderExportIndex) * 24, |
| 508 | + x: Number($nodeGraphImportsExports.exportPosition[0]), |
| 509 | + y: Number($nodeGraphImportsExports.exportPosition[1]) + Number($nodeGraph.reorderExportIndex) * 24, |
515 | 510 | }} |
516 | 511 | <div class="reorder-bar" style:--offset-left={position.x / 24} style:--offset-top={(position.y - 12) / 24}></div> |
517 | 512 | {/if} |
518 | 513 | {/if} |
519 | 514 | </div> |
520 | 515 |
|
521 | 516 | <!-- Layers and nodes --> |
522 | | - <div class="layers-and-nodes" style:transform-origin="0 0" style:transform={`translate(${$nodeGraph.transform.x}px, ${$nodeGraph.transform.y}px) scale(${$nodeGraph.transform.scale})`}> |
| 517 | + <div class="layers-and-nodes" style:transform-origin="0 0" style:transform={`translate(${$nodeGraphTransform.x}px, ${$nodeGraphTransform.y}px) scale(${$nodeGraphTransform.scale})`}> |
523 | 518 | <!-- Layers --> |
524 | 519 | {#each Array.from($nodeGraph.nodes) |
525 | | - .filter(([nodeId, node]) => node.isLayer && $nodeGraph.visibleNodes.has(nodeId)) |
526 | | - .map(([_, node], nodeIndex) => ({ node, nodeIndex })) as { node, nodeIndex } (nodeIndex)} |
| 520 | + .filter(([nodeId, node]) => node.isLayer && $visibleNodes.has(nodeId)) |
| 521 | + .map(([_, node]) => node) as node (node.id)} |
527 | 522 | {@const clipPathId = String(Math.random()).substring(2)} |
528 | 523 | {@const stackDataInput = node.exposedInputs[0]} |
529 | 524 | {@const layerAreaWidth = $nodeGraph.layerWidths.get(node.id) || 8} |
|
687 | 682 | <!-- Node connection wires --> |
688 | 683 | <div class="wires"> |
689 | 684 | <svg> |
690 | | - {#each $nodeGraph.wires.values() as map} |
| 685 | + {#each $nodeGraphWires.values() as map} |
691 | 686 | {#each map.values() as { pathString, dataType, thick, dashed }} |
692 | 687 | {#if !thick} |
693 | 688 | <path |
|
714 | 709 |
|
715 | 710 | <!-- Nodes --> |
716 | 711 | {#each Array.from($nodeGraph.nodes) |
717 | | - .filter(([nodeId, node]) => !node.isLayer && $nodeGraph.visibleNodes.has(nodeId)) |
718 | | - .map(([_, node], nodeIndex) => ({ node, nodeIndex })) as { node, nodeIndex } (nodeIndex)} |
| 712 | + .filter(([nodeId, node]) => !node.isLayer && $visibleNodes.has(nodeId)) |
| 713 | + .map(([_, node]) => node) as node (node.id)} |
719 | 714 | {@const exposedInputsOutputs = zipWithUndefined(node.exposedInputs, node.exposedOutputs)} |
720 | 715 | {@const clipPathId = String(Math.random()).substring(2)} |
721 | 716 | {@const description = node.reference ? $nodeGraph.nodeDescriptions.get(node.reference) : undefined} |
|
870 | 865 | flex-direction: row; |
871 | 866 | flex-grow: 1; |
872 | 867 |
|
873 | | - // We're displaying the dotted grid in a pseudo-element because `image-rendering` is an inherited property and we don't want it to apply to child elements |
874 | | - &::before { |
875 | | - content: ""; |
| 868 | + .grid-background { |
876 | 869 | position: absolute; |
877 | 870 | width: 100%; |
878 | 871 | height: 100%; |
879 | | - background-size: var(--grid-spacing) var(--grid-spacing); |
880 | | - background-position: calc(var(--grid-offset-x) - var(--grid-dot-radius)) calc(var(--grid-offset-y) - var(--grid-dot-radius)); |
881 | | - background-image: radial-gradient(circle at var(--grid-dot-radius) var(--grid-dot-radius), var(--color-3-darkgray) var(--grid-dot-radius), transparent 0); |
882 | | - background-repeat: repeat; |
883 | | - image-rendering: pixelated; |
884 | | - mix-blend-mode: screen; |
| 872 | + pointer-events: none; |
| 873 | +
|
| 874 | + // We're displaying the dotted grid in a pseudo-element because `image-rendering` is an inherited property and we don't want it to apply to child elements |
| 875 | + &::before { |
| 876 | + content: ""; |
| 877 | + position: absolute; |
| 878 | + width: 100%; |
| 879 | + height: 100%; |
| 880 | + background-size: var(--grid-spacing) var(--grid-spacing); |
| 881 | + background-position: calc(var(--grid-offset-x) - var(--grid-dot-radius)) calc(var(--grid-offset-y) - var(--grid-dot-radius)); |
| 882 | + background-image: radial-gradient(circle at var(--grid-dot-radius) var(--grid-dot-radius), var(--color-3-darkgray) var(--grid-dot-radius), transparent 0); |
| 883 | + background-repeat: repeat; |
| 884 | + image-rendering: pixelated; |
| 885 | + mix-blend-mode: screen; |
| 886 | + } |
885 | 887 | } |
886 | 888 |
|
887 | 889 | > img { |
|
0 commit comments