Performance monitor

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

As of 2021-03-12. See the latest version.

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