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