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

Declutter of labels in vector tiles #1177

Closed
MarcelGeo opened this issue Jul 23, 2024 · 21 comments
Closed

Declutter of labels in vector tiles #1177

MarcelGeo opened this issue Jul 23, 2024 · 21 comments

Comments

@MarcelGeo
Copy link

MarcelGeo commented Jul 23, 2024

Hi ol-mapbox-style team. We are prototyping vector tiles rendering in openlayers. There's problem in ol-mapbox-style, where labels are overlapping (countries labels).

If I use declutter: true in VectorTileLayer, there are no labels anymore :(

image

If I disable declutter, labels are overlapping and It is strange...the same style.json in QGIS and everything is ok.

image

We are fetching style from url and then using stylefunction:

stylefunction(
        layer,
        data, // fetched from style.json
        data.layers?.filter((l) => Boolean(l.source))?.map((l) => l.id)
      )
@ahocevar
Copy link
Member

Hard to say without seeing more of your code, and the style.json.

@MarcelGeo
Copy link
Author

Hard to say without seeing more of your code, and the style.json.

Style: https://tiles.dev.merginmaps.com/styles/default.json

Definition of layer:

const layer = new VectorTileLayer({
        source: new VectorTileSource({
          format: new MVT(),
          url: `${tileUrl}/data/default/{z}/{x}/{y}.pbf`,
          tileGrid: tileGrid
        }),
        zIndex: 0,
        declutter: false,
        visible: true
      })

Is it enough?

@ahocevar
Copy link
Member

Unfortunately no. The resources referenced in the style do not point to a public url, and the context of the layer is not clear. Is that the only layer of the map?

@MarcelGeo
Copy link
Author

MarcelGeo commented Jul 24, 2024

Hi @ahocevar ...

      const tileUrl = "https://tiles.dev.merginmaps.com"
      const tileGrid = createXYZ({
        extent: getProjection('EPSG:3857').getExtent(),
        tileSize: 512,
        maxZoom: 14
      })
      const layer = new VectorTileLayer({
        source: new VectorTileSource({
          format: new MVT(),
          url: `${tileUrl}/data/default/{z}/{x}/{y}.pbf`,
          tileGrid: tileGrid
        }),
        zIndex: 0,
        declutter: false,
        visible: true
      })
      const mousePositionControl = new MousePosition({
        coordinateFormat: createStringXY(4),
        projection: 'EPSG:4326'
      })
      const map = new Map({
        layers: [layer],
        view: new View({
          center: [0, 0],
          zoom: 0,
          projection: this.proj,
          extent: [-20026376.39, -20048966.1, 20026376.39, 20048966.1],
          maxZoom: 25,
          constrainResolution: true
        }),
        controls: defaultControls().extend([mousePositionControl])
      })
      
      map.getView().fit([-20026376.39, -20048966.1, 20026376.39, 20048966.1], {
        maxZoom: 16,
        nearest: false
      })
      
      // Then apply style from defaul.json
      const baseUrl = "https://tiles.dev.merginmaps.com"
     const api = axios.create({ withCredentials: false })
      const response = await api.get(`${baseUrl}/styles/default.json`)
      const { data } = response
      await applyBackground(map, data)
      stylefunction(
        layer,
        data,
        data.layers?.filter((l) => Boolean(l.source))?.map((l) => l.id)
      )

Other layers are added after some business logic is done ... thats are ordinary WMTS layers in different grid

          const wmtsLayer = new TileLayer({
            visible: false,
            properties: {
              title: l.name,
              projectsLayer: true
            },
            zIndex: 1,
            source: new WMTS({
              url: `SOME URL`,
              layer: 'Some name',
              matrixSet: 'EPSG:3857',
              format: 'image/png',
              style: 'default',
              wrapX: true,
              tileGrid
            })
          })

I'm currently not able to resolve issue with resources in style.json ... Map is having one background map (vector tiles from defined source) and others are custom WMTS layers.

@ahocevar
Copy link
Member

There are still unaccessible resources referenced from the style, and the server does not send CORS headers.

I'm wondering why you chose to use the lowest level API, instead of applyStyle for the VectorTile layer. See https:/openlayers/ol-mapbox-style/blob/main/examples/apply-layergroup.js.

@MarcelGeo
Copy link
Author

As I mentioned before ... I am not able to update resources now. Tiles base url is the same as for styles.

I can try to use applyStyle / apply . Let me try it. But I think the backend for stylefunction and apply style should be the same? The same style would be applied in both functions.

@ahocevar
Copy link
Member

Yes, I'm just trying to reproduce your problem, and I'd be surprised if this is a bug in ol-mapbox-style, because we're doing the exact same thing over and over, and it works. Just take a look at the examples, e.g. https://openlayers.org/ol-mapbox-style/examples/tilejson-vectortile.html.

@MarcelGeo
Copy link
Author

MarcelGeo commented Jul 24, 2024

Definitely ... I don't see any overlapping labels there ...
image

Is there any dependency on this attribute in openlayers and decluttering: text-allow-overlap false

@ahocevar
Copy link
Member

Yes, it requires v9 of OpenLayers to work properly.

@MarcelGeo
Copy link
Author

Yes, it requires v9 of OpenLayers to work properly.

I am using newest OL versions

@MarcelGeo
Copy link
Author

Hi @ahocevar . I tried to use following higher level methods

  • apply ... there is problem with non-existent sources in style.json.
  • applyStyle ... there is creepy issue with instanceof testing on the top of function

!(layer instanceof VectorLayer || layer instanceof VectorTileLayer)

My example modified with applyStyle

import VectorTileLayer from 'ol/layer/VectorTile'

      const tileUrl = "https://tiles.dev.merginmaps.com"
      const tileGrid = createXYZ({
        extent: getProjection('EPSG:3857').getExtent(),
        tileSize: 512,
        maxZoom: 14
      })
      const layer = new VectorTileLayer({
        source: new VectorTileSource({
          format: new MVT(),
          url: `${tileUrl}/data/default/{z}/{x}/{y}.pbf`,
          tileGrid: tileGrid
        }),
        zIndex: 0,
        declutter: false,
        visible: true
      })
      const mousePositionControl = new MousePosition({
        coordinateFormat: createStringXY(4),
        projection: 'EPSG:4326'
      })
      const map = new Map({
        layers: [layer],
        view: new View({
          center: [0, 0],
          zoom: 0,
          projection: this.proj,
          extent: [-20026376.39, -20048966.1, 20026376.39, 20048966.1],
          maxZoom: 25,
          constrainResolution: true
        }),
        controls: defaultControls().extend([mousePositionControl])
      })
      
      map.getView().fit([-20026376.39, -20048966.1, 20026376.39, 20048966.1], {
        maxZoom: 16,
        nearest: false
      })
      
      // Then apply style from defaul.json
      const baseUrl = "https://tiles.dev.merginmaps.com"
      const api = axios.create({ withCredentials: false })
      const response = await api.get(`${baseUrl}/styles/default.json`)
      const { data } = response
      await applyBackground(map, data)
      applyStyle(
        layer,
        data,
      )

Exception:

Uncaught (in promise) Error: Can only apply to VectorLayer or VectorTileLayer

@ahocevar
Copy link
Member

ahocevar commented Jul 25, 2024

Either you're using an old version of ol-mapbox-style or OpenLayers, or you need to dedupe OpenLayers. What is the output of npm ls ol?

@MarcelGeo
Copy link
Author

MarcelGeo commented Jul 25, 2024

mhh

yarn list snippet

[email protected]
│  ├─ @mapbox/mapbox-gl-style-spec@^13.23.1
│  └─ mapbox-to-css-font@^2.4.1
├─ [email protected]
│  ├─ color-rgba@^3.0.0
│  ├─ color-space@^2.0.1
│  ├─ earcut@^2.2.3
│  ├─ geotiff@^2.0.7
│  ├─ [email protected]
│  └─ rbush@^3.0.1

@ahocevar
Copy link
Member

Sorry, if you cannot provide runnable code that others can debug, I'm afraid we won't be able to solve this here.

@MarcelGeo
Copy link
Author

Ok @ahocevar ... thank you for your help . It's very cool, that there is so fast response from ol-mapbox-style team 🔥 🔥

We have to fix issues in style.json and then try to use higher level apply function. applyStyle (with updateSource: false) is still not possible to use, because instanceof error in vite. I'm not sure why.

I'm not sure If it help us to use higher level functions to avoid labels overlaps. I'll be back If something will change.

@MarcelGeo
Copy link
Author

MarcelGeo commented Jul 29, 2024

@ahocevar ... example with openlayers and applyStyle function (overlapping labels). Let me know If it's running for you.

If I change declutter to true, then labels are not overlapping 👍 👍 ... It's interesting, that stylefunction does the same job... I have to revisit our current implementation

https://codesandbox.io/p/devbox/mapbox-vector-tiles-forked-zc2c5v?welcome=true

Update:
In our codebase was problem with imports, we imported Map and View directly

import { Map, View } from 'ol'

decluttering is running properly

import Map from 'ol/Map'

@ahocevar
Copy link
Member

Glad you were able to make it work, the way you import Map and View should not make a difference though.

Can we close this?

@MarcelGeo
Copy link
Author

MarcelGeo commented Jul 31, 2024

We migrated from old openlayers versions. Definitely It was issue with import there (I don't understand why). in vite are any issues with using ol-mapbox-style. It's not possible to use some functions because instanceof issues in lib. instanceof tests are not running properly in ol-mapbox-style :)

Of course I'm closing this :)

@ahocevar
Copy link
Member

ahocevar commented Jul 31, 2024

If instanceof checks don't work properly, ol might not be deduped properly in these setups. When you run npm ls ol, all occurrences of ol should be the same version. If that's the case, do you have an example for an instanceof Check that still fails?

@MarcelGeo
Copy link
Author

If instanceof checks don't work properly, ol might not be deduped properly in these setups. When you run npm ls ol, all occurrences of ol should be the same version. If that's the case, do you have an example for an instanceof Check that still fails?

There is result of npm ls ol #1177 (comment)

I think these issues are based on vite dependencies handling. I tried also

optimizeDeps: { exclude: ['ol', 'ol-mapbox-style']}

There are also issues in vite directly:

But, I'm not sure what's the problem. In codesandbox I'm not able to simulate this situation.

@ahocevar
Copy link
Member

Strange. I'm using vite in all my recent projects as well, and never had instanceof check problems with ol and ol-mapbox-style.

I also cannot reproduce your problem with a repository created with

npx create-ol-app my-test-app

which uses vite.

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

No branches or pull requests

2 participants