更改自定义圆环图的起始角度和方向
Changing starting angle and direction of a custom doughnut chart
我正在尝试在 WPF 中创建圆环图并使用 this helpful previous answer。
但是,目前 StartAngle 从 3 点钟位置开始,例如
如何更改此代码,使 StartAngle 从 12 点钟位置开始,角度按顺时针方向测量,例如
1] StartAngle = 0, EndAngle = 90 => 覆盖右上角。
2] StartAngle = 0, EndAngle = 180 => 覆盖右半边。
3] StartAngle = 0, EndAngle = 270 => 覆盖图表的四分之三。
我试过将 SweepDirection.Counterclockwise
更改为 SweepDirection.Clockwise
,但这不起作用。我还尝试在我的 Arc class 中添加 ScaleTransform
和 RotateTransform
,如下所示。
WPF代码:
<Viewbox Stretch="Uniform" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Grid Height="100" Width="200">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Rectangle x:Name="divider" Fill="DimGray" Width="2" VerticalAlignment="Stretch" Height="70" Grid.Column="1" Grid.RowSpan="2"/>
<notifications1:Arc
Grid.Column="0"
Stroke="DimGray"
StrokeThickness="5"
StartAngle="0" EndAngle="359.999"
Margin="20"/>
<notifications1:Arc
Grid.Column="0"
Stroke="{Binding DaySalesPercentage, Converter={StaticResource StorePerformanceToColourConverter}}"
StrokeThickness="5"
StartAngle="0" EndAngle="{Binding DaySalesPercentage, Converter={StaticResource StorePerformanceToAngleConverter}}"
Margin="20"/>
<Label Content="sales remaining today"
x:Name="testing"
Foreground="{Binding IsDaySalesPercentageAvailable, Converter={StaticResource UnavailableStorePerformanceToColourConverter}}"
HorizontalContentAlignment="Center"
FontSize="9"
FontWeight="DemiBold"
VerticalAlignment="Top"
Margin="0,0,0,0"
Grid.Column="0"/>
<Label Content="{Binding DaySalesPercentageLabel}"
x:Name="DaySalesPercentageLabel1"
Foreground="{Binding IsDaySalesPercentageAvailable, Converter={StaticResource UnavailableStorePerformanceToColourConverter}}"
HorizontalContentAlignment="Center"
FontSize="20"
FontWeight="DemiBold"
VerticalAlignment="Top"
Margin="0,28,0,0"
Grid.Column="0"/>
<Label Content="-£60"
x:Name="DaySalesPercentageLabel2"
Foreground="{Binding IsDaySalesPercentageAvailable, Converter={StaticResource UnavailableStorePerformanceToColourConverter}}"
HorizontalContentAlignment="Center"
FontSize="10"
FontWeight="DemiBold"
VerticalAlignment="Top"
Margin="0,50,0,0"
Grid.Column="0"/>
</Grid>
</Viewbox>
Arc.cs:
public class Arc : Shape
{
public double StartAngle
{
get { return (double)GetValue(StartAngleProperty); }
set { SetValue(StartAngleProperty, value); }
}
// Using a DependencyProperty as the backing store for StartAngle. This enables animation, styling, binding, etc...
public static readonly DependencyProperty StartAngleProperty =
DependencyProperty.Register("StartAngle", typeof(double), typeof(Arc), new PropertyMetadata(0.0, AnglesChanged));
public double EndAngle
{
get { return (double)GetValue(EndAngleProperty); }
set { SetValue(EndAngleProperty, value); }
}
// Using a DependencyProperty as the backing store for EndAngle. This enables animation, styling, binding, etc...
public static readonly DependencyProperty EndAngleProperty =
DependencyProperty.Register("EndAngle", typeof(double), typeof(Arc), new PropertyMetadata(0.0, AnglesChanged));
protected override Geometry DefiningGeometry
{
get
{
return GetArcGeometry();
}
}
private static void AnglesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var arc = d as Arc;
if (arc != null)
arc.InvalidateVisual();
}
private Geometry GetArcGeometry()
{
Point startPoint = PointAtAngle(Math.Min(StartAngle, EndAngle));
Point endPoint = PointAtAngle(Math.Max(StartAngle, EndAngle));
Size arcSize = new Size(Math.Max(0, (RenderSize.Width - StrokeThickness) / 2),
Math.Max(0, (RenderSize.Height - StrokeThickness) / 2));
bool isLargeArc = Math.Abs(EndAngle - StartAngle) > 180;
StreamGeometry geom = new StreamGeometry();
using (StreamGeometryContext context = geom.Open())
{
context.BeginFigure(startPoint, false, false);
context.ArcTo(endPoint, arcSize, 0, isLargeArc,
SweepDirection.Counterclockwise, true, false);
}
geom.Transform = new TranslateTransform(StrokeThickness / 2, StrokeThickness / 2);
return geom;
}
private Point PointAtAngle(double angle)
{
double radAngle = angle * (Math.PI / 180);
double xRadius = (RenderSize.Width - StrokeThickness) / 2;
double yRadius = (RenderSize.Height - StrokeThickness) / 2;
double x = xRadius + xRadius * Math.Cos(radAngle);
double y = yRadius - yRadius * Math.Sin(radAngle);
return new Point(x, y);
}
}
我试过添加以下内容:
<notifications1:Arc
Grid.Column="0"
Stroke="{Binding DaySalesPercentage, Converter={StaticResource StorePerformanceToColourConverter}}"
StrokeThickness="5"
StartAngle="0" EndAngle="{Binding DaySalesPercentage, Converter={StaticResource StorePerformanceToAngleConverter}}"
Margin="20">
<notifications1:Arc.RenderTransform>
<TransformGroup>
<!-- Triple the size (scale) of the button in the Y direction. -->
<ScaleTransform ScaleX="-1" ScaleY="1" />
<!-- Rotate the button by 45 degrees. -->
<RotateTransform Angle="90" />
</TransformGroup>
</notifications1:Arc.RenderTransform>
</notifications1:Arc>
像这样旋转和移动圆弧:
你差不多明白了
只需使用 LayoutTransform
而不是 RenderTransform
这里是 EndAngle = 120 和 LayoutTransform 的显示:
我正在尝试在 WPF 中创建圆环图并使用 this helpful previous answer。
但是,目前 StartAngle 从 3 点钟位置开始,例如
如何更改此代码,使 StartAngle 从 12 点钟位置开始,角度按顺时针方向测量,例如
1] StartAngle = 0, EndAngle = 90 => 覆盖右上角。
2] StartAngle = 0, EndAngle = 180 => 覆盖右半边。
3] StartAngle = 0, EndAngle = 270 => 覆盖图表的四分之三。
我试过将 SweepDirection.Counterclockwise
更改为 SweepDirection.Clockwise
,但这不起作用。我还尝试在我的 Arc class 中添加 ScaleTransform
和 RotateTransform
,如下所示。
WPF代码:
<Viewbox Stretch="Uniform" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Grid Height="100" Width="200">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Rectangle x:Name="divider" Fill="DimGray" Width="2" VerticalAlignment="Stretch" Height="70" Grid.Column="1" Grid.RowSpan="2"/>
<notifications1:Arc
Grid.Column="0"
Stroke="DimGray"
StrokeThickness="5"
StartAngle="0" EndAngle="359.999"
Margin="20"/>
<notifications1:Arc
Grid.Column="0"
Stroke="{Binding DaySalesPercentage, Converter={StaticResource StorePerformanceToColourConverter}}"
StrokeThickness="5"
StartAngle="0" EndAngle="{Binding DaySalesPercentage, Converter={StaticResource StorePerformanceToAngleConverter}}"
Margin="20"/>
<Label Content="sales remaining today"
x:Name="testing"
Foreground="{Binding IsDaySalesPercentageAvailable, Converter={StaticResource UnavailableStorePerformanceToColourConverter}}"
HorizontalContentAlignment="Center"
FontSize="9"
FontWeight="DemiBold"
VerticalAlignment="Top"
Margin="0,0,0,0"
Grid.Column="0"/>
<Label Content="{Binding DaySalesPercentageLabel}"
x:Name="DaySalesPercentageLabel1"
Foreground="{Binding IsDaySalesPercentageAvailable, Converter={StaticResource UnavailableStorePerformanceToColourConverter}}"
HorizontalContentAlignment="Center"
FontSize="20"
FontWeight="DemiBold"
VerticalAlignment="Top"
Margin="0,28,0,0"
Grid.Column="0"/>
<Label Content="-£60"
x:Name="DaySalesPercentageLabel2"
Foreground="{Binding IsDaySalesPercentageAvailable, Converter={StaticResource UnavailableStorePerformanceToColourConverter}}"
HorizontalContentAlignment="Center"
FontSize="10"
FontWeight="DemiBold"
VerticalAlignment="Top"
Margin="0,50,0,0"
Grid.Column="0"/>
</Grid>
</Viewbox>
Arc.cs:
public class Arc : Shape
{
public double StartAngle
{
get { return (double)GetValue(StartAngleProperty); }
set { SetValue(StartAngleProperty, value); }
}
// Using a DependencyProperty as the backing store for StartAngle. This enables animation, styling, binding, etc...
public static readonly DependencyProperty StartAngleProperty =
DependencyProperty.Register("StartAngle", typeof(double), typeof(Arc), new PropertyMetadata(0.0, AnglesChanged));
public double EndAngle
{
get { return (double)GetValue(EndAngleProperty); }
set { SetValue(EndAngleProperty, value); }
}
// Using a DependencyProperty as the backing store for EndAngle. This enables animation, styling, binding, etc...
public static readonly DependencyProperty EndAngleProperty =
DependencyProperty.Register("EndAngle", typeof(double), typeof(Arc), new PropertyMetadata(0.0, AnglesChanged));
protected override Geometry DefiningGeometry
{
get
{
return GetArcGeometry();
}
}
private static void AnglesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var arc = d as Arc;
if (arc != null)
arc.InvalidateVisual();
}
private Geometry GetArcGeometry()
{
Point startPoint = PointAtAngle(Math.Min(StartAngle, EndAngle));
Point endPoint = PointAtAngle(Math.Max(StartAngle, EndAngle));
Size arcSize = new Size(Math.Max(0, (RenderSize.Width - StrokeThickness) / 2),
Math.Max(0, (RenderSize.Height - StrokeThickness) / 2));
bool isLargeArc = Math.Abs(EndAngle - StartAngle) > 180;
StreamGeometry geom = new StreamGeometry();
using (StreamGeometryContext context = geom.Open())
{
context.BeginFigure(startPoint, false, false);
context.ArcTo(endPoint, arcSize, 0, isLargeArc,
SweepDirection.Counterclockwise, true, false);
}
geom.Transform = new TranslateTransform(StrokeThickness / 2, StrokeThickness / 2);
return geom;
}
private Point PointAtAngle(double angle)
{
double radAngle = angle * (Math.PI / 180);
double xRadius = (RenderSize.Width - StrokeThickness) / 2;
double yRadius = (RenderSize.Height - StrokeThickness) / 2;
double x = xRadius + xRadius * Math.Cos(radAngle);
double y = yRadius - yRadius * Math.Sin(radAngle);
return new Point(x, y);
}
}
我试过添加以下内容:
<notifications1:Arc
Grid.Column="0"
Stroke="{Binding DaySalesPercentage, Converter={StaticResource StorePerformanceToColourConverter}}"
StrokeThickness="5"
StartAngle="0" EndAngle="{Binding DaySalesPercentage, Converter={StaticResource StorePerformanceToAngleConverter}}"
Margin="20">
<notifications1:Arc.RenderTransform>
<TransformGroup>
<!-- Triple the size (scale) of the button in the Y direction. -->
<ScaleTransform ScaleX="-1" ScaleY="1" />
<!-- Rotate the button by 45 degrees. -->
<RotateTransform Angle="90" />
</TransformGroup>
</notifications1:Arc.RenderTransform>
</notifications1:Arc>
像这样旋转和移动圆弧:
你差不多明白了
只需使用 LayoutTransform
而不是 RenderTransform
这里是 EndAngle = 120 和 LayoutTransform 的显示: