grafana/panels/graph.js (116 lines of code) (raw):

// Copyright (c) 2015 Uber Technologies, Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. 'use strict'; const generateGraphId = require('../id'); function Graph(opts) { opts = opts || {}; const self = this; this._currentRefIndex = 0; const defaults = { 'type': 'graph', 'id': generateGraphId(), 'renderer': 'flot', 'title': 'no title (click here)', 'error': false, 'editable': true, 'x-axis': true, 'y-axis': true, 'y_formats': [ 'short', 'short' ], 'grid': { 'leftMax': null, 'rightMax': null, 'leftMin': null, 'rightMin': null, 'threshold1': null, 'threshold2': null, 'threshold1Color': 'rgba(216, 200, 27, 0.27)', 'threshold2Color': 'rgba(234, 112, 112, 0.22)' }, 'lines': true, 'span': 12, 'fill': 0, 'linewidth': 1, 'points': false, 'pointradius': 5, 'bars': false, 'stack': false, 'percentage': false, 'targets': [], 'legend': { 'show': true, 'values': true, 'min': false, 'max': true, 'current': false, 'total': false, 'avg': true }, 'nullPointMode': 'null as zero', 'steppedLine': false, 'tooltip': { 'value_type': 'cumulative', 'shared': false }, 'aliasColors': {}, 'seriesOverrides': [ {} ], 'links': [], 'datasource': 'graphite' }; this.state = defaults; // Overwrite defaults with custom values Object.keys(opts).forEach(function eachOpt(opt) { self.state[opt] = opts[opt]; }); if (opts.targets) { this.state.targets = []; opts.targets.forEach(function addT(target) { self.addTarget(target); }); } // finally add to row/dashboard if given if (opts.row && opts.dashboard) { opts.row.addPanel(this); opts.dashboard.addRow(opts.row); } } Graph.prototype.generate = function generate() { return this.state; }; Graph.prototype.addAlert = function addAlert(alert) { this.state.alert = alert.generate(); }; Graph.prototype.addTarget = function addTarget(target) { const refs = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; const builtTarget = target.toString(); const targetWithRefs = { target: builtTarget, hide: target.hide, refId: refs[this._currentRefIndex++], }; const targetFull = handleRefTargets(builtTarget, this.state.targets); const targetToAdd = Object.assign({}, targetWithRefs, targetFull); this.state.targets.push(targetToAdd); }; function getRefsFromTarget(target) { const refMatchRegex = /.*?#(\w)[,)]/g; const refs = []; let matches; while (matches = refMatchRegex.exec(target)) { refs.push(matches[1]); } return refs; } function handleRefTargets(target, targets) { if (target.includes('#')) { const refs = getRefsFromTarget(target); const findTargetByRefId = (targets, refId) => targets.find(target => target.refId === refId).target; return { targetFull: refs.reduce((res, ref) => res.replace(`#${ref}`, findTargetByRefId(targets, ref)), target) }; } return {} } module.exports = Graph;