簡體   English   中英

多次復制畫布:克隆畫布還是復制圖像數據?

[英]Duplicating a canvas many times: clone the canvas or copy the image data?

我的一個界面元素是使用HTML5 <canvas>元素和相關的JavaScript API呈現的。 此元素在整個應用程序的同一屏幕和多個屏幕上的多個位置使用。 在所需的任何地方展示這種效果的最有效方法是什么?

我的第一個想法是繪制一個主畫布,然后我克隆並插入頁面中需要的位置。 主畫布可能類似於:

var master = $('<canvas>').attr({
      width: 100,
      height: 100
    }),
    c = master[0],
    ctx = c.getContext("2d");

    ctx.fillStyle = "#FF0000";
    ctx.fillRect(0, 0, 150, 75);

假設我想在這些div容器中復制畫布:

<div class="square-container" id="square_header"></div>
...
<div class="square-container" id="square_dataTable"></div>
...
<div class="square-container" id="square_gallery"></div>
....

當頁面加載時,我將這樣做以在每個容器中插入一個重復的canvas元素:

$(document).ready(function() {
    $('.square-container').each(function() {
        master.clone().appendTo($(this));
    });
}); 

在畫布上呈現的內容將比本示例中使用的簡單方塊更復雜,但仍然只是一個靜態圖像。 但是,有可能每頁克隆數十個不同的圖像數十次。

我想到的另一種方法是使用toDataURL()方法創建一個圖像,並將其設置為適當的圖像源:

var master = $('<canvas>').attr({
    width: 100,
    height: 100
}),
    c = master[0],
    ctx = c.getContext("2d");

    ctx.fillStyle = "#FF0000";
    ctx.fillRect(0,0,150,75);

var square = c.toDataURL('image/png'); 

我會在必要時添加圖片標簽:

<img src="" id="square_header" class="square" alt="" />
...
<img src="" id="square_dataTable1" class="square" alt="" />
...
<img src="" id="square_gallery" class="square" alt="" />
....

然后將所有SRC設置為新創建的映像:

$(document).ready(function() {
    $('img.square').attr('src', square);
});

對我來說,它幾乎看起來像六個,另外六個。 但我想知道一種方式是否被認為比另一方更好? 如果在<canvas>上呈現的內容更復雜,那么一種方式比另一種更有效嗎?

同樣的精神,當我需要在后續頁面上使用該元素時,最好是在每個頁面上執行所有javascript(來自上面認為最佳的解決方案),或者將cookie中的CANVAS_ELEMENT.toDataURL()值保存在cookie中然后在后續頁面上使用它會更有效嗎?

克隆畫布將復制其尺寸和樣式,但不會復制其圖像數據。 您可以通過在上下文中調用drawImage來復制圖像數據。 要將originalCanvas的內容繪制到duplicateCanvas ,請寫入:

duplicateCanvas.getContext('2d').drawImage(originalCanvas, 0, 0);

作為演示,以下代碼段生成四個畫布:

  • 一個原始畫布,上面畫着一個小場景

  • 通過僅調用cloneNode的副本

  • 通過調用cloneNodedrawImage創建的副本

  • 通過創建新映像並將其源設置為數據URI而創建的副本

 function message(s) { document.getElementById('message').innerHTML += s + '<br />'; } function timeIt(action, description, initializer) { var totalTime = 0, initializer = initializer || function () {}; initializer(); var startTime = performance.now(); action(); var elapsed = performance.now() - startTime; message('<span class="time"><span class="number">' + Math.round(elapsed * 1000) + ' &mu;s</span></span> ' + description); } function makeCanvas() { var canvas = document.createElement('canvas'), context = canvas.getContext('2d'); canvas.width = 100; canvas.height = 100; timeIt(function () { context.fillStyle = '#a63d3d'; context.fillRect(10, 10, 80, 40); // Paint a small scene. context.fillStyle = '#3b618c'; context.beginPath(); context.arc(60, 60, 25, 0, 2*Math.PI); context.closePath(); context.fill(); }, '(millionths of a second) to draw original scene', function () { context.clearRect(0, 0, canvas.width, canvas.height); }); return canvas; } // copyCanvas returns a canvas containing the same image as the given canvas. function copyCanvas(original) { var copy; timeIt(function () { copy = original.cloneNode(); // Copy the canvas dimensions. copy.getContext('2d').drawImage(original, 0, 0); // Copy the image. }, 'to copy canvas with cloneNode and drawImage'); return copy; } // imageFromStorage extracts the image data from a canvas, stores the image data // in a browser session, then retrieves the image data from the session and // makes a new image element out of it. We measure the total time to retrieve // the data and make the image. function imageFromStorage(original) { var image, dataURI = original.toDataURL(); timeIt(function () { image = document.createElement('img'); image.src = dataURI; }, 'to make image from a dataURI'); return image; } function pageLoad() { var target = document.getElementById('canvases'), containers = {}, // We'll put the canvases inside divs. names = ['original', 'cloneNode', 'drawImage', 'dataURI']; for (var i = 0; i < names.length; ++i) { var name = names[i], // Use the name as an ID and a visible header. container = document.createElement('div'), header = document.createElement('div'); container.className = 'container'; header.className = 'header'; header.innerHTML = container.id = name; container.appendChild(header); target.appendChild(container); containers[name] = container; // The canvas container is ready. } var canvas = makeCanvas(); containers.original.appendChild(canvas); // Original canvas. containers.cloneNode.appendChild(canvas.cloneNode()); // cloneNode containers.drawImage.appendChild(copyCanvas(canvas)); // cloneNode + drawImage containers.dataURI.appendChild(imageFromStorage(canvas)); // localStorage } pageLoad(); 
 body { font-family: sans-serif; } .header { font-size: 18px; } .container { margin: 10px; display: inline-block; } canvas, img { border: 1px solid #eee; } #message { color: #666; font-size: 16px; line-height: 28px; } #message .time { display: inline-block; text-align: right; width: 100px; } #message .number { font-weight: bold; padding: 1px 3px; color: #222; background: #efedd4; } 
 <div id="canvases"></div> <div id="message"></div> 

如果調用toDataURL將圖像數據復制到字符串中以便在其他頁面中使用,請不要將字符串放入cookie中。 Cookie旨在存儲少量數據。 而是使用HTML5 Web Storage API將圖像數據存儲在瀏覽器中。 或者,如果圖像在用戶會話之間沒有變化,您可以將其渲染為服務器上的PNG圖像,並使用Cache-Control標頭來鼓勵瀏覽器緩存圖像文件以便快速檢索

當涉及到客戶端圖像渲染的性能時,重新繪制場景可能比將字符串化圖像數據繪制到畫布上更快。 解碼字符串並繪制像素是一項相對昂貴的操作。 要了解在每個頁面上重繪場景是否有意義,您可以使用performance.now為繪圖操作計時,如片段中所示。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM