import/export overlays via query string, clickable popups; v0.3.0
This commit is contained in:
parent
95dc1c8c9d
commit
696d3bc270
9 changed files with 245 additions and 58 deletions
16
README.md
16
README.md
|
@ -10,6 +10,8 @@ __note__: On mobile, for best experience you should "install to home screen" or
|
||||||
|
|
||||||
When you launch the application for the first time (and subsequent times if you don't set `home`), it will ask for your current location to set the `home` point. If you deny permission or it can't determinte your location, you can set it later via the menu and the map will zoom out to fit the entire Earth.
|
When you launch the application for the first time (and subsequent times if you don't set `home`), it will ask for your current location to set the `home` point. If you deny permission or it can't determinte your location, you can set it later via the menu and the map will zoom out to fit the entire Earth.
|
||||||
|
|
||||||
|
The exception to this behavior is when passing at least `lat` and `lng` values in the query string (eg from a location share link), in which case a marker or circle will be placed on that location and the map centered on it.
|
||||||
|
|
||||||
Along the bottom is the control bar, containing the following buttons:
|
Along the bottom is the control bar, containing the following buttons:
|
||||||
|
|
||||||
- `Home`: If the `home` point has been set, center the map view on it.
|
- `Home`: If the `home` point has been set, center the map view on it.
|
||||||
|
@ -47,15 +49,27 @@ Opening the menu shows a list of all overlays organized by type; clicking on any
|
||||||
This window is similar to the Overlay Creation window save the addition of three buttons:
|
This window is similar to the Overlay Creation window save the addition of three buttons:
|
||||||
|
|
||||||
- `Go Here`: Centers the map view on this overlay.
|
- `Go Here`: Centers the map view on this overlay.
|
||||||
|
- `Share`: Opens the Export window to export this overlay as a shareable link.
|
||||||
- `Export`: Opens the Export window to export this overlay to JSON format.
|
- `Export`: Opens the Export window to export this overlay to JSON format.
|
||||||
- `Delete`: Deletes this overlay from the map.
|
- `Delete`: Deletes this overlay from the map.
|
||||||
|
|
||||||
|
In addition to being reachable from the menu, you can also reach this screen by clicking on an overlay and then clicking on the text in the tooltip.
|
||||||
|
|
||||||
### Import/Export
|
### Import/Export
|
||||||
|
|
||||||
When exporting, the `Copy to Clipboard` button does just that. The JSON data can then be saved to a text file, emailed to a friend, or what have you.
|
When exporting, the `Copy to Clipboard` button does just that. The JSON data can then be saved to a text file, emailed to a friend, or what have you. A link from the `Share` button can be given to anyone to put in their browser.
|
||||||
|
|
||||||
When importing, the imported data is added to the current overlays. If you want to overwrite your current data, clear it first.
|
When importing, the imported data is added to the current overlays. If you want to overwrite your current data, clear it first.
|
||||||
|
|
||||||
|
When using a share link, the following query string values are valid:
|
||||||
|
|
||||||
|
- `lat`: required; should be a number
|
||||||
|
- `lng`: required; should be a number
|
||||||
|
- `rad`: optional; should be a positive number; if omitted, the shared overlay will be a `Marker`.
|
||||||
|
- `name`: optional; defaults to lat,lng
|
||||||
|
- `desc`: optional; defaults to empty
|
||||||
|
- `tile`: optional; if "sat" the tileset will use satellite data; if omitted or any other value, the tileset will use the OpenStreetMap data.
|
||||||
|
|
||||||
## build/deploy
|
## build/deploy
|
||||||
|
|
||||||
If you want to hack on `onyx` and rebuild it, I recommend rebuilding the `sourcemapper` (written in `go`) in the `buildtools` directory first (in case your `glibc` version is older).
|
If you want to hack on `onyx` and rebuild it, I recommend rebuilding the `sourcemapper` (written in `go`) in the `buildtools` directory first (in case your `glibc` version is older).
|
||||||
|
|
|
@ -74,8 +74,11 @@ abstract class OverlayBase implements Overlay {
|
||||||
return `<span class="tiny">${String(long).substring(0, 7)}°${eastWest}, ${String(lat).substring(0,7)}°${northSouth}</span>`;
|
return `<span class="tiny">${String(long).substring(0, 7)}°${eastWest}, ${String(lat).substring(0,7)}°${northSouth}</span>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
setPopupContent(content: string): void {
|
setPopupContent(content: string, state: OverlayType): void {
|
||||||
this.self.bindPopup(content);
|
const node = document.createElement('div')
|
||||||
|
node.innerHTML = content;
|
||||||
|
node.onclick = (e: any)=>{MapHandler.editOverlay(this, state)};
|
||||||
|
this.self.bindPopup(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract add(map: L.Map): void;
|
abstract add(map: L.Map): void;
|
||||||
|
@ -127,7 +130,10 @@ class Marker extends OverlayBase {
|
||||||
constructor(name: string, desc: string, point: Point, options: any) {
|
constructor(name: string, desc: string, point: Point, options: any) {
|
||||||
super(name, desc, [ point ], options);
|
super(name, desc, [ point ], options);
|
||||||
this.self = L.marker(point);
|
this.self = L.marker(point);
|
||||||
this.self.bindPopup(`<h3>${name}</h3><p>${desc}</p>`);
|
const node = document.createElement('div');
|
||||||
|
node.innerHTML = `<h3>${name}</h3><p>${desc}</p>`;
|
||||||
|
node.onclick=(e: any)=>{MapHandler.editOverlay(this, OverlayType.POINT)};
|
||||||
|
this.self.bindPopup(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
add(map: L.Map) {
|
add(map: L.Map) {
|
||||||
|
@ -148,7 +154,10 @@ class Circle extends OverlayBase {
|
||||||
constructor(name: string, desc: string, point: Point, options: any) {
|
constructor(name: string, desc: string, point: Point, options: any) {
|
||||||
super(name, desc, [ point ], options);
|
super(name, desc, [ point ], options);
|
||||||
this.self = L.circle(point, options);
|
this.self = L.circle(point, options);
|
||||||
this.self.bindPopup(`<h3>${name}</h3><p>${desc}</p>`);
|
const node = document.createElement('div');
|
||||||
|
node.innerHTML = `<h3>${name}</h3><p>${desc}</p>`;
|
||||||
|
node.onclick=(e: any)=>{MapHandler.editOverlay(this, OverlayType.CIRCLE)};
|
||||||
|
this.self.bindPopup(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
add(map: L.Map) {
|
add(map: L.Map) {
|
||||||
|
@ -173,7 +182,10 @@ class Polygon extends OverlayBase {
|
||||||
} else {
|
} else {
|
||||||
this.self = L.polyline(points, options);
|
this.self = L.polyline(points, options);
|
||||||
}
|
}
|
||||||
this.self.bindPopup(`<h3>${name}</h3><p>${desc}</p>`);
|
const node = document.createElement('div');
|
||||||
|
node.innerHTML = `<h3>${name}</h3><p>${desc}</p>`;
|
||||||
|
node.onclick=(e: any)=>{MapHandler.editOverlay(this, OverlayType.POLYGON)};
|
||||||
|
this.self.bindPopup(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
center(): Point {
|
center(): Point {
|
||||||
|
|
|
@ -1,3 +1,8 @@
|
||||||
|
enum ExportMode {
|
||||||
|
JSON = 0,
|
||||||
|
URL
|
||||||
|
}
|
||||||
|
|
||||||
class CreateOverlayModal implements Modal {
|
class CreateOverlayModal implements Modal {
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
|
@ -112,6 +117,10 @@ class CreateOverlayModal implements Modal {
|
||||||
return document.getElementById("delete-btn");
|
return document.getElementById("delete-btn");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
shareBtn(): HTMLElement | null {
|
||||||
|
return document.getElementById("share-btn");
|
||||||
|
}
|
||||||
|
|
||||||
clearInputs(): void {
|
clearInputs(): void {
|
||||||
const name = document.getElementById("createOverlay-name") as HTMLInputElement;
|
const name = document.getElementById("createOverlay-name") as HTMLInputElement;
|
||||||
const desc = document.getElementById("createOverlay-desc") as HTMLInputElement;
|
const desc = document.getElementById("createOverlay-desc") as HTMLInputElement;
|
||||||
|
@ -138,6 +147,7 @@ class CreateOverlayModal implements Modal {
|
||||||
const closePoly = _this.closePolyCheckbox();
|
const closePoly = _this.closePolyCheckbox();
|
||||||
const submitBtn = _this.submitBtn();
|
const submitBtn = _this.submitBtn();
|
||||||
const editing = args.self ? true : false;
|
const editing = args.self ? true : false;
|
||||||
|
const shareBtn = _this.shareBtn();
|
||||||
_this.clearInputs();
|
_this.clearInputs();
|
||||||
if (radiusContainer) {
|
if (radiusContainer) {
|
||||||
radiusContainer.style.display = state == OverlayType.CIRCLE ? "block" : "none";
|
radiusContainer.style.display = state == OverlayType.CIRCLE ? "block" : "none";
|
||||||
|
@ -185,6 +195,12 @@ class CreateOverlayModal implements Modal {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (shareBtn) {
|
||||||
|
shareBtn.onclick = () => {
|
||||||
|
MapHandler.exportSingle(args.self, ExportMode.URL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.setName(args.self.name);
|
this.setName(args.self.name);
|
||||||
this.setDesc(args.self.desc);
|
this.setDesc(args.self.desc);
|
||||||
if (state == OverlayType.CIRCLE) {
|
if (state == OverlayType.CIRCLE) {
|
||||||
|
@ -201,7 +217,7 @@ class CreateOverlayModal implements Modal {
|
||||||
|
|
||||||
args.self.name = name;
|
args.self.name = name;
|
||||||
args.self.desc = desc;
|
args.self.desc = desc;
|
||||||
args.self.setPopupContent(`<h3>${name}</h3><p>${desc}</p>`);
|
args.self.setPopupContent(`<h3>${name}</h3><p>${desc}</p>`, state);
|
||||||
_this.setVisible(false);
|
_this.setVisible(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -401,7 +401,7 @@ class MapHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static exportSingle(overlay: OverlayBase): void {
|
static exportSingle(overlay: OverlayBase, mode: ExportMode = ExportMode.JSON): void {
|
||||||
const self = MapHandler.instance;
|
const self = MapHandler.instance;
|
||||||
if (self) {
|
if (self) {
|
||||||
self.modals.closeAll();
|
self.modals.closeAll();
|
||||||
|
@ -419,11 +419,24 @@ class MapHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.modals.importExport.setTextArea(OverlayState.exportSingle(overlay), true);
|
switch (mode) {
|
||||||
|
case ExportMode.JSON:
|
||||||
|
self.modals.importExport.setTextArea(OverlayState.exportSingle(overlay), true);
|
||||||
|
break;
|
||||||
|
case ExportMode.URL:
|
||||||
|
self.modals.importExport.setTextArea(MapHandler.getOverlayUrl(overlay), true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
self.modals.importExport.setVisible(true);
|
self.modals.importExport.setVisible(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static getOverlayUrl(overlay: OverlayBase): string {
|
||||||
|
return window.location.origin
|
||||||
|
+ window.location.pathname
|
||||||
|
+ `?lat=${overlay.points[0].lat}&lng=${overlay.points[0].lng}&name=${overlay.name}${(overlay.desc ? "&desc=" + overlay.desc : "")}${(TileLayerWrapper.getActiveLayer() == "satelliteLayer" ? "&tile=sat" : "")}`
|
||||||
|
}
|
||||||
|
|
||||||
static exportAll(): void {
|
static exportAll(): void {
|
||||||
const self = MapHandler.instance;
|
const self = MapHandler.instance;
|
||||||
if (self) {
|
if (self) {
|
||||||
|
|
38
src/80-share.ts
Normal file
38
src/80-share.ts
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
interface StringMap {
|
||||||
|
[key: string]: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getOverlayFromQuery(): [Circle | Marker | null, string | null] {
|
||||||
|
let urlParams: StringMap = {};
|
||||||
|
let match,
|
||||||
|
pl = /\+/g,
|
||||||
|
search = /([^&=]+)=?([^&]*)/g,
|
||||||
|
decode = function (s: string) {
|
||||||
|
return decodeURIComponent(s.replace(pl, " "));
|
||||||
|
},
|
||||||
|
query = window.location.search.substring(1);
|
||||||
|
|
||||||
|
while (match = search.exec(query)) {
|
||||||
|
urlParams[decode(match[1])] = decode(match[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (urlParams["lat"] && urlParams["lng"]) {
|
||||||
|
urlParams["name"] = urlParams["name"] || `${urlParams["lat"]},${urlParams["lng"]}`;
|
||||||
|
urlParams["desc"] = urlParams["desc"] || "";
|
||||||
|
urlParams["tile"] = urlParams["tile"] || "street";
|
||||||
|
if (urlParams["rad"]) {
|
||||||
|
return [new Circle(
|
||||||
|
urlParams["name"],
|
||||||
|
urlParams["desc"],
|
||||||
|
{lat: Number(urlParams["lat"]), lng: Number(urlParams["lng"])},
|
||||||
|
{radius: Number(urlParams["rad"])}), urlParams["tile"]];
|
||||||
|
} else {
|
||||||
|
return [new Marker(
|
||||||
|
urlParams["name"],
|
||||||
|
urlParams["desc"],
|
||||||
|
{lat: Number(urlParams["lat"]), lng: Number(urlParams["lng"])},
|
||||||
|
{}), urlParams["tile"]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [null, null];
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
const helpLink = "<br>ONYX v0.2.1 [ <a target='_blank' href='https://nilfm.cc/git/onyx/about/LICENSE'>license</a> | <a target='_blank' href='https://nilfm.cc/git/onyx/about'>manual</a> ]";
|
const helpLink = "<br>ONYX v0.3.0 [ <a target='_blank' href='https://nilfm.cc/git/onyx/about/LICENSE'>license</a> | <a target='_blank' href='https://nilfm.cc/git/onyx/about'>manual</a> ]";
|
||||||
|
|
||||||
|
|
||||||
function init(): void {
|
function init(): void {
|
||||||
|
@ -72,27 +72,41 @@ function init(): void {
|
||||||
// the menu doesn't open on the first click unless we do this first... not sure why
|
// the menu doesn't open on the first click unless we do this first... not sure why
|
||||||
modals.closeAll();
|
modals.closeAll();
|
||||||
|
|
||||||
const homeData = localStorage.getItem("home");
|
const [fromQuery, tileset] = getOverlayFromQuery();
|
||||||
if (homeData) {
|
if (tileset === "sat") {
|
||||||
const home = <Point>JSON.parse(homeData);
|
MapHandler.swapTiles(null);
|
||||||
map.setView(home, 13);
|
}
|
||||||
|
if (fromQuery && !overlays.circles.some(c=>c.points[0].lat == fromQuery.points[0].lat && c.points[0].lng == fromQuery.points[0].lng) && !overlays.markers.some(m=>m.points[0].lat == fromQuery.points[0].lat && m.points[0].lng == fromQuery.points[0].lng)) {
|
||||||
|
if (fromQuery.options.radius) {
|
||||||
|
overlays.circles.push(fromQuery);
|
||||||
|
} else {
|
||||||
|
overlays.markers.push(fromQuery);
|
||||||
|
}
|
||||||
|
fromQuery.add(map);
|
||||||
|
map.setView(fromQuery.points[0], 17);
|
||||||
} else {
|
} else {
|
||||||
const okCancel = modals.okCancel;
|
const homeData = localStorage.getItem("home");
|
||||||
const okBtn = okCancel.okBtn();
|
if (homeData) {
|
||||||
if (okBtn) {
|
const home = <Point>JSON.parse(homeData);
|
||||||
okBtn.onclick = () => {
|
map.setView(home, 17);
|
||||||
modals.closeAll();
|
} else {
|
||||||
map.locate({setView: true, maxZoom: 13});
|
const okCancel = modals.okCancel;
|
||||||
|
const okBtn = okCancel.okBtn();
|
||||||
|
if (okBtn) {
|
||||||
|
okBtn.onclick = () => {
|
||||||
|
modals.closeAll();
|
||||||
|
map.locate({setView: true, maxZoom: 13});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
const cancelBtn = okCancel.cancelBtn();
|
||||||
const cancelBtn = okCancel.cancelBtn();
|
if (cancelBtn) {
|
||||||
if (cancelBtn) {
|
cancelBtn.onclick = () => {
|
||||||
cancelBtn.onclick = () => {
|
modals.closeAll();
|
||||||
modals.closeAll();
|
}
|
||||||
}
|
}
|
||||||
|
okCancel.setMsg("Would you like to use location data to set Home?");
|
||||||
|
okCancel.setVisible(true);
|
||||||
}
|
}
|
||||||
okCancel.setMsg("Would you like to use location data to set Home?");
|
|
||||||
okCancel.setVisible(true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<meta name='description' content='map annotation tool'/>
|
<meta name='description' content='map annotation tool'/>
|
||||||
<meta name='viewport' content='width=device-width,initial-scale=1'>
|
<meta name='viewport' content='width=device-width,initial-scale=1'>
|
||||||
<link rel='stylesheet' type="text/css" href="./leaflet.css">
|
<link rel='stylesheet' type="text/css" href="./leaflet.css">
|
||||||
<link rel='stylesheet' type='text/css' href='./style.css?v=0.2.1'>
|
<link rel='stylesheet' type='text/css' href='./style.css?v=0.3.0'>
|
||||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||||
<meta name="mobile-web-app-capable" content="yes" />
|
<meta name="mobile-web-app-capable" content="yes" />
|
||||||
<link rel='shortcut icon' href='/favicon.png'>
|
<link rel='shortcut icon' href='/favicon.png'>
|
||||||
|
@ -55,6 +55,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="multiBtn-container" id="edit-extra-btns">
|
<div class="multiBtn-container" id="edit-extra-btns">
|
||||||
<button id="goto-btn">Go Here</button>
|
<button id="goto-btn">Go Here</button>
|
||||||
|
<button id="share-btn">Share</button>
|
||||||
<button id="export-btn">Export</button>
|
<button id="export-btn">Export</button>
|
||||||
<button id="delete-btn">Delete</button>
|
<button id="delete-btn">Delete</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -112,5 +113,5 @@
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
<script src="./leaflet.js?v=1.8.0"></script>
|
<script src="./leaflet.js?v=1.8.0"></script>
|
||||||
<script src="./onyx.js?v=0.2.1"></script>
|
<script src="./onyx.js?v=0.3.0"></script>
|
||||||
</html>
|
</html>
|
129
static/onyx.js
129
static/onyx.js
|
@ -50,8 +50,11 @@ class OverlayBase {
|
||||||
}
|
}
|
||||||
return `<span class="tiny">${String(long).substring(0, 7)}°${eastWest}, ${String(lat).substring(0, 7)}°${northSouth}</span>`;
|
return `<span class="tiny">${String(long).substring(0, 7)}°${eastWest}, ${String(lat).substring(0, 7)}°${northSouth}</span>`;
|
||||||
}
|
}
|
||||||
setPopupContent(content) {
|
setPopupContent(content, state) {
|
||||||
this.self.bindPopup(content);
|
const node = document.createElement('div');
|
||||||
|
node.innerHTML = content;
|
||||||
|
node.onclick = (e) => { MapHandler.editOverlay(this, state); };
|
||||||
|
this.self.bindPopup(node);
|
||||||
}
|
}
|
||||||
static classSanitize(input) {
|
static classSanitize(input) {
|
||||||
return input.replace(/\-/g, "_");
|
return input.replace(/\-/g, "_");
|
||||||
|
@ -90,7 +93,10 @@ class Marker extends OverlayBase {
|
||||||
super(name, desc, [point], options);
|
super(name, desc, [point], options);
|
||||||
this.menuItem = null;
|
this.menuItem = null;
|
||||||
this.self = L.marker(point);
|
this.self = L.marker(point);
|
||||||
this.self.bindPopup(`<h3>${name}</h3><p>${desc}</p>`);
|
const node = document.createElement('div');
|
||||||
|
node.innerHTML = `<h3>${name}</h3><p>${desc}</p>`;
|
||||||
|
node.onclick = (e) => { MapHandler.editOverlay(this, OverlayType.POINT); };
|
||||||
|
this.self.bindPopup(node);
|
||||||
}
|
}
|
||||||
add(map) {
|
add(map) {
|
||||||
this.self.addTo(map);
|
this.self.addTo(map);
|
||||||
|
@ -106,7 +112,10 @@ class Circle extends OverlayBase {
|
||||||
super(name, desc, [point], options);
|
super(name, desc, [point], options);
|
||||||
this.menuItem = null;
|
this.menuItem = null;
|
||||||
this.self = L.circle(point, options);
|
this.self = L.circle(point, options);
|
||||||
this.self.bindPopup(`<h3>${name}</h3><p>${desc}</p>`);
|
const node = document.createElement('div');
|
||||||
|
node.innerHTML = `<h3>${name}</h3><p>${desc}</p>`;
|
||||||
|
node.onclick = (e) => { MapHandler.editOverlay(this, OverlayType.CIRCLE); };
|
||||||
|
this.self.bindPopup(node);
|
||||||
}
|
}
|
||||||
add(map) {
|
add(map) {
|
||||||
this.self.addTo(map);
|
this.self.addTo(map);
|
||||||
|
@ -127,7 +136,10 @@ class Polygon extends OverlayBase {
|
||||||
else {
|
else {
|
||||||
this.self = L.polyline(points, options);
|
this.self = L.polyline(points, options);
|
||||||
}
|
}
|
||||||
this.self.bindPopup(`<h3>${name}</h3><p>${desc}</p>`);
|
const node = document.createElement('div');
|
||||||
|
node.innerHTML = `<h3>${name}</h3><p>${desc}</p>`;
|
||||||
|
node.onclick = (e) => { MapHandler.editOverlay(this, OverlayType.POLYGON); };
|
||||||
|
this.self.bindPopup(node);
|
||||||
}
|
}
|
||||||
center() {
|
center() {
|
||||||
return this.self.getCenter();
|
return this.self.getCenter();
|
||||||
|
@ -323,6 +335,11 @@ class TextUtils {
|
||||||
return textArea.innerHTML;
|
return textArea.innerHTML;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
var ExportMode;
|
||||||
|
(function (ExportMode) {
|
||||||
|
ExportMode[ExportMode["JSON"] = 0] = "JSON";
|
||||||
|
ExportMode[ExportMode["URL"] = 1] = "URL";
|
||||||
|
})(ExportMode || (ExportMode = {}));
|
||||||
class CreateOverlayModal {
|
class CreateOverlayModal {
|
||||||
constructor() {
|
constructor() {
|
||||||
const _this = this;
|
const _this = this;
|
||||||
|
@ -419,6 +436,9 @@ class CreateOverlayModal {
|
||||||
deleteBtn() {
|
deleteBtn() {
|
||||||
return document.getElementById("delete-btn");
|
return document.getElementById("delete-btn");
|
||||||
}
|
}
|
||||||
|
shareBtn() {
|
||||||
|
return document.getElementById("share-btn");
|
||||||
|
}
|
||||||
clearInputs() {
|
clearInputs() {
|
||||||
const name = document.getElementById("createOverlay-name");
|
const name = document.getElementById("createOverlay-name");
|
||||||
const desc = document.getElementById("createOverlay-desc");
|
const desc = document.getElementById("createOverlay-desc");
|
||||||
|
@ -442,6 +462,7 @@ class CreateOverlayModal {
|
||||||
const closePoly = _this.closePolyCheckbox();
|
const closePoly = _this.closePolyCheckbox();
|
||||||
const submitBtn = _this.submitBtn();
|
const submitBtn = _this.submitBtn();
|
||||||
const editing = args.self ? true : false;
|
const editing = args.self ? true : false;
|
||||||
|
const shareBtn = _this.shareBtn();
|
||||||
_this.clearInputs();
|
_this.clearInputs();
|
||||||
if (radiusContainer) {
|
if (radiusContainer) {
|
||||||
radiusContainer.style.display = state == OverlayType.CIRCLE ? "block" : "none";
|
radiusContainer.style.display = state == OverlayType.CIRCLE ? "block" : "none";
|
||||||
|
@ -483,6 +504,11 @@ class CreateOverlayModal {
|
||||||
MapHandler.confirmDelete(args.self);
|
MapHandler.confirmDelete(args.self);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
if (shareBtn) {
|
||||||
|
shareBtn.onclick = () => {
|
||||||
|
MapHandler.exportSingle(args.self, ExportMode.URL);
|
||||||
|
};
|
||||||
|
}
|
||||||
this.setName(args.self.name);
|
this.setName(args.self.name);
|
||||||
this.setDesc(args.self.desc);
|
this.setDesc(args.self.desc);
|
||||||
if (state == OverlayType.CIRCLE) {
|
if (state == OverlayType.CIRCLE) {
|
||||||
|
@ -497,7 +523,7 @@ class CreateOverlayModal {
|
||||||
}
|
}
|
||||||
args.self.name = name;
|
args.self.name = name;
|
||||||
args.self.desc = desc;
|
args.self.desc = desc;
|
||||||
args.self.setPopupContent(`<h3>${name}</h3><p>${desc}</p>`);
|
args.self.setPopupContent(`<h3>${name}</h3><p>${desc}</p>`, state);
|
||||||
_this.setVisible(false);
|
_this.setVisible(false);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1122,7 +1148,7 @@ class MapHandler {
|
||||||
self.modals.okCancel.setVisible(true);
|
self.modals.okCancel.setVisible(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static exportSingle(overlay) {
|
static exportSingle(overlay, mode = ExportMode.JSON) {
|
||||||
const self = MapHandler.instance;
|
const self = MapHandler.instance;
|
||||||
if (self) {
|
if (self) {
|
||||||
self.modals.closeAll();
|
self.modals.closeAll();
|
||||||
|
@ -1138,10 +1164,22 @@ class MapHandler {
|
||||||
self.modals.info.setVisible(true);
|
self.modals.info.setVisible(true);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
self.modals.importExport.setTextArea(OverlayState.exportSingle(overlay), true);
|
switch (mode) {
|
||||||
|
case ExportMode.JSON:
|
||||||
|
self.modals.importExport.setTextArea(OverlayState.exportSingle(overlay), true);
|
||||||
|
break;
|
||||||
|
case ExportMode.URL:
|
||||||
|
self.modals.importExport.setTextArea(MapHandler.getOverlayUrl(overlay), true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
self.modals.importExport.setVisible(true);
|
self.modals.importExport.setVisible(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
static getOverlayUrl(overlay) {
|
||||||
|
return window.location.origin
|
||||||
|
+ window.location.pathname
|
||||||
|
+ `?lat=${overlay.points[0].lat}&lng=${overlay.points[0].lng}&name=${overlay.name}${(overlay.desc ? "&desc=" + overlay.desc : "")}${(TileLayerWrapper.getActiveLayer() == "satelliteLayer" ? "&tile=sat" : "")}`;
|
||||||
|
}
|
||||||
static exportAll() {
|
static exportAll() {
|
||||||
const self = MapHandler.instance;
|
const self = MapHandler.instance;
|
||||||
if (self) {
|
if (self) {
|
||||||
|
@ -1200,7 +1238,28 @@ class MapHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MapHandler.instance = null;
|
MapHandler.instance = null;
|
||||||
const helpLink = "<br>ONYX v0.2.1 [ <a target='_blank' href='https://nilfm.cc/git/onyx/about/LICENSE'>license</a> | <a target='_blank' href='https://nilfm.cc/git/onyx/about'>manual</a> ]";
|
function getOverlayFromQuery() {
|
||||||
|
let urlParams = {};
|
||||||
|
let match, pl = /\+/g, search = /([^&=]+)=?([^&]*)/g, decode = function (s) {
|
||||||
|
return decodeURIComponent(s.replace(pl, " "));
|
||||||
|
}, query = window.location.search.substring(1);
|
||||||
|
while (match = search.exec(query)) {
|
||||||
|
urlParams[decode(match[1])] = decode(match[2]);
|
||||||
|
}
|
||||||
|
if (urlParams["lat"] && urlParams["lng"]) {
|
||||||
|
urlParams["name"] = urlParams["name"] || `${urlParams["lat"]},${urlParams["lng"]}`;
|
||||||
|
urlParams["desc"] = urlParams["desc"] || "";
|
||||||
|
urlParams["tile"] = urlParams["tile"] || "street";
|
||||||
|
if (urlParams["rad"]) {
|
||||||
|
return [new Circle(urlParams["name"], urlParams["desc"], { lat: Number(urlParams["lat"]), lng: Number(urlParams["lng"]) }, { radius: Number(urlParams["rad"]) }), urlParams["tile"]];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return [new Marker(urlParams["name"], urlParams["desc"], { lat: Number(urlParams["lat"]), lng: Number(urlParams["lng"]) }, {}), urlParams["tile"]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [null, null];
|
||||||
|
}
|
||||||
|
const helpLink = "<br>ONYX v0.3.0 [ <a target='_blank' href='https://nilfm.cc/git/onyx/about/LICENSE'>license</a> | <a target='_blank' href='https://nilfm.cc/git/onyx/about'>manual</a> ]";
|
||||||
function init() {
|
function init() {
|
||||||
let overlays = new OverlayState();
|
let overlays = new OverlayState();
|
||||||
try {
|
try {
|
||||||
|
@ -1246,28 +1305,44 @@ function init() {
|
||||||
});
|
});
|
||||||
// the menu doesn't open on the first click unless we do this first... not sure why
|
// the menu doesn't open on the first click unless we do this first... not sure why
|
||||||
modals.closeAll();
|
modals.closeAll();
|
||||||
const homeData = localStorage.getItem("home");
|
const [fromQuery, tileset] = getOverlayFromQuery();
|
||||||
if (homeData) {
|
if (tileset === "sat") {
|
||||||
const home = JSON.parse(homeData);
|
MapHandler.swapTiles(null);
|
||||||
map.setView(home, 13);
|
}
|
||||||
|
if (fromQuery && !overlays.circles.some(c => c.points[0].lat == fromQuery.points[0].lat && c.points[0].lng == fromQuery.points[0].lng) && !overlays.markers.some(m => m.points[0].lat == fromQuery.points[0].lat && m.points[0].lng == fromQuery.points[0].lng)) {
|
||||||
|
if (fromQuery.options.radius) {
|
||||||
|
overlays.circles.push(fromQuery);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
overlays.markers.push(fromQuery);
|
||||||
|
}
|
||||||
|
fromQuery.add(map);
|
||||||
|
map.setView(fromQuery.points[0], 17);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
const okCancel = modals.okCancel;
|
const homeData = localStorage.getItem("home");
|
||||||
const okBtn = okCancel.okBtn();
|
if (homeData) {
|
||||||
if (okBtn) {
|
const home = JSON.parse(homeData);
|
||||||
okBtn.onclick = () => {
|
map.setView(home, 17);
|
||||||
modals.closeAll();
|
|
||||||
map.locate({ setView: true, maxZoom: 13 });
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
const cancelBtn = okCancel.cancelBtn();
|
else {
|
||||||
if (cancelBtn) {
|
const okCancel = modals.okCancel;
|
||||||
cancelBtn.onclick = () => {
|
const okBtn = okCancel.okBtn();
|
||||||
modals.closeAll();
|
if (okBtn) {
|
||||||
};
|
okBtn.onclick = () => {
|
||||||
|
modals.closeAll();
|
||||||
|
map.locate({ setView: true, maxZoom: 13 });
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const cancelBtn = okCancel.cancelBtn();
|
||||||
|
if (cancelBtn) {
|
||||||
|
cancelBtn.onclick = () => {
|
||||||
|
modals.closeAll();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
okCancel.setMsg("Would you like to use location data to set Home?");
|
||||||
|
okCancel.setVisible(true);
|
||||||
}
|
}
|
||||||
okCancel.setMsg("Would you like to use location data to set Home?");
|
|
||||||
okCancel.setVisible(true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
init();
|
init();
|
||||||
|
|
|
@ -238,8 +238,8 @@ body {
|
||||||
|
|
||||||
#createOverlay-container .multiBtn-container button:hover,
|
#createOverlay-container .multiBtn-container button:hover,
|
||||||
#createOverlay-container .multiBtn-container button:focus,
|
#createOverlay-container .multiBtn-container button:focus,
|
||||||
#createOverlay-container submitBtn:hover,
|
#createOverlay-submitBtn:hover,
|
||||||
#createOverlay-container submitBtn:focus,
|
#createOverlay-submitBtn:focus,
|
||||||
#set-home-btn:hover,
|
#set-home-btn:hover,
|
||||||
#set-home-btn:focus,
|
#set-home-btn:focus,
|
||||||
#import-btn:hover,
|
#import-btn:hover,
|
||||||
|
@ -426,6 +426,10 @@ body {
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.leaflet-popup-content {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
.leaflet-popup-close-button {
|
.leaflet-popup-close-button {
|
||||||
color: #c9c9c9 !important;
|
color: #c9c9c9 !important;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue