This commit is contained in:
2024-02-23 06:53:16 -05:00
commit dbdccce727
1094 changed files with 57645 additions and 0 deletions

View File

@@ -0,0 +1,32 @@
using SkiaSharp;
using System;
using System.Collections.Generic;
using System.Text;
namespace DataDisplay.Common
{
public class DrawingHelper
{
private DrawingHelper()
{
}
public static void DrawIsoTriangle(SKCanvas canvas, SKPoint origin, int length, SKPaint paintStroke, SKPaint paintFill)
{
SKPath path = new SKPath();
float lengthF = (float)length;
float hLength = lengthF / 2f;
float height = (float)Math.Sqrt(Math.Pow(lengthF, 2) - Math.Pow(hLength, 2));
height/=1.15f; // reduce the height by 15%
path.MoveTo(origin.X, origin.Y);
path.LineTo(origin.X - hLength, origin.Y + height);
path.LineTo(origin.X + hLength, origin.Y + height);
path.LineTo(origin.X, origin.Y);
path.Close();
canvas.DrawPath(path, paintStroke);
canvas.DrawPath(path, paintFill);
}
}
}

View File

@@ -0,0 +1,162 @@
using MarketData.Utils;
using SkiaSharp;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
namespace DataDisplay.Common
{
public class GridLines
{
public delegate Type GetXDataType();
public delegate Type GetYDataType();
public delegate String XDataFormatter(Object data); // custom formatter for XData
public delegate String YDataFormatter(Object data); // custom formatter for YData
private SKPaint paintGrid=new SKPaint{Style=SKPaintStyle.Stroke,Color=new SKColor((uint)SKColors.LightGray),StrokeWidth=1f};
private SKPaint paintAxis=new SKPaint{Style=SKPaintStyle.Stroke,Color=new SKColor((uint)SKColors.Black),StrokeWidth=3f};
private SKPaint paintHorizontalLabelText=new SKPaint{TextSize=24f,IsAntialias=true,Color=new SKColor((uint)SKColors.Black),IsStroke=false,Typeface=SKTypeface.FromFamilyName("Calibri",SKFontStyleWeight.Bold,SKFontStyleWidth.Normal,SKFontStyleSlant.Upright)}; // dates
private SKPaint paintVerticalLabelText=new SKPaint{TextSize=24f,IsAntialias=true,Color=new SKColor((uint)SKColors.Black),IsStroke=false,Typeface=SKTypeface.FromFamilyName("Calibri",SKFontStyleWeight.Bold,SKFontStyleWidth.Normal,SKFontStyleSlant.Upright)}; // values
private GetXDataType getXDataType=null;
private GetYDataType getYDataType=null;
private XDataFormatter xDataFormatter;
private YDataFormatter yDataFormatter;
private Dictionary<String,String> uniqueVerticalLabels;
private Dictionary<String,String> uniqueHorizontalLabels;
public GridLines(double xGridLines,double yGridLines)
{
XGridLines=xGridLines;
YGridLines=yGridLines;
uniqueVerticalLabels=new Dictionary<String,String>();
uniqueHorizontalLabels=new Dictionary<String,String>();
}
public double XGridLines{get;private set;}
public double YGridLines{get;private set;}
public GetXDataType AssignXDataType
{
get{return getXDataType;}
set{getXDataType=value;}
}
public GetYDataType AssignGetYDataType
{
get{return getYDataType;}
set{getYDataType=value;}
}
public XDataFormatter AssignXDataFormatter
{
get{return xDataFormatter;}
set{xDataFormatter=value;}
}
public YDataFormatter AssignYDataFormatter
{
get{return yDataFormatter;}
set{yDataFormatter=value;}
}
public void Render(SKCanvas canvas,PointMapping pointMapping,SKPaint axisPaint=null,SKPaint gridPaint=null)
{
if(null==axisPaint)axisPaint=paintAxis;
if(null==gridPaint)gridPaint=paintGrid;
SKPoint p1;
SKPoint p2;
double xLineFactor = pointMapping.XRange/XGridLines;
double yLineFactor = pointMapping.YRange/YGridLines;
if(0==xLineFactor)xLineFactor=.01;
if(0==yLineFactor)yLineFactor=.01;
// Draw horizontal line grid - the labels go along the left
for (double yIndex = pointMapping.YDataExtentMin; yIndex <= pointMapping.YDataExtent+.05; yIndex += yLineFactor)
{
p1 = pointMapping.MapPoint(new SKPoint((float)pointMapping.XDataExtentMin, (float)yIndex));
p2 = pointMapping.MapPoint(new SKPoint((float)pointMapping.XDataExtent, (float)yIndex));
if(yIndex==pointMapping.YDataExtentMin)canvas.DrawPoints(SKPointMode.Polygon, new SKPoint[] { p1, p2 }, axisPaint);
else canvas.DrawPoints(SKPointMode.Polygon, new SKPoint[] { p1, p2 }, gridPaint);
p1.X=0f;
DisplayXAxisLabel(canvas,pointMapping,p1,yIndex);
}
// Draw vertical line grid - the labels go along the bottom
for (double xIndex = pointMapping.XDataExtentMin; xIndex <= pointMapping.XDataExtent+.05; xIndex += xLineFactor)
{
p1 = pointMapping.MapPoint(new SKPoint((float)xIndex,(float)pointMapping.YDataExtentMin));
p2 = pointMapping.MapPoint(new SKPoint((float)xIndex, (float)pointMapping.YDataExtent));
if(xIndex==pointMapping.XDataExtentMin)canvas.DrawPoints(SKPointMode.Polygon, new SKPoint[] { p1, p2 }, axisPaint);
else canvas.DrawPoints(SKPointMode.Polygon, new SKPoint[] { p1, p2 }, gridPaint);
p1.Y=(float)pointMapping.Height;
DisplayYAxisLabel(canvas,pointMapping,p1,xIndex);
}
}
// The labels along the left of the chart
private void DisplayXAxisLabel(SKCanvas canvas,PointMapping pointMapping,SKPoint p1,double yIndex)
{
String strLabel;
double percentage=(yIndex - pointMapping.YDataExtentMin) / pointMapping.YRange;
Type dataType=typeof(double);
if(null!=getYDataType)dataType=getYDataType();
if(dataType.Equals(typeof(DateTime)))
{
DateTime axisDate=new DateTime((long)((pointMapping.YDataExtentMin+(pointMapping.YRange*percentage))*10000000000.0));
if(null!=yDataFormatter)strLabel=yDataFormatter(axisDate);
else strLabel=Utility.DateTimeToStringMMSYY(axisDate);
}
else if(dataType.Equals(typeof(double)))
{
double value=pointMapping.YDataExtentMin+(pointMapping.YRange*percentage);
if(null!=yDataFormatter)strLabel=yDataFormatter(value);
else
{
if(value>=1000)strLabel=Utility.FormatNumber(value,0,true);
else strLabel=Utility.FormatNumber(value,2,true);
}
}
else
{
double value=pointMapping.YDataExtentMin+(pointMapping.YRange*percentage);
strLabel=Utility.FormatNumber(value,0,true);
}
if(uniqueVerticalLabels.ContainsKey(strLabel))return;
uniqueVerticalLabels.Add(strLabel,strLabel);
if(null!=strLabel)canvas.DrawText(strLabel, p1, paintVerticalLabelText);
}
// The labels along the bottom of the chart
private void DisplayYAxisLabel(SKCanvas canvas,PointMapping pointMapping,SKPoint p1,double xIndex)
{
String strLabel=null;
double percentage=(xIndex-pointMapping.XDataExtentMin)/pointMapping.XRange;
Type dataType=typeof(double);
if(null!=getXDataType())dataType=getXDataType();
if (dataType.Equals(typeof(DateTime)))
{
DateTime axisDate=new DateTime((long)((pointMapping.XDataExtentMin+(pointMapping.XRange*percentage))*10000000000.0));
if(null!=xDataFormatter)strLabel=xDataFormatter(axisDate);
else strLabel=Utility.DateTimeToStringMMSYY(axisDate);
}
else if(dataType.Equals(typeof(double)))
{
double value=pointMapping.XDataExtentMin+(pointMapping.XRange*percentage);
if(null!=xDataFormatter)strLabel=xDataFormatter(value);
else
{
if(value>=1000)strLabel=Utility.FormatNumber(value,0,true);
else strLabel=Utility.FormatNumber(value,2,true);
}
}
else
{
double value=pointMapping.XDataExtentMin+(pointMapping.XRange*percentage);
strLabel=Utility.FormatNumber(value,0,true);
}
if(uniqueHorizontalLabels.ContainsKey(strLabel))return;
uniqueHorizontalLabels.Add(strLabel,strLabel);
if(null!=strLabel)canvas.DrawText(strLabel, p1, paintHorizontalLabelText);
}
}
}

View File

@@ -0,0 +1,50 @@
using SkiaSharp;
using System;
using System.Collections.Generic;
using System.Text;
namespace DataDisplay.Common
{
public class PointMapping
{
public PointMapping(double width,double height,double xDataExtent,double xDataExtentMin,double yDataExtent,double yDataExtentMin,double xMarginExtent=0.00,double yMarginExtent=0.00)
{
Width=width;
Height=height;
XMargin=xMarginExtent;
YMargin=yMarginExtent;
XDataExtent=xDataExtent;
XDataExtentMin=xDataExtentMin;
YDataExtent=yDataExtent;
YDataExtentMin=yDataExtentMin;
XScalingFactor=(Width-(XMargin*2))/(XDataExtent-XDataExtentMin);
YScalingFactor=(Height-(YMargin*2))/(YDataExtent-YDataExtentMin);
}
// MapPoint will both scale the given point and translate the given point from an upper left origin system to a bottom left origin system
public SKPoint MapPoint(SKPoint sourcePoint)
{
SKPoint mappedPoint=new SKPoint((float)((sourcePoint.X-XDataExtentMin)*XScalingFactor),(float)(Height-((sourcePoint.Y-YDataExtentMin)*YScalingFactor)));
mappedPoint.X+=(float)XMargin; // offset by the xMargin
mappedPoint.Y-=(float)YMargin; // offset by the yMargin
return mappedPoint;
}
// TranslatePoint will only translate the given point from an upper left origin system to a bottom left origin system
public SKPoint TranslatePoint(SKPoint sourcePoint)
{
SKPoint mappedPoint=new SKPoint((float)sourcePoint.X,(float)(Height-sourcePoint.Y-1));
return mappedPoint;
}
public double Width{get;private set;}
public double Height{get;private set;}
public double XDataExtent{get;private set;}
public double XDataExtentMin{get;private set;}
public double XRange{get{return XDataExtent-XDataExtentMin;}}
public double YDataExtent{get;private set;}
public double YDataExtentMin{get;private set;}
public double YRange{get{return YDataExtent-YDataExtentMin;}}
public double XMargin{get;private set;}
public double YMargin{get;private set;}
public double XScalingFactor{get;private set;}
public double YScalingFactor{get;private set;}
}
}

View File

@@ -0,0 +1,58 @@
using SkiaSharp.Views.Forms;
using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Forms;
namespace DataDisplay.Controls
{
public class CanvasView : SKCanvasView
{
public static readonly BindableProperty RendererProperty = BindableProperty.Create(
nameof(Renderer),
typeof(Renderers.IRenderer),
typeof(CanvasView),
null,
defaultBindingMode: BindingMode.TwoWay,
propertyChanged: (bindable, oldValue, newValue) =>
{
((CanvasView)bindable).RendererChanged((Renderers.IRenderer)oldValue, (Renderers.IRenderer)newValue);
});
// callback appelée lors de la modificiation de la propriété "Renderer"
void RendererChanged(Renderers.IRenderer currentRenderer, Renderers.IRenderer newRenderer)
{
if (currentRenderer != newRenderer)
{
// détacher l'événement de l'ancien renderer
if (currentRenderer != null)
currentRenderer.RefreshRequested -= Renderer_RefreshRequested;
// attacher l'événement du nouveau renderer
if (newRenderer != null)
newRenderer.RefreshRequested += Renderer_RefreshRequested;
// rafraichir le contrôle
InvalidateSurface();
}
}
// Causes refreshing during an event triggered by the ISKRenderer interface
void Renderer_RefreshRequested(object sender, EventArgs e)
{
InvalidateSurface();
}
protected override void OnPaintSurface(SKPaintSurfaceEventArgs e)
{
if (null == Renderer) return;
Renderer.PaintSurface(e.Surface, e.Info);
}
public Renderers.IRenderer Renderer
{
get { return (Renderers.IRenderer)GetValue(RendererProperty); }
set { SetValue(RendererProperty, value); }
}
}
}

View File

@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="SkiaSharp.Views.Forms" Version="1.68.3" />
</ItemGroup>
<ItemGroup>
<Folder Include="Renderers\" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MarketDataLib\MarketDataLib.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,25 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30204.135
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataDisplay", "DataDisplay.csproj", "{11EFBEE6-2BFD-4D05-AD34-C5B0A894EB99}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{11EFBEE6-2BFD-4D05-AD34-C5B0A894EB99}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{11EFBEE6-2BFD-4D05-AD34-C5B0A894EB99}.Debug|Any CPU.Build.0 = Debug|Any CPU
{11EFBEE6-2BFD-4D05-AD34-C5B0A894EB99}.Release|Any CPU.ActiveCfg = Release|Any CPU
{11EFBEE6-2BFD-4D05-AD34-C5B0A894EB99}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {DFC8F4F9-9B94-400D-8E39-6561192D5486}
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,129 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Collections;
using Xamarin.Forms;
using SkiaSharp;
namespace DataDisplay.DataSource
{
public class DataSourceHelper
{
private DataSourceHelper()
{
}
public static IEnumerable<SKPoint> GetPoints(IPointDataSource dataSource)
{
if (dataSource == null) throw new ArgumentNullException("dataSource");
using (IPointEnumerator enumerator = dataSource.GetEnumerator(null))
{
while (enumerator.MoveNext())
{
Point xPoint=new Point();
enumerator.GetCurrent(ref xPoint);
yield return new SKPoint((float)xPoint.X,(float)xPoint.Y);
xPoint=new Point();
}
}
}
}
/// <summary>Data source that is a composer from several other data sources.</summary>
public class CompositeDataSource : IPointDataSource {
/// <summary>Initializes a new instance of the <see cref="CompositeDataSource"/> class</summary>
public CompositeDataSource() { }
public void Clear()
{
dataParts.Clear();
}
/// <summary>
/// Initializes a new instance of the <see cref="CompositeDataSource"/> class.
/// </summary>
/// <param name="dataSources">Data sources.</param>
public CompositeDataSource(params IPointDataSource[] dataSources) {
if (dataSources == null)
throw new ArgumentNullException("dataSources");
foreach (var dataSource in dataSources) {
AddDataPart(dataSource);
}
}
private readonly List<IPointDataSource> dataParts = new List<IPointDataSource>();
public IEnumerable<IPointDataSource> DataParts {
get { return dataParts; }
}
/// <summary>
/// Adds data part.
/// </summary>
/// <param name="dataPart">The data part.</param>
public void AddDataPart(IPointDataSource dataPart) {
if (dataPart == null)
throw new ArgumentNullException("dataPart");
dataParts.Add(dataPart);
dataPart.DataChanged += OnPartDataChanged;
}
private void OnPartDataChanged(object sender, EventArgs e) {
RaiseDataChanged();
}
#region IPointSource Members
public event EventHandler DataChanged;
protected void RaiseDataChanged() {
if (DataChanged != null) {
DataChanged(this, EventArgs.Empty);
}
}
public IPointEnumerator GetEnumerator(BindableObject context) {
return new CompositeEnumerator(this, context);
}
#endregion
private sealed class CompositeEnumerator : IPointEnumerator {
private readonly IEnumerable<IPointEnumerator> enumerators;
public CompositeEnumerator(CompositeDataSource dataSource, BindableObject context) {
enumerators = dataSource.dataParts.Select(part => part.GetEnumerator(context)).ToList();
}
#region IChartPointEnumerator Members
public bool MoveNext() {
bool res = false;
foreach (var enumerator in enumerators) {
res |= enumerator.MoveNext();
}
return res;
}
public void ApplyMappings(BindableObject glyph) {
foreach (var enumerator in enumerators) {
enumerator.ApplyMappings(glyph);
}
}
public void GetCurrent(ref Point p) {
foreach (var enumerator in enumerators) {
enumerator.GetCurrent(ref p);
}
}
public void Dispose() {
foreach (var enumerator in enumerators) {
enumerator.Dispose();
}
}
#endregion
}
}
}

View File

@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace DataDisplay.DataSource
{
public static class DataSourceExtensions
{
public static CompositeDataSource Join(this IPointDataSource ds1, IPointDataSource ds2)
{
return new CompositeDataSource(ds1, ds2);
}
}
}

View File

@@ -0,0 +1,110 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Windows;
using Xamarin.Forms;
namespace DataDisplay.DataSource
{
public class EnumerableDataSource<T> : EnumerableDataSourceBase<T>
{
public EnumerableDataSource(IEnumerable<T> data) : base(data) { }
public EnumerableDataSource(IEnumerable data) : base(data) { }
private readonly List<Mapping<T>> mappings = new List<Mapping<T>>();
private Func<T, double> xMapping;
private Func<T, double> yMapping;
private Func<T, Point> xyMapping;
public Func<T, double> XMapping
{
get { return xMapping; }
set { SetXMapping(value); }
}
public Func<T, double> YMapping
{
get { return yMapping; }
set { SetYMapping(value); }
}
public Func<T, Point> XYMapping
{
get { return xyMapping; }
set { SetXYMapping(value); }
}
public void SetXMapping(Func<T, double> mapping)
{
if (mapping == null)
throw new ArgumentNullException("mapping");
this.xMapping = mapping;
RaiseDataChanged();
}
public void SetYMapping(Func<T, double> mapping)
{
if (mapping == null)
throw new ArgumentNullException("mapping");
this.yMapping = mapping;
RaiseDataChanged();
}
public void SetXYMapping(Func<T, Point> mapping)
{
if (mapping == null)
throw new ArgumentNullException("mapping");
this.xyMapping = mapping;
RaiseDataChanged();
}
public void AddMapping(BindableProperty property, Func<T, object> mapping)
{
if (property == null)
throw new ArgumentNullException("property");
if (mapping == null)
throw new ArgumentNullException("mapping");
mappings.Add(new Mapping<T> { Property = property, F = mapping });
}
public override IPointEnumerator GetEnumerator(BindableObject context)
{
return new EnumerablePointEnumerator<T>(this);
}
internal void FillPoint(T elem, ref Point point)
{
if (xyMapping != null)
{
point = xyMapping(elem);
}
else
{
if (xMapping != null)
{
point.X = xMapping(elem);
}
if (yMapping != null)
{
point.Y = yMapping(elem);
}
}
}
internal void ApplyMappings(BindableObject target, T elem)
{
if (target != null)
{
foreach (var mapping in mappings)
{
target.SetValue(mapping.Property, mapping.F(elem));
}
}
}
}
}

View File

@@ -0,0 +1,57 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Windows;
using Xamarin.Forms;
namespace DataDisplay.DataSource
{
/// <summary>Base class for all sources who receive data for charting
/// from any IEnumerable of T</summary>
/// <typeparam name="T">Type of items in IEnumerable</typeparam>
public abstract class EnumerableDataSourceBase<T> : IPointDataSource {
private IEnumerable data;
/// <summary>
/// Gets or sets the data.
/// </summary>
/// <value>The data.</value>
public IEnumerable Data {
get { return data; }
set {
if (value == null)
throw new ArgumentNullException("value");
data = value;
var observableCollection = data as INotifyCollectionChanged;
if (observableCollection != null) {
observableCollection.CollectionChanged += observableCollection_CollectionChanged;
}
}
}
protected EnumerableDataSourceBase(IEnumerable<T> data) : this((IEnumerable)data) { }
protected EnumerableDataSourceBase(IEnumerable data) {
if (data == null)
throw new ArgumentNullException("data");
Data = data;
}
private void observableCollection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) {
RaiseDataChanged();
}
public event EventHandler DataChanged;
public void RaiseDataChanged() {
if (DataChanged != null) {
DataChanged(this, EventArgs.Empty);
}
}
public abstract IPointEnumerator GetEnumerator(BindableObject context);
}
}

View File

@@ -0,0 +1,37 @@
using System;
using System.Collections;
using System.Windows;
using Xamarin.Forms;
namespace DataDisplay.DataSource
{
/// <summary>This enumerator enumerates given enumerable object as sequence of points</summary>
/// <typeparam name="T">Type parameter of source IEnumerable</typeparam>
public sealed class EnumerablePointEnumerator<T> : IPointEnumerator {
private readonly EnumerableDataSource<T> dataSource;
private readonly IEnumerator enumerator;
public EnumerablePointEnumerator(EnumerableDataSource<T> dataSource) {
this.dataSource = dataSource;
enumerator = dataSource.Data.GetEnumerator();
}
public bool MoveNext()
{
try{return enumerator.MoveNext();}
catch(InvalidOperationException){return false;}
}
public void GetCurrent(ref Point p) {
dataSource.FillPoint((T)enumerator.Current, ref p);
}
public void ApplyMappings(BindableObject target) {
dataSource.ApplyMappings(target, (T)enumerator.Current);
}
public void Dispose() {
//enumerator.Reset();
}
}
}

View File

@@ -0,0 +1,17 @@
using System;
using System.Windows;
using Xamarin.Forms;
namespace DataDisplay.DataSource
{
/// <summary>Data source that returns sequence of 2D points.</summary>
public interface IPointDataSource
{
/// <summary>Returns object to enumerate points in source.</summary>
IPointEnumerator GetEnumerator(BindableObject context);
/// <summary>This event is raised when contents of source are changed.</summary>
event EventHandler DataChanged;
}
}

View File

@@ -0,0 +1,22 @@
using System;
using System.Windows;
using Xamarin.Forms;
namespace DataDisplay.DataSource
{
public interface IPointEnumerator : IDisposable {
/// <summary>Move to next point in sequence</summary>
/// <returns>True if successfully moved to next point
/// or false if end of sequence is reached</returns>
bool MoveNext();
/// <summary>Stores current value(s) in given point.</summary>
/// <param name="p">Reference to store value</param>
/// <remarks>Depending on implementing class this method may set only X or Y
/// fields in specified point. That's why GetCurrent is a regular method and
/// not a property as in standard enumerators</remarks>
void GetCurrent(ref Point p);
void ApplyMappings(BindableObject target);
}
}

View File

@@ -0,0 +1,16 @@
using System;
using System.Windows;
using Xamarin.Forms;
namespace DataDisplay.DataSource
{
/// <summary>Mapping class holds information about mapping of TSource type
/// to some DependencyProperty.</summary>
/// <typeparam name="TSource">Mapping source type.</typeparam>
internal sealed class Mapping<TSource> {
/// <summary>Property that will be set.</summary>
internal BindableProperty Property { get; set; }
/// <summary>Function that computes value for property from TSource type.</summary>
internal Func<TSource, object> F { get; set; }
}
}

View File

@@ -0,0 +1,77 @@
using DataDisplay.Common;
using DataDisplay.DataSource;
using SkiaSharp;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DataDisplay.Graph
{
public class LineGraph
{
private SKPoint[] points=null;
private CompositeDataSource compositeDataSource;
private SKPaint paint;
public LineGraph(SKPaint paint,CompositeDataSource compositeDataSource)
{
this.compositeDataSource = compositeDataSource;
this.paint=paint;
points=GetSKPoints();
}
public void SetPaint(SKPaint paint)
{
this.paint=paint;
}
public void SetDataSource(CompositeDataSource compositeDataSource)
{
this.compositeDataSource=compositeDataSource;
points=GetSKPoints();
}
public void Render(SKCanvas canvas,PointMapping pointMapping)
{
if(null==points)return;
SKPoint[] mappedPoints = new SKPoint[points.Length];
for (int index = 0; index < points.Length; index++) mappedPoints[index] = pointMapping.MapPoint(points[index]);
canvas.DrawPoints(SKPointMode.Polygon,mappedPoints,paint);
}
public SKPoint[] GetSKPoints()
{
IEnumerable<SKPoint> pointsEnumerable=DataSourceHelper.GetPoints(compositeDataSource);
IEnumerator<SKPoint> pointsEnumerator=pointsEnumerable.GetEnumerator();
List<SKPoint> points=new List<SKPoint>();
while(pointsEnumerator.MoveNext())points.Add(pointsEnumerator.Current);
return points.ToArray();
}
public SKPoint[] SKPoints
{
get{return points;}
private set{;}
}
public double GetXExtent()
{
if(null==points)return 0.00;
double xExtents=points.Max(x=>x.X);
return xExtents;
}
public double GetXExtentMin()
{
if(null==points)return 0.00;
double xExtents=points.Min(x=>x.X);
return xExtents;
}
public double GetYExtent()
{
if(null==points)return 0.00;
double yExtents=points.Max(x=>x.Y);
return yExtents;
}
public double GetYExtentMin()
{
if(null==points)return 0.00;
double yExtents=points.Min(x=>x.Y);
return yExtents;
}
}
}

View File

@@ -0,0 +1,41 @@
//using SkiaSharp;
//using System;
//using System.Collections.Generic;
//using System.Text;
//namespace DataDisplay.Renderers
//{
// class CircleRenderer : IRenderer
// {
// public void PaintSurface(SKSurface surface, SKImageInfo info)
// {
// SKCanvas canvas = surface.Canvas; // récupère le canvas
// canvas.Clear();
// // opérations de dessin, par exemple dessiner un cercle
// // paramètre de remplissage du cercle
// SKPaint fillPaint = new SKPaint
// {
// Style = SKPaintStyle.Fill,
// Color = FillColor
// };
// canvas.DrawCircle(info.Width / 2, info.Height / 2, 100, fillPaint);
// }
// SKColor _fillColor = new SKColor(160, 160, 160);
// public SKColor FillColor
// {
// get => _fillColor;
// set
// {
// if (_fillColor != value)
// {
// _fillColor = value;
// RefreshRequested?.Invoke(this, EventArgs.Empty);
// }
// }
// }
// public event EventHandler RefreshRequested;
// }
//}

View File

@@ -0,0 +1,11 @@
using System;
using SkiaSharp;
namespace DataDisplay.Renderers
{
public interface IRenderer
{
void PaintSurface(SKSurface surface, SKImageInfo info);
event EventHandler RefreshRequested;
}
}