mapbox / mapbox/mapbox-gl-js

Allow custom global properties to be used in expressions

Open
#7,946 23 comments 22 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

cross-platform :tv: feature :green_apple:
Dominant language
TypeScript
Stars
12.4k
Forks
2.4k
PR merge metrics
No merged PRs in 30d

Description

## Motivation

Sometimes there is some global "map state" that I would like to use in expressions.

For example, the map I'm currently building has multiple floors and the user can select the floor to display. Most features have a `showOnFloors` array property, which specifies on which floors to show the feature.

Ideally, I would just be able to tell the map what the current floor is and I could use that floor as a variable in all filter expressions.

## Design Alternatives

My current approach is to create a layer per floor with a hardcoded filter and manually implement the logic which layer to insert and which to remove based on the current floor. Alternatively, I could dynamically update the filter expression for these layers.

However, I have multiple layers per floor and also some layers that are independent of the current floor,. This makes that this logic is not trivial and I'm essentially duplicating part of the expression functionality.

## Design

I would propose adding a global properties object on the map. This object could be accessed by the expression `["global"]`, similar to how `["properties"]` behaves now. Optionally, we could add helpers like `["global-get", name]`, although I don't think that's really necessary.

There are already global parameters (`zoom`, most prominently), so I would imagine there is nothing preventing the use of globals in expressions.

The only real additional functionality is that expressions need to be re-evaluated when the global properties are updated. I would tie this to the function call on map (`setGlobalProperties`, or however it's called), so I would not watch the properties themselves, i.e.:

```javascript
const globalProperties = { foo: { a: 1, b: 2}, bar: { c: 3 } };

// this triggers re-evaluating the expressions:
map.setGlobalProperties(globalProperties);

// this does not trigger:
globalProperties.foo.b = 4;
```

It might happen that the global property does not exist. I'm not familiar enough with all workflows users might have but I could imagine a map designer defines the layer with a filter referencing the global property but the map developer forgets to add that data to the map.

Some alternative ways to deal with that:
- just return `undefined`
- return `undefined` and allow providing a default value
- raise an error and stop evaluating the expression

My preference would be defensive and go for the default value but I'm not entirely sure if that is in line with the rest of the API.

### Mock-Up

As already sketched above:

- an additional method on `map`: `map.setGlobalProperties(object)`
- an additional expression name: `["global"]`
- optionally, additional helper expressions: `["global-get", name]`

### Concepts

I'm not entirely sure if "global properties" is the most descriptive name. I'm open to better alternatives. I think, however, that this is a pretty straightforward addition and the API documentation should be enough.

### Implementation

I am not really familiar with the mapbox source code but I had a quick look and thought this object could be part of the [evaluation context](https://github.com/mapbox/mapbox-gl-js/blob/master/src/style-spec/expression/evaluation_context.js). I'm not sure yet how re-evaluating the expressions on changing data would work.

With some guidance from the maintainers I would be happy to give this a try and see if I can make this work.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

The issue points to src/style-spec/expression/evaluation_context.js and proposes map.setGlobalProperties plus a global expression. Start by tracing how evaluation context and expression reevaluation currently work, then resolve the behavior for missing properties with maintainers. Done means the API behavior is defined and expressions reevaluate after the setter is called.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, typescript
Domain
api, frontend
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.