virool-pivot
Version:
A web-based exploratory visualization UI for Druid.io
265 lines (264 loc) • 11.2 kB
JavaScript
;
var plywood_1 = require('plywood');
var chronoshift_1 = require('chronoshift');
var general_1 = require('../../../common/utils/general/general');
var MENU_LENGTH = 5;
function makeCheckpoint(checkPoint, returnValue) {
return {
checkPoint: checkPoint,
returnValue: returnValue
};
}
function makeNumberBuckets(centerAround, count, coarse) {
var granularities = [];
var logTen = Math.log(centerAround) / Math.LN10;
var digits = general_1.getNumberOfWholeDigits(centerAround);
while (granularities.length <= count) {
if (!coarse) {
var halfStep = general_1.toSignificantDigits(5 * Math.pow(10, logTen - 1), digits);
granularities.push(granularityFromJS(halfStep));
}
if (granularities.length >= count)
break;
var wholeStep = general_1.toSignificantDigits(Math.pow(10, logTen), digits);
granularities.push(granularityFromJS(wholeStep));
logTen++;
}
return granularities;
}
function makeNumberBucketsSimple() {
var granularities = [];
for (var i = 3; i > -2; i--) {
granularities.push(granularityFromJS(Math.pow(10, i)));
}
return granularities;
}
function days(count) {
return count * chronoshift_1.day.canonicalLength;
}
function hours(count) {
return count * chronoshift_1.hour.canonicalLength;
}
function minutes(count) {
return count * chronoshift_1.minute.canonicalLength;
}
var TimeHelper = (function () {
function TimeHelper() {
}
TimeHelper.dimensionKind = 'time';
TimeHelper.minGranularity = granularityFromJS('PT1M');
TimeHelper.defaultGranularity = granularityFromJS('P1D');
TimeHelper.supportedGranularities = function (bucketedBy) {
return [
'PT1S', 'PT1M', 'PT5M', 'PT15M',
'PT1H', 'PT6H', 'PT8H', 'PT12H',
'P1D', 'P1W', 'P1M', 'P3M', 'P6M',
'P1Y', 'P2Y'
].map(granularityFromJS);
};
TimeHelper.checkers = [
makeCheckpoint(days(95), 'P1W'),
makeCheckpoint(days(8), 'P1D'),
makeCheckpoint(hours(8), 'PT1H'),
makeCheckpoint(hours(3), 'PT5M')];
TimeHelper.coarseCheckers = [
makeCheckpoint(days(95), 'P1M'),
makeCheckpoint(days(20), 'P1W'),
makeCheckpoint(days(6), 'P1D'),
makeCheckpoint(days(2), 'PT12H'),
makeCheckpoint(hours(23), 'PT6H'),
makeCheckpoint(hours(3), 'PT1H'),
makeCheckpoint(minutes(30), 'PT5M')
];
TimeHelper.defaultGranularities = TimeHelper.checkers.map(function (c) { return granularityFromJS(c.returnValue); }).concat(TimeHelper.minGranularity);
TimeHelper.coarseGranularities = TimeHelper.coarseCheckers.map(function (c) { return granularityFromJS(c.returnValue); }).concat(TimeHelper.minGranularity);
return TimeHelper;
}());
exports.TimeHelper = TimeHelper;
var NumberHelper = (function () {
function NumberHelper() {
}
NumberHelper.dimensionKind = 'number';
NumberHelper.minGranularity = granularityFromJS(1);
NumberHelper.defaultGranularity = granularityFromJS(10);
NumberHelper.checkers = makeNumberBucketsSimple().map(function (v) { return makeCheckpoint(v.size, v); });
NumberHelper.defaultGranularities = NumberHelper.checkers.map(function (c) { return granularityFromJS(c.checkPoint); }).reverse();
NumberHelper.coarseGranularities = null;
NumberHelper.coarseCheckers = null;
NumberHelper.supportedGranularities = function (bucketedBy) {
return makeNumberBuckets(getBucketSize(bucketedBy), 10);
};
return NumberHelper;
}());
exports.NumberHelper = NumberHelper;
function getHelperForKind(kind) {
if (kind === 'time')
return TimeHelper;
return NumberHelper;
}
function getHelperForRange(input) {
if (input instanceof plywood_1.TimeRange)
return TimeHelper;
return NumberHelper;
}
function getBucketSize(input) {
if (input instanceof plywood_1.TimeBucketAction)
return input.duration.getCanonicalLength();
if (input instanceof plywood_1.NumberBucketAction)
return input.size;
throw new Error("unrecognized granularity: " + input + " must be of type TimeBucketAction or NumberBucketAction");
}
function getBucketUnit(input) {
if (input instanceof plywood_1.TimeBucketAction)
return input.duration;
if (input instanceof plywood_1.NumberBucketAction)
return input.size;
throw new Error("unrecognized granularity: " + input + " must be of type TimeBucketAction or NumberBucketAction");
}
function bucketUnitToGranularity(input) {
if (input instanceof plywood_1.Duration) {
return new plywood_1.TimeBucketAction({ duration: input });
}
else if (!isNaN(input)) {
return new plywood_1.NumberBucketAction({ size: input, offset: 0 });
}
throw new Error("unrecognized bucket unit: " + input + " must be of type number or Duration");
}
function startValue(input) {
return input instanceof plywood_1.TimeRange ? input.start.valueOf() : input.start;
}
function endValue(input) {
return input instanceof plywood_1.TimeRange ? input.end.valueOf() : input.end;
}
function findBestMatch(array, target) {
var exactMatch = general_1.findExactIndex(array, target, getBucketSize);
if (exactMatch !== -1) {
return array[exactMatch];
}
var minBiggerIdx = general_1.findFirstBiggerIndex(array, target, getBucketSize);
if (minBiggerIdx !== -1) {
return array[minBiggerIdx];
}
return array[general_1.findMaxValueIndex(array, getBucketSize)];
}
function generateGranularitySet(allGranularities, bucketedBy) {
var start = general_1.findFirstBiggerIndex(allGranularities, bucketedBy, getBucketSize);
var returnGranularities = allGranularities.slice(start, start + MENU_LENGTH);
// makes sure the bucket is part of the list
if (general_1.findExactIndex(returnGranularities, bucketedBy, getBucketSize) === -1) {
returnGranularities = [bucketedBy].concat(returnGranularities.slice(0, returnGranularities.length - 1));
}
return returnGranularities;
}
function granularityFromJS(input) {
if (typeof input === 'number')
return plywood_1.NumberBucketAction.fromJS({ size: input });
if (typeof input === 'string')
return plywood_1.TimeBucketAction.fromJS({ duration: input });
if (typeof input === "object") {
if (!general_1.hasOwnProperty(input, 'action')) {
throw new Error("could not recognize object as action");
}
return plywood_1.Action.fromJS(input);
}
throw new Error("input should be of type number, string, or action");
}
exports.granularityFromJS = granularityFromJS;
function granularityToString(input) {
if (input instanceof plywood_1.TimeBucketAction) {
return input.duration.toString();
}
else if (input instanceof plywood_1.NumberBucketAction) {
return input.size.toString();
}
throw new Error("unrecognized granularity: " + input + " must be of type TimeBucketAction or NumberBucketAction");
}
exports.granularityToString = granularityToString;
function granularityEquals(g1, g2) {
if (!Boolean(g1) === Boolean(g2))
return false;
if (g1 === g2)
return true;
return g1.equals(g2);
}
exports.granularityEquals = granularityEquals;
function granularityToJS(input) {
var js = input.toJS();
if (js.action === 'timeBucket') {
if (Object.keys(js).length === 2)
return js.duration;
}
if (js.action === 'numberBucket') {
if (Object.keys(js).length === 2)
return js.size;
}
return js;
}
exports.granularityToJS = granularityToJS;
function updateBucketSize(existing, newInput) {
if (newInput instanceof plywood_1.TimeBucketAction) {
return new plywood_1.TimeBucketAction({
duration: newInput.duration,
timezone: existing.timezone
});
}
else if (newInput instanceof plywood_1.NumberBucketAction) {
var value = { size: newInput.size };
if (existing.offset)
value.offset = existing.offset;
return new plywood_1.NumberBucketAction(value);
}
throw new Error("unrecognized granularity: " + newInput + " must be of type TimeBucket or NumberBucket");
}
exports.updateBucketSize = updateBucketSize;
function getGranularities(kind, bucketedBy, coarse) {
var helper = getHelperForKind(kind);
var coarseGranularities = helper.coarseGranularities;
if (!bucketedBy)
return coarse && coarseGranularities ? coarseGranularities : helper.defaultGranularities;
// make list that makes most sense with bucket
var allGranularities = helper.supportedGranularities(bucketedBy);
return generateGranularitySet(allGranularities, bucketedBy);
}
exports.getGranularities = getGranularities;
function getDefaultGranularityForKind(kind, bucketedBy, customGranularities) {
if (bucketedBy)
return bucketedBy;
if (customGranularities)
return customGranularities[2];
return getHelperForKind(kind).defaultGranularity;
}
exports.getDefaultGranularityForKind = getDefaultGranularityForKind;
function getBestGranularityForRange(inputRange, bigChecker, bucketedBy, customGranularities) {
return bucketUnitToGranularity(getBestBucketUnitForRange(inputRange, bigChecker, bucketedBy, customGranularities));
}
exports.getBestGranularityForRange = getBestGranularityForRange;
function getBestBucketUnitForRange(inputRange, bigChecker, bucketedBy, customGranularities) {
var rangeLength = Math.abs(endValue(inputRange) - startValue(inputRange));
var helper = getHelperForRange(inputRange);
var bucketLength = bucketedBy ? getBucketSize(bucketedBy) : 0;
var checkPoints = bigChecker && helper.coarseCheckers ? helper.coarseCheckers : helper.checkers;
for (var i = 0; i < checkPoints.length; i++) {
var checkPoint = checkPoints[i].checkPoint;
var returnVal = granularityFromJS(checkPoints[i].returnValue);
if (rangeLength > checkPoint || bucketLength > checkPoint) {
if (bucketedBy) {
var granArray = customGranularities || getGranularities(helper.dimensionKind, bucketedBy);
var closest = general_1.findBiggerClosestToIdeal(granArray, bucketedBy, returnVal, getBucketSize);
// this could happen if bucketedBy were very big or if custom granularities are smaller than maker action
if (closest === null)
return getBucketUnit(helper.defaultGranularity);
return getBucketUnit(closest);
}
else {
if (!customGranularities)
return getBucketUnit(returnVal);
return getBucketUnit(findBestMatch(customGranularities, returnVal));
}
}
}
var minBucket = customGranularities ? customGranularities[general_1.findMinValueIndex(customGranularities, getBucketSize)] : helper.minGranularity;
var granularity = bucketLength > getBucketSize(minBucket) ? bucketedBy : minBucket;
return getBucketUnit(granularity);
}
exports.getBestBucketUnitForRange = getBestBucketUnitForRange;