1<!--
2Copyright 2022 Google LLC
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8    https://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15-->
16
17<link rel="preconnect" href="https://fonts.googleapis.com" />
18<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
19<link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@400;500;700&display=swap" rel="stylesheet" />
20
21<style>
22  body {
23    margin: 0;
24    background: var(--background);
25    font-family: "Montserrat", sans-serif;
26  }
27
28  main {
29    display: flex;
30    flex-direction: row;
31    width: 100vw;
32    height: 100vh;
33  }
34
35  #map {
36    width: var(--map-size);
37  }
38
39  #info {
40    width: 400px;
41    background: var(--sidebar-color);
42    box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23);
43  }
44
45  :root {
46    --map-size: calc(100vw - 400px);
47    --background: #cbd5e1;
48    --grid-line-color: #fbbf24;
49    --grid-background-color: #f8fafc;
50    --sidebar-color: #ea8ca8;
51    --selection-color: #f0abfc;
52  }
53</style>
54<main>
55  <pika-map id="map"></pika-map>
56  <pika-device-info id="info"></pika-device-info>
57</main>
58
59<script type="importmap">
60  {
61    "imports": {
62      "lit": "https://cdn.jsdelivr.net/gh/lit/dist@2/core/lit-core.min.js"
63    }
64  }
65</script>
66
67<script type="module">
68  import { LitElement, html } from "lit";
69
70  import "./src/components/Map.js";
71  import "./src/components/DeviceInfo.js";
72
73  const map = document.getElementById("map");
74  const info = document.getElementById("info");
75
76  map.addEventListener(
77    "select",
78    (event) => (info.device = event.detail.device)
79  );
80
81  map.addEventListener("move", () => info.update());
82
83  function set_position({
84    mac_address,
85    position: { x, y, z },
86    yaw,
87    pitch,
88    roll,
89  }) {
90    const path = "/set-position/" + mac_address;
91    fetch(path, {
92      method: "POST",
93      headers: {
94        "content-type": "application/json",
95      },
96      body: JSON.stringify({
97        x,
98        y,
99        z,
100        yaw,
101        pitch,
102        roll,
103      }),
104    });
105  }
106
107  map.addEventListener("end-move", (event) => {
108    set_position(event.detail.device);
109  });
110
111  info.addEventListener("orientation-change", () => {
112    console.log("Orientation change");
113    set_position(info.device);
114  });
115
116  const events = new EventSource("/events");
117
118  events.addEventListener("device-added", (event) => {
119    const data = JSON.parse(event.data);
120    console.log("Device Added", data);
121
122    const {
123      mac_address, x, y, z, yaw, pitch, roll,
124    } = data;
125    map.devices = [
126      ...map.devices,
127      {
128        mac_address,
129        position: { x, y, z },
130        yaw,
131        pitch,
132        roll,
133        neighbors: [],
134      },
135    ];
136  });
137
138  events.addEventListener("device-removed", (event) => {
139    const data = JSON.parse(event.data);
140    console.log("Device Removed", data);
141
142    const {
143      mac_address,
144    } = data;
145    if (info.device?.mac_address === mac_address) {
146      info.device = null;
147    }
148
149    map.devices = map.devices.filter(
150      (device) => device.mac_address !== mac_address
151    );
152
153    map.devices.forEach((device) => {
154      device.neighbors = device.neighbors.filter(
155        (neighbor) => neighbor.mac_address !== mac_address
156      );
157    });
158  });
159
160  events.addEventListener("device-updated", (event) => {
161    const data = JSON.parse(event.data);
162    console.log("Position updated", data);
163
164    const {
165      mac_address, x, y, z, yaw, pitch, roll,
166    } = data;
167
168    const device = map.devices.find(
169      (device) => device.mac_address === mac_address
170    );
171
172    device.position = { x, y, z };
173    device.yaw = yaw;
174    device.pitch = pitch;
175    device.roll = roll;
176
177    map.update();
178    info.update();
179  });
180
181  events.addEventListener("neighbor-updated", (event) => {
182    const data = JSON.parse(event.data);
183    console.log("Neighbor updated", data);
184
185    const {
186      source_mac_address,
187      destination_mac_address,
188      distance,
189      azimuth,
190      elevation,
191    } = data;
192
193    const device = map.devices.find(
194      (device) => device.mac_address === source_mac_address
195    );
196
197    const neighbor = device.neighbors.find(
198      (device) => device.mac_address == destination_mac_address
199    ) || { mac_address: destination_mac_address };
200
201    neighbor.distance = distance;
202    neighbor.azimuth = azimuth;
203    neighbor.elevation = elevation;
204
205    if (!device.neighbors.includes(neighbor)) device.neighbors.push(neighbor);
206
207    info.update();
208  });
209</script>