first commit

This commit is contained in:
编码猿
2024-09-27 01:22:07 +08:00
commit 1360daaab0
931 changed files with 131068 additions and 0 deletions

View File

@@ -0,0 +1 @@
fc2363c0-9720-43c0-bced-f43fcaabb0c7

View File

@@ -0,0 +1 @@
7682cea9-47ad-46fa-8ada-afd10dfa0655

View File

@@ -0,0 +1,161 @@
body,
ul,
li,
h1,
h2,
h3,
h4,
h5,
h6,
p {
margin: 0;
padding: 0;
list-style: none;
}
body,
html {
width: 100%;
height: 100%;
}
body {
position: relative;
background: url("http://192.168.4.4:81/stream");
background-size: cover;
background-position: center;
}
.remote_rod {
position: absolute;
padding: 0 30px;
width: 100%;
bottom: 40px;
display: flex;
justify-content: space-between;
box-sizing: border-box;
}
.rod {
width: 128px;
height: 128px;
display: flex;
align-items: center;
justify-content: center;
position: relative;
}
.vertical {
background: url("../img/vertical.png");
}
.level {
background: url("../img/level.png");
}
.level img {
position: absolute;
font-size: 32px;
display: inline-block;
text-align: center;
border-radius: 100%;
}
.level .action img {
width: 38px;
height: 38px;
}
.icon-zidongdadeng {
width: 43px !important;
height: 43px !important;
top: -70px;
right: 0;
}
.icon-jinggao_o {
left: -24px;
top: -44px;
}
.icon-xiaolaba {
left: -68px;
top: 43px;
}
.icon-hand {
left: -68px;
top: 43px;
}
.level .active {
color: #f8b84ef2;
}
.top_action {
width: 100%;
position: absolute;
display: flex;
justify-content: space-between;
margin-top: 15px;
padding: 0 15px;
box-sizing: border-box;
}
.back {
width: 40px;
height: 40px;
border-radius: 100%;
display: flex;
align-items: center;
justify-content: center;
background: #c5c5d5;
margin-right: 20px;
}
.right_action .back:last-child {
margin-right: 0 !important;
}
.top_action .obstacle,
.icon-hand {
width: 20px;
height: 20px;
}
.speed {
width: 100px;
border: 1px solid #000;
padding: 5px 15px;
border-radius: 20px;
display: flex;
align-items: center;
}
.speed img {
margin-right: 15px;
}
.right_action {
display: flex;
align-items: center;
}
.lamp {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 200px;
box-sizing: border-box;
position: absolute;
bottom: 10px;
width: 100%;
}
.lamp img {
padding: 0px 12px;
background: #c5c4d5;
color: #fff;
border-radius: 30px;
height: 35px;
}
.open {
animation: openLamp 0.8s infinite alternate;
}
@keyframes openLamp {
from {
background: #a2a1a1;
}
to {
background: #f8bd5d;
}
}

View File

@@ -0,0 +1 @@
a388ed8d-0d80-4fac-8a45-35c99b4a5c34

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 748 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 522 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 895 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 523 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 569 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 970 B

View File

@@ -0,0 +1,57 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>智能小车控制面板</title>
<link rel="stylesheet" href="./css/index.css">
</head>
<body>
<div class="remote_rod">
<div class="vertical rod">
<img id="stick1" src="./img/joystick-speed.png" />
</div>
<div class="level rod">
<img id="stick2" src="./img/joystick-blue.png" />
<div class="action">
<img class="icon-zidongdadeng" src="./img/headlight.png" alt="">
<img class="icon-jinggao_o" src="./img/warning.png" alt="">
<img class="icon-xiaolaba" src="./img/horn.png" alt="">
</div>
</div>
</div>
<div class="top_action">
<div></div>
<div class="speed">
<img src="./img/stop.png" alt=""> 0km/h
</div>
<div class="right_action">
<div class="back hand_wrap">
<img class="icon-hand" src="./img/hand.png" alt="">
</div>
<div class="back obstacle_wrap">
<img class="obstacle" src="./img/obstacle.png" alt="">
</div>
</div>
</div>
<!-- <div class="lamp">
<img class="open" src="./img/leftlight.png" alt="">
<img src="./img/rightlight.png" alt="">
</div> -->
<audio class="actionAudio" src="./img/action.mp3" controls hidden></audio>
</body>
<script src="./js/utils.js"></script>
<script src="./js/WebSocket.js"></script>
<script src="./js/Joystick.js"></script>
<script src="./js/index.js"></script>
</html>

View File

@@ -0,0 +1 @@
525da242-f4be-4a40-9f41-1589a0071a96

View File

@@ -0,0 +1,134 @@
class Joystick {
// 元素id最大移动距离
constructor(stickID, direction, callback) {
this.id = stickID;
this.maxDistance = 64;
this.direction = direction;
this.callback = callback;
this.time = null
this.stick = document.getElementById(stickID);
// 开始拖动的位置,用于计算偏移量
this.dragStart = null;
// 如果存在多个操纵手柄,则跟踪触摸标识符
this.touchId = null;
this.active = false;
this.EventListener();
}
handleDown(event) {
this.active = true;
this.stick.style.transition = '0s';
// 阻止默认事件
event.preventDefault();
// 记录初始点击的坐标
if (event.changedTouches) {
this.dragStart = { x: event.changedTouches[0].clientX, y: event.changedTouches[0].clientY };
} else {
this.dragStart = { x: event.clientX, y: event.clientY };
}
// console.log("event: ", event);
// console.log("event.changedTouches: ", event.changedTouches);
// 记录点击的id
if (event.changedTouches) {
this.touchId = event.changedTouches[0].identifier;
}
}
handleMove(event) {
if (!this.active) return;
if (event.changedTouches && this.touchId != event.changedTouches[0].identifier) return;
// 处理多点触控
if (event.changedTouches) {
for (let i = 0; i < event.changedTouches.length; i++) {
if (this.touchId == event.changedTouches[i].identifier) {
event.clientX = event.changedTouches[i].clientX;
event.clientY = event.changedTouches[i].clientY;
}
}
}
// 计算 x 轴距离
const xDiff = event.clientX - this.dragStart.x;
// 计算 y 轴距离
const yDiff = event.clientY - this.dragStart.y;
// 计算 角度
const angle = Math.atan2(yDiff, xDiff);
// 计算 距离
const distance = Math.min(this.maxDistance, Math.hypot(xDiff, yDiff));
// 计算 xy 的新位置
const xPosition = distance * Math.cos(angle);
const yPosition = distance * Math.sin(angle);
if (this.time && (Date.now() - this.time) < 30) return
this.time = Date.now()
if (this.direction == "x") {
// console.log("xPosition: ", Math.sign(xPosition));
// 左边 0 ~ -64 -1 3
if (xPosition < 0) {
if (xPosition < -63) {
console.log("左边: ", xPosition);
this.callback(3)
}
// 右边 1 4
} else if (xPosition > 0){
if (xPosition > 63) {
console.log("右边: ", xPosition);
this.callback(4)
}
}
// 将图片移动到新位置
this.stick.style.transform = `translate3d(${xPosition}px,0px, 0px)`;
// this.callback(Math.sign(xPosition) == -1 ? 3 : 4)
} else {
console.log("yPosition: ", yPosition);
this.stick.style.transform = `translate3d(0px,${yPosition}px, 0px)`;
this.callback(Math.sign(yPosition) == -1 ? 1 : 2, Math.round(255 * Math.round(Math.abs(yPosition)) / 64))
}
}
handleUp(event) {
if (!this.active) return;
if (event.changedTouches && this.touchId != event.changedTouches[0].identifier) return;
this.active = false;
// console.log("3 handleUp ==== ", this.active);
this.stick.style.transition = '.2s';
this.stick.style.transform = `translate3d(0px, 0px, 0px)`;
this.touchId = null;
this.callback(0, 0)
}
EventListener() {
// 鼠标 & 手指 按下
this.stick.addEventListener('mousedown', this.handleDown.bind(this));
this.stick.addEventListener('touchstart', this.handleDown.bind(this));
// 鼠标 & 手指 移动
document.addEventListener('mousemove', this.handleMove.bind(this), { passive: false });
document.addEventListener('touchmove', this.handleMove.bind(this), { passive: false });
// 鼠标 & 手指 松开
document.addEventListener('mouseup', this.handleUp.bind(this));
document.addEventListener('touchend', this.handleUp.bind(this));
}
}

View File

@@ -0,0 +1,38 @@
class WS {
constructor() {
this.ws = null;
this.connect();
this.onopen();
this.onclose();
this.onerror();
}
connect() {
this.ws = new WebSocket("ws://192.168.4.1:81");
console.log("this.ws: ", this.ws);
}
onopen() {
this.ws.onopen = () => {
console.log("WebSocket open");
}
}
onmessage(callback) {
this.ws.onmessage = (e) => {
callback(e.data)
}
}
onclose() {
this.ws.onclose = (e) => {
console.log("close");
}
}
onerror() {
this.ws.onerror = (e) => {
console.log("onerror");
}
}
}

View File

@@ -0,0 +1,157 @@
/**
* wx.send("操作类型|操作状态|其他数值")
* 操作类型y 代表速度摇杆
* x 代表方向摇杆
* o 代表其他操作
*/
class IndexPage {
constructor() {
// 自动壁障的开关
this.obstacleStatus =
localStorage.getItem("obstacleStatus") == null
? false
: JSON.parse(localStorage.getItem("obstacleStatus"))
// 前大灯的开关
this.fronLamp =
localStorage.getItem("fronLamp") == null
? false
: JSON.parse(localStorage.getItem("fronLamp"))
// 双闪的开关
this.doubleStatus =
localStorage.getItem("doubleStatus") == null
? false
: JSON.parse(localStorage.getItem("doubleStatus"))
// 手势跟随的开关
this.handStatus =
localStorage.getItem("handStatus") == null
? false
: JSON.parse(localStorage.getItem("handStatus"))
this.doubleIntervalId = null;
this.socket = new WS();
this.Joystick();
this.bindActionButton();
}
Joystick() {
// 前进后退摇杆
// status-1 前进 1 后退0 停止
// speed前进后退的速度 0 ~ 255 之间
var s1 = new Joystick("stick1", "y", (status, speed) => {
this.socket.ws.send(`y|${status}|${speed}`)
});
// 左右转向摇杆
// status3左转 4右转 0 转向恢复原样(直行)
var s2 = new Joystick("stick2", "x", (status) => {
this.socket.ws.send(`x|${status}`)
});
this.socket.onmessage((res) => {
console.log("res = ",res);
alert("web收到请求为")
alert(JSON.stringify(res))
res = res.split("|");
switch (res[0]) {
case "server":
if (res[1] == "y") {
$("#stick1").style = "";
$("#stick2").style = "";
s1.active = false;
s1.dragStart = { x: 0, y: 0 };
s2.active = false;
s2.dragStart = { x: 0, y: 0 };
}
break;
case "client":
break;
default:
break;
}
})
}
bindActionButton() {
if (this.obstacleStatus) {
$(".obstacle_wrap").classList.add("open")
}
if (this.fronLamp) {
$(".icon-zidongdadeng").classList.add("open")
}
if (this.doubleStatus) {
$(".icon-jinggao_o").classList.add("open")
}
if (this.handStatus) {
$(".hand_wrap").classList.add("open")
}
// 喇叭开关
$(".icon-xiaolaba").onclick = () => {
this.play();
this.socket.ws.send(`b|buzzer|1`)
}
// 手势跟随
$(".hand_wrap").onclick = () => {
this.play();
this.handStatus = !this.handStatus
$(".hand_wrap").classList.toggle("open")
localStorage.setItem("handStatus", this.handStatus)
this.socket.ws.send(`b|openHand|${this.handStatus ? '1' : '0'}`)
}
// 前面大灯
$(".icon-zidongdadeng").onclick = () => {
this.play();
this.fronLamp = !this.fronLamp
$(".icon-zidongdadeng").classList.toggle("open")
localStorage.setItem("fronLamp", this.fronLamp)
this.socket.ws.send(`b|fronLamp|${this.fronLamp ? '1' : '0'}`)
}
// 双闪
$(".icon-jinggao_o").onclick = () => {
this.play();
this.doubleStatus = !this.doubleStatus
$(".icon-jinggao_o").classList.toggle("open")
localStorage.setItem("doubleStatus", this.doubleStatus)
if (this.doubleStatus) {
this.doubleIntervalId = setInterval(() => this.socket.ws.send(`b|doubleFlash|1`), 1000)
} else {
clearInterval(this.doubleIntervalId)
this.socket.ws.send(`b|doubleFlash|0`)
}
}
$(".obstacle_wrap").onclick = () => {
this.play();
// 1 true, 0 false
this.obstacleStatus = !this.obstacleStatus
$(".obstacle_wrap").classList.toggle("open")
localStorage.setItem("obstacleStatus", this.obstacleStatus)
this.socket.ws.send(`b|obstacle|${this.obstacleStatus ? '1' : '0'}`)
}
}
play() {
$(".actionAudio").play();
}
}
new IndexPage();

View File

@@ -0,0 +1,20 @@
class Utils {
$(className) {
return document.querySelector(className);
}
debounce(fn, delay = 1000) {
let timer = null //借助闭包
return function () {
if (timer) {
clearTimeout(timer)
}
timer = setTimeout(fn, delay) // 简化写法
}
}
}
var { $, debounce } = new Utils();

View File

@@ -0,0 +1,133 @@
class Joystick {
// 元素id最大移动距离
constructor(stickID, direction, callback) {
this.id = stickID;
this.maxDistance = 64;
this.direction = direction;
this.callback = callback;
this.time = null
this.stick = document.getElementById(stickID);
// 开始拖动的位置,用于计算偏移量
this.dragStart = null;
// 如果存在多个操纵手柄,则跟踪触摸标识符
this.touchId = null;
this.active = false;
this.EventListener();
}
handleDown(event) {
this.active = true;
this.stick.style.transition = '0s';
// 阻止默认事件
event.preventDefault();
// 记录初始点击的坐标
if (event.changedTouches) {
this.dragStart = { x: event.changedTouches[0].clientX, y: event.changedTouches[0].clientY };
} else {
this.dragStart = { x: event.clientX, y: event.clientY };
}
// console.log("event: ", event);
// console.log("event.changedTouches: ", event.changedTouches);
// 记录点击的id
if (event.changedTouches) {
this.touchId = event.changedTouches[0].identifier;
}
}
handleMove(event) {
if (!this.active) return;
// 处理多点触控
if (event.changedTouches) {
for (let i = 0; i < event.changedTouches.length; i++) {
if (this.touchId == event.changedTouches[i].identifier) {
event.clientX = event.changedTouches[i].clientX;
event.clientY = event.changedTouches[i].clientY;
}
}
}
// 计算 x 轴距离
const xDiff = event.clientX - this.dragStart.x;
// 计算 y 轴距离
const yDiff = event.clientY - this.dragStart.y;
// 计算 角度
const angle = Math.atan2(yDiff, xDiff);
// 计算 距离
const distance = Math.min(this.maxDistance, Math.hypot(xDiff, yDiff));
// 计算 xy 的新位置
const xPosition = distance * Math.cos(angle);
const yPosition = distance * Math.sin(angle);
if (this.time && (Date.now() - this.time) < 160) return
this.time = Date.now()
if (this.direction == "x") {
// console.log("xPosition: ", Math.sign(xPosition));
// 左边 0 ~ -64 -1 3
if (xPosition < 0) {
if (xPosition < -63) {
console.log("左边: ", xPosition);
this.callback(3)
}
// 右边 1 4
} else if (xPosition > 0){
if (xPosition > 63) {
console.log("右边: ", xPosition);
this.callback(4)
}
}
// 将图片移动到新位置
this.stick.style.transform = `translate3d(${xPosition}px,0px, 0px)`;
// this.callback(Math.sign(xPosition) == -1 ? 3 : 4)
} else {
console.log("yPosition: ", yPosition);
this.stick.style.transform = `translate3d(0px,${yPosition}px, 0px)`;
this.callback(Math.sign(yPosition) == -1 ? 1 : 2, Math.round(255 * Math.round(Math.abs(yPosition)) / 64))
}
}
handleUp(event) {
if (!this.active) return;
if (event.changedTouches && this.touchId != event.changedTouches[0].identifier) return;
this.active = false;
// console.log("3 handleUp ==== ", this.active);
this.stick.style.transition = '.2s';
this.stick.style.transform = `translate3d(0px, 0px, 0px)`;
this.touchId = null;
this.callback(0, 0)
}
EventListener() {
// 鼠标 & 手指 按下
this.stick.addEventListener('mousedown', this.handleDown.bind(this));
this.stick.addEventListener('touchstart', this.handleDown.bind(this));
// 鼠标 & 手指 移动
document.addEventListener('mousemove', this.handleMove.bind(this), { passive: false });
document.addEventListener('touchmove', this.handleMove.bind(this), { passive: false });
// 鼠标 & 手指 松开
document.addEventListener('mouseup', this.handleUp.bind(this));
document.addEventListener('touchend', this.handleUp.bind(this));
}
}