/* Pi-hole: A black hole for Internet advertisements * (c) 2017 Pi-hole, LLC (https://pi-hole.net) * Network-wide ad blocking via your own hardware. * * This file is copyright under the latest version of the EUPL. * Please see LICENSE file for your rights under this license. */ /* global Chart:false, moment:false */ var start__ = moment().subtract(6, "days"); var from = moment(start__).utc().valueOf()/1000; var end__ = moment(); var until = moment(end__).utc().valueOf()/1000; var interval = 0; var timeoutWarning = $("#timeoutWarning"); var dateformat = "MMMM Do YYYY, HH:mm"; $(function () { $("#querytime").daterangepicker( { timePicker: true, timePickerIncrement: 15, locale: { format: dateformat }, startDate: start__, endDate: end__, ranges: { "Today": [moment().startOf("day"), moment()], "Yesterday": [moment().subtract(1, "days").startOf("day"), moment().subtract(1, "days").endOf("day")], "Last 7 Days": [moment().subtract(6, "days"), moment()], "Last 30 Days": [moment().subtract(29, "days"), moment()], "This Month": [moment().startOf("month"), moment()], "Last Month": [moment().subtract(1, "month").startOf("month"), moment().subtract(1, "month").endOf("month")], "This Year": [moment().startOf("year"), moment()], "All Time": [moment(0), moment()] }, "opens": "center", "showDropdowns": true, "autoUpdateInput": false }, function (startt, endt) { from = moment(startt).utc().valueOf()/1000; until = moment(endt).utc().valueOf()/1000; }); }); function padNumber(num) { return ("00" + num).substr(-2,2); } // Helper function needed for converting the Objects to Arrays function objectToArray(p){ var keys = Object.keys(p); keys.sort(function(a, b) { return a - b; }); var arr = [], idx = []; for (var i = 0; i < keys.length; i++) { arr.push(p[keys[i]]); idx.push(keys[i]); } return [idx,arr]; } var timeLineChart; function compareNumbers(a, b) { return a - b; } function updateQueriesOverTime() { $("#queries-over-time .overlay").show(); timeoutWarning.show(); // Compute interval to obtain about 200 values var num = 200; interval = (until-from)/num; // Default displaying axis scaling timeLineChart.options.scales.xAxes[0].time.unit="hour" if(num*interval >= 6*29*24*60*60) { // If the requested data is more than 3 months, set ticks interval to quarterly timeLineChart.options.scales.xAxes[0].time.unit="quarter" } else if(num*interval >= 3*29*24*60*60) { // If the requested data is more than 3 months, set ticks interval to months timeLineChart.options.scales.xAxes[0].time.unit="month" } if(num*interval >= 29*24*60*60) { // If the requested data is more than 1 month, set ticks interval to weeks timeLineChart.options.scales.xAxes[0].time.unit="week" } else if(num*interval >= 6*24*60*60) { // If the requested data is more than 1 week, set ticks interval to days timeLineChart.options.scales.xAxes[0].time.unit="day" } $.getJSON("api_db.php?getGraphData&from="+from+"&until="+until+"&interval="+interval, function(data) { // convert received objects to arrays data.domains_over_time = objectToArray(data.domains_over_time); data.ads_over_time = objectToArray(data.ads_over_time); // Remove possibly already existing data timeLineChart.data.labels = []; timeLineChart.data.datasets[0].data = []; timeLineChart.data.datasets[1].data = []; var dates = [], hour; for (hour in data.domains_over_time[0]) { if (Object.prototype.hasOwnProperty.call(data.domains_over_time[0], hour)) { dates.push(parseInt(data.domains_over_time[0][hour])); } } for (hour in data.ads_over_time[0]) { if (Object.prototype.hasOwnProperty.call(data.ads_over_time[0], hour)) { if(dates.indexOf(parseInt(data.ads_over_time[0][hour])) === -1) { dates.push(parseInt(data.ads_over_time[0][hour])); } } } dates.sort(compareNumbers); // Add data for each hour that is available for (hour in dates) { if (Object.prototype.hasOwnProperty.call(dates, hour)) { var d, dom = 0, ads = 0; d = new Date(1000*dates[hour]); var idx = data.domains_over_time[0].indexOf(dates[hour].toString()); if (idx > -1) { dom = data.domains_over_time[1][idx]; } idx = data.ads_over_time[0].indexOf(dates[hour].toString()); if (idx > -1) { ads = data.ads_over_time[1][idx]; } timeLineChart.data.labels.push(d); timeLineChart.data.datasets[0].data.push(dom - ads); timeLineChart.data.datasets[1].data.push(ads); } } timeLineChart.options.scales.xAxes[0].display=true; $("#queries-over-time .overlay").hide(); timeoutWarning.hide(); timeLineChart.update(); }); } Date.prototype.AddInterval = function () { return new Date(this.valueOf() + 1000 * interval); } $(document).ready(function() { var ctx = document.getElementById("queryOverTimeChart").getContext("2d"); timeLineChart = new Chart(ctx, { type: "bar", data: { labels: [ ], datasets: [ { label: "Permitted DNS Queries", fill: true, backgroundColor: "rgba(0, 166, 90,.8)", borderColor: "rgba(0, 166, 90,.8)", pointBorderColor: "rgba(0, 166, 90,.8)", pointRadius: 1, pointHoverRadius: 5, data: [], pointHitRadius: 5 }, { label: "Blocked DNS Queries", fill: true, backgroundColor: "rgba(0,192,239,1)", borderColor: "rgba(0,192,239,1)", pointBorderColor: "rgba(0,192,239,1)", pointRadius: 1, pointHoverRadius: 5, data: [], pointHitRadius: 5 } ] }, options: { tooltips: { enabled: true, mode: "x-axis", callbacks: { title: function(tooltipItem) { var label = tooltipItem[0].xLabel; var time = new Date(label); var from_date = time.getFullYear() + "-" + padNumber(time.getMonth()+1) + "-" + padNumber(time.getDate()) + " " + padNumber(time.getHours()) + ":" + padNumber(time.getMinutes()) + ":" + padNumber(time.getSeconds()); time = time.AddInterval(); var until_date = time.getFullYear() + "-" + padNumber(time.getMonth()+1) + "-" + padNumber(time.getDate()) + " " + padNumber(time.getHours()) + ":" + padNumber(time.getMinutes()) + ":" + padNumber(time.getSeconds()); return "Queries from " + from_date + " to " + until_date; }, label: function(tooltipItems, data) { if(tooltipItems.datasetIndex === 1) { var percentage = 0.0; var total = parseInt(data.datasets[0].data[tooltipItems.index]); var blocked = parseInt(data.datasets[1].data[tooltipItems.index]); if(total > 0) { percentage = 100.0*blocked/total; } return data.datasets[tooltipItems.datasetIndex].label + ": " + tooltipItems.yLabel + " (" + percentage.toFixed(1) + "%)"; } return data.datasets[tooltipItems.datasetIndex].label + ": " + tooltipItems.yLabel; } } }, legend: { display: false }, scales: { xAxes: [{ type: "time", stacked: true, time: { unit: "hour", displayFormats: { "minute": "HH:mm", "hour": "HH:mm", "day": "MMM DD", "week": "MMM DD", "month": "MMM", "quarter": "MMM", "year": "YYYY MMM" } } }], yAxes: [{ stacked: true, ticks: { beginAtZero: true } }] }, maintainAspectRatio: false } }); }); $("#querytime").on("apply.daterangepicker", function(ev, picker) { $(this).val(picker.startDate.format(dateformat) + " to " + picker.endDate.format(dateformat)); $("#queries-over-time").show(); updateQueriesOverTime(); }); $("#queryOverTimeChart").click(function(evt){ var activePoints = timeLineChart.getElementAtEvent(evt); if(activePoints.length > 0) { //get the internal index in the chart var clickedElementindex = activePoints[0]._index; //get specific label by index var label = timeLineChart.data.labels[clickedElementindex]; //get value by index var from = label/1000; var until = label/1000 + 600; window.location.href = "db_queries.php?from="+from+"&until="+until; } return false; });