mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-27 18:28:12 +08:00
Add the style of right-angle grid-aligned wires in the graph (#2182)
* Verticle and horizontal lines achieved(#2170) * vertical lines alligned with grid dots * fixed vertical lines positioning * Deals with cases 5 and 6 * Fixed case 5 and other problematic zones * edge cases solved * edge cases fixed: HorizontalOut & HorizontalIn * added comments * Changed midX and midY * Clean up if/else statements * Consolidate code * Consolidate further * Add preference for wire style --------- Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
co-authored by
Keavon Chambers
parent
2d90bb0cbf
commit
26fa8d967e
+50
-16
@@ -1,4 +1,5 @@
|
|||||||
use crate::messages::layout::utility_types::widget_prelude::*;
|
use crate::messages::layout::utility_types::widget_prelude::*;
|
||||||
|
use crate::messages::portfolio::document::node_graph::utility_types::GraphWireStyle;
|
||||||
use crate::messages::preferences::SelectionMode;
|
use crate::messages::preferences::SelectionMode;
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
|
|
||||||
@@ -32,6 +33,29 @@ impl PreferencesDialogMessageHandler {
|
|||||||
const TITLE: &'static str = "Editor Preferences";
|
const TITLE: &'static str = "Editor Preferences";
|
||||||
|
|
||||||
fn layout(&self, preferences: &PreferencesMessageHandler) -> Layout {
|
fn layout(&self, preferences: &PreferencesMessageHandler) -> Layout {
|
||||||
|
// =====
|
||||||
|
// INPUT
|
||||||
|
// =====
|
||||||
|
|
||||||
|
let zoom_with_scroll_tooltip = "Use the scroll wheel for zooming instead of vertically panning (not recommended for trackpads)";
|
||||||
|
let input_section = vec![TextLabel::new("Input").italic(true).widget_holder()];
|
||||||
|
let zoom_with_scroll = vec![
|
||||||
|
CheckboxInput::new(preferences.zoom_with_scroll)
|
||||||
|
.tooltip(zoom_with_scroll_tooltip)
|
||||||
|
.on_update(|checkbox_input: &CheckboxInput| {
|
||||||
|
PreferencesMessage::ModifyLayout {
|
||||||
|
zoom_with_scroll: checkbox_input.checked,
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
})
|
||||||
|
.widget_holder(),
|
||||||
|
TextLabel::new("Zoom with Scroll").table_align(true).tooltip(zoom_with_scroll_tooltip).widget_holder(),
|
||||||
|
];
|
||||||
|
|
||||||
|
// =========
|
||||||
|
// SELECTION
|
||||||
|
// =========
|
||||||
|
|
||||||
let selection_section = vec![TextLabel::new("Selection").italic(true).widget_holder()];
|
let selection_section = vec![TextLabel::new("Selection").italic(true).widget_holder()];
|
||||||
let selection_mode = RadioInput::new(vec![
|
let selection_mode = RadioInput::new(vec![
|
||||||
RadioEntryData::new(SelectionMode::Touched.to_string())
|
RadioEntryData::new(SelectionMode::Touched.to_string())
|
||||||
@@ -65,20 +89,28 @@ impl PreferencesDialogMessageHandler {
|
|||||||
.selected_index(Some(preferences.selection_mode as u32))
|
.selected_index(Some(preferences.selection_mode as u32))
|
||||||
.widget_holder();
|
.widget_holder();
|
||||||
|
|
||||||
let zoom_with_scroll_tooltip = "Use the scroll wheel for zooming instead of vertically panning (not recommended for trackpads)";
|
// ================
|
||||||
let input_section = vec![TextLabel::new("Input").italic(true).widget_holder()];
|
// NODE GRAPH WIRES
|
||||||
let zoom_with_scroll = vec![
|
// ================
|
||||||
CheckboxInput::new(preferences.zoom_with_scroll)
|
|
||||||
.tooltip(zoom_with_scroll_tooltip)
|
let node_graph_section_tooltip = "Appearance of the wires running between node connections in the graph";
|
||||||
.on_update(|checkbox_input: &CheckboxInput| {
|
let node_graph_section = vec![TextLabel::new("Node Graph Wires").tooltip(node_graph_section_tooltip).italic(true).widget_holder()];
|
||||||
PreferencesMessage::ModifyLayout {
|
let graph_wire_style = RadioInput::new(vec![
|
||||||
zoom_with_scroll: checkbox_input.checked,
|
RadioEntryData::new(GraphWireStyle::GridAligned.to_string())
|
||||||
}
|
.label(GraphWireStyle::GridAligned.to_string())
|
||||||
.into()
|
.tooltip(GraphWireStyle::GridAligned.tooltip_description())
|
||||||
})
|
.on_update(move |_| PreferencesMessage::GraphWireStyle { style: GraphWireStyle::GridAligned }.into()),
|
||||||
.widget_holder(),
|
RadioEntryData::new(GraphWireStyle::Direct.to_string())
|
||||||
TextLabel::new("Zoom with Scroll").table_align(true).tooltip(zoom_with_scroll_tooltip).widget_holder(),
|
.label(GraphWireStyle::Direct.to_string())
|
||||||
];
|
.tooltip(GraphWireStyle::Direct.tooltip_description())
|
||||||
|
.on_update(move |_| PreferencesMessage::GraphWireStyle { style: GraphWireStyle::Direct }.into()),
|
||||||
|
])
|
||||||
|
.selected_index(Some(preferences.graph_wire_style as u32))
|
||||||
|
.widget_holder();
|
||||||
|
|
||||||
|
// ============
|
||||||
|
// EXPERIMENTAL
|
||||||
|
// ============
|
||||||
|
|
||||||
let vello_tooltip = "Use the experimental Vello renderer (your browser must support WebGPU)";
|
let vello_tooltip = "Use the experimental Vello renderer (your browser must support WebGPU)";
|
||||||
let renderer_section = vec![TextLabel::new("Experimental").italic(true).widget_holder()];
|
let renderer_section = vec![TextLabel::new("Experimental").italic(true).widget_holder()];
|
||||||
@@ -126,10 +158,12 @@ impl PreferencesDialogMessageHandler {
|
|||||||
// ];
|
// ];
|
||||||
|
|
||||||
Layout::WidgetLayout(WidgetLayout::new(vec![
|
Layout::WidgetLayout(WidgetLayout::new(vec![
|
||||||
LayoutGroup::Row { widgets: selection_section },
|
|
||||||
LayoutGroup::Row { widgets: vec![selection_mode] },
|
|
||||||
LayoutGroup::Row { widgets: input_section },
|
LayoutGroup::Row { widgets: input_section },
|
||||||
LayoutGroup::Row { widgets: zoom_with_scroll },
|
LayoutGroup::Row { widgets: zoom_with_scroll },
|
||||||
|
LayoutGroup::Row { widgets: selection_section },
|
||||||
|
LayoutGroup::Row { widgets: vec![selection_mode] },
|
||||||
|
LayoutGroup::Row { widgets: node_graph_section },
|
||||||
|
LayoutGroup::Row { widgets: vec![graph_wire_style] },
|
||||||
LayoutGroup::Row { widgets: renderer_section },
|
LayoutGroup::Row { widgets: renderer_section },
|
||||||
LayoutGroup::Row { widgets: use_vello },
|
LayoutGroup::Row { widgets: use_vello },
|
||||||
LayoutGroup::Row { widgets: vector_meshes },
|
LayoutGroup::Row { widgets: vector_meshes },
|
||||||
|
|||||||
@@ -250,6 +250,8 @@ pub enum FrontendMessage {
|
|||||||
UpdateNodeGraph {
|
UpdateNodeGraph {
|
||||||
nodes: Vec<FrontendNode>,
|
nodes: Vec<FrontendNode>,
|
||||||
wires: Vec<FrontendNodeWire>,
|
wires: Vec<FrontendNodeWire>,
|
||||||
|
#[serde(rename = "wiresDirectNotGridAligned")]
|
||||||
|
wires_direct_not_grid_aligned: bool,
|
||||||
},
|
},
|
||||||
UpdateNodeGraphControlBarLayout {
|
UpdateNodeGraphControlBarLayout {
|
||||||
#[serde(rename = "layoutTarget")]
|
#[serde(rename = "layoutTarget")]
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ pub struct DocumentMessageData<'a> {
|
|||||||
pub persistent_data: &'a PersistentData,
|
pub persistent_data: &'a PersistentData,
|
||||||
pub executor: &'a mut NodeGraphExecutor,
|
pub executor: &'a mut NodeGraphExecutor,
|
||||||
pub current_tool: &'a ToolType,
|
pub current_tool: &'a ToolType,
|
||||||
|
pub preferences: &'a PreferencesMessageHandler,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
|
||||||
@@ -172,6 +173,7 @@ impl MessageHandler<DocumentMessage, DocumentMessageData<'_>> for DocumentMessag
|
|||||||
persistent_data,
|
persistent_data,
|
||||||
executor,
|
executor,
|
||||||
current_tool,
|
current_tool,
|
||||||
|
preferences,
|
||||||
} = data;
|
} = data;
|
||||||
|
|
||||||
let selected_nodes_bounding_box_viewport = self.network_interface.selected_nodes_bounding_box_viewport(&self.breadcrumb_network_path);
|
let selected_nodes_bounding_box_viewport = self.network_interface.selected_nodes_bounding_box_viewport(&self.breadcrumb_network_path);
|
||||||
@@ -222,6 +224,7 @@ impl MessageHandler<DocumentMessage, DocumentMessageData<'_>> for DocumentMessag
|
|||||||
graph_view_overlay_open: self.graph_view_overlay_open,
|
graph_view_overlay_open: self.graph_view_overlay_open,
|
||||||
graph_fade_artwork_percentage: self.graph_fade_artwork_percentage,
|
graph_fade_artwork_percentage: self.graph_fade_artwork_percentage,
|
||||||
navigation_handler: &self.navigation_handler,
|
navigation_handler: &self.navigation_handler,
|
||||||
|
preferences,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ pub struct NodeGraphHandlerData<'a> {
|
|||||||
pub graph_view_overlay_open: bool,
|
pub graph_view_overlay_open: bool,
|
||||||
pub graph_fade_artwork_percentage: f64,
|
pub graph_fade_artwork_percentage: f64,
|
||||||
pub navigation_handler: &'a NavigationMessageHandler,
|
pub navigation_handler: &'a NavigationMessageHandler,
|
||||||
|
pub preferences: &'a PreferencesMessageHandler,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@@ -93,6 +94,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
|
|||||||
graph_view_overlay_open,
|
graph_view_overlay_open,
|
||||||
graph_fade_artwork_percentage,
|
graph_fade_artwork_percentage,
|
||||||
navigation_handler,
|
navigation_handler,
|
||||||
|
preferences,
|
||||||
} = data;
|
} = data;
|
||||||
|
|
||||||
match message {
|
match message {
|
||||||
@@ -1293,8 +1295,14 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
|
|||||||
let wires = Self::collect_wires(network_interface, breadcrumb_network_path);
|
let wires = Self::collect_wires(network_interface, breadcrumb_network_path);
|
||||||
let nodes = self.collect_nodes(network_interface, breadcrumb_network_path);
|
let nodes = self.collect_nodes(network_interface, breadcrumb_network_path);
|
||||||
let (layer_widths, chain_widths, has_left_input_wire) = network_interface.collect_layer_widths(breadcrumb_network_path);
|
let (layer_widths, chain_widths, has_left_input_wire) = network_interface.collect_layer_widths(breadcrumb_network_path);
|
||||||
|
let wires_direct_not_grid_aligned = preferences.graph_wire_style.is_direct();
|
||||||
|
|
||||||
responses.add(NodeGraphMessage::UpdateImportsExports);
|
responses.add(NodeGraphMessage::UpdateImportsExports);
|
||||||
responses.add(FrontendMessage::UpdateNodeGraph { nodes, wires });
|
responses.add(FrontendMessage::UpdateNodeGraph {
|
||||||
|
nodes,
|
||||||
|
wires,
|
||||||
|
wires_direct_not_grid_aligned,
|
||||||
|
});
|
||||||
responses.add(FrontendMessage::UpdateLayerWidths {
|
responses.add(FrontendMessage::UpdateLayerWidths {
|
||||||
layer_widths,
|
layer_widths,
|
||||||
chain_widths,
|
chain_widths,
|
||||||
|
|||||||
@@ -200,3 +200,32 @@ pub enum Direction {
|
|||||||
Left,
|
Left,
|
||||||
Right,
|
Right,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Default, serde::Serialize, serde::Deserialize, specta::Type)]
|
||||||
|
pub enum GraphWireStyle {
|
||||||
|
#[default]
|
||||||
|
GridAligned = 0,
|
||||||
|
Direct = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for GraphWireStyle {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
GraphWireStyle::GridAligned => write!(f, "Grid-Aligned"),
|
||||||
|
GraphWireStyle::Direct => write!(f, "Direct"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GraphWireStyle {
|
||||||
|
pub fn tooltip_description(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
GraphWireStyle::GridAligned => "Wires follow the grid, running in straight lines between nodes",
|
||||||
|
GraphWireStyle::Direct => "Wires bend to run at an angle directly between nodes",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_direct(&self) -> bool {
|
||||||
|
*self == GraphWireStyle::Direct
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -106,6 +106,7 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageData<'_>> for PortfolioMes
|
|||||||
persistent_data: &self.persistent_data,
|
persistent_data: &self.persistent_data,
|
||||||
executor: &mut self.executor,
|
executor: &mut self.executor,
|
||||||
current_tool,
|
current_tool,
|
||||||
|
preferences,
|
||||||
};
|
};
|
||||||
document.process_message(message, responses, document_inputs)
|
document.process_message(message, responses, document_inputs)
|
||||||
}
|
}
|
||||||
@@ -121,6 +122,7 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageData<'_>> for PortfolioMes
|
|||||||
persistent_data: &self.persistent_data,
|
persistent_data: &self.persistent_data,
|
||||||
executor: &mut self.executor,
|
executor: &mut self.executor,
|
||||||
current_tool,
|
current_tool,
|
||||||
|
preferences,
|
||||||
};
|
};
|
||||||
document.process_message(message, responses, document_inputs)
|
document.process_message(message, responses, document_inputs)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
use crate::messages::portfolio::document::node_graph::utility_types::GraphWireStyle;
|
||||||
use crate::messages::preferences::SelectionMode;
|
use crate::messages::preferences::SelectionMode;
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
|
|
||||||
@@ -13,6 +14,7 @@ pub enum PreferencesMessage {
|
|||||||
SelectionMode { selection_mode: SelectionMode },
|
SelectionMode { selection_mode: SelectionMode },
|
||||||
VectorMeshes { enabled: bool },
|
VectorMeshes { enabled: bool },
|
||||||
ModifyLayout { zoom_with_scroll: bool },
|
ModifyLayout { zoom_with_scroll: bool },
|
||||||
|
GraphWireStyle { style: GraphWireStyle },
|
||||||
// ImaginateRefreshFrequency { seconds: f64 },
|
// ImaginateRefreshFrequency { seconds: f64 },
|
||||||
// ImaginateServerHostname { hostname: String },
|
// ImaginateServerHostname { hostname: String },
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use crate::messages::input_mapper::key_mapping::MappingVariant;
|
use crate::messages::input_mapper::key_mapping::MappingVariant;
|
||||||
|
use crate::messages::portfolio::document::node_graph::utility_types::GraphWireStyle;
|
||||||
use crate::messages::preferences::SelectionMode;
|
use crate::messages::preferences::SelectionMode;
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
|
|
||||||
@@ -12,6 +13,7 @@ pub struct PreferencesMessageHandler {
|
|||||||
pub zoom_with_scroll: bool,
|
pub zoom_with_scroll: bool,
|
||||||
pub use_vello: bool,
|
pub use_vello: bool,
|
||||||
pub vector_meshes: bool,
|
pub vector_meshes: bool,
|
||||||
|
pub graph_wire_style: GraphWireStyle,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PreferencesMessageHandler {
|
impl PreferencesMessageHandler {
|
||||||
@@ -37,6 +39,7 @@ impl Default for PreferencesMessageHandler {
|
|||||||
imaginate_hostname: host_name,
|
imaginate_hostname: host_name,
|
||||||
use_vello,
|
use_vello,
|
||||||
} = Default::default();
|
} = Default::default();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
imaginate_server_hostname: host_name,
|
imaginate_server_hostname: host_name,
|
||||||
imaginate_refresh_frequency: 1.,
|
imaginate_refresh_frequency: 1.,
|
||||||
@@ -44,6 +47,7 @@ impl Default for PreferencesMessageHandler {
|
|||||||
zoom_with_scroll: matches!(MappingVariant::default(), MappingVariant::ZoomWithScroll),
|
zoom_with_scroll: matches!(MappingVariant::default(), MappingVariant::ZoomWithScroll),
|
||||||
use_vello,
|
use_vello,
|
||||||
vector_meshes: false,
|
vector_meshes: false,
|
||||||
|
graph_wire_style: GraphWireStyle::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -95,6 +99,10 @@ impl MessageHandler<PreferencesMessage, ()> for PreferencesMessageHandler {
|
|||||||
PreferencesMessage::SelectionMode { selection_mode } => {
|
PreferencesMessage::SelectionMode { selection_mode } => {
|
||||||
self.selection_mode = selection_mode;
|
self.selection_mode = selection_mode;
|
||||||
}
|
}
|
||||||
|
PreferencesMessage::GraphWireStyle { style } => {
|
||||||
|
self.graph_wire_style = style;
|
||||||
|
responses.add(NodeGraphMessage::SendGraph);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// TODO: Reenable when Imaginate is restored (and move back up one line since the auto-formatter doesn't like it in that block)
|
// TODO: Reenable when Imaginate is restored (and move back up one line since the auto-formatter doesn't like it in that block)
|
||||||
// PreferencesMessage::ImaginateRefreshFrequency { seconds } => {
|
// PreferencesMessage::ImaginateRefreshFrequency { seconds } => {
|
||||||
|
|||||||
@@ -159,11 +159,13 @@
|
|||||||
return { nodeOutput, nodeInput };
|
return { nodeOutput, nodeInput };
|
||||||
}
|
}
|
||||||
|
|
||||||
function createWirePath(outputPort: SVGSVGElement, inputPort: SVGSVGElement, verticalOut: boolean, verticalIn: boolean, dashed: boolean): WirePath {
|
function createWirePath(outputPort: SVGSVGElement, inputPort: SVGSVGElement, verticalOut: boolean, verticalIn: boolean, dashed: boolean, directNotGridAligned: boolean): WirePath {
|
||||||
const inputPortRect = inputPort.getBoundingClientRect();
|
const inputPortRect = inputPort.getBoundingClientRect();
|
||||||
const outputPortRect = outputPort.getBoundingClientRect();
|
const outputPortRect = outputPort.getBoundingClientRect();
|
||||||
|
|
||||||
const pathString = buildWirePathString(outputPortRect, inputPortRect, verticalOut, verticalIn);
|
const pathString = directNotGridAligned
|
||||||
|
? buildCurvedWirePathString(outputPortRect, inputPortRect, verticalOut, verticalIn)
|
||||||
|
: buildStraightWirePathString(outputPortRect, inputPortRect, verticalOut, verticalIn);
|
||||||
const dataType = (outputPort.getAttribute("data-datatype") as FrontendGraphDataType) || "General";
|
const dataType = (outputPort.getAttribute("data-datatype") as FrontendGraphDataType) || "General";
|
||||||
const thick = verticalIn && verticalOut;
|
const thick = verticalIn && verticalOut;
|
||||||
|
|
||||||
@@ -184,7 +186,7 @@
|
|||||||
const wireEndNode = wire.wireEnd.nodeId !== undefined ? $nodeGraph.nodes.get(wire.wireEnd.nodeId) : undefined;
|
const wireEndNode = wire.wireEnd.nodeId !== undefined ? $nodeGraph.nodes.get(wire.wireEnd.nodeId) : undefined;
|
||||||
const wireEnd = (wireEndNode?.isLayer && Number(wire.wireEnd.index) === 0) || false;
|
const wireEnd = (wireEndNode?.isLayer && Number(wire.wireEnd.index) === 0) || false;
|
||||||
|
|
||||||
return [createWirePath(nodeOutput, nodeInput, wireStart, wireEnd, wire.dashed)];
|
return [createWirePath(nodeOutput, nodeInput, wireStart, wireEnd, wire.dashed, $nodeGraph.wiresDirectNotGridAligned)];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,7 +200,270 @@
|
|||||||
return iconMap[icon] || "NodeNodes";
|
return iconMap[icon] || "NodeNodes";
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildWirePathLocations(outputBounds: DOMRect, inputBounds: DOMRect, verticalOut: boolean, verticalIn: boolean): { x: number; y: number }[] {
|
function buildStraightWirePathLocations(outputBounds: DOMRect, inputBounds: DOMRect, verticalOut: boolean, verticalIn: boolean): { x: number; y: number }[] {
|
||||||
|
if (!nodesContainer) return [];
|
||||||
|
|
||||||
|
const VERTICAL_WIRE_OVERLAP_ON_SHAPED_CAP = 1;
|
||||||
|
const LINE_WIDTH = 2;
|
||||||
|
|
||||||
|
// Calculate coordinates for input and output connectors
|
||||||
|
const inX = verticalIn ? inputBounds.x + inputBounds.width / 2 : inputBounds.x + 1;
|
||||||
|
const inY = verticalIn ? inputBounds.y + inputBounds.height - VERTICAL_WIRE_OVERLAP_ON_SHAPED_CAP : inputBounds.y + inputBounds.height / 2;
|
||||||
|
const outX = verticalOut ? outputBounds.x + outputBounds.width / 2 : outputBounds.x + outputBounds.width - 1;
|
||||||
|
const outY = verticalOut ? outputBounds.y + VERTICAL_WIRE_OVERLAP_ON_SHAPED_CAP : outputBounds.y + outputBounds.height / 2;
|
||||||
|
|
||||||
|
// Adjust for scale
|
||||||
|
const containerBounds = nodesContainer.getBoundingClientRect();
|
||||||
|
const scale = $nodeGraph.transform.scale;
|
||||||
|
const inConnectorX = Math.round((inX - containerBounds.x) / scale);
|
||||||
|
const inConnectorY = Math.round((inY - containerBounds.y) / scale);
|
||||||
|
const outConnectorX = Math.round((outX - containerBounds.x) / scale);
|
||||||
|
const outConnectorY = Math.round((outY - containerBounds.y) / scale);
|
||||||
|
|
||||||
|
// Helper functions for calculating coordinates
|
||||||
|
const calculateMidX = () => (inConnectorX + outConnectorX) / 2 + (((inConnectorX + outConnectorX) / 2) % gridSpacing);
|
||||||
|
const calculateMidY = () => (inConnectorY + outConnectorY) / 2 + (((inConnectorY + outConnectorY) / 2) % gridSpacing);
|
||||||
|
const calculateMidYAlternate = () => (inConnectorY + outConnectorY) / 2 - (((inConnectorY + outConnectorY) / 2) % gridSpacing);
|
||||||
|
|
||||||
|
// Define X coordinate calculations
|
||||||
|
const x1 = () => outConnectorX;
|
||||||
|
const x2 = () => outConnectorX + gridSpacing;
|
||||||
|
const x3 = () => inConnectorX - 2 * gridSpacing;
|
||||||
|
const x4 = () => inConnectorX;
|
||||||
|
const x5 = () => inConnectorX - 2 * gridSpacing + LINE_WIDTH;
|
||||||
|
const x6 = () => outConnectorX + gridSpacing + LINE_WIDTH;
|
||||||
|
const x7 = () => outConnectorX + 2 * gridSpacing + LINE_WIDTH;
|
||||||
|
const x8 = () => inConnectorX + LINE_WIDTH;
|
||||||
|
const x9 = () => outConnectorX + 2 * gridSpacing;
|
||||||
|
const x10 = () => calculateMidX() + LINE_WIDTH;
|
||||||
|
const x11 = () => outConnectorX - gridSpacing;
|
||||||
|
const x12 = () => outConnectorX - 4 * gridSpacing;
|
||||||
|
const x13 = () => calculateMidX();
|
||||||
|
const x14 = () => inConnectorX + gridSpacing;
|
||||||
|
const x15 = () => inConnectorX - 4 * gridSpacing;
|
||||||
|
const x16 = () => inConnectorX + 8 * gridSpacing;
|
||||||
|
const x17 = () => calculateMidX() - 2 * LINE_WIDTH;
|
||||||
|
const x18 = () => outConnectorX + gridSpacing - 2 * LINE_WIDTH;
|
||||||
|
const x19 = () => outConnectorX - 2 * LINE_WIDTH;
|
||||||
|
const x20 = () => calculateMidX() - LINE_WIDTH;
|
||||||
|
|
||||||
|
// Define Y coordinate calculations
|
||||||
|
const y1 = () => outConnectorY;
|
||||||
|
const y2 = () => outConnectorY - gridSpacing;
|
||||||
|
const y3 = () => inConnectorY;
|
||||||
|
const y4 = () => outConnectorY - gridSpacing + 5.5 * LINE_WIDTH;
|
||||||
|
const y5 = () => inConnectorY - 2 * gridSpacing;
|
||||||
|
const y6 = () => outConnectorY + 4 * LINE_WIDTH;
|
||||||
|
const y7 = () => outConnectorY + 5 * LINE_WIDTH;
|
||||||
|
const y8 = () => outConnectorY - 2 * gridSpacing + 5.5 * LINE_WIDTH;
|
||||||
|
const y9 = () => outConnectorY + 6 * LINE_WIDTH;
|
||||||
|
const y10 = () => inConnectorY + 2 * gridSpacing;
|
||||||
|
const y111 = () => inConnectorY + gridSpacing + 6.5 * LINE_WIDTH;
|
||||||
|
const y12 = () => inConnectorY + gridSpacing - 5.5 * LINE_WIDTH;
|
||||||
|
const y13 = () => inConnectorY - gridSpacing;
|
||||||
|
const y14 = () => inConnectorY + gridSpacing;
|
||||||
|
const y15 = () => calculateMidY();
|
||||||
|
const y16 = () => calculateMidYAlternate();
|
||||||
|
|
||||||
|
// Helper function for constructing coordinate pairs
|
||||||
|
const construct = (...coords: [() => number, () => number][]) => coords.map(([x, y]) => ({ x: x(), y: y() }));
|
||||||
|
|
||||||
|
// Define wire path shapes that get used more than once
|
||||||
|
const wire1 = () => construct([x1, y1], [x1, y4], [x5, y4], [x5, y3], [x4, y3]);
|
||||||
|
const wire2 = () => construct([x1, y1], [x1, y16], [x3, y16], [x3, y3], [x4, y3]);
|
||||||
|
const wire3 = () => construct([x1, y1], [x1, y4], [x12, y4], [x12, y10], [x3, y10], [x3, y3], [x4, y3]);
|
||||||
|
const wire4 = () => construct([x1, y1], [x1, y4], [x13, y4], [x13, y10], [x3, y10], [x3, y3], [x4, y3]);
|
||||||
|
|
||||||
|
// `outConnector` point and `inConnector` point lying on the same horizontal grid line and `outConnector` point lies to the right of `inConnector` point
|
||||||
|
if (outConnectorY === inConnectorY && outConnectorX > inConnectorX && (verticalOut || !verticalIn)) return construct([x1, y1], [x2, y1], [x2, y2], [x3, y2], [x3, y3], [x4, y3]);
|
||||||
|
|
||||||
|
// Handle straight lines
|
||||||
|
if (outConnectorY === inConnectorY || (outConnectorX === inConnectorX && verticalOut)) return construct([x1, y1], [x4, y3]);
|
||||||
|
|
||||||
|
// Handle standard right-angle paths
|
||||||
|
// Start vertical, then horizontal
|
||||||
|
|
||||||
|
// `outConnector` point lies to the left of `inConnector` point
|
||||||
|
if (verticalOut && inConnectorX > outConnectorX) {
|
||||||
|
// `outConnector` point lies above `inConnector` point
|
||||||
|
if (outConnectorY < inConnectorY) {
|
||||||
|
// `outConnector` point lies on the vertical grid line 4 units to the left of `inConnector` point point
|
||||||
|
if (-4 * gridSpacing <= outConnectorX - inConnectorX && outConnectorX - inConnectorX < -3 * gridSpacing) return wire1();
|
||||||
|
|
||||||
|
// `outConnector` point lying on vertical grid lines 3 and 2 units to the left of `inConnector` point
|
||||||
|
if (-3 * gridSpacing <= outConnectorX - inConnectorX && outConnectorX - inConnectorX <= -1 * gridSpacing) {
|
||||||
|
if (-2 * gridSpacing <= outConnectorY - inConnectorY && outConnectorY - inConnectorY <= -1 * gridSpacing) return construct([x1, y1], [x1, y2], [x2, y2], [x2, y3], [x4, y3]);
|
||||||
|
|
||||||
|
if (-1 * gridSpacing <= outConnectorY - inConnectorY && outConnectorY - inConnectorY <= 0 * gridSpacing) return construct([x1, y1], [x1, y4], [x6, y4], [x6, y3], [x4, y3]);
|
||||||
|
|
||||||
|
return construct([x1, y1], [x1, y4], [x7, y4], [x7, y5], [x3, y5], [x3, y3], [x4, y3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// `outConnector` point lying on vertical grid line 1 units to the left of `inConnector` point
|
||||||
|
if (-1 * gridSpacing < outConnectorX - inConnectorX && outConnectorX - inConnectorX <= 0 * gridSpacing) {
|
||||||
|
// `outConnector` point lying on horizontal grid line 1 unit above `inConnector` point
|
||||||
|
if (-2 * gridSpacing <= outConnectorY - inConnectorY && outConnectorY - inConnectorY <= -1 * gridSpacing) return construct([x1, y6], [x2, y6], [x8, y3]);
|
||||||
|
|
||||||
|
// `outConnector` point lying on the same horizontal grid line as `inConnector` point
|
||||||
|
if (-1 * gridSpacing <= outConnectorY - inConnectorY && outConnectorY - inConnectorY <= 0 * gridSpacing) return construct([x1, y7], [x4, y3]);
|
||||||
|
|
||||||
|
return construct([x1, y1], [x1, y2], [x9, y2], [x9, y5], [x3, y5], [x3, y3], [x4, y3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return construct([x1, y1], [x1, y4], [x10, y4], [x10, y3], [x4, y3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// `outConnector` point lies below `inConnector` point
|
||||||
|
// `outConnector` point lying on vertical grid line 1 unit to the left of `inConnector` point
|
||||||
|
if (-1 * gridSpacing <= outConnectorX - inConnectorX && outConnectorX - inConnectorX <= 0 * gridSpacing) {
|
||||||
|
// `outConnector` point lying on the horizontal grid lines 1 and 2 units below the `inConnector` point
|
||||||
|
if (0 * gridSpacing <= outConnectorY - inConnectorY && outConnectorY - inConnectorY <= 2 * gridSpacing) construct([x1, y6], [x11, y6], [x11, y3], [x4, y3]);
|
||||||
|
|
||||||
|
return wire2();
|
||||||
|
}
|
||||||
|
|
||||||
|
return construct([x1, y1], [x1, y3], [x4, y3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// `outConnector` point lies to the right of `inConnector` point
|
||||||
|
if (verticalOut && inConnectorX <= outConnectorX) {
|
||||||
|
// `outConnector` point lying on any horizontal grid line above `inConnector` point
|
||||||
|
if (outConnectorY < inConnectorY) {
|
||||||
|
// `outConnector` point lying on horizontal grid line 1 unit above `inConnector` point
|
||||||
|
if (-2 * gridSpacing < outConnectorY - inConnectorY && outConnectorY - inConnectorY <= -1 * gridSpacing) return wire1();
|
||||||
|
|
||||||
|
// `outConnector` point lying on the same horizontal grid line as `inConnector` point
|
||||||
|
if (-1 * gridSpacing < outConnectorY - inConnectorY && outConnectorY - inConnectorY <= 0 * gridSpacing) return construct([x1, y1], [x1, y8], [x5, y8], [x5, y3], [x4, y3]);
|
||||||
|
|
||||||
|
// `outConnector` point lying on vertical grid lines 1 and 2 units to the right of `inConnector` point
|
||||||
|
if (gridSpacing <= outConnectorX - inConnectorX && outConnectorX - inConnectorX <= 3 * gridSpacing) {
|
||||||
|
return construct([x1, y1], [x1, y4], [x9, y4], [x9, y5], [x3, y5], [x3, y3], [x4, y3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return construct([x1, y1], [x1, y4], [x10, y4], [x10, y5], [x5, y5], [x5, y3], [x4, y3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// `outConnector` point lies below `inConnector` point
|
||||||
|
if (outConnectorY - inConnectorY <= gridSpacing) {
|
||||||
|
// `outConnector` point lies on the horizontal grid line 1 unit below the `inConnector` Point
|
||||||
|
if (0 <= outConnectorX - inConnectorX && outConnectorX - inConnectorX <= 13 * gridSpacing) return construct([x1, y9], [x3, y9], [x3, y3], [x4, y3]);
|
||||||
|
|
||||||
|
if (13 < outConnectorX - inConnectorX && outConnectorX - inConnectorX <= 18 * gridSpacing) return wire3();
|
||||||
|
|
||||||
|
return wire4();
|
||||||
|
}
|
||||||
|
|
||||||
|
// `outConnector` point lies on the horizontal grid line 2 units below `outConnector` point
|
||||||
|
if (gridSpacing <= outConnectorY - inConnectorY && outConnectorY - inConnectorY <= 2 * gridSpacing) {
|
||||||
|
if (0 <= outConnectorX - inConnectorX && outConnectorX - inConnectorX <= 13 * gridSpacing) return construct([x1, y7], [x5, y7], [x5, y3], [x4, y3]);
|
||||||
|
|
||||||
|
if (13 < outConnectorX - inConnectorX && outConnectorX - inConnectorX <= 18 * gridSpacing) return wire3();
|
||||||
|
|
||||||
|
return wire4();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 0 to 4 units below the `outConnector` Point
|
||||||
|
if (outConnectorY - inConnectorY <= 4 * gridSpacing) return wire1();
|
||||||
|
|
||||||
|
return wire2();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start horizontal, then vertical
|
||||||
|
if (verticalIn) {
|
||||||
|
// when `outConnector` lies below `inConnector`
|
||||||
|
if (outConnectorY > inConnectorY) {
|
||||||
|
// `outConnectorX` lies to the left of `inConnectorX`
|
||||||
|
if (outConnectorX < inConnectorX) return construct([x1, y1], [x4, y1], [x4, y3]);
|
||||||
|
|
||||||
|
// `outConnectorX` lies to the right of `inConnectorX`
|
||||||
|
if (outConnectorY - inConnectorY <= gridSpacing) {
|
||||||
|
// `outConnector` point directly below `inConnector` point
|
||||||
|
if (0 <= outConnectorX - inConnectorX && outConnectorX - inConnectorX <= gridSpacing) return construct([x1, y1], [x14, y1], [x14, y2], [x4, y2], [x4, y3]);
|
||||||
|
|
||||||
|
// `outConnector` point lies below `inConnector` point and strictly to the right of `inConnector` point
|
||||||
|
return construct([x1, y1], [x2, y1], [x2, y111], [x4, y111], [x4, y3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return construct([x1, y1], [x2, y1], [x2, y2], [x4, y2], [x4, y3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// `outConnectorY` lies on or above the `inConnectorY` point
|
||||||
|
if (-6 * gridSpacing < inConnectorX - outConnectorX && inConnectorX - outConnectorX < 4 * gridSpacing) {
|
||||||
|
// edge case: `outConnector` point lying on vertical grid lines ranging from 4 units to left to 5 units to right of `inConnector` point
|
||||||
|
if (-1 * gridSpacing < inConnectorX - outConnectorX && inConnectorX - outConnectorX < 4 * gridSpacing) {
|
||||||
|
return construct([x1, y1], [x2, y1], [x2, y2], [x15, y2], [x15, y12], [x4, y12], [x4, y3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return construct([x1, y1], [x16, y1], [x16, y12], [x4, y12], [x4, y3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// left of edge case: `outConnector` point lying on vertical grid lines more than 4 units to left of `inConnector` point
|
||||||
|
if (4 * gridSpacing < inConnectorX - outConnectorX) return construct([x1, y1], [x17, y1], [x17, y12], [x4, y12], [x4, y3]);
|
||||||
|
|
||||||
|
// right of edge case: `outConnector` point lying on the vertical grid lines more than 5 units to right of `inConnector` point
|
||||||
|
if (6 * gridSpacing > inConnectorX - outConnectorX) return construct([x1, y1], [x18, y1], [x18, y12], [x4, y12], [x4, y3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Both horizontal - use horizontal middle point
|
||||||
|
// When `inConnector` point is one of the two closest diagonally opposite points
|
||||||
|
if (0 <= inConnectorX - outConnectorX && inConnectorX - outConnectorX <= gridSpacing && inConnectorY - outConnectorY >= -1 * gridSpacing && inConnectorY - outConnectorY <= gridSpacing) {
|
||||||
|
return construct([x19, y1], [x19, y3], [x4, y3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// When `inConnector` point lies on the horizontal line 1 unit above and below the `outConnector` point
|
||||||
|
if (-1 * gridSpacing <= outConnectorY - inConnectorY && outConnectorY - inConnectorY <= gridSpacing && outConnectorX > inConnectorX) {
|
||||||
|
// Horizontal line above `outConnectorY`
|
||||||
|
if (inConnectorY < outConnectorY) return construct([x1, y1], [x2, y1], [x2, y13], [x3, y13], [x3, y3], [x4, y3]);
|
||||||
|
|
||||||
|
// Horizontal line below `outConnectorY`
|
||||||
|
return construct([x1, y1], [x2, y1], [x2, y14], [x3, y14], [x3, y3], [x4, y3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// `outConnector` point to the right of `inConnector` point
|
||||||
|
if (outConnectorX > inConnectorX - gridSpacing) return construct([x1, y1], [x18, y1], [x18, y15], [x5, y15], [x5, y3], [x4, y3]);
|
||||||
|
|
||||||
|
// When `inConnector` point lies on the vertical grid line two units to the right of `outConnector` point
|
||||||
|
if (gridSpacing <= inConnectorX - outConnectorX && inConnectorX - outConnectorX <= 2 * gridSpacing) return construct([x1, y1], [x18, y1], [x18, y3], [x4, y3]);
|
||||||
|
|
||||||
|
return construct([x1, y1], [x20, y1], [x20, y3], [x4, y3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildStraightWirePathString(outputBounds: DOMRect, inputBounds: DOMRect, verticalOut: boolean, verticalIn: boolean): string {
|
||||||
|
const locations = buildStraightWirePathLocations(outputBounds, inputBounds, verticalOut, verticalIn);
|
||||||
|
if (locations.length === 0) return "[error]";
|
||||||
|
if (locations.length === 2) return `M${locations[0].x},${locations[0].y} L${locations[1].x},${locations[1].y}`;
|
||||||
|
|
||||||
|
const CORNER_RADIUS = 10;
|
||||||
|
|
||||||
|
// Create path with rounded corners
|
||||||
|
let path = `M${locations[0].x},${locations[0].y}`;
|
||||||
|
|
||||||
|
for (let i = 1; i < locations.length - 1; i++) {
|
||||||
|
const prev = locations[i - 1];
|
||||||
|
const curr = locations[i];
|
||||||
|
const next = locations[i + 1];
|
||||||
|
|
||||||
|
// Calculate corner points
|
||||||
|
const isVertical = curr.x === prev.x;
|
||||||
|
const cornerStart = {
|
||||||
|
x: curr.x + (isVertical ? 0 : prev.x < curr.x ? -CORNER_RADIUS : CORNER_RADIUS),
|
||||||
|
y: curr.y + (isVertical ? (prev.y < curr.y ? -CORNER_RADIUS : CORNER_RADIUS) : 0),
|
||||||
|
};
|
||||||
|
const cornerEnd = {
|
||||||
|
x: curr.x + (isVertical ? (next.x < curr.x ? -CORNER_RADIUS : CORNER_RADIUS) : 0),
|
||||||
|
y: curr.y + (isVertical ? 0 : next.y < curr.y ? -CORNER_RADIUS : CORNER_RADIUS),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add line to corner start, quadratic curve for corner, then continue to next point
|
||||||
|
path += ` L${cornerStart.x},${cornerStart.y}`;
|
||||||
|
path += ` Q${curr.x},${curr.y} ${cornerEnd.x},${cornerEnd.y}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
path += ` L${locations[locations.length - 1].x},${locations[locations.length - 1].y}`;
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildCurvedWirePathLocations(outputBounds: DOMRect, inputBounds: DOMRect, verticalOut: boolean, verticalIn: boolean): { x: number; y: number }[] {
|
||||||
if (!nodesContainer) return [];
|
if (!nodesContainer) return [];
|
||||||
|
|
||||||
const VERTICAL_WIRE_OVERLAP_ON_SHAPED_CAP = 1;
|
const VERTICAL_WIRE_OVERLAP_ON_SHAPED_CAP = 1;
|
||||||
@@ -217,19 +482,6 @@
|
|||||||
const horizontalGap = Math.abs(outConnectorX - inConnectorX);
|
const horizontalGap = Math.abs(outConnectorX - inConnectorX);
|
||||||
const verticalGap = Math.abs(outConnectorY - inConnectorY);
|
const verticalGap = Math.abs(outConnectorY - inConnectorY);
|
||||||
|
|
||||||
// TODO: Finish this commented out code replacement for the code below it based on this diagram: <https://files.keavon.com/-/InsubstantialElegantQueenant/capture.png>
|
|
||||||
// // Straight: stacking lines which are always straight, or a straight horizontal wire between two aligned nodes
|
|
||||||
// if ((verticalOut && verticalIn) || (!verticalOut && !verticalIn && verticalGap === 0)) {
|
|
||||||
// return [
|
|
||||||
// { x: outConnectorX, y: outConnectorY },
|
|
||||||
// { x: inConnectorX, y: inConnectorY },
|
|
||||||
// ];
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // L-shape bend
|
|
||||||
// if (verticalOut !== verticalIn) {
|
|
||||||
// }
|
|
||||||
|
|
||||||
const curveLength = 24;
|
const curveLength = 24;
|
||||||
const curveFalloffRate = curveLength * Math.PI * 2;
|
const curveFalloffRate = curveLength * Math.PI * 2;
|
||||||
|
|
||||||
@@ -246,12 +498,14 @@
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildWirePathString(outputBounds: DOMRect, inputBounds: DOMRect, verticalOut: boolean, verticalIn: boolean): string {
|
function buildCurvedWirePathString(outputBounds: DOMRect, inputBounds: DOMRect, verticalOut: boolean, verticalIn: boolean): string {
|
||||||
const locations = buildWirePathLocations(outputBounds, inputBounds, verticalOut, verticalIn);
|
const locations = buildCurvedWirePathLocations(outputBounds, inputBounds, verticalOut, verticalIn);
|
||||||
if (locations.length === 0) return "[error]";
|
if (locations.length === 0) return "[error]";
|
||||||
|
|
||||||
const SMOOTHING = 0.5;
|
const SMOOTHING = 0.5;
|
||||||
const delta01 = { x: (locations[1].x - locations[0].x) * SMOOTHING, y: (locations[1].y - locations[0].y) * SMOOTHING };
|
const delta01 = { x: (locations[1].x - locations[0].x) * SMOOTHING, y: (locations[1].y - locations[0].y) * SMOOTHING };
|
||||||
const delta23 = { x: (locations[3].x - locations[2].x) * SMOOTHING, y: (locations[3].y - locations[2].y) * SMOOTHING };
|
const delta23 = { x: (locations[3].x - locations[2].x) * SMOOTHING, y: (locations[3].y - locations[2].y) * SMOOTHING };
|
||||||
|
|
||||||
return `
|
return `
|
||||||
M${locations[0].x},${locations[0].y}
|
M${locations[0].x},${locations[0].y}
|
||||||
L${locations[1].x},${locations[1].y}
|
L${locations[1].x},${locations[1].y}
|
||||||
@@ -335,31 +589,20 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function outputConnectedToText(output: FrontendGraphOutput): string {
|
function outputConnectedToText(output: FrontendGraphOutput): string {
|
||||||
if (output.connectedTo.length === 0) {
|
if (output.connectedTo.length === 0) return "Connected to nothing";
|
||||||
return "Connected to nothing";
|
|
||||||
} else {
|
return output.connectedTo
|
||||||
return output.connectedTo
|
.map((inputConnector) => {
|
||||||
.map((inputConnector) => {
|
if ((inputConnector as Node).nodeId === undefined) return `Connected to export index ${inputConnector.index}`;
|
||||||
if ((inputConnector as Node).nodeId === undefined) {
|
return `Connected to ${(inputConnector as Node).nodeId}, port index ${inputConnector.index}`;
|
||||||
return `Connected to export index ${inputConnector.index}`;
|
})
|
||||||
} else {
|
.join("\n");
|
||||||
return `Connected to ${(inputConnector as Node).nodeId}, port index ${inputConnector.index}`;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.join("\n");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function inputConnectedToText(input: FrontendGraphInput): string {
|
function inputConnectedToText(input: FrontendGraphInput): string {
|
||||||
if (input.connectedTo === undefined) {
|
if (input.connectedTo === undefined) return "Connected to nothing";
|
||||||
return "Connected to nothing";
|
if ((input.connectedTo as Node).nodeId === undefined) return `Connected to import index ${input.connectedTo.index}`;
|
||||||
} else {
|
return `Connected to ${(input.connectedTo as Node).nodeId}, port index ${input.connectedTo.index}`;
|
||||||
if ((input.connectedTo as Node).nodeId === undefined) {
|
|
||||||
return `Connected to import index ${input.connectedTo.index}`;
|
|
||||||
} else {
|
|
||||||
return `Connected to ${(input.connectedTo as Node).nodeId}, port index ${input.connectedTo.index}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function primaryOutputConnectedToLayer(node: FrontendNode): boolean {
|
function primaryOutputConnectedToLayer(node: FrontendNode): boolean {
|
||||||
|
|||||||
@@ -100,6 +100,8 @@ export class UpdateNodeGraph extends JsMessage {
|
|||||||
|
|
||||||
@Type(() => FrontendNodeWire)
|
@Type(() => FrontendNodeWire)
|
||||||
readonly wires!: FrontendNodeWire[];
|
readonly wires!: FrontendNodeWire[];
|
||||||
|
|
||||||
|
readonly wiresDirectNotGridAligned!: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class UpdateNodeGraphTransform extends JsMessage {
|
export class UpdateNodeGraphTransform extends JsMessage {
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ export function createNodeGraphState(editor: Editor) {
|
|||||||
addExport: undefined as { x: number; y: number } | undefined,
|
addExport: undefined as { x: number; y: number } | undefined,
|
||||||
nodes: new Map<bigint, FrontendNode>(),
|
nodes: new Map<bigint, FrontendNode>(),
|
||||||
wires: [] as FrontendNodeWire[],
|
wires: [] as FrontendNodeWire[],
|
||||||
|
wiresDirectNotGridAligned: false,
|
||||||
wirePathInProgress: undefined as WirePath | undefined,
|
wirePathInProgress: undefined as WirePath | undefined,
|
||||||
inputTypeDescriptions: new Map<string, string>(),
|
inputTypeDescriptions: new Map<string, string>(),
|
||||||
nodeDescriptions: new Map<string, string>(),
|
nodeDescriptions: new Map<string, string>(),
|
||||||
@@ -123,6 +124,7 @@ export function createNodeGraphState(editor: Editor) {
|
|||||||
state.nodes.set(node.id, node);
|
state.nodes.set(node.id, node);
|
||||||
});
|
});
|
||||||
state.wires = updateNodeGraph.wires;
|
state.wires = updateNodeGraph.wires;
|
||||||
|
state.wiresDirectNotGridAligned = updateNodeGraph.wiresDirectNotGridAligned;
|
||||||
return state;
|
return state;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user