icingaweb2-module-graphite/public/js/module.js
Eric Lippmann 05d6f5890a License source files as GPL-3.0-or-later
Add SPDX license headers and mark source files as GPL-3.0-or-later to
preserve the option to relicense under later GPL versions.
2026-03-11 21:48:49 +01:00

121 lines
4.5 KiB
JavaScript

// SPDX-FileCopyrightText: 2018 Icinga GmbH <https://icinga.com>
// SPDX-License-Identifier: GPL-3.0-or-later
(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);