We use a spirograph example from the Mozilla project as our foundation. The original HTML5 was posted as part of the canvas tutorial.
There were a few lines we needed to change:
Qt Quick requires you to declare a variable, so we needed to add some var declarations
for (var i=0;i<3;i++) {...}
We adapted the draw method to receive the Context2D object
functiondraw(ctx) {...}
We needed to adapt the translation for each spiro due to different sizes
ctx.translate(20+j*50,20+i*50);
Finally, we completed our onPaint handler. Inside we acquire a context and call our draw function.
onPaint: { var ctx = getContext("2d"); draw(ctx);}
The result is a ported spiro graph graphics running using the QML canvas.
As you can see, with no changes to the actual logic, and relatively few changes to the code itself, a port from HTML5 to QML is possible.
Glowing Lines
Here is another more complicated port from the W3C organization. The original pretty glowing lines has some pretty nice aspects, which makes the porting more challenging.
<!DOCTYPEHTML><htmllang="en"><head> <title>Pretty Glowing Lines</title></head><body><canvaswidth="800"height="450"></canvas><script>var context =document.getElementsByTagName('canvas')[0].getContext('2d');// initial start positionvar lastX =context.canvas.width *Math.random();var lastY =context.canvas.height *Math.random();var hue =0;// closure function to draw// a random bezier curve with random color with a glow effectfunctionline() {context.save();// scale with factor 0.9 around the center of canvascontext.translate(context.canvas.width/2,context.canvas.height/2);context.scale(0.9,0.9);context.translate(-context.canvas.width/2,-context.canvas.height/2);context.beginPath();context.lineWidth =5+Math.random() *10;// our start positioncontext.moveTo(lastX, lastY);// our new end position lastX =context.canvas.width *Math.random(); lastY =context.canvas.height *Math.random();// random bezier curve, which ends on lastX, lastYcontext.bezierCurveTo(context.canvas.width *Math.random(),context.canvas.height *Math.random(),context.canvas.width *Math.random(),context.canvas.height *Math.random(), lastX, lastY);// glow effect hue = hue +10*Math.random();context.strokeStyle ='hsl('+ hue +', 50%, 50%)';context.shadowColor ='white';context.shadowBlur =10;// stroke the curvecontext.stroke();context.restore();}// call line function every 50msecssetInterval(line,50);functionblank() {// makes the background 10% darker on each callcontext.fillStyle ='rgba(0,0,0,0.1)';context.fillRect(0,0,context.canvas.width,context.canvas.height);}// call blank function every 50msecssetInterval(blank,40);</script></body></html>
In HTML5 the Context2D object can paint at any time on the canvas. In QML it can only point inside the onPaint handler. The timer in usage with setInterval triggers in HTML5 the stroke of the line or to blank the screen. Due to the different handling in QML, it’s not possible to just call these functions, because we need to go through the onPaint handler. Also, the color presentations need to be adapted. Let’s go through the changes on by one.
Everything starts with the canvas element. For simplicity, we just use the Canvas element as the root element of our QML file.
To untangle the direct call of the functions through the setInterval, we replace the setInterval calls with two timers which will request a repaint. A Timer is triggered after a short interval and allows us to execute some code. As we can’t tell the paint function which operation we would like to trigger we define for each operation a bool flag request an operation and trigger then a repaint request.
Here is the code for the line operation. The blank operation is similar.
Now we have an indication which (line or blank or even both) operation we need to perform during the onPaint operation. As we enter the onPaint handler for each paint request we need to extract the initialization of the variable into the canvas element.