diff --git a/doc/distrib/NodeHelpFiles/CoreNodeModelsWpf.Charts.BasicLineChartNodeModel.md b/doc/distrib/NodeHelpFiles/CoreNodeModelsWpf.Charts.BasicLineChartNodeModel.md index 80e6fbc41d1..16a8150d475 100644 --- a/doc/distrib/NodeHelpFiles/CoreNodeModelsWpf.Charts.BasicLineChartNodeModel.md +++ b/doc/distrib/NodeHelpFiles/CoreNodeModelsWpf.Charts.BasicLineChartNodeModel.md @@ -1,6 +1,6 @@ ## In Depth -Basic Line creates a line chart with one or multiple labeled and color-coded lines plotted along a series of points. The number of string values in the list entered in the labels input determines the number of lines in the chart, along with their corresponding labels. +Index-Value Line Plot creates a line chart with one or multiple labeled and color-coded lines plotted along a series of points. The number of string values in the list entered in the labels input determines the number of lines in the chart, along with their corresponding labels. A list of double value lists entered into the values input determines the position of each point along the line(s). Assign a color for each line by entering a list of color values into the colors input. ___ diff --git a/src/DynamoCore/Graph/Nodes/NodeModel.cs b/src/DynamoCore/Graph/Nodes/NodeModel.cs index 55a5f924989..2b1b8101ae6 100644 --- a/src/DynamoCore/Graph/Nodes/NodeModel.cs +++ b/src/DynamoCore/Graph/Nodes/NodeModel.cs @@ -1735,10 +1735,15 @@ public virtual void ClearErrorsAndWarnings() /// /// Clears the info messages that are generated when running the graph, - /// the State will be set to ElementState.Dead. + /// the State will be set to ElementState.Active. /// public virtual void ClearInfoMessages() { + if (State == ElementState.Info) + { + State = ElementState.Active; + } + infos.RemoveWhere(x => x.State == ElementState.Info); OnNodeInfoMessagesClearing(); } diff --git a/src/Libraries/CoreNodeModelsWpf/Charts/BarChartNodeModel.cs b/src/Libraries/CoreNodeModelsWpf/Charts/BarChartNodeModel.cs index accae76bac2..2d0531cfc0c 100644 --- a/src/Libraries/CoreNodeModelsWpf/Charts/BarChartNodeModel.cs +++ b/src/Libraries/CoreNodeModelsWpf/Charts/BarChartNodeModel.cs @@ -18,6 +18,10 @@ using Dynamo.UI; using DynamoServices; using Dynamo.Wpf.Properties; +using Dynamo.Graph.Connectors; +using System.Linq; +using Newtonsoft.Json.Linq; +using Dynamo.ViewModels; namespace CoreNodeModelsWpf.Charts { @@ -26,9 +30,16 @@ namespace CoreNodeModelsWpf.Charts [NodeCategory("Display.Charts.Create")] [NodeDescription("ChartsBarChartDescription", typeof(CoreNodeModelWpfResources))] [NodeSearchTags("ChartsBarChartSearchTags", typeof(CoreNodeModelWpfResources))] - + [InPortNames("labels", "values", "colors")] [InPortTypes("List", "List", "List")] - [OutPortTypes("Dictionary")] + [InPortDescriptions(typeof(CoreNodeModelWpfResources), + "ChartsBarChartLabelsDataPortToolTip", + "ChartsBarChartValuesDataPortToolTip", + "ChartsBarChartColorsDataPortToolTip")] + [OutPortNames("labels:values")] + [OutPortTypes("Dictionary")] + [OutPortDescriptions(typeof(CoreNodeModelWpfResources), + "ChartsBarChartLabelsValuesDataPortToolTip")] [AlsoKnownAs("CoreNodeModelsWpf.Charts.BarChart")] public class BarChartNodeModel : NodeModel { @@ -50,6 +61,16 @@ public class BarChartNodeModel : NodeModel /// Bar chart color values. /// public List Colors { get; set; } + + /// + /// Triggers when port is connected or disconnected + /// + public event EventHandler PortUpdated; + + protected virtual void OnPortUpdated(EventArgs args) + { + PortUpdated?.Invoke(this, args); + } #endregion #region Constructors @@ -58,25 +79,21 @@ public class BarChartNodeModel : NodeModel /// public BarChartNodeModel() { - InPorts.Add(new PortModel(PortType.Input, this, new PortData("labels", "A list of labels for the bar chart categories."))); - InPorts.Add(new PortModel(PortType.Input, this, new PortData("values", "A list (of lists) to supply values for the bars in each category."))); - InPorts.Add(new PortModel(PortType.Input, this, new PortData("colors", "A list of colors for each bar chart category."))); - - OutPorts.Add(new PortModel(PortType.Output, this, new PortData("labels:values", "Dictionary containing label:value key-pairs"))); - RegisterAllPorts(); + PortConnected += BarChartNodeModel_PortConnected; PortDisconnected += BarChartNodeModel_PortDisconnected; ArgumentLacing = LacingStrategy.Disabled; } - [JsonConstructor] /// /// Instantiate a new NodeModel instance. /// + [JsonConstructor] public BarChartNodeModel(IEnumerable inPorts, IEnumerable outPorts) : base(inPorts, outPorts) { + PortConnected += BarChartNodeModel_PortConnected; PortDisconnected += BarChartNodeModel_PortDisconnected; } #endregion @@ -84,16 +101,28 @@ public BarChartNodeModel(IEnumerable inPorts, IEnumerable #region Events private void BarChartNodeModel_PortDisconnected(PortModel port) { + OnPortUpdated(null); // Clear UI when a input port is disconnected - if (port.PortType == PortType.Input && this.State == ElementState.Active) + if (port.PortType == PortType.Input) { - Labels.Clear(); - Values.Clear(); - Colors.Clear(); + Labels?.Clear(); + Values?.Clear(); + Colors?.Clear(); RaisePropertyChanged("DataUpdated"); } } + private void BarChartNodeModel_PortConnected(PortModel port, ConnectorModel arg2) + { + // Reset an info states if any + if (port.PortType == PortType.Input && InPorts[2].IsConnected && NodeInfos.Any(x => x.State.Equals(ElementState.Info))) + { + this.ClearInfoMessages(); + } + + OnPortUpdated(null); + RaisePropertyChanged("DataUpdated"); + } #endregion #region databridge @@ -126,10 +155,9 @@ private void DataBridgeCallback(object data) var values = inputs[1] as ArrayList; var colors = inputs[2] as ArrayList; - // Only continue if key/values match in length - if (labels.Count != values.Count && labels.Count != (values[0] as ArrayList).Count) + if (!InPorts[0].IsConnected && !InPorts[1].IsConnected && !InPorts[2].IsConnected) { - throw new Exception("Label and Values do not properly align in length."); + return; } // Update chart properties @@ -137,6 +165,14 @@ private void DataBridgeCallback(object data) Values = new List>(); Colors = new List(); + var anyNullData = labels == null || values == null; + + // Only continue if key/values match in length + if (anyNullData || labels.Count != values.Count && labels.Count != (values[0] as ArrayList).Count || labels.Count == 0) + { + throw new Exception("Label and Values do not properly align in length."); + } + // If the bar chart contains nested lists if (values[0] is ArrayList) { @@ -159,6 +195,8 @@ private void DataBridgeCallback(object data) Color color; if (colors == null || colors.Count == 0 || colors.Count != labels.Count) { + if (InPorts[2].IsConnected) return; + // In case colors are not provided, we supply some from the default library of colors Info(Dynamo.Wpf.Properties.CoreNodeModelWpfResources.ProvideDefaultColorsWarningMessage); @@ -166,7 +204,6 @@ private void DataBridgeCallback(object data) } else { - var dynColor = (DSCore.Color)colors[i]; color = Color.FromArgb(dynColor.Alpha, dynColor.Red, dynColor.Green, dynColor.Blue); } @@ -191,6 +228,11 @@ private void DataBridgeCallback(object data) Color color; if (colors == null || colors.Count == 0 || colors.Count != labels.Count) { + if (InPorts[3].IsConnected) return; + + // In case colors are not provided, we supply some from the default library of colors + Info(Dynamo.Wpf.Properties.CoreNodeModelWpfResources.ProvideDefaultColorsWarningMessage); + color = Utilities.Colors.GetColor(); } else @@ -227,41 +269,61 @@ public override IEnumerable BuildOutputAst(List, List, List, Dictionary>(BarChartFunctions.GetNodeInput), + new List { inputAstNodes[0], inputAstNodes[1], inputAstNodes[2] } + ); + return new[] { - AstFactory.BuildAssignment(GetAstIdentifierForOutputIndex(0), AstFactory.BuildNullNode()), + AstFactory.BuildAssignment(GetAstIdentifierForOutputIndex(0), inputNode), + AstFactory.BuildAssignment( + AstFactory.BuildIdentifier(AstIdentifierBase + "_dummy"), + VMDataBridge.DataBridge.GenerateBridgeDataAst(GUID.ToString(), AstFactory.BuildExprList(inputAstNodes) + ) + ), }; } - - AssociativeNode inputNode; - if (isNestedList) + else if (!InPorts[0].IsConnected || !InPorts[1].IsConnected) { - inputNode = AstFactory.BuildFunctionCall( - new Func, List>, List, Dictionary>>(BarChartFunctions.GetNodeInput), - new List { inputAstNodes[0], inputAstNodes[1], inputAstNodes[2] } - ); + return new[] + { + AstFactory.BuildAssignment(GetAstIdentifierForOutputIndex(0), AstFactory.BuildNullNode()), + }; } else { - inputNode = AstFactory.BuildFunctionCall( - new Func, List, List, Dictionary>(BarChartFunctions.GetNodeInput), - new List { inputAstNodes[0], inputAstNodes[1], inputAstNodes[2] } - ); + if (isNestedList) + { + inputNode = AstFactory.BuildFunctionCall( + new Func, List>, List, Dictionary>>(BarChartFunctions.GetNodeInput), + new List { inputAstNodes[0], inputAstNodes[1], inputAstNodes[2] } + ); + } + else + { + inputNode = AstFactory.BuildFunctionCall( + new Func, List, List, Dictionary>(BarChartFunctions.GetNodeInput), + new List { inputAstNodes[0], inputAstNodes[1], inputAstNodes[2] } + ); + } + + return new[] + { + AstFactory.BuildAssignment(GetAstIdentifierForOutputIndex(0), inputNode), + AstFactory.BuildAssignment( + AstFactory.BuildIdentifier(AstIdentifierBase + "_dummy"), + VMDataBridge.DataBridge.GenerateBridgeDataAst(GUID.ToString(), AstFactory.BuildExprList(inputAstNodes) + ) + ), + }; } - return new[] - { - AstFactory.BuildAssignment(GetAstIdentifierForOutputIndex(0), inputNode), - AstFactory.BuildAssignment( - AstFactory.BuildIdentifier(AstIdentifierBase + "_dummy"), - VMDataBridge.DataBridge.GenerateBridgeDataAst(GUID.ToString(), AstFactory.BuildExprList(inputAstNodes) - ) - ), - }; } #endregion @@ -272,6 +334,7 @@ public override IEnumerable BuildOutputAst(List public override void Dispose() { + PortConnected -= BarChartNodeModel_PortConnected; PortDisconnected -= BarChartNodeModel_PortDisconnected; VMDataBridge.DataBridge.Instance.UnregisterCallback(GUID.ToString()); } @@ -285,6 +348,8 @@ public override void Dispose() public class BarChartNodeView : INodeViewCustomization { private BarChartControl barChartControl; + private NodeView view; + private BarChartNodeModel model; /// /// At run-time, this method is called during the node @@ -294,6 +359,8 @@ public class BarChartNodeView : INodeViewCustomization /// The NodeView representing the node in the graph. public void CustomizeView(BarChartNodeModel model, NodeView nodeView) { + this.model = model; + this.view = nodeView; barChartControl = new BarChartControl(model); nodeView.inputGrid.Children.Add(barChartControl); @@ -303,6 +370,49 @@ public void CustomizeView(BarChartNodeModel model, NodeView nodeView) var contextMenu = (nodeView.Content as Grid).ContextMenu; contextMenu.Items.Add(exportImage); + + UpdateDefaultInPortValues(); + + model.PortUpdated += ModelOnPortUpdated; + } + + private void ModelOnPortUpdated(object sender, EventArgs e) + { + UpdateDefaultInPortValues(); + } + + private void UpdateDefaultInPortValues() + { + if (!this.view.ViewModel.InPorts.Any()) return; + var inPorts = this.view.ViewModel.InPorts; + + // Only apply default values if all ports are disconnected + if (!model.IsInErrorState && + model.State != ElementState.Active && + !inPorts[0].IsConnected && + !inPorts[1].IsConnected) + { + ((InPortViewModel)inPorts[0]).PortDefaultValueMarkerVisible = true; + ((InPortViewModel)inPorts[1]).PortDefaultValueMarkerVisible = true; + } + else + { + ((InPortViewModel)inPorts[0]).PortDefaultValueMarkerVisible = false; + ((InPortViewModel)inPorts[1]).PortDefaultValueMarkerVisible = false; + } + + var allPortsConnected = inPorts[0].IsConnected && inPorts[1].IsConnected && model.State != ElementState.Warning; + var noPortsConnected = !inPorts[0].IsConnected && !inPorts[1].IsConnected; + + // The color input uses default values if it's not connected + if (!inPorts[2].IsConnected && (allPortsConnected || noPortsConnected)) + { + ((InPortViewModel)inPorts[2]).PortDefaultValueMarkerVisible = true; + } + else + { + ((InPortViewModel)inPorts[2]).PortDefaultValueMarkerVisible = false; + } } private void ExportImage_Click(object sender, RoutedEventArgs e) @@ -314,6 +424,9 @@ private void ExportImage_Click(object sender, RoutedEventArgs e) /// Here you can do any cleanup you require if you've assigned callbacks for particular /// UI events on your node. /// - public void Dispose() { } + public void Dispose() + { + model.PortUpdated -= ModelOnPortUpdated; + } } } diff --git a/src/Libraries/CoreNodeModelsWpf/Charts/BasicLineChartNodeModel.cs b/src/Libraries/CoreNodeModelsWpf/Charts/BasicLineChartNodeModel.cs index 113fb94963a..c78a6765a1d 100644 --- a/src/Libraries/CoreNodeModelsWpf/Charts/BasicLineChartNodeModel.cs +++ b/src/Libraries/CoreNodeModelsWpf/Charts/BasicLineChartNodeModel.cs @@ -17,6 +17,8 @@ using ProtoCore.AST.AssociativeAST; using DynamoServices; using Dynamo.Wpf.Properties; +using Dynamo.Graph.Connectors; +using Dynamo.ViewModels; namespace CoreNodeModelsWpf.Charts { @@ -25,9 +27,16 @@ namespace CoreNodeModelsWpf.Charts [NodeCategory("Display.Charts.Create")] [NodeDescription("ChartsBasicLineChartDescription", typeof(CoreNodeModelWpfResources))] [NodeSearchTags("ChartsBasicLineChartSearchTags", typeof(CoreNodeModelWpfResources))] - + [InPortNames("labels", "values", "colors")] [InPortTypes("List", "List>", "List")] - [OutPortTypes("Dictionary")] + [InPortDescriptions(typeof(CoreNodeModelWpfResources), + "ChartsBasicLineChartLabelsDataPortToolTip", + "ChartsBasicLineChartValuesDataPortToolTip", + "ChartsBasicLineChartColorsDataPortToolTip")] + [OutPortNames("labels:values")] + [OutPortTypes("Dictionary>")] + [OutPortDescriptions(typeof(CoreNodeModelWpfResources), + "ChartsBasicLineChartLabelsValuesDataPortToolTip")] [AlsoKnownAs("CoreNodeModelsWpf.Charts.Index-ValueLinePlot")] public class BasicLineChartNodeModel : NodeModel { @@ -48,6 +57,16 @@ public class BasicLineChartNodeModel : NodeModel /// A list of color values, one for each plotted line. /// public List Colors { get; set; } + + /// + /// Triggers when port is connected or disconnected + /// + public event EventHandler PortUpdated; + + protected virtual void OnPortUpdated(EventArgs args) + { + PortUpdated?.Invoke(this, args); + } #endregion #region Constructors @@ -56,14 +75,9 @@ public class BasicLineChartNodeModel : NodeModel /// public BasicLineChartNodeModel() { - InPorts.Add(new PortModel(PortType.Input, this, new PortData("labels", "A list of string labels for each line to be plotted."))); - InPorts.Add(new PortModel(PortType.Input, this, new PortData("values", "List of lists each containing double values to be plotted against X-Axis values."))); - InPorts.Add(new PortModel(PortType.Input, this, new PortData("colors", "A list of colors for each line."))); - - OutPorts.Add(new PortModel(PortType.Output, this, new PortData("labels:values", "Dictionary containing label:value key-pairs"))); - RegisterAllPorts(); + PortConnected += BasicLineChartNodeModel_PortConnected; PortDisconnected += BasicLineChartNodeModel_PortDisconnected; ArgumentLacing = LacingStrategy.Disabled; @@ -75,6 +89,7 @@ public BasicLineChartNodeModel() /// public BasicLineChartNodeModel(IEnumerable inPorts, IEnumerable outPorts) : base(inPorts, outPorts) { + PortConnected += BasicLineChartNodeModel_PortConnected; PortDisconnected += BasicLineChartNodeModel_PortDisconnected; } #endregion @@ -82,16 +97,29 @@ public BasicLineChartNodeModel(IEnumerable inPorts, IEnumerable x.State.Equals(ElementState.Info))) + { + this.ClearInfoMessages(); + } + + OnPortUpdated(null); + RaisePropertyChanged("DataUpdated"); + } #endregion #region Databridge @@ -124,10 +152,9 @@ private void DataBridgeCallback(object data) var values = inputs[1] as ArrayList; var colors = inputs[2] as ArrayList; - // Only continue if key/values match in length - if (labels.Count != values.Count || labels.Count < 1) + if (!InPorts[0].IsConnected && !InPorts[1].IsConnected && !InPorts[2].IsConnected) { - throw new Exception("Label and Values do not properly align in length."); + return; } // Clear current chart values @@ -135,9 +162,19 @@ private void DataBridgeCallback(object data) Values = new List>(); Colors = new List(); + var anyNullData = labels == null || values == null; + + // Only continue if key/values match in length + if (anyNullData || labels.Count != values.Count || labels.Count < 1 || labels.Count == 0) + { + throw new Exception("Label and Values do not properly align in length."); + } + // If color count doesn't match title count use random colors if (colors == null || colors.Count == 0 || colors.Count != labels.Count) { + if (InPorts[2].IsConnected) return; + // In case colors are not provided, we supply some from the default library of colors Info(Dynamo.Wpf.Properties.CoreNodeModelWpfResources.ProvideDefaultColorsWarningMessage); @@ -202,30 +239,50 @@ public override IEnumerable BuildOutputAst(List, List>, List, Dictionary>>(BasicLineChartFunctions.GetNodeInput), + new List { inputAstNodes[0], inputAstNodes[1], inputAstNodes[2] } + ); + + return new[] + { + AstFactory.BuildAssignment(GetAstIdentifierForOutputIndex(0), inputNode), + AstFactory.BuildAssignment( + AstFactory.BuildIdentifier(AstIdentifierBase + "_dummy"), + VMDataBridge.DataBridge.GenerateBridgeDataAst(GUID.ToString(), AstFactory.BuildExprList(inputAstNodes) + ) + ), + }; + } + else if (!InPorts[0].IsConnected || !InPorts[1].IsConnected) { return new[] { AstFactory.BuildAssignment(GetAstIdentifierForOutputIndex(0), AstFactory.BuildNullNode()), }; } - - AssociativeNode inputNode = AstFactory.BuildFunctionCall( - new Func, List>, List, Dictionary>>(BasicLineChartFunctions.GetNodeInput), - new List { inputAstNodes[0], inputAstNodes[1], inputAstNodes[2] } - ); - - return new[] + else { - AstFactory.BuildAssignment(GetAstIdentifierForOutputIndex(0), inputNode), - AstFactory.BuildAssignment( - AstFactory.BuildIdentifier(AstIdentifierBase + "_dummy"), - VMDataBridge.DataBridge.GenerateBridgeDataAst(GUID.ToString(), AstFactory.BuildExprList(inputAstNodes) - ) - ), - }; + inputNode = AstFactory.BuildFunctionCall( + new Func, List>, List, Dictionary>>(BasicLineChartFunctions.GetNodeInput), + new List { inputAstNodes[0], inputAstNodes[1], inputAstNodes[2] } + ); + + return new[] + { + AstFactory.BuildAssignment(GetAstIdentifierForOutputIndex(0), inputNode), + AstFactory.BuildAssignment( + AstFactory.BuildIdentifier(AstIdentifierBase + "_dummy"), + VMDataBridge.DataBridge.GenerateBridgeDataAst(GUID.ToString(), AstFactory.BuildExprList(inputAstNodes) + ) + ), + }; + } } #endregion @@ -236,6 +293,7 @@ public override IEnumerable BuildOutputAst(List public override void Dispose() { + PortConnected -= BasicLineChartNodeModel_PortConnected; PortDisconnected -= BasicLineChartNodeModel_PortDisconnected; VMDataBridge.DataBridge.Instance.UnregisterCallback(GUID.ToString()); } @@ -250,6 +308,9 @@ public class BasicLineChartNodeView : INodeViewCustomization /// At run-time, this method is called during the node @@ -259,6 +320,8 @@ public class BasicLineChartNodeView : INodeViewCustomizationThe NodeView representing the node in the graph. public void CustomizeView(BasicLineChartNodeModel model, NodeView nodeView) { + this.model = model; + this.view = nodeView; basicLineChartControl = new BasicLineChartControl(model); nodeView.inputGrid.Children.Add(basicLineChartControl); @@ -268,6 +331,49 @@ public void CustomizeView(BasicLineChartNodeModel model, NodeView nodeView) var contextMenu = (nodeView.Content as Grid).ContextMenu; contextMenu.Items.Add(exportImage); + + UpdateDefaultInPortValues(); + + model.PortUpdated += ModelOnPortUpdated; + } + + private void ModelOnPortUpdated(object sender, EventArgs e) + { + UpdateDefaultInPortValues(); + } + + private void UpdateDefaultInPortValues() + { + if (!this.view.ViewModel.InPorts.Any()) return; + var inPorts = this.view.ViewModel.InPorts; + + // Only apply default values if all ports are disconnected + if (!model.IsInErrorState && + model.State != ElementState.Active && + !inPorts[0].IsConnected && + !inPorts[1].IsConnected) + { + ((InPortViewModel)inPorts[0]).PortDefaultValueMarkerVisible = true; + ((InPortViewModel)inPorts[1]).PortDefaultValueMarkerVisible = true; + } + else + { + ((InPortViewModel)inPorts[0]).PortDefaultValueMarkerVisible = false; + ((InPortViewModel)inPorts[1]).PortDefaultValueMarkerVisible = false; + } + + var allPortsConnected = inPorts[0].IsConnected && inPorts[1].IsConnected && model.State != ElementState.Warning; + var noPortsConnected = !inPorts[0].IsConnected && !inPorts[1].IsConnected; + + // The color input uses default values if it's not connected + if (!inPorts[2].IsConnected && (allPortsConnected || noPortsConnected)) + { + ((InPortViewModel)inPorts[2]).PortDefaultValueMarkerVisible = true; + } + else + { + ((InPortViewModel)inPorts[2]).PortDefaultValueMarkerVisible = false; + } } private void ExportImage_Click(object sender, RoutedEventArgs e) @@ -279,6 +385,9 @@ private void ExportImage_Click(object sender, RoutedEventArgs e) /// Here you can do any cleanup you require if you've assigned callbacks for particular /// UI events on your node. /// - public void Dispose() { } + public void Dispose() + { + model.PortUpdated -= ModelOnPortUpdated; + } } } diff --git a/src/Libraries/CoreNodeModelsWpf/Charts/Controls/BarChartControl.xaml.cs b/src/Libraries/CoreNodeModelsWpf/Charts/Controls/BarChartControl.xaml.cs index 0f794c11837..1f6a34936b0 100644 --- a/src/Libraries/CoreNodeModelsWpf/Charts/Controls/BarChartControl.xaml.cs +++ b/src/Libraries/CoreNodeModelsWpf/Charts/Controls/BarChartControl.xaml.cs @@ -2,7 +2,9 @@ using LiveCharts.Wpf; using SharpDX.Direct2D1; using System; +using System.Collections.Generic; using System.ComponentModel; +using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Controls.Primitives; @@ -21,6 +23,9 @@ public partial class BarChartControl : UserControl, INotifyPropertyChanged private static double PADDING = 4.0; private static double MAX_COLUMN_WIDTH = 20.0; + private double MIN_WIDTH = 300; + private double MIN_HEIGHT = 300; + private void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); @@ -41,52 +46,15 @@ public BarChartControl(BarChartNodeModel model) private void BuildUI(BarChartNodeModel model) { - if (!model.InPorts[0].IsConnected && !model.InPorts[1].IsConnected && !model.InPorts[2].IsConnected) { - BarChart.Series = new SeriesCollection - { - new ColumnSeries - { - Title = "2019", - Values = new ChartValues { 5, 6, 7, 8 }, - ColumnPadding = PADDING, - MaxColumnWidth = MAX_COLUMN_WIDTH, - }, - new ColumnSeries - { - Title = "2020", - Values = new ChartValues { 10, 12, 14, 16 }, - ColumnPadding = PADDING, - MaxColumnWidth = MAX_COLUMN_WIDTH, - }, - new ColumnSeries - { - Title = "2021", - Values = new ChartValues { 15, 18, 21, 24 }, - ColumnPadding = PADDING, - MaxColumnWidth = MAX_COLUMN_WIDTH, - } - }; + DefaultSeries(); } else if (model.InPorts[0].IsConnected && model.InPorts[1].IsConnected && model.InPorts[2].IsConnected) { if (model.Labels.Count == model.Values.Count && model.Labels.Count > 0) { - var seriesRange = new ColumnSeries[model.Labels.Count]; - - for (var i = 0; i < model.Labels.Count; i++) - { - seriesRange[i] = new ColumnSeries - { - Title = model.Labels[i], - Values = new ChartValues(model.Values[i]), - Fill = model.Colors[i], - Stroke = model.Colors[i], - ColumnPadding = PADDING, - MaxColumnWidth = MAX_COLUMN_WIDTH, - }; - } + var seriesRange = UpdateSeries(model); BarChart.Series.AddRange(seriesRange); } @@ -102,27 +70,81 @@ private void NodeModel_PropertyChanged(object sender, PropertyChangedEventArgs e // Invoke on UI thread this.Dispatcher.Invoke(() => { - var seriesRange = new ColumnSeries[model.Labels.Count]; + BarChart.Series.Clear(); - for (var i = 0; i < model.Labels.Count; i++) + // Load sample data if any ports are not connected + if (!model.InPorts[0].IsConnected && !model.InPorts[1].IsConnected && !model.InPorts[2].IsConnected) { - seriesRange[i] = new ColumnSeries - { - Title = model.Labels[i], - Values = new ChartValues(model.Values[i]), - Fill = model.Colors[i], - Stroke = model.Colors[i], - ColumnPadding = PADDING, - MaxColumnWidth = MAX_COLUMN_WIDTH, - }; + DefaultSeries(); } + else + { + var seriesRange = UpdateSeries(model); - BarChart.Series.Clear(); - BarChart.Series.AddRange(seriesRange); + BarChart.Series.AddRange(seriesRange.ToArray()); + } }); } } + private void DefaultSeries() + { + BarChart.Series = new SeriesCollection + { + new ColumnSeries + { + Title = "2019", + Values = new ChartValues { 5, 6, 7, 8 }, + ColumnPadding = PADDING, + MaxColumnWidth = MAX_COLUMN_WIDTH, + }, + new ColumnSeries + { + Title = "2020", + Values = new ChartValues { 10, 12, 14, 16 }, + ColumnPadding = PADDING, + MaxColumnWidth = MAX_COLUMN_WIDTH, + }, + new ColumnSeries + { + Title = "2021", + Values = new ChartValues { 15, 18, 21, 24 }, + ColumnPadding = PADDING, + MaxColumnWidth = MAX_COLUMN_WIDTH, + } + }; + } + + private List UpdateSeries(BarChartNodeModel model) + { + var seriesRange = new List(); + + if (model == null) + { + model = this.model; + } + + if (model.Labels != null && model.Labels.Any() + && model.Values != null && model.Values.Any() + && model.Colors != null && model.Colors.Any()) + { + for (var i = 0; i < model.Labels.Count; i++) + { + seriesRange.Add(new ColumnSeries + { + Title = model.Labels[i], + Values = new ChartValues(model.Values[i]), + Fill = model.Colors[i], + Stroke = model.Colors[i], + ColumnPadding = PADDING, + MaxColumnWidth = MAX_COLUMN_WIDTH, + }); + } + } + + return seriesRange; + } + private void ThumbResizeThumbOnDragDeltaHandler(object sender, DragDeltaEventArgs e) { var yAdjust = ActualHeight + e.VerticalChange; @@ -132,12 +154,12 @@ private void ThumbResizeThumbOnDragDeltaHandler(object sender, DragDeltaEventArg { var inputGrid = this.Parent as Grid; - if (xAdjust >= inputGrid.MinWidth) + if (xAdjust >= inputGrid.MinWidth && xAdjust >= MIN_WIDTH) { Width = xAdjust; } - if (yAdjust >= inputGrid.MinHeight) + if (yAdjust >= inputGrid.MinHeight && xAdjust >= MIN_HEIGHT) { Height = yAdjust; } diff --git a/src/Libraries/CoreNodeModelsWpf/Charts/Controls/BasicLineChartControl.xaml.cs b/src/Libraries/CoreNodeModelsWpf/Charts/Controls/BasicLineChartControl.xaml.cs index ccea492333b..f04ed5c943b 100644 --- a/src/Libraries/CoreNodeModelsWpf/Charts/Controls/BasicLineChartControl.xaml.cs +++ b/src/Libraries/CoreNodeModelsWpf/Charts/Controls/BasicLineChartControl.xaml.cs @@ -6,6 +6,8 @@ using LiveCharts.Wpf; using System.ComponentModel; using System.Windows; +using System.Collections.Generic; +using System.Linq; namespace CoreNodeModelsWpf.Charts { @@ -17,6 +19,9 @@ public partial class BasicLineChartControl : UserControl, INotifyPropertyChanged private Random rnd = new Random(); private readonly BasicLineChartNodeModel model; + private double MIN_WIDTH = 300; + private double MIN_HEIGHT = 300; + private void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); @@ -42,12 +47,7 @@ private void BuildUI(BasicLineChartNodeModel model) // Load sample data if any ports are not connected if (!model.InPorts[0].IsConnected && !model.InPorts[1].IsConnected && !model.InPorts[2].IsConnected) { - var seriesRange = new LineSeries[] - { - new LineSeries { Title = "Series 1", Values = new ChartValues { 4, 6, 5, 2, 4 } }, - new LineSeries { Title = "Series 2", Values = new ChartValues { 6, 7, 3, 4, 6 } }, - new LineSeries { Title = "Series 3", Values = new ChartValues { 4, 2, 7, 2, 7 } } - }; + var seriesRange = DefaultSeries(); BasicLineChart.Series.AddRange(seriesRange); } @@ -55,19 +55,7 @@ private void BuildUI(BasicLineChartNodeModel model) { if (model.Labels.Count == model.Values.Count && model.Labels.Count > 0) { - LineSeries[] seriesRange = new LineSeries[model.Labels.Count]; - - for (var i = 0; i < model.Labels.Count; i++) - { - seriesRange[i] = new LineSeries - { - Title = model.Labels[i], - Values = new ChartValues(model.Values[i]), - Stroke = model.Colors[i], - StrokeThickness = 2.0, - //Fill = Brushes.Transparent - }; - } + var seriesRange = UpdateSeries(model); BasicLineChart.Series.AddRange(seriesRange); } @@ -76,34 +64,73 @@ private void BuildUI(BasicLineChartNodeModel model) private void NodeModel_PropertyChanged(object sender, PropertyChangedEventArgs e) { - if(e.PropertyName == "DataUpdated") + if (e.PropertyName == "DataUpdated") { var model = sender as BasicLineChartNodeModel; // Invoke on UI thread this.Dispatcher.Invoke(() => { - LineSeries[] seriesRange = new LineSeries[model.Labels.Count]; + BasicLineChart.Series.Clear(); - for (var i = 0; i < model.Labels.Count; i++) + if (!model.InPorts[0].IsConnected && !model.InPorts[1].IsConnected && !model.InPorts[2].IsConnected) { - seriesRange[i] = new LineSeries - { - Title = model.Labels[i], - Values = new ChartValues(model.Values[i]), - Stroke = model.Colors[i], - StrokeThickness = 2.0, - //Fill = Brushes.Transparent, - //PointGeometrySize = 0 - }; + var seriesRange = DefaultSeries(); + + BasicLineChart.Series.AddRange(seriesRange); } + else + { + var seriesRange = UpdateSeries(model); - BasicLineChart.Series.Clear(); - BasicLineChart.Series.AddRange(seriesRange); + BasicLineChart.Series.AddRange(seriesRange); + } }); } } + + private LineSeries[] DefaultSeries() + { + var series = new LineSeries[] + { + new LineSeries { Title = "Series 1", Values = new ChartValues { 4, 6, 5, 2, 4 } }, + new LineSeries { Title = "Series 2", Values = new ChartValues { 6, 7, 3, 4, 6 } }, + new LineSeries { Title = "Series 3", Values = new ChartValues { 4, 2, 7, 2, 7 } } + }; + + return series; + } + + private List UpdateSeries(BasicLineChartNodeModel model) + { + var seriesRange = new List(); + + if (model == null) + { + model = this.model; + } + + if (model.Labels != null && model.Labels.Any() + && model.Values != null && model.Values.Any() + && model.Colors != null && model.Colors.Any()) + { + for (var i = 0; i < model.Labels.Count; i++) + { + seriesRange.Add(new LineSeries + { + Title = model.Labels[i], + Values = new ChartValues(model.Values[i]), + Stroke = model.Colors[i], + StrokeThickness = 2.0, + }); + } + + } + + return seriesRange; + } + private void ThumbResizeThumbOnDragDeltaHandler(object sender, DragDeltaEventArgs e) { var yAdjust = ActualHeight + e.VerticalChange; @@ -113,12 +140,12 @@ private void ThumbResizeThumbOnDragDeltaHandler(object sender, DragDeltaEventArg { var inputGrid = this.Parent as Grid; - if (xAdjust >= inputGrid.MinWidth) + if (xAdjust >= inputGrid.MinWidth && xAdjust >= MIN_WIDTH) { Width = xAdjust; } - if (yAdjust >= inputGrid.MinHeight) + if (yAdjust >= inputGrid.MinHeight && xAdjust >= MIN_HEIGHT) { Height = yAdjust; } diff --git a/src/Libraries/CoreNodeModelsWpf/Charts/Controls/HeatSeriesControl.xaml.cs b/src/Libraries/CoreNodeModelsWpf/Charts/Controls/HeatSeriesControl.xaml.cs index c4a269832fb..ab6562a8f35 100644 --- a/src/Libraries/CoreNodeModelsWpf/Charts/Controls/HeatSeriesControl.xaml.cs +++ b/src/Libraries/CoreNodeModelsWpf/Charts/Controls/HeatSeriesControl.xaml.cs @@ -7,6 +7,7 @@ using LiveCharts.Wpf; using System.ComponentModel; using System.Windows; +using System.Linq; namespace CoreNodeModelsWpf.Charts.Controls { @@ -18,6 +19,9 @@ public partial class HeatSeriesControl : UserControl, INotifyPropertyChanged private Random rnd = new Random(); private readonly HeatSeriesNodeModel model; + private double MIN_WIDTH = 300; + private double MIN_HEIGHT = 300; + private void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); @@ -43,9 +47,55 @@ private void BuildUI(HeatSeriesNodeModel model) // Load sample data if any ports are not connected if (!model.InPorts[0].IsConnected && !model.InPorts[1].IsConnected && !model.InPorts[2].IsConnected && !model.InPorts[3].IsConnected) { - // X - Products - var XLabels = new[] + var chartValues = DefaultValues(); + + HeatSeriesUI.Series.Add(new HeatSeries() + { + Values = chartValues, + DrawsHeatRange = false, + }); + } + // Else load input data + else if (model.InPorts[0].IsConnected && model.InPorts[1].IsConnected && model.InPorts[2].IsConnected && model.InPorts[3].IsConnected) + { + if (model.XLabels.Count == model.Values.Count && model.XLabels.Count > 0) { + UpdateValues(model); + } + } + } + private void NodeModel_PropertyChanged(object sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == "DataUpdated") + { + var model = sender as HeatSeriesNodeModel; + + // Invoke on UI thread + this.Dispatcher.Invoke(() => + { + if (!model.InPorts[0].IsConnected && !model.InPorts[1].IsConnected && !model.InPorts[2].IsConnected && !model.InPorts[3].IsConnected) + { + var chartValues = DefaultValues(); + + HeatSeriesUI.Series.Add(new HeatSeries() + { + Values = chartValues, + DrawsHeatRange = false, + }); + } + else + { + UpdateValues(model); + } + }); + } + } + + private ChartValues DefaultValues() + { + // X - Products + var XLabels = new[] + { "Item-1", "Item-2", "Item-3", @@ -53,9 +103,9 @@ private void BuildUI(HeatSeriesNodeModel model) "Item-5" }; - // Y - Day of the week - var YLabels = new[] - { + // Y - Day of the week + var YLabels = new[] + { "Monday", "Tuesday", "Wednesday", @@ -65,94 +115,61 @@ private void BuildUI(HeatSeriesNodeModel model) "Sunday" }; - // Value for each product on every day of the week - var chartValues = new ChartValues(); + // Value for each product on every day of the week + var chartValues = new ChartValues(); - for(var i = 0; i < XLabels.Length; i++) + for (var i = 0; i < XLabels.Length; i++) + { + for (var j = 0; j < YLabels.Length; j++) { - for ( var j = 0; j < YLabels.Length; j++) - { - chartValues.Add(new HeatPoint(i, j, rnd.Next(0, 10))); - } + chartValues.Add(new HeatPoint(i, j, rnd.Next(0, 10))); } - - XAxis.Labels = XLabels; - YAxis.Labels = YLabels; - HeatSeriesUI.Series.Add(new HeatSeries() - { - Values = chartValues, - DrawsHeatRange = false, - }); } - // Else load input data - else if (model.InPorts[0].IsConnected && model.InPorts[1].IsConnected && model.InPorts[2].IsConnected && model.InPorts[3].IsConnected) - { - if (model.XLabels.Count == model.Values.Count && model.XLabels.Count > 0) - { - var chartValues = new ChartValues(); - - for (var i = 0; i < model.XLabels.Count; i++) - { - for (var j = 0; j < model.YLabels.Count; j++) - { - chartValues.Add(new HeatPoint(i, j, model.Values[i][j])); - } - } - var colors = BuildColors(model); - var hoverIconColor = new SolidColorBrush(Color.FromArgb(255, 94, 92, 90)); + XAxis.Labels = XLabels; + YAxis.Labels = YLabels; - XAxis.Labels = model.XLabels; - YAxis.Labels = model.YLabels; - HeatSeriesUI.Series.Add(new HeatSeries() - { - Values = chartValues, - DrawsHeatRange = false, - GradientStopCollection = colors, - //Fill = hoverIconColor, - PointGeometry = DefaultGeometries.Square - //DataLabels = true - }); - } - } + return chartValues; } - private void NodeModel_PropertyChanged(object sender, PropertyChangedEventArgs e) + private void UpdateValues(HeatSeriesNodeModel model) { - if (e.PropertyName == "DataUpdated") + var chartValues = new ChartValues(); + HeatSeriesUI.Series.Clear(); + + if (model == null) { - var model = sender as HeatSeriesNodeModel; + model = this.model; + } - // Invoke on UI thread - this.Dispatcher.Invoke(() => - { - var chartValues = new ChartValues(); + var colors = new GradientStopCollection(); - for (var i = 0; i < model.XLabels.Count; i++) + if (model.XLabels != null && model.XLabels.Any() + && model.YLabels != null && model.YLabels.Any() + && model.Values != null && model.Values.Any() + && model.Colors != null && model.Colors.Any()) + { + for (var i = 0; i < model.XLabels.Count; i++) + { + for (var j = 0; j < model.YLabels.Count; j++) { - for (var j = 0; j < model.YLabels.Count; j++) - { - chartValues.Add(new HeatPoint(i, j, model.Values[i][j])); - } + chartValues.Add(new HeatPoint(i, j, model.Values[i][j])); } + } - var colors = BuildColors(model); - var hoverIconColor = new SolidColorBrush(Color.FromArgb(255, 94, 92, 90)); + colors = BuildColors(model); - HeatSeriesUI.Series.Clear(); - XAxis.Labels = model.XLabels; - YAxis.Labels = model.YLabels; - HeatSeriesUI.Series.Add(new HeatSeries() - { - Values = chartValues, - DrawsHeatRange = false, - GradientStopCollection = colors, - //Fill = hoverIconColor, - PointGeometry = DefaultGeometries.Square - //DataLabels = true - }); - }); + XAxis.Labels = model.XLabels; + YAxis.Labels = model.YLabels; } + + HeatSeriesUI.Series.Add(new HeatSeries() + { + Values = chartValues, + DrawsHeatRange = false, + GradientStopCollection = colors, + PointGeometry = DefaultGeometries.Square + }); } private GradientStopCollection BuildColors(HeatSeriesNodeModel model) @@ -202,12 +219,12 @@ private void ThumbResizeThumbOnDragDeltaHandler(object sender, DragDeltaEventArg { var inputGrid = this.Parent as Grid; - if (xAdjust >= inputGrid.MinWidth) + if (xAdjust >= inputGrid.MinWidth && xAdjust >= MIN_WIDTH) { Width = xAdjust; } - if (yAdjust >= inputGrid.MinHeight) + if (yAdjust >= inputGrid.MinHeight && yAdjust >= MIN_HEIGHT) { Height = yAdjust; } diff --git a/src/Libraries/CoreNodeModelsWpf/Charts/Controls/PieChartControl.xaml.cs b/src/Libraries/CoreNodeModelsWpf/Charts/Controls/PieChartControl.xaml.cs index 498490c6bba..3adcc8470e4 100644 --- a/src/Libraries/CoreNodeModelsWpf/Charts/Controls/PieChartControl.xaml.cs +++ b/src/Libraries/CoreNodeModelsWpf/Charts/Controls/PieChartControl.xaml.cs @@ -5,6 +5,9 @@ using LiveCharts.Wpf; using System.ComponentModel; using System.Windows; +using System.Web.ModelBinding; +using System.Collections.Generic; +using System.Linq; namespace CoreNodeModelsWpf.Charts.Controls { @@ -17,6 +20,9 @@ public partial class PieChartControl : UserControl, INotifyPropertyChanged private Random rnd = new Random(); private readonly PieChartNodeModel model; + private double MIN_WIDTH = 300; + private double MIN_HEIGHT = 300; + public event PropertyChangedEventHandler PropertyChanged; private void OnPropertyChanged(string propertyName) @@ -41,12 +47,7 @@ private void BuildUI(PieChartNodeModel model) { if (!model.InPorts[0].IsConnected && !model.InPorts[1].IsConnected && !model.InPorts[2].IsConnected) { - var seriesRange = new PieSeries[] - { - new PieSeries { Title = "Item1", Values = new ChartValues { 100.0 }, DataLabels = true/*, LabelPoint = PointLabel*/ }, - new PieSeries { Title = "Item2", Values = new ChartValues { 100.0 }, DataLabels = true/*, LabelPoint = PointLabel*/ }, - new PieSeries { Title = "Item3", Values = new ChartValues { 100.0 }, DataLabels = true/*, LabelPoint = PointLabel*/ } - }; + var seriesRange = DefaultSeries(); PieChart.Series.AddRange(seriesRange); } @@ -55,19 +56,7 @@ private void BuildUI(PieChartNodeModel model) { if (model.Labels.Count == model.Values.Count && model.Labels.Count > 0) { - var seriesRange = new PieSeries[model.Labels.Count]; - - for (var i = 0; i < model.Labels.Count; i++) - { - seriesRange[i] = new PieSeries - { - Title = model.Labels[i], - Values = new ChartValues { model.Values[i] }, - Fill = model.Colors[i], - DataLabels = true, - //LabelPoint = PointLabel - }; - } + var seriesRange = UpdateSeries(model); PieChart.Series.AddRange(seriesRange); } @@ -83,27 +72,65 @@ private void NodeModel_PropertyChanged(object sender, PropertyChangedEventArgs e // Invoke on UI thread this.Dispatcher.Invoke(() => { - var seriesRange = new PieSeries[nodeModel.Labels.Count]; + PieChart.Series.Clear(); - for (var i = 0; i < nodeModel.Labels.Count; i++) + if (!model.InPorts[0].IsConnected && !model.InPorts[1].IsConnected && !model.InPorts[2].IsConnected) { - seriesRange[i] = new PieSeries - { - Title = nodeModel.Labels[i], - Fill = nodeModel.Colors[i], - //StrokeThickness = 0, - Values = new ChartValues { nodeModel.Values[i] }, - DataLabels = true, - //LabelPoint = PointLabel - }; + var seriesRange = DefaultSeries(); + + PieChart.Series.AddRange(seriesRange); } + else + { + var seriesRange = UpdateSeries(model); - PieChart.Series.Clear(); - PieChart.Series.AddRange(seriesRange); + PieChart.Series.AddRange(seriesRange); + } }); } } + private PieSeries[] DefaultSeries() + { + var series = new PieSeries[] + { + new PieSeries { Title = "Item1", Values = new ChartValues { 100.0 }, DataLabels = true/*, LabelPoint = PointLabel*/ }, + new PieSeries { Title = "Item2", Values = new ChartValues { 100.0 }, DataLabels = true/*, LabelPoint = PointLabel*/ }, + new PieSeries { Title = "Item3", Values = new ChartValues { 100.0 }, DataLabels = true/*, LabelPoint = PointLabel*/ }, + }; + + return series; + } + + private List UpdateSeries(PieChartNodeModel model) + { + var seriesRange = new List(); + + if (model == null) + { + model = this.model; + } + + if (model.Labels != null && model.Labels.Any() + && model.Values != null && model.Values.Any() + && model.Colors != null && model.Colors.Any()) + { + for (var i = 0; i < model.Labels.Count; i++) + { + seriesRange.Add(new PieSeries + { + Title = model.Labels[i], + Values = new ChartValues { model.Values[i] }, + Fill = model.Colors[i], + DataLabels = true, + //LabelPoint = PointLabel + }); + } + } + + return seriesRange; + } + private void ThumbResizeThumbOnDragDeltaHandler(object sender, DragDeltaEventArgs e) { @@ -114,13 +141,13 @@ private void ThumbResizeThumbOnDragDeltaHandler(object sender, DragDeltaEventArg { var inputGrid = this.Parent as Grid; - if (xAdjust >= inputGrid.MinWidth) + if (xAdjust >= inputGrid.MinWidth && xAdjust >= MIN_WIDTH) { Width = xAdjust; Height = xAdjust; } - if (yAdjust >= inputGrid.MinHeight) + if (yAdjust >= inputGrid.MinHeight && xAdjust >= MIN_HEIGHT) { Width = yAdjust; Height = yAdjust; diff --git a/src/Libraries/CoreNodeModelsWpf/Charts/Controls/ScatterPlotControl.xaml.cs b/src/Libraries/CoreNodeModelsWpf/Charts/Controls/ScatterPlotControl.xaml.cs index a95a68b620a..ce4484e184f 100644 --- a/src/Libraries/CoreNodeModelsWpf/Charts/Controls/ScatterPlotControl.xaml.cs +++ b/src/Libraries/CoreNodeModelsWpf/Charts/Controls/ScatterPlotControl.xaml.cs @@ -8,6 +8,7 @@ using LiveCharts.Wpf; using System.ComponentModel; using System.Windows; +using System.Linq; namespace CoreNodeModelsWpf.Charts.Controls { @@ -19,6 +20,9 @@ public partial class ScatterPlotControl : UserControl, INotifyPropertyChanged private Random rnd = new Random(); private readonly ScatterPlotNodeModel model; + private double MIN_WIDTH = 300; + private double MIN_HEIGHT = 300; + private void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); @@ -44,56 +48,15 @@ private void BuildUI(ScatterPlotNodeModel model) // Load sample data if any ports are not connected if (!model.InPorts[0].IsConnected && !model.InPorts[1].IsConnected && !model.InPorts[2].IsConnected && !model.InPorts[3].IsConnected) { - var ValuesA = new ChartValues(); - var ValuesB = new ChartValues(); - var ValuesC = new ChartValues(); - - for (var i = 0; i < 20; i++) - { - ValuesA.Add(new ObservablePoint(rnd.NextDouble() * 10, rnd.NextDouble() * 10)); - ValuesB.Add(new ObservablePoint(rnd.NextDouble() * 10, rnd.NextDouble() * 10)); - ValuesC.Add(new ObservablePoint(rnd.NextDouble() * 10, rnd.NextDouble() * 10)); - } - - var plot1 = new ScatterSeries { Title = "Plot 1", Values = ValuesA }; - var plot2 = new ScatterSeries { Title = "Plot 2", Values = ValuesB }; - var plot3 = new ScatterSeries { Title = "Plot 3", Values = ValuesC }; - - var plots = new ScatterSeries[] { plot1, plot2, plot3 }; - + var plots = DefaultSeries(); ScatterPlot.Series.AddRange(plots); } // Else load input data - else if (model.InPorts[0].IsConnected && model.InPorts[1].IsConnected && model.InPorts[2].IsConnected && model.InPorts[3].IsConnected) + else if (model.InPorts[0].IsConnected && model.InPorts[1].IsConnected && model.InPorts[2].IsConnected) { if (model.Labels.Count == model.XValues.Count && model.XValues.Count == model.YValues.Count && model.Labels.Count > 0) { - var plots = new List(); - - // For each set of points - for (var i = 0; i < model.Labels.Count; i++) - { - - ChartValues points = new ChartValues(); - - // For each x-value list - for (int j = 0; j < model.XValues[i].Count; j++) - { - points.Add(new ObservablePoint - { - X = model.XValues[i][j], - Y = model.YValues[i][j] - }); - } - - plots.Add(new ScatterSeries - { - Title = model.Labels[i], - Values = points, - Fill = model.Colors[i] - }); - } - + var plots = UpdateSeries(); ScatterPlot.Series.AddRange(plots); } } @@ -110,35 +73,82 @@ private void NodeModel_PropertyChanged(object sender, PropertyChangedEventArgs e { ScatterPlot.Series.Clear(); - var plots = new List(); - - // For each set of points - for (var i = 0; i < model.Labels.Count; i++) + // Load sample data if any ports are not connected + if (!model.InPorts[0].IsConnected && !model.InPorts[1].IsConnected && !model.InPorts[2].IsConnected && !model.InPorts[3].IsConnected) { + var plots = DefaultSeries(); + ScatterPlot.Series.AddRange(plots); + } + else + { + var plots = UpdateSeries(model); + ScatterPlot.Series.AddRange(plots); + } + }); + } + } - ChartValues points = new ChartValues(); + private ScatterSeries [] DefaultSeries() + { + var ValuesA = new ChartValues(); + var ValuesB = new ChartValues(); + var ValuesC = new ChartValues(); - // For each x-value list - for (int j = 0; j < model.XValues[i].Count; j++) - { - points.Add(new ObservablePoint - { - X = model.XValues[i][j], - Y = model.YValues[i][j] - }); - } - - plots.Add(new ScatterSeries + for (var i = 0; i < 20; i++) + { + ValuesA.Add(new ObservablePoint(rnd.NextDouble() * 10, rnd.NextDouble() * 10)); + ValuesB.Add(new ObservablePoint(rnd.NextDouble() * 10, rnd.NextDouble() * 10)); + ValuesC.Add(new ObservablePoint(rnd.NextDouble() * 10, rnd.NextDouble() * 10)); + } + + var plot1 = new ScatterSeries { Title = "Plot 1", Values = ValuesA }; + var plot2 = new ScatterSeries { Title = "Plot 2", Values = ValuesB }; + var plot3 = new ScatterSeries { Title = "Plot 3", Values = ValuesC }; + + var plots = new ScatterSeries[] { plot1, plot2, plot3 }; + + return plots; + } + + private List UpdateSeries(ScatterPlotNodeModel model = null) + { + var plots = new List(); + + if(model == null) + { + model = this.model; + } + + if (model.Labels != null && model.Labels.Any() + && model.XValues != null && model.XValues.Any() + && model.YValues != null && model.YValues.Any() + && model.Colors != null && model.Colors.Any()) + { + // For each set of points + for (var i = 0; i < model.Labels.Count; i++) + { + ChartValues points = new ChartValues(); + + // For each x-value list + for (int j = 0; j < model.XValues[i].Count; j++) + { + points.Add(new ObservablePoint { - Title = model.Labels[i], - Values = points, - Fill = model.Colors[i] + X = model.XValues[i][j], + Y = model.YValues[i][j] }); } - ScatterPlot.Series.AddRange(plots); - }); + plots.Add(new ScatterSeries + { + Title = model.Labels[i], + Values = points, + Fill = model.Colors[i] + }); + } } + + return plots; } private void ThumbResizeThumbOnDragDeltaHandler(object sender, DragDeltaEventArgs e) @@ -150,12 +160,12 @@ private void ThumbResizeThumbOnDragDeltaHandler(object sender, DragDeltaEventArg { var inputGrid = this.Parent as Grid; - if (xAdjust >= 100/*inputGrid.MinWidth*/) + if (xAdjust >= MIN_WIDTH/*inputGrid.MinWidth*/ ) { Width = xAdjust; } - if (yAdjust >= 100/*inputGrid.MinHeight*/) + if (yAdjust >= MIN_HEIGHT/*inputGrid.MinHeight*/) { Height = yAdjust; } diff --git a/src/Libraries/CoreNodeModelsWpf/Charts/Controls/XYLineChartControl.xaml.cs b/src/Libraries/CoreNodeModelsWpf/Charts/Controls/XYLineChartControl.xaml.cs index 3c6aa3e4c0e..ac5220eb17d 100644 --- a/src/Libraries/CoreNodeModelsWpf/Charts/Controls/XYLineChartControl.xaml.cs +++ b/src/Libraries/CoreNodeModelsWpf/Charts/Controls/XYLineChartControl.xaml.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Windows.Controls; using System.Windows.Controls.Primitives; using System.Windows.Media; @@ -7,6 +8,7 @@ using LiveCharts.Wpf; using System.ComponentModel; using System.Windows; +using System.Linq; namespace CoreNodeModelsWpf.Charts.Controls { @@ -18,6 +20,9 @@ public partial class XYLineChartControl : UserControl, INotifyPropertyChanged private Random rnd = new Random(); private readonly XYLineChartNodeModel model; + private double MIN_WIDTH = 300; + private double MIN_HEIGHT = 300; + private void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); @@ -43,73 +48,16 @@ private void BuildUI(XYLineChartNodeModel model) // Load sample data if any ports are not connected if (!model.InPorts[0].IsConnected && !model.InPorts[1].IsConnected && !model.InPorts[2].IsConnected && !model.InPorts[3].IsConnected) { - var defaultXValues = new double[][] - { - new double[]{ 0, 1, 2, 3 }, - new double[]{ 0, 1, 2, 3 }, - new double[]{ 0, 1, 2, 3 } - }; - - var defaultYValues = new double[][] - { - new double[]{ 0, 1, 2, 3 }, - new double[]{ 1, 2, 3, 4 }, - new double[]{ 2, 3, 4, 5 } - }; - - LineSeries[] seriesRange = new LineSeries[defaultXValues.Length]; - - for (var i = 0; i < defaultXValues.Length; i++) - { - ChartValues points = new ChartValues(); - - for (int j = 0; j < defaultXValues[i].Length; j++) - { - points.Add(new ObservablePoint - { - X = defaultXValues[i][j], - Y = defaultYValues[i][j] - }); - } - - seriesRange[i] = new LineSeries - { - Values = points, - Fill = Brushes.Transparent - }; - } + var seriesRange = DefaultSeries(); XYLineChart.Series.AddRange(seriesRange); } // Else load input data - else if (model.InPorts[0].IsConnected && model.InPorts[1].IsConnected && model.InPorts[2].IsConnected && model.InPorts[3].IsConnected) + else if (model.InPorts[0].IsConnected && model.InPorts[1].IsConnected && model.InPorts[2].IsConnected) { if (model.Labels.Count == model.XValues.Count && model.XValues.Count == model.YValues.Count && model.Labels.Count > 0) { - LineSeries[] seriesRange = new LineSeries[model.Labels.Count]; - - for (var i = 0; i < model.Labels.Count; i++) - { - ChartValues points = new ChartValues(); - - for (int j = 0; j < model.XValues[i].Count; j++) - { - points.Add(new ObservablePoint - { - X = model.XValues[i][j], - Y = model.YValues[i][j] - }); - } - - seriesRange[i] = new LineSeries - { - Title = model.Labels[i], - Values = points, - Stroke = model.Colors[i], - StrokeThickness = 2.0, - Fill = Brushes.Transparent, - }; - } + var seriesRange = UpdateSeries(); XYLineChart.Series.AddRange(seriesRange); } @@ -125,36 +73,102 @@ private void NodeModel_PropertyChanged(object sender, PropertyChangedEventArgs e // Invoke on UI thread this.Dispatcher.Invoke(() => { - LineSeries[] seriesRange = new LineSeries[model.Labels.Count]; + XYLineChart.Series.Clear(); - for (var i = 0; i < model.Labels.Count; i++) + if (!model.InPorts[0].IsConnected && !model.InPorts[1].IsConnected && !model.InPorts[2].IsConnected && !model.InPorts[3].IsConnected) { - ChartValues points = new ChartValues(); + var seriesRange = DefaultSeries(); + XYLineChart.Series.AddRange(seriesRange); + } + else + { + var seriesRange = UpdateSeries(model); + XYLineChart.Series.AddRange(seriesRange); - for (int j = 0; j < model.XValues[i].Count; j++) - { - points.Add(new ObservablePoint - { - X = model.XValues[i][j], - Y = model.YValues[i][j] - }); - } - - seriesRange[i] = new LineSeries + } + }); + } + } + + private LineSeries[] DefaultSeries() + { + var defaultXValues = new double[][] + { + new double[]{ 0, 1, 2, 3 }, + new double[]{ 0, 1, 2, 3 }, + new double[]{ 0, 1, 2, 3 } + }; + + var defaultYValues = new double[][] + { + new double[]{ 0, 1, 2, 3 }, + new double[]{ 1, 2, 3, 4 }, + new double[]{ 2, 3, 4, 5 } + }; + List labels = new List { "Plot 1", "Plot 2", "Plot 3" }; + LineSeries[] seriesRange = new LineSeries[defaultXValues.Length]; + + for (var i = 0; i < defaultXValues.Length; i++) + { + ChartValues points = new ChartValues(); + + for (int j = 0; j < defaultXValues[i].Length; j++) + { + points.Add(new ObservablePoint + { + X = defaultXValues[i][j], + Y = defaultYValues[i][j] + }); + } + + seriesRange[i] = new LineSeries + { + Title = labels[i], + Values = points, + Fill = Brushes.Transparent + }; + } + + return seriesRange; + } + + private List UpdateSeries(XYLineChartNodeModel model = null) + { + var seriesRange = new List(); + if(model == null) + { + model = this.model; + } + if(model.Labels != null && model.Labels.Any() + && model.XValues != null && model.XValues.Any() + && model.YValues != null && model.YValues.Any() + && model.Colors != null && model.Colors.Any()) + { + for (var i = 0; i < model.Labels.Count; i++) + { + ChartValues points = new ChartValues(); + + for (int j = 0; j < model.XValues[i].Count; j++) + { + points.Add(new ObservablePoint { - Title = model.Labels[i], - Values = points, - Stroke = model.Colors[i], - StrokeThickness = 2.0, - Fill = Brushes.Transparent - //PointGeometrySize = 0 - }; + X = model.XValues[i][j], + Y = model.YValues[i][j] + }); } - XYLineChart.Series.Clear(); - XYLineChart.Series.AddRange(seriesRange); - }); + seriesRange.Add(new LineSeries + { + Title = model.Labels[i], + Values = points, + Stroke = model.Colors[i], + StrokeThickness = 2.0, + Fill = Brushes.Transparent + }); + } } + + return seriesRange; } private void ThumbResizeThumbOnDragDeltaHandler(object sender, DragDeltaEventArgs e) @@ -166,12 +180,12 @@ private void ThumbResizeThumbOnDragDeltaHandler(object sender, DragDeltaEventArg { var inputGrid = this.Parent as Grid; - if (xAdjust >= inputGrid.MinWidth) + if (xAdjust >= inputGrid.MinWidth && xAdjust >= MIN_WIDTH) { Width = xAdjust; } - if (yAdjust >= inputGrid.MinHeight) + if (yAdjust >= inputGrid.MinHeight && xAdjust >= MIN_HEIGHT) { Height = yAdjust; } diff --git a/src/Libraries/CoreNodeModelsWpf/Charts/HeatSeriesNodeModel.cs b/src/Libraries/CoreNodeModelsWpf/Charts/HeatSeriesNodeModel.cs index ece3b24c7c7..0b31dba4417 100644 --- a/src/Libraries/CoreNodeModelsWpf/Charts/HeatSeriesNodeModel.cs +++ b/src/Libraries/CoreNodeModelsWpf/Charts/HeatSeriesNodeModel.cs @@ -18,6 +18,9 @@ using ProtoCore.AST.AssociativeAST; using DynamoServices; using Dynamo.Wpf.Properties; +using Dynamo.Graph.Connectors; +using Newtonsoft.Json.Linq; +using Dynamo.ViewModels; namespace CoreNodeModelsWpf.Charts { @@ -26,9 +29,17 @@ namespace CoreNodeModelsWpf.Charts [NodeCategory("Display.Charts.Create")] [NodeDescription("ChartsHeatSeriesDescription", typeof(CoreNodeModelWpfResources))] [NodeSearchTags("ChartsHeatSeriesSearchTags", typeof(CoreNodeModelWpfResources))] - + [InPortNames("x-labels", "y-labels", "values", "colors")] [InPortTypes("List", "List", "List>", "List")] - [OutPortTypes("object[]")] + [InPortDescriptions(typeof(CoreNodeModelWpfResources), + "ChartsHeatSeriesXLabelsDataPortToolTip", + "ChartsHeatSeriesYLabelsDataPortToolTip", + "ChartsHeatSeriesValuesDataPortToolTip", + "ChartsHeatSeriesColorsDataPortToolTip")] + [OutPortNames("labels:values")] + [OutPortTypes("Dictionary>")] + [OutPortDescriptions(typeof(CoreNodeModelWpfResources), + "ChartsHeatSeriesLabelsValuesDataPortToolTip")] [AlsoKnownAs("CoreNodeModelsWpf.Charts.HeatSeriesPlot")] public class HeatSeriesNodeModel : NodeModel { @@ -54,6 +65,16 @@ public class HeatSeriesNodeModel : NodeModel /// A list of color values, one for each plotted line. /// public List Colors { get; set; } + + /// + /// Triggers when port is connected or disconnected + /// + public event EventHandler PortUpdated; + + protected virtual void OnPortUpdated(EventArgs args) + { + PortUpdated?.Invoke(this, args); + } #endregion #region Constructors @@ -62,16 +83,11 @@ public class HeatSeriesNodeModel : NodeModel /// public HeatSeriesNodeModel() { - InPorts.Add(new PortModel(PortType.Input, this, new PortData("x-labels", "A list of string labels for the x-axis."))); - InPorts.Add(new PortModel(PortType.Input, this, new PortData("y-labels", "A list of string labels for the y-axis."))); - InPorts.Add(new PortModel(PortType.Input, this, new PortData("values", "A list of lists each containing double values representing items in a column."))); - InPorts.Add(new PortModel(PortType.Input, this, new PortData("colors", "A list of colors used to generate a color range."))); - - OutPorts.Add(new PortModel(PortType.Output, this, new PortData("labels:values", "Dictionary containing label:value key-pairs"))); - RegisterAllPorts(); - PortDisconnected += XYLineChartNodeModel_PortDisconnected; + + PortConnected += HeatSeriesNodeModel_PortConnected; + PortDisconnected += HeatSeriesNodeModel_PortDisconnected; ArgumentLacing = LacingStrategy.Disabled; } @@ -82,24 +98,39 @@ public HeatSeriesNodeModel() /// public HeatSeriesNodeModel(IEnumerable inPorts, IEnumerable outPorts) : base(inPorts, outPorts) { - PortDisconnected += XYLineChartNodeModel_PortDisconnected; + PortConnected += HeatSeriesNodeModel_PortConnected; + PortDisconnected += HeatSeriesNodeModel_PortDisconnected; } #endregion #region Events - private void XYLineChartNodeModel_PortDisconnected(PortModel port) + private void HeatSeriesNodeModel_PortDisconnected(PortModel port) { + OnPortUpdated(null); // Clear UI when a input port is disconnected - if (port.PortType == PortType.Input && this.State == ElementState.Active) + if (port.PortType == PortType.Input) { - XLabels.Clear(); - YLabels.Clear(); - Values.Clear(); - Colors.Clear(); + XLabels?.Clear(); + YLabels?.Clear(); + Values?.Clear(); + Colors?.Clear(); RaisePropertyChanged("DataUpdated"); } } + + + private void HeatSeriesNodeModel_PortConnected(PortModel port, ConnectorModel arg2) + { + // Reset an info states if any + if (port.PortType == PortType.Input && InPorts[3].IsConnected && NodeInfos.Any(x => x.State.Equals(ElementState.Info))) + { + this.ClearInfoMessages(); + } + + OnPortUpdated(null); + RaisePropertyChanged("DataUpdated"); + } #endregion #region Databridge @@ -124,6 +155,9 @@ protected override void OnBuilt() /// The data passed through the data bridge. private void DataBridgeCallback(object data) { + // Reset an info states if any + if (NodeInfos.Count > 0) this.ClearInfoMessages(); + // Grab input data which always returned as an ArrayList var inputs = data as ArrayList; @@ -133,11 +167,9 @@ private void DataBridgeCallback(object data) var values = inputs[2] as ArrayList; var colors = inputs[3] as ArrayList; - // TODO - is it worth/possible to display jagged data - // If data is jagged throw warning - if (xLabels.Count != values.Count || xLabels.Count == 0) + if (!InPorts[0].IsConnected && !InPorts[1].IsConnected && !InPorts[2].IsConnected) { - throw new Exception("Label and Values do not properly align in length."); + return; } // Clear current chart values @@ -146,6 +178,13 @@ private void DataBridgeCallback(object data) Values = new List>(); Colors = new List(); + var anyNullData = xLabels == null || yLabels == null || values == null; + + if (anyNullData || xLabels.Count != values.Count || yLabels.Count != (values[0] as ArrayList).Count || xLabels.Count == 0 || yLabels.Count == 0) + { + throw new Exception("Label and Values do not properly align in length."); + } + // Iterate the x and y values separately as they may be different lengths for (var i = 0; i < xLabels.Count; i++) { @@ -174,6 +213,8 @@ private void DataBridgeCallback(object data) // If colors is empty add 1 random color if (colors == null || colors.Count == 0) { + if (InPorts[3].IsConnected) return; + // In case colors are not provided, we supply some from the default library of colors Info(Dynamo.Wpf.Properties.CoreNodeModelWpfResources.ProvideDefaultColorsWarningMessage); @@ -183,7 +224,6 @@ private void DataBridgeCallback(object data) Utilities.Colors.ResetColors(); } - // If provided with 1 color blend white to color // Else create color range from provided color else @@ -196,8 +236,6 @@ private void DataBridgeCallback(object data) } } - // TODO - Should this use Dynamo Scheduler to prevent timing issues with redundant calls? - // Notify UI the data has been modified RaisePropertyChanged("DataUpdated"); } #endregion @@ -216,8 +254,29 @@ public override IEnumerable BuildOutputAst(List, List, List>, List, Dictionary>>(HeatSeriesFunctions.GetNodeInput), + new List { inputAstNodes[0], inputAstNodes[1], inputAstNodes[2], inputAstNodes[3] } + ); + + return new[] + { + AstFactory.BuildAssignment(GetAstIdentifierForOutputIndex(0), inputNode), + AstFactory.BuildAssignment( + AstFactory.BuildIdentifier(AstIdentifierBase + "_dummy"), + VMDataBridge.DataBridge.GenerateBridgeDataAst(GUID.ToString(), AstFactory.BuildExprList(inputAstNodes) + ) + ), + }; + } + else if (!InPorts[0].IsConnected || !InPorts[1].IsConnected || !InPorts[2].IsConnected) { @@ -226,21 +285,23 @@ public override IEnumerable BuildOutputAst(List, List, List>, List, Dictionary>>(HeatSeriesFunctions.GetNodeInput), - new List { inputAstNodes[0], inputAstNodes[1], inputAstNodes[2], inputAstNodes[3] } - ); - - return new[] + else { - AstFactory.BuildAssignment(GetAstIdentifierForOutputIndex(0), inputNode), - AstFactory.BuildAssignment( - AstFactory.BuildIdentifier(AstIdentifierBase + "_dummy"), - VMDataBridge.DataBridge.GenerateBridgeDataAst(GUID.ToString(), AstFactory.BuildExprList(inputAstNodes) - ) - ), - }; + inputNode = AstFactory.BuildFunctionCall( + new Func, List, List>, List, Dictionary>>(HeatSeriesFunctions.GetNodeInput), + new List { inputAstNodes[0], inputAstNodes[1], inputAstNodes[2], inputAstNodes[3] } + ); + + return new[] + { + AstFactory.BuildAssignment(GetAstIdentifierForOutputIndex(0), inputNode), + AstFactory.BuildAssignment( + AstFactory.BuildIdentifier(AstIdentifierBase + "_dummy"), + VMDataBridge.DataBridge.GenerateBridgeDataAst(GUID.ToString(), AstFactory.BuildExprList(inputAstNodes) + ) + ), + }; + } } #endregion @@ -251,7 +312,8 @@ public override IEnumerable BuildOutputAst(List public override void Dispose() { - PortDisconnected -= XYLineChartNodeModel_PortDisconnected; + PortConnected -= HeatSeriesNodeModel_PortConnected; + PortDisconnected -= HeatSeriesNodeModel_PortDisconnected; VMDataBridge.DataBridge.Instance.UnregisterCallback(GUID.ToString()); } @@ -264,6 +326,9 @@ public override void Dispose() public class HeatSeriesNodeView : INodeViewCustomization { private HeatSeriesControl heatSeriesControl; + private NodeView view; + private HeatSeriesNodeModel model; + /// /// At run-time, this method is called during the node @@ -273,6 +338,8 @@ public class HeatSeriesNodeView : INodeViewCustomization /// The NodeView representing the node in the graph. public void CustomizeView(HeatSeriesNodeModel model, NodeView nodeView) { + this.model = model; + this.view = nodeView; heatSeriesControl = new HeatSeriesControl(model); nodeView.inputGrid.Children.Add(heatSeriesControl); @@ -282,6 +349,50 @@ public void CustomizeView(HeatSeriesNodeModel model, NodeView nodeView) var contextMenu = (nodeView.Content as Grid).ContextMenu; contextMenu.Items.Add(exportImage); + + UpdateDefaultInPortValues(); + + model.PortUpdated += ModelOnPortUpdated; + } + private void ModelOnPortUpdated(object sender, EventArgs e) + { + UpdateDefaultInPortValues(); + } + private void UpdateDefaultInPortValues() + { + if (!this.view.ViewModel.InPorts.Any()) return; + var inPorts = this.view.ViewModel.InPorts; + + // Only apply default values if all ports are disconnected + if (!model.IsInErrorState && + model.State != ElementState.Active && + !inPorts[0].IsConnected && + !inPorts[1].IsConnected && + !inPorts[2].IsConnected) + { + ((InPortViewModel)inPorts[0]).PortDefaultValueMarkerVisible = true; + ((InPortViewModel)inPorts[1]).PortDefaultValueMarkerVisible = true; + ((InPortViewModel)inPorts[2]).PortDefaultValueMarkerVisible = true; + } + else + { + ((InPortViewModel)inPorts[0]).PortDefaultValueMarkerVisible = false; + ((InPortViewModel)inPorts[1]).PortDefaultValueMarkerVisible = false; + ((InPortViewModel)inPorts[2]).PortDefaultValueMarkerVisible = false; + } + + var allPortsConnected = inPorts[0].IsConnected && inPorts[1].IsConnected && inPorts[2].IsConnected && model.State != ElementState.Warning; + var noPortsConnected = !inPorts[0].IsConnected && !inPorts[1].IsConnected && !inPorts[2].IsConnected; + + // The color input uses default values if it's not connected + if (!inPorts[3].IsConnected && (allPortsConnected || noPortsConnected)) + { + ((InPortViewModel)inPorts[3]).PortDefaultValueMarkerVisible = true; + } + else + { + ((InPortViewModel)inPorts[3]).PortDefaultValueMarkerVisible = false; + } } private void ExportImage_Click(object sender, RoutedEventArgs e) @@ -293,6 +404,9 @@ private void ExportImage_Click(object sender, RoutedEventArgs e) /// Here you can do any cleanup you require if you've assigned callbacks for particular /// UI events on your node. /// - public void Dispose() { } + public void Dispose() + { + model.PortUpdated -= ModelOnPortUpdated; + } } } diff --git a/src/Libraries/CoreNodeModelsWpf/Charts/PieChartNodeModel.cs b/src/Libraries/CoreNodeModelsWpf/Charts/PieChartNodeModel.cs index d8ece538c61..8f28f85c339 100644 --- a/src/Libraries/CoreNodeModelsWpf/Charts/PieChartNodeModel.cs +++ b/src/Libraries/CoreNodeModelsWpf/Charts/PieChartNodeModel.cs @@ -19,6 +19,8 @@ using DynamoServices; using Dynamo.Wpf.Properties; using Xceed.Wpf.Toolkit; +using Dynamo.Graph.Connectors; +using Dynamo.ViewModels; namespace CoreNodeModelsWpf.Charts { @@ -27,9 +29,16 @@ namespace CoreNodeModelsWpf.Charts [NodeCategory("Display.Charts.Create")] [NodeDescription("ChartsPieChartDescription", typeof(CoreNodeModelWpfResources))] [NodeSearchTags("ChartsPieChartSearchTags", typeof(CoreNodeModelWpfResources))] - + [InPortNames("labels", "values", "colors")] [InPortTypes("List", "List", "List")] - [OutPortTypes("Dictionary")] + [InPortDescriptions(typeof(CoreNodeModelWpfResources), + "ChartsPieChartLabelsDataPortToolTip", + "ChartsPieChartValuesDataPortToolTip", + "ChartsPieChartColorsDataPortToolTip")] + [OutPortNames("labels:values")] + [OutPortTypes("Dictionary")] + [OutPortDescriptions(typeof(CoreNodeModelWpfResources), + "ChartsPieChartLabelsValuesDataPortToolTip")] [AlsoKnownAs("CoreNodeModelsWpf.Charts.PieChart")] public class PieChartNodeModel : NodeModel { @@ -49,6 +58,16 @@ public class PieChartNodeModel : NodeModel /// Pie chart color values. /// public List Colors { get; set; } + + /// + /// Triggers when port is connected or disconnected + /// + public event EventHandler PortUpdated; + + protected virtual void OnPortUpdated(EventArgs args) + { + PortUpdated?.Invoke(this, args); + } #endregion #region Constructors @@ -57,25 +76,22 @@ public class PieChartNodeModel : NodeModel /// public PieChartNodeModel() { - InPorts.Add(new PortModel(PortType.Input, this, new PortData("labels", "A list of string labels for each segment in the pie chart."))); - InPorts.Add(new PortModel(PortType.Input, this, new PortData("values", "A list of double values to supply a value for each segment of the pie chart."))); - InPorts.Add(new PortModel(PortType.Input, this, new PortData("colors", "A list of colors for each segment of the pie chart."))); - - OutPorts.Add(new PortModel(PortType.Output, this, new PortData("labels:values", "Dictionary containing label:value key-pairs"))); - RegisterAllPorts(); + PortConnected += PieChartNodeModel_PortConnected; PortDisconnected += PieChartNodeModel_PortDisconnected; ArgumentLacing = LacingStrategy.Disabled; } + [JsonConstructor] /// /// Instantiate a new NodeModel instance. /// public PieChartNodeModel(IEnumerable inPorts, IEnumerable outPorts) : base(inPorts, outPorts) { + PortConnected += PieChartNodeModel_PortConnected; PortDisconnected += PieChartNodeModel_PortDisconnected; } #endregion @@ -83,16 +99,29 @@ public PieChartNodeModel(IEnumerable inPorts, IEnumerable #region Events private void PieChartNodeModel_PortDisconnected(PortModel port) { + OnPortUpdated(null); // Clear UI when a input port is disconnected - if (port.PortType == PortType.Input && this.State == ElementState.Active) + if (port.PortType == PortType.Input) { - Labels.Clear(); - Values.Clear(); - Colors.Clear(); + Labels?.Clear(); + Values?.Clear(); + Colors?.Clear(); RaisePropertyChanged("DataUpdated"); } } + + private void PieChartNodeModel_PortConnected(PortModel port, ConnectorModel arg2) + { + // Reset an info states if any + if (port.PortType == PortType.Input && InPorts[2].IsConnected && NodeInfos.Any(x => x.State.Equals(ElementState.Info))) + { + this.ClearInfoMessages(); + } + + OnPortUpdated(null); + RaisePropertyChanged("DataUpdated"); + } #endregion #region databridge @@ -125,10 +154,9 @@ private void DataBridgeCallback(object data) var values = inputs[1] as ArrayList; var colors = inputs[2] as ArrayList; - // Only continue if key/values match in length - if (keys.Count != values.Count || keys.Count < 1) + if (!InPorts[0].IsConnected && !InPorts[1].IsConnected && !InPorts[2].IsConnected) { - throw new Exception("Label and Values do not properly align in length."); + return; } // Update chart properties @@ -136,8 +164,18 @@ private void DataBridgeCallback(object data) Values = new List(); Colors = new List(); + var anyNullData = keys == null || values == null; + + // Only continue if key/values match in length + if (anyNullData || keys.Count != values.Count || keys.Count == 0) + { + throw new Exception("Label and Values do not properly align in length."); + } + if (colors == null || colors.Count == 0 || colors.Count != keys.Count) { + if (InPorts[2].IsConnected) return; + // In case colors are not provided, we supply some from the default library of colors Info(Dynamo.Wpf.Properties.CoreNodeModelWpfResources.ProvideDefaultColorsWarningMessage); @@ -186,30 +224,52 @@ public override IEnumerable BuildOutputAst(List, List, List, Dictionary>(PieChartFunctions.GetNodeInput), + new List { inputAstNodes[0], inputAstNodes[1], inputAstNodes[2] } + ); + + return new[] + { + AstFactory.BuildAssignment(GetAstIdentifierForOutputIndex(0), inputNode), + AstFactory.BuildAssignment( + AstFactory.BuildIdentifier(AstIdentifierBase + "_dummy"), + VMDataBridge.DataBridge.GenerateBridgeDataAst(GUID.ToString(), AstFactory.BuildExprList(inputAstNodes) + ) + ), + }; + } + else if (!InPorts[0].IsConnected || !InPorts[1].IsConnected) { return new[] { AstFactory.BuildAssignment(GetAstIdentifierForOutputIndex(0), AstFactory.BuildNullNode()), }; + } + else + { + inputNode = AstFactory.BuildFunctionCall( + new Func, List, List, Dictionary>(PieChartFunctions.GetNodeInput), + new List { inputAstNodes[0], inputAstNodes[1], inputAstNodes[2] } + ); - AssociativeNode inputNode = AstFactory.BuildFunctionCall( - new Func, List, List, Dictionary>(PieChartFunctions.GetNodeInput), - new List { inputAstNodes[0], inputAstNodes[1], inputAstNodes[2] } - ); + return new[] + { + AstFactory.BuildAssignment(GetAstIdentifierForOutputIndex(0), inputNode), + AstFactory.BuildAssignment( + AstFactory.BuildIdentifier(AstIdentifierBase + "_dummy"), + VMDataBridge.DataBridge.GenerateBridgeDataAst(GUID.ToString(), AstFactory.BuildExprList(inputAstNodes) + ) + ), + }; + } - return new[] - { - AstFactory.BuildAssignment(GetAstIdentifierForOutputIndex(0), inputNode), - AstFactory.BuildAssignment( - AstFactory.BuildIdentifier(AstIdentifierBase + "_dummy"), - VMDataBridge.DataBridge.GenerateBridgeDataAst(GUID.ToString(), AstFactory.BuildExprList(inputAstNodes) - ) - ), - }; } #endregion @@ -220,6 +280,7 @@ public override IEnumerable BuildOutputAst(List public override void Dispose() { + PortConnected -= PieChartNodeModel_PortConnected; PortDisconnected -= PieChartNodeModel_PortDisconnected; VMDataBridge.DataBridge.Instance.UnregisterCallback(GUID.ToString()); } @@ -233,6 +294,8 @@ public override void Dispose() public class PieChartNodeView : INodeViewCustomization { private PieChartControl pieChartControl; + private NodeView view; + private PieChartNodeModel model; /// /// At run-time, this method is called during the node @@ -242,6 +305,8 @@ public class PieChartNodeView : INodeViewCustomization /// The NodeView representing the node in the graph. public void CustomizeView(PieChartNodeModel model, NodeView nodeView) { + this.model = model; + this.view = nodeView; pieChartControl = new PieChartControl(model); nodeView.inputGrid.Children.Add(pieChartControl); @@ -251,6 +316,49 @@ public void CustomizeView(PieChartNodeModel model, NodeView nodeView) var contextMenu = (nodeView.Content as Grid).ContextMenu; contextMenu.Items.Add(exportImage); + + UpdateDefaultInPortValues(); + + model.PortUpdated += ModelOnPortUpdated; + } + + private void ModelOnPortUpdated(object sender, EventArgs e) + { + UpdateDefaultInPortValues(); + } + + private void UpdateDefaultInPortValues() + { + if (!this.view.ViewModel.InPorts.Any()) return; + var inPorts = this.view.ViewModel.InPorts; + + // Only apply default values if all ports are disconnected + if (!model.IsInErrorState && + model.State != ElementState.Active && + !inPorts[0].IsConnected && + !inPorts[1].IsConnected) + { + ((InPortViewModel)inPorts[0]).PortDefaultValueMarkerVisible = true; + ((InPortViewModel)inPorts[1]).PortDefaultValueMarkerVisible = true; + } + else + { + ((InPortViewModel)inPorts[0]).PortDefaultValueMarkerVisible = false; + ((InPortViewModel)inPorts[1]).PortDefaultValueMarkerVisible = false; + } + + var allPortsConnected = inPorts[0].IsConnected && inPorts[1].IsConnected && model.State != ElementState.Warning; + var noPortsConnected = !inPorts[0].IsConnected && !inPorts[1].IsConnected; + + // The color input uses default values if it's not connected + if (!inPorts[2].IsConnected && (allPortsConnected || noPortsConnected)) + { + ((InPortViewModel)inPorts[2]).PortDefaultValueMarkerVisible = true; + } + else + { + ((InPortViewModel)inPorts[2]).PortDefaultValueMarkerVisible = false; + } } private void ExportImage_Click(object sender, RoutedEventArgs e) @@ -262,6 +370,9 @@ private void ExportImage_Click(object sender, RoutedEventArgs e) /// Here you can do any cleanup you require if you've assigned callbacks for particular /// UI events on your node. /// - public void Dispose() { } + public void Dispose() + { + model.PortUpdated -= ModelOnPortUpdated; + } } } diff --git a/src/Libraries/CoreNodeModelsWpf/Charts/ScatterPlotNodeModel.cs b/src/Libraries/CoreNodeModelsWpf/Charts/ScatterPlotNodeModel.cs index 43ec13132be..612df33032e 100644 --- a/src/Libraries/CoreNodeModelsWpf/Charts/ScatterPlotNodeModel.cs +++ b/src/Libraries/CoreNodeModelsWpf/Charts/ScatterPlotNodeModel.cs @@ -19,6 +19,8 @@ using DynamoServices; using Dynamo.Wpf.Properties; using ProtoCore.DesignScriptParser; +using Dynamo.Graph.Connectors; +using Dynamo.ViewModels; namespace CoreNodeModelsWpf.Charts { @@ -27,9 +29,17 @@ namespace CoreNodeModelsWpf.Charts [NodeCategory("Display.Charts.Create")] [NodeDescription("ChartsScatterPlotDescription", typeof(CoreNodeModelWpfResources))] [NodeSearchTags("ChartsScatterPlotSearchTags", typeof(CoreNodeModelWpfResources))] - + [InPortNames("labels", "x-values", "y-values", "colors")] [InPortTypes("List", "List>", "List>", "List")] - [OutPortTypes("Dictionary")] + [InPortDescriptions(typeof(CoreNodeModelWpfResources), + "ChartsScatterPlotLabelsDataPortToolTip", + "ChartsScatterPlotXLabelsDataPortToolTip", + "ChartsScatterPlotYLabelsDataPortToolTip", + "ChartsScatterPlotColorsDataPortToolTip")] + [OutPortNames("labels:values")] + [OutPortTypes("Dictionary>>")] + [OutPortDescriptions(typeof(CoreNodeModelWpfResources), + "ChartsScatterPlotLabelsValuesDataPortToolTip")] [AlsoKnownAs("CoreNodeModelsWpf.Charts.ScatterPlot")] public class ScatterPlotNodeModel : NodeModel { @@ -55,6 +65,16 @@ public class ScatterPlotNodeModel : NodeModel /// A list of color values, one for each plotted line. /// public List Colors { get; set; } + + /// + /// Triggers when port is connected or disconnected + /// + public event EventHandler PortUpdated; + + protected virtual void OnPortUpdated(EventArgs args) + { + PortUpdated?.Invoke(this, args); + } #endregion #region Constructors @@ -63,15 +83,9 @@ public class ScatterPlotNodeModel : NodeModel /// public ScatterPlotNodeModel() { - InPorts.Add(new PortModel(PortType.Input, this, new PortData("labels", "A list of string labels for each group of points to be plotted."))); - InPorts.Add(new PortModel(PortType.Input, this, new PortData("x-values", "A list of lists each containing double values representing x-coordinates."))); - InPorts.Add(new PortModel(PortType.Input, this, new PortData("y-values", "A list of lists each containing double values representing y-coordinates."))); - InPorts.Add(new PortModel(PortType.Input, this, new PortData("colors", "A list of colors for each group of points."))); - - OutPorts.Add(new PortModel(PortType.Output, this, new PortData("labels:values", "Dictionary containing label:value key-pairs"))); - RegisterAllPorts(); + PortConnected += ScatterPlotNodeModel_PortConnected; PortDisconnected += ScatterPlotNodeModel_PortDisconnected; ArgumentLacing = LacingStrategy.Disabled; @@ -83,6 +97,7 @@ public ScatterPlotNodeModel() /// public ScatterPlotNodeModel(IEnumerable inPorts, IEnumerable outPorts) : base(inPorts, outPorts) { + PortConnected += ScatterPlotNodeModel_PortConnected; PortDisconnected += ScatterPlotNodeModel_PortDisconnected; } #endregion @@ -90,17 +105,30 @@ public ScatterPlotNodeModel(IEnumerable inPorts, IEnumerable x.State.Equals(ElementState.Info))) + { + this.ClearInfoMessages(); + } + + OnPortUpdated(null); + RaisePropertyChanged("DataUpdated"); + } #endregion #region Databridge @@ -134,10 +162,9 @@ private void DataBridgeCallback(object data) var yValues = inputs[2] as ArrayList; var colors = inputs[3] as ArrayList; - // Only continue if key/values match in length - if (labels.Count != xValues.Count || xValues.Count != yValues.Count || labels.Count < 1) + if (!InPorts[0].IsConnected && !InPorts[1].IsConnected && !InPorts[2].IsConnected) { - throw new Exception("Label and Values do not properly align in length."); + return; } // Clear current chart values @@ -146,9 +173,19 @@ private void DataBridgeCallback(object data) YValues = new List>(); Colors = new List(); + var anyNullData = labels == null || xValues == null || yValues == null; + + // Only continue if key/values match in length + if (anyNullData || labels.Count != xValues.Count || xValues.Count != yValues.Count || labels.Count == 0 || xValues.Count == 0) + { + throw new Exception("Label and Values do not properly align in length."); + } + // If color count doesn't match title count use random colors if (colors == null || colors.Count == 0 || colors.Count != labels.Count) { + if (InPorts[3].IsConnected) return; + // In case colors are not provided, we supply some from the default library of colors Info(Dynamo.Wpf.Properties.CoreNodeModelWpfResources.ProvideDefaultColorsWarningMessage); @@ -199,11 +236,18 @@ private void DataBridgeCallback(object data) XValues.Add(outputXValues); YValues.Add(outputYValues); - var dynColor = (DSCore.Color)colors[i]; - var convertedColor = Color.FromArgb(dynColor.Alpha, dynColor.Red, dynColor.Green, dynColor.Blue); - SolidColorBrush brush = new SolidColorBrush(convertedColor); - brush.Freeze(); - Colors.Add(brush); + try + { + var dynColor = (DSCore.Color)colors[i]; + var convertedColor = Color.FromArgb(dynColor.Alpha, dynColor.Red, dynColor.Green, dynColor.Blue); + SolidColorBrush brush = new SolidColorBrush(convertedColor); + brush.Freeze(); + Colors.Add(brush); + } + catch (Exception) + { + throw new Exception("Colors are not properly defined list of colors."); + } } } @@ -226,31 +270,54 @@ public override IEnumerable BuildOutputAst(List, List>, List>, List, Dictionary>>>(ScatterPlotFunctions.GetNodeInput), + new List { inputAstNodes[0], inputAstNodes[1], inputAstNodes[2], inputAstNodes[3] } + ); + + return new[] + { + AstFactory.BuildAssignment(GetAstIdentifierForOutputIndex(0), inputNode), + AstFactory.BuildAssignment( + AstFactory.BuildIdentifier(AstIdentifierBase + "_dummy"), + VMDataBridge.DataBridge.GenerateBridgeDataAst(GUID.ToString(), AstFactory.BuildExprList(inputAstNodes) + ) + ), + }; + } + else if (!InPorts[0].IsConnected || + !InPorts[1].IsConnected || + !InPorts[2].IsConnected) { return new[] { AstFactory.BuildAssignment(GetAstIdentifierForOutputIndex(0), AstFactory.BuildNullNode()), }; } - - AssociativeNode inputNode = AstFactory.BuildFunctionCall( - new Func, List>, List>, List, Dictionary>>>(ScatterPlotFunctions.GetNodeInput), - new List { inputAstNodes[0], inputAstNodes[1], inputAstNodes[2], inputAstNodes[3] } - ); - - return new[] + else { - AstFactory.BuildAssignment(GetAstIdentifierForOutputIndex(0), inputNode), - AstFactory.BuildAssignment( - AstFactory.BuildIdentifier(AstIdentifierBase + "_dummy"), - VMDataBridge.DataBridge.GenerateBridgeDataAst(GUID.ToString(), AstFactory.BuildExprList(inputAstNodes) - ) - ), - }; + inputNode = AstFactory.BuildFunctionCall( + new Func, List>, List>, List, Dictionary>>>(ScatterPlotFunctions.GetNodeInput), + new List { inputAstNodes[0], inputAstNodes[1], inputAstNodes[2], inputAstNodes[3] } + ); + + return new[] + { + AstFactory.BuildAssignment(GetAstIdentifierForOutputIndex(0), inputNode), + AstFactory.BuildAssignment( + AstFactory.BuildIdentifier(AstIdentifierBase + "_dummy"), + VMDataBridge.DataBridge.GenerateBridgeDataAst(GUID.ToString(), AstFactory.BuildExprList(inputAstNodes) + ) + ), + }; + } } #endregion @@ -261,6 +328,7 @@ public override IEnumerable BuildOutputAst(List public override void Dispose() { + PortConnected -= ScatterPlotNodeModel_PortConnected; PortDisconnected -= ScatterPlotNodeModel_PortDisconnected; VMDataBridge.DataBridge.Instance.UnregisterCallback(GUID.ToString()); } @@ -274,6 +342,8 @@ public override void Dispose() public class ScatterPlotNodeView : INodeViewCustomization { private ScatterPlotControl scatterPlotControl; + private NodeView view; + private ScatterPlotNodeModel model; /// /// At run-time, this method is called during the node @@ -283,6 +353,8 @@ public class ScatterPlotNodeView : INodeViewCustomization /// The NodeView representing the node in the graph. public void CustomizeView(ScatterPlotNodeModel model, NodeView nodeView) { + this.model = model; + this.view = nodeView; scatterPlotControl = new ScatterPlotControl(model); nodeView.inputGrid.Children.Add(scatterPlotControl); @@ -292,6 +364,52 @@ public void CustomizeView(ScatterPlotNodeModel model, NodeView nodeView) var contextMenu = (nodeView.Content as Grid).ContextMenu; contextMenu.Items.Add(exportImage); + + UpdateDefaultInPortValues(); + + model.PortUpdated += ModelOnPortUpdated; + } + + private void ModelOnPortUpdated(object sender, EventArgs e) + { + UpdateDefaultInPortValues(); + } + + private void UpdateDefaultInPortValues() + { + if (!this.view.ViewModel.InPorts.Any()) return; + var inPorts = this.view.ViewModel.InPorts; + + // Only apply default values if all ports are disconnected + if (!model.IsInErrorState && + model.State != ElementState.Active && + !inPorts[0].IsConnected && + !inPorts[1].IsConnected && + !inPorts[2].IsConnected) + { + ((InPortViewModel)inPorts[0]).PortDefaultValueMarkerVisible = true; + ((InPortViewModel)inPorts[1]).PortDefaultValueMarkerVisible = true; + ((InPortViewModel)inPorts[2]).PortDefaultValueMarkerVisible = true; + } + else + { + ((InPortViewModel)inPorts[0]).PortDefaultValueMarkerVisible = false; + ((InPortViewModel)inPorts[1]).PortDefaultValueMarkerVisible = false; + ((InPortViewModel)inPorts[2]).PortDefaultValueMarkerVisible = false; + } + + var allPortsConnected = inPorts[0].IsConnected && inPorts[1].IsConnected && inPorts[2].IsConnected && model.State != ElementState.Warning; + var noPortsConnected = !inPorts[0].IsConnected && !inPorts[1].IsConnected && !inPorts[2].IsConnected; + + // The color input uses default values if it's not connected + if (!inPorts[3].IsConnected && (allPortsConnected || noPortsConnected)) + { + ((InPortViewModel)inPorts[3]).PortDefaultValueMarkerVisible = true; + } + else + { + ((InPortViewModel)inPorts[3]).PortDefaultValueMarkerVisible = false; + } } private void ExportImage_Click(object sender, RoutedEventArgs e) @@ -303,6 +421,9 @@ private void ExportImage_Click(object sender, RoutedEventArgs e) /// Here you can do any cleanup you require if you've assigned callbacks for particular /// UI events on your node. /// - public void Dispose() { } + public void Dispose() + { + model.PortUpdated -= ModelOnPortUpdated; + } } } diff --git a/src/Libraries/CoreNodeModelsWpf/Charts/XYLineChartNodeModel.cs b/src/Libraries/CoreNodeModelsWpf/Charts/XYLineChartNodeModel.cs index bbb5acd8bd3..ef699141c64 100644 --- a/src/Libraries/CoreNodeModelsWpf/Charts/XYLineChartNodeModel.cs +++ b/src/Libraries/CoreNodeModelsWpf/Charts/XYLineChartNodeModel.cs @@ -12,7 +12,9 @@ using CoreNodeModelsWpf.Charts.Controls; using CoreNodeModelsWpf.Charts.Utilities; using Dynamo.Controls; +using Dynamo.Graph.Connectors; using Dynamo.Graph.Nodes; +using Dynamo.ViewModels; using Dynamo.Wpf; using Newtonsoft.Json; using ProtoCore.AST.AssociativeAST; @@ -26,9 +28,17 @@ namespace CoreNodeModelsWpf.Charts [NodeCategory("Display.Charts.Create")] [NodeDescription("ChartsXYLineChartDescription", typeof(CoreNodeModelWpfResources))] [NodeSearchTags("ChartsXYLineChartSearchTags", typeof(CoreNodeModelWpfResources))] - + [InPortNames("labels", "x-values", "y-values", "colors")] [InPortTypes("List", "List>", "List>", "List")] - [OutPortTypes("Dictionary")] + [InPortDescriptions(typeof(CoreNodeModelWpfResources), + "ChartsXYLineChartLabelsDataPortToolTip", + "ChartsXYLineChartXLabelsDataPortToolTip", + "ChartsXYLineChartYLabelsDataPortToolTip", + "ChartsXYLineChartColorsDataPortToolTip")] + [OutPortNames("labels:values")] + [OutPortTypes("Dictionary>>")] + [OutPortDescriptions(typeof(CoreNodeModelWpfResources), + "ChartsXYLineChartLabelsValuesDataPortToolTip")] [AlsoKnownAs("CoreNodeModelsWpf.Charts.XYLinePlot")] public class XYLineChartNodeModel : NodeModel { @@ -54,6 +64,16 @@ public class XYLineChartNodeModel : NodeModel /// A list of color values, one for each plotted line. /// public List Colors { get; set; } + + /// + /// Triggers when port is connected or disconnected + /// + public event EventHandler PortUpdated; + + protected virtual void OnPortUpdated(EventArgs args) + { + PortUpdated?.Invoke(this, args); + } #endregion #region Constructors @@ -62,26 +82,21 @@ public class XYLineChartNodeModel : NodeModel /// public XYLineChartNodeModel() { - InPorts.Add(new PortModel(PortType.Input, this, new PortData("labels", "A list of string labels for each line to be plotted"))); - InPorts.Add(new PortModel(PortType.Input, this, new PortData("x-values", "A list of lists each containing double values representing x-coordinates for each point in a line."))); - InPorts.Add(new PortModel(PortType.Input, this, new PortData("y-values", "A list of lists each containing double values representing y-coordinates for each point in a line."))); - InPorts.Add(new PortModel(PortType.Input, this, new PortData("colors", "A list of colors for each line in the line plot."))); - - OutPorts.Add(new PortModel(PortType.Output, this, new PortData("labels:values", "Dictionary containing label:value key-pairs"))); - RegisterAllPorts(); + PortConnected += XYLineChartNodeModel_PortConnected; PortDisconnected += XYLineChartNodeModel_PortDisconnected; ArgumentLacing = LacingStrategy.Disabled; } - [JsonConstructor] /// /// Instantiate a new NodeModel instance. /// + [JsonConstructor] public XYLineChartNodeModel(IEnumerable inPorts, IEnumerable outPorts) : base(inPorts, outPorts) { + PortConnected += XYLineChartNodeModel_PortConnected; PortDisconnected += XYLineChartNodeModel_PortDisconnected; } #endregion @@ -89,17 +104,29 @@ public XYLineChartNodeModel(IEnumerable inPorts, IEnumerable x.State.Equals(ElementState.Info))) + { + this.ClearInfoMessages(); + } + + OnPortUpdated(null); + RaisePropertyChanged("DataUpdated"); + } #endregion #region Databridge @@ -132,11 +159,10 @@ private void DataBridgeCallback(object data) var xValues = inputs[1] as ArrayList; var yValues = inputs[2] as ArrayList; var colors = inputs[3] as ArrayList; - - // Only continue if key/values match in length - if (labels.Count != xValues.Count || xValues.Count != yValues.Count || labels.Count < 1) + + if (!InPorts[0].IsConnected && !InPorts[1].IsConnected && !InPorts[2].IsConnected) { - throw new Exception("Label and Values do not properly align in length."); + return; } // Clear current chart values @@ -145,9 +171,19 @@ private void DataBridgeCallback(object data) YValues = new List>(); Colors = new List(); + var anyNullData = labels == null || xValues == null || yValues == null; + + // Only continue if key/values match in length + if (anyNullData || labels.Count != xValues.Count || xValues.Count != yValues.Count || labels.Count == 0 || xValues.Count == 0) + { + throw new Exception("Label and Values do not properly align in length."); + } + // If color count doesn't match title count use random colors if (colors == null || colors.Count == 0 || colors.Count != labels.Count) { + if(InPorts[3].IsConnected) return; + // In case colors are not provided, we supply some from the default library of colors Info(Dynamo.Wpf.Properties.CoreNodeModelWpfResources.ProvideDefaultColorsWarningMessage); @@ -198,11 +234,18 @@ private void DataBridgeCallback(object data) XValues.Add(outputXValues); YValues.Add(outputYValues); - var dynColor = (DSCore.Color)colors[i]; - var convertedColor = Color.FromArgb(dynColor.Alpha, dynColor.Red, dynColor.Green, dynColor.Blue); - SolidColorBrush brush = new SolidColorBrush(convertedColor); - brush.Freeze(); - Colors.Add(brush); + try + { + var dynColor = (DSCore.Color)colors[i]; + var convertedColor = Color.FromArgb(dynColor.Alpha, dynColor.Red, dynColor.Green, dynColor.Blue); + SolidColorBrush brush = new SolidColorBrush(convertedColor); + brush.Freeze(); + Colors.Add(brush); + } + catch(Exception) + { + throw new Exception("Colors are not properly defined list of colors."); + } } } @@ -225,31 +268,55 @@ public override IEnumerable BuildOutputAst(List, List>, List>, List, Dictionary>>>(XYLineChartFunctions.GetNodeInput), + new List { inputAstNodes[0], inputAstNodes[1], inputAstNodes[2], inputAstNodes[3] } + ); + + return new[] + { + AstFactory.BuildAssignment(GetAstIdentifierForOutputIndex(0), inputNode), + AstFactory.BuildAssignment( + AstFactory.BuildIdentifier(AstIdentifierBase + "_dummy"), + VMDataBridge.DataBridge.GenerateBridgeDataAst(GUID.ToString(), AstFactory.BuildExprList(inputAstNodes) + ) + ), + }; + } + else if (!InPorts[0].IsConnected || + !InPorts[1].IsConnected || + !InPorts[2].IsConnected) { return new[] { AstFactory.BuildAssignment(GetAstIdentifierForOutputIndex(0), AstFactory.BuildNullNode()), }; } - - AssociativeNode inputNode = AstFactory.BuildFunctionCall( - new Func, List>, List>, List, Dictionary>>>(XYLineChartFunctions.GetNodeInput), - new List { inputAstNodes[0], inputAstNodes[1], inputAstNodes[2], inputAstNodes[3] } - ); - - return new[] + else { - AstFactory.BuildAssignment(GetAstIdentifierForOutputIndex(0), inputNode), + inputNode = AstFactory.BuildFunctionCall( + new Func, List>, List>, List, Dictionary>>>(XYLineChartFunctions.GetNodeInput), + new List { inputAstNodes[0], inputAstNodes[1], inputAstNodes[2], inputAstNodes[3] } + ); + + return new[] + { + AstFactory.BuildAssignment(GetAstIdentifierForOutputIndex(0), inputNode), AstFactory.BuildAssignment( AstFactory.BuildIdentifier(AstIdentifierBase + "_dummy"), VMDataBridge.DataBridge.GenerateBridgeDataAst(GUID.ToString(), AstFactory.BuildExprList(inputAstNodes) - ) - ), - }; + ) + ), + }; + } + } #endregion @@ -260,6 +327,7 @@ public override IEnumerable BuildOutputAst(List public override void Dispose() { + PortConnected -= XYLineChartNodeModel_PortConnected; PortDisconnected -= XYLineChartNodeModel_PortDisconnected; VMDataBridge.DataBridge.Instance.UnregisterCallback(GUID.ToString()); } @@ -273,6 +341,8 @@ public override void Dispose() public class XYLineChartNodeView : INodeViewCustomization { private XYLineChartControl xyLineChartControl; + private NodeView view; + private XYLineChartNodeModel model; /// /// At run-time, this method is called during the node @@ -282,6 +352,8 @@ public class XYLineChartNodeView : INodeViewCustomization /// The NodeView representing the node in the graph. public void CustomizeView(XYLineChartNodeModel model, NodeView nodeView) { + this.model = model; + this.view = nodeView; xyLineChartControl = new XYLineChartControl(model); nodeView.inputGrid.Children.Add(xyLineChartControl); @@ -291,6 +363,51 @@ public void CustomizeView(XYLineChartNodeModel model, NodeView nodeView) var contextMenu = (nodeView.Content as Grid).ContextMenu; contextMenu.Items.Add(exportImage); + + UpdateDefaultInPortValues(); + + model.PortUpdated += ModelOnPortUpdated; + } + + private void ModelOnPortUpdated(object sender, EventArgs e) + { + UpdateDefaultInPortValues(); + } + + private void UpdateDefaultInPortValues() + { + if (!this.view.ViewModel.InPorts.Any()) return; + var inPorts = this.view.ViewModel.InPorts; + // Only apply default values if all ports are disconnected + if (!model.IsInErrorState && + model.State != ElementState.Active && + !inPorts[0].IsConnected && + !inPorts[1].IsConnected && + !inPorts[2].IsConnected) + { + ((InPortViewModel) inPorts[0]).PortDefaultValueMarkerVisible = true; + ((InPortViewModel) inPorts[1]).PortDefaultValueMarkerVisible = true; + ((InPortViewModel) inPorts[2]).PortDefaultValueMarkerVisible = true; + } + else + { + ((InPortViewModel)inPorts[0]).PortDefaultValueMarkerVisible = false; + ((InPortViewModel)inPorts[1]).PortDefaultValueMarkerVisible = false; + ((InPortViewModel)inPorts[2]).PortDefaultValueMarkerVisible = false; + } + + var allPortsConnected = inPorts[0].IsConnected && inPorts[1].IsConnected && inPorts[2].IsConnected && model.State != ElementState.Warning; + var noPortsConnected = !inPorts[0].IsConnected && !inPorts[1].IsConnected && !inPorts[2].IsConnected; + + // The color input uses default values if it's not connected + if (!inPorts[3].IsConnected && (allPortsConnected || noPortsConnected)) + { + ((InPortViewModel) inPorts[3]).PortDefaultValueMarkerVisible = true; + } + else + { + ((InPortViewModel)inPorts[3]).PortDefaultValueMarkerVisible = false; + } } private void ExportImage_Click(object sender, RoutedEventArgs e) @@ -302,6 +419,9 @@ private void ExportImage_Click(object sender, RoutedEventArgs e) /// Here you can do any cleanup you require if you've assigned callbacks for particular /// UI events on your node. /// - public void Dispose() { } + public void Dispose() + { + model.PortUpdated -= ModelOnPortUpdated; + } } } diff --git a/src/Libraries/CoreNodeModelsWpf/Properties/CoreNodeModelWpfResources.Designer.cs b/src/Libraries/CoreNodeModelsWpf/Properties/CoreNodeModelWpfResources.Designer.cs index 12203ff9089..12f2315f405 100644 --- a/src/Libraries/CoreNodeModelsWpf/Properties/CoreNodeModelWpfResources.Designer.cs +++ b/src/Libraries/CoreNodeModelsWpf/Properties/CoreNodeModelWpfResources.Designer.cs @@ -59,6 +59,30 @@ internal CoreNodeModelWpfResources() { resourceCulture = value; } } + + /// + /// Looks up a localized string similar to Dictionary containing label:value key-pairs + /// + ///Dictionary<string, double> + /// + public static string ChartsBarChartLabelsValuesDataPortToolTip + { + get + { + return ResourceManager.GetString("ChartsBarChartLabelsValuesDataPortToolTip", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to A list of colors for each bar chart category. + /// + ///List<color>. + /// + public static string ChartsBarChartColorsDataPortToolTip { + get { + return ResourceManager.GetString("ChartsBarChartColorsDataPortToolTip", resourceCulture); + } + } /// /// Looks up a localized string similar to Create a new Bar Chart. @@ -77,6 +101,54 @@ public static string ChartsBarChartSearchTags { return ResourceManager.GetString("ChartsBarChartSearchTags", resourceCulture); } } + + /// + /// Looks up a localized string similar to A list of labels for the bar chart categories. + /// + ///List<string>. + /// + public static string ChartsBarChartLabelsDataPortToolTip { + get + { + return ResourceManager.GetString("ChartsBarChartLabelsDataPortToolTip", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to A list (of lists) to supply values for the bars in each category. + /// + ///List<var>. + /// + public static string ChartsBarChartValuesDataPortToolTip { + get { + return ResourceManager.GetString("ChartsBarChartValuesDataPortToolTip", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to A list of colors for each line. + /// + ///List<color>. + /// + public static string ChartsBasicLineChartColorsDataPortToolTip + { + get + { + return ResourceManager.GetString("ChartsBasicLineChartColorsDataPortToolTip", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Dictionary containing label:value key-pairs + /// + ///Dictionary<string, List<double>>. + /// + public static string ChartsBasicLineChartLabelsValuesDataPortToolTip + { + get { + return ResourceManager.GetString("ChartsBasicLineChartLabelsValuesDataPortToolTip", resourceCulture); + } + } /// /// Looks up a localized string similar to Create a new Basic Line Chart. @@ -95,7 +167,55 @@ public static string ChartsBasicLineChartSearchTags { return ResourceManager.GetString("ChartsBasicLineChartSearchTags", resourceCulture); } } + + /// + /// Looks up a localized string similar to A list of string labels for each line to be plotted. + /// + ///List<string>. + /// + public static string ChartsBasicLineChartLabelsDataPortToolTip + { + get + { + return ResourceManager.GetString("ChartsBasicLineChartLabelsDataPortToolTip", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to List of lists each containing double values to be plotted against X-Axis values. + /// + ///List<List<double>>. + /// + public static string ChartsBasicLineChartValuesDataPortToolTip { + get { + return ResourceManager.GetString("ChartsBasicLineChartValuesDataPortToolTip", resourceCulture); + } + } + /// + /// Looks up a localized string similar to A list of colors for each bar chart category. + /// + ///List<color>. + /// + public static string ChartsHeatSeriesColorsDataPortToolTip { + get { + return ResourceManager.GetString("ChartsHeatSeriesColorsDataPortToolTip", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Dictionary containing label:value key-pairs + /// + ///Dictionary<string, Dictionary<string, double>> + /// + public static string ChartsHeatSeriesLabelsValuesDataPortToolTip + { + get + { + return ResourceManager.GetString("ChartsHeatSeriesLabelsValuesDataPortToolTip", resourceCulture); + } + } + /// /// Looks up a localized string similar to Create a heat series plot. /// @@ -114,6 +234,50 @@ public static string ChartsHeatSeriesSearchTags { } } + /// + /// Looks up a localized string similar to A list of lists each containing double values representing items in a column. + /// + ///List<List<double>>. + /// + public static string ChartsHeatSeriesValuesDataPortToolTip { + get { + return ResourceManager.GetString("ChartsHeatSeriesValuesDataPortToolTip", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to A list of string labels for the x-axis. + /// + ///List<string>. + /// + public static string ChartsHeatSeriesXLabelsDataPortToolTip { + get { + return ResourceManager.GetString("ChartsHeatSeriesXLabelsDataPortToolTip", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to A list of string labels for the y-axis. + /// + ///List<string>. + /// + public static string ChartsHeatSeriesYLabelsDataPortToolTip { + get { + return ResourceManager.GetString("ChartsHeatSeriesYLabelsDataPortToolTip", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to A list of colors for each segment of the pie chart. + /// + ///List<color>. + /// + public static string ChartsPieChartColorsDataPortToolTip { + get { + return ResourceManager.GetString("ChartsPieChartColorsDataPortToolTip", resourceCulture); + } + } + /// /// Looks up a localized string similar to Create a new Pie Chart. /// @@ -132,6 +296,67 @@ public static string ChartsPieChartSearchTags { } } + /// + /// Looks up a localized string similar to A list of double values to supply a value for each segment of the pie chart. + /// + ///List<double>. + /// + public static string ChartsPieChartValuesDataPortToolTip { + get { + return ResourceManager.GetString("ChartsPieChartValuesDataPortToolTip", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to A list of string labels for each segment in the pie chart. + /// + ///List<string>. + /// + public static string ChartsPieChartLabelsDataPortToolTip + { + get + { + return ResourceManager.GetString("ChartsPieChartLabelsDataPortToolTip", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Dictionary containing label:value key-pairs + /// + ///Dictionary<string, double>. + /// + public static string ChartsPieChartLabelsValuesDataPortToolTip + { + get + { + return ResourceManager.GetString("ChartsPieChartLabelsValuesDataPortToolTip", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to A list of colors for each group of points. + /// + ///List<color>. + /// + public static string ChartsScatterPlotColorsDataPortToolTip { + get { + return ResourceManager.GetString("ChartsScatterPlotColorsDataPortToolTip", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Dictionary containing label:value key-pairs + /// + ///Dictionary<string, List<List<double>>>. + /// + public static string ChartsScatterPlotLabelsValuesDataPortToolTip + { + get + { + return ResourceManager.GetString("ChartsScatterPlotLabelsValuesDataPortToolTip", resourceCulture); + } + } + /// /// Looks up a localized string similar to Create a scatter plot. /// @@ -149,7 +374,66 @@ public static string ChartsScatterPlotSearchTags { return ResourceManager.GetString("ChartsScatterPlotSearchTags", resourceCulture); } } + + /// + /// Looks up a localized string similar to A list of string labels for each group of points to be plotted. + /// + ///List<string>.; + /// + public static string ChartsScatterPlotLabelsDataPortToolTip + { + get + { + return ResourceManager.GetString("ChartsScatterPlotLabelsDataPortToolTip", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to A list of lists each containing double values representing x-coordinates. + /// + ///List<List<double>>. + /// + public static string ChartsScatterPlotXLabelsDataPortToolTip { + get { + return ResourceManager.GetString("ChartsScatterPlotXLabelsDataPortToolTip", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to A list of lists each containing double values representing y-coordinates. + /// + ///List<List<double>>. + /// + public static string ChartsScatterPlotYLabelsDataPortToolTip { + get { + return ResourceManager.GetString("ChartsScatterPlotYLabelsDataPortToolTip", resourceCulture); + } + } + /// + /// Looks up a localized string similar to A list of colors for each line in the line plot. + /// + ///List<color>. + /// + public static string ChartsXYLineChartColorsDataPortToolTip { + get { + return ResourceManager.GetString("ChartsXYLineChartColorsDataPortToolTip", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Dictionary containing label:value key-pairs + /// + ///Dictionary<string, List<List<double>>>. + /// + public static string ChartsXYLineChartLabelsValuesDataPortToolTip + { + get + { + return ResourceManager.GetString("ChartsXYLineChartColorsDataPortToolTip", resourceCulture); + } + } + /// /// Looks up a localized string similar to Create a new XY line plot. /// @@ -167,6 +451,41 @@ public static string ChartsXYLineChartSearchTags { return ResourceManager.GetString("ChartsXYLineChartSearchTags", resourceCulture); } } + + /// + /// Looks up a localized string similar to A list of string labels for each line to be plotted + /// + ///List<string> + /// + public static string ChartsXYLineChartLabelsDataPortToolTip + { + get + { + return ResourceManager.GetString("ChartsXYLineChartLabelsDataPortToolTip", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to A list of lists each containing double values representing x-coordinates for each point in a line. + /// + ///List<List<double>>. + /// + public static string ChartsXYLineChartXLabelsDataPortToolTip { + get { + return ResourceManager.GetString("ChartsXYLineChartXLabelsDataPortToolTip", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to A list of lists each containing double values representing x-coordinates for each point in a line. + /// + ///List<List<double>>. + /// + public static string ChartsXYLineChartYLabelsDataPortToolTip { + get { + return ResourceManager.GetString("ChartsXYLineChartYLabelsDataPortToolTip", resourceCulture); + } + } /// /// Looks up a localized string similar to Advanced. diff --git a/src/Libraries/CoreNodeModelsWpf/Properties/CoreNodeModelWpfResources.en-US.resx b/src/Libraries/CoreNodeModelsWpf/Properties/CoreNodeModelWpfResources.en-US.resx index abe78c99d18..40c96277d06 100644 --- a/src/Libraries/CoreNodeModelsWpf/Properties/CoreNodeModelWpfResources.en-US.resx +++ b/src/Libraries/CoreNodeModelsWpf/Properties/CoreNodeModelWpfResources.en-US.resx @@ -123,61 +123,196 @@ bar;barchart + + A list of labels for the bar chart categories. + +List<string> + + + A list (of lists) to supply values for the bars in each category. + +List<var> + + + A list of colors for each bar chart category. + +List<color> + + + Dictionary containing label:value key-pairs + +Dictionary<string, double> + Create a new Basic Line Chart index;indexvalue;indexvaluelineplot + + A list of string labels for each line to be plotted. + +List<string> + + + List of lists each containing double values to be plotted against X-Axis values. + +List<List<double>> + + + A list of colors for each line. + +List<color> + + + Dictionary containing label:value key-pairs + +Dictionary<string, List<double>> + Create a heat series plot heat;heatseries;heatseriesplot - + + A list of string labels for the x-axis. + +List<string> + + + A list of string labels for the y-axis. + +List<string> + + + A list of lists each containing double values representing items in a column. + +List<List<double>> + + + A list of colors for each bar chart category. + +List<color> + + + Dictionary containing label:value key-pairs + +Dictionary<string, Dictionary<string, double>> + + Create a new Pie Chart - + pie;piechart - + + A list of string labels for each segment in the pie chart. + +List<string> + + + A list of double values to supply a value for each segment of the pie chart. + +List<double> + + + A list of colors for each segment of the pie chart. + +List<color> + + + Dictionary containing label:value key-pairs + +Dictionary<string, double> + + Create a scatter plot - + scatter;scatterplot - + + A list of string labels for each group of points to be plotted. + +List<string> + + + A list of lists each containing double values representing x-coordinates. + +List<List<double>> + + + A list of lists each containing double values representing y-coordinates. + +List<List<double>> + + + A list of colors for each group of points. + +List<color> + + + Dictionary containing label:value key-pairs + +Dictionary<string, List<List<double>>> + + Create a new XY line plot - + lineplot;xylineplot - + + A list of string labels for each line to be plotted + +List<string> + + + A list of lists each containing double values representing x-coordinates for each point in a line. + +List<List<double>> + + + A list of lists each containing double values representing x-coordinates for each point in a line. + +List<List<double>> + + + A list of colors for each line in the line plot. + +List<color> + + + Dictionary containing label:value key-pairs + +Dictionary<string, List<List<double>>> + + Advanced - + Recent Colors - + Standard - + Standard Colors - + Enter time and date in the format 'MMMM dd, yyyy h:mm tt' - + Display - + Value - + Default colors are used. To define custom colors, provide an equal number of colors and labels inputs. - + Drag to modify the size of the chart diff --git a/src/Libraries/CoreNodeModelsWpf/Properties/CoreNodeModelWpfResources.resx b/src/Libraries/CoreNodeModelsWpf/Properties/CoreNodeModelWpfResources.resx index abe78c99d18..f436f098a9b 100644 --- a/src/Libraries/CoreNodeModelsWpf/Properties/CoreNodeModelWpfResources.resx +++ b/src/Libraries/CoreNodeModelsWpf/Properties/CoreNodeModelWpfResources.resx @@ -123,36 +123,171 @@ bar;barchart + + A list of labels for the bar chart categories. + +List<string> + + + A list (of lists) to supply values for the bars in each category. + +List<var> + + + A list of colors for each bar chart category. + +List<color> + + + Dictionary containing label:value key-pairs + +Dictionary<string, double> + Create a new Basic Line Chart index;indexvalue;indexvaluelineplot + + A list of string labels for each line to be plotted. + +List<string> + + + List of lists each containing double values to be plotted against X-Axis values. + +List<List<double>> + + + A list of colors for each line. + +List<color> + + + Dictionary containing label:value key-pairs + +Dictionary<string, List<double>> + Create a heat series plot heat;heatseries;heatseriesplot + + A list of string labels for the x-axis. + +List<string> + + + A list of string labels for the y-axis. + +List<string> + + + A list of lists each containing double values representing items in a column. + +List<List<double>> + + + A list of colors for each bar chart category. + +List<color> + + + Dictionary containing label:value key-pairs + +Dictionary<string, Dictionary<string, double>> + Create a new Pie Chart pie;piechart + + A list of string labels for each segment in the pie chart. + +List<string> + + + A list of double values to supply a value for each segment of the pie chart. + +List<double> + + + A list of colors for each segment of the pie chart. + +List<color> + + + Dictionary containing label:value key-pairs + +Dictionary<string, double> + Create a scatter plot scatter;scatterplot + + A list of string labels for each group of points to be plotted. + +List<string> + + + A list of lists each containing double values representing x-coordinates. + +List<List<double>> + + + A list of lists each containing double values representing y-coordinates. + +List<List<double>> + + + A list of colors for each group of points. + +List<color> + + + Dictionary containing label:value key-pairs + +Dictionary<string, List<List<double>>> + Create a new XY line plot lineplot;xylineplot + + A list of string labels for each line to be plotted + +List<string> + + + A list of lists each containing double values representing x-coordinates for each point in a line. + +List<List<double>> + + + A list of lists each containing double values representing x-coordinates for each point in a line. + +List<List<double>> + + + A list of colors for each line in the line plot. + +List<color> + + + Dictionary containing label:value key-pairs + +Dictionary<string, List<List<double>>> + Advanced @@ -180,4 +315,4 @@ Drag to modify the size of the chart - + \ No newline at end of file diff --git a/src/Libraries/CoreNodes/ChartHelpers/BarChartFunctions.cs b/src/Libraries/CoreNodes/ChartHelpers/BarChartFunctions.cs index de93f18b7cb..7b517d7fa1a 100644 --- a/src/Libraries/CoreNodes/ChartHelpers/BarChartFunctions.cs +++ b/src/Libraries/CoreNodes/ChartHelpers/BarChartFunctions.cs @@ -9,13 +9,32 @@ namespace CoreNodes.ChartHelpers { public class BarChartFunctions { - private BarChartFunctions() { } + private static List defaultLabels = new List { "2019", "2020", "2021" }; + + private static List defaultValues = new List { 5.0, 6.0, 7.0, 8.0 }; + + private static List> defaultNestedValues = new List> { + new List { 5.0, 6.0, 7.0, 8.0 }, + new List { 10.0, 12.0, 14.0, 16.0 }, + new List { 15.0, 18.0, 12.0, 24.0 } }; + private BarChartFunctions() { } + [IsVisibleInDynamoLibrary(false)] public static Dictionary> GetNodeInput(List labels, List> values, List colors) { var output = new Dictionary>(); + if (labels == null || values == null) + { + for (var i = 0; i < defaultLabels.Count; i++) + { + output.Add(defaultLabels[i], defaultNestedValues[i]); + } + + return output; + } + if (labels.Count != values.Count) { return output; @@ -34,6 +53,16 @@ public static Dictionary GetNodeInput(List labels, List< { var output = new Dictionary(); + if (labels == null || values == null) + { + for (var i = 0; i < defaultLabels.Count; i++) + { + output.Add(defaultLabels[i], defaultValues[i]); + } + + return output; + } + if (labels.Count != values.Count) { return output; @@ -46,5 +75,18 @@ public static Dictionary GetNodeInput(List labels, List< return output; } + + [IsVisibleInDynamoLibrary(false)] + public static Dictionary GetDefaultNodeInput() + { + var output = new Dictionary(); + + for (var i = 0; i < defaultLabels.Count; i++) + { + output.Add(defaultLabels[i], defaultValues[i]); + } + + return output; + } } } diff --git a/src/Libraries/CoreNodes/ChartHelpers/BasicLineChartFunctions.cs b/src/Libraries/CoreNodes/ChartHelpers/BasicLineChartFunctions.cs index a6df0247b21..c3fe779813b 100644 --- a/src/Libraries/CoreNodes/ChartHelpers/BasicLineChartFunctions.cs +++ b/src/Libraries/CoreNodes/ChartHelpers/BasicLineChartFunctions.cs @@ -9,6 +9,13 @@ namespace CoreNodes.ChartHelpers { public class BasicLineChartFunctions { + private static List defaultLabels = new List { "Series 1", "Series 2", "Series 3" }; + + private static List> defaultNestedValues = new List> { + new List { 4, 6, 5, 2, 4 }, + new List { 6, 7, 3, 4, 6 }, + new List { 4, 2, 7, 2, 7 } }; + private BasicLineChartFunctions() { } [IsVisibleInDynamoLibrary(false)] @@ -16,6 +23,16 @@ public static Dictionary> GetNodeInput(List titles, { var output = new Dictionary>(); + if (titles == null || values == null) + { + for (var i = 0; i < defaultLabels.Count; i++) + { + output.Add(defaultLabels[i], defaultNestedValues[i]); + } + + return output; + } + if (titles.Count != values.Count) { return output; diff --git a/src/Libraries/CoreNodes/ChartHelpers/HeatSeriesFunctions.cs b/src/Libraries/CoreNodes/ChartHelpers/HeatSeriesFunctions.cs index b14313985f1..3a133f68196 100644 --- a/src/Libraries/CoreNodes/ChartHelpers/HeatSeriesFunctions.cs +++ b/src/Libraries/CoreNodes/ChartHelpers/HeatSeriesFunctions.cs @@ -9,21 +9,56 @@ namespace CoreNodes.ChartHelpers { public class HeatSeriesFunctions { + private static Random rnd = new Random(); + private static List defaultLabelsX = new List { "Item-1", "Item-2", "Item-3", "Item-4", "Item-5" }; + private static List defaultLabelsY = new List + { + "Monday", + "Tuesday", + "Wednesday", + "Thursday", + "Friday", + "Saturday", + "Sunday" + }; + + private HeatSeriesFunctions() { } [IsVisibleInDynamoLibrary(false)] - public static Dictionary> GetNodeInput(List xLabels, List yLabels, List> values, List colors) + public static Dictionary> GetNodeInput(List xLabels, List yLabels, List> values, List colors) { + var output = new Dictionary>(); + + if (xLabels == null || yLabels == null || values == null) + { + for (var i = 0; i < defaultLabelsX.Count; i++) + { + var inner = new Dictionary(); + for (var j = 0; j < defaultLabelsY.Count; j++) + { + inner.Add(defaultLabelsY[j], rnd.Next(0, 10)); + } + output.Add(defaultLabelsX[i], inner); + + } + + return output; + } + if (xLabels.Count != values.Count && xLabels.Count > 0) { return null; } - var output = new Dictionary>(); - for (var i = 0; i < xLabels.Count; i++) { - output.Add(xLabels[i], values[i]); + var inner = new Dictionary(); + for (var j = 0; j < yLabels.Count; j++) + { + inner.Add(yLabels[j], values[i][j]); + } + output.Add(xLabels[i], inner); } return output; diff --git a/src/Libraries/CoreNodes/ChartHelpers/PieChartFunctions.cs b/src/Libraries/CoreNodes/ChartHelpers/PieChartFunctions.cs index 129d1176188..d9f4585db32 100644 --- a/src/Libraries/CoreNodes/ChartHelpers/PieChartFunctions.cs +++ b/src/Libraries/CoreNodes/ChartHelpers/PieChartFunctions.cs @@ -9,16 +9,29 @@ namespace CoreNodes.ChartHelpers { public class PieChartFunctions { + private static List defaultLabels = new List { "Item1", "Item2", "Item3" }; + private static List defaultValues = new List { 100, 100, 100 }; private PieChartFunctions() { } [IsVisibleInDynamoLibrary(false)] - public static Dictionary GetNodeInput(List labels, List values, + public static Dictionary GetNodeInput(List labels, + List values, List colors) { var output = new Dictionary(); + if(labels == null || values == null) + { + for (var i = 0; i < defaultLabels.Count; i++) + { + output.Add(defaultLabels[i], defaultValues[i]); + } + + return output; + } + if (labels.Count != values.Count) { return output; diff --git a/src/Libraries/CoreNodes/ChartHelpers/ScatterPlotFunctions.cs b/src/Libraries/CoreNodes/ChartHelpers/ScatterPlotFunctions.cs index 94901a182f5..eafb1f3d303 100644 --- a/src/Libraries/CoreNodes/ChartHelpers/ScatterPlotFunctions.cs +++ b/src/Libraries/CoreNodes/ChartHelpers/ScatterPlotFunctions.cs @@ -9,12 +9,34 @@ namespace CoreNodes.ChartHelpers { public class ScatterPlotFunctions { + private static Random rnd = new Random(); + private static List defaultTitles = new List { "Plot 1", "Plot 2", "Plot 3" }; + private ScatterPlotFunctions() { } [IsVisibleInDynamoLibrary(false)] - public static Dictionary>> GetNodeInput(List titles, List> xValues, List> yValues, List colors) + public static Dictionary>> GetNodeInput(List titles, List> xValues, List> yValues, List colors) { - var output = new Dictionary>>(); + var output = new Dictionary>>(); + + if (titles == null || xValues == null || yValues == null) + { + var listX = new List>(); + var listY = new List>(); + for (var i = 0; i < defaultTitles.Count; i++) + { + listX.Add(GenerateRandomValuesList(20)); + listY.Add(GenerateRandomValuesList(20)); + } + + for (var i = 0; i < defaultTitles.Count; i++) + { + var combined = new List> { listX[i], listY[i] }; + output.Add(defaultTitles[i], combined); + } + + return output; + } if (titles.Count != xValues.Count || xValues.Count != yValues.Count) { @@ -23,13 +45,24 @@ public static Dictionary>> GetNodeInput( for (var i = 0; i < titles.Count; i++) { - var coordinates = new Dictionary>(); - coordinates.Add("X", xValues[i]); - coordinates.Add("Y", yValues[i]); - output.Add(titles[i], coordinates); + var combined = new List> { xValues[i], yValues[i] }; + + output.Add(titles[i], combined); } return output; } + + private static List GenerateRandomValuesList(int count) + { + List values = new List(); + + for (int i = 0; i < count; i++) + { + values.Add(rnd.NextDouble() * 10); + } + + return values; + } } } diff --git a/src/Libraries/CoreNodes/ChartHelpers/XYLineChartFunctions.cs b/src/Libraries/CoreNodes/ChartHelpers/XYLineChartFunctions.cs index 2dac51af106..8f9ecc04218 100644 --- a/src/Libraries/CoreNodes/ChartHelpers/XYLineChartFunctions.cs +++ b/src/Libraries/CoreNodes/ChartHelpers/XYLineChartFunctions.cs @@ -9,12 +9,45 @@ namespace CoreNodes.ChartHelpers { public class XYLineChartFunctions { + private static List defaultTitles = new List { "Plot 1", "Plot 2", "Plot 3" }; + private static double[][] defaultXValues = new double[][] + { + new double[]{ 0, 1, 2, 3 }, + new double[]{ 0, 1, 2, 3 }, + new double[]{ 0, 1, 2, 3 } + }; + + private static double[][] defaultYValues = new double[][] + { + new double[]{ 0, 1, 2, 3 }, + new double[]{ 1, 2, 3, 4 }, + new double[]{ 2, 3, 4, 5 } + }; private XYLineChartFunctions() { } [IsVisibleInDynamoLibrary(false)] - public static Dictionary>> GetNodeInput(List titles, List> xValues, List> yValues, List colors) + public static Dictionary>> GetNodeInput(List titles, List> xValues, List> yValues, List colors) { - var output = new Dictionary>>(); + var output = new Dictionary>>(); + + if (titles == null || xValues == null || yValues == null) + { + var listX = new List>(); + var listY = new List>(); + for (var i = 0; i < defaultTitles.Count; i++) + { + listX.Add(defaultXValues[i].ToList()); + listY.Add(defaultYValues[i].ToList()); + } + + for (var i = 0; i < defaultTitles.Count; i++) + { + var combined = new List> { listX[i], listY[i] }; + output.Add(defaultTitles[i], combined); + } + + return output; + } if (titles.Count != xValues.Count || xValues.Count != yValues.Count) { @@ -23,12 +56,11 @@ public static Dictionary>> GetNodeInput( for (var i = 0; i < titles.Count; i++) { - var coordinates = new Dictionary>(); - coordinates.Add("X", xValues[i]); - coordinates.Add("Y", yValues[i]); - output.Add(titles[i], coordinates); - } + var combined = new List> { xValues[i], yValues[i] }; + output.Add(titles[i], combined); + } + return output; } } diff --git a/test/DynamoCoreWpfTests/LiveChartsTests.cs b/test/DynamoCoreWpfTests/LiveChartsTests.cs index 16a5fe6aa25..ad38c5e62bd 100644 --- a/test/DynamoCoreWpfTests/LiveChartsTests.cs +++ b/test/DynamoCoreWpfTests/LiveChartsTests.cs @@ -7,12 +7,23 @@ using CoreNodeModelsWpf.Charts; using Dynamo.Graph.Nodes; using DynCmd = Dynamo.Models.DynamoModel; +using System.Collections.Generic; namespace DynamoCoreWpfTests { [TestFixture] class LiveChartsTests : SystemTestBase { + protected override void GetLibrariesToPreload(List libraries) + { + libraries.Add("VMDataBridge.dll"); + libraries.Add("LiveCharts.dll"); + libraries.Add("DesignScriptBuiltin.dll"); + libraries.Add("DSCoreNodes.dll"); + + base.GetLibrariesToPreload(libraries); + } + private CodeBlockNodeModel CreateCodeBlockNode() { var cbn = new CodeBlockNodeModel(this.Model.LibraryServices); @@ -36,11 +47,15 @@ public void LiveChartsBarChartCreationTest() var homespace = Model.CurrentWorkspace as HomeWorkspaceModel; Assert.NotNull(homespace, "The current workspace is not a HomeWorkspaceModel"); + // Create a default chart model var chart = new BarChartNodeModel(); Model.AddNodeToCurrentWorkspace(chart, true); homespace.Run(); + Assert.DoesNotThrow(DispatcherUtil.DoEvents); Assert.AreEqual(1, homespace.Nodes.Count()); + Assert.AreEqual(0, homespace.Connectors.Count()); + Assert.AreEqual(ElementState.Dead, chart.State); string codeA = "[\"January\", \"February\", \"March\"];"; string codeB = "[[4, 12, 34],[14, 22, 14],[15, 3, 6]];"; @@ -51,12 +66,39 @@ public void LiveChartsBarChartCreationTest() UpdateCodeBlockNodeContent(codeBlockNodeA, @codeA); UpdateCodeBlockNodeContent(codeBlockNodeB, @codeB); - new Dynamo.Graph.Connectors.ConnectorModel(codeBlockNodeA.OutPorts.FirstOrDefault(), chart.InPorts[0], Guid.NewGuid()); - new Dynamo.Graph.Connectors.ConnectorModel(codeBlockNodeB.OutPorts.FirstOrDefault(), chart.InPorts[1], Guid.NewGuid()); + // Default values + var cA = new Dynamo.Graph.Connectors.ConnectorModel(codeBlockNodeA.OutPorts.FirstOrDefault(), chart.InPorts[0], Guid.NewGuid()); + var cB = new Dynamo.Graph.Connectors.ConnectorModel(codeBlockNodeB.OutPorts.FirstOrDefault(), chart.InPorts[1], Guid.NewGuid()); homespace.Run(); Assert.DoesNotThrow(DispatcherUtil.DoEvents); Assert.AreEqual(2, homespace.Connectors.Count()); + Assert.AreEqual(ElementState.Info, chart.State); + + string codeD = "a = Color.ByARGB(255, 255, 255, 255);" + + "\r\nb = Color.ByARGB(255, 255, 255, 255);" + + "\r\nc = Color.ByARGB(255, 255, 255, 255);" + + "\r\nt1 = [a, b, c];"; + + var codeBlockNodeD = CreateCodeBlockNode(); + UpdateCodeBlockNodeContent(codeBlockNodeD, @codeD); + + // Fully working node + var cC = new Dynamo.Graph.Connectors.ConnectorModel(codeBlockNodeD.OutPorts.FirstOrDefault(), chart.InPorts[2], Guid.NewGuid()); + + homespace.Run(); + Assert.DoesNotThrow(DispatcherUtil.DoEvents); + Assert.AreEqual(3, homespace.Connectors.Count()); + Assert.AreEqual(ElementState.Active, chart.State); + + // Wrong input types + homespace.ClearConnector(cA); + cA = new Dynamo.Graph.Connectors.ConnectorModel(codeBlockNodeB.OutPorts.FirstOrDefault(), chart.InPorts[0], Guid.NewGuid()); + + homespace.Run(); + Assert.DoesNotThrow(DispatcherUtil.DoEvents); + Assert.AreEqual(3, homespace.Connectors.Count()); + Assert.AreEqual(ElementState.Warning, chart.State); } [Test] @@ -65,11 +107,15 @@ public void LiveChartsBasicLineChartCreationTest() var homespace = Model.CurrentWorkspace as HomeWorkspaceModel; Assert.NotNull(homespace, "The current workspace is not a HomeWorkspaceModel"); + // Create a default chart model var chart = new BasicLineChartNodeModel(); Model.AddNodeToCurrentWorkspace(chart, true); homespace.Run(); + Assert.DoesNotThrow(DispatcherUtil.DoEvents); Assert.AreEqual(1, homespace.Nodes.Count()); + Assert.AreEqual(0, homespace.Connectors.Count()); + Assert.AreEqual(ElementState.Dead, chart.State); string codeA = "[\"January\", \"February\", \"March\"];"; string codeB = "[[2,53,14,45,6],[22,41,45,61,21],[34,51,34,65,2]];"; @@ -80,12 +126,39 @@ public void LiveChartsBasicLineChartCreationTest() UpdateCodeBlockNodeContent(codeBlockNodeA, @codeA); UpdateCodeBlockNodeContent(codeBlockNodeB, @codeB); - new Dynamo.Graph.Connectors.ConnectorModel(codeBlockNodeA.OutPorts.FirstOrDefault(), chart.InPorts[0], Guid.NewGuid()); - new Dynamo.Graph.Connectors.ConnectorModel(codeBlockNodeB.OutPorts.FirstOrDefault(), chart.InPorts[1], Guid.NewGuid()); + // Default values + var cA = new Dynamo.Graph.Connectors.ConnectorModel(codeBlockNodeA.OutPorts.FirstOrDefault(), chart.InPorts[0], Guid.NewGuid()); + var cB = new Dynamo.Graph.Connectors.ConnectorModel(codeBlockNodeB.OutPorts.FirstOrDefault(), chart.InPorts[1], Guid.NewGuid()); homespace.Run(); Assert.DoesNotThrow(DispatcherUtil.DoEvents); Assert.AreEqual(2, homespace.Connectors.Count()); + Assert.AreEqual(ElementState.Info, chart.State); + + string codeD = "a = Color.ByARGB(255, 255, 255, 255);" + + "\r\nb = Color.ByARGB(255, 255, 255, 255);" + + "\r\nc = Color.ByARGB(255, 255, 255, 255);" + + "\r\nt1 = [a, b, c];"; + + var codeBlockNodeD = CreateCodeBlockNode(); + UpdateCodeBlockNodeContent(codeBlockNodeD, @codeD); + + // Fully working node + var cC = new Dynamo.Graph.Connectors.ConnectorModel(codeBlockNodeD.OutPorts.FirstOrDefault(), chart.InPorts[2], Guid.NewGuid()); + + homespace.Run(); + Assert.DoesNotThrow(DispatcherUtil.DoEvents); + Assert.AreEqual(3, homespace.Connectors.Count()); + Assert.AreEqual(ElementState.Active, chart.State); + + // Wrong input types + homespace.ClearConnector(cA); + cA = new Dynamo.Graph.Connectors.ConnectorModel(codeBlockNodeB.OutPorts.FirstOrDefault(), chart.InPorts[0], Guid.NewGuid()); + + homespace.Run(); + Assert.DoesNotThrow(DispatcherUtil.DoEvents); + Assert.AreEqual(3, homespace.Connectors.Count()); + Assert.AreEqual(ElementState.Warning, chart.State); } [Test] @@ -94,17 +167,21 @@ public void LiveChartsHeatSeriesCreationTest() var homespace = Model.CurrentWorkspace as HomeWorkspaceModel; Assert.NotNull(homespace, "The current workspace is not a HomeWorkspaceModel"); + // Create a default chart model var chart = new HeatSeriesNodeModel(); Model.AddNodeToCurrentWorkspace(chart, true); + homespace.Run(); Assert.DoesNotThrow(DispatcherUtil.DoEvents); Assert.AreEqual(1, homespace.Nodes.Count()); + Assert.AreEqual(0, homespace.Connectors.Count()); + Assert.AreEqual(ElementState.Dead, chart.State); string codeA = "[\"Item 1\",\"Item 2\",\"Item 3\",\"Item 4\",\"Item 5\",\"Item 6\"];"; string codeB = "[\"January\",\"February\",\"March\",\"April\",\"May\",\"June\"];"; string codeC = "[[1,2,3,4,2,1],[-12,12,4,-61,45,88],[4,4,5,5,16,-6],[-74,37,83,-262,54,44],[232,133,444,323,414,231],[332,122,98,89,89,78]];"; - //This create a new Code Block node and update the content + // This create a new Code Block node and update the content var codeBlockNodeA = CreateCodeBlockNode(); var codeBlockNodeB = CreateCodeBlockNode(); var codeBlockNodeC = CreateCodeBlockNode(); @@ -112,13 +189,43 @@ public void LiveChartsHeatSeriesCreationTest() UpdateCodeBlockNodeContent(codeBlockNodeB, @codeB); UpdateCodeBlockNodeContent(codeBlockNodeC, @codeC); - new Dynamo.Graph.Connectors.ConnectorModel(codeBlockNodeA.OutPorts.FirstOrDefault(), chart.InPorts[0], Guid.NewGuid()); - new Dynamo.Graph.Connectors.ConnectorModel(codeBlockNodeB.OutPorts.FirstOrDefault(), chart.InPorts[1], Guid.NewGuid()); - new Dynamo.Graph.Connectors.ConnectorModel(codeBlockNodeC.OutPorts.FirstOrDefault(), chart.InPorts[2], Guid.NewGuid()); + // Default values + var cA = new Dynamo.Graph.Connectors.ConnectorModel(codeBlockNodeA.OutPorts.FirstOrDefault(), chart.InPorts[0], Guid.NewGuid()); + var cB = new Dynamo.Graph.Connectors.ConnectorModel(codeBlockNodeB.OutPorts.FirstOrDefault(), chart.InPorts[1], Guid.NewGuid()); + var cC = new Dynamo.Graph.Connectors.ConnectorModel(codeBlockNodeC.OutPorts.FirstOrDefault(), chart.InPorts[2], Guid.NewGuid()); homespace.Run(); Assert.DoesNotThrow(DispatcherUtil.DoEvents); Assert.AreEqual(3, homespace.Connectors.Count()); + Assert.AreEqual(ElementState.Info, chart.State); + + string codeD = "a = Color.ByARGB(255, 255, 255, 255);" + + "\r\nb = Color.ByARGB(255, 255, 255, 255);" + + "\r\nc = Color.ByARGB(255, 255, 255, 255);" + + "\r\nd = Color.ByARGB(255, 255, 255, 255);" + + "\r\ne = Color.ByARGB(255, 255, 255, 255);" + + "\r\nf = Color.ByARGB(255, 255, 255, 255);" + + "\r\nt1 = [a, b, c, d, e, f];"; + + var codeBlockNodeD = CreateCodeBlockNode(); + UpdateCodeBlockNodeContent(codeBlockNodeD, @codeD); + + // Fully working node + var cD = new Dynamo.Graph.Connectors.ConnectorModel(codeBlockNodeD.OutPorts.FirstOrDefault(), chart.InPorts[3], Guid.NewGuid()); + + homespace.Run(); + Assert.DoesNotThrow(DispatcherUtil.DoEvents); + Assert.AreEqual(4, homespace.Connectors.Count()); + Assert.AreEqual(ElementState.Active, chart.State); + + // Wrong input types + homespace.ClearConnector(cC); + cC = new Dynamo.Graph.Connectors.ConnectorModel(codeBlockNodeB.OutPorts.FirstOrDefault(), chart.InPorts[2], Guid.NewGuid()); + + homespace.Run(); + Assert.DoesNotThrow(DispatcherUtil.DoEvents); + Assert.AreEqual(4, homespace.Connectors.Count()); + Assert.AreEqual(ElementState.Warning, chart.State); } [Test] @@ -127,11 +234,15 @@ public void LiveChartsPieChartCreationTest() var homespace = Model.CurrentWorkspace as HomeWorkspaceModel; Assert.NotNull(homespace, "The current workspace is not a HomeWorkspaceModel"); + // Create a default chart model var chart = new PieChartNodeModel(); Model.AddNodeToCurrentWorkspace(chart, true); + homespace.Run(); Assert.DoesNotThrow(DispatcherUtil.DoEvents); Assert.AreEqual(1, homespace.Nodes.Count()); + Assert.AreEqual(0, homespace.Connectors.Count()); + Assert.AreEqual(ElementState.Dead, chart.State); string codeA = "[\"January\", \"February\", \"March\"];"; string codeB = "[4, 12, 34];"; @@ -142,12 +253,39 @@ public void LiveChartsPieChartCreationTest() UpdateCodeBlockNodeContent(codeBlockNodeA, @codeA); UpdateCodeBlockNodeContent(codeBlockNodeB, @codeB); - new Dynamo.Graph.Connectors.ConnectorModel(codeBlockNodeA.OutPorts.FirstOrDefault(), chart.InPorts[0], Guid.NewGuid()); - new Dynamo.Graph.Connectors.ConnectorModel(codeBlockNodeB.OutPorts.FirstOrDefault(), chart.InPorts[1], Guid.NewGuid()); + // Default values + var cA = new Dynamo.Graph.Connectors.ConnectorModel(codeBlockNodeA.OutPorts.FirstOrDefault(), chart.InPorts[0], Guid.NewGuid()); + var cB = new Dynamo.Graph.Connectors.ConnectorModel(codeBlockNodeB.OutPorts.FirstOrDefault(), chart.InPorts[1], Guid.NewGuid()); homespace.Run(); Assert.DoesNotThrow(DispatcherUtil.DoEvents); Assert.AreEqual(2, homespace.Connectors.Count()); + Assert.AreEqual(ElementState.Info, chart.State); + + string codeD = "a = Color.ByARGB(255, 255, 255, 255);" + + "\r\nb = Color.ByARGB(255, 255, 255, 255);" + + "\r\nc = Color.ByARGB(255, 255, 255, 255);" + + "\r\nt1 = [a, b, c];"; + + var codeBlockNodeD = CreateCodeBlockNode(); + UpdateCodeBlockNodeContent(codeBlockNodeD, @codeD); + + // Fully working node + var cC = new Dynamo.Graph.Connectors.ConnectorModel(codeBlockNodeD.OutPorts.FirstOrDefault(), chart.InPorts[2], Guid.NewGuid()); + + homespace.Run(); + Assert.DoesNotThrow(DispatcherUtil.DoEvents); + Assert.AreEqual(3, homespace.Connectors.Count()); + Assert.AreEqual(ElementState.Active, chart.State); + + // Wrong input types + homespace.ClearConnector(cA); + cA = new Dynamo.Graph.Connectors.ConnectorModel(codeBlockNodeB.OutPorts.FirstOrDefault(), chart.InPorts[0], Guid.NewGuid()); + + homespace.Run(); + Assert.DoesNotThrow(DispatcherUtil.DoEvents); + Assert.AreEqual(3, homespace.Connectors.Count()); + Assert.AreEqual(ElementState.Warning, chart.State); } [Test] @@ -156,17 +294,21 @@ public void LiveChartsScatterPlotCreationTest() var homespace = Model.CurrentWorkspace as HomeWorkspaceModel; Assert.NotNull(homespace, "The current workspace is not a HomeWorkspaceModel"); + // Create a default chart model var chart = new ScatterPlotNodeModel(); Model.AddNodeToCurrentWorkspace(chart, true); + homespace.Run(); Assert.DoesNotThrow(DispatcherUtil.DoEvents); Assert.AreEqual(1, homespace.Nodes.Count()); + Assert.AreEqual(0, homespace.Connectors.Count()); + Assert.AreEqual(ElementState.Dead, chart.State); string codeA = "[\"January\", \"February\", \"March\"];"; string codeB = "[[70,20,10],[12,24,44],[35,5,16]];"; string codeC = "[[30,50,40],[60,40,-13],[62,-3,28]];"; - //This create a new Code Block node and update the content + // This create a new Code Block node and update the content var codeBlockNodeA = CreateCodeBlockNode(); var codeBlockNodeB = CreateCodeBlockNode(); var codeBlockNodeC = CreateCodeBlockNode(); @@ -174,13 +316,40 @@ public void LiveChartsScatterPlotCreationTest() UpdateCodeBlockNodeContent(codeBlockNodeB, @codeB); UpdateCodeBlockNodeContent(codeBlockNodeC, @codeC); - new Dynamo.Graph.Connectors.ConnectorModel(codeBlockNodeA.OutPorts.FirstOrDefault(), chart.InPorts[0], Guid.NewGuid()); - new Dynamo.Graph.Connectors.ConnectorModel(codeBlockNodeB.OutPorts.FirstOrDefault(), chart.InPorts[1], Guid.NewGuid()); - new Dynamo.Graph.Connectors.ConnectorModel(codeBlockNodeC.OutPorts.FirstOrDefault(), chart.InPorts[2], Guid.NewGuid()); + // Default values + var cA = new Dynamo.Graph.Connectors.ConnectorModel(codeBlockNodeA.OutPorts.FirstOrDefault(), chart.InPorts[0], Guid.NewGuid()); + var cB = new Dynamo.Graph.Connectors.ConnectorModel(codeBlockNodeB.OutPorts.FirstOrDefault(), chart.InPorts[1], Guid.NewGuid()); + var cC = new Dynamo.Graph.Connectors.ConnectorModel(codeBlockNodeC.OutPorts.FirstOrDefault(), chart.InPorts[2], Guid.NewGuid()); homespace.Run(); Assert.DoesNotThrow(DispatcherUtil.DoEvents); Assert.AreEqual(3, homespace.Connectors.Count()); + Assert.AreEqual(ElementState.Info, chart.State); + + string codeD = "a = Color.ByARGB(255, 255, 255, 255);" + + "\r\nb = Color.ByARGB(255, 255, 255, 255);" + + "\r\nc = Color.ByARGB(255, 255, 255, 255);" + + "\r\nt1 = [a, b, c];"; + + var codeBlockNodeD = CreateCodeBlockNode(); + UpdateCodeBlockNodeContent(codeBlockNodeD, @codeD); + + // Fully working node + var cD = new Dynamo.Graph.Connectors.ConnectorModel(codeBlockNodeD.OutPorts.FirstOrDefault(), chart.InPorts[3], Guid.NewGuid()); + + homespace.Run(); + Assert.DoesNotThrow(DispatcherUtil.DoEvents); + Assert.AreEqual(4, homespace.Connectors.Count()); + Assert.AreEqual(ElementState.Active, chart.State); + + // Wrong input types + homespace.ClearConnector(cA); + cA = new Dynamo.Graph.Connectors.ConnectorModel(codeBlockNodeB.OutPorts.FirstOrDefault(), chart.InPorts[0], Guid.NewGuid()); + + homespace.Run(); + Assert.DoesNotThrow(DispatcherUtil.DoEvents); + Assert.AreEqual(4, homespace.Connectors.Count()); + Assert.AreEqual(ElementState.Warning, chart.State); } [Test] @@ -189,17 +358,21 @@ public void LiveChartsXYLineChartCreationTest() var homespace = Model.CurrentWorkspace as HomeWorkspaceModel; Assert.NotNull(homespace, "The current workspace is not a HomeWorkspaceModel"); + // Create a default chart model var chart = new XYLineChartNodeModel(); Model.AddNodeToCurrentWorkspace(chart, true); + homespace.Run(); Assert.DoesNotThrow(DispatcherUtil.DoEvents); Assert.AreEqual(1, homespace.Nodes.Count()); + Assert.AreEqual(0, homespace.Connectors.Count()); + Assert.AreEqual(ElementState.Dead, chart.State); string codeA = "[\"January\", \"February\", \"March\"];"; string codeB = "[[5,20,50],[12,24,44],[15,25,56]];"; string codeC = "[[30,50,140],[160,40,43],[54,25,54]];"; - //This create a new Code Block node and update the content + // This create a new Code Block node and update the content var codeBlockNodeA = CreateCodeBlockNode(); var codeBlockNodeB = CreateCodeBlockNode(); var codeBlockNodeC = CreateCodeBlockNode(); @@ -207,13 +380,41 @@ public void LiveChartsXYLineChartCreationTest() UpdateCodeBlockNodeContent(codeBlockNodeB, @codeB); UpdateCodeBlockNodeContent(codeBlockNodeC, @codeC); - new Dynamo.Graph.Connectors.ConnectorModel(codeBlockNodeA.OutPorts.FirstOrDefault(), chart.InPorts[0], Guid.NewGuid()); - new Dynamo.Graph.Connectors.ConnectorModel(codeBlockNodeB.OutPorts.FirstOrDefault(), chart.InPorts[1], Guid.NewGuid()); - new Dynamo.Graph.Connectors.ConnectorModel(codeBlockNodeC.OutPorts.FirstOrDefault(), chart.InPorts[2], Guid.NewGuid()); + // Default values + var cA = new Dynamo.Graph.Connectors.ConnectorModel(codeBlockNodeA.OutPorts.FirstOrDefault(), chart.InPorts[0], Guid.NewGuid()); + var cB = new Dynamo.Graph.Connectors.ConnectorModel(codeBlockNodeB.OutPorts.FirstOrDefault(), chart.InPorts[1], Guid.NewGuid()); + var cC = new Dynamo.Graph.Connectors.ConnectorModel(codeBlockNodeC.OutPorts.FirstOrDefault(), chart.InPorts[2], Guid.NewGuid()); homespace.Run(); Assert.DoesNotThrow(DispatcherUtil.DoEvents); Assert.AreEqual(3, homespace.Connectors.Count()); + Assert.AreEqual(ElementState.Info, chart.State); + + string codeD = "a = Color.ByARGB(255, 255, 255, 255);" + + "\r\nb = Color.ByARGB(255, 255, 255, 255);" + + "\r\nc = Color.ByARGB(255, 255, 255, 255);" + + "\r\nt1 = [a, b, c];"; + + var codeBlockNodeD = CreateCodeBlockNode(); + UpdateCodeBlockNodeContent(codeBlockNodeD, @codeD); + + // Fully working node + var cD = new Dynamo.Graph.Connectors.ConnectorModel(codeBlockNodeD.OutPorts.FirstOrDefault(), chart.InPorts[3], Guid.NewGuid()); + + homespace.Run(); + Assert.DoesNotThrow(DispatcherUtil.DoEvents); + Assert.AreEqual(4, homespace.Connectors.Count()); + Assert.AreEqual(ElementState.Active, chart.State); + + // Wrong input types + homespace.ClearConnector(cA); + cA = new Dynamo.Graph.Connectors.ConnectorModel(codeBlockNodeB.OutPorts.FirstOrDefault(), chart.InPorts[0], Guid.NewGuid()); + + homespace.Run(); + Assert.DoesNotThrow(DispatcherUtil.DoEvents); + Assert.AreEqual(4, homespace.Connectors.Count()); + Assert.AreEqual(ElementState.Warning, chart.State); + } } }