UNPKG

@future-grid/fgp-graph

Version:

fgp-graph is a chart lib based on Dygraphs

1,368 lines (1,107 loc) 366 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.GraphOperator = exports.DomElementOperator = void 0; var _dygraphs = _interopRequireDefault(require("dygraphs")); var _configurations = require("../metadata/configurations"); var _momentTimezone = _interopRequireDefault(require("moment-timezone")); var _synchronizer = require("../extras/synchronizer"); var _dataService = require("../services/dataService"); var _interactions = require("../extras/interactions"); var _formatters = require("../extras/formatters"); var _colorService = require("../services/colorService"); var _Toolbar = _interopRequireDefault(require("../extras/toolbar/Toolbar")); var _RangeHandles = _interopRequireDefault(require("../extras/RangeHandles")); var _RectSelection = _interopRequireDefault(require("../extras/toolbar/RectSelection")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } var DomElementOperator = function DomElementOperator() { _classCallCheck(this, DomElementOperator); }; exports.DomElementOperator = DomElementOperator; _defineProperty(DomElementOperator, "createElement", function (type, attrs) { var dom = document.createElement(type); var errorHappened = false; // put attributes on element attrs.forEach(function (attr) { // check the attribute, if exist then throw exception if (!dom.getAttribute(attr.key)) { dom.setAttribute(attr.key, attr.value); } else { throw new Error("Duplicate Attrs " + attr.key); } }); return dom; }); var GraphOperator = function GraphOperator(_mainGraph, rangeGraph, graphContainer, graphBody, datewindowCallback, fgpGraph, eventListeners, _id) { var _this = this; var needSync = arguments.length > 8 && arguments[8] !== undefined ? arguments[8] : true; _classCallCheck(this, GraphOperator); _defineProperty(this, "graphId", void 0); _defineProperty(this, "defaultGraphRanges", [{ name: "3 days", value: 1000 * 60 * 60 * 24 * 3, show: true }, { name: "7 days", value: 604800000, show: true }, { name: "1 month", value: 2592000000, show: false }]); _defineProperty(this, "createElement", function (type, attrs) { var dom = document.createElement(type); // put attributes on element attrs.forEach(function (attr) { dom.setAttribute(attr.key, attr.value); }); return dom; }); _defineProperty(this, "mainGraph", void 0); _defineProperty(this, "rangebarGraph", void 0); _defineProperty(this, "currentView", void 0); _defineProperty(this, "currentCollection", void 0); _defineProperty(this, "rangeCollection", void 0); _defineProperty(this, "start", void 0); _defineProperty(this, "end", void 0); _defineProperty(this, "datewindowCallback", void 0); _defineProperty(this, "currentDateWindow", void 0); _defineProperty(this, "currentGraphData", void 0); _defineProperty(this, "graphContainer", void 0); _defineProperty(this, "graphBody", void 0); _defineProperty(this, "spinner", void 0); _defineProperty(this, "xBoundary", void 0); _defineProperty(this, "yAxisBtnArea", void 0); _defineProperty(this, "y2AxisBtnArea", void 0); _defineProperty(this, "lockedInterval", void 0); _defineProperty(this, "eventListeners", void 0); _defineProperty(this, "graphInstance", void 0); _defineProperty(this, "toolbar", void 0); _defineProperty(this, "rectSelection", void 0); _defineProperty(this, "colorLocked", false); _defineProperty(this, "needSync", false); _defineProperty(this, "axesConfig", void 0); _defineProperty(this, "yScaleBtns", { 'left': undefined, 'right': undefined }); _defineProperty(this, "yScaleLockStatus", { 'left': { lock: true, value: [NaN, NaN] }, 'right': { lock: true, value: [NaN, NaN] } }); _defineProperty(this, "recreateElement", function (el, withChildren) { if (withChildren && el) { if (el.parentNode) { el.parentNode.replaceChild(el.cloneNode(true), el); } } else if (el && el.parentNode) { var newEl = el.cloneNode(false); while (el.hasChildNodes() && el.firstChild) { newEl.appendChild(el.firstChild); } el.parentNode.replaceChild(newEl, el); } }); _defineProperty(this, "showSpinner", function () { if (_this.spinner) { _this.spinner.show(); } }); _defineProperty(this, "highlightSeries", function (series, duration, type) { var visibility = _this.mainGraph.getOption("visibility"); var formatters = new _formatters.Formatters(_this.currentView.timezone ? _this.currentView.timezone : _momentTimezone["default"].tz.guess()); var ranges = _this.mainGraph.yAxisRanges(); if (series && series.length > 0) { // check entities var seriesInGraph = []; series.forEach(function (_series) { // var existEntity = _this.currentView.graphConfig.entities.find(function (entity) { return entity.id === _series; }); if (existEntity) { seriesInGraph.push(existEntity.name); } }); if (type && type === "selection" && seriesInGraph.length > 0) { // convert it to normal graph var _graph = _this.mainGraph; _graph.setSelection(false, seriesInGraph[0]); } else if (seriesInGraph.length > 0) { // update "series" dropdown // hide all the others var _updateVisibility = []; if (_this.currentCollection) { var _graphSeries = _this.mainGraph.getLabels(); // get indexes var _indexsShow = []; _graphSeries.forEach(function (_series, _index) { // if (_index != 0) { seriesInGraph.forEach(function (_showSeries, _showIndex) { if (_showSeries === _series) { _indexsShow.push(_index - 1); } }); } }); if (_indexsShow.length === 0) { // not found // set visibility visibility.forEach(function (_v, _i) { _updateVisibility.push(true); }); } else { // set visibility visibility.forEach(function (_v, _i) { if (_indexsShow.indexOf(_i) == -1) { _v = false; } var exist = false; _indexsShow.forEach(function (_ei) { if (_ei === _i) { // found it exist = true; } }); if (!exist) { _updateVisibility.push(false); } else { _updateVisibility.push(true); } }); } _this.mainGraph.updateOptions({ visibility: _updateVisibility, axes: { x: { axisLabelFormatter: formatters.axisLabel }, y: { valueRange: ranges[0], axisLabelWidth: 80 }, y2: ranges.length > 1 ? { valueRange: ranges[1], axisLabelWidth: 80 } : undefined } }); if (duration > 0) { // take all visibility back setTimeout(function () { _updateVisibility = []; visibility.forEach(function (_v) { _updateVisibility.push(true); }); _this.mainGraph.updateOptions({ visibility: _updateVisibility, axes: { x: { axisLabelFormatter: formatters.axisLabel }, y: { valueRange: ranges[0], axisLabelWidth: 80 }, y2: ranges.length > 1 ? { valueRange: ranges[1], axisLabelWidth: 80 } : undefined } }); }, duration * 1000); } } } } else { // bring all back var _updateVisibility2 = []; visibility.forEach(function (_v) { _updateVisibility2.push(true); }); _this.mainGraph.updateOptions({ visibility: _updateVisibility2, axes: { x: { axisLabelFormatter: formatters.axisLabel }, y: { valueRange: ranges[0], axisLabelWidth: 80 }, y2: ranges.length > 1 ? { valueRange: ranges[1], axisLabelWidth: 80 } : undefined } }); } }); _defineProperty(this, "init", function (view, readyCallback, interactionCallback) { var _this$currentView$int, _this$currentView$int2; _this.currentView = view; var formatters = new _formatters.Formatters(_this.currentView.timezone ? _this.currentView.timezone : _momentTimezone["default"].tz.guess()); var entities = []; var bottomAttrs = [{ key: 'class', value: 'fgp-graph-bottom' }]; var bottom = null; _this.currentView.graphConfig.entities.forEach(function (entity) { if (!entity.fragment) { entities.push(entity.id); } }); // bind rect selection _this.rectSelection = new _RectSelection["default"](); if (_this.rectSelection && ((_this$currentView$int = _this.currentView.interaction) === null || _this$currentView$int === void 0 ? void 0 : (_this$currentView$int2 = _this$currentView$int.callback) === null || _this$currentView$int2 === void 0 ? void 0 : _this$currentView$int2.multiSelectionCallback)) { _this.rectSelection.setCallback(function (series) { if (_this.currentView.interaction && _this.currentView.interaction.callback && _this.currentView.interaction.callback.multiSelectionCallback) { var finalSeries = []; // find ids for series _this.currentView.graphConfig.entities.forEach(function (entity) { // var tempSeries = series.find(function (_name) { return _name === entity.name; }); if (tempSeries) { finalSeries.push(entity.id); } }); _this.currentView.interaction.callback.multiSelectionCallback(finalSeries); } }); } // find fields from configuration var timewindowEnd = _momentTimezone["default"].tz(_this.currentView.timezone ? _this.currentView.timezone : _momentTimezone["default"].tz.guess()).add(1, 'days').startOf('day').valueOf(); var timewindowStart = _momentTimezone["default"].tz(_this.currentView.timezone ? _this.currentView.timezone : _momentTimezone["default"].tz.guess()).subtract(7, 'days').startOf('day').valueOf(); // default 7 days var ranges = _this.currentView.ranges; if (ranges && ranges.length > 0) { // get first "show" == true var selected = ranges.find(function (value, index, arr) { return !!value.show; }); // not found then use first one if (!selected) { // just need to change start timewindowStart = _momentTimezone["default"].tz(_this.currentView.timezone ? _this.currentView.timezone : _momentTimezone["default"].tz.guess()).add(1, 'days').startOf('day').valueOf() - ranges[0].value; } else { timewindowStart = _momentTimezone["default"].tz(_this.currentView.timezone ? _this.currentView.timezone : _momentTimezone["default"].tz.guess()).add(1, 'days').startOf('day').valueOf() - selected.value; } } // set init range if (_this.needSync && _this.currentDateWindow) { timewindowEnd = _this.currentDateWindow.end; timewindowStart = _this.currentDateWindow.start; } else if (view.initRange) { timewindowEnd = (0, _momentTimezone["default"])(view.initRange.end).tz(_this.currentView.timezone ? _this.currentView.timezone : _momentTimezone["default"].tz.guess()).valueOf(); timewindowStart = (0, _momentTimezone["default"])(view.initRange.start).tz(_this.currentView.timezone ? _this.currentView.timezone : _momentTimezone["default"].tz.guess()).valueOf(); } // which one should be shown first? base on current window size? or base on the collection config? // get default time range from graph config var graphRangesConfig = []; if (_this.currentView.ranges) { graphRangesConfig = _this.currentView.ranges; } var dropdownOpts = []; graphRangesConfig.forEach(function (config) { dropdownOpts.push({ id: config.name, label: config.name, selected: config.show }); }); var choosedCollection; // get fields var fieldsForCollection = []; // get range config and find the first and last _this.currentView.graphConfig.rangeCollection.series.forEach(function (series) { var _tempFields = series.exp.match(GraphOperator.FIELD_PATTERN); // replace all "data."" with "" if (_tempFields) { _tempFields = _tempFields.map(function (exp) { return exp.replace("data.", ""); }); } // put fields together fieldsForCollection = fieldsForCollection.concat(_tempFields); }); // tell outside highlight disappeared _this.graphContainer.addEventListener("mouseleave", function (e) { if (_this.currentView.interaction && _this.currentView.interaction.callback && _this.currentView.interaction.callback.highlightCallback) { _this.currentView.interaction.callback.highlightCallback(0, null, []); _this.graphInstance.children.forEach(function (child) { if (child.syncLegend) { child.graph.clearSelection(); } }); } }); // _this.currentView.dataService.fetchFirstNLast([_this.currentView.graphConfig.rangeEntity.id], _this.currentView.graphConfig.rangeEntity.type, _this.currentView.graphConfig.rangeCollection.name, Array.from(new Set(fieldsForCollection))).then(function (resp) { var _choosedCollection; // get first and last records, just need start and end timestamp var first = { timestamp: _momentTimezone["default"].tz(_this.currentView.timezone ? _this.currentView.timezone : _momentTimezone["default"].tz.guess()).valueOf() }; var last = { timestamp: 0 }; // if init range exist put the second on here if (_this.currentView.initRange && _this.currentView.initRange.end) { last.timestamp = _this.currentView.initRange.end; } // get all first and last then find out which first is the smalllest and last is the largest resp.forEach(function (entityData) { if (entityData.id == _this.currentView.graphConfig.rangeEntity.id) { if (entityData.data && entityData.data.first && entityData.data.first.timestamp) { // if (first.timestamp > entityData.data.first.timestamp) { first = entityData.data.first; } } if (entityData.data && entityData.data.last && entityData.data.last.timestamp) { // if (last.timestamp < entityData.data.last.timestamp) { last = entityData.data.last; } } } }); // init empty graph with start and end no other data // let firstRanges: any = graphRangesConfig.find(range => range.show && range.show == true); var firstRanges = graphRangesConfig.find(function (range, index, object) { return range ? range.show : false; }); if (!firstRanges) { // throw errors; console.warn("non default range for range-bar, use default 7 days"); firstRanges = { name: "7 days", value: 604800000, show: true }; } // get fields and labels _this.currentView.graphConfig.collections.forEach(function (collection) { // if there is a config for what level need to show. if (collection.threshold && firstRanges.value) { // >= && < [ in the middle ) if (firstRanges.value > collection.threshold.min && firstRanges.value <= collection.threshold.max) { _this.currentCollection = choosedCollection = collection; } } }); // get choose collection by width.... if (!choosedCollection && firstRanges) { // cal with width var width = _this.graphContainer.offsetWidth; // var pointsCanBeShown = Math.round(width * .9); _this.currentView.graphConfig.collections.forEach(function (collection) { // how many points in this interval if (firstRanges.value / collection.interval <= pointsCanBeShown) { if (!choosedCollection) { _this.currentCollection = choosedCollection = collection; } else if (choosedCollection.interval > collection.interval) { _this.currentCollection = choosedCollection = collection; } } }); } var initialData = [[first.timestamp], [last.timestamp]]; _this.xBoundary = [first.timestamp, last.timestamp]; if (_this.currentView.initRange) { if (_this.currentView.initRange.start < first.timestamp) { initialData[0] = [_this.currentView.initRange.start]; } if (_this.currentView.initRange.end > last.timestamp) { initialData[1] = [_this.currentView.initRange.end]; } // upate choosed collection var gap = _this.currentView.initRange.end - _this.currentView.initRange.start; choosedCollection = _this.currentView.graphConfig.collections.find(function (collection) { return collection.threshold && gap > collection.threshold.min && gap <= collection.threshold.max; }); } var isY2 = false; var mainGraphLabels = []; // check visibility config var initVisibility = []; if (choosedCollection && _this.currentView.graphConfig.entities.length == 1) { mainGraphLabels = []; choosedCollection.series.forEach(function (series, _index) { mainGraphLabels.push(series.label); if (series.visibility == undefined || series.visibility) { initVisibility.push(true); } else if (!series.visibility) { initVisibility.push(false); } initialData.forEach(function (_data) { _data[_index + 1] = null; }); if (series.yIndex == "right") { isY2 = true; } }); } else if (choosedCollection && _this.currentView.graphConfig.entities.length > 1 && choosedCollection.series && choosedCollection.series[0]) { mainGraphLabels = []; entities.forEach(function (entity, _index) { mainGraphLabels.push(entity); initialData.forEach(function (_data) { _data[_index + 1] = null; }); }); } var yScale = null; var y2Scale = null; // check if there is a init scale if (choosedCollection && choosedCollection.initScales) { if (choosedCollection.initScales.left && choosedCollection.initScales.left.min != 0 && choosedCollection.initScales.left.max != 0) { yScale = { valueRange: [choosedCollection.initScales.left.min, choosedCollection.initScales.left.max] }; } if (choosedCollection.initScales.right && choosedCollection.initScales.right.min != 0 && choosedCollection.initScales.right.max != 0) { y2Scale = { valueRange: [choosedCollection.initScales.right.min, choosedCollection.initScales.right.max] }; } } // check if scale locked if (_this.yScaleLockStatus.left.lock) { // set default range if ((isNaN(_this.yScaleLockStatus.left.value[0]) || isNaN(_this.yScaleLockStatus.left.value[1])) && yScale) { _this.yScaleLockStatus.left.value = yScale; } else { yScale = { valueRange: [_this.yScaleLockStatus.left.value] }; } } if (_this.yScaleLockStatus.right.lock) { // set default rangesyncDateWindow if ((isNaN(_this.yScaleLockStatus.right.value[0]) || isNaN(_this.yScaleLockStatus.right.value[1])) && y2Scale) { _this.yScaleLockStatus.right.value = y2Scale; } else { y2Scale = { valueRange: [_this.yScaleLockStatus.right.value] }; } } if (choosedCollection) { // set currentCollection to _this.currentCollection = choosedCollection; } var currentDatewindowOnMouseDown = []; var datewindowChangeFunc = function datewindowChangeFunc(e, yAxisRange) { var datewindow = []; if (_this.rangebarGraph) { datewindow = _this.rangebarGraph.xAxisRange(); } else { datewindow = _this.mainGraph.xAxisRange(); } if (datewindow[0] == currentDatewindowOnMouseDown[0] && datewindow[1] == currentDatewindowOnMouseDown[1]) {// console.debug("no change!"); } else { // fetch data again // sorting _this.currentView.graphConfig.collections.sort(function (a, b) { return a.interval > b.interval ? 1 : -1; }); _this.start = datewindow[0]; _this.end = datewindow[1]; if (!_this.lockedInterval) { choosedCollection = _this.currentView.graphConfig.collections.find(function (collection) { return collection.threshold && datewindow[1] - datewindow[0] <= collection.threshold.max; }); } else if (_this.currentCollection) { choosedCollection = _this.currentCollection; if (_this.currentView.graphConfig.features.pointLimits) { // check limit var gAreaW = _this.mainGraph.getArea().w; var currentInterval = _this.currentCollection.interval; var maxShowP = 0; if (gAreaW) { // call start and end maxShowP = gAreaW * currentInterval; } // get current datewindow if (_this.start > _this.end - maxShowP) {// go ahead } else { _this.start = _this.end - maxShowP * 1.5; // update datewindow if (_this.rangebarGraph) { _this.rangebarGraph.updateOptions({ dateWindow: [_this.start, _this.end] }); } else { _this.mainGraph.updateOptions({ dateWindow: [_this.start, _this.end] }); } } } } var collection = { label: "", name: "", series: [], interval: 0 }; Object.assign(collection, choosedCollection); _this.currentCollection = collection; _this.rangeCollection = _this.currentView.graphConfig.rangeCollection; _this.update(undefined, undefined, true); } }; var updateTimer = 1; var callbackFuncForInteractions = function callbackFuncForInteractions(e, yAxisRange, refreshData) { if (refreshData) { datewindowChangeFunc(e, yAxisRange); } else { // set initsacle if (updateTimer) { window.clearTimeout(updateTimer); } if (yAxisRange) { yAxisRange.forEach(function (element, _index) { if (_index == 0) { //left if (_this.currentCollection && _this.currentCollection.initScales && !_this.currentCollection.initScales.left) {// do nothing here. } else if (_this.currentCollection && _this.yScaleLockStatus.left.lock) { _this.yScaleLockStatus.left.value = element; // update graph yAxes if (_this.axesConfig) { _this.axesConfig.y.valueRange = element; updateTimer = window.setTimeout(function () { console.info("hello"); _this.mainGraph.updateOptions({ axes: _this.axesConfig }); }, 600); } } } else if (_index == 1) { if (_this.currentCollection && _this.currentCollection.initScales && !_this.currentCollection.initScales.right) {// do nothing here. } else if (_this.currentCollection && _this.yScaleLockStatus.right.lock) { _this.yScaleLockStatus.right.value = element; // update graph yAxes if (_this.axesConfig) { _this.axesConfig.y2.valueRange = element; updateTimer = window.setTimeout(function () { _this.mainGraph.updateOptions({ axes: _this.axesConfig }); }, 600); } } } }); } } if (interactionCallback) { // ready to update children interactionCallback(); } }; // create a interaction model instance var interactionModel = new _interactions.GraphInteractions(callbackFuncForInteractions, [first.timestamp, last.timestamp]); var dateLabelLeftAttrs = [{ key: 'class', value: 'fgp-graph-range-bar-date-label-left' }]; var startLabelLeft = DomElementOperator.createElement('label', dateLabelLeftAttrs); var dateLabelRightAttrs = [{ key: 'class', value: 'fgp-graph-range-bar-date-label-right' }]; var endLabelRight = DomElementOperator.createElement('label', dateLabelRightAttrs); var currentSelection = null; var fullVisibility = []; mainGraphLabels.forEach(function (label) { fullVisibility.push(true); }); var interactionModelConfig = { 'mousedown': interactionModel.mouseDown, 'mouseup': interactionModel.mouseUp, 'mouseenter': interactionModel.mouseEnter }; if (_this.currentView.graphConfig.features.rangeLocked) {// remove all event listener. can't zooming, scrolling and panning } else { // disable scrolling. scrolling will change datetime window if (_this.currentView.graphConfig.features.scroll) { interactionModelConfig["mousewheel"] = interactionModel.mouseScroll; interactionModelConfig["DOMMouseScroll"] = interactionModel.mouseScroll; interactionModelConfig["wheel"] = interactionModel.mouseScroll; } } if (_this.currentView.graphConfig.features.zoom) { interactionModelConfig["mousemove"] = interactionModel.mouseMove; } // create toolbar on top, instead of old way! _this.toolbar = new _Toolbar["default"](_this.currentView, _this.graphInstance.viewConfigs, function (collections) { // udpate graph here console.log("new collection config from badges!", collections); var showCollection = collections.find(function (_coll) { return _coll.show; }); if (showCollection) { _this.currentCollection = showCollection; if (showCollection.locked) { _this.lockedInterval = { "name": showCollection.name, "interval": Number(showCollection.interval) }; } else { _this.lockedInterval = undefined; } // reload data _this.refresh(); } }, function (collection, datewindow) { _this.currentCollection = collection; _this.start = datewindow[0]; _this.end = datewindow[1]; _this.update(); if (_this.rangebarGraph) { // shrink and grow base on middle datetime _this.rangebarGraph.updateOptions({ dateWindow: [_this.start, _this.end] }); } if (interactionCallback) { interactionCallback(); } }, function (view) { // change show if (_this.needSync && _this.currentDateWindow) { view.initRange = _this.currentDateWindow; } _this.init(view, function (graph) { _this.mainGraph = graph; _this.graphInstance.children.forEach(function (graph) { // call updateDatewinow if (graph.id != _this.graphInstance.id) { // update data graph.operator.refresh(); } }); // check if we need to tell others the view changed. if (_this.graphInstance.eventListeners && _this.graphInstance.eventListeners.onViewChange) { //f call _this.graphInstance.eventListeners.onViewChange(_this.graphInstance, view); } }, function () { _this.graphInstance.children.forEach(function (graph) { // call updateDatewinow if (graph.id != _this.graphInstance.id) { // update data graph.operator.refresh(); } }); }); }, function (active) { if (_this.rectSelection && active) { _this.rectSelection.enable(); } else { var _this$rectSelection; (_this$rectSelection = _this.rectSelection) === null || _this$rectSelection === void 0 ? void 0 : _this$rectSelection.disable(); } }, function (isLocked) { _this.colorLocked = isLocked; }); var axes = _this.axesConfig = { x: { axisLabelFormatter: formatters.axisLabel, ticker: formatters.DateTickerTZ }, y: yScale, y2: y2Scale }; // create graph instance _this.mainGraph = new _dygraphs["default"](_this.graphBody, initialData, { labels: ['x'].concat(mainGraphLabels), ylabel: choosedCollection && choosedCollection.yLabel ? choosedCollection.yLabel : "", y2label: choosedCollection && choosedCollection.y2Label ? choosedCollection.y2Label : "", rangeSelectorHeight: 30, visibility: initVisibility.length > 0 ? initVisibility : fullVisibility, legend: "follow", legendFormatter: _this.currentView.graphConfig.features.legend ? _this.currentView.graphConfig.features.legend : formatters.legendForSingleSeries, labelsKMB: ((_choosedCollection = choosedCollection) === null || _choosedCollection === void 0 ? void 0 : _choosedCollection.yKMB) == false ? false : true, // showLabelsOnHighlight: false, // drawAxesAtZero: true, connectSeparatedPoints: _this.currentView.connectSeparatedPoints ? _this.currentView.connectSeparatedPoints : false, axes: axes, highlightSeriesBackgroundAlpha: _this.currentView.highlightSeriesBackgroundAlpha ? _this.currentView.highlightSeriesBackgroundAlpha : 0.5, highlightSeriesOpts: { strokeWidth: 1 }, highlightCallback: function highlightCallback(e, x, ps, row, seriesName) { // make sure we got current selection and even no highlightCall in viewConfig we still need to make click dbl working. currentSelection = seriesName; if (_this.currentView.interaction && _this.currentView.interaction.callback && _this.currentView.interaction.callback.highlightCallback) { // find id in entities and send it back to outside var entity = _this.currentView.graphConfig.entities.find(function (_entity) { return _entity.name === currentSelection; }); if (entity) { _this.currentView.interaction.callback.highlightCallback(x, entity.id, ps); } } _this.graphInstance.children.forEach(function (child) { if (child.syncLegend) { child.graph.setSelection(row, seriesName); } }); }, unhighlightCallback: function unhighlightCallback(e) { currentSelection = null; }, clickCallback: function clickCallback(e, x, points) { if (_this.currentView.interaction && _this.currentView.interaction.callback && _this.currentView.interaction.callback.clickCallback) { var entity = _this.currentView.graphConfig.entities.find(function (_entity) { return _entity.name === currentSelection; }); if (entity) { _this.currentView.interaction.callback.clickCallback(entity.id); } } }, interactionModel: interactionModelConfig, drawCallback: function drawCallback(g, is_initial) { var xAxisRange = g.xAxisRange(); if (_this.currentView.graphConfig.features.rangeBar && _this.currentView.graphConfig.rangeCollection) { if (typeof _this.currentView.graphConfig.features.rangeBar === "boolean") { startLabelLeft.innerHTML = _momentTimezone["default"].tz(xAxisRange[0], _this.currentView.timezone ? _this.currentView.timezone : _momentTimezone["default"].tz.guess()).format('lll z'); endLabelRight.innerHTML = _momentTimezone["default"].tz(xAxisRange[1], _this.currentView.timezone ? _this.currentView.timezone : _momentTimezone["default"].tz.guess()).format('lll z'); } else if (_this.currentView.graphConfig.features.rangeBar.format) { var format = _this.currentView.graphConfig.features.rangeBar.format; startLabelLeft.innerHTML = _momentTimezone["default"].tz(xAxisRange[0], _this.currentView.timezone ? _this.currentView.timezone : _momentTimezone["default"].tz.guess()).format(format); endLabelRight.innerHTML = _momentTimezone["default"].tz(xAxisRange[1], _this.currentView.timezone ? _this.currentView.timezone : _momentTimezone["default"].tz.guess()).format(format); } } if (_this.spinner && _this.spinner.isLoading) { // remove spinner from container _this.spinner.done(); } if (_this.toolbar) { _this.toolbar.updateDateWindow(xAxisRange, _this.xBoundary); } _this.currentDateWindow = { start: xAxisRange[0], end: xAxisRange[1] }; // update datewindow _this.datewindowCallback(xAxisRange, _this.currentView); }, plugins: [_this.rectSelection, _this.toolbar] }); // add dbl event if (_this.currentView && _this.currentView.interaction && _this.currentView.interaction.callback && _this.currentView.interaction.callback.dbClickCallback) { var callbackFunc = _this.currentView.interaction.callback.dbClickCallback; _this.graphBody.addEventListener('dblclick', function (e) { if (currentSelection) { // find entity var entity = _this.currentView.graphConfig.entities.find(function (entity) { return entity.name === currentSelection; }); // if (entity) { callbackFunc(entity.id); } } }); } var ctrlBtnTimer = null; var ctrlBtnsEventListener = function ctrlBtnsEventListener(e) { if (e.target instanceof Element) { var btn = e.target; var g = _this.mainGraph; var _ranges = _this.mainGraph.yAxisRanges(); if (g && btn.getAttribute("fgp-ctrl") === "x-pan-left") { var newDatewindow = [0, 0]; // move left // current datewindow var datewindow = g.xAxisRange(); var dateGap = datewindow[1] - datewindow[0]; // if (_this.xBoundary[0] < datewindow[0] - dateGap) { // move allowed newDatewindow[0] = datewindow[0] - dateGap; newDatewindow[1] = datewindow[1] - dateGap; } else { newDatewindow[0] = _this.xBoundary[0]; newDatewindow[1] = datewindow[1] - (datewindow[0] - _this.xBoundary[0]); } // update datewindow _this.mainGraph.updateOptions({ dateWindow: newDatewindow, axes: { x: { axisLabelFormatter: formatters.axisLabel }, y: { valueRange: _ranges[0], axisLabelWidth: 80 }, y2: _ranges.length > 1 ? { valueRange: _ranges[1], axisLabelWidth: 80 } : undefined } }); // update graph if (ctrlBtnTimer) { window.clearTimeout(ctrlBtnTimer); } ctrlBtnTimer = window.setTimeout(function () { // how to updat _this.refresh(); if (interactionCallback) { interactionCallback(); } }, 1000); } else if (g && btn.getAttribute("fgp-ctrl") === "x-pan-right") { var _newDatewindow = [0, 0]; // move left // current datewindow var _datewindow = g.xAxisRange(); var _dateGap = _datewindow[1] - _datewindow[0]; // if (_this.xBoundary[1] > _datewindow[1] + _dateGap) { // move allowed _newDatewindow[0] = _datewindow[0] + _dateGap; _newDatewindow[1] = _datewindow[1] + _dateGap; } else { _newDatewindow[1] = _this.xBoundary[1]; _newDatewindow[0] = _datewindow[0] + (_this.xBoundary[1] - _datewindow[1]); } // update datewindow _this.mainGraph.updateOptions({ dateWindow: _newDatewindow, axes: { x: { axisLabelFormatter: formatters.axisLabel }, y: { valueRange: _ranges[0], axisLabelWidth: 80 }, y2: _ranges.length > 1 ? { valueRange: _ranges[1], axisLabelWidth: 80 } : undefined } }); // update graph if (ctrlBtnTimer) { window.clearTimeout(ctrlBtnTimer); } ctrlBtnTimer = window.setTimeout(function () { // update graph _this.refresh(); if (interactionCallback) { interactionCallback(); } }, 1000); } else if (g && btn.getAttribute("fgp-ctrl") === "x-zoom-in") { var _newDatewindow2 = [0, 0]; // minimum ? left - right > 5 minutes var _datewindow2 = g.xAxisRange(); var delta = (_datewindow2[1] - _datewindow2[0]) / 20; if (_datewindow2[1] - delta > _datewindow2[0] + delta + 1000 * 60 * 300) { _newDatewindow2 = [_datewindow2[0] + delta, _datewindow2[1] - delta]; _this.mainGraph.updateOptions({ dateWindow: _newDatewindow2, axes: { x: { axisLabelFormatter: formatters.axisLabel }, y: { valueRange: _ranges[0], axisLabelWidth: 80 }, y2: _ranges.length > 1 ? { valueRange: _ranges[1], axisLabelWidth: 80 } : undefined } }); // update graph if (ctrlBtnTimer) { window.clearTimeout(ctrlBtnTimer); } ctrlBtnTimer = window.setTimeout(function () { // update graph _this.refresh(); if (interactionCallback) { interactionCallback(); } }, 1000); } } else if (g && btn.getAttribute("fgp-ctrl") === "x-zoom-out") { var _newDatewindow3 = [0, 0]; // minimum ? left - right > 5 minutes var _datewindow3 = g.xAxisRange(); var _delta = (_datewindow3[1] - _datewindow3[0]) / 20; if (_datewindow3[1] + _delta < _this.xBoundary[1]) { _newDatewindow3[1] = _datewindow3[1] + _delta; } else { _newDatewindow3[1] = _this.xBoundary[1]; } if (_datewindow3[0] - _delta > _this.xBoundary[0]) { _newDatewindow3[0] = _datewindow3[0] - _delta; } else { _newDatewindow3[0] = _this.xBoundary[0]; } _this.mainGraph.updateOptions({ dateWindow: _newDatewindow3, axes: { x: { axisLabelFormatter: formatters.axisLabel }, y: { valueRange: _ranges[0], axisLabelWidth: 80 }, y2: _ranges.length > 1 ? { valueRange: _ranges[1], axisLabelWidth: 80 } : undefined } }); // update graph if (ctrlBtnTimer) { window.clearTimeout(ctrlBtnTimer); } ctrlBtnTimer = window.setTimeout(function () { // update graph _this.refresh(); if (interactionCallback) { interactionCallback(); } }, 1000); } } }; // show always // zoom and pan buttons for x-axis var xAxisButtonAreaAttrs = [{ key: 'class', value: 'fgp-graph-xaxis-btn-container' }]; var xAxisBtnArea = DomElementOperator.createElement('div', xAxisButtonAreaAttrs); // add buttons var xAxisZoomInBtnAttrs = [{ key: 'class', value: 'fgp-graph-xaxis-btn fgp-btn-zoom-in fgp-btn-v' }]; var xAxisZoomOutBtnAttrs = [{ key: 'class', value: 'fgp-graph-xaxis-btn fgp-btn-zoom-out fgp-btn-v' }]; var xAxisPanLeftBtnAttrs = [{ key: 'class', value: 'fgp-graph-xaxis-btn fgp-btn-pan-left fgp-btn-v' }]; var xAxisPanRightBtnAttrs = [{ key: 'class', value: 'fgp-graph-xaxis-btn fgp-btn-pan-right fgp-btn-v' }]; // if (!_this.currentView.graphConfig.features.rangeLocked) { var xAxisZoomInBtn = DomElementOperator.createElement('button', xAxisZoomInBtnAttrs); xAxisZoomInBtn.setAttribute("fgp-ctrl", "x-zoom-in"); var xAxisZoomOutBtn = DomElementOperator.createElement('button', xAxisZoomOutBtnAttrs); xAxisZoomOutBtn.setAttribute("fgp-ctrl", "x-zoom-out"); var xAxisPanLeftBtn = DomElementOperator.createElement('button', xAxisPanLeftBtnAttrs); xAxisPanLeftBtn.setAttribute("fgp-ctrl", "x-pan-left"); var xAxisPanRightBtn = DomElementOperator.createElement('button', xAxisPanRightBtnAttrs); xAxisPanRightBtn.setAttribute("fgp-ctrl", "x-pan-right"); xAxisZoomInBtn.addEventListener('mousedown', ctrlBtnsEventListener, false); xAxisZoomOutBtn.addEventListener('mousedown', ctrlBtnsEventListener, false); xAxisPanLeftBtn.addEventListener('mousedown', ctrlBtnsEventListener, false); xAxisPanRightBtn.addEventListener('mousedown', ctrlBtnsEventListener, false); // add buttons into container xAxisBtnArea.appendChild(xAxisPanLeftBtn); xAxisBtnArea.appendChild(xAxisZoomInBtn); xAxisBtnArea.appendChild(xAxisZoomOutBtn); xAxisBtnArea.appendChild(xAxisPanRightBtn); } // add buttons for y and y2 ctrl var ctrlVBtnsEventListener = function ctrlVBtnsEventListener(e) { var g = _this.mainGraph; var yAxes = g.axes_; var yZoomIn = function yZoomIn(side) { var ranges = _this.mainGraph.yAxisRanges(); if (side === "left") { // var range = ranges[0]; yAxes[0]['valueRange'] = [range[0] + (range[1] - range[0]) * 0.2, range[1] - (range[1] - range[0]) * 0.2]; yAxes[0]['valueWindow'] = [range[0] + (range[1] - range[0]) * 0.2, range[1] - (range[1] - range[0]) * 0.2]; } else if (side === "right") { // var _range = ranges[1]; yAxes[1]['valueRange'] = [_range[0] + (_range[1] - _range[0]) * 0.2, _range[1] - (_range[1] - _range[0]) * 0.2]; yAxes[1]['valueWindow'] = [_range[0] + (_range[1] - _range[0]) * 0.2, _range[1] - (_range[1] - _range[0]) * 0.2]; } g.drawGraph_(false); }; var yZoomOut = function yZoomOut(side) { var ranges = _this.mainGraph.yAxisRanges(); if (side === "left") { // var range = ranges[0]; yAxes[0]['valueRange'] = [range[0] - (range[1] - range[0]) * 0.2, range[1] + (range[1] - range[0]) * 0.2]; yAxes[0]['valueWindow'] = [range[0] - (range[1] - range[0]) * 0.2, range[1] + (range[1] - range[0]) * 0.2]; } else if (side === "right") { // var _range2 = ranges[1]; yAxes[1]['valueRange'] = [_range2[0] - (_range2[1] - _range2[0]) * 0.2, _range2[1] + (_range2[1] - _range2[0]) * 0.2]; yAxes[1]['valueWindow'] = [_range2[0] - (_range2[1] - _range2[0]) * 0.2, _range2[1] + (_range2[1] - _range2[0]) * 0.2]; } g.drawGraph_(false); }; var yPanUp = function yPanUp(side) { var ranges = _this.mainGraph.yAxisRanges(); if (side === "left") { var range = ranges[0]; yAxes[0]['valueRange'] = [range[0] - (range[1] - range[0]) * 0.2, range[1] - (range[1] - range[0]) * 0.2]; yAxes[0]['valueWindow'] = [range[0] - (range[1] - range[0]) * 0.2, range[1] - (range[1] - range[0]) * 0.2]; } else if (side === "right") { var _range3 = ranges[1]; yAxes[1]['valueRange'] = [_range3[0] - (_range3[1] - _range3[0]) * 0.2, _range3[1] - (_range3[1] - _range3[0]) * 0.2]; yAxes[1]['valueWindow'] = [_range3[0] - (_range3[1] - _range3[0]) * 0.2, _range3[1] - (_range3[1] - _range3[0]) * 0.2]; } g.drawGraph_(false); }; var yPanDown = function yPanDown(side) { var ranges = _this.mainGraph.yAxisRanges(); if (side === "left") { var range = ranges[0]; yAxes[0]['valueRange'] = [range[0] + (range[1] - range[0]) * 0.2, range[1] + (range[1] - range[0]) * 0.2]; yAxes[0]['valueWindow'] = [range[0] + (range[1] - range[0]) * 0.2, range[1] + (range[1] - range[0]) * 0.2]; } else if (side === "right") { var _range4 = ranges[1]; yAxes[1]['valueRange'] = [_range4[0] + (_range4[1] - _range4[0]) * 0.2, _range4[1] + (_range4[1] - _range4[0]) * 0.2]; yAxes[1]['valueWindow'] = [_range4[0] + (_range4[1] - _range4[0]) * 0.2, _range4[1] + (_range4[1] - _range4[0]) * 0.2]; } g.drawGraph_(false); }; if (e.target instanceof Element) { var btn = e.target; var _g = _this.mainGraph; var ctrlAttrs = btn.getAttribute("fgp-ctrl"); if (ctrlAttrs != null && ctrlAttrs.indexOf("y2") != -1) { if (btn.getAttribute("fgp-ctrl") === "y2-pan-up") { yPanUp("right"); } else if (btn.getAttribute("fgp-ctrl") === "y2-pan-down") { yPanDown("right"); } else if (btn.getAttribute("fgp-ctrl") === "y2-zoom-in") { yZoomIn("right"); } else if (btn.getAttribute("fgp-ctrl") === "y2-zoom-out") { yZoomOut("right"); } } else if (_g && ctrlAttrs != null && ctrlAttrs.indexOf("y") != -1) { if (btn.getAttribute("fgp-ctrl") === "y-pan-up") { yPanUp("left"); } else if (btn.getAttribute("fgp-ctrl") === "y-pan-down") { yPanDown("left"); } else if (btn.getAttribute("fgp-ctrl") === "y-zoom-in") { yZoomIn("left"); } else if (btn.getAttribute("fgp-ctrl") === "y-zoom-out") { yZoomOut("left"); } } } if (_this.yScaleLockStatus.left.lock && yAxes[0]) { _this.yScaleLockStatus.left.value = yAxes[0]['valueRange']; if (_this.axesConfig) { _this.axesConfig.y.valueRange = yAxes[0]['valueRange']; _this.mainGraph.updateOptions({ axes: _this.axesConfig }); } } if (_this.yScaleLockStatus.right.lock && yAxes[1]) { _this.yScaleLockStatus.right.value = yAxes[1]['valueRange']; if (_this.axesConfig) { _this.axesConfig.y2.valueRange = yAxes[1]['valueRange']; _this.mainGraph.updateOptions({ axes: _this.axesConfig }); } } }; // check if exist or not if (_this.graphContainer.getElementsByClassName("fgp-graph-yaxis-btn").length == 0) { // add buttons var yAxisZoomInBtnAttrs = [{ key: 'class', value: 'fgp-graph-yaxis-btn fgp-btn-zoom-in fgp-btn-v' }]; var yAxisZoomOutBtnAttrs = [{ key: 'class', value: 'fgp-graph-xaxis-btn fgp-btn-zoom-out fgp-btn-v' }]; var yAxisPanLeftBtnAttrs = [{ key: 'class', value: 'fgp-graph-xaxis-btn fgp-btn-pan-left fgp-btn-v' }]; var yAxisPanRightBtnAttrs = [{