Warning, /plasma/plasma-mobile/kcms/powermanagement/ui/Graph.qml is written in an unsupported language. File is not indexed.

0001 /*
0002  * SPDX-FileCopyrightText: 2015 David Edmundson <david@davidedmundson.co.uk>
0003  *
0004  * SPDX-License-Identifier: LGPL-2.1-or-later
0005  *
0006  */
0007 
0008 import QtQuick 2.3
0009 
0010 /**
0011  * We need to draw a graph, all other libs are not suitable as we are basically
0012  * a connected scatter plot with non linear X spacing.
0013  * Currently this is not available in kdeclarative nor kqtquickcharts
0014  *
0015  * We only paint once, so canvas is fast enough for our purposes.
0016  * It is designed to look identical to those in ksysguard.
0017  */
0018 
0019 Canvas
0020 {
0021     id: canvas
0022     antialiasing: true
0023     
0024     readonly property real xTicksAtDontCare: 0 
0025     readonly property real xTicksAtTwelveOClock: 1
0026     readonly property real xTicksAtFullHour: 2
0027     readonly property real xTicksAtHalfHour: 3
0028     readonly property real xTicksAtFullSecondHour: 4
0029     readonly property real xTicksAtTenMinutes: 5    
0030     readonly property real xTicksAtFullTwoHours: 6
0031 
0032     property int xPadding: 45
0033     property int yPadding: 40
0034 
0035     property var data //expect an array of QPointF
0036 
0037     property real yMax: 100
0038     property real xMax: 100
0039     property real yMin: 0
0040     property real xMin: 0
0041     property real yStep: 20
0042 
0043     property real xDuration: 3600
0044     property real xDivisions: 6
0045     property real xDivisionWidth: 600000
0046     property real xTicksAt: xTicksAtDontCare
0047 
0048     //internal
0049 
0050     property real plotWidth: width - xPadding * 1.5
0051     property real plotHeight: height - yPadding * 2
0052 
0053     onDataChanged: {
0054         canvas.requestPaint();
0055     }
0056 
0057     //take a QPointF
0058     function scalePoint(plot, currentUnixTime) {
0059         var scaledX = (plot.x - (currentUnixTime / 1000 - xDuration)) / xDuration * plotWidth;
0060         var scaledY = (plot.y - yMin)  * plotHeight / (yMax - yMin);
0061 
0062         return Qt.point(xPadding + scaledX,
0063             height - yPadding - scaledY);
0064     }
0065 
0066     SystemPalette {
0067         id: palette;
0068         colorGroup: SystemPalette.Active
0069     }
0070 
0071 
0072     onPaint: {
0073         var c = canvas.getContext('2d');
0074 
0075         c.clearRect(0,0, width, height)
0076 
0077         //draw the background
0078         c.fillStyle = palette.base
0079         c.fillRect(xPadding, yPadding, plotWidth, plotHeight);
0080 
0081         //reset for fonts and stuff
0082         c.fillStyle = palette.text
0083 
0084         //Draw the lines
0085 
0086         c.lineWidth = 1;
0087         c.lineJoin = 'round';
0088         c.lineCap = 'round';
0089         c.strokeStyle = 'rgba(255, 0, 0, 1)';
0090         var gradient = c.createLinearGradient(0,0,0,height);
0091         gradient.addColorStop(0, 'rgba(255, 0, 0, 0.2)');
0092         gradient.addColorStop(1, 'rgba(255, 0, 0, 0.05)');
0093         c.fillStyle = gradient;
0094 
0095         // For scaling
0096         var currentUnixTime = Date.now()
0097         var xMinUnixTime = currentUnixTime - xDuration * 1000
0098 
0099         // Draw the line graph
0100         c.beginPath();
0101 
0102         var index = 0
0103 
0104         while ((index < data.length - 1) && (data[index].x < (xMinUnixTime / 1000))) {
0105             index++
0106         }
0107 
0108         var firstPoint = scalePoint(data[index], currentUnixTime)
0109         c.moveTo(firstPoint.x, firstPoint.y)
0110 
0111         var point
0112         for (var i = index + 1; i < data.length; i++) {
0113             if (data[i].x > (xMinUnixTime / 1000)) {
0114                 point = scalePoint(data[i], currentUnixTime)
0115                 c.lineTo(point.x, point.y)
0116             }
0117         }
0118             
0119         c.stroke();
0120         c.strokeStyle = 'rgba(0, 0, 0, 0)';
0121         c.lineTo(point.x, height - yPadding);
0122         c.lineTo(firstPoint.x, height - yPadding);
0123         c.fill();
0124 
0125         c.closePath()
0126 
0127         // Draw the frame on top
0128 
0129         //draw an outline
0130         c.strokeStyle = 'rgba(0,50,0,0.02)';
0131         c.lineWidth = 1;
0132         c.rect(xPadding - 1, yPadding - 1, plotWidth + 2, plotHeight + 2);
0133 
0134         // Draw the Y value texts
0135         c.fillStyle = palette.text;
0136         c.textAlign = "right"
0137         c.textBaseline = "middle";
0138         for(var i = 0; i <=  yMax; i += yStep) {
0139             var y = scalePoint(Qt.point(0,i)).y;
0140 
0141             c.fillText(i18nc("%1 is a percentage value", "%1%", i), xPadding - 10, y);
0142 
0143             //grid line
0144             c.moveTo(xPadding, y)
0145             c.lineTo(plotWidth + xPadding, y)
0146         }
0147         c.stroke()
0148 
0149         // Draw the X value texts
0150         c.textAlign = "center"
0151         c.lineWidth = 1
0152         c.strokeStyle = 'rgba(0, 0, 0, 0.15)'
0153 
0154         var xDivisions = xDuration / xDivisionWidth * 1000
0155         var xGridDistance = plotWidth / xDivisions
0156         var xTickPos
0157         var xTickDateTime
0158         var xTickDateStr
0159         var xTickTimeStr
0160 
0161         var currentDateTime = new Date()
0162         var lastDateStr = currentDateTime.toLocaleDateString(Qt.locale(), Locale.ShortFormat)
0163 
0164         var hours = currentDateTime.getHours()
0165         var minutes = currentDateTime.getMinutes()
0166         var seconds = currentDateTime.getSeconds()
0167        
0168         var diff
0169 
0170         switch (xTicksAt) {
0171             case xTicksAtTwelveOClock:
0172                 diff = ((hours - 12) * 60 * 60 + minutes * 60 + seconds)
0173                 break
0174             case xTicksAtFullHour:
0175                 diff = (minutes * 60 + seconds)
0176                 break
0177             case xTicksAtFullSecondHour:
0178                 diff = (minutes * 60 + seconds)
0179                 break
0180             case xTicksAtHalfHour:
0181                 diff = ((minutes - 30) * 60 + seconds)
0182                 break
0183             case xTicksAtTenMinutes:
0184                 diff = ((minutes % 10) * 60 + seconds)
0185                 break
0186             default:
0187                 diff = 0
0188         }
0189 
0190         var xGridOffset = plotWidth * (diff / xDuration)
0191         var dateChanged = false 
0192 
0193         var dashedLines = 50
0194         var dashedLineLength = plotHeight / dashedLines
0195         var dashedLineDutyCycle
0196 
0197         for (var i = xDivisions; i >= -1; i--) {
0198             xTickPos = i * xGridDistance + xPadding - xGridOffset
0199 
0200             if ((xTickPos > xPadding) && (xTickPos < plotWidth + xPadding)) 
0201             {
0202                 xTickDateTime = new Date(currentUnixTime - (xDivisions - i) * xDivisionWidth - diff * 1000)
0203                 xTickDateStr = xTickDateTime.toLocaleDateString(Qt.locale(), Locale.ShortFormat)
0204                 xTickTimeStr = xTickDateTime.toLocaleTimeString(Qt.locale(), Locale.ShortFormat)
0205 
0206                 if (lastDateStr != xTickDateStr) {
0207                     dateChanged = true
0208                 }
0209  
0210                 if  ((i % 2 == 0) || (xDivisions < 10))
0211                 {
0212                     // Display the time
0213                     c.fillText(xTickTimeStr, xTickPos, canvas.height - yPadding / 2)
0214     
0215                     // If the date has changed and is not the current day in a <= 24h graph, display it
0216                     // Always display the date for 48h and 1 week graphs
0217                     if (dateChanged || (xDuration > (60*60*48))) {
0218                         c.fillText(xTickDateStr, xTickPos, canvas.height - yPadding / 4)
0219                         dateChanged = false
0220                     }
0221 
0222                     // Tick markers
0223                     c.moveTo(xTickPos, canvas.height - yPadding)
0224                     c.lineTo(xTickPos, canvas.height - (yPadding * 4) / 5)
0225         
0226                     dashedLineDutyCycle = 0.5
0227                 } else {
0228                     dashedLineDutyCycle = 0.1
0229                 }
0230         
0231                 for (var j = 0; j < dashedLines; j++) { 
0232                     c.moveTo(xTickPos, yPadding + j * dashedLineLength)
0233                     c.lineTo(xTickPos, yPadding + j * dashedLineLength + dashedLineDutyCycle * dashedLineLength)
0234                 }
0235                lastDateStr = xTickDateStr
0236             }
0237         }
0238         c.stroke()
0239     }
0240 }