Skip to content
Merged
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
10 changes: 8 additions & 2 deletions docs/cartesianChart/axes.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,19 @@ Zooming and panning is disabled by default, you can enable it by setting the `Zo
[ZoomAndPanMode](https://lvcharts.com/api/{{ version }}/LiveChartsCore.Measure.ZoomAndPanMode) and the options are:

- `None`: Disables zooming and panning.
- `X`: Enables zooming and panning on the X axis.
- `Y`: Enables zooming and panning on the Y axis.
- `PanX`: Enables panning on the X axis.
- `ZoomX`: Enables zooming on the X axis (wheel, pinch and zoom by section).
- `PanY`: Enables panning on the Y axis.
- `ZoomY`: Enables zooming on the Y axis (wheel, pinch and zoom by section).
- `X`: Enables zooming and panning on the X axis. Equivalent to `PanX | ZoomX`.
- `Y`: Enables zooming and panning on the Y axis. Equivalent to `PanY | ZoomY`.
- `Both`: Enables zooming and panning on both axes.
- `NoFit`: Disables the "Fit to Bounds" feature that forces the chart to bounce back to the data bounds when zooming and panning finishes.
- `NoZoomBySection`: Disables the "Zoom by Section" feature, this feature selects an area and zooms to this area, normally by right clicking or double tapping and then dragging to the end of the section.
- `InvertPanningPointerTrigger`: Inverts the panning and zoom by section pointer triggers, when the flag is present, panning is triggered by right clicking the chart, and zoom by section by left clicking (or inverts single/double taps on mobile).

Because each gesture has its own flag you can mix and match — for example `ZoomMode = ZoomAndPanMode.ZoomX | ZoomAndPanMode.PanY` enables zoom on the X axis and panning on the Y axis only, and `ZoomMode = ZoomAndPanMode.ZoomX` enables zoom on the X axis with no panning at all (useful on mobile where pan gestures can hide tooltips).

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 disable "Fit to Bounds"
and "Zoom by Section" you can set the `ZoomMode` property to:
Expand Down
14 changes: 10 additions & 4 deletions docs/samples/lines/zoom/template.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,21 @@ You can enable zooming and panning by setting the `ZoomMode` property, this prop
[ZoomAndPanMode](https://lvcharts.com/api/{{ version }}/LiveChartsCore.Measure.ZoomAndPanMode) and the options are:

- `None`: Disables zooming and panning.
- `X`: Enables zooming and panning on the X axis.
- `Y`: Enables zooming and panning on the Y axis.
- `PanX`: Enables panning on the X axis.
- `ZoomX`: Enables zooming on the X axis (wheel, pinch and zoom by section).
- `PanY`: Enables panning on the Y axis.
- `ZoomY`: Enables zooming on the Y axis (wheel, pinch and zoom by section).
- `X`: Enables zooming and panning on the X axis. Equivalent to `PanX | ZoomX`.
- `Y`: Enables zooming and panning on the Y axis. Equivalent to `PanY | ZoomY`.
- `Both`: Enables zooming and panning on both axes.
- `NoFit`: Disables the "Fit to Bounds" feature that forces the the chart to bounce back to the data bounds when zooming and panning finishes.
- `NoFit`: Disables the "Fit to Bounds" feature that forces the chart to bounce back to the data bounds when zooming and panning finishes.
- `NoZoomBySection`: Disables the "Zoom by Section" feature, this feature selects an area and zooms to this area, normally by right clicking or double tapping and then dragging to the end of the section.
- `InvertPanningPointerTrigger`: Inverts the panning and zoom by section pointer triggers, when the flag is present, panning is triggered by right clicking the chart, and zoom by section by left clicking (or inverts single/double taps on mobile).

Because each gesture has its own flag you can mix and match — for example `ZoomMode = ZoomAndPanMode.ZoomX | ZoomAndPanMode.PanY` enables zoom on the X axis and panning on the Y axis only, and `ZoomMode = ZoomAndPanMode.ZoomX` enables zoom on the X axis with no panning at all (useful on mobile where pan gestures can hide tooltips).

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 `Both` axes and disable "Fit top Bounds"
so you can combine the options, for example, if you want to enable zooming on the `Both` axes and disable "Fit to Bounds"
you could set the `ZoomMode` property to:


Expand Down
5 changes: 4 additions & 1 deletion samples/AvaloniaSample/MainWindowViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ public class MainWindowViewModel : INotifyPropertyChanged
{
public MainWindowViewModel()
{
Samples = ViewModelsSamples.Index.Samples;
Samples = [..
ViewModelsSamples.Index.Samples,
"VisualTest/Issue1986Repro"
];
}

public string[] Samples { get; set; }
Expand Down
82 changes: 82 additions & 0 deletions samples/AvaloniaSample/VisualTest/Issue1986Repro/View.axaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<UserControl
x:Class="AvaloniaSample.VisualTest.Issue1986Repro.View"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:lvc="using:LiveChartsCore.SkiaSharpView.Avalonia"
xmlns:vm="using:AvaloniaSample.VisualTest.Issue1986Repro"
x:DataType="vm:ViewModel">

<!--
Reproducer for https://github.com/Live-Charts/LiveCharts2/issues/1986

Steps to reproduce (busitech):
1. Wait ~1s for async data to load (simulates server fetch).
2. Switch to "Tab 2", then back to "Tab 1".
3. Open "Tab 2" again and scroll down — the bottom charts may render as
white space (with non-zero size) or have zero size and never render.
4. Resize the window to force a redraw.
-->

<DockPanel>
<TextBlock
DockPanel.Dock="Top"
Margin="8"
FontSize="13"
Text="Issue #1986 reproducer — switch between tabs and scroll. Charts at the bottom of each tab may stay blank until the window is resized." />

<TabControl x:Name="tabs">
<TabItem Header="Tab 1">
<ScrollViewer>
<StackPanel Spacing="12" Margin="8">
<TextBlock Text="Cartesian A (visible at top of tab)" FontWeight="Bold" />
<lvc:CartesianChart Height="260" Series="{Binding CartesianA}" />

<Border Height="500" Background="#1E88E5" CornerRadius="4">
<TextBlock
VerticalAlignment="Center"
HorizontalAlignment="Center"
Foreground="White"
Text="Spacer — scroll down to see more charts" />
</Border>

<TextBlock Text="Cartesian B (off-screen until you scroll)" FontWeight="Bold" />
<lvc:CartesianChart Height="260" Series="{Binding CartesianB}" />

<TextBlock Text="Pie A (off-screen until you scroll)" FontWeight="Bold" />
<lvc:PieChart Height="260" Series="{Binding PieA}" />

<TextBlock Text="Cartesian C (off-screen until you scroll)" FontWeight="Bold" />
<lvc:CartesianChart x:Name="chart1" Height="260" Series="{Binding CartesianC}" />
</StackPanel>
</ScrollViewer>
</TabItem>

<TabItem Header="Tab 2">
<ScrollViewer>
<StackPanel Spacing="12" Margin="8">
<TextBlock Text="Cartesian A copy (visible at top of tab)" FontWeight="Bold" />
<lvc:CartesianChart Height="260" Series="{Binding CartesianA}" />

<Border Height="500" Background="#43A047" CornerRadius="4">
<TextBlock
VerticalAlignment="Center"
HorizontalAlignment="Center"
Foreground="White"
Text="Spacer — scroll down to see more charts" />
</Border>

<TextBlock Text="Cartesian B copy (off-screen until you scroll)" FontWeight="Bold" />
<lvc:CartesianChart Height="260" Series="{Binding CartesianB}" />

<TextBlock Text="Pie B (off-screen until you scroll)" FontWeight="Bold" />
<lvc:PieChart Height="260" Series="{Binding PieB}" />

<TextBlock Text="Cartesian C copy (off-screen until you scroll)" FontWeight="Bold" />
<lvc:CartesianChart x:Name="chart2" Height="260" Series="{Binding CartesianC}" />
</StackPanel>
</ScrollViewer>
</TabItem>
</TabControl>
</DockPanel>

</UserControl>
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,18 @@
using Avalonia.Markup.Xaml;
using LiveChartsCore.SkiaSharpView.Avalonia;

namespace AvaloniaSample.VisualTest.VirtualizationTest;
namespace AvaloniaSample.VisualTest.Issue1986Repro;

public partial class View : UserControl
{
private readonly ViewModel _vm;

public View()
{
_vm = new ViewModel();
DataContext = _vm;
InitializeComponent();
_ = _vm.LoadDataAsync(1000);
}

public CartesianChart Chart1 => this.Find<CartesianChart>("chart1")!;
Expand Down
66 changes: 66 additions & 0 deletions samples/AvaloniaSample/VisualTest/Issue1986Repro/ViewModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using LiveChartsCore;
using LiveChartsCore.SkiaSharpView;

namespace AvaloniaSample.VisualTest.Issue1986Repro;

// Reproducer for https://github.com/Live-Charts/LiveCharts2/issues/1986
// Following busitech's reproduction steps: charts are placed inside a TabControl + ScrollViewer
// and series data is assigned asynchronously (after a delay, simulating a server fetch).
public class ViewModel : INotifyPropertyChanged
{
private IEnumerable<ISeries> _cartesianA = [];
private IEnumerable<ISeries> _cartesianB = [];
private IEnumerable<ISeries> _cartesianC = [];
private IEnumerable<ISeries> _pieA = [];
private IEnumerable<ISeries> _pieB = [];

public IEnumerable<ISeries> CartesianA { get => _cartesianA; private set { _cartesianA = value; OnPropertyChanged(); } }
public IEnumerable<ISeries> CartesianB { get => _cartesianB; private set { _cartesianB = value; OnPropertyChanged(); } }
public IEnumerable<ISeries> CartesianC { get => _cartesianC; private set { _cartesianC = value; OnPropertyChanged(); } }
public IEnumerable<ISeries> PieA { get => _pieA; private set { _pieA = value; OnPropertyChanged(); } }
public IEnumerable<ISeries> PieB { get => _pieB; private set { _pieB = value; OnPropertyChanged(); } }

public async Task LoadDataAsync(int delayMs = 1000)
{
await Task.Delay(delayMs);

CartesianA =
[
new LineSeries<double> { Values = [5, 10, 8, 4, 9, 6, 11] },
new ColumnSeries<double> { Values = [3, 7, 4, 8, 2, 6, 5] }
];

CartesianB =
[
new LineSeries<double> { Values = [8, 3, 6, 9, 4, 7, 5] }
];

CartesianC =
[
new ColumnSeries<double> { Values = [6, 2, 8, 4, 9, 3, 7] }
];

PieA =
[
new PieSeries<double> { Values = [4] },
new PieSeries<double> { Values = [6] },
new PieSeries<double> { Values = [3] }
];

PieB =
[
new PieSeries<double> { Values = [10] },
new PieSeries<double> { Values = [5] },
new PieSeries<double> { Values = [7] }
];
}

public event PropertyChangedEventHandler? PropertyChanged;

protected void OnPropertyChanged([CallerMemberName] string? name = null) =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
44 changes: 0 additions & 44 deletions samples/AvaloniaSample/VisualTest/VirtualizationTest/View.axaml

This file was deleted.

Loading
Loading