replace startDate + dateRange with start and end date

The new datetimepicker can be used to specify date ranges. We no longer
need to define a start date and a range. This simplifies the code
for zooming and shifting considerably.
This commit is contained in:
2018-08-11 17:45:20 +02:00
parent 58623c480f
commit c1974d21b2
8 changed files with 125 additions and 317 deletions

View File

@@ -150,8 +150,7 @@ public class PdbController implements HardcodedValues, PropertyKeys {
@RequestParam(name = "groupBy[]", defaultValue = "") final List<String> aGroupBy,
@RequestParam(name = "limitBy.number", defaultValue = "10") final int limit,
@RequestParam(name = "limitBy.selected", defaultValue = "NO_LIMIT") final Limit limitBy,
@RequestParam(name = "dateFrom", defaultValue = "") final String dateFrom,
@RequestParam(name = "dateRange", defaultValue = "1 week") final String dateRange,
@RequestParam(name = "dateRange") final String dateRange,
@RequestParam(name = "axisScale", defaultValue = "LINEAR") final AxisScale axisScale,
@RequestParam(name = "aggregate", defaultValue = "NONE") final Aggregate aggregate,
@RequestParam(name = "keyOutside", defaultValue = "false") final boolean keyOutside,
@@ -163,6 +162,10 @@ public class PdbController implements HardcodedValues, PropertyKeys {
throw new BadRequest("The query must not be empty!");
}
if (StringUtils.isBlank(dateRange)) {
throw new BadRequest("The parameter 'dateRange' must be set.");
}
final PlotSettings plotSettings = new PlotSettings();
plotSettings.setQuery(query);
plotSettings.setGroupBy(aGroupBy);
@@ -170,7 +173,6 @@ public class PdbController implements HardcodedValues, PropertyKeys {
plotSettings.setWidth(hidth);
plotSettings.setLimit(limit);
plotSettings.setLimitBy(limitBy);
plotSettings.setDateFrom(dateFrom);
plotSettings.setDateRange(dateRange);
plotSettings.setYAxisScale(axisScale);
plotSettings.setAggregate(PlotSettingsTransformer.toAggregateInternal(aggregate));

View File

@@ -21,7 +21,6 @@ class PlotSettingsTransformer {
result.setWidth(request.getWidth());
result.setLimit(request.getLimit());
result.setLimitBy(request.getLimitBy());
result.setDateFrom(request.getDateFrom());
result.setDateRange(request.getDateRange());
result.setYAxisScale(request.getAxisScale());
result.setAggregate(toAggregateInternal(request.getAggregate()));

View File

@@ -24,8 +24,6 @@ public class PlotRequest {
private int limit = Integer.MAX_VALUE;
private String dateFrom;
private String dateRange;
private Aggregate aggregate = Aggregate.NONE;
@@ -107,22 +105,11 @@ public class PlotRequest {
this.limit = limit;
}
public String getDateFrom() {
return dateFrom;
}
public void setDateFrom(final String dateFrom) {
this.dateFrom = dateFrom;
}
public String getDateRange() {
return dateRange;
}
public void setDateRange(final String dateRange) {
if (!dateRange.matches("\\d+ (second|minute|hour|day|week|month)s?")) {
throw new IllegalArgumentException(dateRange + " is not a valid range");
}
this.dateRange = dateRange;
}

View File

@@ -138,8 +138,8 @@ textarea {
width: 4em;
}
.input_date {
max-width: 10em;
#search-date-range {
width: 38ex;
}
#add-filter {

View File

@@ -11,6 +11,8 @@ function ffHasParentWithId(el, id) {
return false;
};
const DATE_PATTERN = "YYYY-MM-DD HH:mm:ss"; // for moment-JS
window.onload=function(){
const gnuplotLMargin = 110; // The left margin configured for gnuplot
@@ -24,6 +26,8 @@ moment.locale('en', {
}
});
Vue.config.keyCodes.arrowUp = 38;
Vue.config.keyCodes.arrowDown = 40;
@@ -225,23 +229,22 @@ Vue.component('result-view', {
return x > gnuplotLMargin && x < imageWith - gnuplotRMargin;
},
drag_start: function(event) {
event.preventDefault();
if (event.buttons == 1 && this.isInPlot(event.x) && !data.searchBar.imageLastUsedParams.keyOutside) {
//console.log("drag-start " +event.x+ " " + event.buttons);
this.in_drag_mode = true;
this.drag_start_x = event.x;
this.drag_end_x = event.x;
}
},
dragging: function(event) {
if (this.in_drag_mode && event.buttons == 1 && this.isInPlot(event.x) && !data.searchBar.imageLastUsedParams.keyOutside){
//console.log("dragging " + event.layerX+ " " + event.x + " button: " + event.buttons);
this.drag_end_x = event.x;
const left = this.drag_start_x < this.drag_end_x ? this.drag_start_x : this.drag_end_x;
const width = Math.abs(this.drag_start_x - this.drag_end_x);
this.zoomInSliderStyle="position: absolute; left: "+left+"px; width: "+width+"px; top:"+gnuplotTMargin+"px; bottom: "+gnuplotBMargin+"px;";
//console.log(this.zoomInSliderStyle);
}
},
drag_stop: function(event) {
@@ -251,9 +254,7 @@ Vue.component('result-view', {
// Zoom in if the selected area has some arbitrary minimal size
if (Math.abs(this.drag_start_x - this.drag_end_x) > 10) {
const dateFrom = data.searchBar.imageLastUsedParams.dateFrom;
const dateRange = data.searchBar.imageLastUsedParams.dateRange;
const dateRange = parseDateRange(data.searchBar.imageLastUsedParams.dateRange);
const startPxInImage = Math.min(this.drag_start_x, this.drag_end_x);
const endPxInImage = Math.max(this.drag_start_x, this.drag_end_x);
@@ -264,16 +265,10 @@ Vue.component('result-view', {
const endPxWithinPlotArea = endPxInImage - gnuplotLMargin;
const startPercentOfDateRange = startPxWithinPlotArea / widthPlotArea;
const intervalPercentOfDateRange = (endPxWithinPlotArea- startPxWithinPlotArea) / widthPlotArea;
const endPercentOfDateRange = 1-endPxWithinPlotArea / widthPlotArea;
const dateRangeInSeconds = this.dateRangeToSeconds(dateRange);
const newStartDate = this.shiftDateBySeconds(dateFrom, dateRangeInSeconds * startPercentOfDateRange);
const newDateRangeInSeconds = Math.max(60, dateRangeInSeconds * intervalPercentOfDateRange);
const newDateRange = Math.ceil(newDateRangeInSeconds) + " seconds";
shiftDate(data.searchBar.imageLastUsedParams.dateRange, startPercentOfDateRange, -1*endPercentOfDateRange);
console.log("new range: "+newStartDate+" with interval "+newDateRange);
data.searchBar.dateFrom = newStartDate;
data.searchBar.dateRange = newDateRange;
plotCurrent();
}
}
@@ -283,51 +278,6 @@ Vue.component('result-view', {
this.drag_start_x = 0;
this.drag_end_x = 0;
this.zoomInSliderStyle="display: none;";
},
shiftDateBySeconds: function(date, shiftInSeconds) {
var oldDate = Date.parse(date);
var newDate = oldDate.add({seconds: shiftInSeconds});
return newDate.toString("yyyy-MM-dd HH:mm:ss");
},
dateRangeToSeconds: function(dateRange){
var tokens = dateRange.split(/ +/,2);
var newValue = -1;
if(tokens.length == 2)
{
var value = parseInt(tokens[0]);
var period = tokens[1];
switch (period) {
case "second":
case "seconds":
newValue = value;
break;
case "minute":
case "minutes":
newValue = value * 60;
break;
case "hour":
case "hours":
newValue = value * 60*60;
break;
case "day":
case "days":
newValue = value * 24*60*60;
break;
case "week":
case "weeks":
newValue = value * 7*24*60*60;
break;
case "month":
case "months":
newValue = value * 30*7*24*60*60;
break;
default:
console.log("unhandled value: "+ period);
break;
}
}
return newValue;
}
},
computed: {
@@ -546,155 +496,33 @@ Vue.component('navigation-bar', {
},
zoomIn: function()
{
this.shiftDate(0.25);
this.zoom(0.5);
shiftDate(data.searchBar.dateRange, 0.25, -0.25);
plotCurrent();
},
zoomOut: function()
{
this.shiftDate(-0.5);
this.zoom(2);
shiftDate(data.searchBar.dateRange, -0.5, 0.5);
plotCurrent();
},
dateLeftShift: function()
{
this.shiftDate(-1);
shiftDate(data.searchBar.dateRange, -1, -1);
plotCurrent();
},
dateHalfLeftShift: function()
{
this.shiftDate(-0.5);
shiftDate(data.searchBar.dateRange, -0.5, -0.5);
plotCurrent();
},
dateHalfRightShift: function()
{
this.shiftDate(0.5);
shiftDate(data.searchBar.dateRange, 0.5, 0.5);
plotCurrent();
},
dateRightShift: function()
{
this.shiftDate(1);
shiftDate(data.searchBar.dateRange, 1, 1);
plotCurrent();
},
zoom: function(factor)
{
if (!$('#search-date-range').is(":invalid")) {
var dateRange = data.searchBar.dateRange;
var tokens = dateRange.split(/ +/,2);
if(tokens.length == 2)
{
var value = parseInt(tokens[0]);
var period = tokens[1];
var newValue = value*factor;
while (newValue != Math.round(newValue)){
switch (period) {
case "second":
case "seconds":
if (value == 1) {
// we reached the smallest range
}
else if (value % 2 == 1){
value = value -1;
}
break;
case "minute":
case "minutes":
value = value * 60;
period = "seconds";
break;
case "hour":
case "hours":
value = value * 60;
period = "minutes";
break;
case "day":
case "days":
value = value * 24;
period = "hours";
break;
case "week":
case "weeks":
value = value * 7;
period = "days";
break;
case "month":
case "months":
value = value * 30;
period = "days";
break;
default:
console.log("unhandled value: "+ period);
break;
}
newValue = value*factor
}
data.searchBar.dateRange = newValue + " " + period;
}
}
},
shiftDate: function(directionalFactor)
{
var dateBefore = Date.parse(data.searchBar.dateFrom);
var newDate = this.shiftByInterval(dateBefore, directionalFactor);
data.searchBar.dateFrom = newDate.toString("yyyy-MM-dd HH:mm:ss");
},
shiftByInterval: function(date, directionalFactor)
{
if (!$('#search-date-range').is(":invalid")) {
var dateRange = data.searchBar.dateRange;
var tokens = dateRange.split(/ +/,2);
if(tokens.length == 2)
{
var value = parseInt(tokens[0]);
var period = tokens[1];
var config = {};
value = directionalFactor * value;
switch (period) {
case "second":
case "seconds":
config = { seconds: value };
break;
case "minute":
case "minutes":
config = { minutes: value };
break;
case "hour":
case "hours":
config = { minutes: 60*value };
break;
case "day":
case "days":
config = { days: value };
break;
case "week":
case "weeks":
config = { days: 7*value };
break;
case "month":
case "months":
config = { days: 30*value };
break;
default:
break;
}
var newDate = date.add(config);
return newDate;
}
}
return date;
}
},
computed: {
@@ -733,10 +561,8 @@ Vue.component('group-by-item', {
Vue.component('search-bar', {
props: ['searchBar'],
mounted: function() {
$('#search-date-from').daterangepicker({
$('#search-date-range').daterangepicker({
timePicker: true,
singleDatePicker: true,
startDate: Date.parse(data.searchBar.dateFrom),
minDate: "2017-01-01",
maxDate: moment(),
maxYear: parseInt(moment().format('YYYY'),10),
@@ -758,15 +584,18 @@ Vue.component('search-bar', {
'Last Month': [moment().subtract(1, 'month').startOf('month'), moment().subtract(1, 'month').endOf('month')]
},
});
$('#search-date-from').on('apply.daterangepicker', function(ev, picker) {
data.searchBar.dateFrom = picker.startDate.format('YYYY-MM-DD HH:mm:ss');
$('#search-date-range').on('apply.daterangepicker', function(ev, picker) {
setDateRange(picker.startDate, picker.endDate);
});
},
watch: {
// whenever searchBar.dateFrom changes, this function will run
'searchBar.dateFrom': function (newDateFrom, oldDateFrom) {
const newDate = Date.parse(newDateFrom);
$('#search-date-from').data('daterangepicker').setStartDate(newDate);
// whenever searchBar.dateRange changes, this function will run
'searchBar.dateRange': function (newdateRangeAsString, olddateRangeAsString) {
if (newdateRangeAsString) {
const newdateRange = parseDateRange(newdateRangeAsString);
$('#search-date-range').data('daterangepicker').setStartDate(newdateRange.startDate);
$('#search-date-range').data('daterangepicker').setEndDate(newdateRange.endDate);
}
}
},
methods: {
@@ -825,7 +654,6 @@ Vue.component('search-bar', {
'splitByKeys.selected': data.searchBar.splitByKeys.selected,
'limitBy.selected': data.searchBar.limitBy.selected,
'limitBy.number': data.searchBar.limitBy.number,
'dateFrom': data.searchBar.dateFrom,
'dateRange': data.searchBar.dateRange,
'axisScale': data.searchBar.axisScale,
'aggregate': data.searchBar.aggregate,
@@ -888,40 +716,13 @@ Vue.component('search-bar', {
</div>
<div class="group">
<label for="search-date-from">From Date:</label>
<label for="search-date-range">Date Range:</label>
<input type='text'
id="search-date-from"
v-model="searchBar.dateFrom"
id="search-date-range"
v-model="searchBar.dateRange"
required="required"
pattern="\\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2]\\d|3[0-1]) [0-2]\\d:[0-5]\\d:[0-5]\\d"
pattern="\\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2]\\d|3[0-1]) [0-2]\\d:[0-5]\\d:[0-5]\\d - \\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2]\\d|3[0-1]) [0-2]\\d:[0-5]\\d:[0-5]\\d"
/>
<!--
<input
id="search-date-from"
v-model="searchBar.dateFrom"
class="input_date"
type="text"
required="required"
pattern="\\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2]\\d|3[0-1]) [0-2]\\d:[0-5]\\d:[0-5]\\d" />-->
</div>
<div class="group">
<label for="search-date-range">Interval:</label>
<input
id="search-date-range"
v-model="searchBar.dateRange"
type="text"
list="ranges"
required="required"
pattern="\\d+ (second|minute|hour|day|week|month)s?">
<datalist id="ranges">
<option value="60 seconds"/>
<option value="5 minutes"/>
<option value="1 hour"/>
<option value="1 day"/>
<option value="1 week"/>
<option value="1 month"/>
</datalist>
</div>
<div class="group">
@@ -1049,8 +850,7 @@ var data = {
'selected': GetURLParameter('limitBy.selected','NO_LIMIT'),
'number': GetURLParameter('limitBy.number',10)
},
dateFrom: GetURLParameter('dateFrom', Date.now().add({ days: -7 }).toString("yyyy-MM-dd HH:mm:ss")), // '2018-01-05 09:03'
dateRange: GetURLParameter('dateRange','1 week'),
dateRange: GetURLParameter('dateRange', moment().add({ days: -6 }).startOf('day').format(DATE_PATTERN)+ ' - '+ moment().endOf('day').format(DATE_PATTERN)), // '2018-01-05 09:03:03'
axisScale: GetURLParameter('axisScale','LOG10'),
aggregate: GetURLParameter('aggregate','NONE'),
yRange: {
@@ -1096,6 +896,46 @@ var data = {
}
};
function parseDateRange(dateRangeAsString){
if (dateRangeAsString) {
const startDate = moment(dateRangeAsString.slice(0, 19));
const endDate = moment(dateRangeAsString.slice(22, 41));
return {
startDate: startDate,
endDate: endDate,
duration: moment.duration(endDate.diff(startDate))
};
}
}
function setDateRange(startDate, endDate) {
const formattedStartDate = startDate.format(DATE_PATTERN);
const formattedEndDate = endDate.format(DATE_PATTERN);
data.searchBar.dateRange = formattedStartDate+" - "+formattedEndDate;
}
/**
* Zoom in/out or shift date by adding factorStartDate*dateRangeInSeconds seconds to the start date
* and factorEndDate*dateRangeInSeconds seconds to the end date.
*
* shiftDate(dateRangeAsString, 0.25, -0.25) will zoom in, making the range half its size
* shiftDate(dateRangeAsString, -0.5, 0.5) will zoom out, making the range double its size
* 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
*/
function shiftDate(dateRange, factorStartDate, factorEndDate)
{
const dateRangeParsed = parseDateRange(dateRange);
const dateRangeInSeconds = dateRangeParsed.duration.asSeconds();
const newStartDate = dateRangeParsed.startDate.add({seconds: dateRangeInSeconds*factorStartDate});
const newEndDate = dateRangeParsed.endDate.add({seconds: dateRangeInSeconds*factorEndDate});
setDateRange(newStartDate, newEndDate);
}
function showLoadingIcon()
{
@@ -1165,7 +1005,6 @@ function createRequest(query, generateThumbnail){
request['groupBy'] = groupBy();
request['limitBy'] = data.searchBar.limitBy.selected;
request['limit'] = parseInt(data.searchBar.limitBy.number);
request['dateFrom'] = data.searchBar.dateFrom;
request['dateRange'] = data.searchBar.dateRange;
request['axisScale'] = data.searchBar.axisScale;
request['aggregate'] = data.searchBar.aggregate;
@@ -1219,7 +1058,6 @@ function updateImageLink(query) {
'splitByKeys.selected': data.searchBar.splitByKeys.selected,
'limitBy.selected': data.searchBar.limitBy.selected,
'limitBy.number': data.searchBar.limitBy.number,
'dateFrom': data.searchBar.dateFrom,
'dateRange': data.searchBar.dateRange,
'axisScale': data.searchBar.axisScale,
'aggregate': data.searchBar.aggregate,