diff --git a/scripts/pi-hole/js/index.js b/scripts/pi-hole/js/index.js
index 2d77c6b4..7367c987 100644
--- a/scripts/pi-hole/js/index.js
+++ b/scripts/pi-hole/js/index.js
@@ -318,115 +318,21 @@ function updateQueryTypesPie() {
queryTypePieChart.data.labels = k;
$("#query-types-pie .overlay").hide();
queryTypePieChart.update();
+
// Don't use rotation animation for further updates
queryTypePieChart.options.animation.duration = 0;
- queryTypePieChart.options.legendCallback = customLegend;
// Generate legend in separate div
// $("#query-types-legend").html(queryTypePieChart.generateLegend());
- $("#query-types-legend > ul > li").click(function (e) {
- if (iscolorBox(e.target)) {
- return false;
- }
-
+ $("#query-types-legend > ul > li > p").click(function () {
window.location.href = "queries.php?querytype=" + querytypeids[$(this).index()];
});
- $("#query-types-legend .colorBoxWrapper").click(function (e) {
- hidePieSlice(e);
- });
}).done(function () {
// Reload graph after minute
setTimeout(updateQueryTypesPie, 60000);
});
}
-function customLegend(chart) {
- var text = [];
- var data = chart.data;
- var datasets = data.datasets;
- var labels = data.labels;
-
- text.push('
');
-
- if (datasets.length > 0) {
- for (var i = 0; i < datasets[0].data.length; ++i) {
- var color = datasets[0].backgroundColor[i];
-
- var txt = "";
-
- // legend box icon
- txt =
- '' +
- '' +
- "";
-
- // color block
- txt += '';
-
- // label
- if (labels[i]) {
- txt +=
- '' +
- labels[i] +
- "";
- }
-
- text.push("- " + txt + "
");
- }
- }
-
- text.push("
");
- return text.join("");
-}
-
-function hidePieSlice(event) {
- togglecolorBox(event.target);
-
- var legendID = $(event.target).closest(".chart-legend").attr("id");
- var ci =
- legendID === "query-types-legend"
- ? event.view.queryTypePieChart
- : event.view.forwardDestinationPieChart;
-
- var listItemParent = $(event.target).closest("li");
- $(listItemParent).toggleClass("strike");
-
- var index = $(listItemParent).index();
- var mobj = ci.data.datasets[0]._meta;
- var metas = Object.keys(mobj).map(function (e) {
- return mobj[e];
- });
- metas.forEach(function (meta) {
- var curr = meta.data[index];
- curr.hidden = !curr.hidden;
- });
-
- ci.update();
-}
-
-function togglecolorBox(target) {
- var parentListItem = $(target).closest("li");
- var colorBox = $(parentListItem).find(".fa-check-square, .fa-square");
-
- if (colorBox) {
- $(colorBox).toggleClass("fa-check-square");
- $(colorBox).toggleClass("fa-square");
- }
-}
-
-function iscolorBox(target) {
- // See if click happened on colorBoxWrapper or child SVG
- if ($(target).closest(".colorBoxWrapper")[0]) {
- return true;
- }
-
- return false;
-}
-
function updateClientsOverTime() {
$.getJSON("api.php?overTimeDataClients&getClientNames", function (data) {
if ("FTLnotrunning" in data) {
@@ -563,25 +469,18 @@ function updateForwardDestinationsPie() {
// and push it at once
$("#forward-destinations-pie .overlay").hide();
forwardDestinationPieChart.update();
+
// Don't use rotation animation for further updates
forwardDestinationPieChart.options.animation.duration = 0;
- forwardDestinationPieChart.options.legendCallback = customLegend;
// Generate legend in separate div
// $("#forward-destinations-legend").html(forwardDestinationPieChart.generateLegend());
- $("#forward-destinations-legend > ul > li").click(function (e) {
- if (iscolorBox(e.target)) {
- return false;
- }
-
+ $("#forward-destinations-legend > ul > li > p").click(function (e) {
var obj = encodeURIComponent(e.target.textContent);
if (obj.length > 0) {
window.location.href = "queries.php?forwarddest=" + obj;
}
});
- $("#forward-destinations-legend .colorBoxWrapper").click(function (e) {
- hidePieSlice(e);
- });
}).done(function () {
// Reload graph after one minute
setTimeout(updateForwardDestinationsPie, 60000);
@@ -869,6 +768,84 @@ function getMaxlogage() {
});
}
+// chartjs plugin used by the custom doughnut legend
+const getOrCreateLegendList = (chart, id) => {
+ const legendContainer = document.getElementById(id);
+ let listContainer = legendContainer.querySelector("ul");
+
+ if (!listContainer) {
+ listContainer = document.createElement("ul");
+ listContainer.style.display = "flex";
+ listContainer.style.flexDirection = "column";
+ listContainer.style.margin = 0;
+ listContainer.style.padding = 0;
+
+ legendContainer.append(listContainer);
+ }
+
+ return listContainer;
+};
+
+const htmlLegendPlugin = {
+ id: "htmlLegend",
+ afterUpdate(chart, args, options) {
+ const ul = getOrCreateLegendList(chart, options.containerID);
+
+ // Remove old legend items
+ while (ul.firstChild) {
+ ul.firstChild.remove();
+ }
+
+ // Reuse the built-in legendItems generator
+ const items = chart.options.plugins.legend.labels.generateLabels(chart);
+
+ items.forEach(item => {
+ const li = document.createElement("li");
+ li.style.alignItems = "center";
+ li.style.cursor = "pointer";
+ li.style.display = "flex";
+ li.style.flexDirection = "row";
+
+ li.addEventListener('click', () => {
+ const { type } = chart.config;
+
+ if (type === "pie" || type === "doughnut") {
+ // Pie and doughnut charts only have a single dataset and visibility is per item
+ chart.toggleDataVisibility(item.index);
+ } else {
+ chart.setDatasetVisibility(item.datasetIndex, !chart.isDatasetVisible(item.datasetIndex));
+ }
+
+ chart.update();
+ };
+
+ // Color checkbox
+ const boxSpan = document.createElement("span");
+ boxSpan.style.color = item.fillStyle;
+ boxSpan.style.display = "inline-block";
+ boxSpan.style.margin = "0 10px";
+ boxSpan.innerHTML = item.hidden
+ ? '
'
+ : '
';
+
+ // Text
+ const textContainer = document.createElement("p");
+ textContainer.style.color = item.fontColor;
+ textContainer.style.margin = 0;
+ textContainer.style.padding = 0;
+ textContainer.style.textDecoration = item.hidden ? "line-through" : "";
+ textContainer.className = "legend-label-text";
+
+ const text = document.createTextNode(item.text);
+ textContainer.append(text);
+
+ li.append(boxSpan);
+ li.append(textContainer);
+ ul.append(li);
+ });
+ },
+};
+
$(function () {
// Pull in data via AJAX
getMaxlogage();
@@ -1139,6 +1116,7 @@ $(function () {
labels: [],
datasets: [{ data: [], parsing: false }],
},
+ plugins: [htmlLegendPlugin],
options: {
responsive: true,
maintainAspectRatio: false,
@@ -1148,14 +1126,11 @@ $(function () {
},
},
plugins: {
+ htmlLegend: {
+ containerID: "query-types-legend",
+ },
legend: {
- display: true,
- position: "right",
- align: "start",
- labels: {
- boxWidth: 13,
- color: ticksColor,
- },
+ display: false,
},
tooltip: {
// Disable the on-canvas tooltip
@@ -1169,7 +1144,6 @@ $(function () {
},
},
},
-
animation: {
duration: 750,
},
@@ -1188,6 +1162,7 @@ $(function () {
labels: [],
datasets: [{ data: [], parsing: false }],
},
+ plugins: [htmlLegendPlugin],
options: {
responsive: true,
maintainAspectRatio: false,
@@ -1197,14 +1172,11 @@ $(function () {
},
},
plugins: {
+ htmlLegend: {
+ containerID: "forward-destinations-legend",
+ },
legend: {
- display: true,
- position: "right",
- align: "start",
- labels: {
- boxWidth: 13,
- color: ticksColor,
- },
+ display: false,
},
tooltip: {
// Disable the on-canvas tooltip
diff --git a/style/pi-hole.css b/style/pi-hole.css
index 9d37490d..7d030b62 100644
--- a/style/pi-hole.css
+++ b/style/pi-hole.css
@@ -234,49 +234,37 @@ td.lookatme {
vertical-align: text-top;
}
-.chart-legend {
- overflow: auto;
+#query-types-pie .box-body,
+#forward-destinations-pie .box-body {
+ display: flex;
}
-.chart-legend ul {
- list-style-type: none;
- padding-left: 45px;
+.chart-legend {
+ overflow: auto;
+ display: flex;
+ justify-content: center;
+ align-self: center;
}
.chart-legend li {
cursor: pointer;
position: relative;
line-height: 1;
- margin: 0 0 6px;
+ margin: 0 0 8px;
}
.chart-legend li span {
display: inline-block;
- height: 12px;
}
.colorBoxWrapper {
- font-size: 14px;
+ font-size: 15px;
}
.colorBoxWrapper:hover {
transform: scale(1.15);
}
-.chart-legend li .colorBoxWrapper {
- position: absolute;
- width: 20px;
- left: -20px;
- top: 0;
- line-height: 1;
-}
-
-.chart-legend li .legend-color-box {
- display: none;
- width: 12px;
- margin-right: 5px;
-}
-
.chart-legend li .legend-label-text {
line-height: 1;
word-break: break-word;