The scenario: a zoommable chart with a DateTime axys that contains a lot of points, approxymately one each 5 or 6 minutes for years.
I set the X Axys MaximumTicks property to 10 and all work good.
But:
1) If I'm looking a range of years the time is not interesting for me
2) If I'm looking a range of years I prefer that any ticks go exaclty to one day (1/3/2013 00:00:00 instead of 1/3/2013 12:23:45)
3) If I'm looking a range of hours the time is really important
How to menage manually the parameters MajorStepUnit and MajorStep?
The ActualRangeChanged event don't exists!
Thank's
marc.
12 Answers, 1 is accepted
For the time being, there is no good way to do this. But, with the release of Q2, which will be released by the end of the business week, there will be an easy way to do that. The new property, ActualVisibleRange, and the new event ZoomChanged will be introduced. And you would need to do something like the following:
private
void
chart_ZoomChanged(
object
sender, Telerik.Windows.Controls.ChartView.ChartZoomChangedEventArgs e)
{
var axis = (chart.HorizontalAxis
as
DateTimeContinuousAxis);
var range = axis.ActualVisibleRange.Maximum - axis.ActualVisibleRange.Minimum;
if
(range > TimeSpan.FromDays(365))
{
axis.LabelFormat =
"dd-MMM-yyyy"
;
axis.MajorStepUnit = Telerik.Charting.TimeInterval.Day;
}
else
{
axis.LabelFormat =
"dd-MMM-yyyy HH:mm"
;
axis.MajorStepUnit = Telerik.Charting.TimeInterval.Hour;
}
}
Regards, Rosko
Telerik
Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.
Thank's very much.
With new version is possible to obtain good results.
But in certain case the dll fails.
Look the attatched example.I set allways the Major Step Unit as Day and Major Step as a int number.
Execute the example, maximize it and start to reduce zoom bar from left to right.
At certain point the chart show point at 06:00 hours!
thank's,
marc.
<
telerik:RadCartesianChart
ZoomChanged
=
"chart_ZoomChanged"
>
<
telerik:RadCartesianChart.HorizontalAxis
>
<
telerik:DateTimeContinuousAxis
MajorStepUnit
=
"Day"
MajorStep
=
"2"
Name
=
"mX"
/>
</
telerik:RadCartesianChart.HorizontalAxis
>
<
telerik:RadCartesianChart.VerticalAxis
>
<
telerik:LinearAxis
/>
</
telerik:RadCartesianChart.VerticalAxis
>
<
telerik:LineSeries
Name
=
"mS"
>
</
telerik:LineSeries
>
<
telerik:RadCartesianChart.Behaviors
>
<
telerik:ChartPanAndZoomBehavior
/>
</
telerik:RadCartesianChart.Behaviors
>
</
telerik:RadCartesianChart
>
public
MainWindow()
{
InitializeComponent();
for
(
int
i = 0; i < 100;i++ )
mS.DataPoints.Add(
new
Telerik.Charting.CategoricalDataPoint() { Category = System.DateTime.Today.AddHours(i*6), Value = 5 });
}
private
void
chart_ZoomChanged(
object
sender, Telerik.Windows.Controls.ChartView.ChartZoomChangedEventArgs e)
{
var axis = mX;
var range = axis.ActualVisibleRange.Maximum - axis.ActualVisibleRange.Minimum;
double
lbs = System.Math.Ceiling(range.TotalDays / 10);
if
(lbs > 0 && range.TotalDays / lbs > 5)
{
//axis.PlotMode = Telerik.Charting.AxisPlotMode.BetweenTicks;
//axis.GapLength = 1;
axis.LabelFormat =
"yyyy/MM/dd\r\nHH:mm:ss"
;
axis.MajorStepUnit = Telerik.Charting.TimeInterval.Day;
axis.MajorStep = lbs;
//axis.LabelInterval = 1;
return
;
}
}
Thank you for the provided code, it proved useful for understanding the scenario.
What you are experiencing is a completely expected behavior. The chart respects this property until some level of zoom in. It has some internal heuristics which make sure that there are a certain number of ticks on the axis. Otherwise, the chart will not make much sense if it has very few ticks on its axis. This is why it changes the MajorStepUnit as it zooms in to half a day and then to one third of a day. In the end, at one moment, you will have one point/tick in the visible range.
Regards,
Rosko
Telerik
Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.
Sorry, but I think this is a bug.
I rewrited my example.
Please run it and maximize the form.
Move zoom bar from left to right. When the zoom bar size is about half of form width the labels for 12:00 hours appears also if the
chart_ZoomChanged method is granting that 11 labels is visibles (llok the new txtbox on bottom left corner).
Now stop project. Change the mMaxLabelsCount value to 30 and restart it. In the same situasion now the program grant to show 24/25 labels but anyway the new labels appears overlapping others!
marc.
<
Grid
>
<
Grid.RowDefinitions
>
<
RowDefinition
Height
=
"*"
/>
<
RowDefinition
Height
=
"Auto"
/>
</
Grid.RowDefinitions
>
<
telerik:RadCartesianChart
ZoomChanged
=
"chart_ZoomChanged"
>
<
telerik:RadCartesianChart.HorizontalAxis
>
<
telerik:DateTimeContinuousAxis
MajorStepUnit
=
"Day"
MajorStep
=
"2"
Name
=
"mX"
/>
</
telerik:RadCartesianChart.HorizontalAxis
>
<
telerik:RadCartesianChart.VerticalAxis
>
<
telerik:LinearAxis
/>
</
telerik:RadCartesianChart.VerticalAxis
>
<
telerik:LineSeries
Name
=
"mS"
>
</
telerik:LineSeries
>
<
telerik:RadCartesianChart.Behaviors
>
<
telerik:ChartPanAndZoomBehavior
/>
</
telerik:RadCartesianChart.Behaviors
>
</
telerik:RadCartesianChart
>
<
TextBlock
Name
=
"mInfo"
Grid.Row
=
"1"
/>
</
Grid
>
private
const
int
mMaxLabelsCount = 15;
public
MainWindow()
{
InitializeComponent();
for
(
int
i = 0; i < 100;i++ )
mS.DataPoints.Add(
new
Telerik.Charting.CategoricalDataPoint() { Category = System.DateTime.Today.AddHours(i*6), Value = 5 });
Loaded += (x, y) => { chart_ZoomChanged(
null
,
null
); };
}
private
void
chart_ZoomChanged(
object
sender, Telerik.Windows.Controls.ChartView.ChartZoomChangedEventArgs e)
{
if
(mX ==
null
)
return
;
if
(!(mX
is
Telerik.Windows.Controls.ChartView.DateTimeContinuousAxis))
return
;
var axis = (mX
as
Telerik.Windows.Controls.ChartView.DateTimeContinuousAxis);
var range = axis.ActualVisibleRange.Maximum - axis.ActualVisibleRange.Minimum;
bool
ms =
false
;
double
k;
if
(range.TotalHours > 12 * mMaxLabelsCount)
//> 120 ore
{
k = range.TotalDays;
var lbs = System.Math.Ceiling(k / mMaxLabelsCount);
axis.MajorStepUnit = Telerik.Charting.TimeInterval.Day;
axis.MajorStep = lbs;
}
else
if
(range.TotalHours > 6 * mMaxLabelsCount)
//>60
{
k = range.TotalHours;
axis.MajorStepUnit = Telerik.Charting.TimeInterval.Hour;
axis.MajorStep = 12;
}
else
if
(range.TotalHours > 3 * mMaxLabelsCount)
{
k = range.TotalHours;
axis.MajorStepUnit = Telerik.Charting.TimeInterval.Hour;
axis.MajorStep = 6;
}
else
if
(range.TotalHours > mMaxLabelsCount)
{
k = range.TotalHours;
axis.MajorStepUnit = Telerik.Charting.TimeInterval.Hour;
axis.MajorStep = 3;
}
else
if
(range.TotalMinutes > 30 * mMaxLabelsCount)
{
k = range.TotalHours;
axis.MajorStepUnit = Telerik.Charting.TimeInterval.Hour;
axis.MajorStep = 1;
}
else
if
(range.TotalMinutes > 15 * mMaxLabelsCount)
{
k = range.TotalMinutes;
axis.MajorStepUnit = Telerik.Charting.TimeInterval.Minute;
axis.MajorStep = 30;
}
else
if
(range.TotalMinutes > mMaxLabelsCount)
{
k = range.TotalMinutes;
axis.MajorStepUnit = Telerik.Charting.TimeInterval.Minute;
axis.MajorStep = 15;
}
else
if
(range.TotalSeconds > 30 * mMaxLabelsCount)
{
k = range.TotalMinutes;
axis.MajorStepUnit = Telerik.Charting.TimeInterval.Minute;
axis.MajorStep = 1;
}
else
if
(range.TotalSeconds > 15 * mMaxLabelsCount)
{
k = range.TotalSeconds;
axis.MajorStepUnit = Telerik.Charting.TimeInterval.Second;
axis.MajorStep = 30;
}
else
if
(range.TotalSeconds > 1 * mMaxLabelsCount)
{
k = range.TotalSeconds;
axis.MajorStepUnit = Telerik.Charting.TimeInterval.Second;
axis.MajorStep = 15;
}
else
if
(range.TotalMilliseconds > 100 * mMaxLabelsCount)
{
k = range.TotalSeconds;
axis.MajorStepUnit = Telerik.Charting.TimeInterval.Second;
axis.MajorStep = 1;
}
else
{
k = 0;
axis.MajorStep = 0;
ms =
true
;
}
axis.LabelFormat =
"yyyy/MM/dd\r\nHH:mm:ss"
+ (ms ?
".xxx"
:
string
.Empty);
if
(axis.MajorStep > 0 && k > 0)
mInfo.Text =
"Granted Labels>="
+ System.Math.Floor( k / axis.MajorStep).ToString();
else
mInfo.Text =
"Granted Labels:?"
;
mInfo.Text +=
" "
+ axis.MajorStepUnit.ToString() +
" "
+ axis.MajorStep.ToString();
}
Thank you for the code and detailed instructions!
I suspect that there is some miscommunication. If this post still does not solve all issues. Can you please share a sketch what you are referring as a bug by pointing or highlighting in the picture?
I used them and you can see the result that I get in the two attached pictures.
I hope that you already understood that the chart is changing the MajorStepUnit by itself as it zooms in and this cannot be changed. Sorry if it is causing any inconvenience.
If you are regarding the overlapping labels as a bug, that can be fixed in more than one way. You can take advantage of the following properties. I believe the first two speak of themselves. The last one sets how many labels should be there per number of ticks. For instance, if you set the property to 2, this means you will have one label for every two ticks and etc. Last but not least, you can reduce the number of ticks, which I believe you already know how to do.
axis.LabelFitMode
axis.LabelRotationAngle
axis.LabelInterval
I hope this has cleared the miscommunication, if not please provide an image showing what do you refer as a bug.
Regards,
Rosko
Telerik
Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.
My problem is simply: how to obtain a good chart visual experience in charts with a lot of datapoints (Years of seconds intervals data)?
Please ignore all previous posts and we try to restart from here.
I create a new simple example:
<
Grid
>
<
Grid.RowDefinitions
>
<
RowDefinition
Height
=
"*"
/>
<
RowDefinition
Height
=
"Auto"
/>
</
Grid.RowDefinitions
>
<
telerik:RadCartesianChart
>
<
telerik:RadCartesianChart.HorizontalAxis
>
<
telerik:DateTimeContinuousAxis
MajorStepUnit
=
"Day"
MajorStep
=
"2"
Name
=
"mX"
/>
</
telerik:RadCartesianChart.HorizontalAxis
>
<
telerik:RadCartesianChart.VerticalAxis
>
<
telerik:LinearAxis
/>
</
telerik:RadCartesianChart.VerticalAxis
>
<
telerik:BarSeries
Name
=
"mS"
>
</
telerik:BarSeries
>
<
telerik:RadCartesianChart.Behaviors
>
<
telerik:ChartPanAndZoomBehavior
/>
</
telerik:RadCartesianChart.Behaviors
>
</
telerik:RadCartesianChart
>
<
TextBlock
Name
=
"mInfo"
Grid.Row
=
"1"
/>
</
Grid
>
public
MainWindow()
{
InitializeComponent();
for
(
int
i = 0; i < 100;i++ )
mS.DataPoints.Add(
new
Telerik.Charting.CategoricalDataPoint() { Category = System.DateTime.Today.AddHours(i*6), Value = 5 });
}
How to change it to obtain:
1) No x lables overlapping for each windows size and zoom level selection
2) No Bar series overlapping
3) Good tick choose depending on zoom selection level (exact days for weeks, exact 12:00 for days, exact ours for day...) [this request is obviously less important]
4) Mantain the previous results (1,2,3) if dataset change.
Thank's
marc.
Perhaps I finded an acceptable solution setting one time the MajorStep on min data interval and working only with labels interval on zoom change event:
<
Window.Resources
>
<
Style
x:Key
=
"mCustomLabelStyle"
TargetType
=
"{x:Type TextBlock}"
>
<
Setter
Property
=
"TextAlignment"
Value
=
"Center"
/>
<
Setter
Property
=
"FontSize"
Value
=
"10"
/>
</
Style
>
</
Window.Resources
>
<
Grid
>
<
Grid.RowDefinitions
>
<
RowDefinition
Height
=
"*"
/>
<
RowDefinition
Height
=
"Auto"
/>
</
Grid.RowDefinitions
>
<
telerik:RadCartesianChart
ZoomChanged
=
"RadCartesianChart_ZoomChanged"
Name
=
"mC"
>
<
telerik:RadCartesianChart.HorizontalAxis
>
<
telerik:DateTimeContinuousAxis
Name
=
"mX"
/>
</
telerik:RadCartesianChart.HorizontalAxis
>
<
telerik:RadCartesianChart.VerticalAxis
>
<
telerik:LinearAxis
/>
</
telerik:RadCartesianChart.VerticalAxis
>
<
telerik:BarSeries
Name
=
"mS"
>
</
telerik:BarSeries
>
<
telerik:RadCartesianChart.Behaviors
>
<
telerik:ChartPanAndZoomBehavior
/>
</
telerik:RadCartesianChart.Behaviors
>
</
telerik:RadCartesianChart
>
<
TextBlock
Name
=
"mInfo"
Grid.Row
=
"1"
/>
</
Grid
>
public
MainWindow()
{
InitializeComponent();
System.DateTime? dprev=
null
;
System.DateTime d;
System.TimeSpan dmin =
new
TimeSpan(0);
for
(
int
i = 0; i < 100; i++)
{
d = System.DateTime.Today.AddHours(i * 6);
if
(dprev.HasValue && (d - dprev.Value) > dmin) dmin = (d - dprev.Value);
dprev = d;
mS.DataPoints.Add(
new
Telerik.Charting.CategoricalDataPoint() { Category = d, Value = 5 });
}
mX.MajorStepUnit = Telerik.Charting.TimeInterval.Second;
mX.MajorStep = dmin.TotalSeconds;
mX.LabelStyle = Resources[
"mCustomLabelStyle"
]
as
Style;
mC.Loaded += (x, y) => { RadCartesianChart_ZoomChanged(
null
,
null
); };
}
private
void
RadCartesianChart_ZoomChanged(
object
sender, Telerik.Windows.Controls.ChartView.ChartZoomChangedEventArgs e)
{
if
(mX ==
null
)
return
;
if
(!(mX
is
Telerik.Windows.Controls.ChartView.DateTimeContinuousAxis))
return
;
var axis = (mX
as
Telerik.Windows.Controls.ChartView.DateTimeContinuousAxis);
var range = axis.ActualVisibleRange.Maximum - axis.ActualVisibleRange.Minimum;
int
t = (
int
)(range.TotalSeconds / mX.MajorStep);
mX.LabelInterval = System.Math.Max(t / mMaxLabelsCount, 1);
axis.LabelFormat =
"yyyy/MM/dd\r\nHH:mm:ss"
+ ((range.TotalMilliseconds <= 100 * mMaxLabelsCount) ?
".xxx"
:
string
.Empty);
}
a new version of solution with this strategies:
- The X Axis Major Step Unit is set to Seconds
- The X Axis Step is set to minimum of points distance, in seconds
This grant that the chart don't add never infra ticks
- The X Axis Minimum is manually set to a good "exact" date, in example 1/1/2013 instead of 1/1/2013 00:00:01
This grant the tick is allways on a "exact" position instead of the point position
- The LabelFitMode is set to multiline
This grant that a good visual experience in possible also resizing the chart.
- In Zoom changed event I find the firts tick, the last tick, the number of visible ticks (via ActualVisibleRange)
- I choose Label Interval and Label Offset for a good visual experience.
This work pretty good, but:
- Is not possible to determine allways exacltly the first and last tick, probabilly for approximations (look the images T1 and T2. The second image don't show first tick but bot cases ave the identical [at milliseconds level] ActualVisibleRange.
- This cause that in certain cases the procedure don't determine correctly the first tick and unespected "not exact" dates appears for a moment [This is visible zooming slowly, in certain cases hours appears also if the visible range is a lot of days]
The strategy introduce also other little problems:
- Is not possible to choose ticks visible number (In possible to set a style for tick depending on tick index?)
- The chart grid contains a lot of lines (In possible to set a style for grid line depending on lines index?)
Suggestions for the future:
- Please add a FirstTick (Datetime) in ActualVisibleRange for a exact determination of LabelInterval
- Please review the Grid architecture and the Bar architecture.
I really love your charts. I worked a lot with other chart developers. You have a really good class architetture that permit to work simply and linearly in a lot of case. Only X Axis interactions contains [for the moment] not good implementations:
- The bar width is not depending on X axys tiks!! It depends only on the back and previous point positions!!
Thank's very much,
marc
<
Window.Resources
>
<
Style
x:Key
=
"mCustomLabelStyle"
TargetType
=
"{x:Type TextBlock}"
>
<
Setter
Property
=
"TextAlignment"
Value
=
"Center"
/>
<
Setter
Property
=
"FontSize"
Value
=
"10"
/>
</
Style
>
</
Window.Resources
>
<
Grid
>
<
Grid.RowDefinitions
>
<
RowDefinition
Height
=
"*"
/>
<
RowDefinition
Height
=
"Auto"
/>
</
Grid.RowDefinitions
>
<
telerik:RadCartesianChart
ZoomChanged
=
"RadCartesianChart_ZoomChanged"
Name
=
"mC"
>
<
telerik:RadCartesianChart.HorizontalAxis
>
<
telerik:DateTimeContinuousAxis
Name
=
"mX"
/>
</
telerik:RadCartesianChart.HorizontalAxis
>
<
telerik:RadCartesianChart.VerticalAxis
>
<
telerik:LinearAxis
/>
</
telerik:RadCartesianChart.VerticalAxis
>
<
telerik:LineSeries
Name
=
"mS"
>
</
telerik:LineSeries
>
<
telerik:RadCartesianChart.Behaviors
>
<
telerik:ChartPanAndZoomBehavior
/>
</
telerik:RadCartesianChart.Behaviors
>
</
telerik:RadCartesianChart
>
<
TextBlock
Name
=
"mInfo"
Grid.Row
=
"1"
/>
</
Grid
>
private
double
TickLength=1;
private
int
mMaxLabelsCount = 10;
private
System.DateTime? FirstTick;
public
MainWindow()
{
InitializeComponent();
System.DateTime? dprev=
null
, dmin=
null
;
System.DateTime d;
System.TimeSpan rmin =
new
TimeSpan(0);
for
(
int
i = 0; i < 100; i++)
{
d = System.DateTime.Today.AddMinutes(3).AddHours(i * 6);
if
(dprev.HasValue && (d - dprev.Value) > rmin) rmin = (d - dprev.Value);
dprev = d;
if
(!dmin.HasValue || dmin > d) dmin = d;
mS.DataPoints.Add(
new
Telerik.Charting.CategoricalDataPoint() { Category = d, Value = 5 });
}
//If nopoints return
if
(!dmin.HasValue)
return
;
//R Min Analysis
if
(rmin >= TimeSpan.FromDays(1)) rmin = TimeSpan.FromDays((
int
)(rmin.TotalDays));
else
if
(rmin >= TimeSpan.FromHours(12)) rmin = TimeSpan.FromHours(12);
else
if
(rmin >= TimeSpan.FromHours(8)) rmin = TimeSpan.FromHours(8);
else
if
(rmin >= TimeSpan.FromHours(6)) rmin = TimeSpan.FromHours(6);
else
if
(rmin >= TimeSpan.FromHours(4)) rmin = TimeSpan.FromHours(4);
else
if
(rmin >= TimeSpan.FromHours(3)) rmin = TimeSpan.FromHours(3);
else
if
(rmin >= TimeSpan.FromHours(2)) rmin = TimeSpan.FromHours(1);
else
if
(rmin >= TimeSpan.FromHours(1)) rmin = TimeSpan.FromHours(1);
else
if
(rmin >= TimeSpan.FromMinutes(30)) rmin = TimeSpan.FromMinutes(30);
else
if
(rmin >= TimeSpan.FromMinutes(20)) rmin = TimeSpan.FromMinutes(20);
else
if
(rmin >= TimeSpan.FromMinutes(15)) rmin = TimeSpan.FromMinutes(15);
else
if
(rmin >= TimeSpan.FromMinutes(10)) rmin = TimeSpan.FromMinutes(10);
else
if
(rmin >= TimeSpan.FromMinutes(5)) rmin = TimeSpan.FromMinutes(5);
else
if
(rmin >= TimeSpan.FromMinutes(1)) rmin = TimeSpan.FromMinutes(1);
else
if
(rmin >= TimeSpan.FromSeconds(30)) rmin = TimeSpan.FromSeconds(30);
else
if
(rmin >= TimeSpan.FromSeconds(20)) rmin = TimeSpan.FromSeconds(20);
else
if
(rmin >= TimeSpan.FromSeconds(15)) rmin = TimeSpan.FromSeconds(15);
else
if
(rmin >= TimeSpan.FromSeconds(10)) rmin = TimeSpan.FromSeconds(10);
else
if
(rmin >= TimeSpan.FromSeconds(5)) rmin = TimeSpan.FromSeconds(5);
else
if
(rmin >= TimeSpan.FromSeconds(1)) rmin = TimeSpan.FromSeconds(1);
else
if
(rmin >= TimeSpan.FromMilliseconds(500)) rmin = TimeSpan.FromMilliseconds(500);
else
if
(rmin >= TimeSpan.FromMilliseconds(100)) rmin = TimeSpan.FromMilliseconds(100);
else
if
(rmin >= TimeSpan.FromMilliseconds(50)) rmin = TimeSpan.FromMilliseconds(50);
else
if
(rmin >= TimeSpan.FromMilliseconds(20)) rmin = TimeSpan.FromMilliseconds(20);
else
if
(rmin >= TimeSpan.FromMilliseconds(10)) rmin = TimeSpan.FromMilliseconds(10);
else
if
(rmin >= TimeSpan.FromMilliseconds(5)) rmin = TimeSpan.FromMilliseconds(5);
else
rmin = TimeSpan.FromMilliseconds(1);
//D Min Analysis -- Additing a gosth point, if necessary, for a good tick start
System.DateTime sdate =
new
System.DateTime(dmin.Value.Year, dmin.Value.Month, dmin.Value.Day);
FirstTick = sdate.AddSeconds(rmin.TotalSeconds * System.Math.Floor((dmin.Value - sdate).TotalSeconds / rmin.TotalSeconds));
if
(FirstTick.Value < dmin.Value)
mX.Minimum = FirstTick.Value;
TickLength = rmin.TotalSeconds;
mX.MajorStepUnit = Telerik.Charting.TimeInterval.Second;
mX.MajorStep = TickLength;
mX.LabelFitMode = Telerik.Charting.AxisLabelFitMode.MultiLine;
mX.PlotMode = Telerik.Charting.AxisPlotMode.OnTicks;
mX.LabelStyle = Resources[
"mCustomLabelStyle"
]
as
Style;
mC.Loaded += (x, y) => { RadCartesianChart_ZoomChanged(
null
,
null
); };
}
private
void
RadCartesianChart_ZoomChanged(
object
sender, Telerik.Windows.Controls.ChartView.ChartZoomChangedEventArgs e)
{
if
(mX ==
null
)
return
;
if
(!FirstTick.HasValue)
return
;
if
(!(mX
is
Telerik.Windows.Controls.ChartView.DateTimeContinuousAxis))
return
;
var axis = (mX
as
Telerik.Windows.Controls.ChartView.DateTimeContinuousAxis);
var range = axis.ActualVisibleRange.Maximum - axis.ActualVisibleRange.Minimum;
System.TimeSpan rv;
if
(range.TotalHours > 12 * mMaxLabelsCount)
//> 120 ore
rv = TimeSpan.FromDays(System.Math.Ceiling(range.TotalDays / mMaxLabelsCount));
else
if
(range.TotalHours > 6 * mMaxLabelsCount)
//>60
rv=TimeSpan.FromHours(12);
else
if
(range.TotalHours > 3 * mMaxLabelsCount)
rv = TimeSpan.FromHours(6);
else
if
(range.TotalHours > mMaxLabelsCount)
rv = TimeSpan.FromHours(3);
else
if
(range.TotalMinutes > 30 * mMaxLabelsCount)
rv = TimeSpan.FromHours(1);
else
if
(range.TotalMinutes > 15 * mMaxLabelsCount)
rv = TimeSpan.FromMinutes(30);
else
if
(range.TotalMinutes > mMaxLabelsCount)
rv = TimeSpan.FromHours(15);
else
if
(range.TotalSeconds > 30 * mMaxLabelsCount)
rv = TimeSpan.FromHours(1);
else
if
(range.TotalSeconds > 15 * mMaxLabelsCount)
rv = TimeSpan.FromSeconds(30);
else
if
(range.TotalSeconds > 1 * mMaxLabelsCount)
rv = TimeSpan.FromSeconds(15);
else
if
(range.TotalMilliseconds > 100 * mMaxLabelsCount)
rv = TimeSpan.FromSeconds(1);
else
rv = TimeSpan.FromSeconds(TickLength);
System.DateTime firsttick = FirstTick.Value.AddSeconds(TickLength * System.Math.Floor((axis.ActualVisibleRange.Minimum - FirstTick.Value).TotalSeconds / TickLength));
System.DateTime lasttick = FirstTick.Value.AddSeconds(TickLength * System.Math.Floor((axis.ActualVisibleRange.Maximum - FirstTick.Value).TotalSeconds / TickLength));
int
ticks = (
int
)((lasttick - firsttick).TotalSeconds / TickLength) + 1;
TimeSpan sv = rv.TotalDays >= 1 ? TimeSpan.FromDays(1) : rv;
System.DateTime sdate =
new
System.DateTime(FirstTick.Value.Year, FirstTick.Value.Month, FirstTick.Value.Day);
System.DateTime firstlabeltick = sdate.AddSeconds(sv.TotalSeconds * System.Math.Ceiling((axis.ActualVisibleRange.Minimum - sdate).TotalSeconds / sv.TotalSeconds));
int
ticklabelinterval = System.Math.Max((
int
)(rv.TotalSeconds / TickLength), 1);
int
firstlabeloffset = (
int
)((firstlabeltick - firsttick).TotalSeconds / TickLength);
mX.LabelInterval = ticklabelinterval;
mX.LabelOffset = firstlabeloffset;
axis.LabelFormat =
"yyyy/MM/dd\r\nHH:mm:ss"
+ ((range.TotalMilliseconds <= 100 * mMaxLabelsCount) ?
".fff"
:
string
.Empty);
mInfo.Text =
"LabelInterval: "
+ ticklabelinterval.ToString() +
"; Offset : "
+ firstlabeloffset.ToString() +
"; Min : "
+ axis.ActualVisibleRange.Minimum.ToString(
"yyyy/MM/dd HH:mm:ss"
)
+
"; First Tick : "
+ firsttick.ToString(
"yyyy/MM/dd HH:mm:ss"
) +
"; First Label Tick : "
+ firstlabeltick.ToString(
"yyyy/MM/dd HH:mm:ss"
) +
"; Visible Minimum: "
+ axis.ActualVisibleRange.Minimum.Ticks.ToString();
}
I am happy to see that you reached to this solution.
I ran your code and saw the described behavior. I can confirm that it is due to the rounding of the double of seconds. Nevertheless, it delivers a really nice user experience.
There is a property called MaximumTicks, but in order to have an effect, you need to leave the MajorStepUnit and MajorStep unset, which will lead to a behavior that you are successfully avoiding by doing those settings on zoom changed.
We do not support such scenario where you can control the number of gridlines. I have added it as a feature request at our public issue tracking system. You can vote for it to raise priority and monitor its progress.
The bar width depends of the size of each category in the chart. You can control its width, but have in mind that if you have it fixed, it will not rescale whenever you resize the window/chart.
<
telerik:BarSeries
Name
=
"mS"
>
<
telerik:BarSeries.PointTemplate
>
<
DataTemplate
>
<
Rectangle
Fill
=
"Blue"
Width
=
"10"
/>
</
DataTemplate
>
</
telerik:BarSeries.PointTemplate
>
</
telerik:BarSeries
>
I will forward your inquiries regarding the bar and grid architecture and the first tick property to the developers' team.
Thank you for your cooperation and understanding.
Regards,
Rosko
Telerik
Learn what features your users use (or don't use) in your application. Know your audience. Target it better. Develop wisely.
Sign up for Free application insights >>
Hello Telerik,
I have a similar scenario but I have a problem : I'm using a method to update the datetime axis and set MajorStep (and unit) depending on the period.
My method :
private
void
updateAxesDateTime(DateTimeContinuousAxis pAxe, DateTime pDateDebut, DateTime pDateFin)
{
TimeSpan range = pDateFin - pDateDebut;
if
(range >= TimeSpan.FromDays(1460))
//Visu sur 4 ans ou +
{
pAxe.LabelFormat =
"dd-MM-yyyy"
;
//Interval 1 an
pAxe.MajorStepUnit = Telerik.Charting.TimeInterval.Year;
pAxe.MajorStep = 1;
}
else
if
(range >= TimeSpan.FromDays(730) && range < TimeSpan.FromDays(1460))
//Visu sur 2 Ã 4 ans
{
pAxe.LabelFormat =
"dd-MM-yyyy"
;
//Interval 6 mois
pAxe.MajorStepUnit = Telerik.Charting.TimeInterval.Month;
pAxe.MajorStep = 6;
}
else
if
(range >= TimeSpan.FromDays(124) && range < TimeSpan.FromDays(730))
//Visu sur 4 mois à 2 ans
{
pAxe.LabelFormat =
"dd-MM-yyyy"
;
//Interval 1 mois
pAxe.MajorStepUnit = Telerik.Charting.TimeInterval.Month;
pAxe.MajorStep = 1;
}
else
if
(range >= TimeSpan.FromDays(31) && range < TimeSpan.FromDays(124))
//Visu sur 1 mois à 4 mois
{
pAxe.LabelFormat =
"dd-MM"
;
//Interval 1 semaine
pAxe.MajorStepUnit = Telerik.Charting.TimeInterval.Week;
pAxe.MajorStep = 1;
}
else
if
(range >= TimeSpan.FromDays(4) && range < TimeSpan.FromDays(31))
//Visu sur 4 jours à 1 mois
{
pAxe.LabelFormat =
"dd-MM"
;
//Interval 1 jour
pAxe.MajorStepUnit = Telerik.Charting.TimeInterval.Day;
pAxe.MajorStep = 1;
}
else
if
(range >= TimeSpan.FromDays(2) && range < TimeSpan.FromDays(4))
//Visu sur 2 jours à 4 jours
{
pAxe.LabelFormat =
"dd-MM HH:mm"
;
//Interval 6 heure
pAxe.MajorStepUnit = Telerik.Charting.TimeInterval.Hour;
pAxe.MajorStep = 6;
}
else
if
(range >= TimeSpan.FromHours(4) && range < TimeSpan.FromDays(2))
//Visu sur 4h à 2 jours
{
pAxe.LabelFormat =
"dd-MM HH:mm"
;
//Interval 1 heure
pAxe.MajorStepUnit = Telerik.Charting.TimeInterval.Hour;
pAxe.MajorStep = 1;
}
else
if
(range >= TimeSpan.FromHours(1) && range < TimeSpan.FromHours(4))
//Visu sur 1 Ã 4 heures
{
pAxe.LabelFormat =
"dd-MM HH:mm"
;
//Interval 30 minutes
pAxe.MajorStepUnit = Telerik.Charting.TimeInterval.Minute;
pAxe.MajorStep = 30
}
else
if
(range >= TimeSpan.FromMinutes(4) && range < TimeSpan.FromHours(1))
//Visu sur 4 minutes à 1 heure
{
pAxe.LabelFormat =
"dd-MM HH:mm"
;
//Interval 1 minute
pAxe.MajorStepUnit = Telerik.Charting.TimeInterval.Minute;
pAxe.MajorStep = 1;
}
else
if
(range >= TimeSpan.FromMinutes(1) && range < TimeSpan.FromMinutes(4))
//Visu sur 1 Ã 4 minutes
{
pAxe.LabelFormat =
"dd-MM HH:mm:ss"
;
//Interval 15 secondes
pAxe.MajorStepUnit = Telerik.Charting.TimeInterval.Second;
pAxe.MajorStep = 15;
}
else
//Visu sur - de 1 minute
{
pAxe.LabelFormat =
"dd-MM HH:mm:ss"
;
//Interval 1 seconde
pAxe.MajorStepUnit = Telerik.Charting.TimeInterval.Second;
pAxe.MajorStep = 1;
}
}
The problem is that based on the sixth 'if', the MajorStep isn't considered and just the MajorStepUnit acted as MajorStep. For exemple, in : [....]
//Interval 6 heure
pAxe.MajorStepUnit = Telerik.Charting.TimeInterval.Hour;
pAxe.MajorStep = 6;
[...] the datetime axis represents 1 Hour for MajorStep. If I set Week for the MajorStepUnit, my datetime axis will represents 1 week.
At the first five,they working find, but after, there is a problem.
Do you have any idea ?
Thank you very much !
Please find attached an isolated project and snapshot from it. Basically the project tries to simulate your scenario - DateTimeContinuousAxis with the following setup :
LabelFormat="dd-MM HH:mm"
MajorStepUnit="Hour"MajorStep="6"
I added 24 consecutive data objects which differ by one hour. The result is expected - 4 labels.
I hope this project can be used as a base for our discussion. We hope you will be able to modify it and show the issue you experience on your side. Thank you in advance for your cooperation.
Regards,
Petar Mladenov
Telerik by Progress
Hello Petar,
I did the correct code but my IsStepRecalculationOnZoomEnabled property was setted to True, and the calculating tick was automatic.
I set the property to False and now, the ticks are corrects.
Thank you for your help !