- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有一个方法,可以在使用 requestAnimationFrame
下次重新绘制之前在 Canvas
中渲染矩形矩阵。我正在努力实现最佳表现。我解决这个问题的第一个方法是在 Canvas
中实时创建矩形。
render(display: PanelDisplay): void {
const ctx = this.parameters.canva.getContext("2d");
const widthEachBit = Math.floor(this.parameters.canva.width / display[0].length);
const heightEachBit = Math.floor(this.parameters.canva.height / display.length);
ctx.lineWidth = 1;
ctx.strokeStyle = this.parameters.colorStroke;
for(var i = 0; i < display.length; i++) {
for(var j = 0; j < display[i].length; j++) {
const x = j*widthEachBit;
const y = i*heightEachBit;
ctx.beginPath();
ctx.fillStyle = display[i][j] == 1 ? this.parameters.colorBitOn : this.parameters.colorBitOff;
ctx.rect(x, y, widthEachBit, heightEachBit);
ctx.fill();
ctx.stroke();
}
}
}
这样做会导致 3k 元素矩阵的性能平庸:
作为第二种方法,我决定预渲染两个矩形并使用 drawImage
将它们渲染在 Canvas
上:
render(display: PanelDisplay): void {
const ctx = this.parameters.canva.getContext("2d");
const widthEachBit = Math.floor(this.parameters.canva.width / display[0].length);
const heightEachBit = Math.floor(this.parameters.canva.height / display.length);
// Render the different canvas once before instead of recalculating every loop
const prerenderedBitOn = this._prerenderBit(this._prerenderedOn, widthEachBit, heightEachBit, this.parameters.colorBitOn);
const prerenderedBitOff = this._prerenderBit(this._prerenderedOff, widthEachBit, heightEachBit, this.parameters.colorBitOff);
for(var i = 0; i < display.length; i++) {
for(var j = 0; j < display[i].length; j++) {
const x = j*widthEachBit;
const y = i*heightEachBit;
ctx.drawImage(display[i][j] == 1 ? prerenderedBitOn : prerenderedBitOff, x, y);
}
}
}
private _prerenderBit(canvas: HTMLCanvasElement, widthEachBit: number, heightEachBit: number, color: string) {
canvas.width = widthEachBit;
canvas.height = heightEachBit;
const ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.fillStyle = color;
ctx.rect(0, 0, widthEachBit, heightEachBit);
ctx.fill();
ctx.lineWidth = 1;
ctx.strokeStyle = this.parameters.colorStroke;
ctx.stroke();
return canvas;
}
这样做的结果是,我在 Firefox 中得到了更好的结果,而在 Chrome 中得到了最差的结果:
我不太确定如何解释这些结果。作为第三种方法,我正在考虑预先创建 n 个 Canvas,其中 n 是矩阵的大小,并且仅更新下一次重新绘制之前需要的内容。在此之前,我想了解一下为什么我在一个浏览器上预渲染的结果更好,而在另一种浏览器上预渲染的结果最差。我还希望得到任何反馈以获得更好的性能。如有必要,我可以提供性能堆栈跟踪。
最佳答案
不同的结果可能是由于 API 的不同实现,甚至可能是您在浏览器上设置的不同设置导致的,这使得一个人更喜欢 GPU 加速而不是 CPU 计算,或者一个人比另一个人处理更好的图形内存或者其他什么。
但无论如何,如果我正确理解您的代码,您可以获得比这两个选项更好的结果。
我可以想到两种主要方法,您必须测试它们。
第一个是以一种颜色渲染整个矩阵大小的一个大矩形,然后循环使用另一种颜色的所有单元格,并将它们组合在一个子路径中,以便您调用 fill( )
仅在此子路径组合的末尾出现一次。
最后,您将在所有这些上绘制网格(网格可以是简单的十字图案,或者在屏幕外 Canvas 上预渲染,或者再次是单个子路径)。
const W = 50;
const H = 50;
const cellSize = 10;
const grid_color = 'black';
var grid_mode = 'inline';
const ctx = canvas.getContext('2d');
const matrix = [];
canvas.width = W * cellSize;
canvas.height = H * cellSize;
for (let i = 0; i < H; i++) {
let row = [];
matrix.push(row);
for (let j = 0; j < W; j++) {
row.push(Math.random() > 0.5 ? 0 : 1);
}
}
const grid_pattern = generateGridPattern();
const grid_img = generateGridImage();
draw();
function draw() {
shuffle();
// first draw all our green rects ;)
ctx.fillStyle = 'green';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// now draw all the red ones
ctx.fillStyle = 'red';
ctx.beginPath(); // single sub-path declaration
for (let i = 0; i < H; i++) {
for (let j = 0; j < W; j++) {
// only if a red cell
if (matrix[i][j])
ctx.rect(i * cellSize, j * cellSize, cellSize, cellSize);
}
}
ctx.fill(); // single fill operation
drawGrid();
requestAnimationFrame(draw);
}
function shuffle() {
let r = Math.floor(Math.random() * H);
for (let i = r; i < r + Math.floor(Math.random() * (H - r)); i++) {
let r = Math.floor(Math.random() * W);
for (let j = r; j < r + Math.floor(Math.random() * (W - r)); j++) {
matrix[i][j] = +!matrix[i][j];
}
}
}
function drawGrid() {
if (grid_mode === 'pattern') {
ctx.fillStyle = grid_pattern;
ctx.beginPath();
ctx.rect(0, 0, canvas.width, canvas.height);
ctx.translate(-cellSize / 2, -cellSize / 2);
ctx.fill();
ctx.setTransform(1, 0, 0, 1, 0, 0);
} else if (grid_mode === 'image') {
ctx.drawImage(grid_img, 0, 0);
} else {
ctx.strokeStyle = grid_color;
ctx.beginPath();
for (let i = 0; i <= cellSize * H; i += cellSize) {
ctx.moveTo(0, i);
ctx.lineTo(cellSize * W, i);
for (let j = 0; j <= cellSize * W; j += cellSize) {
ctx.moveTo(j, 0);
ctx.lineTo(j, cellSize * H);
}
}
ctx.stroke();
}
}
function generateGridPattern() {
const ctx = Object.assign(
document.createElement('canvas'), {
width: cellSize,
height: cellSize
}
).getContext('2d');
// make a cross
ctx.beginPath();
ctx.moveTo(cellSize / 2, 0);
ctx.lineTo(cellSize / 2, cellSize);
ctx.moveTo(0, cellSize / 2);
ctx.lineTo(cellSize, cellSize / 2);
ctx.strokeStyle = grid_color;
ctx.lineWidth = 2;
ctx.stroke();
return ctx.createPattern(ctx.canvas, 'repeat');
}
function generateGridImage() {
grid_mode = 'inline';
drawGrid();
const buf = canvas.cloneNode(true);
buf.getContext('2d').drawImage(canvas, 0, 0);
ctx.clearRect(0, 0, canvas.width, canvas.height);
return buf;
}
field.onchange = e => {
grid_mode = document.querySelector('input:checked').value;
}
<fieldset id="field">
<legend>Draw grid using:</legend>
<label><input name="grid" type="radio" value="inline" checked>inline</label>
<label><input name="grid" type="radio" value="pattern">pattern</label>
<label><input name="grid" type="radio" value="image">image</label>
</fieldset>
<canvas id="canvas"></canvas>
您可以采取的另一种完全不同的方法是直接操作 ImageData。将其设置为矩阵的大小(cellSize 为 1),将其放在 Canvas 上,最后按比例重新绘制它,然后绘制网格。
ctx.putImageData(smallImageData, 0,0);
ctx.imageSmoothingEnabled = false;
ctx.drawImage(ctx.canvas, 0, 0, ctx.canvas.width, ctx.canvas.height);
drawgrid();
const W = 50;
const H = 50;
const cellSize = 10;
const grid_color = 'black';
canvas.width = W * cellSize;
canvas.height = H * cellSize;
const ctx = canvas.getContext('2d');
// we'll do the matrix operations directly on an imageData
const imgData = ctx.createImageData(W, H);
const matrix = new Uint32Array(imgData.data.buffer);
const red = 0xFF0000FF;
const green = 0xFF008000;
for (let i = 0; i < H*W; i++) {
matrix[i] = (Math.random() > 0.5 ? green : red);
}
prepareGrid();
ctx.imageSmoothingEnabled = false;
draw();
function draw() {
shuffle();
// put our update ImageData
ctx.putImageData(imgData, 0, 0);
// scale its result
ctx.drawImage(ctx.canvas,
0,0,W,H,
0,0,canvas.width,canvas.height
);
// draw the grid which is already drawn in memory
ctx.stroke();
requestAnimationFrame(draw);
}
function shuffle() {
// here 'matrix' is actually the data of our ImageData
// beware it is a 1D array, so we need to normalize the coords
let r = Math.floor(Math.random() * H);
for (let i = r; i < r + Math.floor(Math.random() * (H - r)); i++) {
let r = Math.floor(Math.random() * W);
for (let j = r; j < r + Math.floor(Math.random() * (W - r)); j++) {
matrix[i*W + j] = matrix[i*W + j] === red ? green : red;
}
}
}
function prepareGrid() {
// we draw it only once in memory
// 'draw()' will then just have to call ctx.stroke()
ctx.strokeStyle = grid_color;
ctx.beginPath();
for (let i = 0; i <= cellSize * H; i += cellSize) {
ctx.moveTo(0, i);
ctx.lineTo(cellSize * W, i);
for (let j = 0; j <= cellSize * W; j += cellSize) {
ctx.moveTo(j, 0);
ctx.lineTo(j, cellSize * H);
}
}
}
<canvas id="canvas"></canvas>
关于javascript - 预渲染与实时 Canvas 渲染时的奇怪结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52335088/
Closed. This question is opinion-based。它当前不接受答案。 想改善这个问题吗?更新问题,以便editing this post用事实和引用来回答。 2年前关闭。
我想显示我的网站上所有用户都在线(实时;就像任何聊天模块一样)。我正在使用下面提到的脚本来执行此操作。 HTML: Javascript: var doClose = false; documen
有什么方法可以知道 Algolia 何时成功处理了排队作业,或者与上次重新索引相比,Algolia 是否索引了新文档? 我们希望建立一个系统,每当新文档被索引时,浏览网站的用户都会收到实时更新警告,并
构建将在“桌面”而不是浏览器中运行的 Java 应用程序的推荐策略是什么。该应用程序的特点是: 1. Multiple application instances would be running o
这是场景: 我正在编写一个医疗相关程序,可以在没有连接的情况下使用。当采取某些措施时,程序会将时间写入CoreData记录。 这就是问题所在,如果他们的设备将时间设置为比实际时间早的时间。那将是一个大
我有: $(document).ready(function () { $(".div1, .div2, .div3, .div4, .div5").draggable();
我有以下 jquery 代码: $("a[id*='Add_']").live('click', function() { //Get parentID to add to. var
我有一个 jsp 文件,其中包含一个表单。提交表单会调用处理发送的数据的 servlet。我希望当我点击提交按钮时,一个文本区域被跨越并且应该实时显示我的应用程序的日志。我正在使用 Tomcat 7。
我编辑了我的问题,我在 Default.aspx 页面中有一个提交按钮和文本框。我打开两个窗口Default.aspx。我想在这个窗口中向文本框输入文本并按提交,其他窗口将实时更新文本框。 请帮助我!
我用 php 创建了一个小型 CMS,如果其他用户在线或离线,我想显示已登录的用户。 目前,我只创建一个查询请求,但这不会一直更新。我希望用户在发生某些事情时立即看到更改。我正在寻找一个类似于 fac
我有以下问题需要解决。我必须构建一个图形查看器来查看海量数据集。 我们有一些特定格式的文件,其中包含数百万条代表实验结果的记录。每条记录代表大图上的一个样本点。我见过的最大的文件有 4370 万条记录
我最近完成了申请,但遇到了一个大问题。我一次只需要允许 1 个用户访问它。每个用户每次都可以访问一个索引页面和“开始”按钮。当用户点击开始时,应用程序锁定,其他人需要等到用户完成。当用户关闭选项卡/浏
我是 Android 开发新手。我正在寻找任何将音高变换应用到输出声音(实时)的方法。但我找不到任何起点。 我找到了这个 topic但我仍然不知道如何应用它。 有什么建议吗? 最佳答案 一般来说,该算
背景 用户计算机上的桌面应用程序从调制解调器获取电话号码,并在接到电话后将其发送到 PHP 脚本。目前,我可以通过 PHP 在指定端口上接收数据/数据包。然后我有一个连接到 411 数据库并返回指定电
很抱歉提出抽象问题,但我正在寻找一些关于在循环中执行一些等效操作的应用程序类型的示例/建议/文章,并且循环的每次迭代都应该在特定时间部分公开其结果(例如, 10 秒)。 我的应用程序在外部 WCF 服
这个问题在这里已经有了答案: 关闭 10 年前。 Possible Duplicate: What specifically are wall-clock-time, user-cpu-time,
我最近遇到了一个叫做 LiveChart 的工具,决定试用一下。 不幸的是,我在弄清楚如何实时更新图表值时遇到了一些问题。我很确定有一种干净正确的方法可以做到这一点,但我找不到它。 我希望能够通过 p
我正在实现实时 flutter 库 https://pub.dartlang.org/packages/true_time 遇到错误 W/DiskCacheClient(26153): Cannot
我一直在使用 instagram 的实时推送 api ( http://instagram.com/developer/realtime/ ) 来获取特定位置的更新。我使用“半径”的最大可能值,即 5
关闭。这个问题不满足Stack Overflow guidelines .它目前不接受答案。 想改善这个问题吗?更新问题,使其成为 on-topic对于堆栈溢出。 7年前关闭。 Improve thi
我是一名优秀的程序员,十分优秀!