首页 > 其他分享 >Netty+HTML5+Canvas 网络画画板实时在线画画

Netty+HTML5+Canvas 网络画画板实时在线画画

时间:2024-09-21 17:21:01浏览次数:3  
标签:Netty Canvas netty 画画 ctx import box1 event channel

采用Html5的canvas做前端画画板,发送数据到后端Netty服务,实时转发笔迹数据,在线实时同步画笔轨迹,单击绿色小方块,保存画板的图片

页面:

<!-- index.html -->

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>网络画画板</title>
</head>
<body>
<style>
        #box1 {
            width: 100px;
            height: 100px;
            background-color: green;
            position: absolute;
        }
    </style>
<div id="box1" onclick="save()"></div>
<canvas id="canvas" style="background-color: yellow;"></canvas>

<script>

        const canvas = document.getElementById("canvas");
        const ctx = canvas.getContext("2d");
        canvas.width = 800;
        canvas.height = 600;
        let isDrawing = false;
        let x = 0;
        let y = 0;
        let x1 = 0;
        let y1 = 0;
        var socket = new WebSocket("ws://localhost:9911/websocket");

        socket.onopen = function(event) {
            console.log("WebSocket opened: " + event);
        };

        socket.onmessage = function(event) {
            //console.log("WebSocket message received: " + event.data);

            var str = event.data.split("_");

        if(str[0]==='B'){
            switch (str[1]) {
                    case '37':

                        box1.style.left = str[2];
                        break;
                    case '39':

                        box1.style.left = str[2] ;
                        break;
                    case '38':

                        box1.style.top = str[2] ;
                        break;
                    case '40':

                        box1.style.top = str[2] ;
                        break;


                }
        }else if(str[0]==='mousedown'){
         ctx.beginPath();
            ctx.strokeStyle = "red";
            ctx.lineWidth = 1;
            ctx.moveTo(str[1], str[2]);


        }else if(str[0]==='mousemove'){

            ctx.lineTo(str[1], str[2]);
            ctx.stroke();

        }
        };

        socket.onclose = function(event) {
            console.log("WebSocket closed: " + event);
        };

        function send() {
            var message = document.getElementById("message").value;
            socket.send(message);
        }

        document.addEventListener('keydown', function(event) {

          if (event.keyCode === 13) {
            send()
            var txt = document.getElementById('message')
            txt.value = ''
          }
          speed = 10
          switch (event.keyCode) {
                    case 37:
                        box1.style.left = box1.offsetLeft - speed + "px";
                        socket.send("B_"+event.keyCode+"_"+box1.style.left)
                        break;
                    case 39:
                        box1.style.left = box1.offsetLeft + speed + "px";
                        socket.send("B_"+event.keyCode+"_"+box1.style.left)
                        break;
                    case 38:
                        box1.style.top = box1.offsetTop - speed + "px";
                        socket.send("B_"+event.keyCode+"_"+box1.style.top)
                        break;
                    case 40:
                        box1.style.top = box1.offsetTop + speed + "px";
                        socket.send("B_"+event.keyCode+"_"+box1.style.top)
                        break;
                }
        });
    canvas.addEventListener("mousedown", (event) => {
        // console.log(event);

        x = event.layerX - canvas.getBoundingClientRect().left;
        y = event.layerY - canvas.getBoundingClientRect().top;
        ctx.beginPath();
        ctx.strokeStyle = "red";
        ctx.lineWidth = 1;
        ctx.moveTo(x, y);
        isDrawing = true;

         socket.send("mousedown_"+x+"_"+y);
    });

    canvas.addEventListener("mousemove", (event) => {
         //console.log(event);
         //console.log(event.layerX, event.layerY);

        if (isDrawing) {
           x = event.layerX - canvas.getBoundingClientRect().left;
            y = event.layerY - canvas.getBoundingClientRect().top;
            ctx.lineTo(x, y);
            ctx.stroke();
           socket.send("mousemove_"+x+"_"+y);
        }
    });

    canvas.addEventListener("mouseup", (event) => {
            isDrawing = false;
    });
    canvas.addEventListener("mouseout", (event) => {

            isDrawing = false;

    });

    function save(){
        var link = document.createElement("a");
        var imgData =canvas.toDataURL({format: 'png', quality:1, width:20000, height:4000});
        var strDataURI = imgData.substr(22, imgData.length);
        var blob = dataURLtoBlob(imgData);
        var objurl = URL.createObjectURL(blob);
        link.download = "grid1.png";
        link.href = objurl;
        link.click();
    }
 	function  dataURLtoBlob(dataurl) {
    	var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
      	bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
    	while(n--){
     		 u8arr[n] = bstr.charCodeAt(n);
    	}
    	return new Blob([u8arr], {type:mime});
  	}

    </script>
</body>
</html>

后端:

pom:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>org.nno</groupId>
  <artifactId>nno</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>nno</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
    <dependency>
      <groupId>io.netty</groupId>
      <artifactId>netty-all</artifactId>
      <version>4.1.18.Final</version>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-log4j12</artifactId>
      <version>2.0.5</version>
    </dependency>
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-lang3</artifactId>
      <version>3.2.1</version>
    </dependency>
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.26</version>
    </dependency>
  </dependencies>
</project>

类:

package org.nno;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;

import java.util.HashSet;
import java.util.Set;


public class WebSocketServer {

    private final int port;

    public WebSocketServer(int port) {
        this.port = port;
    }
    Set m = new HashSet();
    public void run() throws Exception {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        public void initChannel(SocketChannel ch) throws Exception {
                            ChannelPipeline p = ch.pipeline();
                            p.addLast(new HttpServerCodec());
                            p.addLast(new HttpObjectAggregator(65536));
                            p.addLast(new WebSocketServerProtocolHandler("/websocket"));
                            p.addLast(new WebSocketServerHandler(m));
                        }
                    });

            ChannelFuture f = b.bind(port).sync();
            f.channel().closeFuture().sync();
        } finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }

    public static void main(String[] args) throws Exception {
        int port = 9911;
        if (args.length > 0) {
            port = Integer.parseInt(args[0]);
        }

        new WebSocketServer(port).run();
    }
}
package org.nno;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;

import java.util.*;


public class WebSocketServerHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {


    Set m = new HashSet<>();

    public WebSocketServerHandler(Set m) {
        this.m = m;
    }

    @Override
    public void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
        // 处理消息
//        System.out.println("Received message: " + msg.text());
        Iterator<Channel> iterator = m.iterator();
        while(iterator.hasNext()){

            iterator.next().writeAndFlush(new TextWebSocketFrame(msg.text()));
        }

    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        // 添加连接
//        System.out.println("Client connected: " + ctx.channel());
        m.add(ctx.channel());


    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        // 断开连接
//        System.out.println("Client disconnected: " + ctx.channel());

        m.remove(ctx.channel());


    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        // 异常处理
        cause.printStackTrace();
        ctx.close();
    }

}

标签:Netty,Canvas,netty,画画,ctx,import,box1,event,channel
From: https://blog.csdn.net/airyearth/article/details/142413897

相关文章

  • WPF Canvas show custom control with ellipse filled with image and text,peridoica
    //customcontrol<UserControlx:Class="WpfApp389.ElpImageTbk"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"......
  • 【Canvas与诗词】《侠客行》节选
    【成图】【代码】<!DOCTYPEhtml><htmllang="utf-8"><metahttp-equiv="Content-Type"content="text/html;charset=utf-8"/><head><title>437.侠客行</title><styletype="text/css"&......
  • Netty笔记09-网络协议设计与解析
    文章目录前言一、协议设计1.数据格式2.消息长度3.编码方式4.错误处理5.安全性二、协议解析1.消息分隔2.粘包与半包处理3.校验机制三、为什么需要协议?四、redis协议五、HTTP协议六、自定义协议要素编解码器......
  • 处理微信小程序 ec-canvas 绘制map地图时缩放大小问题
    版本为5.1.2min版本,https://github.com/apache/echarts/releases?page=3 最重要的是这个下面这个dataZoom写法添加dataZoom:{type:'inside'},constoption={dataZoom:{type:'inside'},geo:......
  • WPF System.Windows.Media.Color A value must be set, display ball and number in c
    privateColorGetRndColor(){Colorcr=newColor();cr.A=255;cr.R=(byte)(rnd.Next(0,255));cr.G=(byte)(rnd.Next(0,255));cr.B=(byte)(rnd.Next(0,255));returncr;}         //usercontrol.......
  • WPF Customcontrol with ellipse and textblock display randomly in canvas of mainw
    //usercontrol.xaml<UserControlx:Class="WpfApp381.ElpImgTbk"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"......
  • 诚邀见证2024九章云极DataCanvas算力包产品发布会!
    算力,是驱动全球智能化升级的关键力量,也是智算经济腾飞的主要燃料。在智算经济腾起之际,我们洞察未来:算力不仅是生产力还将作为社会性普惠AI资源。我们思考未来:算力产品和模式需要何种创新才能够加速算力普惠的进程?我们定义未来:用单位来标准化算力,用AI基础软件纳管算力!作为人工......
  • 【Canvas与诗词】《登科后》唐.孟郊
    【成图】【代码】<!DOCTYPEhtml><htmllang="utf-8"><metahttp-equiv="Content-Type"content="text/html;charset=utf-8"/><head><title>昔日龌龊不足夸</title><styletype="text/css"&......
  • Netty WebSocket 最简单的聊天室
    Netty最为后端服务处理WebSocket协议连接后端代码pom.xml<projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0http://maven.apache.org/xs......
  • Canvas简历编辑器-Monorepo+Rspack工程实践
    Canvas简历编辑器-Monorepo+Rspack工程实践在之前我们围绕Canvas聊了很多代码设计层面的东西,在这里我们聊一下工程实践。在之前的文中我也提到过,因为是本着学习的态度以及对技术的好奇心来做的,所以除了一些工具类的库例如 ArcoDesign、ResizeObserve、Jest 等包之外,关于数据结......