/* Icinga Web 2 | (c) 2022 Icinga GmbH | GPLv2+ */ (function(Icinga) { "use strict"; class Graphite extends Icinga.EventListener { constructor(icinga) { super(icinga); this._colorParams = null; this._resizeTimer = null; this._onResizeBound = this.onResize.bind(this); this._onModeChangeBound = this.onModeChange.bind(this); this._mediaQueryList = window.matchMedia('(prefers-color-scheme: light)'); this.on('css-reloaded', 'head', this.onCssReloaded, this); this.on('rendered', '#main > .container', this.onRendered, this); window.addEventListener('resize', this._onResizeBound, { passive: true }); this._mediaQueryList.addEventListener('change', this._onModeChangeBound, { passive: true }); } get colorParams() { if (this._colorParams === null) { let colorRegistry = document.querySelector('.graphite-graph-color-registry'); let registryStyle = window.getComputedStyle(colorRegistry); this._colorParams = { bgcolor: this.rgbToHex(registryStyle.backgroundColor, 'black'), fgcolor: this.rgbToHex(registryStyle.color, 'white'), majorGridLineColor: this.rgbToHex(registryStyle.borderTopColor, '0000003F'), minorGridLineColor: this.rgbToHex(registryStyle.borderBottomColor, 'black') }; } return this._colorParams; } unbind(emitter) { super.unbind(emitter); window.removeEventListener('resize', this._onResizeBound); this._mediaQueryList.removeEventListener('change', this._onModeChangeBound); this._onResizeBound = null; this._onModeChangeBound = null; this._mediaQueryList = null; } onCssReloaded(event) { let _this = event.data.self; _this._colorParams = null; _this.updateImages(document); } onRendered(event, autorefresh, scripted, autosubmit) { let _this = event.data.self; let container = event.target; _this.updateImages(container); } onResize() { // Images are not updated instantly, the user might not yet be finished resizing the window if (this._resizeTimer !== null) { clearTimeout(this._resizeTimer); } this._resizeTimer = setTimeout(() => this.updateImages(document), 200); } onModeChange() { this._colorParams = null; this.updateImages(document); } updateImages(container) { container.querySelectorAll('img.graphiteImg[data-actualimageurl]').forEach(img => { let params = { ...this.colorParams }; // Theming ftw! params.r = (new Date()).getTime(); // To bypass the browser cache params.width = img.scrollWidth; if ('width' in img.dataset) { // If the width is defined in the data attributes, it has been explicitly defined in a template and // therefore must be handled specially. In detail areas the image must not be scaled to 100% and // in the other views it must not exceed the width of the parent container. // Note the `+str` which will convert str to number. params.width = Math.min(+img.dataset.width, img.parentElement.clientWidth); img.style.width = params.width + 'px'; } img.src = this.icinga.utils.addUrlParams(img.dataset.actualimageurl, params); }); } rgbToHex(rgb, def) { if (! rgb) { return def; } let match = rgb.match(/rgba?\((\d+), (\d+), (\d+)(?:, ([\d.]+))?\)/); if (match === null) { return def; } let alpha = ''; if (typeof match[4] !== 'undefined') { alpha = Math.round(parseFloat(match[4]) * 255).toString(16); } return parseInt(match[1], 10).toString(16).padStart(2, '0') + parseInt(match[2], 10).toString(16).padStart(2, '0') + parseInt(match[3], 10).toString(16).padStart(2, '0') + alpha; } } Icinga.Behaviors.Graphite = Graphite; })(Icinga);