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

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