Created
December 31, 2014 09:48
-
-
Save ceee/98d83a35ff5783f6c4a3 to your computer and use it in GitHub Desktop.
Gauge in WinRT
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<Style x:Key="Gauge" TargetType="controls:Gauge"> | |
<Setter Property="FontFamily" Value="Segoe WP" /> | |
<Setter Property="Background" Value="Transparent" /> | |
<Setter Property="Template"> | |
<Setter.Value> | |
<ControlTemplate TargetType="controls:Gauge"> | |
<Viewbox> | |
<Grid x:Name="Container" Height="200" Width="200"> | |
<Path Name="PART_Scale" Stroke="{TemplateBinding ScaleBrush}" StrokeThickness="{TemplateBinding ScaleWidth}" /> | |
<Path Name="PART_Trail" Stroke="{TemplateBinding TrailBrush}" StrokeThickness="{TemplateBinding ScaleWidth}" /> | |
<StackPanel Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Center"> | |
<TextBlock Name="PART_ValueText" Foreground="{TemplateBinding ValueBrush}" FontSize="{TemplateBinding FontSize}" | |
FontFamily="{TemplateBinding FontFamily}" Text="{TemplateBinding Value}" TextAlignment="Center" Margin="0 0 0 2" /> | |
<TextBlock Foreground="{TemplateBinding ValueBrush}" FontSize="{TemplateBinding FontSize}" | |
FontFamily="{TemplateBinding FontFamily}" Text=" %" TextAlignment="Center" Margin="0 0 0 2" /> | |
</StackPanel> | |
</Grid> | |
</Viewbox> | |
</ControlTemplate> | |
</Setter.Value> | |
</Setter> | |
</Style> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Windows; | |
using Windows.Foundation; | |
using Windows.UI; | |
using Windows.UI.Xaml; | |
using Windows.UI.Xaml.Controls; | |
using Windows.UI.Xaml.Media; | |
using Windows.UI.Xaml.Shapes; | |
namespace App.Controls | |
{ | |
/// <summary> | |
/// A Modern UI Radial Gauge. | |
/// </summary> | |
[TemplatePart(Name = NeedlePartName, Type = typeof(Path))] | |
[TemplatePart(Name = ScalePartName, Type = typeof(Path))] | |
[TemplatePart(Name = TrailPartName, Type = typeof(Path))] | |
[TemplatePart(Name = ValueTextPartName, Type = typeof(TextBlock))] | |
public class Gauge : Control | |
{ | |
#region Constants | |
private const string NeedlePartName = "PART_Needle"; | |
private const string ScalePartName = "PART_Scale"; | |
private const string TrailPartName = "PART_Trail"; | |
private const string ValueTextPartName = "PART_ValueText"; | |
private const double Degrees2Radians = Math.PI / 180; | |
#endregion Constants | |
#region Dependency Property Registrations | |
public static readonly DependencyProperty MinimumProperty = | |
DependencyProperty.Register("Minimum", typeof(double), typeof(Gauge), new PropertyMetadata(0.0)); | |
public static readonly DependencyProperty MaximumProperty = | |
DependencyProperty.Register("Maximum", typeof(double), typeof(Gauge), new PropertyMetadata(100.0, OnValueChanged)); | |
public static readonly DependencyProperty ScaleWidthProperty = | |
DependencyProperty.Register("ScaleWidth", typeof(Double), typeof(Gauge), new PropertyMetadata(26.0)); | |
public static readonly DependencyProperty ValueProperty = | |
DependencyProperty.Register("Value", typeof(double), typeof(Gauge), new PropertyMetadata(0.0, OnValueChanged)); | |
public static readonly DependencyProperty UnitProperty = | |
DependencyProperty.Register("Unit", typeof(string), typeof(Gauge), new PropertyMetadata(string.Empty)); | |
public static readonly DependencyProperty NeedleBrushProperty = | |
DependencyProperty.Register("NeedleBrush", typeof(Brush), typeof(Gauge), new PropertyMetadata(new SolidColorBrush(Colors.Red))); | |
public static readonly DependencyProperty ScaleBrushProperty = | |
DependencyProperty.Register("ScaleBrush", typeof(Brush), typeof(Gauge), new PropertyMetadata(new SolidColorBrush(Colors.DarkGray))); | |
public static readonly DependencyProperty TickBrushProperty = | |
DependencyProperty.Register("TickBrush", typeof(Brush), typeof(Gauge), new PropertyMetadata(new SolidColorBrush(Colors.White))); | |
public static readonly DependencyProperty TrailBrushProperty = | |
DependencyProperty.Register("TrailBrush", typeof(Brush), typeof(Gauge), new PropertyMetadata(new SolidColorBrush(Colors.Orange))); | |
public static readonly DependencyProperty ValueBrushProperty = | |
DependencyProperty.Register("ValueBrush", typeof(Brush), typeof(Gauge), new PropertyMetadata(new SolidColorBrush(Colors.White))); | |
public static readonly DependencyProperty ScaleTickBrushProperty = | |
DependencyProperty.Register("ScaleTickBrush", typeof(Brush), typeof(Gauge), new PropertyMetadata(new SolidColorBrush(Colors.Black))); | |
public static readonly DependencyProperty UnitBrushProperty = | |
DependencyProperty.Register("UnitBrush", typeof(Brush), typeof(Gauge), new PropertyMetadata(new SolidColorBrush(Colors.White))); | |
public static readonly DependencyProperty ValueStringFormatProperty = | |
DependencyProperty.Register("ValueStringFormat", typeof(string), typeof(Gauge), new PropertyMetadata("N0")); | |
protected static readonly DependencyProperty ValueAngleProperty = | |
DependencyProperty.Register("ValueAngle", typeof(double), typeof(Gauge), new PropertyMetadata(null)); | |
protected static readonly DependencyProperty TicksProperty = | |
DependencyProperty.Register("Ticks", typeof(IEnumerable<double>), typeof(Gauge), new PropertyMetadata(null)); | |
#endregion Dependency Property Registrations | |
#region Constructors | |
public Gauge() | |
{ | |
this.DefaultStyleKey = typeof(Gauge); | |
this.Ticks = this.getTicks(); | |
} | |
#endregion Constructors | |
#region Properties | |
public double Minimum | |
{ | |
get { return (double)GetValue(MinimumProperty); } | |
set { SetValue(MinimumProperty, value); } | |
} | |
public double Maximum | |
{ | |
get { return (double)GetValue(MaximumProperty); } | |
set { SetValue(MaximumProperty, value); } | |
} | |
public Double ScaleWidth | |
{ | |
get { return (Double)GetValue(ScaleWidthProperty); } | |
set { SetValue(ScaleWidthProperty, value); } | |
} | |
public double Value | |
{ | |
get { return (double)GetValue(ValueProperty); } | |
set { SetValue(ValueProperty, value); } | |
} | |
public string Unit | |
{ | |
get { return (string)GetValue(UnitProperty); } | |
set { SetValue(UnitProperty, value); } | |
} | |
public Brush NeedleBrush | |
{ | |
get { return (Brush)GetValue(NeedleBrushProperty); } | |
set { SetValue(NeedleBrushProperty, value); } | |
} | |
public Brush TrailBrush | |
{ | |
get { return (Brush)GetValue(TrailBrushProperty); } | |
set { SetValue(TrailBrushProperty, value); } | |
} | |
public Brush ScaleBrush | |
{ | |
get { return (Brush)GetValue(ScaleBrushProperty); } | |
set { SetValue(ScaleBrushProperty, value); } | |
} | |
public Brush ScaleTickBrush | |
{ | |
get { return (Brush)GetValue(ScaleTickBrushProperty); } | |
set { SetValue(ScaleTickBrushProperty, value); } | |
} | |
public Brush TickBrush | |
{ | |
get { return (Brush)GetValue(TickBrushProperty); } | |
set { SetValue(TickBrushProperty, value); } | |
} | |
public Brush ValueBrush | |
{ | |
get { return (Brush)GetValue(ValueBrushProperty); } | |
set { SetValue(ValueBrushProperty, value); } | |
} | |
public Brush UnitBrush | |
{ | |
get { return (Brush)GetValue(UnitBrushProperty); } | |
set { SetValue(UnitBrushProperty, value); } | |
} | |
public string ValueStringFormat | |
{ | |
get { return (string)GetValue(ValueStringFormatProperty); } | |
set { SetValue(ValueStringFormatProperty, value); } | |
} | |
protected double ValueAngle | |
{ | |
get { return (double)GetValue(ValueAngleProperty); } | |
set { SetValue(ValueAngleProperty, value); } | |
} | |
public IEnumerable<double> Ticks | |
{ | |
get { return (IEnumerable<double>)GetValue(TicksProperty); } | |
protected set { SetValue(TicksProperty, value); } | |
} | |
#endregion Properties | |
protected override void OnApplyTemplate() | |
{ | |
// Draw Scale | |
var scale = this.GetTemplateChild(ScalePartName) as Path; | |
if (scale != null) | |
{ | |
var pg = new PathGeometry(); | |
var pf = new PathFigure(); | |
pf.IsClosed = true; | |
var middleOfScale = 77 - this.ScaleWidth / 2; | |
pf.StartPoint = this.ScalePoint(-180, middleOfScale); | |
var seg = new ArcSegment(); | |
seg.SweepDirection = SweepDirection.Clockwise; | |
seg.IsLargeArc = true; | |
seg.Size = new Size(middleOfScale, middleOfScale); | |
seg.Point = this.ScalePoint(179, middleOfScale); | |
pf.Segments.Add(seg); | |
pg.Figures.Add(pf); | |
scale.Data = pg; | |
} | |
OnValueChanged(this); | |
base.OnApplyTemplate(); | |
} | |
private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) | |
{ | |
OnValueChanged(d); | |
} | |
private static void OnValueChanged(DependencyObject d) | |
{ | |
Gauge c = (Gauge)d; | |
if (!Double.IsNaN(c.Value)) | |
{ | |
var middleOfScale = 77 - c.ScaleWidth / 2; | |
var needle = c.GetTemplateChild(NeedlePartName) as Path; | |
var valueText = c.GetTemplateChild(ValueTextPartName) as TextBlock; | |
c.ValueAngle = c.ValueToAngle(c.Value); | |
// Needle | |
if (needle != null) | |
{ | |
needle.RenderTransform = new RotateTransform() { Angle = c.ValueAngle }; | |
} | |
// Trail | |
var trail = c.GetTemplateChild(TrailPartName) as Path; | |
if (trail != null) | |
{ | |
trail.Visibility = Visibility.Visible; | |
var pg = new PathGeometry(); | |
var pf = new PathFigure(); | |
pf.IsClosed = false; | |
pf.StartPoint = c.ScalePoint(0, middleOfScale); | |
var seg = new ArcSegment(); | |
seg.SweepDirection = SweepDirection.Clockwise; | |
// We start from -150, so +30 becomes a large arc. | |
seg.IsLargeArc = c.ValueAngle >= 180; | |
seg.Size = new Size(middleOfScale, middleOfScale); | |
seg.Point = c.ScalePoint(c.ValueAngle >= 360 ? 359.9999 : c.ValueAngle, middleOfScale); | |
pf.Segments.Add(seg); | |
pg.Figures.Add(pf); | |
trail.Data = pg; | |
} | |
// Value Text | |
if (valueText != null) | |
{ | |
valueText.Text = c.Value.ToString(c.ValueStringFormat); | |
} | |
} | |
} | |
private Point ScalePoint(double angle, double middleOfScale) | |
{ | |
return new Point(100 + Math.Sin(Degrees2Radians * angle) * middleOfScale, 100 - Math.Cos(Degrees2Radians * angle) * middleOfScale); | |
} | |
private double ValueToAngle(double value) | |
{ | |
double minAngle = 0; | |
double maxAngle = 360; | |
// Off-scale to the left | |
if (value < this.Minimum) | |
{ | |
return minAngle; | |
} | |
// Off-scale to the right | |
if (value > this.Maximum) | |
{ | |
return maxAngle; | |
} | |
double angularRange = maxAngle - minAngle; | |
return (value - this.Minimum) / (this.Maximum - this.Minimum) * angularRange + minAngle; | |
} | |
private IEnumerable<double> getTicks() | |
{ | |
double tickSpacing = (this.Maximum - this.Minimum) / 10; | |
for (double tick = this.Minimum; tick <= this.Maximum; tick += tickSpacing) | |
{ | |
yield return ValueToAngle(tick); | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<controls:Gauge Value="{Binding Achievements.AchievedPercentage}" Maximum="100" Margin="0" Style="{StaticResource Gauge}" | |
ScaleBrush="{ThemeResource BrushMid}" ScaleWidth="14" FontSize="32" | |
ValueBrush="{StaticResource BrushText}" TrailBrush="{ThemeResource BrushPrimary}" Width="140" | |
HorizontalAlignment="Left" VerticalAlignment="Top" /> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment