# HTML5画布移植(Porting from HTML5 Canvas)
* [https://developer.mozilla.org/en/Canvas_tutorial/Transformations](https://developer.mozilla.org/en/Canvas_tutorial/Transformations)
* [http://en.wikipedia.org/wiki/Spirograph](http://en.wikipedia.org/wiki/Spirograph)
移植一个HTML5画布图像到QML画布非常简单。在成百上千的例子中,我们选择了一个来移植。
**螺旋图形(Spiro Graph)**
我们使用一个来自Mozila项目的螺旋图形例子来作为我们的基础示例。原始的HTML5代码被作为画布教程发布。
下面是我们需要修改的代码:
* Qt Quick要求定义变量使用,所以我们需要添加var的定义:
```
for (var i=0;i<3;i++) {
...
}
```
* 修改绘制方法接收Context2D对象:
```
function draw(ctx) {
...
}
```
* 由于不同的大小,我们需要对每个螺旋适配转换:
```
ctx.translate(20+j*50,20+i*50);
```
最后我们实现onPaint操作。在onPaint中我们请求一个context,并且调用我们的绘制方法。
```
onPaint: {
var ctx = getContext("2d");
draw(ctx);
}
```
下面这个结果就是我们使用QML画布移植的螺旋图形。

**发光线(Glowing Lines)**
下面有一个更加复杂的移植来自W3C组织。[原始的发光线](http://www.w3.org/TR/2dcontext/#examples)有些很不错的地方,这使得移植更加具有挑战性。

```
Pretty Glowing Lines
```
在HTML5中,context2D对象可以随意在画布上绘制。在QML中,只能在onPaint操作中绘制。在HTML5中,通常调用setInterval使用计时器触发线段的绘制或者清屏。由于QML中不同的操作方法,仅仅只是调用这些函数不能实现我们想要的结果,因为我们需要通过onPaint操作来实现。我们也需要修改颜色的格式。让我们看看需要改变哪些东西。
修改从画布元素开始。为了简单,我们使用画布元素(Canvas)作为我们QML文件的根元素。
```
import QtQuick 2.0
Canvas {
id: canvas
width: 800; height: 450
...
}
```
代替直接调用的setInterval函数,我们使用两个计时器来请求重新绘制。一个计时器触发间隔较短,允许我们可以执行一些代码。我们无法告诉绘制函数哪个操作是我想触发的,我们为每个操作定义一个布尔标识,当重新绘制请求时,我们请求一个操作并且触发它。
下面是线段绘制的代码,清屏操作类似。
```
...
property bool requestLine: false
Timer {
id: lineTimer
interval: 40
repeat: true
triggeredOnStart: true
onTriggered: {
canvas.requestLine = true
canvas.requestPaint()
}
}
Component.onCompleted: {
lineTimer.start()
}
...
```
现在我们已经有了告诉onPaint操作中我们需要执行哪个操作的指示。当我们进入onPaint处理每个绘制请求时,我们需要提取画布元素中的初始化变量。
```
Canvas {
...
property real hue: 0
property real lastX: width * Math.random();
property real lastY: height * Math.random();
...
}
```
现在我们的绘制函数应该像这样:
```
onPaint: {
var context = getContext('2d')
if(requestLine) {
line(context)
requestLine = false
}
if(requestBlank) {
blank(context)
requestBlank = false
}
}
```
线段绘制函数提取画布作为一个参数。
```
function line(context) {
context.save();
context.translate(canvas.width/2, canvas.height/2);
context.scale(0.9, 0.9);
context.translate(-canvas.width/2, -canvas.height/2);
context.beginPath();
context.lineWidth = 5 + Math.random() * 10;
context.moveTo(lastX, lastY);
lastX = canvas.width * Math.random();
lastY = canvas.height * Math.random();
context.bezierCurveTo(canvas.width * Math.random(),
canvas.height * Math.random(),
canvas.width * Math.random(),
canvas.height * Math.random(),
lastX, lastY);
hue += Math.random()*0.1
if(hue > 1.0) {
hue -= 1
}
context.strokeStyle = Qt.hsla(hue, 0.5, 0.5, 1.0);
// context.shadowColor = 'white';
// context.shadowBlur = 10;
context.stroke();
context.restore();
}
```
最大的变化是使用QML的Qt.rgba()和Qt.hsla()。在QML中需要把变量值适配在0.0到1.0之间。
同样应用在清屏函数中。
```
function blank(context) {
context.fillStyle = Qt.rgba(0,0,0,0.1)
context.fillRect(0, 0, canvas.width, canvas.height);
}
```
下面是最终结果(目前没有阴影)类似下面这样。

查看下面的链接获得更多的信息:
* [W3C HTML Canvas 2D Context Specification](http://www.w3.org/TR/2dcontext/)
* [Mozilla Canvas Documentation](https://developer.mozilla.org/en/HTML/Canvas)
* [HTML5 Canvas Tutorial](http://www.html5canvastutorials.com/)