Profile Picture

Behavior of dynamically adding and positioning charts

Posted By Jarrett Robertson 12 Years Ago
Author
Message
Jarrett Robertson
questionmark Posted 12 Years Ago
View Quick Profile
Junior Member

Junior Member (12 reputation)Junior Member (12 reputation)Junior Member (12 reputation)Junior Member (12 reputation)Junior Member (12 reputation)Junior Member (12 reputation)Junior Member (12 reputation)Junior Member (12 reputation)Junior Member (12 reputation)

Group: Forum Members
Last Active: 11 Years Ago
Posts: 12, Visits: 1
I am working on a program where I've implemented drag and drop from a ListView control to a docking control that can contain several charts. Part of the functionality in this is to allow users to either create new chart strips, add data to a current chart or put a chart side by side on the same control. I have implemented support for NCartesianCharts and NPolarCharts so far. However, I'm not completely understanding the behavior when I attempt to automatically reposition the charts.

First, when I set the NCartesianCharts.Size property it appears to ignore whichever value is larger (for instance if my chart would be wider than it is tall it makes squared the size of its height). Before this I was able to get the look I wanted by setting the Charts.Dock to DockStyle.Right and BoundsMode to Stretch. However now that I'm manually calculating the size I would have thought I would not need to do that.

Second, when I set the Location of NCartesianChart if the control is squared it appears the position is set correctly. However, again if the scenario is that the control is wider than it is tall it appears to ignore the location I specified.

Third, I'm not sure how NPolarCharts Location is defined. It appears that NCartesianChart places the X,Y based on the lower right of the chart (at the origin). In NPolarChart the behavior I think I'm seeing is that it's Location is based on the center of the chart? I wasn't able to find anything on this online or searching the forums. If that is the case it's fine I will just need to apply an offset depending on the chart type. I have also copied the code I'm using to position my charts. I'm confident that the math is correct but as I said what I'm seeing doesn't match the behavior I'm expecting. Any help at all would be appreciated.

As a final note the scenario is that I have n number of charts of various types that must all fit on the same control. The only things I know is the size of the control, the number of charts to place, and the maximum number of columns I will allow (rows are variable depending on the column). So, I am trying to calculate the size I would need to make the charts give them a buffer on the outside and a smaller buffer between each chart. Then programatically position and size them. Also, I apologize if there is a code format function but I didn't see it so I've just pasted it in as plain text.


private void RepositionCharts()
{
int lCurrentColumn = 0;
int lCurrentRow = 1;
int lTotalRows = Charts.Count / mMaxChartColumns;

double lExteriorBuffer = 10.0;
double lInteriorBuffer = 1;
int lChartCount = Charts.Count;
double lChartWidth =
(Size.Width - (2 * lExteriorBuffer) - ((mMaxChartColumns - 1) * lInteriorBuffer)) / lChartCount;
double lChartHeight =
(Size.Height - (2 * lExteriorBuffer) - ((lTotalRows - 1) * lInteriorBuffer)) / lChartCount;
float lXLocation;
float lYLocation;

NSizeL lChartSize = new NSizeL((float)lChartWidth, (float)lChartHeight);

for (int i = 0; i < Charts.Count; ++i)
{
for (int j = 0; j < lTotalRows; ++j)
{
Charts[i].Size = lChartSize;

lXLocation = (float)((lCurrentColumn * lChartWidth) + lInteriorBuffer + lExteriorBuffer);
lYLocation = (float)((j * lChartHeight) + lInteriorBuffer + lExteriorBuffer);
Charts[i].Location = new NPointL(lXLocation, lYLocation);

if (++lCurrentColumn >= mMaxChartColumns)
{
lCurrentColumn = 0;
++lCurrentRow;
}
}
}
}



Nevron Support
Posted 12 Years Ago
View Quick Profile
Supreme Being

Supreme Being (4,435 reputation)Supreme Being (4,435 reputation)Supreme Being (4,435 reputation)Supreme Being (4,435 reputation)Supreme Being (4,435 reputation)Supreme Being (4,435 reputation)Supreme Being (4,435 reputation)Supreme Being (4,435 reputation)Supreme Being (4,435 reputation)

Group: Forum Members
Last Active: Last Week
Posts: 3,054, Visits: 4,009

Hi Bruce,

Regarding 1 & 2 - the BoundsMode works independently from Location, Size and Dock style. The latter three define a chart panel bounding box in which the chart axes and plot are later fitted. When you use BoundsMode.Fit (which is the default) the control will preserve the ratio of chart.Width relative to chart.Height, regardless of its panel bounds ratio. Alternatively when you set BoundsMode.Stretch the aspect ratio is not preserved and the chart will occupy the whole panel bounds specified by (Location and Size) or (Dock and Size). In short:

1. You need to use BoundsMode.Fit when you wish to have a chart whose aspect does not change when the control is resized. Typical example for this is when you need to draw the classic Cartesian coordinate system which requires a square plot (aspect 1:1).

2. You need to use BoundsMode.Stretch when you wish to have a chart that changes its widht / height according to the panel bounds it resides in (probably this is the case with the charts you create).

Regarding 3 - when you position a panel using Location / Size properties (without docking) the Location by default specifies the top left corner of the panel bounding box. You can alter this using the content alignment property which allows you use the location in order to specify a differnt point (for example the center of the bounding box (somePanel.ContentAlignment = ContentAlignment.MiddleCenter). More information regarding content alignment can be found at:

http://helpdotnetvision.nevron.com/UsersGuide_Layout_Layout_Overview.html



Best Regards,
Nevron Support Team



Nevron Support
Posted 12 Years Ago
View Quick Profile
Supreme Being

Supreme Being (4,435 reputation)Supreme Being (4,435 reputation)Supreme Being (4,435 reputation)Supreme Being (4,435 reputation)Supreme Being (4,435 reputation)Supreme Being (4,435 reputation)Supreme Being (4,435 reputation)Supreme Being (4,435 reputation)Supreme Being (4,435 reputation)

Group: Forum Members
Last Active: Last Week
Posts: 3,054, Visits: 4,009

Regarding dynamically positioned charts - we would recommend to use percentages when you specify lengths - the following code snippet shows how to create a dynamically resizable layout with three columns and two rows of charts:

 public partial class Form1 : Form
 {
  public Form1()
  {
   InitializeComponent();
  }

  private void Form1_Load(object sender, EventArgs e)
  {
   int colCount = 3;
   int rowCount = 2;

   float colSize = 100 / colCount;
   float rowSize = 100 / rowCount;

   nChartControl1.Panels.Clear();

   for (int col = 0; col < colCount; col++)
   {
    NDockPanel dock = new NDockPanel();

    // specify spacing between the columns
    if (col == colCount - 1)
    {
     dock.Padding = new NMarginsL(0, 0, 10, 0);
    }
    else
    {
     dock.Padding = new NMarginsL(10, 0, 0, 0);
    }

    dock.PositionChildPanelsInContentBounds = true;
    dock.Location = new NPointL(new NLength(col * colSize, NRelativeUnit.ParentPercentage), new NLength(0));
    dock.Size = new NSizeL(new NLength(colSize, NRelativeUnit.ParentPercentage), new NLength(100, NRelativeUnit.ParentPercentage));

    for (int row = 0; row < rowCount; row++)
    {
     NChart chart = CreateChart();

     // specify spacing between rows
     if (row == rowCount - 1)
     {
      chart.Padding = new NMarginsL(0, 0, 0, 10);
     }
     else
     {
      chart.Padding = new NMarginsL(0, 10, 0, 0);
     }

     chart.Location = new NPointL(new NLength(0), new NLength(row * rowSize, NRelativeUnit.ParentPercentage));
     chart.Size = new NSizeL(new NLength(100, NRelativeUnit.ParentPercentage), new NLength(rowSize, NRelativeUnit.ParentPercentage));

     dock.ChildPanels.Add(chart);
    }

    nChartControl1.Panels.Add(dock);
   }
  }

  private NChart CreateChart()
  {
   NCartesianChart chart = new NCartesianChart();
   NBarSeries bar = new NBarSeries();
   bar.Values.Add(10);
   bar.Values.Add(20);
   bar.Values.Add(30);

   chart.Series.Add(bar);
   chart.BoundsMode = BoundsMode.Stretch;

   return chart;
  }

 

  private void button1_Click(object sender, EventArgs e)
  {
   nChartControl1.ShowEditor();
  }
 }
Hope this helps - let us know if you meet any problems or have any questions.



Best Regards,
Nevron Support Team



Jarrett Robertson
Posted 12 Years Ago
View Quick Profile
Junior Member

Junior Member (12 reputation)Junior Member (12 reputation)Junior Member (12 reputation)Junior Member (12 reputation)Junior Member (12 reputation)Junior Member (12 reputation)Junior Member (12 reputation)Junior Member (12 reputation)Junior Member (12 reputation)

Group: Forum Members
Last Active: 11 Years Ago
Posts: 12, Visits: 1
Thank you for the code, I have two more questions. First, I assume there's a reason the preferred method is to use ParentPercentages instead of literal locations? I started with trying ParentPercentages I'm just curious that the difference is, or why the preference. Second, I notice something that we are doing differently. You are creating a new NDockPanel for each chart. I'm creating 1 docking panel putting 1 chart control in that and then placing all of my charts in the control. Does that matter or should I be creating 1 NDockPanel for each ChartControl I want to use?

Jarrett Robertson
Posted 11 Years Ago
View Quick Profile
Junior Member

Junior Member (12 reputation)Junior Member (12 reputation)Junior Member (12 reputation)Junior Member (12 reputation)Junior Member (12 reputation)Junior Member (12 reputation)Junior Member (12 reputation)Junior Member (12 reputation)Junior Member (12 reputation)

Group: Forum Members
Last Active: 11 Years Ago
Posts: 12, Visits: 1
Again, I appreciate the code that you provided. I was able to manipulate it into something that works for me (it has a few bugs but for the time being it does what I need). However, I was attempting to put back functionality I had previously into this new paradigm. One thing that doesn't appear to work anymore is NDataZoomTool. When I only had a single NCartesianChart I was able to zoom data. The only code I needed to add before was in my NChartControl.Controller.Tools.Add(new NDataZoomTool()); and things just worked. The only other thing that I did that I think might have been related was inside of the CartesianChart I added an NRangeSelection and I added the NSelectorTool to the Controller.

I looked online at the documentation for NDataZoomTool and it says that
"The zoom tool enables the end user to change the zoom factor of the NProjection object attached to the current chart..."

It sounds like I'm not telling my control what it's current chart is but sadly checking the forums or even good for Current Chart isn't turning up anything that appears to show this. Also, I wasn't able to see in the online documentation any way to set the current chart. If there is more setup required for zooming that's fine. But looking at the sample that comes with Nevron .NET Vision doesn't appear to do anything other than create an NDataZoomTool and add it to the Controllers tools.

Is there anything that needs to be done when multiple charts are placed on the same ChartControl? (Also note that the zoom doesn't work even if I only have added a single chart)

Jarrett Robertson
Posted 11 Years Ago
View Quick Profile
Junior Member

Junior Member (12 reputation)Junior Member (12 reputation)Junior Member (12 reputation)Junior Member (12 reputation)Junior Member (12 reputation)Junior Member (12 reputation)Junior Member (12 reputation)Junior Member (12 reputation)Junior Member (12 reputation)

Group: Forum Members
Last Active: 11 Years Ago
Posts: 12, Visits: 1
I was able to resolve my issue regarding the zoom tool. I feel a bit silly that this was the problem but maybe someone else can learn from what I did. Everything worked fine but in my attempts to refactor a portion of my code I commented a lot of methods out. What I forgot was that I had overridden OnMouseDown and OnMouseUp. when I commented these methods out I also commented base.OnMouseDown and base.OnMouseUp. To fix my issue I only had to uncomment these lines.

Nevron Support
Posted 11 Years Ago
View Quick Profile
Supreme Being

Supreme Being (4,435 reputation)Supreme Being (4,435 reputation)Supreme Being (4,435 reputation)Supreme Being (4,435 reputation)Supreme Being (4,435 reputation)Supreme Being (4,435 reputation)Supreme Being (4,435 reputation)Supreme Being (4,435 reputation)Supreme Being (4,435 reputation)

Group: Forum Members
Last Active: Last Week
Posts: 3,054, Visits: 4,009

Hi Bruce,

We're glad you managed to resolve the zoom problem. Regarding:

"Thank you for the code, I have two more questions. First, I assume there's a reason the preferred method is to use ParentPercentages instead of literal locations? I started with trying ParentPercentages I'm just curious that the difference is, or why the preference. Second, I notice something that we are doing differently. "

The sample layout uses ParentPercentage in order to ensure that the panels will automatically resize when you resize the form, otherwise if you use an absolute unit (point for example) you need to adjust the location / size of each panel when the user resizes the control, which can be cumbersome. In general you should use either Point or ParentPercentage if you wish to create print ready/scalable charts and avoid using Pixel as it is device resolution dependent.

"You are creating a new NDockPanel for each chart. I'm creating 1 docking panel putting 1 chart control in that and then placing all of my charts in the control. Does that matter or should I be creating 1 NDockPanel for each ChartControl I want to use?"

You don't have to follow the same layout logic (it is just an example). In the provided code the dock panels are used to enforce same width of all charts contained in the column, nothing more - in fact you can achieve the same layout if you simply position charts using relative units.

Let us know if you meet any problems or have any questions.



Best Regards,
Nevron Support Team





Similar Topics


Reading This Topic