File

projects/onto-search/src/lib/onto-search-facet/range-facet/range-slider/range-slider.component.ts

Metadata

selector onto-range-slider
styleUrls range-slider.component.scss
templateUrl range-slider.component.html

Inputs

data

Type: SearchRangeFacetGroupModel

Outputs

selectionChange $event type: EventEmitter<any>

Methods

onResize
onResize()
Returns: void
draw
draw(splitvalue: number)
Returns: void
init
init()
Returns: void
update
update(rangemax: number)
Returns: void
Private sumRange
sumRange()
Returns: number
Public onSelectionChange
onSelectionChange()
Returns: void
Private updateSelection
updateSelection()
Returns: void
Private isInRange
isInRange(facet: SearchFacetModel)
Returns: boolean
Private parseInt
parseInt(value: string)
Returns: number

Properties

Private facetData
facetData: SearchFacetModel[]
Public maxElement
maxElement: any
Public maxSlider
maxSlider: any
Public maxValue
maxValue: any
Public minElement
minElement: any
Public minSlider
minSlider: any
Public minValue
minValue: any
Public selectedMax
selectedMax: any
Public selectedMin
selectedMin: any
Public slider
slider: any
Public sum
sum: number
Private thumbsize
thumbsize: number
Default value: 14
import {
  AfterViewInit,
  Component,
  ElementRef,
  EventEmitter,
  HostListener,
  Input, OnDestroy,
  OnInit,
  Output,
  ViewChild
} from '@angular/core';
import {SearchFacetModel} from '../../models/search-facet-model';
import {SelectedRange} from '../models/selected-range';
import {SearchRangeFacetGroupModel} from '../models/search-range-facet-group-model';

@Component({
  selector: 'onto-range-slider',
  templateUrl: './range-slider.component.html',
  styleUrls: ['./range-slider.component.scss']
})
export class RangeSliderComponent implements OnInit, AfterViewInit, OnDestroy {
  @Input()
  public data: SearchRangeFacetGroupModel;

  @ViewChild('minMaxSlider')
  public slider: ElementRef;
  @ViewChild('minSlider')
  public minSlider: ElementRef;
  @ViewChild('maxSlider')
  public maxSlider: ElementRef;

  @Output()
  public selectionChange: EventEmitter<any> = new EventEmitter<any>();

  @HostListener('window:resize', ['$event'])
  onResize(): void {}

  private facetData: SearchFacetModel[];
  public sum: number;

  private thumbsize = 14;
  public minValue;
  public maxValue;
  public selectedMin;
  public selectedMax;
  public minElement;
  public maxElement;

  ngOnInit(): void {
    this.facetData = [...this.data.facetGroupData];
    this.facetData.sort((a, b) => {
      try {
        return this.parseInt(a.label) - this.parseInt(b.label);
      } catch (e) {
        throw new Error('Facet labels must represent numbers! ' + e.message);
      }
    });

    this.minValue = this.facetData[0].label;
    this.maxValue = this.facetData[this.facetData.length - 1].label;

    this.selectedMin = this.minValue;
    this.selectedMax = this.maxValue;

    this.sum = this.sumRange();
    this.updateSelection();
  }

  public ngAfterViewInit(): void {
    this.minElement = this.minSlider.nativeElement;
    this.maxElement = this.maxSlider.nativeElement;

    this.init();
    this.onResize = (): void => this.update(this.parseInt(this.maxElement.getAttribute('max')));
  }

  draw(splitvalue: number): void {
    const thumbsize: any = this.parseInt(this.slider.nativeElement.getAttribute('data-thumbsize'));
    const rangewidth = this.slider.nativeElement.clientWidth;

    const rangemin = this.parseInt(this.slider.nativeElement.getAttribute('data-rangemin'));
    const rangemax = this.parseInt(this.slider.nativeElement.getAttribute('data-rangemax'));

    this.minElement.setAttribute('max', splitvalue);
    this.maxElement.setAttribute('min', splitvalue);

    this.minElement.style.width = this.parseInt(thumbsize + ((splitvalue - rangemin) / (rangemax - rangemin)) * (rangewidth - (2 * thumbsize))) + 'px';
    this.maxElement.style.width = this.parseInt(thumbsize + ((rangemax - splitvalue) / (rangemax - rangemin)) * (rangewidth - (2 * thumbsize))) + 'px';
    this.minElement.style.left = '0px';
    this.maxElement.style.left = this.parseInt(this.minElement.style.width) + 'px';

    // correct for 1 off at the end of the max slider
    if (this.maxElement.value > (rangemax - 1)) {
      this.maxElement.setAttribute('data-value', rangemax);
    }

    this.maxElement.value = this.maxElement.getAttribute('data-value');
    this.minElement.value = this.minElement.getAttribute('data-value');
  }

  init(): void {
    this.minElement.removeEventListener('input', () => this.update);
    this.maxElement.removeEventListener('input', () => this.update);

    const rangemin: any = this.parseInt(this.minElement.getAttribute('min'));
    const rangemax: any = this.parseInt(this.maxElement.getAttribute('max'));
    const avgvalue = (rangemin + rangemax) / 2;

    this.minElement.setAttribute('data-value', rangemin);
    this.maxElement.setAttribute('data-value', rangemax);

    this.slider.nativeElement.setAttribute('data-rangemin', rangemin);
    this.slider.nativeElement.setAttribute('data-rangemax', rangemax);
    this.slider.nativeElement.setAttribute('data-thumbsize', this.thumbsize);
    this.slider.nativeElement.setAttribute('data-rangewidth', this.slider.nativeElement.offsetWidth);

    this.draw(avgvalue);

    this.minElement.addEventListener('input', () => this.update(rangemax));
    this.maxElement.addEventListener('input', () => this.update(rangemax));
  }

  update(rangemax: number): void {
    // correction for min value calculation
    let minvalue;
    if (this.minElement.value > (rangemax - 1)) {
      minvalue = Math.floor(this.minElement.value - 1);
    } else {
      minvalue = Math.floor(this.minElement.value);
    }

    // correction for max value calculation
    let maxvalue;
    if (this.maxElement.value > (rangemax - 1)) {
      maxvalue = Math.ceil(this.maxElement.value);
    } else {
      maxvalue = Math.floor(this.maxElement.value);
    }

    this.minElement.setAttribute('data-value', minvalue);
    this.maxElement.setAttribute('data-value', maxvalue);

    this.selectedMin = minvalue;
    this.selectedMax = maxvalue;

    this.updateSelection();
    this.sum = this.sumRange();

    const avgvalue = Math.ceil((minvalue + maxvalue) / 2);
    this.draw(avgvalue);
  }


  private sumRange(): number {
    let sum = 0;
    this.data.facetGroupData.forEach((facet) => {
      if (this.isInRange(facet)) {
        sum += facet.count;
      }
    });
    return sum;
  }

  public onSelectionChange(): void {
    this.selectionChange.emit(this.data.selectedRange);
  }

  private updateSelection(): void {
    this.data.selectedRange = {
      start: this.selectedMin,
      end: this.selectedMax
    } as SelectedRange;
    this.onSelectionChange();
  }

  private isInRange(facet: SearchFacetModel): boolean {
    const value = this.parseInt(facet.label);
    return value >= this.parseInt(this.selectedMin) && value <= this.parseInt(this.selectedMax);
  }

  private parseInt(value: string): number {
    try {
      return parseInt(value);
    } catch (e) {
      throw new Error(`Parsing ${value} to number failed! ` + e.message);
    }
  }

  public ngOnDestroy(): void {
    this.onResize = function(): void {};
    this.minElement.removeEventListener('input', () => this.update);
    this.maxElement.removeEventListener('input', () => this.update);
  }
}

results matching ""

    No results matching ""