-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathTimeLine.cs
More file actions
157 lines (136 loc) · 7.72 KB
/
Copy pathTimeLine.cs
File metadata and controls
157 lines (136 loc) · 7.72 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
using System;
using System.Linq;
using System.Windows;
using Whathecode.System;
using Whathecode.System.Arithmetic.Range;
using Whathecode.System.Linq;
using Whathecode.System.Windows.Controls;
using Whathecode.System.Windows.DependencyPropertyFactory;
using Whathecode.System.Windows.DependencyPropertyFactory.Attributes;
using Whathecode.TimeLine.LabelFactories;
namespace Whathecode.TimeLine
{
public class TimeLine : TimeControl
{
public enum TimeLineProperties
{
LabelFactories,
DominantTickFactory,
DominantHeaderFactory,
DominantBreadcrumbFactory
}
static readonly Type Type = typeof( TimeLine );
public static readonly DependencyPropertyFactory<TimeLineProperties> Factory = new DependencyPropertyFactory<TimeLineProperties>();
public static readonly DependencyProperty LabelFactoriesProperty = Factory[ TimeLineProperties.LabelFactories ];
public static readonly DependencyProperty DominantTickFactoryProperty = Factory[ TimeLineProperties.DominantTickFactory ];
public static readonly DependencyProperty DominantHeaderFactoryProperty = Factory[ TimeLineProperties.DominantHeaderFactory ];
public static readonly DependencyProperty DominantBreadcrumbFactoryProperty = Factory[ TimeLineProperties.DominantBreadcrumbFactory ];
TimePanel _timePanel;
[DependencyProperty( TimeLineProperties.LabelFactories )]
public TimeLineLabelFactories LabelFactories
{
get { return (TimeLineLabelFactories)Factory.GetValue( this, TimeLineProperties.LabelFactories ); }
set { Factory.SetValue( this, TimeLineProperties.LabelFactories, value ); }
}
[DependencyProperty( TimeLineProperties.DominantTickFactory, DefaultValue = "" )]
public string DominantTickFactory
{
get { return (string)Factory.GetValue( this, TimeLineProperties.DominantTickFactory ); }
private set { Factory.SetValue( this,TimeLineProperties.DominantTickFactory, value ); }
}
[DependencyProperty( TimeLineProperties.DominantHeaderFactory, DefaultValue = "" )]
public string DominantHeaderFactory
{
get { return (string)Factory.GetValue( this, TimeLineProperties.DominantHeaderFactory ); }
private set { Factory.SetValue( this,TimeLineProperties.DominantHeaderFactory, value ); }
}
[DependencyProperty( TimeLineProperties.DominantBreadcrumbFactory, DefaultValue = "" )]
public string DominantBreadcrumbFactory
{
get { return (string)Factory.GetValue( this, TimeLineProperties.DominantBreadcrumbFactory ); }
private set { Factory.SetValue( this,TimeLineProperties.DominantBreadcrumbFactory, value ); }
}
static TimeLine()
{
DefaultStyleKeyProperty.OverrideMetadata( Type, new FrameworkPropertyMetadata( Type ) );
}
public TimeLine()
{
// TODO: Could intervals be specified in style, and factory instances initialized in code behind?
// Currently this is initialized in code-behind since XAML resources are reused,
// and the factories contain generated labels belonging to a specific TimeLine instance.
LabelFactories = new TimeLineLabelFactories
{
// Ticks, from quarters to years.
new TimeLineTickFactory { Name="Quarters", StepSize = TimeSpan.FromMinutes( 15 ), MinimumPixelsBetweenLabels = 60, OverrideGroup = "Ticks" },
new TimeLineTickFactory { Name="Hours", TimeStepSize = DateTimePart.Hour, MinimumPixelsBetweenLabels = 60, OverrideGroup = "Ticks" },
new TimeLineTickFactory { Name="DayQuarters", StepSize = TimeSpan.FromHours( 6 ), MinimumPixelsBetweenLabels = 60, OverrideGroup = "Ticks" },
new TimeLineTickFactory { Name="Days", TimeStepSize = DateTimePart.Day, MinimumPixelsBetweenLabels = 50, OverrideGroup = "Ticks" },
new TimeLineTickFactory { Name="Weeks", StepSize = TimeSpan.FromDays( 7 ), MinimumPixelsBetweenLabels = 60, OverrideGroup = "Ticks" },
new TimeLineTickFactory { Name="Months", TimeStepSize = DateTimePart.Month, MinimumPixelsBetweenLabels = 50, OverrideGroup = "Ticks" },
new TimeLineTickFactory { Name="Years", TimeStepSize = DateTimePart.Year, MinimumPixelsBetweenLabels = 60, OverrideGroup = "Ticks" },
// Additional context labels at bottom.
new TimeLineContextLabelFactory { Name = "DayContext", TimeStepSize = DateTimePart.Day, MinimumPixelsBetweenLabels = 50, FixedY = 100 },
new TimeLineContextLabelFactory { Name = "MonthContext", TimeStepSize = DateTimePart.Month, MinimumPixelsBetweenLabels = 100, FixedY = 100 },
new TimeLineContextLabelFactory { Name = "YearContext", TimeStepSize = DateTimePart.Year, MinimumPixelsBetweenLabels = 100, FixedY = 100 },
// Header labels.
new TimeLineHeaderFactory { Name = "YearHeader", TimeStepSize = DateTimePart.Year, MinimumPixelsBetweenLabels = 200 },
new TimeLineHeaderFactory { Name = "MonthHeader", TimeStepSize = DateTimePart.Month, MinimumPixelsBetweenLabels = 200 },
new TimeLineHeaderFactory { Name = "WeekHeader", StepSize = TimeSpan.FromDays( 7 ), MinimumPixelsBetweenLabels = 200 },
new TimeLineHeaderFactory { Name = "DayHeader", TimeStepSize = DateTimePart.Day, MinimumPixelsBetweenLabels = 200 },
new TimeLineHeaderFactory { Name = "DayQuarterHeader", StepSize = TimeSpan.FromHours( 6 ), MinimumPixelsBetweenLabels = 200 },
new TimeLineHeaderFactory { Name = "HourHeader", TimeStepSize = DateTimePart.Hour, MinimumPixelsBetweenLabels = 200 },
new TimeLineHeaderFactory { Name = "QuarterHeader", StepSize = TimeSpan.FromMinutes( 15 ), MinimumPixelsBetweenLabels = 200 },
// Breadcrumb labels underneath headers.
new TimeLineBreadcrumbFactory { Name = "YearBreadcrumbs", TimeStepSize = DateTimePart.Year, MinimumPixelsBetweenLabels = 200 },
new TimeLineBreadcrumbFactory { Name = "MonthBreadcrumbs", TimeStepSize = DateTimePart.Month, MinimumPixelsBetweenLabels = 200 },
new TimeLineBreadcrumbFactory { Name = "DayBreadcrumbs", TimeStepSize = DateTimePart.Day, MinimumPixelsBetweenLabels = 200 },
// Fixed elements.
new TimeLineLabelCollection { new TimeIndicator() }
};
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
_timePanel = (TimePanel)GetTemplateChild( "PART_Labels" );
if ( _timePanel == null )
{
return;
}
// Identify the dominant labels before they are displayed.
_timePanel.LayoutUpdated += ( sender, args ) =>
{
if ( LabelFactories != null )
{
// Find the factory which has populated the time line with the most tick labels which are still visible.
var visibleTicks = LabelFactories.OfType<TimeLineTickFactory>().Where( f => !f.MinimumPixelsExceeded ).ToList();
DominantTickFactory = visibleTicks.Count == 0 ? "" : visibleTicks.MinBy( f => f.MaximumLabelSize ).Name;
// Get dominant header and breadcrumb factories.
var dontFit = LabelFactories
.OfType<TimeLineHeaderFactory>() // Get the smallest interval which is too large to fit the screen vertically.
.Where( f => ( (double)f.MaximumLabelSize.Ticks / VisibleInterval.Size.Ticks ) * ActualWidth > ActualHeight )
.ToList();
TimeLineHeaderFactory currentHeaderFactory = dontFit.Count == 0 ? null : dontFit.MinBy( f => f.MaximumLabelSize );
if ( currentHeaderFactory != null )
{
DominantHeaderFactory = currentHeaderFactory.Name;
// The dominant breadcrumb factory is the first factory bigger than the dominant header factory.
TimeLineBreadcrumbFactory breadcrumbFactory = LabelFactories
.OfType<TimeLineBreadcrumbFactory>()
.OrderBy( f => f.MaximumLabelSize )
.FirstOrDefault( f => f.MaximumLabelSize > currentHeaderFactory.MaximumLabelSize );
DominantBreadcrumbFactory = breadcrumbFactory == null ? "" : breadcrumbFactory.Name;
}
else
{
DominantHeaderFactory = "";
}
}
};
}
public Interval<DateTime, TimeSpan> GetCoercedVisibleInterval()
{
return _timePanel != null ? _timePanel.VisibleIntervalX : VisibleInterval;
}
}
}