Canvas Element

On of the strenghts of QML is its closeness to the Javascript ecosystem. This lets us reuse existing solutions from the web world and combine it with the native performance of QML visuals. However, sometimes we want to reuse graphics solutions from the web space too. That is where the Canvas element comes in handy. The canvas element provides an API very closely aligned to the drawing APIs for the identically named HTML element.

image

The fundamental idea of the canvas element is to render paths using a context 2D object. The context 2D object, contains the necessary graphics functions, whereas the canvas acts as the drawing canvas. The 2D context supports strokes, fills gradients, text and a different set of path creation commands.

Let’s see an example of a simple path drawing:

  1. import QtQuick
  2. Canvas {
  3. id: root
  4. // canvas size
  5. width: 200; height: 200
  6. // handler to override for drawing
  7. onPaint: {
  8. // get context to draw with
  9. var ctx = getContext("2d")
  10. // setup the stroke
  11. ctx.lineWidth = 4
  12. ctx.strokeStyle = "blue"
  13. // setup the fill
  14. ctx.fillStyle = "steelblue"
  15. // begin a new path to draw
  16. ctx.beginPath()
  17. // top-left start point
  18. ctx.moveTo(50,50)
  19. // upper line
  20. ctx.lineTo(150,50)
  21. // right line
  22. ctx.lineTo(150,150)
  23. // bottom line
  24. ctx.lineTo(50,150)
  25. // left line through path closing
  26. ctx.closePath()
  27. // fill using fill style
  28. ctx.fill()
  29. // stroke using line width and stroke style
  30. ctx.stroke()
  31. }
  32. }

This produces a filled rectangle with a starting point at 50,50 and a size of 100 and a stroke used as a border decoration.

image

The stroke width is set to 4 and uses a blue color define by strokeStyle. The final shape is set up to be filled through the fillStyle to a “steel blue” color. Only by calling stroke or fill the actual path will be drawn and they can be used independently from each other. A call to stroke or fill will draw the current path. It’s not possible to store a path for later reuse only a drawing state can be stored and restored.

In QML the Canvas element acts as a container for the drawing. The 2D context object provides the actual drawing operation. The actual drawing needs to be done inside the onPaint event handler.

  1. Canvas {
  2. width: 200; height: 200
  3. onPaint: {
  4. var ctx = getContext("2d")
  5. // setup your path
  6. // fill or/and stroke
  7. }
  8. }

The canvas itself provides a typical two-dimensional Cartesian coordinate system, where the top-left is the (0,0) point. A higher y-value goes down and a hight x-value goes to the right.

A typical order of commands for this path based API is the following:

  1. Setup stroke and/or fill
  2. Create path
  3. Stroke and/or fill
  1. onPaint: {
  2. var ctx = getContext("2d")
  3. // setup the stroke
  4. ctx.strokeStyle = "red"
  5. // create a path
  6. ctx.beginPath()
  7. ctx.moveTo(50,50)
  8. ctx.lineTo(150,50)
  9. // stroke path
  10. ctx.stroke()
  11. }

This produces a horizontal stroked line from point P1(50,50) to point P2(150,50).

image

TIP

Typically you always want to set a start point when you reset your path, so the first operation after beginPath is often moveTo.