nodes-heatmap.js 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. /**
  2. * Licensed to the Apache Software Foundation (ASF) under one
  3. * or more contributor license agreements. See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership. The ASF licenses this file
  6. * to you under the Apache License, Version 2.0 (the
  7. * "License"); you may not use this file except in compliance
  8. * with the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. */
  18. import BaseChartComponent from 'yarn-ui/components/base-chart-component';
  19. import Mock from 'yarn-ui/utils/mock';
  20. export default BaseChartComponent.extend({
  21. CELL_WIDTH: 250,
  22. SAMPLE_CELL_WIDTH: 100,
  23. SAMPLE_HEIGHT: 30,
  24. CELL_HEIGHT: 30,
  25. CELL_MARGIN: 2,
  26. RACK_MARGIN: 20,
  27. filter: "",
  28. bindTP: function(element) {
  29. element.on("mouseover", function() {
  30. this.tooltip
  31. .style("left", (d3.event.pageX) + "px")
  32. .style("top", (d3.event.pageY - 28) + "px");
  33. element.style("opacity", 1.0);
  34. }.bind(this))
  35. .on("mousemove", function() {
  36. // Handle pie chart case
  37. var text = element.attr("tooltiptext");
  38. this.tooltip.style("opacity", .9);
  39. this.tooltip.html(text)
  40. .style("left", (d3.event.pageX) + "px")
  41. .style("top", (d3.event.pageY - 28) + "px");
  42. }.bind(this))
  43. .on("mouseout", function() {
  44. this.tooltip.style("opacity", 0);
  45. element.style("opacity", 0.8);
  46. }.bind(this));
  47. },
  48. // data:
  49. // [{label=label1, value=value1}, ...]
  50. // ...
  51. renderCells: function (model, title) {
  52. var data = [];
  53. model.forEach(function (o) {
  54. data.push(o);
  55. });
  56. this.chart.g.remove();
  57. this.chart.g = this.chart.svg.append("g");
  58. var g = this.chart.g;
  59. var layout = this.getLayout();
  60. layout.margin = 50;
  61. let racks = new Set();
  62. for (var i = 0; i < data.length; i++) {
  63. racks.add(data[i].get("rack"));
  64. }
  65. let racksArray = [];
  66. racks.forEach(v => racksArray.push(v));
  67. var xOffset = layout.margin;
  68. var yOffset = layout.margin * 3;
  69. var colorFunc = d3.interpolate(d3.rgb("#bdddf5"), d3.rgb("#0f3957"));
  70. var sampleXOffset = (layout.x2 - layout.x1) / 2 - 2.5 * this.SAMPLE_CELL_WIDTH -
  71. 2 * this.CELL_MARGIN;
  72. var sampleYOffset = layout.margin * 2;
  73. for (var i = 1; i <= 5; i++) {
  74. var ratio = i * 0.2 - 0.1;
  75. var rect = g.append("rect")
  76. .attr("x", sampleXOffset)
  77. .attr("y", sampleYOffset)
  78. .attr("fill", colorFunc(ratio))
  79. .attr("width", this.SAMPLE_CELL_WIDTH)
  80. .attr("height", this.SAMPLE_HEIGHT);
  81. g.append("text")
  82. .text("" + (ratio * 100).toFixed(1) + "% Used")
  83. .attr("y", sampleYOffset + this.SAMPLE_HEIGHT / 2 + 5)
  84. .attr("x", sampleXOffset + this.SAMPLE_CELL_WIDTH / 2)
  85. .attr("class", "heatmap-cell");
  86. sampleXOffset += this.CELL_MARGIN + this.SAMPLE_CELL_WIDTH;
  87. }
  88. var chartXOffset = -1;
  89. for (var i = 0; i < racksArray.length; i++) {
  90. var text = g.append("text")
  91. .text(racksArray[i])
  92. .attr("y", yOffset + this.CELL_HEIGHT / 2 + 5)
  93. .attr("x", layout.margin)
  94. .attr("class", "heatmap-rack");
  95. if (-1 == chartXOffset) {
  96. chartXOffset = layout.margin + text.node().getComputedTextLength() + 30;
  97. }
  98. xOffset = chartXOffset;
  99. for (var j = 0; j < data.length; j++) {
  100. var rack = data[j].get("rack");
  101. var host = data[j].get("nodeHostName");
  102. if (rack == racksArray[i]) {
  103. if (!rack.includes(this.filter) && !host.includes(this.filter)) {
  104. this.addNode(g, xOffset, yOffset, colorFunc, data[j], false);
  105. var text = g.append("text")
  106. .text(host)
  107. .attr("y", yOffset + this.CELL_HEIGHT / 2 + 5)
  108. .attr("x", xOffset + this.CELL_WIDTH / 2)
  109. .attr("class", "heatmap-cell-notselected");
  110. } else {
  111. this.addNode(g, xOffset, yOffset, colorFunc, data[j], true);
  112. g.append("text")
  113. .text(host)
  114. .attr("y", yOffset + this.CELL_HEIGHT / 2 + 5)
  115. .attr("x", xOffset + this.CELL_WIDTH / 2)
  116. .attr("class", "heatmap-cell");
  117. }
  118. xOffset += this.CELL_MARGIN + this.CELL_WIDTH;
  119. if (xOffset + this.CELL_MARGIN + this.CELL_WIDTH >= layout.x2 -
  120. layout.margin) {
  121. xOffset = chartXOffset;
  122. yOffset = yOffset + this.CELL_MARGIN + this.CELL_HEIGHT;
  123. }
  124. }
  125. }
  126. while (xOffset > chartXOffset && xOffset + this.CELL_MARGIN +
  127. this.CELL_WIDTH < layout.x2 - layout.margin) {
  128. this.addPlaceholderNode(g, xOffset, yOffset);
  129. xOffset += this.CELL_MARGIN + this.CELL_WIDTH;
  130. }
  131. if (xOffset != chartXOffset) {
  132. xOffset = chartXOffset;
  133. yOffset += this.CELL_MARGIN + this.CELL_HEIGHT;
  134. }
  135. yOffset += this.RACK_MARGIN;
  136. }
  137. layout.y2 = yOffset + layout.margin;
  138. this.adjustMaxHeight(layout.y2);
  139. this.renderTitleAndBG(g, title, layout, false);
  140. },
  141. addNode: function (g, xOffset, yOffset, colorFunc, data, selected) {
  142. var rect = g.append("rect")
  143. .attr("y", yOffset)
  144. .attr("x", xOffset)
  145. .attr("height", this.CELL_HEIGHT)
  146. .attr("fill", colorFunc(data.get("usedMemoryMB") /
  147. (data.get("usedMemoryMB") + data.get("availMemoryMB"))))
  148. .attr("width", this.CELL_WIDTH)
  149. .attr("tooltiptext", data.get("toolTipText"));
  150. if (selected) {
  151. rect.style("opacity", 0.8);
  152. this.bindTP(rect);
  153. } else {
  154. rect.style("opacity", 0.8);
  155. rect.attr("fill", "DimGray");
  156. }
  157. },
  158. addPlaceholderNode: function(g, xOffset, yOffset) {
  159. var rect = g.append("rect")
  160. .attr("y", yOffset)
  161. .attr("x", xOffset)
  162. .attr("height", this.CELL_HEIGHT)
  163. .attr("fill", "grey")
  164. .attr("width", this.CELL_WIDTH)
  165. .style("opacity", 0.20);
  166. },
  167. draw: function() {
  168. this.initChart(true);
  169. this.renderCells(this.get("model"), this.get("title"), this.get("textWidth"));
  170. },
  171. didInsertElement: function () {
  172. this.draw();
  173. },
  174. actions: {
  175. applyFilter: function(event) {
  176. this.filter = event.srcElement.value;
  177. this.didInsertElement();
  178. }
  179. }
  180. })