<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                #(89):Canvas(續) ## 變換 `Canvas`中的“變形”,主要指的是坐標系的變換,而不是路徑的變換。這與 QML 元素變換非常相似,都可以實現坐標系統的`scale`(縮放)、`rotate`(旋轉)和`translate`(平移);不同的是,變換的原點是畫布原點。例如,如果以一個路徑的中心點為定點進行縮放,那么,你需要現將畫布原點移動到路徑中心點。我們也可以使用變換函數實現復雜的變換。理解“變換是針對坐標系的”這一點非常重要,有時候可以避免很多意外的結果。 ~~~ import QtQuick 2.0 Canvas { id: root width: 240; height: 120 onPaint: { var ctx = getContext("2d") ctx.strokeStyle = "blue" ctx.lineWidth = 4 ctx.translate(120, 60) ctx.strokeRect(-20, -20, 40, 40) // draw path now rotated ctx.strokeStyle = "green" ctx.rotate(Math.PI / 4) ctx.strokeRect(-20, -20, 40, 40) ctx.restore() } } ~~~ 運行結果如下: [![](https://box.kancloud.cn/2015-12-29_5682328ea20ee.png)](http://files.devbean.net/images/2015/09/qq-canvas-transform.png) 通過調用`resetTransform()`函數,可以將變換矩陣重置為單位矩陣: ~~~ ctx.resetTransform() ~~~ ## 組合 組合意思是,將你繪制的圖形與已存在的像素做一些融合操作。`canvas支持幾種組合方式,使用`globalCompositeOperation`可以設置組合的模式。如下代碼所示,我們可以看到組合的相應表現:` ~~~ import QtQuick 2.0 Canvas { id: root width: 600; height: 450 property var operation : [ 'source-over', 'source-in', 'source-over', 'source-atop', 'destination-over', 'destination-in', 'destination-out', 'destination-atop', 'lighter', 'copy', 'xor', 'qt-clear', 'qt-destination', 'qt-multiply', 'qt-screen', 'qt-overlay', 'qt-darken', 'qt-lighten', 'qt-color-dodge', 'qt-color-burn', 'qt-hard-light', 'qt-soft-light', 'qt-difference', 'qt-exclusion' ] onPaint: { var ctx = getContext('2d') for(var i=0; i<operation.length; i++) { var dx = Math.floor(i%6)*100 var dy = Math.floor(i/6)*100 ctx.save() ctx.fillStyle = '#33a9ff' ctx.fillRect(10+dx,10+dy,60,60) // TODO: does not work yet ctx.globalCompositeOperation = root.operation[i] ctx.fillStyle = '#ff33a9' ctx.globalAlpha = 0.75 ctx.beginPath() ctx.arc(60+dx, 60+dy, 30, 0, 2*Math.PI) ctx.closePath() ctx.fill() ctx.restore() } } } ~~~ 代碼運行結果如下: [![](https://box.kancloud.cn/2015-12-29_5682328eb4a02.png)](http://files.devbean.net/images/2015/09/canvas-composition.png) ## 像素緩存 使用`canvas`,你可以將`canvas`內容的像素數據讀取出來,并且能夠針對這些數據做一些操作。 使用`createImageData(sw, sh)`或`getImageData(sx, sy, sw, sh)`函數可以讀取圖像數據。這兩個函數都會返回一個`ImageData`對象,該對象具有`width`、`height`和`data`等變量。`data`包含一個以 RGBA 格式存儲的像素一維數組,其每一個分量值的范圍都是 [0, 255]。如果要設置畫布上面的像素,可以使用`putImageData(imagedata, dx, dy)`函數。 另外一個獲取畫布內容的方法是,將數據保存到一個圖片。這可以通過`Canvas`的函數`save(path)`或`toDataURL(mimeType)`實現,后者會返回一個圖像的 URL,可以供`Image`元素加載圖像。 ~~~ import QtQuick 2.0 Rectangle { width: 240; height: 120 Canvas { id: canvas x: 10; y: 10 width: 100; height: 100 property real hue: 0.0 onPaint: { var ctx = getContext("2d") var x = 10 + Math.random(80)*80 var y = 10 + Math.random(80)*80 hue += Math.random()*0.1 if(hue > 1.0) { hue -= 1 } ctx.globalAlpha = 0.7 ctx.fillStyle = Qt.hsla(hue, 0.5, 0.5, 1.0) ctx.beginPath() ctx.moveTo(x+5,y) ctx.arc(x,y, x/10, 0, 360) ctx.closePath() ctx.fill() } MouseArea { anchors.fill: parent onClicked: { var url = canvas.toDataURL('image/png') print('image url=', url) image.source = url } } } Image { id: image x: 130; y: 10 width: 100; height: 100 } Timer { interval: 1000 running: true triggeredOnStart: true repeat: true onTriggered: canvas.requestPaint() } } ~~~ 在上面的例子中,我們創建了兩個畫布,左側的畫布每一秒產生一個圓點;鼠標點擊會將畫布內容保存,并且生成一個圖像的 URL,右側則會顯示這個圖像。 ## Canvas 繪制 下面我們利用`Canvas`元素創建一個畫板程序。我們程序的運行結果如下所示: [![](https://box.kancloud.cn/2015-12-29_5682328ec953a.png)](http://files.devbean.net/images/2015/09/canvas-painter.png) 窗口上方是調色板,用于設置畫筆顏色。色板是一個填充了顏色的矩形,其中覆蓋了一個鼠標區域,用于檢測鼠標點擊事件。 ~~~ Row { id: colorTools anchors { horizontalCenter: parent.horizontalCenter top: parent.top topMargin: 8 } property color paintColor: "#33B5E5" spacing: 4 Repeater { model: ["#33B5E5", "#99CC00", "#FFBB33", "#FF4444"] ColorSquare { id: red color: modelData active: parent.paintColor === color onClicked: { parent.paintColor = color } } } } ~~~ 調色板所支持的顏色保存在一個數組中,畫筆的當前顏色則保存在`paintColor`屬性。當用戶點擊調色板的一個色塊,該色塊的顏色就會被賦值給`paintColor`屬性。 為了監聽鼠標事件,我們在畫布上面覆蓋了一個鼠標區域,利用鼠標按下和位置改變的信號處理函數完成繪制: ~~~ Canvas { id: canvas anchors { left: parent.left right: parent.right top: colorTools.bottom bottom: parent.bottom margins: 8 } property real lastX property real lastY property color color: colorTools.paintColor onPaint: { var ctx = getContext('2d') ctx.lineWidth = 1.5 ctx.strokeStyle = canvas.color ctx.beginPath() ctx.moveTo(lastX, lastY) lastX = area.mouseX lastY = area.mouseY ctx.lineTo(lastX, lastY) ctx.stroke() } MouseArea { id: area anchors.fill: parent onPressed: { canvas.lastX = mouseX canvas.lastY = mouseY } onPositionChanged: { canvas.requestPaint() } } } ~~~ 鼠標左鍵按下時,其初始位置保存在`lastX`和`lastY`兩個屬性。鼠標位置的改變會請求畫布進行重繪,該請求則會調用`onPaint()`處理函數。 最后,為了繪制用戶筆記,在`onPaint()`處理函數中,我們首先創建了一個新的路徑,將其移動到最后的位置,然后我們從鼠標區域獲得新的位置,在最后的位置與新的位置之間繪制直線,同時,將當前鼠標位置(也就是新的位置)設置為新的最后的位置。 ## 從 HTML5 移植 由于 QML 的`Canvas`對象由 HTML 5 的 canvas 標簽借鑒而來,將 HTML 5 的 canvas 應用移植到 QML?`Canvas`也是相當容易。我們以 Mozilla 提供的繁華曲線頁面為例,演示移植的過程。可以在[這里](http://files.devbean.net/code/spirograph.html)看到該頁面的運行結果。下面是 HTML 5 canvas 的腳本部分: ~~~ function draw() { var ctx = document.getElementById('canvas').getContext('2d'); ctx.fillRect(0,0,300,300); for (var i=0;i<3;i++) { for (var j=0;j<3;j++) { ctx.save(); ctx.strokeStyle = "#9CFF00"; ctx.translate(50+j*100,50+i*100); drawSpirograph(ctx,20*(j+2)/(j+1),-8*(i+3)/(i+1),10); ctx.restore(); } } } function drawSpirograph(ctx,R,r,O){ var x1 = R-O; var y1 = 0; var i = 1; ctx.beginPath(); ctx.moveTo(x1,y1); do { if (i>20000) break; var x2 = (R+r)*Math.cos(i*Math.PI/72) - (r+O)*Math.cos(((R+r)/r)*(i*Math.PI/72)) var y2 = (R+r)*Math.sin(i*Math.PI/72) - (r+O)*Math.sin(((R+r)/r)*(i*Math.PI/72)) ctx.lineTo(x2,y2); x1 = x2; y1 = y2; i++; } while (x2 != R-O && y2 != 0 ); ctx.stroke(); } draw(); ~~~ 這里我們只解釋如何進行移植,有關繁花曲線的算法則不在我們的闡述范圍之內。幸運的是,我們需要改變的代碼很少,因而這里也會很短。 HTML 按照順序執行,draw() 會成為腳本的入口函數。但是在 QML 中,繪制必須在 onPaint 中完成,因此,我們需要將 draw() 函數的調用移至 onPaint。通常我們會在 onPaint 中獲取繪制上下文,因此,我們將給 draw() 函數添加一個參數,用于接受`Context2D`對象。事實上,這就是我們所有的修改。移植之后的 QML 如下所示: ~~~ import QtQuick 2.2 Canvas { id: root width: 300; height: 300 onPaint: { var ctx = getContext("2d"); draw(ctx); } function draw (ctx) { ctx.fillRect(0, 0, 300, 300); for (var i = 0; i < 3; i++) { for (var j = 0; j < 3; j++) { ctx.save(); ctx.strokeStyle = "#9CFF00"; ctx.translate(50 + j * 100, 50 + i * 100); drawSpirograph(ctx, 20 * (j + 2) / (j + 1), -8 * (i + 3) / (i + 1), 10); ctx.restore(); } } } function drawSpirograph (ctx, R, r, O) { var x1 = R - O; var y1 = 0; var i = 1; ctx.beginPath(); ctx.moveTo(x1, y1); do { if (i > 20000) break; var x2 = (R + r) * Math.cos(i * Math.PI / 72) - (r + O) * Math.cos(((R + r) / r) * (i * Math.PI / 72)) var y2 = (R + r) * Math.sin(i * Math.PI / 72) - (r + O) * Math.sin(((R + r) / r) * (i * Math.PI / 72)) ctx.lineTo(x2, y2); x1 = x2; y1 = y2; i++; } while (x2 != R-O && y2 != 0 ); ctx.stroke(); } } ~~~ 運行一下這段代碼: [![](https://box.kancloud.cn/2015-12-29_5682328ed7bb0.png)](http://files.devbean.net/images/2015/09/canvas-from-html5.png)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看