File

projects/rebirth-ng/src/lib/slider/slider.component.ts

Implements

AfterViewInit OnInit OnDestroy ControlValueAccessor

Metadata

changeDetection ChangeDetectionStrategy.OnPush
exportAs slider
providers { : , : (() => ), : true }
selector re-slider
styleUrls slider.component.scss
templateUrl ./slider.component.html

Index

Properties
Methods
Inputs
Outputs
HostListeners

Constructor

constructor(changeDetectorRef: ChangeDetectorRef, rebirthNGConfig: RebirthNGConfig, documentRef: DocumentRef, windowRef: WindowRef)
Parameters :
Name Type Optional
changeDetectorRef ChangeDetectorRef no
rebirthNGConfig RebirthNGConfig no
documentRef DocumentRef no
windowRef WindowRef no

Inputs

max
min

Outputs

onChange $event type: EventEmitter<number>

HostListeners

window:resize
window:resize()

Methods

Private calcHandleOffset
calcHandleOffset()
Returns : void
Private calcValueWhenMove
calcValueWhenMove(event: MouseEvent)
Parameters :
Name Type Optional
event MouseEvent no
Returns : void
Private changeValue
changeValue(newValue: )
Parameters :
Name Optional
newValue no
Returns : void
ngAfterViewInit
ngAfterViewInit()
Returns : void
ngOnDestroy
ngOnDestroy()
Returns : void
ngOnInit
ngOnInit()
Returns : void
Public onOperateValue
onOperateValue(value: number)
Parameters :
Name Type Optional
value number no
Returns : void
Public onSliderClick
onSliderClick(event: )
Parameters :
Name Optional
event no
Returns : void
Public operateValue
operateValue(value: number)
Parameters :
Name Type Optional
value number no
Returns : void
registerOnChange
registerOnChange(fn: any)
Parameters :
Name Type Optional
fn any no
Returns : void
registerOnTouched
registerOnTouched(fn: any)
Parameters :
Name Type Optional
fn any no
Returns : void
writeValue
writeValue(value: number)
Parameters :
Name Type Optional
value number no
Returns : void

Properties

Private complete$
complete$:
Default value : new Subject<void>()
dot
dot: ElementRef
Type : ElementRef
Decorators : ViewChild
handleOffset
handleOffset: number
Type : number
Default value : 0
Private offset
offset: number
Type : number
Private onTouched
onTouched:
Default value : () => null
Private onValueChange
onValueChange:
Default value : (_: any) => null
slider
slider: ElementRef
Type : ElementRef
Decorators : ViewChild
Private stepWidth
stepWidth: number
Type : number
value
value: number
Type : number
Default value : 0
import {
  Component,
  ChangeDetectorRef,
  ChangeDetectionStrategy,
  forwardRef,
  AfterViewInit,
  ViewChild,
  ElementRef,
  OnDestroy,
  OnInit,
  Input,
  Output,
  EventEmitter,
  HostListener
} from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';

import { Subject, fromEvent } from 'rxjs';
import { switchMap, take, takeUntil } from 'rxjs/operators';
import { RebirthNGConfig } from '../rebirth-ng.config';
import { DocumentRef } from '../window-ref/document-ref.service';
import { WindowRef } from '../window-ref/window-ref.service';

@Component({
  selector: 're-slider',
  templateUrl: './slider.component.html',
  styleUrls: ['./slider.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush,
  exportAs: 'slider',
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => SliderComponent),
      multi: true
    }
  ]
})
export class SliderComponent implements AfterViewInit, OnInit, OnDestroy, ControlValueAccessor {
  @ViewChild('sliderDot') dot: ElementRef;
  @ViewChild('slider') slider: ElementRef;
  @Output() onChange: EventEmitter<number> = new EventEmitter<number>();

  handleOffset = 0;

  @Input() max;
  @Input() min;
  private offset: number;
  private stepWidth: number;

  value = 0;

  private complete$ = new Subject<void>();

  private onValueChange = (_: any) => null;
  private onTouched = () => null;

  constructor(private changeDetectorRef: ChangeDetectorRef,
              private rebirthNGConfig: RebirthNGConfig,
              private documentRef: DocumentRef,
              private windowRef: WindowRef) {
    this.max = rebirthNGConfig.slider.max;
    this.min = rebirthNGConfig.slider.min;
  }

  ngOnInit() {
    this.offset = this.max - this.min;
  }

  ngOnDestroy() {
    this.complete$.complete();
  }

  ngAfterViewInit() {
    this.stepWidth = this.windowRef.getOffsetWidth(this.slider) / this.offset;

    const mousedown$ = fromEvent(this.dot.nativeElement, 'mousedown');
    const mousemove$ = fromEvent(this.documentRef.document, 'mousemove');
    const mouseup$ = fromEvent(this.documentRef.document, 'mouseup');

    mousedown$
      .pipe(
        switchMap(() => {
          this.onTouched();
          return mousemove$.pipe(takeUntil(mouseup$));
        }),
        takeUntil(this.complete$)
      )
      .subscribe((event: MouseEvent) => {
        event.preventDefault();
        this.calcValueWhenMove(event);
        this.changeDetectorRef.markForCheck();
      });

    mousedown$
      .pipe(
        switchMap(() => {
          this.onTouched();
          return mouseup$.pipe(take(1));
        }),
        takeUntil(this.complete$)
      )
      .subscribe((event: MouseEvent) => {
        event.preventDefault();
        this.calcValueWhenMove(event);

        this.calcHandleOffset();
        this.changeDetectorRef.markForCheck();
      });
  }

  @HostListener('window:resize')
  onResize() {
    this.stepWidth = this.windowRef.getOffsetWidth(this.slider) / this.offset;
    this.calcHandleOffset();
  }

  public onSliderClick(event) {
    this.calcValueWhenMove(event);
  }

  public onOperateValue(value: number): void {
    this.onTouched();
    this.operateValue(value);
  }

  public operateValue(value: number): void {
    this.changeValue(value);
    this.calcHandleOffset();
  }

  private calcHandleOffset(): void {
    this.handleOffset = this.value * this.stepWidth;
  }

  private calcValueWhenMove(event: MouseEvent): void {
    const rect = this.windowRef.getBoundingClientRect(this.slider)// IE >= 9
    const mouseRelativeSliderOffsetX = event.clientX - rect.left;
    const fixedOffsetX = Math.max(Math.min(mouseRelativeSliderOffsetX, rect.width), 0);

    this.handleOffset = fixedOffsetX;

    this.changeValue(Math.round(fixedOffsetX / this.stepWidth));
  }

  private changeValue(newValue): void {
    const fixedValue = Math.max(Math.min(newValue, this.max), 0);
    if (fixedValue === this.value) {
      return;
    }
    this.value = fixedValue;
    const outSideValue = fixedValue + this.min;
    this.onValueChange(outSideValue);
    this.onChange.emit(outSideValue);
  }

  writeValue(value: number) {
    const sideValue = value ? value - this.min : this.min;
    this.operateValue(sideValue);
    this.changeDetectorRef.markForCheck();
  }

  registerOnChange(fn: any) {
    this.onValueChange = fn;
  }

  registerOnTouched(fn: any) {
    this.onTouched = fn;
  }
}
<div class="slider-body">
  <div class="slider-container">
    <div #slider class="slider">
      <div class="base-line" (click)="onSliderClick($event)">
        <div class="active-line" [style.width.px]="handleOffset"></div>
      </div>
    </div>

    <div #sliderDot [style.left.px]="handleOffset" class="handle" [attr.title]="value"></div>
  </div>

  <div class="slider-operator-container">
    <button class="btn reduce" (click)="onOperateValue(value - 1)">-</button>
    <button class="btn plus" (click)="onOperateValue(value + 1)">+</button>
  </div>
</div>
Legend
Html element
Component
Html element with directive

results matching ""

    No results matching ""