PluginProbe
Code Profiler – WordPress Performance Profiling and Debugging Made Easy / 1.9.1
Code Profiler – WordPress Performance Profiling and Debugging Made Easy v1.9.1
1.9.5 1.9.4 1.9.3 trunk 1.4 1.4.1 1.4.2 1.4.3 1.4.4 1.5 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.6 1.6.1 1.6.10 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 All 40 releases
code-profiler / static / code-profiler.js

code-profiler.js in Code Profiler – WordPress Performance Profiling and Debugging Made Easy 1.9.1, at static/code-profiler.js

911 lines 23.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /*
2 +=====================================================================+
3 | ____ _ ____ __ _ _ |
4 | / ___|___ __| | ___ | _ \ _ __ ___ / _(_) | ___ _ __ |
5 | | | / _ \ / _` |/ _ \ | |_) | '__/ _ \| |_| | |/ _ \ '__| |
6 | | |__| (_) | (_| | __/ | __/| | | (_) | _| | | __/ | |
7 | \____\___/ \__,_|\___| |_| |_| \___/|_| |_|_|\___|_| |
8 | |
9 | (c) Jerome Bruandet ~ https://nintechnet.com/codeprofiler/ |
10 +=====================================================================+
11 */
12
13 // =====================================================================
14 // Generic stuff
15
16 // TipTip tooltip
17 jQuery( document ).ready(function( $ ) {
18 'use strict';
19 $('.code-profiler-tip').tipTip( {
20 'attribute': 'data-tip',
21 'fadeIn': 50,
22 'fadeOut': 50,
23 'delay': 100,
24 'maxWidth' : '350px'
25 });
26
27 // We remove the '&action=delete_profiles...' query string because
28 // if the user reloaded the page that would throw an error:
29 var url = window.location.href;
30 window.history.replaceState({},
31 document.title,
32 url.replace( /&action=delete_profiles&.+/, '')
33 );
34
35 });
36
37 // Append/clear the search query to/from the query string
38 function cpjs_search_query() {
39
40 'use strict';
41 var query;
42 if ( jQuery('#search_id-search-input').val().length > 0 ) {
43 query = '&s=' + jQuery('#search_id-search-input').val();
44 // Case sensitivity
45 if ( jQuery('#case-search-input').is(':checked') === true ) {
46 query += '&c=1';
47 }
48 jQuery('#profile-form').attr('action', jQuery('#profile-form').attr('action')+ query );
49
50 } else {
51 jQuery('#profile-form').attr('action','');
52 var url = window.location.href;
53 window.history.replaceState({},
54 document.title,
55 url.replace( /&s=[^&$]+/, '')
56 );
57 var url = window.location.href;
58 window.history.replaceState({},
59 document.title,
60 url.replace( /&c=1/, '')
61 );
62 }
63 }
64
65 // =====================================================================
66 // Summary page
67
68 function cpjs_front_or_backend( item ) {
69 'use strict';
70 // Enable/disable frontend/backend select box
71 // depending on user's choice
72 if ( item == 'frontend') {
73 jQuery('#p-frontend').show();
74 jQuery('#p-backend').hide();
75 jQuery('#p-custom').hide();
76 jQuery('#p-wpcron').hide();
77 jQuery('#id-frontend').focus();
78 jQuery('#user-unauthenticated').prop('disabled', false);
79 jQuery('#user-authenticated').prop('disabled', false);
80 } else if ( item == 'backend') {
81 jQuery('#p-backend').show();
82 jQuery('#p-frontend').hide();
83 jQuery('#p-custom').hide();
84 jQuery('#p-wpcron').hide();
85 jQuery('#id-backend').focus();
86 jQuery('#user-unauthenticated').prop('disabled', true);
87 jQuery('#user-authenticated').prop('disabled', false);
88 jQuery('#user-authenticated').prop('checked', true);
89 jQuery('#user-name').prop('disabled', false);
90 } else if ( item == 'custom') {
91 jQuery('#p-custom').show();
92 jQuery('#p-frontend').hide();
93 jQuery('#p-backend').hide();
94 jQuery('#p-wpcron').hide();
95 jQuery('#id-custom').focus();
96 jQuery('#user-unauthenticated').prop('disabled', false);
97 jQuery('#user-authenticated').prop('disabled', false);
98 } else {
99 jQuery('#p-wpcron').show();
100 jQuery('#p-custom').hide();
101 jQuery('#p-frontend').hide();
102 jQuery('#p-backend').hide();
103 jQuery('#id-wpcron').focus();
104 jQuery('#user-unauthenticated').prop('disabled', false);
105 }
106 }
107
108 function cpjs_authenticated( id ) {
109 if ( id == 1 ) {
110 jQuery('#user-name').prop('disabled', false);
111 jQuery('#user-name').focus();
112 } else {
113 jQuery('#user-name').prop('disabled', true);
114 }
115 }
116
117 function cpjs_show_adv_settings() {
118 jQuery('#cp-advanced-settings').slideDown();
119 jQuery('#button-adv-settings').prop('disabled', true);
120 }
121
122 function cpjs_get_post( id ) {
123 if ( id == 1 ) {
124 jQuery('#post-value').prop('disabled', false);
125 jQuery('#id-content-type').prop('disabled', false);
126 jQuery('#post-value').focus();
127 } else {
128 jQuery('#post-value').prop('disabled', true);
129 jQuery('#id-content-type').prop('disabled', true);
130 }
131 }
132
133 function cpjs_content_type( value ) {
134 if ( value == 1 ) {
135 jQuery('#ct-1').slideDown();
136 jQuery('#ct-3').slideUp();
137 jQuery('#ct-2').slideUp();
138 } else if ( value == 2 ) {
139 jQuery('#ct-2').slideDown();
140 jQuery('#ct-3').slideUp();
141 jQuery('#ct-1').slideUp();
142 } else {
143 jQuery('#ct-3').slideDown();
144 jQuery('#ct-1').slideUp();
145 jQuery('#ct-2').slideUp();
146 }
147 }
148
149 function cpjs_isJSON( data ) {
150
151 if ( jQuery('#id-content-type').val() == 1 || jQuery('#get-method').prop('checked') == true ) {
152 // Ignore
153 return 1;
154 }
155 try {
156 return JSON.parse( data );
157 } catch (e) {
158 // Not a JSON-encoded string
159 return null;
160 }
161 }
162
163 function cpjs_ismultiline( data ) {
164 if ( data.match( /[\n\r]/) ) {
165 return true;
166 }
167 return false;
168 }
169
170 // =====================================================================
171 // Log page: filter and delete the log.
172
173 function cpjs_filter_log() {
174 'use strict';
175 // Create bitmask
176 var bitmask = 0;
177 if ( document.cplogform.info.checked == true ) { bitmask += 1; }
178 if ( document.cplogform.warn.checked == true ) { bitmask += 2; }
179 if ( document.cplogform.error.checked == true ) { bitmask += 4; }
180 if ( document.cplogform.debug.checked == true ) { bitmask += 8; }
181
182 // Clear the textarea
183 document.cplogform.cptxtlog.value = '';
184
185 // Browser through our array and return only selected verbosity
186 var cp_count = 0;
187 var i = 0;
188 for ( i = 0; i < cplog_array.length; ++i ) {
189 var line = decodeURIComponent( cplog_array[i] );
190 var line_array = line.split('~~', 2 );
191 if ( line_array[0] & bitmask ) {
192 document.cplogform.cptxtlog.value += line_array[1];
193 ++cp_count;
194 }
195 }
196 if ( cp_count == 0 ) {
197 document.cplogform.cptxtlog.value = '\n > ' + cpi18n.empty_log;
198 }
199 }
200
201 function cpjs_delete_log() {
202 'use strict';
203 if ( confirm( cpi18n.delete_log ) ) {
204 return true;
205 }
206 return false;
207 }
208 // =====================================================================
209 // AJAX call to start the profiler.
210
211 function cpjs_start_profiler() {
212
213 'use strict';
214
215 jQuery('html, body').animate( {
216 scrollTop: jQuery('#button-adv-settings').offset().top
217 }, 1000 );
218
219 // Get the nonce
220 var cp_nonce = jQuery('#cp_nonce').val();
221 if ( cp_nonce == '') {
222 alert( cpi18n.missing_nonce );
223 return;
224 }
225
226 // Get the scan type (frontend/backend)
227 var post;
228 var x_end = jQuery('input[name="x_end"]:checked').val();
229 if ( x_end == 'frontend') {
230 post = jQuery('#id-frontend').val();
231
232 } else if ( x_end == 'backend') {
233 post = jQuery('#id-backend').val();
234
235 } else if ( x_end == 'custom') {
236 post = jQuery('#id-custom').val().trim(); // Trim user input
237
238 } else if ( x_end == 'wpcron') {
239 post = jQuery('#id-wpcron').val();
240 if ( post == 0 ) {
241 alert( cpi18n.missing_wpcron );
242 return;
243 }
244
245 } else {
246 alert( cpi18n.missing_frontbackend );
247 return;
248 }
249 if ( post == '') {
250 alert( cpi18n.missing_post );
251 return;
252 }
253
254 // Get the profile's name
255 var profile = jQuery('input[name="profile"]').val();
256 if ( profile == '') {
257 alert( cpi18n.missing_profilename );
258 jQuery('input[name="profile"]').focus();
259 return;
260 }
261
262 var x_auth = jQuery('input[name="x_auth"]:checked').val();
263 if ( x_auth == '') {
264 alert( cpi18n.missing_userauth );
265 return;
266 }
267
268 var username = jQuery('#user-name').val().trim(); // Trim user input
269 if ( x_auth == 'authenticated') {
270 if ( username == '') {
271 alert( cpi18n.missing_username );
272 jQuery('#user-name').focus();
273 return;
274 }
275 }
276
277 var user_agent = jQuery('#ua-id').val();
278 if ( user_agent == 'undefined') {
279 user_agent = 'FireFox';
280 }
281
282 var theme = jQuery('#id-theme').val();
283
284 // GET or POST
285 var method = jQuery('input[name="method"]:checked').val();
286 var payload = '';
287 if ( method == 'post') {
288 // Payload
289 payload = jQuery('#post-value').val();
290 } else {
291 method = 'get';
292 }
293
294 //Content type
295 var ct = jQuery('#id-content-type').val();
296 if ( ct == 2 ) {
297 // application/json
298 if ( cpjs_isJSON( payload ) == null ) {
299 alert( cpi18n.missing_ajax );
300 jQuery('#user-name').focus();
301 return;
302 }
303 } else if ( ct == 3 ) {
304 // Raw format must be on one single line
305 if ( cpjs_ismultiline( payload.trim() ) == true ) {
306 alert( cpi18n.multiline_raw );
307 jQuery('#post-value').focus();
308 return;
309 }
310 }
311
312 var cookies = jQuery('#cp-cookies').val();
313 var headers = jQuery('#custom-headers').val();
314 var exclusions = jQuery('#exclusions').val();
315
316 // Change buttons status and add animated image with status message
317 jQuery('#start-profile').prop('disabled', true);
318 jQuery('#cp-progress-div').slideDown();
319 jQuery('#progress-gif').slideDown();
320 jQuery('#progress-text').slideDown();
321 jQuery('#code-profiler-error').slideUp();
322 jQuery('#cp-span-progress').css('width', '30%');
323
324 var data = {
325 'action': 'codeprofiler_start_profiler',
326 'cp_nonce': cp_nonce,
327 'x_end': x_end,
328 'post': post,
329 'content_type': ct,
330 'profile': profile,
331 'x_auth': x_auth,
332 'username': username,
333 'cookies': cookies,
334 'custom_headers': headers,
335 'exclusions': exclusions,
336 'method': method,
337 'payload': payload,
338 'user_agent': user_agent,
339 'theme': theme
340 };
341 // Send the request via AJAX
342 jQuery.ajax( {
343 type: 'POST',
344 url: ajaxurl,
345 data: data,
346 dataType: 'json',
347 success: function( response ) {
348
349 if (typeof response === 'undefined') {
350 cpjs_start_error('<p>'+ cpi18n.unknown_error +'</p>');
351 return;
352 }
353
354 if ( response.status != 'success') {
355 cpjs_start_error('<p>'+ response.message +'</p>');
356 return;
357 }
358
359 // ------------------------------------------------------------
360 // Inform the user we're moving to step 2
361 jQuery('#cp-span-progress').css('width', '70%');
362 jQuery('#progress-text').html( cpi18n.preparing_report );
363
364 data['action'] = 'codeprofiler_prepare_report';
365 data['microtime'] = response.microtime;
366 jQuery.ajax( {
367 type: 'POST',
368 url: ajaxurl,
369 data: data,
370 dataType: 'json',
371 success: function( response ) {
372
373 if (typeof response === 'undefined') {
374 cpjs_start_error('<p>'+ cpi18n.unknown_error +'</p>');
375 return;
376 }
377
378 if ( response.status != 'success') {
379 cpjs_start_error('<p>'+ response.message +'</p>');
380 return;
381 }
382 var cp_uri;
383 if (response.cp_profile !== 'undefined' && response.cp_profile != '') {
384 cp_uri = '&cptab=profiles_list&action=view_profile&id=' + response.cp_profile + '&section=1';
385 } else {
386 cp_uri = '&cptab=profiles_list';
387 }
388
389 // All good, redirect to the Profiles List tab
390 jQuery('#cp-span-progress').css('width', '100%');
391 window.location.href = window.location.href + cp_uri;
392 return;
393
394 },
395
396 // Display non-200 HTTP response
397 error: function( xhr, status, err ) {
398 if ( err != '') {
399 if ( xhr.status != 0 ) {
400 var message = cpi18n.http_error +' '+ xhr.status +' '+ err;
401 // Timeout
402 if ( xhr.status == 503 || xhr.status == 504 ) {
403 cpjs_start_error('<p>'+ message +'<br />'+ cpi18n.timeout_error +'.</p>');
404 // Redirections, not found
405 } else if ( xhr.status == 301 || xhr.status == 302 || xhr.status == 404 ) {
406 cpjs_start_error('<p>'+ message +'<br />'+ cpi18n.notfound_error +'.</p>');
407 // Forbidden
408 } else if ( xhr.status == 403 ) {
409 cpjs_start_error('<p>'+ message +'<br />'+ cpi18n.forbidden_error +'.</p>');
410 // Internal error
411 } else if ( xhr.status == 500 ) {
412 cpjs_start_error('<p>'+ message +'<br />'+ cpi18n.internal_error +'.<br />'+ cpi18n.timeout_error +'.</p>');
413 } else {
414 cpjs_start_error('<p>'+ cpi18n.http_error +' '+ xhr.status +' '+ err +'.</p>');
415 }
416 return;
417
418 } else {
419 cpjs_start_error('<p>'+ cpi18n.unknown_error +' '+ err +'.</p>');
420 return;
421 }
422 }
423 return;
424 }
425 });
426 // ------------------------------------------------------------
427 },
428
429 // Display non-200 HTTP response
430 error: function( xhr, status, err ) {
431 if ( err != '') {
432 if ( xhr.status != 0 ) {
433 var message = cpi18n.http_error +' '+ xhr.status +' '+ err;
434 // Timeout
435 if ( xhr.status == 503 || xhr.status == 504 ) {
436 cpjs_start_error('<p>'+ message +'<br />'+ cpi18n.timeout_error +'.</p>');
437 // Redirections, not found
438 } else if ( xhr.status == 301 || xhr.status == 302 || xhr.status == 404 ) {
439 cpjs_start_error('<p>'+ message +'<br />'+ cpi18n.notfound_error +'.</p>');
440 // Forbidden
441 } else if ( xhr.status == 403 ) {
442 cpjs_start_error('<p>'+ message +'<br />'+ cpi18n.forbidden_error +'.</p>');
443 // Internal error
444 } else if ( xhr.status == 500 ) {
445 cpjs_start_error('<p>'+ message +'<br />'+ cpi18n.internal_error +'.<br />'+ cpi18n.timeout_error +'.</p>');
446 } else {
447 cpjs_start_error('<p>'+ cpi18n.http_error +' '+ xhr.status +' '+ err +'.</p>');
448 }
449 return;
450
451 } else {
452 cpjs_start_error('<p>'+ cpi18n.unknown_error +' '+ err +'.</p>');
453 return;
454 }
455 }
456 return;
457 }
458 });
459 }
460
461 // Display error
462 function cpjs_start_error( error ) {
463 'use strict';
464 jQuery('#start-profile').prop('disabled', false);
465 jQuery('#progress-gif').slideUp();
466 jQuery('#progress-text').slideUp();
467 jQuery('#cp-span-progress').css('width', '0%');
468 jQuery('#code-profiler-error').html( error );
469 jQuery('#code-profiler-error').slideDown();
470 jQuery('#cp-progress-div').slideUp();
471
472 }
473
474 // =====================================================================
475 // Profiles List page.
476
477 function cpjs_delete_profile() {
478 'use strict';
479 if ( confirm( cpi18n.delete_profile ) ) {
480 return true;
481 }
482 return false;
483 }
484
485 // Hide/show the edit box and buttons when renaming a profile.
486 function cpjs_toggle_name( row ) {
487 if ( jQuery('#profile_div_'+ row).css('display') == 'none') {
488 jQuery('#profile_name_'+ row).hide();
489 jQuery('#profile_div_'+ row).show();
490 jQuery('#edit-'+ row).val( jQuery('#profile_name_'+ row).html() );
491 jQuery('#edit-'+ row).focus();
492 } else {
493 jQuery('#profile_div_'+ row).hide();
494 jQuery('#profile_name_'+ row).show();
495 }
496 }
497
498 // Edit the profile name via AJAX endpoint.
499 function cpjs_edit_name( profile, id, cp_nonce, row ) {
500
501 'use strict';
502
503 if ( cp_nonce == '') {
504 alert( cpi18n.missing_nonce );
505 return;
506 }
507 if ( profile == '') {
508 alert( cpi18n.missing_profileid );
509 return;
510 }
511
512 var new_name = jQuery('#edit-'+ id).val().trim();
513 if ( new_name == '') {
514 alert( cpi18n.missing_profilename );
515 return;
516 }
517
518 jQuery('#profile_spinner_'+ row).addClass('is-active');
519
520 var data = {
521 'action': 'codeprofiler_rename',
522 'cp_nonce': cp_nonce,
523 'new_name': new_name,
524 'profile': profile,
525 };
526
527 // Send the request via AJAX
528 jQuery.ajax( {
529 type: 'POST',
530 url: ajaxurl,
531 data: data,
532 dataType: 'json',
533 success: function( response ) {
534 jQuery('#profile_spinner_'+ row ).removeClass('is-active');
535
536 if (typeof response === 'undefined') {
537 alert( cpi18n.unknown_error );
538 return;
539 }
540
541 if ( response.status != 'success') {
542 alert( response.message );
543 return;
544 }
545
546 // Success: update the name in the table
547 jQuery('#profile_name_'+ id).html( response.newname );
548 cpjs_toggle_name(row);
549 },
550 // Display non-200 HTTP response
551 error: function( xhr, status, err ) {
552 jQuery('#profile_spinner_'+ row ).removeClass('is-active');
553 if ( err != '') {
554 if ( xhr.status != 0 ) {
555 var message = cpi18n.http_error +' '+ xhr.status +' '+ err;
556 // Timeout
557 if ( xhr.status == 503 || xhr.status == 504 ) {
558 alert( message +'<br />'+ cpi18n.timeout_error );
559 // Redirections, not found
560 } else if ( xhr.status == 301 || xhr.status == 302 || xhr.status == 404 ) {
561 alert( message +'<br />'+ cpi18n.notfound_error );
562 // Forbidden
563 } else if ( xhr.status == 403 ) {
564 alert( message +'<br />'+ cpi18n.forbidden_error );
565 // Internal error
566 } else if ( xhr.status == 500 ) {
567 alert( message +'<br />'+ cpi18n.internal_error +'.<br />'+ cpi18n.timeout_error );
568 } else {
569 alert( cpi18n.http_error +' '+ xhr.status +' '+ err );
570 }
571 return;
572
573 } else {
574 alert( cpi18n.unknown_error +' '+ err );
575 return;
576 }
577 }
578 return;
579 }
580 });
581 }
582
583 // =====================================================================
584 // Plugins/Theme chart.
585
586 function cpjs_plugins_chart( caxis, clabel, cdata, ctotal_time ) {
587 'use strict';
588 // Switch between vertical and horizontal bars
589 var _indexAxis = caxis;
590 document.getElementById('htov').onclick = function() {
591 if ( _indexAxis == 'x') {
592 _indexAxis = 'y';
593 } else {
594 _indexAxis = 'x';
595 }
596 myChart.destroy();
597 myChart = new Chart(ctx, {
598 type: 'bar',
599 options: {
600 animation: {
601 duration: 1000,
602 },
603 indexAxis: _indexAxis,
604 plugins: chartPlugins
605 },
606 plugins:[ plugin],
607 data: chartData
608 });
609 /** Since Chartjs v4.5.1 **/
610 // document.getElementById('download-png-img').href = myChart.toBase64Image();
611
612 };
613
614 var ctx = document.getElementById('myChart').getContext('2d');
615
616 var chartData = {
617 labels: clabel,
618 datasets: [{
619 label: cpi18n.exec_sec_plugins,
620 backgroundColor: 'rgba(204, 0, 0, .5)',
621 borderColor: '#c00',
622 borderWidth: 2,
623 hoverBackgroundColor: '#B45252',
624 data: cdata
625 }]
626 };
627
628 const total_time = ctotal_time;
629 const footer = (tooltipItems) => {
630 var sum;
631 tooltipItems.forEach(function(tooltipItem) {
632 if ( _indexAxis == 'x') {
633 sum = Math.round( ( tooltipItem.parsed.y / total_time ) * 100 );
634 } else {
635 sum = Math.round( ( tooltipItem.parsed.x / total_time ) * 100 );
636 }
637 });
638 return sum + cpi18n.pc_plugins;
639 };
640
641 var chartPlugins = {
642 title: {
643 display: true,
644 text: cpi18n.exec_tot_plugins_1 +' (' + cpi18n.chart_total +' '+ ctotal_time +')'
645 },
646 legend: {
647 display: false
648 },
649 tooltip: {
650 borderWidth: 1,
651 borderColor: '#666',
652 displayColors: false,
653 backgroundColor: '#F5F5B5',
654 titleColor:'#666',
655 padding: 8,
656 footerColor: '#666',
657 callbacks: {
658 footer: footer,
659 labelTextColor: function(context) {
660 return '#543453';
661 }
662 }
663 }
664 }
665
666 // We want a background colour for the downloaded PNG file
667 const plugin = {
668 id: 'custom_canvas_background_color',
669 beforeDraw: (chart) => {
670 const ctx = chart.canvas.getContext('2d');
671 ctx.save();
672 ctx.globalCompositeOperation = 'destination-over';
673 ctx.fillStyle = '#f0f0f1',
674 ctx.fillRect(0, 0, chart.width, chart.height);
675 ctx.restore();
676 }
677 }
678
679 var myChart = new Chart(ctx, {
680 type: 'bar',
681 data: chartData,
682 options: {
683 animation: {
684 duration: 700,
685 onComplete: function() {
686 jQuery('#cp-footer-buttons').slideDown(200);
687 }
688 },
689 indexAxis: _indexAxis,
690 plugins: chartPlugins
691 },
692 plugins:[plugin]
693 });
694 /** Since Chartjs v4.5.1 **/
695 document.getElementById('download-png-img').href = myChart.toBase64Image();
696
697 }
698
699 // =====================================================================
700 // File I/O chart.
701
702 function cpjs_iostats_chart( caxis, clabel, cdata, ctotal_calls ) {
703 'use strict';
704 // Switch between vertical and horizontal bars
705 var _indexAxis = caxis;
706 document.getElementById('htov').onclick = function() {
707 if ( _indexAxis == 'x') {
708 _indexAxis = 'y';
709 } else {
710 _indexAxis = 'x';
711 }
712 myChart.destroy();
713 myChart = new Chart(ctx, {
714 type: 'line',
715 options: {
716 animation: {
717 duration: 1000,
718 },
719 indexAxis: _indexAxis,
720 plugins: chartPlugins
721 },
722 plugins:[ plugin],
723 data: chartData
724 });
725 /** Since Chartjs v4.5.1 **/
726 // document.getElementById('download-png-img').href = myChart.toBase64Image();
727 };
728
729 var ctx = document.getElementById('myChart').getContext('2d');
730
731 var chartData = {
732 labels: clabel,
733 datasets: [{
734 label: cpi18n.iolist_total_calls,
735 backgroundColor: 'rgba(34, 113, 177, .5)',
736 borderColor: '#2271B1',
737 borderWidth: 2,
738 hoverBackgroundColor: '#FF0000',
739 data: cdata,
740 fill: 'origin',
741 radius: 6,
742 pointBackgroundColor: '#B45252'
743 }]
744 };
745 var chartPlugins = {
746 title: {
747 display: true,
748 text: cpi18n.io_calls +' (' + cpi18n.chart_total +' '+ ctotal_calls +')'
749 },
750 legend: {
751 display: false
752 },
753 tooltip: {
754 borderWidth: 1,
755 borderColor: '#666',
756 displayColors: false,
757 backgroundColor: '#F5F5B5',
758 titleColor:'#666',
759 padding: 8,
760 footerColor: '#666',
761 callbacks: {
762 labelTextColor: function(context) {
763 return '#543453';
764 }
765 }
766 }
767 }
768 // We want a background colour for the downloaded PNG file
769 const plugin = {
770 id: 'custom_canvas_background_color',
771 beforeDraw: (chart) => {
772 const ctx = chart.canvas.getContext('2d');
773 ctx.save();
774 ctx.globalCompositeOperation = 'destination-over';
775 ctx.fillStyle = '#f0f0f1',
776 ctx.fillRect(0, 0, chart.width, chart.height);
777 ctx.restore();
778 }
779 }
780
781 var myChart = new Chart(ctx, {
782 type: 'line',
783 data: chartData,
784 options: {
785 animation: {
786 duration: 700,
787 onComplete: function() {
788 jQuery('#cp-footer-buttons').slideDown(200);
789 }
790 },
791 indexAxis: _indexAxis,
792 plugins: chartPlugins
793 },
794 plugins:[plugin]
795 });
796 /** Since Chartjs v4.5.1 **/
797 document.getElementById('download-png-img').href = myChart.toBase64Image();
798
799 }
800 // =====================================================================
801 // Disk I/O chart.
802
803 function cpjs_diskio_chart( caxis, clabel, cdata ) {
804 'use strict';
805 // Switch between vertical and horizontal bars
806 var _indexAxis = caxis;
807 document.getElementById('htov').onclick = function() {
808 if ( _indexAxis == 'x') {
809 _indexAxis = 'y';
810 } else {
811 _indexAxis = 'x';
812 }
813 myChart.destroy();
814 myChart = new Chart(ctx, {
815 type: 'line',
816 options: {
817 animation: {
818 duration: 1000,
819 },
820 indexAxis: _indexAxis,
821 plugins: chartPlugins
822 },
823 plugins:[ plugin],
824 data: chartData
825 });
826 /** Since Chartjs v4.5.1 **/
827 // document.getElementById('download-png-img').href = myChart.toBase64Image();
828 };
829 var ctx = document.getElementById('myChart').getContext('2d');
830
831 var chartData = {
832 labels: clabel,
833 datasets: [{
834 label: cpi18n.disk_io_bytes,
835 backgroundColor: 'rgba(143, 240, 164, .5)',
836 borderColor: '#41B141',
837 borderWidth: 2,
838 hoverBackgroundColor: '#FF0000',
839 data: cdata,
840 fill: 'origin',
841 radius: 6,
842 pointBackgroundColor: '#B45252'
843 }]
844 };
845 var chartPlugins = {
846 title: {
847 display: true,
848 text: cpi18n.disk_io_title,
849 },
850 legend: {
851 display: false
852 },
853 tooltip: {
854 borderWidth: 1,
855 borderColor: '#666',
856 displayColors: false,
857 backgroundColor: '#F5F5B5',
858 titleColor:'#666',
859 padding: 8,
860 footerColor: '#666',
861 callbacks: {
862 labelTextColor: function(context) {
863 return '#543453';
864 }
865 }
866 }
867 }
868 // We want a background colour for the downloaded PNG file
869 const plugin = {
870 id: 'custom_canvas_background_color',
871 beforeDraw: (chart) => {
872 const ctx = chart.canvas.getContext('2d');
873 ctx.save();
874 ctx.globalCompositeOperation = 'destination-over';
875 ctx.fillStyle = '#f0f0f1',
876 ctx.fillRect(0, 0, chart.width, chart.height);
877 ctx.restore();
878 }
879 }
880
881 var myChart = new Chart(ctx, {
882 type: 'line',
883 data: chartData,
884 options: {
885 animation: {
886 duration: 700,
887 onComplete: function() {
888 jQuery('#cp-footer-buttons').slideDown(200);
889 }
890 },
891 indexAxis: _indexAxis,
892 plugins: chartPlugins
893 },
894 plugins:[plugin]
895 });
896 /** Since Chartjs v4.5.1 **/
897 document.getElementById('download-png-img').href = myChart.toBase64Image();
898 }
899
900 // =====================================================================
901 // Settings page
902
903 function cpjs_copy_textarea( id ) {
904 document.getElementById(id).select();
905 document.execCommand('copy');
906 alert( cpi18n.text_copied );
907 }
908
909 // =====================================================================
910 // EOF
911