You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
833 lines
24 KiB
833 lines
24 KiB
/*
|
|
** Zabbix
|
|
** Copyright (C) 2001-2023 Zabbix SIA
|
|
**
|
|
** This program is free software; you can redistribute it and/or modify
|
|
** it under the terms of the GNU General Public License as published by
|
|
** the Free Software Foundation; either version 2 of the License, or
|
|
** (at your option) any later version.
|
|
**
|
|
** This program is distributed in the hope that it will be useful,
|
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
** GNU General Public License for more details.
|
|
**
|
|
** You should have received a copy of the GNU General Public License
|
|
** along with this program; if not, write to the Free Software
|
|
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
**/
|
|
|
|
|
|
/**
|
|
* JQuery class that initializes interactivity for SVG graph.
|
|
*
|
|
* Supported options:
|
|
* - SBox - time range selector;
|
|
* - show_problems - show problems in hintbox when mouse is moved over the problem zone;
|
|
* - min_period - min period in seconds that must be s-boxed to change the data in dashboard timeselector.
|
|
*/
|
|
(function ($) {
|
|
"use strict";
|
|
|
|
// Makes SBox selection cancelable pressing Esc.
|
|
function sBoxKeyboardInteraction(e) {
|
|
if (e.keyCode == 27) {
|
|
destroySBox(e, e.data.graph);
|
|
}
|
|
}
|
|
|
|
// Disable text selection in document when move mouse pressed cursor.
|
|
function disableSelect(e) {
|
|
e.preventDefault();
|
|
}
|
|
|
|
// Cancel SBox and unset its variables.
|
|
function destroySBox(e, graph) {
|
|
var graph = graph || e.data.graph,
|
|
data = graph.data('options');
|
|
|
|
if (data) {
|
|
if (!data.isHintBoxFrozen && !data.isTriggerHintBoxFrozen) {
|
|
graph.data('widget')._resumeUpdating();
|
|
}
|
|
|
|
jQuery('.svg-graph-selection', graph).attr({'width': 0, 'height': 0});
|
|
jQuery('.svg-graph-selection-text', graph).text('');
|
|
graph.data('options').boxing = false;
|
|
}
|
|
|
|
dropDocumentListeners(e, graph);
|
|
}
|
|
|
|
/**
|
|
* Function removes SBox related $(document) event listeners:
|
|
* - if no other widget have active SBox;
|
|
* - to avoid another call of destroySBox on 'mouseup' (in case if user has pressed ESC).
|
|
*/
|
|
function dropDocumentListeners(e, graph) {
|
|
let widgets_boxing = 0; // Number of widgets with active SBox.
|
|
ZABBIX.Dashboard.getSelectedDashboardPage().getWidgets().forEach((widget) => {
|
|
if (widget.getType() === 'svggraph' && widget._svg !== null) {
|
|
const options = jQuery(widget._svg).data('options');
|
|
if (options !== undefined && options.boxing) {
|
|
widgets_boxing++;
|
|
}
|
|
}
|
|
});
|
|
|
|
if (widgets_boxing == 0 || (e && 'keyCode' in e && e.keyCode == 27)) {
|
|
jQuery(document)
|
|
.off('selectstart', disableSelect)
|
|
.off('keydown', sBoxKeyboardInteraction)
|
|
.off('mousemove', moveSBoxMouse)
|
|
.off('mouseup', destroySBox)
|
|
.off('mouseup', endSBoxDrag);
|
|
}
|
|
}
|
|
|
|
// Destroy hintbox, unset its variables and event listeners.
|
|
function destroyHintbox(graph) {
|
|
var data = graph.data('options'),
|
|
hbox = graph.data('hintbox') || null;
|
|
|
|
if (hbox !== null && (data.isHintBoxFrozen === false && data.isTriggerHintBoxFrozen === false)) {
|
|
graph.removeAttr('data-expanded');
|
|
removeFromOverlaysStack(graph.hintboxid);
|
|
graph.off('mouseup', makeHintboxStatic);
|
|
graph.removeData('hintbox');
|
|
hbox.remove();
|
|
}
|
|
}
|
|
|
|
// Hide vertical helper line and highlighted data points.
|
|
function hideHelper(graph) {
|
|
graph.find('.svg-helper').attr({'x1': -10, 'x2': -10});
|
|
graph.find('.svg-point-highlight').attr({'cx': -10, 'cy': -10});
|
|
}
|
|
|
|
// Create a new hintbox and stick it to certain position where user has clicked.
|
|
function makeHintboxStatic(e, graph) {
|
|
var graph = graph || e.data.graph,
|
|
data = graph.data('options'),
|
|
hbox = graph.data('hintbox'),
|
|
content = hbox ? hbox.find('> div') : null;
|
|
|
|
// Destroy old hintbox to make new one with close button.
|
|
destroyHintbox(graph);
|
|
|
|
if (content) {
|
|
// Should be put inside hintBoxItem to use functionality of hintBox.
|
|
graph.hintBoxItem = hintBox.createBox(e, graph, content, '', true, 'top: 0; left: 0',
|
|
graph.closest('.dashboard-grid-widget-container')
|
|
);
|
|
|
|
if (graph.data('simpleTriggersHintbox')) {
|
|
data.isTriggerHintBoxFrozen = true;
|
|
}
|
|
else {
|
|
data.isHintBoxFrozen = true;
|
|
}
|
|
|
|
graph.data('widget')._pauseUpdating();
|
|
|
|
graph.hintBoxItem.on('onDeleteHint.hintBox', function(e) {
|
|
graph.data('widget')._resumeUpdating();
|
|
|
|
data.isTriggerHintBoxFrozen = false;
|
|
data.isHintBoxFrozen = false; // Unfreeze because only onfrozen hintboxes can be removed.
|
|
graph.off('mouseup', hintboxSilentMode);
|
|
destroyHintbox(graph);
|
|
});
|
|
|
|
repositionHintBox(e, graph);
|
|
|
|
Overlay.prototype.recoverFocus.call({'$dialogue': graph.hintBoxItem});
|
|
Overlay.prototype.containFocus.call({'$dialogue': graph.hintBoxItem});
|
|
|
|
graph
|
|
.off('mouseup', hintboxSilentMode)
|
|
.on('mouseup', {graph: graph}, hintboxSilentMode);
|
|
graph.data('hintbox', graph.hintBoxItem);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Silent mode means that hintbox is waiting for click to be repositionated. Once user clicks on graph, existing
|
|
* hintbox will be repositionated with a new values in the place where user clicked on.
|
|
*/
|
|
function hintboxSilentMode(e) {
|
|
var graph = e.data.graph,
|
|
data = graph.data('options');
|
|
|
|
if (data.isHintBoxFrozen) {
|
|
data.isHintBoxFrozen = false;
|
|
showHintbox(e, graph);
|
|
makeHintboxStatic(e, graph);
|
|
}
|
|
if (data.isTriggerHintBoxFrozen) {
|
|
data.isTriggerHintBoxFrozen = false;
|
|
showSimpleTriggerHintbox(e, graph);
|
|
makeHintboxStatic(e, graph);
|
|
}
|
|
}
|
|
|
|
// Method to start selection of some horizontal area in graph.
|
|
function startSBoxDrag(e) {
|
|
e.stopPropagation();
|
|
|
|
var graph = e.data.graph,
|
|
offsetX = e.clientX - graph.offset().left,
|
|
data = graph.data('options');
|
|
|
|
if (data.dimX <= offsetX && offsetX <= data.dimX + data.dimW && data.dimY <= e.offsetY
|
|
&& e.offsetY <= data.dimY + data.dimH) {
|
|
jQuery(document)
|
|
.on('selectstart', disableSelect)
|
|
.on('keydown', {graph: graph}, sBoxKeyboardInteraction)
|
|
.on('mousemove', {graph: graph}, moveSBoxMouse)
|
|
.on('mouseup', {graph: graph}, endSBoxDrag);
|
|
|
|
data.start = offsetX - data.dimX;
|
|
}
|
|
}
|
|
|
|
// Method to recalculate selected area during mouse move.
|
|
function moveSBoxMouse(e) {
|
|
e.stopPropagation();
|
|
|
|
var graph = e.data.graph,
|
|
data = graph.data('options'),
|
|
$sbox = jQuery('.svg-graph-selection', graph),
|
|
$stxt = jQuery('.svg-graph-selection-text', graph),
|
|
offsetX = e.clientX - graph.offset().left;
|
|
|
|
data.end = offsetX - data.dimX;
|
|
|
|
// If mouse movement detected (SBox has dragged), destroy opened hintbox and pause widget refresh.
|
|
if (data.start != data.end && !data.boxing) {
|
|
graph.data('widget')._pauseUpdating();
|
|
data.isHintBoxFrozen = false;
|
|
data.isTriggerHintBoxFrozen = false;
|
|
data.boxing = true;
|
|
destroyHintbox(graph);
|
|
hideHelper(graph);
|
|
}
|
|
|
|
if (data.boxing) {
|
|
data.end = Math.min(offsetX - data.dimX, data.dimW);
|
|
data.end = (data.end > 0) ? data.end : 0;
|
|
|
|
$sbox.attr({
|
|
'x': (Math.min(data.start, data.end) + data.dimX) + 'px',
|
|
'y': data.dimY + 'px',
|
|
'width': Math.abs(data.end - data.start) + 'px',
|
|
'height': data.dimH
|
|
});
|
|
|
|
var seconds = Math.round(Math.abs(data.end - data.start) * data.spp),
|
|
label = formatTimestamp(seconds, false, true)
|
|
+ (seconds < data.minPeriod ? ' [min 1' + t('S_MINUTE_SHORT') + ']' : '');
|
|
|
|
$stxt
|
|
.text(label)
|
|
.attr({
|
|
'x': (Math.min(data.start, data.end) + data.dimX + 5) + 'px',
|
|
'y': (data.dimY + 15) + 'px'
|
|
});
|
|
}
|
|
}
|
|
|
|
// Method to end selection of horizontal area in graph.
|
|
function endSBoxDrag(e) {
|
|
e.stopPropagation();
|
|
|
|
var graph = e.data.graph,
|
|
data = graph.data('options'),
|
|
offsetX = e.clientX - graph.offset().left,
|
|
set_date = data && data.boxing;
|
|
|
|
destroySBox(e, graph);
|
|
|
|
if (set_date) {
|
|
data.end = Math.min(offsetX - data.dimX, data.dimW);
|
|
|
|
var seconds = Math.round(Math.abs(data.end - data.start) * data.spp),
|
|
from_offset = Math.floor(Math.min(data.start, data.end)) * data.spp,
|
|
to_offset = Math.floor(data.dimW - Math.max(data.start, data.end)) * data.spp;
|
|
|
|
if (seconds > data.minPeriod && (from_offset > 0 || to_offset > 0)) {
|
|
jQuery.publish('timeselector.rangeoffset', {
|
|
from_offset: Math.max(0, Math.ceil(from_offset)),
|
|
to_offset: Math.ceil(to_offset)
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
// Read SVG nodes and find closest past value to the given x in each data set.
|
|
function findValues(graph, x) {
|
|
var data_sets = [],
|
|
nodes = graph.querySelectorAll('[data-set]');
|
|
|
|
for (var i = 0, l = nodes.length; l > i; i++) {
|
|
var px = -10,
|
|
py = -10,
|
|
pv = null,
|
|
pp = 0,
|
|
ps = 0;
|
|
|
|
// Find matching X points.
|
|
switch (nodes[i].getAttribute('data-set')) {
|
|
case 'points':
|
|
var test_x = Math.min(x, +nodes[i].lastChild.getAttribute('cx')),
|
|
circle_nodes = nodes[i].querySelectorAll('circle'),
|
|
points = [];
|
|
|
|
for (var c = 0, cl = circle_nodes.length; cl > c; c++) {
|
|
if (test_x >= parseInt(circle_nodes[c].getAttribute('cx'))) {
|
|
points.push(circle_nodes[c]);
|
|
}
|
|
}
|
|
|
|
var point = points.slice(-1)[0];
|
|
if (typeof point !== 'undefined') {
|
|
px = point.getAttribute('cx');
|
|
py = point.getAttribute('cy');
|
|
pv = point.getAttribute('label');
|
|
}
|
|
break;
|
|
|
|
case 'bar':
|
|
var polygons_nodes = nodes[i].querySelectorAll('polygon');
|
|
var points = [];
|
|
var pp = 0;
|
|
|
|
for (var c = 0, cl = polygons_nodes.length; cl > c; c++) {
|
|
var coord = polygons_nodes[c].getAttribute('points').split(' ').map(function (val) {
|
|
return val.split(',');
|
|
});
|
|
if (polygons_nodes[c].getAttribute('data-px') == coord[0][0]) {
|
|
if (x >= parseInt(coord[0][0])) {
|
|
points.push(polygons_nodes[c]);
|
|
}
|
|
}
|
|
else {
|
|
if (x >= parseInt(polygons_nodes[c].getAttribute('data-px'))) {
|
|
points.push(polygons_nodes[c]);
|
|
}
|
|
}
|
|
}
|
|
|
|
px = 0;
|
|
py = 0;
|
|
|
|
var point = points.slice(-1)[0];
|
|
if (typeof point !== 'undefined') {
|
|
var coord = point.getAttribute('points').split(' ').map(function (val) {
|
|
return val.split(',');
|
|
});
|
|
px = coord[0][0];
|
|
py = coord[1][1];
|
|
pv = point.getAttribute('label');
|
|
pp = (coord[2][0] - coord[0][0]) / 2;
|
|
ps = point.getAttribute('data-px');
|
|
}
|
|
break;
|
|
|
|
case 'staircase':
|
|
case 'line':
|
|
var direction_string = '',
|
|
label = [],
|
|
data_set = nodes[i].getAttribute('data-set'),
|
|
data_nodes = nodes[i].childNodes,
|
|
elmnt_label,
|
|
cx,
|
|
cy;
|
|
|
|
for (var index = 0, len = data_nodes.length; index < len; index++) {
|
|
elmnt_label = data_nodes[index].getAttribute('label');
|
|
if (elmnt_label) {
|
|
label.push(elmnt_label);
|
|
|
|
if (data_nodes[index].tagName.toLowerCase() === 'circle') {
|
|
cx = data_nodes[index].getAttribute('cx');
|
|
cy = data_nodes[index].getAttribute('cy');
|
|
direction_string += ' _' + cx + ',' + cy;
|
|
}
|
|
else {
|
|
direction_string += ' ' + data_nodes[index].getAttribute('d');
|
|
}
|
|
}
|
|
}
|
|
|
|
label = label.join(',').split(',');
|
|
|
|
var direction = ED // Edge transforms 'd' attribute.
|
|
? direction_string.substr(1).replace(/([ML])\s(\d+)\s(\d+)/g, '$1$2\,$3').split(' ')
|
|
: direction_string.substr(1).split(' '),
|
|
index = direction.length,
|
|
point,
|
|
point_label;
|
|
|
|
while (index) {
|
|
index--;
|
|
point = direction[index].substr(1).split(',');
|
|
point_label = label[data_set === 'line' ? index : Math.ceil(index / 2)];
|
|
|
|
if (x >= parseInt(point[0]) && point_label !== '') {
|
|
px = point[0];
|
|
py = point[1];
|
|
pv = point_label;
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
data_sets.push({g: nodes[i], x: px, y: py, v: pv, p: pp, s: ps});
|
|
}
|
|
|
|
return data_sets;
|
|
}
|
|
|
|
// Find what problems matches in time to the given x.
|
|
function findProblems(graph, x) {
|
|
var problems = [],
|
|
problem_start,
|
|
problem_width,
|
|
nodes = graph.querySelectorAll('[data-info]');
|
|
|
|
for (var i = 0, l = nodes.length; l > i; i++) {
|
|
problem_start = +nodes[i].getAttribute('x');
|
|
problem_width = +nodes[i].getAttribute('width');
|
|
|
|
if (x > problem_start && problem_start + problem_width > x) {
|
|
problems.push(JSON.parse(nodes[i].getAttribute('data-info')));
|
|
}
|
|
}
|
|
|
|
return problems;
|
|
}
|
|
|
|
// Set position of vertical helper line.
|
|
function setHelperPosition(e, graph) {
|
|
var data = graph.data('options');
|
|
graph.find('.svg-helper').attr({
|
|
'x1': e.clientX - graph.offset().left,
|
|
'y1': data.dimY,
|
|
'x2': e.clientX - graph.offset().left,
|
|
'y2': data.dimY + data.dimH
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Get tolerance for given data set. Tolerance is used to find which elements are hovered by mouse. Script takes
|
|
* actual data point and adds N pixels to all sides. Then looks if mouse is in calculated area. N is calculated by
|
|
* this function. Tolerance is used to find exactly matched point only.
|
|
*/
|
|
function getDataPointTolerance(ds) {
|
|
var data_tag = ds.querySelector(':not(.svg-point-highlight)');
|
|
|
|
if (data_tag.tagName.toLowerCase() === 'circle') {
|
|
return +ds.childNodes[1].getAttribute('r');
|
|
}
|
|
else {
|
|
return +window.getComputedStyle(data_tag)['strokeWidth'];
|
|
}
|
|
}
|
|
|
|
// Position hintbox near current mouse position.
|
|
function repositionHintBox(e, graph) {
|
|
// Use closest positioned ancestor for offset calculation.
|
|
var offset = graph.closest('.dashboard-grid-widget-container').offsetParent().offset(),
|
|
hbox = jQuery(graph.hintBoxItem),
|
|
page_bottom = jQuery(window.top).scrollTop() + jQuery(window.top).height(),
|
|
mouse_distance = 15,
|
|
l = (document.body.clientWidth >= e.clientX + hbox.outerWidth() + mouse_distance)
|
|
? e.clientX + mouse_distance - offset.left
|
|
: e.clientX - mouse_distance - hbox.outerWidth() - offset.left,
|
|
t = e.pageY - offset.top,
|
|
t = page_bottom >= t + offset.top + hbox.outerHeight() + mouse_distance
|
|
? t + mouse_distance
|
|
: t - mouse_distance - hbox.outerHeight(),
|
|
t = (t + offset.top < 0) ? -offset.top : t;
|
|
|
|
hbox.css({'left': l, 'top': t});
|
|
}
|
|
|
|
// Show problem or value hintbox.
|
|
function showHintbox(e, graph) {
|
|
var graph = graph || e.data.graph,
|
|
data = graph.data('options'),
|
|
hbox = graph.data('hintbox') || null,
|
|
offsetX = e.clientX - graph.offset().left,
|
|
html = null,
|
|
in_x = false,
|
|
in_values_area = false,
|
|
in_problem_area = false;
|
|
|
|
if (graph.data('simpleTriggersHintbox') || data.isTriggerHintBoxFrozen === true) {
|
|
return;
|
|
}
|
|
|
|
if (data.boxing === true) {
|
|
hideHelper(graph);
|
|
return;
|
|
}
|
|
|
|
// Check if mouse in the horizontal area in which hintbox must be shown.
|
|
in_x = (data.dimX <= offsetX && offsetX <= data.dimX + data.dimW);
|
|
in_problem_area = in_x && (data.dimY + data.dimH <= e.offsetY && e.offsetY <= data.dimY + data.dimH + 15);
|
|
in_values_area = in_x && (data.dimY <= e.offsetY && e.offsetY <= data.dimY + data.dimH);
|
|
|
|
// Show problems when mouse is in the 15px high area under the graph canvas.
|
|
if (data.showProblems && data.isHintBoxFrozen === false && in_problem_area) {
|
|
hideHelper(graph);
|
|
|
|
var problems = findProblems(graph[0], e.offsetX),
|
|
problems_total = problems.length;
|
|
if (problems_total > 0) {
|
|
var tbody = jQuery('<tbody>');
|
|
|
|
problems.slice(0, data.hintMaxRows).forEach(function(val, i) {
|
|
tbody.append(
|
|
jQuery('<tr>')
|
|
.append(jQuery('<td>').append(jQuery('<a>', {'href': val.url}).text(val.clock)))
|
|
.append(jQuery('<td>').append(val.r_eventid
|
|
? jQuery('<a>', {'href': val.url}).text(val.r_clock)
|
|
: val.r_clock)
|
|
)
|
|
.append(jQuery('<td>').append(
|
|
jQuery('<span>', { 'class': val.status_color }).text(val.status))
|
|
)
|
|
.append(jQuery('<td>', {'class': val.severity}).text(val.name))
|
|
);
|
|
});
|
|
|
|
html = jQuery('<div>')
|
|
.addClass('svg-graph-hintbox')
|
|
.append(
|
|
jQuery('<table>')
|
|
.addClass('list-table compact-view')
|
|
.append(tbody)
|
|
)
|
|
.append(problems_total > data.hintMaxRows
|
|
? makeHintBoxFooter(data.hintMaxRows, problems_total)
|
|
: null
|
|
);
|
|
}
|
|
}
|
|
// Show graph values if mouse is over the graph canvas.
|
|
else if (in_values_area) {
|
|
// Set position of mouse following helper line.
|
|
setHelperPosition(e, graph);
|
|
|
|
// Find values.
|
|
var points = findValues(graph[0], offsetX),
|
|
points_total = points.length,
|
|
show_hint = false,
|
|
xy_point = false,
|
|
tolerance;
|
|
|
|
/**
|
|
* Decide if one specific value or list of all matching Xs should be highlighted and either to show or
|
|
* hide hintbox.
|
|
*/
|
|
if (data.isHintBoxFrozen === false) {
|
|
points.forEach(function(point) {
|
|
if (!show_hint && point.v !== null) {
|
|
show_hint = true;
|
|
}
|
|
|
|
tolerance = getDataPointTolerance(point.g);
|
|
if (!xy_point && point.v !== null
|
|
&& (+point.x + tolerance) > e.offsetX && e.offsetX > (+point.x - tolerance)
|
|
&& (+point.y + tolerance) > e.offsetY && e.offsetY > (+point.y - tolerance)) {
|
|
xy_point = point;
|
|
points_total = 1;
|
|
}
|
|
});
|
|
}
|
|
|
|
// Make html for hintbox.
|
|
if (show_hint) {
|
|
html = jQuery('<ul>');
|
|
}
|
|
var rows_added = 0;
|
|
points.forEach(function(point) {
|
|
var point_highlight = point.g.querySelectorAll('.svg-point-highlight')[0];
|
|
|
|
if (point.v !== null && (xy_point === false || xy_point === point)) {
|
|
point_highlight.setAttribute('cx', point.x);
|
|
point_highlight.setAttribute('cy', point.y);
|
|
|
|
if (point.p > 0) {
|
|
point_highlight.setAttribute('cx', parseInt(point.x) + parseInt(point.p));
|
|
}
|
|
|
|
if (show_hint && data.hintMaxRows > rows_added) {
|
|
jQuery('<li>')
|
|
.text(point.g.getAttribute('data-metric') + ': ' + point.v)
|
|
.append(
|
|
jQuery('<span>')
|
|
.css('background-color', point.g.getAttribute('data-color'))
|
|
.addClass('svg-graph-hintbox-item-color')
|
|
)
|
|
.appendTo(html);
|
|
rows_added++;
|
|
}
|
|
}
|
|
else {
|
|
point_highlight.setAttribute('cx', -10);
|
|
point_highlight.setAttribute('cy', -10);
|
|
}
|
|
});
|
|
|
|
if (show_hint) {
|
|
// Calculate time at mouse position.
|
|
const time = new CDate((data.timeFrom + (offsetX - data.dimX) * data.spp) * 1000);
|
|
|
|
html = jQuery('<div>')
|
|
.addClass('svg-graph-hintbox')
|
|
.append(
|
|
jQuery('<div>')
|
|
.addClass('header')
|
|
.html(time.format(PHP_ZBX_FULL_DATE_TIME))
|
|
)
|
|
.append(html)
|
|
.append(points_total > data.hintMaxRows
|
|
? makeHintBoxFooter(data.hintMaxRows, points_total)
|
|
: null
|
|
);
|
|
}
|
|
}
|
|
else {
|
|
hideHelper(graph);
|
|
}
|
|
|
|
if (html !== null) {
|
|
if (hbox === null) {
|
|
hbox = hintBox.createBox(e, graph, html, '', false, false,
|
|
graph.closest('.dashboard-grid-widget-container')
|
|
);
|
|
graph
|
|
.off('mouseup', makeHintboxStatic)
|
|
.on('mouseup', {graph: graph}, makeHintboxStatic);
|
|
graph.data('hintbox', hbox);
|
|
}
|
|
else {
|
|
hbox.find('> div').replaceWith(html);
|
|
}
|
|
|
|
graph.hintBoxItem = hbox;
|
|
repositionHintBox(e, graph);
|
|
}
|
|
|
|
if (html === null && (in_values_area || in_problem_area)) {
|
|
destroyHintbox(graph);
|
|
}
|
|
}
|
|
|
|
// Function creates hintbox footer.
|
|
function makeHintBoxFooter(num_displayed, num_total) {
|
|
return jQuery('<div>')
|
|
.addClass('table-paging')
|
|
.append(
|
|
jQuery('<div>')
|
|
.addClass('paging-btn-container')
|
|
.append(
|
|
jQuery('<div>')
|
|
.text(sprintf(t('S_DISPLAYING_FOUND'), num_displayed, num_total))
|
|
.addClass('table-stats')
|
|
)
|
|
);
|
|
}
|
|
|
|
var methods = {
|
|
init: function(widget) {
|
|
this.each(function() {
|
|
jQuery(widget._svg)
|
|
.data('options', {
|
|
dimX: widget._svg_options.dims.x,
|
|
dimY: widget._svg_options.dims.y,
|
|
dimW: widget._svg_options.dims.w,
|
|
dimH: widget._svg_options.dims.h,
|
|
showProblems: widget._svg_options.show_problems,
|
|
showSimpleTriggers: widget._svg_options.show_simple_triggers,
|
|
hintMaxRows: widget._svg_options.hint_max_rows,
|
|
isHintBoxFrozen: false,
|
|
isTriggerHintBoxFrozen: false,
|
|
spp: widget._svg_options.spp || null,
|
|
timeFrom: widget._svg_options.time_from,
|
|
minPeriod: widget._svg_options.min_period,
|
|
boxing: false
|
|
})
|
|
.data('widget', widget)
|
|
.attr('unselectable', 'on')
|
|
.css('user-select', 'none');
|
|
|
|
if (widget._svg_options.sbox) {
|
|
dropDocumentListeners(null, jQuery(widget._svg));
|
|
}
|
|
});
|
|
},
|
|
activate: function () {
|
|
const widget = jQuery(this).data('widget');
|
|
const graph = jQuery(widget._svg);
|
|
|
|
graph
|
|
.on('mousemove', (e) => {
|
|
showSimpleTriggerHintbox(e, graph);
|
|
showHintbox(e, graph);
|
|
})
|
|
.on('mouseleave', function() {
|
|
destroyHintbox(graph);
|
|
hideHelper(graph);
|
|
})
|
|
.on('selectstart', false);
|
|
|
|
if (widget._svg_options.sbox) {
|
|
graph
|
|
.on('dblclick', function() {
|
|
hintBox.hideHint(graph, true);
|
|
jQuery.publish('timeselector.zoomout');
|
|
return false;
|
|
})
|
|
.on('mousedown', {graph}, startSBoxDrag);
|
|
}
|
|
},
|
|
deactivate: function (e) {
|
|
const widget = jQuery(this).data('widget');
|
|
const graph = jQuery(widget._svg);
|
|
|
|
destroySBox(e, graph);
|
|
graph.off('mousemove mouseleave dblclick mousedown selectstart');
|
|
}
|
|
};
|
|
|
|
function showSimpleTriggerHintbox(e, graph) {
|
|
graph = graph || e.data.graph;
|
|
const data = graph.data('options');
|
|
let hbox = graph.data('hintbox') || null;
|
|
|
|
graph.data('simpleTriggersHintbox', false);
|
|
let html = null;
|
|
|
|
if (!data.showSimpleTriggers || data.isHintBoxFrozen === true) {
|
|
return;
|
|
}
|
|
|
|
if (data.boxing === true) {
|
|
hideHelper(graph);
|
|
return;
|
|
}
|
|
|
|
// Check if mouse in the horizontal area in which hintbox must be shown.
|
|
const triggers = findTriggers(graph[0], e.offsetY);
|
|
if (data.isTriggerHintBoxFrozen === false && triggers) {
|
|
hideHelper(graph);
|
|
|
|
const triggers_length = triggers.length;
|
|
if (triggers_length > 0) {
|
|
const hint_body = jQuery('<ul></ul>');
|
|
|
|
const trigger_areas = triggers.filter((val) => {
|
|
if (val.begin_position > e.offsetX) {
|
|
return false;
|
|
}
|
|
|
|
if (e.offsetX > val.end_position) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
});
|
|
|
|
if (!trigger_areas.length) {
|
|
return;
|
|
}
|
|
|
|
triggers.slice(0, data.hintMaxRows).forEach((val, i) => {
|
|
hint_body.append(
|
|
jQuery('<li>')
|
|
.text(val.trigger + ' [' + val.constant + ']')
|
|
.append(
|
|
jQuery('<span>')
|
|
.css('background-color', val.color)
|
|
.addClass('svg-graph-hintbox-trigger-color')
|
|
)
|
|
)
|
|
|
|
val.elem.classList.toggle('svg-graph-simple-trigger-hover', true)
|
|
});
|
|
|
|
html = jQuery('<div>')
|
|
.addClass('svg-graph-hintbox')
|
|
.append(hint_body)
|
|
.append(triggers_length > data.hintMaxRows
|
|
? makeHintBoxFooter(data.hintMaxRows, triggers_length)
|
|
: null
|
|
);
|
|
|
|
graph.data('simpleTriggersHintbox', true);
|
|
}
|
|
}
|
|
|
|
if (html !== null) {
|
|
if (hbox === null) {
|
|
hbox = hintBox.createBox(e, graph, html, '', false, false,
|
|
graph.closest('.dashboard-grid-widget-container')
|
|
);
|
|
graph
|
|
.off('mouseup', makeHintboxStatic)
|
|
.on('mouseup', {graph: graph}, makeHintboxStatic);
|
|
graph.data('hintbox', hbox);
|
|
}
|
|
else {
|
|
hbox.find('> div').replaceWith(html);
|
|
}
|
|
|
|
graph.hintBoxItem = hbox;
|
|
repositionHintBox(e, graph);
|
|
}
|
|
else {
|
|
destroyHintbox(graph);
|
|
}
|
|
}
|
|
|
|
function findTriggers(graph, y) {
|
|
const triggers = [];
|
|
const nodes = graph.querySelectorAll('.svg-graph-simple-trigger line');
|
|
|
|
[...graph.querySelectorAll('.svg-graph-simple-trigger.svg-graph-simple-trigger-hover')].map(
|
|
(elem) => elem.classList.toggle('svg-graph-simple-trigger-hover', false)
|
|
);
|
|
|
|
|
|
for (var i = 0, l = nodes.length; l > i; i++) {
|
|
const trigger_y = parseInt(nodes[i].getAttribute('y1'));
|
|
|
|
if (y < trigger_y + 10 && y > trigger_y - 10) {
|
|
triggers.push({
|
|
begin_position: parseInt(nodes[i].getAttribute('x1')),
|
|
end_position: parseInt(nodes[i].getAttribute('x2')),
|
|
color: nodes[i].parentElement.getAttribute('severity-color'),
|
|
constant: nodes[i].parentElement.getAttribute('constant'),
|
|
trigger: nodes[i].parentElement.getAttribute('description'),
|
|
elem: nodes[i].parentElement
|
|
});
|
|
}
|
|
}
|
|
|
|
return triggers;
|
|
}
|
|
|
|
jQuery.fn.svggraph = function(method) {
|
|
if (methods[method]) {
|
|
return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
|
|
}
|
|
|
|
return methods.init.apply(this, arguments);
|
|
};
|
|
})(jQuery);
|