Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add PMTiles support #938

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open

Add PMTiles support #938

wants to merge 6 commits into from

Conversation

pka
Copy link

@pka pka commented Sep 19, 2024

Add support for pmtiles sources. Solves #807

There is still an error, probably when adding the source to the Maputnik sources:
Failed to process sources for 'pmtiles://https://example.com/data/switzerland.pmtiles' TypeError: NetworkError when attempting to fetch resource.
    fetchSources App.tsx:642

@bdon How did you solve this for https://editor.protomaps.com/ ?

@HarelM
Copy link
Collaborator

HarelM commented Sep 19, 2024

Thanks for taking the time to open this PR.
Please see my comments in the linked issue.
This part of the solution is a simple one, I would be more interested in actually looking at the problem from a UX perspective and trying to solve that and not just add the pmtiles plugin...

@pka
Copy link
Author

pka commented Sep 19, 2024

I saw your comment there, but comparing PMTiles with MBTiles didn't make sense for me. PMTiles can be used as local and remote datasource like mvt files when using an HTTP server with Range Request support.

@HarelM
Copy link
Collaborator

HarelM commented Sep 19, 2024

But you still need a http server with range support... From my point if view using a tile server or worker is not a big lift.
Moreover, since this is not supported for native it will create a style that might not work, which is not a great experience...

@pka
Copy link
Author

pka commented Sep 19, 2024

There are not many HTTP servers without Range Request support (python -m http.server comes to my mind) and serving a tileset from a very compact single file without an additional tile server makes hosting a lot easier.

Switching the tile source in a style created with Maputnik is a one-liner like jq '.sources.mysource.url="pmtiles:///mytiles.pmtiles" | del(.sources.mysource.tiles)' mystyle.json. The style itself is the same for any platform.

@HarelM
Copy link
Collaborator

HarelM commented Sep 19, 2024

I could argue that you won't need to run the above script at all and using Martin or tileserver-gl (using docker, or even without) is not that complicated...
Bottom line, I don't feel comfortable with this feature as it is now from a UX perspective (not a technical one).
But if someone else from the maintainers want to approve it, I won't object.

@kevinschaul
Copy link
Collaborator

@pka It might be helpful if you could write your full use-case in #807. Where is the pmtiles file you want to reference? Is it on your local machine or hosted somewhere?

For background I also use maputnik + PMTiles but with a separate tool that runs both. If we can all share our use-cases, that could help reveal pain points and potential solutions.

@pka
Copy link
Author

pka commented Sep 20, 2024

@nyurik @lseelenbinder Could you maybe help formulating use cases for styling maps with PMTiles storage?

@bdon
Copy link

bdon commented Sep 22, 2024

@bdon How did you solve this for https://editor.protomaps.com/ ?

here is the necessary changes to add PMTiles for vector sources to the UI:

bdon/maputnik@8ac5e36

This works fine with remote sources e.g. you can paste in https://data.source.coop/protomaps/openstreetmap/tiles/v3.pmtiles and then reference the layer called water

However, the "inspect" panel doesn't work yet because it relies on MapLibre internals to fetch TileJSON. The inspect panel will work once protomaps/PMTiles#247 is implemented.

(EDIT: I implemented 247 above, so inspect works now.)

@pka pka force-pushed the pmtiles-support branch 3 times, most recently from a11dc3e to d3d4c99 Compare September 25, 2024 20:43
@pka pka marked this pull request as ready for review September 25, 2024 20:43
@bdon
Copy link

bdon commented Sep 26, 2024

There is a UI issue right now where the pmtiles:// prefix sometimes appears in the modal data sources editor, sometime does not. Ideally the pmtiles:// prefix is totally hidden from the editor, letting you naturally input a HTTP or HTTPS URL of a .pmtiles archive, and the internal Style JSON state has the full pmtiles://https://... string. This requires some changes to the existing patches, PR welcome.

@WebFreak001
Copy link

WebFreak001 commented Dec 26, 2024

hello what's needed to get this forward? I would really like to use this since my vector tiles are stored in the pmtiles format, which is simpler for me to deploy than mbtiles as well as even being smaller in size.

Hosting a special-made server that can extract and serve the tiles (either trying to obtain replacement mbtiles or using pmtiles serve) seems like a lot of overhead / unnecessary work since in the end with my usage with MapLibre GL JS just uses the simpler pmtiles format anyway.

Right now my setup with pmtiles looks like this:

in a folder with e.g. planet.pmtiles run:

pmtiles serve --public-url='https://maps.localhost:8123' .

to have a compatibility for the tiles JSON, as well as

sudo caddy reverse-proxy --from maps.localhost:8123 --to :8080 --header-down "access-control-allow-origin: *"

to get a local reverse proxy that adds HTTPS with a self-signed and trusted certificate. Then I can use https://maps.localhost:8123/planet.json in maputnik.

If this PR was merged, I wouldn't need pmtiles anymore and could just host a static fileserver (which I'm doing already for my other web developing needs) with CORS enabled and use the URL for it instead.

And in the future this might even allow me to just select a pmtiles file from disk and without needing to upload it anywhere or host any server, it would just read from it in-memory. (e.g. using a HTML file picker and then using Blob.slice instead of range requests)

@nyurik
Copy link
Member

nyurik commented Dec 26, 2024

I agree this should be added to maputnik. At minimum, we need to rebase this PR to be able to merge it. i don't see any substantial blockers to be honest, as it is indeed a highly useful mode of operation, and we shouldn't require users to host their own tiles anywhere if they have a pmtiles on some s3 or another range-supporting hosting

WebFreak001 added a commit to WebFreak001/maputnik that referenced this pull request Dec 26, 2024
Still contains old bugs

Co-authored-by: Brandon Liu <[email protected]>
Co-authored-by: Pirmin Kalberer <[email protected]>
bdon and others added 3 commits December 28, 2024 20:19
* add PMTiles mode to source editing dialog
* App.tsx detects PMTiles sources for fetching vector_layers (inspect does not yet work)
@pka
Copy link
Author

pka commented Dec 28, 2024

@WebFreak001 thanks for fixing the bug in the modal data sources editor. I've added your commits also to this PR, to keep the full history.

@HarelM
Copy link
Collaborator

HarelM commented Dec 28, 2024

As mentioned in the other PR, It would be better to have a test to cover this scenario/use case/flow.

@pka
Copy link
Author

pka commented Dec 28, 2024

We could test e.g.

diff --git a/cypress/e2e/modals.cy.ts b/cypress/e2e/modals.cy.ts
index aade75f..5eeb0c6 100644
--- a/cypress/e2e/modals.cy.ts
+++ b/cypress/e2e/modals.cy.ts
@@ -83,6 +83,20 @@ describe("modals", () => {
       });
     });
 
+    it("add new pmtiles source", () => {
+      let sourceId = "pmtilestest";
+      when.setValue("modal:sources.add.source_id", sourceId);
+      when.select("modal:sources.add.source_type", "pmtiles_vector");
+      when.setValue("modal:sources.add.source_url", "https://pmtiles.io/stamen_toner(raster)CC-BY+ODbL_z3.pmtiles");
+      when.click("modal:sources.add.add_source");
+      when.wait(200);
+      then(
+        get.styleFromLocalStorage().then((style) => style.sources[sourceId])
+      ).shouldInclude({
+        url: "pmtiles://https://pmtiles.io/stamen_toner(raster)CC-BY+ODbL_z3.pmtiles",
+      });
+    });
+
     it("add new raster source", () => {
       let sourceId = "rastertest";
       when.setValue("modal:sources.add.source_id", sourceId);

Is there a way to address the source_url input field?

get.styleFromLocalStorage().then((style) => style.sources[sourceId])
).shouldInclude({
type: "vector",
// url: "pmtiles://https://data.source.coop/protomaps/openstreetmap/v4.pmtiles",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like some assertion is missing here to properly test this...

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apparently the onChange trigger code is not executed in Cypress, so url can't be tested for a new value. Someone more knowledgeable about Cypress maybe knows a workaround?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CC: @ShellyDCMS, any chance you can take a look at this?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@HarelM , checking

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants