diff --git a/src/app/components/results-menu/timeseries-results-menu/timeseries-results-menu.component.ts b/src/app/components/results-menu/timeseries-results-menu/timeseries-results-menu.component.ts index 49ec9512c..e01f20a8c 100644 --- a/src/app/components/results-menu/timeseries-results-menu/timeseries-results-menu.component.ts +++ b/src/app/components/results-menu/timeseries-results-menu/timeseries-results-menu.component.ts @@ -123,7 +123,7 @@ export class TimeseriesResultsMenuComponent implements OnInit, OnDestroy { this.chartStates = Object.values(chartStates); } )); - + this.subs.add( this.temporalRangeValues$.subscribe( range => { @@ -148,7 +148,6 @@ export class TimeseriesResultsMenuComponent implements OnInit, OnDestroy { if (thing && thing.length > 0) { let previous_points: any[] = thing?.split(';'); if (previous_points.length > 0) { - // console.log(previous_points) previous_points = previous_points?.map(value => { return this.wktService.wktToFeature(value, 'EPSG:4326'); }) @@ -215,13 +214,9 @@ export class TimeseriesResultsMenuComponent implements OnInit, OnDestroy { allPointsData.push(data); // this.chartData.next(allPointsData); this.temporalRange = this.getMaxRange(allPointsData); - console.log('updateChart dataDateMin, dataDateMax', this.dataDateMin, this.dataDateMax); - console.log('updateChart allPointsData', allPointsData); }) } this.maxRange = this.getMaxRange(allPointsData); - console.log('updateChart dataDateMin, dataDateMax', this.dataDateMin, this.dataDateMax); - console.log('updateChart allPointsData', allPointsData); } readonly task = signal({ @@ -246,10 +241,7 @@ export class TimeseriesResultsMenuComponent implements OnInit, OnDestroy { let maxDate = null; for (let points of allSeries) { for (let key of Object.keys(points).filter(x => x !== 'mean' && x !== 'aoi')) { - console.log('getMaxRange key', key); - console.log('getMaxRange points[key]', points[key]); let date = new Date(points[key].secondary_datetime); - console.log('getMaxRange date', date); if (minDate === null || date < minDate) { minDate = date; } @@ -260,7 +252,6 @@ export class TimeseriesResultsMenuComponent implements OnInit, OnDestroy { } let dateRange: models.Range = {start: minDate, end: maxDate}; this.temporalRangeValues$.next([dateRange.start, dateRange.end]); - console.log('getMaxRange dateRange', dateRange); return dateRange; } @@ -271,7 +262,6 @@ export class TimeseriesResultsMenuComponent implements OnInit, OnDestroy { this.store$.dispatch(chartStore.setTimeseriesChecked({wkt, checked})) } public deletePoint(index: number) { - console.log('delete', index); this.pointHistoryService.removePoint(index); } ngOnDestroy() { diff --git a/src/app/components/timeseries-chart/timeseries-chart-temporal-slider/timeseries-chart-temporal-slider.component.ts b/src/app/components/timeseries-chart/timeseries-chart-temporal-slider/timeseries-chart-temporal-slider.component.ts index 7331e2edd..111d51fcd 100644 --- a/src/app/components/timeseries-chart/timeseries-chart-temporal-slider/timeseries-chart-temporal-slider.component.ts +++ b/src/app/components/timeseries-chart/timeseries-chart-temporal-slider/timeseries-chart-temporal-slider.component.ts @@ -1,4 +1,4 @@ -import {Component, ElementRef, ViewChild, OnInit} from '@angular/core'; +import {Component, ElementRef, ViewChild, OnInit, OnDestroy} from '@angular/core'; import * as noUiSlider from 'nouislider'; import { Store } from "@ngrx/store"; import { AppState } from "@store"; @@ -11,6 +11,10 @@ import {SubSink} from "subsink"; // import wNumb from 'wnumb'; import * as filtersStore from '@store/filters'; import * as models from '@models'; +// import moment from 'moment/moment'; +import {Observable, Subject} from 'rxjs'; +import {debounceTime, distinctUntilChanged} from 'rxjs/operators'; +// import {debounceTime, distinctUntilChanged} from 'rxjs/operators'; @Component({ selector: 'app-timeseries-chart-temporal-slider', @@ -18,34 +22,71 @@ import * as models from '@models'; templateUrl: './timeseries-chart-temporal-slider.component.html', styleUrls: ['./timeseries-chart-temporal-slider.component.scss'] }) -export class TimeseriesChartTemporalSliderComponent implements OnInit { +export class TimeseriesChartTemporalSliderComponent implements OnInit, OnDestroy { @ViewChild('ts_slider', { static: true }) sliderRef: ElementRef; private subs = new SubSink(); - public slider; - public maxRange: models.Range = {start: Date.now.valueOf(), end: Date.now.valueOf()}; - // private firstLoad = true; - - + public tsSlider: noUiSlider.API; + public timeSeriesSlider: any; + public maxRange: models.Range = {start: 0, end: 100}; + public lastMaxRange: models.Range = {start: 0, end: 100}; + public selectedRange: models.Range = {start: 0, end: 100}; + public startDate$ = this.store$.select(filtersStore.getStartDate); + public endDate$ = this.store$.select(filtersStore.getEndDate); + public startDate: Date = new Date(); + public endDate: Date = new Date(); constructor( private store$: Store ){} ngOnInit() { + + this.timeSeriesSlider = this.makeTimeSeriesSlider(this.sliderRef); + this.tsSlider = this.timeSeriesSlider.slider; + this.subs.add( this.store$.select(filtersStore.getTemporalRange).subscribe( temp => { - this.maxRange = {start: temp.start, end: temp.end}; - console.log('timeseries-chart-temporal-slider', this.maxRange); - if (this.slider) { this.slider.destroy(); } - this.makeDaysSlider(this.sliderRef); + if (!temp.start || !temp.end) { return; } + this.maxRange = {start: temp.start.valueOf(), end: temp.end.valueOf()}; + if (this.lastMaxRange.start !== this.maxRange.start || this.lastMaxRange.end !== this.maxRange.end) { + this.lastMaxRange.start = this.maxRange.start; + this.lastMaxRange.end = this.maxRange.end; + + this.sliderRef.nativeElement.noUiSlider.updateOptions({ + start: [this.maxRange.start, this.maxRange.end], + range: { + 'min': this.maxRange.start, + 'max': this.maxRange.end + } + }); + } + } + ) + ); + + this.subs.add( + this.timeSeriesSlider.values$.subscribe( + ([start, end]) => { + if (!start || !end) { return; } + if (start === this.selectedRange.start && end === this.selectedRange.end) { + return; + } + this.selectedRange = {start: start, end: end}; + this.sliderRef.nativeElement.noUiSlider.updateOptions({ + start: [this.selectedRange.start, this.selectedRange.end] + }); + const action = new filtersStore.SetStartDate(new Date(start)); + this.store$.dispatch(action); + const action2 = new filtersStore.SetEndDate(new Date(end)); + this.store$.dispatch(action2); } ) ); - // this.makeDaysSlider(this.sliderRef); + } private timestamp(str) { @@ -55,7 +96,6 @@ export class TimeseriesChartTemporalSliderComponent implements OnInit { // Create a string representation of the date. public formatDate(date: any) :string { let fDateStr = date.toLocaleDateString() - console.log('date, formatDate', date, fDateStr); return ( fDateStr ); } @@ -64,19 +104,28 @@ export class TimeseriesChartTemporalSliderComponent implements OnInit { return new Date(value).toLocaleDateString(); } - public makeDaysSlider(filterRef: ElementRef): void { + // private toJSDate(date: moment.Moment) { + // return date.toDate(); + // } + + // private isNumber(x: any): x is number { + // return typeof x === "number"; + // } + + public makeTimeSeriesSlider(filterRef: ElementRef): { slider: noUiSlider.API; values$: Observable } { const self = this; + const values$ = new Subject(); // Steps of one day const increment = 24 * 60 * 60 * 1000; - this.slider = noUiSlider.create(filterRef.nativeElement, { - start: [this.maxRange.start.valueOf(), this.maxRange.end.valueOf()], + const slider = noUiSlider.create(filterRef.nativeElement, { + start: [1, 100], behaviour: 'tap-drag', tooltips: [{to: (d) => self.toFormat(d)}, {to: (d) => self.toFormat(d)}], connect: true, step: increment, range: { - 'min': this.maxRange.start.valueOf(), - 'max': this.maxRange.end.valueOf() + 'min': 1, + 'max': 100 }, pips: { // @ts-ignore @@ -90,6 +139,19 @@ export class TimeseriesChartTemporalSliderComponent implements OnInit { } }, }); + + slider.on('update', (values: any[], _: any) => { + values$.next(values.map(v => +v)); + }); + + return { + slider, + values$: values$.asObservable().pipe( + debounceTime(500), + distinctUntilChanged() + ) + }; + } ngOnDestroy(){ diff --git a/src/app/components/timeseries-chart/timeseries-chart.component.ts b/src/app/components/timeseries-chart/timeseries-chart.component.ts index be27bcbef..153a0eedd 100644 --- a/src/app/components/timeseries-chart/timeseries-chart.component.ts +++ b/src/app/components/timeseries-chart/timeseries-chart.component.ts @@ -2,11 +2,12 @@ import { Component, ElementRef, Input, OnDestroy, OnInit, ViewChild } from '@ang import * as d3 from 'd3'; // import * as models from '@models'; -import { debounceTime, Observable, withLatestFrom, - // Subject +import { debounceTime, Observable, withLatestFrom, + // Subject } from 'rxjs'; import { Store } from '@ngrx/store'; +import * as filtersStore from '@store/filters'; import { AppState } from '@store'; // import * as sceneStore from '@store/scenes'; import * as chartsStore from '@store/charts'; @@ -73,7 +74,12 @@ export class TimeseriesChartComponent implements OnInit, OnDestroy { private lineLabels; private points; public gColorPalette: any; - + public startDate: Date = new Date(); + public endDate: Date = new Date(); + public lastStartDate: Date = new Date(); + public lastEndDate: Date = new Date(); + + // private selectedScene: string; @Input() isLoading: boolean = false; @@ -100,8 +106,6 @@ export class TimeseriesChartComponent implements OnInit, OnDestroy { ) ) - - this.subs.add( this.netcdfService.cacheUpdated.pipe( debounceTime(1000), @@ -109,12 +113,12 @@ export class TimeseriesChartComponent implements OnInit, OnDestroy { ).subscribe(([_updated_id, chartStates]) => { this.refreshChart(chartStates); })); - + this.subs.add( this.store$.select(chartsStore.getTimeseriesChartStates).subscribe( chartStates => { this.refreshChart(chartStates); - } + } ) ); @@ -131,7 +135,7 @@ export class TimeseriesChartComponent implements OnInit, OnDestroy { this.initChart(this.data); } ) - ) + ); this.subs.add( this.language.translate.onLangChange.subscribe(() => { @@ -142,7 +146,31 @@ export class TimeseriesChartComponent implements OnInit, OnDestroy { } ) ); + + this.subs.add( + this.store$.select(filtersStore.getStartDate).subscribe( + start => { + this.startDate = start; + if (this.lastStartDate !== this.startDate) { + this.lastStartDate = this.startDate; + this.initChart(this.data); } + } + ) + ); + + this.subs.add( + this.store$.select(filtersStore.getEndDate).subscribe( + end => { + this.endDate = end; + if (this.lastEndDate !== this.endDate) { + this.lastEndDate = this.endDate; + this.initChart(this.data); } + } + ) + ); + } + private refreshChart(chartStates: {[key: string]: models.timeseriesChartItemState}): void { const cache = this.netcdfService.getCache() const allPointsData: {point: {}, state: models.timeseriesChartItemState}[] = Object.keys(chartStates).map( @@ -151,6 +179,7 @@ export class TimeseriesChartComponent implements OnInit, OnDestroy { this.data = allPointsData; this.initChart(this.data) } + public translateChartText() { this.xAxisTitle = this.language.translate.instant('SCENE') + ' ' + this.language.translate.instant('DATE'); @@ -191,9 +220,11 @@ export class TimeseriesChartComponent implements OnInit, OnDestroy { aoi = result.point[key]; } } - + this.timeSeriesData = []; for (let key of Object.keys(result.point).filter(x => x !== 'mean' && x !== 'aoi')) { + let daDate = new Date(result.point[key].secondary_datetime).valueOf(); + if (daDate < this.startDate.valueOf() || daDate > this.endDate.valueOf()) { continue; } this.dataSource.push({ 'aoi': aoi, 'short_wavelength_displacement': result.point[key].short_wavelength_displacement, @@ -450,13 +481,11 @@ export class TimeseriesChartComponent implements OnInit, OnDestroy { } private pointerEntered(lines, dots) { - console.log('pointerEntered lines, dots', lines, dots); lines.style("mix-blend-mode", null).style("stroke", unSelectedColor); dots.attr("display", null); } - private pointerLeft(lines, dots) { - console.log('pointerLeft', lines, dots); + private pointerLeft(lines, _dots) { let colorName: string; let dClassName: string; lines.style("stroke", (d: DataReady)=> {