javascript - 如何在一个二维 Canvas 上下文上一次绘制多条线?多用户画板

标签 javascript canvas socket.io

我几乎已经制作了一个多用户画板。 我的问题是,由于我一次只能绘制一条线,因此当 2 个或更多用户同时绘制时,该线会在鼠标之间跳跃,如果这有意义的话。如何让每个用户都有自己的线路?

这里是客户端JS代码。我知道它写得不好,但这是我第一次尝试。

document.addEventListener('DOMContentLoaded', function(event){
    var startMoveX = new Array();
    var startMoveY = new Array();
    var socket = io.connect();
    socket.on('draw',function(data){
       outDraw(data);
    });

    canvas = document.getElementById('myCanvas');
    ctx = canvas.getContext("2d");
    ctx.canvas.width  = window.innerWidth;
    ctx.canvas.height = window.innerHeight;
    var drawing = false;
    if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|BB|PlayBook|IEMobile|Windows Phone|Kindle|Silk|Opera Mini/i.test(navigator.userAgent)) {
        canvas.addEventListener('touchmove', function(e){
            var mouseX = Math.round(e.targetTouches[0].clientX);
            var mouseY = Math.round(e.targetTouches[0].clientY);
            var status = document.getElementById('status');
            status.innerHTML = mouseX+" | "+mouseY;
            if(drawing) draw(e)
        }, false);
        canvas.addEventListener("touchstart", function (e) {
            moveBol = true;
            drawing = true;
            startMoveX.pop();
            startMoveY.pop();
            startMoveX.push(Math.round(e.targetTouches[0].clientX));
            startMoveY.push(Math.round(e.targetTouches[0].clientY));
            ctx.moveTo(startMoveX[0], startMoveY[0]);
        }, false);
        canvas.addEventListener("touchend", function (e) {drawing = false;}, false);
        canvas.addEventListener("mousecancel", function (e) {drawing = false;}, false);
    } else {
    canvas.addEventListener('mousemove', function(e){
        var mouseX = e.clientX - ctx.canvas.offsetLeft;
        var mouseY = e.clientY - ctx.canvas.offsetTop;
        var status = document.getElementById('status');
        status.innerHTML = mouseX+" | "+mouseY;
        if(drawing) draw(e)
    }, false);
        canvas.addEventListener("mousedown", function (e) {
            drawing = true;
            moveBol = true;
            startMoveX.pop();
            startMoveY.pop();
            startMoveX.push(e.clientX - ctx.canvas.offsetLeft);
            startMoveY.push(e.clientY - ctx.canvas.offsetTop);
            ctx.moveTo(startMoveX[0], startMoveY[0]);

        }, false);
    canvas.addEventListener("mouseup", function (e) {drawing = false;}, false);
    canvas.addEventListener("mouseout", function (e) {drawing = false;}, false);
    }
    function draw(e) {
        if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|BB|PlayBook|IEMobile|Windows Phone|Kindle|Silk|Opera Mini/i.test(navigator.userAgent)) {
            cX = Math.round(e.targetTouches[0].clientX);
            cY = Math.round(e.targetTouches[0].clientY);
        } else {
            cX = e.clientX - canvas.offsetLeft;
            cY = e.clientY - canvas.offsetTop;
        }

        ctx.lineTo(cX, cY);
        ctx.stroke();
        if (moveBol){
            socket.emit('draw',{x:cX,y:cY, preX: startMoveX[0], preY: startMoveY[0]});
            console.log(moveBol);
            moveBol = false;
        } else {
            socket.emit('draw',{x:cX,y:cY});
            console.log(moveBol);
        }
    }
    function outDraw(e) {


        ctx.moveTo(e.preX, e.preY);
        ctx.lineTo(e.x, e.y);
        ctx.stroke();
    }

});

最佳答案

你有两个选择。

每帧重绘一次所有当前事件的绘制路径,保留屏幕外 Canvas 作为背景。当一条线完成后,将该线绘制到背景上。使用 requestAnimationFrame 更新显示。

或者

仅使用beginPath绘制线段,但需要保留前一个点。

例如

// creates named users that draw to the canvas context ctx
ctx = canvas.getContext("2d"); // I assume canvas is in scope
var users = {  // cant have users that start with _        
    _addUser(name){  
        if(typeof this[name] === "function"){
            throw new ReferenceError("Can not use the user name '"+name+"'");
        }

        this[name] = {
            lastX : null,
            lastY : null,
            draw(x,y){
                ctx.beginPath();
                ctx.moveTo(this.lastX,this.lastY);
                ctx.lineTo(x,y);
                ctx.stroke();
            },                
            addPoint(x,y){
                if(this.lastX !== null){ // new line start
                    this.draw(x,y);
                }
                this.lastX = x;
                this.lastY = y;
            },
            endPoint(x,y){
                if(this.lastX === null){ // incase it is just a point
                    this.lastX = x;
                    this.lastY = y;
                }
                this.draw(x,y);
                this.lastX = null; // end the line
            }
        }
        return this[name];
    }
}

users._createUser("User1");
users._createUser("User2");

然后,要为任何用户绘图,您只需要用户名和点以及线条结束时间。

对于鼠标按下和跟随鼠标移动

user = "User1";
// mousemove and mousedown events should call
users[user].addPoint(x,y); // add a point if mouse is down
socket.send(JSON.stringify({user, x, y, type : "add"});

对于鼠标事件

// when the mouseup 
users[user].endPoint(x,y);
socket.send(JSON.stringify({user, x, y, type : "end"});

用于获取套接字数据

// if from a socket (should have the user name or id passed with the packet)
// Assuming data is as a JSON string as above
socket.onmessage = function(event){
    var data = JSON.parse(event.data);  // should be wrapped in try catch and security checks

    user = data.user;  // 
    if(users[user]){
        if(data.type === "add"){  // add point
            users[user].addPoint(data.x, data.y); // add a point
        }else if(data.type === "end"){
            users[user].endPoint(data.x, data.y);
        }
    }
}

关于javascript - 如何在一个二维 Canvas 上下文上一次绘制多条线?多用户画板,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42013911/

相关文章:

html - 在 HTML Canvas 中创建链接

jquery - html2canvas - 安全错误 : The operation is insecure

javascript - 对于单独的实例禁用 JS 输入验证提交

JavaScript 多重赋值

javascript - 如何将当前连接的设备名称获取到计算机?

javascript - 使 Socket.IO 显示浏览器的页面加载指示器(旋转轮)

node.js - Express/HTTP 监听每个端口的 EADDRINUSE?

javascript - 移动 safari 的 AJAX 响应太大?

javascript - 如果条件不正常

javascript - 如何防止使用Socket.io滚动类似事件? - Angular 7