mirror of
https://github.com/ConnectedHumber/Air-Quality-Web
synced 2024-11-25 06:53:00 +00:00
Implement initial tour.
This commit is contained in:
parent
bc3c631c89
commit
fa433c88b0
6 changed files with 193 additions and 7 deletions
|
@ -6,13 +6,16 @@ import 'leaflet.markercluster';
|
||||||
// We're using the git repo for now until an update is released, and rollup doesn't like that apparently
|
// We're using the git repo for now until an update is released, and rollup doesn't like that apparently
|
||||||
import CreateElement from '../../node_modules/dom-create-element-query-selector/src/index.js';
|
import CreateElement from '../../node_modules/dom-create-element-query-selector/src/index.js';
|
||||||
import tabs from 'tabs';
|
import tabs from 'tabs';
|
||||||
|
import Emitter from 'event-emitter-es6';
|
||||||
|
|
||||||
import Config from './Config.mjs';
|
import Config from './Config.mjs';
|
||||||
import DeviceReadingDisplay from './DeviceReadingDisplay.mjs';
|
import DeviceReadingDisplay from './DeviceReadingDisplay.mjs';
|
||||||
import GetFromUrl from './Helpers/GetFromUrl.mjs';
|
import GetFromUrl from './Helpers/GetFromUrl.mjs';
|
||||||
|
|
||||||
class LayerDeviceMarkers {
|
class LayerDeviceMarkers extends Emitter {
|
||||||
constructor(in_map, in_device_data) {
|
constructor(in_map, in_device_data) {
|
||||||
|
super();
|
||||||
|
|
||||||
this.map = in_map;
|
this.map = in_map;
|
||||||
this.device_data = in_device_data;
|
this.device_data = in_device_data;
|
||||||
|
|
||||||
|
@ -72,6 +75,8 @@ class LayerDeviceMarkers {
|
||||||
delete device_info.longitude;
|
delete device_info.longitude;
|
||||||
|
|
||||||
event.popup.setContent(this.render_device_info(device_info));
|
event.popup.setContent(this.render_device_info(device_info));
|
||||||
|
|
||||||
|
this.emit("marker-popup-opened");
|
||||||
}
|
}
|
||||||
|
|
||||||
render_device_info(device_info) {
|
render_device_info(device_info) {
|
||||||
|
|
|
@ -63,7 +63,7 @@ class MapManager {
|
||||||
// .then(() => console.info("[map] Time dimension initialised."));
|
// .then(() => console.info("[map] Time dimension initialised."));
|
||||||
|
|
||||||
this.ui = new UI(Config, this);
|
this.ui = new UI(Config, this);
|
||||||
this.ui.setup().then(() => console.log("[map] Settings initialised."));
|
this.ui.setup().then(() => console.log("[map] UI setup complete."));
|
||||||
}
|
}
|
||||||
|
|
||||||
async setup_overlay() {
|
async setup_overlay() {
|
||||||
|
|
155
client_src/js/Tour.mjs
Normal file
155
client_src/js/Tour.mjs
Normal file
|
@ -0,0 +1,155 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
import Sheperd from 'shepherd.js';
|
||||||
|
import '../../node_modules/shepherd.js/dist/css/shepherd-theme-default.css';
|
||||||
|
|
||||||
|
class Tour {
|
||||||
|
constructor(in_map_manager) {
|
||||||
|
this.map_manager = in_map_manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
create_tour() {
|
||||||
|
this.tour = new Sheperd.Tour({
|
||||||
|
useModalOverlay: true,
|
||||||
|
defaultStepOptions: {
|
||||||
|
// Default settings for steps go here
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.tour.addStep("welcome", {
|
||||||
|
text: "Welcome to the air quality web interface! Press next to get a short tour.",
|
||||||
|
buttons: this.get_buttons(false, true)
|
||||||
|
});
|
||||||
|
|
||||||
|
this.tour.addStep("map", {
|
||||||
|
text: "Each device has a blue marker. The shape a marker is located in changes colour depending on the value of the measure it reported.",
|
||||||
|
attachTo: {
|
||||||
|
element: "#map",
|
||||||
|
on: "bottom"
|
||||||
|
},
|
||||||
|
buttons: this.get_buttons()
|
||||||
|
});
|
||||||
|
this.tour.addStep("guage", {
|
||||||
|
text: "This guage is a key to the colour of the shapes underneath the device markers.",
|
||||||
|
attachTo: {
|
||||||
|
element: document.querySelector("#canvas-guage"),
|
||||||
|
on: "left"
|
||||||
|
},
|
||||||
|
buttons: this.get_buttons()
|
||||||
|
});
|
||||||
|
|
||||||
|
this.tour.addStep("reading-type", {
|
||||||
|
text: "Devices report multiple types of measurement. Change to another reading type now.",
|
||||||
|
attachTo: {
|
||||||
|
element: document.querySelector("select").parentNode,
|
||||||
|
on: "top"
|
||||||
|
},
|
||||||
|
advanceOn: { selector: "select", event: "change" },
|
||||||
|
buttons: this.get_buttons(true)
|
||||||
|
});
|
||||||
|
this.tour.addStep("reading-type-complete", {
|
||||||
|
text: "Hey, the map changed! Some devices only report certain types of measurement, and different measurements have different colour scales.",
|
||||||
|
attachTo: { element: "#map", on: "bottom" },
|
||||||
|
buttons: this.get_buttons()
|
||||||
|
});
|
||||||
|
this.tour.addStep("layer-showhide", {
|
||||||
|
text: "You can show and hide the device markers and the heatmap here.",
|
||||||
|
attachTo: {
|
||||||
|
element: ".leaflet-control-layers",
|
||||||
|
on: "left"
|
||||||
|
},
|
||||||
|
buttons: this.get_buttons()
|
||||||
|
});
|
||||||
|
|
||||||
|
this.tour.addStep("map-controls", {
|
||||||
|
text: "You can control the zoom level and go fullscreen here. You can also zoom with your mouse wheel if you have one, and pan by clicking and dragging.",
|
||||||
|
attachTo: {
|
||||||
|
element: ".leaflet-top.leaflet-left",
|
||||||
|
on: "right"
|
||||||
|
},
|
||||||
|
buttons: this.get_buttons()
|
||||||
|
});
|
||||||
|
|
||||||
|
this.tour.addStep("device-graph", {
|
||||||
|
text: "By clicking a blue marker, you can view additional information about that device. Not all device are actively reporting data. Try clicking one now.",
|
||||||
|
attachTo: {
|
||||||
|
element: "#map",
|
||||||
|
on: "top"
|
||||||
|
},
|
||||||
|
buttons: this.get_buttons(true)
|
||||||
|
|
||||||
|
}).on("show", (() => {
|
||||||
|
this.map_manager.device_markers.once("marker-popup-opened", this.tour.next.bind(this.tour));
|
||||||
|
}).bind(this));
|
||||||
|
|
||||||
|
this.tour.addStep("device-graph-a", {
|
||||||
|
text: "This is a device information popup. By default it displays recent data that the device has reported on the line graph, but you can control this with the blue buttons.",
|
||||||
|
attachTo: {
|
||||||
|
element: ".popup-device",
|
||||||
|
on: "right"
|
||||||
|
},
|
||||||
|
buttons: this.get_buttons()
|
||||||
|
});
|
||||||
|
this.tour.addStep("device-graph-b", {
|
||||||
|
text: "By clicking here, you can see the specification of the device, including its software, sensor models, exact location, more. Click this now.",
|
||||||
|
attachTo: {
|
||||||
|
element: ".tabs :first-child",
|
||||||
|
on: "left"
|
||||||
|
},
|
||||||
|
advanceOn: { selector: ".tabs :first-child a", event: "click" },
|
||||||
|
buttons: this.get_buttons(true)
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
this.tour.addStep("report-bug", {
|
||||||
|
text: "If you find a bug, you can report it by clicking this button.",
|
||||||
|
attachTo: {
|
||||||
|
element: "button[value='Report bug']",
|
||||||
|
on: "right"
|
||||||
|
},
|
||||||
|
buttons: this.get_buttons()
|
||||||
|
});
|
||||||
|
this.tour.addStep("changelog", {
|
||||||
|
text: "The changelog will be automatically shown every time this web interface updates. Click the version information here to review it again at other times.",
|
||||||
|
attachTo: {
|
||||||
|
element: "button[value~='built']",
|
||||||
|
on: "right"
|
||||||
|
},
|
||||||
|
buttons: this.get_buttons()
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
this.tour.addStep("complete", {
|
||||||
|
text: "Tour complete!\nIf you need any additional assistance, let us know :-)",
|
||||||
|
buttons: [{ text: "Done", action: this.tour.next }]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
run_once() {
|
||||||
|
if(!window.localStorage.has("completed_tour"))
|
||||||
|
this.run();
|
||||||
|
|
||||||
|
window.localStorage.setItem("completed_tour", (new Date()).toISOString());
|
||||||
|
}
|
||||||
|
|
||||||
|
run() {
|
||||||
|
if(typeof this.tour == "undefined")
|
||||||
|
this.create_tour();
|
||||||
|
this.tour.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
get_buttons(no_continue = false, no_prev = false) {
|
||||||
|
let next = { text: "Next", action: this.tour.next },
|
||||||
|
prev = { text: "Previous", action: this.tour.back },
|
||||||
|
exit = { text: "Exit", action: this.tour.cancel };
|
||||||
|
|
||||||
|
let result = [];
|
||||||
|
if(!no_prev) result.push(prev);
|
||||||
|
if(!no_continue) result.push(next);
|
||||||
|
result.push(exit);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Tour;
|
|
@ -6,6 +6,16 @@ import NanoModal from 'nanomodal';
|
||||||
import Config from './Config.mjs';
|
import Config from './Config.mjs';
|
||||||
import GetFromUrl from './Helpers/GetFromUrl.mjs';
|
import GetFromUrl from './Helpers/GetFromUrl.mjs';
|
||||||
|
|
||||||
|
import Tour from './Tour.mjs';
|
||||||
|
|
||||||
|
function show_nanomodal(html) {
|
||||||
|
return new Promise((resolve, _reject) => {
|
||||||
|
let modal = NanoModal(html);
|
||||||
|
modal.onHide(resolve);
|
||||||
|
modal.show();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async function show_changelog(only_if_changed) {
|
async function show_changelog(only_if_changed) {
|
||||||
let current_version = `${Config.version}, built ${Config.build_date.toDateString()}`;
|
let current_version = `${Config.version}, built ${Config.build_date.toDateString()}`;
|
||||||
console.log(`[UI] Comparing current '${current_version}' to '${localStorage.getItem("last_seen_version")}'`);
|
console.log(`[UI] Comparing current '${current_version}' to '${localStorage.getItem("last_seen_version")}'`);
|
||||||
|
@ -15,9 +25,8 @@ async function show_changelog(only_if_changed) {
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("[UI] Showing changelog");
|
console.log("[UI] Showing changelog");
|
||||||
NanoModal(
|
await show_nanomodal(await GetFromUrl(`${Config.api_root}?action=changelog`));
|
||||||
await GetFromUrl(`${Config.api_root}?action=changelog`)
|
|
||||||
).show();
|
|
||||||
localStorage.setItem("last_seen_version", current_version);
|
localStorage.setItem("last_seen_version", current_version);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -29,6 +38,8 @@ class UI {
|
||||||
|
|
||||||
this.ui_panel = new SmartSettings("Settings");
|
this.ui_panel = new SmartSettings("Settings");
|
||||||
// this.ui_panel.watch((event) => console.log(event));
|
// this.ui_panel.watch((event) => console.log(event));
|
||||||
|
|
||||||
|
this.tour = new Tour(this.map_manager);
|
||||||
}
|
}
|
||||||
|
|
||||||
async setup() {
|
async setup() {
|
||||||
|
@ -64,7 +75,9 @@ class UI {
|
||||||
]);
|
]);
|
||||||
this.ui_panel.setIndex("Reading Type", this.reading_types.findIndex((type) => type.short_descr == "PM25"));
|
this.ui_panel.setIndex("Reading Type", this.reading_types.findIndex((type) => type.short_descr == "PM25"));
|
||||||
|
|
||||||
|
|
||||||
await show_changelog(true);
|
await show_changelog(true);
|
||||||
|
await this.tour.run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
13
package-lock.json
generated
13
package-lock.json
generated
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "air-quality-mapper",
|
"name": "air-quality-mapper",
|
||||||
"version": "0.9.1",
|
"version": "0.10.0",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -48,6 +48,12 @@
|
||||||
"integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==",
|
"integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"@types/event-emitter-es6": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/event-emitter-es6/-/event-emitter-es6-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-A0010GUMSopVYUlDdzhYAD8Z2qGC2hG2H32IHy554NpGEHmsx8M6/lLZRRqxXCxLq28aYrmaZtGwDJjeNXbTDQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"@types/geojson": {
|
"@types/geojson": {
|
||||||
"version": "7946.0.7",
|
"version": "7946.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.7.tgz",
|
||||||
|
@ -1120,6 +1126,11 @@
|
||||||
"integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=",
|
"integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"event-emitter-es6": {
|
||||||
|
"version": "1.1.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/event-emitter-es6/-/event-emitter-es6-1.1.5.tgz",
|
||||||
|
"integrity": "sha1-75UxGy4Xqjm+djsDHOSvfunLeEk="
|
||||||
|
},
|
||||||
"expand-brackets": {
|
"expand-brackets": {
|
||||||
"version": "2.1.4",
|
"version": "2.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "air-quality-mapper",
|
"name": "air-quality-mapper",
|
||||||
"version": "0.10",
|
"version": "0.10.0",
|
||||||
"description": "The web interface and JSON api for the ConnectedHumber Air Quality Monitoring Project.",
|
"description": "The web interface and JSON api for the ConnectedHumber Air Quality Monitoring Project.",
|
||||||
"private": true,
|
"private": true,
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
|
@ -22,6 +22,7 @@
|
||||||
"chroma-js": "^2.0.3",
|
"chroma-js": "^2.0.3",
|
||||||
"d3-delaunay": "^4.1.5",
|
"d3-delaunay": "^4.1.5",
|
||||||
"dom-create-element-query-selector": "github:hekigan/dom-create-element-query-selector",
|
"dom-create-element-query-selector": "github:hekigan/dom-create-element-query-selector",
|
||||||
|
"event-emitter-es6": "^1.1.5",
|
||||||
"iso8601-js-period": "^0.2.1",
|
"iso8601-js-period": "^0.2.1",
|
||||||
"leaflet": "^1.5.1",
|
"leaflet": "^1.5.1",
|
||||||
"leaflet-fullscreen": "^1.0.2",
|
"leaflet-fullscreen": "^1.0.2",
|
||||||
|
@ -37,6 +38,7 @@
|
||||||
"@types/chart.js": "^2.7.53",
|
"@types/chart.js": "^2.7.53",
|
||||||
"@types/chroma-js": "^1.4.1",
|
"@types/chroma-js": "^1.4.1",
|
||||||
"@types/d3-delaunay": "^4.1.0",
|
"@types/d3-delaunay": "^4.1.0",
|
||||||
|
"@types/event-emitter-es6": "^1.1.0",
|
||||||
"@types/leaflet": "^1.4.4",
|
"@types/leaflet": "^1.4.4",
|
||||||
"@types/leaflet-fullscreen": "^1.0.4",
|
"@types/leaflet-fullscreen": "^1.0.4",
|
||||||
"nightdocs": "^1.0.5",
|
"nightdocs": "^1.0.5",
|
||||||
|
|
Loading…
Reference in a new issue