Skip to content

Commit

Permalink
feat(ui): Segment editing
Browse files Browse the repository at this point in the history
  • Loading branch information
Hypfer committed Mar 10, 2021
1 parent abe1f9c commit e306569
Show file tree
Hide file tree
Showing 7 changed files with 247 additions and 4 deletions.
70 changes: 70 additions & 0 deletions client/segment-edit-map.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
<ons-page id="segment-edit-map-page">
<div id="segment-edit-container">
<div class="segment-edit-header">
<ons-back-button>Forbidden Markers</ons-back-button>
<span id="segment-edit-map-page-h1"></span>
</div>

<ons-progress-bar id="loading-bar-segment-edit" value="0"></ons-progress-bar>
<canvas id="segment-edit-map"></canvas>
</div>

<div class="map-page-buttons">
<ons-fab ripple id="segment-edit-add-split-line">
<ons-icon icon="fa-arrows-h"></ons-icon>
</ons-fab>
<ons-fab ripple id="segment-edit-split">
<ons-icon icon="fa-cut"></ons-icon>
</ons-fab>
<ons-fab ripple id="segment-edit-join">
<ons-icon icon="fa-object-group"></ons-icon>
</ons-fab>
</div>

<script>
{
let s = document.createElement('script');
s.src = "segment-edit-map.js";
s.type = "module";
s.crossOrigin = "use-credentials";
ons.getScriptPage().appendChild(s);
s.onreadystatechange = s.onload = () => { window.markerConfigInit(); };
}
</script>
<style>
#segment-edit-container {
display: grid;
grid-template-columns: 1fr;
grid-template-rows: auto auto 1fr;

height: 100%;
width: 100%;
}

#segment-edit-map {
touch-action: none;
height: 100%;
width: 100%;
}

#segment-edit-map-page-h1 {
flex-grow: 1;
text-align: center;
}

.segment-edit-header {
display: flex;
align-items: center;
}

.segment-edit-buttons {
position: absolute;
right: 1.5em;
bottom: 1.5em;
display: grid;
grid-template-columns: auto;
grid-template-rows: auto;
grid-gap: 0.5em;
}
</style>
</ons-page>
116 changes: 116 additions & 0 deletions client/segment-edit-map.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
/*global ons, fn*/
import {VacuumMap} from "./zone/js-modules/vacuum-map.js";
import {ApiService} from "./services/api.service.js";

function markerConfigInit() {
const map = new VacuumMap(document.getElementById("segment-edit-map"));
const loadingBarSegmentEdit = document.getElementById("loading-bar-segment-edit");

const topPage = fn.getTopPage();
const mapData = JSON.parse(JSON.stringify(topPage.data.map)); //cloned for good measure

mapData.layers.forEach(layer => {
if (layer.type === "segment") {
layer.metaData.active = false;
}
});

map.initCanvas(mapData, {metaData: "segments", noGotoPoints: true});
window.fn.map = map;

document.getElementById("segment-edit-map-page-h1").innerText = "Editing Segments";

document.getElementById("segment-edit-add-split-line").onclick = () => {
if (map.getLocations().virtualWalls.length === 0) {
map.addVirtualWall(null, false, true);
} else {
ons.notification.toast("There can only be one split line.",{buttonLabel: "Dismiss", timeout: window.fn.toastErrorTimeout});
}
};

document.getElementById("segment-edit-split").onclick = async () => {
let locations = map.getLocations();

if (locations.selectedSegments.length === 1) {
if (locations.virtualWalls.length === 1) {
loadingBarSegmentEdit.setAttribute("indeterminate", "indeterminate");

try {
await ApiService.splitSegment(
{
x: locations.virtualWalls[0][0],
y: locations.virtualWalls[0][1]
},
{
x: locations.virtualWalls[0][2],
y: locations.virtualWalls[0][3]
},
locations.selectedSegments[0].id
);
await ons.notification.toast(
"Successfully split segment!",
{buttonLabel: "Dismiss", timeout: window.fn.toastOKTimeout});
fn.popPage();
} catch (err) {
ons.notification.toast(err.message, {buttonLabel: "Dismiss", timeout: window.fn.toastErrorTimeout});
} finally {
loadingBarSegmentEdit.removeAttribute("indeterminate");
}
} else {
ons.notification.toast("You need to have a split line to split",{buttonLabel: "Dismiss", timeout: window.fn.toastErrorTimeout});
}
} else {
ons.notification.toast("You need to select exactly one segment to execute a split",{buttonLabel: "Dismiss", timeout: window.fn.toastErrorTimeout});
}
};

document.getElementById("segment-edit-join").onclick = async () => {
let locations = map.getLocations();

if (locations.selectedSegments.length === 2) {
loadingBarSegmentEdit.setAttribute("indeterminate", "indeterminate");

try {
await ApiService.joinSegments(
locations.selectedSegments[0].id,
locations.selectedSegments[1].id
);
await ons.notification.toast(
"Successfully joined segment!",
{buttonLabel: "Dismiss", timeout: window.fn.toastOKTimeout});
fn.popPage();
} catch (err) {
ons.notification.toast(err.message, {buttonLabel: "Dismiss", timeout: window.fn.toastErrorTimeout});
} finally {
loadingBarSegmentEdit.removeAttribute("indeterminate");
}
} else {
ons.notification.toast("You need to select exactly two segment to execute a join",{buttonLabel: "Dismiss", timeout: window.fn.toastErrorTimeout});
}
};

/*
saveButton.onclick = async () => {
loadingBarSaveMarkers.setAttribute("indeterminate", "indeterminate");
saveButton.setAttribute("disabled", "disabled");
try {
await ApiService.setPersistentData(
map.getLocations().virtualWalls,
map.getLocations().forbiddenZones,
map.getLocations().forbiddenMopZones
);
await ons.notification.toast(
"Successfully saved forbidden markers!",
{buttonLabel: "Dismiss", timeout: window.fn.toastOKTimeout});
fn.popPage();
} catch (err) {
ons.notification.toast(err.message, {buttonLabel: "Dismiss", timeout: window.fn.toastErrorTimeout});
} finally {
loadingBarSaveMarkers.removeAttribute("indeterminate");
saveButton.removeAttribute("disabled");
}
}; */
}

window.markerConfigInit = markerConfigInit;
17 changes: 17 additions & 0 deletions client/services/api.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,23 @@ export class ApiService {
});
}

static async splitSegment(pA, pB, segment_id) {
await this.fetch("PUT", "api/v2/robot/capabilities/MapSegmentationCapability", {
action: "split_segment",
pA: pA,
pB: pB,
segment_id: segment_id
});
}

static async joinSegments(segment_a_id, segment_b_id) {
await this.fetch("PUT", "api/v2/robot/capabilities/MapSegmentationCapability", {
action: "join_segments",
segment_a_id: segment_a_id,
segment_b_id: segment_b_id
});
}

static async getVacuumState() {
return await this.fetch("GET", "api/v2/robot/state/attributes");
}
Expand Down
4 changes: 4 additions & 0 deletions client/zone/js-modules/vacuum-map.js
Original file line number Diff line number Diff line change
Expand Up @@ -385,10 +385,14 @@ export function VacuumMap(canvasElement) {
case "none":
break;
case "forbidden":
//TODO: This is currently broken and needs fixing
updateForbiddenZones(data.no_go_areas || []);
updateForbiddenMopZones(data.no_mop_areas || []);
updateVirtualWalls(data.virtual_walls || []);
break;
case "segments":
updateSegmentMetadata(data.layers.filter(e => e.type === "segment"));
break;
default:
updateMapMetadata(data);
}
Expand Down
14 changes: 12 additions & 2 deletions client/zones.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@
<ons-list id="spot-list">
<ons-list-item>No spots are configured yet.</ons-list-item>
</ons-list>

<div id="forbidden-zones-item" hidden>
<ons-list-title style="margin-top:20px;">Forbidden markers</ons-list-title>
<ons-list-title style="margin-top:20px;">Segment edit</ons-list-title>
<ons-list id="forbidden-zones-list">
<ons-list-item tappable class="locations-list-item" onclick="switchToForbiddenMarkersEdit()">
<label><ons-icon icon="edit"></ons-icon></label>
Expand All @@ -21,6 +21,16 @@
</ons-list>
</div>

<div id="segment-edit-item" hidden>
<ons-list-title style="margin-top:20px;">Edit Segments</ons-list-title>
<ons-list id="segment-edit-list">
<ons-list-item tappable class="locations-list-item" onclick="switchToSegmentEdit()">
<label><ons-icon icon="edit"></ons-icon></label>
<label>Edit Segments</label>
</ons-list-item>
</ons-list>
</div>

<script>
{
let s = document.createElement('script');
Expand Down
22 changes: 22 additions & 0 deletions client/zones.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ let loadingBarZones = document.getElementById("loading-bar-zones");
let zonesList = document.getElementById("zones-list");
let spotList = document.getElementById("spot-list");
let forbiddenZonesItem = document.getElementById("forbidden-zones-item");
let segmentEditItem = document.getElementById("segment-edit-item");

/** @type {Array<{id:number, name:string, user: boolean, areas: Array}>} */
let zonesConfig = [];
Expand Down Expand Up @@ -62,6 +63,23 @@ async function switchToForbiddenMarkersEdit(index) {
}
}

async function switchToSegmentEdit(index) {
loadingBarZones.setAttribute("indeterminate", "indeterminate");
try {
let mapData = await ApiService.getLatestMap();
fn.pushPage({
"id": "segment-edit-map.html",
"title": "Segment edit map",
"data": {"map": mapData}
});
} catch (err) {
ons.notification.toast(err.message,
{buttonLabel: "Dismiss", timeout: window.fn.toastErrorTimeout});
} finally {
loadingBarZones.removeAttribute("indeterminate");
}
}

function deleteZone(index) {
zonesConfig.splice(index, 1);
saveZones();
Expand Down Expand Up @@ -217,6 +235,9 @@ async function ZonesInit() {
if (robotCapabilities.includes("CombinedVirtualRestrictionsCapability")) {
forbiddenZonesItem.hidden = false;
}
if (robotCapabilities.includes("MapSegmentationCapability")) {
segmentEditItem.hidden = false;
}
} catch (err) {
ons.notification.toast(err.message,
{buttonLabel: "Dismiss", timeout: window.fn.toastErrorTimeout});
Expand All @@ -229,6 +250,7 @@ window.ZonesInit = ZonesInit;
window.switchToMapZoneEdit = switchToMapZoneEdit;
window.switchToMapSpotEdit = switchToMapSpotEdit;
window.switchToForbiddenMarkersEdit = switchToForbiddenMarkersEdit;
window.switchToSegmentEdit = switchToSegmentEdit;
window.deleteZone = deleteZone;
window.deleteSpot = deleteSpot;
window.addNewZone = addNewZone;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ class RoborockMapSegmentationCapability extends MapSegmentationCapability {
* @returns {Promise<void>}
*/
async joinSegments(segmentA, segmentB) {
await this.robot.sendCommand("merge_segment", [segmentA.id, segmentB.id], {timeout: 5000});
await this.robot.sendCommand("merge_segment", [segmentA.id, segmentB.id], {timeout: 5000}).finally(() => {
this.robot.pollMap();
});
}

/**
Expand All @@ -46,7 +48,9 @@ class RoborockMapSegmentationCapability extends MapSegmentationCapability {
RRMapParser.DIMENSION_MM - pB.y * 10
];

await this.robot.sendCommand("split_segment", flippedSplitLine, {timeout: 5000});
await this.robot.sendCommand("split_segment", flippedSplitLine, {timeout: 5000}).finally(() => {
this.robot.pollMap();
});
}
}

Expand Down

0 comments on commit e306569

Please sign in to comment.