291 lines · 10.3 KB · Text
RawDownload
////  PlotPerf.qml//  examples/utilities/render/plotperf////  Created by Sam Gateau on 3//2016//  Copyright 2016 High Fidelity, Inc.////  Distributed under the Apache License, Version 2.0.//  See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html//import QtQuick 2.5import QtQuick.Controls 1.4 Item {    id: root    width: parent.width    height: 100     // The title of the graph    property string title     // The object used as the default source object for the prop plots    property var object     property var backgroundOpacity: 0.6     // Plots is an array of plot descriptor    // a default plot descriptor expects the following object:    //     prop: [ {    //                object: {}             // Optional: this is the object from which the prop will be fetched,     //                                          if nothing than the object from root is used    //                prop:"bufferCPUCount", // Needed the name of the property from the object to feed the plot    //                label: "CPU",          // Optional: Label as displayed on the plot    //                color: "#00B4EF"       // Optional: Color of the curve    //                unit: "km/h"           // Optional: Unit added to the value displayed, if nothing then the default unit is used    //                scale: 1               // Optional: Extra scaling used to represent the value, this scale is combined with the global scale.    //            },    property var plots     // Default value scale used to define the max value of the chart    property var valueScale: 1     // Default value unit appended to the value displayed    property var valueUnit: ""     // Default number of digits displayed    property var valueNumDigits: 0         property var valueMax : 1    property var valueMin : 0     property var displayMinAt0 : true    property var _displayMaxValue : 1    property var _displayMinValue : 0     property var _values    property var tick : 0     function createValues() {        if (!_values) {            _values = new Array();        }        for (var i =0; i < plots.length; i++) {             var plot = plots[i];            var object = plot["object"] || root.object;            var value = plot["prop"];            var isBinding = plot["binding"];            if (isBinding) {                object = root.parent;                value = isBinding;            }            _values.push( {                object: object,                value: value,                fromBinding: isBinding,                valueMax: 1,                valueMin: 0,                numSamplesConstantMax: 0,                numSamplesConstantMin: 0,                valueHistory: new Array(),                label: (plot["label"] !== undefined ? plot["label"] : ""),                color: (plot["color"] !== undefined ? plot["color"] : "white"),                scale: (plot["scale"] !== undefined ? plot["scale"] : 1),                unit: (plot["unit"] !== undefined ? plot["unit"] : valueUnit)            })        }        pullFreshValues();    }     Component.onCompleted: {        createValues();       }    function resetMax() {        for (var i = 0; i < _values.length; i++) {            _values[i].valueMax *= 0.25 // Fast reduce the max value  as we click                           }    }    function resetMin() {        for (var i = 0; i < _values.length; i++) {            _values[i].valueMin *= 0.25 // Fast reduce the min value  as we click                           }    }     function pullFreshValues() {        // Wait until values are created to begin pulling        if (!_values) { return; }         var VALUE_HISTORY_SIZE = 100;        tick++;                        var currentValueMax = 0        var currentValueMin = 0        for (var i = 0; i < _values.length; i++) {             var currentVal = (+_values[i].object[_values[i].value]) * _values[i].scale;             _values[i].valueHistory.push(currentVal)            _values[i].numSamplesConstantMax++;             if (_values[i].valueHistory.length > VALUE_HISTORY_SIZE) {                var lostValue = _values[i].valueHistory.shift();                if (lostValue >= _values[i].valueMax) {                    _values[i].valueMax *= 0.99                    _values[i].numSamplesConstantMax = 0                }                if (lostValue <= _values[i].valueMin) {                    _values[i].valueMin *= 0.99                    _values[i].numSamplesConstantMin = 0                }            }             if (_values[i].valueMax < currentVal) {                _values[i].valueMax = currentVal;                _values[i].numSamplesConstantMax = 0             }                                if (_values[i].valueMin > currentVal) {                _values[i].valueMin = currentVal;                _values[i].numSamplesConstantMin = 0             }                if (_values[i].numSamplesConstantMax > VALUE_HISTORY_SIZE) {                _values[i].numSamplesConstantMax = 0                     _values[i].valueMax *= 0.95 // lower slowly the current max if no new above max since a while                                  }            if (_values[i].numSamplesConstantMin > VALUE_HISTORY_SIZE) {                _values[i].numSamplesConstantMin = 0                     _values[i].valueMin *= 0.95 // lower slowly the current min if no new above min since a while                                  }             if (currentValueMax < _values[i].valueMax) {                currentValueMax = _values[i].valueMax            }            if (currentValueMin > _values[i].valueMin) {                currentValueMin = _values[i].valueMin            }        }         if ((valueMax < currentValueMax) || (tick % VALUE_HISTORY_SIZE == 0)) {            valueMax = currentValueMax;        }        if ((valueMin > currentValueMin) || (tick % VALUE_HISTORY_SIZE == 0)) {            valueMin = currentValueMin;        }        _displayMaxValue = valueMax;        _displayMinValue = ( displayMinAt0 ? 0 : valueMin )         mycanvas.requestPaint()    }     Timer {        interval: 100; running: true; repeat: true        onTriggered: pullFreshValues()    }     Canvas {        id: mycanvas        anchors.fill:parent                onPaint: {            var lineHeight = 12;             function displayValue(val, unit) {                 return (val / root.valueScale).toFixed(root.valueNumDigits) + " " + unit            }             function pixelFromVal(val, valScale) {                return lineHeight + (height - lineHeight) * (1 - (0.99) * (val - _displayMinValue) / (_displayMaxValue - _displayMinValue));            }            function valueFromPixel(pixY) {                return _displayMinValue + (((pixY - lineHeight) / (height - lineHeight) - 1) * (_displayMaxValue - _displayMinValue) / (-0.99));            }            function plotValueHistory(ctx, valHistory, color) {                var widthStep= width / (valHistory.length - 1);                 ctx.beginPath();                ctx.strokeStyle= color; // Green path                ctx.lineWidth="2";                ctx.moveTo(0, pixelFromVal(valHistory[0]));                                    for (var i = 1; i < valHistory.length; i++) {                     ctx.lineTo(i * widthStep, pixelFromVal(valHistory[i]));                 }                 ctx.stroke();            }            function displayValueLegend(ctx, val, num) {                ctx.fillStyle = val.color;                var bestValue = val.valueHistory[val.valueHistory.length -1];                             ctx.textAlign = "right";                ctx.fillText(displayValue(bestValue, val.unit), width, (num + 2) * lineHeight * 1);                ctx.textAlign = "left";                ctx.fillText(val.label, 0, (num + 2) * lineHeight * 1);            }             function displayTitle(ctx, text, maxVal) {                ctx.fillStyle = "grey";                ctx.textAlign = "right";                ctx.fillText("max " + displayValue(_displayMaxValue, root.valueUnit), width, pixelFromVal(_displayMaxValue));                                ctx.fillText("min " + displayValue(_displayMinValue, root.valueUnit), width, pixelFromVal(_displayMinValue));                               ctx.fillStyle = "white";                ctx.textAlign = "left";                ctx.fillText(text, 0, lineHeight);            }            function displayBackground(ctx) {                ctx.fillStyle = Qt.rgba(0, 0, 0, root.backgroundOpacity);                ctx.fillRect(0, 0, width, height);                              /*  ctx.strokeStyle= "grey";                ctx.lineWidth="2";                 ctx.beginPath();                ctx.moveTo(0, lineHeight + 1);                 ctx.lineTo(width, lineHeight + 1);                ctx.moveTo(0, height);                 ctx.lineTo(width, height);                 ctx.stroke();*/            }             function displayMaxZeroMin(ctx) {                var maxY = pixelFromVal(_displayMaxValue);                                ctx.strokeStyle= "LightSlateGray";                ctx.lineWidth="1";                ctx.beginPath();                ctx.moveTo(0, maxY);                 ctx.lineTo(width, maxY);                ctx.stroke();                 if (_displayMinValue != 0) {                     var zeroY = pixelFromVal(0);                    var minY = pixelFromVal(_displayMinValue);                    ctx.beginPath();                    ctx.moveTo(0, zeroY);                     ctx.lineTo(width, zeroY);                    ctx.moveTo(0, minY);                     ctx.lineTo(width, minY);                    ctx.stroke();                }             }                        var ctx = getContext("2d");            ctx.clearRect(0, 0, width, height);            ctx.font="12px Verdana";             displayBackground(ctx);                            for (var i = 0; i < _values.length; i++) {                plotValueHistory(ctx, _values[i].valueHistory, _values[i].color)                displayValueLegend(ctx, _values[i], i)            }             displayMaxZeroMin(ctx);             displayTitle(ctx, title, _displayMaxValue)        }    }     MouseArea {        id: hitbox        anchors.fill: mycanvas         onClicked: {            resetMax();            resetMin();        }    }}