cleanup intends, add transparency switch to path renderer

This commit is contained in:
Christoph Kluge
2025-07-15 18:49:23 +02:00
parent e48ff8be73
commit 5cdb80b4d6

View File

@@ -62,7 +62,7 @@
pxRatio = uPlot.pxRatio; pxRatio = uPlot.pxRatio;
} }
setPxRatio(); setPxRatio();
window.addEventListener('dppxchange', setPxRatio); window.addEventListener('dppxchange', setPxRatio);
// let minSize = 6; // let minSize = 6;
let maxSize = 60; let maxSize = 60;
// let maxArea = Math.PI * (maxSize / 2) ** 2; // let maxArea = Math.PI * (maxSize / 2) ** 2;
@@ -92,8 +92,8 @@
x = 1.0 - (x - 0.25) * 4.0; x = 1.0 - (x - 0.25) * 4.0;
return Math.floor(x * 255.0); return Math.floor(x * 255.0);
} }
function getRGB(c, makeTransparent = false) { function getRGB(c, transparent = false) {
if (makeTransparent) return `rgba(${cbmode ? '0' : getGradientR(c)}, ${getGradientG(c)}, ${getGradientB(c)}, 0.5)`; if (transparent) return `rgba(${cbmode ? '0' : getGradientR(c)}, ${getGradientG(c)}, ${getGradientB(c)}, 0.5)`;
else return `rgb(${cbmode ? '0' : getGradientR(c)}, ${getGradientG(c)}, ${getGradientB(c)})`; else return `rgb(${cbmode ? '0' : getGradientR(c)}, ${getGradientG(c)}, ${getGradientB(c)})`;
} }
function nearestThousand(num) { function nearestThousand(num) {
@@ -240,7 +240,7 @@
// Dot Renderer // Dot Renderer
const makeDrawPoints = (opts) => { const makeDrawPoints = (opts) => {
let {/*size, disp,*/ each = () => {}} = opts; let {/*size, disp,*/ transparentFill, each = () => {}} = opts;
const sizeBase = 5 * pxRatio; const sizeBase = 5 * pxRatio;
return (u, seriesIdx, idx0, idx1) => { return (u, seriesIdx, idx0, idx1) => {
@@ -264,9 +264,10 @@
let filtTop = u.posToVal(-maxSize / 2, scaleY.key); let filtTop = u.posToVal(-maxSize / 2, scaleY.key);
for (let i = 0; i < d[0].length; i++) { for (let i = 0; i < d[0].length; i++) {
// Color based on Duration // Color based on Duration, check index for transparency highlighting
u.ctx.strokeStyle = getRGB(u.data[2][i]); u.ctx.strokeStyle = getRGB(u.data[2][i]);
u.ctx.fillStyle = getRGB(u.data[2][i], true); u.ctx.fillStyle = getRGB(u.data[2][i], transparentFill);
// Get Values // Get Values
let xVal = d[0][i]; let xVal = d[0][i];
let yVal = d[1][i]; let yVal = d[1][i];
@@ -310,6 +311,7 @@
// }, // },
// }, // },
// }, // },
transparentFill: true,
each: (u, seriesIdx, dataIdx, lft, top, wid, hgt) => { each: (u, seriesIdx, dataIdx, lft, top, wid, hgt) => {
// we get back raw canvas coords (included axes & padding). translate to the plotting area origin // we get back raw canvas coords (included axes & padding). translate to the plotting area origin
lft -= u.bbox.left; lft -= u.bbox.left;
@@ -454,64 +456,64 @@
width: width, width: width,
height: height, height: height,
legend: { legend: {
show: true, show: true,
}, },
cursor: { cursor: {
dataIdx: (u, seriesIdx) => { dataIdx: (u, seriesIdx) => {
if (seriesIdx == 1) { if (seriesIdx == 1) {
hRect = null; hRect = null;
let dist = Infinity; let dist = Infinity;
let area = Infinity; let area = Infinity;
let cx = u.cursor.left * pxRatio; let cx = u.cursor.left * pxRatio;
let cy = u.cursor.top * pxRatio; let cy = u.cursor.top * pxRatio;
qt.get(cx, cy, 1, 1, o => { qt.get(cx, cy, 1, 1, o => {
if (pointWithin(cx, cy, o.x, o.y, o.x + o.w, o.y + o.h)) { if (pointWithin(cx, cy, o.x, o.y, o.x + o.w, o.y + o.h)) {
let ocx = o.x + o.w / 2; let ocx = o.x + o.w / 2;
let ocy = o.y + o.h / 2; let ocy = o.y + o.h / 2;
let dx = ocx - cx; let dx = ocx - cx;
let dy = ocy - cy; let dy = ocy - cy;
let d = Math.sqrt(dx ** 2 + dy ** 2); let d = Math.sqrt(dx ** 2 + dy ** 2);
// test against radius for actual hover // test against radius for actual hover
if (d <= o.w / 2) { if (d <= o.w / 2) {
let a = o.w * o.h; let a = o.w * o.h;
// prefer smallest // prefer smallest
if (a < area) { if (a < area) {
area = a; area = a;
dist = d; dist = d;
hRect = o; hRect = o;
} }
// only hover bbox with closest distance // only hover bbox with closest distance
else if (a == area && d <= dist) { else if (a == area && d <= dist) {
dist = d; dist = d;
hRect = o; hRect = o;
} }
} }
} }
}); });
} }
return hRect && seriesIdx == hRect.sidx ? hRect.didx : null; return hRect && seriesIdx == hRect.sidx ? hRect.didx : null;
}, },
// /* Render "Fill" on Data Point Hover: Works in Example Bubble, does not work here? */ /* Render "Fill" on Data Point Hover: Works in Example Bubble, does not work here? Guess: Interference with tooltip */
// points: { // points: {
// size: (u, seriesIdx) => { // size: (u, seriesIdx) => {
// return hRect && seriesIdx == hRect.sidx ? hRect.w / pxRatio : 0; // return hRect && seriesIdx == hRect.sidx ? hRect.w / pxRatio : 0;
// } // }
// }, // },
/* Make all non-focused series semi-transparent: Useless unless more than one series rendered */ /* Make all non-focused series semi-transparent: Useless unless more than one series rendered */
// focus: { // focus: {
// prox: 1e3, // prox: 1e3,
// alpha: 0.3, // alpha: 0.3,
// dist: (u, seriesIdx) => { // dist: (u, seriesIdx) => {
// let prox = (hRect?.sidx === seriesIdx ? 0 : Infinity); // let prox = (hRect?.sidx === seriesIdx ? 0 : Infinity);
// return prox; // return prox;
// }, // },
// }, // },
drag: { // Activates Zoom drag: { // Activates Zoom
x: true, x: true,
y: false y: false
@@ -550,26 +552,26 @@
{ {
/* Facets: Define Purpose of Sub-Arrays in Series-Array, e.g. x, y, size, label, color, ... */ /* Facets: Define Purpose of Sub-Arrays in Series-Array, e.g. x, y, size, label, color, ... */
// facets: [ // facets: [
// { // {
// scale: 'x', // scale: 'x',
// auto: true, // auto: true,
// }, // },
// { // {
// scale: 'y', // scale: 'y',
// auto: true, // auto: true,
// } // }
// ], // ],
paths: drawPoints, paths: drawPoints,
values: legendValues values: legendValues
} }
], ],
hooks: { hooks: {
// setSeries: [ (u, seriesIdx) => console.log('setSeries', seriesIdx) ], // setSeries: [ (u, seriesIdx) => console.log('setSeries', seriesIdx) ],
// setLegend: [ u => console.log('setLegend', u.legend.idxs) ], // setLegend: [ u => console.log('setLegend', u.legend.idxs) ],
drawClear: [ drawClear: [
(u) => { (u) => {
qt = qt || new Quadtree(0, 0, u.bbox.width, u.bbox.height); qt = qt || new Quadtree(0, 0, u.bbox.width, u.bbox.height);
qt.clear(); qt.clear();
// force-clear the path cache to cause drawBars() to rebuild new quadtree // force-clear the path cache to cause drawBars() to rebuild new quadtree
u.series.forEach((s, i) => { u.series.forEach((s, i) => {
@@ -675,11 +677,11 @@
u.ctx.fillText('Short', posX, posY) u.ctx.fillText('Short', posX, posY)
const start = posX + 10 const start = posX + 10
for (let x = start; x < posXLimit; x += 10) { for (let x = start; x < posXLimit; x += 10) {
let c = (x - start) / (posXLimit - start) let c = (x - start) / (posXLimit - start)
u.ctx.fillStyle = getRGB(c) u.ctx.fillStyle = getRGB(c)
u.ctx.beginPath() u.ctx.beginPath()
u.ctx.arc(x, posY, 3, 0, Math.PI * 2, false) u.ctx.arc(x, posY, 3, 0, Math.PI * 2, false)
u.ctx.fill() u.ctx.fill()
} }
u.ctx.fillStyle = 'black' u.ctx.fillStyle = 'black'
u.ctx.fillText('Long', posXLimit + 23, posY) u.ctx.fillText('Long', posXLimit + 23, posY)
@@ -687,13 +689,13 @@
], ],
}, },
plugins: [ plugins: [
tooltipPlugin({ tooltipPlugin({
onclick(u, dataIdx) { onclick(u, dataIdx) {
window.open(`/monitoring/job/${jobsData[dataIdx].id}`); window.open(`/monitoring/job/${jobsData[dataIdx].id}`);
}, },
getJobData: (u, dataIdx) => { return jobsData[dataIdx] } getJobData: (u, dataIdx) => { return jobsData[dataIdx] }
}), }),
], ],
}; };
uplot = new uPlot(opts, roofdata, plotWrapper); uplot = new uPlot(opts, roofdata, plotWrapper);
} else { } else {
@@ -716,6 +718,5 @@
{#if roofData != null} {#if roofData != null}
<div bind:this={plotWrapper} class="p-2"></div> <div bind:this={plotWrapper} class="p-2"></div>
{:else} {:else}
<Card class="mx-4" body color="warning">Cannot render roofline: No data!</Card <Card class="mx-4" body color="warning">Cannot render roofline: No data!</Card>
> {/if}
{/if}