123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808 |
- <script src="./script/useragent.js"></script>
- <link href="./script/datepicker/dp-light.css" rel="stylesheet">
- <script defer src="./script/datepicker/datepicker.js"></script>
- <div class="standardContainer">
- <div class="ui basic segment">
- <h2>Statistical Analysis</h2>
- <p>Statistic of your server in every aspects</p>
- <div style="margin-bottom: 0.4em;">
- <div class="ui small input">
- <input type="text" id="statsRangeStart" placeholder="From date">
- </div>
- <span style="padding-left: 0.6em; padding-right: 0.6em;"> <i class="ui right arrow icon"></i> </span>
- <div class="ui small input">
- <input type="text" id="statsRangeEnd" placeholder="End date">
- </div>
- </div>
- <button onclick="handleLoadStatisticButtonPress();" class="ui basic button"><i class="blue search icon"></i> Load</button>
- <button onclick="clearStatisticDateRange();" class="ui basic button"><i class="eraser icon"></i> Clear Search</button>
- <br>
- <small>Leave end range as empty for showing starting day only statistic</small>
- </div>
- <div class="ui divider"></div>
- <div id="statisticRenderNotEnoughData" class="ui segment" style="padding: 2em;" align="center">
- <h4 class="ui icon header">
- <i class="medium icons" style="color: #dbdbdb !important;">
- <i class="chart pie icon"></i>
- <i class="small corner remove icon" style="
- font-size: 1.4em;
- margin-right: -0.2em;
- margin-bottom: -0em;
- "></i>
- </i>
-
- <div class="content" style="margin-top: 1em; color: #7c7c7c !important;">
- No Data
- <div class="sub header" style="color: #adadad !important;">The selected period contains too little or no request data collected. <br>
- Please select a larger range or make sure there are enough traffic routing through this site.</div>
- </div>
- </h4>
- </div>
- <div id="statisticRenderElement" class="ui basic segment">
- <!-- View Counts Statistics -->
- <div class="ui three small statistics">
- <div class="statistic">
- <div class="value totalViewCount">
-
- </div>
- <div class="label">
- Total Requests
- </div>
- </div>
- <div class="statistic">
- <div class="value">
- <i class="ui green check circle icon"></i> <span class="totalSuccCount"></span>
- </div>
- <div class="label">
- Success Requests
- </div>
- </div>
- <div class="statistic">
- <div class="value">
- <i class="ui red times circle icon"></i> <span class="totalErrorCount"></span>
- </div>
- <div class="label">
- Error Requests
- </div>
- </div>
- </div>
- <!-- Forward Type Data -->
- <h3>Forward Traffic Types</h3>
- <p>Traffic forwarding type classified by their protocols and proxy rules.</p>
- <table class="ui celled unstackable table">
- <thead>
- <tr><th>Forward Type</th>
- <th>Counts</th>
- <th>Percentage</th>
- </tr></thead>
- <tbody class="forwardTypeCounts">
- </tbody>
- </table>
- <!-- Client Geolocation Analysis-->
- <h3>Visitors Countries</h3>
- <p>Distributions of visitors by country code. Access origin are estimated using open source GeoIP database and might not be accurate.</p>
- <div style="min-height: 400px;">
- <canvas id="stats_visitors"></canvas>
- </div>
- <div class="ui divider"></div>
- <!-- Client IP Analysis -->
- <div class="ui stackable grid">
- <div class="eight wide column">
- <h3>Requests IP Version</h3>
- <p>The version of Internet Protocol that the client is using. If the request client is pass through a DNS proxy like CloudFlare,
- the CloudFlare proxy server address will be filtered and only the first value in the RemoteAddress field will be analysised.</p>
- <div>
- <canvas id="stats_ipver"></canvas>
- </div>
- </div>
- <div class="eight wide column">
- <h3>Request Origins</h3>
- <p>Top 25 request origin sorted by request count</p>
- <div style="height: 500px; overflow-y: auto;">
- <table class="ui unstackable striped celled table">
- <thead>
- <tr>
- <th class="no-sort">Request Origin</th>
- <th class="no-sort">No of Requests</th>
- </tr></thead>
- <tbody id="stats_requestCountlist">
-
- </tbody>
- </table>
- </div>
- </div>
- </div>
- <div class="ui divider"></div>
- <!-- Client Device Analysis -->
- <div class="ui stackable grid">
- <div class="eight wide column">
- <h3>Client Devices</h3>
- <p>Device type analysis by its request interactions.The number of iteration count does not means the number unique device, as no cookie is used to track the devices identify.</p>
- <div>
- <canvas id="stats_device"></canvas>
- </div>
- </div>
- <div class="eight wide column">
- <h3>Client Browsers</h3>
- <p>The browsers where your client is using to visit your site</p>
- <div>
- <canvas id="stats_browsers"></canvas>
- </div>
- </div>
- </div>
- <div class="ui stackable grid">
- <div class="eight wide column">
- <h3>Client OS</h3>
- <p>The OS where your client is using. Estimated using the UserAgent header sent by the client browser while requesting a resources from one of your host.</p>
- <div>
- <canvas id="stats_OS"></canvas>
- </div>
- </div>
- <div class="eight wide column">
- <h3>OS Versions</h3>
- <p>The OS versions most commonly used by your site's visitors.</p>
- <div style="height: 500px; overflow-y: auto;">
- <table class="ui unstackable striped celled table">
- <thead>
- <tr>
- <th>OS Version</th>
- <th>Request Counts</th>
- <th>Percentage</th>
- </tr></thead>
- <tbody id="stats_OSVersionList">
-
- </tbody>
- </table>
- </div>
- </div>
- </div>
- <div class="ui divider"></div>
- <div class="ui stackable grid">
- <div class="eight wide column">
- <h3>Request File Types</h3>
- <p>The file types being served by this proxy</p>
- <div>
- <canvas id="stats_filetype"></canvas>
- </div>
- </div>
- <div class="eight wide column">
- <h3>Referring Sites</h3>
- <p>The Top 100 sources of traffic according to referer header</p>
- <div>
- <div style="height: 500px; overflow-y: auto;">
- <table class="ui unstackable striped celled table">
- <thead>
- <tr>
- <th class="no-sort">Referer</th>
- <th class="no-sort">Requests</th>
- </tr></thead>
- <tbody id="stats_RefererTable">
-
- </tbody>
- </table>
- </div>
- </div>
- </div>
- </div>
- <div class="ui divider"></div>
- <div class="ui basic segment" id="trendGraphs">
- <h3>Visitor Trend Analysis</h3>
- <p>Request trends in the selected time range</p>
- <div>
- <canvas id="requestTrends"></canvas>
- </div>
- </div>
- <button onclick="showSideWrapper('snippet/advanceStatsOprs.html?t=' + Date.now() + '#' + encodeURIComponent(JSON.stringify(getStatisticDateRange())));" class="ui basic right floated black button"><i class="external square alternate icon"></i> Advance Operations</button>
- </div>
-
- <!-- <button class="ui icon right floated basic button" onclick="initStatisticSummery();"><i class="green refresh icon"></i> Refresh</button> -->
- <br><br>
- </div>
- <script>
- var statisticCharts = [];
- //Start day must be earlier than end date
- function initStatisticSummery(startdate="", enddate=""){
- if (startdate == "" && enddate == "" ){
- let todaykey = getTodayStatisticKey();
- loadStatisticByDate(todaykey);
- }else if ((startdate != "" && enddate == "") || startdate == enddate){
- //Load the target date
- let targetDate = startdate.trim();
- loadStatisticByDate(targetDate);
- }else{
- //Two dates are given and they are not identical
- loadStatisticByRange(startdate, enddate);
- //console.log(startdate, enddate);
- }
- }
- function loadStatisticByDate(dateid){
- $.getJSON("/api/analytic/load?id=" + dateid, function(data){
- if (data.error != undefined){
- msgbox(data.error, false, 6000);
- return;
- }
-
- //Destroy all the previous charts
- statisticCharts.forEach(function(thisChart){
- thisChart.destroy();
- })
- if (data.TotalRequest == 0){
- //No data to analysis
- $("#statisticRenderElement").hide()
- $("#statisticRenderNotEnoughData").show();
- return;
- }else{
- $("#statisticRenderElement").show();
- $("#statisticRenderNotEnoughData").hide();
- }
- //Render the text values
- $("#statisticRenderElement").find(".totalViewCount").text(abbreviateNumber(data.TotalRequest));
- $("#statisticRenderElement").find(".totalSuccCount").text(abbreviateNumber(data.ValidRequest));
- $("#statisticRenderElement").find(".totalErrorCount").text(abbreviateNumber(data.ErrorRequest));
- //Render forward type data
- renderForwardTypeCounts(data.ForwardTypes);
-
- //Render visitor data
- renderVisitorChart(data.RequestOrigin);
- //Render IP versions
- renderIPVersionChart(data.RequestClientIp);
- //Render user agent analysis
- renderUserAgentCharts(data.UserAgent);
- //Render file type by analysising request URL paths
- renderFileTypeGraph(data.RequestURL);
- //Render Referer header
- renderRefererTable(data.Referer);
- //Hide the trend graphs
- $("#trendGraphs").hide();
- });
- }
- initStatisticSummery();
- $("#statsRangeStart").val(getTodayStatisticKey().split("_").join("-"));
- function loadStatisticByRange(startdate, endDate){
- $.getJSON("/api/analytic/loadRange?start=" + startdate + "&end=" + endDate, function(data){
- //console.log(data);
- //Destroy all the previous charts
-
- statisticCharts.forEach(function(thisChart){
- thisChart.destroy();
- })
-
- if (data.Summary.TotalRequest == 0){
- //No data to analysis
- $("#statisticRenderElement").hide()
- $("#statisticRenderNotEnoughData").show();
- return;
- }else{
- $("#statisticRenderElement").show();
- $("#statisticRenderNotEnoughData").hide();
- }
- //Render the text values
- $("#statisticRenderElement").find(".totalViewCount").text(abbreviateNumber(data.Summary.TotalRequest));
- $("#statisticRenderElement").find(".totalSuccCount").text(abbreviateNumber(data.Summary.ValidRequest));
- $("#statisticRenderElement").find(".totalErrorCount").text(abbreviateNumber(data.Summary.ErrorRequest));
- //Render forward type data
- renderForwardTypeCounts(data.Summary.ForwardTypes);
- //Render visitor data
- renderVisitorChart(data.Summary.RequestOrigin);
- //Render IP versions
- renderIPVersionChart(data.Summary.RequestClientIp);
- //Render user agent analysis
- renderUserAgentCharts(data.Summary.UserAgent);
- //Render file type by analysising request URL paths
- renderFileTypeGraph(data.Summary.RequestURL);
-
- //Render Referer header
- renderRefererTable(data.Summary.Referer);
- //Render the trend graph
- $("#trendGraphs").show();
- renderTrendGraph(data.Records);
- });
- }
- picker.attach({ target: document.getElementById("statsRangeStart") });
- picker.attach({ target: document.getElementById("statsRangeEnd") });
- function renderForwardTypeCounts(forwardTypes){
- let tablBody = $("#statisticRenderElement").find(".forwardTypeCounts");
- tablBody.empty();
- let totalForwardCounts = 0;
- for (let [key, value] of Object.entries(forwardTypes)) {
- totalForwardCounts += value;
- }
- for (let [key, value] of Object.entries(forwardTypes)) {
- tablBody.append(`<tr>
- <td>${key}</td>
- <td>${abbreviateNumber(value)} (${value})</td>
- <td>${((value/totalForwardCounts)*100).toFixed(3)}%</td>
- </tr>
- `);
- }
- }
- function getTodayStatisticKey(){
- var today = new Date();
- var year = today.getFullYear();
- var month = String(today.getMonth() + 1).padStart(2, '0');
- var day = String(today.getDate()).padStart(2, '0');
- var formattedDate = year + '_' + month + '_' + day;
- return formattedDate
- }
- function handleLoadStatisticButtonPress(){
- var sd = $("#statsRangeStart").val();
- var ed = $("#statsRangeEnd").val();
- //Swap them if sd is later than ed
- if (sd != "" && ed != "" && sd > ed) {
- ed = [sd, sd = ed][0];
- $("#statsRangeStart").val(sd);
- $("#statsRangeEnd").val(ed);
- }
-
- initStatisticSummery(sd, ed);
- }
-
- function getStatisticDateRange(){
- var sd = $("#statsRangeStart").val();
- var ed = $("#statsRangeEnd").val();
- if (ed == ""){
- ed = sd;
- }
- if (sd == "" && ed == ""){
- var sk = getTodayStatisticKey();
- sd = sk;
- ed = sk;
- }
- //Swap them if sd is later than ed
- if (sd != "" && ed != "" && sd > ed) {
- ed = [sd, sd = ed][0];
- }
- return [sd, ed];
- }
- function clearStatisticDateRange(){
- $("#statsRangeStart").val("");
- $("#statsRangeEnd").val("");
- }
- function renderRefererTable(refererList){
- const sortedEntries = Object.entries(refererList).sort(([, valueA], [, valueB]) => valueB - valueA);
- $("#stats_RefererTable").html("");
- let endStop = 100;
- if (sortedEntries.length < 100){
- endStop = sortedEntries.length;
- }
- for (var i = 0; i < endStop; i++) {
- let referer = (decodeURIComponent(sortedEntries[i][0])).replace(/(<([^>]+)>)/ig,"");
- if (sortedEntries[i][0] == ""){
- //Root
- referer = `<span style="color: #b5b5b5;">(<i class="eye slash outline icon"></i> Unknown or Hidden)</span>`;
- }
- $("#stats_RefererTable").append(`<tr>
- <td>${referer}</td>
- <td>${sortedEntries[i][1]}</td>
- </tr>`);
- }
- }
- function renderFileTypeGraph(requestURLs){
- //Create the device chart
- let fileExtensions = {};
- for (const [url, count] of Object.entries(requestURLs)) {
- let filename = url.split("/").pop();
- let ext = "";
- if (filename == ""){
- //Loading from a folder
- ext = "Folder path"
- }else{
- if (filename.includes(".")){
- ext = filename.split(".").pop();
- }else{
- ext = "API call"
- }
- }
- if (fileExtensions[ext] != undefined){
- fileExtensions[ext] = fileExtensions[ext] + count;
- }else{
- //First time this ext show up
- fileExtensions[ext] = count;
- }
- }
- //Convert the key-value pairs to array for graph render
- let fileTypes = [];
- let fileCounts = [];
- let colors = [];
- for (const [ftype, count] of Object.entries(fileExtensions)) {
- fileTypes.push(ftype);
- fileCounts.push(count);
- colors.push(generateColorFromHash(ftype));
- }
- let filetypeChart = new Chart(document.getElementById("stats_filetype"), {
- type: 'pie',
- data: {
- labels: fileTypes,
- datasets: [{
- data: fileCounts,
- backgroundColor: colors,
- hoverBackgroundColor: colors,
- }]
- },
- options: {
- responsive: true,
- maintainAspectRatio: false,
- }
- });
- statisticCharts.push(filetypeChart);
- }
-
- function renderTrendGraph(dailySummary){
- // Get the canvas element
- const canvas = document.getElementById('requestTrends');
- //Generate the X axis labels
- let datesLabel = [];
- let succData = [];
- let errorData = [];
- let totalData = [];
- for (var i = 0; i < dailySummary.length; i++){
- let thisDayData = dailySummary[i];
- datesLabel.push("Day " + i);
- succData.push(thisDayData.ValidRequest);
- errorData.push(thisDayData.ErrorRequest);
- totalData.push(thisDayData.TotalRequest);
- }
- // Create the chart
- let TrendChart = new Chart(canvas, {
- type: 'line',
- data: {
- labels: datesLabel,
- datasets: [
- {
- label: 'All Requests',
- data: totalData,
- borderColor: '#7d99f7',
- backgroundColor: 'rgba(125, 153, 247, 0.4)',
- fill: false
- },
- {
- label: 'Success Requests',
- data: succData,
- borderColor: '#6dad7c',
- backgroundColor: "rgba(109, 173, 124, 0.4)",
- fill: true
- },
- {
- label: 'Error Requests',
- data: errorData,
- borderColor: '#de7373',
- backgroundColor: "rgba(222, 115, 115, 0.4)",
- fill: true
- },
- ]
- },
- options: {
- responsive: true,
- maintainAspectRatio: true,
- title: {
- display: true,
- //text: 'Line Chart Example'
- },
- scales: {
- x: {
- display: true,
- title: {
- display: false,
- text: 'Time'
- }
- },
- y: {
- display: true,
- title: {
- display: true,
- text: 'Request Counts'
- }
- }
- }
- }
- });
- statisticCharts.push(TrendChart);
- }
- function renderUserAgentCharts(userAgentsEntries){
- let userAgents = Object.keys(userAgentsEntries);
- let requestCounts = Object.values(userAgentsEntries);
- let mobileUser = 0;
- let desktopUser = 0;
- let osTypes = {};
- let osVersion = {};
- let browserTypes = {};
- let totalRequestCounts = 0;
-
- requestCounts.forEach(function(rc){
- totalRequestCounts += rc;
- })
- //Building a statistic summary
- userAgents.forEach(function(thisUA){
- var uaInfo = parseUserAgent(thisUA);
- if (uaInfo.isMobile){
- mobileUser+=userAgentsEntries[thisUA];
- }else{
- desktopUser+=userAgentsEntries[thisUA];
- }
- let currentNo = osTypes[uaInfo.os];
- let osVersionKey = uaInfo.os + " " + uaInfo.version.split("_").join(".");
- if (currentNo == undefined){
- osTypes[uaInfo.os] = userAgentsEntries[thisUA];
- }else{
- osTypes[uaInfo.os] = currentNo + userAgentsEntries[thisUA];
- }
- let p = osVersion[osVersionKey];
- if (p == undefined){
- osVersion[osVersionKey] = userAgentsEntries[thisUA];
- }else{
- osVersion[osVersionKey] = p + userAgentsEntries[thisUA];
- }
- let browserTypeKey = uaInfo.browser;
- if (browserTypeKey.indexOf("//") >= 0){
- //This is a uncatergorize browser, mostly a bot
- browserTypeKey = "Bots";
- }else if (browserTypeKey == ""){
- //No information
- browserTypeKey = "Unknown";
- }
- let b = browserTypes[browserTypeKey];
- if (b == undefined){
- browserTypes[browserTypeKey] = userAgentsEntries[thisUA];
- }else{
- browserTypes[browserTypeKey] = b + userAgentsEntries[thisUA];
- }
-
- });
- //Create the device chart
- let deviceTypeChart = new Chart(document.getElementById("stats_device"), {
- type: 'pie',
- data: {
- labels: ['Desktop', 'Mobile'],
- datasets: [{
- data: [desktopUser, mobileUser],
- backgroundColor: ['#e56b5e', '#6eb9c1'],
- hoverBackgroundColor: ['#e56b5e', '#6eb9c1']
- }]
- },
- options: {
- responsive: true,
- maintainAspectRatio: false,
- }
- });
- statisticCharts.push(deviceTypeChart);
- //Create the OS chart
- let OSnames = [];
- let OSCounts = [];
- let OSColors = [];
- for (const [key, value] of Object.entries(osTypes)) {
- OSnames.push(key);
- OSCounts.push(value);
- OSColors.push(getOSColorCode(key));
- }
-
- let osTypeChart = new Chart(document.getElementById("stats_OS"), {
- type: 'pie',
- data: {
- labels: OSnames,
- datasets: [{
- data: OSCounts,
- backgroundColor: OSColors,
- hoverBackgroundColor: OSColors
- }]
- },
- options: {
- responsive: true,
- maintainAspectRatio: false,
- }
- });
- statisticCharts.push(osTypeChart);
- //Populate the OS version table
- let sortedOSVersion = Object.entries(osVersion).sort((a, b) => b[1] - a[1]);
- $("#stats_OSVersionList").html("");
- // Loop through the sorted data and populate the table
- for (let i = 0; i < sortedOSVersion.length; i++) {
- let osVersion = sortedOSVersion[i][0];
- let requestcount = abbreviateNumber(sortedOSVersion[i][1]);
- let percentage = (sortedOSVersion[i][1] / totalRequestCounts * 100).toFixed(3);
-
- // Create a new row in the table
- let row = $("<tr>");
-
- // Add the OS version and percentage as columns in the row
- $("<td>").text(osVersion).appendTo(row);
- $("<td>").text(requestcount).appendTo(row);
- $("<td>").text(percentage + "%").appendTo(row);
-
- // Add the row to the table body
- $("#stats_OSVersionList").append(row);
- }
- //Create the browser charts
- let browserNames = [];
- let broserCounts = [];
- let browserColors = [];
- let sortedBrowserTypes = Object.entries(browserTypes).sort((a, b) => b[1] - a[1]);
- console.log(sortedBrowserTypes);
- sortedBrowserTypes.forEach(function(entry){
- browserNames.push(entry[0]);
- broserCounts.push(entry[1]);
- browserColors.push(generateColorFromHash(entry[0]));
- });
-
- let browserTypeChart = new Chart(document.getElementById("stats_browsers"), {
- type: 'pie',
- data: {
- labels: browserNames,
- datasets: [{
- data: broserCounts,
- backgroundColor: browserColors,
- hoverBackgroundColor: browserColors
- }]
- },
- options: {
- responsive: true,
- maintainAspectRatio: false,
- }
- });
- statisticCharts.push(browserTypeChart);
- }
- //Generate the IPversion pie chart
- function renderIPVersionChart(RequestClientIp){
- let ipv4Count = Object.keys(RequestClientIp).filter(ip => ip.includes('.')).length;
- let ipv6Count = Object.keys(RequestClientIp).filter(ip => ip.includes(':')).length;
- let totalCount = ipv4Count + ipv6Count;
- let ipv4Percent = ((ipv4Count / totalCount) * 100).toFixed(2);
- let ipv6Percent = ((ipv6Count / totalCount) * 100).toFixed(2);
- // Create the chart data object
- let chartData = {
- labels: ['IPv4', 'IPv6'],
- datasets: [{
- data: [ipv4Percent, ipv6Percent],
- backgroundColor: ['#9295f0', '#bff092'],
- hoverBackgroundColor: ['#9295f0', '#bff092']
- }]
- };
- // Create the chart options object
- let ipvChartOption = {
- responsive: true,
- maintainAspectRatio: false,
- };
- // Create the pie chart
- let ipTypeChart = new Chart(document.getElementById("stats_ipver"), {
- type: 'pie',
- data: chartData,
- options: ipvChartOption
- });
- statisticCharts.push(ipTypeChart);
- //Populate the request count table
- let requestCounts = Object.entries(RequestClientIp);
- // Sort the array by the value (count)
- requestCounts.sort((a, b) => b[1] - a[1]);
- // Select the table body and empty it
- let tableBody = $('#stats_requestCountlist');
- tableBody.empty();
- // Loop through the sorted array and add the top 25 requested IPs to the table
- for (let i = 0; i < 25 && i < requestCounts.length; i++) {
- let [ip, count] = requestCounts[i];
- let row = $('<tr>').appendTo(tableBody);
- $('<td style="word-break: break-all;">').text(ip).appendTo(row);
- $('<td>').text(count).appendTo(row);
- }
- }
- //Generate a fixed color code from string hash
- function generateColorFromHash(stringToHash){
- let hash = 0;
- for (let i = 0; i < stringToHash.length; i++) {
- hash = stringToHash.charCodeAt(i) + ((hash << 5) - hash);
- }
- const hue = hash % 300;
- const saturation = Math.floor(Math.random() * 20) + 70;
- const lightness = Math.floor(Math.random() * 20) + 60;
- return `hsl(${hue}, ${saturation}%, ${lightness}%)`;
- }
- //Generate the visitor country pie chart
- function renderVisitorChart(visitorData){
- // Extract the labels and data from the visitor data object
- let labels = [];
- let data = Object.values(visitorData);
- Object.keys(visitorData).forEach(function(cc){
- console.log(cc);
- if (cc == ""){
- labels.push("Unknown")
- }else if (cc == "lan"){
- labels.push(`LAN / Loopback`);
- }else{
- labels.push(`${getCountryName(cc)} [${cc.toUpperCase()}]` );
- }
- });
- // Define the colors to be used in the pie chart
- let colors = [];
- labels.forEach(function(cc){
- colors.push(generateColorFromHash(cc));
- });
- // Create the chart data object
- let CCchartData = {
- labels: labels,
- datasets: [{
- data: data,
- backgroundColor: colors
- }]
- };
- // Create the chart options object
- let CCchartOptions = {
- responsive: true,
- maintainAspectRatio: false,
- };
- // Create the pie chart
- const visitorsChart = new Chart(document.getElementById("stats_visitors"), {
- type: 'pie',
- data: CCchartData,
- options: CCchartOptions
- });
- statisticCharts.push(visitorsChart);
- }
- </script>
|