gpt4 book ai didi

javascript - 多次复制 Canvas : clone the canvas or copy the image data?

转载 作者:数据小太阳 更新时间:2023-10-29 06:06:10 31 4
gpt4 key购买 nike

我的一个界面元素正在使用 HTML5 渲染 <canvas>元素和关联的 JavaScript API。此元素在同一屏幕上的多个位置以及整个应用程序的多个屏幕上使用。在需要的地方显示它的最有效方法是什么?

我的第一个想法是绘制到主 Canvas 上,然后将其复制并插入页面中需要的位置。主 Canvas 可能是这样的:

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 中的 Canvas 容器:

<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));
});
});

在 Canvas 上呈现的内容将比本示例中使用的简单正方形更复杂,但最终仍将只是一个静态图像。不过,也有可能有数十张不同的图像,每张图像每页都被克隆了数十次。

我想到的另一种方法是使用 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(从上面认为最好的任何解决方案)还是保存 CANVAS_ELEMENT.toDataURL() 的值?在 cookie 中然后在后续页面上使用它会更有效吗?

最佳答案

克隆 Canvas 将复制其尺寸和样式,但不会复制其图像数据。您可以通过在上下文中调用 drawImage 来复制图像数据。要将 originalCanvas 的内容绘制到 duplicateCanvas 上,请编写:

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

作为演示,以下代码片段生成了四个 Canvas :

  • 画有小场景的原始 Canvas

  • 仅通过调用 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将图像数据存储在浏览器中。或者,如果图像在用户 session 之间没有变化,您可以在服务器上将其呈现为 PNG 图像并使用 Cache-Control header 来鼓励浏览器访问 cache the image file for fast retrieval。 .

当涉及到客户端图像渲染的性能时,重新绘制场景可能比将字符串化的图像数据绘制到 Canvas 上更快。解码字符串和绘制像素是一项相对昂贵的操作。要确定在每个页面上重绘场景是否有意义,您可以使用 performance.now 为您的绘图操作计时,如代码片段所示。

关于javascript - 多次复制 Canvas : clone the canvas or copy the image data?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30116218/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com