概述
本文主要基于 Websocket、Canvas、Webman、HTML5 CSS 等技术实现一个共享白板原型,支持在多个桌面浏览器之间共享一个无限大小、任意缩放的多人实时协作白板,并实时同步绘画、涂鸦。通过 Canvas 渲染画板、产生涂鸦数据,然后通过Websocket实现客户端与服务器的双向通信,并在多个设备之间实时同步涂鸦数据。
协同画板实现
使用workerman作为Websocket消息订阅发布服务器
安装think-template
composer安装
composer require topthink/think-template
修改配置config/view.php
为
<?php
use support\view\ThinkPHP;
return [
'handler' => ThinkPHP::class,
];
HTTP服务
新建app/controller/DemoController.php
控制器
<?php
/**
* @desc Demo.php 描述信息
* @author Tinywan(ShaoBo Wan)
* @date 2024/6/16 20:14
*/
declare(strict_types=1);
namespace app\controller;
use support\Request;
use support\Response;
class DemoController
{
/**
* @desc 实战构建多人互动画板
* @param Request $request
* @return Response
* @author Tinywan(ShaoBo Wan)
*/
public function canvas(Request $request): Response
{
return view('demo/canvas');
}
}
文件app/view/demo/canvas.html
如下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>开源技术小栈 WebSocket+Canvas: 实战构建多人互动画板</title>
</head>
<body>
<canvas id="canvas" height="600" width="600" style="border:1px solid #000000;">你的浏览器不支持canvas,请升级浏览器</canvas>
<script src="/static/js/index.js"></script>
</body>
</html>
/static/js/index.js
文件
var el = document.getElementById('canvas');
el.width = document.body.clientWidth;
el.height = document.body.clientHeight;
var ctx = el.getContext('2d');
var isDrawing;
var point = {};
ctx.strokeStyle = '#fffff';
var ws = new WebSocket('ws://192.168.13.168:8788');
console.log(ws)
// 当连接成功后,再进行绘画操作,以免数据丢失
ws.onopen = function () {
el.onmousedown = function (e) {
isDrawing = true;
ctx.moveTo(e.clientX,e.clientY);
sendPoint(e,1);
}
el.onmousemove = function (e) {
if(isDrawing){
ctx.lineTo(e.clientX,e.clientY);
ctx.stroke();
sendPoint(e,2);
}
}
el.onmouseup = function (e) {
isDrawing = false;
}
}
ws.onmessage = function (e) {
var data = JSON.parse(e.data);
if(data.type == 1){
ctx.moveTo(data.x,data.y);
}else if(data.type == 2){
ctx.lineTo(data.x,data.y);
ctx.stroke();
}
}
function sendPoint(e,type) {
point = {
type:type,
x:e.clientX,
y:e.clientY,
}
ws.send(JSON.stringify(point));
}
Websocket服务
这里通过webman自定义进程实现。在webman中你可以像workerman那样自定义监听或者进程。
新建 process/CanvasWebsocket.php
<?php
/**
* @desc CanvasWebsocket.php
* @author Tinywan(ShaoBo Wan)
* @date 2024/6/18 9:18
*/
declare(strict_types=1);
namespace process;
use Workerman\Connection\TcpConnection;
class CanvasWebsocket
{
public function onConnect(TcpConnection $connection)
{
echo "onConnect\n";
}
public function onWebSocketConnect(TcpConnection $connection, $http_buffer)
{
echo "onWebSocketConnect\n";
}
public function onMessage(TcpConnection $connection, $data)
{
foreach ($connection->worker->connections as $_connection) {
if($connection != $_connection){
$_connection->send($data);
}
}
}
public function onClose(TcpConnection $connection)
{
echo "onClose\n";
}
}
在config/process.php
中添加如下配置
return [
// ... 其它进程配置省略 ...
// canvas_websocket为进程名称
'canvas_websocket' => [
// 这里指定进程类,就是上面定义的Pusher类
'handler' => \process\CanvasWebsocket::class,
'listen' => 'websocket://0.0.0.0:8788',
'count' => 1,
],
];
启动webman