extract SparklineCanvas component from 5 applets
This commit is contained in:
parent
732a14e5cb
commit
8d76df6ef5
8 changed files with 178 additions and 233 deletions
112
shell/applets/SparklineCanvas.qml
Normal file
112
shell/applets/SparklineCanvas.qml
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
import QtQuick
|
||||
|
||||
Canvas {
|
||||
id: root
|
||||
|
||||
// Data - array of 0-100 percentage values
|
||||
property var history: []
|
||||
property color color: "white"
|
||||
property bool active: true
|
||||
|
||||
// Max x-axis slots (0 = use history.length, right-aligns shorter data)
|
||||
property int maxSamples: 0
|
||||
|
||||
// Optional background tint using `color` at low opacity
|
||||
property real backgroundTint: 0 // 0 = off, e.g. 0.15 for memory, 0.08 for temperature
|
||||
|
||||
// Area chart mode (battery-style filled curve + stroke line)
|
||||
property bool areaMode: false
|
||||
property real areaOpacity: 0.18
|
||||
property real lineWidth: 1.5
|
||||
|
||||
// Per-bar color override: function(value) => color. Null = uniform `color`.
|
||||
property var colorFunction: null
|
||||
|
||||
// Horizontal threshold lines: [{value: 70, color: "#..."}]
|
||||
property var thresholds: []
|
||||
|
||||
onHistoryChanged: if (root.active)
|
||||
requestPaint()
|
||||
onColorChanged: if (root.active)
|
||||
requestPaint()
|
||||
|
||||
onVisibleChanged: if (visible)
|
||||
requestPaint()
|
||||
|
||||
onPaint: {
|
||||
const ctx = getContext("2d");
|
||||
if (!ctx)
|
||||
return;
|
||||
ctx.clearRect(0, 0, width, height);
|
||||
const d = history;
|
||||
if (!d.length || (areaMode && d.length < 2))
|
||||
return;
|
||||
|
||||
const samples = maxSamples > 0 ? maxSamples : d.length;
|
||||
const step = width / samples;
|
||||
const offset = samples - d.length;
|
||||
|
||||
// Background tint
|
||||
if (backgroundTint > 0) {
|
||||
ctx.fillStyle = Qt.rgba(color.r, color.g, color.b, backgroundTint).toString();
|
||||
ctx.fillRect(0, 0, width, height);
|
||||
}
|
||||
|
||||
// Threshold lines
|
||||
if (thresholds.length) {
|
||||
ctx.globalAlpha = 0.3;
|
||||
ctx.lineWidth = 1;
|
||||
ctx.setLineDash([3, 3]);
|
||||
for (let t = 0; t < thresholds.length; t++) {
|
||||
const th = thresholds[t];
|
||||
const ty = height - height * (th.value / 100);
|
||||
ctx.strokeStyle = th.color.toString();
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(0, ty);
|
||||
ctx.lineTo(width, ty);
|
||||
ctx.stroke();
|
||||
}
|
||||
ctx.setLineDash([]);
|
||||
ctx.globalAlpha = 1.0;
|
||||
}
|
||||
|
||||
if (areaMode) {
|
||||
// Filled area under curve
|
||||
const xOff = offset * step;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(xOff, height);
|
||||
for (let i = 0; i < d.length; i++) {
|
||||
ctx.lineTo(xOff + i * step, height - height * (d[i] / 100));
|
||||
}
|
||||
ctx.lineTo(xOff + (d.length - 1) * step, height);
|
||||
ctx.closePath();
|
||||
ctx.fillStyle = Qt.rgba(color.r, color.g, color.b, areaOpacity).toString();
|
||||
ctx.fill();
|
||||
|
||||
// Top stroke
|
||||
ctx.beginPath();
|
||||
for (let i = 0; i < d.length; i++) {
|
||||
const x = xOff + i * step;
|
||||
const y = height - height * (d[i] / 100);
|
||||
if (i === 0)
|
||||
ctx.moveTo(x, y);
|
||||
else
|
||||
ctx.lineTo(x, y);
|
||||
}
|
||||
ctx.strokeStyle = color.toString();
|
||||
ctx.lineWidth = root.lineWidth;
|
||||
ctx.stroke();
|
||||
} else {
|
||||
// Bar chart
|
||||
const hasCF = typeof colorFunction === "function";
|
||||
if (!hasCF)
|
||||
ctx.fillStyle = color.toString();
|
||||
for (let i = 0; i < d.length; i++) {
|
||||
const barH = Math.max(1, height * d[i] / 100);
|
||||
if (hasCF)
|
||||
ctx.fillStyle = colorFunction(d[i]).toString();
|
||||
ctx.fillRect((offset + i) * step, height - barH, Math.max(1, step - 0.5), barH);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue