2020-09-09 00:52:14 +08:00
using System ;
2020-12-10 22:30:31 +08:00
using System.Collections.Generic ;
2020-05-13 13:45:49 +08:00
using System.Globalization ;
2020-04-30 01:21:06 +08:00
using System.Linq ;
using System.Text.Json ;
using System.Threading.Tasks ;
2020-09-09 00:52:14 +08:00
using AntDesign.core.Extensions ;
using AntDesign.Core.Helpers ;
using AntDesign.JsInterop ;
using Microsoft.AspNetCore.Components ;
using Microsoft.AspNetCore.Components.Web ;
2020-04-30 01:21:06 +08:00
2020-05-29 00:33:49 +08:00
namespace AntDesign
2020-04-30 01:21:06 +08:00
{
2020-07-15 20:02:39 +08:00
public partial class Slider < TValue > : AntInputComponentBase < TValue >
2020-04-30 01:21:06 +08:00
{
private const string PreFixCls = "ant-slider" ;
2021-04-17 22:14:01 +08:00
private HtmlElement _sliderDom ;
private HtmlElement _leftHandleDom ;
private HtmlElement _rightHandleDom ;
2020-04-30 01:21:06 +08:00
private ElementReference _leftHandle ;
private ElementReference _rightHandle ;
private string _leftHandleStyle = "left: 0%; right: auto; transform: translateX(-50%);" ;
private string _rightHandleStyle = "left: 0%; right: auto; transform: translateX(-50%);" ;
private string _trackStyle = "left: 0%; width: 0%; right: auto;" ;
private bool _mouseDown ;
2020-07-07 22:30:58 +08:00
private bool _mouseMove ;
2020-04-30 01:21:06 +08:00
private bool _right = true ;
2020-07-07 22:30:58 +08:00
private bool _initialized = false ;
2020-12-21 17:31:59 +08:00
private double _initialLeftValue ;
private double _initialRightValue ;
2021-01-21 17:20:10 +08:00
private Tooltip _toolTipRight ;
private Tooltip _toolTipLeft ;
2020-04-30 01:21:06 +08:00
private string RightHandleStyleFormat
{
get
{
if ( Reverse )
{
if ( Vertical )
{
return "bottom: auto; top: {0}; transform: translateY(-50%);" ;
}
else
{
return "right: {0}; left: auto; transform: translateX(50%);" ;
}
}
else
{
if ( Vertical )
{
return "top: auto; bottom: {0}; transform: translateY(50%);" ;
}
else
{
return "left: {0}; right: auto; transform: translateX(-50%);" ;
}
}
}
}
private string LeftHandleStyleFormat
{
get
{
if ( Reverse )
{
if ( Vertical )
{
return "bottom: auto; top: {0}; transform: translateY(-50%);" ;
}
else
{
return "right: {0}; left: auto; transform: translateX(50%);" ;
}
}
else
{
if ( Vertical )
{
return "top: auto; bottom: {0}; transform: translateY(50%);" ;
}
else
{
return "left: {0}; right: auto; transform: translateX(-50%);" ;
}
}
}
}
private string TrackStyleFormat
{
get
{
if ( Reverse )
{
if ( Vertical )
{
return "bottom: auto; height: {1}; top: {0};" ;
}
else
{
return "right: {0}; width: {1}; left: auto;" ;
}
}
else
{
if ( Vertical )
{
return "top: auto; height: {1}; bottom: {0};" ;
}
else
{
return "left: {0}; width: {1}; right: auto;" ;
}
}
}
}
[Inject]
private DomEventService DomEventService { get ; set ; }
#region Parameters
/// <summary>
/// The default value of slider. When <see cref="Range"/> is false, use number, otherwise, use [number, number]
/// </summary>
[Parameter]
2020-07-15 20:02:39 +08:00
public TValue DefaultValue { get ; set ; }
2020-04-30 01:21:06 +08:00
/// <summary>
/// If true, the slider will not be interactable
/// </summary>
[Parameter]
public bool Disabled { get ; set ; }
/// <summary>
/// Whether the thumb can drag over tick only
/// </summary>
[Parameter]
public bool Dots { get ; set ; }
/// <summary>
/// Make effect when <see cref="Marks"/> not null, true means containment and false means coordinative
/// </summary>
[Parameter]
public bool Included { get ; set ; } = true ;
/// <summary>
/// Tick mark of Slider, type of key must be number, and must in closed interval [min, max], each mark can declare its own style
/// </summary>
[Parameter]
2020-05-28 16:56:52 +08:00
public SliderMark [ ] Marks { get ; set ; }
2020-04-30 01:21:06 +08:00
/// <summary>
/// The maximum value the slider can slide to
/// </summary>
[Parameter]
public double Max { get ; set ; } = 100 ;
/// <summary>
/// The minimum value the slider can slide to
/// </summary>
[Parameter]
public double Min { get ; set ; } = 0 ;
/// <summary>
/// dual thumb mode
/// </summary>
//[Parameter]
2020-12-10 22:30:31 +08:00
private bool? _range ;
2020-12-21 17:31:59 +08:00
2020-12-10 22:30:31 +08:00
public bool Range
{
get
{
if ( _range = = null )
{
Type type = typeof ( TValue ) ;
Type doubleType = typeof ( double ) ;
Type tupleDoubleType = typeof ( ( double , double ) ) ;
if ( type = = doubleType )
{
_range = false ;
}
else if ( type = = tupleDoubleType )
{
_range = true ;
}
else
{
throw new ArgumentOutOfRangeException ( $"Type argument of Slider should be one of {doubleType}, {tupleDoubleType}" ) ;
}
}
return _range . Value ;
}
//private set { _range = value; }
}
2020-04-30 01:21:06 +08:00
/// <summary>
/// reverse the component
/// </summary>
2020-12-10 22:30:31 +08:00
private bool _reverse ;
2020-04-30 01:21:06 +08:00
[Parameter]
2020-12-10 22:30:31 +08:00
public bool Reverse
{
get { return _reverse ; }
2020-12-21 17:31:59 +08:00
set
2020-12-10 22:30:31 +08:00
{
if ( _reverse ! = value )
{
_reverse = value ;
SetStyle ( ) ;
}
}
}
2020-04-30 01:21:06 +08:00
/// <summary>
/// The granularity the slider can step through values. Must greater than 0, and be divided by (<see cref="Max"/> - <see cref="Min"/>) . When <see cref="Marks"/> no null, <see cref="Step"/> can be null.
/// </summary>
2021-01-21 17:20:10 +08:00
private double? _step = 1 ;
2021-03-12 17:02:11 +08:00
2021-01-21 17:20:10 +08:00
private int _precision ;
2021-03-12 17:02:11 +08:00
2020-04-30 01:21:06 +08:00
[Parameter]
2021-01-21 17:20:10 +08:00
public double? Step
{
get { return _step ; }
set
{
_step = value ;
//no need to evaluate if no tooltip
if ( _step ! = null & & _isTipFormatterDefault )
{
char separator = CultureInfo . CurrentCulture . NumberFormat . NumberDecimalSeparator [ 0 ] ;
string [ ] number = _step . ToString ( ) . Split ( separator ) ;
if ( number . Length > 1 )
{
_precision = number [ 1 ] . Length ;
_tipFormatter = ( d ) = > string . Format ( CultureInfo . CurrentCulture , "{0:N02}" , Math . Round ( d , _precision ) ) ;
}
}
}
}
2020-04-30 01:21:06 +08:00
private double _leftValue = double . MinValue ;
private double LeftValue
{
get = > _leftValue ;
set
{
2020-12-10 22:30:31 +08:00
double candidate = Clamp ( value , Min , Max ) ;
if ( _leftValue ! = candidate )
2020-07-15 20:02:39 +08:00
{
2020-12-10 22:30:31 +08:00
_leftValue = candidate ;
2020-07-15 20:02:39 +08:00
SetStyle ( ) ;
2020-12-10 22:30:31 +08:00
( double , double ) typedValue = DataConvertionExtensions . Convert < TValue , ( double , double ) > ( CurrentValue ) ;
if ( value ! = typedValue . Item1 )
CurrentValue = DataConvertionExtensions . Convert < ( double , double ) , TValue > ( ( _leftValue , RightValue ) ) ;
2021-01-21 17:20:10 +08:00
if ( _toolTipLeft ! = null )
_toolTipLeft . ChildElementMoved ( ) ;
2020-07-15 20:02:39 +08:00
}
2020-04-30 01:21:06 +08:00
}
}
private double _rightValue = double . MaxValue ;
// the default non-range value
private double RightValue
{
get = > _rightValue ;
set
{
2020-12-10 22:30:31 +08:00
double candidate ;
if ( Range )
2020-04-30 01:21:06 +08:00
{
2020-12-10 22:30:31 +08:00
candidate = Clamp ( value , LeftValue , Max ) ;
}
else
{
candidate = Clamp ( value , Min , Max ) ;
}
if ( _rightValue ! = candidate )
{
_rightValue = candidate ;
2020-07-15 20:02:39 +08:00
SetStyle ( ) ;
if ( Range )
{
//CurrentValue = TupleToGeneric((LeftValue, _rightValue));
2020-12-10 22:30:31 +08:00
( double , double ) typedValue = DataConvertionExtensions . Convert < TValue , ( double , double ) > ( CurrentValue ) ;
if ( value ! = typedValue . Item2 )
CurrentValue = DataConvertionExtensions . Convert < ( double , double ) , TValue > ( ( LeftValue , _rightValue ) ) ;
2020-07-15 20:02:39 +08:00
}
else
{
2020-12-10 22:30:31 +08:00
double typedValue = DataConvertionExtensions . Convert < TValue , double > ( CurrentValue ) ;
if ( value ! = typedValue )
//CurrentValue = DoubleToGeneric(_rightValue);
CurrentValue = DataConvertionExtensions . Convert < double , TValue > ( _rightValue ) ;
2020-07-15 20:02:39 +08:00
}
2021-01-21 17:20:10 +08:00
if ( _toolTipRight ! = null )
_toolTipRight . ChildElementMoved ( ) ;
2020-04-30 01:21:06 +08:00
}
}
}
2020-12-10 22:30:31 +08:00
private double Clamp (
double value , double inclusiveMinimum , double inclusiveMaximum )
{
if ( value < inclusiveMinimum )
{
value = inclusiveMinimum ;
}
if ( value > inclusiveMaximum )
{
value = inclusiveMaximum ;
}
return GetNearestStep ( value ) ;
}
/// <summary>
2020-04-30 01:21:06 +08:00
/// If true, the slider will be vertical.
/// </summary>
[Parameter]
public bool Vertical { get ; set ; }
/// <summary>
/// Fire when onmouseup is fired.
/// </summary>
[Parameter]
2020-07-15 20:02:39 +08:00
public Action < TValue > OnAfterChange { get ; set ; } //use Action here intead of EventCallback, otherwise VS will not complie when user add a delegate
2020-04-30 01:21:06 +08:00
/// <summary>
/// Callback function that is fired when the user changes the slider's value.
/// </summary>
[Parameter]
2020-07-15 20:02:39 +08:00
public Action < TValue > OnChange { get ; set ; }
2020-04-30 01:21:06 +08:00
2021-01-21 17:20:10 +08:00
[Parameter]
public bool HasTooltip { get ; set ; } = true ;
/// <summary>
/// Slider will pass its value to tipFormatter, and display its value in Tooltip
2021-03-12 17:02:11 +08:00
/// </summary>
2021-01-21 17:20:10 +08:00
private bool _isTipFormatterDefault = true ;
2021-03-12 17:02:11 +08:00
2021-01-21 17:20:10 +08:00
private Func < double , string > _tipFormatter = ( d ) = > d . ToString ( LocaleProvider . CurrentLocale . CurrentCulture ) ;
2021-03-12 17:02:11 +08:00
2021-01-21 17:20:10 +08:00
[Parameter]
public Func < double , string > TipFormatter
{
get { return _tipFormatter ; }
set
{
_tipFormatter = value ;
_isTipFormatterDefault = false ;
}
}
2020-04-30 01:21:06 +08:00
/// <summary>
2020-05-13 13:45:49 +08:00
/// Set Tooltip display position. Ref Tooltip
2020-04-30 01:21:06 +08:00
/// </summary>
[Parameter]
2021-01-21 17:20:10 +08:00
public PlacementType TooltipPlacement { get ; set ; }
2020-04-30 01:21:06 +08:00
/// <summary>
/// If true, Tooltip will show always, or it will not show anyway, even if dragging or hovering.
/// </summary>
2021-01-21 17:20:10 +08:00
private bool _tooltipVisible ;
2021-03-12 17:02:11 +08:00
2021-01-21 17:20:10 +08:00
private bool _tooltipRightVisible ;
private bool _tooltipLeftVisible ;
2021-03-12 17:02:11 +08:00
2020-04-30 01:21:06 +08:00
[Parameter]
2021-01-21 17:20:10 +08:00
public bool TooltipVisible
{
get { return _tooltipVisible ; }
set
{
if ( _tooltipVisible ! = value )
{
_tooltipVisible = value ;
//ensure parameter loading is not happening because values are changing during mouse moving
2021-03-12 17:02:11 +08:00
//otherwise the tooltip will be vanishing when mouse moves out of the edge
2021-01-21 17:20:10 +08:00
if ( ! _mouseDown )
{
_tooltipRightVisible = _tooltipVisible ;
_tooltipLeftVisible = _tooltipVisible ;
}
}
}
}
2020-04-30 01:21:06 +08:00
/// <summary>
/// The DOM container of the Tooltip, the default behavior is to create a div element in body.
/// </summary>
[Parameter]
public object GetTooltipPopupContainer { get ; set ; }
#endregion Parameters
protected override void OnInitialized ( )
{
base . OnInitialized ( ) ;
}
public async override Task SetParametersAsync ( ParameterView parameters )
{
await base . SetParametersAsync ( parameters ) ;
var dict = parameters . ToDictionary ( ) ;
2020-07-15 20:02:39 +08:00
if ( ! _initialized )
2020-04-30 01:21:06 +08:00
{
2020-07-15 20:02:39 +08:00
if ( ! dict . ContainsKey ( nameof ( Value ) ) )
{
TValue defaultValue ;
if ( Range )
{
//if (typeof(T) == typeof((int, int)))
//{
// defaultValue = parameters.GetValueOrDefault(nameof(DefaultValue), DataConvertionExtensions.Convert<(int, int), T>((0, 0)));
//}
//else
//{
defaultValue = parameters . GetValueOrDefault ( nameof ( DefaultValue ) , DataConvertionExtensions . Convert < ( double , double ) , TValue > ( ( 0 , 0 ) ) ) ;
//}
LeftValue = DataConvertionExtensions . Convert < TValue , ( double , double ) > ( defaultValue ) . Item1 ;
RightValue = DataConvertionExtensions . Convert < TValue , ( double , double ) > ( defaultValue ) . Item2 ;
}
else
{
//if (typeof(T) == typeof(int))
//{
// defaultValue = parameters.GetValueOrDefault(nameof(DefaultValue), DataConvertionExtensions.Convert<int, T>(0));
//}
//else
//{
defaultValue = parameters . GetValueOrDefault ( nameof ( DefaultValue ) , DataConvertionExtensions . Convert < double , TValue > ( 0 ) ) ;
//}
RightValue = DataConvertionExtensions . Convert < TValue , double > ( defaultValue ) ;
}
}
else
{
if ( Range )
{
LeftValue = DataConvertionExtensions . Convert < TValue , ( double , double ) > ( CurrentValue ) . Item1 ;
RightValue = DataConvertionExtensions . Convert < TValue , ( double , double ) > ( CurrentValue ) . Item2 ;
}
else
{
RightValue = DataConvertionExtensions . Convert < TValue , double > ( CurrentValue ) ;
}
}
2021-01-21 17:20:10 +08:00
if ( ! dict . ContainsKey ( nameof ( TooltipPlacement ) ) )
{
if ( Vertical )
TooltipPlacement = PlacementType . Right ;
else
TooltipPlacement = PlacementType . Top ;
}
2020-04-30 01:21:06 +08:00
}
2020-07-15 20:02:39 +08:00
2020-07-07 22:30:58 +08:00
_initialized = true ;
2020-04-30 01:21:06 +08:00
}
protected override void OnParametersSet ( )
{
base . OnParametersSet ( ) ;
ValidateParameter ( ) ;
ClassMapper . Clear ( )
. Add ( PreFixCls )
. If ( $"{PreFixCls}-disabled" , ( ) = > Disabled )
. If ( $"{PreFixCls}-vertical" , ( ) = > Vertical )
2021-03-12 17:02:11 +08:00
. If ( $"{PreFixCls}-with-marks" , ( ) = > Marks ! = null )
. If ( $"{PreFixCls}-rtl" , ( ) = > RTL ) ;
2020-04-30 01:21:06 +08:00
}
2020-09-21 17:20:19 +08:00
protected override void OnAfterRender ( bool firstRender )
{
if ( firstRender )
{
DomEventService . AddEventListener ( "window" , "mousemove" , OnMouseMove , false ) ;
DomEventService . AddEventListener ( "window" , "mouseup" , OnMouseUp , false ) ;
}
base . OnAfterRender ( firstRender ) ;
}
protected override void Dispose ( bool disposing )
{
DomEventService . RemoveEventListerner < JsonElement > ( "window" , "mousemove" , OnMouseMove ) ;
DomEventService . RemoveEventListerner < JsonElement > ( "window" , "mouseup" , OnMouseUp ) ;
base . Dispose ( disposing ) ;
}
2021-01-21 17:20:10 +08:00
protected override async Task OnAfterRenderAsync ( bool firstRender )
{
if ( ! firstRender )
{
if ( _toolTipRight ! = null & & HasTooltip )
{
_rightHandle = _toolTipRight . Ref ;
await _toolTipRight . ChildElementMoved ( ) ;
if ( _toolTipLeft ! = null )
{
_leftHandle = _toolTipLeft . Ref ;
await _toolTipLeft . ChildElementMoved ( ) ;
}
}
}
await base . OnAfterRenderAsync ( firstRender ) ;
}
2020-04-30 01:21:06 +08:00
private void ValidateParameter ( )
{
if ( Step = = null & & Marks = = null )
{
throw new ArgumentOutOfRangeException ( nameof ( Step ) , $"{nameof(Step)} can only be null when {nameof(Marks)} is not null." ) ;
}
if ( Step < = 0 )
{
throw new ArgumentOutOfRangeException ( nameof ( Step ) , "Must greater than 0." ) ;
}
2020-05-13 13:45:49 +08:00
if ( Step ! = null & & ( Max - Min ) / Step % 1 ! = 0 )
2020-04-30 01:21:06 +08:00
{
throw new ArgumentOutOfRangeException ( nameof ( Step ) , $"Must be divided by ({Max} - {Min})." ) ;
}
}
2020-07-15 20:02:39 +08:00
private async void OnMouseDown ( MouseEventArgs args )
2020-04-30 01:21:06 +08:00
{
2020-09-28 16:44:11 +08:00
//// _sliderDom = await JsInvokeAsync<DomRect>(JSInteropConstants.GetBoundingClientRect, _slider);
//_sliderDom = await JsInvokeAsync<Element>(JSInteropConstants.GetDomInfo, _slider);
//decimal x = (decimal)args.ClientX;
//decimal y = (decimal)args.ClientY;
2020-07-15 20:02:39 +08:00
2020-09-28 16:44:11 +08:00
//_mouseDown = !Disabled
// && _sliderDom.clientLeft <= x && x <= _sliderDom.clientLeft + _sliderDom.clientWidth
// && _sliderDom.clientTop <= y && y <= _sliderDom.clientTop + _sliderDom.clientHeight;
_mouseDown = ! Disabled ;
2020-04-30 01:21:06 +08:00
}
2021-01-21 17:20:10 +08:00
private double _trackedClientX ;
private double _trackedClientY ;
2021-03-12 17:02:11 +08:00
2020-12-10 22:30:31 +08:00
private void OnMouseDownEdge ( MouseEventArgs args , bool right )
{
_right = right ;
2020-12-21 17:31:59 +08:00
_initialLeftValue = _leftValue ;
_initialRightValue = _rightValue ;
2021-01-21 17:20:10 +08:00
_trackedClientX = args . ClientX ;
_trackedClientY = args . ClientY ;
if ( _toolTipRight ! = null )
{
if ( _right )
{
_tooltipRightVisible = true ;
}
else
{
_tooltipLeftVisible = true ;
}
}
2020-12-10 22:30:31 +08:00
}
private bool IsMoveInEdgeBoundary ( JsonElement jsonElement )
{
2021-01-21 17:20:10 +08:00
double clientX = jsonElement . GetProperty ( "clientX" ) . GetDouble ( ) ;
double clientY = jsonElement . GetProperty ( "clientY" ) . GetDouble ( ) ;
return ( clientX = = _trackedClientX & & clientY = = _trackedClientY ) ;
2020-12-10 22:30:31 +08:00
}
2020-04-30 01:21:06 +08:00
private async void OnMouseMove ( JsonElement jsonElement )
{
2020-12-21 17:31:59 +08:00
if ( _mouseDown )
2020-04-30 01:21:06 +08:00
{
2021-01-21 17:20:10 +08:00
_trackedClientX = jsonElement . GetProperty ( "clientX" ) . GetDouble ( ) ;
_trackedClientY = jsonElement . GetProperty ( "clientY" ) . GetDouble ( ) ;
2020-07-07 22:30:58 +08:00
_mouseMove = true ;
2020-09-28 16:44:11 +08:00
await CalculateValueAsync ( Vertical ? jsonElement . GetProperty ( "pageY" ) . GetDouble ( ) : jsonElement . GetProperty ( "pageX" ) . GetDouble ( ) ) ;
2020-05-15 19:19:49 +08:00
2020-07-15 20:02:39 +08:00
OnChange ? . Invoke ( CurrentValue ) ;
2020-04-30 01:21:06 +08:00
}
}
2020-07-07 22:30:58 +08:00
private async void OnMouseUp ( JsonElement jsonElement )
2020-04-30 01:21:06 +08:00
{
2021-01-21 17:20:10 +08:00
bool isMoveInEdgeBoundary = IsMoveInEdgeBoundary ( jsonElement ) ;
2020-07-15 20:02:39 +08:00
if ( _mouseDown )
2020-04-30 01:21:06 +08:00
{
2020-07-15 20:02:39 +08:00
_mouseDown = false ;
2021-01-21 17:20:10 +08:00
if ( ! isMoveInEdgeBoundary )
2020-12-10 22:30:31 +08:00
{
await CalculateValueAsync ( Vertical ? jsonElement . GetProperty ( "pageY" ) . GetDouble ( ) : jsonElement . GetProperty ( "pageX" ) . GetDouble ( ) ) ;
OnAfterChange ? . Invoke ( CurrentValue ) ;
}
}
2021-01-21 17:20:10 +08:00
if ( _toolTipRight ! = null )
2020-12-10 22:30:31 +08:00
{
2021-01-21 17:20:10 +08:00
if ( _tooltipRightVisible ! = TooltipVisible )
{
_tooltipRightVisible = TooltipVisible ;
_toolTipRight . SetVisible ( TooltipVisible ) ;
}
if ( _tooltipLeftVisible ! = TooltipVisible )
{
_tooltipLeftVisible = TooltipVisible ;
_toolTipLeft . SetVisible ( TooltipVisible ) ;
}
2020-04-30 01:21:06 +08:00
}
2021-01-21 17:20:10 +08:00
_initialLeftValue = _leftValue ;
_initialRightValue = _rightValue ;
2020-04-30 01:21:06 +08:00
}
2020-05-13 13:45:49 +08:00
private async Task CalculateValueAsync ( double clickClient )
2020-04-30 01:21:06 +08:00
{
2021-04-17 22:14:01 +08:00
_sliderDom = await JsInvokeAsync < HtmlElement > ( JSInteropConstants . GetDomInfo , Ref ) ;
double sliderOffset = ( double ) ( Vertical ? _sliderDom . AbsoluteTop : _sliderDom . AbsoluteLeft ) ;
double sliderLength = ( double ) ( Vertical ? _sliderDom . ClientHeight : _sliderDom . ClientWidth ) ;
2020-05-13 13:45:49 +08:00
double handleNewPosition ;
2020-04-30 01:21:06 +08:00
if ( _right )
{
if ( _rightHandleDom = = null )
{
2021-04-17 22:14:01 +08:00
_rightHandleDom = await JsInvokeAsync < HtmlElement > ( JSInteropConstants . GetDomInfo , _rightHandle ) ;
2020-04-30 01:21:06 +08:00
}
if ( Reverse )
{
if ( Vertical )
{
2020-12-21 17:31:59 +08:00
handleNewPosition = clickClient - sliderOffset ;
2020-04-30 01:21:06 +08:00
}
else
{
2020-12-21 17:31:59 +08:00
handleNewPosition = sliderLength - ( clickClient - sliderOffset ) ;
2020-04-30 01:21:06 +08:00
}
}
else
{
if ( Vertical )
{
2020-12-21 17:31:59 +08:00
handleNewPosition = sliderOffset + sliderLength - clickClient ;
2020-04-30 01:21:06 +08:00
}
else
{
2020-12-21 17:31:59 +08:00
handleNewPosition = clickClient - sliderOffset ;
2020-04-30 01:21:06 +08:00
}
}
double rightV = Max * handleNewPosition / sliderLength ;
if ( rightV < LeftValue )
{
_right = false ;
2020-12-21 17:31:59 +08:00
if ( _mouseDown )
RightValue = _initialLeftValue ;
2021-04-15 14:19:26 +08:00
LeftValue = rightV ;
await FocusAsync ( _leftHandle ) ;
2020-04-30 01:21:06 +08:00
}
else
{
RightValue = rightV ;
}
}
else
{
if ( _leftHandleDom = = null )
{
2021-04-17 22:14:01 +08:00
_leftHandleDom = await JsInvokeAsync < HtmlElement > ( JSInteropConstants . GetDomInfo , _leftHandle ) ;
2020-04-30 01:21:06 +08:00
}
2020-12-10 22:30:31 +08:00
if ( _rightHandleDom = = null )
{
2021-04-17 22:14:01 +08:00
_rightHandleDom = await JsInvokeAsync < HtmlElement > ( JSInteropConstants . GetDomInfo , _rightHandle ) ;
2020-12-10 22:30:31 +08:00
}
2020-04-30 01:21:06 +08:00
if ( Reverse )
{
if ( Vertical )
{
2020-12-21 17:31:59 +08:00
handleNewPosition = clickClient - sliderOffset ;
2020-04-30 01:21:06 +08:00
}
else
{
2020-12-21 17:31:59 +08:00
handleNewPosition = sliderLength - ( clickClient - sliderOffset ) ;
2020-04-30 01:21:06 +08:00
}
}
else
{
if ( Vertical )
{
2020-12-21 17:31:59 +08:00
handleNewPosition = sliderOffset + sliderLength - clickClient ;
2020-04-30 01:21:06 +08:00
}
else
{
2020-12-21 17:31:59 +08:00
handleNewPosition = clickClient - sliderOffset ;
2020-04-30 01:21:06 +08:00
}
}
double leftV = Max * handleNewPosition / sliderLength ;
if ( leftV > RightValue )
{
_right = true ;
2020-12-21 17:31:59 +08:00
if ( _mouseDown )
LeftValue = _initialRightValue ;
2021-04-15 14:19:26 +08:00
RightValue = leftV ;
await FocusAsync ( _rightHandle ) ;
2020-04-30 01:21:06 +08:00
}
else
{
LeftValue = leftV ;
}
}
}
private void SetStyle ( )
{
2020-07-23 15:49:23 +08:00
_rightHandleStyle = string . Format ( CultureInfo . CurrentCulture , RightHandleStyleFormat , Formatter . ToPercentWithoutBlank ( RightValue / Max ) ) ;
2020-04-30 01:21:06 +08:00
if ( Range )
{
2020-07-23 15:49:23 +08:00
_trackStyle = string . Format ( CultureInfo . CurrentCulture , TrackStyleFormat , Formatter . ToPercentWithoutBlank ( LeftValue / Max ) , Formatter . ToPercentWithoutBlank ( ( RightValue - LeftValue ) / Max ) ) ;
_leftHandleStyle = string . Format ( CultureInfo . CurrentCulture , LeftHandleStyleFormat , Formatter . ToPercentWithoutBlank ( LeftValue / Max ) ) ;
2020-04-30 01:21:06 +08:00
}
else
{
2020-07-23 15:49:23 +08:00
_trackStyle = string . Format ( CultureInfo . CurrentCulture , TrackStyleFormat , "0%" , Formatter . ToPercentWithoutBlank ( RightValue / Max ) ) ;
2020-04-30 01:21:06 +08:00
}
StateHasChanged ( ) ;
}
private string SetMarkPosition ( double key )
{
2020-07-23 15:49:23 +08:00
return Formatter . ToPercentWithoutBlank ( key / Max ) ;
2020-04-30 01:21:06 +08:00
}
private string IsActiveMark ( double key )
{
bool active = ( Range & & key > = LeftValue & & key < = RightValue )
| | ( ! Range & & key < = RightValue ) ;
return active ? "ant-slider-dot-active" : string . Empty ;
}
private double GetNearestStep ( double value )
{
if ( Step . HasValue & & ( Marks = = null | | Marks . Length = = 0 ) )
{
2020-07-15 20:02:39 +08:00
return Math . Round ( value / Step . Value , 0 ) * Step . Value ;
2020-04-30 01:21:06 +08:00
}
else if ( Step . HasValue )
{
return new double [ 2 ] { Math . Round ( value / Step . Value ) * Step . Value , Math . Round ( value / Step . Value + 1 ) * Step . Value } . Union ( Marks . Select ( m = > m . Key ) ) . OrderBy ( v = > Math . Abs ( v - value ) ) . First ( ) ;
}
else if ( Marks . Length = = 0 )
{
return Min ;
}
else
{
return Marks . Select ( m = > m . Key ) . OrderBy ( v = > Math . Abs ( v - value ) ) . First ( ) ;
}
}
2020-07-15 20:02:39 +08:00
protected override void OnValueChange ( TValue value )
{
base . OnValueChange ( value ) ;
if ( Range )
{
2020-12-10 22:30:31 +08:00
if ( IsLeftAndRightChanged ( value ) )
{
_leftValue = double . MinValue ;
_rightValue = double . MaxValue ;
}
2020-07-15 20:02:39 +08:00
LeftValue = DataConvertionExtensions . Convert < TValue , ( double , double ) > ( value ) . Item1 ;
RightValue = DataConvertionExtensions . Convert < TValue , ( double , double ) > ( value ) . Item2 ;
}
else
{
RightValue = DataConvertionExtensions . Convert < TValue , double > ( value ) ;
}
}
2020-12-10 22:30:31 +08:00
private bool IsLeftAndRightChanged ( TValue value )
{
( double , double ) typedValue = DataConvertionExtensions . Convert < TValue , ( double , double ) > ( value ) ;
return ( typedValue . Item1 ! = LeftValue ) & & ( typedValue . Item2 ! = RightValue ) ;
}
2020-12-21 17:31:59 +08:00
private TValue _value ;
2020-12-10 22:30:31 +08:00
/// <summary>
/// Gets or sets the value of the input. This should be used with two-way binding.
/// </summary>
/// <example>
/// @bind-Value="model.PropertyName"
/// </example>
[Parameter]
public sealed override TValue Value
{
get { return _value ; }
set
{
TValue orderedValue = SortValue ( value ) ;
var hasChanged = ! EqualityComparer < TValue > . Default . Equals ( orderedValue , Value ) ;
if ( hasChanged )
{
_value = orderedValue ;
OnValueChange ( orderedValue ) ;
}
}
}
private TValue SortValue ( TValue value )
{
TValue orderedValue = value ;
if ( Range )
{
//sort if needed
( double , double ) typedValue = DataConvertionExtensions . Convert < TValue , ( double , double ) > ( value ) ;
if ( typedValue . Item1 > typedValue . Item2 )
{
orderedValue = DataConvertionExtensions . Convert < ( double , double ) , TValue > ( ( typedValue . Item2 , typedValue . Item1 ) ) ;
}
}
return orderedValue ;
}
2020-04-30 01:21:06 +08:00
}
2020-05-13 13:45:49 +08:00
}