From 0ebf61e14221d2249c1f032dbe82b3111c51c678 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Mon, 24 Jul 2023 17:48:54 -0600 Subject: [PATCH 01/54] add svg poitns support --- .../General/TemplatedLegends/CustomLegend.cs | 2 +- .../General/VisualElements/ViewModel.cs | 2 +- .../Lines/Custom/ViewModel.cs | 54 +++--- .../StepLines/Custom/ViewModel.cs | 33 +--- src/LiveChartsCore/BarSeries.cs | 4 +- src/LiveChartsCore/Drawing/ISvgPath.cs | 32 ++++ src/LiveChartsCore/Drawing/SVGPoints.cs | 132 +++++++++++++++ src/LiveChartsCore/FinancialSeries.cs | 4 +- src/LiveChartsCore/HeatSeries.cs | 4 +- src/LiveChartsCore/ISeries.cs | 7 +- src/LiveChartsCore/Kernel/Drawing/Sketch.cs | 20 ++- src/LiveChartsCore/Kernel/Extensions.cs | 12 ++ src/LiveChartsCore/Kernel/SeriesProperties.cs | 7 +- src/LiveChartsCore/LineSeries.cs | 11 +- src/LiveChartsCore/PieSeries.cs | 4 +- src/LiveChartsCore/PolarLineSeries.cs | 4 +- src/LiveChartsCore/ScatterSeries.cs | 4 +- src/LiveChartsCore/Series.cs | 32 +++- src/LiveChartsCore/StepLineSeries.cs | 4 +- .../Drawing/Geometries/SVGPathGeometry.cs | 8 +- .../LiveChartsCore.SkiaSharp/SVGPoints.cs | 157 ------------------ .../VisualElementsExtensions.cs | 6 + 22 files changed, 292 insertions(+), 251 deletions(-) create mode 100644 src/LiveChartsCore/Drawing/ISvgPath.cs create mode 100644 src/LiveChartsCore/Drawing/SVGPoints.cs delete mode 100644 src/skiasharp/LiveChartsCore.SkiaSharp/SVGPoints.cs diff --git a/samples/ViewModelsSamples/General/TemplatedLegends/CustomLegend.cs b/samples/ViewModelsSamples/General/TemplatedLegends/CustomLegend.cs index 3cbe05019..d18cfe029 100644 --- a/samples/ViewModelsSamples/General/TemplatedLegends/CustomLegend.cs +++ b/samples/ViewModelsSamples/General/TemplatedLegends/CustomLegend.cs @@ -61,7 +61,7 @@ public LvcSize Measure(Chart chart) { new SVGVisual { - Path = SVGPoints.Star, // or define your own svg path: SKPath.ParseSvgPathData(...) + Path = SKPath.ParseSvgPathData(SVGPoints.Star), Width = 25, Height = 25, Fill = new SolidColorPaint(theme.GetSeriesColor(series).AsSKColor()) {ZIndex = s_zIndex + 1 } diff --git a/samples/ViewModelsSamples/General/VisualElements/ViewModel.cs b/samples/ViewModelsSamples/General/VisualElements/ViewModel.cs index e5a373b9c..f67d54724 100644 --- a/samples/ViewModelsSamples/General/VisualElements/ViewModel.cs +++ b/samples/ViewModelsSamples/General/VisualElements/ViewModel.cs @@ -56,7 +56,7 @@ public partial class ViewModel : ObservableObject }, new SVGVisual { - Path = SVGPoints.Star, + Path = SKPath.ParseSvgPathData(SVGPoints.Star), X = 80, Y = 80, LocationUnit = MeasureUnit.Pixels, diff --git a/samples/ViewModelsSamples/Lines/Custom/ViewModel.cs b/samples/ViewModelsSamples/Lines/Custom/ViewModel.cs index 09299f413..6f8dd4173 100644 --- a/samples/ViewModelsSamples/Lines/Custom/ViewModel.cs +++ b/samples/ViewModelsSamples/Lines/Custom/ViewModel.cs @@ -1,7 +1,6 @@ using CommunityToolkit.Mvvm.ComponentModel; using LiveChartsCore; -using LiveChartsCore.Kernel; -using LiveChartsCore.Kernel.Sketches; +using LiveChartsCore.Drawing; using LiveChartsCore.SkiaSharpView; using LiveChartsCore.SkiaSharpView.Drawing.Geometries; using LiveChartsCore.SkiaSharpView.Painting; @@ -31,46 +30,39 @@ public ViewModel() Fill = null }, - // you can also define your own SVG geometry - // MyGeometry class let us change the Path at runtime - // Click on the on any point to change the path. - // You can find the MyGeometry.cs file below - new LineSeries + // You can also use a SVG path data to draw the geometry + new LineSeries { Values = new double[] { -2, 2, 1, 3, -1, 4, 3 }, - Stroke = new SolidColorPaint(SKColors.DarkOliveGreen, 3), Fill = null, + GeometrySvg = SVGPoints.Star, GeometryStroke = new SolidColorPaint(SKColors.DarkOliveGreen, 3), GeometryFill = new SolidColorPaint(SKColors.White), GeometrySize = 35 - } - }; - - // We can change the MyGeometry path at runtime - // the SVGPoints class contains many predefined paths - MyGeometry.SelectedPath = SVGPoints.Gem; - - var variableGeometrySeries = (LineSeries)Series[2]; + }, - // We toggle the geometry path on click - variableGeometrySeries.ChartPointPointerDown += - (IChartView chart, ChartPoint? point) => + new LineSeries { - MyGeometry.SelectedPath = MyGeometry.SelectedPath == SVGPoints.Gem - ? SVGPoints.Star - : SVGPoints.Gem; + Values = new double[] { 3, 5, 2, 4, 3, 2, 1 }, + Stroke = new SolidColorPaint(SKColors.DarkOliveGreen, 3), + Fill = null, + GeometrySvg = SVGPoints.Pin, + GeometryStroke = new SolidColorPaint(SKColors.DarkOliveGreen, 3), + GeometryFill = new SolidColorPaint(SKColors.White), + GeometrySize = 35 + }, + }; - // call chart update to refresh the chart - chart.CoreChart.Update(); - }; + var s = (LineSeries)Series[2]; - // You can also build your own path. - // MyGeometry.SelectedPath = SKPath.ParseSvgPathData( - // "M20.05 17.65C20.8054 17.0834 21.25 16.1943 21.25 15.25V4.25C21.25 " + - // "2.59315 19.9069 1.25 18.25 1.25H6.25C4.59315 1.25 3.25 2.59315 3.25 " + - // "4.25V15.25C3.25 16.1943 3.69458 17.0834 4.45 17.65L10.45 22.15C11.5167 " + - // "22.95 12.9833 22.95 14.05 22.15L20.05 17.65Z"); + s.ChartPointPointerDown += (chart, point) => + { + if (point is null) return; + // you can change the svg at runtime + point.Context.Series.GeometrySvg = + s.GeometrySvg == SVGPoints.Star ? SVGPoints.Gem : SVGPoints.Star; + }; } public ISeries[] Series { get; set; } diff --git a/samples/ViewModelsSamples/StepLines/Custom/ViewModel.cs b/samples/ViewModelsSamples/StepLines/Custom/ViewModel.cs index cc569bc83..8f026e6e7 100644 --- a/samples/ViewModelsSamples/StepLines/Custom/ViewModel.cs +++ b/samples/ViewModelsSamples/StepLines/Custom/ViewModel.cs @@ -1,7 +1,5 @@ using CommunityToolkit.Mvvm.ComponentModel; using LiveChartsCore; -using LiveChartsCore.Kernel; -using LiveChartsCore.Kernel.Sketches; using LiveChartsCore.SkiaSharpView; using LiveChartsCore.SkiaSharpView.Drawing.Geometries; using LiveChartsCore.SkiaSharpView.Painting; @@ -31,11 +29,7 @@ public ViewModel() Fill = null }, - // you can also define your own SVG geometry - // MyGeometry class let us change the Path at runtime - // Click on the on any point to change the path. - // You can find the MyGeometry.cs file below - new StepLineSeries + new StepLineSeries { Values = new double[] { -2, 2, 1, 3, -1, 4, 3 }, @@ -46,31 +40,6 @@ public ViewModel() GeometrySize = 35 } }; - - // We can change the MyGeometry path at runtime - // the SVGPoints class contains many predefined paths - MyGeometry.SelectedPath = SVGPoints.Gem; - - var variableGeometrySeries = (StepLineSeries)Series[2]; - - // We toggle the geometry path on click - variableGeometrySeries.ChartPointPointerDown += - (IChartView chart, ChartPoint? point) => - { - MyGeometry.SelectedPath = MyGeometry.SelectedPath == SVGPoints.Gem - ? SVGPoints.Star - : SVGPoints.Gem; - - // call chart update to refresh the chart - chart.CoreChart.Update(); - }; - - // You can also build your own path. - // MyGeometry.SelectedPath = SKPath.ParseSvgPathData( - // "M20.05 17.65C20.8054 17.0834 21.25 16.1943 21.25 15.25V4.25C21.25 " + - // "2.59315 19.9069 1.25 18.25 1.25H6.25C4.59315 1.25 3.25 2.59315 3.25 " + - // "4.25V15.25C3.25 16.1943 3.69458 17.0834 4.45 17.65L10.45 22.15C11.5167 " + - // "22.95 12.9833 22.95 14.05 22.15L20.05 17.65Z"); } public ISeries[] Series { get; set; } diff --git a/src/LiveChartsCore/BarSeries.cs b/src/LiveChartsCore/BarSeries.cs index 8b7ba43d2..332b83f6b 100644 --- a/src/LiveChartsCore/BarSeries.cs +++ b/src/LiveChartsCore/BarSeries.cs @@ -86,10 +86,8 @@ public override Sketch GetMiniaturesSketch() if (Fill is not null) schedules.Add(BuildMiniatureSchedule(Fill, new TVisual())); if (Stroke is not null) schedules.Add(BuildMiniatureSchedule(Stroke, new TVisual())); - return new Sketch() + return new Sketch(MiniatureShapeSize, MiniatureShapeSize, GeometrySvg) { - Height = MiniatureShapeSize, - Width = MiniatureShapeSize, PaintSchedules = schedules }; } diff --git a/src/LiveChartsCore/Drawing/ISvgPath.cs b/src/LiveChartsCore/Drawing/ISvgPath.cs new file mode 100644 index 000000000..b25c94da6 --- /dev/null +++ b/src/LiveChartsCore/Drawing/ISvgPath.cs @@ -0,0 +1,32 @@ +// 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.Drawing; + +/// +/// Defines a geometry that is built using from a svg path. +/// +public interface ISvgPath : ISizedGeometry + where TDrawingContext : DrawingContext +{ + void OnPathChanged(string path); +} diff --git a/src/LiveChartsCore/Drawing/SVGPoints.cs b/src/LiveChartsCore/Drawing/SVGPoints.cs new file mode 100644 index 000000000..40c1c08e0 --- /dev/null +++ b/src/LiveChartsCore/Drawing/SVGPoints.cs @@ -0,0 +1,132 @@ +// 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.Drawing; + +/// +/// A collections of SVG paths. +/// +public static class SVGPoints +{ + // icons from https://www.svgrepo.com/ + + /// + /// A diamond. + /// + public static string Diamond => + "M7.92950166,15.644 L3.34050166,8.796 C2.88750166,8.342 2.88650166,7.608 3.33750166,7.155 " + + "L7.90350166,0.323 C8.35450166,-0.13 9.08950166,-0.128 9.54550166,0.325 L14.0865017,7.175 " + + "C14.5405017,7.628 14.5415017,8.363 14.0895017,8.816 L9.57150166,15.646 C9.57150166,15.646 " + + "8.38450166,16.097 7.92950166,15.644 Z"; + + /// + /// A gem. + /// + public static string Gem => + "M11.7831 0H3.21691L0.0712554 5.24275C-0.0349835 5.41982 -0.0214476 5.64398 0.105326 5.80697L7.10533 " + + "14.807C7.20005 14.9288 7.34571 15 7.5 15C7.6543 15 7.79995 14.9288 7.89468 14.807L14.8947 " + + "5.80697C15.0215 5.64398 15.035 5.41982 14.9287 5.24275L11.7831 0Z"; + + /// + /// A star. + /// + public static string Star => + "M11.0137 2.76683C11.379 1.89022 12.6208 1.89022 12.9861 2.76683L14.9102 7.38462C15.0654 " + + "7.75726 15.4295 8 15.8332 8H20.893C21.8234 8 22.2893 9.12483 21.6314 9.78268L17.5391 13.875C17.2823 " + + "14.1318 17.185 14.5076 17.2847 14.8568L18.9076 20.5369C19.1816 21.496 18.1122 22.2767 17.2822 " + + "21.7234L12.5546 18.5716C12.2187 18.3477 11.7811 18.3477 11.4452 18.5717L6.72544 21.7182C5.89284 " + + "22.2732 4.81988 21.49 5.09479 20.5279L6.71509 14.8568C6.81486 14.5076 6.71747 14.1318 6.46068 " + + "13.875L2.38859 9.8029C1.72328 9.13758 2.19448 8 3.13538 8H8.16658C8.57028 8 8.93438 7.75726 9.08965 " + + "7.38462L11.0137 2.76683Z"; + + /// + /// A heart. + /// + public static string Heart => + "M5.36129 3.46995C6.03579 3.16081 6.76287 3 7.50002 3C8.23718 3 8.96425 3.16081 9.63875 3.46995C10.3129 " + + "3.77893 10.9185 4.22861 11.4239 4.78788C11.7322 5.12902 12.2678 5.12902 12.5761 4.78788C13.5979 3.65726 " + + "15.0068 3.00001 16.5 3.00001C17.9932 3.00001 19.4021 3.65726 20.4239 4.78788C21.4427 5.91515 22 7.42425 " + + "22 8.9792C22 10.5342 21.4427 12.0433 20.4239 13.1705L14.2257 20.0287C13.0346 21.3467 10.9654 21.3467 9.77429 " + + "20.0287L3.57613 13.1705C3.07086 12.6115 2.67474 11.9531 2.40602 11.2353C2.13731 10.5175 2 9.75113 2 8.9792C2 " + + "8.20728 2.13731 7.44094 2.40602 6.72315C2.67474 6.00531 3.07086 5.34694 3.57613 4.78788C4.08157 4.22861 " + + "4.68716 3.77893 5.36129 3.46995Z"; + + /// + /// A pin. + /// + public static string Pin => + "M174,5248.219 C172.895,5248.219 172,5247.324 172,5246.219 C172,5245.114 172.895,5244.219 174,5244.219 " + + "C175.105,5244.219 176,5245.114 176,5246.219 C176,5247.324 175.105,5248.219 174,5248.219 M174,5239 " + + "C170.134,5239 167,5242.134 167,5246 C167,5249.866 174,5259 174,5259 C174,5259 181,5249.866 181,5246 " + + "C181,5242.134 177.866,5239 174,5239"; + + /// + /// A triangle. + /// + public static string Triangle => + "M246.312928,5.62892705 C252.927596,9.40873724 258.409564,14.8907053 262.189374,21.5053731 " + + "L444.667042,340.84129 C456.358134,361.300701 449.250007,387.363834 428.790595,399.054926 " + + "C422.34376,402.738832 415.04715,404.676552 407.622001,404.676552 L42.6666667,404.676552 " + + "C19.1025173,404.676552 7.10542736e-15,385.574034 7.10542736e-15,362.009885 C7.10542736e-15,354.584736 " + + "1.93772021,347.288125 5.62162594,340.84129 L188.099293,21.5053731 C199.790385,1.04596203 " + + "225.853517,-6.06216498 246.312928,5.62892705 Z"; + + /// + /// A square. + /// + public static string Square => + "M4.281 3h16.437A1.281 1.281 0 0 1 22 4.281v16.437A1.282 1.282 0 0 1 20.718 22H4.282A1.282 1.282 0 0 1 3 " + + "20.718V4.281A1.281 1.281 0 0 1 4.281 3z"; + + /// + /// A circle. + /// + public static string Circle => + "M2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22C6.47715 22 2 17.5228 " + + "2 12Z"; + + /// + /// A pentagon. + /// + public static string Pentagon => + "M10.1259 2.21864C11.2216 1.34212 12.7784 1.34212 13.8741 2.21864L21.5041 8.32262C22.5088 9.12637 22.8891 " + + "10.4813 22.4494 11.6905L19.4185 20.0252C18.9874 21.2108 17.8607 22 16.5992 22H7.40087C6.13935 22 5.01261 " + + "21.2108 4.58149 20.0252L1.55067 11.6905C1.11097 10.4813 1.49127 9.12637 2.49596 8.32262L10.1259 2.21864Z"; + + /// + /// A cross mark. + /// + public static string Cross => + "M12,2A10,10,0,1,0,22,12,10,10,0,0,0,12,2Zm3.71,12.29a1,1,0,0,1,0,1.42,1,1,0,0,1-1.42,0L12,13.42,9.71,15.71" + + "a1,1,0,0,1-1.42,0,1,1,0,0,1,0-1.42L10.58,12,8.29,9.71A1,1,0,0,1,9.71,8.29L12,10.58l2.29-2.29" + + "a1,1,0,0,1,1.42,1.42L13.42,12Z"; + + /// + /// A check mark. + /// + public static string Check => + "M2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22C6.47715 22 2 17.5228 " + + "2 12ZM15.7071 9.29289C16.0976 9.68342 16.0976 10.3166 15.7071 10.7071L12.0243 14.3899C11.4586 14.9556 " + + "10.5414 14.9556 9.97568 14.3899L8.29289 12.7071C7.90237 12.3166 7.90237 11.6834 8.29289 11.2929C8.68342 " + + "10.9024 9.31658 10.9024 9.70711 11.2929L11 12.5858L14.2929 9.29289C14.6834 8.90237 15.3166 8.90237 15.7071 " + + "9.29289Z"; +} diff --git a/src/LiveChartsCore/FinancialSeries.cs b/src/LiveChartsCore/FinancialSeries.cs index 70e143c9d..4eaad335d 100644 --- a/src/LiveChartsCore/FinancialSeries.cs +++ b/src/LiveChartsCore/FinancialSeries.cs @@ -501,10 +501,8 @@ public override Sketch GetMiniaturesSketch() if (UpStroke is not null) schedules.Add(BuildMiniatureSchedule(UpStroke, new TMiniatureGeometry())); - return new Sketch() + return new Sketch(MiniatureShapeSize, MiniatureShapeSize, GeometrySvg) { - Height = MiniatureShapeSize, - Width = MiniatureShapeSize, PaintSchedules = schedules }; } diff --git a/src/LiveChartsCore/HeatSeries.cs b/src/LiveChartsCore/HeatSeries.cs index bff34afb2..577e15c62 100644 --- a/src/LiveChartsCore/HeatSeries.cs +++ b/src/LiveChartsCore/HeatSeries.cs @@ -327,10 +327,8 @@ public override Sketch GetMiniaturesSketch() }; schedules.Add(new PaintSchedule(solidPaint, visual)); - return new Sketch() + return new Sketch(MiniatureShapeSize, MiniatureShapeSize, GeometrySvg) { - Height = MiniatureShapeSize, - Width = MiniatureShapeSize, PaintSchedules = schedules }; } diff --git a/src/LiveChartsCore/ISeries.cs b/src/LiveChartsCore/ISeries.cs index d0e159153..81333e358 100644 --- a/src/LiveChartsCore/ISeries.cs +++ b/src/LiveChartsCore/ISeries.cs @@ -89,7 +89,7 @@ public interface ISeries /// true if this instance is visible at legends; otherwise, false. /// bool IsVisibleAtLegend { get; set; } - + /// /// Gets or sets the size of the legend shape. /// @@ -120,6 +120,11 @@ public interface ISeries /// double Pivot { get; set; } + /// + /// Gets or sets the series geometry svg. + /// + string? GeometrySvg { get; set; } + /// /// Gets or sets the animations speed, if this property is null, the /// property will be used. diff --git a/src/LiveChartsCore/Kernel/Drawing/Sketch.cs b/src/LiveChartsCore/Kernel/Drawing/Sketch.cs index 47fc8557a..ba3967562 100644 --- a/src/LiveChartsCore/Kernel/Drawing/Sketch.cs +++ b/src/LiveChartsCore/Kernel/Drawing/Sketch.cs @@ -32,12 +32,25 @@ namespace LiveChartsCore.Kernel.Drawing; public class Sketch where TDrawingContext : DrawingContext { + /// + /// Initializes a new instance of the class. + /// + /// The widht. + /// The height. + /// The svg path. + public Sketch(double width, double height, string? svg) + { + Svg = svg; + Width = width; + Height = height; + } + /// /// Gets or sets the width. /// /// /// The width. - /// + /// kjio9 public double Width { get; set; } /// @@ -48,6 +61,11 @@ public class Sketch /// public double Height { get; set; } + /// + /// Gets or sets the Svg. + /// / + public string? Svg { get; set; } + /// /// Gets or sets the paint schedules. /// diff --git a/src/LiveChartsCore/Kernel/Extensions.cs b/src/LiveChartsCore/Kernel/Extensions.cs index 39d0ebb0d..e24052e82 100644 --- a/src/LiveChartsCore/Kernel/Extensions.cs +++ b/src/LiveChartsCore/Kernel/Extensions.cs @@ -433,6 +433,18 @@ public static bool IsFinancialSeries(this ISeries series) return (series.SeriesProperties & SeriesProperties.Financial) != 0; } + /// + /// Determines whether is bar series. + /// + /// The series. + /// + /// true if [is bar series] [the specified series]; otherwise, false. + /// + public static bool HasSvgGeometry(this ISeries series) + { + return (series.SeriesProperties & SeriesProperties.IsSVGPath) != 0; + } + /// /// Calculates the tooltips finding strategy based on the series properties. /// diff --git a/src/LiveChartsCore/Kernel/SeriesProperties.cs b/src/LiveChartsCore/Kernel/SeriesProperties.cs index 7973c7587..a2b8c3f54 100644 --- a/src/LiveChartsCore/Kernel/SeriesProperties.cs +++ b/src/LiveChartsCore/Kernel/SeriesProperties.cs @@ -129,5 +129,10 @@ public enum SeriesProperties /// /// The polar line series /// - PolarLine = 1 << 20 + PolarLine = 1 << 20, + + /// + /// Sepcifies that the series visual comes from a svg path. + /// + IsSVGPath = 1 << 21, } diff --git a/src/LiveChartsCore/LineSeries.cs b/src/LiveChartsCore/LineSeries.cs index 05fe59840..f967c387c 100644 --- a/src/LiveChartsCore/LineSeries.cs +++ b/src/LiveChartsCore/LineSeries.cs @@ -223,6 +223,7 @@ public override void Invalidate(Chart chart) } } + var hasSvg = this.HasSvgGeometry(); var isSegmentEmpty = true; foreach (var data in GetSpline(segment, stacker)) @@ -263,6 +264,12 @@ public override void Invalidate(Chart chart) OnPointCreated(data.TargetPoint); } + if (hasSvg && _geometrySvgChanged) + { + var svgVisual = (ISvgPath)visual.Geometry; + svgVisual.OnPathChanged(GeometrySvg ?? throw new Exception("svg path is not defined")); + } + _ = everFetched.Add(data.TargetPoint); GeometryFill?.AddGeometryToPaintTask(cartesianChart.Canvas, visual.Geometry); @@ -440,10 +447,8 @@ public override Sketch GetMiniaturesSketch() if (GeometryStroke is not null) schedules.Add(BuildMiniatureSchedule(GeometryStroke, new TVisual())); else if (Stroke is not null) schedules.Add(BuildMiniatureSchedule(Stroke, new TVisual())); - return new Sketch() + return new Sketch(MiniatureShapeSize, MiniatureShapeSize, GeometrySvg) { - Height = MiniatureShapeSize, - Width = MiniatureShapeSize, PaintSchedules = schedules }; } diff --git a/src/LiveChartsCore/PieSeries.cs b/src/LiveChartsCore/PieSeries.cs index b4a59e32e..061536c50 100644 --- a/src/LiveChartsCore/PieSeries.cs +++ b/src/LiveChartsCore/PieSeries.cs @@ -459,10 +459,8 @@ public override Sketch GetMiniaturesSketch() if (Fill is not null) schedules.Add(BuildMiniatureSchedule(Fill, new TMiniatureGeometry())); if (Stroke is not null) schedules.Add(BuildMiniatureSchedule(Stroke, new TMiniatureGeometry())); - return new Sketch() + return new Sketch(MiniatureShapeSize, MiniatureShapeSize, GeometrySvg) { - Height = MiniatureShapeSize, - Width = MiniatureShapeSize, PaintSchedules = schedules }; } diff --git a/src/LiveChartsCore/PolarLineSeries.cs b/src/LiveChartsCore/PolarLineSeries.cs index 56a4a9103..256e5761b 100644 --- a/src/LiveChartsCore/PolarLineSeries.cs +++ b/src/LiveChartsCore/PolarLineSeries.cs @@ -506,10 +506,8 @@ public override Sketch GetMiniaturesSketch() if (GeometryStroke is not null) schedules.Add(BuildMiniatureSchedule(GeometryStroke, new TVisual())); else if (Stroke is not null) schedules.Add(BuildMiniatureSchedule(Stroke, new TVisual())); - return new Sketch() + return new Sketch(MiniatureShapeSize, MiniatureShapeSize, GeometrySvg) { - Height = MiniatureShapeSize, - Width = MiniatureShapeSize, PaintSchedules = schedules }; } diff --git a/src/LiveChartsCore/ScatterSeries.cs b/src/LiveChartsCore/ScatterSeries.cs index 1ba61a394..40da6f7f4 100644 --- a/src/LiveChartsCore/ScatterSeries.cs +++ b/src/LiveChartsCore/ScatterSeries.cs @@ -249,10 +249,8 @@ public override Sketch GetMiniaturesSketch() if (Fill is not null) schedules.Add(BuildMiniatureSchedule(Fill, new TVisual())); if (Stroke is not null) schedules.Add(BuildMiniatureSchedule(Stroke, new TVisual())); - return new Sketch() + return new Sketch(MiniatureShapeSize, MiniatureShapeSize, GeometrySvg) { - Height = MiniatureShapeSize, - Width = MiniatureShapeSize, PaintSchedules = schedules }; } diff --git a/src/LiveChartsCore/Series.cs b/src/LiveChartsCore/Series.cs index 5a8578be6..c2278cdee 100644 --- a/src/LiveChartsCore/Series.cs +++ b/src/LiveChartsCore/Series.cs @@ -88,6 +88,11 @@ public abstract class Series /// protected Action>? _customMeasureHandler = null; + /// + /// Indicates whether the geometry svg changed. + /// + protected bool _geometrySvgChanged = false; + /// /// Will be deleted on future versions /// @@ -105,9 +110,10 @@ public abstract class Series private DataFactory? _dataFactory; private bool _isVisibleAtLegend = true; private double _miniatureShapeSize = 12; - private Sketch _miniatureSketch = new(); + private Sketch _miniatureSketch = new(0, 0, null); private Func? _easingFunction; private TimeSpan? _animationsSpeed; + private string? _geometrySvg; /// /// Initializes a new instance of the class. @@ -116,6 +122,12 @@ public abstract class Series protected Series(SeriesProperties properties) { SeriesProperties = properties; + + if (typeof(ISizedGeometry).IsAssignableFrom(typeof(TVisual))) + { + SeriesProperties |= SeriesProperties.IsSVGPath; + } + _observer = new CollectionDeepObserver( (sender, e) => NotifySubscribers(), (sender, e) => NotifySubscribers()); @@ -153,6 +165,24 @@ public IEnumerable? Values /// public Action? Mapping { get => _mapping; set => SetProperty(ref _mapping, value); } + /// + public string? GeometrySvg + { + get => _geometrySvg; + set + { + _geometrySvgChanged = true; + SetProperty(ref _geometrySvg, value); + + if (!this.HasSvgGeometry()) + { + throw new Exception( + $"You must use a geometry that implements {nameof(ISvgPath)}, " + + $"{nameof(TVisual)} does not satisfies the constrait."); + } + } + } + int ISeries.SeriesId { get; set; } = -1; bool ISeries.RequiresFindClosestOnPointerDown => DataPointerDown is not null || ChartPointPointerDown is not null; diff --git a/src/LiveChartsCore/StepLineSeries.cs b/src/LiveChartsCore/StepLineSeries.cs index 12f7ea83e..8e55e4b5b 100644 --- a/src/LiveChartsCore/StepLineSeries.cs +++ b/src/LiveChartsCore/StepLineSeries.cs @@ -363,10 +363,8 @@ public override Sketch GetMiniaturesSketch() if (GeometryStroke is not null) schedules.Add(BuildMiniatureSchedule(GeometryStroke, new TVisual())); else if (Stroke is not null) schedules.Add(BuildMiniatureSchedule(Stroke, new TVisual())); - return new Sketch() + return new Sketch(MiniatureShapeSize, MiniatureShapeSize, GeometrySvg) { - Height = MiniatureShapeSize, - Width = MiniatureShapeSize, PaintSchedules = schedules }; } diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/SVGPathGeometry.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/SVGPathGeometry.cs index f1c8a3536..88d31f3a8 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/SVGPathGeometry.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/SVGPathGeometry.cs @@ -23,6 +23,7 @@ // Ignore Spelling: svg using System; +using LiveChartsCore.Drawing; using SkiaSharp; namespace LiveChartsCore.SkiaSharpView.Drawing.Geometries; @@ -31,7 +32,7 @@ namespace LiveChartsCore.SkiaSharpView.Drawing.Geometries; /// Defines a geometry that is built using from a svg path. /// /// -public class SVGPathGeometry : SizedGeometry +public class SVGPathGeometry : SizedGeometry, ISvgPath { private readonly Func _pathSource = () => throw new NotImplementedException("There is no path to render."); @@ -76,6 +77,11 @@ public override void OnDraw(SkiaSharpDrawingContext context, SKPaint paint) DrawPath(context, paint, Path ?? _pathSource()!); } + public void OnPathChanged(string path) + { + Path = SKPath.ParseSvgPathData(path); + } + /// /// Draws the given path to the canvas. /// diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/SVGPoints.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/SVGPoints.cs deleted file mode 100644 index 192b4d096..000000000 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/SVGPoints.cs +++ /dev/null @@ -1,157 +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 SkiaSharp; - -namespace LiveChartsCore.SkiaSharpView; - -/// -/// A collections of SVG paths. -/// -public static class SVGPoints -{ - private static SKPath? s_diamond; - private static SKPath? s_gem; - private static SKPath? s_star; - private static SKPath? s_heart; - private static SKPath? s_pin; - private static SKPath? s_triangle; - private static SKPath? s_square; - private static SKPath? s_circle; - private static SKPath? s_pentagon; - private static SKPath? s_cross; - private static SKPath? s_ckeck; - - // icons from https://www.svgrepo.com/ - - /// - /// A diamond. - /// - public static SKPath Diamond => s_diamond ??= - SKPath.ParseSvgPathData( - "M7.92950166,15.644 L3.34050166,8.796 C2.88750166,8.342 2.88650166,7.608 3.33750166,7.155 " + - "L7.90350166,0.323 C8.35450166,-0.13 9.08950166,-0.128 9.54550166,0.325 L14.0865017,7.175 " + - "C14.5405017,7.628 14.5415017,8.363 14.0895017,8.816 L9.57150166,15.646 C9.57150166,15.646 " + - "8.38450166,16.097 7.92950166,15.644 Z"); - - /// - /// A gem. - /// - public static SKPath Gem => s_gem ??= - SKPath.ParseSvgPathData( - "M11.7831 0H3.21691L0.0712554 5.24275C-0.0349835 5.41982 -0.0214476 5.64398 0.105326 5.80697L7.10533 " + - "14.807C7.20005 14.9288 7.34571 15 7.5 15C7.6543 15 7.79995 14.9288 7.89468 14.807L14.8947 " + - "5.80697C15.0215 5.64398 15.035 5.41982 14.9287 5.24275L11.7831 0Z"); - - /// - /// A star. - /// - public static SKPath Star => s_star ??= - SKPath.ParseSvgPathData( - "M11.0137 2.76683C11.379 1.89022 12.6208 1.89022 12.9861 2.76683L14.9102 7.38462C15.0654 " + - "7.75726 15.4295 8 15.8332 8H20.893C21.8234 8 22.2893 9.12483 21.6314 9.78268L17.5391 13.875C17.2823 " + - "14.1318 17.185 14.5076 17.2847 14.8568L18.9076 20.5369C19.1816 21.496 18.1122 22.2767 17.2822 " + - "21.7234L12.5546 18.5716C12.2187 18.3477 11.7811 18.3477 11.4452 18.5717L6.72544 21.7182C5.89284 " + - "22.2732 4.81988 21.49 5.09479 20.5279L6.71509 14.8568C6.81486 14.5076 6.71747 14.1318 6.46068 " + - "13.875L2.38859 9.8029C1.72328 9.13758 2.19448 8 3.13538 8H8.16658C8.57028 8 8.93438 7.75726 9.08965 " + - "7.38462L11.0137 2.76683Z"); - - /// - /// A heart. - /// - public static SKPath Heart => s_heart ??= - SKPath.ParseSvgPathData( - "M5.36129 3.46995C6.03579 3.16081 6.76287 3 7.50002 3C8.23718 3 8.96425 3.16081 9.63875 3.46995C10.3129 " + - "3.77893 10.9185 4.22861 11.4239 4.78788C11.7322 5.12902 12.2678 5.12902 12.5761 4.78788C13.5979 3.65726 " + - "15.0068 3.00001 16.5 3.00001C17.9932 3.00001 19.4021 3.65726 20.4239 4.78788C21.4427 5.91515 22 7.42425 " + - "22 8.9792C22 10.5342 21.4427 12.0433 20.4239 13.1705L14.2257 20.0287C13.0346 21.3467 10.9654 21.3467 9.77429 " + - "20.0287L3.57613 13.1705C3.07086 12.6115 2.67474 11.9531 2.40602 11.2353C2.13731 10.5175 2 9.75113 2 8.9792C2 " + - "8.20728 2.13731 7.44094 2.40602 6.72315C2.67474 6.00531 3.07086 5.34694 3.57613 4.78788C4.08157 4.22861 " + - "4.68716 3.77893 5.36129 3.46995Z"); - - /// - /// A pin. - /// - public static SKPath Pin => s_pin ??= - SKPath.ParseSvgPathData( - "M174,5248.219 C172.895,5248.219 172,5247.324 172,5246.219 C172,5245.114 172.895,5244.219 174,5244.219 " + - "C175.105,5244.219 176,5245.114 176,5246.219 C176,5247.324 175.105,5248.219 174,5248.219 M174,5239 " + - "C170.134,5239 167,5242.134 167,5246 C167,5249.866 174,5259 174,5259 C174,5259 181,5249.866 181,5246 " + - "C181,5242.134 177.866,5239 174,5239"); - - /// - /// A triangle. - /// - public static SKPath Triangle => s_triangle ??= - SKPath.ParseSvgPathData( - "M246.312928,5.62892705 C252.927596,9.40873724 258.409564,14.8907053 262.189374,21.5053731 " + - "L444.667042,340.84129 C456.358134,361.300701 449.250007,387.363834 428.790595,399.054926 " + - "C422.34376,402.738832 415.04715,404.676552 407.622001,404.676552 L42.6666667,404.676552 " + - "C19.1025173,404.676552 7.10542736e-15,385.574034 7.10542736e-15,362.009885 C7.10542736e-15,354.584736 " + - "1.93772021,347.288125 5.62162594,340.84129 L188.099293,21.5053731 C199.790385,1.04596203 " + - "225.853517,-6.06216498 246.312928,5.62892705 Z"); - - /// - /// A square. - /// - public static SKPath Square => s_square ??= - SKPath.ParseSvgPathData( - "M4.281 3h16.437A1.281 1.281 0 0 1 22 4.281v16.437A1.282 1.282 0 0 1 20.718 22H4.282A1.282 1.282 0 0 1 3 " + - "20.718V4.281A1.281 1.281 0 0 1 4.281 3z"); - - /// - /// A circle. - /// - public static SKPath Circle => s_circle ??= - SKPath.ParseSvgPathData( - "M2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22C6.47715 22 2 17.5228 " + - "2 12Z"); - - /// - /// A pentagon. - /// - public static SKPath Pentagon => s_pentagon ??= - SKPath.ParseSvgPathData( - "M10.1259 2.21864C11.2216 1.34212 12.7784 1.34212 13.8741 2.21864L21.5041 8.32262C22.5088 9.12637 22.8891 " + - "10.4813 22.4494 11.6905L19.4185 20.0252C18.9874 21.2108 17.8607 22 16.5992 22H7.40087C6.13935 22 5.01261 " + - "21.2108 4.58149 20.0252L1.55067 11.6905C1.11097 10.4813 1.49127 9.12637 2.49596 8.32262L10.1259 2.21864Z"); - - /// - /// A cross mark. - /// - public static SKPath Cross => s_cross ??= - SKPath.ParseSvgPathData( - "M12,2A10,10,0,1,0,22,12,10,10,0,0,0,12,2Zm3.71,12.29a1,1,0,0,1,0,1.42,1,1,0,0,1-1.42,0L12,13.42,9.71,15.71" + - "a1,1,0,0,1-1.42,0,1,1,0,0,1,0-1.42L10.58,12,8.29,9.71A1,1,0,0,1,9.71,8.29L12,10.58l2.29-2.29" + - "a1,1,0,0,1,1.42,1.42L13.42,12Z"); - - /// - /// A check mark. - /// - public static SKPath Check => s_ckeck ??= - SKPath.ParseSvgPathData( - "M2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22C6.47715 22 2 17.5228 " + - "2 12ZM15.7071 9.29289C16.0976 9.68342 16.0976 10.3166 15.7071 10.7071L12.0243 14.3899C11.4586 14.9556 " + - "10.5414 14.9556 9.97568 14.3899L8.29289 12.7071C7.90237 12.3166 7.90237 11.6834 8.29289 11.2929C8.68342 " + - "10.9024 9.31658 10.9024 9.70711 11.2929L11 12.5858L14.2929 9.29289C14.6834 8.90237 15.3166 8.90237 15.7071 " + - "9.29289Z"); -} diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/VisualElements/VisualElementsExtensions.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/VisualElements/VisualElementsExtensions.cs index efa10ebdc..a4fab1d5a 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/VisualElements/VisualElementsExtensions.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/VisualElements/VisualElementsExtensions.cs @@ -20,6 +20,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. +using System; using LiveChartsCore.Drawing; using LiveChartsCore.Kernel.Drawing; using LiveChartsCore.SkiaSharpView.Drawing; @@ -55,6 +56,11 @@ public static RelativePanel AsDrawnC Height = sizedGeometry.Height, }; + if (g is ISvgPath svgPath) + { + svgPath.OnPathChanged(sketch.Svg ?? throw new NullReferenceException("sketch.Svg can not be null at this point.")); + } + schedule.PaintTask.ZIndex = schedule.PaintTask.ZIndex + 1 + baseZIndex; if (schedule.PaintTask.IsFill) vgv.Fill = schedule.PaintTask; From e3f6fbc3918f2a670831cf29ad308dc4e507c924 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Mon, 24 Jul 2023 18:39:40 -0600 Subject: [PATCH 02/54] cache svg paths --- .../Drawing/Geometries/SVGPathGeometry.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/SVGPathGeometry.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/SVGPathGeometry.cs index 88d31f3a8..a3732c0e3 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/SVGPathGeometry.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/SVGPathGeometry.cs @@ -23,6 +23,7 @@ // Ignore Spelling: svg using System; +using System.Collections.Generic; using LiveChartsCore.Drawing; using SkiaSharp; @@ -34,6 +35,7 @@ namespace LiveChartsCore.SkiaSharpView.Drawing.Geometries; /// public class SVGPathGeometry : SizedGeometry, ISvgPath { + public static Dictionary _cache = new(); private readonly Func _pathSource = () => throw new NotImplementedException("There is no path to render."); /// @@ -79,7 +81,13 @@ public override void OnDraw(SkiaSharpDrawingContext context, SKPaint paint) public void OnPathChanged(string path) { - Path = SKPath.ParseSvgPathData(path); + if (!_cache.TryGetValue(path, out var skPath)) + { + skPath = SKPath.ParseSvgPathData(path); + _cache[path] = skPath; + } + + Path = skPath; } /// From 804a1c5e6d0c2fbbeee0af31162b4b6d9a6ea74d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Mon, 24 Jul 2023 19:14:03 -0600 Subject: [PATCH 03/54] add support for all series --- src/LiveChartsCore/ColumnSeries.cs | 8 ++++++++ src/LiveChartsCore/HeatSeries.cs | 9 +++++++++ src/LiveChartsCore/LineSeries.cs | 3 ++- src/LiveChartsCore/PolarLineSeries.cs | 9 +++++++++ src/LiveChartsCore/RowSeries.cs | 8 ++++++++ src/LiveChartsCore/ScatterSeries.cs | 8 ++++++++ src/LiveChartsCore/StepLineSeries.cs | 8 ++++++++ 7 files changed, 52 insertions(+), 1 deletion(-) diff --git a/src/LiveChartsCore/ColumnSeries.cs b/src/LiveChartsCore/ColumnSeries.cs index 5ba913346..7efd9333b 100644 --- a/src/LiveChartsCore/ColumnSeries.cs +++ b/src/LiveChartsCore/ColumnSeries.cs @@ -106,6 +106,7 @@ public override void Invalidate(Chart chart) var ry = (float)Ry; var stacker = isStacked ? cartesianChart.SeriesContext.GetStackPosition(this, GetStackGroup()) : null; + var hasSvg = this.HasSvgGeometry(); foreach (var point in Fetch(cartesianChart)) { @@ -169,6 +170,12 @@ public override void Invalidate(Chart chart) _ = everFetched.Add(point); } + if (hasSvg && _geometrySvgChanged) + { + var svgVisual = (ISvgPath)visual; + svgVisual.OnPathChanged(GeometrySvg ?? throw new Exception("svg path is not defined")); + } + Fill?.AddGeometryToPaintTask(cartesianChart.Canvas, visual); Stroke?.AddGeometryToPaintTask(cartesianChart.Canvas, visual); @@ -257,6 +264,7 @@ public override void Invalidate(Chart chart) pointsCleanup.CollectPoints( everFetched, cartesianChart.View, primaryScale, secondaryScale, SoftDeleteOrDisposePoint); + _geometrySvgChanged = false; } /// diff --git a/src/LiveChartsCore/HeatSeries.cs b/src/LiveChartsCore/HeatSeries.cs index 577e15c62..6295b36bd 100644 --- a/src/LiveChartsCore/HeatSeries.cs +++ b/src/LiveChartsCore/HeatSeries.cs @@ -142,6 +142,8 @@ public override void Invalidate(Chart chart) _heatKnownLength = HeatMap.Length; } + var hasSvg = this.HasSvgGeometry(); + foreach (var point in Fetch(cartesianChart)) { var coordinate = point.Coordinate; @@ -199,6 +201,12 @@ public override void Invalidate(Chart chart) _ = everFetched.Add(point); } + if (hasSvg && _geometrySvgChanged) + { + var svgVisual = (ISvgPath)visual; + svgVisual.OnPathChanged(GeometrySvg ?? throw new Exception("svg path is not defined")); + } + _paintTaks?.AddGeometryToPaintTask(cartesianChart.Canvas, visual); visual.X = secondary - uws * 0.5f + p.Left; @@ -246,6 +254,7 @@ public override void Invalidate(Chart chart) pointsCleanup.CollectPoints( everFetched, cartesianChart.View, primaryScale, secondaryScale, SoftDeleteOrDisposePoint); + _geometrySvgChanged = false; } /// diff --git a/src/LiveChartsCore/LineSeries.cs b/src/LiveChartsCore/LineSeries.cs index f967c387c..fb9f2b838 100644 --- a/src/LiveChartsCore/LineSeries.cs +++ b/src/LiveChartsCore/LineSeries.cs @@ -166,6 +166,7 @@ public override void Invalidate(Chart chart) var tooltipPositon = chart.TooltipPosition; var segmentI = 0; + var hasSvg = this.HasSvgGeometry(); foreach (var segment in segments) { @@ -223,7 +224,6 @@ public override void Invalidate(Chart chart) } } - var hasSvg = this.HasSvgGeometry(); var isSegmentEmpty = true; foreach (var data in GetSpline(segment, stacker)) @@ -399,6 +399,7 @@ public override void Invalidate(Chart chart) everFetched, cartesianChart.View, primaryScale, secondaryScale, SoftDeleteOrDisposePoint); IsFirstDraw = false; + _geometrySvgChanged = false; } /// diff --git a/src/LiveChartsCore/PolarLineSeries.cs b/src/LiveChartsCore/PolarLineSeries.cs index 256e5761b..b12a7a081 100644 --- a/src/LiveChartsCore/PolarLineSeries.cs +++ b/src/LiveChartsCore/PolarLineSeries.cs @@ -249,6 +249,8 @@ public override void Invalidate(Chart chart) isCotangent = true; } + var hasSvg = this.HasSvgGeometry(); + foreach (var segment in segments) { TPathGeometry fillPath; @@ -329,6 +331,12 @@ public override void Invalidate(Chart chart) OnPointCreated(data.TargetPoint); } + if (hasSvg && _geometrySvgChanged) + { + var svgVisual = (ISvgPath)visual.Geometry; + svgVisual.OnPathChanged(GeometrySvg ?? throw new Exception("svg path is not defined")); + } + _ = everFetched.Add(data.TargetPoint); GeometryFill?.AddGeometryToPaintTask(polarChart.Canvas, visual.Geometry); @@ -434,6 +442,7 @@ public override void Invalidate(Chart chart) } pointsCleanup.CollectPoints(everFetched, polarChart.View, scaler, SoftDeleteOrDisposePoint); + _geometrySvgChanged = false; } /// diff --git a/src/LiveChartsCore/RowSeries.cs b/src/LiveChartsCore/RowSeries.cs index 0dff61ed0..f98dd8472 100644 --- a/src/LiveChartsCore/RowSeries.cs +++ b/src/LiveChartsCore/RowSeries.cs @@ -107,6 +107,7 @@ public override void Invalidate(Chart chart) var ry = (float)Ry; var stacker = isStacked ? cartesianChart.SeriesContext.GetStackPosition(this, GetStackGroup()) : null; + var hasSvg = this.HasSvgGeometry(); foreach (var point in Fetch(cartesianChart)) { @@ -171,6 +172,12 @@ public override void Invalidate(Chart chart) _ = everFetched.Add(point); } + if (hasSvg && _geometrySvgChanged) + { + var svgVisual = (ISvgPath)visual; + svgVisual.OnPathChanged(GeometrySvg ?? throw new Exception("svg path is not defined")); + } + Fill?.AddGeometryToPaintTask(cartesianChart.Canvas, visual); Stroke?.AddGeometryToPaintTask(cartesianChart.Canvas, visual); @@ -252,6 +259,7 @@ public override void Invalidate(Chart chart) pointsCleanup.CollectPoints( everFetched, cartesianChart.View, primaryScale, secondaryScale, SoftDeleteOrDisposePoint); + _geometrySvgChanged = false; } /// diff --git a/src/LiveChartsCore/ScatterSeries.cs b/src/LiveChartsCore/ScatterSeries.cs index 40da6f7f4..75b73f508 100644 --- a/src/LiveChartsCore/ScatterSeries.cs +++ b/src/LiveChartsCore/ScatterSeries.cs @@ -138,6 +138,7 @@ public override void Invalidate(Chart chart) uwy = uwy < gs ? gs : uwy; var hy = chart.ControlSize.Height * .5f; + var hasSvg = this.HasSvgGeometry(); foreach (var point in Fetch(cartesianChart)) { @@ -185,6 +186,12 @@ public override void Invalidate(Chart chart) _ = everFetched.Add(point); } + if (hasSvg && _geometrySvgChanged) + { + var svgVisual = (ISvgPath)visual; + svgVisual.OnPathChanged(GeometrySvg ?? throw new Exception("svg path is not defined")); + } + Fill?.AddGeometryToPaintTask(cartesianChart.Canvas, visual); Stroke?.AddGeometryToPaintTask(cartesianChart.Canvas, visual); @@ -231,6 +238,7 @@ public override void Invalidate(Chart chart) } pointsCleanup.CollectPoints(everFetched, cartesianChart.View, yScale, xScale, SoftDeleteOrDisposePoint); + _geometrySvgChanged = false; } /// diff --git a/src/LiveChartsCore/StepLineSeries.cs b/src/LiveChartsCore/StepLineSeries.cs index 8e55e4b5b..8b9f0d4c3 100644 --- a/src/LiveChartsCore/StepLineSeries.cs +++ b/src/LiveChartsCore/StepLineSeries.cs @@ -143,6 +143,7 @@ public override void Invalidate(Chart chart) var uwx = secondaryScale.MeasureInPixels(secondaryAxis.UnitWidth); uwx = uwx < gs ? gs : uwx; + var hasSvg = this.HasSvgGeometry(); foreach (var segment in segments) { @@ -228,6 +229,12 @@ public override void Invalidate(Chart chart) OnPointCreated(point); } + if (hasSvg && _geometrySvgChanged) + { + var svgVisual = (ISvgPath)visual.Geometry; + svgVisual.OnPathChanged(GeometrySvg ?? throw new Exception("svg path is not defined")); + } + _ = everFetched.Add(point); GeometryFill?.AddGeometryToPaintTask(cartesianChart.Canvas, visual.Geometry); @@ -344,6 +351,7 @@ public override void Invalidate(Chart chart) everFetched, cartesianChart.View, primaryScale, secondaryScale, SoftDeleteOrDisposePoint); IsFirstDraw = false; + _geometrySvgChanged = false; } /// From 9368c881e84a0bae5a8d9c7e3dcb0cb7baf18232 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Tue, 25 Jul 2023 09:03:33 -0600 Subject: [PATCH 04/54] update samples --- .../Bars/Custom/MyGeometry.cs | 22 ++++----- .../Bars/Custom/ViewModel.cs | 48 +++++------------- .../Lines/Custom/MyGeometry.cs | 19 +++---- .../Lines/Custom/ViewModel.cs | 49 ++++++------------- .../Scatter/Custom/MyGeometry.cs | 25 +++++----- .../Scatter/Custom/ViewModel.cs | 19 +++++-- src/LiveChartsCore/Drawing/SVGPoints.cs | 11 ----- 7 files changed, 72 insertions(+), 121 deletions(-) diff --git a/samples/ViewModelsSamples/Bars/Custom/MyGeometry.cs b/samples/ViewModelsSamples/Bars/Custom/MyGeometry.cs index b5bbcc4e8..c20d9585e 100644 --- a/samples/ViewModelsSamples/Bars/Custom/MyGeometry.cs +++ b/samples/ViewModelsSamples/Bars/Custom/MyGeometry.cs @@ -1,20 +1,20 @@ -using System; +using LiveChartsCore.SkiaSharpView.Drawing; +using LiveChartsCore.SkiaSharpView.Drawing.Geometries; using SkiaSharp; namespace ViewModelsSamples.Bars.Custom; -public class MyGeometry : LiveChartsCore.SkiaSharpView.Drawing.Geometries.SVGPathGeometry +public class MyGeometry : SizedGeometry { - public MyGeometry() - : base(() => SelectedPath ?? throw new NotImplementedException("Path not set yet!")) + public override void OnDraw(SkiaSharpDrawingContext context, SKPaint paint) { - // we passed the "path source" to the base class - // it is a function that returns the path to draw - // this way we can change the path at runtime + var canvas = context.Canvas; + var y = Y; - // Note: LiveCharts geometries do not implement INotifyPropertyChanged - // so if you change the path at runtime you will need to call a chart update. + while (y < Y + Height) + { + canvas.DrawLine(X, y, X + Width, y, paint); + y += 10; + } } - - public static SKPath? SelectedPath { get; set; } } diff --git a/samples/ViewModelsSamples/Bars/Custom/ViewModel.cs b/samples/ViewModelsSamples/Bars/Custom/ViewModel.cs index 2c8758790..2d977c9cd 100644 --- a/samples/ViewModelsSamples/Bars/Custom/ViewModel.cs +++ b/samples/ViewModelsSamples/Bars/Custom/ViewModel.cs @@ -1,56 +1,32 @@ -using System.Collections.Generic; -using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.ComponentModel; using LiveChartsCore; +using LiveChartsCore.Drawing; using LiveChartsCore.SkiaSharpView; using LiveChartsCore.SkiaSharpView.Drawing.Geometries; -using LiveChartsCore.SkiaSharpView.Painting; -using SkiaSharp; namespace ViewModelsSamples.Bars.Custom; public partial class ViewModel : ObservableObject { - public ViewModel() - { - Series = new ISeries[] + public ISeries[] Series { get; set; } = { new ColumnSeries { - Values = new List { 4, 3, 2, 1 }, - Fill = new SolidColorPaint(SKColors.CornflowerBlue) + Values = new double[] { 2, 1, 4, 2, 2, -5, -2 }, }, - // use the second argument type to specify the geometry to draw for every point - // there are already many predefined geometries in the - // LiveChartsCore.SkiaSharpView.Drawing.Geometries namespace - new ColumnSeries + // You can also use SVG paths to draw the geometry + // LiveCharts already provides some predefined paths in the SVGPoints class. + new ColumnSeries { - Values = new double[] { 4, 3, 2, 1 }, - Fill = new SolidColorPaint(SKColors.DarkRed) + Values = new double[] { -2, 2, 1, 3, -1, 4, 3 }, + GeometrySvg = SVGPoints.Gem }, - // you can also define your own SVG geometry - // MyGeometry class let us change the Path at runtime - // Click on the on any point to change the path. - // You can find the MyGeometry.cs file below + // you can declare your own gemetry and use the SkiaSharp api to draw it new ColumnSeries { - Values = new double[] { 4, 3, 2, 1 }, - Fill = new SolidColorPaint(SKColors.Black) - } + Values = new double[] { 4, 5, 2, 4, 3, 2, 1 }, + }, }; - - // We can change the MyGeometry path at runtime - // the SVGPoints class contains many predefined paths - // MyGeometry.SelectedPath = SVGPoints.Gem; - - // You can also build your own path. - MyGeometry.SelectedPath = SKPath.ParseSvgPathData( - "M6 4C6 3.44772 6.44772 3 7 3H17C17.5523 3 18 3.44772 18 4V18C18 18.5523 17.5523 19 17 19H7C6.44772 " + - "19 6 18.5523 6 18V4ZM7 1C5.34315 1 4 2.34315 4 4V20C4 21.6569 5.34315 23 7 " + - "23H17C18.6569 23 20 21.6569 20 20V4C20 2.34315 18.6569 1 17 1H7ZM12 22C12.5523 22 13 21.5523 13 " + - "21C13 20.4477 12.5523 20 12 20C11.4477 20 11 20.4477 11 21C11 21.5523 11.4477 22 12 22Z"); - } - - public ISeries[] Series { get; set; } } diff --git a/samples/ViewModelsSamples/Lines/Custom/MyGeometry.cs b/samples/ViewModelsSamples/Lines/Custom/MyGeometry.cs index b5c6204f8..5e97b1b43 100644 --- a/samples/ViewModelsSamples/Lines/Custom/MyGeometry.cs +++ b/samples/ViewModelsSamples/Lines/Custom/MyGeometry.cs @@ -1,20 +1,17 @@ -using System; +using LiveChartsCore.SkiaSharpView.Drawing; +using LiveChartsCore.SkiaSharpView.Drawing.Geometries; using SkiaSharp; namespace ViewModelsSamples.Lines.Custom; -public class MyGeometry : LiveChartsCore.SkiaSharpView.Drawing.Geometries.SVGPathGeometry +public class MyGeometry : SizedGeometry { - public MyGeometry() - : base(() => SelectedPath ?? throw new NotImplementedException("Path not set yet!")) + public override void OnDraw(SkiaSharpDrawingContext context, SKPaint paint) { - // we passed the "path source" to the base class - // it is a function that returns the path to draw - // this way we can change the path at runtime + var canvas = context.Canvas; - // Note: LiveCharts geometries do not implement INotifyPropertyChanged - // so if you change the path at runtime you will need to call a chart update. + canvas.DrawRect(X, Y, Width, Height, paint); + canvas.DrawLine(X, Y, X + Width, Y + Height, paint); + canvas.DrawLine(X + Width, Y, X, Y + Height, paint); } - - public static SKPath? SelectedPath { get; set; } } diff --git a/samples/ViewModelsSamples/Lines/Custom/ViewModel.cs b/samples/ViewModelsSamples/Lines/Custom/ViewModel.cs index 6f8dd4173..baca7046f 100644 --- a/samples/ViewModelsSamples/Lines/Custom/ViewModel.cs +++ b/samples/ViewModelsSamples/Lines/Custom/ViewModel.cs @@ -3,67 +3,46 @@ using LiveChartsCore.Drawing; using LiveChartsCore.SkiaSharpView; using LiveChartsCore.SkiaSharpView.Drawing.Geometries; -using LiveChartsCore.SkiaSharpView.Painting; -using SkiaSharp; namespace ViewModelsSamples.Lines.Custom; public partial class ViewModel : ObservableObject { - public ViewModel() - { - Series = new ISeries[] + public ISeries[] Series { get; set; } = { new LineSeries { - Values = new double[] { 3, 1, 4, 3, 2, -5, -2 }, - GeometrySize = 10, - Fill = null + Values = new double[] { 2, 1, 4, 2, 2, -5, -2 }, + Fill = null, + GeometrySize = 20 }, - // use the second argument type to specify the geometry to draw for every point + // use the second type parameter to specify the geometry to draw for every point // there are already many predefined geometries in the // LiveChartsCore.SkiaSharpView.Drawing.Geometries namespace new LineSeries { Values = new double[] { 3, 3, -3, -2, -4, -3, -1 }, - Fill = null + Fill = null, + GeometrySize = 20 }, - // You can also use a SVG path data to draw the geometry + // You can also use SVG paths to draw the geometry + // LiveCharts already provides some predefined paths in the SVGPoints class. new LineSeries { Values = new double[] { -2, 2, 1, 3, -1, 4, 3 }, - Stroke = new SolidColorPaint(SKColors.DarkOliveGreen, 3), Fill = null, GeometrySvg = SVGPoints.Star, - GeometryStroke = new SolidColorPaint(SKColors.DarkOliveGreen, 3), - GeometryFill = new SolidColorPaint(SKColors.White), - GeometrySize = 35 + GeometrySize = 20 }, - new LineSeries + // you can declare your own gemetry and use the SkiaSharp api to draw it + new LineSeries { - Values = new double[] { 3, 5, 2, 4, 3, 2, 1 }, - Stroke = new SolidColorPaint(SKColors.DarkOliveGreen, 3), + Values = new double[] { 4, 5, 2, 4, 3, 2, 1 }, Fill = null, - GeometrySvg = SVGPoints.Pin, - GeometryStroke = new SolidColorPaint(SKColors.DarkOliveGreen, 3), - GeometryFill = new SolidColorPaint(SKColors.White), - GeometrySize = 35 + GeometrySize = 20 }, }; - - var s = (LineSeries)Series[2]; - - s.ChartPointPointerDown += (chart, point) => - { - if (point is null) return; - // you can change the svg at runtime - point.Context.Series.GeometrySvg = - s.GeometrySvg == SVGPoints.Star ? SVGPoints.Gem : SVGPoints.Star; - }; - } - - public ISeries[] Series { get; set; } } diff --git a/samples/ViewModelsSamples/Scatter/Custom/MyGeometry.cs b/samples/ViewModelsSamples/Scatter/Custom/MyGeometry.cs index fed3e0cc0..03e50a95e 100644 --- a/samples/ViewModelsSamples/Scatter/Custom/MyGeometry.cs +++ b/samples/ViewModelsSamples/Scatter/Custom/MyGeometry.cs @@ -1,19 +1,20 @@ -using LiveChartsCore.SkiaSharpView.Drawing.Geometries; +using LiveChartsCore.SkiaSharpView.Drawing; +using LiveChartsCore.SkiaSharpView.Drawing.Geometries; using SkiaSharp; namespace ViewModelsSamples.Scatter.Custom; -public class MyGeometry : SVGPathGeometry +public class MyGeometry : SizedGeometry { - // the static field is important to prevent the svg path is parsed multiple times // mark - // Icon from Google Material Icons font. - // https://fonts.google.com/icons?selected=Material%20Icons%20Outlined%3Amy_location%3A - public static SKPath svgPath = SKPath.ParseSvgPathData( - "M12 8c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm8.94 3c-.46-4.17-3.77-7.48-7.94-7.94V1h-2v2.06C6.83 3.52 3.52 6.83 3.06 " + - "11H1v2h2.06c.46 4.17 3.77 7.48 7.94 7.94V23h2v-2.06c4.17-.46 7.48-3.77 7.94-7.94H23v-2h-2.06zM12 19c-3.87 0-7-3.13-7-7s3.13-7 7-7 7 " + - "3.13 7 7-3.13 7-7 7z"); + public override void OnDraw(SkiaSharpDrawingContext context, SKPaint paint) + { + var canvas = context.Canvas; + var y = Y; - public MyGeometry() - : base(svgPath) - { } + while (y < Y + Height) + { + canvas.DrawLine(X, y, X + Width, y, paint); + y += 10; + } + } } diff --git a/samples/ViewModelsSamples/Scatter/Custom/ViewModel.cs b/samples/ViewModelsSamples/Scatter/Custom/ViewModel.cs index 3b6aafee0..7d5617a4a 100644 --- a/samples/ViewModelsSamples/Scatter/Custom/ViewModel.cs +++ b/samples/ViewModelsSamples/Scatter/Custom/ViewModel.cs @@ -3,6 +3,7 @@ using CommunityToolkit.Mvvm.ComponentModel; using LiveChartsCore; using LiveChartsCore.Defaults; +using LiveChartsCore.Drawing; using LiveChartsCore.SkiaSharpView; using LiveChartsCore.SkiaSharpView.Drawing.Geometries; using LiveChartsCore.SkiaSharpView.Painting; @@ -17,16 +18,18 @@ public ViewModel() var r = new Random(); var values1 = new ObservableCollection(); var values2 = new ObservableCollection(); + var values3 = new ObservableCollection(); for (var i = 0; i < 20; i++) { values1.Add(new ObservablePoint(r.Next(0, 20), r.Next(0, 20))); values2.Add(new ObservablePoint(r.Next(0, 20), r.Next(0, 20))); + values3.Add(new ObservablePoint(r.Next(0, 20), r.Next(0, 20))); } Series = new ISeries[] { - // use the second type argument to specify the geometry to draw for every point + // use the second type parameter to specify the geometry to draw for every point // there are already many predefined geometries in the // LiveChartsCore.SkiaSharpView.Drawing.Geometries namespace new ScatterSeries @@ -36,13 +39,19 @@ public ViewModel() GeometrySize = 40, }, - // Or Define your own SVG geometry - new ScatterSeries + // You can also use SVG paths to draw the geometry + // LiveCharts already provides some predefined paths in the SVGPoints class. + new ScatterSeries { Values = values2, + GeometrySvg = SVGPoints.Heart + }, + + // you can declare your own gemetry and use the SkiaSharp api to draw it + new ScatterSeries + { + Values = values3, GeometrySize = 40, - Stroke = null, - Fill = new SolidColorPaint(SKColors.DarkOliveGreen) } }; } diff --git a/src/LiveChartsCore/Drawing/SVGPoints.cs b/src/LiveChartsCore/Drawing/SVGPoints.cs index 40c1c08e0..4e259c400 100644 --- a/src/LiveChartsCore/Drawing/SVGPoints.cs +++ b/src/LiveChartsCore/Drawing/SVGPoints.cs @@ -79,17 +79,6 @@ public static class SVGPoints "C170.134,5239 167,5242.134 167,5246 C167,5249.866 174,5259 174,5259 C174,5259 181,5249.866 181,5246 " + "C181,5242.134 177.866,5239 174,5239"; - /// - /// A triangle. - /// - public static string Triangle => - "M246.312928,5.62892705 C252.927596,9.40873724 258.409564,14.8907053 262.189374,21.5053731 " + - "L444.667042,340.84129 C456.358134,361.300701 449.250007,387.363834 428.790595,399.054926 " + - "C422.34376,402.738832 415.04715,404.676552 407.622001,404.676552 L42.6666667,404.676552 " + - "C19.1025173,404.676552 7.10542736e-15,385.574034 7.10542736e-15,362.009885 C7.10542736e-15,354.584736 " + - "1.93772021,347.288125 5.62162594,340.84129 L188.099293,21.5053731 C199.790385,1.04596203 " + - "225.853517,-6.06216498 246.312928,5.62892705 Z"; - /// /// A square. /// From 39455ef9d4f6d941e05af385981c440e53af9e57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Tue, 25 Jul 2023 13:57:18 -0600 Subject: [PATCH 05/54] improve transforms --- .../Drawing/Geometries/Geometry.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/Geometry.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/Geometry.cs index 66993fe0b..55a869ad8 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/Geometry.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/Geometry.cs @@ -104,7 +104,7 @@ public LvcPoint TranslateTransform set { _translateProperty.SetMovement(value, this); - _hasTranslate = value.X != 0 || value.Y != 0; + _hasTranslate = true; } } @@ -115,7 +115,7 @@ public float RotateTransform set { _rotationProperty.SetMovement(value, this); - _hasRotation = value != 0; + _hasRotation = true; } } @@ -126,7 +126,7 @@ public LvcPoint ScaleTransform set { _scaleProperty.SetMovement(value, this); - _hasScale = value.X != 1 || value.Y != 1; + _hasScale = true; } } @@ -137,7 +137,7 @@ public LvcPoint SkewTransform set { _skewProperty.SetMovement(value, this); - _hasSkew = value.X != 0 || value.Y != 0; + _hasSkew = true; } } @@ -153,7 +153,7 @@ public SKMatrix Transform set { _transformProperty.SetMovement(value, this); - _hasTransform = !value.IsIdentity; + _hasTransform = true; } } From d2b9c54c58942ecbfab1c30d4748bff3d6dccd36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Tue, 25 Jul 2023 13:57:28 -0600 Subject: [PATCH 06/54] clean ns --- samples/ViewModelsSamples/Scatter/Custom/ViewModel.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/samples/ViewModelsSamples/Scatter/Custom/ViewModel.cs b/samples/ViewModelsSamples/Scatter/Custom/ViewModel.cs index 7d5617a4a..9757b398a 100644 --- a/samples/ViewModelsSamples/Scatter/Custom/ViewModel.cs +++ b/samples/ViewModelsSamples/Scatter/Custom/ViewModel.cs @@ -6,8 +6,6 @@ using LiveChartsCore.Drawing; using LiveChartsCore.SkiaSharpView; using LiveChartsCore.SkiaSharpView.Drawing.Geometries; -using LiveChartsCore.SkiaSharpView.Painting; -using SkiaSharp; namespace ViewModelsSamples.Scatter.Custom; From 7ca24d685d81217597c0df733d13a4543f0f98c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Tue, 25 Jul 2023 14:32:28 -0600 Subject: [PATCH 07/54] default tooltips improvements --- src/LiveChartsCore/LineSeries.cs | 6 ++++-- src/LiveChartsCore/StepLineSeries.cs | 6 ++++-- .../Drawing/Geometries/PopUpGeometry.cs | 16 +++++++--------- .../SKCharts/SKDefaultTooltip.cs | 7 ++++--- 4 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/LiveChartsCore/LineSeries.cs b/src/LiveChartsCore/LineSeries.cs index fb9f2b838..326117e39 100644 --- a/src/LiveChartsCore/LineSeries.cs +++ b/src/LiveChartsCore/LineSeries.cs @@ -312,7 +312,9 @@ public override void Invalidate(Chart chart) .SetDimensions(x - uwx * 0.5f, y - hgs, uwx, gs) .CenterXToolTip(); - _ = coordinate.PrimaryValue >= pivot ? ha.CenterYToolTip() : ha.CenterYToolTip().IsLessThanPivot(); + _ = coordinate.PrimaryValue >= pivot + ? ha.StartYToolTip() + : ha.EndYToolTip().IsLessThanPivot(); pointsCleanup.Clean(data.TargetPoint); @@ -407,7 +409,7 @@ protected override void OnPointerEnter(ChartPoint point) { var visual = (TVisual?)point.Context.Visual; if (visual is null) return; - visual.ScaleTransform = new LvcPoint(1.3f, 1.3f); + visual.ScaleTransform = new LvcPoint(1.35f, 1.35f); base.OnPointerEnter(point); } diff --git a/src/LiveChartsCore/StepLineSeries.cs b/src/LiveChartsCore/StepLineSeries.cs index 8b9f0d4c3..85b991e9c 100644 --- a/src/LiveChartsCore/StepLineSeries.cs +++ b/src/LiveChartsCore/StepLineSeries.cs @@ -271,9 +271,11 @@ public override void Invalidate(Chart chart) _ = ha .SetDimensions(x - uwx * 0.5f, y - hgs, uwx, gs) - .CenterXToolTip(); + .CenterXToolTip(); - _ = coordinate.PrimaryValue >= pivot ? ha.CenterYToolTip() : ha.CenterYToolTip().IsLessThanPivot(); + _ = coordinate.PrimaryValue >= pivot + ? ha.StartYToolTip() + : ha.EndYToolTip().IsLessThanPivot(); pointsCleanup.Clean(point); diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/PopUpGeometry.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/PopUpGeometry.cs index e8320f4d1..1e8895024 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/PopUpGeometry.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/PopUpGeometry.cs @@ -35,6 +35,12 @@ public class PopUpGeometry : SizedGeometry /// public double Wedge { get; set; } = 15; + /// + /// Gets or sets the wedge thickness, it controls the width of the wedge, + /// the value is normalized, where 1 means the size, default is 2. + /// + public double WedgeThickness { get; set; } = 2; + /// /// Gets or sets the border radius. /// @@ -51,7 +57,7 @@ public override void OnDraw(SkiaSharpDrawingContext context, SKPaint paint) var wedge = (float)Wedge; var br = (float)BorderRadius; - var wf = 1.25f; + var wf = (float)WedgeThickness; var x = X + (Placement == PopUpPlacement.Right ? 1 : 0) * wedge; var y = Y + (Placement == PopUpPlacement.Bottom ? 1 : 0) * wedge; var w = Width - (Placement is PopUpPlacement.Right or PopUpPlacement.Left ? 1 : 0) * wedge; @@ -102,13 +108,5 @@ public override void OnDraw(SkiaSharpDrawingContext context, SKPaint paint) path.Close(); context.Canvas.DrawPath(path, context.Paint); - - var c = new SKColor( - (byte)(context.Paint.Color.Red * 0.9), - (byte)(context.Paint.Color.Red * 0.9), - (byte)(context.Paint.Color.Red * 0.9), - 255); - using var borderPaint = new SKPaint { Color = c, IsStroke = true, IsAntialias = true }; - context.Canvas.DrawPath(path, borderPaint); } } diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKDefaultTooltip.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKDefaultTooltip.cs index 2e11c9345..fe03f760a 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKDefaultTooltip.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKDefaultTooltip.cs @@ -50,9 +50,9 @@ public class SKDefaultTooltip : IChartTooltip public SKDefaultTooltip() { FontPaint = new SolidColorPaint(new SKColor(28, 49, 58)); - BackgroundPaint = new SolidColorPaint(new SKColor(245, 245, 245, 230)) + BackgroundPaint = new SolidColorPaint(new SKColor(235, 235, 235, 230)) { - ImageFilter = new DropShadow(0, 0, 4, 4, new SKColor(0, 0, 0, 70)) + ImageFilter = new DropShadow(2, 2, 6, 6, new SKColor(50, 0, 0, 100)) }; } @@ -85,7 +85,7 @@ public IPaint? BackgroundPaint /// public void Show(IEnumerable foundPoints, Chart chart) { - const int wedge = 13; + const int wedge = 10; if (chart.View.TooltipTextSize is not null) TextSize = chart.View.TooltipTextSize.Value; if (chart.View.TooltipBackgroundPaint is not null) BackgroundPaint = chart.View.TooltipBackgroundPaint; @@ -102,6 +102,7 @@ public void Show(IEnumerable foundPoints, Chart Date: Tue, 25 Jul 2023 17:59:48 -0600 Subject: [PATCH 08/54] use harfbuzz shaper --- .../Drawing/Geometries/LabelGeometry.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/LabelGeometry.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/LabelGeometry.cs index a062dace8..9e46bcc84 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/LabelGeometry.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/LabelGeometry.cs @@ -123,6 +123,7 @@ public override void OnDraw(SkiaSharpDrawingContext context, SKPaint paint) context.Paint.TextSize = TextSize; var verticalPos = 0f; + var shaper = paint.Typeface is not null ? new SKShaper(paint.Typeface) : null; foreach (var line in Text.Split(new[] { Environment.NewLine }, StringSplitOptions.None)) { @@ -135,10 +136,9 @@ public override void OnDraw(SkiaSharpDrawingContext context, SKPaint paint) if (paint.Typeface is not null) { - // This needs to be verified. - // this is just a temporal fix to support older versions of LiveCharts - using var eventTextShaper = new SKShaper(paint.Typeface); - context.Canvas.DrawShapedText(line, X + ao.X + p.Left, Y + ao.Y + p.Top + lhd + verticalPos, paint); + paint.Typeface = paint.Typeface; + context.Canvas.DrawShapedText( + shaper, line, X + ao.X + p.Left, Y + ao.Y + p.Top + lhd + verticalPos, paint); } else { @@ -171,6 +171,8 @@ public override void OnDraw(SkiaSharpDrawingContext context, SKPaint paint) verticalPos += textBounds.Height * LineHeight; } + + shaper?.Dispose(); } /// From 5d520be1ac0bf3ab9e14e6e07657945e0837a2fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Tue, 25 Jul 2023 18:11:20 -0600 Subject: [PATCH 09/54] ltr default tooltip tooltips --- .../Kernel/LiveChartsSettings.cs | 16 +++++++++++ .../SKCharts/SKDefaultTooltip.cs | 27 ++++++++++--------- 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/src/LiveChartsCore/Kernel/LiveChartsSettings.cs b/src/LiveChartsCore/Kernel/LiveChartsSettings.cs index 320a38323..a3b4588e3 100644 --- a/src/LiveChartsCore/Kernel/LiveChartsSettings.cs +++ b/src/LiveChartsCore/Kernel/LiveChartsSettings.cs @@ -151,6 +151,11 @@ public class LiveChartsSettings /// public TimeSpan UpdateThrottlingTimeout { get; set; } = TimeSpan.FromMilliseconds(50); + /// + /// Gets or sets a value indicating whether the text is right to left. + /// + public bool IsRightToLeft { get; set; } + /// /// Adds or replaces a mapping for a given type, the mapper defines how a type is mapped to a instance, /// then the will be drawn as a point in our chart. @@ -165,6 +170,17 @@ public LiveChartsSettings HasMap(Action mapper) return this; } + /// + /// Indicates that the library should render tooltips in a right to left mode, you also need to load + /// a right to left font. + /// + /// + public LiveChartsSettings UseRightToLeftSettings() + { + IsRightToLeft = true; + return this; + } + internal Action GetMap() { return !_mappers.TryGetValue(typeof(TModel), out var mapper) diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKDefaultTooltip.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKDefaultTooltip.cs index fe03f760a..672cddb63 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKDefaultTooltip.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKDefaultTooltip.cs @@ -138,25 +138,28 @@ public void Show(IEnumerable foundPoints, Chart { Padding = new(0, 8) }); + _panel.Children.Add( + new StackPanel { Padding = new(0, 8) }); } } var content = point.Context.Series.GetPrimaryToolTipText(point) ?? string.Empty; + var ltr = LiveCharts.DefaultSettings.IsRightToLeft; + if (content != LiveCharts.IgnoreToolTipLabel) { - tableLayout.AddChild(series.GetMiniaturesSketch().AsDrawnControl(), i, 0); + tableLayout.AddChild(series.GetMiniaturesSketch().AsDrawnControl(), i, ltr ? 3 : 0); tableLayout.AddChild( new LabelVisual { @@ -176,7 +179,7 @@ public void Show(IEnumerable foundPoints, Chart Date: Tue, 25 Jul 2023 18:36:40 -0600 Subject: [PATCH 10/54] remove dummy assignment --- .../LiveChartsCore.SkiaSharp/Drawing/Geometries/LabelGeometry.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/LabelGeometry.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/LabelGeometry.cs index 9e46bcc84..9b2dd6f55 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/LabelGeometry.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/LabelGeometry.cs @@ -136,7 +136,6 @@ public override void OnDraw(SkiaSharpDrawingContext context, SKPaint paint) if (paint.Typeface is not null) { - paint.Typeface = paint.Typeface; context.Canvas.DrawShapedText( shaper, line, X + ao.X + p.Left, Y + ao.Y + p.Top + lhd + verticalPos, paint); } From 41a9b6b2f9b81309959027e2fbe54ac371ef3a96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Tue, 25 Jul 2023 18:37:50 -0600 Subject: [PATCH 11/54] sort methods by modifier --- .../Drawing/Geometries/LabelGeometry.cs | 58 +++++++++---------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/LabelGeometry.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/LabelGeometry.cs index 9b2dd6f55..a1a127c02 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/LabelGeometry.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/LabelGeometry.cs @@ -84,35 +84,6 @@ public LabelGeometry() public static bool ShowDebugLines { get; set; } #endif - private LvcPoint GetAlignmentOffset(SKRect bounds) - { - var p = Padding; - - var w = bounds.Width + p.Left + p.Right; - var h = bounds.Height * LineHeight + p.Top + p.Bottom; - - float l = -bounds.Left, t = -bounds.Top; - - switch (VerticalAlign) - { - case Align.Start: t += 0; break; - case Align.Middle: t -= h * 0.5f; break; - case Align.End: t -= h + 0; break; - default: - break; - } - switch (HorizontalAlign) - { - case Align.Start: l += 0; break; - case Align.Middle: l -= w * 0.5f; break; - case Align.End: l -= w + 0; break; - default: - break; - } - - return new(l, t); - } - /// public override void OnDraw(SkiaSharpDrawingContext context, SKPaint paint) { @@ -212,4 +183,33 @@ protected override LvcSize OnMeasure(IPaint paint) w + Padding.Left + Padding.Right, h + Padding.Top + Padding.Bottom); } + + private LvcPoint GetAlignmentOffset(SKRect bounds) + { + var p = Padding; + + var w = bounds.Width + p.Left + p.Right; + var h = bounds.Height * LineHeight + p.Top + p.Bottom; + + float l = -bounds.Left, t = -bounds.Top; + + switch (VerticalAlign) + { + case Align.Start: t += 0; break; + case Align.Middle: t -= h * 0.5f; break; + case Align.End: t -= h + 0; break; + default: + break; + } + switch (HorizontalAlign) + { + case Align.Start: l += 0; break; + case Align.Middle: l -= w * 0.5f; break; + case Align.End: l -= w + 0; break; + default: + break; + } + + return new(l, t); + } } From 72c25319a55e8cd5a6657f622e4f645a9a990838 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Wed, 26 Jul 2023 08:40:48 -0600 Subject: [PATCH 12/54] remove obsolete miniatureequals --- src/LiveChartsCore/ChartSeries.cs | 3 --- src/LiveChartsCore/Drawing/ISvgPath.cs | 4 ++++ src/LiveChartsCore/FinancialSeries.cs | 9 --------- src/LiveChartsCore/HeatSeries.cs | 7 ------- src/LiveChartsCore/ISeries.cs | 3 ++- src/LiveChartsCore/Kernel/Sketches/IChartSeries.cs | 7 ------- src/LiveChartsCore/LineSeries.cs | 9 --------- src/LiveChartsCore/PieSeries.cs | 7 ------- src/LiveChartsCore/PolarLineSeries.cs | 7 ------- src/LiveChartsCore/StepLineSeries.cs | 9 --------- src/LiveChartsCore/StrokeAndFillCartesianSeries.cs | 7 ------- 11 files changed, 6 insertions(+), 66 deletions(-) diff --git a/src/LiveChartsCore/ChartSeries.cs b/src/LiveChartsCore/ChartSeries.cs index c78b30784..6e9ebae86 100644 --- a/src/LiveChartsCore/ChartSeries.cs +++ b/src/LiveChartsCore/ChartSeries.cs @@ -72,9 +72,6 @@ public IPaint? DataLabelsPaint /// public bool IsFirstDraw { get; protected set; } = true; - /// - public abstract bool MiniatureEquals(IChartSeries instance); - void IChartSeries.OnDataPointerDown(IChartView chart, IEnumerable points, LvcPoint pointer) { OnDataPointerDown(chart, points, pointer); diff --git a/src/LiveChartsCore/Drawing/ISvgPath.cs b/src/LiveChartsCore/Drawing/ISvgPath.cs index b25c94da6..484b317a8 100644 --- a/src/LiveChartsCore/Drawing/ISvgPath.cs +++ b/src/LiveChartsCore/Drawing/ISvgPath.cs @@ -28,5 +28,9 @@ namespace LiveChartsCore.Drawing; public interface ISvgPath : ISizedGeometry where TDrawingContext : DrawingContext { + /// + /// Called when the path changed. + /// + /// the path. void OnPathChanged(string path); } diff --git a/src/LiveChartsCore/FinancialSeries.cs b/src/LiveChartsCore/FinancialSeries.cs index 4eaad335d..a6b16329a 100644 --- a/src/LiveChartsCore/FinancialSeries.cs +++ b/src/LiveChartsCore/FinancialSeries.cs @@ -485,15 +485,6 @@ protected override void OnPaintChanged(string? propertyName) OnPropertyChanged(); } - /// - public override bool MiniatureEquals(IChartSeries series) - { - return series is FinancialSeries financial && - Name == series.Name && - UpFill == financial.UpFill && UpStroke == financial.UpStroke && - DownFill == financial.DownFill && DownStroke == financial.DownStroke; - } - /// public override Sketch GetMiniaturesSketch() { diff --git a/src/LiveChartsCore/HeatSeries.cs b/src/LiveChartsCore/HeatSeries.cs index 6295b36bd..be15e3e68 100644 --- a/src/LiveChartsCore/HeatSeries.cs +++ b/src/LiveChartsCore/HeatSeries.cs @@ -342,13 +342,6 @@ public override Sketch GetMiniaturesSketch() }; } - /// - public override bool MiniatureEquals(IChartSeries instance) - { - return instance is HeatSeries hSeries - && Name == instance.Name && HeatMap == hSeries.HeatMap; - } - /// internal override IPaint?[] GetPaintTasks() { diff --git a/src/LiveChartsCore/ISeries.cs b/src/LiveChartsCore/ISeries.cs index 81333e358..a15a22389 100644 --- a/src/LiveChartsCore/ISeries.cs +++ b/src/LiveChartsCore/ISeries.cs @@ -121,7 +121,8 @@ public interface ISeries double Pivot { get; set; } /// - /// Gets or sets the series geometry svg. + /// Gets or sets the series geometry svg, this property requires the series visual to be + /// an instance. /// string? GeometrySvg { get; set; } diff --git a/src/LiveChartsCore/Kernel/Sketches/IChartSeries.cs b/src/LiveChartsCore/Kernel/Sketches/IChartSeries.cs index cf350b907..624cec34d 100644 --- a/src/LiveChartsCore/Kernel/Sketches/IChartSeries.cs +++ b/src/LiveChartsCore/Kernel/Sketches/IChartSeries.cs @@ -85,13 +85,6 @@ public interface IChartSeries : ISeries, IChartElement int GetStackGroup(); - /// - /// Determines if the given instance has the same series miniature. - /// - /// The instance to compare. - /// - bool MiniatureEquals(IChartSeries instance); - /// /// /// diff --git a/src/LiveChartsCore/LineSeries.cs b/src/LiveChartsCore/LineSeries.cs index 326117e39..f274204ae 100644 --- a/src/LiveChartsCore/LineSeries.cs +++ b/src/LiveChartsCore/LineSeries.cs @@ -430,15 +430,6 @@ protected override double GetRequestedGeometrySize() return (GeometrySize + (GeometryStroke?.StrokeThickness ?? 0)) * 0.5f; } - /// - public override bool MiniatureEquals(IChartSeries series) - { - return series is LineSeries lineSeries && - Name == series.Name && - Fill == lineSeries.Fill && Stroke == lineSeries.Stroke && - GeometryFill == lineSeries.GeometryFill && GeometryStroke == lineSeries.GeometryStroke; - } - /// public override Sketch GetMiniaturesSketch() { diff --git a/src/LiveChartsCore/PieSeries.cs b/src/LiveChartsCore/PieSeries.cs index 061536c50..1c8bf739f 100644 --- a/src/LiveChartsCore/PieSeries.cs +++ b/src/LiveChartsCore/PieSeries.cs @@ -517,13 +517,6 @@ protected override void OnPointerLeft(ChartPoint point) base.OnPointerLeft(point); } - /// - public override bool MiniatureEquals(IChartSeries instance) - { - return instance is PieSeries pieSeries && - Name == pieSeries.Name && Fill == pieSeries.Fill && Stroke == pieSeries.Stroke; - } - /// /// Sets the default point transitions. /// diff --git a/src/LiveChartsCore/PolarLineSeries.cs b/src/LiveChartsCore/PolarLineSeries.cs index b12a7a081..659af00fa 100644 --- a/src/LiveChartsCore/PolarLineSeries.cs +++ b/src/LiveChartsCore/PolarLineSeries.cs @@ -569,13 +569,6 @@ public override Sketch GetMiniaturesSketch() return label; } - /// - public override bool MiniatureEquals(IChartSeries series) - { - return series is StrokeAndFillCartesianSeries sfSeries && - Name == series.Name && Fill == sfSeries.Fill && Stroke == sfSeries.Stroke; - } - /// /// Builds an spline from the given points. /// diff --git a/src/LiveChartsCore/StepLineSeries.cs b/src/LiveChartsCore/StepLineSeries.cs index 85b991e9c..4567a4f37 100644 --- a/src/LiveChartsCore/StepLineSeries.cs +++ b/src/LiveChartsCore/StepLineSeries.cs @@ -379,15 +379,6 @@ public override Sketch GetMiniaturesSketch() }; } - /// - public override bool MiniatureEquals(IChartSeries series) - { - return series is StepLineSeries stepSeries && - Name == series.Name && - Fill == stepSeries.Fill && Stroke == stepSeries.Stroke && - GeometryFill == stepSeries.GeometryFill && GeometryStroke == stepSeries.GeometryStroke; - } - /// protected override void OnPointerEnter(ChartPoint point) { diff --git a/src/LiveChartsCore/StrokeAndFillCartesianSeries.cs b/src/LiveChartsCore/StrokeAndFillCartesianSeries.cs index d59501fcb..ee013c879 100644 --- a/src/LiveChartsCore/StrokeAndFillCartesianSeries.cs +++ b/src/LiveChartsCore/StrokeAndFillCartesianSeries.cs @@ -84,11 +84,4 @@ public IPaint? Fill { return new[] { _stroke, _fill, DataLabelsPaint }; } - - /// - public override bool MiniatureEquals(IChartSeries series) - { - return series is StrokeAndFillCartesianSeries sfSeries && - Name == series.Name && Fill == sfSeries.Fill && Stroke == sfSeries.Stroke; - } } From 072cf80f03a6a086cf093f7333bf80230033f3d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Wed, 26 Jul 2023 08:57:29 -0600 Subject: [PATCH 13/54] center line geometry on remove --- src/LiveChartsCore/LineSeries.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/LiveChartsCore/LineSeries.cs b/src/LiveChartsCore/LineSeries.cs index f274204ae..ab3f36afe 100644 --- a/src/LiveChartsCore/LineSeries.cs +++ b/src/LiveChartsCore/LineSeries.cs @@ -620,8 +620,8 @@ protected internal override void SoftDeleteOrDisposePoint(ChartPoint point, Scal var x = secondaryScale.ToPixels(c.SecondaryValue); var y = primaryScale.ToPixels(c.PrimaryValue); - visual.Geometry.X = x; - visual.Geometry.Y = y; + visual.Geometry.X = x + visual.Geometry.Width * 0.5f; + visual.Geometry.Y = y + visual.Geometry.Height * 0.5f; visual.Geometry.Height = 0; visual.Geometry.Width = 0; visual.Geometry.RemoveOnCompleted = true; From 3d9c822c89004a2f889cfb28d654ae2bcdfa980d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Wed, 26 Jul 2023 09:04:48 -0600 Subject: [PATCH 14/54] center step line geometry on remove --- src/LiveChartsCore/StepLineSeries.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/LiveChartsCore/StepLineSeries.cs b/src/LiveChartsCore/StepLineSeries.cs index 4567a4f37..999662a44 100644 --- a/src/LiveChartsCore/StepLineSeries.cs +++ b/src/LiveChartsCore/StepLineSeries.cs @@ -432,8 +432,8 @@ protected internal override void SoftDeleteOrDisposePoint(ChartPoint point, Scal var x = secondaryScale.ToPixels(coordinate.SecondaryValue); var y = primaryScale.ToPixels(coordinate.PrimaryValue); - visual.Geometry.X = x; - visual.Geometry.Y = y; + visual.Geometry.X = x + visual.Geometry.Width * 0.5f; + visual.Geometry.Y = y + visual.Geometry.Height * 0.5f; visual.Geometry.Height = 0; visual.Geometry.Width = 0; visual.Geometry.RemoveOnCompleted = true; From 95123ac7c84f56c560498105cdb24a07b65ddce5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Wed, 26 Jul 2023 09:15:46 -0600 Subject: [PATCH 15/54] avvalonia default buttons style --- samples/AvaloniaSample/App.axaml | 38 ++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/samples/AvaloniaSample/App.axaml b/samples/AvaloniaSample/App.axaml index 65b171c20..4cc746a9b 100644 --- a/samples/AvaloniaSample/App.axaml +++ b/samples/AvaloniaSample/App.axaml @@ -4,4 +4,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From d7a24f0f40cd09169468dc4e57e0724568b825ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Wed, 26 Jul 2023 09:29:45 -0600 Subject: [PATCH 16/54] center row and column on remove --- src/LiveChartsCore/ColumnSeries.cs | 2 +- src/LiveChartsCore/RowSeries.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/LiveChartsCore/ColumnSeries.cs b/src/LiveChartsCore/ColumnSeries.cs index 7efd9333b..0a36ac665 100644 --- a/src/LiveChartsCore/ColumnSeries.cs +++ b/src/LiveChartsCore/ColumnSeries.cs @@ -300,7 +300,7 @@ protected internal override void SoftDeleteOrDisposePoint(ChartPoint point, Scal var p = primaryScale.ToPixels(pivot); var secondary = secondaryScale.ToPixels(point.Coordinate.SecondaryValue); - visual.X = secondary; + visual.X = secondary - visual.Width * 0.5f; visual.Y = p; visual.Height = 0; visual.RemoveOnCompleted = true; diff --git a/src/LiveChartsCore/RowSeries.cs b/src/LiveChartsCore/RowSeries.cs index f98dd8472..4818c2964 100644 --- a/src/LiveChartsCore/RowSeries.cs +++ b/src/LiveChartsCore/RowSeries.cs @@ -302,7 +302,7 @@ protected internal override void SoftDeleteOrDisposePoint(ChartPoint point, Scal var secondary = secondaryScale.ToPixels(point.Coordinate.SecondaryValue); visual.X = p; - visual.Y = secondary; + visual.Y = secondary - visual.Height * 0.5f; visual.Width = 0; visual.RemoveOnCompleted = true; From 30d3241034f09eea1756ccb61c6e794f800e33ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Wed, 26 Jul 2023 13:38:18 -0600 Subject: [PATCH 17/54] avalonia style --- samples/AvaloniaSample/App.axaml | 25 ++++--------------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/samples/AvaloniaSample/App.axaml b/samples/AvaloniaSample/App.axaml index 4cc746a9b..d0f5576d0 100644 --- a/samples/AvaloniaSample/App.axaml +++ b/samples/AvaloniaSample/App.axaml @@ -4,29 +4,9 @@ - - - - - - - - - - - - - - - - - + @@ -41,5 +21,8 @@ + + + From 89adc5aa79674217264aadfda63dc6001d5c62e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Wed, 26 Jul 2023 13:39:41 -0600 Subject: [PATCH 18/54] ignore series name when not set --- src/LiveChartsCore/LiveCharts.cs | 7 ++++- .../SKCharts/SKDefaultTooltip.cs | 25 +++++++++------- .../ThemesExtensions.cs | 30 +++++-------------- 3 files changed, 28 insertions(+), 34 deletions(-) diff --git a/src/LiveChartsCore/LiveCharts.cs b/src/LiveChartsCore/LiveCharts.cs index 84d792414..98ad685d8 100644 --- a/src/LiveChartsCore/LiveCharts.cs +++ b/src/LiveChartsCore/LiveCharts.cs @@ -33,7 +33,12 @@ public static class LiveCharts /// /// A constant that indicates that the tool tip should not add the current label. /// - public static string IgnoreToolTipLabel { get; } = "{{please-ignore-me}}"; + public static string IgnoreToolTipLabel { get; } = $"{{{nameof(IgnoreToolTipLabel)}}}"; + + /// + /// A constant that indicates that the tool tip should ignore the series name. + /// + public static string IgnoreSeriesName { get; } = "{{Series Name not set}}"; /// /// Gets a value indicating whether LiveCharts should create a log as it renders the charts. diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKDefaultTooltip.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKDefaultTooltip.cs index 672cddb63..bb2c51872 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKDefaultTooltip.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/SKCharts/SKDefaultTooltip.cs @@ -160,23 +160,26 @@ public void Show(IEnumerable foundPoints, Chart + { + series.Name = LiveCharts.IgnoreSeriesName; + }) .HasRuleForLineSeries(lineSeries => { var color = theme.GetSeriesColor(lineSeries).AsSKColor(); - lineSeries.Name = $"Series #{lineSeries.SeriesId + 1}"; lineSeries.GeometrySize = 12; lineSeries.GeometryStroke = new SolidColorPaint(color, 4); lineSeries.GeometryFill = new SolidColorPaint(new SKColor(250, 250, 250)); @@ -91,7 +94,6 @@ public static LiveChartsSettings AddLightTheme( { var color = theme.GetSeriesColor(steplineSeries).AsSKColor(); - steplineSeries.Name = $"Series #{steplineSeries.SeriesId + 1}"; steplineSeries.GeometrySize = 12; steplineSeries.GeometryStroke = new SolidColorPaint(color, 4); steplineSeries.GeometryFill = new SolidColorPaint(new SKColor(250, 250, 250)); @@ -102,7 +104,6 @@ public static LiveChartsSettings AddLightTheme( { var color = theme.GetSeriesColor(stackedLine).AsSKColor(); - stackedLine.Name = $"Series #{stackedLine.SeriesId + 1}"; stackedLine.GeometrySize = 0; stackedLine.GeometryStroke = null; stackedLine.GeometryFill = null; @@ -113,7 +114,6 @@ public static LiveChartsSettings AddLightTheme( { var color = theme.GetSeriesColor(barSeries).AsSKColor(); - barSeries.Name = $"Series #{barSeries.SeriesId + 1}"; barSeries.Stroke = null; barSeries.Fill = new SolidColorPaint(color); barSeries.Rx = 4; @@ -123,7 +123,6 @@ public static LiveChartsSettings AddLightTheme( { var color = theme.GetSeriesColor(stackedBarSeries).AsSKColor(); - stackedBarSeries.Name = $"Series #{stackedBarSeries.SeriesId + 1}"; stackedBarSeries.Stroke = null; stackedBarSeries.Fill = new SolidColorPaint(color); stackedBarSeries.Rx = 0; @@ -133,7 +132,6 @@ public static LiveChartsSettings AddLightTheme( { var color = theme.GetSeriesColor(stackedStep).AsSKColor(); - stackedStep.Name = $"Series #{stackedStep.SeriesId + 1}"; stackedStep.GeometrySize = 0; stackedStep.GeometryStroke = null; stackedStep.GeometryFill = null; @@ -146,8 +144,6 @@ public static LiveChartsSettings AddLightTheme( }) .HasRuleForFinancialSeries(financialSeries => { - financialSeries.Name = $"Series #{financialSeries.SeriesId + 1}"; - financialSeries.UpFill = new SolidColorPaint(new SKColor(139, 195, 74, 255)); financialSeries.UpStroke = new SolidColorPaint(new SKColor(139, 195, 74, 255), 3); financialSeries.DownFill = new SolidColorPaint(new SKColor(239, 83, 80, 255)); @@ -157,7 +153,6 @@ public static LiveChartsSettings AddLightTheme( { var color = theme.GetSeriesColor(scatterSeries).AsSKColor(); - scatterSeries.Name = $"Series #{scatterSeries.SeriesId + 1}"; scatterSeries.Stroke = null; scatterSeries.Fill = new SolidColorPaint(color.WithAlpha(200)); }) @@ -165,7 +160,6 @@ public static LiveChartsSettings AddLightTheme( { var color = theme.GetSeriesColor(pieSeries).AsSKColor(); - pieSeries.Name = $"Series #{pieSeries.SeriesId + 1}"; pieSeries.Stroke = null; pieSeries.Fill = new SolidColorPaint(color); }) @@ -173,7 +167,6 @@ public static LiveChartsSettings AddLightTheme( { var color = theme.GetSeriesColor(polarLine).AsSKColor(); - polarLine.Name = $"Series #{polarLine.SeriesId + 1}"; polarLine.GeometrySize = 12; polarLine.GeometryStroke = new SolidColorPaint(color, 4); polarLine.GeometryFill = new SolidColorPaint(new SKColor(250, 250, 250)); @@ -184,7 +177,6 @@ public static LiveChartsSettings AddLightTheme( { var color = theme.GetSeriesColor(gaugeSeries).AsSKColor(); - gaugeSeries.Name = $"Series #{gaugeSeries.SeriesId + 1}"; gaugeSeries.Stroke = null; gaugeSeries.Fill = new SolidColorPaint(color); gaugeSeries.DataLabelsPosition = PolarLabelsPosition.ChartCenter; @@ -240,11 +232,14 @@ public static LiveChartsSettings AddDarkTheme( axis.SeparatorsPaint = new SolidColorPaint(new SKColor(90, 90, 90)); } }) + .HasRuleForAnySeries(series => + { + series.Name = LiveCharts.IgnoreSeriesName; + }) .HasRuleForLineSeries(lineSeries => { var color = theme.GetSeriesColor(lineSeries).AsSKColor(); - lineSeries.Name = $"Series #{lineSeries.SeriesId + 1}"; lineSeries.GeometrySize = 12; lineSeries.GeometryStroke = new SolidColorPaint(color, 4); lineSeries.GeometryFill = new SolidColorPaint(new SKColor(30, 30, 30)); @@ -255,7 +250,6 @@ public static LiveChartsSettings AddDarkTheme( { var color = theme.GetSeriesColor(steplineSeries).AsSKColor(); - steplineSeries.Name = $"Series #{steplineSeries.SeriesId + 1}"; steplineSeries.GeometrySize = 12; steplineSeries.GeometryStroke = new SolidColorPaint(color, 4); steplineSeries.GeometryFill = new SolidColorPaint(new SKColor(30, 30, 30)); @@ -266,7 +260,6 @@ public static LiveChartsSettings AddDarkTheme( { var color = theme.GetSeriesColor(stackedLine).AsSKColor(); - stackedLine.Name = $"Series #{stackedLine.SeriesId + 1}"; stackedLine.GeometrySize = 0; stackedLine.GeometryStroke = null; stackedLine.GeometryFill = null; @@ -277,7 +270,6 @@ public static LiveChartsSettings AddDarkTheme( { var color = theme.GetSeriesColor(barSeries).AsSKColor(); - barSeries.Name = $"Series #{barSeries.SeriesId + 1}"; barSeries.Stroke = null; barSeries.Fill = new SolidColorPaint(color); barSeries.Rx = 4; @@ -287,7 +279,6 @@ public static LiveChartsSettings AddDarkTheme( { var color = theme.GetSeriesColor(stackedBarSeries).AsSKColor(); - stackedBarSeries.Name = $"Series #{stackedBarSeries.SeriesId + 1}"; stackedBarSeries.Stroke = null; stackedBarSeries.Fill = new SolidColorPaint(color); stackedBarSeries.Rx = 0; @@ -297,7 +288,6 @@ public static LiveChartsSettings AddDarkTheme( { var color = theme.GetSeriesColor(pieSeries).AsSKColor(); - pieSeries.Name = $"Series #{pieSeries.SeriesId + 1}"; pieSeries.Stroke = null; pieSeries.Fill = new SolidColorPaint(color); }) @@ -305,7 +295,6 @@ public static LiveChartsSettings AddDarkTheme( { var color = theme.GetSeriesColor(stackedStep).AsSKColor(); - stackedStep.Name = $"Series #{stackedStep.SeriesId + 1}"; stackedStep.GeometrySize = 0; stackedStep.GeometryStroke = null; stackedStep.GeometryFill = null; @@ -318,7 +307,6 @@ public static LiveChartsSettings AddDarkTheme( }) .HasRuleForFinancialSeries(financialSeries => { - financialSeries.Name = $"Series #{financialSeries.SeriesId + 1}"; financialSeries.UpFill = new SolidColorPaint(new SKColor(139, 195, 74, 255)); financialSeries.UpStroke = new SolidColorPaint(new SKColor(139, 195, 74, 255), 3); financialSeries.DownFill = new SolidColorPaint(new SKColor(239, 83, 80, 255)); @@ -328,7 +316,6 @@ public static LiveChartsSettings AddDarkTheme( { var color = theme.GetSeriesColor(polarLine).AsSKColor(); - polarLine.Name = $"Series #{polarLine.SeriesId + 1}"; polarLine.GeometrySize = 12; polarLine.GeometryStroke = new SolidColorPaint(color, 4); polarLine.GeometryFill = new SolidColorPaint(new SKColor()); @@ -339,7 +326,6 @@ public static LiveChartsSettings AddDarkTheme( { var color = theme.GetSeriesColor(gaugeSeries).AsSKColor(); - gaugeSeries.Name = $"Series #{gaugeSeries.SeriesId + 1}"; gaugeSeries.Stroke = null; gaugeSeries.Fill = new SolidColorPaint(color); gaugeSeries.DataLabelsPaint = new SolidColorPaint(new SKColor(200, 200, 200)); From 256b3867dc10706e3e2b8778a2e23cc15e824cf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Wed, 26 Jul 2023 13:45:51 -0600 Subject: [PATCH 19/54] update custom step line sample --- .../Lines/Custom/ViewModel.cs | 64 +++++++++---------- .../StepLines/Custom/MyGeometry.cs | 19 +++--- .../StepLines/Custom/ViewModel.cs | 64 ++++++++++--------- 3 files changed, 73 insertions(+), 74 deletions(-) diff --git a/samples/ViewModelsSamples/Lines/Custom/ViewModel.cs b/samples/ViewModelsSamples/Lines/Custom/ViewModel.cs index baca7046f..b44e4cb00 100644 --- a/samples/ViewModelsSamples/Lines/Custom/ViewModel.cs +++ b/samples/ViewModelsSamples/Lines/Custom/ViewModel.cs @@ -9,40 +9,40 @@ namespace ViewModelsSamples.Lines.Custom; public partial class ViewModel : ObservableObject { public ISeries[] Series { get; set; } = + { + new LineSeries { - new LineSeries - { - Values = new double[] { 2, 1, 4, 2, 2, -5, -2 }, - Fill = null, - GeometrySize = 20 - }, + Values = new double[] { 2, 1, 4, 2, 2, -5, -2 }, + Fill = null, + GeometrySize = 20 + }, - // use the second type parameter to specify the geometry to draw for every point - // there are already many predefined geometries in the - // LiveChartsCore.SkiaSharpView.Drawing.Geometries namespace - new LineSeries - { - Values = new double[] { 3, 3, -3, -2, -4, -3, -1 }, - Fill = null, - GeometrySize = 20 - }, + // use the second type parameter to specify the geometry to draw for every point + // there are already many predefined geometries in the + // LiveChartsCore.SkiaSharpView.Drawing.Geometries namespace + new LineSeries + { + Values = new double[] { 3, 3, -3, -2, -4, -3, -1 }, + Fill = null, + GeometrySize = 20 + }, - // You can also use SVG paths to draw the geometry - // LiveCharts already provides some predefined paths in the SVGPoints class. - new LineSeries - { - Values = new double[] { -2, 2, 1, 3, -1, 4, 3 }, - Fill = null, - GeometrySvg = SVGPoints.Star, - GeometrySize = 20 - }, + // You can also use SVG paths to draw the geometry + // LiveCharts already provides some predefined paths in the SVGPoints class. + new LineSeries + { + Values = new double[] { -2, 2, 1, 3, -1, 4, 3 }, + Fill = null, + GeometrySvg = SVGPoints.Star, + GeometrySize = 20 + }, - // you can declare your own gemetry and use the SkiaSharp api to draw it - new LineSeries - { - Values = new double[] { 4, 5, 2, 4, 3, 2, 1 }, - Fill = null, - GeometrySize = 20 - }, - }; + // you can declare your own gemetry and use the SkiaSharp api to draw it + new LineSeries + { + Values = new double[] { 4, 5, 2, 4, 3, 2, 1 }, + Fill = null, + GeometrySize = 20 + }, + }; } diff --git a/samples/ViewModelsSamples/StepLines/Custom/MyGeometry.cs b/samples/ViewModelsSamples/StepLines/Custom/MyGeometry.cs index 9761fd90e..491a14707 100644 --- a/samples/ViewModelsSamples/StepLines/Custom/MyGeometry.cs +++ b/samples/ViewModelsSamples/StepLines/Custom/MyGeometry.cs @@ -1,20 +1,17 @@ -using System; +using LiveChartsCore.SkiaSharpView.Drawing; +using LiveChartsCore.SkiaSharpView.Drawing.Geometries; using SkiaSharp; namespace ViewModelsSamples.StepLines.Custom; -public class MyGeometry : LiveChartsCore.SkiaSharpView.Drawing.Geometries.SVGPathGeometry +public class MyGeometry : SizedGeometry { - public MyGeometry() - : base(() => SelectedPath ?? throw new NotImplementedException("Path not set yet!")) + public override void OnDraw(SkiaSharpDrawingContext context, SKPaint paint) { - // we passed the "path source" to the base class - // it is a function that returns the path to draw - // this way we can change the path at runtime + var canvas = context.Canvas; - // Note: LiveCharts geometries do not implement INotifyPropertyChanged - // so if you change the path at runtime you will need to call a chart update. + canvas.DrawRect(X, Y, Width, Height, paint); + canvas.DrawLine(X, Y, X + Width, Y + Height, paint); + canvas.DrawLine(X + Width, Y, X, Y + Height, paint); } - - public static SKPath? SelectedPath { get; set; } } diff --git a/samples/ViewModelsSamples/StepLines/Custom/ViewModel.cs b/samples/ViewModelsSamples/StepLines/Custom/ViewModel.cs index 8f026e6e7..cc24a2fb3 100644 --- a/samples/ViewModelsSamples/StepLines/Custom/ViewModel.cs +++ b/samples/ViewModelsSamples/StepLines/Custom/ViewModel.cs @@ -1,46 +1,48 @@ using CommunityToolkit.Mvvm.ComponentModel; using LiveChartsCore; +using LiveChartsCore.Drawing; using LiveChartsCore.SkiaSharpView; using LiveChartsCore.SkiaSharpView.Drawing.Geometries; -using LiveChartsCore.SkiaSharpView.Painting; -using SkiaSharp; namespace ViewModelsSamples.StepLines.Custom; public partial class ViewModel : ObservableObject { - public ViewModel() + public ISeries[] Series { get; set; } = { - Series = new ISeries[] + new StepLineSeries { - new StepLineSeries - { - Values = new double[] { 3, 1, 4, 3, 2, -5, -2 }, - GeometrySize = 10, - Fill = null - }, + Values = new double[] { 2, 1, 4, 2, 2, -5, -2 }, + Fill = null, + GeometrySize = 20 + }, - // use the second argument type to specify the geometry to draw for every point - // there are already many predefined geometries in the - // LiveChartsCore.SkiaSharpView.Drawing.Geometries namespace - new StepLineSeries - { - Values = new double[] { 3, 3, -3, -2, -4, -3, -1 }, - Fill = null - }, - - new StepLineSeries - { - Values = new double[] { -2, 2, 1, 3, -1, 4, 3 }, + // use the second type parameter to specify the geometry to draw for every point + // there are already many predefined geometries in the + // LiveChartsCore.SkiaSharpView.Drawing.Geometries namespace + new StepLineSeries + { + Values = new double[] { 3, 3, -3, -2, -4, -3, -1 }, + Fill = null, + GeometrySize = 20 + }, - Stroke = new SolidColorPaint(SKColors.DarkOliveGreen, 3), - Fill = null, - GeometryStroke = new SolidColorPaint(SKColors.DarkOliveGreen, 3), - GeometryFill = new SolidColorPaint(SKColors.White), - GeometrySize = 35 - } - }; - } + // You can also use SVG paths to draw the geometry + // LiveCharts already provides some predefined paths in the SVGPoints class. + new StepLineSeries + { + Values = new double[] { -2, 2, 1, 3, -1, 4, 3 }, + Fill = null, + GeometrySvg = SVGPoints.Star, + GeometrySize = 20 + }, - public ISeries[] Series { get; set; } + // you can declare your own gemetry and use the SkiaSharp api to draw it + new StepLineSeries + { + Values = new double[] { 4, 5, 2, 4, 3, 2, 1 }, + Fill = null, + GeometrySize = 20 + }, + }; } From 0d546a83bdad7a6d399855730131f583048ad2d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Wed, 26 Jul 2023 13:53:14 -0600 Subject: [PATCH 20/54] update legend samples --- samples/ViewModelsSamples/Design/LinearGradients/ViewModel.cs | 2 ++ samples/ViewModelsSamples/Design/RadialGradients/ViewModel.cs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/samples/ViewModelsSamples/Design/LinearGradients/ViewModel.cs b/samples/ViewModelsSamples/Design/LinearGradients/ViewModel.cs index e99e01eb7..23f32f9d0 100644 --- a/samples/ViewModelsSamples/Design/LinearGradients/ViewModel.cs +++ b/samples/ViewModelsSamples/Design/LinearGradients/ViewModel.cs @@ -16,6 +16,7 @@ public partial class ViewModel : ObservableObject { new ColumnSeries { + Name = "John", Values = new []{ 3, 7, 2, 9, 4 }, Stroke = null, @@ -47,6 +48,7 @@ public partial class ViewModel : ObservableObject }, new LineSeries { + Name = "Charles", Values = new []{ 4, 2, 8, 5, 3 }, GeometrySize = 22, Stroke = new LinearGradientPaint(new[]{ new SKColor(45, 64, 89), new SKColor(255, 212, 96)}) { StrokeThickness = 10 }, diff --git a/samples/ViewModelsSamples/Design/RadialGradients/ViewModel.cs b/samples/ViewModelsSamples/Design/RadialGradients/ViewModel.cs index a773dc6fc..eb55f45c0 100644 --- a/samples/ViewModelsSamples/Design/RadialGradients/ViewModel.cs +++ b/samples/ViewModelsSamples/Design/RadialGradients/ViewModel.cs @@ -28,6 +28,7 @@ public partial class ViewModel : ObservableObject { new PieSeries { + Name = "Maria", Values = new []{ 7 }, Stroke = null, Fill = new RadialGradientPaint(s_colors), @@ -36,6 +37,7 @@ public partial class ViewModel : ObservableObject }, new PieSeries { + Name = "Charles", Values = new []{ 3 }, Stroke = null, Fill = new RadialGradientPaint(new SKColor(255, 205, 210), new SKColor(183, 28, 28)) From b17439393a4a928011724498df586c07829f4078 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Wed, 26 Jul 2023 13:54:54 -0600 Subject: [PATCH 21/54] make basic pie sample actually basic. --- .../ViewModelsSamples/Pies/Basic/ViewModel.cs | 33 ++----------------- 1 file changed, 2 insertions(+), 31 deletions(-) diff --git a/samples/ViewModelsSamples/Pies/Basic/ViewModel.cs b/samples/ViewModelsSamples/Pies/Basic/ViewModel.cs index a94235570..51443c0c7 100644 --- a/samples/ViewModelsSamples/Pies/Basic/ViewModel.cs +++ b/samples/ViewModelsSamples/Pies/Basic/ViewModel.cs @@ -10,37 +10,8 @@ namespace ViewModelsSamples.Pies.Basic; public partial class ViewModel : ObservableObject { - public ViewModel() - { - // you could convert any IEnumerable to a pie series collection - var data = new double[] { 2, 4, 1, 4, 3 }; - - // Series = data.AsLiveChartsPieSeries(); this could be enough in some cases // mark - - // but you can customize the series properties using the following overload: // mark - Series = data.AsPieSeries((value, series) => - { - // here you can configure the series assigned to each value. - series.Name = $"Series for value {value}"; - series.DataLabelsPaint = new SolidColorPaint(new SKColor(30, 30, 30)); - series.DataLabelsPosition = LiveChartsCore.Measure.PolarLabelsPosition.Outer; - series.DataLabelsFormatter = - p => $"{p.Coordinate.PrimaryValue} / {p.StackedValue!.Total} ({p.StackedValue.Share:P2})"; - series.ToolTipLabelFormatter = p => $"{p.Coordinate.PrimaryValue:C2}"; - }); - - // this is an equivalent and more verbose syntax. // mark - // Series = new ISeries[] - // { - // new PieSeries { Values = new double[] { 2 }, Name = "Slice 1" }, - // new PieSeries { Values = new double[] { 4 }, Name = "Slice 2" }, - // new PieSeries { Values = new double[] { 1 }, Name = "Slice 3" }, - // new PieSeries { Values = new double[] { 4 }, Name = "Slice 4" }, - // new PieSeries { Values = new double[] { 3 }, Name = "Slice 5" } - // }; - } - - public IEnumerable Series { get; set; } + public IEnumerable Series { get; set; } = + new[] { 2, 4, 1, 4, 3 }.AsPieSeries(); public LabelVisual Title { get; set; } = new LabelVisual From 19b469461340a3b4cfd205ee601ef356d5091219 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Wed, 26 Jul 2023 13:57:22 -0600 Subject: [PATCH 22/54] remove legend from basic pie sample --- samples/AvaloniaSample/Pies/Basic/View.axaml | 2 +- samples/BlazorSample/Pages/Pies/Basic.razor | 1 - samples/EtoFormsSample/Pies/Basic/View.cs | 3 +-- samples/MauiSample/Pies/Basic/View.xaml | 3 +-- samples/UWPSample/Pies/Basic/View.xaml | 2 +- .../UnoPlatformSample/LiveChartsSamples/Pies/Basic/View.xaml | 3 +-- samples/WPFSample/Pies/Basic/View.xaml | 3 +-- samples/WinFormsSample/Pies/Basic/View.cs | 1 - .../XamarinSample/XamarinSample/Pies/Basic/View.xaml | 1 - 9 files changed, 6 insertions(+), 13 deletions(-) diff --git a/samples/AvaloniaSample/Pies/Basic/View.axaml b/samples/AvaloniaSample/Pies/Basic/View.axaml index cdc03b14a..17baa9c3e 100644 --- a/samples/AvaloniaSample/Pies/Basic/View.axaml +++ b/samples/AvaloniaSample/Pies/Basic/View.axaml @@ -8,5 +8,5 @@ - + diff --git a/samples/BlazorSample/Pages/Pies/Basic.razor b/samples/BlazorSample/Pages/Pies/Basic.razor index 28a7bf7b5..fbf985ddf 100644 --- a/samples/BlazorSample/Pages/Pies/Basic.razor +++ b/samples/BlazorSample/Pages/Pies/Basic.razor @@ -4,7 +4,6 @@ diff --git a/samples/EtoFormsSample/Pies/Basic/View.cs b/samples/EtoFormsSample/Pies/Basic/View.cs index 43380763a..626a88c99 100644 --- a/samples/EtoFormsSample/Pies/Basic/View.cs +++ b/samples/EtoFormsSample/Pies/Basic/View.cs @@ -15,8 +15,7 @@ public View() pieChart = new PieChart { Series = viewModel.Series, - Title = viewModel.Title, - LegendPosition = LiveChartsCore.Measure.LegendPosition.Right, + Title = viewModel.Title }; Content = pieChart; diff --git a/samples/MauiSample/Pies/Basic/View.xaml b/samples/MauiSample/Pies/Basic/View.xaml index 84b680bed..0d23c9069 100644 --- a/samples/MauiSample/Pies/Basic/View.xaml +++ b/samples/MauiSample/Pies/Basic/View.xaml @@ -10,7 +10,6 @@ + Title="{Binding Title}"> diff --git a/samples/UWPSample/Pies/Basic/View.xaml b/samples/UWPSample/Pies/Basic/View.xaml index 2c7135bbb..405136fc0 100644 --- a/samples/UWPSample/Pies/Basic/View.xaml +++ b/samples/UWPSample/Pies/Basic/View.xaml @@ -9,5 +9,5 @@ - + diff --git a/samples/UnoPlatformSample/UnoPlatformSample/LiveChartsSamples/Pies/Basic/View.xaml b/samples/UnoPlatformSample/UnoPlatformSample/LiveChartsSamples/Pies/Basic/View.xaml index 03e2cfb26..be0b554cb 100644 --- a/samples/UnoPlatformSample/UnoPlatformSample/LiveChartsSamples/Pies/Basic/View.xaml +++ b/samples/UnoPlatformSample/UnoPlatformSample/LiveChartsSamples/Pies/Basic/View.xaml @@ -11,7 +11,6 @@ + Title="{Binding Title}"> diff --git a/samples/WPFSample/Pies/Basic/View.xaml b/samples/WPFSample/Pies/Basic/View.xaml index eba0ea309..25583cfca 100644 --- a/samples/WPFSample/Pies/Basic/View.xaml +++ b/samples/WPFSample/Pies/Basic/View.xaml @@ -8,7 +8,6 @@ + Title="{Binding Title}"> diff --git a/samples/WinFormsSample/Pies/Basic/View.cs b/samples/WinFormsSample/Pies/Basic/View.cs index 5c92191e1..2989f18ef 100644 --- a/samples/WinFormsSample/Pies/Basic/View.cs +++ b/samples/WinFormsSample/Pies/Basic/View.cs @@ -19,7 +19,6 @@ public View() { Series = viewModel.Series, Title= viewModel.Title, - LegendPosition = LiveChartsCore.Measure.LegendPosition.Right, // out of livecharts properties... Location = new System.Drawing.Point(0, 0), diff --git a/samples/XamarinSample/XamarinSample/XamarinSample/Pies/Basic/View.xaml b/samples/XamarinSample/XamarinSample/XamarinSample/Pies/Basic/View.xaml index 5eb8d3d60..42d0fa6e4 100644 --- a/samples/XamarinSample/XamarinSample/XamarinSample/Pies/Basic/View.xaml +++ b/samples/XamarinSample/XamarinSample/XamarinSample/Pies/Basic/View.xaml @@ -9,7 +9,6 @@ From 9500a83a0c4fa2f80e91ce3e670b92d32de5c661 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Wed, 26 Jul 2023 14:01:34 -0600 Subject: [PATCH 23/54] remove processing sample --- samples/ViewModelsSamples/Index.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/ViewModelsSamples/Index.cs b/samples/ViewModelsSamples/Index.cs index dbfee37f1..3b8901659 100644 --- a/samples/ViewModelsSamples/Index.cs +++ b/samples/ViewModelsSamples/Index.cs @@ -42,7 +42,7 @@ public static class Index "Pies/Basic", "Pies/AutoUpdate", - "Pies/Processing", + //"Pies/Processing", "Pies/Doughnut", "Pies/Pushout", "Pies/Custom", From e9d54781d9a47b9d0dc939183dd9742f1b49bacd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Wed, 26 Jul 2023 17:35:20 -0600 Subject: [PATCH 24/54] notify crosshairbackground --- src/LiveChartsCore/Axis.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/LiveChartsCore/Axis.cs b/src/LiveChartsCore/Axis.cs index 0af78aafc..3d6aa9df0 100644 --- a/src/LiveChartsCore/Axis.cs +++ b/src/LiveChartsCore/Axis.cs @@ -88,6 +88,7 @@ public abstract class Axis private ILabelGeometry? _crosshairLabel; private IPaint? _crosshairPaint; private IPaint? _crosshairLabelsPaint; + private LvcColor? _crosshairLabelsBackground; private bool _showSeparatorLines = true; private bool _isVisible = true; private bool _isInverted; @@ -100,7 +101,6 @@ public abstract class Axis private Align? _labelsAlignment; private bool _inLineNamePlacement; private IEnumerable? _customSeparators; - private int _stepCount; #endregion @@ -254,7 +254,11 @@ public IPaint? CrosshairLabelsPaint } /// - public LvcColor? CrosshairLabelsBackground { get; set; } + public LvcColor? CrosshairLabelsBackground + { + get => _crosshairLabelsBackground; + set => SetProperty(ref _crosshairLabelsBackground, value); + } /// public Padding? CrosshairPadding { get; set; } From f068a1c08461fb32168ce4d797962a32e649394b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Wed, 26 Jul 2023 17:53:23 -0600 Subject: [PATCH 25/54] label background --- .../Drawing/Geometries/LabelGeometry.cs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/LabelGeometry.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/LabelGeometry.cs index a1a127c02..9f36764b8 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/LabelGeometry.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/LabelGeometry.cs @@ -93,6 +93,10 @@ public override void OnDraw(SkiaSharpDrawingContext context, SKPaint paint) // for a reason the text size is not set on the InitializeTask() method. context.Paint.TextSize = TextSize; + var p = Padding; + var bg = Background; + + var isFirstLine = true; var verticalPos = 0f; var shaper = paint.Typeface is not null ? new SKShaper(paint.Typeface) : null; @@ -103,7 +107,16 @@ public override void OnDraw(SkiaSharpDrawingContext context, SKPaint paint) var lhd = (textBounds.Height * LineHeight - textBounds.Height) * 0.5f; var ao = GetAlignmentOffset(textBounds); - var p = Padding; + + if (isFirstLine && bg != LvcColor.Empty) + { + var size = OnMeasure(context.PaintTask); + var c = new SKColor(bg.R, bg.G, bg.B, (byte)(bg.A * Opacity)); + using var bgPaint = new SKPaint { Color = c }; + + context.Canvas.DrawRect( + X + ao.X, Y + ao.Y - textBounds.Height, size.Width, size.Height, bgPaint); + } if (paint.Typeface is not null) { @@ -140,6 +153,7 @@ public override void OnDraw(SkiaSharpDrawingContext context, SKPaint paint) #endif verticalPos += textBounds.Height * LineHeight; + isFirstLine = false; } shaper?.Dispose(); From cf52ee2f8a53a762821423e2634648f3c620d05d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Wed, 26 Jul 2023 18:11:39 -0600 Subject: [PATCH 26/54] update wpf crosshair sampl --- .../Axes/Crosshairs/ViewModel.cs | 30 ++----------------- samples/WPFSample/Axes/Crosshairs/View.xaml | 22 ++------------ 2 files changed, 6 insertions(+), 46 deletions(-) diff --git a/samples/ViewModelsSamples/Axes/Crosshairs/ViewModel.cs b/samples/ViewModelsSamples/Axes/Crosshairs/ViewModel.cs index 8dab73776..72da8a684 100644 --- a/samples/ViewModelsSamples/Axes/Crosshairs/ViewModel.cs +++ b/samples/ViewModelsSamples/Axes/Crosshairs/ViewModel.cs @@ -1,26 +1,4 @@ -// 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.ObjectModel; +using System.Collections.ObjectModel; using CommunityToolkit.Mvvm.ComponentModel; using LiveChartsCore; using LiveChartsCore.SkiaSharpView; @@ -47,22 +25,20 @@ public partial class ViewModel : ObservableObject { new Axis { - Name = "XAxis1", CrosshairLabelsBackground = SKColors.DarkOrange.AsLvcColor(), CrosshairLabelsPaint = new SolidColorPaint(SKColors.DarkRed, 1), CrosshairPaint = new SolidColorPaint(SKColors.DarkOrange, 1), - CrosshairSnapEnabled = true + Labeler = value => value.ToString("N2") } }; public Axis[] YAxes { get; set; } = { new Axis { - Name = "YAxis1", CrosshairLabelsBackground = SKColors.DarkOrange.AsLvcColor(), CrosshairLabelsPaint = new SolidColorPaint(SKColors.DarkRed, 1), CrosshairPaint = new SolidColorPaint(SKColors.DarkOrange, 1), - CrosshairSnapEnabled = true + CrosshairSnapEnabled = true // snapping is also supported } }; } diff --git a/samples/WPFSample/Axes/Crosshairs/View.xaml b/samples/WPFSample/Axes/Crosshairs/View.xaml index 913c3fa5e..07498ccf1 100644 --- a/samples/WPFSample/Axes/Crosshairs/View.xaml +++ b/samples/WPFSample/Axes/Crosshairs/View.xaml @@ -7,26 +7,10 @@ - - - - - - - - - - - - - - - - - + YAxes="{Binding YAxes}"> + From 1ba3c68e8c91e4690854a5b64d4c309cbd33cea1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Wed, 26 Jul 2023 18:54:04 -0600 Subject: [PATCH 27/54] add crosshair samples to all platforms --- .../AvaloniaSample/Axes/Crosshairs/View.axaml | 16 +++++ .../Axes/Crosshairs/View.axaml.cs | 17 ++++++ .../BlazorSample/Pages/Axes/Crosshairs.razor | 13 ++++ .../EtoFormsSample/Axes/Crosshairs/View.cs | 24 ++++++++ samples/MauiSample/Axes/Crosshairs/View.xaml | 22 +++++++ .../MauiSample/Axes/Crosshairs/View.xaml.cs | 10 ++++ .../Axes/Crosshairs/View.xaml | 22 +++++++ .../Axes/Crosshairs/View.xaml.cs | 11 ++++ .../Axes/Crosshairs/View.Designer.cs | 46 ++++++++++++++ .../WinFormsSample/Axes/Crosshairs/View.cs | 32 ++++++++++ .../WinFormsSample/Axes/Crosshairs/View.resx | 60 +++++++++++++++++++ .../WinUISample/Axes/Crosshairs/View.xaml | 22 +++++++ .../WinUISample/Axes/Crosshairs/View.xaml.cs | 11 ++++ .../XamarinSample/XamarinSample/App.xaml.cs | 3 +- .../XamarinSample/Axes/Crosshairs/View.xaml | 17 ++++++ .../Axes/Crosshairs/View.xaml.cs | 13 ++++ 16 files changed, 338 insertions(+), 1 deletion(-) create mode 100644 samples/AvaloniaSample/Axes/Crosshairs/View.axaml create mode 100644 samples/AvaloniaSample/Axes/Crosshairs/View.axaml.cs create mode 100644 samples/BlazorSample/Pages/Axes/Crosshairs.razor create mode 100644 samples/EtoFormsSample/Axes/Crosshairs/View.cs create mode 100644 samples/MauiSample/Axes/Crosshairs/View.xaml create mode 100644 samples/MauiSample/Axes/Crosshairs/View.xaml.cs create mode 100644 samples/UnoPlatformSample/UnoPlatformSample/LiveChartsSamples/Axes/Crosshairs/View.xaml create mode 100644 samples/UnoPlatformSample/UnoPlatformSample/LiveChartsSamples/Axes/Crosshairs/View.xaml.cs create mode 100644 samples/WinFormsSample/Axes/Crosshairs/View.Designer.cs create mode 100644 samples/WinFormsSample/Axes/Crosshairs/View.cs create mode 100644 samples/WinFormsSample/Axes/Crosshairs/View.resx create mode 100644 samples/WinUISample/WinUISample/Axes/Crosshairs/View.xaml create mode 100644 samples/WinUISample/WinUISample/Axes/Crosshairs/View.xaml.cs create mode 100644 samples/XamarinSample/XamarinSample/XamarinSample/Axes/Crosshairs/View.xaml create mode 100644 samples/XamarinSample/XamarinSample/XamarinSample/Axes/Crosshairs/View.xaml.cs diff --git a/samples/AvaloniaSample/Axes/Crosshairs/View.axaml b/samples/AvaloniaSample/Axes/Crosshairs/View.axaml new file mode 100644 index 000000000..b9362472e --- /dev/null +++ b/samples/AvaloniaSample/Axes/Crosshairs/View.axaml @@ -0,0 +1,16 @@ + + + + + + + + + diff --git a/samples/AvaloniaSample/Axes/Crosshairs/View.axaml.cs b/samples/AvaloniaSample/Axes/Crosshairs/View.axaml.cs new file mode 100644 index 000000000..8f805927d --- /dev/null +++ b/samples/AvaloniaSample/Axes/Crosshairs/View.axaml.cs @@ -0,0 +1,17 @@ +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace AvaloniaSample.Axes.Crosshairs; + +public class View : UserControl +{ + public View() + { + InitializeComponent(); + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } +} diff --git a/samples/BlazorSample/Pages/Axes/Crosshairs.razor b/samples/BlazorSample/Pages/Axes/Crosshairs.razor new file mode 100644 index 000000000..8fee887e4 --- /dev/null +++ b/samples/BlazorSample/Pages/Axes/Crosshairs.razor @@ -0,0 +1,13 @@ +@page "/Axes/Crosshairs" +@using LiveChartsCore.SkiaSharpView.Blazor +@using ViewModelsSamples.Axes.Crosshairs + + + + +@code { + public ViewModel ViewModel { get; set; } = new(); +} diff --git a/samples/EtoFormsSample/Axes/Crosshairs/View.cs b/samples/EtoFormsSample/Axes/Crosshairs/View.cs new file mode 100644 index 000000000..3b826c229 --- /dev/null +++ b/samples/EtoFormsSample/Axes/Crosshairs/View.cs @@ -0,0 +1,24 @@ +using Eto.Forms; +using LiveChartsCore.SkiaSharpView.Eto; +using ViewModelsSamples.Axes.Crosshairs; + +namespace EtoFormsSample.Axes.Crosshairs; + +public class View : Panel +{ + private readonly CartesianChart cartesianChart; + + public View() + { + var viewModel = new ViewModel(); + + cartesianChart = new CartesianChart + { + Series = viewModel.Series, + XAxes = viewModel.XAxes, + YAxes = viewModel.YAxes, + }; + + Content = new DynamicLayout(cartesianChart); + } +} diff --git a/samples/MauiSample/Axes/Crosshairs/View.xaml b/samples/MauiSample/Axes/Crosshairs/View.xaml new file mode 100644 index 000000000..7a2d9ec72 --- /dev/null +++ b/samples/MauiSample/Axes/Crosshairs/View.xaml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + diff --git a/samples/MauiSample/Axes/Crosshairs/View.xaml.cs b/samples/MauiSample/Axes/Crosshairs/View.xaml.cs new file mode 100644 index 000000000..3810d86f8 --- /dev/null +++ b/samples/MauiSample/Axes/Crosshairs/View.xaml.cs @@ -0,0 +1,10 @@ +namespace MauiSample.Axes.Crosshairs; + +[XamlCompilation(XamlCompilationOptions.Compile)] +public partial class View : ContentPage +{ + public View() + { + InitializeComponent(); + } +} diff --git a/samples/UnoPlatformSample/UnoPlatformSample/LiveChartsSamples/Axes/Crosshairs/View.xaml b/samples/UnoPlatformSample/UnoPlatformSample/LiveChartsSamples/Axes/Crosshairs/View.xaml new file mode 100644 index 000000000..50740a29e --- /dev/null +++ b/samples/UnoPlatformSample/UnoPlatformSample/LiveChartsSamples/Axes/Crosshairs/View.xaml @@ -0,0 +1,22 @@ + + + + + + + + + + + diff --git a/samples/UnoPlatformSample/UnoPlatformSample/LiveChartsSamples/Axes/Crosshairs/View.xaml.cs b/samples/UnoPlatformSample/UnoPlatformSample/LiveChartsSamples/Axes/Crosshairs/View.xaml.cs new file mode 100644 index 000000000..382f6287c --- /dev/null +++ b/samples/UnoPlatformSample/UnoPlatformSample/LiveChartsSamples/Axes/Crosshairs/View.xaml.cs @@ -0,0 +1,11 @@ +using Microsoft.UI.Xaml.Controls; + +namespace UnoWinUISample.Axes.Crosshairs; + +public sealed partial class View : UserControl +{ + public View() + { + InitializeComponent(); + } +} diff --git a/samples/WinFormsSample/Axes/Crosshairs/View.Designer.cs b/samples/WinFormsSample/Axes/Crosshairs/View.Designer.cs new file mode 100644 index 000000000..87d39a32e --- /dev/null +++ b/samples/WinFormsSample/Axes/Crosshairs/View.Designer.cs @@ -0,0 +1,46 @@ + +namespace WinFormsSample.Axes.Crosshairs +{ + 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/Axes/Crosshairs/View.cs b/samples/WinFormsSample/Axes/Crosshairs/View.cs new file mode 100644 index 000000000..b9776f5f9 --- /dev/null +++ b/samples/WinFormsSample/Axes/Crosshairs/View.cs @@ -0,0 +1,32 @@ +using System.Windows.Forms; +using LiveChartsCore.SkiaSharpView.WinForms; +using ViewModelsSamples.Axes.Crosshairs; + +namespace WinFormsSample.Axes.Crosshairs; + +public partial class View : UserControl +{ + private readonly CartesianChart cartesianChart; + + public View() + { + InitializeComponent(); + Size = new System.Drawing.Size(100, 100); + + var viewModel = new ViewModel(); + + cartesianChart = new CartesianChart + { + Series = viewModel.Series, + XAxes = viewModel.XAxes, + YAxes = viewModel.YAxes, + + // out of livecharts properties... + Location = new System.Drawing.Point(0, 50), + Size = new System.Drawing.Size(100, 50), + Anchor = AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top | AnchorStyles.Bottom + }; + + Controls.Add(cartesianChart); + } +} diff --git a/samples/WinFormsSample/Axes/Crosshairs/View.resx b/samples/WinFormsSample/Axes/Crosshairs/View.resx new file mode 100644 index 000000000..f298a7be8 --- /dev/null +++ b/samples/WinFormsSample/Axes/Crosshairs/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/WinUISample/WinUISample/Axes/Crosshairs/View.xaml b/samples/WinUISample/WinUISample/Axes/Crosshairs/View.xaml new file mode 100644 index 000000000..5a0686f9a --- /dev/null +++ b/samples/WinUISample/WinUISample/Axes/Crosshairs/View.xaml @@ -0,0 +1,22 @@ + + + + + + + + + + + diff --git a/samples/WinUISample/WinUISample/Axes/Crosshairs/View.xaml.cs b/samples/WinUISample/WinUISample/Axes/Crosshairs/View.xaml.cs new file mode 100644 index 000000000..7264491d2 --- /dev/null +++ b/samples/WinUISample/WinUISample/Axes/Crosshairs/View.xaml.cs @@ -0,0 +1,11 @@ +using Microsoft.UI.Xaml.Controls; + +namespace WinUISample.Axes.Crosshairs; + +public sealed partial class View : UserControl +{ + public View() + { + InitializeComponent(); + } +} diff --git a/samples/XamarinSample/XamarinSample/XamarinSample/App.xaml.cs b/samples/XamarinSample/XamarinSample/XamarinSample/App.xaml.cs index 1e7eaa8d1..a66ad6bb3 100644 --- a/samples/XamarinSample/XamarinSample/XamarinSample/App.xaml.cs +++ b/samples/XamarinSample/XamarinSample/XamarinSample/App.xaml.cs @@ -18,7 +18,8 @@ protected override void OnStart() { LiveCharts.Configure(config => // mark config // mark - // you can override the theme + // you can override the theme + .AddLightTheme() // optional, this is the default theme // .AddDarkTheme() // mark // In case you need a non-Latin based font, you must register a typeface for SkiaSharp diff --git a/samples/XamarinSample/XamarinSample/XamarinSample/Axes/Crosshairs/View.xaml b/samples/XamarinSample/XamarinSample/XamarinSample/Axes/Crosshairs/View.xaml new file mode 100644 index 000000000..2cb31a64a --- /dev/null +++ b/samples/XamarinSample/XamarinSample/XamarinSample/Axes/Crosshairs/View.xaml @@ -0,0 +1,17 @@ + + + + + + + + + + diff --git a/samples/XamarinSample/XamarinSample/XamarinSample/Axes/Crosshairs/View.xaml.cs b/samples/XamarinSample/XamarinSample/XamarinSample/Axes/Crosshairs/View.xaml.cs new file mode 100644 index 000000000..70a37ff6c --- /dev/null +++ b/samples/XamarinSample/XamarinSample/XamarinSample/Axes/Crosshairs/View.xaml.cs @@ -0,0 +1,13 @@ +using Xamarin.Forms; +using Xamarin.Forms.Xaml; + +namespace XamarinSample.Axes.Crosshairs; + +[XamlCompilation(XamlCompilationOptions.Compile)] +public partial class View : ContentPage +{ + public View() + { + InitializeComponent(); + } +} From bc26d154b897f435595dea59f03aa4c13143ec66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Wed, 26 Jul 2023 18:56:23 -0600 Subject: [PATCH 28/54] remove licence from uno app start (docs) --- .../UnoPlatformSample/App.cs | 24 +------------------ 1 file changed, 1 insertion(+), 23 deletions(-) diff --git a/samples/UnoPlatformSample/UnoPlatformSample/App.cs b/samples/UnoPlatformSample/UnoPlatformSample/App.cs index 7cbdd8b15..e9a50d303 100644 --- a/samples/UnoPlatformSample/UnoPlatformSample/App.cs +++ b/samples/UnoPlatformSample/UnoPlatformSample/App.cs @@ -1,26 +1,4 @@ -// 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; // mark +using LiveChartsCore; // mark using LiveChartsCore.SkiaSharpView; // mark using SkiaSharp; // mark From 037c47638a52ae2e4a510f24a477bd8e6a52bfb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Thu, 27 Jul 2023 10:47:33 -0600 Subject: [PATCH 29/54] remove fromatter from sample --- samples/ViewModelsSamples/Axes/DateTimeScaled/ViewModel.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/ViewModelsSamples/Axes/DateTimeScaled/ViewModel.cs b/samples/ViewModelsSamples/Axes/DateTimeScaled/ViewModel.cs index 8f11d5556..b315d8e9a 100644 --- a/samples/ViewModelsSamples/Axes/DateTimeScaled/ViewModel.cs +++ b/samples/ViewModelsSamples/Axes/DateTimeScaled/ViewModel.cs @@ -13,8 +13,6 @@ public partial class ViewModel : ObservableObject { new ColumnSeries { - YToolTipLabelFormatter = (chartPoint) => - $"{new DateTime((long) chartPoint.Coordinate.SecondaryValue):MMMM dd}: {chartPoint.Coordinate.PrimaryValue}", Values = new ObservableCollection { new DateTimePoint(new DateTime(2021, 1, 1), 3), @@ -37,6 +35,8 @@ public partial class ViewModel : ObservableObject LabelsRotation = 80, // when using a date time type, let the library know your unit // mark + // where "unit" means the distance between your points, this will improve + // how tooltips are triggered. UnitWidth = TimeSpan.FromDays(1).Ticks, // mark // if the difference between our points is in hours then we would: From 19dd8a8f4598ab6a1a4583526b0a8970d356d146 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Thu, 27 Jul 2023 12:05:43 -0600 Subject: [PATCH 30/54] update samples legends --- samples/ViewModelsSamples/Axes/Logarithmic/ViewModel.cs | 2 +- samples/ViewModelsSamples/Events/Cartesian/ViewModel.cs | 3 +-- .../ViewModelsSamples/General/TemplatedLegends/ViewModel.cs | 1 + samples/ViewModelsSamples/General/Tooltips/ViewModel.cs | 4 +++- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/samples/ViewModelsSamples/Axes/Logarithmic/ViewModel.cs b/samples/ViewModelsSamples/Axes/Logarithmic/ViewModel.cs index dee83d805..0dc4e0757 100644 --- a/samples/ViewModelsSamples/Axes/Logarithmic/ViewModel.cs +++ b/samples/ViewModelsSamples/Axes/Logarithmic/ViewModel.cs @@ -42,7 +42,7 @@ public partial class ViewModel : ObservableObject MinStep = 1, // converts the log scale back for the label - Labeler = value => Math.Pow(s_logBase, value).ToString() // mark + Labeler = value => Math.Pow(s_logBase, value).ToString("N2") // mark } }; } diff --git a/samples/ViewModelsSamples/Events/Cartesian/ViewModel.cs b/samples/ViewModelsSamples/Events/Cartesian/ViewModel.cs index 783809db6..497f7205b 100644 --- a/samples/ViewModelsSamples/Events/Cartesian/ViewModel.cs +++ b/samples/ViewModelsSamples/Events/Cartesian/ViewModel.cs @@ -27,9 +27,8 @@ public ViewModel() var salesPerDaysSeries = new ColumnSeries { - Name = "Items sold per day", Values = data, - YToolTipLabelFormatter = point => $"{point.Model?.Name}, sold {point.Model?.SalesPerDay} items", + YToolTipLabelFormatter = point => $"{point.Model?.SalesPerDay} {point.Model?.Name}", DataLabelsPaint = new SolidColorPaint(new SKColor(30, 30, 30)), DataLabelsFormatter = point => $"{point.Model?.SalesPerDay} {point.Model?.Name}", DataLabelsPosition = DataLabelsPosition.End, diff --git a/samples/ViewModelsSamples/General/TemplatedLegends/ViewModel.cs b/samples/ViewModelsSamples/General/TemplatedLegends/ViewModel.cs index ef975454c..d6488cad0 100644 --- a/samples/ViewModelsSamples/General/TemplatedLegends/ViewModel.cs +++ b/samples/ViewModelsSamples/General/TemplatedLegends/ViewModel.cs @@ -11,6 +11,7 @@ public partial class ViewModel : ObservableObject { new ColumnSeries { + Name = "Roger", Values = new ObservableCollection { 2, 1, 3, 5, 3, 4, 6 } } }; diff --git a/samples/ViewModelsSamples/General/Tooltips/ViewModel.cs b/samples/ViewModelsSamples/General/Tooltips/ViewModel.cs index 5ec47e274..41903d8a8 100644 --- a/samples/ViewModelsSamples/General/Tooltips/ViewModel.cs +++ b/samples/ViewModelsSamples/General/Tooltips/ViewModel.cs @@ -24,11 +24,13 @@ public ViewModel() new ColumnSeries { Values = new ObservableCollection { 3, 7, 3, 1, 4, 5, 6 }, + Name = "Sales" }, new LineSeries { Values = new ObservableCollection { 2, 1, 3, 5, 3, 4, 6 }, - Fill = null + Fill = null, + Name = "Customers" } }; From e54ce9f4ab2864cdfb7b37e7cc12e5ef9fe3b46d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Thu, 27 Jul 2023 15:01:21 -0600 Subject: [PATCH 31/54] right to left docs and sample --- docs/overview/1.2.install.md | 6 +++--- samples/AvaloniaSample/App.axaml.cs | 6 ++++-- samples/EtoFormsSample/Program.cs | 7 ++++--- samples/MauiSample/App.xaml.cs | 4 +++- samples/UnoPlatformSample/UnoPlatformSample/App.cs | 4 +++- samples/WPFSample/App.xaml.cs | 4 +++- samples/WinFormsSample/Program.cs | 4 +++- samples/WinUISample/WinUISample/App.xaml.cs | 4 +++- .../XamarinSample/XamarinSample/XamarinSample/App.xaml.cs | 7 +++++-- 9 files changed, 31 insertions(+), 15 deletions(-) diff --git a/docs/overview/1.2.install.md b/docs/overview/1.2.install.md index 7d9bb3483..ffa8d4895 100644 --- a/docs/overview/1.2.install.md +++ b/docs/overview/1.2.install.md @@ -631,9 +631,9 @@ And that's it, start your application and you will see the chart. ## Configure themes, fonts or mappers (Optional) -Optionally you could configure LiveCharts to add a theme, register a global font or add a custom mapper for a type, -when you need a non-Latin font you must register a typeface so SkiaShap can render the text correctly, -add the following code when your application starts: +Optionally you could configure LiveCharts to add a theme, register a global font, enable `right to left` tooltips and +or a custom mapper for a type, when you need a non-Latin font you must register a typeface so SkiaShap can render +the text correctly, add the following code when your application starts: {{~ if avalonia ~}} diff --git a/samples/AvaloniaSample/App.axaml.cs b/samples/AvaloniaSample/App.axaml.cs index cb9087875..15878a655 100644 --- a/samples/AvaloniaSample/App.axaml.cs +++ b/samples/AvaloniaSample/App.axaml.cs @@ -17,15 +17,17 @@ public override void Initialize() LiveCharts.Configure(config => // mark config // mark // you can override the theme - // .AddDarkTheme() // mark + //.AddDarkTheme() // mark // In case you need a non-Latin based font, you must register a typeface for SkiaSharp //.HasGlobalSKTypeface(SKFontManager.Default.MatchCharacter('汉')) // <- Chinese // mark - //.HasGlobalSKTypeface(SKFontManager.Default.MatchCharacter('أ')) // <- Arabic // mark //.HasGlobalSKTypeface(SKFontManager.Default.MatchCharacter('あ')) // <- Japanese // mark //.HasGlobalSKTypeface(SKFontManager.Default.MatchCharacter('헬')) // <- Korean // mark //.HasGlobalSKTypeface(SKFontManager.Default.MatchCharacter('Ж')) // <- Russian // mark + //.HasGlobalSKTypeface(SKFontManager.Default.MatchCharacter('أ')) // <- Arabic // mark + //.UseRightToLeftSettings() // Enables right to left tooltips // mark + // finally register your own mappers // you can learn more about mappers at: // https://lvcharts.com/docs/{{ platform }}/{{ version }}/Overview.Mappers diff --git a/samples/EtoFormsSample/Program.cs b/samples/EtoFormsSample/Program.cs index a6b5721a4..9a4dac58b 100644 --- a/samples/EtoFormsSample/Program.cs +++ b/samples/EtoFormsSample/Program.cs @@ -17,16 +17,17 @@ static void Main() LiveCharts.Configure(config => // mark config // mark // you can override the theme - // .AddDarkTheme() // mark - .AddLightTheme() // mark + //.AddDarkTheme() // mark // In case you need a non-Latin based font, you must register a typeface for SkiaSharp //.HasGlobalSKTypeface(SKFontManager.Default.MatchCharacter('汉')) // <- Chinese // mark - //.HasGlobalSKTypeface(SKFontManager.Default.MatchCharacter('أ')) // <- Arabic // mark //.HasGlobalSKTypeface(SKFontManager.Default.MatchCharacter('あ')) // <- Japanese // mark //.HasGlobalSKTypeface(SKFontManager.Default.MatchCharacter('헬')) // <- Korean // mark //.HasGlobalSKTypeface(SKFontManager.Default.MatchCharacter('Ж')) // <- Russian // mark + //.HasGlobalSKTypeface(SKFontManager.Default.MatchCharacter('أ')) // <- Arabic // mark + //.UseRightToLeftSettings() // Enables right to left tooltips // mark + // finally register your own mappers // you can learn more about mappers at: // https://lvcharts.com/docs/{{ platform }}/{{ version }}/Overview.Mappers diff --git a/samples/MauiSample/App.xaml.cs b/samples/MauiSample/App.xaml.cs index ec26d1322..44d5b7b82 100644 --- a/samples/MauiSample/App.xaml.cs +++ b/samples/MauiSample/App.xaml.cs @@ -25,11 +25,13 @@ protected override void OnStart() // In case you need a non-Latin based font, you must register a typeface for SkiaSharp //.HasGlobalSKTypeface(SKFontManager.Default.MatchCharacter('汉')) // <- Chinese // mark - //.HasGlobalSKTypeface(SKFontManager.Default.MatchCharacter('أ')) // <- Arabic // mark //.HasGlobalSKTypeface(SKFontManager.Default.MatchCharacter('あ')) // <- Japanese // mark //.HasGlobalSKTypeface(SKFontManager.Default.MatchCharacter('헬')) // <- Korean // mark //.HasGlobalSKTypeface(SKFontManager.Default.MatchCharacter('Ж')) // <- Russian // mark + //.HasGlobalSKTypeface(SKFontManager.Default.MatchCharacter('أ')) // <- Arabic // mark + //.UseRightToLeftSettings() // Enables right to left tooltips // mark + // finally register your own mappers // you can learn more about mappers at: // https://lvcharts.com/docs/{{ platform }}/{{ version }}/Overview.Mappers diff --git a/samples/UnoPlatformSample/UnoPlatformSample/App.cs b/samples/UnoPlatformSample/UnoPlatformSample/App.cs index e9a50d303..b8b26333b 100644 --- a/samples/UnoPlatformSample/UnoPlatformSample/App.cs +++ b/samples/UnoPlatformSample/UnoPlatformSample/App.cs @@ -20,11 +20,13 @@ protected async override void OnLaunched(LaunchActivatedEventArgs args) // In case you need a non-Latin based font, you must register a typeface for SkiaSharp //.HasGlobalSKTypeface(SKFontManager.Default.MatchCharacter('汉')) // <- Chinese // mark - //.HasGlobalSKTypeface(SKFontManager.Default.MatchCharacter('أ')) // <- Arabic // mark //.HasGlobalSKTypeface(SKFontManager.Default.MatchCharacter('あ')) // <- Japanese // mark //.HasGlobalSKTypeface(SKFontManager.Default.MatchCharacter('헬')) // <- Korean // mark //.HasGlobalSKTypeface(SKFontManager.Default.MatchCharacter('Ж')) // <- Russian // mark + //.HasGlobalSKTypeface(SKFontManager.Default.MatchCharacter('أ')) // <- Arabic // mark + //.UseRightToLeftSettings() // Enables right to left tooltips // mark + // finally register your own mappers // you can learn more about mappers at: // https://lvcharts.com/docs/{{ platform }}/{{ version }}/Overview.Mappers diff --git a/samples/WPFSample/App.xaml.cs b/samples/WPFSample/App.xaml.cs index 275df71cd..2639e04d4 100644 --- a/samples/WPFSample/App.xaml.cs +++ b/samples/WPFSample/App.xaml.cs @@ -21,11 +21,13 @@ protected override void OnStartup(StartupEventArgs e) // In case you need a non-Latin based font, you must register a typeface for SkiaSharp //.HasGlobalSKTypeface(SKFontManager.Default.MatchCharacter('汉')) // <- Chinese // mark - //.HasGlobalSKTypeface(SKFontManager.Default.MatchCharacter('أ')) // <- Arabic // mark //.HasGlobalSKTypeface(SKFontManager.Default.MatchCharacter('あ')) // <- Japanese // mark //.HasGlobalSKTypeface(SKFontManager.Default.MatchCharacter('헬')) // <- Korean // mark //.HasGlobalSKTypeface(SKFontManager.Default.MatchCharacter('Ж')) // <- Russian // mark + //.HasGlobalSKTypeface(SKFontManager.Default.MatchCharacter('أ')) // <- Arabic // mark + //.UseRightToLeftSettings() // Enables right to left tooltips // mark + // finally register your own mappers // you can learn more about mappers at: // https://lvcharts.com/docs/{{ platform }}/{{ version }}/Overview.Mappers diff --git a/samples/WinFormsSample/Program.cs b/samples/WinFormsSample/Program.cs index e77f3962e..0191944f0 100644 --- a/samples/WinFormsSample/Program.cs +++ b/samples/WinFormsSample/Program.cs @@ -21,11 +21,13 @@ static void Main() // In case you need a non-Latin based font, you must register a typeface for SkiaSharp //.HasGlobalSKTypeface(SKFontManager.Default.MatchCharacter('汉')) // <- Chinese // mark - //.HasGlobalSKTypeface(SKFontManager.Default.MatchCharacter('أ')) // <- Arabic // mark //.HasGlobalSKTypeface(SKFontManager.Default.MatchCharacter('あ')) // <- Japanese // mark //.HasGlobalSKTypeface(SKFontManager.Default.MatchCharacter('헬')) // <- Korean // mark //.HasGlobalSKTypeface(SKFontManager.Default.MatchCharacter('Ж')) // <- Russian // mark + //.HasGlobalSKTypeface(SKFontManager.Default.MatchCharacter('أ')) // <- Arabic // mark + //.UseRightToLeftSettings() // Enables right to left tooltips // mark + // finally register your own mappers // you can learn more about mappers at: // https://lvcharts.com/docs/{{ platform }}/{{ version }}/Overview.Mappers diff --git a/samples/WinUISample/WinUISample/App.xaml.cs b/samples/WinUISample/WinUISample/App.xaml.cs index 97ebc8431..a4613ffc3 100644 --- a/samples/WinUISample/WinUISample/App.xaml.cs +++ b/samples/WinUISample/WinUISample/App.xaml.cs @@ -38,11 +38,13 @@ protected override void OnLaunched(LaunchActivatedEventArgs args) // In case you need a non-Latin based font, you must register a typeface for SkiaSharp //.HasGlobalSKTypeface(SKFontManager.Default.MatchCharacter('汉')) // <- Chinese // mark - //.HasGlobalSKTypeface(SKFontManager.Default.MatchCharacter('أ')) // <- Arabic // mark //.HasGlobalSKTypeface(SKFontManager.Default.MatchCharacter('あ')) // <- Japanese // mark //.HasGlobalSKTypeface(SKFontManager.Default.MatchCharacter('헬')) // <- Korean // mark //.HasGlobalSKTypeface(SKFontManager.Default.MatchCharacter('Ж')) // <- Russian // mark + //.HasGlobalSKTypeface(SKFontManager.Default.MatchCharacter('أ')) // <- Arabic // mark + //.UseRightToLeftSettings() // Enables right to left tooltips // mark + // finally register your own mappers // you can learn more about mappers at: // https://lvcharts.com/docs/{{ platform }}/{{ version }}/Overview.Mappers diff --git a/samples/XamarinSample/XamarinSample/XamarinSample/App.xaml.cs b/samples/XamarinSample/XamarinSample/XamarinSample/App.xaml.cs index a66ad6bb3..bdc54ee23 100644 --- a/samples/XamarinSample/XamarinSample/XamarinSample/App.xaml.cs +++ b/samples/XamarinSample/XamarinSample/XamarinSample/App.xaml.cs @@ -29,17 +29,20 @@ protected override void OnStart() //.HasGlobalSKTypeface(SKFontManager.Default.MatchCharacter('헬')) // <- Korean // mark //.HasGlobalSKTypeface(SKFontManager.Default.MatchCharacter('Ж')) // <- Russian // mark + //.HasGlobalSKTypeface(SKFontManager.Default.MatchCharacter('أ')) // <- Arabic // mark + //.UseRightToLeftSettings() // Enables right to left tooltips // mark + // finally register your own mappers // you can learn more about mappers at: // https://lvcharts.com/docs/{{ platform }}/{{ version }}/Overview.Mappers //.HasMap((city, point) => // mark //{ // mark // // here we use the index as X, and the population as Y // mark - //point.Coordinate = new(point.Index, city.Population); // mark + //point.Coordinate = new(point.Index, city.Population); // mark //}) // mark // .HasMap( .... ) // mark // .HasMap( .... ) // mark - ); // mark + ); // mark } protected override void OnSleep() From a22ca0d1108c539fbe8eaae4a8da4b133db1a12b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Thu, 27 Jul 2023 15:01:59 -0600 Subject: [PATCH 32/54] typo --- docs/overview/1.2.install.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/overview/1.2.install.md b/docs/overview/1.2.install.md index ffa8d4895..1d595c321 100644 --- a/docs/overview/1.2.install.md +++ b/docs/overview/1.2.install.md @@ -631,7 +631,7 @@ And that's it, start your application and you will see the chart. ## Configure themes, fonts or mappers (Optional) -Optionally you could configure LiveCharts to add a theme, register a global font, enable `right to left` tooltips and +Optionally you could configure LiveCharts to add a theme, register a global font, enable `right to left` tooltips or a custom mapper for a type, when you need a non-Latin font you must register a typeface so SkiaShap can render the text correctly, add the following code when your application starts: From 618985739bfe3bd5ff3d68fc09145ed60dc6fdf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Thu, 27 Jul 2023 19:39:09 -0600 Subject: [PATCH 33/54] simplify pie samples --- .../ViewModelsSamples/Pies/Basic/ViewModel.cs | 13 ++++++++ .../Pies/Custom/ViewModel.cs | 31 ++++++++++++++----- .../Pies/Doughnut/ViewModel.cs | 18 +++++------ .../Pies/NightingaleRose/ViewModel.cs | 25 ++++++++++----- .../Pies/Pushout/ViewModel.cs | 17 +++++----- 5 files changed, 72 insertions(+), 32 deletions(-) diff --git a/samples/ViewModelsSamples/Pies/Basic/ViewModel.cs b/samples/ViewModelsSamples/Pies/Basic/ViewModel.cs index 51443c0c7..4d0dea3de 100644 --- a/samples/ViewModelsSamples/Pies/Basic/ViewModel.cs +++ b/samples/ViewModelsSamples/Pies/Basic/ViewModel.cs @@ -10,9 +10,22 @@ namespace ViewModelsSamples.Pies.Basic; public partial class ViewModel : ObservableObject { + // you can convert any array, list or IEnnumerable to a pie series collection: public IEnumerable Series { get; set; } = new[] { 2, 4, 1, 4, 3 }.AsPieSeries(); + // the expression above is equivalent to the next series collection, + // use the AsPieSeries() to convert + public IEnumerable Series2 { get; set; } = + new[] + { + new PieSeries { Values = new[]{ 2 } }, + new PieSeries { Values = new[]{ 4 } }, + new PieSeries { Values = new[]{ 1 } }, + new PieSeries { Values = new[]{ 4 } }, + new PieSeries { Values = new[]{ 3 } }, + }; + public LabelVisual Title { get; set; } = new LabelVisual { diff --git a/samples/ViewModelsSamples/Pies/Custom/ViewModel.cs b/samples/ViewModelsSamples/Pies/Custom/ViewModel.cs index dd52c7de7..2180f38e3 100644 --- a/samples/ViewModelsSamples/Pies/Custom/ViewModel.cs +++ b/samples/ViewModelsSamples/Pies/Custom/ViewModel.cs @@ -7,12 +7,29 @@ namespace ViewModelsSamples.Pies.Custom; public partial class ViewModel : ObservableObject { - public ISeries[] Series { get; set; } = + public ViewModel() { - new PieSeries { Values = new List { 4 }, MaxOuterRadius = 0.60 }, - new PieSeries { Values = new List { 5 }, MaxOuterRadius = 0.65 }, - new PieSeries { Values = new List { 3 }, MaxOuterRadius = 0.70 }, - new PieSeries { Values = new List { 5 }, MaxOuterRadius = 0.85 }, - new PieSeries { Values = new List { 7 }, MaxOuterRadius = 1.00 }, - }; + var outer = 1d; + var data = new[] { 6, 5, 4, 3, 2 }; + + // you can convert any array, list or IEnumerable to a pie series collection: + Series = data.AsPieSeries((value, series) => + { + // this method is called once per element in the array, so: + + // for the series with the value 6, we set the outer radius to 1 + // for the series with the value 5, the outer radius is 0.9 + // for the series with the value 4, the outer radius is 0.8 + // for the series with the value 3, the outer radius is 0.7 + // for the series with the value 2, the outer radius is 0.6 + + // The MaxOuterRadius property sets the maximum outer, the value goes from + // 0 to 1, where 1 is the full available radius and 0 is none. + + series.MaxOuterRadius = outer; + outer -= 0.1; + }); + } + + public IEnumerable Series { get; set; } } diff --git a/samples/ViewModelsSamples/Pies/Doughnut/ViewModel.cs b/samples/ViewModelsSamples/Pies/Doughnut/ViewModel.cs index da6c2557b..e5a989d5e 100644 --- a/samples/ViewModelsSamples/Pies/Doughnut/ViewModel.cs +++ b/samples/ViewModelsSamples/Pies/Doughnut/ViewModel.cs @@ -1,18 +1,16 @@ -using System.Collections.Generic; -using LiveChartsCore; +using LiveChartsCore; using LiveChartsCore.SkiaSharpView; using CommunityToolkit.Mvvm.ComponentModel; +using System.Collections.Generic; namespace ViewModelsSamples.Pies.Doughnut; public partial class ViewModel : ObservableObject { - public ISeries[] Series { get; set; } = new ISeries[] - { - new PieSeries { Values = new List { 2 }, InnerRadius = 50 }, - new PieSeries { Values = new List { 4 }, InnerRadius = 50 }, - new PieSeries { Values = new List { 1 }, InnerRadius = 50 }, - new PieSeries { Values = new List { 4 }, InnerRadius = 50 }, - new PieSeries { Values = new List { 3 }, InnerRadius = 50 } - }; + // you can convert any array, list or IEnumerable to a pie series collection: + public IEnumerable Series { get; set; } = + new[] { 2, 4, 1, 4, 3 }.AsPieSeries((value, series) => + { + series.InnerRadius = 50; + }); } diff --git a/samples/ViewModelsSamples/Pies/NightingaleRose/ViewModel.cs b/samples/ViewModelsSamples/Pies/NightingaleRose/ViewModel.cs index 5b531c31c..ca357bc7e 100644 --- a/samples/ViewModelsSamples/Pies/NightingaleRose/ViewModel.cs +++ b/samples/ViewModelsSamples/Pies/NightingaleRose/ViewModel.cs @@ -7,12 +7,23 @@ namespace ViewModelsSamples.Pies.NightingaleRose; public partial class ViewModel : ObservableObject { - public ISeries[] Series { get; set; } = + public ViewModel() { - new PieSeries { Values = new List { 2 }, InnerRadius = 50, MaxOuterRadius = 1.0 }, - new PieSeries { Values = new List { 4 }, InnerRadius = 50, MaxOuterRadius = 0.9 }, - new PieSeries { Values = new List { 1 }, InnerRadius = 50, MaxOuterRadius = 0.8 }, - new PieSeries { Values = new List { 4 }, InnerRadius = 50, MaxOuterRadius = 0.7 }, - new PieSeries { Values = new List { 3 }, InnerRadius = 50, MaxOuterRadius = 0.6 } - }; + var outer = 1d; + var data = new[] { 6, 5, 4, 3, 2 }; + + // you can convert any array, list or IEnumerable to a pie series collection: + Series = data.AsPieSeries((value, series) => + { + // this method is called once per element in the array + // we are decremting the outer radius 10 percent (0.1) + // on every element in the array. + + series.InnerRadius = 50; + series.MaxOuterRadius = outer; + outer -= 0.1; + }); + } + + public IEnumerable Series { get; set; } } diff --git a/samples/ViewModelsSamples/Pies/Pushout/ViewModel.cs b/samples/ViewModelsSamples/Pies/Pushout/ViewModel.cs index 8c024f72b..00327ec4d 100644 --- a/samples/ViewModelsSamples/Pies/Pushout/ViewModel.cs +++ b/samples/ViewModelsSamples/Pies/Pushout/ViewModel.cs @@ -7,12 +7,13 @@ namespace ViewModelsSamples.Pies.Pushout; public partial class ViewModel : ObservableObject { - public ISeries[] Series { get; set; } = - { - new PieSeries { Values = new List { 3 }, Pushout = 4 }, - new PieSeries { Values = new List { 3 }, Pushout = 4 }, - new PieSeries { Values = new List { 3 }, Pushout = 4 }, - new PieSeries { Values = new List { 2 }, Pushout = 4 }, - new PieSeries { Values = new List { 5 }, Pushout = 30 } - }; + // you can convert any array, list or IEnumerable to a pie series collection: + public IEnumerable Series { get; set; } = + new[] { 6, 5, 4, 3, 2 }.AsPieSeries((value, series) => + { + // pushes out the slice with the value of 6 to 30 pixels. + if (value != 6) return; + + series.Pushout = 30; + }); } From b555006e8713d558010d9143425506ad1742eba9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Thu, 27 Jul 2023 19:47:39 -0600 Subject: [PATCH 34/54] typo --- samples/ViewModelsSamples/Pies/Basic/ViewModel.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/samples/ViewModelsSamples/Pies/Basic/ViewModel.cs b/samples/ViewModelsSamples/Pies/Basic/ViewModel.cs index 4d0dea3de..d4e3b0389 100644 --- a/samples/ViewModelsSamples/Pies/Basic/ViewModel.cs +++ b/samples/ViewModelsSamples/Pies/Basic/ViewModel.cs @@ -14,8 +14,7 @@ public partial class ViewModel : ObservableObject public IEnumerable Series { get; set; } = new[] { 2, 4, 1, 4, 3 }.AsPieSeries(); - // the expression above is equivalent to the next series collection, - // use the AsPieSeries() to convert + // the expression above is equivalent to the next series collection: public IEnumerable Series2 { get; set; } = new[] { From cb179b76226d455727217d6bba9e669006852a52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Thu, 27 Jul 2023 22:07:20 -0600 Subject: [PATCH 35/54] add series name to fix test --- .../SeriesTests/ColumnSeriesTest.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/LiveChartsCore.UnitTesting/SeriesTests/ColumnSeriesTest.cs b/tests/LiveChartsCore.UnitTesting/SeriesTests/ColumnSeriesTest.cs index c11191e22..adc3d2a79 100644 --- a/tests/LiveChartsCore.UnitTesting/SeriesTests/ColumnSeriesTest.cs +++ b/tests/LiveChartsCore.UnitTesting/SeriesTests/ColumnSeriesTest.cs @@ -106,6 +106,7 @@ public void ShouldPlaceToolTips() var sutSeries = new ColumnSeries { Values = new double[] { 1, 2, 3, 4, 5 }, + Name = "Series #1", DataPadding = new Drawing.LvcPoint(0, 0) }; @@ -116,7 +117,7 @@ public void ShouldPlaceToolTips() Width = 300, Height = 300, Tooltip = tooltip, - TooltipPosition = TooltipPosition.Top, + TooltipPosition = TooltipPosition.Top Series = new[] { sutSeries }, XAxes = new[] { new Axis { IsVisible = false } }, YAxes = new[] { new Axis { IsVisible = false } } @@ -181,6 +182,7 @@ public void ShouldPlaceToolTips() sutSeries.Values = new double[] { 1, 2, 3, 4, 5 }; chart.Core._pointerPosition = new(299, 150); _ = chart.GetImage(); + chart.SaveImage("__err.png"); Assert.IsTrue( Math.Abs(tp.X - (300 - 300 * (1 / 5d) * 0.5 - tp.Width)) < 0.0001 && Math.Abs(tp.Y - -tp.Height * 0.5f) < 0.1 && @@ -193,7 +195,7 @@ public void ShouldPlaceToolTips() Math.Abs(tp.X - 300 * (1 / 5d) * 0.5) < 0.0001 && Math.Abs(tp.Y - (300 - tp.Height * 0.5f)) < 0.1 && chart.Core.AutoToolTipsInfo.ToolTipPlacement == PopUpPlacement.Right, - "Tool tip on left failed [AUTO]"); + "Tool tip on right failed [AUTO]"); } [TestMethod] From 5b07950a22c1339f44f1dcff8cae407ede737204 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Thu, 27 Jul 2023 22:09:19 -0600 Subject: [PATCH 36/54] typo --- .../LiveChartsCore.UnitTesting/SeriesTests/ColumnSeriesTest.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/LiveChartsCore.UnitTesting/SeriesTests/ColumnSeriesTest.cs b/tests/LiveChartsCore.UnitTesting/SeriesTests/ColumnSeriesTest.cs index adc3d2a79..70d432869 100644 --- a/tests/LiveChartsCore.UnitTesting/SeriesTests/ColumnSeriesTest.cs +++ b/tests/LiveChartsCore.UnitTesting/SeriesTests/ColumnSeriesTest.cs @@ -117,7 +117,7 @@ public void ShouldPlaceToolTips() Width = 300, Height = 300, Tooltip = tooltip, - TooltipPosition = TooltipPosition.Top + TooltipPosition = TooltipPosition.Top, Series = new[] { sutSeries }, XAxes = new[] { new Axis { IsVisible = false } }, YAxes = new[] { new Axis { IsVisible = false } } @@ -182,7 +182,6 @@ public void ShouldPlaceToolTips() sutSeries.Values = new double[] { 1, 2, 3, 4, 5 }; chart.Core._pointerPosition = new(299, 150); _ = chart.GetImage(); - chart.SaveImage("__err.png"); Assert.IsTrue( Math.Abs(tp.X - (300 - 300 * (1 / 5d) * 0.5 - tp.Width)) < 0.0001 && Math.Abs(tp.Y - -tp.Height * 0.5f) < 0.1 && From 5cd47f870855313cfe7ba70af1a1bd12559fbcf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Thu, 27 Jul 2023 22:42:48 -0600 Subject: [PATCH 37/54] add a lot of new tests --- src/LiveChartsCore/PieSeries.cs | 99 +++--- .../SeriesTests/PieSeriesTest.cs | 321 +++++++++++++++++- 2 files changed, 375 insertions(+), 45 deletions(-) diff --git a/src/LiveChartsCore/PieSeries.cs b/src/LiveChartsCore/PieSeries.cs index 1c8bf739f..eb1482818 100644 --- a/src/LiveChartsCore/PieSeries.cs +++ b/src/LiveChartsCore/PieSeries.cs @@ -393,43 +393,17 @@ public override void Invalidate(Chart chart) label.Padding = DataLabelsPadding; label.RotateTransform = actualRotation; - if (DataLabelsPosition == PolarLabelsPosition.Start) - { - var a = start + initialRotation; - a %= 360; - if (a < 0) a += 360; - var c = 90; - - if (a > 180) c = -90; - - label.HorizontalAlign = a > 180 ? Align.End : Align.Start; - label.RotateTransform = (float)(a - c); - } - - if (DataLabelsPosition == PolarLabelsPosition.End) - { - var a = start + initialRotation + sweep; - a %= 360; - if (a < 0) a += 360; - var c = 90; - - if (a > 180) c = -90; - - label.HorizontalAlign = a > 180 ? Align.Start : Align.End; - label.RotateTransform = (float)(a - c); - } - - if (DataLabelsPosition == PolarLabelsPosition.Outer) - { - var a = start + initialRotation + sweep * 0.5; - var isStart = a % 360 is < 90 or (> 270 and < 360); - label.HorizontalAlign = label.HorizontalAlign = isStart ? Align.Start : Align.End; - } + AlignLabel(label, (float)start, initialRotation, sweep); var labelPosition = GetLabelPolarPosition( - cx, cy, ((stackedOuterRadius + relativeOuterRadius * 2) * 0.5f + stackedInnerRadius) * 0.5f, - stackedInnerRadius, (float)(start + initialRotation), (float)sweep, - label.Measure(DataLabelsPaint), DataLabelsPosition); + cx, + cy, + stackedInnerRadius, + (stackedOuterRadius + relativeOuterRadius * 2) * 0.5f, + (float)(start + initialRotation), + (float)sweep, + label.Measure(DataLabelsPaint), + DataLabelsPosition); label.X = labelPosition.X; label.Y = labelPosition.Y; @@ -569,8 +543,8 @@ protected virtual void SoftDeleteOrDisposePoint(ChartPoint point, Scaler primary /// /// The center x. /// The center y. - /// The radius. /// The iner radius. + /// The outer radius. /// The start angle. /// The sweep angle. /// Size of the label. @@ -579,31 +553,33 @@ protected virtual void SoftDeleteOrDisposePoint(ChartPoint point, Scaler primary protected virtual LvcPoint GetLabelPolarPosition( float centerX, float centerY, - float radius, float innerRadius, + float outerRadius, float startAngle, float sweepAngle, LvcSize labelSize, PolarLabelsPosition position) { - const float toRadians = (float)(Math.PI / 180); - float angle = 0; + float angle = 0, radius = 0; switch (position) { case PolarLabelsPosition.End: angle = startAngle + sweepAngle; + radius = innerRadius + (outerRadius - innerRadius) * 0.5f; break; case PolarLabelsPosition.Start: angle = startAngle; + radius = innerRadius + (outerRadius - innerRadius) * 0.5f; break; case PolarLabelsPosition.Outer: angle = startAngle + sweepAngle * 0.5f; - radius += radius - innerRadius; + radius = outerRadius + + 0.5f * (float)Math.Sqrt(Math.Pow(labelSize.Width, 2) + Math.Pow(labelSize.Height, 2)); break; case PolarLabelsPosition.Middle: angle = startAngle + sweepAngle * 0.5f; - radius *= 1.15f; + radius = innerRadius + (outerRadius - innerRadius) * 0.65f; break; case PolarLabelsPosition.ChartCenter: return new LvcPoint(centerX, centerY); @@ -611,10 +587,8 @@ protected virtual LvcPoint GetLabelPolarPosition( break; } - //angle %= 360; - //if (angle < 0) angle += 360; + const float toRadians = (float)(Math.PI / 180); angle *= toRadians; - radius += 0.5f * (float)Math.Sqrt(Math.Pow(labelSize.Width, 2) + Math.Pow(labelSize.Height, 2)); return new LvcPoint( (float)(centerX + Math.Cos(angle) * radius), @@ -648,4 +622,41 @@ public override void SoftDeleteOrDispose(IChartView chart) OnVisibilityChanged(); } + + private void AlignLabel(TLabel label, double start, double initialRotation, double sweep) + { + switch (DataLabelsPosition) + { + case PolarLabelsPosition.Middle: + case PolarLabelsPosition.ChartCenter: + label.HorizontalAlign = Align.Middle; + label.VerticalAlign = Align.Middle; + break; + case PolarLabelsPosition.End: + var a = start + initialRotation + sweep; + a %= 360; + if (a < 0) a += 360; + var c = 90; + if (a > 180) c = -90; + label.HorizontalAlign = a > 180 ? Align.Start : Align.End; + label.RotateTransform = (float)(a - c); + break; + case PolarLabelsPosition.Start: + var a1 = start + initialRotation; + a1 %= 360; + if (a1 < 0) a1 += 360; + var c1 = 90; + if (a1 > 180) c1 = -90; + label.HorizontalAlign = a1 > 180 ? Align.End : Align.Start; + label.RotateTransform = (float)(a1 - c1); + break; + case PolarLabelsPosition.Outer: + var a2 = start + initialRotation + sweep * 0.5; + var isStart = a2 % 360 is < 90 or (> 270 and < 360); + label.HorizontalAlign = label.HorizontalAlign = isStart ? Align.Start : Align.End; + break; + default: + break; + } + } } diff --git a/tests/LiveChartsCore.UnitTesting/SeriesTests/PieSeriesTest.cs b/tests/LiveChartsCore.UnitTesting/SeriesTests/PieSeriesTest.cs index 48888a1f2..8f870b9b0 100644 --- a/tests/LiveChartsCore.UnitTesting/SeriesTests/PieSeriesTest.cs +++ b/tests/LiveChartsCore.UnitTesting/SeriesTests/PieSeriesTest.cs @@ -140,6 +140,8 @@ public void ShouldPlaceToolTips() [TestMethod] public void ShouldPlaceDataLabel() { + LabelGeometry.ShowDebugLines = true; + var vals = new[] { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; var seriesCollection = vals.AsPieSeries(); @@ -154,6 +156,7 @@ public void ShouldPlaceDataLabel() // TEST HIDDEN =========================================================== _ = chart.GetImage(); + chart.SaveImage("_pie-hidden.png"); var points = seriesCollection.SelectMany(x => x.DataFactory @@ -170,9 +173,11 @@ public void ShouldPlaceDataLabel() SKTypeface = SKTypeface.FromFamilyName("Arial", SKFontStyle.Bold) }; - // TEST TOP =============================================================== + #region normal + foreach (var series in seriesCollection) series.DataLabelsPosition = PolarLabelsPosition.ChartCenter; _ = chart.GetImage(); + chart.SaveImage("_pie-center.png"); points = seriesCollection.SelectMany(x => x.DataFactory @@ -188,6 +193,7 @@ public void ShouldPlaceDataLabel() foreach (var series in seriesCollection) series.DataLabelsPosition = PolarLabelsPosition.Middle; _ = chart.GetImage(); + chart.SaveImage("_pie-middle.png"); points = seriesCollection.SelectMany(x => x.DataFactory @@ -208,6 +214,7 @@ public void ShouldPlaceDataLabel() foreach (var series in seriesCollection) series.DataLabelsPosition = PolarLabelsPosition.Start; _ = chart.GetImage(); + chart.SaveImage("_pie-start.png"); points = seriesCollection.SelectMany(x => x.DataFactory @@ -228,6 +235,7 @@ public void ShouldPlaceDataLabel() foreach (var series in seriesCollection) series.DataLabelsPosition = PolarLabelsPosition.End; _ = chart.GetImage(); + chart.SaveImage("_pie-end.png"); foreach (var p in points) { @@ -244,6 +252,7 @@ public void ShouldPlaceDataLabel() foreach (var series in seriesCollection) series.DataLabelsPosition = PolarLabelsPosition.Outer; _ = chart.GetImage(); + chart.SaveImage("_pie-outer.png"); points = seriesCollection.SelectMany(x => x.DataFactory @@ -261,5 +270,315 @@ public void ShouldPlaceDataLabel() Assert.IsTrue(Math.Abs(a - r) < 0.01); } + + #endregion + + #region inner + + foreach (var series in seriesCollection) series.InnerRadius = 100; + + foreach (var series in seriesCollection) series.DataLabelsPosition = PolarLabelsPosition.ChartCenter; + _ = chart.GetImage(); + chart.SaveImage("_pie-center-inner.png"); + + points = seriesCollection.SelectMany(x => + x.DataFactory + .Fetch(x, chart.Core) + .Select(x.ConvertToTypedChartPoint)); + + foreach (var p in points) + { + Assert.IsTrue( + Math.Abs(p.Label.X - 250) < 0.01 && + Math.Abs(p.Label.Y - 250) < 0.01); + } + + foreach (var series in seriesCollection) series.DataLabelsPosition = PolarLabelsPosition.Middle; + _ = chart.GetImage(); + chart.SaveImage("_pie-middle-inner.png"); + + points = seriesCollection.SelectMany(x => + x.DataFactory + .Fetch(x, chart.Core) + .Select(x.ConvertToTypedChartPoint)); + + foreach (var p in points) + { + var h = Math.Sqrt(Math.Pow(p.Label.X - 250, 2) + Math.Pow(p.Label.Y - 250, 2)); + Assert.IsTrue(h < 500 * 0.5f * 0.65f); + + var a = Math.Atan2(p.Label.Y - 250, p.Label.X - 250) * 180 / Math.PI; + if (a < 0) a += 360; + var r = p.Visual.StartAngle + p.Visual.SweepAngle * 0.5f; + + Assert.IsTrue(Math.Abs(a - r) < 0.01); + } + + foreach (var series in seriesCollection) series.DataLabelsPosition = PolarLabelsPosition.Start; + _ = chart.GetImage(); + chart.SaveImage("_pie-start-inner.png"); + + points = seriesCollection.SelectMany(x => + x.DataFactory + .Fetch(x, chart.Core) + .Select(x.ConvertToTypedChartPoint)); + + foreach (var p in points) + { + var h = Math.Sqrt(Math.Pow(p.Label.X - 250, 2) + Math.Pow(p.Label.Y - 250, 2)); + Assert.IsTrue(h < 500 * 0.5f * 0.65f); + + var a = Math.Atan2(p.Label.Y - 250, p.Label.X - 250) * 180 / Math.PI; + if (a < 0) a += 360; + var r = p.Visual.StartAngle; + + Assert.IsTrue(Math.Abs(a - r) < 0.01); + } + + foreach (var series in seriesCollection) series.DataLabelsPosition = PolarLabelsPosition.End; + _ = chart.GetImage(); + chart.SaveImage("_pie-end-inner.png"); + + foreach (var p in points) + { + var h = Math.Sqrt(Math.Pow(p.Label.X - 250, 2) + Math.Pow(p.Label.Y - 250, 2)); + Assert.IsTrue(h < 500 * 0.5f * 0.65f); + + var a = Math.Atan2(p.Label.Y - 250, p.Label.X - 250) * 180 / Math.PI; + if (a < 0) a += 360; + var r = p.Visual.StartAngle + p.Visual.SweepAngle; + if (Math.Abs(r - 360) < 0.001) r = 0; + + Assert.IsTrue(Math.Abs(a - r) < 0.01); + } + + foreach (var series in seriesCollection) series.DataLabelsPosition = PolarLabelsPosition.Outer; + _ = chart.GetImage(); + chart.SaveImage("_pie-outer-inner.png"); + + points = seriesCollection.SelectMany(x => + x.DataFactory + .Fetch(x, chart.Core) + .Select(x.ConvertToTypedChartPoint)); + + foreach (var p in points) + { + var h = Math.Sqrt(Math.Pow(p.Label.X - 250, 2) + Math.Pow(p.Label.Y - 250, 2)); + Assert.IsTrue(h > p.Visual.Width * 0.5f); + + var a = Math.Atan2(p.Label.Y - 250, p.Label.X - 250) * 180 / Math.PI; + if (a < 0) a += 360; + var r = p.Visual.StartAngle + p.Visual.SweepAngle * 0.5f; + + Assert.IsTrue(Math.Abs(a - r) < 0.01); + } + + #endregion + + #region outer + + foreach (var series in seriesCollection) series.InnerRadius = 0; + foreach (var series in seriesCollection) series.MaxOuterRadius = 0.5; + + foreach (var series in seriesCollection) series.DataLabelsPosition = PolarLabelsPosition.ChartCenter; + _ = chart.GetImage(); + chart.SaveImage("_pie-center-outer.png"); + + points = seriesCollection.SelectMany(x => + x.DataFactory + .Fetch(x, chart.Core) + .Select(x.ConvertToTypedChartPoint)); + + foreach (var p in points) + { + Assert.IsTrue( + Math.Abs(p.Label.X - 250) < 0.01 && + Math.Abs(p.Label.Y - 250) < 0.01); + } + + foreach (var series in seriesCollection) series.DataLabelsPosition = PolarLabelsPosition.Middle; + _ = chart.GetImage(); + chart.SaveImage("_pie-middle-outer.png"); + + points = seriesCollection.SelectMany(x => + x.DataFactory + .Fetch(x, chart.Core) + .Select(x.ConvertToTypedChartPoint)); + + foreach (var p in points) + { + var h = Math.Sqrt(Math.Pow(p.Label.X - 250, 2) + Math.Pow(p.Label.Y - 250, 2)); + Assert.IsTrue(h < 500 * 0.5f * 0.65f); + + var a = Math.Atan2(p.Label.Y - 250, p.Label.X - 250) * 180 / Math.PI; + if (a < 0) a += 360; + var r = p.Visual.StartAngle + p.Visual.SweepAngle * 0.5f; + + Assert.IsTrue(Math.Abs(a - r) < 0.01); + } + + foreach (var series in seriesCollection) series.DataLabelsPosition = PolarLabelsPosition.Start; + _ = chart.GetImage(); + chart.SaveImage("_pie-start-outer.png"); + + points = seriesCollection.SelectMany(x => + x.DataFactory + .Fetch(x, chart.Core) + .Select(x.ConvertToTypedChartPoint)); + + foreach (var p in points) + { + var h = Math.Sqrt(Math.Pow(p.Label.X - 250, 2) + Math.Pow(p.Label.Y - 250, 2)); + Assert.IsTrue(h < 500 * 0.5f * 0.65f); + + var a = Math.Atan2(p.Label.Y - 250, p.Label.X - 250) * 180 / Math.PI; + if (a < 0) a += 360; + var r = p.Visual.StartAngle; + + Assert.IsTrue(Math.Abs(a - r) < 0.01); + } + + foreach (var series in seriesCollection) series.DataLabelsPosition = PolarLabelsPosition.End; + _ = chart.GetImage(); + chart.SaveImage("_pie-end-outer.png"); + + foreach (var p in points) + { + var h = Math.Sqrt(Math.Pow(p.Label.X - 250, 2) + Math.Pow(p.Label.Y - 250, 2)); + Assert.IsTrue(h < 500 * 0.5f * 0.65f); + + var a = Math.Atan2(p.Label.Y - 250, p.Label.X - 250) * 180 / Math.PI; + if (a < 0) a += 360; + var r = p.Visual.StartAngle + p.Visual.SweepAngle; + if (Math.Abs(r - 360) < 0.001) r = 0; + + Assert.IsTrue(Math.Abs(a - r) < 0.01); + } + + foreach (var series in seriesCollection) series.DataLabelsPosition = PolarLabelsPosition.Outer; + _ = chart.GetImage(); + chart.SaveImage("_pie-outer-outer.png"); + + points = seriesCollection.SelectMany(x => + x.DataFactory + .Fetch(x, chart.Core) + .Select(x.ConvertToTypedChartPoint)); + + foreach (var p in points) + { + var h = Math.Sqrt(Math.Pow(p.Label.X - 250, 2) + Math.Pow(p.Label.Y - 250, 2)); + Assert.IsTrue(h > p.Visual.Width * 0.5f); + + var a = Math.Atan2(p.Label.Y - 250, p.Label.X - 250) * 180 / Math.PI; + if (a < 0) a += 360; + var r = p.Visual.StartAngle + p.Visual.SweepAngle * 0.5f; + + Assert.IsTrue(Math.Abs(a - r) < 0.01); + } + + #endregion + + #region inner and outer + + foreach (var series in seriesCollection) series.InnerRadius = 50; + foreach (var series in seriesCollection) series.MaxOuterRadius = 0.75; + + foreach (var series in seriesCollection) series.DataLabelsPosition = PolarLabelsPosition.ChartCenter; + _ = chart.GetImage(); + chart.SaveImage("_pie-center-inner-outer.png"); + + points = seriesCollection.SelectMany(x => + x.DataFactory + .Fetch(x, chart.Core) + .Select(x.ConvertToTypedChartPoint)); + + foreach (var p in points) + { + Assert.IsTrue( + Math.Abs(p.Label.X - 250) < 0.01 && + Math.Abs(p.Label.Y - 250) < 0.01); + } + + foreach (var series in seriesCollection) series.DataLabelsPosition = PolarLabelsPosition.Middle; + _ = chart.GetImage(); + chart.SaveImage("_pie-middle-inner-outer.png"); + + points = seriesCollection.SelectMany(x => + x.DataFactory + .Fetch(x, chart.Core) + .Select(x.ConvertToTypedChartPoint)); + + foreach (var p in points) + { + var h = Math.Sqrt(Math.Pow(p.Label.X - 250, 2) + Math.Pow(p.Label.Y - 250, 2)); + Assert.IsTrue(h < 500 * 0.5f * 0.65f); + + var a = Math.Atan2(p.Label.Y - 250, p.Label.X - 250) * 180 / Math.PI; + if (a < 0) a += 360; + var r = p.Visual.StartAngle + p.Visual.SweepAngle * 0.5f; + + Assert.IsTrue(Math.Abs(a - r) < 0.01); + } + + foreach (var series in seriesCollection) series.DataLabelsPosition = PolarLabelsPosition.Start; + _ = chart.GetImage(); + chart.SaveImage("_pie-start-inner-outer.png"); + + points = seriesCollection.SelectMany(x => + x.DataFactory + .Fetch(x, chart.Core) + .Select(x.ConvertToTypedChartPoint)); + + foreach (var p in points) + { + var h = Math.Sqrt(Math.Pow(p.Label.X - 250, 2) + Math.Pow(p.Label.Y - 250, 2)); + Assert.IsTrue(h < 500 * 0.5f * 0.65f); + + var a = Math.Atan2(p.Label.Y - 250, p.Label.X - 250) * 180 / Math.PI; + if (a < 0) a += 360; + var r = p.Visual.StartAngle; + + Assert.IsTrue(Math.Abs(a - r) < 0.01); + } + + foreach (var series in seriesCollection) series.DataLabelsPosition = PolarLabelsPosition.End; + _ = chart.GetImage(); + chart.SaveImage("_pie-end-inner-outer.png"); + + foreach (var p in points) + { + var h = Math.Sqrt(Math.Pow(p.Label.X - 250, 2) + Math.Pow(p.Label.Y - 250, 2)); + Assert.IsTrue(h < 500 * 0.5f * 0.65f); + + var a = Math.Atan2(p.Label.Y - 250, p.Label.X - 250) * 180 / Math.PI; + if (a < 0) a += 360; + var r = p.Visual.StartAngle + p.Visual.SweepAngle; + if (Math.Abs(r - 360) < 0.001) r = 0; + + Assert.IsTrue(Math.Abs(a - r) < 0.01); + } + + foreach (var series in seriesCollection) series.DataLabelsPosition = PolarLabelsPosition.Outer; + _ = chart.GetImage(); + chart.SaveImage("_pie-outer-inner-outer.png"); + + points = seriesCollection.SelectMany(x => + x.DataFactory + .Fetch(x, chart.Core) + .Select(x.ConvertToTypedChartPoint)); + + foreach (var p in points) + { + var h = Math.Sqrt(Math.Pow(p.Label.X - 250, 2) + Math.Pow(p.Label.Y - 250, 2)); + Assert.IsTrue(h > p.Visual.Width * 0.5f); + + var a = Math.Atan2(p.Label.Y - 250, p.Label.X - 250) * 180 / Math.PI; + if (a < 0) a += 360; + var r = p.Visual.StartAngle + p.Visual.SweepAngle * 0.5f; + + Assert.IsTrue(Math.Abs(a - r) < 0.01); + } + + #endregion } } From 0fa9bd003beee957ef91bdf47b4e143757feb723 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Fri, 28 Jul 2023 10:19:08 -0600 Subject: [PATCH 38/54] fixes #1140 --- src/LiveChartsCore/CartesianSeries.cs | 30 ++---------- src/LiveChartsCore/FinancialSeries.cs | 13 ----- src/LiveChartsCore/RowSeries.cs | 69 ++++++++++++++++++++++++--- 3 files changed, 67 insertions(+), 45 deletions(-) diff --git a/src/LiveChartsCore/CartesianSeries.cs b/src/LiveChartsCore/CartesianSeries.cs index 64f3c1d82..3725db13e 100644 --- a/src/LiveChartsCore/CartesianSeries.cs +++ b/src/LiveChartsCore/CartesianSeries.cs @@ -136,8 +136,8 @@ public virtual SeriesBounds GetBounds( }, PrimaryBounds = new Bounds { - Max = rawBaseBounds.PrimaryBounds.Max + rpo * secondaryAxis.UnitWidth, - Min = rawBaseBounds.PrimaryBounds.Min - rpo * secondaryAxis.UnitWidth, + Max = rawBaseBounds.PrimaryBounds.Max + rpo * primaryAxis.UnitWidth, + Min = rawBaseBounds.PrimaryBounds.Min - rpo * primaryAxis.UnitWidth, MinDelta = rawBaseBounds.PrimaryBounds.MinDelta, PaddingMax = tp, PaddingMin = tp, @@ -150,26 +150,13 @@ public virtual SeriesBounds GetBounds( }, VisiblePrimaryBounds = new Bounds { - Max = rawBaseBounds.VisiblePrimaryBounds.Max + rpo * secondaryAxis.UnitWidth, - Min = rawBaseBounds.VisiblePrimaryBounds.Min - rpo * secondaryAxis.UnitWidth + Max = rawBaseBounds.VisiblePrimaryBounds.Max + rpo * primaryAxis.UnitWidth, + Min = rawBaseBounds.VisiblePrimaryBounds.Min - rpo * primaryAxis.UnitWidth }, TertiaryBounds = rawBaseBounds.TertiaryBounds, VisibleTertiaryBounds = rawBaseBounds.VisibleTertiaryBounds }; - if (GetIsInvertedBounds()) - { - var tempSb = dimensionalBounds.SecondaryBounds; - var tempPb = dimensionalBounds.PrimaryBounds; - var tempVsb = dimensionalBounds.VisibleSecondaryBounds; - var tempVpb = dimensionalBounds.VisiblePrimaryBounds; - - dimensionalBounds.SecondaryBounds = tempPb; - dimensionalBounds.PrimaryBounds = tempSb; - dimensionalBounds.VisibleSecondaryBounds = tempVpb; - dimensionalBounds.VisiblePrimaryBounds = tempVsb; - } - return new SeriesBounds(dimensionalBounds, false); } @@ -252,15 +239,6 @@ protected virtual double GetRequestedPrimaryOffset() return 0; } - /// - /// Gets whether the requested bounds are inverted. - /// - /// The offset - protected virtual bool GetIsInvertedBounds() - { - return false; - } - /// /// Deletes the series from the user interface. /// diff --git a/src/LiveChartsCore/FinancialSeries.cs b/src/LiveChartsCore/FinancialSeries.cs index a6b16329a..4b481dd96 100644 --- a/src/LiveChartsCore/FinancialSeries.cs +++ b/src/LiveChartsCore/FinancialSeries.cs @@ -379,19 +379,6 @@ public override SeriesBounds GetBounds( VisibleTertiaryBounds = rawBaseBounds.VisibleTertiaryBounds }; - if (GetIsInvertedBounds()) - { - var tempSb = dimensionalBounds.SecondaryBounds; - var tempPb = dimensionalBounds.PrimaryBounds; - var tempVsb = dimensionalBounds.VisibleSecondaryBounds; - var tempVpb = dimensionalBounds.VisiblePrimaryBounds; - - dimensionalBounds.SecondaryBounds = tempPb; - dimensionalBounds.PrimaryBounds = tempSb; - dimensionalBounds.VisibleSecondaryBounds = tempVpb; - dimensionalBounds.VisiblePrimaryBounds = tempVsb; - } - return new SeriesBounds(dimensionalBounds, false); } diff --git a/src/LiveChartsCore/RowSeries.cs b/src/LiveChartsCore/RowSeries.cs index 4818c2964..08f6895d2 100644 --- a/src/LiveChartsCore/RowSeries.cs +++ b/src/LiveChartsCore/RowSeries.cs @@ -268,12 +268,6 @@ protected override double GetRequestedSecondaryOffset() return 0.5f; } - /// - protected override bool GetIsInvertedBounds() - { - return true; - } - /// protected override void SetDefaultPointTransitions(ChartPoint chartPoint) { @@ -314,4 +308,67 @@ protected internal override void SoftDeleteOrDisposePoint(ChartPoint point, Scal label.TextSize = 1; label.RemoveOnCompleted = true; } + + /// + public override SeriesBounds GetBounds(CartesianChart chart, ICartesianAxis secondaryAxis, ICartesianAxis primaryAxis) + { + var rawBounds = DataFactory.GetCartesianBounds(chart, this, secondaryAxis, primaryAxis); + if (rawBounds.HasData) return rawBounds; + + var rawBaseBounds = rawBounds.Bounds; + + var tickPrimary = primaryAxis.GetTick(chart.ControlSize, rawBaseBounds.VisibleSecondaryBounds); + var tickSecondary = secondaryAxis.GetTick(chart.ControlSize, rawBaseBounds.VisiblePrimaryBounds); + + var ts = tickSecondary.Value * DataPadding.X; + var tp = tickPrimary.Value * DataPadding.Y; + + // using different methods for both primary and secondary axis seems to be the best solution + // if this the following 2 lines needs to be changed again, please ensure that the following test passes: + // https://github.com/beto-rodriguez/LiveCharts2/issues/522 + // https://github.com/beto-rodriguez/LiveCharts2/issues/642 + + if (rawBaseBounds.VisibleSecondaryBounds.Delta == 0) tp = secondaryAxis.UnitWidth * DataPadding.X; + if (rawBaseBounds.VisiblePrimaryBounds.Delta == 0) ts = rawBaseBounds.VisiblePrimaryBounds.Max * 0.25f; + + var rgs = GetRequestedGeometrySize(); + var rso = GetRequestedSecondaryOffset(); + var rpo = GetRequestedPrimaryOffset(); + + var dimensionalBounds = new DimensionalBounds + { + SecondaryBounds = new Bounds + { + Max = rawBaseBounds.PrimaryBounds.Max + rpo * secondaryAxis.UnitWidth, + Min = rawBaseBounds.PrimaryBounds.Min - rpo * secondaryAxis.UnitWidth, + MinDelta = rawBaseBounds.PrimaryBounds.MinDelta, + PaddingMax = ts, + PaddingMin = ts, + RequestedGeometrySize = rgs + }, + PrimaryBounds = new Bounds + { + Max = rawBaseBounds.SecondaryBounds.Max + rso * primaryAxis.UnitWidth, + Min = rawBaseBounds.SecondaryBounds.Min - rso * primaryAxis.UnitWidth, + MinDelta = rawBaseBounds.SecondaryBounds.MinDelta, + PaddingMax = tp, + PaddingMin = tp, + RequestedGeometrySize = rgs + }, + VisibleSecondaryBounds = new Bounds + { + Max = rawBaseBounds.VisiblePrimaryBounds.Max + rpo * secondaryAxis.UnitWidth, + Min = rawBaseBounds.VisiblePrimaryBounds.Min - rpo * secondaryAxis.UnitWidth + }, + VisiblePrimaryBounds = new Bounds + { + Max = rawBaseBounds.VisibleSecondaryBounds.Max + rso * primaryAxis.UnitWidth, + Min = rawBaseBounds.VisibleSecondaryBounds.Min - rso * primaryAxis.UnitWidth, + }, + TertiaryBounds = rawBaseBounds.TertiaryBounds, + VisibleTertiaryBounds = rawBaseBounds.VisibleTertiaryBounds + }; + + return new SeriesBounds(dimensionalBounds, false); + } } From 1a7753eb883016921ac9136ac6f21a4bfdc8e22b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Fri, 28 Jul 2023 11:35:22 -0600 Subject: [PATCH 39/54] remove unessesary usings --- src/LiveChartsCore/Kernel/Drawing/SemicircleHoverArea.cs | 1 - src/LiveChartsCore/Kernel/Events/VisualElementHandler.cs | 4 ---- src/LiveChartsCore/Kernel/Sketches/IPolarChartView.cs | 1 - src/LiveChartsCore/Labelers.cs | 1 - src/LiveChartsCore/StrokeAndFillCartesianSeries.cs | 1 - 5 files changed, 8 deletions(-) diff --git a/src/LiveChartsCore/Kernel/Drawing/SemicircleHoverArea.cs b/src/LiveChartsCore/Kernel/Drawing/SemicircleHoverArea.cs index 77ef3cd86..5b5879a59 100644 --- a/src/LiveChartsCore/Kernel/Drawing/SemicircleHoverArea.cs +++ b/src/LiveChartsCore/Kernel/Drawing/SemicircleHoverArea.cs @@ -21,7 +21,6 @@ // SOFTWARE. using System; -using System.Diagnostics; using LiveChartsCore.Drawing; using LiveChartsCore.Measure; diff --git a/src/LiveChartsCore/Kernel/Events/VisualElementHandler.cs b/src/LiveChartsCore/Kernel/Events/VisualElementHandler.cs index 7a8663557..f7a195476 100644 --- a/src/LiveChartsCore/Kernel/Events/VisualElementHandler.cs +++ b/src/LiveChartsCore/Kernel/Events/VisualElementHandler.cs @@ -20,12 +20,8 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -using System; -using System.Collections.Generic; -using System.Linq; using LiveChartsCore.Drawing; using LiveChartsCore.Kernel.Sketches; -using LiveChartsCore.VisualElements; namespace LiveChartsCore.Kernel.Events; diff --git a/src/LiveChartsCore/Kernel/Sketches/IPolarChartView.cs b/src/LiveChartsCore/Kernel/Sketches/IPolarChartView.cs index d1ffa7c70..301777f24 100644 --- a/src/LiveChartsCore/Kernel/Sketches/IPolarChartView.cs +++ b/src/LiveChartsCore/Kernel/Sketches/IPolarChartView.cs @@ -20,7 +20,6 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -using System; using System.Collections.Generic; using LiveChartsCore.Drawing; diff --git a/src/LiveChartsCore/Labelers.cs b/src/LiveChartsCore/Labelers.cs index fd99b3e23..282ab1daf 100644 --- a/src/LiveChartsCore/Labelers.cs +++ b/src/LiveChartsCore/Labelers.cs @@ -23,7 +23,6 @@ using System; using System.Collections.Generic; using System.Globalization; -using LiveChartsCore.Kernel; namespace LiveChartsCore; diff --git a/src/LiveChartsCore/StrokeAndFillCartesianSeries.cs b/src/LiveChartsCore/StrokeAndFillCartesianSeries.cs index ee013c879..c5efe1037 100644 --- a/src/LiveChartsCore/StrokeAndFillCartesianSeries.cs +++ b/src/LiveChartsCore/StrokeAndFillCartesianSeries.cs @@ -23,7 +23,6 @@ using System; using LiveChartsCore.Drawing; using LiveChartsCore.Kernel; -using LiveChartsCore.Kernel.Sketches; namespace LiveChartsCore; From 693a744969a230dd26311ebe90c7b1dcf4bd00dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Fri, 28 Jul 2023 11:39:13 -0600 Subject: [PATCH 40/54] custom bars sample upgrade --- samples/ViewModelsSamples/Bars/Custom/ViewModel.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/samples/ViewModelsSamples/Bars/Custom/ViewModel.cs b/samples/ViewModelsSamples/Bars/Custom/ViewModel.cs index 2d977c9cd..f7dfbe078 100644 --- a/samples/ViewModelsSamples/Bars/Custom/ViewModel.cs +++ b/samples/ViewModelsSamples/Bars/Custom/ViewModel.cs @@ -12,21 +12,21 @@ public partial class ViewModel : ObservableObject { new ColumnSeries { - Values = new double[] { 2, 1, 4, 2, 2, -5, -2 }, + Values = new double[] { 2, 1, 4}, }, // You can also use SVG paths to draw the geometry // LiveCharts already provides some predefined paths in the SVGPoints class. new ColumnSeries { - Values = new double[] { -2, 2, 1, 3, -1, 4, 3 }, - GeometrySvg = SVGPoints.Gem + Values = new double[] { -2, 2, 1 }, + GeometrySvg = SVGPoints.Star }, // you can declare your own gemetry and use the SkiaSharp api to draw it new ColumnSeries { - Values = new double[] { 4, 5, 2, 4, 3, 2, 1 }, + Values = new double[] { 4, 5, 2 }, }, }; } From 18ab28aa4ebe9af029c7173ab76bfec21a51d2dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Fri, 28 Jul 2023 11:41:43 -0600 Subject: [PATCH 41/54] typo --- samples/ViewModelsSamples/Bars/Custom/MyGeometry.cs | 2 +- .../Drawing/Geometries/SVGPathGeometry.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/ViewModelsSamples/Bars/Custom/MyGeometry.cs b/samples/ViewModelsSamples/Bars/Custom/MyGeometry.cs index c20d9585e..4edd67813 100644 --- a/samples/ViewModelsSamples/Bars/Custom/MyGeometry.cs +++ b/samples/ViewModelsSamples/Bars/Custom/MyGeometry.cs @@ -14,7 +14,7 @@ public override void OnDraw(SkiaSharpDrawingContext context, SKPaint paint) while (y < Y + Height) { canvas.DrawLine(X, y, X + Width, y, paint); - y += 10; + y += 5; } } } diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/SVGPathGeometry.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/SVGPathGeometry.cs index a3732c0e3..54ab747ec 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/SVGPathGeometry.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/SVGPathGeometry.cs @@ -30,7 +30,7 @@ namespace LiveChartsCore.SkiaSharpView.Drawing.Geometries; /// -/// Defines a geometry that is built using from a svg path. +/// Defines a geometry that is buil from a svg path. /// /// public class SVGPathGeometry : SizedGeometry, ISvgPath From e77d3de9ec18f27d100884000a2a8e22d2f7dac6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Fri, 28 Jul 2023 12:57:17 -0600 Subject: [PATCH 42/54] update conditinal draw sample --- .../General/ConditionalDraw/ViewModel.cs | 59 +++++-------------- 1 file changed, 16 insertions(+), 43 deletions(-) diff --git a/samples/ViewModelsSamples/General/ConditionalDraw/ViewModel.cs b/samples/ViewModelsSamples/General/ConditionalDraw/ViewModel.cs index 5448d02e9..53c8652d9 100644 --- a/samples/ViewModelsSamples/General/ConditionalDraw/ViewModel.cs +++ b/samples/ViewModelsSamples/General/ConditionalDraw/ViewModel.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.ObjectModel; using System.Threading.Tasks; using CommunityToolkit.Mvvm.ComponentModel; using LiveChartsCore; @@ -6,45 +7,32 @@ using LiveChartsCore.Defaults; using LiveChartsCore.SkiaSharpView; using LiveChartsCore.SkiaSharpView.Painting; -using LiveChartsCore.SkiaSharpView.Painting.Effects; using SkiaSharp; namespace ViewModelsSamples.General.ConditionalDraw; public partial class ViewModel : ObservableObject { + private readonly ObservableCollection _values = new(); + public ViewModel() { - var series1 = new ColumnSeries + _values = new ObservableCollection { - Name = "Mary", - Values = new ObservableValue[] { new(2), new(5), new(4), new(6), new(8), new(3), new(2), new(4), new(6) } - } - .WithConditionalPaint(new SolidColorPaint(SKColors.Black.WithAlpha(50))) - .When(point => point.Model?.Value > 5); + new(2), new(5), new(4), new(6), new(8), new(3), new(2), new(4), new(6) + }; - var series2 = new ColumnSeries + var series1 = new ColumnSeries { Name = "Mary", - Values = new City[] { new(4), new(2), new(8), new(3), new(2), new(4), new(6), new(4), new(4) }, - Mapping = (city, point) => - { - // use the Population property as the Y coordinate - // and the index of the city in the array as the X coordinate - point.Coordinate = new(point.Index, city.Population); - } + Values = _values } - .WithConditionalPaint(new SolidColorPaint(SKColors.Black.WithAlpha(50))) - .When(point => point.Model?.Population > 5); + .WithConditionalPaint(new SolidColorPaint(SKColors.Red)) + .When(point => point.Model?.Value > 5); - Series = new ISeries[] - { - series1, - series2 - }; + Series = new ISeries[] { series1 }; - Randomize((ISeries)Series[0]); - Randomize((ISeries)Series[1]); + Randomize(); } public ISeries[] Series { get; set; } @@ -53,14 +41,8 @@ public ViewModel() { new RectangularSection { - Yi = 5, Yj = 5, - Stroke = new SolidColorPaint - { - Color = SKColors.Black, - StrokeThickness = 3, - PathEffect = new DashEffect(new float[] { 6, 6 }) - } + Fill = new SolidColorPaint(SKColors.Red.WithAlpha(50)) } }; @@ -69,26 +51,17 @@ public ViewModel() new Axis { MinLimit = 0 } }; - private async void Randomize(ISeries series) + private async void Randomize() { var r = new Random(); - if (series.Values is null) return; while (true) { await Task.Delay(3000); - foreach (var item in series.Values) + foreach (var item in _values) { - if (item is ObservableValue observableValue) - { - observableValue.Value = r.Next(0, 10); - } - - if (item is City city) - { - city.Population = r.Next(0, 10); - } + item.Value = r.Next(0, 10); } } } From cdc47cef0535cb1ceff80884d4f6f397f22bf4c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Fri, 28 Jul 2023 13:00:46 -0600 Subject: [PATCH 43/54] conditianl draw sample --- .../ViewModelsSamples/General/ConditionalDraw/ViewModel.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/samples/ViewModelsSamples/General/ConditionalDraw/ViewModel.cs b/samples/ViewModelsSamples/General/ConditionalDraw/ViewModel.cs index 53c8652d9..88c16e750 100644 --- a/samples/ViewModelsSamples/General/ConditionalDraw/ViewModel.cs +++ b/samples/ViewModelsSamples/General/ConditionalDraw/ViewModel.cs @@ -41,6 +41,12 @@ public ViewModel() { new RectangularSection { + Label = "Danger zone!", + LabelSize = 15, + LabelPaint = new SolidColorPaint(SKColors.Red) + { + SKTypeface = SKTypeface.FromFamilyName("Arial", SKFontStyle.Bold) + }, Yj = 5, Fill = new SolidColorPaint(SKColors.Red.WithAlpha(50)) } From 95a0ddac258cac353a16afe11dad2681afd184b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Fri, 28 Jul 2023 13:04:28 -0600 Subject: [PATCH 44/54] fixes #1132 --- .../General/ConditionalDraw/ViewModel.cs | 2 +- samples/ViewModelsSamples/Index.cs | 174 +++++++++--------- .../ConditionalDraw/ConditionalDrawBuilder.cs | 1 + 3 files changed, 89 insertions(+), 88 deletions(-) diff --git a/samples/ViewModelsSamples/General/ConditionalDraw/ViewModel.cs b/samples/ViewModelsSamples/General/ConditionalDraw/ViewModel.cs index 88c16e750..8bc14539c 100644 --- a/samples/ViewModelsSamples/General/ConditionalDraw/ViewModel.cs +++ b/samples/ViewModelsSamples/General/ConditionalDraw/ViewModel.cs @@ -22,7 +22,7 @@ public ViewModel() new(2), new(5), new(4), new(6), new(8), new(3), new(2), new(4), new(6) }; - var series1 = new ColumnSeries + var series1 = new LineSeries { Name = "Mary", Values = _values diff --git a/samples/ViewModelsSamples/Index.cs b/samples/ViewModelsSamples/Index.cs index 3b8901659..21aab9c19 100644 --- a/samples/ViewModelsSamples/Index.cs +++ b/samples/ViewModelsSamples/Index.cs @@ -4,93 +4,93 @@ 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/LabelsFormat", - "Axes/LabelsFormat2", - "Axes/NamedLabels", - "Axes/LabelsRotation", - "Axes/Multiple", - "Axes/Shared", - "Axes/ColorsAndPosition", - "Axes/Crosshairs", - "Axes/CustomSeparatorsInterval", - "Axes/DateTimeScaled", - "Axes/TimeSpanScaled", - "Axes/Logarithmic", - "Axes/Style", - "Axes/Paging", - - "Events/AddPointOnClick", - "Events/Cartesian", - "Events/Pie", - "Events/Polar", - - "General/Scrollable", - "General/Sections", - "General/Sections2", + //"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/LabelsFormat", + //"Axes/LabelsFormat2", + //"Axes/NamedLabels", + //"Axes/LabelsRotation", + //"Axes/Multiple", + //"Axes/Shared", + //"Axes/ColorsAndPosition", + //"Axes/Crosshairs", + //"Axes/CustomSeparatorsInterval", + //"Axes/DateTimeScaled", + //"Axes/TimeSpanScaled", + //"Axes/Logarithmic", + //"Axes/Style", + //"Axes/Paging", + + //"Events/AddPointOnClick", + //"Events/Cartesian", + //"Events/Pie", + //"Events/Polar", + + //"General/Scrollable", + //"General/Sections", + //"General/Sections2", "General/ConditionalDraw", "General/VisualElements", "General/ChartToImage", diff --git a/src/LiveChartsCore/ConditionalDraw/ConditionalDrawBuilder.cs b/src/LiveChartsCore/ConditionalDraw/ConditionalDrawBuilder.cs index c68eeb2af..0f5317243 100644 --- a/src/LiveChartsCore/ConditionalDraw/ConditionalDrawBuilder.cs +++ b/src/LiveChartsCore/ConditionalDraw/ConditionalDrawBuilder.cs @@ -83,6 +83,7 @@ private void OnMeasured(ChartPoint point) if (!_isPaintInCanvas) { canvas.AddDrawableTask(_paint); + if (_paint.ZIndex == 0) _paint.ZIndex = int.MaxValue; _isPaintInCanvas = true; } From e714fb81ff5fc324cb84832e5d72c1a74dcc59c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Fri, 28 Jul 2023 13:05:55 -0600 Subject: [PATCH 45/54] restore samples --- .../General/ConditionalDraw/ViewModel.cs | 2 +- samples/ViewModelsSamples/Index.cs | 174 +++++++++--------- 2 files changed, 88 insertions(+), 88 deletions(-) diff --git a/samples/ViewModelsSamples/General/ConditionalDraw/ViewModel.cs b/samples/ViewModelsSamples/General/ConditionalDraw/ViewModel.cs index 8bc14539c..88c16e750 100644 --- a/samples/ViewModelsSamples/General/ConditionalDraw/ViewModel.cs +++ b/samples/ViewModelsSamples/General/ConditionalDraw/ViewModel.cs @@ -22,7 +22,7 @@ public ViewModel() new(2), new(5), new(4), new(6), new(8), new(3), new(2), new(4), new(6) }; - var series1 = new LineSeries + var series1 = new ColumnSeries { Name = "Mary", Values = _values diff --git a/samples/ViewModelsSamples/Index.cs b/samples/ViewModelsSamples/Index.cs index 21aab9c19..3b8901659 100644 --- a/samples/ViewModelsSamples/Index.cs +++ b/samples/ViewModelsSamples/Index.cs @@ -4,93 +4,93 @@ 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/LabelsFormat", - //"Axes/LabelsFormat2", - //"Axes/NamedLabels", - //"Axes/LabelsRotation", - //"Axes/Multiple", - //"Axes/Shared", - //"Axes/ColorsAndPosition", - //"Axes/Crosshairs", - //"Axes/CustomSeparatorsInterval", - //"Axes/DateTimeScaled", - //"Axes/TimeSpanScaled", - //"Axes/Logarithmic", - //"Axes/Style", - //"Axes/Paging", - - //"Events/AddPointOnClick", - //"Events/Cartesian", - //"Events/Pie", - //"Events/Polar", - - //"General/Scrollable", - //"General/Sections", - //"General/Sections2", + "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/LabelsFormat", + "Axes/LabelsFormat2", + "Axes/NamedLabels", + "Axes/LabelsRotation", + "Axes/Multiple", + "Axes/Shared", + "Axes/ColorsAndPosition", + "Axes/Crosshairs", + "Axes/CustomSeparatorsInterval", + "Axes/DateTimeScaled", + "Axes/TimeSpanScaled", + "Axes/Logarithmic", + "Axes/Style", + "Axes/Paging", + + "Events/AddPointOnClick", + "Events/Cartesian", + "Events/Pie", + "Events/Polar", + + "General/Scrollable", + "General/Sections", + "General/Sections2", "General/ConditionalDraw", "General/VisualElements", "General/ChartToImage", From ec4000505831c2e8761b1172808273b1d2515931 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Fri, 28 Jul 2023 14:39:40 -0600 Subject: [PATCH 46/54] better message for #1124 --- src/LiveChartsCore/Axis.cs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/LiveChartsCore/Axis.cs b/src/LiveChartsCore/Axis.cs index 3d6aa9df0..b51ccbc9b 100644 --- a/src/LiveChartsCore/Axis.cs +++ b/src/LiveChartsCore/Axis.cs @@ -592,7 +592,7 @@ NamePadding is not null || SeparatorsPaint is not null || LabelsPaint is not nul if (hasActivePaint) _ = measured.Add(visualSeparator); - if (_stepCount++ > 10000) ThrowPresicionError(); + if (_stepCount++ > 10000) ThrowInfiniteSeparators(); } foreach (var separatorValueKey in separators.ToArray()) @@ -842,7 +842,7 @@ public virtual LvcSize GetPossibleSize(Chart chart) if (m.Width > w) w = m.Width; if (m.Height > h) h = m.Height; - if (_stepCount++ > 10000) ThrowPresicionError(); + if (_stepCount++ > 10000) ThrowInfiniteSeparators(); } return new LvcSize(w, h); @@ -953,7 +953,7 @@ private LvcSize GetPossibleMaxLabelSize(Chart chart) maxLabelSize.Width > m.Width ? maxLabelSize.Width : m.Width, maxLabelSize.Height > m.Height ? maxLabelSize.Height : m.Height); - if (_stepCount++ > 10000) ThrowPresicionError(); + if (_stepCount++ > 10000) ThrowInfiniteSeparators(); } return maxLabelSize; @@ -1358,10 +1358,12 @@ private string TryGetLabelOrLogError(Func labeler, double value) } } - private void ThrowPresicionError() + private void ThrowInfiniteSeparators() { throw new Exception( - "LiveCharts has detected a precision error, this is probably caused because you are zooming too deep, " + + $"The {_orientation} axis has an excesive number of separators. " + + $"If you set the step manually, ensure the number of separators is less than 10,000. " + + $"This could also be caused because you are zooming too deep, " + $"try to set a limit to the current chart zoom using the Axis.{nameof(MinZoomDelta)} property. " + $"For more info see: https://github.com/beto-rodriguez/LiveCharts2/issues/1076."); } From f82ba20031607c722406eea1be50f32a9fe1b1d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Fri, 28 Jul 2023 14:51:45 -0600 Subject: [PATCH 47/54] fixes #1126 --- src/LiveChartsCore/CartesianChart.cs | 8 ++--- src/LiveChartsCore/Measure/ZoomAndPanMode.cs | 34 ++++++++++++++++---- 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/src/LiveChartsCore/CartesianChart.cs b/src/LiveChartsCore/CartesianChart.cs index 03ebe4828..8948513e5 100644 --- a/src/LiveChartsCore/CartesianChart.cs +++ b/src/LiveChartsCore/CartesianChart.cs @@ -185,7 +185,7 @@ public void Zoom(LvcPoint pivot, ZoomDirection direction, double? scaleFactor = var m = direction == ZoomDirection.ZoomIn ? speed : 1 / speed; - if ((_zoomMode & ZoomAndPanMode.X) == ZoomAndPanMode.X) + if ((_zoomMode & ZoomAndPanMode.ZoomX) == ZoomAndPanMode.ZoomX) { for (var index = 0; index < XAxes.Length; index++) { @@ -241,7 +241,7 @@ public void Zoom(LvcPoint pivot, ZoomDirection direction, double? scaleFactor = } } - if ((_zoomMode & ZoomAndPanMode.Y) == ZoomAndPanMode.Y) + if ((_zoomMode & ZoomAndPanMode.ZoomY) == ZoomAndPanMode.ZoomY) { for (var index = 0; index < YAxes.Length; index++) { @@ -307,7 +307,7 @@ public void Zoom(LvcPoint pivot, ZoomDirection direction, double? scaleFactor = /// public void Pan(LvcPoint delta, bool isActive) { - if ((_zoomMode & ZoomAndPanMode.X) == ZoomAndPanMode.X) + if ((_zoomMode & ZoomAndPanMode.PanX) == ZoomAndPanMode.PanX) { for (var index = 0; index < XAxes.Length; index++) { @@ -340,7 +340,7 @@ public void Pan(LvcPoint delta, bool isActive) } } - if ((_zoomMode & ZoomAndPanMode.Y) == ZoomAndPanMode.Y) + if ((_zoomMode & ZoomAndPanMode.PanY) == ZoomAndPanMode.PanY) { for (var index = 0; index < YAxes.Length; index++) { diff --git a/src/LiveChartsCore/Measure/ZoomAndPanMode.cs b/src/LiveChartsCore/Measure/ZoomAndPanMode.cs index 8c2494f40..9ed20b76b 100644 --- a/src/LiveChartsCore/Measure/ZoomAndPanMode.cs +++ b/src/LiveChartsCore/Measure/ZoomAndPanMode.cs @@ -36,23 +36,43 @@ public enum ZoomAndPanMode None = 0, /// - /// Enables zooming and panning on the X axis. + /// Enables panning on the X axis. /// - X = 1 << 0, + PanX = 1 << 0, /// - /// Enables zooming and panning on the Y axis. + /// Enables panning on the Y axis. /// - Y = 1 << 1, + PanY = 1 << 1, /// - /// Enables zooming and panning on both axes. + /// Enables zooming on the X axis. /// - Both = X | Y, + ZoomX = 1 << 2, + + /// + /// Enables zooming on the Y axis. + /// + ZoomY = 1 << 3, /// /// When this flag is present the panning will be triggered using the right click on desktop devices and the touch-and-hold gesture on touch devices. /// The "Zoom by section" feature will be triggered to the left click on desktop devices and the touch-and-hold gesture on touch devices. /// - InvertPanningPointerTrigger + InvertPanningPointerTrigger = 1 << 4, + + /// + /// Enables zooming and panning on the X axis. + /// + X = 1 << PanX | ZoomX, + + /// + /// Enables zooming and panning on the Y axis. + /// + Y = 1 << PanY | ZoomY, + + /// + /// Enables zooming and panning on both axes. + /// + Both = X | Y, } From 26efb5e144e8c6c60ad153d5fc057727879fa3a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Fri, 28 Jul 2023 15:07:11 -0600 Subject: [PATCH 48/54] docs for #1126 --- docs/cartesianChart/axes.md | 25 ++++++++++++++++++++++--- docs/samples/lines/zoom/template.md | 24 +++++++++++++++++++++--- 2 files changed, 43 insertions(+), 6 deletions(-) diff --git a/docs/cartesianChart/axes.md b/docs/cartesianChart/axes.md index 525c99556..c517165cc 100644 --- a/docs/cartesianChart/axes.md +++ b/docs/cartesianChart/axes.md @@ -19,10 +19,29 @@ not cover all of them, if you need to know more about this type then use the [AP Both of these features are directly related to the MaxLimit and MinLimit properties, zooming occurs when the mouse wheel moves or when the pinch gesture occurs, the panning is called when the pointer goes down, -moves and then goes up +moves and then goes up or when the pinch gesture occurs. -Zooming is disabled by default, you must set the `ZoomMode` property to `X`, `Y` or `Both`, normally the `X` mode is the most accurate -for horizontal series (LineSeries, ColumnSeries), the `Y` mode for vertical series (RowSeries) and the `Both` mode for Heat or Scatter series. +Zooming and panning is disabled by default, you can enable it by setting the `ZoomMode` property, this property is of type +[ZoomAndPanMode](https://lvcharts.com/api/{{ version }}/LiveChartsCore.Measure.ZoomAndPanMode) and the options are: + +- `X`: Enables zooming and panning on the X axis. +- `Y`: Enables zooming and panning on the Y axis. +- `Both`: Enables zooming and panning on both axes. +- `None`: Disables zooming and panning. +- `PanX`: Enables panning on the X axis. +- `PanY`: Enables panning on the Y axis. +- `ZoomX`: Enables zooming on the X axis. +- `ZoomY`: Enables zooming on the Y axis. + +The [ZoomAndPanMode](https://lvcharts.com/api/{{ version }}/LiveChartsCore.Measure.ZoomAndPanMode) type is a flag enum, +so you can combine the options, for example, if you want to enable zooming on the X axis and panning on the Y axis you can +set the `ZoomMode` property to `ZoomAndPanMode.ZoomX | ZoomAndPanMode.PanY`. + +There is also the `InvertPanningPointerTrigger` flag, when this flag is present the panning will be triggered using +the right click on desktop devices and the touch-and-hold gesture on touch devices, the `zoom by section` feature will be +triggered to the left click on desktop devices and the touch-and-hold gesture on touch devices. + +Here are a few examples of the different zoom modes: **X Mode:** diff --git a/docs/samples/lines/zoom/template.md b/docs/samples/lines/zoom/template.md index dcceb3e21..f60b73148 100644 --- a/docs/samples/lines/zoom/template.md +++ b/docs/samples/lines/zoom/template.md @@ -2,8 +2,26 @@ {{ render this "~/shared/genericSampleJustGifHeader.md" }} Zooming and panning is disabled by default, you can enable it by setting the `ZoomMode` property, this property is of type -`LiveChartsCore.Measure.ZoomAndPanMode` (enum) and the options are `X`, `Y`, `Both` and `None` (default), you can learn more -about zooming an panning [here](https://lvcharts.com/docs/{{ platform }}/{{ version }}/CartesianChart.Axes%20properties#zooming-and-panning). +[ZoomAndPanMode](https://lvcharts.com/api/{{ version }}/LiveChartsCore.Measure.ZoomAndPanMode) and the options are: + +- `X`: Enables zooming and panning on the X axis. +- `Y`: Enables zooming and panning on the Y axis. +- `Both`: Enables zooming and panning on both axes. +- `None`: Disables zooming and panning. +- `PanX`: Enables panning on the X axis. +- `PanY`: Enables panning on the Y axis. +- `ZoomX`: Enables zooming on the X axis. +- `ZoomY`: Enables zooming on the Y axis. + +The [ZoomAndPanMode](https://lvcharts.com/api/{{ version }}/LiveChartsCore.Measure.ZoomAndPanMode) type is a flag enum, +so you can combine the options, for example, if you want to enable zooming on the X axis and panning on the Y axis you can +set the `ZoomMode` property to `ZoomAndPanMode.ZoomX | ZoomAndPanMode.PanY`. + +There is also the `InvertPanningPointerTrigger` flag, when this flag is present the panning will be triggered using +the right click on desktop devices and the touch-and-hold gesture on touch devices, the `zoom by section` feature will be +triggered to the left click on desktop devices and the touch-and-hold gesture on touch devices. + +You can learn more about zooming an panning [here](https://lvcharts.com/docs/{{ platform }}/{{ version }}/CartesianChart.Axes%20properties#zooming-and-panning). {{~ if desktop ~}} @@ -43,4 +61,4 @@ In touch devices, pinch the screen in/out to zoom, hold tap and drag to move the {{ full_name | get_view_from_docs }} ``` -{{ render this "~/shared/relatedTo.md" }} \ No newline at end of file +{{ render this "~/shared/relatedTo.md" }} From fee0a8038fe40cb2e18005e900c15c323e2dac8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Fri, 28 Jul 2023 16:27:34 -0600 Subject: [PATCH 49/54] typo --- src/LiveChartsCore/Measure/ZoomAndPanMode.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/LiveChartsCore/Measure/ZoomAndPanMode.cs b/src/LiveChartsCore/Measure/ZoomAndPanMode.cs index 9ed20b76b..9b4d1e38f 100644 --- a/src/LiveChartsCore/Measure/ZoomAndPanMode.cs +++ b/src/LiveChartsCore/Measure/ZoomAndPanMode.cs @@ -64,15 +64,15 @@ public enum ZoomAndPanMode /// /// Enables zooming and panning on the X axis. /// - X = 1 << PanX | ZoomX, + X = PanX | ZoomX, /// /// Enables zooming and panning on the Y axis. /// - Y = 1 << PanY | ZoomY, + Y = PanY | ZoomY, /// /// Enables zooming and panning on both axes. /// - Both = X | Y, + Both = X | Y } From 5ab6e28359931b15b5c364e8976c5ca683941c46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Sun, 30 Jul 2023 14:06:57 -0600 Subject: [PATCH 50/54] fixes #1087 --- src/LiveChartsCore/Drawing/IVectorGeometry.cs | 76 +------- .../Kernel/Drawing/BezierData.cs | 5 + src/LiveChartsCore/Kernel/Extensions.cs | 2 + src/LiveChartsCore/LineSeries.cs | 169 +++++++++++------- src/LiveChartsCore/Measure/VectorManager.cs | 18 +- src/LiveChartsCore/PolarLineSeries.cs | 8 +- .../Drawing/Geometries/VectorGeometry.cs | 66 +------ 7 files changed, 136 insertions(+), 208 deletions(-) diff --git a/src/LiveChartsCore/Drawing/IVectorGeometry.cs b/src/LiveChartsCore/Drawing/IVectorGeometry.cs index 25cf5748c..1ffba786e 100644 --- a/src/LiveChartsCore/Drawing/IVectorGeometry.cs +++ b/src/LiveChartsCore/Drawing/IVectorGeometry.cs @@ -34,6 +34,11 @@ public interface IVectorGeometry : IDrawable + /// Gets or sets the commands. + /// + LinkedList Commands { get; } + /// /// Defines the closing method. /// @@ -43,75 +48,4 @@ public interface IVectorGeometry : IDrawable float Pivot { get; set; } - - /// - /// Gets the first linked node. - /// - LinkedListNode? FirstCommand { get; } - - /// - /// Gets the last linked node. - /// - LinkedListNode? LastCommand { get; } - - /// - /// Gets current commands count. - /// - int CountCommands { get; } - - /// - /// Adds a path command at the end. - /// - /// The command. - /// The linked node. - LinkedListNode AddLast(TSegment command); - - /// - /// Adds a path command at the beginning. - /// - /// The command. - /// The linked node. - LinkedListNode AddFirst(TSegment command); - - /// - /// Adds a command after the given liked node. - /// - /// The linked node. - /// - /// The linked node. - LinkedListNode AddAfter(LinkedListNode node, TSegment command); - - /// - /// Adds a path command before the given linked node. - /// - /// The linked node. - /// - /// The linked node. - LinkedListNode AddBefore(LinkedListNode node, TSegment command); - - /// - /// Removes a path command. - /// - /// The command. - bool RemoveCommand(TSegment command); - - /// - /// Removes the specified node. - /// - /// The node. - void RemoveCommand(LinkedListNode node); - - /// - /// Determines whether the specified command is contained in the current path. - /// - /// The command. - /// - /// true if the specified command contains command; otherwise, false. - /// - bool ContainsCommand(TSegment command); - - /// - /// Clears the commands. - /// - void ClearCommands(); } diff --git a/src/LiveChartsCore/Kernel/Drawing/BezierData.cs b/src/LiveChartsCore/Kernel/Drawing/BezierData.cs index c4f2d8186..07aa810c9 100644 --- a/src/LiveChartsCore/Kernel/Drawing/BezierData.cs +++ b/src/LiveChartsCore/Kernel/Drawing/BezierData.cs @@ -92,5 +92,10 @@ public BezierData(ChartPoint chartPoint) /// The y2. /// public double Y2 { get; set; } + + /// + /// Gets or sets a value indicating whether the next point is empty. + /// + public bool IsNextEmpty { get; set; } } diff --git a/src/LiveChartsCore/Kernel/Extensions.cs b/src/LiveChartsCore/Kernel/Extensions.cs index e24052e82..aca5bbf9c 100644 --- a/src/LiveChartsCore/Kernel/Extensions.cs +++ b/src/LiveChartsCore/Kernel/Extensions.cs @@ -596,6 +596,7 @@ internal static IEnumerable AsSplineData(this IEnumerable chart) foreach (var segment in segments) { - TPathGeometry fillPath; - TPathGeometry strokePath; - var isNew = false; + var hasPaths = false; + var isSegmentEmpty = true; + VectorManager? strokeVector = null, fillVector = null; - if (segmentI >= fillPathHelperContainer.Count) - { - isNew = true; - fillPath = new TPathGeometry { ClosingMethod = VectorClosingMethod.CloseToPivot }; - fillPathHelperContainer.Add(fillPath); - } - else - { - fillPath = fillPathHelperContainer[segmentI]; - } + var line = GetSpline(segment, stacker).ToArray(); - if (segmentI >= strokePathHelperContainer.Count) - { - isNew = true; - strokePath = new TPathGeometry { ClosingMethod = VectorClosingMethod.NotClosed }; - strokePathHelperContainer.Add(strokePath); - } - else + foreach (var data in line) { - strokePath = strokePathHelperContainer[segmentI]; - } + if (!hasPaths) + { + hasPaths = true; - var strokeVector = new VectorManager(strokePath); - var fillVector = new VectorManager(fillPath); + var fillLookup = GetSegmentVisual(segmentI, fillPathHelperContainer, VectorClosingMethod.CloseToPivot); + var strokeLookup = GetSegmentVisual(segmentI, strokePathHelperContainer, VectorClosingMethod.NotClosed); - if (Fill is not null) - { - Fill.AddGeometryToPaintTask(cartesianChart.Canvas, fillPath); - cartesianChart.Canvas.AddDrawableTask(Fill); - Fill.ZIndex = actualZIndex + 0.1; - Fill.SetClipRectangle(cartesianChart.Canvas, new LvcRectangle(drawLocation, drawMarginSize)); - fillPath.Pivot = p; - if (isNew) - { - fillPath.Animate(EasingFunction ?? cartesianChart.EasingFunction, AnimationsSpeed ?? cartesianChart.AnimationsSpeed); - } - } - if (Stroke is not null) - { - Stroke.AddGeometryToPaintTask(cartesianChart.Canvas, strokePath); - cartesianChart.Canvas.AddDrawableTask(Stroke); - Stroke.ZIndex = actualZIndex + 0.2; - Stroke.SetClipRectangle(cartesianChart.Canvas, new LvcRectangle(drawLocation, drawMarginSize)); - strokePath.Pivot = p; - if (isNew) - { - strokePath.Animate(EasingFunction ?? cartesianChart.EasingFunction, AnimationsSpeed ?? cartesianChart.AnimationsSpeed); - } - } + if (fillLookup.Path.Commands.Count == 1 && !data.IsNextEmpty) + { + Fill?.RemoveGeometryFromPainTask(cartesianChart.Canvas, fillLookup.Path); + fillLookup.Path.Commands.Clear(); + fillPathHelperContainer.RemoveAt(segmentI); - var isSegmentEmpty = true; + fillLookup = GetSegmentVisual(segmentI, fillPathHelperContainer, VectorClosingMethod.CloseToPivot); + } + + if (strokeLookup.Path.Commands.Count == 1 && !data.IsNextEmpty) + { + Stroke?.RemoveGeometryFromPainTask(cartesianChart.Canvas, strokeLookup.Path); + strokeLookup.Path.Commands.Clear(); + strokePathHelperContainer.RemoveAt(segmentI); + + strokeLookup = GetSegmentVisual(segmentI, strokePathHelperContainer, VectorClosingMethod.NotClosed); + } + + var isNew = fillLookup.IsNew || strokeLookup.IsNew; + var fillPath = fillLookup.Path; + var strokePath = strokeLookup.Path; + + strokeVector = new VectorManager(strokePath); + fillVector = new VectorManager(fillPath); + + if (Fill is not null) + { + Fill.AddGeometryToPaintTask(cartesianChart.Canvas, fillPath); + cartesianChart.Canvas.AddDrawableTask(Fill); + Fill.ZIndex = actualZIndex + 0.1; + Fill.SetClipRectangle(cartesianChart.Canvas, new LvcRectangle(drawLocation, drawMarginSize)); + fillPath.Pivot = p; + if (isNew) + { + fillPath.Animate(EasingFunction ?? cartesianChart.EasingFunction, AnimationsSpeed ?? cartesianChart.AnimationsSpeed); + } + } + if (Stroke is not null) + { + Stroke.AddGeometryToPaintTask(cartesianChart.Canvas, strokePath); + cartesianChart.Canvas.AddDrawableTask(Stroke); + Stroke.ZIndex = actualZIndex + 0.2; + Stroke.SetClipRectangle(cartesianChart.Canvas, new LvcRectangle(drawLocation, drawMarginSize)); + strokePath.Pivot = p; + if (isNew) + { + strokePath.Animate(EasingFunction ?? cartesianChart.EasingFunction, AnimationsSpeed ?? cartesianChart.AnimationsSpeed); + } + } + } - foreach (var data in GetSpline(segment, stacker)) - { var coordinate = data.TargetPoint.Coordinate; isSegmentEmpty = false; @@ -277,8 +286,8 @@ public override void Invalidate(Chart chart) visual.Bezier.Id = data.TargetPoint.Context.Entity.MetaData!.EntityIndex; - if (Fill is not null) fillVector.AddConsecutiveSegment(visual.Bezier, !IsFirstDraw); - if (Stroke is not null) strokeVector.AddConsecutiveSegment(visual.Bezier, !IsFirstDraw); + if (Fill is not null) fillVector!.AddConsecutiveSegment(visual.Bezier, !IsFirstDraw); + if (Stroke is not null) strokeVector!.AddConsecutiveSegment(visual.Bezier, !IsFirstDraw); visual.Bezier.Xi = secondaryScale.ToPixels(data.X0); visual.Bezier.Xm = secondaryScale.ToPixels(data.X1); @@ -300,8 +309,8 @@ public override void Invalidate(Chart chart) visual.Geometry.Height = gs; visual.Geometry.RemoveOnCompleted = false; - visual.FillPath = fillPath; - visual.StrokePath = strokePath; + visual.FillPath = fillVector!.AreaGeometry; + visual.StrokePath = strokeVector!.AreaGeometry; var hags = gs < 8 ? 8 : gs; @@ -348,8 +357,8 @@ public override void Invalidate(Chart chart) OnPointMeasured(data.TargetPoint); } - strokeVector.End(); - fillVector.End(); + strokeVector?.End(); + fillVector?.End(); if (GeometryFill is not null) { @@ -377,7 +386,7 @@ public override void Invalidate(Chart chart) { var segmentFill = fillPathHelperContainer[i]; Fill?.RemoveGeometryFromPainTask(cartesianChart.Canvas, segmentFill); - segmentFill.ClearCommands(); + segmentFill.Commands.Clear(); fillPathHelperContainer.RemoveAt(i); } @@ -385,7 +394,7 @@ public override void Invalidate(Chart chart) { var segmentStroke = strokePathHelperContainer[i]; Stroke?.RemoveGeometryFromPainTask(cartesianChart.Canvas, segmentStroke); - segmentStroke.ClearCommands(); + segmentStroke.Commands.Clear(); strokePathHelperContainer.RemoveAt(i); } } @@ -400,6 +409,13 @@ public override void Invalidate(Chart chart) pointsCleanup.CollectPoints( everFetched, cartesianChart.View, primaryScale, secondaryScale, SoftDeleteOrDisposePoint); + Trace.WriteLine($"==="); + var ii = 0; + foreach (var item in strokePathHelperContainer) + { + Trace.WriteLine($"segment {ii++} => {item.Commands.Count} commands"); + } + IsFirstDraw = false; _geometrySvgChanged = false; } @@ -516,7 +532,8 @@ protected internal IEnumerable GetSpline( X1 = c.SecondaryValue, Y1 = c.PrimaryValue + sc, X2 = c.SecondaryValue, - Y2 = c.PrimaryValue + sc + Y2 = c.PrimaryValue + sc, + IsNextEmpty = item.IsNextEmpty }; continue; @@ -653,6 +670,25 @@ private void DeleteNullPoint(ChartPoint point, Scaler xScale, Scaler yScale) point.Context.Visual = null; } + private SegmentVisual GetSegmentVisual(int index, List container, VectorClosingMethod method) + { + var isNew = false; + TPathGeometry? path; + + if (index >= container.Count) + { + isNew = true; + path = new TPathGeometry { ClosingMethod = method }; + container.Add(path); + } + else + { + path = container[index]; + } + + return new SegmentVisual(isNew, path); + } + private class SplineData { public SplineData(ChartPoint start) @@ -681,4 +717,17 @@ public void GoNext(ChartPoint point) AfterNext = point; } } + + private class SegmentVisual + { + public SegmentVisual(bool isNew, TPathGeometry path) + { + IsNew = isNew; + Path = path; + } + + public bool IsNew { get; set; } + + public TPathGeometry Path { get; set; } + } } diff --git a/src/LiveChartsCore/Measure/VectorManager.cs b/src/LiveChartsCore/Measure/VectorManager.cs index 935d41e91..925dc03b7 100644 --- a/src/LiveChartsCore/Measure/VectorManager.cs +++ b/src/LiveChartsCore/Measure/VectorManager.cs @@ -46,7 +46,7 @@ public class VectorManager public VectorManager(IVectorGeometry areaGeometry) { AreaGeometry = areaGeometry; - _nextNode = areaGeometry.FirstCommand; + _nextNode = areaGeometry.Commands.First; } /// @@ -68,7 +68,7 @@ _nextNode.Next is not null && { _nextNode = _nextNode.Next; if (_nextNode.Previous is null) continue; - AreaGeometry.RemoveCommand(_nextNode.Previous); + AreaGeometry.Commands.Remove(_nextNode.Previous); } // at this points "_nextNode" is: @@ -79,7 +79,7 @@ _nextNode.Next is not null && if (_nextNode is null) { if (_currentNode is not null && followsPrevious) segment.Follows(_currentNode.Value); - _currentNode = AreaGeometry.AddLast(segment); + _currentNode = AreaGeometry.Commands.AddLast(segment); return; } @@ -95,10 +95,10 @@ _nextNode.Next is not null && return; } - if (_currentNode is null) _currentNode = _nextNode; + _currentNode ??= _nextNode; if (followsPrevious) segment.Follows(_currentNode.Value); - _currentNode = AreaGeometry.AddBefore(_nextNode, segment); + _currentNode = AreaGeometry.Commands.AddBefore(_nextNode, segment); _nextNode = _currentNode.Next; } @@ -107,7 +107,7 @@ _nextNode.Next is not null && /// public void Clear() { - AreaGeometry.ClearCommands(); + AreaGeometry.Commands.Clear(); } /// @@ -117,8 +117,10 @@ public void End() { while (_currentNode?.Next is not null) { - AreaGeometry.RemoveCommand(_currentNode.Next); + AreaGeometry.Commands.Remove(_currentNode.Next); } + + AreaGeometry.IsValid = false; } /// @@ -127,7 +129,7 @@ public void End() public void LogPath() { var a = ""; - var c = AreaGeometry.FirstCommand; + var c = AreaGeometry.Commands.First; while (c != null) { diff --git a/src/LiveChartsCore/PolarLineSeries.cs b/src/LiveChartsCore/PolarLineSeries.cs index 659af00fa..eea580b36 100644 --- a/src/LiveChartsCore/PolarLineSeries.cs +++ b/src/LiveChartsCore/PolarLineSeries.cs @@ -230,8 +230,8 @@ public override void Invalidate(Chart chart) _fillPathHelperDictionary[chart.Canvas.Sync] = fillPathHelperContainer; } - foreach (var item in strokePathHelperContainer) item.ClearCommands(); - foreach (var item in fillPathHelperContainer) item.ClearCommands(); + foreach (var item in strokePathHelperContainer) item.Commands.Clear(); + foreach (var item in fillPathHelperContainer) item.Commands.Clear(); var r = (float)DataLabelsRotation; var isTangent = false; @@ -349,8 +349,8 @@ public override void Invalidate(Chart chart) visual.Bezier.Xj = (float)data.X2; visual.Bezier.Yj = (float)data.Y2; - if (Fill is not null) _ = fillPath.AddLast(visual.Bezier); - if (Stroke is not null) _ = strokePath.AddLast(visual.Bezier); + if (Fill is not null) _ = fillPath.Commands.AddLast(visual.Bezier); + if (Stroke is not null) _ = strokePath.Commands.AddLast(visual.Bezier); visual.Geometry.X = x - hgs; visual.Geometry.Y = y - hgs; diff --git a/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/VectorGeometry.cs b/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/VectorGeometry.cs index a33c82d90..d068df74e 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/VectorGeometry.cs +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/VectorGeometry.cs @@ -48,16 +48,7 @@ public VectorGeometry() /// /// Gets the commands in the vector. /// - protected LinkedList Commands { get; } = new(); - - /// - public LinkedListNode? FirstCommand => Commands.First; - - /// - public LinkedListNode? LastCommand => Commands.Last; - - /// - public int CountCommands => Commands.Count; + public LinkedList Commands { get; } = new(); /// public VectorClosingMethod ClosingMethod { get; set; } @@ -65,61 +56,6 @@ public VectorGeometry() /// public float Pivot { get => _pivotProperty.GetMovement(this); set => _pivotProperty.SetMovement(value, this); } - /// - public LinkedListNode AddLast(TSegment command) - { - IsValid = false; - return Commands.AddLast(command); - } - - /// - public LinkedListNode AddFirst(TSegment command) - { - IsValid = false; - return Commands.AddFirst(command); - } - - /// - public LinkedListNode AddAfter(LinkedListNode node, TSegment command) - { - IsValid = false; - return Commands.AddAfter(node, command); - } - - /// - public LinkedListNode AddBefore(LinkedListNode node, TSegment command) - { - IsValid = false; - return Commands.AddBefore(node, command); - } - - /// - public bool ContainsCommand(TSegment segment) - { - return Commands.Contains(segment); - } - - /// - public bool RemoveCommand(TSegment command) - { - IsValid = false; - return Commands.Remove(command); - } - - /// - public void RemoveCommand(LinkedListNode node) - { - IsValid = false; - Commands.Remove(node); - } - - /// - public void ClearCommands() - { - IsValid = false; - Commands.Clear(); - } - /// public override void CompleteTransition(params string[]? propertyName) { From 310c184ccc373259fa998968e48592f6b1c5a16e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Sun, 30 Jul 2023 14:14:54 -0600 Subject: [PATCH 51/54] remove trace --- src/LiveChartsCore/LineSeries.cs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/LiveChartsCore/LineSeries.cs b/src/LiveChartsCore/LineSeries.cs index d793fb4ea..42786f3d4 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; @@ -409,13 +408,6 @@ public override void Invalidate(Chart chart) pointsCleanup.CollectPoints( everFetched, cartesianChart.View, primaryScale, secondaryScale, SoftDeleteOrDisposePoint); - Trace.WriteLine($"==="); - var ii = 0; - foreach (var item in strokePathHelperContainer) - { - Trace.WriteLine($"segment {ii++} => {item.Commands.Count} commands"); - } - IsFirstDraw = false; _geometrySvgChanged = false; } From 50380e33705ec0fdd5fcbf7b1d327f547589cabd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Sun, 30 Jul 2023 15:16:01 -0600 Subject: [PATCH 52/54] fixes #693 --- src/LiveChartsCore/VisualElements/GeometryVisual.cs | 4 ++++ src/LiveChartsCore/VisualElements/LabelVisual.cs | 12 ------------ src/LiveChartsCore/VisualElements/RelativePanel.cs | 2 ++ src/LiveChartsCore/VisualElements/StackPanel.cs | 2 ++ src/LiveChartsCore/VisualElements/TableLayout.cs | 2 ++ .../VisualElements/VariableGeometryVisual.cs | 2 ++ src/LiveChartsCore/VisualElements/VisualElement.cs | 12 ++++++++++++ 7 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/LiveChartsCore/VisualElements/GeometryVisual.cs b/src/LiveChartsCore/VisualElements/GeometryVisual.cs index 22014bb7b..3204f9ed7 100644 --- a/src/LiveChartsCore/VisualElements/GeometryVisual.cs +++ b/src/LiveChartsCore/VisualElements/GeometryVisual.cs @@ -94,6 +94,8 @@ protected internal override void OnInvalidated(Chart chart) _geometry.Y = l.Y; _geometry.Width = size.Width; _geometry.Height = size.Height; + _geometry.RotateTransform = (float)Rotation; + _geometry.TranslateTransform = Translate; if (Fill is not null) { @@ -133,6 +135,8 @@ protected internal override void OnInvalidated(Chart chart) _labelGeometry.Y = l.Y + padding; _labelGeometry.Text = _label; _labelGeometry.TextSize = _labelSize; + _labelGeometry.RotateTransform = (float)Rotation; + _labelGeometry.TranslateTransform = Translate; chart.Canvas.AddDrawableTask(LabelPaint); LabelPaint.AddGeometryToPaintTask(chart.Canvas, _labelGeometry); diff --git a/src/LiveChartsCore/VisualElements/LabelVisual.cs b/src/LiveChartsCore/VisualElements/LabelVisual.cs index 03a1d71fe..d6195ad7d 100644 --- a/src/LiveChartsCore/VisualElements/LabelVisual.cs +++ b/src/LiveChartsCore/VisualElements/LabelVisual.cs @@ -44,9 +44,7 @@ public class LabelVisual : VisualElement /// Gets or sets the fill paint. @@ -67,16 +65,6 @@ public IPaint? Paint /// public double TextSize { get => _textSize; set => SetProperty(ref _textSize, value); } - /// - /// 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 => SetProperty(ref _translate, value); } - /// /// Gets or sets the vertical alignment. /// diff --git a/src/LiveChartsCore/VisualElements/RelativePanel.cs b/src/LiveChartsCore/VisualElements/RelativePanel.cs index e0a91e1f6..fdb789ad2 100644 --- a/src/LiveChartsCore/VisualElements/RelativePanel.cs +++ b/src/LiveChartsCore/VisualElements/RelativePanel.cs @@ -86,6 +86,8 @@ protected internal override void OnInvalidated(Chart chart) BackgroundGeometry.Y = (float)Y; BackgroundGeometry.Width = Size.Width; BackgroundGeometry.Height = Size.Height; + BackgroundGeometry.RotateTransform = (float)Rotation; + BackgroundGeometry.TranslateTransform = Translate; BackgroundPaint.AddGeometryToPaintTask(chart.Canvas, BackgroundGeometry); foreach (var child in Children) diff --git a/src/LiveChartsCore/VisualElements/StackPanel.cs b/src/LiveChartsCore/VisualElements/StackPanel.cs index f9eaee03c..a212175e9 100644 --- a/src/LiveChartsCore/VisualElements/StackPanel.cs +++ b/src/LiveChartsCore/VisualElements/StackPanel.cs @@ -120,6 +120,8 @@ protected internal override void OnInvalidated(Chart chart) BackgroundGeometry.Y = (float)Y; BackgroundGeometry.Width = controlSize.Width; BackgroundGeometry.Height = controlSize.Height; + BackgroundGeometry.RotateTransform = (float)Rotation; + BackgroundGeometry.TranslateTransform = Translate; BackgroundPaint.AddGeometryToPaintTask(chart.Canvas, BackgroundGeometry); } diff --git a/src/LiveChartsCore/VisualElements/TableLayout.cs b/src/LiveChartsCore/VisualElements/TableLayout.cs index 63b62141a..6b5216092 100644 --- a/src/LiveChartsCore/VisualElements/TableLayout.cs +++ b/src/LiveChartsCore/VisualElements/TableLayout.cs @@ -234,6 +234,8 @@ protected internal override void OnInvalidated(Chart chart) BackgroundGeometry.Y = (float)Y; BackgroundGeometry.Width = controlSize.Width; BackgroundGeometry.Height = controlSize.Height; + BackgroundGeometry.RotateTransform = (float)Rotation; + BackgroundGeometry.TranslateTransform = Translate; BackgroundPaint.AddGeometryToPaintTask(chart.Canvas, BackgroundGeometry); } diff --git a/src/LiveChartsCore/VisualElements/VariableGeometryVisual.cs b/src/LiveChartsCore/VisualElements/VariableGeometryVisual.cs index aaf4b7a3d..cb62c6136 100644 --- a/src/LiveChartsCore/VisualElements/VariableGeometryVisual.cs +++ b/src/LiveChartsCore/VisualElements/VariableGeometryVisual.cs @@ -105,6 +105,8 @@ protected internal override void OnInvalidated(Chart chart) Geometry.Y = y; Geometry.Width = size.Width; Geometry.Height = size.Height; + Geometry.RotateTransform = (float)Rotation; + Geometry.TranslateTransform = Translate; if (Fill is not null) { diff --git a/src/LiveChartsCore/VisualElements/VisualElement.cs b/src/LiveChartsCore/VisualElements/VisualElement.cs index 90b8d7605..336fdab33 100644 --- a/src/LiveChartsCore/VisualElements/VisualElement.cs +++ b/src/LiveChartsCore/VisualElements/VisualElement.cs @@ -38,6 +38,8 @@ public abstract class VisualElement : ChartElement : ChartElement public double Y { get => _y; set => SetProperty(ref _y, value); } + /// + /// 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 => SetProperty(ref _translate, value); } + /// /// Gets or sets the unit of the and properties. /// From 4928055efb29ad21eb54211c76cb756f2883ce48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Sun, 30 Jul 2023 16:18:25 -0600 Subject: [PATCH 53/54] update sample --- .../Pies/Custom/ViewModel.cs | 32 +++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/samples/ViewModelsSamples/Pies/Custom/ViewModel.cs b/samples/ViewModelsSamples/Pies/Custom/ViewModel.cs index 2180f38e3..88823f841 100644 --- a/samples/ViewModelsSamples/Pies/Custom/ViewModel.cs +++ b/samples/ViewModelsSamples/Pies/Custom/ViewModel.cs @@ -2,6 +2,9 @@ using LiveChartsCore; using LiveChartsCore.SkiaSharpView; using CommunityToolkit.Mvvm.ComponentModel; +using LiveChartsCore.SkiaSharpView.Painting; +using SkiaSharp; +using System; namespace ViewModelsSamples.Pies.Custom; @@ -10,7 +13,8 @@ public partial class ViewModel : ObservableObject public ViewModel() { var outer = 1d; - var data = new[] { 6, 5, 4, 3, 2 }; + //var data = new[] { 6, 5, 4, 3 }; + var data = new[] { 6 }; // you can convert any array, list or IEnumerable to a pie series collection: Series = data.AsPieSeries((value, series) => @@ -21,13 +25,37 @@ public ViewModel() // for the series with the value 5, the outer radius is 0.9 // for the series with the value 4, the outer radius is 0.8 // for the series with the value 3, the outer radius is 0.7 - // for the series with the value 2, the outer radius is 0.6 // The MaxOuterRadius property sets the maximum outer, the value goes from // 0 to 1, where 1 is the full available radius and 0 is none. series.MaxOuterRadius = outer; outer -= 0.1; + + series.DataLabelsPaint = new SolidColorPaint(SKColors.White) + { + SKTypeface = SKTypeface.FromFamilyName("Arial", SKFontStyle.Bold) + }; + + series.ToolTipLabelFormatter = + point => + { + var pv = point.Coordinate.PrimaryValue; + var sv = point.StackedValue!; + + var a = $"{pv}/{sv.Total}{Environment.NewLine}{sv.Share:P2}"; + return a; + }; + + series.DataLabelsFormatter = + point => + { + var pv = point.Coordinate.PrimaryValue; + var sv = point.StackedValue!; + + var a = $"{pv}/{sv.Total}{Environment.NewLine}{sv.Share:P2}"; + return a; + }; }); } From 419dadbab3446e4a45164585702fec0490e68f44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Sun, 30 Jul 2023 16:19:07 -0600 Subject: [PATCH 54/54] 2.0.0-beta.900 --- src/LiveChartsCore/LiveChartsCore.csproj | 2 +- .../LiveChartsCore.SkiaSharpView.Avalonia.csproj | 2 +- .../LiveChartsCore.SkiaSharpView.WPF.csproj | 2 +- .../LiveChartsCore.SkiaSharpView.WinForms.csproj | 2 +- ...LiveChartsCore.SkiaSharpView.Xamarin.Forms.csproj | 2 +- .../LiveChartsCore.SkiaSharpView.csproj | 2 +- .../LiveChartsCore.SkiaSharpView.Blazor.csproj | 2 +- .../LiveChartsCore.SkiaSharpView.Eto.csproj | 2 +- .../LiveChartsCore.SkiaSharpView.Maui.csproj | 2 +- .../LiveChartsCore.SkiaSharpView.Maui.nuspec | 12 ++++++------ .../LiveChartsCore.SkiaSharpView.Uno.WinUI.csproj | 2 +- .../LiveChartsCore.SkiaSharpView.Uno.csproj | 2 +- .../LiveChartsCore.SkiaSharpView.WinUI.csproj | 2 +- .../LiveChartsCore.SkiaSharpView.WinUI.nuspec | 6 +++--- 14 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/LiveChartsCore/LiveChartsCore.csproj b/src/LiveChartsCore/LiveChartsCore.csproj index 9887520e3..9e5c16757 100644 --- a/src/LiveChartsCore/LiveChartsCore.csproj +++ b/src/LiveChartsCore/LiveChartsCore.csproj @@ -17,7 +17,7 @@ LiveChartsCore LiveChartsCore - 2.0.0-beta.860 + 2.0.0-beta.900 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 a26630f5a..45c69e709 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.860 + 2.0.0-beta.900 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 d06e38637..643955e9b 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp.WPF/LiveChartsCore.SkiaSharpView.WPF.csproj +++ b/src/skiasharp/LiveChartsCore.SkiaSharp.WPF/LiveChartsCore.SkiaSharpView.WPF.csproj @@ -7,7 +7,7 @@ net462;netcoreapp3.1 LiveChartsCore.SkiaSharpView.WPF LiveChartsCore.SkiaSharpView.WPF - 2.0.0-beta.860 + 2.0.0-beta.900 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 d4a773c7f..f032063fa 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.860 + 2.0.0-beta.900 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 6948808cf..6ab985a11 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.860 + 2.0.0-beta.900 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 ca2ff852d..62ae2c486 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharp/LiveChartsCore.SkiaSharpView.csproj +++ b/src/skiasharp/LiveChartsCore.SkiaSharp/LiveChartsCore.SkiaSharpView.csproj @@ -17,7 +17,7 @@ LiveChartsCore.SkiaSharpView LiveChartsCore.SkiaSharpView - 2.0.0-beta.860 + 2.0.0-beta.900 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 748ed6cd5..840900d16 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.860 + 2.0.0-beta.900 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 e187cf577..05ecd31aa 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharpView.Eto/LiveChartsCore.SkiaSharpView.Eto.csproj +++ b/src/skiasharp/LiveChartsCore.SkiaSharpView.Eto/LiveChartsCore.SkiaSharpView.Eto.csproj @@ -7,7 +7,7 @@ netstandard2.0 LiveChartsCore.SkiaSharpView.Eto LiveChartsCore.SkiaSharpView.Eto - 2.0.0-beta.860 + 2.0.0-beta.900 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 619216f0a..7bf10d007 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharpView.Maui/LiveChartsCore.SkiaSharpView.Maui.csproj +++ b/src/skiasharp/LiveChartsCore.SkiaSharpView.Maui/LiveChartsCore.SkiaSharpView.Maui.csproj @@ -15,7 +15,7 @@ 10.0.17763.0 6.5 - 2.0.0-beta.860 + 2.0.0-beta.900 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 206f2d533..3f8de5da6 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.860 + 2.0.0-beta.900 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 9ce056ed8..afeeedd2d 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 11.0 - 2.0.0-beta.860 + 2.0.0-beta.900 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 3e073ecb9..3ac303115 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharpView.Uno/LiveChartsCore.SkiaSharpView.Uno.csproj +++ b/src/skiasharp/LiveChartsCore.SkiaSharpView.Uno/LiveChartsCore.SkiaSharpView.Uno.csproj @@ -17,7 +17,7 @@ enable 11.0 - 2.0.0-beta.860 + 2.0.0-beta.900 icon.png Simple, flexible, interactive and powerful data visualization for Uno. MIT diff --git a/src/skiasharp/LiveChartsCore.SkiaSharpView.WinUI/LiveChartsCore.SkiaSharpView.WinUI.csproj b/src/skiasharp/LiveChartsCore.SkiaSharpView.WinUI/LiveChartsCore.SkiaSharpView.WinUI.csproj index 1357ea853..04d302015 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharpView.WinUI/LiveChartsCore.SkiaSharpView.WinUI.csproj +++ b/src/skiasharp/LiveChartsCore.SkiaSharpView.WinUI/LiveChartsCore.SkiaSharpView.WinUI.csproj @@ -9,7 +9,7 @@ win10-x86;win10-x64;win10-arm64 true - 2.0.0-beta.860 + 2.0.0-beta.900 icon.png Simple, flexible, interactive and powerful data visualization for WindowsAppSDK. MIT diff --git a/src/skiasharp/LiveChartsCore.SkiaSharpView.WinUI/LiveChartsCore.SkiaSharpView.WinUI.nuspec b/src/skiasharp/LiveChartsCore.SkiaSharpView.WinUI/LiveChartsCore.SkiaSharpView.WinUI.nuspec index 4d489ec12..29875c167 100644 --- a/src/skiasharp/LiveChartsCore.SkiaSharpView.WinUI/LiveChartsCore.SkiaSharpView.WinUI.nuspec +++ b/src/skiasharp/LiveChartsCore.SkiaSharpView.WinUI/LiveChartsCore.SkiaSharpView.WinUI.nuspec @@ -2,7 +2,7 @@ LiveChartsCore.SkiaSharpView.WinUI - 2.0.0-beta.860 + 2.0.0-beta.900 LiveChartsCore.SkiaSharpView.WinUI BetoRodriguez true @@ -18,8 +18,8 @@ - - + +