github.com/Ilhicas/nomad@v1.0.4-0.20210304152020-e86851182bc3/ui/app/components/topo-viz/node.js (about) 1 import Component from '@glimmer/component'; 2 import { tracked } from '@glimmer/tracking'; 3 import { action } from '@ember/object'; 4 import { guidFor } from '@ember/object/internals'; 5 6 export default class TopoVizNode extends Component { 7 @tracked data = { cpu: [], memory: [] }; 8 @tracked dimensionsWidth = 0; 9 @tracked padding = 5; 10 @tracked activeAllocation = null; 11 12 get height() { 13 return this.args.heightScale ? this.args.heightScale(this.args.node.memory) : 15; 14 } 15 16 get labelHeight() { 17 return this.height / 2; 18 } 19 20 get paddingLeft() { 21 const labelWidth = 20; 22 return this.padding + labelWidth; 23 } 24 25 // Since strokes are placed centered on the perimeter of fills, The width of the stroke needs to be removed from 26 // the height of the fill to match unstroked height and avoid clipping. 27 get selectedHeight() { 28 return this.height - 1; 29 } 30 31 // Since strokes are placed centered on the perimeter of fills, half the width of the stroke needs to be added to 32 // the yOffset to match heights with unstroked shapes. 33 get selectedYOffset() { 34 return this.height + 2.5; 35 } 36 37 get yOffset() { 38 return this.height + 2; 39 } 40 41 get maskHeight() { 42 return this.height + this.yOffset; 43 } 44 45 get totalHeight() { 46 return this.maskHeight + this.padding * 2; 47 } 48 49 get maskId() { 50 return `topo-viz-node-mask-${guidFor(this)}`; 51 } 52 53 get count() { 54 return this.allocations.length; 55 } 56 57 get allocations() { 58 // Sort by the delta between memory and cpu percent. This creates the least amount of 59 // drift between the positional alignment of an alloc's cpu and memory representations. 60 return this.args.node.allocations.filterBy('allocation.isScheduled').sort((a, b) => { 61 const deltaA = Math.abs(a.memoryPercent - a.cpuPercent); 62 const deltaB = Math.abs(b.memoryPercent - b.cpuPercent); 63 return deltaA - deltaB; 64 }); 65 } 66 67 @action 68 async reloadNode() { 69 if (this.args.node.isPartial) { 70 await this.args.node.reload(); 71 this.data = this.computeData(this.dimensionsWidth); 72 } 73 } 74 75 @action 76 render(svg) { 77 this.dimensionsWidth = svg.clientWidth - this.padding - this.paddingLeft; 78 this.data = this.computeData(this.dimensionsWidth); 79 } 80 81 @action 82 updateRender(svg) { 83 // Only update all data when the width changes 84 const newWidth = svg.clientWidth - this.padding - this.paddingLeft; 85 if (newWidth !== this.dimensionsWidth) { 86 this.dimensionsWidth = newWidth; 87 this.data = this.computeData(this.dimensionsWidth); 88 } 89 } 90 91 @action 92 highlightAllocation(allocation, { target }) { 93 this.activeAllocation = allocation; 94 this.args.onAllocationFocus && this.args.onAllocationFocus(allocation, target); 95 } 96 97 @action 98 allocationBlur() { 99 this.args.onAllocationBlur && this.args.onAllocationBlur(); 100 } 101 102 @action 103 clearHighlight() { 104 this.activeAllocation = null; 105 } 106 107 @action 108 selectNode() { 109 if (this.args.isDense && this.args.onNodeSelect) { 110 this.args.onNodeSelect(this.args.node.isSelected ? null : this.args.node); 111 } 112 } 113 114 @action 115 selectAllocation(allocation) { 116 if (this.args.onAllocationSelect) this.args.onAllocationSelect(allocation); 117 } 118 119 containsActiveTaskGroup() { 120 return this.args.node.allocations.some( 121 allocation => 122 allocation.taskGroupName === this.args.activeTaskGroup && 123 allocation.belongsTo('job').id() === this.args.activeJobId 124 ); 125 } 126 127 computeData(width) { 128 const allocations = this.allocations; 129 let cpuOffset = 0; 130 let memoryOffset = 0; 131 132 const cpu = []; 133 const memory = []; 134 for (const allocation of allocations) { 135 const { cpuPercent, memoryPercent, isSelected } = allocation; 136 const isFirst = allocation === allocations[0]; 137 138 let cpuWidth = cpuPercent * width - 1; 139 let memoryWidth = memoryPercent * width - 1; 140 if (isFirst) { 141 cpuWidth += 0.5; 142 memoryWidth += 0.5; 143 } 144 if (isSelected) { 145 cpuWidth--; 146 memoryWidth--; 147 } 148 149 cpu.push({ 150 allocation, 151 offset: cpuOffset * 100, 152 percent: cpuPercent * 100, 153 width: Math.max(cpuWidth, 0), 154 x: cpuOffset * width + (isFirst ? 0 : 0.5) + (isSelected ? 0.5 : 0), 155 className: allocation.allocation.clientStatus, 156 }); 157 memory.push({ 158 allocation, 159 offset: memoryOffset * 100, 160 percent: memoryPercent * 100, 161 width: Math.max(memoryWidth, 0), 162 x: memoryOffset * width + (isFirst ? 0 : 0.5) + (isSelected ? 0.5 : 0), 163 className: allocation.allocation.clientStatus, 164 }); 165 166 cpuOffset += cpuPercent; 167 memoryOffset += memoryPercent; 168 } 169 170 const cpuRemainder = { 171 x: cpuOffset * width + 0.5, 172 width: Math.max(width - cpuOffset * width, 0), 173 }; 174 const memoryRemainder = { 175 x: memoryOffset * width + 0.5, 176 width: Math.max(width - memoryOffset * width, 0), 177 }; 178 179 return { 180 cpu, 181 memory, 182 cpuRemainder, 183 memoryRemainder, 184 cpuLabel: { x: -this.paddingLeft / 2, y: this.height / 2 + this.yOffset }, 185 memoryLabel: { x: -this.paddingLeft / 2, y: this.height / 2 }, 186 }; 187 } 188 }