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

Enable property functions for *-translate properties #2731

Open
lucaswoj opened this issue Jun 13, 2016 · 10 comments
Open

Enable property functions for *-translate properties #2731

lucaswoj opened this issue Jun 13, 2016 · 10 comments

Comments

@lucaswoj
Copy link
Contributor

lucaswoj commented Jun 13, 2016

Supporting *-translate properties isn't as straightforward as supporting other paint properties because translation is incorporated into the transform matrix.

Potential Designs

  • incorporate translation property function into position in vertex buffer, requires translate be treated like a layout property
  • add new "translate" shader uniform
  • don't support this feature

Properties

  • circle-translate
  • circle-translate-anchor
  • line-translate
  • line-translate-anchor
  • fill-translate
  • fill-translate-anchor
@lucaswoj
Copy link
Contributor Author

We should be able to implement this by adding a vec2 translate attribute to the paint buffer. Ideally we could implement this such that the attribute not needed for non-data-driven translate values.

@anandthakker
Copy link
Contributor

This applies to the symbol properties as well:

  • text-translate
  • text-translate-anchor
  • icon-translate
  • icon-translate-anchor

@anandthakker
Copy link
Contributor

incorporate translation property function into position in vertex buffer, requires translate be treated like a layout property

The only downsides that I can think of for doing it this way is the hackiness of including special-case checking for paint['...-translate'] properties in groupByLayout(). @lucaswoj do you think there's more to it than that?

add new "translate" shader uniform

Would this need to be an attribute, rather than a uniform, to allow for property functions?

@shayke
Copy link

shayke commented Nov 23, 2017

I'm looking into implementing this (specifically circle-translate) but I was wondering how to support per feature translation?
From the codebase my understanding is that the layoutVertexArray in CircleBucket is created only once and when draw_circle.js is called to actually draw all circles I'm not able to change (or inject a vec2 translate) into each circle per it's feature. Ideally my geojson should be something like:

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "properties": {
        "zoom5": [300,300],
        "zoom7": [200,200],
      },
      "geometry": {
        "type": "Point",
        "coordinates": [-97,39]
      }
    }
  ]
}

Any pointers maybe of where to look if I'd like to implement this per feature?

Thanks!

@ericjames
Copy link

ericjames commented Apr 2, 2018

This isn't working? UPDATE: Looks like it is not yet merged.
'circle-translate': ['get', 'markerOffset'] produces Error: layers.stopCircleLayer.paint.circle-translate: property expressions not supported

Geojson being:

var newOffset = someCondition ? [0, -20] : [0, -100];
    var feature = {
        'type': 'Feature',
        'geometry': {
            'type': 'Point',
            'coordinates': [stop.longitude, stop.latitude],
        },
        'properties': {
            'markerOffset': newOffset,
        },
    };

I was trying to use this as a means of doing cheap spiderfying/exploding/clustering by pre-identifying circles to be offset. In my case I am using a circle to create a dynamic colored icon since markers do not support dynamic coloring. But I can see where someone working with circle graph data would have overlaps.

@timothyde
Copy link

@ericjames I am pursuing a similar solution and I am kind of confused why property expressions work for *-offset properties e.g. on symbol type layers, but not for circle-translate.
Is there known workaround?

While this doesn't work

map.addLayer({ 'id': 'points', 'source': 'points', 'type': 'circle', 'paint': { 'circle-color': ['get', 'color'], 'circle-radius': 16, 'circle-translate': ['get', 'offset'], 'circle-stroke-width': 2, 'circle-stroke-color': ['get', 'outlineColor'] } },'place_town');

this works perfectly fine

map.addLayer({ 'id': 'points_icons', 'source': 'points', 'type': 'symbol', 'layout': { 'icon-image': ['get', 'iconName'], 'icon-size': 0.5, 'icon-offset': ['get', 'offset'], 'icon-allow-overlap': true, 'icon-ignore-placement': true } },'place_town');

Only thing I can think of right now is adding a separate layer for each feature in a loop like this:

points.features.forEach((feature) => { map.addLayer({ 'id': feature.properties.object_type, 'source': 'points', 'type': 'circle', 'paint': { 'circle-color': feature.properties.color, 'circle-radius': 16, 'circle-translate': feature.properties.offset, 'circle-stroke-width': 2, 'circle-stroke-color': feature.properties.outlineColor } },'place_town'); });

but that's messy to handle.
Or I could switch to symbol type layers, but since I am working with many different colors that would make my sprites messy as well.

If this is just a matter of merging, maybe this could be implemented fast?

@patrickkempff
Copy link

@jfirebaugh @lucaswoj @ericrwolfe any news on this?

We would love to be able to use these properties with the data-driven styling API. Makes the API a lot more complete. A less than ideal workaround we often need to use is to create separate layers with the corresponding settings, which impacts performance and makes the code less readable.

@ericjames
Copy link

I'm simply modifying the actual coordinates of the values of markers I want spiderfied.

@raegen-work
Copy link

raegen-work commented Oct 5, 2020

@asheemmamoowala does this mean that there is an alternative solution that doesn't rely upon duplication and main-thread js processing of all the features we need to offset?
For that matter, this is from 2016. Quite frankly, I find it kind of impossible that this is still not tackled? Especially since sources accept urls (read sources containing data that's not available locally) and that's kind of severely affected by this.

@dgaitsgo
Copy link

dgaitsgo commented Feb 22, 2024

I'm wondering if there have been other solutions since. I ran into this thread looking for ways to evenly distribute circles that share the same coordinate without manually adjusting the coordinates. This is what I've got so far but it's not ideal because it doesn't take into consideration zoom or the pixel size of circles:

function distributeFeatures(center, features) {
    const numFeatures = features.length;
    const radius = 0.005
    const angleIncrement = (2 * Math.PI) / numFeatures

    features.forEach((feature, index) => {
        const angle = index * angleIncrement;
        const newX = center[0] + radius * Math.cos(angle)
        const newY = center[1] + radius * Math.sin(angle)
        feature.geometry.coordinates = [newX, newY]
    })

    return features
}

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

No branches or pull requests

9 participants