TimelineGrid.js 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. /*
  2. * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
  3. * Copyright (C) 2008, 2009 Anthony Ricaud <rik@webkit.org>
  4. * Copyright (C) 2009 Google Inc. All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. *
  10. * 1. Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions and the following disclaimer.
  12. * 2. Redistributions in binary form must reproduce the above copyright
  13. * notice, this list of conditions and the following disclaimer in the
  14. * documentation and/or other materials provided with the distribution.
  15. * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
  16. * its contributors may be used to endorse or promote products derived
  17. * from this software without specific prior written permission.
  18. *
  19. * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
  20. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  21. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  22. * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
  23. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  24. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  25. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  26. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  28. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29. */
  30. /**
  31. * @constructor
  32. */
  33. WebInspector.TimelineGrid = function()
  34. {
  35. this.element = document.createElement("div");
  36. this._itemsGraphsElement = document.createElement("div");
  37. this._itemsGraphsElement.id = "resources-graphs";
  38. this.element.appendChild(this._itemsGraphsElement);
  39. this._dividersElement = this.element.createChild("div", "resources-dividers");
  40. this._gridHeaderElement = document.createElement("div");
  41. this._eventDividersElement = this._gridHeaderElement.createChild("div", "resources-event-dividers");
  42. this._dividersLabelBarElement = this._gridHeaderElement.createChild("div", "resources-dividers-label-bar");
  43. this.element.appendChild(this._gridHeaderElement);
  44. this._leftCurtainElement = this.element.createChild("div", "timeline-cpu-curtain-left");
  45. this._rightCurtainElement = this.element.createChild("div", "timeline-cpu-curtain-right");
  46. }
  47. WebInspector.TimelineGrid.prototype = {
  48. get itemsGraphsElement()
  49. {
  50. return this._itemsGraphsElement;
  51. },
  52. get dividersElement()
  53. {
  54. return this._dividersElement;
  55. },
  56. get dividersLabelBarElement()
  57. {
  58. return this._dividersLabelBarElement;
  59. },
  60. get gridHeaderElement()
  61. {
  62. return this._gridHeaderElement;
  63. },
  64. removeDividers: function()
  65. {
  66. this._dividersElement.removeChildren();
  67. this._dividersLabelBarElement.removeChildren();
  68. },
  69. updateDividers: function(calculator)
  70. {
  71. const minGridSlicePx = 48; // minimal distance between grid lines.
  72. const gridFreeZoneAtLeftPx = 50;
  73. var dividersElementClientWidth = this._dividersElement.clientWidth;
  74. var dividersCount = dividersElementClientWidth / minGridSlicePx;
  75. var gridSliceTime = calculator.boundarySpan() / dividersCount;
  76. var pixelsPerTime = dividersElementClientWidth / calculator.boundarySpan();
  77. // Align gridSliceTime to a nearest round value.
  78. // We allow spans that fit into the formula: span = (1|2|5)x10^n,
  79. // e.g.: ... .1 .2 .5 1 2 5 10 20 50 ...
  80. // After a span has been chosen make grid lines at multiples of the span.
  81. var logGridSliceTime = Math.ceil(Math.log(gridSliceTime) / Math.log(10));
  82. gridSliceTime = Math.pow(10, logGridSliceTime);
  83. if (gridSliceTime * pixelsPerTime >= 5 * minGridSlicePx)
  84. gridSliceTime = gridSliceTime / 5;
  85. if (gridSliceTime * pixelsPerTime >= 2 * minGridSlicePx)
  86. gridSliceTime = gridSliceTime / 2;
  87. var firstDividerTime = Math.ceil((calculator.minimumBoundary() - calculator.zeroTime()) / gridSliceTime) * gridSliceTime + calculator.zeroTime();
  88. var lastDividerTime = calculator.maximumBoundary();
  89. // Add some extra space past the right boundary as the rightmost divider label text
  90. // may be partially shown rather than just pop up when a new rightmost divider gets into the view.
  91. if (calculator.paddingLeft > 0)
  92. lastDividerTime = lastDividerTime + minGridSlicePx / pixelsPerTime;
  93. dividersCount = Math.ceil((lastDividerTime - firstDividerTime) / gridSliceTime);
  94. // Reuse divider elements and labels.
  95. var divider = this._dividersElement.firstChild;
  96. var dividerLabelBar = this._dividersLabelBarElement.firstChild;
  97. var skipLeftmostDividers = calculator.paddingLeft === 0;
  98. if (!gridSliceTime)
  99. dividersCount = 0;
  100. for (var i = 0; i < dividersCount; ++i) {
  101. var left = calculator.computePosition(firstDividerTime + gridSliceTime * i);
  102. if (skipLeftmostDividers && left < gridFreeZoneAtLeftPx)
  103. continue;
  104. if (!divider) {
  105. divider = document.createElement("div");
  106. divider.className = "resources-divider";
  107. this._dividersElement.appendChild(divider);
  108. dividerLabelBar = document.createElement("div");
  109. dividerLabelBar.className = "resources-divider";
  110. var label = document.createElement("div");
  111. label.className = "resources-divider-label";
  112. dividerLabelBar._labelElement = label;
  113. dividerLabelBar.appendChild(label);
  114. this._dividersLabelBarElement.appendChild(dividerLabelBar);
  115. }
  116. dividerLabelBar._labelElement.textContent = calculator.formatTime(firstDividerTime + gridSliceTime * i - calculator.minimumBoundary());
  117. var percentLeft = 100 * left / dividersElementClientWidth;
  118. divider.style.left = percentLeft + "%";
  119. dividerLabelBar.style.left = percentLeft + "%";
  120. divider = divider.nextSibling;
  121. dividerLabelBar = dividerLabelBar.nextSibling;
  122. }
  123. // Remove extras.
  124. while (divider) {
  125. var nextDivider = divider.nextSibling;
  126. this._dividersElement.removeChild(divider);
  127. divider = nextDivider;
  128. }
  129. while (dividerLabelBar) {
  130. var nextDivider = dividerLabelBar.nextSibling;
  131. this._dividersLabelBarElement.removeChild(dividerLabelBar);
  132. dividerLabelBar = nextDivider;
  133. }
  134. return true;
  135. },
  136. addEventDivider: function(divider)
  137. {
  138. this._eventDividersElement.appendChild(divider);
  139. },
  140. addEventDividers: function(dividers)
  141. {
  142. this._gridHeaderElement.removeChild(this._eventDividersElement);
  143. for (var i = 0; i < dividers.length; ++i) {
  144. if (dividers[i])
  145. this._eventDividersElement.appendChild(dividers[i]);
  146. }
  147. this._gridHeaderElement.appendChild(this._eventDividersElement);
  148. },
  149. removeEventDividers: function()
  150. {
  151. this._eventDividersElement.removeChildren();
  152. },
  153. hideEventDividers: function()
  154. {
  155. this._eventDividersElement.addStyleClass("hidden");
  156. },
  157. showEventDividers: function()
  158. {
  159. this._eventDividersElement.removeStyleClass("hidden");
  160. },
  161. hideCurtains: function()
  162. {
  163. this._leftCurtainElement.addStyleClass("hidden");
  164. this._rightCurtainElement.addStyleClass("hidden");
  165. },
  166. /**
  167. * @param {number} gapOffset
  168. * @param {number} gapWidth
  169. */
  170. showCurtains: function(gapOffset, gapWidth)
  171. {
  172. this._leftCurtainElement.style.width = gapOffset + "px";
  173. this._leftCurtainElement.removeStyleClass("hidden");
  174. this._rightCurtainElement.style.left = (gapOffset + gapWidth) + "px";
  175. this._rightCurtainElement.removeStyleClass("hidden");
  176. },
  177. setScrollAndDividerTop: function(scrollTop, dividersTop)
  178. {
  179. this._dividersElement.style.top = scrollTop + "px";
  180. this._leftCurtainElement.style.top = scrollTop + "px";
  181. this._rightCurtainElement.style.top = scrollTop + "px";
  182. }
  183. }
  184. /**
  185. * @interface
  186. */
  187. WebInspector.TimelineGrid.Calculator = function() { }
  188. WebInspector.TimelineGrid.Calculator.prototype = {
  189. /** @param {number} time */
  190. computePosition: function(time) { },
  191. /** @param {number} time */
  192. formatTime: function(time) { },
  193. /** @return {number} */
  194. minimumBoundary: function() { },
  195. /** @return {number} */
  196. zeroTime: function() { },
  197. /** @return {number} */
  198. maximumBoundary: function() { },
  199. /** @return {number} */
  200. boundarySpan: function() { }
  201. }