Skip to content

Commit

Permalink
Merge pull request #1102 from beto-rodriguez/scrollable-charts
Browse files Browse the repository at this point in the history
Scrollable charts
  • Loading branch information
beto-rodriguez committed Jul 8, 2023
2 parents 627d09c + 5555b81 commit 4446c45
Show file tree
Hide file tree
Showing 37 changed files with 1,809 additions and 26 deletions.
3 changes: 3 additions & 0 deletions samples/AvaloniaSample/AvaloniaSample.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,9 @@
<Compile Update="General\MultiThreading\View.axaml.cs">
<DependentUpon>%(Filename)</DependentUpon>
</Compile>
<Compile Update="General\Scrollable\View.axaml.cs">
<DependentUpon>%(Filename)</DependentUpon>
</Compile>
<Compile Update="General\VisualElements\View.axaml.cs">
<DependentUpon>%(Filename)</DependentUpon>
</Compile>
Expand Down
38 changes: 38 additions & 0 deletions samples/AvaloniaSample/General/Scrollable/View.axaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<UserControl x:Class="AvaloniaSample.General.Scrollable.View"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:lvc="using:LiveChartsCore.SkiaSharpView.Avalonia"
xmlns:vms="using:ViewModelsSamples.General.Scrollable">
<UserControl.DataContext>
<vms:ViewModel/>
</UserControl.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="100"/>
</Grid.RowDefinitions>

<lvc:CartesianChart
Grid.Row="0"
Series="{Binding Series}"
XAxes="{Binding ScrollableAxes}"
ZoomMode="X"
DrawMargin="{Binding Margin}"
UpdateStarted="OnChart_Updated">
</lvc:CartesianChart>

<lvc:CartesianChart
x:Name="ScrollBarChart"
Grid.Row="1"
Series="{Binding ScrollbarSeries}"
DrawMargin="{Binding Margin}"
Sections="{Binding Thumbs}"
XAxes="{Binding InvisibleX}"
YAxes="{Binding InvisibleY}"
PointerPressed="OnPointerPressed"
PointerMoved="OnPointerMoved"
PointerReleased="OnPointerReleased"
TooltipPosition="Hidden">
</lvc:CartesianChart>
</Grid>
</UserControl>
72 changes: 72 additions & 0 deletions samples/AvaloniaSample/General/Scrollable/View.axaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
using System.Linq;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Markup.Xaml;
using LiveChartsCore.Kernel.Sketches;
using LiveChartsCore.SkiaSharpView.Avalonia;
using LiveChartsCore.SkiaSharpView.Drawing;
using ViewModelsSamples.General.Scrollable;

namespace AvaloniaSample.General.Scrollable;

public class View : UserControl
{
private bool _isDown = true;

public View()
{
InitializeComponent();
}

private void OnChart_Updated(IChartView<SkiaSharpDrawingContext> chart)
{
var vm = (ViewModel)DataContext!;
var cartesianChart = (CartesianChart)chart;

var x = cartesianChart.XAxes.First();

// update the scroll bar thumb when the chart is updated (zoom/pan)
// this will let the user know the current visible range
var thumb = vm.Thumbs[0];

thumb.Xi = x.MinLimit;
thumb.Xj = x.MaxLimit;
}

private void OnPointerPressed(object? sender, PointerPressedEventArgs e)
{
_isDown = true;
}

private void OnPointerMoved(object? sender, PointerEventArgs e)
{
if (!_isDown) return;

var vm = (ViewModel)DataContext!;
var scrollBarChart = this.Find<CartesianChart>("ScrollBarChart");

var pointerPosition = e.GetPosition(scrollBarChart);
var positionInData = scrollBarChart.ScalePixelsToData(new(pointerPosition.X, pointerPosition.Y));

var thumb = vm.Thumbs[0];
var currentRange = thumb.Xj - thumb.Xi;

// update the scroll bar thumb when the user is dragging the chart
thumb.Xi = positionInData.X - currentRange / 2;
thumb.Xj = positionInData.X + currentRange / 2;

// update the chart visible range
vm.ScrollableAxes[0].MinLimit = thumb.Xi;
vm.ScrollableAxes[0].MaxLimit = thumb.Xj;
}

private void OnPointerReleased(object? sender, PointerReleasedEventArgs e)
{
_isDown = false;
}

private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}
94 changes: 94 additions & 0 deletions samples/BlazorSample/Pages/General/Scrollable.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
@page "/General/Scrollable"
@using LiveChartsCore.Kernel.Sketches;
@using LiveChartsCore.SkiaSharpView.Blazor
@using LiveChartsCore.SkiaSharpView.Drawing;
@using ViewModelsSamples.General.Scrollable

<div class="bg-primary text-white p-3">
This is an experimental feature, it is not ready for production in Blazor, it seems that
the chart is updating multiple times resulting in a poor performance.
</div>

<CartesianChart
@ref="_mainChart"
Series="ViewModel.Series"
XAxes="ViewModel.ScrollableAxes"
ZoomMode="LiveChartsCore.Measure.ZoomAndPanMode.X"
DrawMargin="ViewModel.Margin">
</CartesianChart>

<div style="height: 100px">
<CartesianChart
@ref="_scrollableChart"
Series="ViewModel.ScrollbarSeries"
DrawMargin="ViewModel.Margin"
Sections="ViewModel.Thumbs"
XAxes="ViewModel.InvisibleX"
YAxes="ViewModel.InvisibleY"
OnPointerDownCallback="OnPointeDown"
OnPointerUpCallback="OnPointeUp"
OnPointerMoveCallback="OnPointeMove"
TooltipPosition="LiveChartsCore.Measure.TooltipPosition.Hidden">
</CartesianChart>
</div>

@code {
private bool _isDown;

public CartesianChart _mainChart = null!;
public CartesianChart _scrollableChart = null!;
public ViewModel ViewModel { get; set; } = new();

protected override void OnAfterRender(bool firstRender)
{
base.OnAfterRender(firstRender);

_mainChart.UpdateStarted += OnChart_Updated;
}

private void OnChart_Updated(IChartView<SkiaSharpDrawingContext> chart)
{
var vm = ViewModel;
var cartesianChart = (CartesianChart)chart;

var x = cartesianChart.XAxes.First();

// update the scroll bar thumb when the chart is updated (zoom/pan)
// this will let the user know the current visible range
var thumb = vm.Thumbs[0];

thumb.Xi = x.MinLimit;
thumb.Xj = x.MaxLimit;
}

private void OnPointeDown(PointerEventArgs e)
{
_isDown = true;
}

private void OnPointeMove(PointerEventArgs e)
{
if (!_isDown) return;

var vm = ViewModel;
var scrollBarChart = _scrollableChart;

var positionInData = scrollBarChart.ScalePixelsToData(new(e.OffsetX, e.OffsetY));

var thumb = vm.Thumbs[0];
var currentRange = thumb.Xj - thumb.Xi;

// update the scroll bar thumb when the user is dragging the chart
thumb.Xi = positionInData.X - currentRange / 2;
thumb.Xj = positionInData.X + currentRange / 2;

// update the chart visible range
vm.ScrollableAxes[0].MinLimit = thumb.Xi;
vm.ScrollableAxes[0].MaxLimit = thumb.Xj;
}

private void OnPointeUp(PointerEventArgs e)
{
_isDown = false;
}
}
3 changes: 1 addition & 2 deletions samples/EtoFormsSample/Axes/Shared/View.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ public View()

Content = new DynamicLayout(
new DynamicRow(new DynamicControl() { Control = cartesianChart, YScale = true }),
new DynamicRow(new DynamicControl() { Control = cartesianChart2, YScale = true })
);
new DynamicRow(new DynamicControl() { Control = cartesianChart2, YScale = true }));
}
}
94 changes: 94 additions & 0 deletions samples/EtoFormsSample/General/Scrollable/View.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
using System.Linq;
using Eto.Forms;
using LiveChartsCore.Kernel.Sketches;
using LiveChartsCore.SkiaSharpView.Drawing;
using LiveChartsCore.SkiaSharpView.Eto;
using ViewModelsSamples.General.Scrollable;

namespace EtoFormsSample.General.Scrollable;

public class View : Panel
{
private readonly ViewModel _viewModel = new();
private readonly CartesianChart _scrollBarChart;
private bool _isDown = true;

public View()
{
var viewModel = _viewModel;

var cartesianChart = new CartesianChart
{
Series = viewModel.Series,
XAxes = viewModel.ScrollableAxes,
ZoomMode = LiveChartsCore.Measure.ZoomAndPanMode.X,
DrawMargin = viewModel.Margin
};

cartesianChart.UpdateStarted += OnChart_Updated;

var cartesianChart2 = _scrollBarChart = new CartesianChart
{
Series = viewModel.ScrollbarSeries,
DrawMargin = viewModel.Margin,
Sections = viewModel.Thumbs,
XAxes = viewModel.InvisibleX,
YAxes = viewModel.InvisibleY,
TooltipPosition = LiveChartsCore.Measure.TooltipPosition.Hidden
};

cartesianChart2.MouseDown += CartesianChart2_MouseDown;
cartesianChart2.MouseMove += CartesianChart2_MouseMove;
cartesianChart2.MouseUp += CartesianChart2_MouseUp;

Content = new DynamicLayout(
new DynamicRow(new DynamicControl() { Control = cartesianChart, YScale = true }),
new DynamicRow(new DynamicControl() { Control = cartesianChart2, YScale = true }));
}

private void OnChart_Updated(IChartView<SkiaSharpDrawingContext> chart)
{
var vm = _viewModel;
var cartesianChart = (CartesianChart)chart;

var x = cartesianChart.XAxes.First();

// update the scroll bar thumb when the chart is updated (zoom/pan)
// this will let the user know the current visible range
var thumb = vm.Thumbs[0];

thumb.Xi = x.MinLimit;
thumb.Xj = x.MaxLimit;
}

private void CartesianChart2_MouseDown(object sender, MouseEventArgs e)
{
_isDown = true;
}

private void CartesianChart2_MouseMove(object sender, MouseEventArgs e)
{
if (!_isDown) return;

var vm = _viewModel;
var scrollBarChart = _scrollBarChart;

var positionInData = scrollBarChart.ScalePixelsToData(new(e.Location.X, e.Location.Y));

var thumb = vm.Thumbs[0];
var currentRange = thumb.Xj - thumb.Xi;

// update the scroll bar thumb when the user is dragging the chart
thumb.Xi = positionInData.X - currentRange / 2;
thumb.Xj = positionInData.X + currentRange / 2;

// update the chart visible range
vm.ScrollableAxes[0].MinLimit = thumb.Xi;
vm.ScrollableAxes[0].MaxLimit = thumb.Xj;
}

private void CartesianChart2_MouseUp(object sender, MouseEventArgs e)
{
_isDown = true;
}
}
7 changes: 6 additions & 1 deletion samples/MauiSample/App.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@
xmlns:local="clr-namespace:MauiSample"
x:Class="MauiSample.App">
<Application.Resources>
<ResourceDictionary Source="Resources/Styles.xaml" />
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Resources/Styles/Colors.xaml" />
<ResourceDictionary Source="Resources/Styles/Styles.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
52 changes: 52 additions & 0 deletions samples/MauiSample/General/Scrollable/View.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage x:Class="MauiSample.General.Scrollable.View"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:lvc="clr-namespace:LiveChartsCore.SkiaSharpView.Maui;assembly=LiveChartsCore.SkiaSharpView.Maui"
xmlns:vms="clr-namespace:ViewModelsSamples.General.Scrollable;assembly=ViewModelsSamples"
>
<ContentPage.BindingContext>
<vms:ViewModel/>
</ContentPage.BindingContext>
<ContentPage.Content>
<!--
This sample requies net MAUI 7 at least, if you are on net6.0 please update:
https://devblogs.microsoft.com/dotnet/dotnet-maui-dotnet-7/#upgrading-from-net-6
-->

<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="100"/>
</Grid.RowDefinitions>

<lvc:CartesianChart
Grid.Row="0"
Series="{Binding Series}"
XAxes="{Binding ScrollableAxes}"
ZoomMode="X"
DrawMargin="{Binding Margin}"
UpdateStarted="OnChart_Updated">
</lvc:CartesianChart>

<lvc:CartesianChart
x:Name="ScrollBarChart"
Grid.Row="1"
Series="{Binding ScrollbarSeries}"
DrawMargin="{Binding Margin}"
Sections="{Binding Thumbs}"
XAxes="{Binding InvisibleX}"
YAxes="{Binding InvisibleY}"
TooltipPosition="Hidden"
>
<lvc:CartesianChart.GestureRecognizers>
<PointerGestureRecognizer
PointerEntered="OnPointerEntered"
PointerMoved="OnPointerMoved"
PointerExited="OnPointerExited">
</PointerGestureRecognizer>
</lvc:CartesianChart.GestureRecognizers>
</lvc:CartesianChart>
</Grid>
</ContentPage.Content>
</ContentPage>

0 comments on commit 4446c45

Please sign in to comment.