/** * W3TC image service widgets Google Charts driver. * * @file Google Charts driver for W3TC dashboard image service widget. * @author W3TC. * @version 1.0 * @since 2.7.0 */ jQuery( document ).ready( function() { google.charts.load( 'current', { packages: ['corechart', 'gauge'] } ); google.charts.setOnLoadCallback( load ); setInterval(load, 60000); // Refresh charts every 60 seconds jQuery(window).resize(load); // Redraw charts after resize // Load method for image service charts. Fires on document ready, window resize, and on 60 second interval. function load() { processed_data = preprocess_data( w3tc_webp_data ); draw_charts( processed_data ); } // Preprocesses statistics data for chart use. /** * @param {array} data Image Service data. * @returns {array} Image Service data in format required for Google charts. */ function preprocess_data( data ) { var processed_data = { 'counts': { 'data': [ [ 'Converted', Number(data.counts.data['converted']),data.counts.data['convertedbytes'] ], [ 'Not Converted', Number(data.counts.data['notconverted']),data.counts.data['notconvertedbytes'] ], [ 'Processing', Number(data.counts.data['processing']),data.counts.data['processingbytes'] ], [ 'Sending', Number(data.counts.data['sending']),data.counts.data['sendingbytes'] ], [ 'Unconverted', Number(data.counts.data['unconverted']),data.counts.data['unconvertedbytes'] ] ], 'type': data.counts.type }, 'apihourly': { 'data': [ [ 'Hourly', Number( data.api.data['usage_hourly'] ) ] ], 'limit': Number( data.api.data['limit_hourly'] ), 'type': data.api.type } }; // Monthly data is only present for free users as pro is unlimited monthly usage. if( 'limit_monthly' in data.api.data ) { processed_data['apimonthly'] = { 'data': [ [ 'Monthly', Number( data.api.data['usage_monthly'] ) ] ], 'limit': Number( data.api.data['limit_monthly'] ), 'type': data.api.type }; } return processed_data; } // Draws the stats charts. /** * @param {array} data - Preprocessed Image Service data. */ function draw_charts( data ) { for ( var key in data ) { if ( data[key]['type'] === 'pie' && document.getElementById( key + '_chart' ) ) { var chart_data = new google.visualization.DataTable(); // Add columns for the chart data chart_data.addColumn( 'string', 'Status' ); chart_data.addColumn( 'number', 'Count' ); chart_data.addColumn( { type: 'string', role: 'tooltip', 'p': { 'html': true } } ); chart_data.addColumn( 'number', 'Bytes' ); // Add rows for the chart data data[key]['data'].forEach( function ( row ) { chart_data.addRow( [ row[0], row[1], generateTooltip( row[0], row[1], row[2]), row[2] ] ); }); var chart_options = { chartArea: { width: '100%', height: '100%', top: 8, bottom: 40 }, legend: { position: 'bottom' }, tooltip: { isHtml: true } }; var chart = new google.visualization.PieChart( document.getElementById( key + '_chart' ) ); } else if( data[key]['type'] === 'gauge' ) { if( document.getElementById( key + '_chart' ) === null ) { jQuery( '#api_charts' ).append( '
' ); } var chart_data = google.visualization.arrayToDataTable( data[key]['data'], true ); var yellow_from, yellow_to, red_from; if ( data[key]['limit'] > 100 && data[key]['limit'] <= 1000 ) { yellow_from = data[key]['limit'] - 200; yellow_to = data[key]['limit'] - 100; red_from = data[key]['limit'] - 100; } else if ( data[key]['limit'] > 1000 ) { yellow_from = data[key]['limit'] - 2000; yellow_to = data[key]['limit'] - 1000; red_from = data[key]['limit'] - 1000; } else { yellow_from = data[key]['limit'] - 20; yellow_to = data[key]['limit'] - 10; red_from = data[key]['limit'] - 10; } var chart_options = { legend: { position: 'bottom' }, max: data[key]['limit'], yellowFrom: yellow_from, yellowTo: yellow_to, redFrom: red_from, redTo: data[key]['limit'], minorTicks: 5 }; var chart = new google.visualization.Gauge( document.getElementById( key + '_chart' ) ); } chart.draw( chart_data, chart_options ); }; } // Function to generate custom tooltip with count and bytes function generateTooltip( dataType, count, bytes ) { return `
Type: ${dataType}
Count: ${count}
Bytes: ${formatBytes(bytes)}
`; } // Formats a timestamp into a human readable string. /** * @param {Object} d Timestamp. * @returns {string} Human readable date/time string. */ function dateFormat( d ){ return ( "0" + d.getUTCHours() ).slice( -2 ) + ":" + ( "0" + d.getUTCMinutes() ).slice( -2 ); } // Formats bytes into a human readable string. /** * @param {Number} x Bytes. * @returns {string} Human readable string. */ function formatBytes( x ){ const units = [ 'bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB' ]; let l = 0, n = parseInt(x, 10) || 0; while( n >= 1000 && ++l ){ n = n/1000; } return( n.toFixed( n < 10 && l > 0 ? 1 : 0 ) + ' ' + units[l] ); } // Time since last refresh. var seconds_timer_id; // Interval for the image service data refresh. /** * @param {Number} new_seconds_till_refresh Interval to trigger refresh. */ function setRefresh( new_seconds_till_refresh ) { clearTimeout( seconds_timer_id ); var seconds_till_refresh = new_seconds_till_refresh; seconds_timer_id = setInterval( function () { seconds_till_refresh--; if ( seconds_till_refresh <= 0 ) { clearInterval( seconds_timer_id ); // Change clearTimeout to clearInterval here seconds_timer_id = null; load(); setRefresh( new_seconds_till_refresh ); // Restart the timer after calling load() return; } }, 1000 ); } } );