Javascript 两个人在同一张画布上画画
我正在html5画布上制作一个实时绘画应用程序。当一个用户在画布上绘制时,一切都会正常进行,但当两个用户同时绘制时,一切都会变得一团糟,例如,如果一个用户更改颜色,所有客户端的颜色都会更改,线条从一个点开始绘制到另一个点。如何解决这个问题?谢谢,这是我的密码Javascript 两个人在同一张画布上画画,javascript,html,canvas,socket.io,real-time,Javascript,Html,Canvas,Socket.io,Real Time,我正在html5画布上制作一个实时绘画应用程序。当一个用户在画布上绘制时,一切都会正常进行,但当两个用户同时绘制时,一切都会变得一团糟,例如,如果一个用户更改颜色,所有客户端的颜色都会更改,线条从一个点开始绘制到另一个点。如何解决这个问题?谢谢,这是我的密码 var canvas = document.getElementById("myCanvas"); var context = canvas.getContext("2d"); canvas.width="600"; canvas.heig
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
canvas.width="600";
canvas.height="500";
var radius = 10;
var mouse = {x:0,y:0};
var drag = false;
var imageObj = new Image();
imageObj.onload = function() {
context.drawImage(imageObj, 20, 20);
};
imageObj.src = 'rhino4.png';
$scope.colorChange = function(color){
Socket.emit("colorChange",color);
};
Socket.on("colorChange",function (color) {
context.strokeStyle = color;
context.fillStyle = color;
})
$scope.radiusChange = function(size) {
Socket.emit("radiusChange",size);
}
Socket.on("radiusChange",function (size) {
radius = size;
context.lineWidth = radius*2;
})
context.lineWidth = radius*2;
var putPoint = function (mouse) {
if(drag){
context.lineTo(mouse.x,mouse.y)
context.stroke();
context.beginPath();
context.arc(mouse.x,mouse.y,radius,0,Math.PI*2);
context.fill();
context.beginPath();
context.moveTo(mouse.x,mouse.y);
context.globalCompositeOperation='source-atop';
context.drawImage(imageObj, 20, 20);
context.globalCompositeOperation='source-over';
}
}
Socket.on("putPoint",function (mouse) {
putPoint(mouse);
});
var engage = function(mouse){
console.log("in engage",mouse);
drag = true;
putPoint(mouse);
}
var disengage = function(){
drag = false;
context.beginPath();
}
var socketPutPoint = function(e){
mouse.x = e.offsetX;
mouse.y = e.offsetY;
Socket.emit("putPoint",mouse);
}
Socket.on("engage",function (mouse) {
console.log("engaging");
engage(mouse);
});
var socketEngage = function (e) {
mouse.x = e.offsetX;
mouse.y = e.offsetY;
console.log(mouse);
Socket.emit("engage",mouse);
}
var socketDisengage = function (e) {
mouse.x = e.offsetX;
mouse.y = e.offsetY;
console.log(mouse);
Socket.emit("disengage",mouse);
}
Socket.on("disengage",function (mouse) {
disengage();
})
canvas.addEventListener('mouseup',socketDisengage);
canvas.addEventListener('mouseleave',socketDisengage);
canvas.addEventListener('mousedown',socketEngage);
canvas.addEventListener('mousemove',socketPutPoint);
我曾想过在putpoint之后在colorChange方法中将颜色更改回原始颜色,但这似乎不起作用您需要跟踪每个客户端的最后一点,然后再发布context.lineTomouse.x,y移动到客户端的最后一个点,该点也将应用于颜色,以便设置正确的客户端颜色 要获得理想,您可以尝试执行以下操作: 在mousedown处理程序socketEngage上添加原始代码 mouse.last_x=e.offsetX; mouse.last_y=e.offsetY 函数的开头 在mousemove处理程序socketPutPoint中 mouse.last_x=mouse.x; mouse.last_y=mouse.y 函数的开头 并在context.lineTomouse.x、mouse.y之前的putPoint上添加 如果mouse.last\u x&&mouse.last\u y context.moveTomouse.last\u x,mouse.last\u y
希望您可以进行其余的调整。您需要跟踪每个客户端的最后一点,然后再发布上下文。lineTomouse.x,mouse.y移动到客户端的最后一点,该点也将应用于颜色,以便您可以设置正确的客户端颜色 要获得理想,您可以尝试执行以下操作: 在mousedown处理程序socketEngage上添加原始代码 mouse.last_x=e.offsetX; mouse.last_y=e.offsetY 函数的开头 在mousemove处理程序socketPutPoint中 mouse.last_x=mouse.x; mouse.last_y=mouse.y 函数的开头 并在context.lineTomouse.x、mouse.y之前的putPoint上添加 如果mouse.last\u x&&mouse.last\u y context.moveTomouse.last\u x,mouse.last\u y 希望您可以完成其余的调整。一些白板提示: 以下所有代码都是伪代码 使用WebSocket进行通信。有几个流行的websocket库是和。当Websocket不受支持时,Websocket库通常具有回退方法 使用JSON序列化图形数据。JSON的好处在于它自动获取JavaScript对象/数组,并从中生成适合websocket传输的字符串。反之亦然:自动接收JSON字符串并将字符串重新水化为JavaScript对象/数组
var command = {
client:'sam',
points:[{x:5,y:10},...],
// optionally add styling (strokeStyle, linewidth, etc)
};
// serialize a command
var jsonCommand = JSON.stringify(command);
// deserialize a command
var command = JSON.parse(jsonCommand);
这是非常重要的!要使所有图形保持原子状态,每个路径图形应完整,包括样式。不要启动context.beginPath并发出一系列context.lineTo
draw(command.points);
// ALWAYS issue complete drawing commands
// including styling (if any)
function draw(points);
var ptsLength=points.length;
context.beginPath;
context.moveTo(points[0].x,points[0].y);
for(var i=0;i<ptsLength;i++){
var pt=points[i];
context.lineTo(pt.x,pt.y);
}
context.stroke();
}
使用单独的循环向服务器发出本地绘图命令,并绘制传入的远程绘图命令:
// vars to schedule drawing from remote clients
// and sending local drawings to server
var nextDrawingTime, nextSendingTime;
var drawingTimeDelay=1000; // or some other delay, but don't be a burden!
var sendingTimeDelay=1000; // or some other delay, but don't be a burden!
// start the processing loop (it runs continuously non-stop)
requestAnimationFrame(process);
function process(time){
// a simplification ...
// don't interrupt if the local user is drawing
if(isDown){ return; }
// draw incoming strokes
if(time>nextDrawingTime && receivedCommands.length>0){
// set the next drawing time for remote draws
nextDrawingTime=time+drawingTimeDelay;
// draw all accumulated received commands
for(var i=0;i<receivedCommands.length;i++){
var c=receivedCommands[i];
if(c.client!==myName){
draw(c.points);
}
}
receivedCommands.length=0;
// emit outgoing strokes
} else if(time>nextSendingTime && commands.length>0){
// set the next emitting time for locally drawing paths
nextSendingTime=time+sendingTimeDelay;
// JSON.stringify
var jsonPacket=JSON.stringify(commands);
// reset the set of local drawing commands
commands=[];
// emit to server for broadcast to everyone
}
requestAnimationFrame(process);
}
让服务器执行一些重要任务:
如果您选择的websockets库没有自动包含时间戳,请为每个广播添加时间戳
将收到的所有图形命令保存到数据库中,因为出现问题,您可能需要不时地完全重新同步客户端
Mousemove每秒大约发射30次,因此会累积大量点数。为了减少数据传输的大小,考虑使用路径缩减算法来去除冗余点。一个好的算法是
一个好的白板应用程序还有很多,但这就是我现在所有的时间。。。祝你的项目好运!:- 一些白板提示:
以下所有代码都是伪代码
使用WebSocket进行通信。有几个流行的websocket库是和。当Websocket不受支持时,Websocket库通常具有回退方法
使用JSON序列化图形数据。JSON的好处在于它自动获取JavaScript对象/数组,并从中生成适合websocket传输的字符串。反之亦然:自动接收JSON字符串并将字符串重新水化为JavaScript对象/数组
var command = {
client:'sam',
points:[{x:5,y:10},...],
// optionally add styling (strokeStyle, linewidth, etc)
};
// serialize a command
var jsonCommand = JSON.stringify(command);
// deserialize a command
var command = JSON.parse(jsonCommand);
这是非常重要的!要使所有图形保持原子状态,每个路径图形应完整,包括样式。不要启动context.beginPath并发出一系列context.lineTo
draw(command.points);
// ALWAYS issue complete drawing commands
// including styling (if any)
function draw(points);
var ptsLength=points.length;
context.beginPath;
context.moveTo(points[0].x,points[0].y);
for(var i=0;i<ptsLength;i++){
var pt=points[i];
context.lineTo(pt.x,pt.y);
}
context.stroke();
}
使用单独的循环向服务器发出本地绘图命令,并绘制传入的远程绘图命令:
// vars to schedule drawing from remote clients
// and sending local drawings to server
var nextDrawingTime, nextSendingTime;
var drawingTimeDelay=1000; // or some other delay, but don't be a burden!
var sendingTimeDelay=1000; // or some other delay, but don't be a burden!
// start the processing loop (it runs continuously non-stop)
requestAnimationFrame(process);
function process(time){
// a simplification ...
// don't interrupt if the local user is drawing
if(isDown){ return; }
// draw incoming strokes
if(time>nextDrawingTime && receivedCommands.length>0){
// set the next drawing time for remote draws
nextDrawingTime=time+drawingTimeDelay;
// draw all accumulated received commands
for(var i=0;i<receivedCommands.length;i++){
var c=receivedCommands[i];
if(c.client!==myName){
draw(c.points);
}
}
receivedCommands.length=0;
// emit outgoing strokes
} else if(time>nextSendingTime && commands.length>0){
// set the next emitting time for locally drawing paths
nextSendingTime=time+sendingTimeDelay;
// JSON.stringify
var jsonPacket=JSON.stringify(commands);
// reset the set of local drawing commands
commands=[];
// emit to server for broadcast to everyone
}
requestAnimationFrame(process);
}
让服务器执行一些重要任务:
如果您选择的websockets库没有自动包含时间戳,请为每个广播添加时间戳
将收到的所有图形命令保存到数据库中,因为出现问题,您可能需要不时地完全重新同步客户端
Mousemove每秒大约发射30次,因此会累积大量点数。减少数据量
传输大小,考虑使用路径缩减算法来去除冗余点。一个好的算法是
一个好的白板应用程序还有很多,但这就是我现在所有的时间。。。祝你的项目好运!:- 在发布context.lineTomouse.x,mouse.y之前,您需要跟踪每个客户端的最后一点,并将其移动到客户端的最后一点,该点也将应用于颜色,以便您可以设置正确的客户端颜色。了解颜色,但我对该点不太清楚,我是否必须在每次绘图后或在其他客户端启动mouseup事件后移动到旧点尝试在您的mousedown处理程序socketEngage上加上原始代码mouse.last_x=e.offsetX;mouse.last_y=e.offsetY;函数的开头,在mousemove处理程序socketPutPoint mouse.last_x=mouse.x;mouse.last_y=mouse.y;函数开头,在context.lineTomouse.x,mouse.y之前的putPoint上添加if mouse.last_x&&mouse.last_y context.moveTomouse.last_x,mouse.last_;要了解我在说什么=希望您可以进行其余的调整。感谢提示:我已固定了颜色,第一行几乎已固定,请写一个答案,以便我可以接受。您需要跟踪每个客户的最后一点,然后再发布上下文。lineTomouse.x,鼠标。y移动到客户端的最后一个点,该点也将应用于颜色,以便您可以设置正确的客户端颜色。了解颜色,但我对该点不太清楚,我是否必须在每次绘图后或在其他客户端启动mouseup事件后移动到旧点尝试在您的mousedown处理程序socketEngage上加上原始代码mouse.last_x=e.offsetX;mouse.last_y=e.offsetY;函数的开头,在mousemove处理程序socketPutPoint mouse.last_x=mouse.x;mouse.last_y=mouse.y;函数开头,在context.lineTomouse.x,mouse.y之前的putPoint上添加if mouse.last_x&&mouse.last_y context.moveTomouse.last_x,mouse.last_;要了解我在说什么=希望你能做其余的调整。感谢提示:我固定了颜色,第一行几乎固定了,请写一个答案,这样我可以接受在白板时保持所有图形原子化非常重要-每个路径图形都应完整,包括样式:.beginPath,.moveTo、.lineTo、.strokeStyle='something',stroke。不要让路径保持打开状态:因此不要设计一个套接字应用程序来接合和分离,这会导致绘图操作不完整。这意味着您应该等待用户拖动操作完成,然后再发出完整的绘图操作。hi@markE,如果我当时理解您的意思,我不应该在用户拖动鼠标时发出事件,那么我应该如何实时向所有其他用户显示用户所绘制的内容?请您解释一下,也许可以给出一个答案,谢谢:在白板上时,保持所有图形原子化非常重要-每个路径图形都应完整,包括样式:.beginPath、.moveTo、.lineTo、.strokeStyle='something',stroke。不要让路径保持打开状态:因此不要设计一个套接字应用程序来接合和分离,这会导致绘图操作不完整。这意味着您应该等待用户拖动操作完成,然后再发出完整的绘图操作。hi@markE,如果我当时理解您的意思,我不应该在用户拖动鼠标时发出事件,那么我应该如何实时向所有其他用户显示用户所绘制的内容?你能解释一下吗,也许可以回答一下,谢谢:这是我读过的关于白板的最好的解释。非常感谢!!:。这是我读过的关于白板的最好解释。非常感谢!!:。