pandorafms/pandora_console/include/graphs/pandora.d3.js

2800 lines
70 KiB
JavaScript
Raw Normal View History

// Pandora FMS - http://pandorafms.com
// ==================================================
2020-11-27 13:52:35 +01:00
// Copyright (c) 2005-2021 Artica Soluciones Tecnologicas
// Please see http://pandorafms.org for full contribution list
// 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; version 2
// 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.
2020-01-24 15:13:42 +01:00
/* globals jQuery, d3 */
// The recipient is the selector of the html element
// The elements is an array with the names of the wheel elements
// The matrix must be a 2 dimensional array with a row and a column for each element
// Ex:
// elements = ["a", "b", "c"];
// matrix = [[0, 0, 2], // a[a => a, a => b, a => c]
// [5, 0, 1], // b[b => a, b => b, b => c]
// [2, 3, 0]]; // c[c => a, c => b, c => c]
function chordDiagram(recipient, elements, matrix, width) {
d3.chart = d3.chart || {};
d3.chart.chordWheel = function(options) {
// Default values
var width = 700;
var margin = 150;
var padding = 0.02;
2022-05-06 14:23:24 +02:00
var consoleStyle = document.getElementById("hidden-selected_style_theme")
.value;
var textColor =
consoleStyle === "pandora_black" ? "rgb(240, 240, 240)" : "rgb(0, 0, 0)";
var tooltipColor =
consoleStyle === "pandora_black" ? "rgb(0, 0, 0)" : "rgb(240, 240, 240)";
function chart(selection) {
selection.each(function(data) {
var matrix = data.matrix;
var elements = data.elements;
var radius = width / 2 - margin;
// create the layout
var chord = d3.layout
.chord()
.padding(padding)
.sortSubgroups(d3.descending);
// Select the svg element, if it exists.
var svg = d3
.select(this)
.selectAll("svg")
.data([data]);
// Otherwise, create the skeletal chart.
var gEnter = svg
.enter()
.append("svg:svg")
.attr("width", width)
.attr("height", width)
.attr("class", "dependencyWheel")
.append("g")
.attr("transform", "translate(" + width / 2 + "," + width / 2 + ")");
var arc = d3.svg
.arc()
.innerRadius(radius)
.outerRadius(radius + 20);
var fill = function(d) {
return "hsl(" + parseInt((d.index / 26) * 360, 10) + ",80%,70%)";
};
// Returns an event handler for fading a given chord group.
var fade = function(opacity) {
return function(g, i) {
svg
.selectAll(".chord")
.filter(function(d) {
return d.source.index != i && d.target.index != i;
})
.transition()
.style("opacity", opacity);
var groups = [];
svg.selectAll(".chord").filter(function(d) {
if (d.source.index == i) {
groups.push(d.target.index);
}
if (d.target.index == i) {
groups.push(d.source.index);
}
});
groups.push(i);
var length = groups.length;
svg
.selectAll(".group")
.filter(function(d) {
for (var i = 0; i < length; i++) {
if (groups[i] == d.index) return false;
}
return true;
})
.transition()
.style("opacity", opacity);
2021-09-28 09:42:05 +02:00
2021-09-29 10:57:57 +02:00
if (event.type == "mouseover") {
const chords = chord.chords();
2021-09-29 16:47:24 +02:00
let aux = 0;
2021-09-29 10:57:57 +02:00
$.each(chords, function(key, value) {
2021-09-29 16:47:24 +02:00
if (aux < 5) {
2021-09-29 10:57:57 +02:00
if (
2021-09-29 16:47:24 +02:00
(value.source.index == i && value.target.subindex == i) ||
(value.source.subindex == i && value.target.index == i)
2021-09-29 10:57:57 +02:00
) {
2021-09-29 16:47:24 +02:00
if (
$("#tooltip").is(":hidden") ||
$("#tooltip").length == 0
) {
show_tooltip(value);
} else {
add_tooltip(value);
aux++;
}
2021-09-29 10:57:57 +02:00
}
}
});
} else {
hide_tooltip();
}
};
};
chord.matrix(matrix);
var rootGroup = chord.groups()[0];
var rotation =
(-(rootGroup.endAngle - rootGroup.startAngle) / 2) * (180 / Math.PI);
var g = gEnter
.selectAll("g.group")
.data(chord.groups)
.enter()
.append("svg:g")
.attr("class", "group")
.attr("transform", function(d) {
return "rotate(" + rotation + ")";
});
g.append("svg:path")
.style("fill", fill)
.style("stroke", fill)
.attr("d", arc)
.on("mouseover", fade(0.1))
2021-09-28 09:42:05 +02:00
.on("mouseout", fade(1))
.on("mousemove", move_tooltip);
g.append("svg:text")
.each(function(d) {
d.angle = (d.startAngle + d.endAngle) / 2;
})
.attr("dy", ".35em")
.attr("text-anchor", function(d) {
return d.angle > Math.PI ? "end" : null;
})
2022-05-06 14:23:24 +02:00
.attr("style", "fill: " + textColor)
.attr("transform", function(d) {
return (
"rotate(" +
((d.angle * 180) / Math.PI - 90) +
")" +
"translate(" +
(radius + 26) +
")" +
(d.angle > Math.PI ? "rotate(180)" : "")
);
})
.text(function(d) {
return elements[d.index];
});
gEnter
.selectAll("path.chord")
.data(chord.chords)
.enter()
.append("svg:path")
.attr("class", "chord")
.style("stroke", function(d) {
return d3.rgb(fill(d.source)).darker();
})
.style("fill", function(d) {
return fill(d.source);
})
.attr("d", d3.svg.chord().radius(radius))
.attr("transform", function(d) {
return "rotate(" + rotation + ")";
})
.style("opacity", 1);
// Add an elaborate mouseover title for each chord.
gEnter
.selectAll("path.chord")
.on("mouseover", over_user)
.on("mouseout", out_user)
.on("mousemove", move_tooltip);
function move_tooltip(d) {
x = d3.event.pageX + 10;
y = d3.event.pageY + 10;
$("#tooltip").css("left", x + "px");
$("#tooltip").css("top", y + "px");
}
function over_user(d) {
id = d.id;
$("#" + id).css("border", "1px solid black");
$("#" + id).css("z-index", "1");
show_tooltip(d);
}
function out_user(d) {
id = d.id;
$("#" + id).css("border", "");
$("#" + id).css("z-index", "");
hide_tooltip();
}
function create_tooltip(d, x, y) {
if ($("#tooltip").length == 0) {
$(recipient).append(
$("<div></div>")
.attr("id", "tooltip")
.html(
elements[d.source.index] +
" → " +
elements[d.target.index] +
": <b>" +
valueToBytes(d.source.value) +
"</b>" +
"<br>" +
elements[d.target.index] +
" → " +
elements[d.source.index] +
": <b>" +
valueToBytes(d.target.value) +
"</b>"
)
);
} else {
$("#tooltip").html(
elements[d.source.index] +
" → " +
elements[d.target.index] +
": <b>" +
valueToBytes(d.source.value) +
"</b>" +
"<br>" +
elements[d.target.index] +
" → " +
elements[d.source.index] +
": <b>" +
valueToBytes(d.target.value) +
"</b>"
);
}
$("#tooltip").attr(
"style",
2022-05-06 14:23:24 +02:00
"background: " +
tooltipColor +
";" +
"color: " +
textColor +
";" +
"position: absolute;" +
"display: inline-block;" +
"width: auto;" +
"max-width: 500px;" +
"text-align: left;" +
"padding: 10px 10px 10px 10px;" +
"z-index: 2;" +
"-webkit-box-shadow: 7px 7px 5px rgba(50, 50, 50, 0.75);" +
"-moz-box-shadow: 7px 7px 5px rgba(50, 50, 50, 0.75);" +
"box-shadow: 7px 7px 5px rgba(50, 50, 50, 0.75);" +
"left: " +
x +
"px;" +
"top: " +
y +
"px;"
);
}
2021-09-29 10:57:57 +02:00
function add_tooltip(d) {
$("#tooltip").append(
"</br>" +
elements[d.source.index] +
" → " +
elements[d.target.index] +
": <b>" +
valueToBytes(d.source.value) +
"</b>" +
"<br>" +
elements[d.target.index] +
" → " +
elements[d.source.index] +
": <b>" +
valueToBytes(d.target.value) +
"</b>"
);
}
function show_tooltip(d) {
x = d3.event.pageX + 10;
y = d3.event.pageY + 10;
create_tooltip(d, x, y);
}
function hide_tooltip() {
$("#tooltip").hide();
}
});
}
chart.width = function(value) {
if (!arguments.length) return width;
width = value;
return chart;
};
chart.margin = function(value) {
if (!arguments.length) return margin;
margin = value;
return chart;
};
chart.padding = function(value) {
if (!arguments.length) return padding;
padding = value;
return chart;
};
return chart;
};
var chart = d3.chart
.chordWheel()
.width(width)
.margin(150)
.padding(0.02);
d3.select(recipient)
.datum({
elements: elements,
matrix: matrix
})
.call(chart);
}
// The recipient is the selector of the html element
// The data must be a bunch of associative arrays like this
// data = {
// "name": "IP Traffic",
// "id": 0,
// "children": [
// {
// "name": "192.168.1.1",
// "id": 1,
// "children": [
// {
// "name": "HTTP",
// "id": 2,
// "value": 33938
// }
// ]
// },
// {
// "name": "192.168.1.2",
// "id": 3,
// "children": [
// {
// "name": "HTTP",
// "id": 4,
// "value": 3938
// },
// {
// "name": "FTP",
// "id": 5,
// "value": 1312
// }
// ]
// }
// ]
// };
function treeMap(recipient, data, width, height) {
//var isIE = BrowserDetect.browser == 'Explorer';
var isIE = true;
var chartWidth = width;
var chartHeight = height;
2022-06-16 16:04:22 +02:00
var consoleStyle = document.getElementById("hidden-selected_style_theme")
.value;
$("#tooltip").css(
"color",
consoleStyle === "pandora_black" ? "rgb(240, 240, 240)" : "rgb(0, 0, 0)"
);
$("#tooltip").css(
"background-color",
consoleStyle === "pandora_black" ? "rgb(0, 0, 0)" : "rgb(240, 240, 240)"
);
if (width === "auto") {
chartWidth = $(recipient).innerWidth();
}
if (height === "auto") {
chartHeight = $(recipient).innerHeight();
}
var xscale = d3.scale.linear().range([0, chartWidth]);
var yscale = d3.scale.linear().range([0, chartHeight]);
var color = d3.scale.category10();
var headerHeight = 20;
var headerColor = "#555555";
var transitionDuration = 500;
var root;
var node;
var treemap = d3.layout
.treemap()
.round(false)
.size([chartWidth, chartHeight])
.sticky(true)
.value(function(d) {
return d.value;
});
var chart = d3
.select(recipient)
.append("svg:svg")
.attr("width", chartWidth)
.attr("height", chartHeight)
.append("svg:g");
node = root = data;
var nodes = treemap.nodes(root);
var children = nodes.filter(function(d) {
return !d.children;
});
var parents = nodes.filter(function(d) {
return d.children;
});
// create parent cells
var parentCells = chart.selectAll("g.cell.parent").data(parents, function(d) {
return d.id;
});
var parentEnterTransition = parentCells
.enter()
.append("g")
.attr("class", "cell parent")
.on("click", function(d) {
zoom(d);
})
.append("svg")
.attr("class", "clip")
.attr("width", function(d) {
return Math.max(0.01, d.dx);
})
.attr("height", headerHeight);
parentEnterTransition
.append("rect")
.attr("width", function(d) {
return Math.max(0.01, d.dx);
})
.attr("height", headerHeight)
.style("fill", headerColor);
parentEnterTransition
.append("text")
.attr("class", "label")
.attr("fill", "white")
.attr("transform", "translate(3, 13)")
.attr("width", function(d) {
return Math.max(0.01, d.dx);
})
.attr("height", headerHeight)
.text(function(d) {
return d.name;
});
// update transition
var parentUpdateTransition = parentCells
.transition()
.duration(transitionDuration);
parentUpdateTransition.select(".cell").attr("transform", function(d) {
return "translate(" + d.dx + "," + d.y + ")";
});
parentUpdateTransition
.select("rect")
.attr("width", function(d) {
return Math.max(0.01, d.dx);
})
.attr("height", headerHeight)
.style("fill", headerColor);
parentUpdateTransition
.select(".label")
.attr("transform", "translate(3, 13)")
.attr("width", function(d) {
return Math.max(0.01, d.dx);
})
.attr("height", headerHeight)
.text(function(d) {
return d.name;
});
// remove transition
parentCells.exit().remove();
// create children cells
var childrenCells = chart
.selectAll("g.cell.child")
.data(children, function(d) {
return d.id;
});
// enter transition
var childEnterTransition = childrenCells
.enter()
.append("g")
.attr("class", "cell child")
.on("click", function(d) {
zoom(node === d.parent ? root : d.parent);
})
.on("mouseover", over_user)
.on("mouseout", out_user)
.on("mousemove", move_tooltip)
.append("svg")
.attr("class", "clip");
childEnterTransition
.append("rect")
.classed("background", true)
.style("fill", function(d) {
return color(d.name);
});
childEnterTransition
.append("text")
.attr("class", "label")
.attr("x", function(d) {
return d.dx / 2;
})
.attr("y", function(d) {
return d.dy / 2;
})
.attr("dy", ".35em")
.attr("text-anchor", "middle")
.style("display", "none")
.text(function(d) {
return d.name;
});
// update transition
var childUpdateTransition = childrenCells
.transition()
.duration(transitionDuration);
childUpdateTransition.select(".cell").attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});
childUpdateTransition
.select("rect")
.attr("width", function(d) {
return Math.max(0.01, d.dx);
})
.attr("height", function(d) {
return d.dy;
});
childUpdateTransition
.select(".label")
.attr("x", function(d) {
return d.dx / 2;
})
.attr("y", function(d) {
return d.dy / 2;
})
.attr("dy", ".35em")
.attr("text-anchor", "middle")
.style("display", "none")
.text(function(d) {
return d.name;
});
// exit transition
childrenCells.exit().remove();
d3.select("select").on("change", function() {
treemap.value(this.value == "size" ? size : count).nodes(root);
zoom(node);
});
zoom(node);
function size(d) {
return d.size;
}
function count(d) {
return 1;
}
//and another one
function textHeight(d) {
var ky = chartHeight / d.dy;
yscale.domain([d.y, d.y + d.dy]);
return (ky * d.dy) / headerHeight;
}
function getRGBComponents(color) {
var r = color.substring(1, 3);
var g = color.substring(3, 5);
var b = color.substring(5, 7);
return {
R: parseInt(r, 16),
G: parseInt(g, 16),
B: parseInt(b, 16)
};
}
function idealTextColor(bgColor) {
var nThreshold = 105;
var components = getRGBComponents(bgColor);
var bgDelta =
components.R * 0.299 + components.G * 0.587 + components.B * 0.114;
return 255 - bgDelta < nThreshold ? "#000000" : "#ffffff";
}
function zoom(d) {
treemap.padding([headerHeight / (chartHeight / d.dy), 0, 0, 0]).nodes(d);
// moving the next two lines above treemap layout messes up padding of zoom result
var kx = chartWidth / d.dx;
var ky = chartHeight / d.dy;
var level = d;
xscale.domain([d.x, d.x + d.dx]);
yscale.domain([d.y, d.y + d.dy]);
if (node != level) {
chart.selectAll(".cell.child .label").style("display", "none");
}
var zoomTransition = chart
.selectAll("g.cell")
.transition()
.duration(transitionDuration)
.attr("transform", function(d) {
return "translate(" + xscale(d.x) + "," + yscale(d.y) + ")";
})
.each("start", function() {
d3.select(this)
.select("label")
.style("display", "none");
})
.each("end", function(d, i) {
if (!i && level !== self.root) {
chart
.selectAll(".cell.child")
.filter(function(d) {
return d.parent === self.node; // only get the children for selected group
})
.select(".label")
.style("display", "")
.style("color", function(d) {
return idealTextColor(color(d.parent.name));
});
}
});
zoomTransition
.select(".clip")
.attr("width", function(d) {
return Math.max(0.01, kx * d.dx);
})
.attr("height", function(d) {
return d.children ? headerHeight : Math.max(0.01, ky * d.dy);
});
zoomTransition
.select(".label")
.attr("width", function(d) {
return Math.max(0.01, kx * d.dx);
})
.attr("height", function(d) {
return d.children ? headerHeight : Math.max(0.01, ky * d.dy);
})
.text(function(d) {
return d.name;
});
zoomTransition
.select(".child .label")
.attr("x", function(d) {
return (kx * d.dx) / 2;
})
.attr("y", function(d) {
return (ky * d.dy) / 2;
});
zoomTransition
.select("rect")
.attr("width", function(d) {
return Math.max(0.01, kx * d.dx);
})
.attr("height", function(d) {
return d.children ? headerHeight : Math.max(0.01, ky * d.dy);
});
node = d;
if (d3.event) {
d3.event.stopPropagation();
}
}
function position() {
this.style("left", function(d) {
return d.x + "px";
})
.style("top", function(d) {
return d.y + "px";
})
.style("width", function(d) {
return Math.max(0, d.dx - 1) + "px";
})
.style("height", function(d) {
return Math.max(0, d.dy - 1) + "px";
});
}
function move_tooltip(d) {
x = d3.event.pageX + 10;
y = d3.event.pageY + 10;
$("#tooltip").css("left", x + "px");
$("#tooltip").css("top", y + "px");
}
function over_user(d) {
id = d.id;
$("#" + id).css("border", "1px solid black");
$("#" + id).css("z-index", "1");
show_tooltip(d);
}
function out_user(d) {
id = d.id;
$("#" + id).css("border", "");
$("#" + id).css("z-index", "");
hide_tooltip();
}
function create_tooltip(d, x, y) {
if ($("#tooltip").length == 0) {
$(recipient).append(
$("<div></div>")
.attr("id", "tooltip")
.html(d.tooltip_content)
);
} else {
$("#tooltip").html(d.tooltip_content);
}
$("#tooltip").attr(
"style",
"background: #fff;" +
2022-06-17 12:42:24 +02:00
"color: #111;" +
"position: absolute;" +
"display: block;" +
"width: 200px;" +
"text-align: left;" +
"padding: 10px 10px 10px 10px;" +
"z-index: 2;" +
"-webkit-box-shadow: 7px 7px 5px rgba(50, 50, 50, 0.75);" +
"-moz-box-shadow: 7px 7px 5px rgba(50, 50, 50, 0.75);" +
"box-shadow: 7px 7px 5px rgba(50, 50, 50, 0.75);" +
"left: " +
x +
"px;" +
"top: " +
y +
"px;"
);
}
function show_tooltip(d) {
x = d3.event.pageX + 10;
y = d3.event.pageY + 10;
create_tooltip(d, x, y);
}
function hide_tooltip() {
$("#tooltip").hide();
}
}
// A sunburst is similar to a treemap, except it uses a radial layout.
// The root node of the tree is at the center, with leaves on the circumference.
// The area (or angle, depending on implementation) of each arc corresponds to its value.
// Sunburst design by John Stasko. Data courtesy Jeff Heer.
// http://bl.ocks.org/mbostock/4348373
2022-04-13 15:24:31 +02:00
function sunburst(recipient, data, width, height, tooltip = true) {
if (width === "auto") {
width = $(recipient).innerWidth();
}
if (height === "auto") {
height = width;
}
// var width = 960,
// height = 700;
var radius = Math.min(width, height) / 2;
var x = d3.scale.linear().range([0, 2 * Math.PI]);
var y = d3.scale.sqrt().range([0, radius]);
var color = d3.scale.category20c();
var svg = d3
.select(recipient)
.append("svg")
.attr("width", width)
.attr("height", height);
var partition = d3.layout.partition().value(function(d) {
return d.size;
});
var arc = d3.svg
.arc()
.startAngle(function(d) {
return Math.max(0, Math.min(2 * Math.PI, x(d.x)));
})
.endAngle(function(d) {
return Math.max(0, Math.min(2 * Math.PI, x(d.x + d.dx)));
})
.innerRadius(function(d) {
return Math.max(0, y(d.y));
})
.outerRadius(function(d) {
return Math.max(0, y(d.y + d.dy));
});
var g = svg
.selectAll("g")
.data(partition.nodes(data))
.enter()
.append("g")
.attr(
"transform",
"translate(" + width / 2 + "," + (height / 2 + 10) + ")"
);
var path = g
.append("path")
.attr("d", arc)
.style("fill", function(d) {
return d.color
? d3.rgb(d.color)
: color((d.children ? d : d.parent).name);
})
.style("cursor", "pointer")
.on("click", click)
2022-04-13 15:24:31 +02:00
.on("mouseover", tooltip === "1" ? over_user : "")
.on("mouseout", out_user)
.on("mousemove", move_tooltip);
function computeTextRotation(d) {
2022-04-13 15:24:31 +02:00
if (d.type === "central_service") {
return 0;
}
var ang = ((x(d.x + d.dx / 2) - Math.PI / 2) / Math.PI) * 180;
return ang > 90 ? 180 + ang : ang;
}
var text = g
.append("text")
.attr("transform", function(d) {
return (
"translate(" +
arc.centroid(d) +
")rotate(" +
computeTextRotation(d) +
")"
);
})
.attr("x", function(d) {
return computeTextRotation(d) > 180 ? -40 : -30;
})
.attr("dx", "6") // margin
2022-04-13 15:24:31 +02:00
.attr("dy", function(d) {
if (d.type === "central_service") {
return "-7em";
}
return ".35em";
}) // vertical-align
.attr("opacity", function(d) {
2022-04-13 15:24:31 +02:00
if (
(typeof d.show_name != "undefined" && d.show_name) ||
d.type === "central_service"
)
return 1;
else return 0;
})
.text(function(d) {
return d.name;
})
.style("font-size", "10px")
// Makes svg elements invisible to events
.style("pointer-events", "none");
function click(d) {
if (typeof d.link != "undefined") {
window.location.href = d.link;
} else {
// fade out all text elements
2022-04-13 15:24:31 +02:00
if (d.type === "central_service") {
text.transition().attr("opacity", 1);
} else {
text.transition().attr("opacity", 0);
}
path
.transition()
.duration(750)
.attrTween("d", arcTween(d))
.each("end", function(e, i) {
// check if the animated element's data e lies within the visible angle span given in d
if (
typeof e.type != "undefined" &&
(e.type == "group" ||
(e.type == "agent" &&
(d.type == "group" ||
d.type == "agent" ||
d.type == "module_group" ||
d.type == "module")) ||
((e.type == "module_group" || e.type == "module") &&
(d.type == "agent" || d.type == "module_group"))) &&
e.x >= d.x &&
e.x < d.x + d.dx
) {
// get a selection of the associated text element
var arcText = d3.select(this.parentNode).select("text");
// fade in the text element and recalculate positions
arcText
.attr("transform", function(d) {
return (
"translate(" +
arc.centroid(d) +
")rotate(" +
computeTextRotation(d) +
")"
);
})
.attr("x", function(d) {
return computeTextRotation(d) > 180 ? -40 : -30;
})
.transition()
.duration(250)
.attr("opacity", 1);
}
});
}
}
d3.select(self.frameElement).style("height", height + "px");
// Interpolate the scales!
function arcTween(d) {
var xd = d3.interpolate(x.domain(), [d.x, d.x + d.dx]),
yd = d3.interpolate(y.domain(), [d.y, 1]),
yr = d3.interpolate(y.range(), [d.y ? 20 : 0, radius]);
return function(d, i) {
return i
? function(t) {
return arc(d);
}
: function(t) {
x.domain(xd(t));
y.domain(yd(t)).range(yr(t));
return arc(d);
};
};
}
function move_tooltip(d) {
2022-04-12 17:24:47 +02:00
var x = d3.event.pageX + 10 - $("#menu_full").width();
var y = d3.event.pageY - 90;
$("#tooltip").css("left", x + "px");
$("#tooltip").css("top", y + "px");
}
function over_user(d) {
id = d.id;
$("#" + id).css("border", "1px solid black");
$("#" + id).css("z-index", "1");
show_tooltip(d);
}
function out_user(d) {
id = d.id;
$("#" + id).css("border", "");
$("#" + id).css("z-index", "");
hide_tooltip();
}
function create_tooltip(d, x, y) {
var tooltip =
typeof d.tooltip_content != "undefined" ? d.tooltip_content : d.name;
if ($("#tooltip").length == 0) {
$(recipient).append(
$("<div></div>")
.attr("id", "tooltip")
.html(tooltip)
);
} else {
$("#tooltip").html(tooltip);
}
$("#tooltip").attr(
"style",
"background: #fff;" +
2022-06-17 12:42:24 +02:00
"color: #111;" +
"position: absolute;" +
"display: block;" +
"width: 200px;" +
"text-align: left;" +
"padding: 10px 10px 10px 10px;" +
"z-index: 2;" +
"-webkit-box-shadow: 7px 7px 5px rgba(50, 50, 50, 0.75);" +
"-moz-box-shadow: 7px 7px 5px rgba(50, 50, 50, 0.75);" +
"box-shadow: 7px 7px 5px rgba(50, 50, 50, 0.75);" +
"left: " +
2022-04-12 17:24:47 +02:00
100 +
"px;" +
"top: " +
2022-04-12 17:24:47 +02:00
100 +
"px;"
);
}
function show_tooltip(d) {
var x = d3.event.pageX + 10;
var y = d3.event.pageY + 10;
create_tooltip(d, x, y);
}
function hide_tooltip() {
$("#tooltip").hide();
}
}
function createGauge(
name,
etiqueta,
value,
min,
max,
min_warning,
max_warning,
warning_inverse,
min_critical,
max_critical,
critical_inverse,
font_size,
height,
2020-06-01 14:48:53 +02:00
font,
transitionDuration
) {
var gauges;
var config = {
size: height,
label: etiqueta,
min: undefined != min ? min : 0,
max: undefined != max ? max : 100,
2020-06-01 14:48:53 +02:00
font_size: font_size,
transitionDuration: transitionDuration
};
if (value == null) {
config.majorTicks = 1;
config.minorTicks = 1;
value = false;
} else {
config.minorTicks = 10;
}
save_min_critical = min_critical;
save_max_critical = max_critical;
save_min_warning = min_warning;
save_max_warning = max_warning;
if (max_warning < config.min) {
config.min = max_warning;
}
if (min_warning < config.min) {
config.min = min_warning;
}
if (max_critical < config.min) {
config.min = max_critical;
}
if (min_critical < config.min) {
config.min = min_critical;
}
if (max_warning > config.max) {
config.max = max_warning;
}
if (min_warning > config.max) {
config.max = min_warning;
}
if (max_critical > config.max) {
config.max = max_critical;
}
if (min_critical > config.max) {
config.max = min_critical;
}
if (config.max < value) {
config.max = value;
}
if (config.min > value) {
config.min = value;
}
if (critical_inverse == 1) {
if (max_critical == 0) {
max_critical = min_critical;
min_critical = config.min;
} else {
max_critical = save_min_critical;
min_critical = config.min;
max_critical2 = config.max;
min_critical2 = save_max_critical;
}
} else {
if (min_critical > max_critical && max_critical == 0) {
max_critical = config.max;
}
}
if (warning_inverse == 1) {
if (max_warning == 0) {
max_warning = min_warning;
min_warning = config.min;
} else {
max_warning = save_min_warning;
min_warning = config.min;
max_warning2 = config.max;
min_warning2 = save_max_warning;
}
} else {
if (min_warning > max_warning && max_warning == 0) {
max_warning = config.max;
}
}
if (value !== false) {
if (typeof max_warning2 !== "undefined") {
if (min_warning >= 0 && min_warning != max_warning) {
config.yellowZones = [
{ from: min_warning, to: max_warning },
{ from: min_warning2, to: max_warning2 }
];
}
} else {
if (min_warning >= 0 && min_warning != max_warning) {
config.yellowZones = [{ from: min_warning, to: max_warning }];
}
}
if (typeof max_critical2 !== "undefined") {
if (min_critical >= 0 && min_critical != max_critical) {
config.redZones = [
{ from: min_critical, to: max_critical },
{ from: min_critical2, to: max_critical2 }
];
}
} else {
if (min_critical >= 0 && min_critical != max_critical) {
config.redZones = [{ from: min_critical, to: max_critical }];
}
}
}
var range = config.max - config.min;
gauges = new Gauge(name, config, font);
gauges.render();
2020-06-01 14:48:53 +02:00
gauges.redraw(value, config.transitionDuration);
$(".gauge>text").each(function() {
label = $(this).text();
if (!isNaN(label)) {
label = parseFloat(label);
text = label.toLocaleString();
if (label >= 1000000) text = text.substring(0, 4) + "M";
else if (label >= 100000) text = text.substring(0, 3) + "K";
else if (label >= 10000) text = text.substring(0, 3) + "K";
$(this).text(text);
}
});
$(".pointerContainer>text").each(function() {
label = $(this).text();
if (!isNaN(label)) {
label = parseFloat(label);
text = label.toLocaleString();
if (label >= 10000000) text = text.substring(0, 4) + "M";
else if (label >= 1000000) text = text.substring(0, 4) + "M";
else if (label >= 100000) text = text.substring(0, 3) + "K";
else if (label >= 10000) text = text.substring(0, 3) + "K";
$(this).text(text);
}
});
}
2020-06-01 14:48:53 +02:00
function createGauges(
data,
width,
height,
font_size,
no_data_image,
font,
transitionDuration
) {
var nombre,
label,
minimun_warning,
maximun_warning,
minimun_critical,
maximun_critical,
mininum,
maxinum,
valor;
2019-12-13 09:06:54 +01:00
for (var key in data) {
nombre = data[key].gauge;
label = data[key].label;
label = label.replace(/&#x20;/g, " ");
label = label.replace(/\(/g, "(");
label = label.replace(/\)/g, ")");
label = label.replace(/&#40;/g, "(");
label = label.replace(/&#41;/g, ")");
minimun_warning = round_with_decimals(parseFloat(data[key].min_warning));
maximun_warning = round_with_decimals(parseFloat(data[key].max_warning));
minimun_critical = round_with_decimals(parseFloat(data[key].min_critical));
maximun_critical = round_with_decimals(parseFloat(data[key].max_critical));
mininum = round_with_decimals(parseFloat(data[key].min));
maxinum = round_with_decimals(parseFloat(data[key].max));
2019-12-13 09:06:54 +01:00
var critical_inverse = parseInt(data[key].critical_inverse);
var warning_inverse = parseInt(data[key].warning_inverse);
valor = round_with_decimals(data[key].value);
if (isNaN(valor)) valor = null;
createGauge(
nombre,
label,
valor,
mininum,
maxinum,
minimun_warning,
maximun_warning,
warning_inverse,
minimun_critical,
maximun_critical,
critical_inverse,
font_size,
height,
2020-06-01 14:48:53 +02:00
font,
transitionDuration
);
}
}
function Gauge(placeholderName, configuration, font) {
var font = font
.split("/")
.pop()
.split(".")
.shift();
this.placeholderName = placeholderName;
var self = this; // for internal d3 functions
this.configure = function(configuration) {
this.config = configuration;
this.config.size = this.config.size * 0.9;
this.config.font_size = this.config.font_size;
this.config.raduis = (this.config.size * 0.97) / 2;
this.config.cx = this.config.size / 2;
this.config.cy = this.config.size / 2;
this.config.min = undefined != configuration.min ? configuration.min : 0;
this.config.max = undefined != configuration.max ? configuration.max : 100;
this.config.range = this.config.max - this.config.min;
this.config.majorTicks = configuration.majorTicks || 5;
this.config.minorTicks = configuration.minorTicks || 2;
this.config.greenColor = configuration.greenColor || "#109618";
this.config.yellowColor = configuration.yellowColor || "#FF9900";
this.config.redColor = configuration.redColor || "#DC3912";
2020-06-01 14:48:53 +02:00
this.config.transitionDuration = configuration.transitionDuration;
};
this.render = function() {
this.body = d3
.select("#" + this.placeholderName)
.append("svg:svg")
.attr("class", "gauge")
.attr("width", this.config.size)
.attr("height", this.config.size);
this.body
.append("svg:circle")
.attr("cx", this.config.cx)
.attr("cy", this.config.cy)
.attr("r", this.config.raduis)
.style("fill", "#ccc")
.style("stroke", "#000")
.style("stroke-width", "0.5px");
this.body
.append("svg:circle")
.attr("cx", this.config.cx)
.attr("cy", this.config.cy)
.attr("r", 0.9 * this.config.raduis)
.style("fill", "#fff")
.style("stroke", "#e0e0e0")
.style("stroke-width", "2px");
for (var index in this.config.greenZones) {
this.drawBand(
this.config.greenZones[index].from,
this.config.greenZones[index].to,
self.config.greenColor
);
}
for (var index in this.config.yellowZones) {
this.drawBand(
this.config.yellowZones[index].from,
this.config.yellowZones[index].to,
self.config.yellowColor
);
}
for (var index in this.config.redZones) {
this.drawBand(
this.config.redZones[index].from,
this.config.redZones[index].to,
self.config.redColor
);
}
if (undefined != this.config.label) {
var fontSize = Math.round(this.config.size / 9);
this.body
.append("svg:text")
.attr("x", this.config.cx)
.attr("y", this.config.cy / 2 + fontSize / 2)
.attr("dy", fontSize / 2)
.attr("text-anchor", "middle")
.attr("class", font)
.text(this.config.label)
.style("font-size", this.config.font_size + "pt")
.style("fill", "#333")
.style("stroke-width", "0px");
}
var fontSize = Math.round(this.config.size / 16);
var majorDelta = this.config.range / (this.config.majorTicks - 1);
for (
var major = this.config.min;
major <= this.config.max;
major += majorDelta
) {
var minorDelta = majorDelta / this.config.minorTicks;
for (
var minor = major + minorDelta;
minor < Math.min(major + majorDelta, this.config.max);
minor += minorDelta
) {
var point1 = this.valueToPoint(minor, 0.75);
var point2 = this.valueToPoint(minor, 0.85);
this.body
.append("svg:line")
.attr("x1", point1.x)
.attr("y1", point1.y)
.attr("x2", point2.x)
.attr("y2", point2.y)
.style("stroke", "#666")
.style("stroke-width", "1px");
}
var point1 = this.valueToPoint(major, 0.7);
var point2 = this.valueToPoint(major, 0.85);
this.body
.append("svg:line")
.attr("x1", point1.x)
.attr("y1", point1.y)
.attr("x2", point2.x)
.attr("y2", point2.y)
.style("stroke", "#333")
.style("stroke-width", "2px");
if (major == this.config.min || major == this.config.max) {
var point = this.valueToPoint(major, 0.63);
this.body
.append("svg:text")
.attr("x", point.x)
.attr("y", point.y)
.attr("dy", fontSize / 3)
.attr("text-anchor", major == this.config.min ? "start" : "end")
.text(major)
.style("font-size", this.config.font_size + "pt")
.style("fill", "#333")
.style("stroke-width", "0px");
}
}
var pointerContainer = this.body
.append("svg:g")
.attr("class", "pointerContainer");
var midValue = (this.config.min + this.config.max) / 2;
var pointerPath = this.buildPointerPath(midValue);
var pointerLine = d3.svg
.line()
.x(function(d) {
return d.x;
})
.y(function(d) {
return d.y;
})
.interpolate("basis");
pointerContainer
.selectAll("path")
.data([pointerPath])
.enter()
.append("svg:path")
.attr("d", pointerLine)
.style("fill", "#dc3912")
.style("stroke", "#c63310")
.style("fill-opacity", 0.7);
pointerContainer
.append("svg:circle")
.attr("cx", this.config.cx)
.attr("cy", this.config.cy)
.attr("r", 0.12 * this.config.raduis)
.style("fill", "#4684EE")
.style("stroke", "#666")
.style("opacity", 1);
var fontSize = Math.round(this.config.size / 10);
pointerContainer
.selectAll("text")
.data([midValue])
.enter()
.append("svg:text")
.attr("x", this.config.cx)
.attr("y", this.config.size - this.config.cy / 4 - fontSize)
.attr("dy", fontSize / 2)
.attr("text-anchor", "middle")
.style("font-size", this.config.font_size + "pt")
.style("fill", "#000")
.style("stroke-width", "0px");
this.redraw(this.config.min, 0);
};
this.buildPointerPath = function(value) {
var delta = this.config.range / 13;
var head = valueToPoint(value, 0.85);
var head1 = valueToPoint(value - delta, 0.12);
var head2 = valueToPoint(value + delta, 0.12);
var tailValue = value - (this.config.range * (1 / (270 / 360))) / 2;
var tail = valueToPoint(tailValue, 0.28);
var tail1 = valueToPoint(tailValue - delta, 0.12);
var tail2 = valueToPoint(tailValue + delta, 0.12);
return [head, head1, tail2, tail, tail1, head2, head];
function valueToPoint(value, factor) {
var point = self.valueToPoint(value, factor);
point.x -= self.config.cx;
point.y -= self.config.cy;
return point;
}
};
this.drawBand = function(start, end, color) {
if (start === undefined) return;
if (end === undefined) return;
if (0 >= end - start) return;
this.body
.append("svg:path")
.style("fill", color)
.attr(
"d",
d3.svg
.arc()
.startAngle(this.valueToRadians(start))
.endAngle(this.valueToRadians(end))
.innerRadius(Math.round(0.65 * this.config.raduis))
.outerRadius(Math.round(0.85 * this.config.raduis))
)
.attr("transform", function() {
return (
"translate(" +
self.config.cx +
", " +
self.config.cy +
") rotate(270)"
);
});
};
this.redraw = function(value, transitionDuration) {
var pointerContainer = this.body.select(".pointerContainer");
pointerContainer.selectAll("text").text(round_with_decimals(value));
var pointer = pointerContainer.selectAll("path");
pointer
.transition()
2020-06-01 14:48:53 +02:00
.duration(undefined != transitionDuration ? transitionDuration : 0)
//.delay(0)
//.ease("linear")
//.attr("transform", function(d)
.attrTween("transform", function() {
var pointerValue = value;
if (value > self.config.max)
pointerValue = self.config.max + 0.02 * self.config.range;
else if (value < self.config.min)
pointerValue = self.config.min - 0.02 * self.config.range;
var targetRotation = self.valueToDegrees(pointerValue) - 90;
var currentRotation = self._currentRotation || targetRotation;
self._currentRotation = targetRotation;
return function(step) {
var rotation =
currentRotation + (targetRotation - currentRotation) * step;
return (
"translate(" +
self.config.cx +
", " +
self.config.cy +
") rotate(" +
rotation +
")"
);
};
});
};
this.valueToDegrees = function(value) {
// thanks @closealert
//return value / this.config.range * 270 - 45;
return (
(value / this.config.range) * 270 -
((this.config.min / this.config.range) * 270 + 45)
);
};
this.valueToRadians = function(value) {
return (this.valueToDegrees(value) * Math.PI) / 180;
};
this.valueToPoint = function(value, factor) {
return {
x:
this.config.cx -
this.config.raduis * factor * Math.cos(this.valueToRadians(value)),
y:
this.config.cy -
this.config.raduis * factor * Math.sin(this.valueToRadians(value))
};
};
// initialization
this.configure(configuration);
2017-04-25 15:34:11 +02:00
}
2020-03-26 12:29:38 +01:00
function print_phases_donut(recipient, phases, width, height) {
var svg = d3
.select(recipient)
.append("svg")
2020-03-26 12:29:38 +01:00
.attr("width", width)
.attr("height", height)
.append("g");
svg.append("g").attr("class", "slices");
svg.append("g").attr("class", "labels");
svg.append("g").attr("class", "lines");
2020-03-26 12:29:38 +01:00
var radius = Math.min(width, height) / 2 - 50;
var pie = d3.layout
.pie()
.sort(null)
.value(function(d) {
return parseFloat(d.label2);
});
var arc = d3.svg
.arc()
.outerRadius(radius * 0.8)
.innerRadius(radius * 0.4);
var outerArc = d3.svg
.arc()
.innerRadius(radius * 0.9)
.outerRadius(radius * 0.9);
svg.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var key = function(d) {
return d.data.label;
};
function phasesData() {
return phases.map(function(phase) {
return {
label: phase_name(phase, 1),
label2: phase_name(phase, 2),
value: phase.status
};
});
}
function phase_name(phase, index) {
if (index == 1) {
return phase.phase_name;
} else {
return phase.phase_time;
}
}
print_phases(phasesData());
function print_phases(data) {
/* ------- PIE SLICES -------*/
var slice = svg
.select(".slices")
.selectAll("path.slice")
.data(pie(data), key);
slice
.enter()
.insert("path")
.style("fill", function(d) {
if (d.data.value == 0) {
2019-06-04 14:08:07 +02:00
return "#82b92e";
} else {
2019-06-04 14:08:07 +02:00
return "#e63c52";
}
})
.attr("class", "slice");
slice
.transition()
.duration(0)
.attrTween("d", function(d) {
this._current = this._current || d;
var interpolate = d3.interpolate(this._current, d);
this._current = interpolate(0);
return function(t) {
return arc(interpolate(t));
};
});
slice.exit().remove();
/* ------- TEXT LABELS -------*/
var text = svg
.select(".labels")
.selectAll("text")
.data(pie(data), key);
text
.enter()
.append("text")
.append("tspan")
.attr("dy", ".1em")
.text(function(d) {
return d.data.label;
})
.style("font-size", "15px")
.append("tspan")
.attr("dy", "1.2em")
.attr("dx", "-2.8em")
.text(function(d) {
return d.data.label2 + "ms";
})
.style("font-size", "15px");
function midAngle(d) {
return d.startAngle + (d.endAngle - d.startAngle) / 2;
}
var ex = 1;
var sum = 0;
text
.transition()
.duration(0)
.attrTween("transform", function(d) {
this._current = this._current || d;
var interpolate = d3.interpolate(this._current, d);
this._current = interpolate(0);
return function(t) {
var d2 = interpolate(t);
//fix for labels of a very small portion increase the
//height of the label so that they do not overlap
if (d2.endAngle - d2.startAngle < 0.1) {
var pos = outerArc.centroid(d2);
if (ex % 2 == 0) {
pos[0] = 150;
} else {
pos[0] = -150;
sum++;
}
pos[1] = pos[1] - 35 * sum;
ex++;
} else {
var pos = outerArc.centroid(d2);
pos[0] = radius * (midAngle(d2) < Math.PI ? 1 : -1);
}
return "translate(" + pos + ")";
};
})
.styleTween("text-anchor", function(d) {
this._current = this._current || d;
var interpolate = d3.interpolate(this._current, d);
this._current = interpolate(0);
return function(t) {
var d2 = interpolate(t);
//fix for labels of a very small portion increase the
//height of the label so that they do not overlap
if (d2.endAngle - d2.startAngle < 0.1) {
if (ex % 2 == 0) {
return "start";
} else {
return "end";
}
}
return midAngle(d2) < Math.PI ? "start" : "end";
};
});
text.exit().remove();
/* ------- SLICE TO TEXT POLYLINES -------*/
var polyline = svg
.select(".lines")
.selectAll("polyline")
.data(pie(data), key);
polyline.enter().append("polyline");
var ex2 = 1;
var sum2 = 0;
polyline
.transition()
.duration(0)
.attrTween("points", function(d) {
this._current = this._current || d;
var interpolate = d3.interpolate(this._current, d);
this._current = interpolate(0);
return function(t) {
var d2 = interpolate(t);
//fix for labels of a very small portion increase the
//height of the label so that they do not overlap
if (d2.endAngle - d2.startAngle < 0.1) {
var pos = outerArc.centroid(d2);
if (ex2 % 2 == 0) {
pos[0] = 150 * 0.95;
} else {
pos[0] = -150 * 0.95;
sum2++;
}
pos[1] = pos[1] - 30 * sum2;
ex2++;
} else {
var pos = outerArc.centroid(d2);
pos[0] = radius * 0.95 * (midAngle(d2) < Math.PI ? 1 : -1);
}
return [arc.centroid(d2), outerArc.centroid(d2), pos];
};
})
.style("stroke", "black")
.style("opacity", ".3")
.style("stroke-width", "2px")
.style("fill", "none");
polyline.exit().remove();
}
2017-10-25 18:40:58 +02:00
}
function progress_bar_d3(
recipient,
percentile,
width,
height,
color,
unit,
label,
label_color,
radiusx,
radiusy,
transition
) {
var startPercent = 0;
var endPercent = parseInt(percentile) / 100;
var count = Math.abs((endPercent - startPercent) / 0.01);
var step = endPercent < startPercent ? -0.01 : 0.01;
var circle = d3
.select(recipient)
.append("svg")
.attr("width", width)
.attr("height", height);
var progress_back = circle
.append("rect")
.attr("fill", "#000000")
.attr("fill-opacity", 0.5)
.attr("height", height)
.attr("width", width)
.attr("rx", radiusx)
.attr("ry", radiusy)
.attr("x", 0);
var progress_front = circle
.append("rect")
.attr("fill", color)
.attr("fill-opacity", 1)
.attr("height", height)
.attr("width", 0)
.attr("rx", radiusx)
.attr("ry", radiusy)
.attr("x", 0);
var labelText = circle
.append("text")
.attr("transform", "translate(" + width / 2 + ", " + height / 2 + ")")
.attr("fill", label_color)
.style("font-weight", "bold")
.style("font-size", 20)
.html(label)
.attr("dy", "15")
.attr("text-anchor", "middle");
var numberText = circle
.append("text")
.attr("transform", "translate(" + width / 2 + ", " + height / 2 + ")")
.attr("fill", "#FFFFFF")
.style("font-weight", "bold")
.style("font-size", 14)
.attr("text-anchor", "middle")
.attr("dy", (height - height / 2) / 4);
function updateProgress(bar_progress) {
var percent_value = Number(bar_progress * 100);
numberText.text(percent_value.toFixed() + " " + unit);
progress_front.attr("width", width * bar_progress);
}
if (transition == 0) {
var bar_progress = endPercent;
updateProgress(bar_progress);
} else {
var bar_progress = startPercent;
(function loops() {
updateProgress(bar_progress);
if (count > 0) {
count--;
bar_progress += step;
setTimeout(loops, 30);
}
})();
}
}
function progress_bubble_d3(
recipient,
percentile,
width,
height,
color,
unit,
label,
label_color
) {
var startPercent = 0;
var endPercent = parseInt(percentile) / 100;
var count = Math.abs((endPercent - startPercent) / 0.01);
var step = endPercent < startPercent ? -0.01 : 0.01;
var numberSize = 0;
var textSize = 0;
var unitSize = 0;
var yPosText = 0;
var yPosNumber = 0;
if (width >= 500) {
numberSize = 100;
textSize = 50;
unitSize = 50;
yPosNumber = "15";
yPosText = "-100";
} else if (width >= 400) {
numberSize = 80;
textSize = 40;
unitSize = 40;
yPosNumber = "15";
yPosText = "-80";
} else if (width >= 300) {
numberSize = 60;
textSize = 30;
unitSize = 30;
yPosNumber = "15";
yPosText = "-45";
} else if (width >= 200) {
numberSize = 40;
textSize = 20;
unitSize = 20;
yPosNumber = "50";
yPosText = "-30";
} else if (width >= 100) {
numberSize = 20;
textSize = 10;
unitSize = 10;
yPosNumber = "5";
yPosText = "-20";
} else {
numberSize = 10;
textSize = 8;
unitSize = 8;
yPosNumber = "5";
yPosText = "-10";
}
var circle = d3
.select(recipient)
.append("svg")
.attr("width", width)
.attr("height", height);
var progress_back = circle
.append("circle")
.attr("transform", "translate(" + width / 2 + ", " + height / 2 + ")")
.attr("fill", "#000000")
.attr("fill-opacity", 0)
.attr("r", width / 2);
var progress_front = circle
.append("circle")
.attr("transform", "translate(" + width / 2 + ", " + height / 2 + ")")
.attr("fill", color)
.attr("fill-opacity", 1)
.attr("r", 0);
var labelText = circle
.append("text")
.attr("transform", "translate(" + width / 2 + ", " + height / 2 + ")")
.attr("fill", label_color)
.style("font-weight", "bold")
.style("font-size", textSize)
.html(label)
.attr("dy", -(width / 3))
.attr("text-anchor", "middle");
var numberText = circle
.append("text")
.attr("transform", "translate(" + width / 2 + ", " + height / 2 + ")")
.attr("fill", label_color)
.style("font-weight", "bold")
.style("font-size", numberSize)
.attr("text-anchor", "middle")
.attr("dy", width / 3);
function updateProgress(bar_progress) {
var percent_value = Number(bar_progress * 100);
numberText.text(percent_value.toFixed() + " " + unit);
progress_front.attr("r", (width / 2) * bar_progress);
}
var bar_progress = startPercent;
(function loops() {
updateProgress(bar_progress);
if (count > 0) {
count--;
bar_progress += step;
setTimeout(loops, 30);
}
})();
}
function print_circular_progress_bar(
recipient,
percentile,
width,
height,
color,
unit,
label,
label_color,
transition
) {
var twoPi = Math.PI * 2;
var radius = width / 2;
var border = 20;
var startPercent = 0;
var endPercent = parseInt(percentile) / 100;
var count = Math.abs((endPercent - startPercent) / 0.01);
var step = endPercent < startPercent ? -0.01 : 0.01;
var numberSize = 0;
var textSize = 0;
var unitSize = 0;
var yPosText = 0;
var yPosUnit = 0;
var yPosNumber = 0;
if (width >= 500) {
numberSize = 100;
textSize = 50;
unitSize = 50;
yPosNumber = "15";
yPosText = "-100";
yPosUnit = "100";
} else if (width >= 400) {
numberSize = 80;
textSize = 40;
unitSize = 40;
yPosNumber = "15";
yPosText = "-80";
yPosUnit = "80";
} else if (width >= 300) {
numberSize = 60;
textSize = 30;
unitSize = 30;
yPosNumber = "15";
yPosText = "-45";
yPosUnit = "60";
} else if (width >= 200) {
numberSize = 40;
textSize = 20;
unitSize = 20;
yPosNumber = "10";
yPosText = "-30";
yPosUnit = "40";
} else if (width >= 100) {
numberSize = 20;
textSize = 10;
unitSize = 10;
yPosNumber = "5";
yPosText = "-15";
yPosUnit = "20";
} else {
numberSize = 8;
textSize = 4;
unitSize = 4;
yPosNumber = "2";
yPosText = "-5";
yPosUnit = "5";
}
var arc = d3.svg
.arc()
.startAngle(0)
.innerRadius(radius)
.outerRadius(radius - border);
var circle = d3
.select(recipient)
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + ", " + height / 2 + ")");
var meter = circle.append("g").attr("class", "progress-meter");
meter
.append("path")
.attr("fill", "#000000")
.attr("fill-opacity", 0.5)
.attr("d", arc.endAngle(twoPi));
var foreground = circle
.append("path")
.attr("fill", color)
.attr("fill-opacity", 1)
.attr("stroke", color)
.attr("stroke-opacity", 1);
var front = circle
.append("path")
.attr("fill", color)
.attr("fill-opacity", 1);
var labelText = circle
.append("text")
.attr("fill", label_color)
.style("font-weight", "bold")
.style("font-size", textSize)
.html(label)
.attr("text-anchor", "middle")
.attr("dy", yPosText);
var numberText = circle
.append("text")
2023-03-13 15:44:55 +01:00
.attr("fill", "#333333")
.style("font-weight", "bold")
.style("font-size", numberSize)
.attr("text-anchor", "middle")
.attr("dy", yPosNumber);
var percentText = circle
.append("text")
2023-03-13 15:44:55 +01:00
.attr("fill", "#333333")
.style("font-weight", "bold")
.style("font-size", unitSize)
.text(unit)
.attr("text-anchor", "middle")
.attr("dy", yPosUnit);
function updateProgress(progress) {
foreground.attr("d", arc.endAngle(twoPi * progress));
front.attr("d", arc.endAngle(twoPi * progress));
var percent_value = Number(progress * 100);
numberText.text(percent_value.toFixed());
}
var progress = startPercent;
2019-05-27 19:00:48 +02:00
if (transition == 0) updateProgress(endPercent);
else {
(function loops() {
updateProgress(progress);
if (count > 0) {
count--;
progress += step;
setTimeout(loops, 30);
}
})();
}
2017-10-05 16:38:21 +02:00
}
function print_interior_circular_progress_bar(
recipient,
percentile,
width,
height,
color,
unit,
label,
label_color
) {
var twoPi = Math.PI * 2;
var radius = width / 2 - 20;
var radius2 = width / 2;
var border = 20;
var startPercent = 0;
var endPercent = parseInt(percentile) / 100;
var count = Math.abs((endPercent - startPercent) / 0.01);
var step = endPercent < startPercent ? -0.01 : 0.01;
var numberSize = 0;
var textSize = 0;
var unitSize = 0;
var yPosText = 0;
var yPosUnit = 0;
var yPosNumber = 0;
if (width >= 500) {
numberSize = 100;
textSize = 50;
unitSize = 50;
yPosNumber = "15";
yPosText = "-100";
yPosUnit = "100";
} else if (width >= 400) {
numberSize = 80;
textSize = 40;
unitSize = 40;
yPosNumber = "15";
yPosText = "-80";
yPosUnit = "80";
} else if (width >= 300) {
numberSize = 60;
textSize = 30;
unitSize = 30;
yPosNumber = "15";
yPosText = "-45";
yPosUnit = "60";
} else if (width >= 200) {
numberSize = 40;
textSize = 20;
unitSize = 20;
yPosNumber = "10";
yPosText = "-30";
yPosUnit = "40";
} else if (width >= 100) {
numberSize = 20;
textSize = 10;
unitSize = 10;
yPosNumber = "5";
yPosText = "-15";
yPosUnit = "20";
} else {
numberSize = 8;
textSize = 4;
unitSize = 4;
yPosNumber = "2";
yPosText = "-5";
yPosUnit = "5";
}
var arc = d3.svg
.arc()
.startAngle(0)
.innerRadius(radius)
.outerRadius(radius - border);
var arc2 = d3.svg
.arc()
.startAngle(0)
.innerRadius(radius2)
.outerRadius(radius2 - border);
var circle = d3
.select(recipient)
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + ", " + height / 2 + ")");
var meter = circle.append("g").attr("class", "progress-meter");
meter
.append("path")
.attr("fill", "#000000")
.attr("fill-opacity", 0.5)
.attr("d", arc.endAngle(twoPi));
var meter = circle.append("g").attr("class", "progress-meter");
meter
.append("path")
.attr("fill", color)
.attr("fill-opacity", 1)
.attr("d", arc2.endAngle(twoPi));
var foreground = circle
.append("path")
.attr("fill", color)
.attr("fill-opacity", 1)
.attr("stroke", color)
.attr("stroke-opacity", 1);
var front = circle
.append("path")
.attr("fill", color)
.attr("fill-opacity", 1);
var labelText = circle
.append("text")
.attr("fill", label_color)
.style("font-weight", "bold")
.style("font-size", textSize)
.html(label)
.attr("text-anchor", "middle")
.attr("dy", yPosText);
var numberText = circle
.append("text")
.attr("fill", label_color)
.style("font-weight", "bold")
.style("font-size", numberSize)
.attr("text-anchor", "middle")
.attr("dy", yPosNumber);
var percentText = circle
.append("text")
.attr("fill", label_color)
.style("font-weight", "bold")
.style("font-size", unitSize)
.text(unit)
.attr("text-anchor", "middle")
.attr("dy", yPosUnit);
function updateProgress(progress) {
foreground.attr("d", arc.endAngle(twoPi * progress));
front.attr("d", arc.endAngle(twoPi * progress));
var percent_value = Number(progress * 100);
numberText.text(percent_value.toFixed());
}
var progress = startPercent;
(function loops() {
updateProgress(progress);
if (count > 0) {
count--;
progress += step;
setTimeout(loops, 30);
}
})();
2017-10-26 15:37:43 +02:00
}
2020-01-24 15:13:42 +01:00
// eslint-disable-next-line no-unused-vars
function print_donut_graph(
recipient,
width,
height,
module_data,
resume_color
) {
var svg = d3
.select(recipient)
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g");
svg.append("g").attr("class", "slices");
2020-01-24 15:13:42 +01:00
var heightLegend = 25 * module_data.length;
var maxRadius = (height - heightLegend) / 2;
var radius = maxRadius;
if (maxRadius > width / 2) {
radius = width / 2;
}
var arc = d3.svg
.arc()
.outerRadius(radius * 0.8)
.innerRadius(radius * 0.4);
var key = function(d) {
return d.data.label;
};
var pie = d3.layout
.pie()
.sort(null)
.value(function(d) {
return parseFloat(d.percent);
});
jQuery.each(module_data, function(key, m_d) {
svg
.append("g")
.append("rect")
.attr("fill", m_d.color)
2020-01-24 15:13:42 +01:00
.attr("x", 20)
.attr("y", 20 * (key + 1))
.attr("width", 25)
.attr("height", 15);
svg
.append("g")
.append("text")
.attr("fill", resume_color)
2020-01-24 15:13:42 +01:00
.attr("transform", "translate(" + 40 + "," + 20 * (key + 1) + ")")
.attr("x", 15)
.attr("y", 10)
.text(m_d.tag_name)
.style("font-size", "7pt");
});
function donutData() {
return module_data.map(function(m_data) {
return {
label: m_data.tag_name,
percent: m_data.percent,
color: m_data.color
};
});
}
print_phases(donutData());
function print_phases(data) {
var slice = svg
.select(".slices")
.selectAll("path.slice")
.data(pie(data), key);
slice
.enter()
.insert("path")
.style("fill", function(d) {
return d.data.color;
})
.attr("class", "slice")
.attr(
"transform",
2020-01-24 15:13:42 +01:00
"translate(" + width / 2 + "," + (height + heightLegend) / 2 + ")"
);
slice
.transition()
.duration(0)
.attrTween("d", function(d) {
this._current = this._current || d;
var interpolate = d3.interpolate(this._current, d);
this._current = interpolate(0);
return function(t) {
return arc(interpolate(t));
};
});
slice.exit().remove();
}
2017-12-01 12:14:56 +01:00
}
function printClockAnalogic1(
time_format,
timezone,
clock_animation,
width,
height,
id_element,
color
) {
if (width != 0) {
width = width - 20;
height = width - 20;
}
if (width == 0) {
width = 180;
height = 180;
}
var radians = 0.0174532925,
clockRadius = width / 2,
margin = 10,
width = (clockRadius + margin) * 2,
height = (clockRadius + margin) * 2,
hourHandLength = (2 * clockRadius) / 3,
2017-12-01 12:14:56 +01:00
minuteHandLength = clockRadius,
secondHandLength = clockRadius - 12,
2017-12-01 12:14:56 +01:00
secondHandBalance = 30,
secondTickStart = clockRadius;
(secondTickLength = -10),
(hourTickStart = clockRadius),
(hourTickLength = -18),
(secondLabelRadius = clockRadius + 16),
(secondLabelYOffset = 5),
(hourLabelRadius = clockRadius - 40),
(hourLabelYOffset = 7);
var hourScale = d3.scale
.linear()
.range([0, 330])
.domain([0, 11]);
var minuteScale = (secondScale = d3.scale
.linear()
.range([0, 354])
.domain([0, 59]));
var handData = [
{
type: "hour",
value: 0,
length: -hourHandLength,
scale: hourScale
},
{
type: "minute",
value: 0,
length: -minuteHandLength,
scale: minuteScale
},
{
type: "second",
value: 0,
length: -secondHandLength,
scale: secondScale,
balance: secondHandBalance
}
];
function drawClock() {
//create all the clock elements
updateData(timezone); //draw them in the correct starting position
var svg = d3
.select("#clock_" + id_element)
.append("svg")
.attr("width", width)
.attr("height", height);
var face = svg
.append("g")
.attr("id", "clock-face")
2021-04-14 15:09:19 +02:00
.attr("class", "invert_filter")
.attr(
"transform",
"translate(" +
(clockRadius + margin) +
"," +
(clockRadius + margin) +
")"
);
//add marks for seconds
face
.selectAll(".second-tick")
.data(d3.range(0, 60))
.enter()
.append("line")
.attr("class", "second-tick")
.attr("x1", 0)
.attr("x2", 0)
.attr("y1", secondTickStart)
.attr("y2", secondTickStart + secondTickLength)
.attr("stroke", color)
.attr("transform", function(d) {
return "rotate(" + secondScale(d) + ")";
});
//and labels
// face.selectAll('.second-label')
// .data(d3.range(5,61,5))
// .enter()
// .append('text')
// .attr('class', 'second-label')
// .attr('text-anchor','middle')
// .attr('x',function(d){
// return secondLabelRadius*Math.sin(secondScale(d)*radians);
// })
// .attr('y',function(d){
// return -secondLabelRadius*Math.cos(secondScale(d)*radians) + secondLabelYOffset;
// })
// .text(function(d){
// return d;
// });
//... and hours
face
.selectAll(".hour-tick")
.data(d3.range(0, 12))
.enter()
.append("line")
.attr("class", "hour-tick")
.attr("x1", 0)
.attr("x2", 0)
.attr("y1", hourTickStart)
.attr("y2", hourTickStart + hourTickLength)
.attr("stroke", color)
.attr("transform", function(d) {
return "rotate(" + hourScale(d) + ")";
});
face
.selectAll(".hour-label")
.data(d3.range(3, 13, 3))
.enter()
.append("text")
.attr("class", "hour-label")
.attr("text-anchor", "middle")
.attr("stroke", color)
.attr("x", function(d) {
return hourLabelRadius * Math.sin(hourScale(d) * radians);
})
.attr("y", function(d) {
return (
-hourLabelRadius * Math.cos(hourScale(d) * radians) + hourLabelYOffset
);
})
.text(function(d) {
return d;
});
var hands = face.append("g").attr("id", "clock-hands");
face
.append("g")
.attr("id", "face-overlay")
.append("circle")
.attr("class", "hands-cover")
.attr("stroke", color)
.attr("x", 0)
.attr("y", 0)
.attr("r", clockRadius / 20);
hands
.selectAll("line")
.data(handData)
.enter()
.append("line")
.attr("stroke", color)
.attr("class", function(d) {
return d.type + "-hand";
})
.attr("x1", 0)
.attr("y1", function(d) {
return d.balance ? d.balance : 0;
})
.attr("x2", 0)
.attr("y2", function(d) {
return d.length;
})
.attr("transform", function(d) {
return "rotate(" + d.scale(d.value) + ")";
});
}
function moveHands() {
d3.select("#clock_" + id_element + " #clock-hands")
.selectAll("line")
.data(handData)
.transition()
.attr("transform", function(d) {
return "rotate(" + d.scale(d.value) + ")";
});
}
function updateData(tz) {
var d = new Date();
var dt = d.getTime();
2017-12-01 12:14:56 +01:00
os = d.getTimezoneOffset();
tz = parseInt(tz) + parseInt(os * 60);
var t = new Date(dt + tz * 1000);
2017-12-01 12:14:56 +01:00
handData[0].value = (t.getHours() % 12) + t.getMinutes() / 60;
handData[1].value = t.getMinutes();
handData[2].value = t.getSeconds();
}
2017-12-01 12:14:56 +01:00
drawClock();
2017-12-01 12:14:56 +01:00
setInterval(function() {
updateData(timezone);
moveHands();
}, 1000);
2017-12-01 12:14:56 +01:00
d3.select(self.frameElement).style("height", height + "px");
2017-12-01 12:14:56 +01:00
$("#clock_" + id_element).css("margin-top", "0");
}
2017-12-01 12:14:56 +01:00
function printClockDigital1(
time_format,
timezone,
clock_animation,
width,
height,
id_element,
color
) {
var svgUnderlay = d3.select("#clock_" + id_element + " svg"),
svgOverlay = d3.select("#clock_" + id_element),
svg = d3.selectAll("#clock_" + id_element + " svg");
svgUnderlay.attr("id", "underlay_" + id_element);
2021-04-14 12:07:38 +02:00
svgUnderlay.attr("class", "invert_filter");
svgOverlay.attr("id", "overlay_" + id_element);
var digit = svg.selectAll(".digit"),
2017-12-01 12:14:56 +01:00
separator = svg.selectAll(".separator circle");
var digitPattern = [
[1, 0, 1, 1, 0, 1, 1, 1, 1, 1],
[1, 0, 0, 0, 1, 1, 1, 0, 1, 1],
[1, 1, 1, 1, 1, 0, 0, 1, 1, 1],
[0, 0, 1, 1, 1, 1, 1, 0, 1, 1],
[1, 0, 1, 0, 0, 0, 1, 0, 1, 0],
[1, 1, 0, 1, 1, 1, 1, 1, 1, 1],
[1, 0, 1, 1, 0, 1, 1, 0, 1, 1]
];
(function tick() {
var tz = timezone;
var d = new Date();
var dt = d.getTime();
os = d.getTimezoneOffset();
tz = parseInt(tz) + parseInt(os * 60);
var t = new Date(dt + tz * 1000);
var now = new Date(),
2017-12-01 12:14:56 +01:00
hours = t.getHours(),
minutes = t.getMinutes(),
seconds = t.getSeconds();
digit = digit.data([
(hours / 10) | 0,
hours % 10,
(minutes / 10) | 0,
minutes % 10,
(seconds / 10) | 0,
seconds % 10
]);
digit.select("path:nth-child(1)").classed("lit", function(d) {
return digitPattern[0][d];
});
digit.select("path:nth-child(2)").classed("lit", function(d) {
return digitPattern[1][d];
});
digit.select("path:nth-child(3)").classed("lit", function(d) {
return digitPattern[2][d];
});
digit.select("path:nth-child(4)").classed("lit", function(d) {
return digitPattern[3][d];
});
digit.select("path:nth-child(5)").classed("lit", function(d) {
return digitPattern[4][d];
});
digit.select("path:nth-child(6)").classed("lit", function(d) {
return digitPattern[5][d];
});
digit.select("path:nth-child(7)").classed("lit", function(d) {
return digitPattern[6][d];
});
separator.classed("lit", 1);
setTimeout(tick, 1000 - (now % 1000));
})();
}
function valueToBytes(value) {
var shorts = ["", "K", "M", "G", "T", "P", "E", "Z", "Y"];
var pos = 0;
while (value >= 1024) {
// As long as the number can be divided by divider.
pos++;
// Position in array starting with 0.
value = value / 1024;
}
// This will actually do the rounding and the decimals.
return value.toFixed(2) + shorts[pos] + "B";
}