Hi David,
Most likely the stock series is not instructed to use the x values:
stockSeries.UseXValues = true;
We just tested the control with the following code and it was working properly:
private void Form1_Load(object sender, EventArgs e)
{
NCartesianChart cartChart = (NCartesianChart)nChartControl1.Charts[0];
cartChart.BoundsMode = BoundsMode.Stretch;
NStockSeries stockSeries = new NStockSeries();
stockSeries.UseXValues = true;
stockSeries.DataLabelStyle.Visible = false;
GenerateData(stockSeries, 10, 200);
cartChart.Series.Add(stockSeries);
cartChart.Axis(StandardAxis.PrimaryX).ScaleConfigurator = new NRangeTimelineScaleConfigurator();
DateTime endDate = DateTime.FromOADate((double)stockSeries.XValues[stockSeries.XValues.Count -1]);
DateTime viewBegin = endDate.AddMonths(-4);
NNumericAxisPagingView dateAxis = new NNumericAxisPagingView(new NRange1DD(viewBegin.ToOADate(), endDate.ToOADate()));
dateAxis.Enabled = true;
cartChart.Axis(StandardAxis.PrimaryX).PagingView = dateAxis;
}
private void GenerateData(NStockSeries s, double dPrevClose, int nCount)
{
DateTime now = DateTime.Now;
double open, high, low, close;
s.ClearDataPoints();
Random rand = new Random();
for (int nIndex = 0; nIndex < nCount; nIndex++)
{
open = dPrevClose;
if (dPrevClose < 25 || rand.NextDouble() > 0.5)
{
// upward price change
close = open + (2 + (rand.NextDouble() * 20));
high = close + (rand.NextDouble() * 10);
low = open - (rand.NextDouble() * 10);
}
else
{
// downward price change
close = open - (2 + (rand.NextDouble() * 20));
high = open + (rand.NextDouble() * 10);
low = close - (rand.NextDouble() * 10);
}
if (low < 1)
{
low = 1;
}
dPrevClose = close;
s.OpenValues.Add(open);
s.HighValues.Add(high);
s.LowValues.Add(low);
s.CloseValues.Add(close);
s.XValues.Add(now.ToOADate());
// advance to next working day
now += new TimeSpan(1, 0, 0, 0);
}
}
One other question I have is is it possible to discover which bars are in the view after the user zooms + scrolls? This is so that I can set the y axis paging view to the min and max value of the visible bars, in order to zoom the y axis in on what is visible.
You can easliy intercept the scrollbar view changed and data zoom end drag events:
cartChart.Axis(StandardAxis.PrimaryX).ScrollBar.ViewRangeChanged += new EventHandler(ScrollBar_ViewRangeChanged);
cartChart.Axis(StandardAxis.PrimaryX).ScrollBar.Visible = true;
NRangeSelection rs = new NRangeSelection();
rs.VerticalValueSnapper = new NAxisRulerMinMaxSnapper();
cartChart.RangeSelections.Add(rs);
nChartControl1.Controller.Tools.Add(new NSelectorTool());
nChartControl1.Controller.Tools.Add(new NAxisScrollTool());
NDataZoomTool dzt = new NDataZoomTool();
dzt.EndDrag +=new EventHandler(dzt_EndDrag);
nChartControl1.Controller.Tools.Add(dzt);
// ....
void dzt_EndDrag(object sender, EventArgs e)
{
NRange1DD range = nChartControl1.Charts[0].Axis(StandardAxis.PrimaryX).PageRange;
textBox1.Text = "Range: Begin[" + DateTime.FromOADate(range.Begin).ToString() + "], End [" + DateTime.FromOADate(range.End).ToString() + "]";
}
void ScrollBar_ViewRangeChanged(object sender, EventArgs e)
{
NRange1DD range = nChartControl1.Charts[0].Axis(StandardAxis.PrimaryX).PageRange;
textBox1.Text = "Range: Begin[" + DateTime.FromOADate(range.Begin).ToString() + "], End [" + DateTime.FromOADate(range.End).ToString() + "]";
}
In order to implement a Y axis that has variable range depending on the x axis range you need to create a custom range view for the Y axis - the following code snippet shows how to achieve this for a simple line chart showing the sin function, however the code with minor modifications for the min/max calculation is the same in the case of stock chart:
/// <summary>
/// Configures the axis to display the range of the content that scales on it
/// </summary>
[Serializable]
public partial class NCustomAxisView : NRangeAxisView
{
#region Constructors
public NCustomAxisView(NChartControl chartControl)
{
m_ChartControl = chartControl;
}
#endregion
#region Overrides
/// <summary>
/// Obtains the range displayed by the axis given the current content range
/// </summary>
/// <param name="range"></param>
/// <param name="isZoomed"></param>
/// <returns></returns>
public override NRange1DD GetViewRange(NRange1DD range, ref bool isZoomed)
{
NChart chart = (NChart)this.ProvideReference(typeof(NChart));
// recalculate the x axis - this ensures the RulerRange is valid
chart.Axis(StandardAxis.PrimaryX).CalculateAxis(m_ChartControl.View.Context);
NRange1DD xRange = chart.Axis(StandardAxis.PrimaryX).Scale.RulerRange;
NLineSeries line = chart.Series[0] as NLineSeries;
if (line.Values.Count == 0)
return range;
bool hasMinMax = false;
double min = 0;
double max = 0;
for (int i = 0; i < line.Values.Count; i++)
{
if (!xRange.Contains((double)line.XValues[i]))
continue;
double value = (double)line.Values[i];
if (hasMinMax)
{
max = Math.Max(max, value);
min = Math.Min(min, value);
}
else
{
max = value;
min = value;
hasMinMax = true;
}
}
isZoomed = hasMinMax;
if (hasMinMax)
{
range = new NRange1DD(min, max);
}
return range;
}
#endregion
#region Fields
NChartControl m_ChartControl;
#endregion
}
private void Form1_Load(object sender, EventArgs e)
{
NCartesianChart chart = (NCartesianChart)nChartControl1.Charts[0];
chart.Axis(StandardAxis.PrimaryY).View = new NCustomAxisView(nChartControl1);
chart.BoundsMode = BoundsMode.Stretch;
chart.Axis(StandardAxis.PrimaryX).ScrollBar.Visible = true;
NLineSeries line = new NLineSeries();
line.UseXValues = true;
line.DataLabelStyle.Visible = false;
for (int i = 0; i < 200; i++)
{
line.Values.Add(Math.Sin(2 * Math.PI * i / 200.0));
line.XValues.Add(i);
}
chart.Series.Add(line);
NRangeSelection rs = new NRangeSelection();
rs.VerticalValueSnapper = new NAxisRulerMinMaxSnapper();
chart.RangeSelections.Add(rs);
nChartControl1.Controller.Tools.Add(new NSelectorTool());
nChartControl1.Controller.Tools.Add(new NAxisScrollTool());
nChartControl1.Controller.Tools.Add(new NDataZoomTool());
}
Hope this helps - let us know if you meet any problems or have any questions.
Best Regards,
Nevron Support Team