iobroker.roborock
Version:
256 lines (230 loc) • 5.28 kB
HTML
<html>
<head>
<title>Roborock Map</title>
<script type="importmap">
{
"imports": {
"d3": "https://esm.sh/d3@7.9.0"
}
}
</script>
<script src="/socket.io/socket.io.js"></script>
<script type="module" src="./app.js"></script>
<style>
/* Main Layout */
body {
display: flex;
align-items: center;
background-color: #000000;
margin: 0;
overflow: hidden; /* Prevents scrollbars from D3 zoom */
font-family:
system-ui,
-apple-system,
BlinkMacSystemFont,
"Segoe UI",
Roboto,
Oxygen,
Ubuntu,
Cantarell,
"Open Sans",
"Helvetica Neue",
sans-serif;
}
#mapSvgContainer {
/* SVG Container */
width: 450px;
height: 450px;
border: 2px solid #4f4f4f;
box-shadow: 0px 0px 10px #333;
border-radius: 15px;
overflow: hidden; /* Important for Pan/Zoom constraints */
position: relative;
background-color: #1a1a1a;
}
#mapSvg {
width: 100%;
height: 100%;
display: block;
cursor: grab;
}
#mapSvg:active {
cursor: grabbing;
}
/* --- Interactive SVG Elements --- */
.zone-rect {
fill: rgba(255, 255, 255, 0.5);
stroke: white;
stroke-width: 1.5;
/* vector-effect: non-scaling-stroke; Keeps stroke width constant */
cursor: move;
}
.zone-handle {
fill: red;
cursor: nwse-resize;
}
.obstacle-marker {
fill: rgba(0, 150, 255, 0.7);
stroke: white;
stroke-width: 0.5;
vector-effect: non-scaling-stroke;
cursor: pointer;
transition: r 0.1s ease-in-out;
}
.obstacle-marker:hover {
fill: rgba(0, 200, 255, 0.9);
}
.go-to-pin {
cursor: crosshair;
}
/* --- Popup Styling --- */
#popup {
display: none;
position: absolute;
background-color: white;
border-radius: 5px;
padding: 5px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5);
pointer-events: none;
transform: translate(-50%, -100%);
margin-top: -15px;
z-index: 10;
}
#popup-image {
display: block;
width: 100px;
height: 100px;
border: 1px solid black;
cursor: pointer;
pointer-events: auto;
}
#triangle {
display: none;
position: absolute;
bottom: -10px;
left: 50%;
transform: translateX(-50%);
width: 0;
height: 0;
border-style: solid;
border-width: 10px 10px 0 10px;
border-color: white transparent transparent transparent;
z-index: 10;
}
#largePhoto {
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
display: none;
position: fixed;
z-index: 1000;
border: 2px solid white;
box-shadow: 0 0 15px rgba(0, 0, 0, 0.7);
}
#largePhoto-image {
display: block;
max-width: 80vw;
max-height: 80vh;
width: auto;
height: auto;
}
#largePhoto-bbox {
display: none;
position: absolute;
border: 3px solid #ff3b30;
box-shadow: 0 0 8px rgba(255, 59, 48, 0.8);
pointer-events: none;
z-index: 1001;
}
/* --- General Styling --- */
#addButton,
#deleteButton {
display: inline-block;
width: 100px;
}
#addButton {
margin-right: 0px;
}
#deleteButton {
margin-left: 0px;
}
#startButton,
#stopButton,
#pauseButton {
display: inline-block;
width: 100px;
}
#startButton,
#pauseButton {
margin-right: 0px;
}
#stopButton {
margin-left: 0px;
}
button,
select {
margin: 10px 20px;
padding: 10px 20px;
border-radius: 10px;
background-color: #2d9cdb;
color: #f0f0f0;
cursor: pointer;
transition: background-color 0.2s ease-in-out;
font-size: 16px;
font-weight: bold;
border: 1px solid #4f4f4f;
width: 200px;
}
button:hover,
select:hover {
background-color: #47a9dc;
}
button:disabled {
color: gray;
background-color: lightgray;
cursor: not-allowed;
}
.hovered-option {
background-color: #47a9dc ;
}
</style>
</head>
<body>
<div id="mapSvgContainer">
<svg id="mapSvg" width="450" height="450"></svg>
</div>
<div id="popup">
<img id="popup-image" src="" alt="Obstacle Preview" />
<div id="triangle"></div>
</div>
<div id="largePhoto">
<img id="largePhoto-image" src="" alt="Obstacle Detail" />
<div id="largePhoto-bbox"></div>
</div>
<div style="display: flex; flex-direction: column; align-items: center">
<div style="margin-left: auto">
<select id="robotSelect"></select>
</div>
<div style="margin-left: auto">
<select id="cleanCount">
<option value="1">1 Time</option>
<option value="2">2 Times</option>
<option value="3">3 Times</option>
</select>
</div>
<div style="display: flex" id="zoneButtons">
<button id="addButton">+ Zone</button>
<button disabled id="deleteButton">- Zone</button>
</div>
<div style="display: flex" id="robotButtons">
<button id="pauseButton" style="display: none">Pause</button>
<button id="startButton">Start</button>
<button id="stopButton">Stop</button>
</div>
<button id="dockButton">Dock</button>
<button id="goToButton">GoTo Point</button>
<button id="resetZoomButton">Reset zoom</button>
</div>
</body>
</html>