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
8 changes: 8 additions & 0 deletions src/OSPSuite.Assets/UIConstants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ public static class Captions
public static readonly string Scaling = "Scaling";
public static readonly string AxisMinimum = "Axis Minimum";
public static readonly string AxisMaximum = "Axis Maximum";
public static readonly string AxisMajorInterval = "Major Interval";
public static readonly string AxisMinorTicks = "Minor Ticks";
public static readonly string GridLines = "Grid Lines";
public static readonly string DefaultColor = "Default Color";
public static readonly string DefaultLineStyle = "Default Line Style";
Expand Down Expand Up @@ -1274,6 +1276,8 @@ public static class AxisOptions
public static string GridLines = "Grid";
public static string Min = "Min";
public static string Max = "Max";
public static string MajorInterval = "Major Interval";
public static string MinorTicks = "Minor Ticks";
public static string Caption = "Caption";
public static string DefaultLinestyle = "Default Linestyle";
public static string DefaultColor = "Default Color";
Expand Down Expand Up @@ -1988,6 +1992,10 @@ public static string AxisMinMustBeLessThanOrEqualToAxisMax(float? axisMaximumVal
}

public static readonly string LogAxisMaxMustBeGreaterThanZero = "Loagarithmic axis maximum must be greater than 0";

public static readonly string AxisMajorIntervalMustBeGreaterThanZero = "The axis major interval must be greater than 0";

public static readonly string AxisMinorTicksMustBeGreaterThanZeroAndLessThan100 = "The number of minor ticks must be greater than 0 and less than 100";
}

public static class Rules
Expand Down
45 changes: 45 additions & 0 deletions src/OSPSuite.Core/Chart/Axis.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,16 @@ public enum NumberModes

public class Axis : Notifier, IWithDimension, IValidatable
{
// DevExpress only accepts a minor tick count that is greater than 0 and less than 100.
public const int MIN_MINOR_TICKS = 1;
public const int MAX_MINOR_TICKS = 99;

private IDimension _dimension;
private bool _gridLines;
private float? _max;
private float? _min;
private float? _majorInterval;
private int? _minorTicks;
private NumberModes _numberMode;
private Scalings _scaling;
private string _unitName;
Expand All @@ -56,6 +62,8 @@ public Axis(AxisTypes axisType)
_gridLines = false;
_min = null;
_max = null;
_majorInterval = null;
_minorTicks = null;
Visible = true;
_defaultLineStyle = defaultLineStyleForAxisType();
_defaultColor = Color.White;
Expand All @@ -69,11 +77,15 @@ internal static IEnumerable<IBusinessRule> AllRules()
yield return maxGreaterThanOrEqualToMin;
yield return minLessThanOrEqualToMax;
yield return maxGreaterThanZero;
yield return majorIntervalGreaterThanZero;
yield return minorTicksWithinValidRange;
}

private static IBusinessRule maxGreaterThanOrEqualToMin { get; } = createMaxGreaterThanOrEqualToMinRuleForAxis();
private static IBusinessRule minLessThanOrEqualToMax { get; } = createMinLessThanOrEqualToMaxRuleForAxis();
private static IBusinessRule maxGreaterThanZero { get; } = createMaxGreaterThanZeroRuleForLogarithmicAxis();
private static IBusinessRule majorIntervalGreaterThanZero { get; } = createMajorIntervalGreaterThanZeroRuleForAxis();
private static IBusinessRule minorTicksWithinValidRange { get; } = createMinorTicksWithinValidRangeRuleForAxis();

private static IBusinessRule createMinLessThanOrEqualToMaxRuleForAxis() => CreateRule.For<Axis>()
.Property(axis => axis.Min)
Expand All @@ -89,6 +101,17 @@ private static IBusinessRule createMaxGreaterThanOrEqualToMinRuleForAxis() => Cr
.Property(axis => axis.Max)
.WithRule((axis, value) => !value.HasValue || !axis.Min.HasValue || value >= axis.Min)
.WithError((axis, value) => Validation.AxisMaxMustBeGreaterThanOrEqualToAxisMin(axis.Min));

private static IBusinessRule createMajorIntervalGreaterThanZeroRuleForAxis() => CreateRule.For<Axis>()
.Property(axis => axis.MajorInterval)
.WithRule((axis, value) => !value.HasValue || value > 0F)
.WithError((axis, value) => Validation.AxisMajorIntervalMustBeGreaterThanZero);

// The allowed range is dictated by DevExpress: its axis rejects a minor tick count outside [MIN_MINOR_TICKS, MAX_MINOR_TICKS].
private static IBusinessRule createMinorTicksWithinValidRangeRuleForAxis() => CreateRule.For<Axis>()
.Property(axis => axis.MinorTicks)
.WithRule((axis, value) => !value.HasValue || (value >= MIN_MINOR_TICKS && value <= MAX_MINOR_TICKS))
.WithError((axis, value) => Validation.AxisMinorTicksMustBeGreaterThanZeroAndLessThan100);
}

private LineStyles defaultLineStyleForAxisType()
Expand Down Expand Up @@ -123,6 +146,8 @@ public void UpdateFrom(Axis axis)
UnitName = axis.UnitName;
GridLines = axis.GridLines;
SetRange(axis.Min, axis.Max);
MajorInterval = axis.MajorInterval;
MinorTicks = axis.MinorTicks;
DefaultLineStyle = axis.DefaultLineStyle;
DefaultColor = axis.DefaultColor;
Visible = axis.Visible;
Expand Down Expand Up @@ -229,6 +254,26 @@ public float? Max
set => SetProperty(ref _max, value);
}

/// <summary>
/// Spacing between major gridlines/ticks in axis units. When null, the spacing is calculated automatically.
/// Only applied for linearly scaled axes.
/// </summary>
public float? MajorInterval
{
get => _majorInterval;
set => SetProperty(ref _majorInterval, value);
}

/// <summary>
/// Number of minor ticks between two adjacent major ticks. When null, the count is calculated automatically.
/// Only applied for linearly scaled axes.
/// </summary>
public int? MinorTicks
{
get => _minorTicks;
set => SetProperty(ref _minorTicks, value);
}

public Unit Unit => _dimension?.Unit(UnitName);

/// <summary>
Expand Down
2 changes: 2 additions & 0 deletions src/OSPSuite.Core/Serialization/Chart/AxisXmlSerializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ public override void PerformMapping()
Map(x => x.UnitName).WithMappingName(Constants.Serialization.Attribute.UNIT_NAME);
Map(x => x.Min);
Map(x => x.Max);
Map(x => x.MajorInterval);
Map(x => x.MinorTicks);
Map(x => x.Scaling);
Map(x => x.NumberMode);
Map(x => x.GridLines);
Expand Down
2 changes: 2 additions & 0 deletions src/OSPSuite.Core/Snapshots/Axis.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ public class Axis
public bool Visible { get; set; }
public float? Min { get; set; }
public float? Max { get; set; }
public float? MajorInterval { get; set; }
public int? MinorTicks { get; set; }
public Color DefaultColor { get; set; }
public LineStyles DefaultLineStyle { get; set; }
public Scalings Scaling { get; set; }
Expand Down
4 changes: 4 additions & 0 deletions src/OSPSuite.Core/Snapshots/Mappers/AxisMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ public override Task<Axis> MapToSnapshot(Core.Chart.Axis axis)
x.DefaultLineStyle = axis.DefaultLineStyle;
x.Min = axis.Min;
x.Max = axis.Max;
x.MajorInterval = axis.MajorInterval;
x.MinorTicks = axis.MinorTicks;
});
}

Expand All @@ -49,6 +51,8 @@ public override Task<Axis> MapToSnapshot(Core.Chart.Axis axis)
axis.UnitName = ModelValueFor(snapshot.Unit);
axis.Min = snapshot.Min;
axis.Max = snapshot.Max;
axis.MajorInterval = snapshot.MajorInterval;
axis.MinorTicks = snapshot.MinorTicks;

return Task.FromResult(axis);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ public enum AxisOptionsColumns
GridLines,
Min,
Max,
MajorInterval,
MinorTicks,
Caption,
DefaultLineStyle,
DefaultColor
Expand Down Expand Up @@ -73,6 +75,8 @@ protected override void SetDefaultColumnSettings()
AddColumnSettings(AxisOptionsColumns.NumberMode).WithCaption(Captions.Chart.AxisOptions.NumberMode);
AddColumnSettings(AxisOptionsColumns.Min).WithCaption(Captions.Chart.AxisOptions.Min);
AddColumnSettings(AxisOptionsColumns.Max).WithCaption(Captions.Chart.AxisOptions.Max);
AddColumnSettings(AxisOptionsColumns.MajorInterval).WithCaption(Captions.Chart.AxisOptions.MajorInterval);
AddColumnSettings(AxisOptionsColumns.MinorTicks).WithCaption(Captions.Chart.AxisOptions.MinorTicks);
AddColumnSettings(AxisOptionsColumns.GridLines).WithCaption(Captions.Chart.AxisOptions.GridLines);
AddColumnSettings(AxisOptionsColumns.DefaultLineStyle).WithCaption(Captions.Chart.AxisOptions.DefaultLinestyle);
AddColumnSettings(AxisOptionsColumns.DefaultColor).WithCaption(Captions.Chart.AxisOptions.DefaultColor);
Expand All @@ -81,6 +85,8 @@ protected override void SetDefaultColumnSettings()
public void UnitChanged(Axis axis)
{
axis.ResetRange();
// the major interval is expressed in axis units, so it is no longer meaningful once the unit changes
axis.MajorInterval = null;
}

public void NotifyAxisPropertyChanged(Axis axis) => AxisPropertyChanged(this, new AxisEventArgs(axis));
Expand Down
42 changes: 42 additions & 0 deletions src/OSPSuite.UI/Binders/AxisBinder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -212,8 +212,50 @@ private void automaticallyConfigureAxisScale()
_axisView.NumericScaleOptions.AutoGrid = true;
}

// The manual tick override is only applied for linearly scaled axes. Logarithmic axes keep their
// decade gridlines and the fixed minor count handled in setAxisRange.
private bool hasManualTickSettings => Axis.Scaling != Scalings.Log && (hasValidMajorInterval || Axis.MinorTicks.HasValue);

private bool hasValidMajorInterval => Axis.MajorInterval.HasValue && Axis.MajorInterval.Value > 0;

// The charting component throws if the minor tick count is outside [MIN_MINOR_TICKS, MAX_MINOR_TICKS]. An out-of-range
// value is flagged to the user by the axis validation rules; here we simply fall back to the automatic count.
private bool hasValidMinorTicks =>
Axis.MinorTicks.HasValue && Axis.MinorTicks.Value >= OSPAxis.MIN_MINOR_TICKS && Axis.MinorTicks.Value <= OSPAxis.MAX_MINOR_TICKS;

private void applyManualTickSettings()
{
if (hasValidMajorInterval)
{
_axisView.NumericScaleOptions.AutoGrid = false;
_axisView.NumericScaleOptions.GridSpacing = Axis.MajorInterval.Value;
_axisView.NumericScaleOptions.GridAlignment = NumericGridAlignment.Ones;
_axisView.NumericScaleOptions.MeasureUnit = NumericMeasureUnit.Ones;
}
else
{
_axisView.NumericScaleOptions.AutoGrid = true;
}

if (hasValidMinorTicks)
{
_axisView.MinorCount = Axis.MinorTicks.Value;
_axisView.Tickmarks.MinorVisible = true;
}
else
{
_axisView.MinorCount = _defaultMinorTickCount;
}
}

private void configureAxisScale(int axisWidthInPixel)
{
if (hasManualTickSettings)
{
applyManualTickSettings();
return;
}

var ticksConfig = new TicksConfig { AutoScale = true };

if (shouldApplyPreferredMinorTicks())
Expand Down
4 changes: 4 additions & 0 deletions src/OSPSuite.UI/Views/Charts/AxisSettingsView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,10 @@ public override void InitializeBinding()

createColumn(x => x.Max, AxisOptionsColumns.Max);

createColumn(x => x.MajorInterval, AxisOptionsColumns.MajorInterval);

createColumn(x => x.MinorTicks, AxisOptionsColumns.MinorTicks);

createColumn(x => x.GridLines, AxisOptionsColumns.GridLines, _gridLinesRepository);

createColumn(x => x.DefaultColor, AxisOptionsColumns.DefaultColor, _colorRepository, toolTip: ToolTips.DefaultCurveColor)
Expand Down
Loading