dashboard #1
@@ -7,6 +7,7 @@ import { Overlay } from "@angular/cdk/overlay";
|
|||||||
|
|
||||||
import { DateTime, Duration } from "luxon";
|
import { DateTime, Duration } from "luxon";
|
||||||
import { DateValue } from '../components/datepicker/date-picker.component';
|
import { DateValue } from '../components/datepicker/date-picker.component';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'pdb-plot-view',
|
selector: 'pdb-plot-view',
|
||||||
@@ -190,11 +191,11 @@ export class PlotViewComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
zoomRange(range: SelectionRange) {
|
zoomRange(range: SelectionRange) {
|
||||||
this.shiftDate(this.config?.dateRange.value!, range.startPercentOfDateRange, range.endPercentOfDateRange-1);
|
this.shiftDate(this.config?.dateRange!, range.startPercentOfDateRange, range.endPercentOfDateRange-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
zoomWithDateAnchor(dateAnchor: DateAnchor){
|
zoomWithDateAnchor(dateAnchor: DateAnchor){
|
||||||
this.shiftDateByAnchor(this.config?.dateRange.value!, dateAnchor.cursorPercentOfDateRange, dateAnchor.zoomFactor);
|
this.shiftDateByAnchor(this.config?.dateRange!, dateAnchor.cursorPercentOfDateRange, dateAnchor.zoomFactor);
|
||||||
}
|
}
|
||||||
|
|
||||||
zoomByScroll(event: WheelEvent) {
|
zoomByScroll(event: WheelEvent) {
|
||||||
@@ -295,18 +296,27 @@ export class PlotViewComponent {
|
|||||||
* shiftDateByAnchor(dateRangeAsString, 0.20, 0.5) zooms in by 50%, so that the date that was at 20% before the zoom is still at 20% after the zoom
|
* shiftDateByAnchor(dateRangeAsString, 0.20, 0.5) zooms in by 50%, so that the date that was at 20% before the zoom is still at 20% after the zoom
|
||||||
* shiftDateByAnchor(dateRangeAsString, 0.33, 2) zooms out by 50%, so that the date that was at 33% before the zoom is still at 33% after the zoom
|
* shiftDateByAnchor(dateRangeAsString, 0.33, 2) zooms out by 50%, so that the date that was at 33% before the zoom is still at 33% after the zoom
|
||||||
*/
|
*/
|
||||||
shiftDateByAnchor(dateRange:string, anchorInPercentOfDateRange:number, zoomFactor:number)
|
shiftDateByAnchor(dateValue:DateValue, anchorInPercentOfDateRange:number, zoomFactor:number)
|
||||||
{
|
{
|
||||||
const dateRangeParsed = this.parseDateRange(dateRange);
|
debugger;
|
||||||
const dateRangeInSeconds = Math.floor(dateRangeParsed.duration.toMillis()/1000);
|
const dateRangeParsed = this.parseDateRange(dateValue);
|
||||||
|
dateRangeParsed.subscribe({
|
||||||
|
next: (dataRange: DateRange) => {
|
||||||
|
const dateRangeInSeconds = Math.floor(dataRange.duration.toMillis()/1000);
|
||||||
|
|
||||||
const anchorTimestampInSeconds = dateRangeParsed.startDate.plus(Math.floor(dateRangeInSeconds*anchorInPercentOfDateRange)*1000);
|
const anchorTimestampInSeconds = dataRange.startDate.plus(Math.floor(dateRangeInSeconds*anchorInPercentOfDateRange)*1000);
|
||||||
const newDateRangeInSeconds = dateRangeInSeconds * zoomFactor;
|
const newDateRangeInSeconds = dateRangeInSeconds * zoomFactor;
|
||||||
|
|
||||||
const newStartDate = anchorTimestampInSeconds.minus(newDateRangeInSeconds*anchorInPercentOfDateRange*1000);
|
const newStartDate = anchorTimestampInSeconds.minus(newDateRangeInSeconds*anchorInPercentOfDateRange*1000);
|
||||||
const newEndDate = newStartDate.plus({seconds: newDateRangeInSeconds});;
|
const newEndDate = newStartDate.plus({seconds: newDateRangeInSeconds});;
|
||||||
|
|
||||||
|
this.setDateRange(newStartDate, newEndDate);
|
||||||
|
},
|
||||||
|
error: (err: any) => {
|
||||||
|
window.console.error("failed to parse DateValue into DateRange: ", err);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
this.setDateRange(newStartDate, newEndDate);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -318,27 +328,36 @@ export class PlotViewComponent {
|
|||||||
* shiftDate(dateRangeAsString, -0.5, -0.5) will move the range by half its size to older values
|
* shiftDate(dateRangeAsString, -0.5, -0.5) will move the range by half its size to older values
|
||||||
* shiftDate(dateRangeAsString, 1, 1) will move the range by its size to newer values
|
* shiftDate(dateRangeAsString, 1, 1) will move the range by its size to newer values
|
||||||
*/
|
*/
|
||||||
shiftDate(dateRange: string, factorStartDate: number, factorEndDate: number)
|
shiftDate(dateValue: DateValue, factorStartDate: number, factorEndDate: number)
|
||||||
{
|
{
|
||||||
const dateRangeParsed = this.parseDateRange(dateRange);
|
debugger;
|
||||||
const dateRangeInSeconds = Math.floor(dateRangeParsed.duration.toMillis()/1000);
|
this.parseDateRange(dateValue).subscribe(
|
||||||
|
dateRangeParsed => {
|
||||||
|
const dateRangeInSeconds = Math.floor(dateRangeParsed.duration.toMillis()/1000);
|
||||||
|
|
||||||
const newStartDate = dateRangeParsed.startDate.plus({seconds: dateRangeInSeconds*factorStartDate});
|
const newStartDate = dateRangeParsed.startDate.plus({seconds: dateRangeInSeconds*factorStartDate});
|
||||||
const newEndDate = dateRangeParsed.endDate.plus({seconds: dateRangeInSeconds*factorEndDate});
|
const newEndDate = dateRangeParsed.endDate.plus({seconds: dateRangeInSeconds*factorEndDate});
|
||||||
|
|
||||||
this.setDateRange(newStartDate, newEndDate);
|
this.setDateRange(newStartDate, newEndDate);
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
parseDateRange(dateRangeAsString : string) : DateRange {
|
parseDateRange(dateValue : DateValue) : Observable<DateRange> {
|
||||||
const startDate = DateTime.fromFormat(dateRangeAsString.slice(0, 19), this.DATE_PATTERN );
|
return this.service.toDateRange(dateValue);
|
||||||
const endDate = DateTime.fromFormat(dateRangeAsString.slice(22, 41), this.DATE_PATTERN );
|
/*
|
||||||
|
.pipe(map((dateRangeAsString:string) => {
|
||||||
|
const startDate = DateTime.fromFormat(dateRangeAsString.slice(0, 19), this.DATE_PATTERN );
|
||||||
|
const endDate = DateTime.fromFormat(dateRangeAsString.slice(22, 41), this.DATE_PATTERN );
|
||||||
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
startDate: startDate,
|
startDate: startDate,
|
||||||
endDate: endDate,
|
endDate: endDate,
|
||||||
duration: endDate.diff(startDate),
|
duration: endDate.diff(startDate),
|
||||||
};
|
};
|
||||||
|
}));
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -3,11 +3,16 @@ import { HttpClient, HttpParams } from "@angular/common/http";
|
|||||||
import { Observable } from "rxjs";
|
import { Observable } from "rxjs";
|
||||||
import { map } from "rxjs/operators";
|
import { map } from "rxjs/operators";
|
||||||
import { DateValue } from "./components/datepicker/date-picker.component";
|
import { DateValue } from "./components/datepicker/date-picker.component";
|
||||||
|
import { DateRange } from "./plot-view/plot-view.component";
|
||||||
|
import { DateTime } from "luxon";
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: "root",
|
providedIn: "root",
|
||||||
})
|
})
|
||||||
export class PlotService {
|
export class PlotService {
|
||||||
|
|
||||||
|
readonly DATE_PATTERN = "yyyy-MM-dd'T'HH:mm:ss";
|
||||||
|
|
||||||
plotTypes: Array<PlotType>;
|
plotTypes: Array<PlotType>;
|
||||||
|
|
||||||
constructor(private http: HttpClient) {
|
constructor(private http: HttpClient) {
|
||||||
@@ -253,6 +258,20 @@ export class PlotService {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
toDateRange(dateValue: DateValue): Observable<DateRange> {
|
||||||
|
return this.http.post<{start: string, end:string, startEpochMilli: number, endEpochMilli: number}>("//" + window.location.hostname+":" + window.location.port +"/api/dates",dateValue)
|
||||||
|
.pipe(map((data) => {
|
||||||
|
const startDate = DateTime.fromFormat(data.start.slice(0, -1), this.DATE_PATTERN );
|
||||||
|
const endDate = DateTime.fromFormat(data.end.slice(0, -1), this.DATE_PATTERN );
|
||||||
|
|
||||||
|
|
||||||
|
return {
|
||||||
|
startDate: startDate,
|
||||||
|
endDate: endDate,
|
||||||
|
duration: endDate.diff(startDate),
|
||||||
|
};
|
||||||
|
}));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PlotType {
|
export class PlotType {
|
||||||
|
|||||||
@@ -1,16 +1,22 @@
|
|||||||
package org.lucares.pdb.plot.api;
|
package org.lucares.pdb.plot.api;
|
||||||
|
|
||||||
import java.time.DayOfWeek;
|
import java.time.DayOfWeek;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
import java.time.OffsetDateTime;
|
import java.time.OffsetDateTime;
|
||||||
|
import java.time.ZoneOffset;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.time.temporal.ChronoUnit;
|
import java.time.temporal.ChronoUnit;
|
||||||
import java.time.temporal.TemporalAdjusters;
|
import java.time.temporal.TemporalAdjusters;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import org.lucares.pdb.api.DateTimeRange;
|
import org.lucares.pdb.api.DateTimeRange;
|
||||||
|
import org.lucares.utils.Preconditions;
|
||||||
|
|
||||||
public class DateTimeRangeParser {
|
public class DateTimeRangeParser {
|
||||||
|
|
||||||
|
private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||||
|
|
||||||
public static DateTimeRange parse(final OffsetDateTime offsetTime, final String datePeriod) {
|
public static DateTimeRange parse(final OffsetDateTime offsetTime, final String datePeriod) {
|
||||||
|
|
||||||
final String[] startEnd = datePeriod.split(Pattern.quote("/"));
|
final String[] startEnd = datePeriod.split(Pattern.quote("/"));
|
||||||
@@ -122,4 +128,16 @@ public class DateTimeRangeParser {
|
|||||||
throw new IllegalArgumentException("invalid input: " + timeDefinition);
|
throw new IllegalArgumentException("invalid input: " + timeDefinition);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static DateTimeRange parseAbsolute(final String dateRangeAsString) {
|
||||||
|
final String[] startEnd = dateRangeAsString.split(Pattern.quote(" - "));
|
||||||
|
Preconditions.checkEqual(startEnd.length, 2, "invalid date range: ''{0}''", dateRangeAsString);
|
||||||
|
|
||||||
|
final String startString = startEnd[0];
|
||||||
|
final String endString = startEnd[1];
|
||||||
|
|
||||||
|
final OffsetDateTime start = LocalDateTime.parse(startString, DATE_FORMAT).atOffset(ZoneOffset.UTC);
|
||||||
|
final OffsetDateTime end = LocalDateTime.parse(endString, DATE_FORMAT).atOffset(ZoneOffset.UTC);
|
||||||
|
|
||||||
|
return new DateTimeRange(start, end);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,15 @@
|
|||||||
package org.lucares.pdb.plot.api;
|
package org.lucares.pdb.plot.api;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import java.time.OffsetDateTime;
|
import java.time.OffsetDateTime;
|
||||||
import java.time.ZoneOffset;
|
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
import org.lucares.pdb.api.DateTimeRange;
|
import org.lucares.pdb.api.DateTimeRange;
|
||||||
import org.lucares.recommind.logs.GnuplotAxis;
|
import org.lucares.recommind.logs.GnuplotAxis;
|
||||||
import org.lucares.recommind.logs.GnuplotSettings;
|
import org.lucares.recommind.logs.GnuplotSettings;
|
||||||
import org.lucares.utils.Preconditions;
|
|
||||||
|
|
||||||
public class PlotSettings {
|
public class PlotSettings {
|
||||||
|
|
||||||
@@ -96,12 +92,7 @@ public class PlotSettings {
|
|||||||
final DateTimeRange dateTimeRange = DateTimeRangeParser.parse(OffsetDateTime.now(), dateValue.getValue());
|
final DateTimeRange dateTimeRange = DateTimeRangeParser.parse(OffsetDateTime.now(), dateValue.getValue());
|
||||||
return dateTimeRange;
|
return dateTimeRange;
|
||||||
case ABSOLUTE:
|
case ABSOLUTE:
|
||||||
final String[] startEnd = dateValue.getValue().split(Pattern.quote(" - "));
|
return DateTimeRangeParser.parseAbsolute(dateValue.getValue());
|
||||||
Preconditions.checkEqual(startEnd.length, 2, "invalid date range: ''{0}''", dateValue);
|
|
||||||
|
|
||||||
final OffsetDateTime startDate = LocalDateTime.parse(startEnd[0], DATE_FORMAT).atOffset(ZoneOffset.UTC);
|
|
||||||
final OffsetDateTime endDate = LocalDateTime.parse(startEnd[1], DATE_FORMAT).atOffset(ZoneOffset.UTC);
|
|
||||||
return new DateTimeRange(startDate, endDate);
|
|
||||||
}
|
}
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package org.lucares.pdbui;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.text.Collator;
|
import java.text.Collator;
|
||||||
|
import java.time.OffsetDateTime;
|
||||||
|
import java.time.ZoneId;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -26,6 +28,9 @@ import org.lucares.pdb.api.DateTimeRange;
|
|||||||
import org.lucares.pdb.api.QueryWithCaretMarker;
|
import org.lucares.pdb.api.QueryWithCaretMarker;
|
||||||
import org.lucares.pdb.api.QueryWithCaretMarker.ResultMode;
|
import org.lucares.pdb.api.QueryWithCaretMarker.ResultMode;
|
||||||
import org.lucares.pdb.datastore.Proposal;
|
import org.lucares.pdb.datastore.Proposal;
|
||||||
|
import org.lucares.pdb.plot.api.DateTimeRangeParser;
|
||||||
|
import org.lucares.pdb.plot.api.DateValue;
|
||||||
|
import org.lucares.pdb.plot.api.DateValue.DateType;
|
||||||
import org.lucares.pdb.plot.api.PlotSettings;
|
import org.lucares.pdb.plot.api.PlotSettings;
|
||||||
import org.lucares.pdbui.domain.AutocompleteProposal;
|
import org.lucares.pdbui.domain.AutocompleteProposal;
|
||||||
import org.lucares.pdbui.domain.AutocompleteProposalByValue;
|
import org.lucares.pdbui.domain.AutocompleteProposalByValue;
|
||||||
@@ -345,6 +350,22 @@ public class PdbController implements HardcodedValues, PropertyKeys {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RequestMapping(path = "/dates", //
|
||||||
|
method = RequestMethod.POST, //
|
||||||
|
consumes = MediaType.APPLICATION_JSON_VALUE, //
|
||||||
|
produces = MediaType.APPLICATION_JSON_VALUE //
|
||||||
|
)
|
||||||
|
@ResponseBody
|
||||||
|
public DateTimeRange dates(@RequestBody final DateValue dateValue) {
|
||||||
|
final DateType type = dateValue.getType();
|
||||||
|
final DateTimeRange result = switch (type) {
|
||||||
|
case RELATIVE -> DateTimeRangeParser.parse(OffsetDateTime.now(ZoneId.of("UTC")), dateValue.getValue());
|
||||||
|
case QUICK -> DateTimeRangeParser.parse(OffsetDateTime.now(ZoneId.of("UTC")), dateValue.getValue());
|
||||||
|
case ABSOLUTE -> DateTimeRangeParser.parseAbsolute(dateValue.getValue());
|
||||||
|
};
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
@PostMapping(path = "/data", consumes = MediaType.MULTIPART_MIXED_VALUE)
|
@PostMapping(path = "/data", consumes = MediaType.MULTIPART_MIXED_VALUE)
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
@ResponseStatus(code = HttpStatus.CREATED)
|
@ResponseStatus(code = HttpStatus.CREATED)
|
||||||
|
|||||||
Reference in New Issue
Block a user