color roofline plot, add option to match pie and table color for ndoestate

This commit is contained in:
Christoph Kluge
2025-12-11 18:51:19 +01:00
parent 4083de2a51
commit 6e385db378
6 changed files with 304 additions and 129 deletions

View File

@@ -82,7 +82,7 @@
} }
`, `,
variables: { variables: {
filter: { cluster: { eq: presetCluster }, timeStart: 1760096999}, // DEBUG VALUE, use StackedFrom filter: { cluster: { eq: presetCluster }, timeStart: stackedFrom}, // DEBUG VALUE 1760096999, use StackedFrom
typeNode: "node", typeNode: "node",
typeHealth: "health" typeHealth: "health"
}, },
@@ -97,6 +97,7 @@
query ( query (
$cluster: String! $cluster: String!
$metrics: [String!] $metrics: [String!]
# $nmetrics: [String!]
$from: Time! $from: Time!
$to: Time! $to: Time!
$clusterFrom: Time! $clusterFrom: Time!
@@ -183,7 +184,7 @@
totalCores totalCores
totalAccs totalAccs
} }
# TEST # ClusterMetrics for doubleMetricPlot
clusterMetrics( clusterMetrics(
cluster: $cluster cluster: $cluster
metrics: $metrics metrics: $metrics
@@ -205,7 +206,8 @@
`, `,
variables: { variables: {
cluster: presetCluster, cluster: presetCluster,
metrics: ["flops_any", "mem_bw"], // Fixed names for roofline and status bars metrics: ["flops_any", "mem_bw"], // Metrics For Cluster Plot and Roofline
// nmetrics: ["cpu_load", "acc_utilization"], // Metrics for Node Graph
from: from.toISOString(), from: from.toISOString(),
clusterFrom: clusterFrom.toISOString(), clusterFrom: clusterFrom.toISOString(),
to: to.toISOString(), to: to.toISOString(),
@@ -349,18 +351,18 @@
}); });
/* Functions */ /* Functions */
function legendColors(targetIdx, useAltColors) { // function legendColors(targetIdx, useAltColors) {
// Reuses first color if targetIdx overflows // // Reuses first color if targetIdx overflows
let c; // let c;
if (useCbColors) { // if (useCbColors) {
c = [...colors['colorblind']]; // c = [...colors['colorblind']];
} else if (useAltColors) { // } else if (useAltColors) {
c = [...colors['alternative']]; // c = [...colors['alternative']];
} else { // } else {
c = [...colors['default']]; // c = [...colors['default']];
} // }
return c[(c.length + targetIdx) % c.length]; // return c[(c.length + targetIdx) % c.length];
} // }
function transformNodesStatsToData(subclusterData) { function transformNodesStatsToData(subclusterData) {
let data = null let data = null
@@ -425,10 +427,10 @@
</script> </script>
<Card style="height: 98vh;"> <Card style="height: 98vh;">
<CardHeader class="text-center"> <!-- <CardHeader class="text-center">
<h3 class="mb-0">{presetCluster.charAt(0).toUpperCase() + presetCluster.slice(1)} Dashboard</h3> <h3 class="mb-0">{presetCluster.charAt(0).toUpperCase() + presetCluster.slice(1)} Dashboard</h3>
</CardHeader> </CardHeader> -->
<CardBody> <CardBody class="align-content-center">
{#if $statusQuery.fetching || $statesTimed.fetching || $topJobsQuery.fetching || $nodeStatusQuery.fetching} {#if $statusQuery.fetching || $statesTimed.fetching || $topJobsQuery.fetching || $nodeStatusQuery.fetching}
<Row class="justify-content-center"> <Row class="justify-content-center">
<Col xs="auto"> <Col xs="auto">
@@ -461,13 +463,24 @@
</Row> </Row>
{:else} {:else}
<Row cols={{xs:1, md:2, xl: 3}}> <Row cols={{xs:1, md:2}}>
<Col> <!-- Info Card --> <Col> <!-- General Cluster Info Card -->
<Card class="h-auto mt-1"> <Card class="h-100">
<CardHeader> <CardHeader class="text-center">
<h2 class="mb-0">Cluster {presetCluster.charAt(0).toUpperCase() + presetCluster.slice(1)}</h2>
</CardHeader>
<CardBody>
<h4>CPU(s)</h4><p><strong>{[...clusterInfo?.processorTypes].join(', ')}</strong></p>
</CardBody>
</Card>
</Col>
<Col> <!-- Utilization Info Card -->
<Card class="h-100">
<!-- <CardHeader>
<CardTitle class="mb-0">Cluster "{presetCluster.charAt(0).toUpperCase() + presetCluster.slice(1)}"</CardTitle> <CardTitle class="mb-0">Cluster "{presetCluster.charAt(0).toUpperCase() + presetCluster.slice(1)}"</CardTitle>
<span>{[...clusterInfo?.processorTypes].toString()}</span> <span>{[...clusterInfo?.processorTypes].toString()}</span>
</CardHeader> </CardHeader> -->
<CardBody> <CardBody>
<Table borderless> <Table borderless>
<tr class="py-2"> <tr class="py-2">
@@ -545,77 +558,7 @@
</CardBody> </CardBody>
</Card> </Card>
</Col> </Col>
<Col> <!-- Pie Last States -->
<Row>
<Col class="px-3 mt-2 mt-lg-0">
<div bind:clientWidth={colWidthStates}>
{#key refinedStateData}
<h4 class="text-center">
Current Node States
</h4>
<Pie
useAltColors
canvasId="hpcpie-slurm"
size={colWidthStates * 0.75}
sliceLabel="Nodes"
quantities={refinedStateData.map(
(sd) => sd.count,
)}
entities={refinedStateData.map(
(sd) => sd.state,
)}
/>
{/key}
</div>
</Col>
<Col class="px-4 py-2">
{#key refinedStateData}
<Table>
<tr class="mb-2">
<th></th>
<th>Current State</th>
<th>Nodes</th>
</tr>
{#each refinedStateData as sd, i}
<tr>
<td><Icon name="circle-fill" style="color: {legendColors(i, true)};"/></td>
<td>{sd.state}</td>
<td>{sd.count}</td>
</tr>
{/each}
</Table>
{/key}
</Col>
</Row>
</Col>
<Col> <!-- General Cluster Info Card? -->
<!-- TODO -->
<Card>
<CardHeader>
<CardTitle>Infos</CardTitle>
</CardHeader>
<CardBody>
Contents
</CardBody>
</Card>
</Col>
<Col> <!-- Nodes Roofline -->
<div bind:clientWidth={colWidthRoof}>
{#key $statusQuery?.data?.nodeMetrics}
<Roofline
useColors={false}
useLegend={false}
allowSizeChange
width={colWidthRoof - 10}
height={300}
cluster={presetCluster}
subCluster={clusterInfo?.roofData ? clusterInfo.roofData : null}
roofData={transformNodesStatsToData($statusQuery?.data?.nodeMetrics)}
nodesData={transformNodesStatsToInfo($statusQuery?.data?.nodeMetrics)}
/>
{/key}
</div>
</Col>
<Col> <!-- Resources/Job Histogram OR Total Cluster Metric in Time SUMS--> <Col> <!-- Resources/Job Histogram OR Total Cluster Metric in Time SUMS-->
<div bind:clientWidth={colWidthTotals}> <div bind:clientWidth={colWidthTotals}>
<DoubleMetric <DoubleMetric
@@ -624,6 +567,7 @@
numNodes={$statusQuery?.data?.clusterMetrics?.nodeCount || 0} numNodes={$statusQuery?.data?.clusterMetrics?.nodeCount || 0}
metricData={$statusQuery?.data?.clusterMetrics?.metrics || []} metricData={$statusQuery?.data?.clusterMetrics?.metrics || []}
cluster={presetCluster} cluster={presetCluster}
fixLinewidth={2}
/> />
</div> </div>
<!-- {#if clusterInfo?.totalAccs == 0} <!-- {#if clusterInfo?.totalAccs == 0}
@@ -650,6 +594,73 @@
/> />
{/if} --> {/if} -->
</Col> </Col>
<Col> <!-- Nodes Roofline -->
<div bind:clientWidth={colWidthRoof}>
{#key $statusQuery?.data?.nodeMetrics}
<Roofline
colorBackground
useColors={false}
useLegend={false}
allowSizeChange
width={colWidthRoof - 10}
height={300}
cluster={presetCluster}
subCluster={clusterInfo?.roofData ? clusterInfo.roofData : null}
roofData={transformNodesStatsToData($statusQuery?.data?.nodeMetrics)}
nodesData={transformNodesStatsToInfo($statusQuery?.data?.nodeMetrics)}
fixTitle="Node Utilization"
yMinimum={1.0}
/>
{/key}
</div>
</Col>
<Col> <!-- Pie Last States -->
<Row>
<Col class="px-3 mt-2 mt-lg-0">
<div bind:clientWidth={colWidthStates}>
{#key refinedStateData}
<!-- <h4 class="text-center">
Cluster Status
</h4> -->
<Pie
canvasId="hpcpie-slurm"
size={colWidthStates * 0.66}
sliceLabel="Nodes"
quantities={refinedStateData.map(
(sd) => sd.count,
)}
entities={refinedStateData.map(
(sd) => sd.state,
)}
fixColors={refinedStateData.map(
(sd) => colors['nodeStates'][sd.state],
)}
/>
{/key}
</div>
</Col>
<Col class="px-4 py-2">
{#key refinedStateData}
<Table>
<tr class="mb-2">
<th></th>
<th class="h4">State</th>
<th class="h4">Count</th>
</tr>
{#each refinedStateData as sd, i}
<tr>
<td><Icon name="circle-fill" style="color: {colors['nodeStates'][sd.state]}; font-size: 30px;"/></td>
<td class="h5">{sd.state.charAt(0).toUpperCase() + sd.state.slice(1)}</td>
<td class="h5">{sd.count}</td>
</tr>
{/each}
</Table>
{/key}
</Col>
</Row>
</Col>
<Col> <!-- Stacked SchedState --> <Col> <!-- Stacked SchedState -->
<div bind:clientWidth={colWidthStacked}> <div bind:clientWidth={colWidthStacked}>
{#key $statesTimed?.data?.nodeStates} {#key $statesTimed?.data?.nodeStates}
@@ -659,7 +670,7 @@
xlabel="Time" xlabel="Time"
ylabel="Nodes" ylabel="Nodes"
yunit = "#Count" yunit = "#Count"
title = "Node States" title = "Cluster Status"
stateType = "Node" stateType = "Node"
/> />
{/key} {/key}

View File

@@ -33,6 +33,7 @@
// metric, // metric,
width = 0, width = 0,
height = 300, height = 300,
fixLinewidth = null,
timestep, timestep,
numNodes, numNodes,
metricData, metricData,
@@ -52,7 +53,7 @@
// const subClusterTopology = getContext("getHardwareTopology")(cluster, subCluster); // const subClusterTopology = getContext("getHardwareTopology")(cluster, subCluster);
// const metricConfig = getContext("getMetricConfig")(cluster, subCluster, metric); // const metricConfig = getContext("getMetricConfig")(cluster, subCluster, metric);
const lineColors = clusterCockpitConfig.plotConfiguration_colorScheme; const lineColors = clusterCockpitConfig.plotConfiguration_colorScheme;
const lineWidth = clusterCockpitConfig.plotConfiguration_lineWidth / window.devicePixelRatio; const lineWidth = fixLinewidth ? fixLinewidth : clusterCockpitConfig.plotConfiguration_lineWidth / window.devicePixelRatio;
// const cbmode = clusterCockpitConfig?.plotConfiguration_colorblindMode || false; // const cbmode = clusterCockpitConfig?.plotConfiguration_colorblindMode || false;
const renderSleepTime = 200; const renderSleepTime = 200;
// const normalLineColor = "#000000"; // const normalLineColor = "#000000";
@@ -444,6 +445,7 @@
const opts = { const opts = {
width, width,
height, height,
title: 'Cluster Utilization',
plugins: [legendAsTooltipPlugin()], plugins: [legendAsTooltipPlugin()],
series: plotSeries, series: plotSeries,
axes: [ axes: [

View File

@@ -59,7 +59,15 @@
'rgb(135,133,0)', 'rgb(135,133,0)',
'rgb(0,167,108)', 'rgb(0,167,108)',
'rgb(189,189,189)', 'rgb(189,189,189)',
] ],
nodeStates: {
allocated: "rgba(0, 128, 0, 0.75)",
down: "rgba(255, 0, 0, 0.75)",
idle: "rgba(0, 0, 255, 0.75)",
reserved: "rgba(255, 0, 255, 0.75)",
mixed: "rgba(255, 215, 0, 0.75)",
unknown: "rgba(0, 0, 0, 0.75)"
}
} }
</script> </script>
@@ -77,6 +85,7 @@
entities, entities,
displayLegend = false, displayLegend = false,
useAltColors = false, useAltColors = false,
fixColors = null
} = $props(); } = $props();
/* Const Init */ /* Const Init */
@@ -98,6 +107,8 @@
c = [...colors['colorblind']]; c = [...colors['colorblind']];
} else if (useAltColors) { } else if (useAltColors) {
c = [...colors['alternative']]; c = [...colors['alternative']];
} else if (fixColors?.length > 0) {
c = [...fixColors];
} else { } else {
c = [...colors['default']]; c = [...colors['default']];
} }

View File

@@ -34,15 +34,18 @@
nodesData = null, nodesData = null,
cluster = null, cluster = null,
subCluster = null, subCluster = null,
fixTitle = null,
yMinimum = null,
allowSizeChange = false, allowSizeChange = false,
useColors = true, useColors = true,
useLegend = true, useLegend = true,
colorBackground = false,
width = 600, width = 600,
height = 380, height = 380,
} = $props(); } = $props();
/* Const Init */ /* Const Init */
const lineWidth = clusterCockpitConfig.plotConfiguration_lineWidth; const lineWidth = 2 // clusterCockpitConfig.plotConfiguration_lineWidth;
const cbmode = clusterCockpitConfig?.plotConfiguration_colorblindMode || false; const cbmode = clusterCockpitConfig?.plotConfiguration_colorblindMode || false;
/* Var Init */ /* Var Init */
@@ -294,7 +297,7 @@
} else { } else {
// No Colors: Use Black // No Colors: Use Black
u.ctx.strokeStyle = "rgb(0, 0, 0)"; u.ctx.strokeStyle = "rgb(0, 0, 0)";
u.ctx.fillStyle = "rgba(0, 0, 0, 0.5)"; u.ctx.fillStyle = colorBackground ? "rgb(0, 0, 0)" : "rgba(0, 0, 0, 0.5)";
} }
// Get Values // Get Values
@@ -527,6 +530,7 @@
let plotTitle = "CPU Roofline Diagram"; let plotTitle = "CPU Roofline Diagram";
if (jobsData) plotTitle = "Job Average Roofline Diagram"; if (jobsData) plotTitle = "Job Average Roofline Diagram";
if (nodesData) plotTitle = "Node Average Roofline Diagram"; if (nodesData) plotTitle = "Node Average Roofline Diagram";
if (fixTitle) plotTitle = fixTitle
if (roofData) { if (roofData) {
const opts = { const opts = {
@@ -617,7 +621,7 @@
}, },
y: { y: {
range: [ range: [
0.01, yMinimum ? yMinimum : 0.01,
subCluster?.flopRateSimd?.value subCluster?.flopRateSimd?.value
? nearestThousand(subCluster.flopRateSimd.value) ? nearestThousand(subCluster.flopRateSimd.value)
: 10000, : 10000,
@@ -669,6 +673,7 @@
u.ctx.lineWidth = lineWidth; u.ctx.lineWidth = lineWidth;
u.ctx.beginPath(); u.ctx.beginPath();
// Get Values
const ycut = 0.01 * subCluster.memoryBandwidth.value; const ycut = 0.01 * subCluster.memoryBandwidth.value;
const scalarKnee = const scalarKnee =
(subCluster.flopRateScalar.value - ycut) / (subCluster.flopRateScalar.value - ycut) /
@@ -676,19 +681,27 @@
const simdKnee = const simdKnee =
(subCluster.flopRateSimd.value - ycut) / (subCluster.flopRateSimd.value - ycut) /
subCluster.memoryBandwidth.value; subCluster.memoryBandwidth.value;
const scalarKneeX = u.valToPos(scalarKnee, "x", true), // Value, axis, toCanvasPixels
simdKneeX = u.valToPos(simdKnee, "x", true),
flopRateScalarY = u.valToPos(
subCluster.flopRateScalar.value,
"y",
true,
),
flopRateSimdY = u.valToPos(
subCluster.flopRateSimd.value,
"y",
true,
);
// Get Const Coords
const originX = u.valToPos(0.01, "x", true);
const originY = u.valToPos(yMinimum ? yMinimum : 0.01, "y", true);
const outerX = u.valToPos(1000, "x", true); // rightmost x in plot coords
const outerY = u.valToPos(
subCluster?.flopRateSimd?.value
? nearestThousand(subCluster.flopRateSimd.value)
: 10000,
"y",
true
);
const scalarKneeX = u.valToPos(scalarKnee, "x", true) // Value, axis, toCanvasPixels
const simdKneeX = u.valToPos(simdKnee, "x", true)
const flopRateScalarY = u.valToPos(subCluster.flopRateScalar.value, "y", true)
const flopRateSimdY = u.valToPos(subCluster.flopRateSimd.value, "y", true);
/* Render Lines */
if ( if (
scalarKneeX < scalarKneeX <
width * window.devicePixelRatio - width * window.devicePixelRatio -
@@ -728,10 +741,10 @@
y1, y1,
x2, x2,
y2, y2,
u.valToPos(0.01, "x", true), originX, // x3; X-Axis Start Coord-X
u.valToPos(1.0, "y", true), // X-Axis Start Coords originY, // y3; X-Axis Start Coord-Y
u.valToPos(1000, "x", true), outerX, // x4; X-Axis End Coord-X
u.valToPos(1.0, "y", true), // X-Axis End Coords originY, // y4; X-Axis End Coord-Y
); );
if (xAxisIntersect.x > x1) { if (xAxisIntersect.x > x1) {
@@ -746,6 +759,144 @@
u.ctx.stroke(); u.ctx.stroke();
// Reset grid lineWidth // Reset grid lineWidth
u.ctx.lineWidth = 0.15; u.ctx.lineWidth = 0.15;
/* Render Area */
if (colorBackground) {
u.ctx.beginPath();
// Additional Coords for Colored Regions
const yhalf = u.valToPos(ycut/2, "y", true)
const simdShift = u.valToPos(simdKnee*1.75, "x", true)
let upperBorderIntersect = lineIntersect(
x1,
y1,
x2,
y2,
originX, // x3; X-Axis Start Coord-X
flopRateSimdY*1.667, // y3; X-Axis Start Coord-Y
outerX, // x4; X-Axis End Coord-X
flopRateSimdY*1.667, // y4; X-Axis End Coord-Y
);
let lowerBorderIntersect = lineIntersect(
x1,
y1,
x2,
y2,
originX, // x3; X-Axis Start Coord-X
flopRateScalarY*1.1667, // y3; X-Axis Start Coord-Y
outerX, // x4; X-Axis End Coord-X
flopRateScalarY*1.1667, // y4; X-Axis End Coord-Y
);
let helperUpperBorderIntersect = lineIntersect(
x1,
yhalf,
simdShift,
y2,
originX, // x3; X-Axis Start Coord-X
flopRateSimdY*1.667, // y3; X-Axis Start Coord-Y
outerX, // x4; X-Axis End Coord-X
flopRateSimdY*1.667, // y4; X-Axis End Coord-Y
);
let helperLowerBorderIntersect = lineIntersect(
x1,
yhalf,
simdShift,
y2,
originX, // x3; X-Axis Start Coord-X
flopRateScalarY*1.1667, // y3; X-Axis Start Coord-Y
outerX, // x4; X-Axis End Coord-X
flopRateScalarY*1.1667, // y4; X-Axis End Coord-Y
);
let helperLowerBorderIntersectTop = lineIntersect(
x1,
yhalf,
simdShift,
y2,
scalarKneeX, // x3; X-Axis Start Coord-X
flopRateScalarY, // y3; X-Axis Start Coord-Y
outerX, // x4; X-Axis End Coord-X
flopRateScalarY, // y4; X-Axis End Coord-Y
);
// Diagonal Helper
u.ctx.moveTo(x1, yhalf);
u.ctx.lineTo(simdShift, y2);
// Upper Simd Helper
u.ctx.moveTo(upperBorderIntersect.x, flopRateSimdY*1.667);
u.ctx.lineTo(outerX, flopRateSimdY*1.667);
// Lower Scalar Helper
u.ctx.moveTo(lowerBorderIntersect.x, flopRateScalarY*1.1667);
u.ctx.lineTo(outerX, flopRateScalarY*1.1667);
u.ctx.stroke();
/* Color Regions */
// MemoryBound
u.ctx.save();
u.ctx.beginPath();
u.ctx.lineTo(x1, y1); // YCut
u.ctx.lineTo(x2, y2); // Upper Knee
u.ctx.lineTo(simdShift, y2); // Upper Helper Knee
u.ctx.lineTo(x1, yhalf); // Half yCut
u.ctx.closePath();
u.ctx.fillStyle = "rgba(255, 200, 0, 0.4)"; // Yellow
u.ctx.fill();
u.ctx.restore();
// Compute Lower
u.ctx.save();
u.ctx.beginPath();
u.ctx.moveTo(lowerBorderIntersect.x, flopRateScalarY*1.1667); // Lower Helper Knee
u.ctx.lineTo(scalarKneeX, flopRateScalarY); // Lower Knee
u.ctx.lineTo(outerX, flopRateScalarY); // Outer Border
u.ctx.lineTo(outerX, flopRateScalarY*1.1667); // Outer Lower Helper Border
u.ctx.closePath();
u.ctx.fillStyle = "rgba(0, 180, 255, 0.4)"; // Cyan Blue
u.ctx.fill();
u.ctx.restore();
// Compute Upper
u.ctx.save();
u.ctx.beginPath();
u.ctx.moveTo(upperBorderIntersect.x, flopRateSimdY*1.667); // Upper Helper Knee
u.ctx.lineTo(simdKneeX, flopRateSimdY); // Upper Knee
u.ctx.lineTo(outerX, flopRateSimdY); // Outer Border
u.ctx.lineTo(outerX, flopRateSimdY*1.667); // Outer Upper Helper Border
u.ctx.closePath();
u.ctx.fillStyle = "rgba(0, 180, 255, 0.4)"; // Cyan Blue
u.ctx.fill();
u.ctx.restore();
// Nomansland Lower
u.ctx.save();
u.ctx.beginPath();
u.ctx.moveTo(originX, originY); // Origin
u.ctx.lineTo(originX, yhalf); // YCut Half
u.ctx.lineTo(helperLowerBorderIntersect.x, flopRateScalarY*1.1667); // Lower Inner Helper Knee
u.ctx.lineTo(outerX, flopRateScalarY*1.1667); // Lower Inner Border
u.ctx.lineTo(outerX, originY); // Lower Right Corner
u.ctx.closePath();
u.ctx.fillStyle = "rgba(255, 50, 50, 0.1)"; // Red Light
u.ctx.fill();
u.ctx.restore();
// Nomansland Upper
u.ctx.save();
u.ctx.beginPath();
u.ctx.moveTo(helperLowerBorderIntersectTop.x, flopRateScalarY); // Lower Knee Top
u.ctx.lineTo(helperUpperBorderIntersect.x, flopRateSimdY*1.667); // Upper Helper Knee
u.ctx.lineTo(outerX, flopRateSimdY*1.667); // Upper Inner Border
u.ctx.lineTo(outerX, flopRateScalarY); // Lower Knee Border
u.ctx.closePath();
u.ctx.fillStyle = "rgba(255, 50, 50, 0.1)"; // Red Light
u.ctx.fill();
u.ctx.restore();
}
} }
/* Render Scales */ /* Render Scales */

View File

@@ -315,10 +315,10 @@
y1, y1,
x2, x2,
y2, y2,
u.valToPos(0.01, "x", true), u.valToPos(0.01, "x", true), // x3; X-Axis Start Coord-X
u.valToPos(1.0, "y", true), // X-Axis Start Coords u.valToPos(1.0, "y", true), // y3; X-Axis Start Coord-Y
u.valToPos(1000, "x", true), u.valToPos(1000, "x", true), // x4; X-Axis End Coord-X
u.valToPos(1.0, "y", true), // X-Axis End Coords u.valToPos(1.0, "y", true), // y4; X-Axis End Coord-Y
); );
if (xAxisIntersect.x > x1) { if (xAxisIntersect.x > x1) {

View File

@@ -39,63 +39,63 @@
label: "Full", label: "Full",
scale: "y", scale: "y",
width: lineWidth, width: lineWidth,
fill: cbmode ? "rgba(0, 110, 0, 0.4)" : "rgba(0, 128, 0, 0.4)", fill: cbmode ? "rgba(0, 110, 0, 0.6)" : "rgba(0, 128, 0, 0.6)",
stroke: cbmode ? "rgb(0, 110, 0)" : "green", stroke: cbmode ? "rgb(0, 110, 0)" : "green",
}, },
partial: { partial: {
label: "Partial", label: "Partial",
scale: "y", scale: "y",
width: lineWidth, width: lineWidth,
fill: cbmode ? "rgba(235, 172, 35, 0.4)" : "rgba(255, 215, 0, 0.4)", fill: cbmode ? "rgba(235, 172, 35, 0.6)" : "rgba(255, 215, 0, 0.6)",
stroke: cbmode ? "rgb(235, 172, 35)" : "gold", stroke: cbmode ? "rgb(235, 172, 35)" : "gold",
}, },
failed: { failed: {
label: "Failed", label: "Failed",
scale: "y", scale: "y",
width: lineWidth, width: lineWidth,
fill: cbmode ? "rgb(181, 29, 20, 0.4)" : "rgba(255, 0, 0, 0.4)", fill: cbmode ? "rgb(181, 29, 20, 0.6)" : "rgba(255, 0, 0, 0.6)",
stroke: cbmode ? "rgb(181, 29, 20)" : "red", stroke: cbmode ? "rgb(181, 29, 20)" : "red",
}, },
idle: { idle: {
label: "Idle", label: "Idle",
scale: "y", scale: "y",
width: lineWidth, width: lineWidth,
fill: cbmode ? "rgba(0, 140, 249, 0.4)" : "rgba(0, 0, 255, 0.4)", fill: cbmode ? "rgba(0, 140, 249, 0.6)" : "rgba(0, 0, 255, 0.6)",
stroke: cbmode ? "rgb(0, 140, 249)" : "blue", stroke: cbmode ? "rgb(0, 140, 249)" : "blue",
}, },
allocated: { allocated: {
label: "Allocated", label: "Allocated",
scale: "y", scale: "y",
width: lineWidth, width: lineWidth,
fill: cbmode ? "rgba(0, 110, 0, 0.4)" : "rgba(0, 128, 0, 0.4)", fill: cbmode ? "rgba(0, 110, 0, 0.6)" : "rgba(0, 128, 0, 0.6)",
stroke: cbmode ? "rgb(0, 110, 0)" : "green", stroke: cbmode ? "rgb(0, 110, 0)" : "green",
}, },
reserved: { reserved: {
label: "Reserved", label: "Reserved",
scale: "y", scale: "y",
width: lineWidth, width: lineWidth,
fill: cbmode ? "rgba(209, 99, 230, 0.4)" : "rgba(255, 0, 255, 0.4)", fill: cbmode ? "rgba(209, 99, 230, 0.6)" : "rgba(255, 0, 255, 0.6)",
stroke: cbmode ? "rgb(209, 99, 230)" : "magenta", stroke: cbmode ? "rgb(209, 99, 230)" : "magenta",
}, },
mixed: { mixed: {
label: "Mixed", label: "Mixed",
scale: "y", scale: "y",
width: lineWidth, width: lineWidth,
fill: cbmode ? "rgba(235, 172, 35, 0.4)" : "rgba(255, 215, 0, 0.4)", fill: cbmode ? "rgba(235, 172, 35, 0.6)" : "rgba(255, 215, 0, 0.6)",
stroke: cbmode ? "rgb(235, 172, 35)" : "gold", stroke: cbmode ? "rgb(235, 172, 35)" : "gold",
}, },
down: { down: {
label: "Down", label: "Down",
scale: "y", scale: "y",
width: lineWidth, width: lineWidth,
fill: cbmode ? "rgba(181, 29 ,20, 0.4)" : "rgba(255, 0, 0, 0.4)", fill: cbmode ? "rgba(181, 29 ,20, 0.6)" : "rgba(255, 0, 0, 0.6)",
stroke: cbmode ? "rgb(181, 29, 20)" : "red", stroke: cbmode ? "rgb(181, 29, 20)" : "red",
}, },
unknown: { unknown: {
label: "Unknown", label: "Unknown",
scale: "y", scale: "y",
width: lineWidth, width: lineWidth,
fill: "rgba(0, 0, 0, 0.4)", fill: "rgba(0, 0, 0, 0.6)",
stroke: "black", stroke: "black",
} }
}; };