@trailstash/ultra 3.6.0 → 3.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Examples/add-a-title.ultra +16 -0
- package/Examples/add-an-info-modal.ultra +66 -0
- package/Examples/htmlcontrol-linkbutton.ultra +25 -0
- package/components/html-control.js +74 -0
- package/components/ultra-map.js +14 -1
- package/docs/assets/Examples/add-a-title.png +0 -0
- package/docs/assets/Examples/add-an-info-modal.png +0 -0
- package/docs/assets/Examples/htmlcontrol-linkbutton.png +0 -0
- package/docs/assets/screenshot.png +0 -0
- package/docs/index.md +2 -2
- package/docs/resources.md +123 -0
- package/index.js +12 -0
- package/package.json +1 -1
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Add a title to a map
|
|
3
|
+
description: Use Ultra's HTMLControl to add a title to the map
|
|
4
|
+
controls:
|
|
5
|
+
- type: HTMLControl
|
|
6
|
+
options:
|
|
7
|
+
html: >
|
|
8
|
+
<h1><center>A Titled Map!</center></h1>
|
|
9
|
+
css: >
|
|
10
|
+
h1 {
|
|
11
|
+
position: fixed;
|
|
12
|
+
top: 0;
|
|
13
|
+
left: 0;
|
|
14
|
+
right: 0;
|
|
15
|
+
}
|
|
16
|
+
---
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Add a custom modal control to the map
|
|
3
|
+
description: This adds an info button that opens a modal clicked using Ultra's HTMLControl
|
|
4
|
+
controls:
|
|
5
|
+
- type: NavigationControl
|
|
6
|
+
- type: HTMLControl
|
|
7
|
+
options:
|
|
8
|
+
html: >
|
|
9
|
+
<div class="maplibregl-ctrl maplibregl-ctrl-group">
|
|
10
|
+
<label for="info-modal">
|
|
11
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 192 512"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M48 80a48 48 0 1 1 96 0A48 48 0 1 1 48 80zM0 224c0-17.7 14.3-32 32-32l64 0c17.7 0 32 14.3 32 32l0 224 32 0c17.7 0 32 14.3 32 32s-14.3 32-32 32L32 512c-17.7 0-32-14.3-32-32s14.3-32 32-32l32 0 0-192-32 0c-17.7 0-32-14.3-32-32z"/></svg>
|
|
12
|
+
</label>
|
|
13
|
+
</div>
|
|
14
|
+
<input type="checkbox" id="info-modal" checked></input>
|
|
15
|
+
<div class="info-modal">
|
|
16
|
+
<label for="info-modal" class="close">✕</label>
|
|
17
|
+
<h1>Information!</h1>
|
|
18
|
+
<p>
|
|
19
|
+
This is a simple way to add a information modal to your map.
|
|
20
|
+
</p>
|
|
21
|
+
<p>
|
|
22
|
+
To have it closed by default, remove the <code>checked</code> attribute from the checkbox <code>input</code>
|
|
23
|
+
</p>
|
|
24
|
+
</div>
|
|
25
|
+
css: >
|
|
26
|
+
.maplibregl-ctrl svg {
|
|
27
|
+
height: 16px;
|
|
28
|
+
width: 16px;
|
|
29
|
+
padding: 6.5px;
|
|
30
|
+
float: right;
|
|
31
|
+
}
|
|
32
|
+
.maplibregl-ctrl svg:hover {
|
|
33
|
+
background-color: rgba(0, 0, 0, 0.05);
|
|
34
|
+
}
|
|
35
|
+
label[for=info-modal] {
|
|
36
|
+
cursor: pointer;
|
|
37
|
+
}
|
|
38
|
+
label[for=info-modal].close {
|
|
39
|
+
float: right;
|
|
40
|
+
text-align: center;
|
|
41
|
+
height: 20px;
|
|
42
|
+
width: 20px;
|
|
43
|
+
display: block;
|
|
44
|
+
}
|
|
45
|
+
#info-modal {
|
|
46
|
+
display: none;
|
|
47
|
+
}
|
|
48
|
+
.info-modal {
|
|
49
|
+
display: none;
|
|
50
|
+
}
|
|
51
|
+
#info-modal:checked + .info-modal {
|
|
52
|
+
display: block;
|
|
53
|
+
position: fixed;
|
|
54
|
+
top: 0;
|
|
55
|
+
left: 0;
|
|
56
|
+
right: 0;
|
|
57
|
+
margin: 50px 20%;
|
|
58
|
+
padding: 20px;
|
|
59
|
+
background: white;
|
|
60
|
+
border-radius: 10px;
|
|
61
|
+
border: 1px solid grey;
|
|
62
|
+
pointer-events: initial;
|
|
63
|
+
box-shadow: 0 0 5px;
|
|
64
|
+
}
|
|
65
|
+
style: https://demotiles.maplibre.org/style.json
|
|
66
|
+
---
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Use HTMLControl to add a link button to your map
|
|
3
|
+
description: This adds an info button that opens a link in a new window when clicked using Ultra's HTMLControl
|
|
4
|
+
controls:
|
|
5
|
+
- type: NavigationControl
|
|
6
|
+
- type: HTMLControl
|
|
7
|
+
options:
|
|
8
|
+
html: >
|
|
9
|
+
<div class="maplibregl-ctrl maplibregl-ctrl-group">
|
|
10
|
+
<a href="https://overpass-ultra.us/docs" target="_blank">
|
|
11
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 192 512"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M48 80a48 48 0 1 1 96 0A48 48 0 1 1 48 80zM0 224c0-17.7 14.3-32 32-32l64 0c17.7 0 32 14.3 32 32l0 224 32 0c17.7 0 32 14.3 32 32s-14.3 32-32 32L32 512c-17.7 0-32-14.3-32-32s14.3-32 32-32l32 0 0-192-32 0c-17.7 0-32-14.3-32-32z"/></svg>
|
|
12
|
+
</a>
|
|
13
|
+
</div>
|
|
14
|
+
css: >
|
|
15
|
+
.maplibregl-ctrl svg {
|
|
16
|
+
height: 16px;
|
|
17
|
+
width: 16px;
|
|
18
|
+
padding: 6.5px;
|
|
19
|
+
float: right;
|
|
20
|
+
}
|
|
21
|
+
.maplibregl-ctrl svg:hover {
|
|
22
|
+
background-color: rgba(0, 0, 0, 0.05);
|
|
23
|
+
}
|
|
24
|
+
style: https://demotiles.maplibre.org/style.json
|
|
25
|
+
---
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import DOMPurify from "dompurify";
|
|
2
|
+
|
|
3
|
+
import { h } from "../lib/dom.js";
|
|
4
|
+
import { normalizeCSS } from "../lib/normalize.js";
|
|
5
|
+
import maplibreglStyle from "maplibre-gl/dist/maplibre-gl.css";
|
|
6
|
+
|
|
7
|
+
const maplibreCSS = new CSSStyleSheet();
|
|
8
|
+
maplibreCSS.replaceSync(`
|
|
9
|
+
${maplibreglStyle}
|
|
10
|
+
/* override inset(top/left/bottom/right) & position bc nestin in existing controlgroup corner */
|
|
11
|
+
.maplibregl-ctrl-top-right,
|
|
12
|
+
.maplibregl-ctrl-top-left,
|
|
13
|
+
.maplibregl-ctrl-bottom-right,
|
|
14
|
+
.maplibregl-ctrl-bottom-left {
|
|
15
|
+
inset: initial;
|
|
16
|
+
position: initial;
|
|
17
|
+
}
|
|
18
|
+
`);
|
|
19
|
+
|
|
20
|
+
export class HTMLControl extends HTMLElement {
|
|
21
|
+
static observedAttributes = ["css", "html"];
|
|
22
|
+
|
|
23
|
+
get css() {
|
|
24
|
+
return this.getAttribute("css");
|
|
25
|
+
}
|
|
26
|
+
set css(value) {
|
|
27
|
+
return this.setAttribute("css", value);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
get html() {
|
|
31
|
+
return this.getAttribute("html");
|
|
32
|
+
}
|
|
33
|
+
set html(value) {
|
|
34
|
+
return this.setAttribute("html", value);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
constructor(options) {
|
|
38
|
+
super();
|
|
39
|
+
if (options) {
|
|
40
|
+
const { html, css } = options;
|
|
41
|
+
this.html = html;
|
|
42
|
+
this.css = css;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
onAdd(map) {
|
|
46
|
+
this._map = map;
|
|
47
|
+
this._container = h("html-control");
|
|
48
|
+
if (this.html) this._container.html = this.html;
|
|
49
|
+
if (this.css) this._container.css = this.css;
|
|
50
|
+
|
|
51
|
+
return this._container;
|
|
52
|
+
}
|
|
53
|
+
onRemove() {
|
|
54
|
+
this.container.parentNode.removeChild(this.container);
|
|
55
|
+
this.map = undefined;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
connectedCallback() {
|
|
59
|
+
const shadow = this.attachShadow({ mode: "open" });
|
|
60
|
+
|
|
61
|
+
// Add styles: Normalize, MapLibre, & User-specified
|
|
62
|
+
shadow.adoptedStyleSheets.push(normalizeCSS);
|
|
63
|
+
shadow.adoptedStyleSheets.push(maplibreCSS);
|
|
64
|
+
const style = new CSSStyleSheet();
|
|
65
|
+
style.replaceSync(this.css);
|
|
66
|
+
shadow.adoptedStyleSheets.push(style);
|
|
67
|
+
|
|
68
|
+
// Wrap in a div with the same className as parent so that control position CSS works
|
|
69
|
+
const container = h("div", { className: this.parentElement.className });
|
|
70
|
+
container.innerHTML = DOMPurify.sanitize(this.html);
|
|
71
|
+
|
|
72
|
+
shadow.appendChild(container);
|
|
73
|
+
}
|
|
74
|
+
}
|
package/components/ultra-map.js
CHANGED
|
@@ -14,6 +14,7 @@ import { getStyle } from "../lib/style.js";
|
|
|
14
14
|
import { handleStyleImageMissing } from "../lib/sprites.js";
|
|
15
15
|
import { handleMouseClick, handleMouseMove } from "../lib/queryMap.js";
|
|
16
16
|
import { localStorage, optionsFromStorage } from "../lib/localStorage.js";
|
|
17
|
+
import { HTMLControl } from "./html-control.js";
|
|
17
18
|
|
|
18
19
|
const css = new CSSStyleSheet();
|
|
19
20
|
css.replaceSync(`
|
|
@@ -65,7 +66,7 @@ export class UltraMap extends HTMLElement {
|
|
|
65
66
|
querySources = UltraMap.defaults.querySources;
|
|
66
67
|
|
|
67
68
|
options = UltraMap.defaults.options;
|
|
68
|
-
controls = UltraMap.defaults.controls;
|
|
69
|
+
#controls = UltraMap.defaults.controls;
|
|
69
70
|
|
|
70
71
|
fitBounds = UltraMap.defaults.fitBounds;
|
|
71
72
|
|
|
@@ -119,6 +120,18 @@ export class UltraMap extends HTMLElement {
|
|
|
119
120
|
get center() {
|
|
120
121
|
return this.refs?.mapLibre?.center;
|
|
121
122
|
}
|
|
123
|
+
get controls() {
|
|
124
|
+
return this.#controls;
|
|
125
|
+
}
|
|
126
|
+
set controls(value) {
|
|
127
|
+
this.#controls = value.map
|
|
128
|
+
? value.map(({ type, options, position }) =>
|
|
129
|
+
type === "HTMLControl"
|
|
130
|
+
? { type: new HTMLControl(options), position }
|
|
131
|
+
: { type, options, position },
|
|
132
|
+
)
|
|
133
|
+
: value;
|
|
134
|
+
}
|
|
122
135
|
|
|
123
136
|
connectedCallback() {
|
|
124
137
|
this.#shadow = this.attachShadow({ mode: "open" });
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/docs/index.md
CHANGED
|
@@ -43,8 +43,8 @@ style:
|
|
|
43
43
|
}
|
|
44
44
|
```
|
|
45
45
|
|
|
46
|
-
For more examples, see the [Examples](./Examples) and [MapLibre
|
|
47
|
-
sections.
|
|
46
|
+
For more examples, see the [Examples](./Examples/index.md) and [MapLibre
|
|
47
|
+
Examples](./MapLibre-Examples/index.md) sections.
|
|
48
48
|
|
|
49
49
|
## Configuration
|
|
50
50
|
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# Mapping Resources
|
|
2
|
+
|
|
3
|
+
## Query Data
|
|
4
|
+
|
|
5
|
+
There are many sources of query data for use with Ultra.
|
|
6
|
+
|
|
7
|
+
### OpenStreetMap
|
|
8
|
+
|
|
9
|
+
Ultra was initially made to visualize OSM data via [Overpass](#overpass) queries. OSM continues to
|
|
10
|
+
be an excellent source of data for Ultra, and can be consumed in more ways than one.
|
|
11
|
+
|
|
12
|
+
#### Overpass
|
|
13
|
+
|
|
14
|
+
[OverpassQL](https://wiki.openstreetmap.org/wiki/Overpass_API/Overpass_QL) or [Overpass
|
|
15
|
+
XML](https://wiki.openstreetmap.org/wiki/Overpass_API/Language_Guide) queries are supported by the
|
|
16
|
+
[`overpass` query provider](./yaml.md#overpass).
|
|
17
|
+
|
|
18
|
+
#### Ohsome
|
|
19
|
+
|
|
20
|
+
The [ohsome API](https://api.ohsome.org) can be used via the [`ohsome` query
|
|
21
|
+
provider](./yaml.md#ohsome) to loader quanties of OSM data with a simpler [filtering
|
|
22
|
+
syntax](https://docs.ohsome.org/ohsome-api/v1/filter.html) than Overpass.
|
|
23
|
+
|
|
24
|
+
#### Bunting Labs
|
|
25
|
+
Using [separate N/S/E/W bbox
|
|
26
|
+
placeholders](./query-shortcuts.md#other-formats), the [`geojson`
|
|
27
|
+
provider](./yaml.md#geojson) can load data from the [Bunting Labs
|
|
28
|
+
API](https://buntinglabs.com/solutions/openstreetmap-extracts)
|
|
29
|
+
|
|
30
|
+
#### OSM API
|
|
31
|
+
The [`osmxml`](./yaml.md#osmxml) and [`osmjson`](./yaml.md#osmjson) providers can load data
|
|
32
|
+
directly from the [OSM API](https://wiki.openstreetmap.org/wiki/API_v0.6).
|
|
33
|
+
|
|
34
|
+
#### Tiles
|
|
35
|
+
There are a variety of providers of tiled OSM data.
|
|
36
|
+
|
|
37
|
+
##### OpenStreetMap US Tileserver
|
|
38
|
+
|
|
39
|
+
Née the [OSM Americana](https://americanamap.org/) Community Vector Tile Server, [OSM
|
|
40
|
+
US](https://openstreetmap.us) hosts [OpenMapTiles](https://openmaptiles.org) on
|
|
41
|
+
[tile.ourmap.us](https://tile.ourmap.us). For usage, see their
|
|
42
|
+
[policy](https://tile.ourmap.us/usage.html).
|
|
43
|
+
|
|
44
|
+
### Google My Maps
|
|
45
|
+
|
|
46
|
+
The [`kml` provider](./yaml.md#kml) can directly load Google My Maps URLs.
|
|
47
|
+
|
|
48
|
+
### Natural Earth
|
|
49
|
+
|
|
50
|
+
[Natural Earth Data](https://www.naturalearthdata.com/) data is available as GeoJSON from the
|
|
51
|
+
[geojson.xyz CDN](https://geojson.xyz)
|
|
52
|
+
|
|
53
|
+
### Wilderness.net
|
|
54
|
+
|
|
55
|
+
[Wilderness.net](https://wilderness.net) provides GIS data for Wildernes Areas in the USA. The data
|
|
56
|
+
files need to be downloaded, converted to tiles or GeoJSON, and hosted before using them with Ultra
|
|
57
|
+
|
|
58
|
+
* [Downloads Page](https://wilderness.net/visit-wilderness/gis-gps.php)
|
|
59
|
+
* [Shapefile](https://www.wilderness.net/GIS/Wilderness_Areas.zip)
|
|
60
|
+
* [state KMZs](https://wilderness.net/visit-wilderness/google-earth.php)
|
|
61
|
+
|
|
62
|
+
### All The Places
|
|
63
|
+
|
|
64
|
+
[All The Places](https://alltheplaces.xyz) provides GeoJSON files for a many retail establishments,
|
|
65
|
+
scraped from their websites.
|
|
66
|
+
|
|
67
|
+
ATP doesn't serve the files with [CORS
|
|
68
|
+
headers](https://developer.mozilla.org/en-US/docs/Glossary/CORS), so you must re-host them with the
|
|
69
|
+
appropriate headers yourself.
|
|
70
|
+
|
|
71
|
+
### Overture Maps
|
|
72
|
+
|
|
73
|
+
The [Overture foundation](https://overturemaps.org/) makes map data derived from various sources
|
|
74
|
+
available. It needs to be processed and hosted before use with Ultra.
|
|
75
|
+
|
|
76
|
+
## Base Style resources
|
|
77
|
+
|
|
78
|
+
### TrailStash Style Server
|
|
79
|
+
|
|
80
|
+
Most of the styles made available in the **Style Picker** menu on
|
|
81
|
+
[overpass-ultra.us](https://overpass-ultra.us) are hosted on
|
|
82
|
+
[styles.trailsta.sh](https://styles.trailsta.sh).
|
|
83
|
+
|
|
84
|
+
#### OpenMapTiles Styles
|
|
85
|
+
|
|
86
|
+
Most of the [OpenMapTiles Styles](https://openmaptiles.org/styles/) are available, with fonts and
|
|
87
|
+
sprites hosted along-side the style, and tiles hosted by the [OSM US Tile
|
|
88
|
+
Server](#openstreetmap-us-tileserver).
|
|
89
|
+
|
|
90
|
+
#### Protomaps
|
|
91
|
+
|
|
92
|
+
The light, dark, white, grey, black variants and the community "contrast" varaint of the Protomaps
|
|
93
|
+
styles are available, with fonts and sprites hosted by the [protomaps basemaps assets
|
|
94
|
+
repo](https://github.com/protomaps/basemaps-assets) and tiles hosted by the [Protomaps
|
|
95
|
+
API](https://protomaps.com)
|
|
96
|
+
|
|
97
|
+
#### Esri Satellite
|
|
98
|
+
|
|
99
|
+
A style using [Esri World
|
|
100
|
+
Imagery](https://www.arcgis.com/home/item.html?id=10df2279f9684e4a9f6a7f08febac2a9) is available.
|
|
101
|
+
|
|
102
|
+
### Natural Earth
|
|
103
|
+
|
|
104
|
+
The [TrailStash fork](https://trailstash.github.io/naturalearthtiles/) of [Lukas Martinelli's
|
|
105
|
+
Natural Earth Tiles](https://github.com/lukasmartinelli/naturalearthtiles) includes a MapLibre
|
|
106
|
+
vector style.
|
|
107
|
+
|
|
108
|
+
### Versatiles
|
|
109
|
+
|
|
110
|
+
[Versatiles](https://versatiles.org/intro.html) provides a few styles based on the [Shortbread
|
|
111
|
+
Schema](https://shortbread-tiles.org/), free for use anywhere.
|
|
112
|
+
|
|
113
|
+
### OpenFreeMap
|
|
114
|
+
|
|
115
|
+
[OpenFreeMap](https://openfreemap.org/quick_start/) provides a few styles based on the [OpenMapTile
|
|
116
|
+
schema](https://openmaptiles.org/schema/) free for use
|
|
117
|
+
anywhere.
|
|
118
|
+
|
|
119
|
+
### Commercial Providers
|
|
120
|
+
|
|
121
|
+
Any MapLibre style provider can be used with Ultra. See [Awesome
|
|
122
|
+
MapLibre](https://github.com/maplibre/awesome-maplibre?tab=readme-ov-file#maptile-providers) for a
|
|
123
|
+
more comprehensive list of MapLibre style providers.
|
package/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import DOMPurify from "dompurify";
|
|
1
2
|
import { Protocol } from "pmtiles";
|
|
2
3
|
import MapLibre from "@trailstash/maplibre-component";
|
|
3
4
|
import maplibregl from "maplibre-gl";
|
|
@@ -5,6 +6,7 @@ import maplibregl from "maplibre-gl";
|
|
|
5
6
|
import { normalizeCSS } from "./lib/normalize.js";
|
|
6
7
|
import FallbackGlyphProtocol from "./lib/glyphFallback.js";
|
|
7
8
|
|
|
9
|
+
import { HTMLControl } from "./components/html-control.js";
|
|
8
10
|
import { UltraLoader } from "./components/ultra-loader.js";
|
|
9
11
|
import { UltraMap } from "./components/ultra-map.js";
|
|
10
12
|
import { UltraIDE } from "./components/ultra-ide.js";
|
|
@@ -20,6 +22,15 @@ import { FontAwesomeIcon } from "./components/fontawesome-icon.js";
|
|
|
20
22
|
import { ButtonModal } from "./components/button-modal.js";
|
|
21
23
|
import { MapPopup } from "./components/map-popup.js";
|
|
22
24
|
|
|
25
|
+
// Allow pages in new windows securely
|
|
26
|
+
DOMPurify.addHook("afterSanitizeAttributes", function (node) {
|
|
27
|
+
// set all elements owning target to target=_blank
|
|
28
|
+
if ("target" in node) {
|
|
29
|
+
node.setAttribute("target", "_blank");
|
|
30
|
+
node.setAttribute("rel", "noopener");
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
|
|
23
34
|
// style
|
|
24
35
|
document.adoptedStyleSheets.push(normalizeCSS);
|
|
25
36
|
|
|
@@ -48,6 +59,7 @@ customElements.define("map-popup", MapPopup);
|
|
|
48
59
|
customElements.define("ultra-map", UltraMap);
|
|
49
60
|
customElements.define("ultra-ide", UltraIDE);
|
|
50
61
|
customElements.define("ultra-loader", UltraLoader);
|
|
62
|
+
customElements.define("html-control", HTMLControl);
|
|
51
63
|
|
|
52
64
|
// reload on hash changes
|
|
53
65
|
addEventListener("hashchange", () => window.location.reload());
|
package/package.json
CHANGED