266 lines
8.4 KiB
HTML
Executable File
266 lines
8.4 KiB
HTML
Executable File
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<meta
|
|
name="viewport"
|
|
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
|
|
/>
|
|
<title>Arrow Button Layout</title>
|
|
<script src="{{ url_for('static', filename='js/socketio/socket.io.min.js') }}"></script>
|
|
<style>
|
|
/* 禁用用户选择 */
|
|
* {
|
|
-webkit-user-select: none;
|
|
/* Chrome, Opera, Safari */
|
|
-moz-user-select: none;
|
|
/* Firefox */
|
|
-ms-user-select: none;
|
|
/* Internet Explorer/Edge */
|
|
user-select: none;
|
|
/* Non-prefixed version, currently supported by Chrome, Opera and Firefox */
|
|
-webkit-tap-highlight-color: transparent;
|
|
/* 禁用触控点击的蓝色叠加层 */
|
|
}
|
|
body {
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
height: 180px;
|
|
margin: 0;
|
|
background-color: #f3f4f600;
|
|
font-family: Arial, sans-serif;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.button-container {
|
|
display: grid;
|
|
grid-template-columns: 45px 45px 45px;
|
|
grid-template-rows: 45px 45px 45px;
|
|
gap: 8px;
|
|
align-items: center;
|
|
justify-items: center;
|
|
padding: 20px;
|
|
background-color: #bb29ff13;
|
|
border-radius: 50%;
|
|
box-shadow: inset 0 2px 4px 0 rgba(0, 0, 0, 0.1);
|
|
transform: scale(0.8);
|
|
}
|
|
|
|
.arrow-button {
|
|
width: 110px;
|
|
height: 110px;
|
|
cursor: pointer;
|
|
transition: opacity 0.1s;
|
|
}
|
|
|
|
/* SVG 的渐变颜色 */
|
|
.gradient-fill {
|
|
fill: url(#gradient);
|
|
stroke: none; /* 移除边框 */
|
|
opacity: 0.45; /* 默认透明度提高 */
|
|
transition: all 0.1s;
|
|
}
|
|
|
|
.active .gradient-fill {
|
|
opacity: 1; /* 点击后透明度变高 */
|
|
}
|
|
|
|
#up-button {
|
|
grid-column: 2 / 3;
|
|
grid-row: 1 / 2;
|
|
transform: rotate(180deg);
|
|
}
|
|
|
|
#left-button {
|
|
grid-column: 1 / 2;
|
|
grid-row: 2 / 3;
|
|
transform: rotate(90deg);
|
|
}
|
|
|
|
#right-button {
|
|
grid-column: 3 / 4;
|
|
grid-row: 2 / 3;
|
|
transform: rotate(-90deg);
|
|
}
|
|
|
|
#down-button {
|
|
grid-column: 2 / 3;
|
|
grid-row: 3 / 4;
|
|
transform: rotate(0deg);
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="button-container">
|
|
<div class="arrow-button" id="up-button" data-direction="up">
|
|
<svg
|
|
id="图层_1"
|
|
data-name="图层 1"
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
viewBox="0 0 87.65 41.25"
|
|
width="110"
|
|
height="110"
|
|
>
|
|
<defs>
|
|
<linearGradient id="gradient" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
<stop offset="0%" style="stop-color: #d460f1; stop-opacity: 1" />
|
|
<stop
|
|
offset="100%"
|
|
style="stop-color: #9142c5; stop-opacity: 0.5"
|
|
/>
|
|
</linearGradient>
|
|
</defs>
|
|
<path
|
|
class="gradient-fill"
|
|
d="M7218.47,7153.94a5.51,5.51,0,0,0-6.19-1.09,31.16,31.16,0,0,1-25.53,0,5.51,5.51,0,0,0-6.16,1.07l-22.87,22.62a5.48,5.48,0,0,0,.33,8.1,65.7,65.7,0,0,0,82.87.27,5.47,5.47,0,0,0,.39-8.09Z"
|
|
transform="translate(-7155.59 -7151.85)"
|
|
/>
|
|
</svg>
|
|
</div>
|
|
<div class="arrow-button" id="left-button" data-direction="left">
|
|
<svg
|
|
id="图层_1"
|
|
data-name="图层 1"
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
viewBox="0 0 87.65 41.25"
|
|
width="110"
|
|
height="110"
|
|
>
|
|
<defs>
|
|
<linearGradient id="gradient" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
<stop offset="0%" style="stop-color: #d460f1; stop-opacity: 1" />
|
|
<stop
|
|
offset="100%"
|
|
style="stop-color: #9142c5; stop-opacity: 0.5"
|
|
/>
|
|
</linearGradient>
|
|
</defs>
|
|
<path
|
|
class="gradient-fill"
|
|
d="M7218.47,7153.94a5.51,5.51,0,0,0-6.19-1.09,31.16,31.16,0,0,1-25.53,0,5.51,5.51,0,0,0-6.16,1.07l-22.87,22.62a5.48,5.48,0,0,0,.33,8.1,65.7,65.7,0,0,0,82.87.27,5.47,5.47,0,0,0,.39-8.09Z"
|
|
transform="translate(-7155.59 -7151.85)"
|
|
/>
|
|
</svg>
|
|
</div>
|
|
<div class="arrow-button" id="right-button" data-direction="right">
|
|
<svg
|
|
id="图层_1"
|
|
data-name="图层 1"
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
viewBox="0 0 87.65 41.25"
|
|
width="110"
|
|
height="110"
|
|
>
|
|
<defs>
|
|
<linearGradient id="gradient" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
<stop offset="0%" style="stop-color: #d460f1; stop-opacity: 1" />
|
|
<stop
|
|
offset="100%"
|
|
style="stop-color: #9142c5; stop-opacity: 0.5"
|
|
/>
|
|
</linearGradient>
|
|
</defs>
|
|
<path
|
|
class="gradient-fill"
|
|
d="M7218.47,7153.94a5.51,5.51,0,0,0-6.19-1.09,31.16,31.16,0,0,1-25.53,0,5.51,5.51,0,0,0-6.16,1.07l-22.87,22.62a5.48,5.48,0,0,0,.33,8.1,65.7,65.7,0,0,0,82.87.27,5.47,5.47,0,0,0,.39-8.09Z"
|
|
transform="translate(-7155.59 -7151.85)"
|
|
/>
|
|
</svg>
|
|
</div>
|
|
<div class="arrow-button" id="down-button" data-direction="down">
|
|
<svg
|
|
id="图层_1"
|
|
data-name="图层 1"
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
viewBox="0 0 87.65 41.25"
|
|
width="110"
|
|
height="110"
|
|
>
|
|
<defs>
|
|
<linearGradient id="gradient" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
<stop offset="0%" style="stop-color: #d460f1; stop-opacity: 1" />
|
|
<stop
|
|
offset="100%"
|
|
style="stop-color: #9142c5; stop-opacity: 0.5"
|
|
/>
|
|
</linearGradient>
|
|
</defs>
|
|
<path
|
|
class="gradient-fill"
|
|
d="M7218.47,7153.94a5.51,5.51,0,0,0-6.19-1.09,31.16,31.16,0,0,1-25.53,0,5.51,5.51,0,0,0-6.16,1.07l-22.87,22.62a5.48,5.48,0,0,0,.33,8.1,65.7,65.7,0,0,0,82.87.27,5.47,5.47,0,0,0,.39-8.09Z"
|
|
transform="translate(-7155.59 -7151.85)"
|
|
/>
|
|
</svg>
|
|
</div>
|
|
</div>
|
|
<script>
|
|
const socket = io();
|
|
|
|
document.querySelectorAll(".arrow-button").forEach((button) => {
|
|
const svgPath = button.querySelector("path");
|
|
const direction = button.getAttribute("data-direction");
|
|
|
|
button.addEventListener("touchstart", function (event) {
|
|
const touch = event.touches[0];
|
|
if (isInsidePath(svgPath, touch.clientX, touch.clientY)) {
|
|
button.classList.add("active");
|
|
socket.emit("send_command", `adjust:pose:move ${direction}:mid`);
|
|
}
|
|
});
|
|
|
|
button.addEventListener("touchend", function (event) {
|
|
if (button.classList.contains("active")) {
|
|
button.classList.remove("active");
|
|
}
|
|
event.preventDefault();
|
|
});
|
|
|
|
button.addEventListener("mousedown", function (event) {
|
|
if (isInsidePath(svgPath, event.clientX, event.clientY)) {
|
|
button.classList.add("active");
|
|
socket.emit("send_command", `adjust:pose:move ${direction}:mid`);
|
|
}
|
|
});
|
|
|
|
button.addEventListener("mouseup", function (event) {
|
|
if (button.classList.contains("active")) {
|
|
button.classList.remove("active");
|
|
}
|
|
});
|
|
|
|
button.addEventListener("mouseleave", function () {
|
|
button.classList.remove("active");
|
|
});
|
|
});
|
|
|
|
function isInsidePath(path, x, y, tolerance = 5) {
|
|
const point = path.ownerSVGElement.createSVGPoint();
|
|
point.x = x;
|
|
point.y = y;
|
|
const matrix = path.getScreenCTM().inverse();
|
|
const transformedPoint = point.matrixTransform(matrix);
|
|
|
|
if (path.isPointInFill(transformedPoint)) {
|
|
return true;
|
|
}
|
|
|
|
const bbox = path.getBBox();
|
|
const expandedBBox = {
|
|
x: bbox.x - tolerance,
|
|
y: bbox.y - tolerance,
|
|
width: bbox.width + 2 * tolerance,
|
|
height: bbox.height + 2 * tolerance,
|
|
};
|
|
|
|
return (
|
|
transformedPoint.x >= expandedBBox.x &&
|
|
transformedPoint.x <= expandedBBox.x + expandedBBox.width &&
|
|
transformedPoint.y >= expandedBBox.y &&
|
|
transformedPoint.y <= expandedBBox.y + expandedBBox.height
|
|
);
|
|
}
|
|
</script>
|
|
</body>
|
|
</html>
|