From b196093150cf731a5b390600a084097170206c45 Mon Sep 17 00:00:00 2001 From: beto-rodriguez Date: Sat, 27 Aug 2022 19:27:48 -0500 Subject: [PATCH 01/50] drawTicksPath, improves multiple axes sample --- .../Axes/Multiple/ViewModel.cs | 15 ++++ .../ViewModelsSamples/Axes/Style/ViewModel.cs | 2 + src/LiveChartsCore/Axis.cs | 79 +++++++++++++------ src/LiveChartsCore/CartesianChart.cs | 3 + .../Kernel/Sketches/ICartesianAxis.cs | 21 +++-- 5 files changed, 89 insertions(+), 31 deletions(-) diff --git a/samples/ViewModelsSamples/Axes/Multiple/ViewModel.cs b/samples/ViewModelsSamples/Axes/Multiple/ViewModel.cs index ddc8418d3..63d6299ce 100644 --- a/samples/ViewModelsSamples/Axes/Multiple/ViewModel.cs +++ b/samples/ViewModelsSamples/Axes/Multiple/ViewModel.cs @@ -66,16 +66,26 @@ public partial class ViewModel Name = "Tens", NameTextSize = 14, NamePaint = new SolidColorPaint(s_blue), + NamePadding = new LiveChartsCore.Drawing.Padding(0, 20), + Padding = new LiveChartsCore.Drawing.Padding(0, 0, 20, 0), TextSize = 12, LabelsPaint = new SolidColorPaint(s_blue), + TicksPaint = new SolidColorPaint(s_blue), + SubticksPaint = new SolidColorPaint(s_blue), + DrawTicksPath = true }, new Axis // the "hundreds" series will be scaled on this axis { Name = "Hundreds", NameTextSize = 14, NamePaint = new SolidColorPaint(s_red), + NamePadding = new LiveChartsCore.Drawing.Padding(0, 20), + Padding = new LiveChartsCore.Drawing.Padding(20, 0, 0, 0), TextSize = 12, LabelsPaint = new SolidColorPaint(s_red), + TicksPaint = new SolidColorPaint(s_red), + SubticksPaint = new SolidColorPaint(s_red), + DrawTicksPath = true, ShowSeparatorLines = false, Position = LiveChartsCore.Measure.AxisPosition.End }, @@ -83,9 +93,14 @@ public partial class ViewModel { Name = "Thousands", NameTextSize = 14, + NamePadding = new LiveChartsCore.Drawing.Padding(0, 20), + Padding = new LiveChartsCore.Drawing.Padding(20, 0, 0, 0), NamePaint = new SolidColorPaint(s_yellow), TextSize = 12, LabelsPaint = new SolidColorPaint(s_yellow), + TicksPaint = new SolidColorPaint(s_yellow), + SubticksPaint = new SolidColorPaint(s_yellow), + DrawTicksPath = true, ShowSeparatorLines = false, Position = LiveChartsCore.Measure.AxisPosition.End } diff --git a/samples/ViewModelsSamples/Axes/Style/ViewModel.cs b/samples/ViewModelsSamples/Axes/Style/ViewModel.cs index 222d2e897..b10dbeb64 100644 --- a/samples/ViewModelsSamples/Axes/Style/ViewModel.cs +++ b/samples/ViewModelsSamples/Axes/Style/ViewModel.cs @@ -32,6 +32,7 @@ public partial class ViewModel { new Axis { + Position = LiveChartsCore.Measure.AxisPosition.End, Name = "X axis", NamePaint = new SolidColorPaint(s_gray1), TextSize = 18, @@ -70,6 +71,7 @@ public partial class ViewModel { new Axis { + Position = LiveChartsCore.Measure.AxisPosition.End, Name = "Y axis", NamePaint = new SolidColorPaint(s_gray1), TextSize = 18, diff --git a/src/LiveChartsCore/Axis.cs b/src/LiveChartsCore/Axis.cs index c9bc31d62..7279f549c 100644 --- a/src/LiveChartsCore/Axis.cs +++ b/src/LiveChartsCore/Axis.cs @@ -23,7 +23,6 @@ using System; using System.Collections.Generic; using System.ComponentModel; -using System.Diagnostics; using System.Linq; using System.Runtime.CompilerServices; using LiveChartsCore.Drawing; @@ -54,8 +53,8 @@ public abstract class Axis /// protected readonly Dictionary>> activeSeparators = new(); - // xo (x origin) and yo (y origin) are the distance to the center of the axis to the control bounds internal float _xo = 0f, _yo = 0f; + internal LvcSize _size; internal AxisOrientation _orientation; internal AnimatableAxisBounds _animatableBounds = new(); internal Bounds _dataBounds = new(); @@ -78,11 +77,12 @@ public abstract class Axis private double _textSize = 16; private IPaint? _separatorsPaint; private IPaint? _subseparatorsPaint; + private bool _drawTicksPath; + private ILineGeometry? _ticksPath; private IPaint? _ticksPaint; private IPaint? _subticksPaint; private IPaint? _zeroPaint; private ILineGeometry? _zeroLine; - private bool _showTicks = true; private bool _showSeparatorLines = true; private bool _isVisible = true; private bool _isInverted; @@ -96,6 +96,7 @@ public abstract class Axis float ICartesianAxis.Xo { get => _xo; set => _xo = value; } float ICartesianAxis.Yo { get => _yo; set => _yo = value; } + LvcSize ICartesianAxis.Size { get => _size; set => _size = value; } LvcRectangle ICartesianAxis.LabelsDesiredSize { get => _labelsDesiredSize; set => _labelsDesiredSize = value; } LvcRectangle ICartesianAxis.NameDesiredSize { get => _nameDesiredSize; set => _nameDesiredSize = value; } @@ -158,6 +159,9 @@ public abstract class Axis /// public IPaint? SubseparatorsPaint { get => _subseparatorsPaint; set { _subseparatorsPaint = value; OnPropertyChanged(); } } + /// + public bool DrawTicksPath { get => _drawTicksPath; set { _drawTicksPath = value; OnPropertyChanged(); } } + /// public IPaint? TicksPaint { get => _ticksPaint; set { _ticksPaint = value; OnPropertyChanged(); } } @@ -167,9 +171,6 @@ public abstract class Axis /// public IPaint? ZeroPaint { get => _zeroPaint; set { _zeroPaint = value; OnPropertyChanged(); } } - /// - public bool ShowTicks { get => _showTicks; set { _showTicks = value; OnPropertyChanged(); } } - /// public bool IsVisible { get => _isVisible; set { _isVisible = value; OnPropertyChanged(); } } @@ -387,6 +388,37 @@ NamePadding is not null || SeparatorsPaint is not null || LabelsPaint is not nul } } + if (TicksPaint is not null && _drawTicksPath) + { + if (_ticksPath is null) + { + _ticksPath = new TLineGeometry(); + InitializeLine(_ticksPath, cartesianChart); + TicksPaint.AddGeometryToPaintTask(cartesianChart.Canvas, _ticksPath); + } + + if (_orientation == AxisOrientation.X) + { + var yp = xoo + _size.Height * 0.5f * (_position == AxisPosition.Start ? -1 : 1); + _ticksPath.X = lxi; + _ticksPath.X1 = lxj; + _ticksPath.Y = yp; + _ticksPath.Y1 = yp; + } + else + { + var xp = xoo + _size.Width * 0.5f * (_position == AxisPosition.Start ? 1 : -1); + _ticksPath.X = xp; + _ticksPath.X1 = xp; + _ticksPath.Y = lyi; + _ticksPath.Y1 = lyj; + } + + if (!_animatableBounds.HasPreviousState) _ticksPath.CompleteTransition(null); + } + if (TicksPaint is not null && _ticksPath is not null && !_drawTicksPath) + TicksPaint.RemoveGeometryFromPainTask(cartesianChart.Canvas, _ticksPath); + for (var i = start - s; i <= max + s; i += s) { var separatorKey = labeler(i - 1d + 1d); @@ -416,8 +448,6 @@ NamePadding is not null || SeparatorsPaint is not null || LabelsPaint is not nul yc = actualScale.ToPixels(i); } - if (_orientation == AxisOrientation.Y) Trace.WriteLine($"@{i:N2}"); - if (!separators.TryGetValue(separatorKey, out var visualSeparator)) { visualSeparator = new AxisVisualSeprator() { Value = i }; @@ -426,22 +456,21 @@ NamePadding is not null || SeparatorsPaint is not null || LabelsPaint is not nul { InitializeSeparator(visualSeparator, cartesianChart); UpdateSeparator(visualSeparator.Separator!, xc, yc, lxi, lxj, lyi, lyj, UpdateMode.UpdateAndComplete); - if (_orientation == AxisOrientation.Y) Trace.WriteLine($"{i:N2} => {yc:N2}"); } if (SubseparatorsPaint is not null) { InitializeSubseparators(visualSeparator, cartesianChart); UpdateSubseparators(visualSeparator.Subseparators!, actualScale, s, xc, yc, lxi, lxj, lyi, lyj, UpdateMode.UpdateAndComplete); } - if (TicksPaint is not null && ShowTicks) + if (TicksPaint is not null) { InitializeTick(visualSeparator, cartesianChart); - UpdateTick(visualSeparator.Tick!, _tickLength, xc, yc, lxi, lxj, lyi, lyj, UpdateMode.UpdateAndComplete); + UpdateTick(visualSeparator.Tick!, _tickLength, xc, yc, UpdateMode.UpdateAndComplete); } if (SubticksPaint is not null && _subSections > 0) { InitializeSubticks(visualSeparator, cartesianChart); - UpdateSubticks(visualSeparator.Subticks!, actualScale, s, xc, yc, lxi, lxj, lyi, lyj, UpdateMode.UpdateAndComplete); + UpdateSubticks(visualSeparator.Subticks!, actualScale, s, xc, yc, UpdateMode.UpdateAndComplete); } if (LabelsPaint is not null) { @@ -465,8 +494,8 @@ NamePadding is not null || SeparatorsPaint is not null || LabelsPaint is not nul if (visualSeparator.Separator is not null) UpdateSeparator(visualSeparator.Separator, x, y, lxi, lxj, lyi, lyj, UpdateMode.Update); if (visualSeparator.Subseparators is not null) UpdateSubseparators(visualSeparator.Subseparators, scale, s, x, y, lxi, lxj, lyi, lyj, UpdateMode.Update); - if (visualSeparator.Tick is not null) UpdateTick(visualSeparator.Tick, _tickLength, x, y, lxi, lxj, lyi, lyj, UpdateMode.Update); - if (visualSeparator.Subticks is not null) UpdateSubticks(visualSeparator.Subticks, scale, s, x, y, lxi, lxj, lyi, lyj, UpdateMode.Update); + if (visualSeparator.Tick is not null) UpdateTick(visualSeparator.Tick, _tickLength, x, y, UpdateMode.Update); + if (visualSeparator.Subticks is not null) UpdateSubticks(visualSeparator.Subticks, scale, s, x, y, UpdateMode.Update); if (visualSeparator.Label is not null) UpdateLabel(visualSeparator.Label, x, y, labelContent, hasRotation, r, UpdateMode.Update); if (hasActivePaint) _ = measured.Add(visualSeparator); @@ -491,8 +520,8 @@ NamePadding is not null || SeparatorsPaint is not null || LabelsPaint is not nul if (separator.Separator is not null) UpdateSeparator(separator.Separator, x, y, lxi, lxj, lyi, lyj, UpdateMode.UpdateAndRemove); if (separator.Subseparators is not null) UpdateSubseparators(separator.Subseparators, scale, s, x, y, lxi, lxj, lyi, lyj, UpdateMode.UpdateAndRemove); - if (separator.Tick is not null) UpdateTick(separator.Tick, _tickLength, x, y, lxi, lxj, lyi, lyj, UpdateMode.UpdateAndRemove); - if (separator.Subticks is not null) UpdateSubticks(separator.Subticks, scale, s, x, y, lxi, lxj, lyi, lyj, UpdateMode.UpdateAndRemove); + if (separator.Tick is not null) UpdateTick(separator.Tick, _tickLength, x, y, UpdateMode.UpdateAndRemove); + if (separator.Subticks is not null) UpdateSubticks(separator.Subticks, scale, s, x, y, UpdateMode.UpdateAndRemove); if (separator.Label is not null) UpdateLabel(separator.Label, x, y, labeler(separator.Value - 1d + 1d), hasRotation, r, UpdateMode.UpdateAndRemove); _ = separators.Remove(separatorValueKey.Key); @@ -815,19 +844,23 @@ private void UpdateSeparator( } private void UpdateTick( - ILineGeometry tick, float length, float x, float y, float lxi, float lxj, float lyi, float lyj, UpdateMode mode) + ILineGeometry tick, float length, float x, float y, UpdateMode mode) { if (_orientation == AxisOrientation.X) { + var lyi = y - _size.Height * 0.5f; + var lyj = y + _size.Height * 0.5f; tick.X = x; tick.X1 = x; - tick.Y = lyj; - tick.Y1 = lyj + length; + tick.Y = _position == AxisPosition.Start ? lyj : lyi - length; + tick.Y1 = _position == AxisPosition.Start ? lyj + length : lyi; } else { - tick.X = lxi; - tick.X1 = lxi - length; + var lxi = x + _size.Width * 0.5f; + var lxj = x - _size.Width * 0.5f; + tick.X = _position == AxisPosition.Start ? lxi : lxj + length; + tick.X1 = _position == AxisPosition.Start ? lxi - length : lxj; tick.Y = y; tick.Y1 = y; } @@ -858,7 +891,7 @@ private void UpdateSubseparators( } private void UpdateSubticks( - ILineGeometry[] subticks, Scaler scale, double s, float x, float y, float lxi, float lxj, float lyi, float lyj, UpdateMode mode) + ILineGeometry[] subticks, Scaler scale, double s, float x, float y, UpdateMode mode) { for (var j = 0; j < subticks.Length; j++) { @@ -878,7 +911,7 @@ private void UpdateSubticks( ys = scale.MeasureInPixels(s * kl); } - UpdateTick(subtick, _tickLength * k, x + xs, y + ys, lxi, lxj, lyi, lyj, mode); + UpdateTick(subtick, _tickLength * k, x + xs, y + ys, mode); } } diff --git a/src/LiveChartsCore/CartesianChart.cs b/src/LiveChartsCore/CartesianChart.cs index 66bb943d6..b2ede9022 100644 --- a/src/LiveChartsCore/CartesianChart.cs +++ b/src/LiveChartsCore/CartesianChart.cs @@ -566,6 +566,8 @@ protected internal override void Measure() var drawablePlane = (IPlane)axis; var ns = drawablePlane.GetNameLabelSize(this); var s = drawablePlane.GetPossibleSize(this); + axis.Size = s; + if (axis.Position == AxisPosition.Start) { // X Bottom @@ -611,6 +613,7 @@ protected internal override void Measure() var drawablePlane = (IPlane)axis; var ns = drawablePlane.GetNameLabelSize(this); var s = drawablePlane.GetPossibleSize(this); + axis.Size = s; var w = s.Width; if (axis.Position == AxisPosition.Start) diff --git a/src/LiveChartsCore/Kernel/Sketches/ICartesianAxis.cs b/src/LiveChartsCore/Kernel/Sketches/ICartesianAxis.cs index 7afadd66f..8d65208e8 100644 --- a/src/LiveChartsCore/Kernel/Sketches/ICartesianAxis.cs +++ b/src/LiveChartsCore/Kernel/Sketches/ICartesianAxis.cs @@ -64,6 +64,14 @@ public interface ICartesianAxis : IPlane, INotifyPropertyChanged /// float Yo { get; set; } + /// + /// Gets or sets the size of the axis, this value is used internally to calculate the axis position. + /// + /// + /// The length. + /// + LvcSize Size { get; set; } + /// /// Gets or sets the reserved area for the labels. /// @@ -109,6 +117,11 @@ public interface ICartesianAxis : ICartesianAxis /// IPaint? SubseparatorsPaint { get; set; } + /// + /// Gets or sets whether the ticks path should be drawn. + /// + bool DrawTicksPath { get; set; } + /// /// Gets or sets the separators paint. /// @@ -132,12 +145,4 @@ public interface ICartesianAxis : ICartesianAxis /// The separators paint. /// IPaint? ZeroPaint { get; set; } - - /// - /// Gets or sets the separators paint. - /// - /// - /// The separators paint. - /// - bool ShowTicks { get; set; } } From 6ce92498dd2d6b6cdc6b16acc6b86d29f167cb26 Mon Sep 17 00:00:00 2001 From: beto-rodriguez Date: Sun, 28 Aug 2022 11:53:29 -0500 Subject: [PATCH 02/50] fixed multiple axis style issues --- .../ViewModelsSamples/Axes/Style/ViewModel.cs | 2 -- src/LiveChartsCore/Axis.cs | 21 ++++++++----------- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/samples/ViewModelsSamples/Axes/Style/ViewModel.cs b/samples/ViewModelsSamples/Axes/Style/ViewModel.cs index b10dbeb64..222d2e897 100644 --- a/samples/ViewModelsSamples/Axes/Style/ViewModel.cs +++ b/samples/ViewModelsSamples/Axes/Style/ViewModel.cs @@ -32,7 +32,6 @@ public partial class ViewModel { new Axis { - Position = LiveChartsCore.Measure.AxisPosition.End, Name = "X axis", NamePaint = new SolidColorPaint(s_gray1), TextSize = 18, @@ -71,7 +70,6 @@ public partial class ViewModel { new Axis { - Position = LiveChartsCore.Measure.AxisPosition.End, Name = "Y axis", NamePaint = new SolidColorPaint(s_gray1), TextSize = 18, diff --git a/src/LiveChartsCore/Axis.cs b/src/LiveChartsCore/Axis.cs index 7279f549c..f6e0575c1 100644 --- a/src/LiveChartsCore/Axis.cs +++ b/src/LiveChartsCore/Axis.cs @@ -377,15 +377,12 @@ NamePadding is not null || SeparatorsPaint is not null || LabelsPaint is not nul { _zeroLine = new TLineGeometry(); ZeroPaint.AddGeometryToPaintTask(cartesianChart.Canvas, _zeroLine); - + InitializeLine(_zeroLine, cartesianChart); - UpdateSeparator(_zeroLine!, x, y, lxi, lxj, lyi, lyj, UpdateMode.UpdateAndComplete); - } - - if (min <= 0 && max >= 0) - { - UpdateSeparator(_zeroLine!, x, y, lxi, lxj, lyi, lyj, UpdateMode.Update); + UpdateSeparator(_zeroLine, x, y, lxi, lxj, lyi, lyj, UpdateMode.UpdateAndComplete); } + + UpdateSeparator(_zeroLine, x, y, lxi, lxj, lyi, lyj, UpdateMode.Update); } if (TicksPaint is not null && _drawTicksPath) @@ -399,7 +396,7 @@ NamePadding is not null || SeparatorsPaint is not null || LabelsPaint is not nul if (_orientation == AxisOrientation.X) { - var yp = xoo + _size.Height * 0.5f * (_position == AxisPosition.Start ? -1 : 1); + var yp = yoo + _size.Height * 0.5f * (_position == AxisPosition.Start ? -1 : 1); _ticksPath.X = lxi; _ticksPath.X1 = lxj; _ticksPath.Y = yp; @@ -848,8 +845,8 @@ private void UpdateTick( { if (_orientation == AxisOrientation.X) { - var lyi = y - _size.Height * 0.5f; - var lyj = y + _size.Height * 0.5f; + var lyi = y + _size.Height * 0.5f; + var lyj = y - _size.Height * 0.5f; tick.X = x; tick.X1 = x; tick.Y = _position == AxisPosition.Start ? lyj : lyi - length; @@ -897,9 +894,9 @@ private void UpdateSubticks( { var subtick = subticks[j]; - var k = 0.6f; + var k = 0.5f; var kl = (j + 1) / (double)(_subSections + 1); - if (Math.Abs(kl - 0.5f) < 0.01) k += 0.5f; + if (Math.Abs(kl - 0.5f) < 0.01) k += 0.25f; float xs = 0f, ys = 0f; if (_orientation == AxisOrientation.X) From 0fd072be3e94b1e1f4cf1e109927603d18e3b825 Mon Sep 17 00:00:00 2001 From: beto-rodriguez Date: Sun, 28 Aug 2022 16:21:51 -0500 Subject: [PATCH 03/50] in-memory legends skeleton --- .../ConsoleSample/ConsoleSample/Program.cs | 3 +- .../FluentDrawingExtensions.cs | 100 ++++++++++++++++++ .../SKCharts/SKCartesianChart.cs | 2 +- .../SKCharts/SKDefaultLegend.cs | 48 +++++++++ 4 files changed, 151 insertions(+), 2 deletions(-) create mode 100644 src/skiasharp/LiveChartsCore.SkiaSharp/FluentDrawingExtensions.cs create mode 100644 src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKDefaultLegend.cs diff --git a/samples/ConsoleSample/ConsoleSample/Program.cs b/samples/ConsoleSample/ConsoleSample/Program.cs index 20de92c33..2ff32a200 100644 --- a/samples/ConsoleSample/ConsoleSample/Program.cs +++ b/samples/ConsoleSample/ConsoleSample/Program.cs @@ -12,7 +12,8 @@ { new LineSeries { Values = new int[] { 1, 5, 4, 6 } }, new ColumnSeries { Values = new int[] { 4, 8, 2, 4 } } - } + }, + LegendPosition = LiveChartsCore.Measure.LegendPosition.Left }; // you can save the image to png (by default) diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/FluentDrawingExtensions.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/FluentDrawingExtensions.cs new file mode 100644 index 000000000..3a4adbe58 --- /dev/null +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/FluentDrawingExtensions.cs @@ -0,0 +1,100 @@ +// The MIT License(MIT) +// +// Copyright(c) 2021 Alberto Rodriguez Orozco & LiveCharts Contributors +// +// 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 LiveChartsCore.Drawing; +using LiveChartsCore.Motion; +using LiveChartsCore.SkiaSharpView.Drawing; +using LiveChartsCore.SkiaSharpView.Painting; +using SkiaSharp; + +namespace LiveChartsCore.SkiaSharpView; + +/// +/// Defines the drawing extensions. +/// +public static class DrawingFluentExtensions +{ + /// + /// Adds a paint task to the canvas. + /// + /// The canvas. + public static Drawing Draw(this MotionCanvas canvas) + { + return new Drawing(canvas); + } + + /// + /// Defines the Drawing class. + /// + public class Drawing + { + private IPaint? _selectedPaint; + + /// + /// Initializes a new instance of the Drawing class. + /// + /// The canvas. + public Drawing(MotionCanvas canvas) + { + Canvas = canvas; + } + + /// + /// Gets the canvas. + /// + public MotionCanvas Canvas { get; } + + /// + /// Selects the specified color. + /// + /// The color to draw with. + /// The stroke width. + /// Indicates whether the geometries are filled with the specified color. + /// The current drawing instance. + public Drawing SelectColor(SKColor color, float? strokeWidth = null, bool? isFill = null) + { + strokeWidth ??= 1; + isFill ??= false; + _selectedPaint = new SolidColorPaint(color, strokeWidth.Value) { IsFill = isFill.Value }; + Canvas.AddDrawableTask(_selectedPaint); + + return this; + } + + /// + /// + /// + /// + /// + public Drawing DrawGeometry(IGeometry geometry) + { + if (_selectedPaint is null) + throw new Exception( + "There is no paint selected, please select a paint (By calling a Select method) to add the geometry to."); + + _selectedPaint.AddGeometryToPaintTask(Canvas, geometry); + + return this; + } + } +} diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKCartesianChart.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKCartesianChart.cs index 73750c536..5afec16a9 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKCartesianChart.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKCartesianChart.cs @@ -139,7 +139,7 @@ public SKCartesianChart(ICartesianChartView view) : thi public MotionCanvas CoreCanvas { get; } = new(); /// - public IChartLegend? Legend => null; + public IChartLegend? Legend { get; } = new SKDefaultLegend(); /// public IChartTooltip? Tooltip => null; diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKDefaultLegend.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKDefaultLegend.cs new file mode 100644 index 000000000..ddabf2194 --- /dev/null +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKDefaultLegend.cs @@ -0,0 +1,48 @@ +// The MIT License(MIT) +// +// Copyright(c) 2021 Alberto Rodriguez Orozco & LiveCharts Contributors +// +// 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.Linq; +using LiveChartsCore.Kernel.Sketches; +using LiveChartsCore.SkiaSharpView.Drawing; +using LiveChartsCore.SkiaSharpView.Drawing.Geometries; +using SkiaSharp; + +namespace LiveChartsCore.SkiaSharpView.SKCharts; + +/// +public class SKDefaultLegend : IChartLegend +{ + void IChartLegend.Draw(Chart chart) + { + var series = chart.ChartSeries.Where(x => x.IsVisibleAtLegend); + var legendOrientation = chart.LegendOrientation; + var legendPosition = chart.LegendPosition; + + //var p = new SolidColorPaint(SKColors.AliceBlue) { IsFill = true }; + //p.AddGeometryToPaintTask(new RectangleGeometry() { }) + //chart.Canvas.AddDrawableTask(p); + + var drawing = chart.Canvas.Draw() + .SelectColor(SKColors.Blue) + .DrawGeometry(new RectangleGeometry { X = 0, Y = 0, Width = 50, Height = 50 }); + } +} From 14759d953c241c60a95542be7beff9668e6a1b5a Mon Sep 17 00:00:00 2001 From: beto-rodriguez Date: Mon, 29 Aug 2022 11:53:56 -0500 Subject: [PATCH 04/50] basic legend --- src/LiveChartsCore/Axis.cs | 5 +- src/LiveChartsCore/Drawing/Animatable.cs | 6 +- .../Drawing/Containers/Container.cs | 59 +++++++++ .../FluentDrawingExtensions.cs | 26 ++-- .../SKCharts/IDrawnLegend.cs | 42 +++++++ .../SKCharts/SKCartesianChart.cs | 9 +- .../SKCharts/SKDefaultLegend.cs | 118 +++++++++++++++++- 7 files changed, 247 insertions(+), 18 deletions(-) create mode 100644 src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Containers/Container.cs create mode 100644 src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/IDrawnLegend.cs diff --git a/src/LiveChartsCore/Axis.cs b/src/LiveChartsCore/Axis.cs index f6e0575c1..b138a6755 100644 --- a/src/LiveChartsCore/Axis.cs +++ b/src/LiveChartsCore/Axis.cs @@ -377,11 +377,10 @@ NamePadding is not null || SeparatorsPaint is not null || LabelsPaint is not nul { _zeroLine = new TLineGeometry(); ZeroPaint.AddGeometryToPaintTask(cartesianChart.Canvas, _zeroLine); - InitializeLine(_zeroLine, cartesianChart); UpdateSeparator(_zeroLine, x, y, lxi, lxj, lyi, lyj, UpdateMode.UpdateAndComplete); } - + UpdateSeparator(_zeroLine, x, y, lxi, lxj, lyi, lyj, UpdateMode.Update); } @@ -935,7 +934,7 @@ private void SetUpdateMode(IGeometry geometry, UpdateMode mode) switch (mode) { case Axis.UpdateMode.UpdateAndComplete: - if(_animatableBounds.HasPreviousState) geometry.Opacity = 0; + if (_animatableBounds.HasPreviousState) geometry.Opacity = 0; geometry.CompleteTransition(null); break; case Axis.UpdateMode.UpdateAndRemove: diff --git a/src/LiveChartsCore/Drawing/Animatable.cs b/src/LiveChartsCore/Drawing/Animatable.cs index 2ead3b2ff..0653b250c 100644 --- a/src/LiveChartsCore/Drawing/Animatable.cs +++ b/src/LiveChartsCore/Drawing/Animatable.cs @@ -52,7 +52,7 @@ public void SetTransition(Animation? animation, params string[]? propertyName) { var a = animation?.Duration == 0 ? null : animation; - if (propertyName is null) propertyName = MotionProperties.Keys.ToArray(); + propertyName ??= MotionProperties.Keys.ToArray(); foreach (var name in propertyName) { @@ -63,7 +63,7 @@ public void SetTransition(Animation? animation, params string[]? propertyName) /// public void RemoveTransition(params string[]? propertyName) { - if (propertyName is null) propertyName = MotionProperties.Keys.ToArray(); + propertyName ??= MotionProperties.Keys.ToArray(); foreach (var name in propertyName) { @@ -74,7 +74,7 @@ public void RemoveTransition(params string[]? propertyName) /// public virtual void CompleteTransition(params string[]? propertyName) { - if (propertyName is null) propertyName = MotionProperties.Keys.ToArray(); + propertyName ??= MotionProperties.Keys.ToArray(); foreach (var property in propertyName) { diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Containers/Container.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Containers/Container.cs new file mode 100644 index 000000000..549ea86d8 --- /dev/null +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Containers/Container.cs @@ -0,0 +1,59 @@ +// The MIT License(MIT) +// +// Copyright(c) 2021 Alberto Rodriguez Orozco & LiveCharts Contributors +// +// 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.Collections.Generic; +using LiveChartsCore.Drawing; + +namespace LiveChartsCore.SkiaSharpView.Drawing.Containers; + +/// +/// Defines a drawable container. +/// +public class Container : Animatable, IDrawable +{ + private readonly HashSet> _children = new(); + + /// + public void Draw(SkiaSharpDrawingContext context) + { + //context.Canvas.Translate(new SKPoint(100, 100)); + context.Canvas.Translate(100, 100); + } + + /// + /// Adds a child to the container. + /// + /// The child. + public void AddChild(IPaint child) + { + _ = _children.Add(child); + } + + /// + /// Removes a child from the container. + /// + /// The child. + public void RemoveChild(IPaint child) + { + _ = _children.Remove(child); + } +} diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/FluentDrawingExtensions.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/FluentDrawingExtensions.cs index 3a4adbe58..f12ce2a47 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/FluentDrawingExtensions.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/FluentDrawingExtensions.cs @@ -64,6 +64,19 @@ public Drawing(MotionCanvas canvas) /// public MotionCanvas Canvas { get; } + /// + /// Selects the specified paint. + /// + /// The paint. + /// The current drawing instance. + public Drawing SelectPaint(IPaint paint) + { + _selectedPaint = paint; + Canvas.AddDrawableTask(_selectedPaint); + + return this; + } + /// /// Selects the specified color. /// @@ -75,24 +88,23 @@ public Drawing SelectColor(SKColor color, float? strokeWidth = null, bool? isFil { strokeWidth ??= 1; isFill ??= false; - _selectedPaint = new SolidColorPaint(color, strokeWidth.Value) { IsFill = isFill.Value }; - Canvas.AddDrawableTask(_selectedPaint); + var paint = new SolidColorPaint(color, strokeWidth.Value) { IsFill = isFill.Value }; - return this; + return SelectPaint(paint); } /// - /// + /// Draws the specified object. /// - /// + /// The drawable. /// - public Drawing DrawGeometry(IGeometry geometry) + public Drawing Draw(IDrawable drawable) { if (_selectedPaint is null) throw new Exception( "There is no paint selected, please select a paint (By calling a Select method) to add the geometry to."); - _selectedPaint.AddGeometryToPaintTask(Canvas, geometry); + _selectedPaint.AddGeometryToPaintTask(Canvas, drawable); return this; } diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/IDrawnLegend.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/IDrawnLegend.cs new file mode 100644 index 000000000..b9f59e229 --- /dev/null +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/IDrawnLegend.cs @@ -0,0 +1,42 @@ +// The MIT License(MIT) +// +// Copyright(c) 2021 Alberto Rodriguez Orozco & LiveCharts Contributors +// +// 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 LiveChartsCore.Drawing; +using LiveChartsCore.SkiaSharpView.Drawing; + +namespace LiveChartsCore.SkiaSharpView.SKCharts; + +/// +/// A chart with a drawn legend using SkiaSharp. +/// +public interface IDrawnLegend +{ + /// + /// Gets or sets the font paint. + /// + IPaint? LegendFontPaint { get; set; } + + /// + /// Gets or sets the legend font size. + /// + double LegendFontSize { get; set; } +} diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKCartesianChart.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKCartesianChart.cs index 5afec16a9..a00abd86d 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKCartesianChart.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKCartesianChart.cs @@ -31,6 +31,7 @@ using LiveChartsCore.Motion; using LiveChartsCore.SkiaSharpView.Drawing; using LiveChartsCore.SkiaSharpView.Drawing.Geometries; +using LiveChartsCore.SkiaSharpView.Painting; using SkiaSharp; namespace LiveChartsCore.SkiaSharpView.SKCharts; @@ -38,7 +39,7 @@ namespace LiveChartsCore.SkiaSharpView.SKCharts; /// /// In-memory chart that is able to generate a chart images. /// -public class SKCartesianChart : ICartesianChartView, ISkiaSharpChart +public class SKCartesianChart : ICartesianChartView, ISkiaSharpChart, IDrawnLegend { private LvcColor _backColor; @@ -141,6 +142,12 @@ public SKCartesianChart(ICartesianChartView view) : thi /// public IChartLegend? Legend { get; } = new SKDefaultLegend(); + /// + public IPaint? LegendFontPaint { get; set; } = new SolidColorPaint { FontFamily = "Arial", Color = new SKColor(40, 40, 40) }; + + /// + public double LegendFontSize { get; set; } = 13; + /// public IChartTooltip? Tooltip => null; diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKDefaultLegend.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKDefaultLegend.cs index ddabf2194..9fc4e6c0e 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKDefaultLegend.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKDefaultLegend.cs @@ -20,11 +20,16 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. +using System; +using System.Collections.Specialized; using System.Linq; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.ComTypes; +using LiveChartsCore.Drawing; using LiveChartsCore.Kernel.Sketches; using LiveChartsCore.SkiaSharpView.Drawing; +using LiveChartsCore.SkiaSharpView.Drawing.Containers; using LiveChartsCore.SkiaSharpView.Drawing.Geometries; -using SkiaSharp; namespace LiveChartsCore.SkiaSharpView.SKCharts; @@ -33,6 +38,9 @@ public class SKDefaultLegend : IChartLegend { void IChartLegend.Draw(Chart chart) { + var drawnLegendChart = (IDrawnLegend)chart.View; + if (drawnLegendChart.LegendFontPaint is null) return; + var series = chart.ChartSeries.Where(x => x.IsVisibleAtLegend); var legendOrientation = chart.LegendOrientation; var legendPosition = chart.LegendPosition; @@ -41,8 +49,110 @@ void IChartLegend.Draw(Chart c //p.AddGeometryToPaintTask(new RectangleGeometry() { }) //chart.Canvas.AddDrawableTask(p); - var drawing = chart.Canvas.Draw() - .SelectColor(SKColors.Blue) - .DrawGeometry(new RectangleGeometry { X = 0, Y = 0, Width = 50, Height = 50 }); + var drawing = chart.Canvas.Draw(); + var y = 100f; + + var miniatureMaxSize = series + .Aggregate(new LvcSize(), (current, s) => + { + var maxScheduleSize = s.CanvasSchedule.PaintSchedules + .Aggregate(new LvcSize(), (current, schedule) => + { + var maxGeometrySize = schedule.Geometries.OfType>() + .Aggregate(new LvcSize(), (current, geometry) => + { + var size = geometry.Measure(schedule.PaintTask); + var t = schedule.PaintTask.StrokeThickness; + + return GetMaxSize(current, new LvcSize(size.Width + t, size.Height + t)); + }); + + return GetMaxSize(current, maxGeometrySize); + }); + + return GetMaxSize(current, maxScheduleSize); + }); + + var labelMaxSize = series + .Aggregate(new LvcSize(), (current, s) => + { + var label = new LabelGeometry + { + HorizontalAlign = Align.Start, + VerticalAlign = Align.Start, + Text = s.Name ?? string.Empty, + TextSize = (float)drawnLegendChart.LegendFontSize + }; + + return GetMaxSize(current, label.Measure(drawnLegendChart.LegendFontPaint)); + }); + + // set a padding + var p = 4f; + miniatureMaxSize = new LvcSize(miniatureMaxSize.Width + p, miniatureMaxSize.Height + p); + labelMaxSize = new LvcSize(labelMaxSize.Width + p, labelMaxSize.Height + p); + + var maxY = miniatureMaxSize.Height > labelMaxSize.Height ? miniatureMaxSize.Height : labelMaxSize.Height; + + foreach (var s in series) + { + var x = 100f; + + foreach (var miniatureSchedule in s.CanvasSchedule.PaintSchedules) + { + _ = drawing.SelectPaint(miniatureSchedule.PaintTask); + + foreach (var geometry in miniatureSchedule.Geometries.Cast>()) + { + var size = geometry.Measure(miniatureSchedule.PaintTask); + var t = miniatureSchedule.PaintTask.StrokeThickness; + + // distance to center (in miniatureMaxSize) in the x and y axis + //var cx = 0;// (miniatureMaxSize.Width - (size.Width + t)) * 0.5f; + var cy = (maxY - (size.Height + t)) * 0.5f; + + geometry.X = x; // + cx; // this is already centered by the LiveCharts API + geometry.Y = y + cy; + + _ = drawing.Draw(geometry); + } + } + + x += miniatureMaxSize.Width; + + if (drawnLegendChart.LegendFontPaint is not null) + { + var label = new LabelGeometry + { + X = x, + Y = y, + HorizontalAlign = Align.Start, + VerticalAlign = Align.Start, + Text = s.Name ?? string.Empty, + TextSize = (float)drawnLegendChart.LegendFontSize + }; + var size = label.Measure(drawnLegendChart.LegendFontPaint); + + var cy = (maxY - size.Height) * 0.5f; + label.Y = y + cy; + + _ = drawing + .SelectPaint(drawnLegendChart.LegendFontPaint) + .Draw(label); + } + + y += maxY; + } + } + + private LvcSize GetMaxSize(LvcSize size1, LvcSize size2) + { + var w = size1.Width; + var h = size1.Height; + + if (size2.Width > w) w = size2.Width; + if (size2.Height > h) h = size2.Height; + + return new LvcSize(w, h); } } From 88d0100c8a6e6cb84f39466c19b6ef5c47457d1a Mon Sep 17 00:00:00 2001 From: beto-rodriguez Date: Mon, 29 Aug 2022 12:24:33 -0500 Subject: [PATCH 05/50] iimagecontrol --- .../SKCharts/IImageControl.cs | 37 ++++++++++++++++ .../SKCharts/SKDefaultLegend.cs | 44 +++++++++++-------- 2 files changed, 63 insertions(+), 18 deletions(-) create mode 100644 src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/IImageControl.cs diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/IImageControl.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/IImageControl.cs new file mode 100644 index 000000000..013a4b2fe --- /dev/null +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/IImageControl.cs @@ -0,0 +1,37 @@ +// The MIT License(MIT) +// +// Copyright(c) 2021 Alberto Rodriguez Orozco & LiveCharts Contributors +// +// 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 LiveChartsCore.Drawing; + +namespace LiveChartsCore.SkiaSharpView.SKCharts; + +/// +/// An image control +/// +public interface IImageControl +{ + /// + /// Measures the image. + /// + /// + public LvcSize Measure(params object[] data); +} diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKDefaultLegend.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKDefaultLegend.cs index 9fc4e6c0e..c95bb9b42 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKDefaultLegend.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKDefaultLegend.cs @@ -20,37 +20,40 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -using System; -using System.Collections.Specialized; using System.Linq; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.ComTypes; using LiveChartsCore.Drawing; using LiveChartsCore.Kernel.Sketches; using LiveChartsCore.SkiaSharpView.Drawing; -using LiveChartsCore.SkiaSharpView.Drawing.Containers; using LiveChartsCore.SkiaSharpView.Drawing.Geometries; namespace LiveChartsCore.SkiaSharpView.SKCharts; /// -public class SKDefaultLegend : IChartLegend +public class SKDefaultLegend : IChartLegend, IImageControl { void IChartLegend.Draw(Chart chart) { + _ = DrawOrMeasure(chart); + } + + /// + public LvcSize Measure(params object[] data) + { + return DrawOrMeasure((Chart)data[0]); + } + + private LvcSize DrawOrMeasure(Chart chart, bool isMeasure = false) + { + float xi = 0f, yi = 0f; + var drawnLegendChart = (IDrawnLegend)chart.View; - if (drawnLegendChart.LegendFontPaint is null) return; + if (drawnLegendChart.LegendFontPaint is null) return new LvcSize(); var series = chart.ChartSeries.Where(x => x.IsVisibleAtLegend); var legendOrientation = chart.LegendOrientation; var legendPosition = chart.LegendPosition; - //var p = new SolidColorPaint(SKColors.AliceBlue) { IsFill = true }; - //p.AddGeometryToPaintTask(new RectangleGeometry() { }) - //chart.Canvas.AddDrawableTask(p); - var drawing = chart.Canvas.Draw(); - var y = 100f; var miniatureMaxSize = series .Aggregate(new LvcSize(), (current, s) => @@ -94,13 +97,15 @@ void IChartLegend.Draw(Chart c var maxY = miniatureMaxSize.Height > labelMaxSize.Height ? miniatureMaxSize.Height : labelMaxSize.Height; + var y = yi; foreach (var s in series) { - var x = 100f; + var x = xi; foreach (var miniatureSchedule in s.CanvasSchedule.PaintSchedules) { - _ = drawing.SelectPaint(miniatureSchedule.PaintTask); + if (!isMeasure) + _ = drawing.SelectPaint(miniatureSchedule.PaintTask); foreach (var geometry in miniatureSchedule.Geometries.Cast>()) { @@ -114,7 +119,7 @@ void IChartLegend.Draw(Chart c geometry.X = x; // + cx; // this is already centered by the LiveCharts API geometry.Y = y + cy; - _ = drawing.Draw(geometry); + if (!isMeasure) _ = drawing.Draw(geometry); } } @@ -136,13 +141,16 @@ void IChartLegend.Draw(Chart c var cy = (maxY - size.Height) * 0.5f; label.Y = y + cy; - _ = drawing - .SelectPaint(drawnLegendChart.LegendFontPaint) - .Draw(label); + if (!isMeasure) + _ = drawing + .SelectPaint(drawnLegendChart.LegendFontPaint) + .Draw(label); } y += maxY; } + + return new LvcSize(xi - xi, y - yi); } private LvcSize GetMaxSize(LvcSize size1, LvcSize size2) From 0832185718adec53d875717861bc49d28a8ac2c6 Mon Sep 17 00:00:00 2001 From: beto-rodriguez Date: Mon, 29 Aug 2022 12:24:53 -0500 Subject: [PATCH 06/50] measure only --- .../LiveChartsCore.SkiaSharp/SKCharts/SKDefaultLegend.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKDefaultLegend.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKDefaultLegend.cs index c95bb9b42..1dc5faa65 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKDefaultLegend.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKDefaultLegend.cs @@ -39,7 +39,7 @@ void IChartLegend.Draw(Chart c /// public LvcSize Measure(params object[] data) { - return DrawOrMeasure((Chart)data[0]); + return DrawOrMeasure((Chart)data[0], true); } private LvcSize DrawOrMeasure(Chart chart, bool isMeasure = false) From e7aa47b0d3ddf511559822586d1c124cbb8bef0f Mon Sep 17 00:00:00 2001 From: beto-rodriguez Date: Mon, 29 Aug 2022 19:01:51 -0500 Subject: [PATCH 07/50] basic in-memory legend implementation --- .../ConsoleSample/ConsoleSample/Program.cs | 80 +++++++++---------- src/LiveChartsCore/CartesianChart.cs | 7 +- .../SKCharts/IImageControl.cs | 5 +- .../SKCharts/SKCartesianChart.cs | 15 +++- .../SKCharts/SKDefaultLegend.cs | 44 ++++++---- 5 files changed, 88 insertions(+), 63 deletions(-) diff --git a/samples/ConsoleSample/ConsoleSample/Program.cs b/samples/ConsoleSample/ConsoleSample/Program.cs index 2ff32a200..8279321c1 100644 --- a/samples/ConsoleSample/ConsoleSample/Program.cs +++ b/samples/ConsoleSample/ConsoleSample/Program.cs @@ -20,43 +20,43 @@ // or use the second argument to specify another format. cartesianChart.SaveImage("cartesianChart.png"); -var pieChart = new SKPieChart -{ - Width = 900, - Height = 600, - Series = new ISeries[] - { - new PieSeries { Values = new int[] { 10, } }, - new PieSeries { Values = new int[] { 6 } }, - new PieSeries { Values = new int[] { 4 } } - } -}; - -pieChart.SaveImage("pieChart.png"); - -var geoHeatMap = new SKGeoMap -{ - Width = 900, - Height = 600, - Series = new IGeoSeries[] - { - new HeatLandSeries - { - Lands = new HeatLand[] - { - new() { Name = "mex", Value = 10 }, - new() { Name = "usa", Value = 15 }, - new() { Name = "can", Value = 8 } - } - } - } -}; - -geoHeatMap.SaveImage("geoHeatMap.png"); - -// alternatively you can get the image and do different operations: -using var image = cartesianChart.GetImage(); -using var data = image.Encode(); -var base64CartesianChart = Convert.ToBase64String(data.AsSpan()); - -Console.WriteLine("Images saved at the root folder!"); +//var pieChart = new SKPieChart +//{ +// Width = 900, +// Height = 600, +// Series = new ISeries[] +// { +// new PieSeries { Values = new int[] { 10, } }, +// new PieSeries { Values = new int[] { 6 } }, +// new PieSeries { Values = new int[] { 4 } } +// } +//}; + +//pieChart.SaveImage("pieChart.png"); + +//var geoHeatMap = new SKGeoMap +//{ +// Width = 900, +// Height = 600, +// Series = new IGeoSeries[] +// { +// new HeatLandSeries +// { +// Lands = new HeatLand[] +// { +// new() { Name = "mex", Value = 10 }, +// new() { Name = "usa", Value = 15 }, +// new() { Name = "can", Value = 8 } +// } +// } +// } +//}; + +//geoHeatMap.SaveImage("geoHeatMap.png"); + +//// alternatively you can get the image and do different operations: +//using var image = cartesianChart.GetImage(); +//using var data = image.Encode(); +//var base64CartesianChart = Convert.ToBase64String(data.AsSpan()); + +//Console.WriteLine("Images saved at the root folder!"); diff --git a/src/LiveChartsCore/CartesianChart.cs b/src/LiveChartsCore/CartesianChart.cs index b2ede9022..c73e0d1d1 100644 --- a/src/LiveChartsCore/CartesianChart.cs +++ b/src/LiveChartsCore/CartesianChart.cs @@ -535,17 +535,20 @@ protected internal override void Measure() #endregion + var a = SeriesMiniatureChanged(Series, LegendPosition); + var b = _requiresLegendMeasureAlways && SizeChanged(); if (Legend is not null && (SeriesMiniatureChanged(Series, LegendPosition) || (_requiresLegendMeasureAlways && SizeChanged()))) { Legend.Draw(this); - Update(); + //Update(); PreviousLegendPosition = LegendPosition; PreviousSeriesAtLegend = Series.Where(x => x.IsVisibleAtLegend).ToList(); preserveFirstDraw = IsFirstDraw; + Measure(); + return; } // calculate draw margin - var m = new Margin(); float ts = 0f, bs = 0f, ls = 0f, rs = 0f; SetDrawMargin(ControlSize, m); diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/IImageControl.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/IImageControl.cs index 013a4b2fe..79c81b692 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/IImageControl.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/IImageControl.cs @@ -30,8 +30,7 @@ namespace LiveChartsCore.SkiaSharpView.SKCharts; public interface IImageControl { /// - /// Measures the image. + /// Gets the sized. /// - /// - public LvcSize Measure(params object[] data); + public LvcSize Size { get; set; } } diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKCartesianChart.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKCartesianChart.cs index a00abd86d..bcc8cd104 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKCartesianChart.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKCartesianChart.cs @@ -164,7 +164,7 @@ LvcColor IChartView.BackColor } } - LvcSize IChartView.ControlSize => new(Width, Height); + LvcSize IChartView.ControlSize => GetControlSize(); /// public Margin? DrawMargin { get; set; } @@ -282,6 +282,19 @@ private void OnCoreMeasuring(IChartView chart) Measuring?.Invoke(this); } + private LvcSize GetControlSize() + { + if (LegendPosition == LegendPosition.Hidden || Legend is null) return new(Width, Height); + + if (LegendPosition is LegendPosition.Left or LegendPosition.Right) + { + var imageControl = (IImageControl)Legend; + return new(Width - imageControl.Size.Width, Height); + } + + return new(Width, Height); + } + void IChartView.OnDataPointerDown(IEnumerable points, LvcPoint pointer) { DataPointerDown?.Invoke(this, points); diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKDefaultLegend.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKDefaultLegend.cs index 1dc5faa65..880ccb1ac 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKDefaultLegend.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKDefaultLegend.cs @@ -31,29 +31,39 @@ namespace LiveChartsCore.SkiaSharpView.SKCharts; /// public class SKDefaultLegend : IChartLegend, IImageControl { + /// + public LvcSize Size { get; set; } + void IChartLegend.Draw(Chart chart) { - _ = DrawOrMeasure(chart); + DrawOrMeasure(chart, false); + DrawOrMeasure(chart, true); } - /// - public LvcSize Measure(params object[] data) + private void DrawOrMeasure(Chart chart, bool draw) { - return DrawOrMeasure((Chart)data[0], true); - } + float xi, yi; - private LvcSize DrawOrMeasure(Chart chart, bool isMeasure = false) - { - float xi = 0f, yi = 0f; + if (draw) + { + var actualChartSize = chart.View.ControlSize; + xi = actualChartSize.Width; + yi = actualChartSize.Height * 0.5f - Size.Height * 0.5f; + } + else + { + xi = 0f; + yi = 0f; + } var drawnLegendChart = (IDrawnLegend)chart.View; - if (drawnLegendChart.LegendFontPaint is null) return new LvcSize(); + if (drawnLegendChart.LegendFontPaint is null) return; var series = chart.ChartSeries.Where(x => x.IsVisibleAtLegend); var legendOrientation = chart.LegendOrientation; var legendPosition = chart.LegendPosition; - var drawing = chart.Canvas.Draw(); + var drawing = draw ? chart.Canvas.Draw() : null; var miniatureMaxSize = series .Aggregate(new LvcSize(), (current, s) => @@ -104,8 +114,7 @@ private LvcSize DrawOrMeasure(Chart chart, bool isMeasu foreach (var miniatureSchedule in s.CanvasSchedule.PaintSchedules) { - if (!isMeasure) - _ = drawing.SelectPaint(miniatureSchedule.PaintTask); + if (draw) _ = drawing!.SelectPaint(miniatureSchedule.PaintTask); foreach (var geometry in miniatureSchedule.Geometries.Cast>()) { @@ -119,7 +128,7 @@ private LvcSize DrawOrMeasure(Chart chart, bool isMeasu geometry.X = x; // + cx; // this is already centered by the LiveCharts API geometry.Y = y + cy; - if (!isMeasure) _ = drawing.Draw(geometry); + if (draw) _ = drawing!.Draw(geometry); } } @@ -141,16 +150,17 @@ private LvcSize DrawOrMeasure(Chart chart, bool isMeasu var cy = (maxY - size.Height) * 0.5f; label.Y = y + cy; - if (!isMeasure) - _ = drawing + if (draw) + _ = drawing! .SelectPaint(drawnLegendChart.LegendFontPaint) .Draw(label); + + x += size.Width; } y += maxY; + if (!draw) Size = new LvcSize(x - xi, y - yi); } - - return new LvcSize(xi - xi, y - yi); } private LvcSize GetMaxSize(LvcSize size1, LvcSize size2) From 59d34ea3f19a92dc9c9d7c9347ad941ef5ebe898 Mon Sep 17 00:00:00 2001 From: beto-rodriguez Date: Tue, 30 Aug 2022 13:39:41 -0500 Subject: [PATCH 08/50] fix legend position --- .../SKCharts/SKDefaultLegend.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKDefaultLegend.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKDefaultLegend.cs index 880ccb1ac..9d8fab066 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKDefaultLegend.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKDefaultLegend.cs @@ -43,6 +43,7 @@ void IChartLegend.Draw(Chart c private void DrawOrMeasure(Chart chart, bool draw) { float xi, yi; + var p = 8f; if (draw) { @@ -101,8 +102,7 @@ private void DrawOrMeasure(Chart chart, bool draw) }); // set a padding - var p = 4f; - miniatureMaxSize = new LvcSize(miniatureMaxSize.Width + p, miniatureMaxSize.Height + p); + miniatureMaxSize = new LvcSize(miniatureMaxSize.Width, miniatureMaxSize.Height); labelMaxSize = new LvcSize(labelMaxSize.Width + p, labelMaxSize.Height + p); var maxY = miniatureMaxSize.Height > labelMaxSize.Height ? miniatureMaxSize.Height : labelMaxSize.Height; @@ -132,7 +132,7 @@ private void DrawOrMeasure(Chart chart, bool draw) } } - x += miniatureMaxSize.Width; + x += miniatureMaxSize.Width + p; if (drawnLegendChart.LegendFontPaint is not null) { @@ -155,11 +155,11 @@ private void DrawOrMeasure(Chart chart, bool draw) .SelectPaint(drawnLegendChart.LegendFontPaint) .Draw(label); - x += size.Width; + x += labelMaxSize.Width + p; } y += maxY; - if (!draw) Size = new LvcSize(x - xi, y - yi); + if (!draw) Size = GetMaxSize(Size, new LvcSize(x - xi, y - yi)); } } From 582925095f8401526366cbc7553284a408b0ef44 Mon Sep 17 00:00:00 2001 From: beto-rodriguez Date: Tue, 30 Aug 2022 14:25:29 -0500 Subject: [PATCH 09/50] left and right legends --- src/LiveChartsCore/Drawing/DrawingContext.cs | 12 ++++++++++++ src/LiveChartsCore/Motion/MotionCanvas.cs | 13 ++++++++----- .../Drawing/SkiaSharpDrawingContext.cs | 16 ++++++++++++++++ .../SKCharts/SKDefaultLegend.cs | 17 ++++++++++++++--- 4 files changed, 50 insertions(+), 8 deletions(-) diff --git a/src/LiveChartsCore/Drawing/DrawingContext.cs b/src/LiveChartsCore/Drawing/DrawingContext.cs index 4c864205c..ae293259d 100644 --- a/src/LiveChartsCore/Drawing/DrawingContext.cs +++ b/src/LiveChartsCore/Drawing/DrawingContext.cs @@ -27,6 +27,18 @@ namespace LiveChartsCore.Drawing; /// public abstract class DrawingContext { + /// + /// Called when the frame starts. + /// + public virtual void OnBegingDraw() + { } + + /// + /// Called when the frame ends. + /// + public virtual void OnEndDraw() + { } + /// /// Clears the canvas. /// diff --git a/src/LiveChartsCore/Motion/MotionCanvas.cs b/src/LiveChartsCore/Motion/MotionCanvas.cs index e59d51561..6542b3d0b 100644 --- a/src/LiveChartsCore/Motion/MotionCanvas.cs +++ b/src/LiveChartsCore/Motion/MotionCanvas.cs @@ -49,13 +49,12 @@ public MotionCanvas() _stopwatch.Start(); } + internal bool DisableAnimations { get; set; } + /// - /// Gets a value indicating whether the animations are disabled. + /// Gets or sets the point where the draw starts. /// - /// - /// true if [disable animations]; otherwise, false. - /// - internal bool DisableAnimations { get; set; } + public LvcPoint? StartPoint { get; set; } /// /// Occurs when the visual is invalidated. @@ -104,6 +103,8 @@ public void DrawFrame(TDrawingContext context) lock (Sync) { + context.OnBegingDraw(); + var isValid = true; var frameTime = _stopwatch.ElapsedMilliseconds; context.ClearCanvas(); @@ -170,6 +171,8 @@ public void DrawFrame(TDrawingContext context) _previousFrameTime = frameTime; IsValid = isValid; + + context.OnEndDraw(); } if (IsValid) Validated?.Invoke(this); diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/SkiaSharpDrawingContext.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/SkiaSharpDrawingContext.cs index 6f0f063cc..216a680e4 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/SkiaSharpDrawingContext.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/SkiaSharpDrawingContext.cs @@ -110,6 +110,22 @@ public SkiaSharpDrawingContext( /// public SKColor ClearColor { get; set; } = SKColor.Empty; + /// + public override void OnBegingDraw() + { + if (MotionCanvas.StartPoint is null) return; + + Canvas.Translate(new SKPoint(MotionCanvas.StartPoint.Value.X, MotionCanvas.StartPoint.Value.Y)); + } + + /// + public override void OnEndDraw() + { + if (MotionCanvas.StartPoint is null) return; + + Canvas.Restore(); + } + /// /// Clears the canvas. /// diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKDefaultLegend.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKDefaultLegend.cs index 9d8fab066..42b5a9a9c 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKDefaultLegend.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKDefaultLegend.cs @@ -23,6 +23,7 @@ using System.Linq; using LiveChartsCore.Drawing; using LiveChartsCore.Kernel.Sketches; +using LiveChartsCore.Measure; using LiveChartsCore.SkiaSharpView.Drawing; using LiveChartsCore.SkiaSharpView.Drawing.Geometries; @@ -42,14 +43,24 @@ void IChartLegend.Draw(Chart c private void DrawOrMeasure(Chart chart, bool draw) { - float xi, yi; + float xi = 0f, yi = 0f; var p = 8f; if (draw) { var actualChartSize = chart.View.ControlSize; - xi = actualChartSize.Width; - yi = actualChartSize.Height * 0.5f - Size.Height * 0.5f; + + if (chart.LegendPosition == LegendPosition.Left) + { + chart.Canvas.StartPoint = new LvcPoint(Size.Width, 0); + xi = -Size.Width + p; + yi = actualChartSize.Height * 0.5f - Size.Height * 0.5f; + } + if (chart.LegendPosition == LegendPosition.Right) + { + xi = actualChartSize.Width; + yi = actualChartSize.Height * 0.5f - Size.Height * 0.5f; + } } else { From c7722fafe371e4af50fa2d15e98d45f5f73511d0 Mon Sep 17 00:00:00 2001 From: beto-rodriguez Date: Tue, 30 Aug 2022 14:58:13 -0500 Subject: [PATCH 10/50] top and bottom position --- .../ConsoleSample/ConsoleSample/Program.cs | 2 +- .../SKCharts/SKCartesianChart.cs | 6 + .../SKCharts/SKDefaultLegend.cs | 144 +++++++++++++++++- 3 files changed, 148 insertions(+), 4 deletions(-) diff --git a/samples/ConsoleSample/ConsoleSample/Program.cs b/samples/ConsoleSample/ConsoleSample/Program.cs index 8279321c1..13a101eab 100644 --- a/samples/ConsoleSample/ConsoleSample/Program.cs +++ b/samples/ConsoleSample/ConsoleSample/Program.cs @@ -13,7 +13,7 @@ new LineSeries { Values = new int[] { 1, 5, 4, 6 } }, new ColumnSeries { Values = new int[] { 4, 8, 2, 4 } } }, - LegendPosition = LiveChartsCore.Measure.LegendPosition.Left + LegendPosition = LiveChartsCore.Measure.LegendPosition.Bottom }; // you can save the image to png (by default) diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKCartesianChart.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKCartesianChart.cs index bcc8cd104..96f7c5086 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKCartesianChart.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKCartesianChart.cs @@ -292,6 +292,12 @@ private LvcSize GetControlSize() return new(Width - imageControl.Size.Width, Height); } + if (LegendPosition is LegendPosition.Top or LegendPosition.Bottom) + { + var imageControl = (IImageControl)Legend; + return new(Width, Height - imageControl.Size.Height); + } + return new(Width, Height); } diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKDefaultLegend.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKDefaultLegend.cs index 42b5a9a9c..11ed725c5 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKDefaultLegend.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKDefaultLegend.cs @@ -37,11 +37,14 @@ public class SKDefaultLegend : IChartLegend, IImageCont void IChartLegend.Draw(Chart chart) { - DrawOrMeasure(chart, false); - DrawOrMeasure(chart, true); + //DrawOrMeasureVertical(chart, false); + //DrawOrMeasureVertical(chart, true); + + DrawOrMeasureHorizontal(chart, false); + DrawOrMeasureHorizontal(chart, true); } - private void DrawOrMeasure(Chart chart, bool draw) + private void DrawOrMeasureVertical(Chart chart, bool draw) { float xi = 0f, yi = 0f; var p = 8f; @@ -174,6 +177,141 @@ private void DrawOrMeasure(Chart chart, bool draw) } } + private void DrawOrMeasureHorizontal(Chart chart, bool draw) + { + float xi = 0f, yi = 0f; + var p = 8f; + + if (draw) + { + var actualChartSize = chart.View.ControlSize; + + if (chart.LegendPosition == LegendPosition.Top) + { + chart.Canvas.StartPoint = new LvcPoint(0, Size.Height); + xi = actualChartSize.Width * 0.5f - Size.Width * 0.5f; + yi = -Size.Height + p; + } + if (chart.LegendPosition == LegendPosition.Bottom) + { + xi = actualChartSize.Width * 0.5f - Size.Width * 0.5f; + yi = actualChartSize.Height + p; + } + } + else + { + xi = 0f; + yi = 0f; + } + + var drawnLegendChart = (IDrawnLegend)chart.View; + if (drawnLegendChart.LegendFontPaint is null) return; + + var series = chart.ChartSeries.Where(x => x.IsVisibleAtLegend); + var legendOrientation = chart.LegendOrientation; + var legendPosition = chart.LegendPosition; + + var drawing = draw ? chart.Canvas.Draw() : null; + + var miniatureMaxSize = series + .Aggregate(new LvcSize(), (current, s) => + { + var maxScheduleSize = s.CanvasSchedule.PaintSchedules + .Aggregate(new LvcSize(), (current, schedule) => + { + var maxGeometrySize = schedule.Geometries.OfType>() + .Aggregate(new LvcSize(), (current, geometry) => + { + var size = geometry.Measure(schedule.PaintTask); + var t = schedule.PaintTask.StrokeThickness; + + return GetMaxSize(current, new LvcSize(size.Width + t, size.Height + t)); + }); + + return GetMaxSize(current, maxGeometrySize); + }); + + return GetMaxSize(current, maxScheduleSize); + }); + + var labelMaxSize = series + .Aggregate(new LvcSize(), (current, s) => + { + var label = new LabelGeometry + { + HorizontalAlign = Align.Start, + VerticalAlign = Align.Start, + Text = s.Name ?? string.Empty, + TextSize = (float)drawnLegendChart.LegendFontSize + }; + + return GetMaxSize(current, label.Measure(drawnLegendChart.LegendFontPaint)); + }); + + // set a padding + miniatureMaxSize = new LvcSize(miniatureMaxSize.Width, miniatureMaxSize.Height); + labelMaxSize = new LvcSize(labelMaxSize.Width + p, labelMaxSize.Height + p); + + var maxY = miniatureMaxSize.Height > labelMaxSize.Height ? miniatureMaxSize.Height : labelMaxSize.Height; + + var y = yi; + var x = xi; + + foreach (var s in series) + { + foreach (var miniatureSchedule in s.CanvasSchedule.PaintSchedules) + { + if (draw) _ = drawing!.SelectPaint(miniatureSchedule.PaintTask); + + foreach (var geometry in miniatureSchedule.Geometries.Cast>()) + { + var size = geometry.Measure(miniatureSchedule.PaintTask); + var t = miniatureSchedule.PaintTask.StrokeThickness; + + // distance to center (in miniatureMaxSize) in the x and y axis + //var cx = 0;// (miniatureMaxSize.Width - (size.Width + t)) * 0.5f; + var cy = (maxY - (size.Height + t)) * 0.5f; + + geometry.X = x; // + cx; // this is already centered by the LiveCharts API + geometry.Y = y + cy; + + if (draw) _ = drawing!.Draw(geometry); + } + } + + x += miniatureMaxSize.Width + p; + + if (drawnLegendChart.LegendFontPaint is not null) + { + var label = new LabelGeometry + { + X = x, + Y = y, + HorizontalAlign = Align.Start, + VerticalAlign = Align.Start, + Text = s.Name ?? string.Empty, + TextSize = (float)drawnLegendChart.LegendFontSize + }; + var size = label.Measure(drawnLegendChart.LegendFontPaint); + + var cy = (maxY - size.Height) * 0.5f; + label.Y = y + cy; + + if (draw) + _ = drawing! + .SelectPaint(drawnLegendChart.LegendFontPaint) + .Draw(label); + + x += labelMaxSize.Width + p; + } + + x += p; + } + + y += maxY + 2 * p; + if (!draw) Size = GetMaxSize(Size, new LvcSize(x - xi, y - yi)); + } + private LvcSize GetMaxSize(LvcSize size1, LvcSize size2) { var w = size1.Width; From 11b7a6b9bde7b1846fda799a99c4a2806ea22a63 Mon Sep 17 00:00:00 2001 From: beto-rodriguez Date: Tue, 30 Aug 2022 15:11:42 -0500 Subject: [PATCH 11/50] extend in-memory legends to pie and polar charts --- .../SKCharts/SKPieChart.cs | 32 +++++++++++++++++-- .../SKCharts/SKPolarChart.cs | 32 +++++++++++++++++-- 2 files changed, 58 insertions(+), 6 deletions(-) diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKPieChart.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKPieChart.cs index d6e237a2d..91a5b8a01 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKPieChart.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKPieChart.cs @@ -30,6 +30,7 @@ using LiveChartsCore.Measure; using LiveChartsCore.Motion; using LiveChartsCore.SkiaSharpView.Drawing; +using LiveChartsCore.SkiaSharpView.Painting; using SkiaSharp; namespace LiveChartsCore.SkiaSharpView.SKCharts; @@ -37,7 +38,7 @@ namespace LiveChartsCore.SkiaSharpView.SKCharts; /// /// In-memory chart that is able to generate a chart images. /// -public class SKPieChart : IPieChartView, ISkiaSharpChart +public class SKPieChart : IPieChartView, ISkiaSharpChart, IDrawnLegend { private LvcColor _backColor; @@ -124,7 +125,13 @@ public SKPieChart(IPieChartView view) : this() public MotionCanvas CoreCanvas { get; } = new(); /// - public IChartLegend? Legend => null; + public IChartLegend? Legend { get; } = new SKDefaultLegend(); + + /// + public IPaint? LegendFontPaint { get; set; } = new SolidColorPaint { FontFamily = "Arial", Color = new SKColor(40, 40, 40) }; + + /// + public double LegendFontSize { get; set; } = 13; /// public IChartTooltip? Tooltip => null; @@ -142,7 +149,7 @@ LvcColor IChartView.BackColor } } - LvcSize IChartView.ControlSize => new(Width, Height); + LvcSize IChartView.ControlSize => GetControlSize(); /// public Margin? DrawMargin { get; set; } @@ -252,6 +259,25 @@ private void OnCoreMeasuring(IChartView chart) Measuring?.Invoke(this); } + private LvcSize GetControlSize() + { + if (LegendPosition == LegendPosition.Hidden || Legend is null) return new(Width, Height); + + if (LegendPosition is LegendPosition.Left or LegendPosition.Right) + { + var imageControl = (IImageControl)Legend; + return new(Width - imageControl.Size.Width, Height); + } + + if (LegendPosition is LegendPosition.Top or LegendPosition.Bottom) + { + var imageControl = (IImageControl)Legend; + return new(Width, Height - imageControl.Size.Height); + } + + return new(Width, Height); + } + void IChartView.OnDataPointerDown(IEnumerable points, LvcPoint pointer) { DataPointerDown?.Invoke(this, points); diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKPolarChart.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKPolarChart.cs index 659b684cb..b285391f6 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKPolarChart.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKPolarChart.cs @@ -30,6 +30,7 @@ using LiveChartsCore.Measure; using LiveChartsCore.Motion; using LiveChartsCore.SkiaSharpView.Drawing; +using LiveChartsCore.SkiaSharpView.Painting; using SkiaSharp; namespace LiveChartsCore.SkiaSharpView.SKCharts; @@ -37,7 +38,7 @@ namespace LiveChartsCore.SkiaSharpView.SKCharts; /// /// In-memory chart that is able to generate a chart images. /// -public class SKPolarChart : IPolarChartView, ISkiaSharpChart +public class SKPolarChart : IPolarChartView, ISkiaSharpChart, IDrawnLegend { private LvcColor _backColor; @@ -121,7 +122,13 @@ public SKPolarChart(IPolarChartView view) : this() public MotionCanvas CoreCanvas { get; } = new(); /// - public IChartLegend? Legend => null; + public IChartLegend? Legend { get; } = new SKDefaultLegend(); + + /// + public IPaint? LegendFontPaint { get; set; } = new SolidColorPaint { FontFamily = "Arial", Color = new SKColor(40, 40, 40) }; + + /// + public double LegendFontSize { get; set; } = 13; /// public IChartTooltip? Tooltip => null; @@ -139,7 +146,7 @@ LvcColor IChartView.BackColor } } - LvcSize IChartView.ControlSize => new(Width, Height); + LvcSize IChartView.ControlSize => GetControlSize(); /// public Margin? DrawMargin { get; set; } @@ -270,6 +277,25 @@ private void OnCoreMeasuring(IChartView chart) Measuring?.Invoke(this); } + private LvcSize GetControlSize() + { + if (LegendPosition == LegendPosition.Hidden || Legend is null) return new(Width, Height); + + if (LegendPosition is LegendPosition.Left or LegendPosition.Right) + { + var imageControl = (IImageControl)Legend; + return new(Width - imageControl.Size.Width, Height); + } + + if (LegendPosition is LegendPosition.Top or LegendPosition.Bottom) + { + var imageControl = (IImageControl)Legend; + return new(Width, Height - imageControl.Size.Height); + } + + return new(Width, Height); + } + void IChartView.OnDataPointerDown(IEnumerable points, LvcPoint pointer) { DataPointerDown?.Invoke(this, points); From 9ac48129669b93f7326a88d6f7076b5e34a12574 Mon Sep 17 00:00:00 2001 From: beto-rodriguez Date: Tue, 30 Aug 2022 15:17:00 -0500 Subject: [PATCH 12/50] in-memory legends positioning --- .../ConsoleSample/ConsoleSample/Program.cs | 83 ++++++++++--------- .../SKCharts/SKDefaultLegend.cs | 15 ++-- 2 files changed, 52 insertions(+), 46 deletions(-) diff --git a/samples/ConsoleSample/ConsoleSample/Program.cs b/samples/ConsoleSample/ConsoleSample/Program.cs index 13a101eab..e907a77df 100644 --- a/samples/ConsoleSample/ConsoleSample/Program.cs +++ b/samples/ConsoleSample/ConsoleSample/Program.cs @@ -13,50 +13,51 @@ new LineSeries { Values = new int[] { 1, 5, 4, 6 } }, new ColumnSeries { Values = new int[] { 4, 8, 2, 4 } } }, - LegendPosition = LiveChartsCore.Measure.LegendPosition.Bottom + LegendPosition = LiveChartsCore.Measure.LegendPosition.Right }; // you can save the image to png (by default) // or use the second argument to specify another format. cartesianChart.SaveImage("cartesianChart.png"); -//var pieChart = new SKPieChart -//{ -// Width = 900, -// Height = 600, -// Series = new ISeries[] -// { -// new PieSeries { Values = new int[] { 10, } }, -// new PieSeries { Values = new int[] { 6 } }, -// new PieSeries { Values = new int[] { 4 } } -// } -//}; - -//pieChart.SaveImage("pieChart.png"); - -//var geoHeatMap = new SKGeoMap -//{ -// Width = 900, -// Height = 600, -// Series = new IGeoSeries[] -// { -// new HeatLandSeries -// { -// Lands = new HeatLand[] -// { -// new() { Name = "mex", Value = 10 }, -// new() { Name = "usa", Value = 15 }, -// new() { Name = "can", Value = 8 } -// } -// } -// } -//}; - -//geoHeatMap.SaveImage("geoHeatMap.png"); - -//// alternatively you can get the image and do different operations: -//using var image = cartesianChart.GetImage(); -//using var data = image.Encode(); -//var base64CartesianChart = Convert.ToBase64String(data.AsSpan()); - -//Console.WriteLine("Images saved at the root folder!"); +var pieChart = new SKPieChart +{ + Width = 900, + Height = 600, + Series = new ISeries[] + { + new PieSeries { Values = new int[] { 10, } }, + new PieSeries { Values = new int[] { 6 } }, + new PieSeries { Values = new int[] { 4 } } + }, + LegendPosition = LiveChartsCore.Measure.LegendPosition.Right +}; + +pieChart.SaveImage("pieChart.png"); + +var geoHeatMap = new SKGeoMap +{ + Width = 900, + Height = 600, + Series = new IGeoSeries[] + { + new HeatLandSeries + { + Lands = new HeatLand[] + { + new() { Name = "mex", Value = 10 }, + new() { Name = "usa", Value = 15 }, + new() { Name = "can", Value = 8 } + } + } + } +}; + +geoHeatMap.SaveImage("geoHeatMap.png"); + +// alternatively you can get the image and do different operations: +using var image = cartesianChart.GetImage(); +using var data = image.Encode(); +var base64CartesianChart = Convert.ToBase64String(data.AsSpan()); + +Console.WriteLine("Images saved at the root folder!"); diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKDefaultLegend.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKDefaultLegend.cs index 11ed725c5..d4b09734a 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKDefaultLegend.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKDefaultLegend.cs @@ -37,11 +37,16 @@ public class SKDefaultLegend : IChartLegend, IImageCont void IChartLegend.Draw(Chart chart) { - //DrawOrMeasureVertical(chart, false); - //DrawOrMeasureVertical(chart, true); - - DrawOrMeasureHorizontal(chart, false); - DrawOrMeasureHorizontal(chart, true); + if (chart.LegendPosition is LegendPosition.Left or LegendPosition.Right) + { + DrawOrMeasureVertical(chart, false); + DrawOrMeasureVertical(chart, true); + } + else + { + DrawOrMeasureHorizontal(chart, false); + DrawOrMeasureHorizontal(chart, true); + } } private void DrawOrMeasureVertical(Chart chart, bool draw) From ac0c500dfea6a28b2e3bd2321225dcbf0c18b3eb Mon Sep 17 00:00:00 2001 From: beto-rodriguez Date: Tue, 30 Aug 2022 15:17:29 -0500 Subject: [PATCH 13/50] remove unecessary objects --- .../Drawing/Containers/Container.cs | 59 ------------------- 1 file changed, 59 deletions(-) delete mode 100644 src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Containers/Container.cs diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Containers/Container.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Containers/Container.cs deleted file mode 100644 index 549ea86d8..000000000 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Containers/Container.cs +++ /dev/null @@ -1,59 +0,0 @@ -// The MIT License(MIT) -// -// Copyright(c) 2021 Alberto Rodriguez Orozco & LiveCharts Contributors -// -// 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.Collections.Generic; -using LiveChartsCore.Drawing; - -namespace LiveChartsCore.SkiaSharpView.Drawing.Containers; - -/// -/// Defines a drawable container. -/// -public class Container : Animatable, IDrawable -{ - private readonly HashSet> _children = new(); - - /// - public void Draw(SkiaSharpDrawingContext context) - { - //context.Canvas.Translate(new SKPoint(100, 100)); - context.Canvas.Translate(100, 100); - } - - /// - /// Adds a child to the container. - /// - /// The child. - public void AddChild(IPaint child) - { - _ = _children.Add(child); - } - - /// - /// Removes a child from the container. - /// - /// The child. - public void RemoveChild(IPaint child) - { - _ = _children.Remove(child); - } -} From 8e89d7a7da092f76cea17b379e0a6839bbe2777a Mon Sep 17 00:00:00 2001 From: beto-rodriguez Date: Tue, 30 Aug 2022 15:21:39 -0500 Subject: [PATCH 14/50] inherit legend position from view --- .../LiveChartsCore.SkiaSharp/SKCharts/SKCartesianChart.cs | 1 + src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKPieChart.cs | 1 + src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKPolarChart.cs | 1 + 3 files changed, 3 insertions(+) diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKCartesianChart.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKCartesianChart.cs index 96f7c5086..307879571 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKCartesianChart.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKCartesianChart.cs @@ -74,6 +74,7 @@ public SKCartesianChart(ICartesianChartView view) : thi Series = view.Series; Sections = view.Sections; DrawMarginFrame = view.DrawMarginFrame; + LegendPosition = view.LegendPosition; } /// diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKPieChart.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKPieChart.cs index 91a5b8a01..035e75aca 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKPieChart.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKPieChart.cs @@ -71,6 +71,7 @@ public SKPieChart(IPieChartView view) : this() InitialRotation = view.InitialRotation; MaxAngle = view.MaxAngle; Total = view.Total; + LegendPosition = view.LegendPosition; } /// diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKPolarChart.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKPolarChart.cs index b285391f6..7afbfb7f2 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKPolarChart.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKPolarChart.cs @@ -74,6 +74,7 @@ public SKPolarChart(IPolarChartView view) : this() TotalAngle = view.TotalAngle; InnerRadius = view.InnerRadius; InitialRotation = view.InitialRotation; + LegendPosition = view.LegendPosition; } /// From 02353775b54619bd3c57ebf1314b00272dda4528 Mon Sep 17 00:00:00 2001 From: beto-rodriguez Date: Tue, 30 Aug 2022 15:34:24 -0500 Subject: [PATCH 15/50] better use sized geometries --- src/LiveChartsCore/PieSeries.cs | 24 +++++++------------ .../LiveChartsCore.SkiaSharp/PieSeries.cs | 2 +- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/src/LiveChartsCore/PieSeries.cs b/src/LiveChartsCore/PieSeries.cs index fd95d62fd..b3618edd2 100644 --- a/src/LiveChartsCore/PieSeries.cs +++ b/src/LiveChartsCore/PieSeries.cs @@ -37,12 +37,14 @@ namespace LiveChartsCore; /// The type of the model. /// The type of the visual. /// The type of the label. +/// The type of the miniature geometry, used in tool tips and legends. /// The type of the drawing context. -public abstract class PieSeries +public abstract class PieSeries : ChartSeries, IPieSeries where TDrawingContext : DrawingContext where TVisual : class, IDoughnutVisualChartPoint, new() where TLabel : class, ILabelGeometry, new() + where TMiniatureGeometry : ISizedGeometry, new() { private IPaint? _stroke = null; private IPaint? _fill = null; @@ -60,7 +62,7 @@ public abstract class PieSeries private PolarLabelsPosition _labelsPosition = PolarLabelsPosition.Middle; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// protected PieSeries(bool isGauge = false, bool isGaugeFill = false) : base(SeriesProperties.PieSeries | SeriesProperties.Stacked | @@ -456,16 +458,12 @@ protected override void OnSeriesMiniatureChanged() strokeClone.StrokeThickness = MaxSeriesStroke; } - var visual = new TVisual + var visual = new TMiniatureGeometry { X = st + MaxSeriesStroke - st, Y = st + MaxSeriesStroke - st, Height = (float)LegendShapeSize, - Width = (float)LegendShapeSize, - CenterX = (float)LegendShapeSize * 0.5f, - CenterY = (float)LegendShapeSize * 0.5f, - StartAngle = 0, - SweepAngle = 359.9999f + Width = (float)LegendShapeSize }; sh = st; strokeClone.ZIndex = 1; @@ -475,16 +473,12 @@ protected override void OnSeriesMiniatureChanged() if (Fill is not null) { var fillClone = Fill.CloneTask(); - var visual = new TVisual + var visual = new TMiniatureGeometry { X = sh + MaxSeriesStroke - sh, Y = sh + MaxSeriesStroke - sh, Height = (float)LegendShapeSize, - Width = (float)LegendShapeSize, - CenterX = (float)LegendShapeSize * 0.5f, - CenterY = (float)LegendShapeSize * 0.5f, - StartAngle = 0, - SweepAngle = 359.9999f + Width = (float)LegendShapeSize }; context.PaintSchedules.Add(new PaintSchedule(fillClone, visual)); } @@ -545,7 +539,7 @@ protected override void OnPaintChanged(string? propertyName) /// public override bool MiniatureEquals(IChartSeries instance) { - return instance is PieSeries pieSeries && + return instance is PieSeries pieSeries && Name == pieSeries.Name && Fill == pieSeries.Fill && Stroke == pieSeries.Stroke; } diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/PieSeries.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/PieSeries.cs index ba25e6bfc..7920275b1 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/PieSeries.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/PieSeries.cs @@ -89,7 +89,7 @@ public PieSeries(bool isGauge = false, bool isGaugeFill = false) : base(isGauge, /// /// The type of the data label of every point. /// -public class PieSeries : PieSeries +public class PieSeries : PieSeries where TVisual : class, IDoughnutVisualChartPoint, new() where TLabel : class, ILabelGeometry, new() { From b8845e6faca762d09ad122d244aa54e17d4170fa Mon Sep 17 00:00:00 2001 From: beto-rodriguez Date: Wed, 31 Aug 2022 13:41:17 -0500 Subject: [PATCH 16/50] fix cyclic legends update --- .../BlazorSample/Pages/Design/LinearGradients.razor | 3 ++- .../BlazorSample/Pages/Design/RadialGradients.razor | 3 ++- src/LiveChartsCore/CartesianChart.cs | 12 +++--------- src/LiveChartsCore/Chart.cs | 11 ++++++++++- .../CartesianChart.cs | 2 +- .../CartesianChart.cs | 2 +- 6 files changed, 19 insertions(+), 14 deletions(-) diff --git a/samples/BlazorSample/Pages/Design/LinearGradients.razor b/samples/BlazorSample/Pages/Design/LinearGradients.razor index 113e31ef1..a6e9756c9 100644 --- a/samples/BlazorSample/Pages/Design/LinearGradients.razor +++ b/samples/BlazorSample/Pages/Design/LinearGradients.razor @@ -3,7 +3,8 @@ @using ViewModelsSamples.Design.LinearGradients + Series="ViewModel.Series" + LegendPosition="LiveChartsCore.Measure.LegendPosition.Right"> @code { diff --git a/samples/BlazorSample/Pages/Design/RadialGradients.razor b/samples/BlazorSample/Pages/Design/RadialGradients.razor index 905ed32b0..a09d79de1 100644 --- a/samples/BlazorSample/Pages/Design/RadialGradients.razor +++ b/samples/BlazorSample/Pages/Design/RadialGradients.razor @@ -3,7 +3,8 @@ @using ViewModelsSamples.Design.RadialGradients + Series="ViewModel.Series" + LegendPosition="LiveChartsCore.Measure.LegendPosition.Right"> @code { diff --git a/src/LiveChartsCore/CartesianChart.cs b/src/LiveChartsCore/CartesianChart.cs index c73e0d1d1..84af45fef 100644 --- a/src/LiveChartsCore/CartesianChart.cs +++ b/src/LiveChartsCore/CartesianChart.cs @@ -47,7 +47,6 @@ public class CartesianChart : Chart private readonly ISizedGeometry _zoomingSection; private int _nextSeries = 0; private double _zoomingSpeed = 0; - private readonly bool _requiresLegendMeasureAlways = false; private ZoomAndPanMode _zoomMode; private DrawMarginFrame? _previousDrawMarginFrame; private const double MaxAxisBound = 0.05; @@ -60,17 +59,14 @@ public class CartesianChart : Chart /// The default platform configuration. /// The canvas. /// The zooming section. - /// Forces the legends to redraw with every measure request. public CartesianChart( ICartesianChartView view, Action defaultPlatformConfig, MotionCanvas canvas, - ISizedGeometry? zoomingSection, - bool requiresLegendMeasureAlways = false) + ISizedGeometry? zoomingSection) : base(canvas, defaultPlatformConfig, view) { _chartView = view; - _requiresLegendMeasureAlways = requiresLegendMeasureAlways; _zoomingSection = zoomingSection ?? throw new Exception($"{nameof(zoomingSection)} is required."); _zoomingSection.X = -1; _zoomingSection.Y = -1; @@ -535,15 +531,13 @@ protected internal override void Measure() #endregion - var a = SeriesMiniatureChanged(Series, LegendPosition); - var b = _requiresLegendMeasureAlways && SizeChanged(); - if (Legend is not null && (SeriesMiniatureChanged(Series, LegendPosition) || (_requiresLegendMeasureAlways && SizeChanged()))) + if (Legend is not null && (SeriesMiniatureChanged(Series, LegendPosition) || SizeChanged())) { Legend.Draw(this); - //Update(); PreviousLegendPosition = LegendPosition; PreviousSeriesAtLegend = Series.Where(x => x.IsVisibleAtLegend).ToList(); preserveFirstDraw = IsFirstDraw; + SetPreviousSize(); Measure(); return; } diff --git a/src/LiveChartsCore/Chart.cs b/src/LiveChartsCore/Chart.cs index a6059b9f6..e3c84c9c0 100644 --- a/src/LiveChartsCore/Chart.cs +++ b/src/LiveChartsCore/Chart.cs @@ -408,6 +408,14 @@ protected void SetDrawMargin(LvcSize controlSize, Margin margin) DrawMarginLocation = new LvcPoint(margin.Left, margin.Top); } + /// + /// Saves the previous size of the chart. + /// + protected void SetPreviousSize() + { + _previousSize = ControlSize; + } + /// /// Invokes the event. /// @@ -417,13 +425,14 @@ protected void InvokeOnMeasuring() Measuring?.Invoke(View); } + /// /// Invokes the on update started. /// /// protected void InvokeOnUpdateStarted() { - _previousSize = ControlSize; + SetPreviousSize(); UpdateStarted?.Invoke(View); } diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp.WinForms/CartesianChart.cs b/src/skiasharp/LiveChartsCore.SkiaSharp.WinForms/CartesianChart.cs index ae2e93c7e..80839db81 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp.WinForms/CartesianChart.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp.WinForms/CartesianChart.cs @@ -185,7 +185,7 @@ protected override void InitializeCore() motionCanvas.CanvasCore.AddDrawableTask(zoomingSectionPaint); core = new CartesianChart( - this, LiveChartsSkiaSharp.DefaultPlatformBuilder, motionCanvas.CanvasCore, zoomingSection, true); + this, LiveChartsSkiaSharp.DefaultPlatformBuilder, motionCanvas.CanvasCore, zoomingSection); if (((IChartView)this).DesignerMode) return; core.Update(); } diff --git a/src/skiasharp/LiveChartsCore.SkiaSharpView.Eto/CartesianChart.cs b/src/skiasharp/LiveChartsCore.SkiaSharpView.Eto/CartesianChart.cs index ac7243097..4ee7e3fdc 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharpView.Eto/CartesianChart.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharpView.Eto/CartesianChart.cs @@ -177,7 +177,7 @@ protected override void InitializeCore() motionCanvas.CanvasCore.AddDrawableTask(zoomingSectionPaint); core = new CartesianChart( - this, LiveChartsSkiaSharp.DefaultPlatformBuilder, motionCanvas.CanvasCore, zoomingSection, true); + this, LiveChartsSkiaSharp.DefaultPlatformBuilder, motionCanvas.CanvasCore, zoomingSection); core.Update(); } From cef279c08f06d621898896e4d0fada0b6eddbc82 Mon Sep 17 00:00:00 2001 From: beto-rodriguez Date: Wed, 31 Aug 2022 14:04:30 -0500 Subject: [PATCH 17/50] cleaner drawing context --- src/LiveChartsCore/Drawing/DrawingContext.cs | 5 ----- src/LiveChartsCore/Motion/MotionCanvas.cs | 1 - .../Drawing/AvaloniaDrawingContext.cs | 11 ++++++---- .../Drawing/SkiaSharpDrawingContext.cs | 20 ++----------------- .../SKCharts/SKCartesianChart.cs | 5 +---- .../SKCharts/SKGeoMap.cs | 5 +---- .../SKCharts/SKPieChart.cs | 5 +---- .../SKCharts/SKPolarChart.cs | 5 +---- 8 files changed, 13 insertions(+), 44 deletions(-) diff --git a/src/LiveChartsCore/Drawing/DrawingContext.cs b/src/LiveChartsCore/Drawing/DrawingContext.cs index ae293259d..85085889c 100644 --- a/src/LiveChartsCore/Drawing/DrawingContext.cs +++ b/src/LiveChartsCore/Drawing/DrawingContext.cs @@ -38,9 +38,4 @@ public virtual void OnBegingDraw() /// public virtual void OnEndDraw() { } - - /// - /// Clears the canvas. - /// - public abstract void ClearCanvas(); } diff --git a/src/LiveChartsCore/Motion/MotionCanvas.cs b/src/LiveChartsCore/Motion/MotionCanvas.cs index 6542b3d0b..10e3a9a61 100644 --- a/src/LiveChartsCore/Motion/MotionCanvas.cs +++ b/src/LiveChartsCore/Motion/MotionCanvas.cs @@ -107,7 +107,6 @@ public void DrawFrame(TDrawingContext context) var isValid = true; var frameTime = _stopwatch.ElapsedMilliseconds; - context.ClearCanvas(); var toRemoveGeometries = new List, IDrawable>>(); diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/AvaloniaDrawingContext.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/AvaloniaDrawingContext.cs index 52e557687..e68ee1387 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/AvaloniaDrawingContext.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/AvaloniaDrawingContext.cs @@ -20,6 +20,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. +using LiveChartsCore.Drawing; using LiveChartsCore.Motion; using SkiaSharp; @@ -42,8 +43,10 @@ public AvaloniaDrawingContext(MotionCanvas motionCanvas : base(motionCanvas, info, surface, canvas) { } - /// - /// Clears the canvas. - /// - public override void ClearCanvas() { } + /// + public override void OnBegingDraw() + { + if (MotionCanvas.StartPoint is null) return; + Canvas.Translate(new SKPoint(MotionCanvas.StartPoint.Value.X, MotionCanvas.StartPoint.Value.Y)); + } } diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/SkiaSharpDrawingContext.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/SkiaSharpDrawingContext.cs index 216a680e4..fa40fc931 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/SkiaSharpDrawingContext.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/SkiaSharpDrawingContext.cs @@ -102,19 +102,12 @@ public SkiaSharpDrawingContext( /// public SKPaint Paint { get; set; } - /// - /// Gets or sets the color of the clear. - /// - /// - /// The color of the clear. - /// - public SKColor ClearColor { get; set; } = SKColor.Empty; - /// public override void OnBegingDraw() { - if (MotionCanvas.StartPoint is null) return; + Canvas.Clear(); + if (MotionCanvas.StartPoint is null) return; Canvas.Translate(new SKPoint(MotionCanvas.StartPoint.Value.X, MotionCanvas.StartPoint.Value.Y)); } @@ -122,15 +115,6 @@ public override void OnBegingDraw() public override void OnEndDraw() { if (MotionCanvas.StartPoint is null) return; - Canvas.Restore(); } - - /// - /// Clears the canvas. - /// - public override void ClearCanvas() - { - Canvas.Clear(ClearColor); - } } diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKCartesianChart.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKCartesianChart.cs index 307879571..c3919e2c9 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKCartesianChart.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKCartesianChart.cs @@ -249,10 +249,7 @@ public SKImage GetImage() CoreCanvas, new SKImageInfo(Height, Width), surface, - canvas) - { - ClearColor = Background - }); + canvas)); Core.Unload(); diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKGeoMap.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKGeoMap.cs index b3b8fedd2..435954895 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKGeoMap.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKGeoMap.cs @@ -159,10 +159,7 @@ public SKImage GetImage() Canvas, new SKImageInfo(Height, Width), surface, - canvas) - { - ClearColor = Background - }); + canvas)); _core.Unload(); diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKPieChart.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKPieChart.cs index 035e75aca..57cdbb7f0 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKPieChart.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKPieChart.cs @@ -227,10 +227,7 @@ public SKImage GetImage() CoreCanvas, new SKImageInfo(Height, Width), surface, - canvas) - { - ClearColor = Background - }); + canvas)); Core.Unload(); return surface.Snapshot(); diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKPolarChart.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKPolarChart.cs index 7afbfb7f2..c19bf7315 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKPolarChart.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKPolarChart.cs @@ -245,10 +245,7 @@ public SKImage GetImage() CoreCanvas, new SKImageInfo(Height, Width), surface, - canvas) - { - ClearColor = Background - }); + canvas)); Core.Unload(); return surface.Snapshot(); From 48c633e5eff3ca15495f4039d6b1c21712df7306 Mon Sep 17 00:00:00 2001 From: beto-rodriguez Date: Thu, 1 Sep 2022 13:21:58 -0500 Subject: [PATCH 18/50] fixes #584 --- src/LiveChartsCore/CartesianChart.cs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/LiveChartsCore/CartesianChart.cs b/src/LiveChartsCore/CartesianChart.cs index 84af45fef..e1f67bd0f 100644 --- a/src/LiveChartsCore/CartesianChart.cs +++ b/src/LiveChartsCore/CartesianChart.cs @@ -845,6 +845,18 @@ internal override void InvokePointerUp(LvcPoint point, bool isSecondaryAction) { if (_sectionZoomingStart is not null) { + var xy = Math.Sqrt(Math.Pow(point.X - _sectionZoomingStart.Value.X, 2) + Math.Pow(point.Y - _sectionZoomingStart.Value.Y, 2)); + if (xy < 15) + { + _zoomingSection.X = -1; + _zoomingSection.Y = -1; + _zoomingSection.Width = 0; + _zoomingSection.Height = 0; + Update(); + _sectionZoomingStart = null; + return; + } + if ((_zoomMode & ZoomAndPanMode.X) == ZoomAndPanMode.X) { for (var i = 0; i < XAxes.Length; i++) @@ -916,7 +928,6 @@ internal override void InvokePointerUp(LvcPoint point, bool isSecondaryAction) _zoomingSection.Width = 0; _zoomingSection.Height = 0; Update(); - _sectionZoomingStart = null; return; } From 3fa1b3180a1fb6d165a18aceb316d27f44f7481e Mon Sep 17 00:00:00 2001 From: beto-rodriguez Date: Thu, 1 Sep 2022 13:57:35 -0500 Subject: [PATCH 19/50] fixes #199 --- src/LiveChartsCore/Kernel/ChartElement.cs | 3 +++ src/LiveChartsCore/Kernel/IChartElement.cs | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/src/LiveChartsCore/Kernel/ChartElement.cs b/src/LiveChartsCore/Kernel/ChartElement.cs index af1312d8b..1c442ed63 100644 --- a/src/LiveChartsCore/Kernel/ChartElement.cs +++ b/src/LiveChartsCore/Kernel/ChartElement.cs @@ -35,6 +35,9 @@ public abstract class ChartElement : IChartElement> _deletingTasks = new(); + /// + public object? Tag { get; set; } + /// public abstract void Measure(Chart chart); diff --git a/src/LiveChartsCore/Kernel/IChartElement.cs b/src/LiveChartsCore/Kernel/IChartElement.cs index 9d6da960e..48c0f987b 100644 --- a/src/LiveChartsCore/Kernel/IChartElement.cs +++ b/src/LiveChartsCore/Kernel/IChartElement.cs @@ -31,6 +31,11 @@ namespace LiveChartsCore.Kernel; public interface IChartElement where TDrawingContext : DrawingContext { + /// + /// Gets or sets the object that contains data about the control. + /// + object? Tag { get; set; } + /// /// Measures and schedule the draw of the element in the user interface. /// From d4b799f24a7e924d75bbc3894e78fe8776461535 Mon Sep 17 00:00:00 2001 From: beto-rodriguez Date: Thu, 1 Sep 2022 15:11:14 -0500 Subject: [PATCH 20/50] fixes #365 --- src/LiveChartsCore/Axis.cs | 1 + src/LiveChartsCore/CartesianChart.cs | 1 + src/LiveChartsCore/Chart.cs | 1 - src/LiveChartsCore/DrawMarginFrame.cs | 1 + src/LiveChartsCore/FinancialSeries.cs | 1 + src/LiveChartsCore/ISeries.cs | 7 ++++++- src/LiveChartsCore/LineSeries.cs | 11 ++++++++++- src/LiveChartsCore/PieSeries.cs | 1 + src/LiveChartsCore/PolarAxis.cs | 1 + src/LiveChartsCore/PolarLineSeries.cs | 1 + src/LiveChartsCore/Section.cs | 1 + src/LiveChartsCore/Series.cs | 9 +++++++++ src/LiveChartsCore/StepLineSeries.cs | 10 ++++++++++ src/LiveChartsCore/StrokeAndFillCartesianSeries.cs | 3 ++- 14 files changed, 45 insertions(+), 4 deletions(-) diff --git a/src/LiveChartsCore/Axis.cs b/src/LiveChartsCore/Axis.cs index b138a6755..ceecd464f 100644 --- a/src/LiveChartsCore/Axis.cs +++ b/src/LiveChartsCore/Axis.cs @@ -643,6 +643,7 @@ protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName /// protected override void OnPaintChanged(string? propertyName) { + base.OnPaintChanged(propertyName); OnPropertyChanged(propertyName); } diff --git a/src/LiveChartsCore/CartesianChart.cs b/src/LiveChartsCore/CartesianChart.cs index e1f67bd0f..f4dad42e9 100644 --- a/src/LiveChartsCore/CartesianChart.cs +++ b/src/LiveChartsCore/CartesianChart.cs @@ -536,6 +536,7 @@ protected internal override void Measure() Legend.Draw(this); PreviousLegendPosition = LegendPosition; PreviousSeriesAtLegend = Series.Where(x => x.IsVisibleAtLegend).ToList(); + foreach (var series in PreviousSeriesAtLegend.Cast()) series.PaintsChanged = false; preserveFirstDraw = IsFirstDraw; SetPreviousSize(); Measure(); diff --git a/src/LiveChartsCore/Chart.cs b/src/LiveChartsCore/Chart.cs index e3c84c9c0..063f442fc 100644 --- a/src/LiveChartsCore/Chart.cs +++ b/src/LiveChartsCore/Chart.cs @@ -474,7 +474,6 @@ protected virtual bool SeriesMiniatureChanged(IReadOnlyList? Fill /// protected override void OnPaintChanged(string? propertyName) { + base.OnPaintChanged(propertyName); OnPropertyChanged(propertyName); } diff --git a/src/LiveChartsCore/FinancialSeries.cs b/src/LiveChartsCore/FinancialSeries.cs index 59f263f2b..28cd151bb 100644 --- a/src/LiveChartsCore/FinancialSeries.cs +++ b/src/LiveChartsCore/FinancialSeries.cs @@ -420,6 +420,7 @@ protected internal override void SoftDeleteOrDisposePoint(ChartPoint point, Scal /// protected override void OnPaintChanged(string? propertyName) { + base.OnPaintChanged(propertyName); OnSeriesMiniatureChanged(); OnPropertyChanged(); } diff --git a/src/LiveChartsCore/ISeries.cs b/src/LiveChartsCore/ISeries.cs index 87c3a0127..30ba3ac26 100644 --- a/src/LiveChartsCore/ISeries.cs +++ b/src/LiveChartsCore/ISeries.cs @@ -43,7 +43,12 @@ public interface ISeries : IStopNPC /// /// Gets the properties of the series. /// - SeriesProperties SeriesProperties { get; } + SeriesProperties SeriesProperties { get; } + + /// + /// Gets a value indicating whether any paint changed. + /// + bool PaintsChanged { get; set; } /// /// Gets the active pints. diff --git a/src/LiveChartsCore/LineSeries.cs b/src/LiveChartsCore/LineSeries.cs index 45854a291..01ac1f771 100644 --- a/src/LiveChartsCore/LineSeries.cs +++ b/src/LiveChartsCore/LineSeries.cs @@ -22,7 +22,6 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; using LiveChartsCore.Drawing; using LiveChartsCore.Drawing.Segments; @@ -534,6 +533,16 @@ protected override void OnSeriesMiniatureChanged() CanvasSchedule = context; } + /// + public override bool MiniatureEquals(IChartSeries series) + { + return series is LineSeries lineSeries && + Name == series.Name && + !((ISeries)this).PaintsChanged && + Fill == lineSeries.Fill && Stroke == lineSeries.Stroke && + GeometryFill == lineSeries.GeometryFill && GeometryStroke == lineSeries.GeometryStroke; + } + /// /// Builds an spline from the given points. /// diff --git a/src/LiveChartsCore/PieSeries.cs b/src/LiveChartsCore/PieSeries.cs index b3618edd2..a511302b9 100644 --- a/src/LiveChartsCore/PieSeries.cs +++ b/src/LiveChartsCore/PieSeries.cs @@ -532,6 +532,7 @@ protected override void WhenPointerLeaves(ChartPoint point) /// protected override void OnPaintChanged(string? propertyName) { + base.OnPaintChanged(propertyName); OnSeriesMiniatureChanged(); OnPropertyChanged(propertyName); } diff --git a/src/LiveChartsCore/PolarAxis.cs b/src/LiveChartsCore/PolarAxis.cs index cb9910899..4237ca060 100644 --- a/src/LiveChartsCore/PolarAxis.cs +++ b/src/LiveChartsCore/PolarAxis.cs @@ -656,6 +656,7 @@ protected virtual void SoftDeleteSeparator( /// protected override void OnPaintChanged(string? propertyName) { + base.OnPaintChanged(propertyName); OnPropertyChanged(propertyName); } diff --git a/src/LiveChartsCore/PolarLineSeries.cs b/src/LiveChartsCore/PolarLineSeries.cs index 6e8c24f8f..f06f3963d 100644 --- a/src/LiveChartsCore/PolarLineSeries.cs +++ b/src/LiveChartsCore/PolarLineSeries.cs @@ -489,6 +489,7 @@ public override bool MiniatureEquals(IChartSeries series) /// protected override void OnPaintChanged(string? propertyName) { + base.OnPaintChanged(propertyName); OnSeriesMiniatureChanged(); OnPropertyChanged(); } diff --git a/src/LiveChartsCore/Section.cs b/src/LiveChartsCore/Section.cs index 3b6b4e874..5eab64bbd 100644 --- a/src/LiveChartsCore/Section.cs +++ b/src/LiveChartsCore/Section.cs @@ -160,6 +160,7 @@ public IPaint? Fill /// protected override void OnPaintChanged(string? propertyName) { + base.OnPaintChanged(propertyName); OnPropertyChanged(propertyName); } diff --git a/src/LiveChartsCore/Series.cs b/src/LiveChartsCore/Series.cs index 3e19b1377..d424831fd 100644 --- a/src/LiveChartsCore/Series.cs +++ b/src/LiveChartsCore/Series.cs @@ -117,6 +117,8 @@ protected Series(SeriesProperties properties) (sender, e) => NotifySubscribers()); } + bool ISeries.PaintsChanged { get; set; } + /// public HashSet ActivePoints => everFetched; @@ -455,6 +457,13 @@ protected virtual void WhenPointerLeaves(ChartPoint point) ChartPointPointerHoverLost?.Invoke(point.Context.Chart, new ChartPoint(point)); } + /// + protected override void OnPaintChanged(string? propertyName) + { + base.OnPaintChanged(propertyName); + ((ISeries)this).PaintsChanged = true; + } + /// public override void RemoveFromUI(Chart chart) { diff --git a/src/LiveChartsCore/StepLineSeries.cs b/src/LiveChartsCore/StepLineSeries.cs index 39300a3a4..0d3d8defc 100644 --- a/src/LiveChartsCore/StepLineSeries.cs +++ b/src/LiveChartsCore/StepLineSeries.cs @@ -483,6 +483,16 @@ protected override void OnSeriesMiniatureChanged() CanvasSchedule = context; } + /// + public override bool MiniatureEquals(IChartSeries series) + { + return series is StepLineSeries stepSeries && + Name == series.Name && + !((ISeries)this).PaintsChanged && + Fill == stepSeries.Fill && Stroke == stepSeries.Stroke && + GeometryFill == stepSeries.GeometryFill && GeometryStroke == stepSeries.GeometryStroke; + } + /// protected override void SetDefaultPointTransitions(ChartPoint chartPoint) { diff --git a/src/LiveChartsCore/StrokeAndFillCartesianSeries.cs b/src/LiveChartsCore/StrokeAndFillCartesianSeries.cs index 91a33da77..15ef2e5c6 100644 --- a/src/LiveChartsCore/StrokeAndFillCartesianSeries.cs +++ b/src/LiveChartsCore/StrokeAndFillCartesianSeries.cs @@ -82,6 +82,7 @@ public IPaint? Fill /// protected override void OnPaintChanged(string? propertyName) { + base.OnPaintChanged(propertyName); OnSeriesMiniatureChanged(); OnPropertyChanged(); } @@ -100,6 +101,6 @@ protected override void OnPaintChanged(string? propertyName) public override bool MiniatureEquals(IChartSeries series) { return series is StrokeAndFillCartesianSeries sfSeries && - Name == series.Name && Fill == sfSeries.Fill && Stroke == sfSeries.Stroke; + Name == series.Name && !((ISeries)this).PaintsChanged && Fill == sfSeries.Fill && Stroke == sfSeries.Stroke; } } From a91009685a9827f85b52b2bbb1deadec202bca16 Mon Sep 17 00:00:00 2001 From: beto-rodriguez Date: Fri, 2 Sep 2022 13:52:11 -0500 Subject: [PATCH 21/50] fixes #389 --- .../Drawing/Geometries/DoughnutGeometry.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/DoughnutGeometry.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/DoughnutGeometry.cs index b0ed7a61f..384d022df 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/DoughnutGeometry.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/DoughnutGeometry.cs @@ -125,8 +125,8 @@ public override void OnDraw(SkiaSharpDrawingContext context, SKPaint paint) (float)(cx + Math.Cos(startAngle * toRadians) * wedge), (float)(cy + Math.Sin(startAngle * toRadians) * wedge)); path.LineTo( - (float)(cx + Math.Cos(startAngle * toRadians) * (r + pushout)), - (float)(cy + Math.Sin(startAngle * toRadians) * (r + pushout))); + (float)(cx + Math.Cos(startAngle * toRadians) * r), + (float)(cy + Math.Sin(startAngle * toRadians) * r)); path.ArcTo( new SKRect { Left = X, Top = Y, Size = new SKSize { Width = Width, Height = Height } }, startAngle, From 1334ac1a0c9358cc1c6fff69ae1c3f856d950aea Mon Sep 17 00:00:00 2001 From: beto-rodriguez Date: Fri, 2 Sep 2022 14:07:03 -0500 Subject: [PATCH 22/50] fixes #413 --- src/LiveChartsCore/Axis.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/LiveChartsCore/Axis.cs b/src/LiveChartsCore/Axis.cs index ceecd464f..32408a174 100644 --- a/src/LiveChartsCore/Axis.cs +++ b/src/LiveChartsCore/Axis.cs @@ -477,8 +477,13 @@ NamePadding is not null || SeparatorsPaint is not null || LabelsPaint is not nul separators.Add(separatorKey, visualSeparator); } - if (SeparatorsPaint is not null && ShowSeparatorLines && visualSeparator.Separator is not null) - SeparatorsPaint.AddGeometryToPaintTask(cartesianChart.Canvas, visualSeparator.Separator); + if (SeparatorsPaint is not null && visualSeparator.Separator is not null) + { + if (ShowSeparatorLines) + SeparatorsPaint.AddGeometryToPaintTask(cartesianChart.Canvas, visualSeparator.Separator); + else + SeparatorsPaint.RemoveGeometryFromPainTask(cartesianChart.Canvas, visualSeparator.Separator); + } if (SubseparatorsPaint is not null && visualSeparator.Subseparators is not null) foreach (var subtick in visualSeparator.Subseparators) SubseparatorsPaint.AddGeometryToPaintTask(cartesianChart.Canvas, subtick); if (LabelsPaint is not null && visualSeparator.Label is not null) From 0ef25803b16e1bc479ec5f93f31c08ebfa99865c Mon Sep 17 00:00:00 2001 From: beto-rodriguez Date: Fri, 2 Sep 2022 15:28:44 -0500 Subject: [PATCH 23/50] fixes #424 --- src/LiveChartsCore/Drawing/ILabelGeometry.cs | 5 ++ .../Drawing/Geometries/LabelGeometry.cs | 68 +++++++++++++++---- 2 files changed, 61 insertions(+), 12 deletions(-) diff --git a/src/LiveChartsCore/Drawing/ILabelGeometry.cs b/src/LiveChartsCore/Drawing/ILabelGeometry.cs index a00fc5473..a46b49f67 100644 --- a/src/LiveChartsCore/Drawing/ILabelGeometry.cs +++ b/src/LiveChartsCore/Drawing/ILabelGeometry.cs @@ -70,6 +70,11 @@ public interface ILabelGeometry : IGeometry /// float TextSize { get; set; } + /// + /// Gets or sets the line height, in percentage of the raw hight. + /// + float LineHeight { get; set; } + /// /// Gets or sets the background color. /// diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/LabelGeometry.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/LabelGeometry.cs index fc31f9bdd..ceb6ab57f 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/LabelGeometry.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/LabelGeometry.cs @@ -21,6 +21,9 @@ // SOFTWARE. using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; using LiveChartsCore.Drawing; using LiveChartsCore.Motion; using LiveChartsCore.SkiaSharpView.Painting; @@ -65,6 +68,10 @@ public LabelGeometry() /// public string Text { get; set; } = string.Empty; + + /// + public float LineHeight { get; set; } = 1.2f; + /// public float TextSize { get => _textSizeProperty.GetMovement(this); set => _textSizeProperty.SetMovement(value, this); } @@ -78,25 +85,45 @@ public LabelGeometry() public override void OnDraw(SkiaSharpDrawingContext context, SKPaint paint) { var bg = Background; + var totalSize = OnMeasure(context.PaintTask); + if (bg != LvcColor.Empty) { - var m = OnMeasure(context.PaintTask); using (var bgPaint = new SKPaint { Color = new SKColor(bg.R, bg.G, bg.B, (byte)(bg.A * Opacity)) }) { var p = Padding; - context.Canvas.DrawRect(X - p.Left, Y - m.Height + p.Top, m.Width, m.Height, bgPaint); + context.Canvas.DrawRect(X - p.Left, Y - totalSize.Height + p.Top, totalSize.Width, totalSize.Height, bgPaint); } } - if (paint.Typeface != null) + + var currentY = Padding.Top; + + var lines = GetLines(Text).ToArray(); + foreach (var line in lines) { - using (var eventTextShaper = new SKShaper(paint.Typeface)) + var actualLineContent = line ?? string.Empty; + var lineSize = MeasureLine(paint, actualLineContent); + + var oy = (lineSize.Height - lineSize.Height / LineHeight) * 0.5f; + var ox = HorizontalAlign == Align.Start + ? 0 + : (HorizontalAlign == Align.End + ? totalSize.Width - lineSize.Width + : (totalSize.Width - lineSize.Width) * 0.5f); + + if (paint.Typeface != null) { - context.Canvas.DrawShapedText(eventTextShaper, Text ?? "", new SKPoint(X, Y), paint); + using (var eventTextShaper = new SKShaper(paint.Typeface)) + { + context.Canvas.DrawShapedText(eventTextShaper, actualLineContent, new SKPoint(X + ox, Y + currentY + oy), paint); + } } - } - else - { - context.Canvas.DrawText(Text ?? "", new SKPoint(X, Y), paint); + else + { + context.Canvas.DrawText(actualLineContent, new SKPoint(X + ox, Y + currentY + oy), paint); + } + + currentY += lineSize.Height; } } @@ -112,10 +139,14 @@ protected override LvcSize OnMeasure(Paint drawable) TextSize = TextSize }; - var bounds = new SKRect(); + var size = new LvcSize(); + foreach (var line in GetLines(Text)) + { + var result = MeasureLine(p, line); + size = new LvcSize(size.Width > result.Width ? size.Width : result.Width, size.Height + result.Height); + } - _ = p.MeasureText(Text, ref bounds); - return new LvcSize(bounds.Size.Width + Padding.Left + Padding.Right, bounds.Size.Height + Padding.Top + Padding.Bottom); + return new LvcSize(size.Width + Padding.Left + Padding.Right, size.Height + Padding.Top + Padding.Bottom); } /// @@ -157,4 +188,17 @@ protected override void ApplyCustomGeometryTransform(SkiaSharpDrawingContext con // and also translate according to the vertical an horizontal alignment properties context.Canvas.Translate((float)xp, (float)yp); } + + private SKRect MeasureLine(SKPaint paint, string text) + { + var bounds = new SKRect(); + _ = paint.MeasureText(text, ref bounds); + bounds = new SKRect(0, 0, bounds.Width, bounds.Height * LineHeight); + return bounds; + } + + private IEnumerable GetLines(string rawText) + { + return rawText.Split(new string[] { Environment.NewLine }, StringSplitOptions.None); + } } From 1c85303262dbecdef8b5480d9eb03720dd1d4750 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Fri, 2 Sep 2022 15:47:57 -0500 Subject: [PATCH 24/50] #424 also --- .../Drawing/Geometries/LabelGeometry.cs | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/LabelGeometry.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/LabelGeometry.cs index ceb6ab57f..bee98c80e 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/LabelGeometry.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/LabelGeometry.cs @@ -96,20 +96,22 @@ public override void OnDraw(SkiaSharpDrawingContext context, SKPaint paint) } } - var currentY = Padding.Top; + var currentY = 0f; - var lines = GetLines(Text).ToArray(); - foreach (var line in lines) + foreach (var line in GetLines(Text)) { var actualLineContent = line ?? string.Empty; var lineSize = MeasureLine(paint, actualLineContent); - var oy = (lineSize.Height - lineSize.Height / LineHeight) * 0.5f; - var ox = HorizontalAlign == Align.Start - ? 0 - : (HorizontalAlign == Align.End - ? totalSize.Width - lineSize.Width - : (totalSize.Width - lineSize.Width) * 0.5f); + //var oy = (lineSize.Height - lineSize.Height / LineHeight) * 0.5f; + //var ox = HorizontalAlign == Align.Start + // ? 0 + // : (HorizontalAlign == Align.End + // ? totalSize.Width - lineSize.Width + // : (totalSize.Width - lineSize.Width) * 0.5f); + + var oy = 0; + var ox = 0; if (paint.Typeface != null) { From 0cde4208dd56b58522c48a96d5d915f2078f057e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Fri, 2 Sep 2022 15:48:22 -0500 Subject: [PATCH 25/50] #424 also --- .../Drawing/Geometries/LabelGeometry.cs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/LabelGeometry.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/LabelGeometry.cs index bee98c80e..29f039ab9 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/LabelGeometry.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/LabelGeometry.cs @@ -103,15 +103,12 @@ public override void OnDraw(SkiaSharpDrawingContext context, SKPaint paint) var actualLineContent = line ?? string.Empty; var lineSize = MeasureLine(paint, actualLineContent); - //var oy = (lineSize.Height - lineSize.Height / LineHeight) * 0.5f; - //var ox = HorizontalAlign == Align.Start - // ? 0 - // : (HorizontalAlign == Align.End - // ? totalSize.Width - lineSize.Width - // : (totalSize.Width - lineSize.Width) * 0.5f); - - var oy = 0; - var ox = 0; + var oy = (lineSize.Height - lineSize.Height / LineHeight) * 0.5f; + var ox = HorizontalAlign == Align.Start + ? 0 + : (HorizontalAlign == Align.End + ? totalSize.Width - lineSize.Width + : (totalSize.Width - lineSize.Width) * 0.5f); if (paint.Typeface != null) { From b77959ac8a0d0893b55733a67186963a75b341e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Fri, 2 Sep 2022 15:49:04 -0500 Subject: [PATCH 26/50] #424 also --- .../Drawing/Geometries/LabelGeometry.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/LabelGeometry.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/LabelGeometry.cs index 29f039ab9..cc2c3f05e 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/LabelGeometry.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/LabelGeometry.cs @@ -22,8 +22,6 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Runtime.InteropServices; using LiveChartsCore.Drawing; using LiveChartsCore.Motion; using LiveChartsCore.SkiaSharpView.Painting; From f235963a5b62835885b7c726daf4beb8a691bf98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Fri, 2 Sep 2022 17:48:25 -0500 Subject: [PATCH 27/50] remove unecessary overloads --- .../Axes/LabelsRotation/ViewModel.cs | 3 +- samples/ViewModelsSamples/Index.cs | 210 +++++++++--------- src/LiveChartsCore/Kernel/Extensions.cs | 31 +-- 3 files changed, 113 insertions(+), 131 deletions(-) diff --git a/samples/ViewModelsSamples/Axes/LabelsRotation/ViewModel.cs b/samples/ViewModelsSamples/Axes/LabelsRotation/ViewModel.cs index 1ec9ad66b..1e9258c18 100644 --- a/samples/ViewModelsSamples/Axes/LabelsRotation/ViewModel.cs +++ b/samples/ViewModelsSamples/Axes/LabelsRotation/ViewModel.cs @@ -26,7 +26,7 @@ public partial class ViewModel { // Use the Label property to indicate the format of the labels in the axis // The Labeler takes the value of the label as parameter and must return it as string - Labeler = (value) => "Day " + value, + Labeler = (value) => "so long label with this Day " + value, // The MinStep property lets you define the minimum separation (in chart values scale) // between every axis separator, in this case we don't want decimals, @@ -44,6 +44,7 @@ public partial class ViewModel { new Axis { + IsVisible = false, LabelsRotation = 15, // Now the Y axis we will display it as currency diff --git a/samples/ViewModelsSamples/Index.cs b/samples/ViewModelsSamples/Index.cs index 4474da96c..59865d3a9 100644 --- a/samples/ViewModelsSamples/Index.cs +++ b/samples/ViewModelsSamples/Index.cs @@ -4,111 +4,111 @@ public static class Index { public static string[] Samples = { - "Design/LinearGradients", - "Design/RadialGradients", - - "Lines/Basic", - "Lines/AutoUpdate", - "Lines/Straight", - "Lines/Properties", - "Lines/Area", - "Lines/Custom", - "Lines/Padding", - "Lines/XY", - "Lines/Zoom", - - "StepLines/Basic", - "StepLines/AutoUpdate", - "StepLines/Properties", - "StepLines/Area", - "StepLines/Custom", - "StepLines/Zoom", - - "StackedArea/Basic", - "StackedArea/StepArea", - - "Bars/Basic", - "Bars/AutoUpdate", - "Bars/Custom", - "Bars/WithBackground", - "Bars/Spacing", - "Bars/DelayedAnimation", - "Bars/Race", - "Bars/RowsWithLabels", - "Bars/Layered", - - "StackedBars/Basic", - "StackedBars/Groups", - - "Pies/Basic", - "Pies/AutoUpdate", - "Pies/Processing", - "Pies/Doughnut", - "Pies/Pushout", - "Pies/Custom", - "Pies/NightingaleRose", - "Pies/Gauges", - //"Pies/Gauge", - "Pies/Gauge1", - "Pies/Gauge2", - "Pies/Gauge3", - "Pies/Gauge4", - "Pies/Gauge5", - - "Scatter/Basic", - "Scatter/Bubbles", - "Scatter/AutoUpdate", - "Scatter/Custom", - - "Financial/BasicCandlesticks", - - "Heat/Basic", - - "Polar/Basic", - "Polar/RadialArea", - "Polar/Coordinates", - - "Axes/ColorsAndPosition", - "Axes/LabelsFormat", - "Axes/LabelsFormat2", - "Axes/NamedLabels", + //"Design/LinearGradients", + //"Design/RadialGradients", + + //"Lines/Basic", + //"Lines/AutoUpdate", + //"Lines/Straight", + //"Lines/Properties", + //"Lines/Area", + //"Lines/Custom", + //"Lines/Padding", + //"Lines/XY", + //"Lines/Zoom", + + //"StepLines/Basic", + //"StepLines/AutoUpdate", + //"StepLines/Properties", + //"StepLines/Area", + //"StepLines/Custom", + //"StepLines/Zoom", + + //"StackedArea/Basic", + //"StackedArea/StepArea", + + //"Bars/Basic", + //"Bars/AutoUpdate", + //"Bars/Custom", + //"Bars/WithBackground", + //"Bars/Spacing", + //"Bars/DelayedAnimation", + //"Bars/Race", + //"Bars/RowsWithLabels", + //"Bars/Layered", + + //"StackedBars/Basic", + //"StackedBars/Groups", + + //"Pies/Basic", + //"Pies/AutoUpdate", + //"Pies/Processing", + //"Pies/Doughnut", + //"Pies/Pushout", + //"Pies/Custom", + //"Pies/NightingaleRose", + //"Pies/Gauges", + ////"Pies/Gauge", + //"Pies/Gauge1", + //"Pies/Gauge2", + //"Pies/Gauge3", + //"Pies/Gauge4", + //"Pies/Gauge5", + + //"Scatter/Basic", + //"Scatter/Bubbles", + //"Scatter/AutoUpdate", + //"Scatter/Custom", + + //"Financial/BasicCandlesticks", + + //"Heat/Basic", + + //"Polar/Basic", + //"Polar/RadialArea", + //"Polar/Coordinates", + + //"Axes/ColorsAndPosition", + //"Axes/LabelsFormat", + //"Axes/LabelsFormat2", + //"Axes/NamedLabels", "Axes/LabelsRotation", - "Axes/Multiple", - "Axes/Shared", - "Axes/DateTimeScaled", - "Axes/TimeSpanScaled", - "Axes/Logarithmic", - "Axes/Style", - "Axes/Paging", - - "Events/AddPointOnClick", - "Events/Cartesian", - "Events/Pie", - "Events/Polar", - - "General/Sections", - "General/Sections2", - "General/ChartToImage", - "General/Tooltips", - "General/Legends", - "General/Animations", - "General/Visibility", - "General/TemplatedTooltips", - "General/TemplatedLegends", - "General/UserDefinedTypes", - "General/NullPoints", - "General/MultiThreading", - "General/MultiThreading2", - - "VisualTest/TwoChartsOneSeries", - "VisualTest/ReattachVisual", - "VisualTest/DataTemplate", - "VisualTest/Tabs", - - //"Test/ChangeSeriesInstance", - //"Test/Dispose", - //"Test/MotionCanvasDispose", - - "Maps/World" + //"Axes/Multiple", + //"Axes/Shared", + //"Axes/DateTimeScaled", + //"Axes/TimeSpanScaled", + //"Axes/Logarithmic", + //"Axes/Style", + //"Axes/Paging", + + //"Events/AddPointOnClick", + //"Events/Cartesian", + //"Events/Pie", + //"Events/Polar", + + //"General/Sections", + //"General/Sections2", + //"General/ChartToImage", + //"General/Tooltips", + //"General/Legends", + //"General/Animations", + //"General/Visibility", + //"General/TemplatedTooltips", + //"General/TemplatedLegends", + //"General/UserDefinedTypes", + //"General/NullPoints", + //"General/MultiThreading", + //"General/MultiThreading2", + + //"VisualTest/TwoChartsOneSeries", + //"VisualTest/ReattachVisual", + //"VisualTest/DataTemplate", + //"VisualTest/Tabs", + + ////"Test/ChangeSeriesInstance", + ////"Test/Dispose", + ////"Test/MotionCanvasDispose", + + //"Maps/World" }; } diff --git a/src/LiveChartsCore/Kernel/Extensions.cs b/src/LiveChartsCore/Kernel/Extensions.cs index aedc535b7..e6835f7fa 100644 --- a/src/LiveChartsCore/Kernel/Extensions.cs +++ b/src/LiveChartsCore/Kernel/Extensions.cs @@ -105,29 +105,6 @@ public static class Extensions : null; } - /// - /// Gets the tick. - /// - /// The axis. - /// Size of the control. - /// - public static AxisTick GetTick(this ICartesianAxis axis, LvcSize controlSize) - { - return GetTick(axis, controlSize, axis.VisibleDataBounds); - } - - /// - /// Gets the tick. - /// - /// The axis. - /// The chart. - /// - public static AxisTick GetTick(this IPolarAxis axis, PolarChart chart) - where TDrawingContext : DrawingContext - { - return GetTick(axis, chart, axis.VisibleDataBounds); - } - /// /// Gets the tick. /// @@ -135,8 +112,10 @@ public static AxisTick GetTick(this IPolarAxis axis, PolarChart /// Size of the control. /// The bounds. /// - public static AxisTick GetTick(this ICartesianAxis axis, LvcSize controlSize, Bounds bounds) + public static AxisTick GetTick(this ICartesianAxis axis, LvcSize controlSize, Bounds? bounds = null) { + bounds ??= axis.VisibleDataBounds; + var max = axis.MaxLimit is null ? bounds.Max : axis.MaxLimit.Value; var min = axis.MinLimit is null ? bounds.Min : axis.MinLimit.Value; @@ -164,9 +143,11 @@ public static AxisTick GetTick(this ICartesianAxis axis, LvcSize controlSize, Bo /// The chart. /// The bounds. /// - public static AxisTick GetTick(this IPolarAxis axis, PolarChart chart, Bounds bounds) + public static AxisTick GetTick(this IPolarAxis axis, PolarChart chart, Bounds? bounds = null) where TDrawingContext : DrawingContext { + bounds ??= axis.VisibleDataBounds; + var max = axis.MaxLimit is null ? bounds.Max : axis.MaxLimit.Value; var min = axis.MinLimit is null ? bounds.Min : axis.MinLimit.Value; From 813da55e1ecab99d2f3d35e59d69ad404427f6c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Fri, 2 Sep 2022 18:13:02 -0500 Subject: [PATCH 28/50] use max label size to calculate tick --- src/LiveChartsCore/Axis.cs | 39 ++++++++++++++++++++++++- src/LiveChartsCore/Kernel/Extensions.cs | 9 ++++-- 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/src/LiveChartsCore/Axis.cs b/src/LiveChartsCore/Axis.cs index 32408a174..11d74ffe2 100644 --- a/src/LiveChartsCore/Axis.cs +++ b/src/LiveChartsCore/Axis.cs @@ -261,7 +261,7 @@ public override void Measure(Chart chart) var scale = this.GetNextScaler(cartesianChart); var actualScale = this.GetActualScalerScaler(cartesianChart) ?? scale; - var axisTick = this.GetTick(drawMarginSize); + var axisTick = this.GetTick(drawMarginSize, null, GetPossibleMaxLabelSize()); var labeler = Labeler; if (Labels is not null) @@ -661,6 +661,43 @@ protected override void OnPaintChanged(string? propertyName) return new[] { _separatorsPaint, _labelsPaint, _namePaint, _zeroPaint, _ticksPaint, _subticksPaint, _subseparatorsPaint }; } + private LvcSize GetPossibleMaxLabelSize() + { + if (LabelsPaint is null) return new LvcSize(); + + var labeler = Labeler; + + if (Labels is not null) + { + labeler = Labelers.BuildNamedLabeler(Labels).Function; + _minStep = 1; + } + + var max = MaxLimit is null ? _visibleDataBounds.Max : MaxLimit.Value; + var min = MinLimit is null ? _visibleDataBounds.Min : MinLimit.Value; + var s = (max - min) / 20d; + + var maxLabelSize = new LvcSize(); + for (var i = min; i <= max; i += s) + { + var textGeometry = new TTextGeometry + { + Text = labeler(i), + TextSize = (float)TextSize, + RotateTransform = (float)LabelsRotation, + Padding = _padding + }; + + var m = textGeometry.Measure(LabelsPaint); + + maxLabelSize = new LvcSize( + maxLabelSize.Width > m.Width ? maxLabelSize.Width : m.Width, + maxLabelSize.Height > m.Height ? maxLabelSize.Height : m.Height); + } + + return maxLabelSize; + } + private void DrawName( CartesianChart cartesianChart, float size, diff --git a/src/LiveChartsCore/Kernel/Extensions.cs b/src/LiveChartsCore/Kernel/Extensions.cs index e6835f7fa..95387343d 100644 --- a/src/LiveChartsCore/Kernel/Extensions.cs +++ b/src/LiveChartsCore/Kernel/Extensions.cs @@ -111,10 +111,13 @@ public static class Extensions /// The axis. /// Size of the control. /// The bounds. + /// The max label size. /// - public static AxisTick GetTick(this ICartesianAxis axis, LvcSize controlSize, Bounds? bounds = null) + public static AxisTick GetTick(this ICartesianAxis axis, LvcSize controlSize, Bounds? bounds = null, LvcSize? maxLabelSize = null) { bounds ??= axis.VisibleDataBounds; + var w = maxLabelSize is not null ? maxLabelSize.Value.Width * 0.60 : 20 * Cf; + var h = maxLabelSize is not null ? maxLabelSize.Value.Height * 0.60 : 12 * Cf; var max = axis.MaxLimit is null ? bounds.Max : axis.MaxLimit.Value; var min = axis.MinLimit is null ? bounds.Min : axis.MinLimit.Value; @@ -123,8 +126,8 @@ public static AxisTick GetTick(this ICartesianAxis axis, LvcSize controlSize, Bo if (range == 0) range = min; var separations = axis.Orientation == AxisOrientation.Y - ? Math.Round(controlSize.Height / (12 * Cf), 0) - : Math.Round(controlSize.Width / (20 * Cf), 0); + ? Math.Round(controlSize.Height / h, 0) + : Math.Round(controlSize.Width / w, 0); var minimum = range / separations; From f304eb077092b2ad0af9f81674f9c715a6d54eb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Fri, 2 Sep 2022 18:15:19 -0500 Subject: [PATCH 29/50] restore and verify samples --- samples/ViewModelsSamples/Index.cs | 210 ++++++++++++++--------------- 1 file changed, 105 insertions(+), 105 deletions(-) diff --git a/samples/ViewModelsSamples/Index.cs b/samples/ViewModelsSamples/Index.cs index 59865d3a9..4474da96c 100644 --- a/samples/ViewModelsSamples/Index.cs +++ b/samples/ViewModelsSamples/Index.cs @@ -4,111 +4,111 @@ public static class Index { public static string[] Samples = { - //"Design/LinearGradients", - //"Design/RadialGradients", - - //"Lines/Basic", - //"Lines/AutoUpdate", - //"Lines/Straight", - //"Lines/Properties", - //"Lines/Area", - //"Lines/Custom", - //"Lines/Padding", - //"Lines/XY", - //"Lines/Zoom", - - //"StepLines/Basic", - //"StepLines/AutoUpdate", - //"StepLines/Properties", - //"StepLines/Area", - //"StepLines/Custom", - //"StepLines/Zoom", - - //"StackedArea/Basic", - //"StackedArea/StepArea", - - //"Bars/Basic", - //"Bars/AutoUpdate", - //"Bars/Custom", - //"Bars/WithBackground", - //"Bars/Spacing", - //"Bars/DelayedAnimation", - //"Bars/Race", - //"Bars/RowsWithLabels", - //"Bars/Layered", - - //"StackedBars/Basic", - //"StackedBars/Groups", - - //"Pies/Basic", - //"Pies/AutoUpdate", - //"Pies/Processing", - //"Pies/Doughnut", - //"Pies/Pushout", - //"Pies/Custom", - //"Pies/NightingaleRose", - //"Pies/Gauges", - ////"Pies/Gauge", - //"Pies/Gauge1", - //"Pies/Gauge2", - //"Pies/Gauge3", - //"Pies/Gauge4", - //"Pies/Gauge5", - - //"Scatter/Basic", - //"Scatter/Bubbles", - //"Scatter/AutoUpdate", - //"Scatter/Custom", - - //"Financial/BasicCandlesticks", - - //"Heat/Basic", - - //"Polar/Basic", - //"Polar/RadialArea", - //"Polar/Coordinates", - - //"Axes/ColorsAndPosition", - //"Axes/LabelsFormat", - //"Axes/LabelsFormat2", - //"Axes/NamedLabels", + "Design/LinearGradients", + "Design/RadialGradients", + + "Lines/Basic", + "Lines/AutoUpdate", + "Lines/Straight", + "Lines/Properties", + "Lines/Area", + "Lines/Custom", + "Lines/Padding", + "Lines/XY", + "Lines/Zoom", + + "StepLines/Basic", + "StepLines/AutoUpdate", + "StepLines/Properties", + "StepLines/Area", + "StepLines/Custom", + "StepLines/Zoom", + + "StackedArea/Basic", + "StackedArea/StepArea", + + "Bars/Basic", + "Bars/AutoUpdate", + "Bars/Custom", + "Bars/WithBackground", + "Bars/Spacing", + "Bars/DelayedAnimation", + "Bars/Race", + "Bars/RowsWithLabels", + "Bars/Layered", + + "StackedBars/Basic", + "StackedBars/Groups", + + "Pies/Basic", + "Pies/AutoUpdate", + "Pies/Processing", + "Pies/Doughnut", + "Pies/Pushout", + "Pies/Custom", + "Pies/NightingaleRose", + "Pies/Gauges", + //"Pies/Gauge", + "Pies/Gauge1", + "Pies/Gauge2", + "Pies/Gauge3", + "Pies/Gauge4", + "Pies/Gauge5", + + "Scatter/Basic", + "Scatter/Bubbles", + "Scatter/AutoUpdate", + "Scatter/Custom", + + "Financial/BasicCandlesticks", + + "Heat/Basic", + + "Polar/Basic", + "Polar/RadialArea", + "Polar/Coordinates", + + "Axes/ColorsAndPosition", + "Axes/LabelsFormat", + "Axes/LabelsFormat2", + "Axes/NamedLabels", "Axes/LabelsRotation", - //"Axes/Multiple", - //"Axes/Shared", - //"Axes/DateTimeScaled", - //"Axes/TimeSpanScaled", - //"Axes/Logarithmic", - //"Axes/Style", - //"Axes/Paging", - - //"Events/AddPointOnClick", - //"Events/Cartesian", - //"Events/Pie", - //"Events/Polar", - - //"General/Sections", - //"General/Sections2", - //"General/ChartToImage", - //"General/Tooltips", - //"General/Legends", - //"General/Animations", - //"General/Visibility", - //"General/TemplatedTooltips", - //"General/TemplatedLegends", - //"General/UserDefinedTypes", - //"General/NullPoints", - //"General/MultiThreading", - //"General/MultiThreading2", - - //"VisualTest/TwoChartsOneSeries", - //"VisualTest/ReattachVisual", - //"VisualTest/DataTemplate", - //"VisualTest/Tabs", - - ////"Test/ChangeSeriesInstance", - ////"Test/Dispose", - ////"Test/MotionCanvasDispose", - - //"Maps/World" + "Axes/Multiple", + "Axes/Shared", + "Axes/DateTimeScaled", + "Axes/TimeSpanScaled", + "Axes/Logarithmic", + "Axes/Style", + "Axes/Paging", + + "Events/AddPointOnClick", + "Events/Cartesian", + "Events/Pie", + "Events/Polar", + + "General/Sections", + "General/Sections2", + "General/ChartToImage", + "General/Tooltips", + "General/Legends", + "General/Animations", + "General/Visibility", + "General/TemplatedTooltips", + "General/TemplatedLegends", + "General/UserDefinedTypes", + "General/NullPoints", + "General/MultiThreading", + "General/MultiThreading2", + + "VisualTest/TwoChartsOneSeries", + "VisualTest/ReattachVisual", + "VisualTest/DataTemplate", + "VisualTest/Tabs", + + //"Test/ChangeSeriesInstance", + //"Test/Dispose", + //"Test/MotionCanvasDispose", + + "Maps/World" }; } From da558d570ff44bd0c375a93f1533fd1b6bdb1f87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Fri, 2 Sep 2022 18:32:47 -0500 Subject: [PATCH 30/50] min threshold for label spacing --- src/LiveChartsCore/Kernel/Extensions.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/LiveChartsCore/Kernel/Extensions.cs b/src/LiveChartsCore/Kernel/Extensions.cs index 95387343d..db7e02bb4 100644 --- a/src/LiveChartsCore/Kernel/Extensions.cs +++ b/src/LiveChartsCore/Kernel/Extensions.cs @@ -116,8 +116,12 @@ public static class Extensions public static AxisTick GetTick(this ICartesianAxis axis, LvcSize controlSize, Bounds? bounds = null, LvcSize? maxLabelSize = null) { bounds ??= axis.VisibleDataBounds; - var w = maxLabelSize is not null ? maxLabelSize.Value.Width * 0.60 : 20 * Cf; - var h = maxLabelSize is not null ? maxLabelSize.Value.Height * 0.60 : 12 * Cf; + + var w = (maxLabelSize?.Width ?? 0d) * 0.60; + if (w < 20 * Cf) w = 20 * Cf; + + var h = maxLabelSize?.Height ?? 0d; + if (h < 12 * Cf) h = 12 * Cf; var max = axis.MaxLimit is null ? bounds.Max : axis.MaxLimit.Value; var min = axis.MinLimit is null ? bounds.Min : axis.MinLimit.Value; From 174d637bdcaea8e6763471ac1fd342cf56c887c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Fri, 2 Sep 2022 18:34:35 -0500 Subject: [PATCH 31/50] code style --- src/LiveChartsCore/Chart.cs | 1 - .../LiveChartsCore.SkiaSharp/Drawing/Geometries/LabelGeometry.cs | 1 - 2 files changed, 2 deletions(-) diff --git a/src/LiveChartsCore/Chart.cs b/src/LiveChartsCore/Chart.cs index 063f442fc..c470a0ac9 100644 --- a/src/LiveChartsCore/Chart.cs +++ b/src/LiveChartsCore/Chart.cs @@ -425,7 +425,6 @@ protected void InvokeOnMeasuring() Measuring?.Invoke(View); } - /// /// Invokes the on update started. /// diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/LabelGeometry.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/LabelGeometry.cs index cc2c3f05e..94902c2eb 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/LabelGeometry.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/LabelGeometry.cs @@ -66,7 +66,6 @@ public LabelGeometry() /// public string Text { get; set; } = string.Empty; - /// public float LineHeight { get; set; } = 1.2f; From bc3ed03b5aeb3c353caf756636d9785a88ccfc4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Sun, 4 Sep 2022 13:22:23 -0500 Subject: [PATCH 32/50] improve multiline labels positioning --- src/LiveChartsCore/Drawing/ILabelGeometry.cs | 5 -- .../Drawing/Geometries/LabelGeometry.cs | 89 ++++++++----------- 2 files changed, 39 insertions(+), 55 deletions(-) diff --git a/src/LiveChartsCore/Drawing/ILabelGeometry.cs b/src/LiveChartsCore/Drawing/ILabelGeometry.cs index a46b49f67..a00fc5473 100644 --- a/src/LiveChartsCore/Drawing/ILabelGeometry.cs +++ b/src/LiveChartsCore/Drawing/ILabelGeometry.cs @@ -70,11 +70,6 @@ public interface ILabelGeometry : IGeometry /// float TextSize { get; set; } - /// - /// Gets or sets the line height, in percentage of the raw hight. - /// - float LineHeight { get; set; } - /// /// Gets or sets the background color. /// diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/LabelGeometry.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/LabelGeometry.cs index 94902c2eb..42b4dd81c 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/LabelGeometry.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/LabelGeometry.cs @@ -21,7 +21,6 @@ // SOFTWARE. using System; -using System.Collections.Generic; using LiveChartsCore.Drawing; using LiveChartsCore.Motion; using LiveChartsCore.SkiaSharpView.Painting; @@ -66,9 +65,6 @@ public LabelGeometry() /// public string Text { get; set; } = string.Empty; - /// - public float LineHeight { get; set; } = 1.2f; - /// public float TextSize { get => _textSizeProperty.GetMovement(this); set => _textSizeProperty.SetMovement(value, this); } @@ -81,45 +77,24 @@ public LabelGeometry() /// public override void OnDraw(SkiaSharpDrawingContext context, SKPaint paint) { - var bg = Background; - var totalSize = OnMeasure(context.PaintTask); + var size = OnMeasure(context.PaintTask); + var bg = Background; if (bg != LvcColor.Empty) { using (var bgPaint = new SKPaint { Color = new SKColor(bg.R, bg.G, bg.B, (byte)(bg.A * Opacity)) }) { var p = Padding; - context.Canvas.DrawRect(X - p.Left, Y - totalSize.Height + p.Top, totalSize.Width, totalSize.Height, bgPaint); + context.Canvas.DrawRect(X - p.Left, Y - size.Height + p.Top, size.Width, size.Height, bgPaint); } } - var currentY = 0f; - - foreach (var line in GetLines(Text)) + var lines = GetLines(Text); + double linesCount = lines.Length; + var lineNumber = 0; + foreach (var line in lines) { - var actualLineContent = line ?? string.Empty; - var lineSize = MeasureLine(paint, actualLineContent); - - var oy = (lineSize.Height - lineSize.Height / LineHeight) * 0.5f; - var ox = HorizontalAlign == Align.Start - ? 0 - : (HorizontalAlign == Align.End - ? totalSize.Width - lineSize.Width - : (totalSize.Width - lineSize.Width) * 0.5f); - - if (paint.Typeface != null) - { - using (var eventTextShaper = new SKShaper(paint.Typeface)) - { - context.Canvas.DrawShapedText(eventTextShaper, actualLineContent, new SKPoint(X + ox, Y + currentY + oy), paint); - } - } - else - { - context.Canvas.DrawText(actualLineContent, new SKPoint(X + ox, Y + currentY + oy), paint); - } - - currentY += lineSize.Height; + DrawLine(line, -size.Height + (float)(++lineNumber / linesCount * size.Height), context, paint); } } @@ -135,24 +110,18 @@ protected override LvcSize OnMeasure(Paint drawable) TextSize = TextSize }; - var size = new LvcSize(); - foreach (var line in GetLines(Text)) - { - var result = MeasureLine(p, line); - size = new LvcSize(size.Width > result.Width ? size.Width : result.Width, size.Height + result.Height); - } + var bounds = MeasureLines(p); - return new LvcSize(size.Width + Padding.Left + Padding.Right, size.Height + Padding.Top + Padding.Bottom); + return new LvcSize(bounds.Width + Padding.Left + Padding.Right, bounds.Height + Padding.Top + Padding.Bottom); } /// protected override void ApplyCustomGeometryTransform(SkiaSharpDrawingContext context) { - var size = new SKRect(); context.Paint.TextSize = TextSize; - _ = context.Paint.MeasureText(Text, ref size); - const double toRadians = Math.PI / 180d; + var size = MeasureLines(context.Paint); + const double toRadians = Math.PI / 180d; var p = Padding; float w = 0.5f, h = 0.5f; @@ -185,16 +154,36 @@ protected override void ApplyCustomGeometryTransform(SkiaSharpDrawingContext con context.Canvas.Translate((float)xp, (float)yp); } - private SKRect MeasureLine(SKPaint paint, string text) + private void DrawLine(string content, float yLine, SkiaSharpDrawingContext context, SKPaint paint) + { + if (paint.Typeface is not null) + { + using var eventTextShaper = new SKShaper(paint.Typeface); + context.Canvas.DrawShapedText(content, new SKPoint(X, Y + yLine), paint); + return; + } + + context.Canvas.DrawText(content, new SKPoint(X, Y + yLine), paint); + } + + private LvcSize MeasureLines(SKPaint paint) { - var bounds = new SKRect(); - _ = paint.MeasureText(text, ref bounds); - bounds = new SKRect(0, 0, bounds.Width, bounds.Height * LineHeight); - return bounds; + float w = 0f, h = 0f; + + foreach (var line in GetLines(Text)) + { + var bounds = new SKRect(); + _ = paint.MeasureText(line, ref bounds); + + if (bounds.Width > w) w = bounds.Width; + h += bounds.Height; + } + + return new LvcSize(w, h); } - private IEnumerable GetLines(string rawText) + private string[] GetLines(string multiLineText) { - return rawText.Split(new string[] { Environment.NewLine }, StringSplitOptions.None); + return multiLineText.Split(new string[] { Environment.NewLine }, StringSplitOptions.None); } } From c96b1aacf0983f5499d78c2364065a9d33c7c7fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Sun, 4 Sep 2022 19:08:19 -0500 Subject: [PATCH 33/50] visual elements in wpf --- .../Drawing/TransitionBuilder.cs | 13 ++ .../Kernel/Sketches/ICartesianChartView.cs | 5 + .../CartesianChart.cs | 38 ++++- .../FluentDrawingExtensions.cs | 2 +- .../SKCharts/SKCartesianChart.cs | 3 + .../VisualElements/GeometryVisualElement.cs | 161 ++++++++++++++++++ .../VisualElements/MeasureUnit.cs | 39 +++++ .../VisualElements/RectangleVisualElement.cs | 110 ++++++++++++ 8 files changed, 367 insertions(+), 4 deletions(-) create mode 100644 src/skiasharp/LiveChartsCore.SkiaSharp/VisualElements/GeometryVisualElement.cs create mode 100644 src/skiasharp/LiveChartsCore.SkiaSharp/VisualElements/MeasureUnit.cs create mode 100644 src/skiasharp/LiveChartsCore.SkiaSharp/VisualElements/RectangleVisualElement.cs diff --git a/src/LiveChartsCore/Drawing/TransitionBuilder.cs b/src/LiveChartsCore/Drawing/TransitionBuilder.cs index 048d344db..9609d0162 100644 --- a/src/LiveChartsCore/Drawing/TransitionBuilder.cs +++ b/src/LiveChartsCore/Drawing/TransitionBuilder.cs @@ -21,6 +21,7 @@ // SOFTWARE. using System; +using LiveChartsCore.Kernel.Sketches; namespace LiveChartsCore.Drawing; @@ -66,6 +67,18 @@ public TransitionBuilder WithAnimation(Action animationBuilder) return WithAnimation(animation); } + /// + /// Sets the animations based on the chart and properties. + /// + /// The chart. + /// The transition + public TransitionBuilder WithAnimation(IChart chart) + { + return WithAnimation(new Animation() + .WithDuration(chart.View.AnimationsSpeed) + .WithEasingFunction(chart.View.EasingFunction)); + } + /// /// Sets the current transitions. /// diff --git a/src/LiveChartsCore/Kernel/Sketches/ICartesianChartView.cs b/src/LiveChartsCore/Kernel/Sketches/ICartesianChartView.cs index 629d07c7f..f9b7d2524 100644 --- a/src/LiveChartsCore/Kernel/Sketches/ICartesianChartView.cs +++ b/src/LiveChartsCore/Kernel/Sketches/ICartesianChartView.cs @@ -66,6 +66,11 @@ public interface ICartesianChartView : IChartView IEnumerable> Sections { get; set; } + /// + /// Gets or sets the visual elements. + /// + IEnumerable> VisualElements { get; set; } + /// /// Gets or sets the series to plot in the user interface. /// diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp.WPF/CartesianChart.cs b/src/skiasharp/LiveChartsCore.SkiaSharp.WPF/CartesianChart.cs index 0c439c1ef..7689c8692 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp.WPF/CartesianChart.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp.WPF/CartesianChart.cs @@ -46,6 +46,7 @@ public class CartesianChart : Chart, ICartesianChartView _xObserver; private readonly CollectionDeepObserver _yObserver; private readonly CollectionDeepObserver> _sectionsObserver; + private readonly CollectionDeepObserver> _visualsObserver; private readonly RectangleGeometry _zoomingSection = new(); #endregion @@ -65,6 +66,8 @@ public CartesianChart() _yObserver = new CollectionDeepObserver(OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); _sectionsObserver = new CollectionDeepObserver>( OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); + _visualsObserver = new CollectionDeepObserver>( + OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); SetCurrentValue(XAxesProperty, new ObservableCollection() { @@ -178,6 +181,28 @@ public CartesianChart() : new List>(); })); + /// + /// The visual elements property + /// + public static readonly DependencyProperty VisualElementsProperty = + DependencyProperty.Register( + nameof(VisualElements), typeof(IEnumerable>), typeof(CartesianChart), new PropertyMetadata(null, + (DependencyObject o, DependencyPropertyChangedEventArgs args) => + { + var chart = (CartesianChart)o; + var observer = chart._visualsObserver; + observer?.Dispose((IEnumerable>)args.OldValue); + observer?.Initialize((IEnumerable>)args.NewValue); + if (chart.core is null) return; + chart.core.Update(); + }, + (DependencyObject o, object value) => + { + return value is IEnumerable> + ? value + : new List>(); + })); + /// /// The zoom mode property /// @@ -244,6 +269,13 @@ public IEnumerable> Sections set => SetValue(SectionsProperty, value); } + /// + public IEnumerable> VisualElements + { + get => (IEnumerable>)GetValue(VisualElementsProperty); + set => SetValue(VisualElementsProperty, value); + } + /// public DrawMarginFrame? DrawMarginFrame { @@ -340,21 +372,21 @@ private void OnDeepCollectionPropertyChanged(object? sender, PropertyChangedEven core.Update(); } - private void OnMouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e) + private void OnMouseDown(object sender, MouseButtonEventArgs e) { _ = CaptureMouse(); var p = e.GetPosition(this); core?.InvokePointerDown(new LvcPoint((float)p.X, (float)p.Y), e.ChangedButton == MouseButton.Right); } - private void OnMouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e) + private void OnMouseUp(object sender, MouseButtonEventArgs e) { var p = e.GetPosition(this); core?.InvokePointerUp(new LvcPoint((float)p.X, (float)p.Y), e.ChangedButton == MouseButton.Right); ReleaseMouseCapture(); } - private void OnMouseWheel(object? sender, System.Windows.Input.MouseWheelEventArgs e) + private void OnMouseWheel(object? sender, MouseWheelEventArgs e) { if (core is null) throw new Exception("core not found"); var c = (CartesianChart)core; diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/FluentDrawingExtensions.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/FluentDrawingExtensions.cs index f12ce2a47..65cb867ac 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/FluentDrawingExtensions.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/FluentDrawingExtensions.cs @@ -35,7 +35,7 @@ namespace LiveChartsCore.SkiaSharpView; public static class DrawingFluentExtensions { /// - /// Adds a paint task to the canvas. + /// Initializes a drawing in the given canvas. /// /// The canvas. public static Drawing Draw(this MotionCanvas canvas) diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKCartesianChart.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKCartesianChart.cs index c3919e2c9..9a360e3da 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKCartesianChart.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKCartesianChart.cs @@ -119,6 +119,9 @@ public SKCartesianChart(ICartesianChartView view) : thi /// public IEnumerable> Sections { get; set; } = Array.Empty(); + /// + public IEnumerable> VisualElements { get; set; } = Array.Empty>(); + /// public IEnumerable Series { get; set; } = Array.Empty(); diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/VisualElements/GeometryVisualElement.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/VisualElements/GeometryVisualElement.cs new file mode 100644 index 000000000..e8e7ac8ce --- /dev/null +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/VisualElements/GeometryVisualElement.cs @@ -0,0 +1,161 @@ +// The MIT License(MIT) +// +// Copyright(c) 2021 Alberto Rodriguez Orozco & LiveCharts Contributors +// +// 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 System.ComponentModel; +using System.Runtime.CompilerServices; +using LiveChartsCore.Drawing; +using LiveChartsCore.Kernel; +using LiveChartsCore.Kernel.Sketches; +using LiveChartsCore.Measure; +using LiveChartsCore.SkiaSharpView.Drawing; +using LiveChartsCore.SkiaSharpView.Drawing.Geometries; + +namespace LiveChartsCore.SkiaSharpView.VisualElements; + +/// +/// Defines a visual element with stroke and fill properties. +/// +public abstract class GeometryVisualElement : ChartElement, INotifyPropertyChanged +{ + private IPaint? _fill; + private IPaint? _stroke; + private int _scalesXAt; + private int _scalesYAt; + + /// + /// Called when a property changes. + /// + public event PropertyChangedEventHandler? PropertyChanged; + + /// + /// Gets or sets the fill paint. + /// + public IPaint? Fill + { + get => _fill; + set => SetPaintProperty(ref _fill, value); + } + + /// + /// Gets or sets the stroke paint. + /// + public IPaint? Stroke + { + get => _stroke; + set => SetPaintProperty(ref _stroke, value); + } + + /// + /// Gets or sets the axis index where the series is scaled in the X plane, the index must exist + /// in the collection. + /// + /// + /// The index of the axis. + /// + public int ScalesXAt { get => _scalesXAt; set { _scalesXAt = value; OnPropertyChanged(); } } + + /// + /// Gets or sets the axis index where the series is scaled in the Y plane, the index must exist + /// in the collection. + /// + /// + /// The index of the axis. + /// + public int ScalesYAt { get => _scalesYAt; set { _scalesYAt = value; OnPropertyChanged(); } } + + /// + public override void Measure(Chart chart) + { + Scaler? primary = null; + Scaler? secondary = null; + + CartesianChart? cartesianChart = null; + + if (chart is CartesianChart cc) + { + cartesianChart = cc; + var primaryAxis = cartesianChart.YAxes[ScalesYAt]; + var secondaryAxis = cartesianChart.XAxes[ScalesXAt]; + secondary = secondaryAxis.GetNextScaler(cartesianChart); + primary = primaryAxis.GetNextScaler(cartesianChart); + } + + foreach (var paintTask in GetPaintTasks()) + { + if (paintTask is null) continue; + + if (cartesianChart is not null) + { + paintTask.SetClipRectangle( + cartesianChart.Canvas, + new LvcRectangle(cartesianChart.DrawMarginLocation, cartesianChart.DrawMarginSize)); + } + + chart.Canvas.AddDrawableTask(paintTask); + } + + if (primary is null || secondary is null) throw new Exception($"This chart does not support VisualElements"); + + Draw(chart, primary, secondary); + } + + /// + protected override IPaint?[] GetPaintTasks() + { + return new[] { _fill, _stroke }; + } + + /// + /// Called when [paint changed]. + /// + /// Name of the property. + /// + protected override void OnPaintChanged(string? propertyName) + { + base.OnPaintChanged(propertyName); + OnPropertyChanged(propertyName); + } + + /// + /// Called when a property changes. + /// + /// Name of the property. + /// + protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + + /// + /// Called when the visual is drawn. + /// + /// The chart. + /// + /// The primary axis scaler, normally the Y axis. If the chart is Polar then it is the Angle scaler. If the chart is a pie chart + /// then it is the Values Scaler. + /// + /// + /// The secondary axis scaler, normally the X axis. If the chart is Polar then it is the Radius scaler. If the chart is a pie chart + /// then it is the index Scaler. + protected abstract void Draw(Chart chart, Scaler primaryAxisScale, Scaler secondaryAxisScale); +} diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/VisualElements/MeasureUnit.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/VisualElements/MeasureUnit.cs new file mode 100644 index 000000000..8ca3e7704 --- /dev/null +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/VisualElements/MeasureUnit.cs @@ -0,0 +1,39 @@ +// The MIT License(MIT) +// +// Copyright(c) 2021 Alberto Rodriguez Orozco & LiveCharts Contributors +// +// 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. + +namespace LiveChartsCore.SkiaSharpView.VisualElements; + +/// +/// Defines measurement units. +/// +public enum MeasureUnit +{ + /// + /// Indicates that the unit is in pixels. + /// + Pixels, + + /// + /// Indicates that the unit is in CahrtValues. + /// + ChartValues +} diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/VisualElements/RectangleVisualElement.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/VisualElements/RectangleVisualElement.cs new file mode 100644 index 000000000..4992eeffd --- /dev/null +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/VisualElements/RectangleVisualElement.cs @@ -0,0 +1,110 @@ +// The MIT License(MIT) +// +// Copyright(c) 2021 Alberto Rodriguez Orozco & LiveCharts Contributors +// +// 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 LiveChartsCore.Kernel; +using LiveChartsCore.Measure; +using LiveChartsCore.SkiaSharpView.Drawing; +using LiveChartsCore.SkiaSharpView.Drawing.Geometries; + +namespace LiveChartsCore.SkiaSharpView.VisualElements; + +/// +/// Defines a visual element in a chart that draws a rectangle geometry in the user interface. +/// +public class RectangleVisualElement : GeometryVisualElement +{ + private RectangleGeometry? _rectangleGeometry; + private double _x; + private double _y; + private double _width; + private double _height; + + /// + /// Gets or sets the X coordinate [in Pixels or ChartValues, see ]. + /// + public double X { get => _x; set { _x = value; OnPropertyChanged(); } } + + /// + /// Gets or sets the Y coordinate [in Pixels or ChartValues, see ]. + /// + public double Y { get => _y; set { _y = value; OnPropertyChanged(); } } + + /// + /// Gets or sets the unit of the and properties. + /// + public MeasureUnit LocationUnit { get; set; } = MeasureUnit.Pixels; + + /// + /// Gets or sets the height of the rectangle [in Pixels or ChartValues, see ]. + /// + public double Width { get => _width; set { _width = value; OnPropertyChanged(); } } + + /// + /// Gets or sets the width of the rectangle [in Pixels or ChartValues, see ]. + /// + public double Height { get => _height; set { _height = value; OnPropertyChanged(); } } + + /// + /// Gets or sets the unit of the and properties. + /// + public MeasureUnit SizeUnit { get; set; } = MeasureUnit.Pixels; + + /// + protected override void Draw(Chart chart, Scaler primaryAxisScale, Scaler secondaryAxisScale) + { + var x = (float)X; + var y = (float)Y; + var w = (float)Width; + var h = (float)Height; + + if (SizeUnit == MeasureUnit.ChartValues) + { + x = secondaryAxisScale.ToPixels(x); + y = primaryAxisScale.ToPixels(y); + } + + if (LocationUnit == MeasureUnit.ChartValues) + { + w = secondaryAxisScale.ToPixels(w); + h = primaryAxisScale.ToPixels(h); + } + + if (_rectangleGeometry is null) + { + _rectangleGeometry = new RectangleGeometry { X = x, Y = y, Width = w, Height = h }; + + _ = _rectangleGeometry + .TransitionateProperties() + .WithAnimation(chart) + .CompleteCurrentTransitions(); + } + + _rectangleGeometry.X = x; + _rectangleGeometry.Y = y; + _rectangleGeometry.Width = w; + _rectangleGeometry.Height = h; + + var drawing = chart.Canvas.Draw(); + if (Fill is not null) _ = drawing.SelectPaint(Fill).Draw(_rectangleGeometry); + if (Stroke is not null) _ = drawing.SelectPaint(Stroke).Draw(_rectangleGeometry); + } +} From e9eb68b7b1d968f3b951755f61e388de3f3a20b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Sun, 4 Sep 2022 20:00:13 -0500 Subject: [PATCH 34/50] wpf visual element sample --- .../General/VisualElements/ViewModel.cs | 36 +++++++++++++++++++ samples/ViewModelsSamples/Index.cs | 1 + .../General/VisualElements/View.xaml | 15 ++++++++ .../General/VisualElements/View.xaml.cs | 14 ++++++++ samples/WPFSample/WPFSample.csproj | 7 ++++ src/LiveChartsCore/CartesianChart.cs | 26 ++++++++++++++ .../Kernel/Sketches/ICartesianChartView.cs | 2 +- .../CartesianChart.cs | 19 +++++----- .../SKCharts/SKCartesianChart.cs | 2 +- 9 files changed, 111 insertions(+), 11 deletions(-) create mode 100644 samples/ViewModelsSamples/General/VisualElements/ViewModel.cs create mode 100644 samples/WPFSample/General/VisualElements/View.xaml create mode 100644 samples/WPFSample/General/VisualElements/View.xaml.cs diff --git a/samples/ViewModelsSamples/General/VisualElements/ViewModel.cs b/samples/ViewModelsSamples/General/VisualElements/ViewModel.cs new file mode 100644 index 000000000..549a603f5 --- /dev/null +++ b/samples/ViewModelsSamples/General/VisualElements/ViewModel.cs @@ -0,0 +1,36 @@ +using System.Collections.Generic; +using LiveChartsCore; +using LiveChartsCore.Kernel; +using LiveChartsCore.SkiaSharpView; +using LiveChartsCore.SkiaSharpView.Drawing; +using LiveChartsCore.SkiaSharpView.Painting; +using LiveChartsCore.SkiaSharpView.VisualElements; +using SkiaSharp; + +namespace ViewModelsSamples.General.VisualElements; + +public partial class ViewModel +{ + public IEnumerable> VisualElements { get; set; } = new List> + { + new RectangleVisualElement + { + X = 5, + Y = 1, + LocationUnit = MeasureUnit.ChartValues, + Width = 1, + Height = 1, + SizeUnit = MeasureUnit.ChartValues, + Stroke = new SolidColorPaint(SKColors.Red, 2) + } + }; + + public ISeries[] Series { get; set; } = + { + new LineSeries + { + GeometrySize = 13, + Values = new int[] { 1,2,3,4,2,1,3,6,3,5,2,1,4,5,2,3,1,4,5,3,1,6,2,4,5,8,4,5,6,4,7,5,8,4,6,5,4,7,8,9,9,8,7,9,8,7,9,9,8,6,8 } + } + }; +} diff --git a/samples/ViewModelsSamples/Index.cs b/samples/ViewModelsSamples/Index.cs index 4474da96c..b6325e8bb 100644 --- a/samples/ViewModelsSamples/Index.cs +++ b/samples/ViewModelsSamples/Index.cs @@ -88,6 +88,7 @@ public static class Index "General/Sections", "General/Sections2", + "General/VisualElements", "General/ChartToImage", "General/Tooltips", "General/Legends", diff --git a/samples/WPFSample/General/VisualElements/View.xaml b/samples/WPFSample/General/VisualElements/View.xaml new file mode 100644 index 000000000..666d8f2c6 --- /dev/null +++ b/samples/WPFSample/General/VisualElements/View.xaml @@ -0,0 +1,15 @@ + + + + + + + + + diff --git a/samples/WPFSample/General/VisualElements/View.xaml.cs b/samples/WPFSample/General/VisualElements/View.xaml.cs new file mode 100644 index 000000000..41332e3e3 --- /dev/null +++ b/samples/WPFSample/General/VisualElements/View.xaml.cs @@ -0,0 +1,14 @@ +using System.Windows.Controls; + +namespace WPFSample.General.VisualElements; + +/// +/// Interaction logic for View.xaml +/// +public partial class View : UserControl +{ + public View() + { + InitializeComponent(); + } +} diff --git a/samples/WPFSample/WPFSample.csproj b/samples/WPFSample/WPFSample.csproj index 8927025d2..f7af80729 100644 --- a/samples/WPFSample/WPFSample.csproj +++ b/samples/WPFSample/WPFSample.csproj @@ -116,6 +116,9 @@ Code + + Code + Code @@ -387,6 +390,10 @@ $(DefaultXamlRuntime) Designer + + $(DefaultXamlRuntime) + Designer + $(DefaultXamlRuntime) Designer diff --git a/src/LiveChartsCore/CartesianChart.cs b/src/LiveChartsCore/CartesianChart.cs index f4dad42e9..c796d25fc 100644 --- a/src/LiveChartsCore/CartesianChart.cs +++ b/src/LiveChartsCore/CartesianChart.cs @@ -43,6 +43,7 @@ public class CartesianChart : Chart internal readonly HashSet _everMeasuredSeries = new(); internal readonly HashSet> _everMeasuredAxes = new(); internal readonly HashSet> _everMeasuredSections = new(); + internal readonly HashSet> _everMeasuredVisuals = new(); private readonly ICartesianChartView _chartView; private readonly ISizedGeometry _zoomingSection; private int _nextSeries = 0; @@ -106,6 +107,14 @@ public CartesianChart( /// public Section[] Sections { get; private set; } = Array.Empty>(); + /// + /// Gets the visual elements. + /// + /// + /// The visual elements. + /// + public ChartElement[] VisualElements { get; private set; } = Array.Empty>(); + /// /// Gets the drawable series. /// @@ -439,6 +448,7 @@ protected internal override void Measure() .ToArray(); Sections = _chartView.Sections?.Where(x => x.IsVisible).ToArray() ?? Array.Empty>(); + VisualElements = _chartView.VisualElements?.ToArray() ?? Array.Empty>(); #endregion @@ -716,6 +726,15 @@ protected internal override void Measure() _ = toDeleteSections.Remove(section); } + var toDeleteVisualElements = new HashSet>(_everMeasuredVisuals); + foreach (var visual in VisualElements) + { + visual.Measure(this); + visual.RemoveOldPaints(View); + _ = _everMeasuredVisuals.Add(visual); + _ = toDeleteVisualElements.Remove(visual); + } + var toDeleteSeries = new HashSet(_everMeasuredSeries); foreach (var series in Series) { @@ -752,6 +771,11 @@ protected internal override void Measure() section.RemoveFromUI(this); _ = _everMeasuredSections.Remove(section); } + foreach (var visual in toDeleteVisualElements) + { + visual.RemoveFromUI(this); + _ = _everMeasuredVisuals.Remove(visual); + } foreach (var axis in totalAxes) { @@ -784,6 +808,8 @@ public override void Unload() _everMeasuredAxes.Clear(); foreach (var item in _everMeasuredSections) item.RemoveFromUI(this); _everMeasuredSections.Clear(); + foreach (var item in _everMeasuredVisuals) item.RemoveFromUI(this); + _everMeasuredVisuals.Clear(); foreach (var item in _everMeasuredSeries) ((ChartElement)item).RemoveFromUI(this); _everMeasuredSeries.Clear(); diff --git a/src/LiveChartsCore/Kernel/Sketches/ICartesianChartView.cs b/src/LiveChartsCore/Kernel/Sketches/ICartesianChartView.cs index f9b7d2524..bfef33960 100644 --- a/src/LiveChartsCore/Kernel/Sketches/ICartesianChartView.cs +++ b/src/LiveChartsCore/Kernel/Sketches/ICartesianChartView.cs @@ -69,7 +69,7 @@ public interface ICartesianChartView : IChartView /// Gets or sets the visual elements. /// - IEnumerable> VisualElements { get; set; } + IEnumerable> VisualElements { get; set; } /// /// Gets or sets the series to plot in the user interface. diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp.WPF/CartesianChart.cs b/src/skiasharp/LiveChartsCore.SkiaSharp.WPF/CartesianChart.cs index 7689c8692..c59eefeaa 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp.WPF/CartesianChart.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp.WPF/CartesianChart.cs @@ -46,7 +46,7 @@ public class CartesianChart : Chart, ICartesianChartView _xObserver; private readonly CollectionDeepObserver _yObserver; private readonly CollectionDeepObserver> _sectionsObserver; - private readonly CollectionDeepObserver> _visualsObserver; + private readonly CollectionDeepObserver> _visualsObserver; private readonly RectangleGeometry _zoomingSection = new(); #endregion @@ -66,7 +66,7 @@ public CartesianChart() _yObserver = new CollectionDeepObserver(OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); _sectionsObserver = new CollectionDeepObserver>( OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); - _visualsObserver = new CollectionDeepObserver>( + _visualsObserver = new CollectionDeepObserver>( OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); SetCurrentValue(XAxesProperty, new ObservableCollection() @@ -79,6 +79,7 @@ public CartesianChart() }); SetCurrentValue(SeriesProperty, new ObservableCollection()); SetCurrentValue(SectionsProperty, new ObservableCollection>()); + SetCurrentValue(VisualElementsProperty, new ObservableCollection>()); MouseWheel += OnMouseWheel; MouseDown += OnMouseDown; @@ -186,21 +187,21 @@ public CartesianChart() /// public static readonly DependencyProperty VisualElementsProperty = DependencyProperty.Register( - nameof(VisualElements), typeof(IEnumerable>), typeof(CartesianChart), new PropertyMetadata(null, + nameof(VisualElements), typeof(IEnumerable>), typeof(CartesianChart), new PropertyMetadata(null, (DependencyObject o, DependencyPropertyChangedEventArgs args) => { var chart = (CartesianChart)o; var observer = chart._visualsObserver; - observer?.Dispose((IEnumerable>)args.OldValue); - observer?.Initialize((IEnumerable>)args.NewValue); + observer?.Dispose((IEnumerable>)args.OldValue); + observer?.Initialize((IEnumerable>)args.NewValue); if (chart.core is null) return; chart.core.Update(); }, (DependencyObject o, object value) => { - return value is IEnumerable> + return value is IEnumerable> ? value - : new List>(); + : new List>(); })); /// @@ -270,9 +271,9 @@ public IEnumerable> Sections } /// - public IEnumerable> VisualElements + public IEnumerable> VisualElements { - get => (IEnumerable>)GetValue(VisualElementsProperty); + get => (IEnumerable>)GetValue(VisualElementsProperty); set => SetValue(VisualElementsProperty, value); } diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKCartesianChart.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKCartesianChart.cs index 9a360e3da..ac15cd503 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKCartesianChart.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKCartesianChart.cs @@ -120,7 +120,7 @@ public SKCartesianChart(ICartesianChartView view) : thi public IEnumerable> Sections { get; set; } = Array.Empty(); /// - public IEnumerable> VisualElements { get; set; } = Array.Empty>(); + public IEnumerable> VisualElements { get; set; } = Array.Empty>(); /// public IEnumerable Series { get; set; } = Array.Empty(); From c45d5cb307cc21048f10267e01813f41438f4e06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Sun, 4 Sep 2022 20:19:12 -0500 Subject: [PATCH 35/50] improvoe animations api --- .../General/VisualElements/ViewModel.cs | 11 ++++++----- src/LiveChartsCore/Drawing/Animatable.cs | 7 +++---- .../VisualElements/GeometryVisualElement.cs | 3 +-- .../VisualElements/RectangleVisualElement.cs | 4 ++-- 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/samples/ViewModelsSamples/General/VisualElements/ViewModel.cs b/samples/ViewModelsSamples/General/VisualElements/ViewModel.cs index 549a603f5..c951f79d2 100644 --- a/samples/ViewModelsSamples/General/VisualElements/ViewModel.cs +++ b/samples/ViewModelsSamples/General/VisualElements/ViewModel.cs @@ -15,13 +15,14 @@ public partial class ViewModel { new RectangleVisualElement { - X = 5, - Y = 1, + X = 2.5, + Y = 3.5, LocationUnit = MeasureUnit.ChartValues, - Width = 1, - Height = 1, + Width = 4, + Height = 2, SizeUnit = MeasureUnit.ChartValues, - Stroke = new SolidColorPaint(SKColors.Red, 2) + Fill = new SolidColorPaint(new SKColor(239, 83, 80, 120)) { ZIndex = 10 }, + Stroke = new SolidColorPaint(new SKColor(239, 83, 80)) { ZIndex = 10, StrokeThickness = 1.5f }, } }; diff --git a/src/LiveChartsCore/Drawing/Animatable.cs b/src/LiveChartsCore/Drawing/Animatable.cs index 0653b250c..62de9f6d0 100644 --- a/src/LiveChartsCore/Drawing/Animatable.cs +++ b/src/LiveChartsCore/Drawing/Animatable.cs @@ -51,8 +51,7 @@ protected Animatable() { } public void SetTransition(Animation? animation, params string[]? propertyName) { var a = animation?.Duration == 0 ? null : animation; - - propertyName ??= MotionProperties.Keys.ToArray(); + if (propertyName is null || propertyName.Length == 0) propertyName = MotionProperties.Keys.ToArray(); foreach (var name in propertyName) { @@ -63,7 +62,7 @@ public void SetTransition(Animation? animation, params string[]? propertyName) /// public void RemoveTransition(params string[]? propertyName) { - propertyName ??= MotionProperties.Keys.ToArray(); + if (propertyName is null || propertyName.Length == 0) propertyName = MotionProperties.Keys.ToArray(); foreach (var name in propertyName) { @@ -74,7 +73,7 @@ public void RemoveTransition(params string[]? propertyName) /// public virtual void CompleteTransition(params string[]? propertyName) { - propertyName ??= MotionProperties.Keys.ToArray(); + if (propertyName is null || propertyName.Length == 0) propertyName = MotionProperties.Keys.ToArray(); foreach (var property in propertyName) { diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/VisualElements/GeometryVisualElement.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/VisualElements/GeometryVisualElement.cs index e8e7ac8ce..b343e0632 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/VisualElements/GeometryVisualElement.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/VisualElements/GeometryVisualElement.cs @@ -28,7 +28,6 @@ using LiveChartsCore.Kernel.Sketches; using LiveChartsCore.Measure; using LiveChartsCore.SkiaSharpView.Drawing; -using LiveChartsCore.SkiaSharpView.Drawing.Geometries; namespace LiveChartsCore.SkiaSharpView.VisualElements; @@ -62,7 +61,7 @@ public IPaint? Fill public IPaint? Stroke { get => _stroke; - set => SetPaintProperty(ref _stroke, value); + set => SetPaintProperty(ref _stroke, value, true); } /// diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/VisualElements/RectangleVisualElement.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/VisualElements/RectangleVisualElement.cs index 4992eeffd..8f4199b10 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/VisualElements/RectangleVisualElement.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/VisualElements/RectangleVisualElement.cs @@ -84,8 +84,8 @@ protected override void Draw(Chart chart, Scaler primar if (LocationUnit == MeasureUnit.ChartValues) { - w = secondaryAxisScale.ToPixels(w); - h = primaryAxisScale.ToPixels(h); + w = secondaryAxisScale.MeasureInPixels(w); + h = primaryAxisScale.MeasureInPixels(h); } if (_rectangleGeometry is null) From 0161b8fa0f64cdd61b8f07a98761f1bc0217cf30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Sun, 4 Sep 2022 21:31:18 -0500 Subject: [PATCH 36/50] label visual and cleanup --- .../General/VisualElements/MyGeometry.cs | 25 +++ .../General/VisualElements/ViewModel.cs | 42 ++++- ...VisualElement.cs => BaseGeometryVisual.cs} | 73 ++++---- ...GeometryVisualElement.cs => BaseVisual.cs} | 30 +--- .../VisualElements/GeometryVisual.cs | 77 ++++++++ .../VisualElements/LabelVisual.cs | 166 ++++++++++++++++++ 6 files changed, 343 insertions(+), 70 deletions(-) create mode 100644 samples/ViewModelsSamples/General/VisualElements/MyGeometry.cs rename src/skiasharp/LiveChartsCore.SkiaSharp/VisualElements/{RectangleVisualElement.cs => BaseGeometryVisual.cs} (62%) rename src/skiasharp/LiveChartsCore.SkiaSharp/VisualElements/{GeometryVisualElement.cs => BaseVisual.cs} (85%) create mode 100644 src/skiasharp/LiveChartsCore.SkiaSharp/VisualElements/GeometryVisual.cs create mode 100644 src/skiasharp/LiveChartsCore.SkiaSharp/VisualElements/LabelVisual.cs diff --git a/samples/ViewModelsSamples/General/VisualElements/MyGeometry.cs b/samples/ViewModelsSamples/General/VisualElements/MyGeometry.cs new file mode 100644 index 000000000..b7ed66be5 --- /dev/null +++ b/samples/ViewModelsSamples/General/VisualElements/MyGeometry.cs @@ -0,0 +1,25 @@ +using SkiaSharp; + +namespace ViewModelsSamples.General.VisualElements; + +public class MyGeometry : LiveChartsCore.SkiaSharpView.Drawing.Geometries.SVGPathGeometry +{ + // https://fonts.google.com/icons?icon.query=sun + public static SKPath svgPath = SKPath.ParseSvgPathData( + "M24 9.5q-.65 0-1.075-.425Q22.5 8.65 22.5 8V3.5q0-.65.425-1.075Q23.35 2 24 2q.65 0 1.075.425.425.425.425 1.075V8q0 " + + ".65-.425 1.075Q24.65 9.5 24 9.5Zm10.25 4.25q-.45-.45-.45-1.05 0-.6.45-1.05l3.15-3.2Q37.85 8 38.475 8t1.075.45Q40 8.9 40 9.5q0 " + + ".6-.45 1.05l-3.2 3.2q-.45.45-1.05.45-.6 0-1.05-.45ZM40 25.5q-.65 0-1.075-.425Q38.5 24.65 38.5 24q0-.65.425-1.075Q39.35 " + + "22.5 40 22.5h4.5q.65 0 1.075.425Q46 23.35 46 24q0 .65-.425 1.075-.425.425-1.075.425ZM24 46q-.65 " + + "0-1.075-.425-.425-.425-.425-1.075V40q0-.65.425-1.075Q23.35 38.5 24 38.5q.65 0 1.075.425.425.425.425 1.075v4.5q0 " + + ".65-.425 1.075Q24.65 46 24 46ZM11.65 13.75l-3.2-3.15Q8 10.15 8 9.525t.45-1.075Q8.9 8 9.5 8q.6 0 1.05.45l3.2 " + + "3.2q.45.45.45 1.05 0 .6-.45 1.05-.45.4-1.075.4t-1.025-.4Zm25.8 25.8-3.2-3.2q-.45-.45-.45-1.05 0-.6.45-1.05.4-.4 1.025-.4.625 " + + "0 1.075.4l3.25 3.15q.45.45.425 1.075Q40 39.1 39.6 39.55q-.45.45-1.075.45t-1.075-.45ZM3.5 25.5q-.65 0-1.075-.425Q2 24.65 2 " + + "24q0-.65.425-1.075Q2.85 22.5 3.5 22.5H8q.65 0 1.075.425Q9.5 23.35 9.5 24q0 .65-.425 1.075Q8.65 25.5 8 25.5Zm4.95 14.05Q8 " + + "39.1 8 38.5q0-.6.45-1.05l3.2-3.2q.4-.4 1.025-.4.625 0 1.075.4.45.45.45 1.075t-.45 1.075l-3.15 3.15q-.45.45-1.075.45t-1.075-.45ZM24 " + + "36q-5 0-8.5-3.5T12 24q0-5 3.5-8.5T24 12q5 0 8.5 3.5T36 24q0 5-3.5 8.5T24 36Zm0-3q3.75 0 6.375-2.625T33 24q0-3.75-2.625-6.375T24 " + + "15q-3.75 0-6.375 2.625T15 24q0 3.75 2.625 6.375T24 33Z"); + + public MyGeometry() + : base(svgPath) + { } +} diff --git a/samples/ViewModelsSamples/General/VisualElements/ViewModel.cs b/samples/ViewModelsSamples/General/VisualElements/ViewModel.cs index c951f79d2..a82ae782c 100644 --- a/samples/ViewModelsSamples/General/VisualElements/ViewModel.cs +++ b/samples/ViewModelsSamples/General/VisualElements/ViewModel.cs @@ -1,8 +1,10 @@ using System.Collections.Generic; using LiveChartsCore; +using LiveChartsCore.Drawing; using LiveChartsCore.Kernel; using LiveChartsCore.SkiaSharpView; using LiveChartsCore.SkiaSharpView.Drawing; +using LiveChartsCore.SkiaSharpView.Drawing.Geometries; using LiveChartsCore.SkiaSharpView.Painting; using LiveChartsCore.SkiaSharpView.VisualElements; using SkiaSharp; @@ -13,7 +15,7 @@ public partial class ViewModel { public IEnumerable> VisualElements { get; set; } = new List> { - new RectangleVisualElement + new GeometryVisual { X = 2.5, Y = 3.5, @@ -21,8 +23,42 @@ public partial class ViewModel Width = 4, Height = 2, SizeUnit = MeasureUnit.ChartValues, - Fill = new SolidColorPaint(new SKColor(239, 83, 80, 120)) { ZIndex = 10 }, + Fill = new SolidColorPaint(new SKColor(239, 83, 80, 50)) { ZIndex = 10 }, Stroke = new SolidColorPaint(new SKColor(239, 83, 80)) { ZIndex = 10, StrokeThickness = 1.5f }, + }, + new GeometryVisual + { + X = 5.5, + Y = 6, + LocationUnit = MeasureUnit.ChartValues, + Width = 4, + Height = 5, + SizeUnit = MeasureUnit.ChartValues, + Fill = new SolidColorPaint(new SKColor(100, 221, 23, 50)) { ZIndex = - 10 }, + Stroke = new SolidColorPaint(new SKColor(100, 221, 23)) { ZIndex = -10, StrokeThickness = 1.5f }, + }, + new GeometryVisual + { + X = 18, + Y = 6, + LocationUnit = MeasureUnit.ChartValues, + Width = 100, + Height = 100, + SizeUnit = MeasureUnit.Pixels, + Fill = new SolidColorPaint(new SKColor(251, 192, 45, 50)) { ZIndex = 10 }, + Stroke = new SolidColorPaint(new SKColor(251, 192, 45)) { ZIndex = 10, StrokeThickness = 1.5f }, + }, + new LabelVisual + { + Text = "What happened here?", + X = 11, + Y = 1, + TextSize = 16, + Paint = new SolidColorPaint(new SKColor(250, 250, 250)) { ZIndex = 11 }, + BackgroundColor = new LvcColor(55, 71, 79), + Padding = new Padding(12), + LocationUnit = MeasureUnit.ChartValues, + Translate = new LvcPoint(0, -35) } }; @@ -31,7 +67,7 @@ public partial class ViewModel new LineSeries { GeometrySize = 13, - Values = new int[] { 1,2,3,4,2,1,3,6,3,5,2,1,4,5,2,3,1,4,5,3,1,6,2,4,5,8,4,5,6,4,7,5,8,4,6,5,4,7,8,9,9,8,7,9,8,7,9,9,8,6,8 } + Values = new int[] { 2,2,3,4,2,2,3,6,3,5,2,1,4,5,2,3,2,4,5,3,2,6 } } }; } diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/VisualElements/RectangleVisualElement.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/VisualElements/BaseGeometryVisual.cs similarity index 62% rename from src/skiasharp/LiveChartsCore.SkiaSharp/VisualElements/RectangleVisualElement.cs rename to src/skiasharp/LiveChartsCore.SkiaSharp/VisualElements/BaseGeometryVisual.cs index 8f4199b10..f5af434a8 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/VisualElements/RectangleVisualElement.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/VisualElements/BaseGeometryVisual.cs @@ -20,23 +20,23 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. +using LiveChartsCore.Drawing; using LiveChartsCore.Kernel; -using LiveChartsCore.Measure; using LiveChartsCore.SkiaSharpView.Drawing; -using LiveChartsCore.SkiaSharpView.Drawing.Geometries; namespace LiveChartsCore.SkiaSharpView.VisualElements; /// -/// Defines a visual element in a chart that draws a rectangle geometry in the user interface. +/// Defines a visual element with stroke and fill properties. /// -public class RectangleVisualElement : GeometryVisualElement +public abstract class BaseGeometryVisual : BaseVisual { - private RectangleGeometry? _rectangleGeometry; private double _x; private double _y; private double _width; private double _height; + private IPaint? _fill; + private IPaint? _stroke; /// /// Gets or sets the X coordinate [in Pixels or ChartValues, see ]. @@ -68,43 +68,38 @@ public class RectangleVisualElement : GeometryVisualElement /// public MeasureUnit SizeUnit { get; set; } = MeasureUnit.Pixels; - /// - protected override void Draw(Chart chart, Scaler primaryAxisScale, Scaler secondaryAxisScale) + /// + /// Gets or sets the fill paint. + /// + public IPaint? Fill { - var x = (float)X; - var y = (float)Y; - var w = (float)Width; - var h = (float)Height; - - if (SizeUnit == MeasureUnit.ChartValues) - { - x = secondaryAxisScale.ToPixels(x); - y = primaryAxisScale.ToPixels(y); - } - - if (LocationUnit == MeasureUnit.ChartValues) - { - w = secondaryAxisScale.MeasureInPixels(w); - h = primaryAxisScale.MeasureInPixels(h); - } - - if (_rectangleGeometry is null) - { - _rectangleGeometry = new RectangleGeometry { X = x, Y = y, Width = w, Height = h }; + get => _fill; + set => SetPaintProperty(ref _fill, value); + } - _ = _rectangleGeometry - .TransitionateProperties() - .WithAnimation(chart) - .CompleteCurrentTransitions(); - } + /// + /// Gets or sets the stroke paint. + /// + public IPaint? Stroke + { + get => _stroke; + set => SetPaintProperty(ref _stroke, value, true); + } - _rectangleGeometry.X = x; - _rectangleGeometry.Y = y; - _rectangleGeometry.Width = w; - _rectangleGeometry.Height = h; + /// + protected override IPaint?[] GetPaintTasks() + { + return new[] { _fill, _stroke }; + } - var drawing = chart.Canvas.Draw(); - if (Fill is not null) _ = drawing.SelectPaint(Fill).Draw(_rectangleGeometry); - if (Stroke is not null) _ = drawing.SelectPaint(Stroke).Draw(_rectangleGeometry); + /// + /// Called when [paint changed]. + /// + /// Name of the property. + /// + protected override void OnPaintChanged(string? propertyName) + { + base.OnPaintChanged(propertyName); + OnPropertyChanged(propertyName); } } diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/VisualElements/GeometryVisualElement.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/VisualElements/BaseVisual.cs similarity index 85% rename from src/skiasharp/LiveChartsCore.SkiaSharp/VisualElements/GeometryVisualElement.cs rename to src/skiasharp/LiveChartsCore.SkiaSharp/VisualElements/BaseVisual.cs index b343e0632..97cd88443 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/VisualElements/GeometryVisualElement.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/VisualElements/BaseVisual.cs @@ -32,12 +32,10 @@ namespace LiveChartsCore.SkiaSharpView.VisualElements; /// -/// Defines a visual element with stroke and fill properties. +/// Defines the base visual element class, inheriting from this class makes it easy to implement a visual element. /// -public abstract class GeometryVisualElement : ChartElement, INotifyPropertyChanged +public abstract class BaseVisual : ChartElement, INotifyPropertyChanged { - private IPaint? _fill; - private IPaint? _stroke; private int _scalesXAt; private int _scalesYAt; @@ -46,24 +44,6 @@ public abstract class GeometryVisualElement : ChartElement public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the fill paint. - /// - public IPaint? Fill - { - get => _fill; - set => SetPaintProperty(ref _fill, value); - } - - /// - /// Gets or sets the stroke paint. - /// - public IPaint? Stroke - { - get => _stroke; - set => SetPaintProperty(ref _stroke, value, true); - } - /// /// Gets or sets the axis index where the series is scaled in the X plane, the index must exist /// in the collection. @@ -118,12 +98,6 @@ public override void Measure(Chart chart) Draw(chart, primary, secondary); } - /// - protected override IPaint?[] GetPaintTasks() - { - return new[] { _fill, _stroke }; - } - /// /// Called when [paint changed]. /// diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/VisualElements/GeometryVisual.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/VisualElements/GeometryVisual.cs new file mode 100644 index 000000000..c7d241b34 --- /dev/null +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/VisualElements/GeometryVisual.cs @@ -0,0 +1,77 @@ +// The MIT License(MIT) +// +// Copyright(c) 2021 Alberto Rodriguez Orozco & LiveCharts Contributors +// +// 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 LiveChartsCore.Drawing; +using LiveChartsCore.Kernel; +using LiveChartsCore.Measure; +using LiveChartsCore.SkiaSharpView.Drawing; + +namespace LiveChartsCore.SkiaSharpView.VisualElements; + +/// +/// Defines a visual element in a chart that draws a rectangle geometry in the user interface. +/// +public class GeometryVisual : BaseGeometryVisual + where TGeometry : ISizedGeometry, new() +{ + private TGeometry? _rectangleGeometry; + + /// + protected override void Draw(Chart chart, Scaler primaryAxisScale, Scaler secondaryAxisScale) + { + var x = (float)X; + var y = (float)Y; + var w = (float)Width; + var h = (float)Height; + + if (SizeUnit == MeasureUnit.ChartValues) + { + w = secondaryAxisScale.MeasureInPixels(w); + h = primaryAxisScale.MeasureInPixels(h); + } + + if (LocationUnit == MeasureUnit.ChartValues) + { + x = secondaryAxisScale.ToPixels(x); + y = primaryAxisScale.ToPixels(y); + } + + if (_rectangleGeometry is null) + { + _rectangleGeometry = new TGeometry { X = x, Y = y, Width = w, Height = h }; + + _ = _rectangleGeometry + .TransitionateProperties() + .WithAnimation(chart) + .CompleteCurrentTransitions(); + } + + _rectangleGeometry.X = x; + _rectangleGeometry.Y = y; + _rectangleGeometry.Width = w; + _rectangleGeometry.Height = h; + + var drawing = chart.Canvas.Draw(); + if (Fill is not null) _ = drawing.SelectPaint(Fill).Draw(_rectangleGeometry); + if (Stroke is not null) _ = drawing.SelectPaint(Stroke).Draw(_rectangleGeometry); + } +} diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/VisualElements/LabelVisual.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/VisualElements/LabelVisual.cs new file mode 100644 index 000000000..aa7ef81b3 --- /dev/null +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/VisualElements/LabelVisual.cs @@ -0,0 +1,166 @@ +// The MIT License(MIT) +// +// Copyright(c) 2021 Alberto Rodriguez Orozco & LiveCharts Contributors +// +// 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 LiveChartsCore.Drawing; +using LiveChartsCore.Kernel; +using LiveChartsCore.Measure; +using LiveChartsCore.SkiaSharpView.Drawing; +using LiveChartsCore.SkiaSharpView.Drawing.Geometries; + +namespace LiveChartsCore.SkiaSharpView.VisualElements; + +/// +/// Defines a visual element with stroke and fill properties. +/// +public class LabelVisual : BaseVisual +{ + private LabelGeometry? _labelGeometry; + private IPaint? _paint; + private double _x; + private double _y; + private string _text = string.Empty; + private double _textSize = 12; + private Align _verticalAlignment = Align.Middle; + private Align _horizontalAlignment = Align.Middle; + private LvcColor _backgroundColor; + private Padding _padding = new(0); + private double _rotation; + private LvcPoint _translate = new(); + + /// + /// Gets or sets the fill paint. + /// + public IPaint? Paint + { + get => _paint; + set => SetPaintProperty(ref _paint, value); + } + + /// + /// Gets or sets the X coordinate [in Pixels or ChartValues, see ]. + /// + public double X { get => _x; set { _x = value; OnPropertyChanged(); } } + + /// + /// Gets or sets the Y coordinate [in Pixels or ChartValues, see ]. + /// + public double Y { get => _y; set { _y = value; OnPropertyChanged(); } } + + /// + /// Gets or sets the label text. + /// + public string Text { get => _text; set { _text = value; OnPropertyChanged(); } } + + /// + /// Gets or sets the font size. + /// + public double TextSize { get => _textSize; set { _textSize = value; OnPropertyChanged(); } } + + /// + /// Gets or sets the rotation. + /// + public double Rotation { get => _rotation; set { _rotation = value; OnPropertyChanged(); } } + + /// + /// Gets or sets the translate transform. + /// + public LvcPoint Translate { get => _translate; set { _translate = value; OnPropertyChanged(); } } + + /// + /// Gets or sets the vertical alignment. + /// + public Align VerticalAlignment { get => _verticalAlignment; set { _verticalAlignment = value; OnPropertyChanged(); } } + + /// + /// Gets or sets the horizontal alignment. + /// + public Align HorizontalAlignment { get => _horizontalAlignment; set { _horizontalAlignment = value; OnPropertyChanged(); } } + + /// + /// Gets or sets the background color. + /// + public LvcColor BackgroundColor { get => _backgroundColor; set { _backgroundColor = value; OnPropertyChanged(); } } + + /// + /// Gets or sets the padding. + /// + public Padding Padding { get => _padding; set { _padding = value; OnPropertyChanged(); } } + + /// + /// Gets or sets the unit of the and properties. + /// + public MeasureUnit LocationUnit { get; set; } = MeasureUnit.Pixels; + + /// + protected override IPaint?[] GetPaintTasks() + { + return new[] { _paint }; + } + + /// + protected override void Draw(Chart chart, Scaler primaryAxisScale, Scaler secondaryAxisScale) + { + var x = (float)X; + var y = (float)Y; + + if (LocationUnit == MeasureUnit.ChartValues) + { + x = secondaryAxisScale.ToPixels(x); + y = primaryAxisScale.ToPixels(y); + } + + if (_labelGeometry is null) + { + _labelGeometry = new LabelGeometry + { + TextSize = (float)TextSize, + X = x, + Y = y, + RotateTransform = (float)Rotation, + TranslateTransform = Translate, + VerticalAlign = VerticalAlignment, + HorizontalAlign = HorizontalAlignment, + Background = BackgroundColor, + Padding = Padding + }; + + _ = _labelGeometry + .TransitionateProperties() + .WithAnimation(chart) + .CompleteCurrentTransitions(); + } + + _labelGeometry.Text = Text; + _labelGeometry.TextSize = (float)TextSize; + _labelGeometry.X = x; + _labelGeometry.Y = y; + _labelGeometry.RotateTransform = (float)Rotation; + _labelGeometry.TranslateTransform = Translate; + _labelGeometry.VerticalAlign = VerticalAlignment; + _labelGeometry.HorizontalAlign = HorizontalAlignment; + _labelGeometry.Background = BackgroundColor; + _labelGeometry.Padding = Padding; + + var drawing = chart.Canvas.Draw(); + if (Paint is not null) _ = drawing.SelectPaint(Paint).Draw(_labelGeometry); + } +} From 13629039004e43e6598ceceaf5a9bdbda7e9d170 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Sun, 4 Sep 2022 21:48:33 -0500 Subject: [PATCH 37/50] extend visual elements to pie and polar charts --- .../Kernel/Sketches/IPieChartView.cs | 5 ++ .../Kernel/Sketches/IPolarChartView.cs | 27 ++--------- src/LiveChartsCore/PieChart.cs | 27 +++++++++++ src/LiveChartsCore/PolarChart.cs | 27 +++++++++++ .../LiveChartsCore.SkiaSharp.WPF/PieChart.cs | 48 +++++++++++++++++-- .../PolarChart.cs | 39 +++++++++++++-- .../SKCharts/SKPieChart.cs | 3 ++ .../SKCharts/SKPolarChart.cs | 3 ++ 8 files changed, 150 insertions(+), 29 deletions(-) diff --git a/src/LiveChartsCore/Kernel/Sketches/IPieChartView.cs b/src/LiveChartsCore/Kernel/Sketches/IPieChartView.cs index 7607c72b7..8da06a4a7 100644 --- a/src/LiveChartsCore/Kernel/Sketches/IPieChartView.cs +++ b/src/LiveChartsCore/Kernel/Sketches/IPieChartView.cs @@ -49,6 +49,11 @@ public interface IPieChartView : IChartView /// IEnumerable Series { get; set; } + /// + /// Gets or sets the visual elements. + /// + IEnumerable> VisualElements { get; set; } + /// /// Gets or sets the initial rotation in degrees, this angle specifies where the first pie slice will be drawn, then the remaining /// slices will stack according to its corresponding position. diff --git a/src/LiveChartsCore/Kernel/Sketches/IPolarChartView.cs b/src/LiveChartsCore/Kernel/Sketches/IPolarChartView.cs index aa6d16a15..047c9acc0 100644 --- a/src/LiveChartsCore/Kernel/Sketches/IPolarChartView.cs +++ b/src/LiveChartsCore/Kernel/Sketches/IPolarChartView.cs @@ -87,13 +87,10 @@ public interface IPolarChartView : IChartView /// IEnumerable RadiusAxes { get; set; } - ///// - ///// Gets or sets the sections. - ///// - ///// - ///// The sections. - ///// - //IEnumerable> Sections { get; set; } + /// + /// Gets or sets the visual elements. + /// + IEnumerable> VisualElements { get; set; } /// /// Gets or sets the series to plot in the user interface. @@ -103,22 +100,6 @@ public interface IPolarChartView : IChartView /// IEnumerable Series { get; set; } - ///// - ///// Gets or sets the tool tip finding strategy. - ///// - ///// - ///// The tool tip finding strategy. - ///// - //TooltipFindingStrategy TooltipFindingStrategy { get; set; } - - ///// - ///// Gets or sets the zooming speed from 0 to 1, where 0 is the fastest and 1 the slowest. - ///// - ///// - ///// The zooming speed. - ///// - //double ZoomingSpeed { get; set; } - /// /// Scales the UI point. /// diff --git a/src/LiveChartsCore/PieChart.cs b/src/LiveChartsCore/PieChart.cs index d3c896ef0..06df7db6d 100644 --- a/src/LiveChartsCore/PieChart.cs +++ b/src/LiveChartsCore/PieChart.cs @@ -41,6 +41,7 @@ public class PieChart : Chart where TDrawingContext : DrawingContext { private readonly HashSet _everMeasuredSeries = new(); + internal readonly HashSet> _everMeasuredVisuals = new(); private readonly IPieChartView _chartView; private int _nextSeries = 0; private readonly bool _requiresLegendMeasureAlways = false; @@ -71,6 +72,14 @@ public PieChart( /// public IPieSeries[] Series { get; private set; } = Array.Empty>(); + /// + /// Gets the visual elements. + /// + /// + /// The visual elements. + /// + public ChartElement[] VisualElements { get; private set; } = Array.Empty>(); + /// /// Gets the drawable series. /// @@ -163,6 +172,8 @@ protected internal override void Measure() .Cast>() .ToArray(); + VisualElements = _chartView.VisualElements?.ToArray() ?? Array.Empty>(); + LegendPosition = _chartView.LegendPosition; LegendOrientation = _chartView.LegendOrientation; Legend = _chartView.Legend; @@ -221,6 +232,15 @@ protected internal override void Measure() // or it is initializing in the UI and has no dimensions yet if (DrawMarginSize.Width <= 0 || DrawMarginSize.Height <= 0) return; + var toDeleteVisualElements = new HashSet>(_everMeasuredVisuals); + foreach (var visual in VisualElements) + { + visual.Measure(this); + visual.RemoveOldPaints(View); + _ = _everMeasuredVisuals.Add(visual); + _ = toDeleteVisualElements.Remove(visual); + } + var toDeleteSeries = new HashSet(_everMeasuredSeries); foreach (var series in Series) { @@ -235,6 +255,11 @@ protected internal override void Measure() series.SoftDeleteOrDispose(View); _ = _everMeasuredSeries.Remove(series); } + foreach (var visual in toDeleteVisualElements) + { + visual.RemoveFromUI(this); + _ = _everMeasuredVisuals.Remove(visual); + } InvokeOnUpdateStarted(); IsFirstDraw = false; @@ -252,6 +277,8 @@ public override void Unload() foreach (var item in _everMeasuredSeries) ((ChartElement)item).RemoveFromUI(this); _everMeasuredSeries.Clear(); + foreach (var item in _everMeasuredVisuals) item.RemoveFromUI(this); + _everMeasuredVisuals.Clear(); IsFirstDraw = true; } } diff --git a/src/LiveChartsCore/PolarChart.cs b/src/LiveChartsCore/PolarChart.cs index 3ce0a1bc7..5a5833623 100644 --- a/src/LiveChartsCore/PolarChart.cs +++ b/src/LiveChartsCore/PolarChart.cs @@ -43,6 +43,7 @@ public class PolarChart : Chart internal readonly HashSet _everMeasuredSeries = new(); internal readonly HashSet> _everMeasuredAxes = new(); internal readonly HashSet> _everMeasuredSections = new(); + internal readonly HashSet> _everMeasuredVisuals = new(); private readonly IPolarChartView _chartView; private int _nextSeries = 0; private readonly bool _requiresLegendMeasureAlways = false; @@ -89,6 +90,14 @@ public PolarChart( /// public IPolarSeries[] Series { get; private set; } = Array.Empty>(); + /// + /// Gets the visual elements. + /// + /// + /// The visual elements. + /// + public ChartElement[] VisualElements { get; private set; } = Array.Empty>(); + /// /// Gets whether the series fit to bounds or not. /// @@ -208,6 +217,8 @@ protected internal override void Measure() .Cast>() .ToArray(); + VisualElements = _chartView.VisualElements?.ToArray() ?? Array.Empty>(); + #endregion SeriesContext = new SeriesContext(Series); @@ -476,6 +487,15 @@ protected internal override void Measure() drawablePlane.RemoveOldPaints(View); } + var toDeleteVisualElements = new HashSet>(_everMeasuredVisuals); + foreach (var visual in VisualElements) + { + visual.Measure(this); + visual.RemoveOldPaints(View); + _ = _everMeasuredVisuals.Add(visual); + _ = toDeleteVisualElements.Remove(visual); + } + var toDeleteSeries = new HashSet(_everMeasuredSeries); foreach (var series in Series) { @@ -495,6 +515,11 @@ protected internal override void Measure() axis.RemoveFromUI(this); _ = _everMeasuredAxes.Remove(axis); } + foreach (var visual in toDeleteVisualElements) + { + visual.RemoveFromUI(this); + _ = _everMeasuredVisuals.Remove(visual); + } foreach (var axis in totalAxes) { @@ -545,6 +570,8 @@ public override void Unload() _everMeasuredAxes.Clear(); foreach (var item in _everMeasuredSections) item.RemoveFromUI(this); _everMeasuredSections.Clear(); + foreach (var item in _everMeasuredVisuals) item.RemoveFromUI(this); + _everMeasuredVisuals.Clear(); foreach (var item in _everMeasuredSeries) ((ChartElement)item).RemoveFromUI(this); _everMeasuredSeries.Clear(); IsFirstDraw = true; diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp.WPF/PieChart.cs b/src/skiasharp/LiveChartsCore.SkiaSharp.WPF/PieChart.cs index 2c7f65839..0863d4435 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp.WPF/PieChart.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp.WPF/PieChart.cs @@ -37,7 +37,8 @@ namespace LiveChartsCore.SkiaSharpView.WPF; /// public class PieChart : Chart, IPieChartView { - private CollectionDeepObserver _seriesObserver; + private readonly CollectionDeepObserver _seriesObserver; + private readonly CollectionDeepObserver> _visualsObserver; static PieChart() { @@ -59,9 +60,21 @@ public PieChart() { if (core is null || (sender is IStopNPC stop && !stop.IsNotifyingChanges)) return; core.Update(); - }); + }, true); + _visualsObserver = new CollectionDeepObserver>( + (object? sender, NotifyCollectionChangedEventArgs e) => + { + if (core is null || (sender is IStopNPC stop && !stop.IsNotifyingChanges)) return; + core.Update(); + }, + (object? sender, PropertyChangedEventArgs e) => + { + if (core is null || (sender is IStopNPC stop && !stop.IsNotifyingChanges)) return; + core.Update(); + }, true); SetCurrentValue(SeriesProperty, new ObservableCollection()); + SetCurrentValue(VisualElementsProperty, new ObservableCollection>()); MouseDown += OnMouseDown; } @@ -85,6 +98,28 @@ public PieChart() return value is IEnumerable ? value : new ObservableCollection(); })); + /// + /// The visual elements property + /// + public static readonly DependencyProperty VisualElementsProperty = + DependencyProperty.Register( + nameof(VisualElements), typeof(IEnumerable>), typeof(PieChart), new PropertyMetadata(null, + (DependencyObject o, DependencyPropertyChangedEventArgs args) => + { + var chart = (PieChart)o; + var observer = chart._visualsObserver; + observer?.Dispose((IEnumerable>)args.OldValue); + observer?.Initialize((IEnumerable>)args.NewValue); + if (chart.core is null) return; + chart.core.Update(); + }, + (DependencyObject o, object value) => + { + return value is IEnumerable> + ? value + : new List>(); + })); + /// /// The initial rotation property /// @@ -115,6 +150,13 @@ public IEnumerable Series set => SetValue(SeriesProperty, value); } + /// + public IEnumerable> VisualElements + { + get => (IEnumerable>)GetValue(VisualElementsProperty); + set => SetValue(VisualElementsProperty, value); + } + /// public double InitialRotation { @@ -155,7 +197,7 @@ protected override void OnUnloaded() core?.Unload(); } - private void OnMouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e) + private void OnMouseDown(object sender, MouseButtonEventArgs e) { var p = e.GetPosition(this); core?.InvokePointerDown(new LvcPoint((float)p.X, (float)p.Y), e.ChangedButton == MouseButton.Right); diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp.WPF/PolarChart.cs b/src/skiasharp/LiveChartsCore.SkiaSharp.WPF/PolarChart.cs index febdf2ac8..a03e6ddb5 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp.WPF/PolarChart.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp.WPF/PolarChart.cs @@ -39,9 +39,10 @@ public class PolarChart : Chart, IPolarChartView { #region fields - private CollectionDeepObserver _seriesObserver; - private CollectionDeepObserver _angleObserver; - private CollectionDeepObserver _radiusObserver; + private readonly CollectionDeepObserver _seriesObserver; + private readonly CollectionDeepObserver _angleObserver; + private readonly CollectionDeepObserver _radiusObserver; + private readonly CollectionDeepObserver> _visualsObserver; #endregion @@ -58,6 +59,8 @@ public PolarChart() _seriesObserver = new CollectionDeepObserver(OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); _angleObserver = new CollectionDeepObserver(OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); _radiusObserver = new CollectionDeepObserver(OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); + _visualsObserver = new CollectionDeepObserver>( + OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); SetCurrentValue(AngleAxesProperty, new ObservableCollection() { @@ -68,6 +71,7 @@ public PolarChart() LiveCharts.CurrentSettings.GetProvider().GetDefaultPolarAxis() }); SetCurrentValue(SeriesProperty, new ObservableCollection()); + SetCurrentValue(VisualElementsProperty, new ObservableCollection>()); MouseWheel += OnMouseWheel; MouseDown += OnMouseDown; @@ -124,6 +128,28 @@ public PolarChart() return value is IEnumerable ? value : new ObservableCollection(); })); + /// + /// The visual elements property + /// + public static readonly DependencyProperty VisualElementsProperty = + DependencyProperty.Register( + nameof(VisualElements), typeof(IEnumerable>), typeof(PolarChart), new PropertyMetadata(null, + (DependencyObject o, DependencyPropertyChangedEventArgs args) => + { + var chart = (PolarChart)o; + var observer = chart._visualsObserver; + observer?.Dispose((IEnumerable>)args.OldValue); + observer?.Initialize((IEnumerable>)args.NewValue); + if (chart.core is null) return; + chart.core.Update(); + }, + (DependencyObject o, object value) => + { + return value is IEnumerable> + ? value + : new List>(); + })); + /// /// The x axes property. /// @@ -216,6 +242,13 @@ public IEnumerable Series set => SetValue(SeriesProperty, value); } + /// + public IEnumerable> VisualElements + { + get => (IEnumerable>)GetValue(VisualElementsProperty); + set => SetValue(VisualElementsProperty, value); + } + /// public IEnumerable AngleAxes { diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKPieChart.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKPieChart.cs index 57cdbb7f0..bf8f50f98 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKPieChart.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKPieChart.cs @@ -110,6 +110,9 @@ public SKPieChart(IPieChartView view) : this() /// public IEnumerable Series { get; set; } = Array.Empty(); + /// + public IEnumerable> VisualElements { get; set; } = Array.Empty>(); + /// public double InitialRotation { get; set; } diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKPolarChart.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKPolarChart.cs index c19bf7315..9282cf627 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKPolarChart.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKPolarChart.cs @@ -119,6 +119,9 @@ public SKPolarChart(IPolarChartView view) : this() /// public IEnumerable Series { get; set; } = Array.Empty(); + /// + public IEnumerable> VisualElements { get; set; } = Array.Empty>(); + /// public MotionCanvas CoreCanvas { get; } = new(); From fef611d5600ee5acbcc41151955df0e2c435e5df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Sun, 4 Sep 2022 22:03:36 -0500 Subject: [PATCH 38/50] visual elements for avalonia --- .../CartesianChart.axaml.cs | 24 ++++++++++++ .../PieChart.axaml.cs | 39 ++++++++++++++++++- .../PolarChart.axaml.cs | 30 ++++++++++++-- 3 files changed, 88 insertions(+), 5 deletions(-) diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp.Avalonia/CartesianChart.axaml.cs b/src/skiasharp/LiveChartsCore.SkiaSharp.Avalonia/CartesianChart.axaml.cs index 937f8420c..4d8f65126 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp.Avalonia/CartesianChart.axaml.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp.Avalonia/CartesianChart.axaml.cs @@ -67,6 +67,7 @@ public class CartesianChart : UserControl, ICartesianChartView _xObserver; private readonly CollectionDeepObserver _yObserver; private readonly CollectionDeepObserver> _sectionsObserver; + private readonly CollectionDeepObserver> _visualsObserver; #endregion @@ -99,6 +100,8 @@ public CartesianChart() _yObserver = new CollectionDeepObserver(OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); _sectionsObserver = new CollectionDeepObserver>( OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); + _visualsObserver = new CollectionDeepObserver>( + OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); XAxes = new List() { @@ -109,6 +112,7 @@ public CartesianChart() LiveCharts.CurrentSettings.GetProvider().GetDefaultCartesianAxis() }; Series = new ObservableCollection(); + VisualElements = new ObservableCollection>(); PointerPressed += CartesianChart_PointerPressed; PointerMoved += CartesianChart_PointerMoved; @@ -158,6 +162,13 @@ public CartesianChart() AvaloniaProperty.Register>>( nameof(Sections), Enumerable.Empty>(), inherits: true); + /// + /// The sections property + /// + public static readonly AvaloniaProperty>> VisualElementsProperty = + AvaloniaProperty.Register>>( + nameof(Sections), Enumerable.Empty>(), inherits: true); + /// /// The draw margin frame property /// @@ -418,6 +429,13 @@ public IEnumerable> Sections set => SetValue(SectionsProperty, value); } + /// + public IEnumerable> VisualElements + { + get => (IEnumerable>)GetValue(VisualElementsProperty); + set => SetValue(VisualElementsProperty, value); + } + /// public DrawMarginFrame? DrawMarginFrame { @@ -801,6 +819,12 @@ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs _sectionsObserver?.Initialize((IEnumerable>)change.NewValue.Value); } + if (change.Property.Name == nameof(VisualElementsProperty)) + { + _visualsObserver?.Dispose((IEnumerable>)change.OldValue.Value); + _visualsObserver?.Initialize((IEnumerable>)change.NewValue.Value); + } + _core.Update(); } diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp.Avalonia/PieChart.axaml.cs b/src/skiasharp/LiveChartsCore.SkiaSharp.Avalonia/PieChart.axaml.cs index 26955ce9a..bac56987d 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp.Avalonia/PieChart.axaml.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp.Avalonia/PieChart.axaml.cs @@ -25,6 +25,7 @@ using System.Collections.ObjectModel; using System.Collections.Specialized; using System.ComponentModel; +using System.Linq; using System.Windows.Input; using Avalonia; using Avalonia.Controls; @@ -59,7 +60,8 @@ public class PieChart : UserControl, IPieChartView, IAv protected IChartTooltip? tooltip; private Chart? _core; - private CollectionDeepObserver _seriesObserver; + private readonly CollectionDeepObserver _seriesObserver; + private readonly CollectionDeepObserver> _visualsObserver; private MotionCanvas? _avaloniaCanvas; #endregion @@ -98,9 +100,21 @@ public PieChart() { if (_core is null || (sender is IStopNPC stop && !stop.IsNotifyingChanges)) return; _core.Update(); - }); + }, true); + _visualsObserver = new CollectionDeepObserver>( + (object? sender, NotifyCollectionChangedEventArgs e) => + { + if (_core is null || (sender is IStopNPC stop && !stop.IsNotifyingChanges)) return; + _core.Update(); + }, + (object? sender, PropertyChangedEventArgs e) => + { + if (_core is null || (sender is IStopNPC stop && !stop.IsNotifyingChanges)) return; + _core.Update(); + }, true); Series = new ObservableCollection(); + VisualElements = new ObservableCollection>(); PointerLeave += Chart_PointerLeave; PointerMoved += Chart_PointerMoved; @@ -128,6 +142,13 @@ public PieChart() public static readonly AvaloniaProperty> SeriesProperty = AvaloniaProperty.Register>(nameof(Series), new List(), inherits: true); + /// + /// The sections property + /// + public static readonly AvaloniaProperty>> VisualElementsProperty = + AvaloniaProperty.Register>>( + nameof(Visual), Enumerable.Empty>(), inherits: true); + /// /// The initial rotation property /// @@ -356,6 +377,13 @@ public IEnumerable Series set => SetValue(SeriesProperty, value); } + /// + public IEnumerable> VisualElements + { + get => (IEnumerable>)GetValue(VisualElementsProperty); + set => SetValue(VisualElementsProperty, value); + } + /// public double InitialRotation { @@ -695,6 +723,13 @@ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs return; } + if (change.Property.Name == nameof(VisualElements)) + { + _visualsObserver?.Dispose((IEnumerable>)change.OldValue.Value); + _visualsObserver?.Initialize((IEnumerable>)change.NewValue.Value); + return; + } + _core.Update(); } diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp.Avalonia/PolarChart.axaml.cs b/src/skiasharp/LiveChartsCore.SkiaSharp.Avalonia/PolarChart.axaml.cs index bdf997ff7..6cb388b61 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp.Avalonia/PolarChart.axaml.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp.Avalonia/PolarChart.axaml.cs @@ -62,9 +62,10 @@ public class PolarChart : UserControl, IPolarChartView, private MotionCanvas? _avaloniaCanvas; private Chart? _core; - private CollectionDeepObserver _seriesObserver; - private CollectionDeepObserver _angleObserver; - private CollectionDeepObserver _radiusObserver; + private readonly CollectionDeepObserver _seriesObserver; + private readonly CollectionDeepObserver _angleObserver; + private readonly CollectionDeepObserver _radiusObserver; + private readonly CollectionDeepObserver> _visualsObserver; #endregion @@ -95,6 +96,8 @@ public PolarChart() _seriesObserver = new CollectionDeepObserver(OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); _angleObserver = new CollectionDeepObserver(OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); _radiusObserver = new CollectionDeepObserver(OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); + _visualsObserver = new CollectionDeepObserver>( + OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); AngleAxes = new List() { @@ -105,6 +108,7 @@ public PolarChart() LiveCharts.CurrentSettings.GetProvider().GetDefaultPolarAxis() }; Series = new ObservableCollection(); + VisualElements = new ObservableCollection>(); PointerWheelChanged += PolarChart_PointerWheelChanged; PointerPressed += PolarChart_PointerPressed; @@ -128,6 +132,13 @@ public PolarChart() public static readonly AvaloniaProperty> SeriesProperty = AvaloniaProperty.Register>(nameof(Series), Enumerable.Empty(), inherits: true); + /// + /// The sections property + /// + public static readonly AvaloniaProperty>> VisualElementsProperty = + AvaloniaProperty.Register>>( + nameof(VisualElements), Enumerable.Empty>(), inherits: true); + /// /// The fit to bounds property. /// @@ -421,6 +432,13 @@ public IEnumerable RadiusAxes set => SetValue(RadiusAxesProperty, value); } + /// + public IEnumerable> VisualElements + { + get => (IEnumerable>)GetValue(VisualElementsProperty); + set => SetValue(VisualElementsProperty, value); + } + /// public TimeSpan AnimationsSpeed { @@ -760,6 +778,12 @@ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs _radiusObserver?.Initialize((IEnumerable)change.NewValue.Value); } + if (change.Property.Name == nameof(VisualElements)) + { + _visualsObserver?.Dispose((IEnumerable>)change.OldValue.Value); + _visualsObserver?.Initialize((IEnumerable>)change.NewValue.Value); + } + _core.Update(); } From 873dee2dd8c3e8463714186e91d988d5d157fcb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Sun, 4 Sep 2022 22:13:36 -0500 Subject: [PATCH 39/50] visual elements for blazor --- .../CartesianChart.razor.cs | 20 +++++++++++++ .../PieChart.razor.cs | 30 +++++++++++++++++++ .../PolarChart.razor.cs | 22 +++++++++++++- 3 files changed, 71 insertions(+), 1 deletion(-) diff --git a/src/skiasharp/LiveChartsCore.SkiaSharpView.Blazor/CartesianChart.razor.cs b/src/skiasharp/LiveChartsCore.SkiaSharpView.Blazor/CartesianChart.razor.cs index a4cb3f599..c895d7e89 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharpView.Blazor/CartesianChart.razor.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharpView.Blazor/CartesianChart.razor.cs @@ -42,10 +42,12 @@ public partial class CartesianChart : Chart, ICartesianChartView? _xObserver; private CollectionDeepObserver? _yObserver; private CollectionDeepObserver>? _sectionsObserver; + private CollectionDeepObserver>? _visualsObserver; private IEnumerable _series = new ObservableCollection(); private IEnumerable? _xAxes; private IEnumerable? _yAxes; private IEnumerable> _sections = new List>(); + private IEnumerable> _visuals = new List>(); private DrawMarginFrame? _drawMarginFrame; private TooltipFindingStrategy _tooltipFindingStrategy = LiveCharts.CurrentSettings.DefaultTooltipFindingStrategy; @@ -59,6 +61,8 @@ protected override void OnInitialized() _yObserver = new CollectionDeepObserver(OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); _sectionsObserver = new CollectionDeepObserver>( OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); + _visualsObserver = new CollectionDeepObserver>( + OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); if (_xAxes is null) XAxes = new List() @@ -139,6 +143,20 @@ public IEnumerable> Sections } } + /// + [Parameter] + public IEnumerable> VisualElements + { + get => _visuals; + set + { + _visualsObserver?.Dispose(_visuals); + _visualsObserver?.Initialize(value); + _visuals = value; + OnPropertyChanged(); + } + } + /// [Parameter] public DrawMarginFrame? DrawMarginFrame @@ -225,10 +243,12 @@ protected override void OnDisposing() XAxes = Array.Empty(); YAxes = Array.Empty(); Sections = Array.Empty(); + VisualElements = Array.Empty>(); _seriesObserver = null!; _xObserver = null!; _yObserver = null!; _sectionsObserver = null!; + _visuals = null!; } private void OnDeepCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e) diff --git a/src/skiasharp/LiveChartsCore.SkiaSharpView.Blazor/PieChart.razor.cs b/src/skiasharp/LiveChartsCore.SkiaSharpView.Blazor/PieChart.razor.cs index 356e8fedf..7f0bed070 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharpView.Blazor/PieChart.razor.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharpView.Blazor/PieChart.razor.cs @@ -33,7 +33,9 @@ namespace LiveChartsCore.SkiaSharpView.Blazor; public partial class PieChart : Chart, IPieChartView { private CollectionDeepObserver? _seriesObserver; + private CollectionDeepObserver>? _visualsObserver; private IEnumerable _series = new List(); + private IEnumerable> _visuals = new List>(); private double _initialRotation; private double _maxAngle = 360; private double? _total; @@ -57,6 +59,18 @@ protected override void OnInitialized() OnPropertyChanged(); }, true); + _visualsObserver = new CollectionDeepObserver>( + (object? sender, NotifyCollectionChangedEventArgs e) => + { + if (sender is IStopNPC stop && !stop.IsNotifyingChanges) return; + OnPropertyChanged(); + }, + (object? sender, PropertyChangedEventArgs e) => + { + if (sender is IStopNPC stop && !stop.IsNotifyingChanges) return; + OnPropertyChanged(); + }, + true); } PieChart IPieChartView.Core => @@ -76,6 +90,20 @@ public IEnumerable Series } } + /// + [Parameter] + public IEnumerable> VisualElements + { + get => _visuals; + set + { + _visualsObserver?.Dispose(_visuals); + _visualsObserver?.Initialize(value); + _visuals = value; + OnPropertyChanged(); + } + } + /// [Parameter] public double InitialRotation { get => _initialRotation; set { _initialRotation = value; OnPropertyChanged(); } } @@ -108,5 +136,7 @@ protected override void OnDisposing() Series = Array.Empty(); _seriesObserver = null!; + VisualElements = Array.Empty>(); + _visualsObserver = null!; } } diff --git a/src/skiasharp/LiveChartsCore.SkiaSharpView.Blazor/PolarChart.razor.cs b/src/skiasharp/LiveChartsCore.SkiaSharpView.Blazor/PolarChart.razor.cs index f70171570..7364031d6 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharpView.Blazor/PolarChart.razor.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharpView.Blazor/PolarChart.razor.cs @@ -40,9 +40,11 @@ public partial class PolarChart : Chart, IPolarChartView? _seriesObserver; private CollectionDeepObserver? _angleObserver; private CollectionDeepObserver? _radiusObserver; + private CollectionDeepObserver>? _visualsObserver; private IEnumerable _series = new List(); private IEnumerable? _angleAxes; private IEnumerable? _radiusAxes; + private IEnumerable> _visuals = new List>(); /// /// Called when the control is initalized. @@ -54,6 +56,8 @@ protected override void OnInitialized() _seriesObserver = new CollectionDeepObserver(OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); _angleObserver = new CollectionDeepObserver(OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); _radiusObserver = new CollectionDeepObserver(OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); + _visualsObserver = new CollectionDeepObserver>( + OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); if (_angleAxes is null) AngleAxes = new List() @@ -167,8 +171,22 @@ public IEnumerable RadiusAxes } } + /// + [Parameter] + public IEnumerable> VisualElements + { + get => _visuals; + set + { + _visualsObserver?.Dispose(_visuals); + _visualsObserver?.Initialize(value); + _visuals = value; + OnPropertyChanged(); + } + } + /// - /// Called then the core is intialized. + /// Called then the core is initialized. /// /// protected override void InitializeCore() @@ -198,9 +216,11 @@ protected override void OnDisposing() Series = Array.Empty(); AngleAxes = Array.Empty(); RadiusAxes = Array.Empty(); + VisualElements = Array.Empty>(); _seriesObserver = null!; _angleObserver = null!; _radiusObserver = null!; + _visuals = null!; } private void OnDeepCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e) From a69fe3ac66997c8611f9eb63088284c7bc0e1fa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Sun, 4 Sep 2022 22:38:59 -0500 Subject: [PATCH 40/50] visual elements for eto --- .../CartesianChart.cs | 19 ++++++++++++ .../PieChart.cs | 30 +++++++++++++++++++ .../PolarChart.cs | 19 ++++++++++++ 3 files changed, 68 insertions(+) diff --git a/src/skiasharp/LiveChartsCore.SkiaSharpView.Eto/CartesianChart.cs b/src/skiasharp/LiveChartsCore.SkiaSharpView.Eto/CartesianChart.cs index 4ee7e3fdc..5807b20f5 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharpView.Eto/CartesianChart.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharpView.Eto/CartesianChart.cs @@ -43,10 +43,12 @@ public class CartesianChart : Chart, ICartesianChartView _xObserver; private CollectionDeepObserver _yObserver; private CollectionDeepObserver> _sectionsObserver; + private CollectionDeepObserver> _visualsObserver; private IEnumerable _series = new List(); private IEnumerable _xAxes = new List { new() }; private IEnumerable _yAxes = new List { new() }; private IEnumerable> _sections = new List>(); + private IEnumerable> _visuals = new List>(); private DrawMarginFrame? _drawMarginFrame; private TooltipFindingStrategy _tooltipFindingStrategy = LiveCharts.CurrentSettings.DefaultTooltipFindingStrategy; @@ -68,6 +70,8 @@ public CartesianChart(IChartTooltip? tooltip = null, IC _yObserver = new CollectionDeepObserver(OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); _sectionsObserver = new CollectionDeepObserver>( OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); + _visualsObserver = new CollectionDeepObserver>( + OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); XAxes = new List() { @@ -141,6 +145,19 @@ public IEnumerable> Sections } } + /// + public IEnumerable> VisualElements + { + get => _visuals; + set + { + _visualsObserver?.Dispose(_visuals); + _visualsObserver?.Initialize(value); + _visuals = value; + OnPropertyChanged(); + } + } + /// public DrawMarginFrame? DrawMarginFrame { @@ -188,10 +205,12 @@ protected override void OnUnloading() XAxes = Array.Empty(); YAxes = Array.Empty(); Sections = Array.Empty(); + VisualElements = Array.Empty>(); _seriesObserver = null!; _xObserver = null!; _yObserver = null!; _sectionsObserver = null!; + _visualsObserver = null!; } /// diff --git a/src/skiasharp/LiveChartsCore.SkiaSharpView.Eto/PieChart.cs b/src/skiasharp/LiveChartsCore.SkiaSharpView.Eto/PieChart.cs index de3e03f49..1657b0bca 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharpView.Eto/PieChart.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharpView.Eto/PieChart.cs @@ -37,6 +37,8 @@ public class PieChart : Chart, IPieChartView { private CollectionDeepObserver _seriesObserver; private IEnumerable _series = new List(); + private CollectionDeepObserver> _visualsObserver; + private IEnumerable> _visuals = new List>(); private double _initialRotation; private double _maxAngle = 360; private double? _total; @@ -66,6 +68,18 @@ public PieChart(IChartTooltip? tooltip = null, IChartLe OnPropertyChanged(); }, true); + _visualsObserver = new CollectionDeepObserver>( + (object? sender, NotifyCollectionChangedEventArgs e) => + { + if (sender is IStopNPC stop && !stop.IsNotifyingChanges) return; + OnPropertyChanged(); + }, + (object? sender, PropertyChangedEventArgs e) => + { + if (sender is IStopNPC stop && !stop.IsNotifyingChanges) return; + OnPropertyChanged(); + }, + true); motionCanvas.MouseDown += OnMouseDown; } @@ -86,6 +100,20 @@ public IEnumerable Series } } + /// + public IEnumerable> VisualElements + { + get => _visuals; + set + { + _visualsObserver?.Dispose(_visuals); + _visualsObserver?.Initialize(value); + _visuals = value; + OnPropertyChanged(); + } + } + + /// public double InitialRotation { get => _initialRotation; set { _initialRotation = value; OnPropertyChanged(); } } @@ -110,6 +138,8 @@ protected override void OnUnloading() { Series = Array.Empty(); _seriesObserver = null!; + VisualElements = Array.Empty>(); + _visualsObserver = null!; } private void OnMouseDown(object? sender, MouseEventArgs e) diff --git a/src/skiasharp/LiveChartsCore.SkiaSharpView.Eto/PolarChart.cs b/src/skiasharp/LiveChartsCore.SkiaSharpView.Eto/PolarChart.cs index ff9e73293..22cd5b60e 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharpView.Eto/PolarChart.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharpView.Eto/PolarChart.cs @@ -43,9 +43,11 @@ public class PolarChart : Chart, IPolarChartView private CollectionDeepObserver _seriesObserver; private CollectionDeepObserver _angleObserver; private CollectionDeepObserver _radiusObserver; + private CollectionDeepObserver> _visualsObserver; private IEnumerable _series = new List(); private IEnumerable _angleAxes = new List(); private IEnumerable _radiusAxes = new List(); + private IEnumerable> _visuals = new List>(); /// /// Initializes a new instance of the class. @@ -63,6 +65,8 @@ public PolarChart(IChartTooltip? tooltip = null, IChart _seriesObserver = new CollectionDeepObserver(OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); _angleObserver = new CollectionDeepObserver(OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); _radiusObserver = new CollectionDeepObserver(OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); + _visualsObserver = new CollectionDeepObserver>( + OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); AngleAxes = new List() { @@ -141,6 +145,19 @@ public IEnumerable Series } } + /// + public IEnumerable> VisualElements + { + get => _visuals; + set + { + _visualsObserver?.Dispose(_visuals); + _visualsObserver?.Initialize(value); + _visuals = value; + OnPropertyChanged(); + } + } + /// public IEnumerable AngleAxes { @@ -183,9 +200,11 @@ protected override void OnUnloading() Series = Array.Empty(); AngleAxes = Array.Empty(); RadiusAxes = Array.Empty(); + VisualElements = Array.Empty>(); _seriesObserver = null!; _angleObserver = null!; _radiusObserver = null!; + _visualsObserver = null!; } /// From 2c35877bc9832cd34d63d3ed13a06756216d830d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Sun, 4 Sep 2022 23:07:46 -0500 Subject: [PATCH 41/50] visual elements for maui --- .../CartesianChart.xaml.cs | 35 +++++++++++++++-- .../PieChart.xaml.cs | 38 ++++++++++++++++++- .../PolarChart.xaml.cs | 33 ++++++++++++++-- 3 files changed, 98 insertions(+), 8 deletions(-) diff --git a/src/skiasharp/LiveChartsCore.SkiaSharpView.Maui/CartesianChart.xaml.cs b/src/skiasharp/LiveChartsCore.SkiaSharpView.Maui/CartesianChart.xaml.cs index f461b1a12..1934230be 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharpView.Maui/CartesianChart.xaml.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharpView.Maui/CartesianChart.xaml.cs @@ -57,10 +57,11 @@ public partial class CartesianChart : ContentView, ICartesianChartView protected Chart? core; - private CollectionDeepObserver _seriesObserver; - private CollectionDeepObserver _xObserver; - private CollectionDeepObserver _yObserver; - private CollectionDeepObserver> _sectionsObserver; + private readonly CollectionDeepObserver _seriesObserver; + private readonly CollectionDeepObserver _xObserver; + private readonly CollectionDeepObserver _yObserver; + private readonly CollectionDeepObserver> _sectionsObserver; + private readonly CollectionDeepObserver> _visualsObserver; private double _lastScale = 0; private DateTime _panLocketUntil; private double _lastPanX = 0; @@ -92,6 +93,8 @@ public CartesianChart() _yObserver = new CollectionDeepObserver(OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); _sectionsObserver = new CollectionDeepObserver>( OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); + _visualsObserver = new CollectionDeepObserver>( + OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); XAxes = new List() { @@ -102,6 +105,7 @@ public CartesianChart() LiveCharts.CurrentSettings.GetProvider().GetDefaultCartesianAxis() }; Series = new ObservableCollection(); + VisualElements = new ObservableCollection>(); canvas.SkCanvasView.EnableTouchEvents = true; canvas.SkCanvasView.Touch += OnSkCanvasTouched; @@ -192,6 +196,22 @@ public CartesianChart() chart.core.Update(); }); + /// + /// The visual elements property. + /// + public static readonly BindableProperty VisualElementsProperty = + BindableProperty.Create( + nameof(VisualElements), typeof(IEnumerable>), typeof(CartesianChart), new List>(), + BindingMode.Default, null, (BindableObject o, object oldValue, object newValue) => + { + var chart = (CartesianChart)o; + var observer = chart._visualsObserver; + observer?.Dispose((IEnumerable>)oldValue); + observer?.Initialize((IEnumerable>)newValue); + if (chart.core is null) return; + chart.core.Update(); + }); + /// /// The draw margin frame property. /// @@ -477,6 +497,13 @@ public IEnumerable> Sections set => SetValue(SectionsProperty, value); } + /// + public IEnumerable> VisualElements + { + get => (IEnumerable>)GetValue(VisualElementsProperty); + set => SetValue(VisualElementsProperty, value); + } + /// public DrawMarginFrame? DrawMarginFrame { diff --git a/src/skiasharp/LiveChartsCore.SkiaSharpView.Maui/PieChart.xaml.cs b/src/skiasharp/LiveChartsCore.SkiaSharpView.Maui/PieChart.xaml.cs index d7070e17c..a96cd93b7 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharpView.Maui/PieChart.xaml.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharpView.Maui/PieChart.xaml.cs @@ -52,7 +52,8 @@ public partial class PieChart : ContentView, IPieChartView protected Chart? core; - private CollectionDeepObserver _seriesObserver; + private readonly CollectionDeepObserver _seriesObserver; + private readonly CollectionDeepObserver> _visualsObserver; #endregion @@ -86,8 +87,20 @@ public PieChart() if (core is null || (sender is IStopNPC stop && !stop.IsNotifyingChanges)) return; core.Update(); }); + _visualsObserver = new CollectionDeepObserver>( + (object? sender, NotifyCollectionChangedEventArgs e) => + { + if (core is null || (sender is IStopNPC stop && !stop.IsNotifyingChanges)) return; + core.Update(); + }, + (object? sender, PropertyChangedEventArgs e) => + { + if (core is null || (sender is IStopNPC stop && !stop.IsNotifyingChanges)) return; + core.Update(); + }); Series = new ObservableCollection(); + VisualElements = new ObservableCollection>(); canvas.SkCanvasView.EnableTouchEvents = true; canvas.SkCanvasView.Touch += OnSkCanvasTouched; @@ -130,6 +143,22 @@ public PieChart() chart.core.Update(); }); + /// + /// The visual elements property. + /// + public static readonly BindableProperty VisualElementsProperty = + BindableProperty.Create( + nameof(VisualElements), typeof(IEnumerable>), typeof(PieChart), new List>(), + BindingMode.Default, null, (BindableObject o, object oldValue, object newValue) => + { + var chart = (PieChart)o; + var observer = chart._visualsObserver; + observer?.Dispose((IEnumerable>)oldValue); + observer?.Initialize((IEnumerable>)newValue); + if (chart.core is null) return; + chart.core.Update(); + }); + /// /// The initial rotation property /// @@ -382,6 +411,13 @@ public IEnumerable Series set => SetValue(SeriesProperty, value); } + /// + public IEnumerable> VisualElements + { + get => (IEnumerable>)GetValue(VisualElementsProperty); + set => SetValue(VisualElementsProperty, value); + } + /// public double InitialRotation { diff --git a/src/skiasharp/LiveChartsCore.SkiaSharpView.Maui/PolarChart.xaml.cs b/src/skiasharp/LiveChartsCore.SkiaSharpView.Maui/PolarChart.xaml.cs index 87cdfa3a1..59e880ae8 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharpView.Maui/PolarChart.xaml.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharpView.Maui/PolarChart.xaml.cs @@ -53,9 +53,10 @@ public partial class PolarChart : ContentView, IPolarChartView protected Chart? core; - private CollectionDeepObserver _seriesObserver; - private CollectionDeepObserver _angleObserver; - private CollectionDeepObserver _radiusObserver; + private readonly CollectionDeepObserver _seriesObserver; + private readonly CollectionDeepObserver _angleObserver; + private readonly CollectionDeepObserver _radiusObserver; + private readonly CollectionDeepObserver> _visualsObserver; #endregion @@ -81,6 +82,8 @@ public PolarChart() _seriesObserver = new CollectionDeepObserver(OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); _angleObserver = new CollectionDeepObserver(OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); _radiusObserver = new CollectionDeepObserver(OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); + _visualsObserver = new CollectionDeepObserver>( + OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); AngleAxes = new List() { @@ -91,6 +94,7 @@ public PolarChart() LiveCharts.CurrentSettings.GetProvider().GetDefaultPolarAxis() }; Series = new ObservableCollection(); + VisualElements = new ObservableCollection>(); canvas.SkCanvasView.EnableTouchEvents = true; canvas.SkCanvasView.Touch += OnSkCanvasTouched; @@ -161,6 +165,22 @@ public PolarChart() chart.core.Update(); }); + /// + /// The visual elements property. + /// + public static readonly BindableProperty VisualElementsProperty = + BindableProperty.Create( + nameof(VisualElements), typeof(IEnumerable>), typeof(PolarChart), new List>(), + BindingMode.Default, null, (BindableObject o, object oldValue, object newValue) => + { + var chart = (PolarChart)o; + var observer = chart._visualsObserver; + observer?.Dispose((IEnumerable>)oldValue); + observer?.Initialize((IEnumerable>)newValue); + if (chart.core is null) return; + chart.core.Update(); + }); + /// /// The x axes property. /// @@ -468,6 +488,13 @@ public IEnumerable RadiusAxes set => SetValue(RadiusAxesProperty, value); } + /// + public IEnumerable> VisualElements + { + get => (IEnumerable>)GetValue(VisualElementsProperty); + set => SetValue(VisualElementsProperty, value); + } + /// public TimeSpan AnimationsSpeed { From 10d9b21c0f65aa201b747183a626d2dd79d71e2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Sun, 4 Sep 2022 23:18:57 -0500 Subject: [PATCH 42/50] visual elements for uno --- .../CartesianChart.xaml.cs | 38 +++++++++++++---- .../PieChart.xaml.cs | 41 ++++++++++++++++++- .../PolarChart.xaml.cs | 33 +++++++++++++-- 3 files changed, 101 insertions(+), 11 deletions(-) diff --git a/src/skiasharp/LiveChartsCore.SkiaSharpView.Uno/CartesianChart.xaml.cs b/src/skiasharp/LiveChartsCore.SkiaSharpView.Uno/CartesianChart.xaml.cs index 257d82fbf..2566967e3 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharpView.Uno/CartesianChart.xaml.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharpView.Uno/CartesianChart.xaml.cs @@ -54,14 +54,12 @@ public sealed partial class CartesianChart : UserControl, ICartesianChartView? _core; private MotionCanvas? _motionCanvas; - private CollectionDeepObserver _seriesObserver; - private CollectionDeepObserver _xObserver; - private CollectionDeepObserver _yObserver; - private CollectionDeepObserver> _sectionsObserver; - //private double _lastScale = 0; + private readonly CollectionDeepObserver _seriesObserver; + private readonly CollectionDeepObserver _xObserver; + private readonly CollectionDeepObserver _yObserver; + private readonly CollectionDeepObserver> _sectionsObserver; + private readonly CollectionDeepObserver> _visualsObserver; private DateTime _panLocketUntil; - //private double _lastPanX = 0; - //private double _lastPanY = 0; #endregion @@ -85,6 +83,8 @@ public CartesianChart() _yObserver = new CollectionDeepObserver(OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); _sectionsObserver = new CollectionDeepObserver>( OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); + _visualsObserver = new CollectionDeepObserver>( + OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); Loaded += OnLoaded; Unloaded += OnUnloaded; @@ -99,6 +99,7 @@ public CartesianChart() }); SetValue(SeriesProperty, new ObservableCollection()); SetValue(SectionsProperty, new ObservableCollection>()); + SetValue(VisualElementsProperty, new ObservableCollection>()); } #region dependency properties @@ -167,6 +168,22 @@ public CartesianChart() chart._core.Update(); })); + /// + /// The visual elements property + /// + public static readonly DependencyProperty VisualElementsProperty = + DependencyProperty.Register( + nameof(VisualElements), typeof(IEnumerable>), typeof(CartesianChart), new PropertyMetadata(null, + (DependencyObject o, DependencyPropertyChangedEventArgs args) => + { + var chart = (CartesianChart)o; + var observer = chart._visualsObserver; + observer?.Dispose((IEnumerable>)args.OldValue); + observer?.Initialize((IEnumerable>)args.NewValue); + if (chart._core == null) return; + chart._core.Update(); + })); + /// /// The sync context property /// @@ -498,6 +515,13 @@ public IEnumerable> Sections set => SetValue(SectionsProperty, value); } + /// + public IEnumerable> VisualElements + { + get => (IEnumerable>)GetValue(VisualElementsProperty); + set => SetValue(VisualElementsProperty, value); + } + /// public DrawMarginFrame? DrawMarginFrame { diff --git a/src/skiasharp/LiveChartsCore.SkiaSharpView.Uno/PieChart.xaml.cs b/src/skiasharp/LiveChartsCore.SkiaSharpView.Uno/PieChart.xaml.cs index 089d3f6ac..b7fba9503 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharpView.Uno/PieChart.xaml.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharpView.Uno/PieChart.xaml.cs @@ -23,6 +23,7 @@ using System; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Collections.Specialized; using System.ComponentModel; using System.Windows.Input; @@ -47,7 +48,8 @@ public sealed partial class PieChart : UserControl, IPieChartView? _core; private MotionCanvas? _canvas; - private CollectionDeepObserver _seriesObserver; + private readonly CollectionDeepObserver _seriesObserver; + private readonly CollectionDeepObserver> _visualsObserver; /// /// Initializes a new instance of the class. @@ -75,6 +77,20 @@ public PieChart() if (_core == null || (sender is IStopNPC stop && !stop.IsNotifyingChanges)) return; _core.Update(); }); + _visualsObserver = new CollectionDeepObserver>( + (object sender, NotifyCollectionChangedEventArgs e) => + { + if (_core == null || (sender is IStopNPC stop && !stop.IsNotifyingChanges)) return; + _core.Update(); + }, + (object sender, PropertyChangedEventArgs e) => + { + if (_core == null || (sender is IStopNPC stop && !stop.IsNotifyingChanges)) return; + _core.Update(); + }); + + SetValue(SeriesProperty, new ObservableCollection()); + SetValue(VisualElementsProperty, new ObservableCollection>()); Loaded += OnLoaded; Unloaded += OnUnloaded; @@ -98,6 +114,22 @@ public PieChart() chart._core.Update(); })); + /// + /// The visual elements property + /// + public static readonly DependencyProperty VisualElementsProperty = + DependencyProperty.Register( + nameof(VisualElements), typeof(IEnumerable>), typeof(PieChart), new PropertyMetadata(null, + (DependencyObject o, DependencyPropertyChangedEventArgs args) => + { + var chart = (PieChart)o; + var observer = chart._visualsObserver; + observer?.Dispose((IEnumerable>)args.OldValue); + observer?.Initialize((IEnumerable>)args.NewValue); + if (chart._core == null) return; + chart._core.Update(); + })); + /// /// The sync context property /// @@ -378,6 +410,13 @@ public IEnumerable Series set => SetValue(SeriesProperty, value); } + /// + public IEnumerable> VisualElements + { + get => (IEnumerable>)GetValue(VisualElementsProperty); + set => SetValue(VisualElementsProperty, value); + } + /// public double InitialRotation { diff --git a/src/skiasharp/LiveChartsCore.SkiaSharpView.Uno/PolarChart.xaml.cs b/src/skiasharp/LiveChartsCore.SkiaSharpView.Uno/PolarChart.xaml.cs index 3dcf5e4f2..d556d58f1 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharpView.Uno/PolarChart.xaml.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharpView.Uno/PolarChart.xaml.cs @@ -51,9 +51,10 @@ public sealed partial class PolarChart : UserControl, IPolarChartView? _core; private MotionCanvas? _canvas; - private CollectionDeepObserver _seriesObserver; - private CollectionDeepObserver _angleObserver; - private CollectionDeepObserver _radiusObserver; + private readonly CollectionDeepObserver _seriesObserver; + private readonly CollectionDeepObserver _angleObserver; + private readonly CollectionDeepObserver _radiusObserver; + private readonly CollectionDeepObserver> _visualsObserver; #endregion @@ -75,6 +76,8 @@ public PolarChart() _seriesObserver = new CollectionDeepObserver(OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); _angleObserver = new CollectionDeepObserver(OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); _radiusObserver = new CollectionDeepObserver(OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); + _visualsObserver = new CollectionDeepObserver>( + OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); Loaded += OnLoaded; Unloaded += OnUnloaded; @@ -88,6 +91,7 @@ public PolarChart() LiveCharts.CurrentSettings.GetProvider().GetDefaultPolarAxis() }); SetValue(SeriesProperty, new ObservableCollection()); + SetValue(VisualElementsProperty, new ObservableCollection>()); } #region dependency properties @@ -169,6 +173,22 @@ public PolarChart() chart._core.Update(); })); + /// + /// The visual elements property + /// + public static readonly DependencyProperty VisualElementsProperty = + DependencyProperty.Register( + nameof(VisualElements), typeof(IEnumerable>), typeof(PolarChart), new PropertyMetadata(null, + (DependencyObject o, DependencyPropertyChangedEventArgs args) => + { + var chart = (PolarChart)o; + var observer = chart._visualsObserver; + observer?.Dispose((IEnumerable>)args.OldValue); + observer?.Initialize((IEnumerable>)args.NewValue); + if (chart._core == null) return; + chart._core.Update(); + })); + /// /// The sync context property. /// @@ -491,6 +511,13 @@ public IEnumerable RadiusAxes set => SetValue(RadiusAxesProperty, value); } + /// + public IEnumerable> VisualElements + { + get => (IEnumerable>)GetValue(VisualElementsProperty); + set => SetValue(VisualElementsProperty, value); + } + /// public TimeSpan AnimationsSpeed { From 8b5ce2b722e5e4354209a7a4168e455f6e26b52b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Sun, 4 Sep 2022 23:27:59 -0500 Subject: [PATCH 43/50] visual elements for uno winui --- .../CartesianChart.xaml.cs | 38 ++++++++++++++---- .../PieChart.xaml.cs | 39 +++++++++++++++++++ .../PolarChart.xaml.cs | 27 +++++++++++++ 3 files changed, 97 insertions(+), 7 deletions(-) diff --git a/src/skiasharp/LiveChartsCore.SkiaSharpView.Uno.WinUI/CartesianChart.xaml.cs b/src/skiasharp/LiveChartsCore.SkiaSharpView.Uno.WinUI/CartesianChart.xaml.cs index 422804291..317342550 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharpView.Uno.WinUI/CartesianChart.xaml.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharpView.Uno.WinUI/CartesianChart.xaml.cs @@ -55,14 +55,12 @@ public sealed partial class CartesianChart : UserControl, ICartesianChartView? _core; private MotionCanvas? _motionCanvas; - private CollectionDeepObserver _seriesObserver; - private CollectionDeepObserver _xObserver; - private CollectionDeepObserver _yObserver; - private CollectionDeepObserver> _sectionsObserver; - //private double _lastScale = 0; + private readonly CollectionDeepObserver _seriesObserver; + private readonly CollectionDeepObserver _xObserver; + private readonly CollectionDeepObserver _yObserver; + private readonly CollectionDeepObserver> _sectionsObserver; + private readonly CollectionDeepObserver> _visualsObserver; private DateTime _panLocketUntil; - //private double _lastPanX = 0; - //private double _lastPanY = 0; #endregion @@ -86,6 +84,8 @@ public CartesianChart() _yObserver = new CollectionDeepObserver(OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); _sectionsObserver = new CollectionDeepObserver>( OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); + _visualsObserver = new CollectionDeepObserver>( + OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); Loaded += OnLoaded; Unloaded += OnUnloaded; @@ -100,6 +100,7 @@ public CartesianChart() }); SetValue(SeriesProperty, new ObservableCollection()); SetValue(SectionsProperty, new ObservableCollection>()); + SetValue(VisualElementsProperty, new ObservableCollection>()); } #region dependency properties @@ -168,6 +169,22 @@ public CartesianChart() chart._core.Update(); })); + /// + /// The visual elements property + /// + public static readonly DependencyProperty VisualElementsProperty = + DependencyProperty.Register( + nameof(VisualElements), typeof(IEnumerable>), typeof(CartesianChart), new PropertyMetadata(null, + (DependencyObject o, DependencyPropertyChangedEventArgs args) => + { + var chart = (CartesianChart)o; + var observer = chart._visualsObserver; + observer?.Dispose((IEnumerable>)args.OldValue); + observer?.Initialize((IEnumerable>)args.NewValue); + if (chart._core == null) return; + chart._core.Update(); + })); + /// /// The sync context property /// @@ -499,6 +516,13 @@ public IEnumerable> Sections set => SetValue(SectionsProperty, value); } + /// + public IEnumerable> VisualElements + { + get => (IEnumerable>)GetValue(VisualElementsProperty); + set => SetValue(VisualElementsProperty, value); + } + /// public DrawMarginFrame? DrawMarginFrame { diff --git a/src/skiasharp/LiveChartsCore.SkiaSharpView.Uno.WinUI/PieChart.xaml.cs b/src/skiasharp/LiveChartsCore.SkiaSharpView.Uno.WinUI/PieChart.xaml.cs index 906f470f1..5108a2a08 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharpView.Uno.WinUI/PieChart.xaml.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharpView.Uno.WinUI/PieChart.xaml.cs @@ -23,6 +23,7 @@ using System; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Collections.Specialized; using System.ComponentModel; using System.Windows.Input; @@ -49,6 +50,7 @@ public sealed partial class PieChart : UserControl, IPieChartView? _core; private MotionCanvas? _canvas; private readonly CollectionDeepObserver _seriesObserver; + private readonly CollectionDeepObserver> _visualsObserver; /// /// Initializes a new instance of the class. @@ -76,9 +78,23 @@ public PieChart() if (_core == null || (sender is IStopNPC stop && !stop.IsNotifyingChanges)) return; _core.Update(); }); + _visualsObserver = new CollectionDeepObserver>( + (object? sender, NotifyCollectionChangedEventArgs e) => + { + if (_core == null || (sender is IStopNPC stop && !stop.IsNotifyingChanges)) return; + _core.Update(); + }, + (object? sender, PropertyChangedEventArgs e) => + { + if (_core == null || (sender is IStopNPC stop && !stop.IsNotifyingChanges)) return; + _core.Update(); + }); Loaded += OnLoaded; Unloaded += OnUnloaded; + + SetValue(SeriesProperty, new ObservableCollection()); + SetValue(VisualElementsProperty, new ObservableCollection>()); } #region dependency properties @@ -99,6 +115,22 @@ public PieChart() chart._core.Update(); })); + /// + /// The visual elements property + /// + public static readonly DependencyProperty VisualElementsProperty = + DependencyProperty.Register( + nameof(VisualElements), typeof(IEnumerable>), typeof(PieChart), new PropertyMetadata(null, + (DependencyObject o, DependencyPropertyChangedEventArgs args) => + { + var chart = (PieChart)o; + var observer = chart._visualsObserver; + observer?.Dispose((IEnumerable>)args.OldValue); + observer?.Initialize((IEnumerable>)args.NewValue); + if (chart._core == null) return; + chart._core.Update(); + })); + /// /// The sync context property /// @@ -379,6 +411,13 @@ public IEnumerable Series set => SetValue(SeriesProperty, value); } + /// + public IEnumerable> VisualElements + { + get => (IEnumerable>)GetValue(VisualElementsProperty); + set => SetValue(VisualElementsProperty, value); + } + /// public double InitialRotation { diff --git a/src/skiasharp/LiveChartsCore.SkiaSharpView.Uno.WinUI/PolarChart.xaml.cs b/src/skiasharp/LiveChartsCore.SkiaSharpView.Uno.WinUI/PolarChart.xaml.cs index 765516c33..9cc63220d 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharpView.Uno.WinUI/PolarChart.xaml.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharpView.Uno.WinUI/PolarChart.xaml.cs @@ -55,6 +55,7 @@ public sealed partial class PolarChart : UserControl, IPolarChartView _seriesObserver; private readonly CollectionDeepObserver _angleObserver; private readonly CollectionDeepObserver _radiusObserver; + private readonly CollectionDeepObserver> _visualsObserver; #endregion @@ -76,6 +77,8 @@ public PolarChart() _seriesObserver = new CollectionDeepObserver(OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); _angleObserver = new CollectionDeepObserver(OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); _radiusObserver = new CollectionDeepObserver(OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); + _visualsObserver = new CollectionDeepObserver>( + OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); Loaded += OnLoaded; Unloaded += OnUnloaded; @@ -89,6 +92,7 @@ public PolarChart() LiveCharts.CurrentSettings.GetProvider().GetDefaultPolarAxis() }); SetValue(SeriesProperty, new ObservableCollection()); + SetValue(VisualElementsProperty, new ObservableCollection>()); } #region dependency properties @@ -138,6 +142,22 @@ public PolarChart() chart._core.Update(); })); + /// + /// The visual elements property + /// + public static readonly DependencyProperty VisualElementsProperty = + DependencyProperty.Register( + nameof(VisualElements), typeof(IEnumerable>), typeof(PolarChart), new PropertyMetadata(null, + (DependencyObject o, DependencyPropertyChangedEventArgs args) => + { + var chart = (PolarChart)o; + var observer = chart._visualsObserver; + observer?.Dispose((IEnumerable>)args.OldValue); + observer?.Initialize((IEnumerable>)args.NewValue); + if (chart._core == null) return; + chart._core.Update(); + })); + /// /// The x axes property. /// @@ -492,6 +512,13 @@ public IEnumerable RadiusAxes set => SetValue(RadiusAxesProperty, value); } + /// + public IEnumerable> VisualElements + { + get => (IEnumerable>)GetValue(VisualElementsProperty); + set => SetValue(VisualElementsProperty, value); + } + /// public TimeSpan AnimationsSpeed { From fbfc44ea50aec354f5f5bfa9b6c9bc2dd9889a22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Sun, 4 Sep 2022 23:41:29 -0500 Subject: [PATCH 44/50] visual elements for winforms --- .../CartesianChart.cs | 27 ++++++++++++--- .../PieChart.cs | 34 ++++++++++++++++++- .../PolarChart.cs | 25 ++++++++++++-- 3 files changed, 78 insertions(+), 8 deletions(-) diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp.WinForms/CartesianChart.cs b/src/skiasharp/LiveChartsCore.SkiaSharp.WinForms/CartesianChart.cs index 80839db81..7ca979a40 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp.WinForms/CartesianChart.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp.WinForms/CartesianChart.cs @@ -39,14 +39,16 @@ namespace LiveChartsCore.SkiaSharpView.WinForms; /// public class CartesianChart : Chart, ICartesianChartView { - private CollectionDeepObserver _seriesObserver; - private CollectionDeepObserver _xObserver; - private CollectionDeepObserver _yObserver; - private CollectionDeepObserver> _sectionsObserver; + private readonly CollectionDeepObserver _seriesObserver; + private readonly CollectionDeepObserver _xObserver; + private readonly CollectionDeepObserver _yObserver; + private readonly CollectionDeepObserver> _sectionsObserver; + private readonly CollectionDeepObserver> _visualsObserver; private IEnumerable _series = new List(); private IEnumerable _xAxes = new List { new() }; private IEnumerable _yAxes = new List { new() }; private IEnumerable> _sections = new List>(); + private IEnumerable> _visuals = new List>(); private DrawMarginFrame? _drawMarginFrame; private TooltipFindingStrategy _tooltipFindingStrategy = LiveCharts.CurrentSettings.DefaultTooltipFindingStrategy; @@ -68,6 +70,8 @@ public CartesianChart(IChartTooltip? tooltip = null, IC _yObserver = new CollectionDeepObserver(OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); _sectionsObserver = new CollectionDeepObserver>( OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); + _visualsObserver = new CollectionDeepObserver>( + OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); XAxes = new List() { @@ -78,6 +82,7 @@ public CartesianChart(IChartTooltip? tooltip = null, IC LiveCharts.CurrentSettings.GetProvider().GetDefaultCartesianAxis() }; Series = new ObservableCollection(); + VisualElements = new ObservableCollection>(); var c = Controls[0].Controls[0]; @@ -145,6 +150,20 @@ public IEnumerable> Sections } } + /// + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public IEnumerable> VisualElements + { + get => _visuals; + set + { + _visualsObserver?.Dispose(_visuals); + _visualsObserver?.Initialize(value); + _visuals = value; + OnPropertyChanged(); + } + } + /// [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public DrawMarginFrame? DrawMarginFrame diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp.WinForms/PieChart.cs b/src/skiasharp/LiveChartsCore.SkiaSharp.WinForms/PieChart.cs index 64fea2698..b5b874ef8 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp.WinForms/PieChart.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp.WinForms/PieChart.cs @@ -22,6 +22,7 @@ using System; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Collections.Specialized; using System.ComponentModel; using System.Windows.Forms; @@ -35,8 +36,10 @@ namespace LiveChartsCore.SkiaSharpView.WinForms; /// public class PieChart : Chart, IPieChartView { - private CollectionDeepObserver _seriesObserver; + private readonly CollectionDeepObserver _seriesObserver; + private readonly CollectionDeepObserver> _visualsObserver; private IEnumerable _series = new List(); + private IEnumerable> _visuals = new List>(); private double _initialRotation; private double _maxAngle = 360; private double? _total; @@ -66,6 +69,21 @@ public PieChart(IChartTooltip? tooltip = null, IChartLe OnPropertyChanged(); }, true); + _visualsObserver = new CollectionDeepObserver>( + (object? sender, NotifyCollectionChangedEventArgs e) => + { + if (sender is IStopNPC stop && !stop.IsNotifyingChanges) return; + OnPropertyChanged(); + }, + (object? sender, PropertyChangedEventArgs e) => + { + if (sender is IStopNPC stop && !stop.IsNotifyingChanges) return; + OnPropertyChanged(); + }, + true); + + Series = new ObservableCollection(); + VisualElements = new ObservableCollection>(); var c = Controls[0].Controls[0]; c.MouseDown += OnMouseDown; @@ -88,6 +106,20 @@ public IEnumerable Series } } + /// + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public IEnumerable> VisualElements + { + get => _visuals; + set + { + _visualsObserver?.Dispose(_visuals); + _visualsObserver?.Initialize(value); + _visuals = value; + OnPropertyChanged(); + } + } + /// public double InitialRotation { get => _initialRotation; set { _initialRotation = value; OnPropertyChanged(); } } diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp.WinForms/PolarChart.cs b/src/skiasharp/LiveChartsCore.SkiaSharp.WinForms/PolarChart.cs index 1f683cfcf..49423c121 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp.WinForms/PolarChart.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp.WinForms/PolarChart.cs @@ -40,12 +40,14 @@ public class PolarChart : Chart, IPolarChartView private double _totalAngle = 360; private double _innerRadius; private double _initialRotation = LiveCharts.CurrentSettings.PolarInitialRotation; - private CollectionDeepObserver _seriesObserver; - private CollectionDeepObserver _angleObserver; - private CollectionDeepObserver _radiusObserver; + private readonly CollectionDeepObserver _seriesObserver; + private readonly CollectionDeepObserver _angleObserver; + private readonly CollectionDeepObserver _radiusObserver; + private readonly CollectionDeepObserver> _visualsObserver; private IEnumerable _series = new List(); private IEnumerable _angleAxes = new List(); private IEnumerable _radiusAxes = new List(); + private IEnumerable> _visuals = new List>(); /// /// Initializes a new instance of the class. @@ -63,6 +65,8 @@ public PolarChart(IChartTooltip? tooltip = null, IChart _seriesObserver = new CollectionDeepObserver(OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); _angleObserver = new CollectionDeepObserver(OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); _radiusObserver = new CollectionDeepObserver(OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); + _visualsObserver = new CollectionDeepObserver>( + OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); AngleAxes = new List() { @@ -73,6 +77,7 @@ public PolarChart(IChartTooltip? tooltip = null, IChart LiveCharts.CurrentSettings.GetProvider().GetDefaultPolarAxis() }; Series = new ObservableCollection(); + VisualElements = new ObservableCollection>(); var c = Controls[0].Controls[0]; @@ -174,6 +179,20 @@ public IEnumerable RadiusAxes } } + /// + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public IEnumerable> VisualElements + { + get => _visuals; + set + { + _visualsObserver?.Dispose(_visuals); + _visualsObserver?.Initialize(value); + _visuals = value; + OnPropertyChanged(); + } + } + /// /// Initializes the core. /// From e585296dc40dae6db31f3a86ac4821aa00395bfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Sun, 4 Sep 2022 23:53:59 -0500 Subject: [PATCH 45/50] visual elements for winui --- .../CartesianChart.xaml.cs | 35 ++++++++++++++-- .../PieChart.xaml.cs | 42 ++++++++++++++++++- .../PolarChart.xaml.cs | 33 +++++++++++++-- 3 files changed, 102 insertions(+), 8 deletions(-) diff --git a/src/skiasharp/LiveChartsCore.SkiaSharpView.WinUI/CartesianChart.xaml.cs b/src/skiasharp/LiveChartsCore.SkiaSharpView.WinUI/CartesianChart.xaml.cs index 368ec80e5..05a3293ed 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharpView.WinUI/CartesianChart.xaml.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharpView.WinUI/CartesianChart.xaml.cs @@ -50,10 +50,11 @@ public sealed partial class CartesianChart : UserControl, ICartesianChartView? _core; private MotionCanvas? _canvas; - private CollectionDeepObserver _seriesObserver; - private CollectionDeepObserver _xObserver; - private CollectionDeepObserver _yObserver; - private CollectionDeepObserver> _sectionsObserver; + private readonly CollectionDeepObserver _seriesObserver; + private readonly CollectionDeepObserver _xObserver; + private readonly CollectionDeepObserver _yObserver; + private readonly CollectionDeepObserver> _sectionsObserver; + private readonly CollectionDeepObserver> _visualsObserver; #endregion @@ -77,6 +78,8 @@ public CartesianChart() _yObserver = new CollectionDeepObserver(OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); _sectionsObserver = new CollectionDeepObserver>( OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); + _visualsObserver = new CollectionDeepObserver>( + OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); Loaded += OnLoaded; Unloaded += OnUnloaded; @@ -91,6 +94,7 @@ public CartesianChart() }); SetValue(SeriesProperty, new ObservableCollection()); SetValue(SectionsProperty, new ObservableCollection>()); + SetValue(VisualElementsProperty, new ObservableCollection>()); } #region dependency properties @@ -159,6 +163,22 @@ public CartesianChart() chart._core.Update(); })); + /// + /// The visual elements property + /// + public static readonly DependencyProperty VisualElementsProperty = + DependencyProperty.Register( + nameof(VisualElements), typeof(IEnumerable>), typeof(CartesianChart), new PropertyMetadata(null, + (DependencyObject o, DependencyPropertyChangedEventArgs args) => + { + var chart = (CartesianChart)o; + var observer = chart._visualsObserver; + observer?.Dispose((IEnumerable>)args.OldValue); + observer?.Initialize((IEnumerable>)args.NewValue); + if (chart._core == null) return; + chart._core.Update(); + })); + /// /// The sync context property /// @@ -489,6 +509,13 @@ public IEnumerable> Sections set => SetValue(SectionsProperty, value); } + /// + public IEnumerable> VisualElements + { + get => (IEnumerable>)GetValue(VisualElementsProperty); + set => SetValue(VisualElementsProperty, value); + } + /// public DrawMarginFrame? DrawMarginFrame { diff --git a/src/skiasharp/LiveChartsCore.SkiaSharpView.WinUI/PieChart.xaml.cs b/src/skiasharp/LiveChartsCore.SkiaSharpView.WinUI/PieChart.xaml.cs index 9c18b466c..d9b0a5314 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharpView.WinUI/PieChart.xaml.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharpView.WinUI/PieChart.xaml.cs @@ -22,6 +22,7 @@ using System; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Collections.Specialized; using System.ComponentModel; using System.Windows.Input; @@ -45,7 +46,8 @@ public sealed partial class PieChart : UserControl, IPieChartView? _core; private MotionCanvas? _canvas; - private CollectionDeepObserver _seriesObserver; + private readonly CollectionDeepObserver _seriesObserver; + private readonly CollectionDeepObserver> _visualsObserver; /// /// Initializes a new instance of the class. @@ -73,9 +75,23 @@ public PieChart() if (_core == null || (sender is IStopNPC stop && !stop.IsNotifyingChanges)) return; _core.Update(); }); + _visualsObserver = new CollectionDeepObserver>( + (object? sender, NotifyCollectionChangedEventArgs e) => + { + if (_core == null || (sender is IStopNPC stop && !stop.IsNotifyingChanges)) return; + _core.Update(); + }, + (object? sender, PropertyChangedEventArgs e) => + { + if (_core == null || (sender is IStopNPC stop && !stop.IsNotifyingChanges)) return; + _core.Update(); + }); Loaded += OnLoaded; Unloaded += OnUnloaded; + + SetValue(SeriesProperty, new ObservableCollection()); + SetValue(VisualElementsProperty, new ObservableCollection>()); } #region dependency properties @@ -96,6 +112,22 @@ public PieChart() chart._core.Update(); })); + /// + /// The visual elements property + /// + public static readonly DependencyProperty VisualElementsProperty = + DependencyProperty.Register( + nameof(VisualElements), typeof(IEnumerable>), typeof(PieChart), new PropertyMetadata(null, + (DependencyObject o, DependencyPropertyChangedEventArgs args) => + { + var chart = (PieChart)o; + var observer = chart._visualsObserver; + observer?.Dispose((IEnumerable>)args.OldValue); + observer?.Initialize((IEnumerable>)args.NewValue); + if (chart._core == null) return; + chart._core.Update(); + })); + /// /// The sync context property /// @@ -375,6 +407,13 @@ public IEnumerable Series set => SetValue(SeriesProperty, value); } + /// + public IEnumerable> VisualElements + { + get => (IEnumerable>)GetValue(VisualElementsProperty); + set => SetValue(VisualElementsProperty, value); + } + /// public double InitialRotation { @@ -785,6 +824,7 @@ private void OnLoaded(object sender, RoutedEventArgs e) PointerMoved += OnPointerMoved; PointerExited += OnPointerExited; PointerPressed += OnPointerPressed; + PointerReleased += OnPointerReleased; } _core.Load(); diff --git a/src/skiasharp/LiveChartsCore.SkiaSharpView.WinUI/PolarChart.xaml.cs b/src/skiasharp/LiveChartsCore.SkiaSharpView.WinUI/PolarChart.xaml.cs index e9f49136b..bce6e1299 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharpView.WinUI/PolarChart.xaml.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharpView.WinUI/PolarChart.xaml.cs @@ -48,9 +48,10 @@ public sealed partial class PolarChart : UserControl, IPolarChartView? _core; private MotionCanvas? _canvas; - private CollectionDeepObserver _seriesObserver; - private CollectionDeepObserver _angleObserver; - private CollectionDeepObserver _radiusObserver; + private readonly CollectionDeepObserver _seriesObserver; + private readonly CollectionDeepObserver _angleObserver; + private readonly CollectionDeepObserver _radiusObserver; + private readonly CollectionDeepObserver> _visualsObserver; #endregion @@ -72,6 +73,8 @@ public PolarChart() _seriesObserver = new CollectionDeepObserver(OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); _angleObserver = new CollectionDeepObserver(OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); _radiusObserver = new CollectionDeepObserver(OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); + _visualsObserver = new CollectionDeepObserver>( + OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); Loaded += OnLoaded; Unloaded += OnUnloaded; @@ -85,6 +88,7 @@ public PolarChart() LiveCharts.CurrentSettings.GetProvider().GetDefaultPolarAxis() }); SetValue(SeriesProperty, new ObservableCollection()); + SetValue(VisualElementsProperty, new ObservableCollection>()); } #region dependency properties @@ -137,6 +141,22 @@ public PolarChart() chart._core.Update(); })); + /// + /// The visual elements property + /// + public static readonly DependencyProperty VisualElementsProperty = + DependencyProperty.Register( + nameof(VisualElements), typeof(IEnumerable>), typeof(PolarChart), new PropertyMetadata(null, + (DependencyObject o, DependencyPropertyChangedEventArgs args) => + { + var chart = (PolarChart)o; + var observer = chart._visualsObserver; + observer?.Dispose((IEnumerable>)args.OldValue); + observer?.Initialize((IEnumerable>)args.NewValue); + if (chart._core == null) return; + chart._core.Update(); + })); + /// /// The x axes property. /// @@ -482,6 +502,13 @@ public IEnumerable RadiusAxes set => SetValue(RadiusAxesProperty, value); } + /// + public IEnumerable> VisualElements + { + get => (IEnumerable>)GetValue(VisualElementsProperty); + set => SetValue(VisualElementsProperty, value); + } + /// public TimeSpan AnimationsSpeed { From 37bd21c8fe6e416585c723d64436b9d5af6ee9fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Mon, 5 Sep 2022 00:03:24 -0500 Subject: [PATCH 46/50] visual elements for xamarin --- .../CartesianChart.xaml.cs | 42 +++++++++++++--- .../PieChart.xaml.cs | 49 ++++++++++++++++--- .../PolarChart.xaml.cs | 40 ++++++++++++--- 3 files changed, 109 insertions(+), 22 deletions(-) diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp.Xamarin.Forms/CartesianChart.xaml.cs b/src/skiasharp/LiveChartsCore.SkiaSharp.Xamarin.Forms/CartesianChart.xaml.cs index cc53d8772..11e6fb3c4 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp.Xamarin.Forms/CartesianChart.xaml.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp.Xamarin.Forms/CartesianChart.xaml.cs @@ -40,7 +40,6 @@ using Xamarin.Essentials; using Xamarin.Forms; using Xamarin.Forms.Xaml; -using c = Xamarin.Forms.Color; namespace LiveChartsCore.SkiaSharpView.Xamarin.Forms; @@ -55,10 +54,11 @@ public partial class CartesianChart : ContentView, ICartesianChartView protected Chart? core; - private CollectionDeepObserver _seriesObserver; - private CollectionDeepObserver _xObserver; - private CollectionDeepObserver _yObserver; - private CollectionDeepObserver> _sectionsObserver; + private readonly CollectionDeepObserver _seriesObserver; + private readonly CollectionDeepObserver _xObserver; + private readonly CollectionDeepObserver _yObserver; + private readonly CollectionDeepObserver> _sectionsObserver; + private readonly CollectionDeepObserver> _visualsObserver; private Grid? _grid; private double _lastScale = 0; private DateTime _panLocketUntil; @@ -91,6 +91,8 @@ public CartesianChart() _yObserver = new CollectionDeepObserver(OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); _sectionsObserver = new CollectionDeepObserver>( OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); + _visualsObserver = new CollectionDeepObserver>( + OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); XAxes = new List() { @@ -101,6 +103,7 @@ public CartesianChart() LiveCharts.CurrentSettings.GetProvider().GetDefaultCartesianAxis() }; Series = new ObservableCollection(); + VisualElements = new ObservableCollection>(); canvas.SkCanvasView.EnableTouchEvents = true; canvas.SkCanvasView.Touch += OnSkCanvasTouched; @@ -191,6 +194,22 @@ public CartesianChart() chart.core.Update(); }); + /// + /// The visual elements property. + /// + public static readonly BindableProperty VisualElementsProperty = + BindableProperty.Create( + nameof(VisualElements), typeof(IEnumerable>), typeof(CartesianChart), new List>(), + BindingMode.Default, null, (BindableObject o, object oldValue, object newValue) => + { + var chart = (CartesianChart)o; + var observer = chart._visualsObserver; + observer?.Dispose((IEnumerable>)oldValue); + observer?.Initialize((IEnumerable>)newValue); + if (chart.core is null) return; + chart.core.Update(); + }); + /// /// The draw margin frame property. /// @@ -415,7 +434,7 @@ LvcColor IChartView.BackColor ? new LvcColor() : LvcColor.FromArgb( (byte)(b.Color.R * 255), (byte)(b.Color.G * 255), (byte)(b.Color.B * 255), (byte)(b.Color.A * 255)); - set => Background = new SolidColorBrush(new c(value.R / 255, value.G / 255, value.B / 255, value.A / 255)); + set => Background = new SolidColorBrush(new Color(value.R / 255, value.G / 255, value.B / 255, value.A / 255)); } CartesianChart ICartesianChartView.Core => core is null ? throw new Exception("core not found") : (CartesianChart)core; @@ -477,6 +496,13 @@ public IEnumerable> Sections set => SetValue(SectionsProperty, value); } + /// + public IEnumerable> VisualElements + { + get => (IEnumerable>)GetValue(VisualElementsProperty); + set => SetValue(VisualElementsProperty, value); + } + /// public DrawMarginFrame? DrawMarginFrame { @@ -758,8 +784,8 @@ LvcPoint IMobileChart.GetCanvasPosition() /// public void SetTooltipStyle(LvcColor background, LvcColor textColor) { - TooltipBackground = new c(background.R, background.G, background.B, background.A); - TooltipTextBrush = new c(textColor.R, textColor.G, textColor.B, textColor.A); + TooltipBackground = new Color(background.R, background.G, background.B, background.A); + TooltipTextBrush = new Color(textColor.R, textColor.G, textColor.B, textColor.A); } void IChartView.InvokeOnUIThread(Action action) diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp.Xamarin.Forms/PieChart.xaml.cs b/src/skiasharp/LiveChartsCore.SkiaSharp.Xamarin.Forms/PieChart.xaml.cs index 2e1fce041..8c675f309 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp.Xamarin.Forms/PieChart.xaml.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp.Xamarin.Forms/PieChart.xaml.cs @@ -38,7 +38,6 @@ using Xamarin.Essentials; using Xamarin.Forms; using Xamarin.Forms.Xaml; -using c = Xamarin.Forms.Color; namespace LiveChartsCore.SkiaSharpView.Xamarin.Forms; @@ -52,7 +51,8 @@ public partial class PieChart : ContentView, IPieChartView protected Chart? core; - private CollectionDeepObserver _seriesObserver; + private readonly CollectionDeepObserver _seriesObserver; + private readonly CollectionDeepObserver> _visualsObserver; private Grid? _grid; #endregion @@ -87,8 +87,20 @@ public PieChart() if (core is null || (sender is IStopNPC stop && !stop.IsNotifyingChanges)) return; core.Update(); }); + _visualsObserver = new CollectionDeepObserver>( + (object sender, NotifyCollectionChangedEventArgs e) => + { + if (core is null || (sender is IStopNPC stop && !stop.IsNotifyingChanges)) return; + core.Update(); + }, + (object sender, PropertyChangedEventArgs e) => + { + if (core is null || (sender is IStopNPC stop && !stop.IsNotifyingChanges)) return; + core.Update(); + }); Series = new ObservableCollection(); + VisualElements = new ObservableCollection>(); canvas.SkCanvasView.EnableTouchEvents = true; canvas.SkCanvasView.Touch += OnSkCanvasTouched; @@ -131,6 +143,22 @@ public PieChart() chart.core.Update(); }); + /// + /// The visual elements property. + /// + public static readonly BindableProperty VisualElementsProperty = + BindableProperty.Create( + nameof(VisualElements), typeof(IEnumerable>), typeof(PieChart), new List>(), + BindingMode.Default, null, (BindableObject o, object oldValue, object newValue) => + { + var chart = (PieChart)o; + var observer = chart._visualsObserver; + observer?.Dispose((IEnumerable>)oldValue); + observer?.Initialize((IEnumerable>)newValue); + if (chart.core is null) return; + chart.core.Update(); + }); + /// /// The initial rotation property /// @@ -215,7 +243,7 @@ public PieChart() /// public static readonly BindableProperty LegendTextBrushProperty = BindableProperty.Create( - nameof(LegendTextBrush), typeof(c), typeof(CartesianChart), + nameof(LegendTextBrush), typeof(Color), typeof(CartesianChart), new Color(35 / 255d, 35 / 255d, 35 / 255d), propertyChanged: OnBindablePropertyChanged); /// @@ -223,7 +251,7 @@ public PieChart() /// public static readonly BindableProperty LegendBackgroundProperty = BindableProperty.Create( - nameof(LegendBackground), typeof(c), typeof(CartesianChart), + nameof(LegendBackground), typeof(Color), typeof(CartesianChart), new Color(250 / 255d, 250 / 255d, 250 / 255d), propertyChanged: OnBindablePropertyChanged); /// @@ -343,7 +371,7 @@ LvcColor IChartView.BackColor ? new LvcColor() : LvcColor.FromArgb( (byte)(b.Color.A * 255), (byte)(b.Color.R * 255), (byte)(b.Color.G * 255), (byte)(b.Color.B * 255)); - set => Background = new SolidColorBrush(new c(value.R / 255, value.G / 255, value.B / 255, value.A / 255)); + set => Background = new SolidColorBrush(new Color(value.R / 255, value.G / 255, value.B / 255, value.A / 255)); } PieChart IPieChartView.Core => @@ -385,6 +413,13 @@ public IEnumerable Series set => SetValue(SeriesProperty, value); } + /// + public IEnumerable> VisualElements + { + get => (IEnumerable>)GetValue(VisualElementsProperty); + set => SetValue(VisualElementsProperty, value); + } + /// public double InitialRotation { @@ -651,8 +686,8 @@ LvcPoint IMobileChart.GetCanvasPosition() /// public void SetTooltipStyle(LvcColor background, LvcColor textColor) { - TooltipBackground = new c(background.R, background.G, background.B, background.A); - TooltipTextBrush = new c(textColor.R, textColor.G, textColor.B, textColor.A); + TooltipBackground = new Color(background.R, background.G, background.B, background.A); + TooltipTextBrush = new Color(textColor.R, textColor.G, textColor.B, textColor.A); } void IChartView.InvokeOnUIThread(Action action) diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp.Xamarin.Forms/PolarChart.xaml.cs b/src/skiasharp/LiveChartsCore.SkiaSharp.Xamarin.Forms/PolarChart.xaml.cs index 5581dbbfa..90e4d14c3 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp.Xamarin.Forms/PolarChart.xaml.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp.Xamarin.Forms/PolarChart.xaml.cs @@ -38,7 +38,6 @@ using Xamarin.Essentials; using Xamarin.Forms; using Xamarin.Forms.Xaml; -using c = Xamarin.Forms.Color; namespace LiveChartsCore.SkiaSharpView.Xamarin.Forms; @@ -53,9 +52,10 @@ public partial class PolarChart : ContentView, IPolarChartView protected Chart? core; - private CollectionDeepObserver _seriesObserver; - private CollectionDeepObserver _angleObserver; - private CollectionDeepObserver _radiusObserver; + private readonly CollectionDeepObserver _seriesObserver; + private readonly CollectionDeepObserver _angleObserver; + private readonly CollectionDeepObserver _radiusObserver; + private readonly CollectionDeepObserver> _visualsObserver; private Grid? _grid; #endregion @@ -82,6 +82,8 @@ public PolarChart() _seriesObserver = new CollectionDeepObserver(OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); _angleObserver = new CollectionDeepObserver(OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); _radiusObserver = new CollectionDeepObserver(OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); + _visualsObserver = new CollectionDeepObserver>( + OnDeepCollectionChanged, OnDeepCollectionPropertyChanged, true); AngleAxes = new List() { @@ -92,6 +94,7 @@ public PolarChart() LiveCharts.CurrentSettings.GetProvider().GetDefaultPolarAxis() }; Series = new ObservableCollection(); + VisualElements = new ObservableCollection>(); canvas.SkCanvasView.EnableTouchEvents = true; canvas.SkCanvasView.Touch += OnSkCanvasTouched; @@ -162,6 +165,22 @@ public PolarChart() chart.core.Update(); }); + /// + /// The visual elements property. + /// + public static readonly BindableProperty VisualElementsProperty = + BindableProperty.Create( + nameof(VisualElements), typeof(IEnumerable>), typeof(PolarChart), new List>(), + BindingMode.Default, null, (BindableObject o, object oldValue, object newValue) => + { + var chart = (PolarChart)o; + var observer = chart._visualsObserver; + observer?.Dispose((IEnumerable>)oldValue); + observer?.Initialize((IEnumerable>)newValue); + if (chart.core is null) return; + chart.core.Update(); + }); + /// /// The x axes property. /// @@ -387,7 +406,7 @@ LvcColor IChartView.BackColor ? new LvcColor() : LvcColor.FromArgb( (byte)(b.Color.R * 255), (byte)(b.Color.G * 255), (byte)(b.Color.B * 255), (byte)(b.Color.A * 255)); - set => Background = new SolidColorBrush(new c(value.R / 255, value.G / 255, value.B / 255, value.A / 255)); + set => Background = new SolidColorBrush(new Color(value.R / 255, value.G / 255, value.B / 255, value.A / 255)); } PolarChart IPolarChartView.Core @@ -457,6 +476,13 @@ public IEnumerable Series set => SetValue(SeriesProperty, value); } + /// + public IEnumerable> VisualElements + { + get => (IEnumerable>)GetValue(VisualElementsProperty); + set => SetValue(VisualElementsProperty, value); + } + /// public IEnumerable AngleAxes { @@ -725,8 +751,8 @@ LvcPoint IMobileChart.GetCanvasPosition() /// public void SetTooltipStyle(LvcColor background, LvcColor textColor) { - TooltipBackground = new c(background.R, background.G, background.B, background.A); - TooltipTextBrush = new c(textColor.R, textColor.G, textColor.B, textColor.A); + TooltipBackground = new Color(background.R, background.G, background.B, background.A); + TooltipTextBrush = new Color(textColor.R, textColor.G, textColor.B, textColor.A); } void IChartView.InvokeOnUIThread(Action action) From 288859f0a27948f42bd71c6e7973aea231c0da51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Mon, 5 Sep 2022 00:38:49 -0500 Subject: [PATCH 47/50] visual elements samples for all platforms --- samples/AvaloniaSample/AvaloniaSample.csproj | 3 + .../General/VisualElements/View.axaml | 15 +++++ .../General/VisualElements/View.axaml.cs | 17 ++++++ .../Pages/General/VisualElements.razor | 12 ++++ .../General/VisualElements/View.cs | 21 +++++++ .../General/VisualElements/View.xaml | 19 ++++++ .../General/VisualElements/View.xaml.cs | 10 ++++ samples/MauiSample/MauiSample.csproj | 6 ++ .../General/VisualElements/View.xaml | 22 +++++++ .../General/VisualElements/View.xaml.cs | 12 ++++ samples/UWPSample/UWPSample.csproj | 7 +++ .../General/Sections2/View.xaml | 2 +- .../General/VisualElements/View.xaml | 22 +++++++ .../General/VisualElements/View.xaml.cs | 11 ++++ .../UnoSample.Shared.projitems | 13 +++- .../UnoSample.Shared/UnoSample.Shared.shproj | 1 + .../General/VisualElements/View.xaml | 22 +++++++ .../General/VisualElements/View.xaml.cs | 11 ++++ .../UnoWinUISample.Shared.projitems | 16 ++++- .../General/VisualElements/View.Designer.cs | 46 ++++++++++++++ .../General/VisualElements/View.cs | 29 +++++++++ .../General/VisualElements/View.resx | 60 +++++++++++++++++++ samples/WinFormsSample/WinFormsSample.csproj | 3 + .../General/VisualElements/View.xaml | 20 +++++++ .../General/VisualElements/View.xaml.cs | 11 ++++ .../WinUISample/WinUISample.csproj | 4 ++ .../General/VisualElements/View.xaml | 16 +++++ .../General/VisualElements/View.xaml.cs | 13 ++++ .../XamarinSample/XamarinSample.csproj | 3 + .../CartesianChart.axaml.cs | 4 +- .../PieChart.axaml.cs | 4 +- .../PolarChart.axaml.cs | 2 +- 32 files changed, 448 insertions(+), 9 deletions(-) create mode 100644 samples/AvaloniaSample/General/VisualElements/View.axaml create mode 100644 samples/AvaloniaSample/General/VisualElements/View.axaml.cs create mode 100644 samples/BlazorSample/Pages/General/VisualElements.razor create mode 100644 samples/EtoFormsSample/General/VisualElements/View.cs create mode 100644 samples/MauiSample/General/VisualElements/View.xaml create mode 100644 samples/MauiSample/General/VisualElements/View.xaml.cs create mode 100644 samples/UWPSample/General/VisualElements/View.xaml create mode 100644 samples/UWPSample/General/VisualElements/View.xaml.cs create mode 100644 samples/UnoSample/UnoSample.Shared/LiveChartsSamples/General/VisualElements/View.xaml create mode 100644 samples/UnoSample/UnoSample.Shared/LiveChartsSamples/General/VisualElements/View.xaml.cs create mode 100644 samples/UnoWinUISample/UnoWinUISample/UnoWinUISample.Shared/LiveChartsSamples/General/VisualElements/View.xaml create mode 100644 samples/UnoWinUISample/UnoWinUISample/UnoWinUISample.Shared/LiveChartsSamples/General/VisualElements/View.xaml.cs create mode 100644 samples/WinFormsSample/General/VisualElements/View.Designer.cs create mode 100644 samples/WinFormsSample/General/VisualElements/View.cs create mode 100644 samples/WinFormsSample/General/VisualElements/View.resx create mode 100644 samples/WinUISample/WinUISample/General/VisualElements/View.xaml create mode 100644 samples/WinUISample/WinUISample/General/VisualElements/View.xaml.cs create mode 100644 samples/XamarinSample/XamarinSample/XamarinSample/General/VisualElements/View.xaml create mode 100644 samples/XamarinSample/XamarinSample/XamarinSample/General/VisualElements/View.xaml.cs diff --git a/samples/AvaloniaSample/AvaloniaSample.csproj b/samples/AvaloniaSample/AvaloniaSample.csproj index 29543f8a1..7e2afc6bc 100644 --- a/samples/AvaloniaSample/AvaloniaSample.csproj +++ b/samples/AvaloniaSample/AvaloniaSample.csproj @@ -118,6 +118,9 @@ %(Filename) + + %(Filename) + %(Filename) diff --git a/samples/AvaloniaSample/General/VisualElements/View.axaml b/samples/AvaloniaSample/General/VisualElements/View.axaml new file mode 100644 index 000000000..a02b83b96 --- /dev/null +++ b/samples/AvaloniaSample/General/VisualElements/View.axaml @@ -0,0 +1,15 @@ + + + + + + + + + diff --git a/samples/AvaloniaSample/General/VisualElements/View.axaml.cs b/samples/AvaloniaSample/General/VisualElements/View.axaml.cs new file mode 100644 index 000000000..6d3b64875 --- /dev/null +++ b/samples/AvaloniaSample/General/VisualElements/View.axaml.cs @@ -0,0 +1,17 @@ +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace AvaloniaSample.General.VisualElements; + +public class View : UserControl +{ + public View() + { + InitializeComponent(); + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } +} diff --git a/samples/BlazorSample/Pages/General/VisualElements.razor b/samples/BlazorSample/Pages/General/VisualElements.razor new file mode 100644 index 000000000..ac516582b --- /dev/null +++ b/samples/BlazorSample/Pages/General/VisualElements.razor @@ -0,0 +1,12 @@ +@page "/General/VisualElements" +@using LiveChartsCore.SkiaSharpView.Blazor +@using ViewModelsSamples.General.VisualElements + + + + +@code { + public ViewModel ViewModel { get; set; } = new(); +} diff --git a/samples/EtoFormsSample/General/VisualElements/View.cs b/samples/EtoFormsSample/General/VisualElements/View.cs new file mode 100644 index 000000000..87bfeb277 --- /dev/null +++ b/samples/EtoFormsSample/General/VisualElements/View.cs @@ -0,0 +1,21 @@ +using Eto.Forms; +using LiveChartsCore.SkiaSharpView.Eto; +using ViewModelsSamples.General.VisualElements; + +namespace EtoFormsSample.General.VisualElements; + +public class View : Panel +{ + public View() + { + var viewModel = new ViewModel(); + + var cartesianChart = new CartesianChart + { + Series = viewModel.Series, + VisualElements = viewModel.VisualElements, + }; + + Content = cartesianChart; + } +} diff --git a/samples/MauiSample/General/VisualElements/View.xaml b/samples/MauiSample/General/VisualElements/View.xaml new file mode 100644 index 000000000..cf19c1780 --- /dev/null +++ b/samples/MauiSample/General/VisualElements/View.xaml @@ -0,0 +1,19 @@ + + + + + + + + + + + + diff --git a/samples/MauiSample/General/VisualElements/View.xaml.cs b/samples/MauiSample/General/VisualElements/View.xaml.cs new file mode 100644 index 000000000..6908f34ff --- /dev/null +++ b/samples/MauiSample/General/VisualElements/View.xaml.cs @@ -0,0 +1,10 @@ +namespace MauiSample.General.VisualElements; + +[XamlCompilation(XamlCompilationOptions.Compile)] +public partial class View : ContentPage +{ + public View() + { + InitializeComponent(); + } +} diff --git a/samples/MauiSample/MauiSample.csproj b/samples/MauiSample/MauiSample.csproj index f209e36ef..ea5c8c7b7 100644 --- a/samples/MauiSample/MauiSample.csproj +++ b/samples/MauiSample/MauiSample.csproj @@ -51,6 +51,9 @@ + + %(Filename) + %(Filename) @@ -162,6 +165,9 @@ MSBuild:Compile + + MSBuild:Compile + MSBuild:Compile diff --git a/samples/UWPSample/General/VisualElements/View.xaml b/samples/UWPSample/General/VisualElements/View.xaml new file mode 100644 index 000000000..026728614 --- /dev/null +++ b/samples/UWPSample/General/VisualElements/View.xaml @@ -0,0 +1,22 @@ + + + + + + + + + + + + diff --git a/samples/UWPSample/General/VisualElements/View.xaml.cs b/samples/UWPSample/General/VisualElements/View.xaml.cs new file mode 100644 index 000000000..49e931815 --- /dev/null +++ b/samples/UWPSample/General/VisualElements/View.xaml.cs @@ -0,0 +1,12 @@ +using Windows.UI.Xaml.Controls; + +namespace UWPSample.General.VisualElements +{ + public sealed partial class View : UserControl + { + public View() + { + InitializeComponent(); + } + } +} diff --git a/samples/UWPSample/UWPSample.csproj b/samples/UWPSample/UWPSample.csproj index 7af746017..586f9bf62 100644 --- a/samples/UWPSample/UWPSample.csproj +++ b/samples/UWPSample/UWPSample.csproj @@ -223,6 +223,9 @@ View.xaml + + View.xaml + View.xaml @@ -546,6 +549,10 @@ MSBuild:Compile Designer + + MSBuild:Compile + Designer + MSBuild:Compile Designer diff --git a/samples/UnoSample/UnoSample.Shared/LiveChartsSamples/General/Sections2/View.xaml b/samples/UnoSample/UnoSample.Shared/LiveChartsSamples/General/Sections2/View.xaml index af4f6954b..1d48b10b0 100644 --- a/samples/UnoSample/UnoSample.Shared/LiveChartsSamples/General/Sections2/View.xaml +++ b/samples/UnoSample/UnoSample.Shared/LiveChartsSamples/General/Sections2/View.xaml @@ -13,6 +13,6 @@ + Sections="{Binding Sections}"> diff --git a/samples/UnoSample/UnoSample.Shared/LiveChartsSamples/General/VisualElements/View.xaml b/samples/UnoSample/UnoSample.Shared/LiveChartsSamples/General/VisualElements/View.xaml new file mode 100644 index 000000000..f19a122d8 --- /dev/null +++ b/samples/UnoSample/UnoSample.Shared/LiveChartsSamples/General/VisualElements/View.xaml @@ -0,0 +1,22 @@ + + + + + + + + + + + + diff --git a/samples/UnoSample/UnoSample.Shared/LiveChartsSamples/General/VisualElements/View.xaml.cs b/samples/UnoSample/UnoSample.Shared/LiveChartsSamples/General/VisualElements/View.xaml.cs new file mode 100644 index 000000000..979d66f63 --- /dev/null +++ b/samples/UnoSample/UnoSample.Shared/LiveChartsSamples/General/VisualElements/View.xaml.cs @@ -0,0 +1,11 @@ +using Windows.UI.Xaml.Controls; + +namespace UnoSample.General.VisualElements; + +public sealed partial class View : UserControl +{ + public View() + { + InitializeComponent(); + } +} diff --git a/samples/UnoSample/UnoSample.Shared/UnoSample.Shared.projitems b/samples/UnoSample/UnoSample.Shared/UnoSample.Shared.projitems index c0be98bbb..02ebb0541 100644 --- a/samples/UnoSample/UnoSample.Shared/UnoSample.Shared.projitems +++ b/samples/UnoSample/UnoSample.Shared/UnoSample.Shared.projitems @@ -123,6 +123,9 @@ View.xaml + + View.xaml + View.xaml @@ -674,7 +677,9 @@ Designer MSBuild:Compile - + + Designer + <_Globbed_Compile Include="$(MSBuildThisFileDirectory)**/*.xaml.cs" Exclude="@(Compile)"> %(Filename) @@ -684,4 +689,10 @@ <_Globbed_Content Include="$(MSBuildThisFileDirectory)Assets/**/*.*" Exclude="@(Content)" /> + + + Designer + MSBuild:Compile + + \ No newline at end of file diff --git a/samples/UnoSample/UnoSample.Shared/UnoSample.Shared.shproj b/samples/UnoSample/UnoSample.Shared/UnoSample.Shared.shproj index 75fff3f88..491347104 100644 --- a/samples/UnoSample/UnoSample.Shared/UnoSample.Shared.shproj +++ b/samples/UnoSample/UnoSample.Shared/UnoSample.Shared.shproj @@ -100,6 +100,7 @@ <_Globbed_Compile Remove="LiveChartsSamples\General\MultiThreading2\View.xaml.cs" /> <_Globbed_Compile Remove="LiveChartsSamples\General\MultiThreading\View.xaml.cs" /> <_Globbed_Compile Remove="LiveChartsSamples\General\NullPoints\View.xaml.cs" /> + <_Globbed_Compile Remove="LiveChartsSamples\General\Sections - Copy\View.xaml.cs" /> <_Globbed_Compile Remove="LiveChartsSamples\General\Sections2\View.xaml.cs" /> <_Globbed_Compile Remove="LiveChartsSamples\General\Sections\View.xaml.cs" /> <_Globbed_Compile Remove="LiveChartsSamples\General\TemplatedLegends\View.xaml.cs" /> diff --git a/samples/UnoWinUISample/UnoWinUISample/UnoWinUISample.Shared/LiveChartsSamples/General/VisualElements/View.xaml b/samples/UnoWinUISample/UnoWinUISample/UnoWinUISample.Shared/LiveChartsSamples/General/VisualElements/View.xaml new file mode 100644 index 000000000..e97aca2a0 --- /dev/null +++ b/samples/UnoWinUISample/UnoWinUISample/UnoWinUISample.Shared/LiveChartsSamples/General/VisualElements/View.xaml @@ -0,0 +1,22 @@ + + + + + + + + + + + + diff --git a/samples/UnoWinUISample/UnoWinUISample/UnoWinUISample.Shared/LiveChartsSamples/General/VisualElements/View.xaml.cs b/samples/UnoWinUISample/UnoWinUISample/UnoWinUISample.Shared/LiveChartsSamples/General/VisualElements/View.xaml.cs new file mode 100644 index 000000000..70fbc4805 --- /dev/null +++ b/samples/UnoWinUISample/UnoWinUISample/UnoWinUISample.Shared/LiveChartsSamples/General/VisualElements/View.xaml.cs @@ -0,0 +1,11 @@ +using Microsoft.UI.Xaml.Controls; + +namespace UnoWinUISample.General.VisualElements; + +public sealed partial class View : UserControl +{ + public View() + { + InitializeComponent(); + } +} diff --git a/samples/UnoWinUISample/UnoWinUISample/UnoWinUISample.Shared/UnoWinUISample.Shared.projitems b/samples/UnoWinUISample/UnoWinUISample/UnoWinUISample.Shared/UnoWinUISample.Shared.projitems index e13133f1d..58ea3f4b8 100644 --- a/samples/UnoWinUISample/UnoWinUISample/UnoWinUISample.Shared/UnoWinUISample.Shared.projitems +++ b/samples/UnoWinUISample/UnoWinUISample/UnoWinUISample.Shared/UnoWinUISample.Shared.projitems @@ -674,12 +674,12 @@ Designer MSBuild:Compile - + <_Globbed_Compile Include="$(MSBuildThisFileDirectory)**/*.xaml.cs" Exclude="@(Compile)"> %(Filename) <_Globbed_Compile Include="$(MSBuildThisFileDirectory)**/*.cs" Exclude="@(Compile);@(_Globbed_Compile)" /> - + <_Globbed_PRIResource Include="$(MSBuildThisFileDirectory)**/*.resw" Exclude="@(PRIResource)" /> <_Globbed_Content Include="$(MSBuildThisFileDirectory)Assets/**/*.*" Exclude="@(Content)" /> @@ -690,4 +690,16 @@ + + + View.xaml + + + + + WinUI + Designer + MSBuild:Compile + + \ No newline at end of file diff --git a/samples/WinFormsSample/General/VisualElements/View.Designer.cs b/samples/WinFormsSample/General/VisualElements/View.Designer.cs new file mode 100644 index 000000000..cd651000f --- /dev/null +++ b/samples/WinFormsSample/General/VisualElements/View.Designer.cs @@ -0,0 +1,46 @@ + +namespace WinFormsSample.General.VisualElements +{ + partial class View + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.SuspendLayout(); + // + // View + // + this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Name = "View"; + this.Size = new System.Drawing.Size(427, 375); + this.ResumeLayout(false); + + } + + #endregion + } +} diff --git a/samples/WinFormsSample/General/VisualElements/View.cs b/samples/WinFormsSample/General/VisualElements/View.cs new file mode 100644 index 000000000..039d2a38c --- /dev/null +++ b/samples/WinFormsSample/General/VisualElements/View.cs @@ -0,0 +1,29 @@ +using System.Windows.Forms; +using LiveChartsCore.SkiaSharpView.WinForms; +using ViewModelsSamples.General.VisualElements; + +namespace WinFormsSample.General.VisualElements; + +public partial class View : UserControl +{ + public View() + { + InitializeComponent(); + Size = new System.Drawing.Size(50, 50); + + var viewModel = new ViewModel(); + + var cartesianChart = new CartesianChart + { + Series = viewModel.Series, + VisualElements = viewModel.VisualElements, + + // out of livecharts properties... + Location = new System.Drawing.Point(0, 0), + Size = new System.Drawing.Size(50, 50), + Anchor = AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top | AnchorStyles.Bottom + }; + + Controls.Add(cartesianChart); + } +} diff --git a/samples/WinFormsSample/General/VisualElements/View.resx b/samples/WinFormsSample/General/VisualElements/View.resx new file mode 100644 index 000000000..f298a7be8 --- /dev/null +++ b/samples/WinFormsSample/General/VisualElements/View.resx @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/samples/WinFormsSample/WinFormsSample.csproj b/samples/WinFormsSample/WinFormsSample.csproj index 48348c405..1bb46cb55 100644 --- a/samples/WinFormsSample/WinFormsSample.csproj +++ b/samples/WinFormsSample/WinFormsSample.csproj @@ -111,6 +111,9 @@ UserControl + + UserControl + UserControl diff --git a/samples/WinUISample/WinUISample/General/VisualElements/View.xaml b/samples/WinUISample/WinUISample/General/VisualElements/View.xaml new file mode 100644 index 000000000..79df8e7c3 --- /dev/null +++ b/samples/WinUISample/WinUISample/General/VisualElements/View.xaml @@ -0,0 +1,20 @@ + + + + + + + + + + diff --git a/samples/WinUISample/WinUISample/General/VisualElements/View.xaml.cs b/samples/WinUISample/WinUISample/General/VisualElements/View.xaml.cs new file mode 100644 index 000000000..bb10350f4 --- /dev/null +++ b/samples/WinUISample/WinUISample/General/VisualElements/View.xaml.cs @@ -0,0 +1,11 @@ +using Microsoft.UI.Xaml.Controls; + +namespace WinUISample.General.VisualElements; + +public sealed partial class View : UserControl +{ + public View() + { + InitializeComponent(); + } +} diff --git a/samples/WinUISample/WinUISample/WinUISample.csproj b/samples/WinUISample/WinUISample/WinUISample.csproj index 552277b13..5877d2092 100644 --- a/samples/WinUISample/WinUISample/WinUISample.csproj +++ b/samples/WinUISample/WinUISample/WinUISample.csproj @@ -47,6 +47,7 @@ + @@ -237,6 +238,9 @@ $(DefaultXamlRuntime) + + $(DefaultXamlRuntime) + $(DefaultXamlRuntime) diff --git a/samples/XamarinSample/XamarinSample/XamarinSample/General/VisualElements/View.xaml b/samples/XamarinSample/XamarinSample/XamarinSample/General/VisualElements/View.xaml new file mode 100644 index 000000000..2fb9061c6 --- /dev/null +++ b/samples/XamarinSample/XamarinSample/XamarinSample/General/VisualElements/View.xaml @@ -0,0 +1,16 @@ + + + + + + + + + + diff --git a/samples/XamarinSample/XamarinSample/XamarinSample/General/VisualElements/View.xaml.cs b/samples/XamarinSample/XamarinSample/XamarinSample/General/VisualElements/View.xaml.cs new file mode 100644 index 000000000..38e28f2e7 --- /dev/null +++ b/samples/XamarinSample/XamarinSample/XamarinSample/General/VisualElements/View.xaml.cs @@ -0,0 +1,13 @@ +using Xamarin.Forms; +using Xamarin.Forms.Xaml; + +namespace XamarinSample.General.VisualElements; + +[XamlCompilation(XamlCompilationOptions.Compile)] +public partial class View : ContentPage +{ + public View() + { + InitializeComponent(); + } +} diff --git a/samples/XamarinSample/XamarinSample/XamarinSample/XamarinSample.csproj b/samples/XamarinSample/XamarinSample/XamarinSample/XamarinSample.csproj index 7949b2814..471dcb48e 100644 --- a/samples/XamarinSample/XamarinSample/XamarinSample/XamarinSample.csproj +++ b/samples/XamarinSample/XamarinSample/XamarinSample/XamarinSample.csproj @@ -128,6 +128,9 @@ %(Filename) + + %(Filename) + %(Filename) diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp.Avalonia/CartesianChart.axaml.cs b/src/skiasharp/LiveChartsCore.SkiaSharp.Avalonia/CartesianChart.axaml.cs index 4d8f65126..e6444db4a 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp.Avalonia/CartesianChart.axaml.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp.Avalonia/CartesianChart.axaml.cs @@ -163,11 +163,11 @@ public CartesianChart() nameof(Sections), Enumerable.Empty>(), inherits: true); /// - /// The sections property + /// The visual elements property /// public static readonly AvaloniaProperty>> VisualElementsProperty = AvaloniaProperty.Register>>( - nameof(Sections), Enumerable.Empty>(), inherits: true); + nameof(VisualElements), Enumerable.Empty>(), inherits: true); /// /// The draw margin frame property diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp.Avalonia/PieChart.axaml.cs b/src/skiasharp/LiveChartsCore.SkiaSharp.Avalonia/PieChart.axaml.cs index bac56987d..1516bc9d3 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp.Avalonia/PieChart.axaml.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp.Avalonia/PieChart.axaml.cs @@ -143,11 +143,11 @@ public PieChart() AvaloniaProperty.Register>(nameof(Series), new List(), inherits: true); /// - /// The sections property + /// The visual elements property /// public static readonly AvaloniaProperty>> VisualElementsProperty = AvaloniaProperty.Register>>( - nameof(Visual), Enumerable.Empty>(), inherits: true); + nameof(VisualElements), Enumerable.Empty>(), inherits: true); /// /// The initial rotation property diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp.Avalonia/PolarChart.axaml.cs b/src/skiasharp/LiveChartsCore.SkiaSharp.Avalonia/PolarChart.axaml.cs index 6cb388b61..54e2b0c18 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp.Avalonia/PolarChart.axaml.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp.Avalonia/PolarChart.axaml.cs @@ -133,7 +133,7 @@ public PolarChart() AvaloniaProperty.Register>(nameof(Series), Enumerable.Empty(), inherits: true); /// - /// The sections property + /// The visual elements property /// public static readonly AvaloniaProperty>> VisualElementsProperty = AvaloniaProperty.Register>>( From c5505f5e55e7ce4593332b12a8c124bc7e5a902a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Mon, 5 Sep 2022 00:51:35 -0500 Subject: [PATCH 48/50] update skia sharp to 2.88.1 --- .../LiveChartsCore.SkiaSharpView.WPF.csproj | 2 +- .../LiveChartsCore.SkiaSharpView.WinForms.csproj | 2 +- .../LiveChartsCore.SkiaSharpView.Xamarin.Forms.csproj | 4 ++-- .../LiveChartsCore.SkiaSharpView.csproj | 6 +++--- .../LiveChartsCore.SkiaSharpView.Blazor.csproj | 2 +- .../LiveChartsCore.SkiaSharpView.Maui.csproj | 2 +- .../LiveChartsCore.SkiaSharpView.Maui.nuspec | 10 +++++----- .../LiveChartsCore.SkiaSharpView.Uno.WinUI.csproj | 4 ++-- .../LiveChartsCore.SkiaSharpView.Uno.csproj | 2 +- .../LiveChartsCore.SkiaSharpView.WinUI.csproj | 2 +- .../LiveChartsCore.SkiaSharpView.WinUI.nuspec | 2 +- 11 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp.WPF/LiveChartsCore.SkiaSharpView.WPF.csproj b/src/skiasharp/LiveChartsCore.SkiaSharp.WPF/LiveChartsCore.SkiaSharpView.WPF.csproj index 41ce05dff..609ad318a 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp.WPF/LiveChartsCore.SkiaSharpView.WPF.csproj +++ b/src/skiasharp/LiveChartsCore.SkiaSharp.WPF/LiveChartsCore.SkiaSharpView.WPF.csproj @@ -23,7 +23,7 @@ - + diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp.WinForms/LiveChartsCore.SkiaSharpView.WinForms.csproj b/src/skiasharp/LiveChartsCore.SkiaSharp.WinForms/LiveChartsCore.SkiaSharpView.WinForms.csproj index 881289651..139d3d62d 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp.WinForms/LiveChartsCore.SkiaSharpView.WinForms.csproj +++ b/src/skiasharp/LiveChartsCore.SkiaSharp.WinForms/LiveChartsCore.SkiaSharpView.WinForms.csproj @@ -25,7 +25,7 @@ - + diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp.Xamarin.Forms/LiveChartsCore.SkiaSharpView.Xamarin.Forms.csproj b/src/skiasharp/LiveChartsCore.SkiaSharp.Xamarin.Forms/LiveChartsCore.SkiaSharpView.Xamarin.Forms.csproj index d1d8dcaf5..8d34e8082 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp.Xamarin.Forms/LiveChartsCore.SkiaSharpView.Xamarin.Forms.csproj +++ b/src/skiasharp/LiveChartsCore.SkiaSharp.Xamarin.Forms/LiveChartsCore.SkiaSharpView.Xamarin.Forms.csproj @@ -1,4 +1,4 @@ - + 10.0 @@ -22,7 +22,7 @@ - + diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/LiveChartsCore.SkiaSharpView.csproj b/src/skiasharp/LiveChartsCore.SkiaSharp/LiveChartsCore.SkiaSharpView.csproj index 568a5e3a7..d6fbca893 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/LiveChartsCore.SkiaSharpView.csproj +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/LiveChartsCore.SkiaSharpView.csproj @@ -1,4 +1,4 @@ - + enable @@ -37,8 +37,8 @@ - - + + diff --git a/src/skiasharp/LiveChartsCore.SkiaSharpView.Blazor/LiveChartsCore.SkiaSharpView.Blazor.csproj b/src/skiasharp/LiveChartsCore.SkiaSharpView.Blazor/LiveChartsCore.SkiaSharpView.Blazor.csproj index d905b09cc..af2173850 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharpView.Blazor/LiveChartsCore.SkiaSharpView.Blazor.csproj +++ b/src/skiasharp/LiveChartsCore.SkiaSharpView.Blazor/LiveChartsCore.SkiaSharpView.Blazor.csproj @@ -44,7 +44,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/src/skiasharp/LiveChartsCore.SkiaSharpView.Maui/LiveChartsCore.SkiaSharpView.Maui.csproj b/src/skiasharp/LiveChartsCore.SkiaSharpView.Maui/LiveChartsCore.SkiaSharpView.Maui.csproj index cbc3c64aa..46ffc620b 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharpView.Maui/LiveChartsCore.SkiaSharpView.Maui.csproj +++ b/src/skiasharp/LiveChartsCore.SkiaSharpView.Maui/LiveChartsCore.SkiaSharpView.Maui.csproj @@ -27,7 +27,7 @@ - + diff --git a/src/skiasharp/LiveChartsCore.SkiaSharpView.Maui/LiveChartsCore.SkiaSharpView.Maui.nuspec b/src/skiasharp/LiveChartsCore.SkiaSharpView.Maui/LiveChartsCore.SkiaSharpView.Maui.nuspec index bd3d42cdd..3c03ea0b4 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharpView.Maui/LiveChartsCore.SkiaSharpView.Maui.nuspec +++ b/src/skiasharp/LiveChartsCore.SkiaSharpView.Maui/LiveChartsCore.SkiaSharpView.Maui.nuspec @@ -16,23 +16,23 @@ - + - + - + - + - + diff --git a/src/skiasharp/LiveChartsCore.SkiaSharpView.Uno.WinUI/LiveChartsCore.SkiaSharpView.Uno.WinUI.csproj b/src/skiasharp/LiveChartsCore.SkiaSharpView.Uno.WinUI/LiveChartsCore.SkiaSharpView.Uno.WinUI.csproj index 1d482a424..7e1f9c57d 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharpView.Uno.WinUI/LiveChartsCore.SkiaSharpView.Uno.WinUI.csproj +++ b/src/skiasharp/LiveChartsCore.SkiaSharpView.Uno.WinUI/LiveChartsCore.SkiaSharpView.Uno.WinUI.csproj @@ -21,8 +21,8 @@ bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml - - + + diff --git a/src/skiasharp/LiveChartsCore.SkiaSharpView.Uno/LiveChartsCore.SkiaSharpView.Uno.csproj b/src/skiasharp/LiveChartsCore.SkiaSharpView.Uno/LiveChartsCore.SkiaSharpView.Uno.csproj index 2f030d9e1..2b0f5e3b7 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharpView.Uno/LiveChartsCore.SkiaSharpView.Uno.csproj +++ b/src/skiasharp/LiveChartsCore.SkiaSharpView.Uno/LiveChartsCore.SkiaSharpView.Uno.csproj @@ -35,7 +35,7 @@ - 2.88.1-preview.91 + 2.88.1 diff --git a/src/skiasharp/LiveChartsCore.SkiaSharpView.WinUI/LiveChartsCore.SkiaSharpView.WinUI.csproj b/src/skiasharp/LiveChartsCore.SkiaSharpView.WinUI/LiveChartsCore.SkiaSharpView.WinUI.csproj index 5ed96bdad..4f49fb0de 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharpView.WinUI/LiveChartsCore.SkiaSharpView.WinUI.csproj +++ b/src/skiasharp/LiveChartsCore.SkiaSharpView.WinUI/LiveChartsCore.SkiaSharpView.WinUI.csproj @@ -33,7 +33,7 @@ - + diff --git a/src/skiasharp/LiveChartsCore.SkiaSharpView.WinUI/LiveChartsCore.SkiaSharpView.WinUI.nuspec b/src/skiasharp/LiveChartsCore.SkiaSharpView.WinUI/LiveChartsCore.SkiaSharpView.WinUI.nuspec index 45235f870..074f8a149 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharpView.WinUI/LiveChartsCore.SkiaSharpView.WinUI.nuspec +++ b/src/skiasharp/LiveChartsCore.SkiaSharpView.WinUI/LiveChartsCore.SkiaSharpView.WinUI.nuspec @@ -19,7 +19,7 @@ - + From 7230ae911fd6573705d1d62faac5aa62940c23af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Mon, 5 Sep 2022 00:56:38 -0500 Subject: [PATCH 49/50] fixed memory leak in visual elements sample --- samples/ViewModelsSamples/General/VisualElements/ViewModel.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/samples/ViewModelsSamples/General/VisualElements/ViewModel.cs b/samples/ViewModelsSamples/General/VisualElements/ViewModel.cs index a82ae782c..f554087cd 100644 --- a/samples/ViewModelsSamples/General/VisualElements/ViewModel.cs +++ b/samples/ViewModelsSamples/General/VisualElements/ViewModel.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using CommunityToolkit.Mvvm.ComponentModel; using LiveChartsCore; using LiveChartsCore.Drawing; using LiveChartsCore.Kernel; @@ -11,6 +12,7 @@ namespace ViewModelsSamples.General.VisualElements; +[ObservableObject] public partial class ViewModel { public IEnumerable> VisualElements { get; set; } = new List> From 4bd98489f96c831e88f9a246573a8b71a7439ef9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Mon, 5 Sep 2022 00:58:49 -0500 Subject: [PATCH 50/50] beta 400 --- src/LiveChartsCore/LiveChartsCore.csproj | 2 +- .../LiveChartsCore.SkiaSharpView.Avalonia.csproj | 2 +- .../LiveChartsCore.SkiaSharpView.WPF.csproj | 4 ++-- .../LiveChartsCore.SkiaSharpView.WinForms.csproj | 2 +- ...LiveChartsCore.SkiaSharpView.Xamarin.Forms.csproj | 2 +- .../LiveChartsCore.SkiaSharpView.csproj | 4 ++-- .../LiveChartsCore.SkiaSharpView.Blazor.csproj | 2 +- .../LiveChartsCore.SkiaSharpView.Eto.csproj | 4 ++-- .../LiveChartsCore.SkiaSharpView.Maui.csproj | 4 ++-- .../LiveChartsCore.SkiaSharpView.Maui.nuspec | 12 ++++++------ .../LiveChartsCore.SkiaSharpView.Uno.WinUI.csproj | 2 +- .../LiveChartsCore.SkiaSharpView.Uno.csproj | 4 ++-- .../LiveChartsCore.SkiaSharpView.WinUI.csproj | 2 +- .../LiveChartsCore.SkiaSharpView.WinUI.nuspec | 6 +++--- 14 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/LiveChartsCore/LiveChartsCore.csproj b/src/LiveChartsCore/LiveChartsCore.csproj index 89fa556b0..2c85d9c0c 100644 --- a/src/LiveChartsCore/LiveChartsCore.csproj +++ b/src/LiveChartsCore/LiveChartsCore.csproj @@ -17,7 +17,7 @@ LiveChartsCore LiveChartsCore - 2.0.0-beta.361 + 2.0.0-beta.400 icon.png Simple, flexible, interactive and powerful data visualization for .Net, this is the core package probably you need another package also unless you are building your own backed. MIT diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp.Avalonia/LiveChartsCore.SkiaSharpView.Avalonia.csproj b/src/skiasharp/LiveChartsCore.SkiaSharp.Avalonia/LiveChartsCore.SkiaSharpView.Avalonia.csproj index 66efb3895..faedf3156 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp.Avalonia/LiveChartsCore.SkiaSharpView.Avalonia.csproj +++ b/src/skiasharp/LiveChartsCore.SkiaSharp.Avalonia/LiveChartsCore.SkiaSharpView.Avalonia.csproj @@ -6,7 +6,7 @@ netcoreapp2.0;netstandard2.0;net462; LiveChartsCore.SkiaSharpView.Avalonia LiveChartsCore.SkiaSharpView.Avalonia - 2.0.0-beta.361 + 2.0.0-beta.400 icon.png Simple, flexible, interactive and powerful data visualization for AvaloniaUI. MIT diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp.WPF/LiveChartsCore.SkiaSharpView.WPF.csproj b/src/skiasharp/LiveChartsCore.SkiaSharp.WPF/LiveChartsCore.SkiaSharpView.WPF.csproj index 609ad318a..1a9c29352 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp.WPF/LiveChartsCore.SkiaSharpView.WPF.csproj +++ b/src/skiasharp/LiveChartsCore.SkiaSharp.WPF/LiveChartsCore.SkiaSharpView.WPF.csproj @@ -1,4 +1,4 @@ - + enable @@ -7,7 +7,7 @@ net462;netcoreapp3.1 LiveChartsCore.SkiaSharpView.WPF LiveChartsCore.SkiaSharpView.WPF - 2.0.0-beta.361 + 2.0.0-beta.400 icon.png Simple, flexible, interactive and powerful data visualization for WPF. MIT diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp.WinForms/LiveChartsCore.SkiaSharpView.WinForms.csproj b/src/skiasharp/LiveChartsCore.SkiaSharp.WinForms/LiveChartsCore.SkiaSharpView.WinForms.csproj index 139d3d62d..e3f890092 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp.WinForms/LiveChartsCore.SkiaSharpView.WinForms.csproj +++ b/src/skiasharp/LiveChartsCore.SkiaSharp.WinForms/LiveChartsCore.SkiaSharpView.WinForms.csproj @@ -9,7 +9,7 @@ net462;netcoreapp3.1 LiveChartsCore.SkiaSharpView.WinForms LiveChartsCore.SkiaSharpView.WinForms - 2.0.0-beta.361 + 2.0.0-beta.400 icon.png Simple, flexible, interactive and powerful data visualization for WindowsForms. MIT diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp.Xamarin.Forms/LiveChartsCore.SkiaSharpView.Xamarin.Forms.csproj b/src/skiasharp/LiveChartsCore.SkiaSharp.Xamarin.Forms/LiveChartsCore.SkiaSharpView.Xamarin.Forms.csproj index 8d34e8082..22357b7ff 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp.Xamarin.Forms/LiveChartsCore.SkiaSharpView.Xamarin.Forms.csproj +++ b/src/skiasharp/LiveChartsCore.SkiaSharp.Xamarin.Forms/LiveChartsCore.SkiaSharpView.Xamarin.Forms.csproj @@ -6,7 +6,7 @@ netstandard2.0; LiveChartsCore.SkiaSharpView.XamarinForms LiveChartsCore.SkiaSharpView.XamarinForms - 2.0.0-beta.361 + 2.0.0-beta.400 icon.png Simple, flexible, interactive and powerful data visualization for XamarinForms. MIT diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/LiveChartsCore.SkiaSharpView.csproj b/src/skiasharp/LiveChartsCore.SkiaSharp/LiveChartsCore.SkiaSharpView.csproj index d6fbca893..103ef9992 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/LiveChartsCore.SkiaSharpView.csproj +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/LiveChartsCore.SkiaSharpView.csproj @@ -1,4 +1,4 @@ - + enable @@ -17,7 +17,7 @@ LiveChartsCore.SkiaSharpView LiveChartsCore.SkiaSharpView - 2.0.0-beta.361 + 2.0.0-beta.400 icon.png Simple, flexible, interactive and powerful data visualization for .Net, this package contains the SkiaSharp backend. MIT diff --git a/src/skiasharp/LiveChartsCore.SkiaSharpView.Blazor/LiveChartsCore.SkiaSharpView.Blazor.csproj b/src/skiasharp/LiveChartsCore.SkiaSharpView.Blazor/LiveChartsCore.SkiaSharpView.Blazor.csproj index af2173850..2c4d63270 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharpView.Blazor/LiveChartsCore.SkiaSharpView.Blazor.csproj +++ b/src/skiasharp/LiveChartsCore.SkiaSharpView.Blazor/LiveChartsCore.SkiaSharpView.Blazor.csproj @@ -17,7 +17,7 @@ net6.0 enable enable - 2.0.0-beta.361 + 2.0.0-beta.400 icon.png Simple, flexible, interactive and powerful data visualization for Blazor. MIT diff --git a/src/skiasharp/LiveChartsCore.SkiaSharpView.Eto/LiveChartsCore.SkiaSharpView.Eto.csproj b/src/skiasharp/LiveChartsCore.SkiaSharpView.Eto/LiveChartsCore.SkiaSharpView.Eto.csproj index 6ae6fa6e0..85ca7aa66 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharpView.Eto/LiveChartsCore.SkiaSharpView.Eto.csproj +++ b/src/skiasharp/LiveChartsCore.SkiaSharpView.Eto/LiveChartsCore.SkiaSharpView.Eto.csproj @@ -1,4 +1,4 @@ - + Library @@ -7,7 +7,7 @@ netstandard2.0 LiveChartsCore.SkiaSharpView.Eto LiveChartsCore.SkiaSharpView.Eto - 2.0.0-beta.361 + 2.0.0-beta.400 icon.png Simple, flexible, interactive and powerful data visualization for Eto.Forms. MIT diff --git a/src/skiasharp/LiveChartsCore.SkiaSharpView.Maui/LiveChartsCore.SkiaSharpView.Maui.csproj b/src/skiasharp/LiveChartsCore.SkiaSharpView.Maui/LiveChartsCore.SkiaSharpView.Maui.csproj index 46ffc620b..e1544635b 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharpView.Maui/LiveChartsCore.SkiaSharpView.Maui.csproj +++ b/src/skiasharp/LiveChartsCore.SkiaSharpView.Maui/LiveChartsCore.SkiaSharpView.Maui.csproj @@ -1,4 +1,4 @@ - + net6.0;net6.0-android;net6.0-ios;net6.0-maccatalyst @@ -14,7 +14,7 @@ 10.0.17763.0 10.0.17763.0 - 2.0.0-beta.361 + 2.0.0-beta.400 icon.png Simple, flexible, interactive and powerful data visualization for Maui. MIT diff --git a/src/skiasharp/LiveChartsCore.SkiaSharpView.Maui/LiveChartsCore.SkiaSharpView.Maui.nuspec b/src/skiasharp/LiveChartsCore.SkiaSharpView.Maui/LiveChartsCore.SkiaSharpView.Maui.nuspec index 3c03ea0b4..4a6542e2b 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharpView.Maui/LiveChartsCore.SkiaSharpView.Maui.nuspec +++ b/src/skiasharp/LiveChartsCore.SkiaSharpView.Maui/LiveChartsCore.SkiaSharpView.Maui.nuspec @@ -2,7 +2,7 @@ LiveChartsCore.SkiaSharpView.Maui - 2.0.0-beta.361 + 2.0.0-beta.400 LiveChartsCore.SkiaSharpView.Maui BetoRodriguez true @@ -17,23 +17,23 @@ - + - + - + - + - + diff --git a/src/skiasharp/LiveChartsCore.SkiaSharpView.Uno.WinUI/LiveChartsCore.SkiaSharpView.Uno.WinUI.csproj b/src/skiasharp/LiveChartsCore.SkiaSharpView.Uno.WinUI/LiveChartsCore.SkiaSharpView.Uno.WinUI.csproj index 7e1f9c57d..e867b2e0a 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharpView.Uno.WinUI/LiveChartsCore.SkiaSharpView.Uno.WinUI.csproj +++ b/src/skiasharp/LiveChartsCore.SkiaSharpView.Uno.WinUI/LiveChartsCore.SkiaSharpView.Uno.WinUI.csproj @@ -6,7 +6,7 @@ enable 10.0 - 2.0.0-beta.361 + 2.0.0-beta.400 icon.png Simple, flexible, interactive and powerful data visualization for Uno.WinUI. MIT diff --git a/src/skiasharp/LiveChartsCore.SkiaSharpView.Uno/LiveChartsCore.SkiaSharpView.Uno.csproj b/src/skiasharp/LiveChartsCore.SkiaSharpView.Uno/LiveChartsCore.SkiaSharpView.Uno.csproj index 2b0f5e3b7..c8b48134d 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharpView.Uno/LiveChartsCore.SkiaSharpView.Uno.csproj +++ b/src/skiasharp/LiveChartsCore.SkiaSharpView.Uno/LiveChartsCore.SkiaSharpView.Uno.csproj @@ -1,4 +1,4 @@ - + - - + +