socketIo+canvas实现互动画板

HTML代码


        

CSS代码

*{margin:0; padding: 0;user-select: none;}
body{overflow:hidden}
#drawing-board{background: white;cursor: crosshair;width: 100%;height: 100%;}
.tools{position: fixed;left:180px;top: 447px; width:500px;display: flex;justify-content: center;text-align: center}
.tools button{border-radius: 50%;width: 50px;height: 50px;border: 1px solid #eee;outline: none;cursor: pointer;box-sizing: border-box;margin: 0 10px;text-align: center;color:#ccc;line-height: 50px;box-shadow:0 0 8px rgba(0,0,0,0.1); transition: 0.3s;}
.tools button.active,.tools button:active{box-shadow: 0 0 15px #00CCFF; color:#00CCFF;}
.tools button i{font-size: 24px;}
.color-group{position:fixed;width: 30px;left: 30px;top:230px;transform: translate(0,-150px)}
.color-group ul{list-style: none;}
.color-group ul li{width: 30px;height: 30px;margin: 10px 0;border-radius: 50%;box-sizing: border-box;border:3px solid white;box-shadow: 0 0 8px rgba(0,0,0,0.2);cursor: pointer;transition: 0.3s;}
.color-group ul li.active{box-shadow:0 0 15px #00CCFF;}
#range-wrap{position: fixed;top: 22%;left:874px;width: 30px;height: 150px;margin-top: -75px;}
#range-wrap input{transform: rotate(-90deg);width: 150px;height: 20px;margin: 0;transform-origin: 75px 75px;    border-radius: 15px;-webkit-appearance: none;outline: none;position: relative;}
#range-wrap input::after{display: block;content:"";width:0;height: 0;border:5px solid transparent;
    border-right:150px solid #00CCFF;border-left-width:0;position: absolute;left: 0;top: 5px;border-radius:15px; z-index: 0; }
#range-wrap input[type=range]::-webkit-slider-thumb,#range-wrap input[type=range]::-moz-range-thumb{-webkit-appearance: none;}
#range-wrap input[type=range]::-webkit-slider-runnable-track,#range-wrap input[type=range]::-moz-range-track {height: 10px;border-radius: 10px;box-shadow: none;}
#range-wrap input[type=range]::-webkit-slider-thumb{-webkit-appearance: none;height: 20px;width: 20px;margin-top: -1px;background: #ffffff;border-radius: 50%;box-shadow: 0 0 8px #00CCFF;position: relative;z-index: 999;}

@media screen and (max-width: 768px) {
    .tools{bottom:auto;top:20px;}
    .tools button{width: 35px;height: 35px;line-height: 35px;margin-bottom: 15px;box-shadow:0 0 5px rgba(0,0,0,0.1);}
    .tools button.active,.tools button:active{box-shadow: 0 0 5px #00CCFF;}
    .tools button i{font-size: 18px;}
    .tools #swatches{display: none}
    .color-group{left: 0;top:auto;bottom: 20px;display: flex;width:100%;justify-content: center;text-align: center;transform: translate(0,0)}
    .color-group ul li{display: inline-block;margin:0 5px;}
    .color-group ul li.active{box-shadow:0 0 10px #00CCFF;}
    #range-wrap{right:auto;left: 20px;}
}
#imgcontainer {
    position: absolute;
    z-index: 999;
    top: 80%;
    left: 50%;
    transform: translate(-50%, -50%);
}
#imgcontainer li{
    width:160px;
    height: 80px;
    list-style: none;
    margin: 0 10px;
}
#imgcontainer ul{
    display: flex;
    justify-content: center;
}
#imgcontainer img{ 
    width: 100%;
    height: 100%;
    
}
#a{
    height: 500px;
    width: 900px;
    position: relative;
    display:none
}
html,body{
    width: 100%;
    height: 100%;
}

JS代码

let canvas = document.getElementById("drawing-board");
let ctx = canvas.getContext("2d");
let eraser = document.getElementById("eraser");
let brush = document.getElementById("brush");
let reSetCanvas = document.getElementById("clear");
let aColorBtn = document.getElementsByClassName("color-item");
let save = document.getElementById("save");
let undo = document.getElementById("undo");
let range = document.getElementById("range");
let clear = null;
let ioClear = null;
let activeColor = 'black';
let lWidth = 4;
let lWidthIo = 4;
var socket = io('192.168.0.133:8081', {transports: ['websocket']});
let ioColor = 'black';
var originalWidth = null;
var originalHeight = null;
    // 监听连接
var flag = true;
var noSaveThePicture = null;
autoSetSize(canvas);

setCanvasBg('white');

listenToUser(canvas);

getColor();

// window.onbeforeunload = function(){
//     return "Reload site?";
// };

function autoSetSize(canvas) { 
    canvasSetSize();
    // window.onresize = function () {
    //             noSaveThePicture = ctx.getImageData(0,0,1920,973)
    //             canvasSetSize();
    // }
}

function canvasSetSize() {         
    let pageWidth = document.getElementById('a').offsetWidth;
    let pageHeight = document.getElementById('a').offsetHeight;
    canvas.width = pageWidth;
    originalWidth = pageWidth;
    canvas.height = pageHeight;
    originalHeight = pageHeight;
        // if(noSaveThePicture != null){
        //     ctx.putImageData(noSaveThePicture,0,0,0,0,pageWidth,pageHeight)
        // }
    }
function setCanvasBg(color) {
    ctx.fillStyle = color;
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    ctx.fillStyle = "black";
}

function listenToUser(canvas) {
    let painting = false;
    let lastPoint = {x: undefined, y: undefined};
    // if (document.body.ontouchstart !== undefined) {
    //     canvas.ontouchstart = function (e) {
    //         this.firstDot = ctx.getImageData(0, 0, canvas.width, canvas.height);//在这里储存绘图表面
    //         saveData(this.firstDot);
    //         painting = true;
    //         let x = e.touches[0].clientX;
    //         let y = e.touches[0].clientY;
    //         lastPoint = {"x": x, "y": y};
    //         ctx.save();
    //         drawCircle(x, y, 0);
    //     };
    //     canvas.ontouchmove = function (e) {
    //         if (painting) {
    //             let x = e.touches[0].clientX;
    //             let y = e.touches[0].clientY;
    //             let newPoint = {"x": x, "y": y};
    //             drawLine(lastPoint.x, lastPoint.y, newPoint.x, newPoint.y);
    //             lastPoint = newPoint;
    //         }
    //     };
    //     canvas.ontouchend = function () {
    //         painting = false;
    //     }
    // } else {
        canvas.onmousedown = function (e) {
            this.firstDot = ctx.getImageData(0, 0, canvas.width, canvas.height);//在这里储存绘图表面
            saveData(this.firstDot);
            painting = true;
            let x = e.clientX;
            let y = e.clientY;
            let canvasWidth = document.getElementById('a').offsetWidth;
            let canvasHeight = document.getElementById('a').offsetHeight;
            let conversionWidth = originalWidth/canvasWidth
            let conversionHeight = originalHeight/canvasHeight
            x = x*conversionWidth
            y = y*conversionHeight
            socket.emit('serverDown',{x,y,originalWidth,originalHeight})
            lastPoint = {"x": x, "y": y};
            ctx.save();
            drawCircle(x, y, 0);
        };
        canvas.onmousemove = function (e) {
            if (painting) {
                let x = e.clientX;
                let y = e.clientY;
                let canvasWidth = document.getElementById('a').offsetWidth;
                let canvasHeight = document.getElementById('a').offsetHeight;
                let conversionWidth = originalWidth/canvasWidth
                let conversionHeight = originalHeight/canvasHeight
                x = x*conversionWidth
                y = y*conversionHeight
                socket.emit('serverMouse',{x,y,originalWidth,originalHeight})
                let newPoint = {"x": x, "y": y};
                drawLine(lastPoint.x, lastPoint.y, newPoint.x, newPoint.y,clear);
                lastPoint = newPoint;
            }
        };

        canvas.onmouseup = function () {
            socket.emit('serverUp',false)
            painting = false;
        };

        canvas.mouseleave = function () {
            socket.emit('serverLeave',false)
            painting = false;
        }
    // }                      
}

function drawCircle(x, y, radius) {
    ctx.save();
    ctx.beginPath();
    ctx.arc(x, y, radius, 0, Math.PI * 2);
    ctx.fill();
    if (clear) {
        ctx.clip();
        ctx.clearRect(0,0,canvas.width,canvas.height);
        ctx.restore();
    }
    ctx.stroke();
    ctx.closePath();
}

function drawLine(x1, y1, x2, y2) {
    ctx.lineWidth = lWidth;
    ctx.lineCap = "round";
    ctx.lineJoin = "round";
    if (clear) {
        ctx.beginPath()
        ctx.save();
        ctx.globalCompositeOperation = "destination-out";
        ctx.moveTo(x1, y1);
        ctx.lineTo(x2, y2);
        ctx.stroke();
        ctx.closePath();
        ctx.clip();
        ctx.clearRect(0,0,canvas.width,canvas.height);
        ctx.restore();
    }else{
        ctx.beginPath()
        ctx.fillStyle = activeColor;
        ctx.strokeStyle = activeColor;
        ctx.moveTo(x1, y1);
        ctx.lineTo(x2, y2);
        ctx.stroke();
        ctx.closePath();
    }
}

function drawLineIo(x1, y1, x2, y2,ioClear,ioColor) {
    ctx.lineCap = "round";
    ctx.lineJoin = "round";
    if (ioClear) {
        ctx.beginPath()
        ctx.lineWidth = lWidthIo;
        ctx.save();
        ctx.globalCompositeOperation = "destination-out";
        ctx.moveTo(x1, y1);
        ctx.lineTo(x2, y2);
        ctx.stroke();
        ctx.closePath();
        ctx.clip();
        ctx.clearRect(0,0,canvas.width,canvas.height);
        ctx.restore();
    }else{
        ctx.beginPath()
        ctx.lineWidth = lWidthIo;
        ctx.fillStyle = ioColor;
        ctx.strokeStyle = ioColor;
        ctx.moveTo(x1, y1);
        ctx.lineTo(x2, y2);
        ctx.stroke();
        ctx.closePath();
    }
}

range.onchange = function(){
    lWidth = this.value;
    socket.emit('serverLindeWidth',lWidth)
};

eraser.onclick = function () {
    clear = true;
    socket.emit('serverClear',true)
    this.classList.add("active");
    brush.classList.remove("active");
};

brush.onclick = function () {
    clear = null;
    socket.emit('serverClear',null)
    this.classList.add("active");
    eraser.classList.remove("active");
};

reSetCanvas.onclick = function () {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    setCanvasBg('white');
    ctx.drawImage(originalityImg,0,0,canvas.width,canvas.height)
    socket.emit('serverOriginalityImg','')
};

socket.on('clientOriginalityImg',function(){
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    setCanvasBg('white');
    ctx.drawImage(originalityImg,0,0,canvas.width,canvas.height)
})

save.onclick = function () {
    let imgUrl = canvas.toDataURL("image/png");
    let saveA = document.createElement("a");
    document.body.appendChild(saveA);
    saveA.href = imgUrl;
    saveA.download = "zspic" + (new Date).getTime();
    saveA.target = "_blank";
    saveA.click();
};

function getColor(){
    for (let i = 0; i < aColorBtn.length; i++) {
        aColorBtn[i].onclick = function () {
            for (let i = 0; i < aColorBtn.length; i++) {
                aColorBtn[i].classList.remove("active");
                this.classList.add("active");
                activeColor = this.style.backgroundColor;
                socket.emit('serverColor',activeColor)
                ctx.fillStyle = activeColor;
                ctx.strokeStyle = activeColor;
            }
        }
    }
}

let historyDeta = [];

function saveData (data) {
    (historyDeta.length === 10) && (historyDeta.shift());// 上限为储存10步,太多了怕挂掉
    historyDeta.push(data);
}

undo.onclick = function(){
    if(historyDeta.length < 1) return false;
    ctx.putImageData(historyDeta[historyDeta.length - 1], 0, 0);
    historyDeta.pop()
    socket.emit('serverUndo','')
};
socket.on('clientUndo',function(){
    if(historyDeta.length < 1) return false;
    ctx.putImageData(historyDeta[historyDeta.length - 1], 0, 0);
    historyDeta.pop()
})
socket.on('clientDown', function(data) {
    canvas.firstDot = ctx.getImageData(0, 0, canvas.width, canvas.height);//在这里储存绘图表面
        saveData(canvas.firstDot);
        painting = true;
        let x = data.x;
        let y = data.y;
        let canvasWidth = document.getElementById('a').offsetWidth;   //获取当前窗口宽度
        let canvasHeight = document.getElementById('a').offsetHeight;  
        let conversionWidth = canvasWidth/data.originalWidth    //获取对方宽度换算比列
        let conversionHeight = canvasHeight/data.originalHeight     
        let theirConversionWidth = originalWidth/canvasWidth      //获取自身窗口换算比列
        let theirConversionHeight = originalHeight/canvasHeight
        x = x*conversionWidth*theirConversionWidth         //转换后的x坐标
        y = y*conversionHeight*theirConversionHeight
        lastPointIo = {"x": x, "y": y};
        ctx.save();
        drawCircle(x, y, 0);
});

let lastPointIo = {x: undefined, y: undefined};

socket.on('clientMouse',function(data){
    if (painting) {
        let x = data.x;
        let y = data.y;
        let canvasWidth = document.getElementById('a').offsetWidth;
        let canvasHeight = document.getElementById('a').offsetHeight;
        let conversionWidth = canvasWidth/data.originalWidth
        let conversionHeight = canvasHeight/data.originalHeight
        let theirConversionWidth = originalWidth/canvasWidth
        let theirConversionHeight = originalHeight/canvasHeight
        x = x*conversionWidth*theirConversionWidth
        y = y*conversionHeight*theirConversionHeight
        let newPoint = {"x": x, "y": y};
        drawLineIo(lastPointIo.x, lastPointIo.y, newPoint.x, newPoint.y,ioClear,ioColor);
        lastPointIo = newPoint;
    }
})

socket.on('clientColor',function(data){
    ioColor = data
})

socket.on('clientClear',function(data){
    ioClear= data
})

socket.on('clientLindeWidth',function(data){
    lWidthIo = data
})

let originalityImg = document.getElementById('firstView');
let SaveThePicture = 0;
ctx.drawImage(document.getElementById('firstView'),0,0,canvas.width,canvas.height)
let imgcontainer = document.getElementById('imgcontainer')
let imgData = [null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null]
imgcontainer.addEventListener('click',function(e){
    if(e.target.nodeName == 'IMG'){
        originalityImg = e.target
        let imgNum = e.target.getAttribute('data-id')
        imgData[SaveThePicture] = ctx.getImageData(0,0,canvas.width,canvas.height)
        socket.emit('serverImg',imgNum,SaveThePicture)
        SaveThePicture = imgNum
        if(imgData[SaveThePicture] != null){
            ctx.putImageData(imgData[SaveThePicture],0,0)
        }else{
            ctx.drawImage(e.target,0,0,canvas.width,canvas.height)
        }
    }
})

socket.on('clientImg',function(data,data2){
    let imgItem = document.getElementsByTagName('img')
    SaveThePicture = data2
    let imgNum = imgItem[data].getAttribute('data-id')
    originalityImg = imgItem[data]
    imgData[SaveThePicture] = ctx.getImageData(0,0,canvas.width,canvas.height)
    SaveThePicture = imgNum
    if(imgData[imgNum] != null){
        ctx.putImageData(imgData[imgNum],0,0)
    }else{
        ctx.drawImage(imgItem[data],0,0,canvas.width,canvas.height)
    }
})

socketIo 代码

var app = require('express')();
var fs = require('fs')
var express = require("express");
var key = fs.readFileSync('./private.key') //HTTPS证书
var cert = fs.readFileSync('./mydomain.crt') //HTTPS证书
var options = {
    key:key,
    cert:cert
}
var server = require('https').Server(options,app);
// 引入 socket.io
var io = require('socket.io')(server);
// 监听 8081 端口
server.listen(8081);
// 开启静态资源服务
app.use(express.static("./public"));
app.get('/',function(req,res){
    fs.readFile('./canvas.html',(err,data)=>{
        if(err) throw err;
        res.write(data)
        res.end()
    })
})
// io 各种事件
io.on('connection', function (socket) {
  socket.emit('message', { hello: '欢迎链接' });

  socket.on('serverDown', function (data) {
    socket.broadcast.emit('clientDown', data);
  });
  socket.on('serverMouse', function (data) {
    socket.broadcast.emit('clientMouse', data);
  });
  socket.on('serverUp', function (data) {
    socket.broadcast.emit('clientUp', data);
  });
  socket.on('serverLeave', function (data) {
    socket.broadcast.emit('clientLeave', data);
  });
  socket.on('serverColor', function (data) {
    socket.broadcast.emit('clientColor', data);
  });
  socket.on('serverClear', function (data) {console.log(data)
    socket.broadcast.emit('clientClear', data);
  });
  socket.on('serverImg', function (data,data2) {
    socket.broadcast.emit('clientImg', data,data2);
  });
  socket.on('serverLindeWidth', function (data) {
    socket.broadcast.emit('clientLindeWidth',data);
  });
  socket.on('serverOriginalityImg', function () {
    socket.broadcast.emit('clientOriginalityImg','');
  });
  socket.on('serverUndo', function () {
    socket.broadcast.emit('clientUndo','');
  });

});



你可能感兴趣的:(socketIo+canvas实现互动画板)