Files
aistudio-wpf-diagram/Live-Charts-master/UwpView/AxisSection.cs
2021-07-23 09:42:22 +08:00

472 lines
18 KiB
C#

//copyright(c) 2016 Alberto Rodriguez
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
using System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Shapes;
using LiveCharts.Definitions.Charts;
using LiveCharts.Dtos;
using LiveCharts.Helpers;
using LiveCharts.Uwp.Components;
namespace LiveCharts.Uwp
{
/// <summary>
/// An Axis section highlights values or ranges in a chart.
/// </summary>
public class AxisSection : FrameworkElement, IAxisSectionView
{
private readonly Rectangle _rectangle;
private TextBlock _label;
internal static AxisSection Dragging;
/// <summary>
/// Initializes a new instance of AxisSection class
/// </summary>
public AxisSection()
{
_rectangle = new Rectangle();
//_rectangle.MouseDown += (sender, args) =>
//{
// if (!Draggable) return;
// Dragging = this;
// args.Handled = true;
// Chart.Ldsp = null;
//};
//SetCurrentValue(StrokeProperty, new SolidColorBrush(Color.FromRgb(131, 172, 191)));
//SetCurrentValue(FillProperty, new SolidColorBrush(Color.FromRgb(131, 172, 191)) {Opacity = .35});
//SetCurrentValue(StrokeThicknessProperty, 0d);
}
#region Properties
/// <summary>
/// Gets or sets the model.
/// </summary>
/// <value>
/// The model.
/// </value>
public AxisSectionCore Model { get; set; }
/// <summary>
/// The label property
/// </summary>
public static readonly DependencyProperty LabelProperty = DependencyProperty.Register(
"Label", typeof(string), typeof(AxisSection), new PropertyMetadata(default(string)));
/// <summary>
/// Gets or sets the name, the title of the section, a visual element will be added to the chart if this property is not null.
/// </summary>
[Obsolete("Use a VisualElement instead")]
public string Label
{
get { return (string)GetValue(LabelProperty); }
set { SetValue(LabelProperty, value); }
}
/// <summary>
/// From value property
/// </summary>
public static readonly DependencyProperty FromValueProperty = DependencyProperty.Register(
"FromValue", typeof(double), typeof(AxisSection),
new PropertyMetadata(double.NaN, UpdateSection));
/// <summary>
/// Gets or sets the value where the section starts
/// </summary>
[Obsolete("This property will be removed in future versions, instead use Value and SectionWidth properties")]
public double FromValue
{
get { return (double)GetValue(FromValueProperty); }
set { SetValue(FromValueProperty, value); }
}
/// <summary>
/// To value property
/// </summary>
public static readonly DependencyProperty ToValueProperty = DependencyProperty.Register(
"ToValue", typeof(double), typeof(AxisSection),
new PropertyMetadata(double.NaN, UpdateSection));
/// <summary>
/// Gets or sets the value where the section ends
/// </summary>
[Obsolete("This property will be removed in future versions, instead use Value and SectionWidth properties")]
public double ToValue
{
get { return (double)GetValue(ToValueProperty); }
set { SetValue(ToValueProperty, value); }
}
/// <summary>
/// The value property
/// </summary>
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(
"Value", typeof(double), typeof(AxisSection), new PropertyMetadata(default(double), UpdateSection));
/// <summary>
/// Gets or sets the value where the section is drawn
/// </summary>
public double Value
{
get { return (double) GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
/// <summary>
/// The section width property
/// </summary>
public static readonly DependencyProperty SectionWidthProperty = DependencyProperty.Register(
"SectionWidth", typeof(double), typeof(AxisSection), new PropertyMetadata(default(double), UpdateSection));
/// <summary>
/// Gets or sets the section width
/// </summary>
public double SectionWidth
{
get { return (double) GetValue(SectionWidthProperty); }
set { SetValue(SectionWidthProperty, value); }
}
/// <summary>
/// The stroke property
/// </summary>
public static readonly DependencyProperty StrokeProperty = DependencyProperty.Register(
"Stroke", typeof(Brush), typeof(AxisSection), new PropertyMetadata(default(Brush)));
/// <summary>
/// Gets o sets the section stroke, the stroke brush will be used to draw the border of the section
/// </summary>
public Brush Stroke
{
get { return (Brush)GetValue(StrokeProperty); }
set { SetValue(StrokeProperty, value); }
}
/// <summary>
/// The fill property
/// </summary>
public static readonly DependencyProperty FillProperty = DependencyProperty.Register(
"Fill", typeof(Brush), typeof(AxisSection), new PropertyMetadata(default(Brush)));
/// <summary>
/// Gets or sets the section fill brush.
/// </summary>
public Brush Fill
{
get { return (Brush)GetValue(FillProperty); }
set { SetValue(FillProperty, value); }
}
/// <summary>
/// The stroke thickness property
/// </summary>
public static readonly DependencyProperty StrokeThicknessProperty = DependencyProperty.Register(
"StrokeThickness", typeof(double), typeof(AxisSection), new PropertyMetadata(default(double)));
/// <summary>
/// Gets or sets the stroke thickness.
/// </summary>
public double StrokeThickness
{
get { return (double)GetValue(StrokeThicknessProperty); }
set { SetValue(StrokeThicknessProperty, value); }
}
/// <summary>
/// The stroke dash array property
/// </summary>
public static readonly DependencyProperty StrokeDashArrayProperty = DependencyProperty.Register(
"StrokeDashArray", typeof(DoubleCollection), typeof(AxisSection), new PropertyMetadata(default(DoubleCollection)));
/// <summary>
/// Gets or sets the stroke dash array collection, use this property to create dashed stroke sections
/// </summary>
public DoubleCollection StrokeDashArray
{
get { return (DoubleCollection)GetValue(StrokeDashArrayProperty); }
set { SetValue(StrokeDashArrayProperty, value); }
}
/// <summary>
/// The draggable property
/// </summary>
public static readonly DependencyProperty DraggableProperty = DependencyProperty.Register(
"Draggable", typeof(bool), typeof(AxisSection), new PropertyMetadata(default(bool)));
/// <summary>
/// Gets or sets if a user can drag the section
/// </summary>
public bool Draggable
{
get { return (bool) GetValue(DraggableProperty); }
set { SetValue(DraggableProperty, value); }
}
/// <summary>
/// The disable animations property
/// </summary>
public static readonly DependencyProperty DisableAnimationsProperty = DependencyProperty.Register(
"DisableAnimations", typeof(bool), typeof(AxisSection), new PropertyMetadata(default(bool)));
/// <summary>
/// Gets or sets a value indicating whether the section is animated
/// </summary>
/// <value>
/// <c>true</c> if [disable animations]; otherwise, <c>false</c>.
/// </value>
public bool DisableAnimations
{
get { return (bool) GetValue(DisableAnimationsProperty); }
set { SetValue(DisableAnimationsProperty, value); }
}
/// <summary>
/// The data label property
/// </summary>
public static readonly DependencyProperty DataLabelProperty = DependencyProperty.Register(
"DataLabel", typeof(bool), typeof(AxisSection), new PropertyMetadata(default(bool)));
/// <summary>
/// Gets or sets a value indicating whether the section should display a label that displays its current value.
/// </summary>
/// <value>
/// <c>true</c> if [data label]; otherwise, <c>false</c>.
/// </value>
public bool DataLabel
{
get { return (bool) GetValue(DataLabelProperty); }
set { SetValue(DataLabelProperty, value); }
}
/// <summary>
/// The data label brush property
/// </summary>
public static readonly DependencyProperty DataLabelForegroundProperty = DependencyProperty.Register(
"DataLabelForeground", typeof(Brush), typeof(AxisSection), new PropertyMetadata(default(Brush)));
/// <summary>
/// Gets or sets the data label brush.
/// </summary>
/// <value>
/// The label brush.
/// </value>
public Brush DataLabelForeground
{
get { return (Brush) GetValue(DataLabelForegroundProperty); }
set { SetValue(DataLabelForegroundProperty, value); }
}
#endregion
/// <summary>
/// Draws the or move.
/// </summary>
/// <param name="source">The source.</param>
/// <param name="axis">The axis.</param>
public void DrawOrMove(AxisOrientation source, int axis)
{
_rectangle.Fill = Fill;
_rectangle.Stroke = Stroke;
_rectangle.StrokeDashArray = StrokeDashArray;
_rectangle.StrokeThickness = StrokeThickness;
Canvas.SetZIndex(_rectangle, Canvas.GetZIndex(this));
BindingOperations.SetBinding(_rectangle, VisibilityProperty,
new Binding {Path = new PropertyPath(nameof(Visibility)), Source = this});
var ax = source == AxisOrientation.X ? Model.Chart.AxisX[axis] : Model.Chart.AxisY[axis];
var uw = ax.EvaluatesUnitWidth ? ChartFunctions.GetUnitWidth(source, Model.Chart, axis) / 2 : 0;
if (Parent == null)
{
_label = ((Axis) ax.View).BindATextBlock();
_label.Padding = new Thickness(5, 2, 5, 2);
Model.Chart.View.AddToView(this);
Model.Chart.View.AddToDrawMargin(_rectangle);
Model.Chart.View.AddToView(_label);
_rectangle.Height = 0;
_rectangle.Width = 0;
Canvas.SetLeft(_rectangle, 0d);
Canvas.SetTop(_rectangle, Model.Chart.DrawMargin.Height);
#region Obsolete
Canvas.SetTop(_label, Model.Chart.DrawMargin.Height);
Canvas.SetLeft(_label, 0d);
#endregion
}
#pragma warning disable 618
var from = ChartFunctions.ToDrawMargin(double.IsNaN(FromValue) ? Value : FromValue, source, Model.Chart, axis) + uw;
#pragma warning restore 618
#pragma warning disable 618
var to = ChartFunctions.ToDrawMargin(double.IsNaN(ToValue) ? Value + SectionWidth : ToValue, source, Model.Chart, axis) + uw;
#pragma warning restore 618
if (from > to)
{
var temp = to;
to = from;
from = temp;
}
var anSpeed = Model.Chart.View.AnimationsSpeed;
if (DataLabel)
{
if (DataLabelForeground != null) _label.Foreground = DataLabelForeground;
_label.UpdateLayout();
//_label.Background = Stroke ?? Fill;
PlaceLabel(ax.GetFormatter()(Value), ax, source);
}
if (source == AxisOrientation.X)
{
var w = to - from;
w = StrokeThickness > w ? StrokeThickness : w;
Canvas.SetTop(_rectangle, 0);
_rectangle.Height = Model.Chart.DrawMargin.Height;
if (Model.Chart.View.DisableAnimations || DisableAnimations)
{
_rectangle.Width = w > 0 ? w : 0;
Canvas.SetLeft(_rectangle, from - StrokeThickness/2);
}
else
{
_rectangle.BeginDoubleAnimation(nameof(Width), w > 0 ? w : 0, anSpeed);
_rectangle.BeginDoubleAnimation("Canvas.Left", from - StrokeThickness / 2, anSpeed);
}
return;
}
var h = to - from;
h = StrokeThickness > h ? StrokeThickness : h;
Canvas.SetLeft(_rectangle, 0d);
_rectangle.Width = Model.Chart.DrawMargin.Width;
if (Model.Chart.View.DisableAnimations || DisableAnimations)
{
Canvas.SetTop(_rectangle, from - StrokeThickness/2);
_rectangle.Height = h > 0 ? h : 0;
}
else
{
_rectangle.BeginDoubleAnimation("Canvas.Left", from, anSpeed);
_rectangle.BeginDoubleAnimation(nameof(Height), h, anSpeed);
}
}
/// <summary>
/// Removes this instance.
/// </summary>
public void Remove()
{
Model.Chart.View.RemoveFromView(this);
Model.Chart.View.RemoveFromDrawMargin(_rectangle);
Model.Chart.View.RemoveFromDrawMargin(_label);
}
/// <summary>
/// Ases the core element.
/// </summary>
/// <param name="axis">The axis.</param>
/// <param name="source">The source.</param>
/// <returns></returns>
public AxisSectionCore AsCoreElement(AxisCore axis, AxisOrientation source)
{
var model = new AxisSectionCore(this, axis.Chart);
model.View.Model = model;
return model;
}
private static void UpdateSection(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
var section = (AxisSection) dependencyObject;
if (section.Model != null && section.Model.Chart != null)
{
if (!section.Model.Chart.AreComponentsLoaded) return;
section.DrawOrMove(section.Model.Source, section.Model.AxisIndex);
}
}
private void PlaceLabel(string text, AxisCore axis, AxisOrientation source)
{
_label.Text = text;
_label.UpdateLayout();
var transform = new LabelEvaluation(axis.View.LabelsRotation,
_label.Width + 10, _label.Height, axis, source);
_label.RenderTransform = Math.Abs(transform.LabelAngle) > 1
? new RotateTransform {Angle = transform.LabelAngle}
: null;
var toLine = ChartFunctions.ToPlotArea(Value, source, Model.Chart, axis);
var direction = source == AxisOrientation.X ? 1 : -1;
toLine += axis.EvaluatesUnitWidth ? direction * ChartFunctions.GetUnitWidth(source, Model.Chart, axis) / 2 : 0;
var toLabel = toLine + transform.GetOffsetBySource(source);
var chart = Model.Chart;
if (axis.IsMerged)
{
const double padding = 4;
if (source == AxisOrientation.Y)
{
if (toLabel + transform.ActualHeight >
chart.DrawMargin.Top + chart.DrawMargin.Height)
toLabel -= transform.ActualHeight + padding;
}
else
{
if (toLabel + transform.ActualWidth >
chart.DrawMargin.Left + chart.DrawMargin.Width)
toLabel -= transform.ActualWidth + padding;
}
}
var labelTab = axis.Tab;
labelTab += transform.GetOffsetBySource(source.Invert());
if (source == AxisOrientation.Y)
{
if (Model.View.DisableAnimations || DisableAnimations)
{
Canvas.SetLeft(_label, labelTab);
Canvas.SetTop(_label, toLabel);
return;
}
_label.BeginDoubleAnimation("Canvas.Top", toLabel, chart.View.AnimationsSpeed);
_label.BeginDoubleAnimation("Canvas.Left", labelTab, chart.View.AnimationsSpeed);
}
else
{
if (Model.View.DisableAnimations || DisableAnimations)
{
Canvas.SetLeft(_label, toLabel);
Canvas.SetTop(_label, labelTab);
return;
}
_label.BeginDoubleAnimation("Canvas.Left", toLabel, chart.View.AnimationsSpeed);
_label.BeginDoubleAnimation("Canvas.Top", labelTab, chart.View.AnimationsSpeed);
}
}
}
}