2020-05-06 17:33:11 +08:00
using System ;
using System.Collections.Generic ;
using System.Threading ;
using System.Threading.Tasks ;
2020-05-29 00:33:49 +08:00
using AntDesign.JsInterop ;
2020-05-06 17:33:11 +08:00
using Microsoft.AspNetCore.Components ;
2020-05-29 00:33:49 +08:00
namespace AntDesign
2020-05-06 17:33:11 +08:00
{
2020-06-07 00:20:28 +08:00
public partial class Carousel : AntDomComponentBase
2020-05-06 17:33:11 +08:00
{
private const string PrefixCls = "ant-carousel" ;
private string _trackStyle ;
private string _slickClonedStyle ;
2020-06-11 23:24:58 +08:00
private string _slickListStyle ;
2020-05-06 17:33:11 +08:00
private ElementReference _ref ;
private int _slickWidth = - 1 ;
2020-06-11 23:24:58 +08:00
private int _slickHeight = - 1 ;
2020-05-06 17:33:11 +08:00
private int _totalWidth = - 1 ;
2020-06-11 23:24:58 +08:00
private int _totalHeight = - 1 ;
2020-06-07 00:20:28 +08:00
private List < CarouselSlick > _slicks = new List < CarouselSlick > ( ) ;
private CarouselSlick _activeSlick ;
2020-05-06 17:33:11 +08:00
private Timer _timer ;
2020-06-07 00:20:28 +08:00
private ClassMapper SlickSliderClassMapper { get ; } = new ClassMapper ( ) ;
2020-06-11 23:24:58 +08:00
private bool IsHorizontal = > DotPosition = = CarouselDotPosition . Top | | DotPosition = = CarouselDotPosition . Bottom ;
2020-05-06 17:33:11 +08:00
#region Parameters
[Parameter]
public RenderFragment ChildContent { get ; set ; }
/// <summary>
2020-06-07 00:20:28 +08:00
/// The position of the dots, which can be one of Top, Bottom, Left or Right, <see cref="CarouselDotPosition"/>
2020-05-06 17:33:11 +08:00
/// </summary>
[Parameter]
2020-06-07 00:20:28 +08:00
public string DotPosition { get ; set ; } = CarouselDotPosition . Bottom ;
2020-05-06 17:33:11 +08:00
/// <summary>
/// Whether to scroll automatically
/// </summary>
[Parameter]
public TimeSpan Autoplay { get ; set ; } = TimeSpan . Zero ;
/// <summary>
2020-06-07 00:20:28 +08:00
/// Transition effect, <see cref="CarouselEffect"/>
2020-05-06 17:33:11 +08:00
/// </summary>
[Parameter]
2020-06-07 00:20:28 +08:00
public string Effect { get ; set ; } = CarouselEffect . ScrollX ;
2020-05-06 17:33:11 +08:00
#endregion Parameters
2020-06-07 00:20:28 +08:00
private void SetClass ( )
{
2020-06-11 23:24:58 +08:00
SlickSliderClassMapper . Clear ( )
. Add ( "slick-slider slick-initialized" )
. If ( "slick-vertical" , ( ) = > ! IsHorizontal ) ;
2020-06-07 00:20:28 +08:00
ClassMapper . Clear ( )
. Add ( PrefixCls )
2020-06-11 23:24:58 +08:00
. If ( $"{PrefixCls}-vertical" , ( ) = > ! IsHorizontal ) ;
2020-06-07 00:20:28 +08:00
}
2020-05-06 17:33:11 +08:00
protected override void OnParametersSet ( )
{
base . OnParametersSet ( ) ;
2020-06-11 23:24:58 +08:00
SetClass ( ) ;
2020-06-07 00:20:28 +08:00
if ( Effect ! = CarouselEffect . ScrollX & & Effect ! = CarouselEffect . Fade )
2020-05-06 17:33:11 +08:00
{
2020-06-07 00:20:28 +08:00
throw new ArgumentOutOfRangeException ( $"{nameof(Effect)} must be one of {nameof(CarouselEffect)}.{nameof(CarouselEffect.ScrollX)} or {nameof(CarouselEffect)}.{nameof(CarouselEffect.Fade)}." ) ;
2020-05-06 17:33:11 +08:00
}
_timer ? . Dispose ( ) ;
if ( Autoplay ! = TimeSpan . Zero )
{
_timer = new Timer ( AutoplaySlick , null , ( int ) Autoplay . TotalMilliseconds , ( int ) Autoplay . TotalMilliseconds ) ;
}
}
protected async override Task OnAfterRenderAsync ( bool firstRender )
{
await base . OnAfterRenderAsync ( firstRender ) ;
DomRect listRect = await JsInvokeAsync < DomRect > ( JSInteropConstants . getBoundingClientRect , _ref ) ;
2020-06-11 23:24:58 +08:00
if ( ( _slickWidth ! = ( int ) listRect . width & & IsHorizontal )
| | ( _slickHeight ! = ( int ) listRect . height & & ! IsHorizontal )
| | IsHorizontal & & ! string . IsNullOrEmpty ( _slickListStyle )
| | ! IsHorizontal & & string . IsNullOrEmpty ( _slickListStyle ) )
2020-05-06 17:33:11 +08:00
{
_slickWidth = ( int ) listRect . width ;
2020-06-11 23:24:58 +08:00
_slickHeight = ( int ) listRect . height ;
2020-05-06 17:33:11 +08:00
_totalWidth = _slickWidth * ( _slicks . Count * 2 + 1 ) ;
2020-06-11 23:24:58 +08:00
_totalHeight = _slickHeight * ( _slicks . Count * 2 + 1 ) ;
2020-06-07 00:20:28 +08:00
if ( Effect = = CarouselEffect . ScrollX )
2020-05-06 17:33:11 +08:00
{
2020-06-11 23:24:58 +08:00
if ( IsHorizontal )
{
_trackStyle = $"width: {_totalWidth}px; opacity: 1; transform: translate3d(-{_slickWidth}px, 0px, 0px); transition: -webkit-transform 500ms ease 0s;" ;
}
else
{
_trackStyle = $"height: {_totalHeight}px; opacity: 1; transform: translate3d(0px, -{_slickHeight}px, 0px); transition: -webkit-transform 500ms ease 0s;" ;
}
2020-05-06 17:33:11 +08:00
}
else
{
2020-06-11 23:24:58 +08:00
if ( IsHorizontal )
{
_trackStyle = $"width: {_totalWidth}px; opacity: 1;" ;
}
else
{
_trackStyle = $"height: {_totalHeight}px; opacity: 1;" ;
}
2020-05-06 17:33:11 +08:00
}
2020-06-11 23:24:58 +08:00
_slickListStyle = IsHorizontal ? string . Empty : $"height: {_slickHeight}px" ;
2020-05-06 17:33:11 +08:00
_slickClonedStyle = $"width: {_slickWidth}px;" ;
2020-06-11 23:24:58 +08:00
Activate ( _slicks . IndexOf ( _activeSlick ) ) ;
2020-05-06 17:33:11 +08:00
StateHasChanged ( ) ;
}
}
2020-06-07 00:20:28 +08:00
internal void AddSlick ( CarouselSlick slick )
2020-05-06 17:33:11 +08:00
{
_slicks . Add ( slick ) ;
if ( _activeSlick = = null )
{
Activate ( 0 ) ;
}
}
private int Activate ( int index , string transition = " transition: -webkit-transform 500ms ease 0s;" )
{
2020-06-07 00:20:28 +08:00
if ( Effect = = CarouselEffect . ScrollX )
2020-05-06 17:33:11 +08:00
{
2020-06-11 23:24:58 +08:00
if ( IsHorizontal )
{
_trackStyle = $"width: {_totalWidth}px; opacity: 1; transform: translate3d(-{_slickWidth * (index + 1)}px, 0px, 0px);{transition}" ;
}
else
{
_trackStyle = $"height: {_totalHeight}px; opacity: 1; transform: translate3d(0px, -{_slickHeight * (index + 1)}px, 0px);{transition}" ;
}
2020-05-06 17:33:11 +08:00
}
if ( index = = _slicks . Count )
{
index = 0 ;
}
2020-06-07 00:20:28 +08:00
CarouselSlick slick = _slicks [ index ] ;
2020-05-06 17:33:11 +08:00
_slicks . ForEach ( s = >
{
if ( s = = slick )
{
_activeSlick = s ;
s . Activate ( ) ;
}
else
{
s . Deactivate ( ) ;
}
} ) ;
return index ;
}
private async void AutoplaySlick ( object state )
{
int newIndex = _slicks . IndexOf ( _activeSlick ) + 1 ;
int realIndex = Activate ( newIndex ) ;
// The current thread is not associated with the Dispatcher.
// Use InvokeAsync() to switch execution to the Dispatcher when triggering rendering or component state
await InvokeAsync ( ( ) = > StateHasChanged ( ) ) ;
2020-06-07 00:20:28 +08:00
if ( realIndex = = 0 & & Effect = = CarouselEffect . ScrollX )
2020-05-06 17:33:11 +08:00
{
Thread . Sleep ( ( int ) Autoplay . TotalMilliseconds / 2 ) ;
2020-06-11 23:24:58 +08:00
if ( IsHorizontal )
{
_trackStyle = $"width: {_totalWidth}px; opacity: 1; transform: translate3d(-{_slickWidth}px, 0px, 0px);" ;
}
else
{
_trackStyle = $"height: {_totalHeight}px; opacity: 1; transform: translate3d(0px, -{_slickHeight}px, 0px);" ;
}
2020-05-06 17:33:11 +08:00
}
await InvokeAsync ( ( ) = > StateHasChanged ( ) ) ;
}
}
}