// Copyright (C) Stichting Deltares 2016. All rights reserved.
//
// This file is part of Ringtoets.
//
// Ringtoets is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see .
//
// All names, logos, and references to "Deltares" are registered trademarks of
// Stichting Deltares and remain full property of Stichting Deltares at all times.
// All rights reserved.
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using Core.Common.Base;
using Core.Components.Charting.Data;
using Core.Components.Charting.Forms;
using Core.Components.OxyPlot.DataSeries;
using OxyPlot.Series;
namespace Core.Components.OxyPlot.Forms
{
///
/// This class describes a plot view with configured representation of axes.
///
public sealed class ChartControl : Control, IChartControl
{
private readonly RecursiveObserver chartDataCollectionObserver;
private readonly IList drawnChartDataList = new List();
private LinearPlotView plotView;
private DynamicPlotController plotController;
private ChartDataCollection data;
///
/// Creates a new instance of .
///
public ChartControl()
{
InitializePlotView();
MinimumSize = new Size(100, 100);
chartDataCollectionObserver = new RecursiveObserver(HandleChartDataCollectionChange, cdc => cdc.Collection);
}
public ChartDataCollection Data
{
get
{
return data;
}
set
{
if (data != null)
{
ClearChartData();
}
data = value;
chartDataCollectionObserver.Observable = data;
if (data != null)
{
DrawInitialChartData();
}
}
}
public string ChartTitle
{
get
{
return plotView.ModelTitle;
}
set
{
plotView.ModelTitle = value;
}
}
public string BottomAxisTitle
{
get
{
return plotView.BottomAxisTitle;
}
set
{
plotView.BottomAxisTitle = value;
}
}
public string LeftAxisTitle
{
get
{
return plotView.LeftAxisTitle;
}
set
{
plotView.LeftAxisTitle = value;
}
}
public bool IsPanningEnabled
{
get
{
return plotController.IsPanningEnabled;
}
}
public bool IsRectangleZoomingEnabled
{
get
{
return plotController.IsRectangleZoomingEnabled;
}
}
public void TogglePanning()
{
plotController.TogglePanning();
}
public void ToggleRectangleZooming()
{
plotController.ToggleRectangleZooming();
}
public void ZoomToAll()
{
plotView.ZoomToAll();
}
protected override void Dispose(bool disposing)
{
plotView.Dispose();
chartDataCollectionObserver.Dispose();
base.Dispose(disposing);
}
private void InitializePlotView()
{
plotView = new LinearPlotView
{
BackColor = Color.White,
Model =
{
IsLegendVisible = false
}
};
plotController = new DynamicPlotController();
plotView.Controller = plotController;
Controls.Add(plotView);
}
private static IEnumerable GetItemBasedChartDataRecursively(ChartDataCollection chartDataCollection)
{
var itemBasedChartDataList = new List();
foreach (ChartData chartData in chartDataCollection.Collection)
{
var nestedChartDataCollection = chartData as ChartDataCollection;
if (nestedChartDataCollection != null)
{
itemBasedChartDataList.AddRange(GetItemBasedChartDataRecursively(nestedChartDataCollection));
continue;
}
itemBasedChartDataList.Add((ItemBasedChartData) chartData);
}
return itemBasedChartDataList;
}
private void HandleChartDataCollectionChange()
{
var chartDataThatShouldBeDrawn = GetItemBasedChartDataRecursively(Data).ToList();
var drawnChartDataLookup = drawnChartDataList.ToDictionary(dcd => dcd.ItemBasedChartData, dcd => dcd);
DrawMissingChartDataOnCollectionChange(chartDataThatShouldBeDrawn, drawnChartDataLookup);
RemoveRedundantChartDataOnCollectionChange(chartDataThatShouldBeDrawn, drawnChartDataLookup);
drawnChartDataLookup = drawnChartDataList.ToDictionary(dcd => dcd.ItemBasedChartData, dcd => dcd);
ReorderChartDataOnCollectionChange(chartDataThatShouldBeDrawn, drawnChartDataLookup);
plotView.InvalidatePlot(true);
}
private void DrawMissingChartDataOnCollectionChange(IEnumerable chartDataThatShouldBeDrawn,
IDictionary drawnChartDataLookup)
{
foreach (var chartDataToDraw in chartDataThatShouldBeDrawn.Where(chartDataToDraw => !drawnChartDataLookup.ContainsKey(chartDataToDraw)))
{
DrawChartData(chartDataToDraw);
}
}
private void RemoveRedundantChartDataOnCollectionChange(IEnumerable chartDataThatShouldBeDrawn,
IDictionary drawnChartDataLookup)
{
foreach (var itemBasedChartData in drawnChartDataLookup.Keys.Except(chartDataThatShouldBeDrawn))
{
RemoveChartData(drawnChartDataLookup[itemBasedChartData]);
}
}
private void ReorderChartDataOnCollectionChange(IEnumerable chartDataThatShouldBeDrawn,
IDictionary drawnChartDataLookup)
{
plotView.Model.Series.Clear();
foreach (ItemBasedChartData itemBasedChartData in chartDataThatShouldBeDrawn)
{
plotView.Model.Series.Add((Series) drawnChartDataLookup[itemBasedChartData].ItemBasedChartDataSeries);
}
}
private void RemoveChartData(DrawnChartData drawnChartDataToRemove)
{
drawnChartDataToRemove.Observer.Dispose();
drawnChartDataList.Remove(drawnChartDataToRemove);
plotView.Model.Series.Remove((Series) drawnChartDataToRemove.ItemBasedChartDataSeries);
}
private void DrawInitialChartData()
{
foreach (var itemBasedChartData in GetItemBasedChartDataRecursively(Data))
{
DrawChartData(itemBasedChartData);
}
plotView.InvalidatePlot(true);
}
private void DrawChartData(ItemBasedChartData itemBasedChartData)
{
var itemBasedChartDataSeries = ItemBasedChartDataSeriesFactory.Create(itemBasedChartData);
var drawnChartData = new DrawnChartData
{
ItemBasedChartData = itemBasedChartData,
ItemBasedChartDataSeries = itemBasedChartDataSeries
};
drawnChartData.Observer = new Observer(() =>
{
drawnChartData.ItemBasedChartDataSeries.Update();
plotView.InvalidatePlot(true);
})
{
Observable = itemBasedChartData
};
drawnChartDataList.Add(drawnChartData);
plotView.Model.Series.Add((Series) itemBasedChartDataSeries);
}
private void ClearChartData()
{
foreach (DrawnChartData drawnChartData in drawnChartDataList)
{
drawnChartData.Observer.Dispose();
}
drawnChartDataList.Clear();
plotView.Model.Series.Clear();
}
///
/// Lookup class for administration related to drawn chart data series.
///
private class DrawnChartData
{
///
/// The item based chart data which the drawn is based upon.
///
public ItemBasedChartData ItemBasedChartData { get; set; }
///
/// The drawn chart data series.
///
public IItemBasedChartDataSeries ItemBasedChartDataSeries { get; set; }
///
/// The observer attached to and responsible for updating .
///
public Observer Observer { get; set; }
}
}
}