Javascript 如何在单独的页面上同步两个画布元素
我需要在另一个页面上复制画布,这两个页面都与socket.io连接,所以我有一个通信通道 就我的研究而言,我可以使用Javascript 如何在单独的页面上同步两个画布元素,javascript,html,canvas,Javascript,Html,Canvas,我需要在另一个页面上复制画布,这两个页面都与socket.io连接,所以我有一个通信通道 就我的研究而言,我可以使用getImageData获取像素数据并发送到另一个页面,以便该页面绘制此画布,我将保持发送间隔,以便任何更改也将同步。。 (现在我正在编写代码,用于管理20x20像素块以及任何将复制到另一页的已更改块。) 同步意味着我还需要更改才能同步 有没有更好的解决办法?要同步,请仅在最后一刻更改内容,或不使用getImageData [此画布不是我的,它将不在我的控制范围内,因为我正在实施共
getImageData
获取像素数据并发送到另一个页面,以便该页面绘制此画布,我将保持发送间隔,以便任何更改也将同步。。
(现在我正在编写代码,用于管理20x20像素块以及任何将复制到另一页的已更改块。)
同步意味着我还需要更改才能同步
有没有更好的解决办法?要同步,请仅在最后一刻更改内容,或不使用getImageData
[此画布不是我的,它将不在我的控制范围内,因为我正在实施共同浏览解决方案,所以在代理端,我将渲染我控制范围内的画布。]取决于画布的大小和绘制频率,只使用
canvas.toBlob
或canvas.toDataURL
并发送整个画布可能更便宜
使用
getImageData
检查整个画布的更改可能非常昂贵,因为您必须迭代每个像素。如果每次都要更改大部分画布,我至少会使用canvas.toDataURL
测试发送整个画布,以发送base64编码版本。取决于画布的大小和绘制频率,只使用canvas.toBlob
或canvas.toDataURL
并发送整个画布可能更便宜
使用
getImageData
检查整个画布的更改可能非常昂贵,因为您必须迭代每个像素。如果每次都要更改大部分画布,我至少会使用canvas.toDataURL
测试发送整个画布,以发送base64编码版本。使用每次发射传输完整的画布内容是资源密集型且效率低下的。
想象一下,发送一个完整的300x300px图像,以将一个1x1px矩形绘制到画布上
相反,将每组绘图命令序列化(==每个beginPath
通过其结尾fill
/笔划
)。可以使用标记来表示每个图形命令
例如
ctx.beginPath();
ctx.moveTo(100,50);
ctx.lineTo(150,100);
ctx.lineTo(50,100);
ctx.closePath();
ctx.fillStyle='red';
ctx.fill();
。。。可以标记为:
var set1=[
['m',100,50],
['l',150,100],
['l',50,100],
['z'],
['fs','red'],
['f'],
['sequence',myOrder++],
['timestamp',performance.now()]
];
当然,您可以自定义特定于您的设计的任何复杂命令集。例如,您可能有一个移动整个20x20像素块的标记
您可以JSON.toString
此标记化命令集并将其广播给其他客户端(=其他页面)
当客户机收到消息时,他们可以使用JSON.parse对命令集进行重新水化,并在自己的画布上进行处理
让您开始学习的几点注意事项:
- emit可能会丢失,因此可以使用
序列
和时间戳
字段来请求丢失的数据包并正确排序数据包。您可以进行点对点数据包管理,但让服务器处理数据包管理更容易
- 有些画布操作不容易序列化。特别是,使用
getImageData
的像素操作不容易序列化(包括使用getImageData的第三方图像过滤器)
- 在实践中,您有时需要将所有画布“硬重置”为“最后已知良好”的内容状态。您可以通过清除所有画布并从一开始就重新发出所有命令集来实现这一点。为了提高效率,让服务器偶尔缓存最后一个已知良好画布的图像(以及在已知良好画布之后发出的任何命令集)。这样,如果需要,您可以硬重置
每次发射都要传输完整的画布内容,这是资源密集型且效率低下的。
想象一下,发送一个完整的300x300px图像,以将一个1x1px矩形绘制到画布上
相反,将每组绘图命令序列化(==每个beginPath
通过其结尾fill
/笔划
)。可以使用标记来表示每个图形命令
例如
ctx.beginPath();
ctx.moveTo(100,50);
ctx.lineTo(150,100);
ctx.lineTo(50,100);
ctx.closePath();
ctx.fillStyle='red';
ctx.fill();
。。。可以标记为:
var set1=[
['m',100,50],
['l',150,100],
['l',50,100],
['z'],
['fs','red'],
['f'],
['sequence',myOrder++],
['timestamp',performance.now()]
];
当然,您可以自定义特定于您的设计的任何复杂命令集。例如,您可能有一个移动整个20x20像素块的标记
您可以JSON.toString
此标记化命令集并将其广播给其他客户端(=其他页面)
当客户机收到消息时,他们可以使用JSON.parse对命令集进行重新水化,并在自己的画布上进行处理
让您开始学习的几点注意事项:
- emit可能会丢失,因此可以使用
序列
和时间戳
字段来请求丢失的数据包并正确排序数据包。您可以进行点对点数据包管理,但让服务器处理数据包管理更容易
- 有些画布操作不容易序列化。特别是,使用
getImageData
的像素操作不容易序列化(包括使用getImageData的第三方图像过滤器)
- 在实践中,您有时需要将所有画布“硬重置”为“最后已知良好”的内容状态。您可以通过清除所有画布并从一开始就重新发出所有命令集来实现这一点。为了提高效率,让服务器偶尔缓存最后一个已知良好画布的图像(以及在已知良好画布之后发出的任何命令集)。这样,如果需要,您可以硬重置
不使用间隔,只在绘制操作发生时发送数据…是的,我也会看一下。。甚至我也会将两者结合使用。因为在一秒钟内可能会有太多的绘图。请不要使用间隔,只在draw
操作发生时发送数据…是