summaryrefslogtreecommitdiff
path: root/src/scripts/controllers/simulation/chart.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/scripts/controllers/simulation/chart.ts')
-rw-r--r--src/scripts/controllers/simulation/chart.ts241
1 files changed, 241 insertions, 0 deletions
diff --git a/src/scripts/controllers/simulation/chart.ts b/src/scripts/controllers/simulation/chart.ts
new file mode 100644
index 00000000..84009622
--- /dev/null
+++ b/src/scripts/controllers/simulation/chart.ts
@@ -0,0 +1,241 @@
+import * as c3 from "c3";
+import {InteractionLevel, MapController} from "../mapcontroller";
+import {ColorRepresentation, SimulationController} from "../simulationcontroller";
+import {Util} from "../../util";
+
+
+export interface IStateColumn {
+ loadFractions: string[] | number[];
+ inUseMemoryMb: string[] | number[];
+ temperatureC: string[] | number[];
+}
+
+
+export class ChartController {
+ public roomSeries: { [key: number]: IStateColumn };
+ public rackSeries: { [key: number]: IStateColumn };
+ public machineSeries: { [key: number]: IStateColumn };
+ public chart: c3.ChartAPI;
+ public machineChart: c3.ChartAPI;
+
+ private simulationController: SimulationController;
+ private mapController: MapController;
+ private chartData: (string | number)[][];
+ private xSeries: (string | number)[];
+ private names: { [key: string]: string };
+
+
+ constructor(simulationController: SimulationController) {
+ this.simulationController = simulationController;
+ this.mapController = simulationController.mapController;
+ }
+
+ public setup(): void {
+ this.names = {};
+
+ this.roomSeries = {};
+ this.rackSeries = {};
+ this.machineSeries = {};
+
+ this.simulationController.sections.forEach((simulationSection: ISection) => {
+ simulationSection.datacenter.rooms.forEach((room: IRoom) => {
+ if (room.roomType === "SERVER" && this.roomSeries[room.id] === undefined) {
+ this.names["ro" + room.id] = (room.name === "" || room.name === undefined) ?
+ "Unnamed room" : room.name;
+
+ this.roomSeries[room.id] = {
+ loadFractions: ["ro" + room.id],
+ inUseMemoryMb: ["ro" + room.id],
+ temperatureC: ["ro" + room.id]
+ };
+ }
+
+ room.tiles.forEach((tile: ITile) => {
+ if (tile.object !== undefined && tile.objectType === "RACK" && this.rackSeries[tile.objectId] === undefined) {
+ let objectName = (<IRack>tile.object).name;
+ this.names["ra" + tile.objectId] = objectName === "" || objectName === undefined ?
+ "Unnamed rack" : objectName;
+
+ this.rackSeries[tile.objectId] = {
+ loadFractions: ["ra" + tile.objectId],
+ inUseMemoryMb: ["ra" + tile.objectId],
+ temperatureC: ["ra" + tile.objectId]
+ };
+
+ (<IRack>tile.object).machines.forEach((machine: IMachine) => {
+ if (machine === null || this.machineSeries[machine.id] !== undefined) {
+ return;
+ }
+
+ this.names["ma" + machine.id] = "Machine at position " + (machine.position + 1).toString();
+
+ this.machineSeries[machine.id] = {
+ loadFractions: ["ma" + machine.id],
+ inUseMemoryMb: ["ma" + machine.id],
+ temperatureC: ["ma" + machine.id]
+ };
+ });
+ }
+ });
+ });
+ });
+
+
+ this.xSeries = ["time"];
+ this.chartData = [this.xSeries];
+
+ this.chart = this.chartSetup("#statistics-chart");
+ this.machineChart = this.chartSetup("#machine-statistics-chart");
+ }
+
+ public chartSetup(chartId: string): c3.ChartAPI {
+ return c3.generate({
+ bindto: chartId,
+ data: {
+ xFormat: '%S',
+ x: "time",
+ columns: this.chartData,
+ names: this.names
+ },
+ axis: {
+ x: {
+ type: "timeseries",
+ tick: {
+ format: function (time: Date) {
+ let formattedTime = time.getSeconds() + "s";
+
+ if (time.getMinutes() > 0) {
+ formattedTime = time.getMinutes() + "m" + formattedTime;
+ }
+ if (time.getHours() > 0) {
+ formattedTime = time.getHours() + "h" + formattedTime;
+ }
+
+ return formattedTime;
+ },
+ culling: {
+ max: 5
+ },
+ count: 8
+ },
+ padding: {
+ left: 0,
+ right: 10
+ }
+ },
+ y: {
+ min: 0,
+ max: 1,
+ padding: {
+ top: 0,
+ bottom: 0
+ },
+ tick: {
+ format: function (d) {
+ return (Math.round(d * 100) / 100).toString();
+ }
+ }
+ }
+ }
+ });
+ }
+
+ public update(): void {
+ this.xSeries = (<(number|string)[]>["time"]).concat(Util.range(this.simulationController.currentTick));
+
+ this.chartData = [this.xSeries];
+
+ let prefix = "";
+ let machineId = -1;
+ if (this.mapController.interactionLevel === InteractionLevel.BUILDING) {
+ for (let roomId in this.roomSeries) {
+ if (this.roomSeries.hasOwnProperty(roomId)) {
+ if (this.simulationController.colorRepresentation === ColorRepresentation.LOAD) {
+ this.chartData.push(this.roomSeries[roomId].loadFractions);
+ }
+ }
+ }
+ prefix = "ro";
+ } else if (this.mapController.interactionLevel === InteractionLevel.ROOM) {
+ for (let rackId in this.rackSeries) {
+ if (this.rackSeries.hasOwnProperty(rackId) &&
+ this.simulationController.rackToRoomMap[rackId] ===
+ this.mapController.roomModeController.currentRoom.id) {
+ if (this.simulationController.colorRepresentation === ColorRepresentation.LOAD) {
+ this.chartData.push(this.rackSeries[rackId].loadFractions);
+ }
+ }
+ }
+ prefix = "ra";
+ } else if (this.mapController.interactionLevel === InteractionLevel.NODE) {
+ if (this.simulationController.colorRepresentation === ColorRepresentation.LOAD) {
+ this.chartData.push(
+ this.machineSeries[this.mapController.nodeModeController.currentMachine.id].loadFractions
+ );
+ }
+ prefix = "ma";
+ machineId = this.mapController.nodeModeController.currentMachine.id;
+ }
+
+ let unloads: string[] = [];
+ for (let id in this.names) {
+ if (this.names.hasOwnProperty(id)) {
+ if (machineId === -1) {
+ if (id.substr(0, 2) !== prefix ||
+ (this.mapController.interactionLevel === InteractionLevel.ROOM &&
+ this.simulationController.rackToRoomMap[parseInt(id.substr(2))] !==
+ this.mapController.roomModeController.currentRoom.id)) {
+ unloads.push(id);
+ }
+ }
+ else {
+ if (id !== prefix + machineId) {
+ unloads.push(id);
+ }
+ }
+ }
+ }
+
+ let targetChart: c3.ChartAPI;
+ if (this.mapController.interactionLevel === InteractionLevel.NODE) {
+ targetChart = this.machineChart;
+ } else {
+ targetChart = this.chart;
+ }
+
+ targetChart.load({
+ columns: this.chartData,
+ unload: unloads
+ });
+
+ }
+
+ public tickUpdated(tick: number): void {
+ let roomStates: IRoomState[] = this.simulationController.stateCache.stateList[tick].roomStates;
+ roomStates.forEach((roomState: IRoomState) => {
+ ChartController.insertAtIndex(this.roomSeries[roomState.roomId].loadFractions, tick + 1, roomState.loadFraction);
+ });
+
+ let rackStates: IRackState[] = this.simulationController.stateCache.stateList[tick].rackStates;
+ rackStates.forEach((rackState: IRackState) => {
+ ChartController.insertAtIndex(this.rackSeries[rackState.rackId].loadFractions, tick + 1, rackState.loadFraction);
+ });
+
+ let machineStates: IMachineState[] = this.simulationController.stateCache.stateList[tick].machineStates;
+ machineStates.forEach((machineState: IMachineState) => {
+ ChartController.insertAtIndex(this.machineSeries[machineState.machineId].loadFractions, tick + 1, machineState.loadFraction);
+ });
+ }
+
+ private static insertAtIndex(list: any[], index: number, data: any): void {
+ if (index > list.length) {
+ let i = list.length;
+ while (i < index) {
+ list[i] = null;
+ i++;
+ }
+ }
+
+ list[index] = data;
+ }
+} \ No newline at end of file