File: src/core/datetime_measure.js
window.multigraph.util.namespace("window.multigraph.core", function (ns) {
"use strict";
var DatetimeMeasure,
DatetimeUnit = new window.multigraph.math.Enum("DatetimeUnit");
DatetimeMeasure = function (measure, unit) {
if (typeof(measure) !== "number" || DatetimeMeasure.isUnit(unit) !== true) {
throw new Error("Improper input for Datetime Measure's constructor");
} else if (arguments.length !== 2) {
throw new Error("Datetime Measure's contructor requires exactly two arguments");
}
this.measure = measure;
this.unit = unit;
};
DatetimeMeasure.isUnit = function (unit) {
return DatetimeUnit.isInstance(unit);
};
DatetimeMeasure.prototype.negative = function () {
return new DatetimeMeasure(-this.measure, this.unit);
};
DatetimeMeasure.prototype.getRealValue = function () {
var factor;
switch (this.unit) {
case DatetimeMeasure.MILLISECOND:
factor = 1;
break;
case DatetimeMeasure.SECOND:
factor = 1000;
break;
case DatetimeMeasure.MINUTE:
factor = 60000;
break;
case DatetimeMeasure.HOUR:
factor = 3600000;
break;
case DatetimeMeasure.DAY:
factor = 86400000;
break;
case DatetimeMeasure.WEEK:
factor = 604800000;
break;
case DatetimeMeasure.MONTH:
factor = 2592000000;
break;
case DatetimeMeasure.YEAR:
factor = 31536000000;
break;
}
return this.measure * factor;
};
DatetimeMeasure.parse = function (s) {
var re, measure, unit;
if (typeof(s) !== "string" || s.match(/\s*-?(([0-9]+\.?[0-9]*)|([0-9]*\.?[0-9]+))\s*(ms|s|m|H|D|W|M|Y){1}\s*$/) === null) {
throw new Error("Improper input for Datetime Measure's parse method");
}
re = /ms|s|m|H|D|W|M|Y/;
measure = parseFloat(s.replace(re, ""));
unit = s.match(re); // returns an array
unit = DatetimeUnit.parse(unit[0]);
return new DatetimeMeasure(measure, unit);
};
DatetimeMeasure.findTickmarkWithMillisecondSpacing = function (/*number(milliseconds)*/value, /*number(milliseconds)*/alignment, /*number(milliseconds)*/spacing) {
var offset = value - alignment,
d = Math.floor( offset / spacing );
if (offset % spacing !== 0) {
++d;
}
return new ns.DatetimeValue(alignment + d * spacing);
};
DatetimeMeasure.findTickmarkWithMonthSpacing = function (/*DatetimeValue*/value, /*DatetimeValue*/alignment, /*number(months)*/monthSpacing) {
var valueD = value.value, //NOTE: ".value" property of DatetimeValue is a javascript Date object
alignD = alignment.value, //NOTE: ".value" property of DatetimeValue is a javascript Date object
monthOffset = 12 * (valueD.getUTCFullYear() - alignD.getUTCFullYear()) + (valueD.getUTCMonth() - alignD.getUTCMonth()),
d = Math.floor( monthOffset / monthSpacing );
if (monthOffset % monthSpacing !== 0) { ++d; }
else if (valueD.getUTCDate() > alignD.getUTCDate()) { ++d; }
else if (valueD.getUTCDate() === alignD.getUTCDate() && valueD.getUTCHours() > alignD.getUTCHours()) { ++d; }
else if (valueD.getUTCDate() === alignD.getUTCDate() && valueD.getUTCHours() === alignD.getUTCHours() && valueD.getUTCMinutes() > alignD.getUTCMinutes()) { ++d; }
else if (valueD.getUTCDate() === alignD.getUTCDate() && valueD.getUTCHours() === alignD.getUTCHours() && valueD.getUTCMinutes() === alignD.getUTCMinutes() && valueD.getUTCSeconds() > alignD.getUTCSeconds()) { ++d; }
else if (valueD.getUTCDate() === alignD.getUTCDate() && valueD.getUTCHours() === alignD.getUTCHours() && valueD.getUTCMinutes() === alignD.getUTCMinutes() && valueD.getUTCSeconds() === alignD.getUTCSeconds() && valueD.getUTCMilliseconds() > alignD.getUTCMilliseconds()) { ++d; }
return alignment.add( DatetimeMeasure.parse((d * monthSpacing) + "M") );
};
/**
* Consider the regular lattice of points on the Datetime line separated from each other
* by `this` DatetimeMeasure, and aligned at the DatetimeValue `alignment`. This function
* return the smallest DatetimeValue in that lattice which is greater than or equal to
* `value`.
*
* return: a DatetimeValue
*/
DatetimeMeasure.prototype.firstSpacingLocationAtOrAfter = function (/*DatetimeValue*/value, /*DatetimeValue*/alignment) {
switch (this.unit) {
case DatetimeMeasure.MONTH:
return DatetimeMeasure.findTickmarkWithMonthSpacing(value, alignment, this.measure);
case DatetimeMeasure.YEAR:
return DatetimeMeasure.findTickmarkWithMonthSpacing(value, alignment, this.measure * 12);
//case DatetimeMeasure.MILLISECOND:
//case DatetimeMeasure.SECOND:
//case DatetimeMeasure.MINUTE:
//case DatetimeMeasure.HOUR:
//case DatetimeMeasure.DAY:
//case DatetimeMeasure.WEEK:
default:
return DatetimeMeasure.findTickmarkWithMillisecondSpacing(value.getRealValue(), alignment.getRealValue(), this.getRealValue());
}
};
/**
* This function is just like `firstSpacingLocationAtOrAfter` above, but returns the
* greatest DatetimeValue in the lattice that is less than or equal to `value`.
*
* return: a DatetimeValue
*/
DatetimeMeasure.prototype.lastSpacingLocationAtOrBefore = function (/*DatetimeValue*/value, /*DatetimeValue*/alignment) {
var x = this.firstSpacingLocationAtOrAfter(value, alignment);
if (x.eq(value)) {
return x;
}
var y = x.add(this.negative());
return y;
};
DatetimeMeasure.prototype.toString = function () {
return this.measure.toString() + this.unit.toString();
};
DatetimeMeasure.MILLISECOND = new DatetimeUnit("ms");
DatetimeMeasure.SECOND = new DatetimeUnit("s");
DatetimeMeasure.MINUTE = new DatetimeUnit("m");
DatetimeMeasure.HOUR = new DatetimeUnit("H");
DatetimeMeasure.DAY = new DatetimeUnit("D");
DatetimeMeasure.WEEK = new DatetimeUnit("W");
DatetimeMeasure.MONTH = new DatetimeUnit("M");
DatetimeMeasure.YEAR = new DatetimeUnit("Y");
ns.DatetimeMeasure = DatetimeMeasure;
});