maplibre / maplibre-gl-js

MapLibre GL JS - Interactive vector tile maps in the browser
https://maplibre.org/maplibre-gl-js/docs/
Other
6.61k stars 712 forks source link

Map Source Refresh #3419

Open lawrencenika opened 11 months ago

lawrencenika commented 11 months ago

User Story

As a user I can delete a geometry in one of my layers of the map source via SQL command and force the maplibre GL JS map to refresh source, so that I can immediately see the deleted geometry object disappeared from my map.

Rationale

Impact

Better UX for all users who need smooth experience with map apps built on Maplibre

lawrencenika commented 11 months ago

my current code for the map is

import Map, { Source, Layer, FillLayer, MapLayerMouseEvent, SymbolLayer } from 'react-map-gl/maplibre';

  const handleDelete = async () => {
      const response = await fetch('/api/deleteGeometry', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify(hoveringVectorId),
      });

      if (!response.ok) {
        console.error(`Error encountered during geometry deletion: ${response.toString()}`);
      }
  }

  ...
       <div id="hoverButtons" className="hidden absolute z-10" style={{ display: 'none' }}>
        <button className="p-2" onClick={() => handleDelete()}>
          <FaTrashAlt />
        </button>
      </div>
      <Map
        initialViewState={{
          longitude: 18.7322,
          latitude: 15.4542,
          zoom: 2
        }}
        mapStyle={basemapOptions[store.map.baseMap]}
        onLoad={ handleMapLoad }
        onClick={ handleClick }
        onMouseMove={ handleHover }
        onMouseLeave={ handleHoverExit }
        interactiveLayerIds={ [pointLayer.id, fillLayer.id] }
      >
          <Source id={"my_function_name"} type="vector" tiles={[`${process.env.NEXT_PUBLIC_MARTIN_URL}/my_function_name/{z}/{x}/{y}?filter_param=abc`]} promoteId={"id"}>
            <Layer { ...fillLayer } />
            <Layer { ...pointLayer } />
          </Source>
      </Map>

so that s the context for why I need to refresh my source immediately to reflect changes in my DB after a DB operation and get martin + maplibre to reflect those changes asap.

HarelM commented 11 months ago

Can you please post maplibre code? So that we eliminate some wrappers noise?

Also, I think the main problem is cache control for the tiles - even if you refresh the map, the browser might not fetch it.

You can set a low cache control value for the tiles I guess in the server...?

Not sure there's an easy solution to this issue...

lawrencenika commented 11 months ago

Can you please post maplibre code? So that we eliminate some wrappers noise?

Also, I think the main problem is cache control for the tiles - even if you refresh the map, the browser might not fetch it.

You can set a low cache control value for the tiles I guess in the server...?

Not sure there's an easy solution to this issue...

I updated the code above, how to decrease cache control value?

HarelM commented 11 months ago

The code above is still using some wrapper. cache control is a server-side header, depend on the backend.

lawrencenika commented 11 months ago

The code above is still using some wrapper. cache control is a server-side header, depend on the backend.

My backend is martin, I simply used martin server to run the following config.yaml

listen_addresses: '0.0.0.0:4001'
postgres:
  connection_string: ${NEXT_PUBLIC_DATABASE_URL}
  auto_publish: true
  functions:
    my_function_name:
      schema: public
      function: my_function_name
      minzoom: 0
      maxzoom: 30
      bounds: [-180.0, -90.0, 180.0, 90.0]
  tables: {} 
HarelM commented 11 months ago

I'm not familiar with the internals and configuration of martin, unfortunately.

lawrencenika commented 11 months ago

I see, is it right to say then this feature should not be requested on maplibre, but whichever backend I chose?

HarelM commented 11 months ago

I'm not 100% sure, there are a lot of moving parts here with the browser, data update, tiles, cache etc. Instant refresh can be mainly done in the client side, when there is a backend involved things get more complicated. I'll be surprised if martin can't define cache control headers, and if not, you can probably use nginx or similar proxy to solve this.

lawrencenika commented 11 months ago

thank you for explaining these to me. are there ways to submit a PR for maplibre to handle this while working with martin?

HarelM commented 11 months ago

Sure, everything is possible, but I think better understanding of all the moving parts is needed here...

lawrencenika commented 11 months ago

yeah agree, problem is I m using stuffs out of the box. those are the stack I m trying to use for DB Transaction based web app

nyurik commented 5 months ago

@lawrencenika I think Martin should allow cache header config - I think we might have even had some similar issues for that - and that's definitely needed. In the mean time - nginx proxy is your best bet -- using add_header would allow you to modify Martin's response, as well as do some server-side caching too.

Fabioni commented 5 months ago

I am also interested in how actual realtime push updates can be made from sth like Martin to maplibre