00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053 using System;
00054 using System.Drawing;
00055 using System.Collections;
00056 using System.Globalization;
00057
00058
00059
00060
00061
00062 namespace NPlot
00063 {
00067 public class DateTimeAxis : Axis
00068 {
00069
00070
00071 #region Clone implementation
00076 public override object Clone()
00077 {
00078 DateTimeAxis a = new DateTimeAxis();
00079
00080 if (this.GetType() != a.GetType())
00081 {
00082 throw new NPlotException( "Clone not defined in derived type. Help!" );
00083 }
00084 DoClone( this, a );
00085 return a;
00086 }
00087
00088
00094 protected static void DoClone( DateTimeAxis b, DateTimeAxis a )
00095 {
00096 Axis.DoClone( b, a );
00097 }
00098 #endregion
00099
00100 private void Init()
00101 {
00102 }
00103
00104
00109 public DateTimeAxis( Axis a )
00110 : base( a )
00111 {
00112 this.Init();
00113 this.NumberFormat = null;
00114 }
00115
00116
00120 public DateTimeAxis()
00121 : base()
00122 {
00123 this.Init();
00124 }
00125
00126
00132 public DateTimeAxis( double worldMin, double worldMax )
00133 : base( worldMin, worldMax )
00134 {
00135 this.Init();
00136 }
00137
00138
00144 public DateTimeAxis( long worldMin, long worldMax )
00145 : base( (double)worldMin, (double)worldMax )
00146 {
00147 this.Init();
00148 }
00149
00150
00156 public DateTimeAxis( DateTime worldMin, DateTime worldMax )
00157 : base( (double)worldMin.Ticks, (double)worldMax.Ticks )
00158 {
00159 this.Init();
00160 }
00161
00162
00171 protected override void DrawTicks(
00172 Graphics g,
00173 Point physicalMin,
00174 Point physicalMax,
00175 out object labelOffset,
00176 out object boundingBox )
00177 {
00178
00179
00180
00181 Point tLabelOffset;
00182 Rectangle tBoundingBox;
00183
00184 labelOffset = this.getDefaultLabelOffset( physicalMin, physicalMax );
00185 boundingBox = null;
00186
00187 ArrayList largeTicks;
00188 ArrayList smallTicks;
00189 this.WorldTickPositions( physicalMin, physicalMax, out largeTicks, out smallTicks );
00190
00191
00192 for (int i=0; i<smallTicks.Count; ++i)
00193 {
00194 this.DrawTick( g, (double)smallTicks[i],
00195 this.SmallTickSize, "", new Point(0, 0),
00196 physicalMin, physicalMax,
00197 out tLabelOffset, out tBoundingBox );
00198
00199 }
00200
00201
00202 for (int i=0; i<largeTicks.Count; ++i)
00203 {
00204
00205 DateTime tickDate = new DateTime( (long)((double)largeTicks[i]) );
00206 string label = "";
00207
00208 if(this.NumberFormat == null || this.NumberFormat == String.Empty)
00209 {
00210 if ( this.LargeTickLabelType_ == LargeTickLabelType.year )
00211 {
00212 label = tickDate.Year.ToString();
00213 }
00214
00215 else if ( this.LargeTickLabelType_ == LargeTickLabelType.month )
00216 {
00217 label = tickDate.ToString("MMM");
00218 label += " ";
00219 label += tickDate.Year.ToString().Substring(2,2);
00220 }
00221
00222 else if ( this.LargeTickLabelType_ == LargeTickLabelType.day )
00223 {
00224 label = (tickDate.Day).ToString();
00225 label += " ";
00226 label += tickDate.ToString("MMM");
00227 }
00228
00229 else if ( this.LargeTickLabelType_ == LargeTickLabelType.hourMinute )
00230 {
00231 string minutes = tickDate.Minute.ToString();
00232 if (minutes.Length == 1)
00233 {
00234 minutes = "0" + minutes;
00235 }
00236 label = tickDate.Hour.ToString() + ":" + minutes;
00237 }
00238 else if ( this.LargeTickLabelType_ == LargeTickLabelType.hourMinuteSeconds )
00239 {
00240 string minutes = tickDate.Minute.ToString();
00241 string seconds = tickDate.Second.ToString();
00242 if (seconds.Length == 1)
00243 {
00244 seconds = "0" + seconds;
00245 }
00246
00247 if (minutes.Length == 1)
00248 {
00249 minutes = "0" + minutes;
00250 }
00251 label = tickDate.Hour.ToString() + ":" + minutes + "." + seconds;
00252 }
00253
00254 }
00255 else
00256 {
00257 label = tickDate.ToString(NumberFormat);
00258 }
00259
00260 this.DrawTick( g, (double)largeTicks[i],
00261 this.LargeTickSize, label, new Point( 0, 0 ),
00262 physicalMin, physicalMax, out tLabelOffset, out tBoundingBox );
00263
00264 Axis.UpdateOffsetAndBounds( ref labelOffset, ref boundingBox, tLabelOffset, tBoundingBox );
00265 }
00266
00267 }
00268
00269
00270 private enum LargeTickLabelType
00271 {
00272 none = 0,
00273 year = 1,
00274 month = 2,
00275 day = 3,
00276 hourMinute = 4,
00277 hourMinuteSeconds = 5
00278 }
00279
00280
00281
00282 private LargeTickLabelType LargeTickLabelType_;
00283
00293 internal override void WorldTickPositions_FirstPass(
00294 Point physicalMin,
00295 Point physicalMax,
00296 out ArrayList largeTickPositions,
00297 out ArrayList smallTickPositions
00298 )
00299 {
00300 smallTickPositions = null;
00301
00302 largeTickPositions = new ArrayList();
00303
00304 const int daysInMonth = 30;
00305
00306 TimeSpan timeLength = new TimeSpan( (long)(WorldMax-WorldMin));
00307 DateTime worldMinDate = new DateTime( (long)this.WorldMin );
00308 DateTime worldMaxDate = new DateTime( (long)this.WorldMax );
00309
00310 if(largeTickStep_ == TimeSpan.Zero)
00311 {
00312
00313
00314
00315 if ( timeLength < new TimeSpan(0,0,2,0,0) )
00316 {
00317 this.LargeTickLabelType_ = LargeTickLabelType.hourMinuteSeconds;
00318
00319 double secondsSkip;
00320
00321 if (timeLength < new TimeSpan( 0,0,0,10,0 ) )
00322 secondsSkip = 1.0;
00323 else if ( timeLength < new TimeSpan(0,0,0,20,0) )
00324 secondsSkip = 2.0;
00325 else if ( timeLength < new TimeSpan(0,0,0,50,0) )
00326 secondsSkip = 5.0;
00327 else if ( timeLength < new TimeSpan(0,0,2,30,0) )
00328 secondsSkip = 15.0;
00329 else
00330 secondsSkip = 30.0;
00331
00332 int second = worldMinDate.Second;
00333 second -= second % (int)secondsSkip;
00334
00335 DateTime currentTickDate = new DateTime(
00336 worldMinDate.Year,
00337 worldMinDate.Month,
00338 worldMinDate.Day,
00339 worldMinDate.Hour,
00340 second,0,0 );
00341
00342 while ( currentTickDate < worldMaxDate )
00343 {
00344 double world = (double)currentTickDate.Ticks;
00345
00346 if ( world >= this.WorldMin && world <= this.WorldMax )
00347 {
00348 largeTickPositions.Add( world );
00349 }
00350
00351 currentTickDate = currentTickDate.AddSeconds( secondsSkip );
00352 }
00353 }
00354
00355
00356
00357 else if ( timeLength < new TimeSpan(0,2,0,0,0) )
00358 {
00359 this.LargeTickLabelType_ = LargeTickLabelType.hourMinute;
00360
00361 double minuteSkip;
00362
00363 if ( timeLength < new TimeSpan(0,0,10,0,0) )
00364 minuteSkip = 1.0;
00365 else if ( timeLength < new TimeSpan(0,0,20,0,0) )
00366 minuteSkip = 2.0;
00367 else if ( timeLength < new TimeSpan(0,0,50,0,0) )
00368 minuteSkip = 5.0;
00369 else if ( timeLength < new TimeSpan(0,2,30,0,0) )
00370 minuteSkip = 15.0;
00371 else
00372 minuteSkip = 30.0;
00373
00374 int minute = worldMinDate.Minute;
00375 minute -= minute % (int)minuteSkip;
00376
00377 DateTime currentTickDate = new DateTime(
00378 worldMinDate.Year,
00379 worldMinDate.Month,
00380 worldMinDate.Day,
00381 worldMinDate.Hour,
00382 minute,0,0 );
00383
00384 while ( currentTickDate < worldMaxDate )
00385 {
00386 double world = (double)currentTickDate.Ticks;
00387
00388 if ( world >= this.WorldMin && world <= this.WorldMax )
00389 {
00390 largeTickPositions.Add( world );
00391 }
00392
00393 currentTickDate = currentTickDate.AddMinutes( minuteSkip );
00394 }
00395 }
00396
00397
00398
00399 else if ( timeLength < new TimeSpan(2,0,0,0,0) )
00400 {
00401 this.LargeTickLabelType_ = LargeTickLabelType.hourMinute;
00402
00403 double hourSkip;
00404 if ( timeLength < new TimeSpan(0,10,0,0,0) )
00405 hourSkip = 1.0;
00406 else if ( timeLength < new TimeSpan(0,20,0,0,0) )
00407 hourSkip = 2.0;
00408 else
00409 hourSkip = 6.0;
00410
00411
00412 int hour = worldMinDate.Hour;
00413 hour -= hour % (int)hourSkip;
00414
00415 DateTime currentTickDate = new DateTime(
00416 worldMinDate.Year,
00417 worldMinDate.Month,
00418 worldMinDate.Day,
00419 hour,0,0,0 );
00420
00421 while ( currentTickDate < worldMaxDate )
00422 {
00423 double world = (double)currentTickDate.Ticks;
00424
00425 if ( world >= this.WorldMin && world <= this.WorldMax )
00426 {
00427 largeTickPositions.Add( world );
00428 }
00429
00430 currentTickDate = currentTickDate.AddHours( hourSkip );
00431 }
00432
00433 }
00434
00435
00436
00437
00438 else if ( timeLength < new TimeSpan(daysInMonth*4,0,0,0,0))
00439 {
00440 this.LargeTickLabelType_ = LargeTickLabelType.day;
00441
00442 double daySkip;
00443 if ( timeLength < new TimeSpan(10,0,0,0,0) )
00444 daySkip = 1.0;
00445 else if (timeLength < new TimeSpan(20,0,0,0,0) )
00446 daySkip = 2.0;
00447 else if (timeLength < new TimeSpan(7*10,0,0,0,0) )
00448 daySkip = 7.0;
00449 else
00450 daySkip = 14.0;
00451
00452 DateTime currentTickDate = new DateTime(
00453 worldMinDate.Year,
00454 worldMinDate.Month,
00455 worldMinDate.Day );
00456
00457 if (daySkip == 2.0)
00458 {
00459
00460 TimeSpan timeSinceBeginning = currentTickDate - DateTime.MinValue;
00461
00462 if (timeSinceBeginning.Days % 2 == 1)
00463 currentTickDate = currentTickDate.AddDays(-1.0);
00464 }
00465
00466 if (daySkip == 7 || daySkip == 14.0)
00467 {
00468 DayOfWeek dow = currentTickDate.DayOfWeek;
00469 switch (dow)
00470 {
00471 case DayOfWeek.Monday:
00472 break;
00473 case DayOfWeek.Tuesday:
00474 currentTickDate = currentTickDate.AddDays(-1.0);
00475 break;
00476 case DayOfWeek.Wednesday:
00477 currentTickDate = currentTickDate.AddDays(-2.0);
00478 break;
00479 case DayOfWeek.Thursday:
00480 currentTickDate = currentTickDate.AddDays(-3.0);
00481 break;
00482 case DayOfWeek.Friday:
00483 currentTickDate = currentTickDate.AddDays(-4.0);
00484 break;
00485 case DayOfWeek.Saturday:
00486 currentTickDate = currentTickDate.AddDays(-5.0);
00487 break;
00488 case DayOfWeek.Sunday:
00489 currentTickDate = currentTickDate.AddDays(-6.0);
00490 break;
00491 }
00492
00493 }
00494
00495 if (daySkip == 14.0f)
00496 {
00497 TimeSpan timeSinceBeginning = currentTickDate - DateTime.MinValue;
00498
00499 if ((timeSinceBeginning.Days / 7) % 2 == 1)
00500 {
00501 currentTickDate = currentTickDate.AddDays(-7.0);
00502 }
00503 }
00504
00505 while ( currentTickDate < worldMaxDate )
00506 {
00507 double world = (double)currentTickDate.Ticks;
00508
00509 if ( world >= this.WorldMin && world <= this.WorldMax )
00510 {
00511 largeTickPositions.Add( world );
00512 }
00513
00514 currentTickDate = currentTickDate.AddDays(daySkip);
00515 }
00516 }
00517
00518
00519
00520
00521 else if ( timeLength >= new TimeSpan(daysInMonth*4,0,0,0,0) )
00522 {
00523
00524 int monthSpacing = 0;
00525
00526 if ( timeLength.Days < daysInMonth*(12*3+6) )
00527 {
00528 LargeTickLabelType_ = LargeTickLabelType.month;
00529
00530 if ( timeLength.Days < daysInMonth*10 )
00531 monthSpacing = 1;
00532 else if ( timeLength.Days < daysInMonth*(12*2) )
00533 monthSpacing = 3;
00534 else
00535 monthSpacing = 6;
00536 }
00537 else
00538 {
00539 LargeTickLabelType_ = LargeTickLabelType.year;
00540
00541 if (timeLength.Days < daysInMonth * (12 * 6))
00542 monthSpacing = 12;
00543 else if (timeLength.Days < daysInMonth * (12 * 12))
00544 monthSpacing = 24;
00545 else if (timeLength.Days < daysInMonth * (12 * 30))
00546 monthSpacing = 60;
00547 else
00548 monthSpacing = 120;
00549
00550 }
00551
00552
00553 DateTime currentTickDate = new DateTime(
00554 worldMinDate.Year,
00555 worldMinDate.Month,
00556 1 );
00557
00558 if (monthSpacing > 1)
00559 {
00560 currentTickDate = currentTickDate.AddMonths(
00561 -(currentTickDate.Month-1)%monthSpacing );
00562 }
00563
00564
00565 if (monthSpacing >= 24)
00566 {
00567 currentTickDate = currentTickDate.AddYears(
00568 -(currentTickDate.Year)%(monthSpacing/12) );
00569 }
00570
00571
00572
00573 if ( LargeTickLabelType_ != LargeTickLabelType.none )
00574 {
00575 while ( currentTickDate < worldMaxDate )
00576 {
00577 double world = (double)currentTickDate.Ticks;
00578
00579 if ( world >= this.WorldMin && world <= this.WorldMax )
00580 {
00581 largeTickPositions.Add( world );
00582 }
00583
00584 currentTickDate = currentTickDate.AddMonths( monthSpacing );
00585 }
00586 }
00587 }
00588 }
00589 else
00590 {
00591 for (DateTime date = worldMinDate; date < worldMaxDate; date += largeTickStep_)
00592 {
00593 largeTickPositions.Add((double)date.Ticks);
00594 }
00595 }
00596 }
00597
00598
00611 internal override void WorldTickPositions_SecondPass(
00612 Point physicalMin,
00613 Point physicalMax,
00614 ArrayList largeTickPositions,
00615 ref ArrayList smallTickPositions
00616 )
00617 {
00618 if (largeTickPositions.Count < 2 || !(LargeTickLabelType_.Equals(LargeTickLabelType.year)))
00619 {
00620 smallTickPositions = new ArrayList(); ;
00621 }
00622 else
00623 {
00624 smallTickPositions = new ArrayList();
00625 double diff = 0.5 * (((double)largeTickPositions[1]) - ((double)largeTickPositions[0]));
00626 if (((double)largeTickPositions[0] - diff) > this.WorldMin)
00627 {
00628 smallTickPositions.Add((double)largeTickPositions[0] - diff);
00629 }
00630 for (int i = 0; i < largeTickPositions.Count - 1; i++)
00631 {
00632 smallTickPositions.Add(((double)largeTickPositions[i]) + diff);
00633 }
00634 if (((double)largeTickPositions[largeTickPositions.Count - 1] + diff) < this.WorldMax)
00635 {
00636 smallTickPositions.Add((double)largeTickPositions[largeTickPositions.Count - 1] + diff);
00637 }
00638 }
00639 }
00640
00641
00646 public TimeSpan LargeTickStep
00647 {
00648 set
00649 {
00650 largeTickStep_ = value;
00651 }
00652 get
00653 {
00654 return largeTickStep_;
00655 }
00656 }
00657 private TimeSpan largeTickStep_ = TimeSpan.Zero;
00658
00659
00660 }
00661 }