PluginProbe
Code Profiler – WordPress Performance Profiling and Debugging Made Easy / 1.8
Code Profiler – WordPress Performance Profiling and Debugging Made Easy v1.8
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.8, at static/code-profiler.js

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