Skip to content

Commit 8f05318

Browse files
authored
docs: use raw URLs in the embedding data/style examples (#1803)
* docs: use raw URLs in the embedding data/style examples The `data` and `style` deep-link examples were written with every nested URL percent-encoded, which made them hard to read and copy even though `:` and `/` need no escaping in a query value. Encoding is now shown only where it is actually required, on the REST endpoint that carries its own query string. Also moves "Open remote data" below "Embedding in a page" so the page introduces the iframe before the data parameters it takes. * docs: add a copy-paste "Open in GeoLibre" badge Publishing a dataset is a common way GeoLibre gets shared, but the docs gave no ready-made badge for a README or catalog entry. Adds Markdown, reStructuredText, and HTML snippets for both the data and project deep links, matching the shields.io style already used elsewhere in the docs. * Address review feedback - Drop `=` from the list of characters that force encoding in a nested data/style URL. `URLSearchParams` splits each `&`-delimited pair on its first `=` only, so a nested `=` survives verbatim; listing it undercut the point that raw URLs need less encoding than commonly assumed. - Cover that behavior in tests/data-url.test.ts so the documented claim is pinned rather than asserted only in prose. * Address review feedback - Correct the badge caveat. It claimed an unencoded `&` ends a Markdown link at that character; checked against a CommonMark renderer, the link destination survives `&` intact. The real reason to encode is unchanged and already stated: GeoLibre reads the `&` as its own separator.
1 parent f983f08 commit 8f05318

4 files changed

Lines changed: 133 additions & 72 deletions

File tree

docs/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ https://web.geolibre.app/?url=https://share.geolibre.app/giswqs/3d-tiles.geolibr
144144
You can also open hosted data directly. `data` accepts GeoJSON, GeoParquet, PMTiles, REST endpoints returning GeoJSON or ZIP, ZIP archives containing multiple GeoJSON files, and COGs. Add `style` to apply hosted vector or raster symbology:
145145

146146
```text
147-
https://web.geolibre.app/?data=https%3A%2F%2Fassets.geolibre.app%2Fdata%2Fplaces.geojson&style=https%3A%2F%2Fassets.geolibre.app%2Fdata%2Fsample.style.json
147+
https://web.geolibre.app/?data=https://assets.geolibre.app/data/places.geojson&style=https://assets.geolibre.app/data/sample.style.json
148148
```
149149

150150
Vector layers can produce a compatible file from **Layer actions → Styles → Export GeoLibre URL style**, and apply it again with **Import style (GeoLibre URL / Mapbox GL / SLD / QML)…**.

docs/user-guide/embedding.md

Lines changed: 115 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -2,76 +2,6 @@
22

33
GeoLibre's browser build can be embedded in any web page and configured through URL query parameters. This is how you turn a shared project into a live, focused map for a website, a report, or a dashboard.
44

5-
## Open remote data
6-
7-
Use `data` to open public GeoJSON, GeoParquet, PMTiles, Cloud-Optimized GeoTIFF (COG), or a ZIP archive containing one or more `.geojson`/`.json` FeatureCollections. Each GeoJSON file in a ZIP becomes a separate layer. An optional `style` URL applies Mapbox/MapLibre style JSON to vector data:
8-
9-
```text
10-
https://web.geolibre.app/?data=https%3A%2F%2Fassets.geolibre.app%2Fdata%2Fplaces.geojson&style=https%3A%2F%2Fassets.geolibre.app%2Fdata%2Fsample.style.json
11-
```
12-
13-
`data` may also point to a REST API endpoint that returns either a GeoJSON `FeatureCollection` or a ZIP containing multiple GeoJSON files. ZIP API responses are recognized from their `Content-Type`/`Content-Disposition` headers or their ZIP file signature, so the endpoint does not need a `.zip` suffix. For example:
14-
15-
```text
16-
https://web.geolibre.app/?data=https%3A%2F%2Fapi.example.com%2Ffeatures%3Fcategory%3Dparks%26limit%3D100
17-
```
18-
19-
The example API URL is illustrative. Use the hosted `places.geojson` example above for a directly runnable test.
20-
21-
A hosted ZIP with per-file styles can be tested directly:
22-
23-
```text
24-
https://web.geolibre.app/?data=https%3A%2F%2Fassets.geolibre.app%2Fdata%2Fmultiple-layers.zip&style=https%3A%2F%2Fassets.geolibre.app%2Fdata%2Fmultiple-layers.style.json
25-
```
26-
27-
GeoParquet is loaded through GeoLibre's DuckDB-backed vector reader. PMTiles is streamed with HTTP range requests and may contain either vector or raster tiles. These real vector examples also apply the hosted sample style:
28-
29-
```text
30-
https://web.geolibre.app/?data=https%3A%2F%2Fdata.source.coop%2Fgiswqs%2Fopengeos%2Fbuilding_count_h3.parquet&style=https%3A%2F%2Fassets.geolibre.app%2Fdata%2Fsample.style.json
31-
```
32-
33-
```text
34-
https://web.geolibre.app/?data=https%3A%2F%2Fdata.source.coop%2Fgiswqs%2Fopengeos%2Fbuilding_count_h3.pmtiles&style=https%3A%2F%2Fassets.geolibre.app%2Fdata%2Fsample.style.json
35-
```
36-
37-
For a vector PMTiles archive, the style is applied to the layer after the archive's source layers are discovered. A raster PMTiles archive can be loaded with `data`, but it does not accept a MapLibre vector style through `style`.
38-
39-
A public DEM COG can be tested directly:
40-
41-
```text
42-
https://web.geolibre.app/?data=https%3A%2F%2Fdata.source.coop%2Fgiswqs%2Fopengeos%2Fdem.tif
43-
```
44-
45-
Encode the nested data and style URLs with `encodeURIComponent`, especially when they contain their own query parameters. Remote servers must permit browser cross-origin requests (CORS). COG, GeoParquet, and PMTiles servers should also support HTTP byte-range requests.
46-
47-
For a COG, `style` may point to a raster style JSON object. Supported fields are `mode` (`single`, `rgb`, or `index`), 1-based `bands`, `rescale` ranges, `colormap`, `reversed`, `nodata`, `opacity`, `gamma`, `stretch` (`linear`, `log`, or `sqrt`), and the normalized-difference `index` preset. For example:
48-
49-
```json
50-
{
51-
"mode": "single",
52-
"bands": [1],
53-
"rescale": [[0, 1000]],
54-
"colormap": "viridis",
55-
"reversed": false,
56-
"nodata": "auto",
57-
"opacity": 0.85,
58-
"gamma": 1,
59-
"stretch": "linear"
60-
}
61-
```
62-
63-
After hosting that JSON as `dem.style.json`, pass both encoded URLs:
64-
65-
```text
66-
https://web.geolibre.app/?data=https%3A%2F%2Fdata.source.coop%2Fgiswqs%2Fopengeos%2Fdem.tif&style=https%3A%2F%2Fassets.geolibre.app%2Fdata%2Fdem.style.json
67-
```
68-
69-
For a ZIP containing files of the same geometry type, assign different styles by setting each Mapbox style layer's `source` to the corresponding filename stem. For example, `source: "parks"` targets `parks.geojson`, while `source: "counties"` targets `counties.geojson`. Style layers without a `source` are shared by every imported file. GeoLibre validates all filename/style matches before adding any ZIP layers.
70-
71-
You do not need to author that JSON by hand. Open the vector layer's **Layer actions → Styles → Export GeoLibre URL style** menu. The downloaded `.geolibre.style.json` contains only symbology—not feature data—and its render-layer `source` is already set to the original GeoJSON filename stem. Host the file on a CORS-enabled server and pass its URL as `style` alongside the corresponding `data` URL. For a multi-file ZIP, export each layer's GeoLibre URL style and combine their `layers` and `sources` into one style document; layers without `source` can be used for rules shared by every ZIP member.
72-
73-
The same file can be applied interactively to an existing vector layer through **Layer actions → Styles → Import style (GeoLibre URL / Mapbox GL / SLD / QML)…**. Interactive import ignores the file's query-param `source` binding and applies its supported symbology to the layer you selected, so the data filename does not need to match.
74-
755
## The live viewer
766

777
The browser build is hosted at `https://web.geolibre.app/`. It is a static site deployed on GitHub Pages that runs entirely in your browser: it has no analytics and no server account, and the data you load is processed client-side. Data leaves your browser only when you add a remote URL or explicitly share a project.
@@ -164,6 +94,121 @@ project file. Display plugins (layer control, basemaps, time slider, legend and
16494
colorbar components) keep working, so the project still looks as it was saved. Use `layout=compact` for the complete authoring
16595
toolbar in a smaller space, or `maponly` for a pure map.
16696

97+
## Open remote data
98+
99+
Use `data` to open public GeoJSON, GeoParquet, PMTiles, Cloud-Optimized GeoTIFF (COG), or a ZIP archive containing one or more `.geojson`/`.json` FeatureCollections. Each GeoJSON file in a ZIP becomes a separate layer. An optional `style` URL applies Mapbox/MapLibre style JSON to vector data:
100+
101+
```text
102+
https://web.geolibre.app/?data=https://assets.geolibre.app/data/places.geojson&style=https://assets.geolibre.app/data/sample.style.json
103+
```
104+
105+
`data` may also point to a REST API endpoint that returns either a GeoJSON `FeatureCollection` or a ZIP containing multiple GeoJSON files. ZIP API responses are recognized from their `Content-Type`/`Content-Disposition` headers or their ZIP file signature, so the endpoint does not need a `.zip` suffix. An endpoint that takes its own query parameters is the case that does need percent-encoding, so its `&` separators are not read as GeoLibre's own:
106+
107+
```text
108+
https://web.geolibre.app/?data=https%3A%2F%2Fapi.example.com%2Ffeatures%3Fcategory%3Dparks%26limit%3D100
109+
```
110+
111+
The example API URL is illustrative. Use the hosted `places.geojson` example above for a directly runnable test.
112+
113+
A hosted ZIP with per-file styles can be tested directly:
114+
115+
```text
116+
https://web.geolibre.app/?data=https://assets.geolibre.app/data/multiple-layers.zip&style=https://assets.geolibre.app/data/multiple-layers.style.json
117+
```
118+
119+
GeoParquet is loaded through GeoLibre's DuckDB-backed vector reader. PMTiles is streamed with HTTP range requests and may contain either vector or raster tiles. These real vector examples also apply the hosted sample style:
120+
121+
```text
122+
https://web.geolibre.app/?data=https://data.source.coop/giswqs/opengeos/building_count_h3.parquet&style=https://assets.geolibre.app/data/sample.style.json
123+
```
124+
125+
```text
126+
https://web.geolibre.app/?data=https://data.source.coop/giswqs/opengeos/building_count_h3.pmtiles&style=https://assets.geolibre.app/data/sample.style.json
127+
```
128+
129+
For a vector PMTiles archive, the style is applied to the layer after the archive's source layers are discovered. A raster PMTiles archive can be loaded with `data`, but it does not accept a MapLibre vector style through `style`.
130+
131+
A public DEM COG can be tested directly:
132+
133+
```text
134+
https://web.geolibre.app/?data=https://data.source.coop/giswqs/opengeos/dem.tif
135+
```
136+
137+
A plain `https://…` URL can be passed as-is, as above: `:` and `/` are legal in a query value and need no escaping. Encode the nested data and style URLs with `encodeURIComponent` only when they contain a character that would be read as GeoLibre's own query syntax — `&`, `+`, `%`, or `#`. A bare `=` inside the value is fine, since only the first `=` in each `&`-delimited pair separates the name from the value. Remote servers must permit browser cross-origin requests (CORS). COG, GeoParquet, and PMTiles servers should also support HTTP byte-range requests.
138+
139+
For a COG, `style` may point to a raster style JSON object. Supported fields are `mode` (`single`, `rgb`, or `index`), 1-based `bands`, `rescale` ranges, `colormap`, `reversed`, `nodata`, `opacity`, `gamma`, `stretch` (`linear`, `log`, or `sqrt`), and the normalized-difference `index` preset. For example:
140+
141+
```json
142+
{
143+
"mode": "single",
144+
"bands": [1],
145+
"rescale": [[0, 1000]],
146+
"colormap": "viridis",
147+
"reversed": false,
148+
"nodata": "auto",
149+
"opacity": 0.85,
150+
"gamma": 1,
151+
"stretch": "linear"
152+
}
153+
```
154+
155+
After hosting that JSON as `dem.style.json`, pass both URLs:
156+
157+
```text
158+
https://web.geolibre.app/?data=https://data.source.coop/giswqs/opengeos/dem.tif&style=https://assets.geolibre.app/data/dem.style.json
159+
```
160+
161+
For a ZIP containing files of the same geometry type, assign different styles by setting each Mapbox style layer's `source` to the corresponding filename stem. For example, `source: "parks"` targets `parks.geojson`, while `source: "counties"` targets `counties.geojson`. Style layers without a `source` are shared by every imported file. GeoLibre validates all filename/style matches before adding any ZIP layers.
162+
163+
You do not need to author that JSON by hand. Open the vector layer's **Layer actions → Styles → Export GeoLibre URL style** menu. The downloaded `.geolibre.style.json` contains only symbology—not feature data—and its render-layer `source` is already set to the original GeoJSON filename stem. Host the file on a CORS-enabled server and pass its URL as `style` alongside the corresponding `data` URL. For a multi-file ZIP, export each layer's GeoLibre URL style and combine their `layers` and `sources` into one style document; layers without `source` can be used for rules shared by every ZIP member.
164+
165+
The same file can be applied interactively to an existing vector layer through **Layer actions → Styles → Import style (GeoLibre URL / Mapbox GL / SLD / QML)…**. Interactive import ignores the file's query-param `source` binding and applies its supported symbology to the layer you selected, so the data filename does not need to match.
166+
167+
### An "Open in GeoLibre" badge
168+
169+
If you publish a dataset — in a repository README, a data catalog, a paper's
170+
supplementary material — an **Open in GeoLibre** badge turns it into a one-click
171+
interactive map. Copy one of these and swap in your own URL:
172+
173+
[![Open in GeoLibre](https://img.shields.io/badge/Open%20in-GeoLibre-green.svg)](https://web.geolibre.app/?data=https://assets.geolibre.app/data/places.geojson)
174+
175+
```markdown
176+
[![Open in GeoLibre](https://img.shields.io/badge/Open%20in-GeoLibre-green.svg)](https://web.geolibre.app/?data=https://assets.geolibre.app/data/places.geojson)
177+
```
178+
179+
The same badge can open a shared project instead of a single file, using `url`:
180+
181+
```markdown
182+
[![Open in GeoLibre](https://img.shields.io/badge/Open%20in-GeoLibre-green.svg)](https://web.geolibre.app/?url=https://share.geolibre.app/you/project.geolibre.json)
183+
```
184+
185+
In reStructuredText:
186+
187+
```rst
188+
.. image:: https://img.shields.io/badge/Open%20in-GeoLibre-green.svg
189+
:target: https://web.geolibre.app/?data=https://assets.geolibre.app/data/places.geojson
190+
:alt: Open in GeoLibre
191+
```
192+
193+
In HTML:
194+
195+
```html
196+
<a href="https://web.geolibre.app/?data=https://assets.geolibre.app/data/places.geojson">
197+
<img src="https://img.shields.io/badge/Open%20in-GeoLibre-green.svg" alt="Open in GeoLibre" />
198+
</a>
199+
```
200+
201+
Add any of the [URL parameters](#url-parameters) to the link to control how the
202+
map opens — `&style=` for symbology, `&theme=dark`, or `&maponly` for a
203+
chrome-free view.
204+
205+
One caveat specific to badges: a badge lives in a `README.md` that GitHub, PyPI,
206+
and docs sites all render, and each of those rewrites relative links
207+
differently, so keep the target URL **absolute**. The encoding rule above
208+
applies unchanged — a data URL carrying its own query string still needs
209+
`encodeURIComponent`, because the `&` is read as GeoLibre's own separator well
210+
before the browser ever sees it.
211+
167212
## Talking to the map at runtime
168213

169214
URL parameters configure the app once, at load. To keep talking to a **live**

docs/user-guide/layers.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ Vector layers have a **Layer actions → Styles** submenu for symbology intercha
3333
To use a GeoLibre URL style, upload it to a CORS-enabled web host and open GeoLibre with both URLs:
3434

3535
```text
36-
https://web.geolibre.app/?data=https%3A%2F%2Fassets.geolibre.app%2Fdata%2Fplaces.geojson&style=https%3A%2F%2Fassets.geolibre.app%2Fdata%2Fsample.style.json
36+
https://web.geolibre.app/?data=https://assets.geolibre.app/data/places.geojson&style=https://assets.geolibre.app/data/sample.style.json
3737
```
3838

3939
See [Embedding & Sharing](embedding.md#open-remote-data) for GeoParquet and PMTiles deep links, ZIP source matching, REST API responses, raster-style JSON, and encoding nested URLs.

tests/data-url.test.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,22 @@ describe("data URL deep links", () => {
113113
assert.equal(parsed?.styleUrl, style);
114114
});
115115

116+
it("parses raw, unencoded data and style URLs as documented", () => {
117+
// The spelling docs/user-guide/embedding.md leads with: `:` and `/` are legal
118+
// in a query value, so a plain https URL needs no encodeURIComponent.
119+
const parsed = dataUrlParameters(
120+
"?data=https://assets.geolibre.app/data/places.geojson" +
121+
"&style=https://assets.geolibre.app/data/sample.style.json",
122+
);
123+
assert.equal(parsed?.dataUrl, "https://assets.geolibre.app/data/places.geojson");
124+
assert.equal(parsed?.styleUrl, "https://assets.geolibre.app/data/sample.style.json");
125+
126+
// Only the first `=` of each `&`-delimited pair separates name from value,
127+
// so a nested `=` survives unencoded — the docs tell readers not to escape it.
128+
const nested = dataUrlParameters("?data=https://api.example.com/features?category=parks");
129+
assert.equal(nested?.dataUrl, "https://api.example.com/features?category=parks");
130+
});
131+
116132
it("rejects non-http data URLs", () => {
117133
assert.equal(dataUrlParameters("?data=file:///tmp/private.geojson"), null);
118134
});

0 commit comments

Comments
 (0)