Skip to content

Commit

Permalink
Merge remote-tracking branch 'Discovery-SearchUI/displacement' into a…
Browse files Browse the repository at this point in the history
…ndy/DS-5552-Multiline-ASF-2
  • Loading branch information
artisticlight committed Nov 13, 2024
2 parents 16a684d + 4c43ab3 commit 0b65eb3
Show file tree
Hide file tree
Showing 17 changed files with 186 additions and 74 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
<li>
<mat-checkbox [checked]="point.checked"
(change)="updateSeries($event.checked, $index)">
<mat-icon class="ts-wkt-icon">place</mat-icon>
<mat-icon class="ts-wkt-icon" [style.color]="point.color">place</mat-icon>
<span class="ts-wkt-label">
{{'SERIES' | translate}} {{point.seriesNumber}}
</span>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@
</button>
</div>
<mat-menu #menu="matMenu">
<div class="chart-config-menu-panel" [ngSwitch]="searchType" (click)="$event.stopPropagation()">
<app-timeseries-chart-config *ngSwitchCase="SearchTypes.DISPLACEMENT"></app-timeseries-chart-config>
<app-timeseries-chart-config *ngSwitchDefault></app-timeseries-chart-config>
<div class="chart-config-menu-panel" (click)="$event.stopPropagation()">
<app-timeseries-chart-config (resetReferenceEvent)="onResetReference()"></app-timeseries-chart-config>
</div>
</mat-menu>
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Component, OnDestroy, OnInit } from '@angular/core';
import { Component, OnDestroy, OnInit, Output, EventEmitter } from '@angular/core';
import { MatDialog, MatDialogModule } from '@angular/material/dialog';
import { MatIconModule } from '@angular/material/icon'
import { MatButtonModule } from '@angular/material/button'
Expand Down Expand Up @@ -31,6 +31,7 @@ export class ChartModalComponent implements OnInit, OnDestroy {
private subs = new SubSink()
public searchType: SearchType;
public SearchTypes = SearchType;
@Output() public resetReferenceEvent = new EventEmitter();

constructor(public dialog: MatDialog,
private $store: Store<AppState>,
Expand All @@ -42,6 +43,9 @@ export class ChartModalComponent implements OnInit, OnDestroy {
searchtype => this.searchType = searchtype
))
}
public onResetReference() {
this.resetReferenceEvent.emit();
}

ngOnDestroy(): void {
this.subs.unsubscribe()
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
<mat-checkbox (change)="onToggleLines($event)" [checked]="showLines">Show Lines</mat-checkbox>
<div style="display: flex; flex-direction: column;">
<mat-checkbox (change)="onToggleLines($event)" [checked]="showLines">Show Lines</mat-checkbox>
<button mat-button (click)="resetReference()">Reset chart reference</button>
</div>
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Component, OnDestroy, OnInit } from '@angular/core';
import { Component, OnDestroy, OnInit, Output, EventEmitter } from '@angular/core';
import { MatIconModule } from '@angular/material/icon';
import { MatButtonModule } from '@angular/material/button';
import { MatCheckboxChange, MatCheckboxModule } from '@angular/material/checkbox';
Expand All @@ -18,7 +18,7 @@ import * as chartsStore from '@store/charts'
export class TimeseriesChartConfigComponent implements OnInit, OnDestroy {
private subs = new SubSink()
public showLines: boolean = true

@Output() public resetReferenceEvent = new EventEmitter();
constructor(private store$: Store<AppState>) { }

public onToggleLines(event: MatCheckboxChange) {
Expand All @@ -36,6 +36,10 @@ export class TimeseriesChartConfigComponent implements OnInit, OnDestroy {
);
}

public resetReference() {
this.resetReferenceEvent.emit();
}

ngOnDestroy(): void {
this.subs.unsubscribe()
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<div #tsChartWrapper class="chart-wrapper" (resized)="onResized()">
<div #timeseriesChart id="timeseriesChart">
<div #timeseriesChart id="timeseriesChart" [contextMenuTriggerFor]="menu" [contextMenuTriggerData]="{'tooltipData': hoveredData}">
</div>
<app-chart-modal class="ts-chart-config-button"></app-chart-modal>
<app-chart-modal class="ts-chart-config-button" (resetReferenceEvent)="resetBasePoint()"></app-chart-modal>
<app-timeseries-chart-zoom class="ts-chart-zoom" (zoomInEvent)="onZoomIn()" (zoomOutEvent)="onZoomOut()"
(zoomToFitEvent)="onZoomToFit()"></app-timeseries-chart-zoom>

Expand All @@ -10,4 +10,10 @@
<mat-spinner></mat-spinner>
</div>
}
<mat-menu #menu="matMenu">
<ng-template matMenuContent let-tooltipData="tooltipData">
<button mat-button (click)="setReference(tooltipData)">Set as Reference</button>

</ng-template>
</mat-menu>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -54,5 +54,6 @@
top: 17px;
right: 95px;
}


:host ::ng-deep .ts-reference-point {
fill: red !important;
}
81 changes: 49 additions & 32 deletions src/app/components/timeseries-chart/timeseries-chart.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import { Component, ElementRef, Input, OnDestroy, OnInit, ViewChild } from '@ang

import * as d3 from 'd3';
// import * as models from '@models';
import { debounceTime, Observable, withLatestFrom,
import {
debounceTime, Observable, withLatestFrom,
// Subject
} from 'rxjs';

Expand All @@ -20,7 +21,10 @@ import * as models from '@models';
interface TimeSeriesData {
short_wavelength_displacement: number
date: string,
id: string,
base: number,
seriesNumber: number,
color: string,
}

interface DataReady {
Expand Down Expand Up @@ -69,10 +73,10 @@ export class TimeseriesChartComponent implements OnInit, OnDestroy {
public margin = { top: 10, right: 30, bottom: 60, left: 55 };
private thing: d3.Selection<SVGGElement, {}, HTMLElement, any>
private hoveredElement;
public hoveredData;
private data: any;
private lines;
private points;
public gColorPalette: any;
public startDate: Date = new Date();
public endDate: Date = new Date();
public lastStartDate: Date = new Date();
Expand All @@ -87,8 +91,9 @@ export class TimeseriesChartComponent implements OnInit, OnDestroy {
private yAxisTitle = '';

private subs = new SubSink();
private allGroup: string[];
// private allGroup: string[];

private baseData: TimeSeriesData;
constructor(
private store$: Store<AppState>,
private language: AsfLanguageService,
Expand All @@ -110,8 +115,8 @@ export class TimeseriesChartComponent implements OnInit, OnDestroy {
debounceTime(1000),
withLatestFrom(this.store$.select(chartsStore.getTimeseriesChartStates))
).subscribe(([_updated_id, chartStates]) => {
this.refreshChart(chartStates);
}));
this.refreshChart(chartStates);
}));

this.subs.add(
this.store$.select(chartsStore.getTimeseriesChartStates).subscribe(
Expand Down Expand Up @@ -152,7 +157,8 @@ export class TimeseriesChartComponent implements OnInit, OnDestroy {
this.startDate = start;
if (this.lastStartDate !== this.startDate) {
this.lastStartDate = this.startDate;
this.initChart(this.data); }
this.initChart(this.data);
}
}
)
);
Expand All @@ -163,17 +169,18 @@ export class TimeseriesChartComponent implements OnInit, OnDestroy {
this.endDate = end;
if (this.lastEndDate !== this.endDate) {
this.lastEndDate = this.endDate;
this.initChart(this.data); }
this.initChart(this.data);
}
}
)
);

}

private refreshChart(chartStates: {[key: string]: models.timeseriesChartItemState}): void {
private refreshChart(chartStates: { [key: string]: models.timeseriesChartItemState }): void {
const cache = this.netcdfService.getCache()
const allPointsData: {point: {}, state: models.timeseriesChartItemState}[] = Object.keys(chartStates).map(
wkt => ({point: cache[wkt], state: chartStates[wkt]})
const allPointsData: { point: {}, state: models.timeseriesChartItemState }[] = Object.keys(chartStates).map(
wkt => ({ point: cache[wkt], state: chartStates[wkt] })
);
this.data = allPointsData;
this.initChart(this.data)
Expand Down Expand Up @@ -235,9 +242,12 @@ export class TimeseriesChartComponent implements OnInit, OnDestroy {
'temporal_baseline': result.point[key].temporal_baseline,
})
this.timeSeriesData.push({
'short_wavelength_displacement': result.point[key].short_wavelength_displacement,
'short_wavelength_displacement': result.point[key].short_wavelength_displacement - (this.baseData?.base ?? 0),
'date': result.point[key].secondary_datetime,
'seriesNumber': result.state.seriesNumber,
'color': result.state.color,
'base': result.point[key].short_wavelength_displacement,
'id': key + result.point[key].short_wavelength_displacement
});
}
this.timeSeriesData.sort((a, b) => {
Expand Down Expand Up @@ -296,22 +306,17 @@ export class TimeseriesChartComponent implements OnInit, OnDestroy {
const toolTip = d3.select('body').append('div')
.attr('class', 'tooltip')
.style('opacity', 0);

if (this.toolTip) {
this.toolTip.remove();
}
this.toolTip = toolTip
this.toolTip.attr('transform', `translate(0, 0)`).style('text-anchor', 'middle').style('z-index', 100).style('opacity', 0)

this.allGroup = [...new Set(this.dataReadyForChart.map(d => d.name))];
// this.allGroup = [...new Set(this.dataReadyForChart.map(d => d.name))];

// this.pointGraph = this.clipContainer.append("pointGraph");
this.lineGraph = this.clipContainer.append("path");

// A color scale: one color for each group
const colorPalette = d3.scaleOrdinal()
.domain(this.allGroup)
.range(d3.schemeSet2);

this.gColorPalette = colorPalette;

const self = this;

this.points = this.dataSource.map((d) => [this.x(new Date(d.date)), this.y(d.short_wavelength_displacement), d.aoi]);
Expand Down Expand Up @@ -379,7 +384,7 @@ export class TimeseriesChartComponent implements OnInit, OnDestroy {
return line(d.values)
})
// @ts-ignore
.attr("stroke", function (d: DataReady) { return colorPalette(d.name) })
.attr("stroke", function (d: DataReady) { return d.color })
.style("opacity", (d: DataReady) => d.opacity)
.style("stroke-width", 1)
.style("fill", "none")
Expand All @@ -394,25 +399,32 @@ export class TimeseriesChartComponent implements OnInit, OnDestroy {
.enter()
.append('g')
.attr('clip-path', 'url(#clip)')
.style('fill', (d) : string=> { return <string>colorPalette(d.name) })
.style('fill', (d) : string=> { return d.color })
.style('opacity', (d) => d.opacity)
.attr('class', (d) : string=> { return d.name.replace(/\W/g, '')})
.attr('class', (d): string => { return d.name.replace(/\W/g, '') })
.selectAll('circle')
.data(d => d.values)
.enter()
.append('circle')
.attr('cx', (d) => this.x(Date.parse(d.date)))
.attr('cy', (d) => this.y(d.short_wavelength_displacement))
.attr('class', (d): string => {
if (this.baseData && this.baseData.id === d.id) {
return 'ts-reference-point'
}
})
.on('mouseover', function (_event: any, p: TimeSeriesData) {
self.hoveredElement = this;
self.hoveredData = p;
const date = new Date(p.date);
toolTip.interrupt();
toolTip
.style('opacity', .9);
toolTip.html(`<div style="text-align: left"><b>Series ${p.seriesNumber}</b><br>${self.tooltipDateFormat(date)}, ${p.short_wavelength_displacement.toFixed(5)} meters</div>`);
toolTip.html(`<div style="text-align: left">${self.tooltipDateFormat(date)}, ${p.short_wavelength_displacement.toFixed(5)} meters<br><b>Series ${p.seriesNumber}</b></div>`);
self.updateTooltip();
})
.on('mouseleave', function (_) {
self.hoveredData = null;
toolTip.transition()
.duration(500)
.style('opacity', 0);
Expand All @@ -421,7 +433,10 @@ export class TimeseriesChartComponent implements OnInit, OnDestroy {

this.updateChart();
}

public setReference(reference) {
this.baseData = reference;
this.initChart(this.data);
}
// When the pointer moves, find the closest point, update the interactive tip, and highlight
// the corresponding line.
private pointerMoved(event, lines, dots, points) {
Expand All @@ -434,10 +449,10 @@ export class TimeseriesChartComponent implements OnInit, OnDestroy {
let colorName: string;
let dClassName: string;
// set the color of the selected line to the color of the series; make all other lines grey
lines.style("stroke", (d: DataReady)=> {
lines.style("stroke", (d: DataReady) => {
if (d.name === k) {
dClassName = '.' + d.name.replace(/\W/g, '');
colorName = this.gColorPalette(d.name);
colorName = d.color;
return colorName;
}
return unSelectedColor;
Expand All @@ -463,13 +478,11 @@ export class TimeseriesChartComponent implements OnInit, OnDestroy {
}

private pointerLeft(lines, _dots) {
let colorName: string;
let dClassName: string;
lines.style("stroke", (d: DataReady)=> {
lines.style("stroke", (d: DataReady) => {
dClassName = '.' + d.name.replace(/\W/g, '');
colorName = this.gColorPalette(d.name);
this.svg.selectAll(dClassName + ' ' + 'circle').style("fill", colorName);
return colorName;
this.svg.selectAll(dClassName + ' ' + 'circle').style("fill", d.color);
return d.color;
});
}

Expand Down Expand Up @@ -553,6 +566,10 @@ export class TimeseriesChartComponent implements OnInit, OnDestroy {
.range(d3.schemeCategory10);

}
public resetBasePoint() {
this.baseData = null;
this.initChart(this.data);
}

public ngOnDestroy(): void {
this.subs.unsubscribe();
Expand Down
11 changes: 9 additions & 2 deletions src/app/components/timeseries-chart/timeseries-chart.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,14 @@ import { TimeseriesChartConfigComponent } from './timeseries-chart-config'
import { ChartModalComponent } from '@components/shared/chart-modal/chart-modal.component'
import {TimeseriesChartZoomComponent} from '@components/timeseries-chart/timeseries-chart-zoom/timeseries-chart-zoom.component';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { MatMenuModule } from '@angular/material/menu';
import { ContextMenuTriggerDirective } from '@directives/context-menu.directive';

@NgModule({
declarations: [TimeseriesChartComponent],
declarations: [TimeseriesChartComponent,
ContextMenuTriggerDirective

],
imports: [
CommonModule,
MatSharedModule,
Expand All @@ -25,7 +31,8 @@ import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
ChartModalComponent,
TimeseriesChartConfigComponent,
TimeseriesChartZoomComponent,
MatProgressSpinnerModule
MatProgressSpinnerModule,
MatMenuModule,

],
exports: [
Expand Down
Loading

0 comments on commit 0b65eb3

Please sign in to comment.