QML Canvas Element and Javascript Performance



  • Hi,

    I've been playing around a bit with the QML Canvas element ("http://qt.gitorious.org/qt-labs/qmlcanvas":http://qt.gitorious.org/qt-labs/qmlcanvas). I started by modifying the graph example so that it produces a line graph that is updated as fast as possible with random data. I've found that the update rate gets very very slow as the number of points increases (for 250 points ~6 updates/second on my desktop machine!). Here is the code:

    @
    import "./Canvas"
    import Qt 4.7

    Canvas {
    width:600
    height:400
    property int count: 250
    property int graphPadding: 20
    property variant lastTime
    property variant currentTime

    Timer {
        interval: 1; running: true; repeat: true; onTriggered: requestPaint()
    }
    
    Component.onCompleted: {
        marker.minimumX = graphPadding
        marker.maximumX = width - graphPadding - marker.width
        lastTime = new Date()
        currentTime = new Date()
    }
    
    Text {
        id: updatesPerSecond
        anchors.right: parent.right
        anchors.top: parent.top
        text: ""
        color: "white"
    }
    
    onPaint:
    {
        currentTime = new Date()
        updatesPerSecond.text = (1000/(currentTime - lastTime)).toFixed(1) + " updates/second"
        lastTime = currentTime
    
        var ctx = getContext();        
        var tickWidth = 20;
        var numTicks = 10;
        var cHeight = height;
        var cWidth = width;
    
        ctx.fillStyle = '#000';
        ctx.fillRect(0, 0, width, height);
        ctx.strokeStyle = "rgb(150,150,150)";
        ctx.lineWidth = 1;
    
        // Draw Axis
        ctx.beginPath();
        ctx.moveTo(graphPadding, graphPadding);
        ctx.lineTo(graphPadding,cHeight - graphPadding);
        ctx.lineTo(cWidth - graphPadding, cHeight - graphPadding);
        ctx.stroke();
        ctx.closePath();
    
        // Draw ticks
        var tickSpacing = (cHeight - graphPadding*2)/(numTicks+1);
        ctx.beginPath();
        for(var i = 0; i <= numTicks; i++)
        {
            ctx.moveTo(graphPadding - tickWidth/2, graphPadding + tickSpacing*i);
            ctx.lineTo(graphPadding + tickWidth/2, graphPadding + tickSpacing*i);
        }
        ctx.stroke();
        ctx.closePath();
    
        // Draw gridlines
        ctx.beginPath();
        for(var i = 0; i <= numTicks; i++)
        {
            ctx.moveTo(graphPadding + tickWidth/2, graphPadding + tickSpacing*i);
            ctx.lineTo(cWidth - graphPadding, graphPadding + tickSpacing*i);
        }
        ctx.stroke();
        ctx.closePath();
    
        // Draw trace (with random data)
        var horizSpace = (cWidth - graphPadding * 2)/count
        var vertSpace = cHeight - (graphPadding * 2);
        var xPos = graphPadding
        var yPercent = 0
        var yPos = 0
        ctx.strokeStyle = '#ffff00'
        ctx.beginPath();
        for(var i = 0;i < count;i++)
        {
            yPercent  =  100 - Math.floor(Math.random()*100)
            yPos = (vertSpace * (yPercent / 100) + (graphPadding));
    
            if(i == 0)
                ctx.moveTo(xPos, yPos);
            else
                ctx.lineTo(xPos, yPos);
            xPos += horizSpace;
        }
        ctx.stroke();
        ctx.closePath();
    }
    

    }
    @

    After trying different things out, I've found that the culprit is the line

    @
    yPercent = 100 - Math.floor(Math.random()*100)
    @

    If I comment out the Math function calls and replace with a constant, the update rate goes up to ~60 updates/second. Why is this Javascript so slow? Is there anything I can do to increase the performance of random data generation (i.e., going to C++?)?

    As a side note, I've also noticed that if I try resizing the canvas window most of the screen will go white and I get the following error message in the output:

    "QPixmap::operator=: Cannot assign to pixmap during painting"

    I would have expected the canvas to resize and redraw correctly, but perhaps I don't understand the implementation well enough. Is there anything I can do to make the canvas resizing work as expected?

    Thanks!



  • I don't know why javascript is slow, but i'm guessing this will improve since Qt 5 is here with the V8 engine. (yes, the google javascript engine that they made for chrome)

    Anyway, a "solution" i can think of is just making a C++ function for it and call that. Or different (don't know if it's better), make a list of random values in C++, make that list available in QML and just use that for your random values.

    Good luck!



  • Hi,
    The http://qt.gitorious.org/qt-labs/qmlcanvas is a demo project and totally unpolished and discontinued. You can still use it with QtQuick 1.0, but for QtQuick2, there is already a builtin Canvas item to do the same thing. With many improvements in Qt5 (scene graph, v8, etc) the performance will be better and more completed in features.

    See the online documentation for more details:

    http://doc.qt.nokia.com/5.0-snapshot/qml-qtquick2-canvas.html



  • Sadly I'm using the QtQuick2 Canvas item in Qt 5.1 and performance is still pretty terrible. I'd recommend using C++ for any custom widgets.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.