新增画笔粗细、橡皮粗细、画笔颜色调节、清空画布功能,可能存在逻辑上的不合理,后续再完善细节

This commit is contained in:
2024-04-14 19:27:44 +08:00
parent b0c00624da
commit f9c972846d
8 changed files with 302 additions and 96 deletions
+1 -1
View File
@@ -86,7 +86,7 @@ public class Room {
* @param playerId 发送者的ID(用于排除发送者) * @param playerId 发送者的ID(用于排除发送者)
*/ */
public void sendMessage(String type, String playerId, String message) { public void sendMessage(String type, String playerId, String message) {
if (type.equals(Global.MSG_TYPE_ROOM_DRAW)) { if (type.startsWith(Global.MSG_TYPE_ROOM_DRAW)) {
log.info("【绘画房间消息】{}: {}", id, message); log.info("【绘画房间消息】{}: {}", id, message);
for (Player player : players) { for (Player player : players) {
// 向除自己之外的玩家发送消息 // 向除自己之外的玩家发送消息
+92 -59
View File
@@ -1,90 +1,123 @@
#game-top-box { #game-top-box {
width: 100%; width: 100%;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
} }
#draw-box { #draw-box {
width: 350px; width: 350px;
margin: 0 auto; margin: 0 auto;
min-height: 350px; min-height: 350px;
box-sizing: border-box; box-sizing: border-box;
border: #000000 solid 1px; border: #000000 solid 1px;
border-radius: 15px; border-radius: 15px;
background-color: #daeefd; background-color: #daeefd;
} }
#topic-bar { #topic-bar {
width: 350px; width: 350px;
height: 30px; height: 30px;
line-height: 30px; line-height: 30px;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
font-size: 0.8em; font-size: 0.8em;
} }
#topic-bar > div { #topic-bar > div {
flex: 1; flex: 1;
} }
#board { #board {
width: 300px; width: 300px;
height: 300px; height: 300px;
background-color: #ffffff; background-color: #ffffff;
box-shadow: #000000 0 0 1px; box-shadow: #000000 0 0 1px;
border-radius: 10px; border-radius: 10px;
touch-action: none; touch-action: none;
}
.control-btn {
box-sizing: border-box;
width: 30px;
height: 30px;
font-size: 1.2em;
background-color: transparent;
border: none;
border-radius: 30px;
}
.select-box {
display: flex;
align-items:center;
justify-content: space-around;
width: 100%;
height: 80px;
box-sizing: border-box;
padding: 15px;
text-align: left;
} }
.color-btn { .color-btn {
width: 20px; width: 30px;
height: 20px; height: 30px;
padding: 0; padding: 0;
background-color: #ffffff; background-color: #ffffff;
border-radius: 20px; border-radius: 30px;
border: 2px solid white; border: 4px solid transparent;
box-shadow: #00000033 0 0 10px;
} }
.width-btn,.eraser-btn {
box-sizing: content-box;
width: 12px;
height: 12px;
padding: 0;
border-radius: 24px;
background-color: #444444;
border: 4px solid #444444;
box-shadow: #00000033 0 0 10px;
}
#player-box { #player-box {
display: flex; display: flex;
justify-content: center; justify-content: center;
width: 100%; width: 100%;
} }
.player-item { .player-item {
box-sizing: border-box; box-sizing: border-box;
width: 30px; width: 30px;
height: 30px; height: 30px;
line-height: 30px; line-height: 30px;
border-radius: 4px; border-radius: 4px;
font-size: 1.4em; font-size: 1.4em;
color: coral; color: coral;
background-color: #ffffff; background-color: #ffffff;
box-shadow: #00000022 0 0 5px; box-shadow: #00000022 0 0 5px;
margin: 5px 10px; margin: 5px 10px;
} }
#chat-box { #chat-box {
width: calc(100vw - 20px); width: calc(100vw - 20px);
height: calc(100vh - 540px); height: calc(100vh - 540px);
box-sizing: border-box; box-sizing: border-box;
padding: 10px; padding: 10px;
margin: auto; margin: auto;
border-radius: 10px; border-radius: 10px;
background-color: #00000022; background-color: #00000022;
box-shadow: #000000 0 0 1px; box-shadow: #000000 0 0 1px;
text-align: left; text-align: left;
font-size: 0.8em; font-size: 0.8em;
overflow-y: scroll; overflow-y: scroll;
} }
#chat-input-box { #chat-input-box {
width: 100vw; width: 100vw;
height: 50px; height: 50px;
position: fixed; position: fixed;
bottom: 0; bottom: 0;
background-color: #bbe1ec; background-color: #bbe1ec;
} }
#chat-input { #chat-input {
width: calc(100vw - 100px); width: calc(100vw - 100px);
} }
+15
View File
@@ -101,4 +101,19 @@ body {
color: #000000; color: #000000;
border-radius: 6px; border-radius: 6px;
pointer-events: none; pointer-events: none;
}
@font-face {
font-family: 'iconfont';
src: url('../icon/iconfont.woff2?t=1713086382342') format('woff2'),
url('../icon/iconfont.woff?t=1713086382342') format('woff'),
url('../icon/iconfont.ttf?t=1713086382342') format('truetype');
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
} }
Binary file not shown.
Binary file not shown.
Binary file not shown.
+66 -28
View File
@@ -39,7 +39,7 @@
<!-- 游戏页面 --> <!-- 游戏页面 -->
<div id="page-game"> <div id="page-game">
<div id="game-top-box"> <div id="game-top-box">
<button id="back-btn" class="button">返回</button> <button id="back-btn" class="button"><span class="iconfont">&#xe65d;</span></button>
<button id="userIcon" class="button">玩家:admin</button> <button id="userIcon" class="button">玩家:admin</button>
</div> </div>
<div id="draw-box"> <div id="draw-box">
@@ -48,31 +48,65 @@
<div>提示:<span id="topic-tip">成语,四个字</span></div> <div>提示:<span id="topic-tip">成语,四个字</span></div>
</div> </div>
<canvas id="board" width="600" height="600"></canvas> <canvas id="board" width="600" height="600"></canvas>
<div style="display: flex;width: 100%;justify-content: space-between;padding: 0 15px 10px 15px;box-sizing: border-box;">
<div>
<!--颜色-->
<button id="color-select-btn" class="control-btn" onclick="toggleColorBox()"><span class="iconfont">&#xe6da;</span></button>
<!--粗细-->
<button id="width-select-btn" class="control-btn" onclick="toggleWidthBox()"><span class="iconfont">&#xe641;</span></button>
<!--橡皮-->
<button id="eraser-select-btn" class="control-btn" onclick="toggleEraserBox()"><span class="iconfont">&#xe61b;</span></button>
</div>
<div>
<!--清空-->
<button class="control-btn" onclick="sendClearDraw()"><span class="iconfont">&#xe60b;</span>
</button>
</div>
</div>
<!--颜色选择框-->
<div id="color-select-box" class="select-box">
<span style="font-size: 1.5em;" class="iconfont">&#xe6da;</span>
<button class="color-btn" data-color="#000000"
style="background-color: #000000;border-color: #ffffff;"></button>
<button class="color-btn" data-color="#ff1744"
style="background-color: #ff1744;"></button>
<button class="color-btn" data-color="#00c853"
style="background-color: #00c853;"></button>
<button class="color-btn" data-color="#2962ff"
style="background-color: #2962ff;"></button>
<button class="color-btn" data-color="#ffd600"
style="background-color: #ffd600;"></button>
</div>
<!--画笔粗细选择框-->
<div id="width-select-box" class="select-box">
<span style="font-size: 1.5em;" class="iconfont">&#xe641;</span>
<button class="width-btn" data-width="8"
style="border-color: #ffffff;width: 8px;height: 8px;"></button>
<button class="width-btn" data-width="12"
style="width: 12px;height: 12px;"></button>
<button class="width-btn" data-width="16"
style="width: 16px;height: 16px;"></button>
<button class="width-btn" data-width="20"
style="width: 20px;height: 20px;"></button>
<button class="width-btn" data-width="24"
style="width: 24px;height: 24px;"></button>
</div>
<!--橡皮粗细选择框-->
<div id="eraser-select-box" class="select-box">
<span style="font-size: 1.5em;" class="iconfont">&#xe61b;</span>
<button class="eraser-btn" data-width="8"
style="border-color: #ffffff;width: 8px;height: 8px;"></button>
<button class="eraser-btn" data-width="12"
style="width: 12px;height: 12px;"></button>
<button class="eraser-btn" data-width="16"
style="width: 16px;height: 16px;"></button>
<button class="eraser-btn" data-width="20"
style="width: 20px;height: 20px;"></button>
<button class="eraser-btn" data-width="24"
style="width: 24px;height: 24px;"></button>
</div>
</div> </div>
<div>
<button class="color-btn" onclick="changeBrushColor('#000000')"
style="background-color: #000000;"></button>
<button class="color-btn" onclick="changeBrushColor('#ff0000')"
style="background-color: #ff0000;"></button>
<button class="color-btn" onclick="changeBrushColor('#00ff00')"
style="background-color: #00ff00;"></button>
<button class="color-btn" onclick="changeBrushColor('#0000ff')"
style="background-color: #0000ff;"></button>
<button class="color-btn" onclick="changeBrushColor('#ffff00')"
style="background-color: #ffff00;"></button>
</div>
<div>
<button class="color-btn" onclick="changeBrushWidth(4)"
style="background-color: #888888;"></button>
<button class="color-btn" onclick="changeBrushWidth(8)"
style="background-color: #666666;"></button>
<button class="color-btn" onclick="changeBrushWidth(12)"
style="background-color: #444444;"></button>
<button class="color-btn" onclick="changeBrushWidth(16)"
style="background-color: #222222;"></button>
<button class="color-btn" onclick="changeBrushWidth(20)"
style="background-color: #000000;"></button>
</div>
<div id="player-box"> <div id="player-box">
<div class="player-item">张</div> <div class="player-item">张</div>
<div class="player-item">王</div> <div class="player-item">王</div>
@@ -321,16 +355,17 @@
}; };
ws.onmessage = function (evt) { ws.onmessage = function (evt) {
let result = JSON.parse(evt.data); let result = JSON.parse(evt.data);
//接收到通知消息 // 接收到通知消息
if (result.type === "room-msg") { if (result.type === "room-msg") {
showMsg(result.data); showMsg(result.data);
} }
// 接收聊天消息
if (result.type === "room-chat") { if (result.type === "room-chat") {
$("#chat-box").append("<p>" + result.data + "</p>") $("#chat-box").append("<p>" + result.data + "</p>")
} }
// 接收绘画消息
if (result.type === "room-draw") { if (result.type === "room-draw") {
let brush = JSON.parse(result.data); let brush = JSON.parse(result.data);
console.log("收到坐标: ", brush.x, brush.y);
if (brush.isPoint) { if (brush.isPoint) {
brushPoint = {x: brush.x, y: brush.y} brushPoint = {x: brush.x, y: brush.y}
drawPoint(brush.x, brush.y, brush.width, brush.color); drawPoint(brush.x, brush.y, brush.width, brush.color);
@@ -347,7 +382,10 @@
}, brush.width, brush.color); }, brush.width, brush.color);
brushPoint = {x: brush.x, y: brush.y}; brushPoint = {x: brush.x, y: brush.y};
} }
}
// 接收清空画板消息
if (result.type === "room-draw-clear") {
clearDraw();
} }
}; };
+128 -8
View File
@@ -3,9 +3,12 @@ let canvas = document.getElementById("board");
let context = canvas.getContext("2d"); let context = canvas.getContext("2d");
context.imageSmoothingEnabled = true; context.imageSmoothingEnabled = true;
let brushColor = "#000000"; let brushColor = "#000000";
let brushWidth = 2; let brushWidth = 8;
let brushPoint = {x: 0, y: 0}; let brushPoint = {x: 0, y: 0};
let isDrawing = false; let isDrawing = false;
let eraserWidth = 8;
let useEraser = false;
// PC端 ******************************* // PC端 *******************************
// 鼠标按下事件处理程序 // 鼠标按下事件处理程序
canvas.addEventListener("mousedown", function (event) { canvas.addEventListener("mousedown", function (event) {
@@ -13,7 +16,12 @@ canvas.addEventListener("mousedown", function (event) {
brushPoint = getBrushPoint(event); brushPoint = getBrushPoint(event);
// 广播绘画数据 // 广播绘画数据
sendDrawData(brushPoint.x, brushPoint.y, true); sendDrawData(brushPoint.x, brushPoint.y, true);
drawPoint(brushPoint.x, brushPoint.y, brushWidth, brushColor); // 判断是否是橡皮
if (useEraser) {
drawPoint(brushPoint.x, brushPoint.y, eraserWidth, "#ffffff");
} else {
drawPoint(brushPoint.x, brushPoint.y, brushWidth, brushColor);
}
}); });
// 鼠标移动事件处理程序 // 鼠标移动事件处理程序
@@ -22,7 +30,12 @@ canvas.addEventListener("mousemove", function (event) {
let newPoint = getBrushPoint(event); let newPoint = getBrushPoint(event);
// 广播绘画数据 // 广播绘画数据
sendDrawData(newPoint.x, newPoint.y, false); sendDrawData(newPoint.x, newPoint.y, false);
drawLine(brushPoint, newPoint, brushWidth, brushColor); // 判断是否是橡皮
if (useEraser) {
drawLine(brushPoint, newPoint, eraserWidth, "#ffffff");
} else {
drawLine(brushPoint, newPoint, brushWidth, brushColor);
}
brushPoint = newPoint; brushPoint = newPoint;
} }
}); });
@@ -39,7 +52,12 @@ canvas.addEventListener("touchstart", function (event) {
brushPoint = getTouchPoint(event); brushPoint = getTouchPoint(event);
// 广播绘画数据 // 广播绘画数据
sendDrawData(brushPoint.x, brushPoint.y, true); sendDrawData(brushPoint.x, brushPoint.y, true);
drawPoint(brushPoint.x, brushPoint.y, brushWidth, brushColor); // 判断是否是橡皮
if (useEraser) {
drawPoint(brushPoint.x, brushPoint.y, eraserWidth, "#ffffff");
} else {
drawPoint(brushPoint.x, brushPoint.y, brushWidth, brushColor);
}
}); });
// 触摸移动事件处理程序 // 触摸移动事件处理程序
@@ -49,7 +67,12 @@ canvas.addEventListener("touchmove", function (event) {
let newPoint = getTouchPoint(event.touches[0]); // 使用第一个触摸点 let newPoint = getTouchPoint(event.touches[0]); // 使用第一个触摸点
// 广播绘画数据 // 广播绘画数据
sendDrawData(newPoint.x, newPoint.y, false); sendDrawData(newPoint.x, newPoint.y, false);
drawLine(brushPoint, newPoint, brushWidth, brushColor); // 判断是否是橡皮
if (useEraser) {
drawLine(brushPoint, newPoint, eraserWidth, "#ffffff");
} else {
drawLine(brushPoint, newPoint, brushWidth, brushColor);
}
brushPoint = newPoint; brushPoint = newPoint;
} }
}); });
@@ -67,6 +90,7 @@ function getBrushPoint(event) {
y: (event.clientY - rect.top) * 2 y: (event.clientY - rect.top) * 2
}; };
} }
// 计算画笔在画布上的触摸坐标 // 计算画笔在画布上的触摸坐标
function getTouchPoint(touch) { function getTouchPoint(touch) {
let rect = canvas.getBoundingClientRect(); let rect = canvas.getBoundingClientRect();
@@ -75,6 +99,7 @@ function getTouchPoint(touch) {
y: (touch.clientY - rect.top) * (canvas.height / rect.height) y: (touch.clientY - rect.top) * (canvas.height / rect.height)
}; };
} }
// 绘制单个点 // 绘制单个点
function drawPoint(x, y, width, color) { function drawPoint(x, y, width, color) {
context.beginPath(); context.beginPath();
@@ -102,8 +127,8 @@ function sendDrawData(x, y, isPoint) {
const drawData = { const drawData = {
x, x,
y, y,
color: brushColor, color: useEraser ? "#ffffff" : brushColor,
width: brushWidth, width: useEraser ? eraserWidth : brushWidth,
isPoint isPoint
}; };
@@ -118,10 +143,105 @@ function changeBrushColor(color) {
brushColor = color; brushColor = color;
} }
/** /**
* 切换画笔宽度 * 切换画笔宽度
* @param width 整数 * @param width 整数
*/ */
function changeBrushWidth(width) { function changeBrushWidth(width) {
brushWidth = width; brushWidth = width;
} }
/**
* 切换橡皮宽度
* @param width 整数
*/
function changeEraserWidth(width) {
eraserWidth = width;
}
/**
* 发送清空画板命令
*/
function sendClearDraw() {
sendMessage("room-draw-clear", true);
clearDraw();
}
/**
* 清空画板
*/
function clearDraw() {
context.clearRect(0, 0, 600, 600);
context.beginPath();
canvas.width = canvas.width;
showMsg("画板已清空");
}
/**
* 打开或关闭颜色选择框
*/
function toggleColorBox() {
$("#width-select-box").hide();
$("#eraser-select-box").hide();
$("#color-select-box").show();
}
/**
* 打开或关闭画笔粗细选择框
*/
function toggleWidthBox() {
$("#color-select-box").hide();
$("#eraser-select-box").hide();
$("#width-select-box").show();
}
/**
* 打开或关闭橡皮粗细选择框
*/
function toggleEraserBox() {
$("#width-select-box").hide();
$("#color-select-box").hide();
$("#eraser-select-box").show();
}
// 默认隐藏所有工具框
$(".select-box").hide();
/**
* 颜色按钮事件
*/
$(".color-btn").click(function () {
changeBrushColor($(this).attr("data-color"));
$(".color-btn").css("border-color", "transparent");
$(this).css("border-color", "#ffffff");
})
/**
* 画笔宽度按钮事件
*/
$(".width-btn").click(function () {
changeBrushWidth($(this).attr("data-width"));
$(".width-btn").css("border-color", "#444444");
$(this).css("border-color", "#ffffff");
})
/**
* 画笔宽度按钮事件
*/
$(".eraser-btn").click(function () {
changeEraserWidth($(this).attr("data-width"));
$(".eraser-btn").css("border-color", "#444444");
$(this).css("border-color", "#ffffff");
})
/**
* 橡皮状态切换
*/
$("#eraser-select-btn").click(function () {
useEraser = !useEraser;
if(useEraser){
$(this).css("background-color", "#ffffff");
}else {
$(this).css("background-color", "transparent");
}
})