我的一个界面元素正在使用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()
方法创建图像,并将其设置为适当的图像&#39;来源:
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中然后在后续页面上使用它会更有效吗?
答案 0 :(得分:6)
克隆画布将复制其尺寸和样式,但不会复制其图像数据。您可以通过在上下文中调用drawImage
来复制图像数据。要将originalCanvas
的内容绘制到duplicateCanvas
,请写:
duplicateCanvas.getContext('2d').drawImage(originalCanvas, 0, 0);
作为演示,以下代码段会生成四个画布:
原画布上画有小场景
仅通过调用cloneNode
通过致电cloneNode
和drawImage
通过创建新图像并将其源设置为数据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) + ' μ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();
&#13;
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;
}
&#13;
<div id="canvases"></div>
<div id="message"></div>
&#13;
如果您致电toDataURL
将图片数据复制到字符串中以便在其他页面中使用,请不要将字符串放入Cookie中。 Cookie旨在存储少量数据。而是使用HTML5 Web Storage API将图像数据存储在浏览器中。或者,如果图像在用户会话之间没有变化,您可以将其渲染为服务器上的PNG图像,并使用Cache-Control标头鼓励浏览器cache the image file for fast retrieval。
当涉及到客户端图像渲染的性能时,重新绘制场景可能比将字符串化图像数据绘制到画布上更快。解码字符串并绘制像素是一项相对昂贵的操作。要了解在每个页面上重绘场景是否有意义,您可以使用performance.now
计划绘图操作,如代码段所示。