ui-widget-toolkit
Version:
UI widgets built on top of D3, Pixi.js and ag-grid-community
171 lines • 90.6 kB
JavaScript
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory(require("d3"));
else if(typeof define === 'function' && define.amd)
define("UWT", ["d3"], factory);
else if(typeof exports === 'object')
exports["UWT"] = factory(require("d3"));
else
root["UWT"] = factory(root["d3"]);
})(window, function(__WEBPACK_EXTERNAL_MODULE_d3__) {
return /******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
/******/ }
/******/ };
/******/
/******/ // define __esModule on exports
/******/ __webpack_require__.r = function(exports) {
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ }
/******/ Object.defineProperty(exports, '__esModule', { value: true });
/******/ };
/******/
/******/ // create a fake namespace object
/******/ // mode & 1: value is a module id, require it
/******/ // mode & 2: merge all properties of value into the ns
/******/ // mode & 4: return value when already ns object
/******/ // mode & 8|1: behave like require
/******/ __webpack_require__.t = function(value, mode) {
/******/ if(mode & 1) value = __webpack_require__(value);
/******/ if(mode & 8) return value;
/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
/******/ var ns = Object.create(null);
/******/ __webpack_require__.r(ns);
/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
/******/ return ns;
/******/ };
/******/
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return getter;
/******/ };
/******/
/******/ // Object.prototype.hasOwnProperty.call
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = "./src/core/cartesian/decimator/worker.ts");
/******/ })
/************************************************************************/
/******/ ({
/***/ "./src/core/cartesian/decimator/decimator.ts":
/*!***************************************************!*\
!*** ./src/core/cartesian/decimator/decimator.ts ***!
\***************************************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
eval("\nObject.defineProperty(exports, \"__esModule\", { value: true });\nconst data_1 = __webpack_require__(/*! ../../data */ \"./src/core/data.ts\");\nconst utilities_1 = __webpack_require__(/*! ../../utilities */ \"./src/core/utilities.ts\");\nexports.findFirstInsertionIdx = utilities_1.bisectBuffer(function (xy) { return xy.x; }).left;\nexports.findLastInsertionIdx = utilities_1.bisectBuffer(function (xy) { return xy.x; }).right;\nclass XYDummyDecimator {\n constructor() {\n this._values = [];\n }\n initialize(xValueToCoord, xCoordToValue, yValueToCoord) {\n }\n getKey() {\n return '';\n }\n getName() {\n return '';\n }\n /**\n * Returns the decimated list of data\n */\n getValues() {\n return this._values;\n }\n /**\n * Values to be decimated\n *\n * @param xStart - start time of the region\n * @param xEnd - start time of the region\n * @param values - Values to be decimated.\n */\n decimateValues(xStart, xEnd, values) {\n if (Array.isArray(values)) {\n values.forEach((data) => {\n this._values.push(data.getData());\n });\n }\n else {\n this._values = values.getData();\n }\n return this._values;\n }\n} // interface IDecimator\nexports.XYDummyDecimator = XYDummyDecimator;\n/**\n * this class allows a decimation function to be passed in to allow for\n * generic decimation\n */\nclass CustomPointXYDecimator {\n constructor() {\n this._name = 'Simple Unimplemented Decimator';\n }\n /**\n * construct a generic decimator using a custom user function\n *\n * @param xValueToCoord converts the x value to a GUI x coordinate\n * @param yValueToCoord converts the y value to a GUI y coordinate\n * @param decimationFunc convert a list of data to a for rendering smaller list\n */\n initialize(xValueToCoord, xCoordToValue, yValueToCoord) {\n this._xValueToCoord = xValueToCoord;\n this._xCoordToValue = xCoordToValue;\n this._yValueToCoord = yValueToCoord;\n }\n /**\n * Returns the key of this decimator\n */\n getKey() {\n return this._key;\n }\n /**\n * Returns the name of this decimator\n */\n getName() {\n return this._name;\n }\n /**\n * Returns the decimated list of buckets\n */\n getValues() {\n return this._decimatedValues;\n }\n /**\n * Values to be decimated\n *\n * @param xStart - start time of the region\n * @param xEnd - start time of the region\n * @param values - Values to be decimated.\n */\n decimateValues(xStart, xEnd, inputValues) {\n // loop over the data samples\n this._decimatedValues = [];\n if (inputValues.length() === 0) {\n return this._decimatedValues;\n }\n let left = exports.findFirstInsertionIdx(inputValues, xStart);\n let right = exports.findLastInsertionIdx(inputValues, xEnd);\n if (left > 0) {\n --left;\n }\n if (right < inputValues.length()) {\n ++right;\n }\n let lastX;\n if (left < inputValues.length()) {\n lastX = Math.floor(this._xValueToCoord(inputValues.get(left).x));\n --lastX;\n }\n let xStartCoord;\n if (xStart) {\n xStartCoord = Math.floor(this._xValueToCoord(xStart));\n }\n else {\n xStartCoord = Math.floor(this._xValueToCoord(inputValues.get(left).x));\n }\n let lastIdx = left;\n let endIdx;\n for (let index = left; index < right; ++index) {\n let inputValue = inputValues.get(index);\n let xEndCoord = Math.floor(this._xValueToCoord(inputValue.x));\n endIdx = index;\n if (xEndCoord !== lastX) {\n this._decimatedValues = this._decimatedValues.concat(this._customFunc(inputValues, lastIdx, endIdx, this._yValueToCoord, this._xValueToCoord, this._xCoordToValue(xStartCoord), this._xCoordToValue(xEndCoord)));\n xStartCoord = xEndCoord;\n lastX = xEndCoord;\n lastIdx = endIdx;\n }\n }\n if (lastIdx !== inputValues.length()) {\n this._decimatedValues = this._decimatedValues.concat(this._customFunc(inputValues, lastIdx, endIdx + 1, this._yValueToCoord, this._xValueToCoord, this._xCoordToValue(xStartCoord), Number.MAX_VALUE));\n }\n return this._decimatedValues;\n }\n}\nexports.CustomPointXYDecimator = CustomPointXYDecimator;\n/** used to compute the min values for a set of data */\nclass MinPointDecimator extends CustomPointXYDecimator {\n constructor() {\n super();\n this._key = MinPointDecimator.KEY;\n this._name = 'Min';\n this._customFunc = function (values, startIdx, endIdx, yValueToCoord) {\n if (values.length() > 0 && startIdx !== endIdx) {\n let minY = Number.MAX_VALUE;\n let minValue;\n for (let i = startIdx; i < endIdx; ++i) {\n let value = values.get(i);\n let y = value.y;\n if (y < minY) {\n minValue = value;\n minY = y;\n }\n }\n return [minValue];\n }\n return [];\n };\n }\n}\nexports.MinPointDecimator = MinPointDecimator;\nMinPointDecimator.KEY = 'MinPointDecimator';\n;\nfunction computeAvg(values, startIdx, endIdx, yValueToCoord) {\n if (values.length() > 0 && startIdx !== endIdx) {\n let total = 0;\n for (let i = startIdx; i < endIdx; ++i) {\n let value = values.get(i);\n total += value.y;\n }\n return [new data_1.XYValue(values.get(endIdx - 1).x, total / (endIdx - startIdx))];\n }\n return [];\n}\n/** used to compute the avg values for a set of data */\nclass AvgPointDecimator extends CustomPointXYDecimator {\n constructor() {\n super();\n this._key = AvgPointDecimator.KEY;\n this._name = 'Avg';\n this._customFunc = computeAvg;\n }\n}\nexports.AvgPointDecimator = AvgPointDecimator;\nAvgPointDecimator.KEY = 'AvgPointDecimator';\n;\n/** used to compute the min values for a set of data */\nclass MaxPointDecimator extends CustomPointXYDecimator {\n constructor() {\n super();\n this._key = MaxPointDecimator.KEY;\n this._name = 'Max';\n this._customFunc = function (values, startIdx, endIdx, yValueToCoord) {\n if (values.length() > 0 && startIdx !== endIdx) {\n let maxY = -Number.MAX_VALUE;\n let maxValue;\n for (let i = startIdx; i < endIdx; ++i) {\n let value = values.get(i);\n let y = value.y;\n if (y > maxY) {\n maxValue = value;\n maxY = y;\n }\n }\n return [maxValue];\n }\n return [];\n };\n }\n}\nexports.MaxPointDecimator = MaxPointDecimator;\nMaxPointDecimator.KEY = 'MaxPointDecimator';\n;\n/**\n * Data decimation to fit information to onto the graph.\n *\n * This class divides the x-Axis time range into a set of buckets. Each\n * bucket provides the average of the values, the minimum & maximum\n * values, and the values upon entry & exit.\n * It assumes that the DB values are increase over the time.\n */\nclass XYPointDecimator extends CustomPointXYDecimator {\n constructor() {\n super();\n this._key = XYPointDecimator.KEY;\n this._name = 'XYPointDecimator';\n this._customFunc = function (values, startIdx, endIdx, yValueToCoord) {\n let yMap = {};\n let reducedValues = [];\n for (let i = startIdx; i < endIdx; ++i) {\n let value = values.get(i);\n let yCoord = Math.floor(yValueToCoord(value.y));\n if (!yMap.hasOwnProperty(yCoord.toString())) {\n reducedValues.push(value);\n yMap[yCoord] = true;\n }\n }\n return reducedValues;\n };\n }\n} // class VerticalDecimator\nexports.XYPointDecimator = XYPointDecimator;\nXYPointDecimator.KEY = 'XYPointDecimator';\n/**\n * this class allows a decimation function to be passed in to allow for\n * generic decimation\n */\nclass CustomContinuousXYDecimator {\n constructor() {\n this._name = 'Simple Unimplemented Decimator';\n }\n /**\n * construct a generic decimator using a custom user function\n *\n * @param xValueToCoord converts the x value to a GUI x coordinate\n * @param yValueToCoord converts the y value to a GUI y coordinate\n * @param decimationFunc convert a list of data to a for rendering smaller list\n */\n initialize(xValueToCoord, xCoordToValue, yValueToCoord) {\n this._xValueToCoord = xValueToCoord;\n this._xCoordToValue = xCoordToValue;\n this._yValueToCoord = yValueToCoord;\n }\n /**\n * Returns the key of this decimator\n */\n getKey() {\n return this._key;\n }\n /**\n * Returns the name of this decimator\n */\n getName() {\n return this._name;\n }\n /**\n * Returns the decimated list of buckets\n */\n getValues() {\n return this._decimatedValues;\n }\n /**\n * Values to be decimated\n *\n * @param xStart - start time of the region\n * @param xEnd - start time of the region\n * @param values - Values to be decimated.\n */\n decimateValues(xStart, xEnd, inputValues) {\n // loop over the data samples\n this._decimatedValues = [];\n if (inputValues.length() === 0) {\n return this._decimatedValues;\n }\n let left = exports.findFirstInsertionIdx(inputValues, xStart);\n let right = exports.findLastInsertionIdx(inputValues, xEnd);\n if (left > 0) {\n --left;\n }\n if (right < inputValues.length()) {\n ++right;\n }\n let lastX;\n if (left < inputValues.length()) {\n lastX = Math.floor(this._xValueToCoord(inputValues.get(left).x));\n --lastX;\n }\n let xStartCoord;\n if (xStart) {\n xStartCoord = this._xValueToCoord(xStart);\n }\n else {\n xStartCoord = left;\n }\n let lastIdx = left;\n for (let index = left; index < right; ++index) {\n let inputValue = inputValues.get(index);\n let xEndCoord = Math.floor(this._xValueToCoord(inputValue.x));\n let endIdx = index + 1;\n if (xEndCoord !== lastX) {\n this._decimatedValues = this._decimatedValues.concat(this._customFunc(inputValues, lastIdx, endIdx, this._yValueToCoord, this._xValueToCoord, this._xCoordToValue(xStartCoord), this._xCoordToValue(xEndCoord)));\n xStartCoord = xEndCoord;\n lastX = xEndCoord;\n lastIdx = endIdx;\n }\n }\n if (lastIdx !== inputValues.length()) {\n this._decimatedValues = this._decimatedValues.concat(this._customFunc(inputValues, lastIdx, lastIdx + 1, this._yValueToCoord, this._xValueToCoord, this._xCoordToValue(xStartCoord), Number.MAX_VALUE));\n }\n return this._decimatedValues;\n }\n}\nexports.CustomContinuousXYDecimator = CustomContinuousXYDecimator;\n/** used to compute the avg values for a set of data */\nclass AvgContinuousDecimator extends CustomContinuousXYDecimator {\n constructor() {\n super();\n this._key = AvgContinuousDecimator.KEY;\n this._name = 'Avg';\n this._customFunc = computeAvg;\n }\n}\nexports.AvgContinuousDecimator = AvgContinuousDecimator;\nAvgContinuousDecimator.KEY = 'AvgContinuousDecimator';\n;\n/** this is a helper function class that computes the summed values for each\n * Y state per each X bucket\n */\nfunction sumMultiXYSeriesValues(_xValueToCoord, _xCoordToValue, _yValueToCoord, xStart, xEnd, values) {\n let ret = [];\n // first this is total weighted sum per x, then used to store percentage per x\n let tempValues = [];\n let globalStartBucket = 0;\n let globalEndBucket = Math.ceil(_xValueToCoord(Number.MAX_VALUE));\n if (globalEndBucket < globalStartBucket) {\n return undefined;\n }\n // NOTE: I do this up here so I can cheat and use the x values here\n // so later I don't keep calling _xCoordToValue\n let xBucketValues = [];\n for (let bucket = 0; bucket <= globalEndBucket + 1; ++bucket) {\n xBucketValues.push(_xCoordToValue(bucket));\n }\n // for a series get the weighted sum for the number of buckets xStart to xEnd\n for (let stateIdx = 0; stateIdx < values.length; ++stateIdx) {\n let perStateData = values[stateIdx];\n let value;\n let nextValue;\n let start = exports.findFirstInsertionIdx(values[stateIdx], xStart);\n let end = exports.findLastInsertionIdx(values[stateIdx], xEnd);\n if (start > 0) {\n --start;\n }\n // the last element would be caught by the algorithm already\n if (end === perStateData.length()) {\n --end;\n }\n // pad endBucket + 1 so we get data past the last point in the bucket\n // so we can graph to the first value in the next bucket\n tempValues[stateIdx] = Array.apply(null, Array(globalEndBucket)).\n map(Number.prototype.valueOf, 0);\n // get weighted sum of the values for each bucket\n for (let rawDataIdx = start; rawDataIdx < end; ++rawDataIdx) {\n value = perStateData.get(rawDataIdx);\n nextValue = perStateData.get(rawDataIdx + 1);\n let startBucket = Math.floor(_xValueToCoord(value.x));\n let endBucket = Math.floor(_xValueToCoord(nextValue.x));\n let totalX = (nextValue.x - value.x);\n let valuePerX = totalX === 0 ? 0 : nextValue.y / totalX;\n if (startBucket === endBucket) {\n if (xStart === undefined || (value.x > xStart && nextValue.x < xEnd)) {\n // here it's all in the existing bucket\n tempValues[stateIdx][startBucket] += valuePerX;\n }\n else {\n let bucketScalar = 1 / (xBucketValues[startBucket + 1] - xBucketValues[startBucket]);\n if (nextValue.x < xEnd) {\n // here the back half is in the bucket\n tempValues[stateIdx][startBucket] +=\n (nextValue.x - xBucketValues[startBucket]) * valuePerX * bucketScalar;\n }\n else {\n // here the front half is in the bucket\n tempValues[stateIdx][startBucket] +=\n (xBucketValues[startBucket + 1] - value.x) * valuePerX * bucketScalar;\n }\n }\n }\n else {\n let bucketScalar = 1 / (xBucketValues[startBucket + 1] - xBucketValues[startBucket]);\n let startX = xStart ? Math.max(xStart, value.x) : value.x;\n let endStartBucket = xBucketValues[startBucket + 1];\n tempValues[stateIdx][startBucket] +=\n (endStartBucket - startX) * valuePerX * bucketScalar;\n // add in all the bucket values in between\n for (let currBucket = startBucket + 1; currBucket < endBucket; ++currBucket) {\n tempValues[stateIdx][currBucket] += valuePerX;\n }\n // add in end bucket amount\n bucketScalar = 1 / (xBucketValues[endBucket] - xBucketValues[endBucket - 1]);\n let endX = xEnd ? Math.min(xEnd, nextValue.x) : nextValue.x;\n let startEndBucket = xBucketValues[endBucket];\n tempValues[stateIdx][endBucket] +=\n (endX - startEndBucket) * valuePerX * bucketScalar;\n }\n }\n ret[stateIdx] = [];\n let buckets = tempValues[stateIdx];\n for (let bucket = 0; bucket < buckets.length; ++bucket) {\n ret[stateIdx][bucket] = {\n x: xBucketValues[bucket],\n y: tempValues[stateIdx][bucket]\n };\n }\n }\n return ret;\n}\nexports.sumMultiXYSeriesValues = sumMultiXYSeriesValues;\n/** class that computes the summed values for each Y state per each X bucket */\nclass SummedValueMultiXYSeriesDecimator {\n constructor() {\n }\n /**\n * construct a generic decimator using a custom user function\n *\n * @param xValueToCoord converts the x value to a GUI x coordinate\n * @param yValueToCoord converts the y value to a GUI y coordinate\n * @param decimationFunc convert a list of data to a for rendering smaller list\n */\n initialize(xValueToCoord, xCoordToValue, yValueToCoord) {\n this._xValueToCoord = xValueToCoord;\n this._xCoordToValue = xCoordToValue;\n this._yValueToCoord = yValueToCoord;\n }\n /**\n * Returns the key of this decimator\n */\n getKey() {\n return SummedValueMultiXYSeriesDecimator.KEY;\n }\n /**\n * Returns the decimated list of buckets\n */\n getName() {\n return '';\n }\n /**\n * Returns the decimated list of buckets\n */\n getValues() {\n return this._decimatedValues;\n }\n /**\n * Values to be decimated\n *\n * @param xStart - start time of the region\n * @param xEnd - start time of the region\n * @param values - Values to be decimated.\n */\n decimateValues(xStart, xEnd, values) {\n this._decimatedValues = sumMultiXYSeriesValues(this._xValueToCoord, this._xCoordToValue, this._yValueToCoord, xStart, xEnd, values);\n return this._decimatedValues;\n }\n}\nexports.SummedValueMultiXYSeriesDecimator = SummedValueMultiXYSeriesDecimator;\nSummedValueMultiXYSeriesDecimator.KEY = 'SummedValueMultiXYSeriesDecimator';\n;\n/** class that computes the residency values for each Y state per each X bucket.\n * This means the sum of all values within an output bucket is 100.\n*/\nclass ResidencyDecimator extends SummedValueMultiXYSeriesDecimator {\n constructor() {\n super();\n }\n /**\n * Returns the key of this decimator\n */\n getKey() {\n return ResidencyDecimator.KEY;\n }\n /**\n * Returns the decimated list of buckets\n */\n getName() {\n return '';\n }\n /**\n * Values to be decimated\n *\n * @param xStart - start time of the region\n * @param xEnd - start time of the region\n * @param values - Values to be decimated.\n */\n decimateValues(xStart, xEnd, values) {\n this._decimatedValues = sumMultiXYSeriesValues(this._xValueToCoord, this._xCoordToValue, this._yValueToCoord, xStart, xEnd, values);\n // normalize all values to 100%\n for (let bucket = 0; bucket < this._decimatedValues[0].length; ++bucket) {\n let total = 0;\n for (let stateIdx = 0; stateIdx < this._decimatedValues.length; ++stateIdx) {\n if (this._decimatedValues[stateIdx][bucket].y) {\n total += this._decimatedValues[stateIdx][bucket].y;\n }\n }\n if (total > 0) {\n let scalar = 100 / total;\n for (let stateIdx = 0; stateIdx < values.length; ++stateIdx) {\n if (this._decimatedValues[stateIdx][bucket].y) {\n this._decimatedValues[stateIdx][bucket].y =\n this._decimatedValues[stateIdx][bucket].y * scalar;\n }\n }\n }\n }\n return this._decimatedValues;\n }\n}\nexports.ResidencyDecimator = ResidencyDecimator;\nResidencyDecimator.KEY = 'ResidencyDecimator';\n;\n/** class that computes the summed Y value per each X bucket */\nclass SummedValueXYSeriesDecimator {\n constructor() {\n }\n /**\n * construct a generic decimator using a custom user function\n *\n * @param xValueToCoord converts the x value to a GUI x coordinate\n * @param yValueToCoord converts the y value to a GUI y coordinate\n * @param decimationFunc convert a list of data to a for rendering smaller list\n */\n initialize(xValueToCoord, xCoordToValue, yValueToCoord) {\n this._xValueToCoord = xValueToCoord;\n this._xCoordToValue = xCoordToValue;\n this._yValueToCoord = yValueToCoord;\n }\n /**\n * Returns the name of this decimator\n */\n getKey() {\n return SummedValueXYSeriesDecimator.KEY;\n }\n /**\n * Returns the name of this decimator\n */\n getName() {\n return '';\n }\n /**\n * Returns the decimated list of buckets\n */\n getValues() {\n return this._decimatedValues;\n }\n /**\n * Values to be decimated\n *\n * @param xStart - start time of the region\n * @param xEnd - start time of the region\n * @param values - Values to be decimated.\n */\n decimateValues(xStart, xEnd, values) {\n this._decimatedValues = sumMultiXYSeriesValues(this._xValueToCoord, this._xCoordToValue, this._yValueToCoord, xStart, xEnd, [values])[0];\n return this._decimatedValues;\n }\n}\nexports.SummedValueXYSeriesDecimator = SummedValueXYSeriesDecimator;\nSummedValueXYSeriesDecimator.KEY = 'SummedValueXYSeriesDecimator';\n/*************************************************************\n * NEWS (Min/Max/Entry/Exit) CHART DECIMATORS\n */\n/**\n * Internally used class for the array of values\n */\nclass NEWSDecimationValue extends data_1.CandlestickValue {\n /**\n * Construct a DecimationValue instance\n *\n * @param value - an XYValue to initialize the decimation value\n */\n constructor(x) {\n super(x, undefined, undefined, undefined, undefined);\n this._bucketPts = 0;\n } // constructor\n} // class DecimationValue\nexports.NEWSDecimationValue = NEWSDecimationValue;\n/**\n * Data decimation to fit information to onto the graph.\n *\n * This class divides the x-Axis time range into a set of buckets. Each\n * bucket provides the average of the values, the minimum & maximum\n * values, and the values upon entry & exit.\n * It assumes that the DB values are increase over the time.\n */\nclass NEWSBaseDecimator {\n initialize(xValueToCoord, xCoordToValue, yValueToCoord) {\n this._xValueToCoord = xValueToCoord;\n this._xCoordToValue = xCoordToValue;\n this._yValueToCoord = yValueToCoord;\n }\n /**\n * Returns the key of this decimator\n */\n getKey() {\n return this._key;\n }\n getName() {\n return '';\n }\n /**\n * Get the accumulated buckets\n *\n * @returns the accumulated buckets\n */\n getValues() {\n return this._buckets;\n }\n /**\n * Bucket dumper\n */\n _dumpBucket(firstTimeStamp, bucket, valuesInBucket) {\n let details = \"valuesInBucket = \" + valuesInBucket.toFixed(0) + \", \";\n details += \"([avg]Time delta, avgValue) = (\" +\n (bucket.x - firstTimeStamp).toFixed(2) + \", \" + bucket.y.toFixed(2) + \"), \";\n details += \"(entry, min, max, exit) = (\" + (bucket.entry).toFixed(2) + \", \" +\n (bucket.min).toFixed(2) + \", \" + (bucket.max).toFixed(2) + \", \" +\n (bucket.exit).toFixed(2) + \")\";\n return details;\n }\n /**\n * Values to be decimated\n *\n * @param xStart - start time of the region\n * @param xEnd - start time of the region\n * @param values - Values to be decimated.\n */\n decimateValues(xStart, xEnd, inputValues) {\n throw 'Error need to implement decimate code';\n }\n}\nexports.NEWSBaseDecimator = NEWSBaseDecimator;\n/** this class takes a series x, y points and using for each X bucket provides\n * the Y entry/exit/min/max/average for that X bucket\n */\nclass NEWSPointDecimator extends NEWSBaseDecimator {\n constructor() {\n super();\n this._key = NEWSPointDecimator.KEY;\n }\n createNewBucket(decimatedValue, value) {\n decimatedValue.entry = value.y;\n decimatedValue.exit = value.y;\n decimatedValue.min = value.y;\n decimatedValue.max = value.y;\n decimatedValue.x = 0;\n decimatedValue.y = 0;\n decimatedValue._bucketPts = 0;\n this.addToBucket(decimatedValue, value);\n }\n /**\n * Add an x/y value pair to this value. Both the time (x) and\n * value (y) are added to this point/bucket\n *\n * @param dbPoint - The x/y value pair to add to this value.\n */\n addToBucket(decimatedValue, value) {\n decimatedValue.x += value.x;\n decimatedValue.y += value.y;\n decimatedValue.min = Math.min(decimatedValue.min, value.y);\n decimatedValue.max = Math.max(decimatedValue.max, value.y);\n decimatedValue.exit = value.y;\n decimatedValue._bucketPts++;\n }\n finalizeBucket(decimatedValue, pointsInBucket) {\n if (undefined !== pointsInBucket) {\n if (pointsInBucket !== decimatedValue._bucketPts) {\n console.log(\"AverageTime: mismatching pt calculation\");\n }\n }\n if (decimatedValue._bucketPts === 0) {\n console.log(\"AverageTime: 0 points\");\n }\n decimatedValue.x = decimatedValue.x / decimatedValue._bucketPts;\n decimatedValue.y = decimatedValue.y / decimatedValue._bucketPts;\n }\n /**\n * Values to be decimated\n *\n * @param xStart - start time of the region\n * @param xEnd - start time of the region\n * @param values - Values to be decimated.\n */\n decimateValues(xStart, xEnd, inputValues) {\n // loop over the data samples\n this._buckets = [];\n if (inputValues.length() === 0) {\n return this._buckets;\n }\n let currentPoint;\n let left = exports.findFirstInsertionIdx(inputValues, xStart);\n let right = exports.findLastInsertionIdx(inputValues, xEnd);\n if (left > 0) {\n --left;\n }\n if (right < inputValues.length()) {\n ++right;\n }\n let lastX = 0;\n if (left < inputValues.length()) {\n lastX = Math.floor(this._xValueToCoord(inputValues.get(left).x));\n --lastX;\n }\n for (let index = left; index < right; ++index) {\n let inputValue = inputValues.get(index);\n let xCoord = Math.floor(this._xValueToCoord(inputValue.x));\n if (xCoord !== lastX) {\n if (currentPoint) {\n this.finalizeBucket(currentPoint);\n this._buckets.push(currentPoint);\n }\n currentPoint = new NEWSDecimationValue();\n this.createNewBucket(currentPoint, inputValue);\n lastX = xCoord;\n }\n else {\n this.addToBucket(currentPoint, inputValue);\n }\n }\n if (currentPoint) {\n this.finalizeBucket(currentPoint);\n this._buckets.push(currentPoint);\n }\n return this._buckets;\n } // decimateValues()\n} // class NEWSDecimator\nexports.NEWSPointDecimator = NEWSPointDecimator;\nNEWSPointDecimator.KEY = 'NEWSPointDecimator';\n/** this class takes a series x, y points and using for each X bucket provides\n * the Y entry/exit/min/max/average for that X bucket\n */\nclass NEWSStateDecimator extends NEWSBaseDecimator {\n constructor(states) {\n super();\n this._weightedSums = {};\n this._prevX = 0;\n this._prevX = 0;\n this._key = NEWSStateDecimator.KEY;\n if (states) {\n this._states = states;\n }\n }\n createNewBucket(decimatedValue, value) {\n this._weightedSums = {};\n decimatedValue._bucketPts = 0;\n let defaultValue;\n if (!this._isYObject) {\n defaultValue = value.y;\n decimatedValue.x = 0;\n decimatedValue.y = defaultValue;\n decimatedValue.entry = defaultValue;\n decimatedValue.exit = defaultValue;\n decimatedValue.min = defaultValue;\n decimatedValue.max = defaultValue;\n }\n this.addToBucket(decimatedValue, value);\n }\n ;\n addToStateValueToBucket(state, value) {\n if (value === 0) {\n return;\n }\n if (!this._weightedSums[state]) {\n this._weightedSums[state] = 0;\n }\n this._weightedSums[state] += value;\n }\n addToBucket(decimatedValue, value) {\n if (this._isYObject) {\n if (this._states) {\n // take prevX and currentX\n for (let stateKey in value.y) {\n this.addToStateValueToBucket(this._states[stateKey], (value.x - this._prevX) * value.y[stateKey]);\n }\n }\n else {\n // take prevX and currentX\n for (let state in value.y) {\n this.addToStateValueToBucket(state, (value.x - this._prevX) * value.y[state]);\n }\n }\n }\n else {\n let state;\n if (this._states) {\n state = this._states[value.y];\n }\n else {\n state = value.y;\n }\n decimatedValue.exit = state;\n this.addToStateValueToBucket(state, (value.x - this._prevX));\n }\n decimatedValue.x += value.x;\n decimatedValue._bucketPts++;\n this._prevX = value.x;\n }\n finalizeBucket(decimatedValue, pointsInBucket) {\n if (undefined !== pointsInBucket) {\n if (pointsInBucket !== decimatedValue._bucketPts) {\n console.log(\"AverageTime: mismatching pt calculation\");\n }\n }\n if (decimatedValue._bucketPts === 0) {\n console.log(\"AverageTime: 0 points\");\n }\n decimatedValue.x = decimatedValue.x / decimatedValue._bucketPts;\n // find the maximum value by weightedSums\n var maxWeightedKey;\n var maxWeightValue = -Number.MAX_VALUE;\n let minState = -Number.MAX_VALUE;\n let maxState = Number.MAX_VALUE;\n for (let state in this._weightedSums) {\n if (this._weightedSums[state] !== undefined) {\n let stateWeight = this._weightedSums[state];\n if (stateWeight > maxWeightValue) {\n maxWeightedKey = state;\n maxWeightValue = stateWeight;\n }\n }\n // min is bigger since Y values increase as you go down the axis\n let yOffset = this._yValueToCoord(state);\n if (yOffset > minState) {\n decimatedValue.min = state;\n minState = yOffset;\n }\n if (yOffset < maxState) {\n decimatedValue.max = state;\n maxState = yOffset;\n }\n }\n let hasValues = maxWeightedKey !== undefined;\n if (hasValues) {\n decimatedValue.y = maxWeightedKey;\n }\n else {\n // no values so set a default a y value\n if (!this._isYObject) {\n decimatedValue.min = decimatedValue.y;\n decimatedValue.max = decimatedValue.y;\n }\n }\n } // finalize );\n /**\n * Values to be decimated\n *\n * @param xStart - start time of the region\n * @param xEnd - start time of the region\n * @param values - Values to be decimated.\n */\n decimateValues(xStart, xEnd, inputValues) {\n // loop over the data samples\n this._buckets = [];\n if (inputValues.length() === 0) {\n return this._buckets;\n }\n let currentPoint;\n let left = exports.findFirstInsertionIdx(inputValues, xStart);\n let right = exports.findLastInsertionIdx(inputValues, xEnd);\n if (left > 0) {\n --left;\n }\n if (right < inputValues.length()) {\n ++right;\n }\n let lastX = 0;\n if (left < inputValues.length()) {\n this._isYObject = typeof (inputValues.get(left).y) === 'object';\n lastX = Math.floor(this._xValueToCoord(inputValues.get(left).x));\n --lastX;\n }\n for (let index = left; index < right; ++index) {\n let inputValue = inputValues.get(index);\n let xCoord = Math.floor(this._xValueToCoord(inputValue.x));\n if (xCoord !== lastX) {\n if (currentPoint) {\n this.finalizeBucket(currentPoint);\n this._buckets.push(currentPoint);\n }\n // add in buckets between the previous bucket and the new bucket since\n // the state spans the whole time\n if (lastX + 1 < xCoord) {\n let point = new NEWSDecimationValue();\n this.createNewBucket(point, inputValue);\n this.finalizeBucket(point);\n point.x = this._xCoordToValue(xCoord - 1);\n this._buckets.push(point);\n this._prevX = point.x;\n }\n currentPoint = new NEWSDecimationValue();\n this.createNewBucket(currentPoint, inputValue);\n lastX = xCoord;\n }\n else {\n this.addToBucket(currentPoint, inputValue);\n }\n }\n if (currentPoint) {\n this.finalizeBucket(currentPoint);\n this._buckets.push(currentPoint);\n }\n return this._buckets;\n } // decimateValues()\n}\nexports.NEWSStateDecimator = NEWSStateDecimator;\nNEWSStateDecimator.KEY = 'NEWSStateDecimator';\n;\nclass FlameChartRectLimitDecimator {\n initialize(xValueToCoord, xCoordToValue, yValueToCoord) {\n this._data = [];\n this._xValueToCoord = xValueToCoord;\n this._xCoordToValue = xCoordToValue;\n this._yValueToCoord = yValueToCoord;\n }\n /**\n * Returns the key of this decimator\n */\n getKey() {\n return FlameChartRectLimitDecimator.KEY;\n }\n /**\n * the name of this decimation scheme\n */\n getName() {\n return '';\n }\n /**\n * Returns the decimated list of data\n */\n getValues() {\n return this._data;\n }\n setRectLimit(rectLimit) {\n this._rectLimit = rectLimit;\n return this;\n }\n /**\n * Values to be decimated\n *\n * @param xStart - start time of the region\n * @param xEnd - start time of the region\n * @param values - Values to be decimated.\n */\n decimateValues(xStart, xEnd, values) {\n // using the whole view\n this._data = [];\n let rects = values.getData();\n for (let i = 0; i < rects.length; ++i) {\n this._data = this._data.concat(rects[i]);\n }\n if (this._rectLimit) {\n this._data.sort(function (a, b) {\n if (a.traceValue.dx > b.traceValue.dx) {\n return -1;\n }\n if (a.traceValue.dx < b.traceValue.dx) {\n return 1;\n }\n return 0;\n });\n this._data = this._data.splice(0, this._rectLimit);\n }\n return this._data;\n }\n}\nexports.FlameChartRectLimitDecimator = FlameChartRectLimitDecimator;\nFlameChartRectLimitDecimator.KEY = 'FlameChartRectLimitDecimator';\n;\n/** this decimator merges the rectangles in a flame chart to combine\n * identical rectangles that are touching on a left/right pixel basis so\n * we can merge them for rendering\n */\nclass FlameChartMergeRectDecimator {\n constructor() {\n this._minRectDelta = 1;\n }\n initialize(xValueToCoord, xCoordToValue, yValueToCoord) {\n this._data = [];\n this._xValueToCoord = xValueToCoord;\n this._xCoordToValue = xCoordToValue;\n this._yValueToCoord = yValueToCoord;\n }\n /**\n * Returns the key of this decimator\n */\n getKey() {\n return FlameChartMergeRectDecimator.KEY;\n }\n /**\n * the name of this decimation scheme\n */\n getName() {\n return '';\n }\n /**\n * Returns the decimated list of data\n */\n getValues() {\n return this._data;\n }\n /**\n * Set the minimum width of a rectangle. If there is multiple trace points\n * within the the minimum width then the data is merged together into\n * a single rectangle. Once all data in a rectangle is merged then we call\n * the [setUserPixelFunction] callback so the the user can modify the value\n * to be rendered if needed\n *\n * @param width the minimum width of a pixel in which data is grouped together\n */\n setPixelWidth(width) {\n this._minRectDelta = width - 1;\n return this;\n }\n setUserPixelFunction(cb) {\n this._userPixelFunction = cb;\n }\n /**\n * used to generate a list of all rects that could be drawn sorted by duration\n */\n mergeRects(values) {\n let ret = [];\n // get the width of a pixel\n let buckets = Math.ceil(this._xValueToCoord(Number.MAX_VALUE)) + 1;\n // NOTE: I do this up here so I can cheat and use the x values here\n // so later I don't keep calling this._xCoordToValue\n let xBucketValues = [];\n for (let bucket = 0; bucket <= buckets; ++bucket) {\n xBucketValues.push(this._xCoordToValue(bucket));\n }\n // get the width of a pixel so we can force it to be visible by\n // making the rect width value 1 full pixel delta wide\n let bucketValueWidth = 0;\n if (buckets > 1) {\n bucketValueWidth = this._xCoordToValue(1) - this._xCoordToValue(0);\n }\n // compute merged rects\n for (let i = 0; i < values.length; ++i) {\n let perLevelData = values[i];\n if (perLevelData === undefined) {\n continue;\n }\n let mergedLevelData = [];\n let prevValue;\n let mergeBucketEnd = -Number.MAX_VALUE;\n let startXCoord;\n let endXCoord;\n // first we walk over all the data and create rects with at least\n // the minimum width which is specified by this._minPixelWidth\n let len = perLevelData.length;\n for (let j = 0; j < len; j++) {\n let value = perLevelData[j];\n // check if you need to do a simple merge with the previous identical rectangle\n if (prevValue && prevValue.traceValue.key === value.traceValue.key &&\n prevValue.traceValue.x + prevValue.traceValue.dx === value.traceValue.x) {\n prevValue.traceValue.dx += value.traceValue.dx;\n continue;\n }\n startXCoord = Math.floor(this._xValueToCoord(value.traceValue.x));\n // check if we already partially counted this sample\n if (mergeBucketEnd > startXCoord) {\n startXCoord = mergeBucketEnd;\n }\n endXCoord = Math.floor(this._xValueToCoord(value.traceValue.x + value.traceValue.dx));\n let fcValue;\n if (endXCoord - startXCoord > this._minRectDelta) {\n // if this single trace value rectangle is wide enough to be rendered by itself\n fcValue = {\n traceValue: {\n x: xBucketValues[startXCoord],\n dx: xBucketValues[endXCoord] - xBucketValues[startXCoord],\n key: value.traceValue.key,\n name: value.traceValue.name,\n desc: value.traceValue.desc,\n },\n decimatedValues: [value.traceValue],\n depth: value.depth\n };\n }\n else {\n // might have to merge with other rectangles\n let subpixelMap = {};\n let valueList = [];\n // set this so we know when to stop merging data for this rectangle\n mergeBucketEnd = startXCoord + this._minRectDelta;\n // add in the initial weight\n if (value.traceValue.x < xBucketValues[startXCoord]) {\n subpixelMap[value.traceValue.name] = value.traceValue.x + value.traceValue.dx - xBucketValues[startXCoord];\n }\n else {\n subpixelMap[value.traceValue.name] = value.traceValue.dx;\n }\n valueList.push(value.traceValue);\n // before adding the next item iterate to a point where the next\n // value starts in the next pixel for the given depth`\n for (++j; j < len; ++j) {\n value = perLevelData[j];\n let localStartXCoord = Math.floor(this._xValueToCoord(value.traceValue.x));\n if (localStartXCoord >= mergeBucketEnd) {\n // back up to the last item that broke the subpixel\n // iteration loop so it can be handled by the outer loop\n --j;\n break;\n }\n else {\n valueList.push(value.traceValue);\n // if we have multiple items in the end pixel add up the\n // the durations and find the one with the most weight\n if (!subpixelMap.hasOwnProperty(value.traceValue.name)) {\n subpixelMap[value.traceValue.name] = 0;\n }\n if (value.traceValue.x + value.traceValue.dx > xBucketValues[mergeBucketEnd]) {\n subpixelMap[value.traceValue.name] += xBucketValues[mergeBucketEnd] - value.traceValue.x;\n // back up to the last item that broke the subpixel\n // iteration loop so it can be handled by the outer loop\n --j;\n break;\n }\n else {\n subpixelMap[value.traceValue.name] += value.traceValue.dx;\n }\n }\n }\n let lastTraceValue = valueList[valueList.length - 1];\n if (valueList.length === 1) {\n // if we have just one item just add it to the trace\n fcValue = {\n traceValue: {\n x: xBucketValues[startXCoord],\n dx: xBucketValues[endXCoord] - xBucketValues[startXCoord],\n key: lastTraceValue.key,\n name: lastTraceValue.name,\n desc: lastTraceValue.desc,\n },\n decimatedValues: valueList,\n depth: value.depth\n };\n }\n else {\n // find the subpixel value with the most weight\n let pixelName;\n let max = 0;\n for (let name in subpixelMap) {\n let groupWeight = subpixelMap[name];\n if (groupWeight > max) {\n pixelName = name;\n max = groupWeight;\n }\n }\n fcValue = {\n traceValue: {\n x: xBucketValues[startXCoord],\n dx: mergeBucketEnd < xBucketValues.length ? xBucketValues[mergeBucketEnd] - xBucketValues[startXCoord] :\n xBucketValues[startXCoord] + bucketValueWidth,\n key: 'merged',\n name: pixelName,\n desc: lastTraceValue.desc,\n },\n decimatedValues: valueList,\n depth: value.depth\n };\n }\n }\n mergedLevelData.push(fcValue);\n // update the last value for this level\n prevValue = fcValue;\n }\n // now that we have computed rects and their the subpixel values\n // if applicable we actually go through and clean things up and then\n // merge the rects for rendering performance\n prevValue = undefined;\n let lastTs = 0;\n let isNewValue = true;\n for (let j = 0; j < mergedLevelData.length; ++j) {\n isNewValue = true;\n let value = mergedLevelData[j];\n if (value.traceValue.dx < bucketValueWidth) {\n // first make the rectangles at least 1 pixel wide\n value.traceValue.dx = bucketValueWidth;\n }\n if (this._userPixelFunction) {\n // let the user clean up the flame chart value if they want\n value = this._userPixelFunction(value);\n }\n // now actually merge the rects\n if (prevValue && prevValue.traceValue.key === value.traceValue.key &&\n prevValue.traceValue.name === value.traceValue.name) {\n lastTs = prevValue.traceValue.x + prevValue.traceValue.dx;\n if (lastTs >= value.traceValue.x) {\n prevValue.traceValue.dx = value.traceValue.x + value.traceValue.dx - prevValue.traceValue.x;\n prevValue.decimatedValues.concat(value.decimatedValues);\n isNewValue = false;\n }\n }\n if (isNewValue) {\n ret.push(value);\n prevValue = value;\n }\n }\n }\n return ret;\n }\n /**\n * Values to be decimated\n *\n * @param xStart - start time of the region\n * @param xEnd - start time of the region\n * @param values - Values to be decimated.\n */\n decimateValues(xStart, xEnd, values) {\n // using the whole view\n this._data = this.mergeRects(values.getData());\n return this._data;\n }\n}\nexports.FlameChartMergeRectDecimator = FlameChartMergeRectDecimator;\nFlameChartMergeRectDecimator.KEY = 'FlameChartMergeRectDecimator';\n;\n/**\n * Takes ITraceValue data and for each bucket returns a residency value\n * by ITracevalue.name. This means the sum of all values within an output bucket is 100.\n */\nclass TraceResidencyDecimator {\n initialize(xValueToCoord, xCoordToValue, yValueToCoord, states) {\n this._decimatedValues = [];\n this._xValueToCoord = xValueToCoord;\n this._xCoordToValue = xCoordToValue;\n this._yValueToCoord = yValueToCoord;\n this._states = states;\n }\n /**\n * Returns the key of this decimator\n */\n getKey() {\n return TraceResidencyDecimator.KEY;\n }\n /**\n * the name of this decimation scheme\n */\n getName() {\n return '';\n }\n /**\n * Returns the decimated list of data\n */\n getValues() {\n return this._decimatedValues;\n }\n /**\n * Values to be decimated\n *\n * @param xStart - start time of the region\n * @param xEnd - start time of the region\n * @param values - Values to be decimated.\n */\n decimateValues(xStart, xEnd, values) {\n this._decimatedValues = new Array(this._states.length).fill(0).map(() => new Array());\n let globalStartBucket = 0;\n let globalEndBucket = Math.ceil(this._xValueToCoord(Number.MAX_VALUE));\n if (globalEndBucket < globalStartBucket) {\n return undefined;\n }\n // this is total weighted sum for each state per x, then used to store percentage per x\n let tempValues = {};\n // map states to return index\n let stateMap = {};\n this._states.forEach((state, index) => {\n stateMap[state] = index;\n tempValues[state] = Array.apply(null, Array(globalEndBucket)).\n map(Number.prototype.valueOf, 0);\n });\n // set up the values for iteration\n // for a series get the weighted sum for the number of buckets xStart to xEnd\n let value;\n let traceEndX;\n let start = exports.findFirstInsertionIdx(values, xStart);\n let end = exports.findLastInsertionIdx(values, xEnd);\n if (start > 0) {\n --start;\n }\n // NOTE: I do this up here so I can cheat and use the x values here\n // so later I don't keep calling this._xCoordToValue\n let xBucketValues = [];\n for (let bucket = 0; bucket <= globalEndBucket; ++bucket) {\n xBucketValues.push(this._xCoordToValue(bucket));\n }\n // this is the amount of x values within a given bucket\n let bucketScalar = 1 / (xBucketValues[globalStartBucket + 1] - xBucketValues[globalStartBucket]);\n // get weighted sum of the values for each bucket\n // note this is forward looking data unlike most of our data so\n // the algorithm is a little different\n for (let rawDataIdx = start; rawDataIdx < end; ++rawDataIdx) {\n value = values.get(rawDataIdx);\n traceEndX = value.x + value.dx;\n let startBucket = Math.floor(this._xValueToCoord(value.x));\n let endBucket = Math.floor(this._xValueToCoord(traceEndX));\n if (startBucket === endBucket) {\n tempValues[value.name][startBucket] += value.dx * bucketScalar;\n // TODO consider we should/can fix this corner case\n // Code below is technically more correct as it handles some edge cases\n // but it's about 3x slower?\n // if (xStart === undefined || (value.x > xStart && traceEndX < xEnd)) {\n // // here it's all in the existing bucket\n // tempValues[value.name][startBucket] += value.dx * bucketScalar;\n // } else if (traceEndX > xStart) {\n // if (traceEndX < xEnd) {\n // // here the back half is in the bucket\n // tempValues[value.name][startBucket] += (traceEndX - xStart) * bucketScalar;\n // } else {\n // // here the front half is in the bucket\n // tempValues[value.name][startBucket] += (xEnd - value.x) * bucketScalar;\n // }\n // }\n }\n else {\n // add in start bucket amount\n let startX = xStart ? Math.max(xStart, value.x) : value.x;\n let endStartBucket = xBucketValues[startBucket + 1];\n tempValues[value.name][startBucket] += (endStartBucket - startX) * bucketScalar;\n // add in all the bucket values in between\n for (let currBucket = startBucket + 1; currBucket < endBucket; ++currBucket) {\n tempValues[value.name][currBucket] += 1;\n }\n // add in end bucket amount\n let endX = xEnd ? Math.min(xEnd, traceEndX) : traceEndX;\n let startEndBucket = xBucketValues[endBucket];\n tempValues[value.name][endBucket] += (endX - startEndBucket) * bucketScalar;\n }\n }\n // create an array that is used when this state wasn't seen at\n // all in the time region.\n let emptyArray = [];\n for (let bucket = 0; bucket < globalEndBucket; ++bucket) {\n emptyArray[bucket] = {\n x: xBucketValues[bucket],\n y: 0\n };\n }\n for (let stateIdx = 0; stateIdx < this._states.length; ++stateIdx) {\n let buckets = tempValues[this._states[stateIdx]];\n if (buckets) {\n for (let bucket = 0; bucket < buckets.length; ++bucket) {\n let y = tempValues[this._states[stateIdx]][bucket] ?\n tempValues[this._states[stateIdx]][bucket] : 0;\n this._decimatedValues[stateIdx][bucket] = {\n x: xBucketValues[bucket],\n y: y * 100\n };\n }\n }\n else {\n this._decimatedValues[stateIdx] = emptyArray;\n }\n }\n return this._decimatedValues;\n }\n}\nexports.TraceResidencyDecimator = TraceResidencyDecimator;\nTraceResidencyDecimator.KEY = 'TraceResidencyDecimator';\n;\n/**\n* Takes ITraceValue data and for each bucket returns a sum by ITracevalue.name.\n* This means the sum of all values within an output bucket is 100.\n*/\nclass TraceStateDecimator {\n initialize(xValueToCoord, xCoordToValue, yValueToCoord, states) {\n this._decimatedValues = [];\n this._xValueToCoord = xValueToCoord;\n this._xCoordToValue = xCoordToValue;\n this._yValueToCoord = yValueToCoord;\n this._states = states;\n }\n /**\n * Returns the key of this decimator\n */\n getKey() {\n return TraceStateDecimator.KEY;\n }\n /**\n * the name of this decimation scheme\n */\n getName() {\n return '';\n }\n /**\n * Returns the decimated list of data\n */\n getValues() {\n return this._decimatedValues;\n }\n /**\n * Values to be decimated\n *\n * @param xStart - start time of the region\n * @param xEnd - start time of the region\n * @param values - Values to be decimated.\n */\n decimateValues(xStart, xEnd, values) {\n let globalStartBucket = 0;\n let globalEndBucket = Math.ceil(this._xValueToCoord(Number.MAX_VALUE));\n if (globalEndBucket < globalStartBucket) {\n return undefined;\n }\n // set up the values for iteration\n // for a series get the weighted sum for the number of buckets xStart to xEnd\n let value;\n let traceEndX;\n let start = exports.findFirstInsertionIdx(values, xStart);\n let end = exports.findLastInsertionIdx(values, xEnd);\n if (start > 0) {\n --start;\n }\n // NOTE: I do this up here so I can cheat and use the x values here\n // so later I don't keep calling this._xCoordToValue\n this._decimatedValues = [];\n for (let bucket = 0; bucket <= globalEndBucket; ++bucket) {\n this._decimatedValues[bucket] = new NEWSDecimationValue(this._xCoordToValue(bucket));\n }\n let states = {};\n this._states.forEach((state, i) => {\n states[state] = i;\n });\n // store the entry/exit/min/max of each bucket\n // min and max are based on the state index\n for (let rawDataIdx = start; rawDataIdx < end; ++rawDataIdx) {\n value = values.get(rawDataIdx);\n traceEndX = value.x + value.dx;\n let startBucket = Math.floor(this._xValueToCoord(value.x));\n let endBucket = Math.floor(this._xValueToCoord(traceEndX));\n if (!this._decimatedValues[startBucket].entry) {\n this._decimatedValues[startBucket].entry = states[value.name];\n this._decimatedValues[startBucket].exit = states[value.name];\n this._decimatedValues[startBucket].min = states[value.name];\n this._decimatedValues[startBucket].max = states[value.name];\n }\n if (startBucket === endBucket) {\n this._decimatedValues[startBucket].exit = states[value.name];\n this._decimatedValues[startBucket].min =\n Math.min(this._decimatedValues[startBucket].min, states[value.name]);\n this._decimatedValues[startBucket].max =\n Math.max(this._decimatedValues[startBucket].max, states[value.name]);\n }\n else {\n // start bucket exit\n this._decimatedValues[startBucket].exit = states[value.name];\n this._decimatedValues[startBucket].min =\n Math.min(this._decimatedValues[startBucket].min, states[value.name]);\n this._decimatedValues[startBucket].max =\n Math.max(this._decimatedValues[startBucket].max, states[value.name]);\n // add in all the bucket values in between\n for (let currBucket = startBucket + 1; currBucket <= endBucket; ++currBucket) {\n this._decimatedValues[currBucket].entry = states[value.name];\n this._decimatedValues[currBucket].exit = states[value.name];\n this._decimatedValues[currBucket].min = states[value.name];\n this._decimatedValues[currBucket].max = states[value.name];\n }\n }\n }\n // convert state index to actual state names for rendering\n for (let i = 0; i < this._decimatedValues.length; ++i) {\n let newsValue = this._decimatedValues[i];\n let exit = newsValue.exit;\n newsValue.entry = this._states[newsValue.entry];\n newsValue.exit = this._states[exit];\n newsValue.y = this._states[exit];\n newsValue.min = this._states[newsValue.min];\n newsValue.max = this._states[newsValue.max];\n }\n return this._decimatedValues;\n }\n}\nexports.TraceStateDecimator = TraceStateDecimator;\nTraceStateDecimator.KEY = 'TraceStateDecimator';\n;\n/**\n * For a marker layer just removes markers that have the same X value\n */\nclass SimpleMarkerDecimator {\n initialize(xValueToCoord, xCoordToValue, yValueToCoord) {\n this._data = [];\n this._xValueToCoord = xValueToCoord;\n this._xCoordToValue = xCoordToValue;\n this._yValueToCoord = yValueToCoord;\n }\n /**\n * Returns the key of this decimator\n */\n getKey() {\n return SimpleMarkerDecimator.KEY;\n }\n /**\n * the name of this decimation scheme\n */\n getName() {\n return '';\n }\n /**\n * Returns the decimated list of data\n */\n getValues() {\n return this._data;\n }\n mergeMarkers(values) {\n let ret = [];\n let lastCoord = -Number.MAX_VALUE;\n for (let i = 0; i < values.length; ++i) {\n let value = values[i];\n let coord = this._xValueToCoord(value.x);\n if (coord !== lastCoord) {\n ret.push(value);\n lastCoord = coord;\n }\n }\n return ret;\n }\n /**\n * Values to be decimated\n *\n * @param xStart - start time of the region\n * @param xEnd - start time of the region\n * @param values - Values to be decimated.\n */\n decimateValues(xStart, xEnd, values) {\n let allData = values.getData();\n // using the whole view\n if (xStart !== undefined && xEnd !== undefined) {\n let filteredData = [];\n for (let i = 0; i < allData.length; ++i) {\n let value = allData[i];\n if (value.x < xEnd && value.x > xStart) {\n filteredData.push(value);\n }\n else if (value.dx && value.x + value.dx < xEnd &&\n value.x + value.dx > xStart) {\n filteredData.push(value);\n }\n }\n this._data = this.mergeMarkers(filteredData);\n }\n else {\n this._data = this.mergeMarkers(allData);\n }\n return this._data;\n }\n}\nexports.SimpleMarkerDecimator = SimpleMarkerDecimator;\nSimpleMarkerDecimator.KEY = 'SimpleMarkerDecimator';\n;\n/** */\nclass XYHeatMapDecimator {\n constructor() {\n }\n /**\n * construct a generic decimator using a custom user function\n *\n * @param xValueToCoord converts the x value to a GUI x coordinate\n * @param yValueToCoord converts the y value to a GUI y coordinate\n * @param decimationFunc convert a list of data to a for rendering smaller list\n */\n initialize(xValueToCoord, xCoordToValue, yValueToCoord) {\n this._xValueToCoord = xValueToCoord;\n this._xCoordToValue = xCoordToValue;\n this._yValueToCoord = yValueToCoord;\n }\n /**\n * Returns the key of this decimator\n */\n getKey() {\n return SummedValueMultiXYSeriesDecimator.KEY;\n }\n /**\n * Returns the decimated list of buckets\n */\n getName() {\n return '';\n }\n /**\n * Returns the decimated list of buckets\n */\n getValues() {\n return this._decimatedValues;\n }\n /**\n * Values to be decimated\n *\n * @param xStart - start time of the region\n * @param xEnd - start time of the region\n * @param values - Values to be decimated.\n */\n decimateValues(xStart, xEnd, values) {\n this._decimatedValues = [];\n // first this is total weighted sum per x, then used to store percentage per x\n let tempValues = [];\n let globalStartBucket = 0;\n let globalEndBucket = Math.ceil(this._xValueToCoord(Number.MAX_VALUE));\n if (globalEndBucket < globalStartBucket) {\n return undefined;\n }\n // NOTE: I do this up here so I can cheat and use the x values here\n // so later I don't keep calling _xCoordToValue\n let xBucketValues = [];\n for (let bucket = 0; bucket <= globalEndBucket + 1; ++bucket) {\n xBucketValues.push(this._xCoordToValue(bucket));\n }\n // for a series get the weighted sum for the number of buckets xStart to xEnd\n for (let stateIdx = 0; stateIdx < values.length; ++stateIdx) {\n let perStateData = values[stateIdx];\n let value;\n let nextValue;\n let start = exports.findFirstInsertionIdx(values[stateIdx], xStart);\n let end = exports.findLastInsertionIdx(values[stateIdx], xEnd);\n if (start > 0) {\n --start;\n }\n // the last element would be caught by the algorithm already\n if (end === perStateData.length()) {\n --end;\n }\n // pad endBucket + 1 so we get data past the last point in the bucket\n // so we can graph to the first value in the next bucket\n tempValues[stateIdx] = Array.apply(null, Array(globalEndBucket)).\n map(Number.prototype.valueOf, 0);\n // get weighted sum of the values for each bucket\n for (let rawDataIdx = start; rawDataIdx < end; ++rawDataIdx) {\n value = perStateData.get(rawDataIdx);\n nextValue = perStateData.get(rawDataIdx + 1);\n let startBucket = Math.floor(this._xValueToCoord(value.x));\n let endBucket = Math.floor(this._xValueToCoord(nextValue.x));\n let totalX = (nextValue.x - value.x);\n let valuePerX = totalX === 0 ? 0 : nextValue.y / totalX;\n if (startBucket === endBucket) {\n if (xStart === undefined || (value.x > xStart && nextValue.x < xEnd)) {\n // here it's all in the existing bucket\n tempValues[stateIdx][startBucket] += valuePerX;\n }\n else {\n let bucketScalar = 1 / (xBucketValues[startBucket + 1] - xBucketValues[startBucket]);\n if (nextValue.x < xEnd) {\n // here the back half is in the bucket\n tempValues[stateIdx][startBucket] +=\n (nextValue.x - xBucketValues[startBucket]) * valuePerX * bucketScalar;\n }\n else {\n // here the front half is in the bucket\n tempValues[stateIdx][startBucket] +=\n (xBucketValues[startBucket + 1] - value.x) * valuePerX * bucketScalar;\n }\n }\n }\n else {\n let bucketScalar = 1 / (xBucketValues[startBucket + 1] - xBucketValues[startBucket]);\n let startX = xStart ? Math.max(xStart, value.x) : value.x;\n let endStartBucket = xBucketValues[startBucket + 1];\n tempValues[stateIdx][startBucket] +=\n (endStartBucket - startX) * valuePerX * bucketScalar;\n // add in all the bucket values in between\n for (let currBucket = startBucket + 1; currBucket < endBucket; ++currBucket) {\n tempValues[stateIdx][currBucket] += valuePerX;\n }\n // add in end bucket amount\n bucketScalar = 1 / (xBucketValues[endBucket] - xBucketValues[endBucket - 1]);\n let endX = xEnd ? Math.min(xEnd, nextValue.x) : nextValue.x;\n let startEndBucket = xBucketValues[endBucket];\n tempValues[stateIdx][endBucket] +=\n (endX - startEndBucket) * valuePerX * bucketScalar;\n }\n }\n this._decimatedValues[stateIdx] = [];\n let buckets = tempValues[stateIdx];\n for (let bucket = 0; bucket < buckets.length; ++bucket) {\n this._decimatedValues[stateIdx][bucket] = {\n x: xBucketValues[bucket],\n y: tempValues[stateIdx][bucket] ? tempValues[stateIdx][bucket] : 0\n };\n }\n }\n return this._decimatedValues;\n }\n}\nexports.XYHeatMapDecimator = XYHeatMapDecimator;\nXYHeatMapDecimator.KEY = 'XYHeatMapDecimator';\n;\nlet decimatorList = [\n new ResidencyDecimator(), new MinPointDecimator(),\n new AvgPointDecimator(), new MaxPointDecimator(), new AvgContinuousDecimator(),\n new FlameChartMergeRectDecimator(), new FlameChartRectLimitDecimator(),\n new NEWSPointDecimator(), new NEWSStateDecimator(), new SimpleMarkerDecimator(),\n new XYPointDecimator(), new SummedValueXYSeriesDecimator(),\n new SummedValueMultiXYSeriesDecimator(), new TraceResidencyDecimator()\n];\nexports.InternalDecimatorMap = {};\ndecimatorList.forEach(function (decimator) {\n exports.InternalDecimatorMap[decimator.getKey()] = decimator;\n});\n\n\n//# sourceURL=webpack://UWT/./src/core/cartesian/decimator/decimator.ts?");
/***/ }),
/***/ "./src/core/cartesian/decimator/worker.ts":
/*!************************************************!*\
!*** ./src/core/cartesian/decimator/worker.ts ***!
\************************************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
eval("\nObject.defineProperty(exports, \"__esModule\", { value: true });\nconst axis_1 = __webpack_require__(/*! ../../../interface/chart/axis */ \"./src/interface/chart/axis.ts\");\nconst utilities_1 = __webpack_require__(/*! ../../utilities */ \"./src/core/utilities.ts\");\nconst decimator_1 = __webpack_require__(/*! ./decimator */ \"./src/core/cartesian/decimator/decimator.ts\");\nconst d3 = __webpack_require__(/*! d3 */ \"d3\");\n// Worker.ts\nconst ctx = self;\n// Respond to message from parent thread\nctx.addEventListener(\"message\", (message) => {\n let xScale;\n let yScale;\n let def = message.data;\n if (def.xAxis.axisDesc.scaleType === axis_1.AxisType.Ordinal) {\n xScale = d3.scaleBand().range([0, def.xRange]).padding(0.1)\n .align(0.5).domain(def.xDomain);\n }\n else {\n if (def.xAxis.axisDesc.scaleType === axis_1.AxisType.Linear) {\n xScale = d3.scaleLinear().domain(def.xDomain).clamp(true);\n }\n else if (def.xAxis.axisDesc.scaleType === axis_1.AxisType.Logarithmic) {\n xScale = d3.scaleLog().domain(def.xDomain).clamp(true);\n }\n xScale.range([0, def.xRange]);\n }\n if (def.yAxis) {\n if (def.yAxis.axisDesc.scaleType === axis_1.AxisType.Ordinal) {\n yScale = d3.scaleBand().range([0, def.yRange]).padding(0.1)\n .align(0.5).domain(def.yDomain);\n }\n else {\n if (def.yAxis.axisDesc.scaleType === axis_1.AxisType.Linear) {\n yScale = d3.scaleLinear().domain(def.yDomain).clamp(true);\n }\n else if (def.yAxis.axisDesc.scaleType === axis_1.AxisType.Logarithmic) {\n yScale = d3.scaleLog().domain(def.yDomain).clamp(true);\n }\n yScale.range([def.yRange, 0]);\n }\n }\n let decimator = decimator_1.InternalDecimatorMap[def.decimatorName];\n decimator.initialize(xScale, xScale.invert, yScale, def.names);\n // ugly hardcode for now\n let values;\n if (!def.names) {\n values = new utilities_1.SimpleBuffer(def.values);\n }\n else {\n values = [];\n for (let i = 0; i < def.values.length; ++i) {\n values[i] = new utilities_1.SimpleBuffer(def.values[i]);\n }\n }\n let data = decimator.decimateValues(def.xStart, def.xEnd, values);\n ctx.postMessage(data, undefined);\n});\n\n\n//# sourceURL=webpack://UWT/./src/core/cartesian/decimator/worker.ts?");
/***/ }),
/***/ "./src/core/data.ts":
/*!**************************!*\
!*** ./src/core/data.ts ***!
\**************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
eval("\nObject.defineProperty(exports, \"__esModule\", { value: true });\n/**\n* XYValue\n*\n* Class for simple data that will be rendered as part of a chart\n*/\nclass XYValue {\n /**\n * Creates a XYValue instance\n *\n * @param x the independent axis coordinate\n * @param y the dependent axis coordinate\n */\n constructor(x, y) {\n this.x = x;\n this.y = y;\n }\n} // XYValue\nexports.XYValue = XYValue;\n/**\n * MinMaxValue\n *\n * Class for candlestick data that will be rendered as part of a chart\n */\nclass MinMaxValue {\n /**\n * Creates a MinMaxValue instance\n *\n * @param key - the axis co-ordinate which will be x co-ordinate\n * @param min - the minimum value of metric for the axis co-ordinate\n * @param max - the maximum value of metric for the axis co-ordinate\n * @param misc - a misc value of metric for the axis co-ordinate\n */\n constructor(x, min, max, misc) {\n this.x = x;\n this.min = min;\n this.max = max;\n this.y = misc;\n }\n} // MinMaxValue\nexports.MinMaxValue = MinMaxValue;\n/**\n * CandlestickValue\n *\n * Class for candlestick data that will be rendered as part of a chart\n */\nclass CandlestickValue {\n /**\n * Creates a CandlestickValue instance\n *\n * @param x - the axis co-ordinate which will be x co-ordinate\n * @param min - the minimum value of metric for the axis co-ordinate\n * @param max - the maximum value of metric for the axis co-ordinate\n * @param entry - the entry value of metric for the axis co-ordinate\n * @param exit - the exit value of metric for the axis co-ordinate\n */\n constructor(x, min, max, entry, exit) {\n this.x = x;\n this.min = min;\n this.max = max;\n this.entry = entry;\n this.exit = exit;\n }\n} // CandlestickValue\nexports.CandlestickValue = CandlestickValue;\n/**\n * SummaryValue class\n */\nclass SummaryValue {\n /**\n * SummaryValue class\n *\n * @param primaryKey - key for the data\n * @param value - value for this key\n * @param secondaryKey - optional secondary key for the data\n */\n constructor(key, value = {}) {\n this.key = key;\n this.data = value;\n }\n /**\n * Value getter\n *\n * @returns add a value to this key\n */\n addValue(key, value) {\n let data = this.data;\n if (data.hasOwnProperty(key)) {\n data[key] += value;\n }\n else {\n data[key] = value;\n }\n return this;\n }\n} // class SummaryValue\nexports.SummaryValue = SummaryValue;\n\n\n//# sourceURL=webpack://UWT/./src/core/data.ts?");
/***/ }),
/***/ "./src/core/utilities.ts":
/*!*******************************!*\
!*** ./src/core/utilities.ts ***!
\*******************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
eval("\nObject.defineProperty(exports, \"__esModule\", { value: true });\nfunction getSelectionName(className) {\n if (typeof (className) === 'number') {\n return 'n' + className;\n }\n if (!className) {\n return '';\n }\n if (className.length > 0 && !isNaN(Number(className[0]))) {\n className = 'z' + className;\n }\n className = className.replace(/[\\*\\%\\#\\[\\]\\/\\>\\<\\s\\+\\(\\)\\;\\@\\:\\?\\\"=.,]/g, '-');\n return className;\n}\nexports.getSelectionName = getSelectionName;\nfunction removeFromList(value, arr) {\n if (value) {\n let index = arr.indexOf(value);\n if (index !== -1) {\n arr.splice(index, 1);\n }\n }\n}\nexports.removeFromList = removeFromList;\n/** taken from d3-array */\nfunction ascending(a, b) {\n return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;\n}\n/** taken from d3-array */\nfunction ascendingComparator(f) {\n return function (d, x) {\n return ascending(f(d), x);\n };\n}\n/** modified from d3-array */\nfunction bisect(compare) {\n if (!compare)\n compare = ascending;\n if (compare.length === 1)\n compare = ascendingComparator(compare);\n return {\n left: function (a, x, lo, hi) {\n if (lo == null)\n lo = 0;\n if (hi == null)\n hi = a.length;\n while (lo < hi) {\n var mid = lo + hi >>> 1;\n if (compare(a[mid], x) < 0)\n lo = mid + 1;\n else\n hi = mid;\n }\n return lo;\n },\n right: function (a, x, lo, hi) {\n if (lo == null)\n lo = 0;\n if (hi == null)\n hi = a.length;\n while (lo < hi) {\n var mid = lo + hi >>> 1;\n if (compare(a[mid], x) > 0)\n hi = mid;\n else\n lo = mid + 1;\n }\n return lo;\n }\n };\n}\nexports.bisect = bisect;\n/** puts all raw data into buckets based on thresholds and values */\nfunction bucketData(values, thresholds, accessor) {\n let findRight = bisect().right;\n let buckets = [];\n // need one less bucket than thresholds\n for (let i = 0; i < thresholds.length - 1; ++i) {\n buckets[i] = [];\n }\n let min = thresholds[0];\n let max = thresholds[thresholds.length - 1];\n let usedThresholds = thresholds.slice(1);\n for (let i = 0; i < values.length; ++i) {\n let compareValue = accessor(values[i]);\n if (compareValue < min || compareValue > max) {\n continue;\n }\n let valueIdx = findRight(usedThresholds, compareValue);\n buckets[valueIdx].push(values[i]);\n }\n // name the return buckets\n let ret = {};\n for (let i = 0; i < thresholds.length - 1; ++i) {\n let bucketName = thresholds[i] + '-' + thresholds[i + 1];\n ret[bucketName] = buckets[i];\n }\n return ret;\n}\nexports.bucketData = bucketData;\nfunction copy(obj) {\n let ret = {};\n for (let key in obj) {\n ret[key] = obj[key];\n }\n return ret;\n}\nexports.copy = copy;\nfunction merge(obj1, obj2) {\n for (let key in obj2) {\n obj1[key] = obj2[key];\n }\n}\nexports.merge = merge;\nfunction convertTraceToTrees(input) {\n let roots = [];\n let stack = []; // used to represent the current stack state\n let nodeStack = []; // used to represent the current stack state\n for (let i = 0; i < input.length; i++) {\n let value = input[i];\n let parent = stack[stack.length - 1];\n // pop stuff off the stack\n while (stack.length && value.x > parent.x + parent.dx) {\n --stack.length;\n --nodeStack.length;\n parent = stack[stack.length - 1];\n }\n let parentNode = nodeStack[nodeStack.length - 1];\n let node = {\n key: value.key,\n value: value.dx,\n children: [],\n parent: parentNode\n };\n if (value.name) {\n node.name = value.name;\n }\n if (parentNode) {\n parentNode.children.push(node);\n }\n else {\n roots.push(node);\n }\n stack.push(value);\n nodeStack.push(node);\n }\n return roots;\n}\nexports.convertTraceToTrees = convertTraceToTrees;\nclass SimpleBuffer {\n constructor(data) {\n if (data) {\n this._data = data;\n }\n else {\n this._data = [];\n }\n }\n push(d) {\n this._data.push(d);\n }\n get(index) {\n return this._data[index];\n }\n length() {\n return this._data.length;\n }\n getData() {\n return this._data;\n }\n}\nexports.SimpleBuffer = SimpleBuffer;\nclass RingBuffer {\n constructor(size) {\n this._data = new Array(size);\n this._startIdx = 0;\n this._count = 0;\n this._isRotating = false;\n }\n /** add a new value to the buffer */\n push(d) {\n if (this._isRotating) {\n // the buffer is rotating\n this._data[this._startIdx] = d;\n ++this._startIdx;\n if (this._startIdx === this._count) {\n this._startIdx = 0;\n }\n this._isRotating = true;\n }\n else if (this._count === this._data.length - 1) {\n // here the buffer will start rotating as the buffer is full\n this._data[this._count] = d;\n ++this._count;\n this._isRotating = true;\n }\n else {\n // here the buffer has not been filled yet\n this._data[this._count] = d;\n ++this._count;\n }\n }\n /** return the value offset index from the start index\n * @param index the offset from the start of the buffer\n */\n get(index) {\n if (this._isRotating) {\n // the buffer is rotating\n index = index + this._startIdx;\n if (index >= this._count) {\n index = index - this._count;\n }\n }\n return this._data[index];\n }\n /** get the number of items in the buffer */\n length() {\n return this._count;\n }\n getData() {\n if (this._isRotating) {\n // the buffer is rotating\n let ret = [];\n for (let i = this._startIdx; i < this._data.length; ++i) {\n ret.push(this._data[i]);\n }\n for (let i = 0; i < this._startIdx; ++i) {\n ret.push(this._data[i]);\n }\n return ret;\n }\n return this._data;\n }\n}\nexports.RingBuffer = RingBuffer;\nfunction bisectBuffer(compare) {\n if (!compare)\n compare = ascending;\n if (compare.length === 1)\n compare = ascendingComparator(compare);\n return {\n left: function (a, x, lo, hi) {\n if (lo == null)\n lo = 0;\n if (hi == null)\n hi = a.length();\n while (lo < hi) {\n var mid = lo + hi >>> 1;\n if (compare(a.get(mid), x) < 0)\n lo = mid + 1;\n else\n hi = mid;\n }\n return lo;\n },\n right: function (a, x, lo, hi) {\n if (lo == null)\n lo = 0;\n if (hi == null)\n hi = a.length();\n while (lo < hi) {\n var mid = lo + hi >>> 1;\n if (compare(a.get(mid), x) > 0)\n hi = mid;\n else\n lo = mid + 1;\n }\n return lo;\n }\n };\n}\nexports.bisectBuffer = bisectBuffer;\nfunction transposeKeys(data) {\n // this is used to map the keys to their indicies in the output summary data\n let keyIdxMapping = {};\n function transposeHelper(output, parentKeys, value, level) {\n let myKeys = [];\n for (let i = 0; i < parentKeys.length; ++i) {\n myKeys[i] = parentKeys[i];\n }\n myKeys.push(value.key);\n if (Array.isArray(value.data)) {\n for (let i = 0; i < value.data.length; ++i) {\n transposeHelper(output, myKeys, value.data[i], level + 1);\n }\n }\n else {\n let currSummaryArray = output;\n for (let keyIdx = myKeys.length - 1; keyIdx >= 0; --keyIdx) {\n let key = myKeys[keyIdx];\n let dataIdx;\n if (!keyIdxMapping.hasOwnProperty(key)) {\n dataIdx = currSummaryArray.length;\n keyIdxMapping[key] = dataIdx;\n }\n else {\n dataIdx = keyIdxMapping[key];\n }\n // create the summary data if it doesn't exist yet\n if (!currSummaryArray[dataIdx]) {\n currSummaryArray[dataIdx] = { key: key, data: [] };\n }\n // if we are the leaf add the data, else just move to the next level\n if (keyIdx === 0) {\n currSummaryArray[dataIdx].data = value.data;\n }\n else {\n currSummaryArray = currSummaryArray[dataIdx].data;\n }\n }\n }\n }\n let output = [];\n for (let i = 0; i < data.length; ++i) {\n transposeHelper(output, [], data[i], 0);\n }\n return output;\n}\nexports.transposeKeys = transposeKeys;\nfunction runFunctionOnLeaf(node, func) {\n if (node && node.children && node.children.length > 0) {\n for (let i = 0; i < node.children.length; ++i) {\n runFunctionOnLeaf(node.children[i], func);\n }\n }\n else {\n func(node);\n }\n}\nexports.runFunctionOnLeaf = runFunctionOnLeaf;\nfunction isOverlapping(rect1, rect2) {\n return rect1.x <= rect2.right && rect1.right >= rect2.x &&\n rect1.y <= rect2.bottom && rect1.bottom >= rect2.y;\n}\nexports.isOverlapping = isOverlapping;\n\n\n//# sourceURL=webpack://UWT/./src/core/utilities.ts?");
/***/ }),
/***/ "./src/interface/chart/axis.ts":
/*!*************************************!*\
!*** ./src/interface/chart/axis.ts ***!
\*************************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
eval("\nObject.defineProperty(exports, \"__esModule\", { value: true });\n/**\n * defines what type of axis scaling to use\n *\n * @enum {number}\n */\nvar AxisType;\n(function (AxisType) {\n /** continuous axis of data with a linear scale */\n AxisType[AxisType[\"Linear\"] = 0] = \"Linear\";\n /** continuous axis of data with a logarithmic (base 10) scale */\n AxisType[AxisType[\"Logarithmic\"] = 1] = \"Logarithmic\";\n /** axis of data with discrete values that are enumerated or derived from the data */\n AxisType[AxisType[\"Ordinal\"] = 2] = \"Ordinal\";\n})(AxisType = exports.AxisType || (exports.AxisType = {})); // enum AxisType\n\n\n//# sourceURL=webpack://UWT/./src/interface/chart/axis.ts?");
/***/ }),
/***/ "d3":
/*!*********************!*\
!*** external "d3" ***!
\*********************/
/*! no static exports found */
/***/ (function(module, exports) {
eval("module.exports = __WEBPACK_EXTERNAL_MODULE_d3__;\n\n//# sourceURL=webpack://UWT/external_%22d3%22?");
/***/ })
/******/ });
});