Performance monitor

Works on any website. Shows fps, frame time, used memory. Change modes by click

  1. // ==UserScript==
  2. // @name Performance monitor
  3. // @description Works on any website. Shows fps, frame time, used memory. Change modes by click
  4. //
  5. // @name:ru Монитор производительности
  6. // @description:ru Работает на любом сайте. Отображает fps, время кадра, используемую память. Смена режимов по клику
  7. //
  8. // @version 1.1.1
  9. // @author Konf
  10. // @namespace https://greasyfork.org/users/424058
  11. // @compatible Chrome
  12. // @compatible Opera
  13. // @compatible Firefox
  14. // @icon https://i.imgur.com/MrU4sID.png
  15. // @include *
  16. // @run-at document-body
  17. // @grant none
  18. // @noframes
  19. // @require https://cdn.jsdelivr.net/npm/stats.js@0.17.0
  20. // @require https://cdn.jsdelivr.net/npm/interactjs@1.9.20
  21. // ==/UserScript==
  22.  
  23. /* jshint esversion: 6 */
  24. /* global Stats, interact */
  25.  
  26. /**
  27. * In the code below I just try to make proper work of the two ready libraries:
  28. * One makes performance monitor, and second makes the monitor movable
  29. * It was not so easy, and seems it works now, but DON'T try to understand why
  30. * Most likely, even me already do not know it
  31. */
  32.  
  33. (function() {
  34. 'use strict';
  35.  
  36. const stats = new Stats();
  37. const statsParentNode = document.body;
  38. let statsIsHidden = false;
  39. let mouseOverParentNode = true;
  40.  
  41. stats.dom.style.touchAction = 'none';
  42. stats.dom.style.width = '80px';
  43. stats.dom.style.height = '48px';
  44. stats.dom.style.padding = 0;
  45. stats.dom.style.margin = 0;
  46.  
  47. statsParentNode.appendChild(stats.dom);
  48.  
  49. const panelNum = {
  50. current: 0,
  51. max: 2
  52. };
  53.  
  54. const listeners = {
  55. statsDragInteract: {
  56. // call this function on every dragmove event
  57. move(event) {
  58. const target = event.target;
  59.  
  60. // keep the dragged position in the data-x/data-y attributes
  61. const x = (parseFloat(target.getAttribute('data-x')) || 0) + event.dx;
  62. const y = (parseFloat(target.getAttribute('data-y')) || 0) + event.dy;
  63.  
  64. // translate the element
  65. target.style.transform = 'translate(' + x + 'px, ' + (y < 0 ? 0 : y) + 'px)';
  66. target.style.webkitTransform = target.style.transform;
  67.  
  68. // update the position attributes
  69. target.setAttribute('data-x', x);
  70. target.setAttribute('data-y', y);
  71. },
  72.  
  73. // bugfix...
  74. start(event) {
  75. const target = event.target;
  76. const targetTransform = target.style.transform;
  77. const transformY = (/,( |)*(\d*)/.exec(targetTransform) || [])[2];
  78.  
  79. if (targetTransform && transformY <= 0) {
  80. target.setAttribute('data-y', 0);
  81. }
  82. },
  83.  
  84. // call this function on every dragend event
  85. end(event) {
  86. statsIsHidden = false;
  87.  
  88. if (mouseOverParentNode && --panelNum.current < 0) {
  89. panelNum.current = panelNum.max;
  90. }
  91.  
  92. if (!mouseOverParentNode || statsIsHidden) {
  93. return stats.showPanel(panelNum.current);
  94. }
  95.  
  96. stats.showPanel(panelNum.current - 1);
  97. }
  98. },
  99.  
  100. statsNative: {
  101. node: {
  102. click(event) {
  103. if (statsIsHidden) {
  104. statsIsHidden = false;
  105. return stats.showPanel(panelNum.current);
  106. }
  107.  
  108. if (++panelNum.current > panelNum.max) {
  109. panelNum.current = 0;
  110. }
  111.  
  112. stats.showPanel(panelNum.current);
  113. }
  114. },
  115.  
  116. parent: {
  117. mouseenter(event) {
  118. mouseOverParentNode = true;
  119. },
  120. mouseleave(event) {
  121. mouseOverParentNode = false;
  122. }
  123. },
  124.  
  125. canvas: {
  126. contextmenu(event) {
  127. event.preventDefault();
  128.  
  129. statsIsHidden = true;
  130. this.style.display = 'none';
  131. }
  132. }
  133. }
  134. };
  135.  
  136. interact(stats.dom).draggable({
  137. // keep the element within the area of it's parent
  138. modifiers: [
  139. interact.modifiers.restrictRect({
  140. restriction: 'parent'
  141. })
  142. ],
  143.  
  144. listeners: listeners.statsDragInteract
  145. });
  146.  
  147. const panels = Array.from(stats.dom.querySelectorAll('canvas'));
  148. panels.forEach((canvas) => {
  149. canvas.addEventListener('contextmenu', listeners.statsNative.canvas.contextmenu);
  150. });
  151.  
  152. stats.dom.addEventListener('click', listeners.statsNative.node.click);
  153.  
  154. statsParentNode.addEventListener('mouseenter', listeners.statsNative.parent.mouseenter);
  155. statsParentNode.addEventListener('mouseleave', listeners.statsNative.parent.mouseleave);
  156.  
  157. requestAnimationFrame(function loop() {
  158. stats.update();
  159. requestAnimationFrame(loop);
  160. });
  161. })();