sparkline: dynamic bar width, log scale x-axis option
This commit is contained in:
parent
45814286b8
commit
2803bca1c3
2 changed files with 33 additions and 14 deletions
|
|
@ -13,9 +13,14 @@ Canvas {
|
||||||
readonly property real _max: maxValue !== null && maxValue !== undefined ? maxValue : (history.length ? Math.max(...history) : 100)
|
readonly property real _max: maxValue !== null && maxValue !== undefined ? maxValue : (history.length ? Math.max(...history) : 100)
|
||||||
readonly property real _min: minValue !== null && minValue !== undefined ? minValue : (history.length ? Math.min(...history) : 0)
|
readonly property real _min: minValue !== null && minValue !== undefined ? minValue : (history.length ? Math.min(...history) : 0)
|
||||||
|
|
||||||
// Max x-axis slots (0 = use history.length, right-aligns shorter data)
|
// Max x-axis slots - bars get narrower as data fills up, then oldest drops off
|
||||||
property int maxSamples: 0
|
property int maxSamples: 0
|
||||||
|
|
||||||
|
// Logarithmic x-axis: compresses old data on the left, expands recent data on the right.
|
||||||
|
// logCurve controls strength (0 = linear, 3 = strong compression). Only visual - does not affect data.
|
||||||
|
property bool logScale: false
|
||||||
|
property real logCurve: 3
|
||||||
|
|
||||||
// Optional background tint using `color` at low opacity
|
// Optional background tint using `color` at low opacity
|
||||||
property real backgroundTint: 0 // 0 = off, e.g. 0.15 for memory, 0.08 for temperature
|
property real backgroundTint: 0 // 0 = off, e.g. 0.15 for memory, 0.08 for temperature
|
||||||
|
|
||||||
|
|
@ -47,9 +52,7 @@ Canvas {
|
||||||
if (!d.length || (areaMode && d.length < 2))
|
if (!d.length || (areaMode && d.length < 2))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const samples = maxSamples > 0 ? maxSamples : d.length;
|
const n = d.length;
|
||||||
const step = width / samples;
|
|
||||||
const offset = samples - d.length;
|
|
||||||
const lo = _min;
|
const lo = _min;
|
||||||
const hi = _max;
|
const hi = _max;
|
||||||
const range = hi - lo || 1;
|
const range = hi - lo || 1;
|
||||||
|
|
@ -57,6 +60,20 @@ Canvas {
|
||||||
return height - height * ((v - lo) / range);
|
return height - height * ((v - lo) / range);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// x-axis mapping: returns [x, barWidth] for data index i
|
||||||
|
const k = logScale ? logCurve : 0;
|
||||||
|
const expK = k > 0 ? Math.exp(k) - 1 : 0;
|
||||||
|
function xOf(i) {
|
||||||
|
if (k > 0) {
|
||||||
|
const x0 = width * (Math.exp(k * i / n) - 1) / expK;
|
||||||
|
const x1 = width * (Math.exp(k * (i + 1) / n) - 1) / expK;
|
||||||
|
return [x0, x1 - x0];
|
||||||
|
}
|
||||||
|
const step = width / (maxSamples > n ? maxSamples : n);
|
||||||
|
const off = maxSamples > n ? (maxSamples - n) * step : 0;
|
||||||
|
return [off + i * step, step];
|
||||||
|
}
|
||||||
|
|
||||||
// Background tint
|
// Background tint
|
||||||
if (backgroundTint > 0) {
|
if (backgroundTint > 0) {
|
||||||
ctx.fillStyle = Qt.rgba(color.r, color.g, color.b, backgroundTint).toString();
|
ctx.fillStyle = Qt.rgba(color.r, color.g, color.b, backgroundTint).toString();
|
||||||
|
|
@ -93,22 +110,24 @@ Canvas {
|
||||||
|
|
||||||
if (areaMode) {
|
if (areaMode) {
|
||||||
// Filled area under curve
|
// Filled area under curve
|
||||||
const xOff = offset * step;
|
|
||||||
const baseY = lo < 0 ? yOf(0) : height;
|
const baseY = lo < 0 ? yOf(0) : height;
|
||||||
|
const [x0] = xOf(0);
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
ctx.moveTo(xOff, baseY);
|
ctx.moveTo(x0, baseY);
|
||||||
for (let i = 0; i < d.length; i++) {
|
for (let i = 0; i < n; i++) {
|
||||||
ctx.lineTo(xOff + i * step, yOf(d[i]));
|
const [x] = xOf(i);
|
||||||
|
ctx.lineTo(x, yOf(d[i]));
|
||||||
}
|
}
|
||||||
ctx.lineTo(xOff + (d.length - 1) * step, baseY);
|
const [xLast] = xOf(n - 1);
|
||||||
|
ctx.lineTo(xLast, baseY);
|
||||||
ctx.closePath();
|
ctx.closePath();
|
||||||
ctx.fillStyle = Qt.rgba(color.r, color.g, color.b, areaOpacity).toString();
|
ctx.fillStyle = Qt.rgba(color.r, color.g, color.b, areaOpacity).toString();
|
||||||
ctx.fill();
|
ctx.fill();
|
||||||
|
|
||||||
// Top stroke
|
// Top stroke
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
for (let i = 0; i < d.length; i++) {
|
for (let i = 0; i < n; i++) {
|
||||||
const x = xOff + i * step;
|
const [x] = xOf(i);
|
||||||
if (i === 0)
|
if (i === 0)
|
||||||
ctx.moveTo(x, yOf(d[i]));
|
ctx.moveTo(x, yOf(d[i]));
|
||||||
else
|
else
|
||||||
|
|
@ -123,13 +142,14 @@ Canvas {
|
||||||
const zy = lo < 0 ? yOf(0) : height;
|
const zy = lo < 0 ? yOf(0) : height;
|
||||||
if (!hasCF)
|
if (!hasCF)
|
||||||
ctx.fillStyle = color.toString();
|
ctx.fillStyle = color.toString();
|
||||||
for (let i = 0; i < d.length; i++) {
|
for (let i = 0; i < n; i++) {
|
||||||
if (hasCF)
|
if (hasCF)
|
||||||
ctx.fillStyle = colorFunction(d[i]).toString();
|
ctx.fillStyle = colorFunction(d[i]).toString();
|
||||||
|
const [bx, bw] = xOf(i);
|
||||||
const dy = yOf(d[i]);
|
const dy = yOf(d[i]);
|
||||||
const barTop = Math.min(dy, zy);
|
const barTop = Math.min(dy, zy);
|
||||||
const barH = Math.max(1, Math.abs(dy - zy));
|
const barH = Math.max(1, Math.abs(dy - zy));
|
||||||
ctx.fillRect((offset + i) * step, barTop, Math.max(1, step - 0.5), barH);
|
ctx.fillRect(bx, barTop, Math.max(1, bw - 0.5), barH);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@ shell/applets/NetworkApplet.qml: Unqualified access [unqualified]
|
||||||
shell/applets/NotifApplet.qml: Member "_notif" not found on type "QQuickItem" [missing-property]
|
shell/applets/NotifApplet.qml: Member "_notif" not found on type "QQuickItem" [missing-property]
|
||||||
shell/applets/NotifApplet.qml: Member "_type" not found on type "QQuickItem" [missing-property]
|
shell/applets/NotifApplet.qml: Member "_type" not found on type "QQuickItem" [missing-property]
|
||||||
shell/applets/NotifApplet.qml: Unqualified access [unqualified]
|
shell/applets/NotifApplet.qml: Unqualified access [unqualified]
|
||||||
shell/applets/SparklineCanvas.qml: Property "colorFunction" is a var property. It may or may not be a method. Use a regular function instead. [use-proper-function]
|
|
||||||
shell/applets/TemperatureApplet.qml: Unqualified access [unqualified]
|
shell/applets/TemperatureApplet.qml: Unqualified access [unqualified]
|
||||||
shell/applets/VolumeApplet.qml: Unqualified access [unqualified]
|
shell/applets/VolumeApplet.qml: Unqualified access [unqualified]
|
||||||
shell/lock/Lock.qml: Unqualified access [unqualified]
|
shell/lock/Lock.qml: Unqualified access [unqualified]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue