mirror of
https://github.com/ClusterCockpit/cc-backend
synced 2025-01-23 18:09:06 +01:00
add colorblind setting and friendly palettes
- mode applies to plot data, plot background color, statsseries colors, roofline timescale
This commit is contained in:
parent
42e8e37bd4
commit
736236e9ca
@ -18,6 +18,7 @@
|
|||||||
const ccconfig = getContext("cc-config");
|
const ccconfig = getContext("cc-config");
|
||||||
let message = { msg: "", target: "", color: "#d63384" };
|
let message = { msg: "", target: "", color: "#d63384" };
|
||||||
let displayMessage = false;
|
let displayMessage = false;
|
||||||
|
let cbmode = ccconfig?.plot_general_colorblindMode || false;
|
||||||
|
|
||||||
async function handleSettingSubmit(event) {
|
async function handleSettingSubmit(event) {
|
||||||
const selector = event.detail.selector
|
const selector = event.detail.selector
|
||||||
@ -28,6 +29,9 @@
|
|||||||
const res = await fetch(form.action, { method: "POST", body: formData });
|
const res = await fetch(form.action, { method: "POST", body: formData });
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
let text = await res.text();
|
let text = await res.text();
|
||||||
|
if (formData.get("key") === "plot_general_colorblindMode") {
|
||||||
|
cbmode = JSON.parse(formData.get("value"));
|
||||||
|
}
|
||||||
popMessage(text, target, "#048109");
|
popMessage(text, target, "#048109");
|
||||||
} else {
|
} else {
|
||||||
let text = await res.text();
|
let text = await res.text();
|
||||||
@ -51,4 +55,4 @@
|
|||||||
|
|
||||||
<UserOptions config={ccconfig} {username} {isApi} bind:message bind:displayMessage on:update-config={(e) => handleSettingSubmit(e)}/>
|
<UserOptions config={ccconfig} {username} {isApi} bind:message bind:displayMessage on:update-config={(e) => handleSettingSubmit(e)}/>
|
||||||
<PlotRenderOptions config={ccconfig} bind:message bind:displayMessage on:update-config={(e) => handleSettingSubmit(e)}/>
|
<PlotRenderOptions config={ccconfig} bind:message bind:displayMessage on:update-config={(e) => handleSettingSubmit(e)}/>
|
||||||
<PlotColorScheme config={ccconfig} bind:message bind:displayMessage on:update-config={(e) => handleSettingSubmit(e)}/>
|
<PlotColorScheme config={ccconfig} bind:cbmode bind:message bind:displayMessage on:update-config={(e) => handleSettingSubmit(e)}/>
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
export let config;
|
export let config;
|
||||||
export let message;
|
export let message;
|
||||||
export let displayMessage;
|
export let displayMessage;
|
||||||
|
export let cbmode = false;
|
||||||
|
|
||||||
const dispatch = createEventDispatcher();
|
const dispatch = createEventDispatcher();
|
||||||
function updateSetting(selector, target) {
|
function updateSetting(selector, target) {
|
||||||
@ -265,6 +266,62 @@
|
|||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// https://personal.sron.nl/~pault/
|
||||||
|
// https://tsitsul.in/blog/coloropt/
|
||||||
|
const cvdschemes = {
|
||||||
|
HighContrast: [
|
||||||
|
"rgb(221,170,51)",
|
||||||
|
"rgb(187,85,102)",
|
||||||
|
"rgb(0,68,136)",
|
||||||
|
"rgb(0,0,0)",
|
||||||
|
],
|
||||||
|
Bright: [
|
||||||
|
"rgb(68,119,170)",
|
||||||
|
"rgb(102,204,238)",
|
||||||
|
"rgb(34,136,51)",
|
||||||
|
"rgb(204,187,68)",
|
||||||
|
"rgb(238,102,119)",
|
||||||
|
"rgb(170,51,119)",
|
||||||
|
"rgb(187,187,187)",
|
||||||
|
],
|
||||||
|
Muted: [
|
||||||
|
"rgb(51,34,136)",
|
||||||
|
"rgb(136,204,238)",
|
||||||
|
"rgb(68,170,153)",
|
||||||
|
"rgb(17,119,51)",
|
||||||
|
"rgb(153,153,51)",
|
||||||
|
"rgb(221,204,119)",
|
||||||
|
"rgb(204,102,119)",
|
||||||
|
"rgb(136,34,85)",
|
||||||
|
"rgb(170,68,153)",
|
||||||
|
"rgb(221,221,221)",
|
||||||
|
],
|
||||||
|
NormalSixColor: [
|
||||||
|
"rgb(64,83,211)",
|
||||||
|
"rgb(221,179,16)",
|
||||||
|
"rgb(181,29,20)",
|
||||||
|
"rgb(0,190,255)",
|
||||||
|
"rgb(251,73,176)",
|
||||||
|
"rgb(0,178,93)",
|
||||||
|
"rgb(202,202,202)",
|
||||||
|
],
|
||||||
|
NormalTwelveColor: [
|
||||||
|
"rgb(235,172,35)",
|
||||||
|
"rgb(184,0,88)",
|
||||||
|
"rgb(0,140,249)",
|
||||||
|
"rgb(0,110,0)",
|
||||||
|
"rgb(0,187,173)",
|
||||||
|
"rgb(209,99,230)",
|
||||||
|
"rgb(178,69,2)",
|
||||||
|
"rgb(255,146,135)",
|
||||||
|
"rgb(89,84,214)",
|
||||||
|
"rgb(0,198,248)",
|
||||||
|
"rgb(135,133,0)",
|
||||||
|
"rgb(0,167,108)",
|
||||||
|
"rgb(189,189,189)",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Row cols={1} class="p-2 g-2">
|
<Row cols={1} class="p-2 g-2">
|
||||||
@ -281,7 +338,7 @@
|
|||||||
<CardTitle
|
<CardTitle
|
||||||
style="margin-bottom: 1em; display: flex; align-items: center;"
|
style="margin-bottom: 1em; display: flex; align-items: center;"
|
||||||
>
|
>
|
||||||
<div>Color Scheme for Timeseries Plots</div>
|
<div>Color Scheme for Timeseries Plots {cbmode ? `(Color Blind Friendly Palettes)` : ``}</div>
|
||||||
{#if displayMessage && message.target == "cs"}<div
|
{#if displayMessage && message.target == "cs"}<div
|
||||||
style="margin-left: auto; font-size: 0.9em;"
|
style="margin-left: auto; font-size: 0.9em;"
|
||||||
>
|
>
|
||||||
@ -293,7 +350,7 @@
|
|||||||
<input type="hidden" name="key" value="plot_general_colorscheme" />
|
<input type="hidden" name="key" value="plot_general_colorscheme" />
|
||||||
<Table hover>
|
<Table hover>
|
||||||
<tbody>
|
<tbody>
|
||||||
{#each Object.entries(colorschemes) as [name, rgbrow]}
|
{#each Object.entries(cbmode ? cvdschemes : colorschemes) as [name, rgbrow]}
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="col">{name}</th>
|
<th scope="col">{name}</th>
|
||||||
<td>
|
<td>
|
||||||
@ -333,8 +390,9 @@
|
|||||||
|
|
||||||
<style>
|
<style>
|
||||||
.color-dot {
|
.color-dot {
|
||||||
height: 10px;
|
margin-left: 1px;
|
||||||
width: 10px;
|
height: 12px;
|
||||||
|
width: 12px;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
@ -129,8 +129,8 @@
|
|||||||
>
|
>
|
||||||
|
|
||||||
<!-- BACKGROUND -->
|
<!-- BACKGROUND -->
|
||||||
<Col
|
<Col class="d-flex justify-content-between"
|
||||||
><Card class="h-100">
|
><Card class="h-100" style="width: 49%;">
|
||||||
<form
|
<form
|
||||||
id="backgrounds-form"
|
id="backgrounds-form"
|
||||||
method="post"
|
method="post"
|
||||||
@ -173,6 +173,50 @@
|
|||||||
</div>
|
</div>
|
||||||
<Button color="primary" type="submit">Submit</Button>
|
<Button color="primary" type="submit">Submit</Button>
|
||||||
</form>
|
</form>
|
||||||
</Card></Col
|
</Card>
|
||||||
>
|
<Card class="h-100" style="width: 49%;">
|
||||||
|
<form
|
||||||
|
id="colorblindmode-form"
|
||||||
|
method="post"
|
||||||
|
action="/frontend/configuration/"
|
||||||
|
class="card-body"
|
||||||
|
on:submit|preventDefault={() =>
|
||||||
|
updateSetting("#colorblindmode-form", "cbm")}
|
||||||
|
>
|
||||||
|
<!-- Svelte 'class' directive only on DOMs directly, normal 'class="xxx"' does not work, so style-array it is. -->
|
||||||
|
<CardTitle
|
||||||
|
style="margin-bottom: 1em; display: flex; align-items: center;"
|
||||||
|
>
|
||||||
|
<div>Color Blind Mode</div>
|
||||||
|
{#if displayMessage && message.target == "cbm"}<div
|
||||||
|
style="margin-left: auto; font-size: 0.9em;"
|
||||||
|
>
|
||||||
|
<code style="color: {message.color};" out:fade
|
||||||
|
>Update: {message.msg}</code
|
||||||
|
>
|
||||||
|
</div>{/if}
|
||||||
|
</CardTitle>
|
||||||
|
<input type="hidden" name="key" value="plot_general_colorblindMode" />
|
||||||
|
<div class="mb-3">
|
||||||
|
<div>
|
||||||
|
{#if config?.plot_general_colorblindMode}
|
||||||
|
<input type="radio" id="cbm-true-checked" name="value" value="true" checked />
|
||||||
|
{:else}
|
||||||
|
<input type="radio" id="cbm-true" name="value" value="true" />
|
||||||
|
{/if}
|
||||||
|
<label for="true">Yes</label>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{#if config?.plot_general_colorblindMode}
|
||||||
|
<input type="radio" id="cbm-false" name="value" value="false" />
|
||||||
|
{:else}
|
||||||
|
<input type="radio" id="cbm-false-checked" name="value" value="false" checked />
|
||||||
|
{/if}
|
||||||
|
<label for="false">No</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Button color="primary" type="submit">Submit</Button>
|
||||||
|
</form>
|
||||||
|
</Card>
|
||||||
|
</Col>
|
||||||
</Row>
|
</Row>
|
@ -152,10 +152,12 @@
|
|||||||
const lineWidth =
|
const lineWidth =
|
||||||
clusterCockpitConfig.plot_general_lineWidth / window.devicePixelRatio;
|
clusterCockpitConfig.plot_general_lineWidth / window.devicePixelRatio;
|
||||||
const lineColors = clusterCockpitConfig.plot_general_colorscheme;
|
const lineColors = clusterCockpitConfig.plot_general_colorscheme;
|
||||||
|
const cbmode = clusterCockpitConfig?.plot_general_colorblindMode || false;
|
||||||
|
|
||||||
const backgroundColors = {
|
const backgroundColors = {
|
||||||
normal: "rgba(255, 255, 255, 1.0)",
|
normal: "rgba(255, 255, 255, 1.0)",
|
||||||
caution: "rgba(255, 128, 0, 0.3)",
|
caution: cbmode ? "rgba(239, 230, 69, 0.3)" : "rgba(255, 128, 0, 0.3)",
|
||||||
alert: "rgba(255, 0, 0, 0.3)",
|
alert: cbmode ? "rgba(225, 86, 44, 0.3)" : "rgba(255, 0, 0, 0.3)",
|
||||||
};
|
};
|
||||||
const thresholds = findThresholds(
|
const thresholds = findThresholds(
|
||||||
subClusterTopology,
|
subClusterTopology,
|
||||||
@ -346,13 +348,13 @@
|
|||||||
label: "min",
|
label: "min",
|
||||||
scale: "y",
|
scale: "y",
|
||||||
width: lineWidth,
|
width: lineWidth,
|
||||||
stroke: "red",
|
stroke: cbmode ? "rgb(0,255,0)" : "red",
|
||||||
});
|
});
|
||||||
plotSeries.push({
|
plotSeries.push({
|
||||||
label: "max",
|
label: "max",
|
||||||
scale: "y",
|
scale: "y",
|
||||||
width: lineWidth,
|
width: lineWidth,
|
||||||
stroke: "green",
|
stroke: cbmode ? "rgb(0,0,255)" : "green",
|
||||||
});
|
});
|
||||||
plotSeries.push({
|
plotSeries.push({
|
||||||
label: usesMeanStatsSeries ? "mean" : "median",
|
label: usesMeanStatsSeries ? "mean" : "median",
|
||||||
@ -362,8 +364,8 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
plotBands = [
|
plotBands = [
|
||||||
{ series: [2, 3], fill: "rgba(0,255,0,0.1)" },
|
{ series: [2, 3], fill: cbmode ? "rgba(0,0,255,0.1)" : "rgba(0,255,0,0.1)" },
|
||||||
{ series: [3, 1], fill: "rgba(255,0,0,0.1)" },
|
{ series: [3, 1], fill: cbmode ? "rgba(0,255,0,0.1)" : "rgba(255,0,0,0.1)" },
|
||||||
];
|
];
|
||||||
} else {
|
} else {
|
||||||
for (let i = 0; i < series.length; i++) {
|
for (let i = 0; i < series.length; i++) {
|
||||||
|
@ -40,6 +40,7 @@
|
|||||||
let timeoutId = null;
|
let timeoutId = null;
|
||||||
|
|
||||||
const lineWidth = clusterCockpitConfig.plot_general_lineWidth;
|
const lineWidth = clusterCockpitConfig.plot_general_lineWidth;
|
||||||
|
const cbmode = clusterCockpitConfig?.plot_general_colorblindMode || false;
|
||||||
|
|
||||||
// Helpers
|
// Helpers
|
||||||
function getGradientR(x) {
|
function getGradientR(x) {
|
||||||
@ -61,7 +62,7 @@
|
|||||||
return Math.floor(x * 255.0);
|
return Math.floor(x * 255.0);
|
||||||
}
|
}
|
||||||
function getRGB(c) {
|
function getRGB(c) {
|
||||||
return `rgb(${getGradientR(c)}, ${getGradientG(c)}, ${getGradientB(c)})`;
|
return `rgb(${cbmode ? '0' : getGradientR(c)}, ${getGradientG(c)}, ${getGradientB(c)})`;
|
||||||
}
|
}
|
||||||
function nearestThousand(num) {
|
function nearestThousand(num) {
|
||||||
return Math.ceil(num / 1000) * 1000;
|
return Math.ceil(num / 1000) * 1000;
|
||||||
|
Loading…
Reference in New Issue
Block a user