Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[wip] implement SkiaSharp PlotViews #71

Draft
wants to merge 10 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Source/Examples/Avalonia/ExampleBrowser/App.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
<Application.Styles>
<SimpleTheme/>
<StyleInclude Source="avares://OxyPlot.Avalonia/Themes/Default.axaml"/>
<StyleInclude Source="avares://OxyPlot.SkiaSharp.Avalonia/Themes/Default.axaml"/>
</Application.Styles>
</Application>
27 changes: 27 additions & 0 deletions Source/Examples/Avalonia/ExampleBrowser/Category.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="Category.cs" company="OxyPlot">
// Copyright (c) 2014 OxyPlot contributors
// </copyright>
// <summary>
// Represents a category of examples.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace ExampleBrowser
{
using ExampleLibrary;
using System;
using System.Collections.Generic;

public class Category
{
public Category(string key, List<ExampleInfo> examples)
{
this.Key = key;
this.Examples = examples ?? throw new ArgumentNullException(nameof(examples));
}

public string Key { get; }
public List<ExampleInfo> Examples { get; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\OxyPlot.Avalonia\OxyPlot.Avalonia.csproj" />
<ProjectReference Include="..\..\..\OxyPlot.SkiaSharp.Avalonia\OxyPlot.SkiaSharp.Avalonia.csproj" />
</ItemGroup>
</Project>
96 changes: 57 additions & 39 deletions Source/Examples/Avalonia/ExampleBrowser/MainViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,51 +11,57 @@ namespace ExampleBrowser
{
using ExampleLibrary;
using OxyPlot;
using OxyPlot.Series;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;

public class Category
{
public Category(string key, List<ExampleInfo> examples)
{
Key = key;
Examples = examples ?? throw new ArgumentNullException(nameof(examples));
}

public string Key { get; }
public List<ExampleInfo> Examples { get; }
}

/// <summary>
/// Represents the view-model for the main window.
/// </summary>
public class MainViewModel : INotifyPropertyChanged
{
private ExampleInfo example;
private Renderer selectedRenderer;
private PlotModel model;

/// <summary>
/// Initializes a new instance of the <see cref="MainViewModel" /> class.
/// </summary>
public MainViewModel()
{
Model = new PlotModel() { Title = "Example Browser", Subtitle = "Select an example from the list" };
Categories = Examples.GetList()
this.model = new PlotModel() { Title = "Example Browser", Subtitle = "Select an example from the list" };
this.Categories = Examples.GetList()
.GroupBy(e => e.Category)
.Select(g => new Category(g.Key, g.ToList()))
.OrderBy(c => c.Key)
.ToList();
}

public IReadOnlyList<Renderer> Renderers { get; } = Enum.GetValues<Renderer>();

public Renderer SelectedRenderer
{
get => this.selectedRenderer;
set
{
if (this.selectedRenderer != value)
{
this.selectedRenderer = value;
this.CoerceSelectedRenderer();
this.OnPropertyChanged(nameof(this.SelectedRenderer));
}
}
}

public List<Category> Categories { get; }

private ExampleInfo example;
/// <summary>
/// Gets the plot model.
/// </summary>
public ExampleInfo Example
{
get => example;
get => this.example;
set
{
if (value == null)
Expand All @@ -64,38 +70,50 @@ public ExampleInfo Example
return;
}

if (example != value)
if (this.example != value)
{
example = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Example)));
Model = example?.PlotModel;
Model?.InvalidatePlot(true);
this.example = value;
this.OnPropertyChanged(nameof(this.Example));
this.CoerceExample();
}
}
}

private PlotModel model;
/// <summary>
/// Gets the plot model.
/// </summary>
public PlotModel Model
{
get => model;
set
{
if (model != value)
{
model = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Model)));
}
}
}
public PlotModel CanvasModel => this.SelectedRenderer == Renderer.Canvas ? this.model : null;

public PlotModel SkiaSharpModel => this.SelectedRenderer == Renderer.SkiaSharp ? this.model : null;
public PlotModel SkiaSharpDoubleBufferedModel => this.SelectedRenderer == Renderer.SkiaSharpDoubleBuffered ? this.model : null;
public PlotModel SkiaSharpPictureRecorderModel => this.SelectedRenderer == Renderer.SkiaSharpRecorder ? this.model : null;

public void ChangeExample(ExampleInfo example)
{
Example = example;
this.Example = example;
}

public event PropertyChangedEventHandler PropertyChanged;

private void CoerceSelectedRenderer()
{
((IPlotModel)this.model)?.AttachPlotView(null);
this.OnPropertyChanged(nameof(this.CanvasModel));
this.OnPropertyChanged(nameof(this.SkiaSharpModel));
this.OnPropertyChanged(nameof(this.SkiaSharpDoubleBufferedModel));
this.OnPropertyChanged(nameof(this.SkiaSharpPictureRecorderModel));
}

private void CoerceExample()
{
this.model = this.example?.PlotModel;
this.model?.InvalidatePlot(true);
this.OnPropertyChanged(nameof(this.CanvasModel));
this.OnPropertyChanged(nameof(this.SkiaSharpModel));
this.OnPropertyChanged(nameof(this.SkiaSharpDoubleBufferedModel));
this.OnPropertyChanged(nameof(this.SkiaSharpPictureRecorderModel));
}

private void OnPropertyChanged(string propertyName)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
18 changes: 15 additions & 3 deletions Source/Examples/Avalonia/ExampleBrowser/MainWindow.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:oxy="clr-namespace:OxyPlot.Avalonia;assembly=OxyPlot.Avalonia"
xmlns:oxy="http://oxyplot.org/avalonia"
xmlns:oxySkia="http://oxyplot.org/skiasharp/avalonia"
xmlns:oxySkiaDb="http://oxyplot.org/skiasharp/avalonia/doublebuffered"
xmlns:oxySkiaPr="http://oxyplot.org/skiasharp/avalonia/picturerecorder"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
xmlns:exampleBrowser="clr-namespace:ExampleBrowser;assembly=ExampleBrowser"
xmlns:exampleLibrary="clr-namespace:ExampleLibrary;assembly=ExampleLibrary"
Expand All @@ -11,7 +14,7 @@
<Window.DataContext>
<exampleBrowser:MainViewModel />
</Window.DataContext>

<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
Expand Down Expand Up @@ -42,6 +45,15 @@
</ItemsControl.DataTemplates>
</ItemsControl>
</ScrollViewer>
<oxy:PlotView Model="{Binding Model}" Grid.Row="0" Grid.Column="1" />
<Grid Grid.Column="1" RowDefinitions="*,auto">
<oxy:PlotView Model="{Binding CanvasModel}" IsVisible="{Binding CanvasModel, Converter={x:Static ObjectConverters.IsNotNull}}" />
<oxySkia:PlotView Model="{Binding SkiaSharpModel}" IsVisible="{Binding SkiaSharpModel, Converter={x:Static ObjectConverters.IsNotNull}}" />
<oxySkiaDb:PlotView Model="{Binding SkiaSharpDoubleBufferedModel}" IsVisible="{Binding SkiaSharpDoubleBufferedModel, Converter={x:Static ObjectConverters.IsNotNull}}" />
<oxySkiaPr:PlotView Model="{Binding SkiaSharpPictureRecorderModel}" IsVisible="{Binding SkiaSharpPictureRecorderModel, Converter={x:Static ObjectConverters.IsNotNull}}" />
<StackPanel Orientation="Horizontal" Grid.Row="1">
<TextBlock Text="Renderer:" VerticalAlignment="Center" Margin="5" />
<ComboBox ItemsSource="{Binding Renderers}" SelectedItem="{Binding SelectedRenderer}" />
</StackPanel>
</Grid>
</Grid>
</Window>
8 changes: 7 additions & 1 deletion Source/Examples/Avalonia/ExampleBrowser/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,14 @@ class Program
// Initialization code. Don't use any Avalonia, third-party APIs or any
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized
// yet and stuff might break.
public static void Main(string[] args) => BuildAvaloniaApp()
public static void Main(string[] args)
{
OxyPlot.Avalonia.OxyPlotModule.EnsureLoaded();
OxyPlot.SkiaSharp.Avalonia.OxyPlotModule.EnsureLoaded();
Comment on lines +12 to +13
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What purpose do these serve?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No idea, I have this from some Avalonia example which I can't find anymore. This seemed to be required at some point when I was testing, but I just tried without these lines and it seems to work fine...

Copy link
Contributor

@VisualMelon VisualMelon Aug 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had wondered if it was to force the XML namespaces or something, but I don't know.

If it works without, I'd say scrub them until we have reason to put them back in.


BuildAvaloniaApp()
.StartWithClassicDesktopLifetime(args);
}

// Avalonia configuration, don't remove; also used by visual designer.
public static AppBuilder BuildAvaloniaApp()
Expand Down
10 changes: 10 additions & 0 deletions Source/Examples/Avalonia/ExampleBrowser/Renderer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace ExampleBrowser
{
public enum Renderer
{
Canvas,
SkiaSharp,
SkiaSharpDoubleBuffered,
SkiaSharpRecorder,
}
}
16 changes: 16 additions & 0 deletions Source/OxyPlot.Avalonia.Shared/Extensions/ConverterExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using Avalonia;

namespace OxyPlot.Avalonia.Extensions
{
public static class ConverterExtensions
{
public static OxyRect ToOxyRect(this Rect rect)
{
return new OxyRect(rect.Left, rect.Top, rect.Width, rect.Height);
}
public static Rect ToRect(this OxyRect rect)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Micronit: Probably wants a line break between these

{
return new Rect(rect.Left, rect.Top, rect.Width, rect.Height);
}
}
}
27 changes: 27 additions & 0 deletions Source/OxyPlot.Avalonia.Shared/OxyPlot.Avalonia.Shared.projitems
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<MSBuildAllProjects Condition="'$(MSBuildVersion)' == '' Or '$(MSBuildVersion)' &lt; '16.0'">$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
<HasSharedItems>true</HasSharedItems>
<SharedGUID>8f6dadff-7073-4862-86c7-4299ae17cd68</SharedGUID>
</PropertyGroup>
<PropertyGroup Label="Configuration">
<Import_RootNamespace>OxyPlot.Avalonia.Shared</Import_RootNamespace>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildThisFileDirectory)Converters\OxyColorConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Converters\ThicknessConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Extensions\ConverterExtensions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Extensions\DataPointExtension.cs" />
<Compile Include="$(MSBuildThisFileDirectory)MoreColors.cs" />
<Compile Include="$(MSBuildThisFileDirectory)PlotBase.cs" />
<Compile Include="$(MSBuildThisFileDirectory)PlotBase.Events.cs" />
<Compile Include="$(MSBuildThisFileDirectory)PlotBase.Properties.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Tracker\TrackerControl.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Tracker\TrackerDefinition.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Utilities\ConverterExtensions.cs" />
</ItemGroup>
<ItemGroup>
<Compile Include="$(MSBuildThisFileDirectory)PlotBase.Model.cs" />
</ItemGroup>
</Project>
13 changes: 13 additions & 0 deletions Source/OxyPlot.Avalonia.Shared/OxyPlot.Avalonia.Shared.shproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="Globals">
<ProjectGuid>8f6dadff-7073-4862-86c7-4299ae17cd68</ProjectGuid>
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.Default.props" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.props" />
<PropertyGroup />
<Import Project="OxyPlot.Avalonia.Shared.projitems" Label="Shared" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.CSharp.targets" />
</Project>
Loading