mapbox / mapbox/mapbox-gl-js

Evaluate an expression, outside of rendering

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

Nobody has claimed this yet.

api :memo: feature :green_apple:
Dominant language
TypeScript
Stars
12.4k
Forks
2.4k
PR merge metrics
No merged PRs in 30d

Description

## Motivation

MapboxGL expressions allow computing things based on feature properties. For example, at my work, we use an expression to determine which color various point features should be rendered as.

However, sometimes it is useful to be able to reuse logic between Mapbox code and other code. In this case, we would like a marker tooltip attached to a point to have the same color as the point.

## Design Alternatives

Currently, if a value is needed both during rendering, and outside of rendering, it looks like you need to implement it once as an expression, and once in Javascript. This is possible (and is what we're doing now), but has some downsides:

* If the expression is somewhat complicated, it's possible that there will be differences between the expression version and the Javascript version.
* It's not possible to write unit tests for expressions at present, so it's also not possible to test that the implementations match.

## Design

The `Map` instance could include a method to evaluate expressions. It would take an expression and a feature, and return the result of evaluating that expression on that feature. Any global properties (such as `zoom`) would come from the map.

Alternatively, the evaluation could be a pure function, independent of a map. However, this would make it more difficult to handle properties like `zoom`, and doesn't really add much value in the case described under "Motivation".

### Mock-Up

Here's a simplified example:

```js
const map = new mapboxgl.Map();

const colorExpr = ['case', ['get', 'isRed'], 'red', 'green'];

const redFeature = {
type: "Feature",
geometry: { type: "Point", coordinates: [0, 0] },
properties: { isRed: true },
}

const notRedFeature = {
type: "Feature",
geometry: { type: "Point", coordinates: [0, 1] },
properties: { isRed: false },
}

map.evaluateExpression(colorExpr, redFeature); // 'red'
map.evaluateExpression(colorExpr, notRedFeature); // 'green'
```

### Concepts

Adding an entry under the list of methods [here](https://www.mapbox.com/mapbox-gl-js/api/) should be sufficient, I think.

### Implementation

I'm currently not very familiar with the internals of MapboxGL JS. However, a quick look inside the source, under `style-spec/expression/index.js`, shows code that compiles and executes expressions, so I would hope that it wouldn't require too much work to hook into this code. With a little direction, I'd be happy to take a stab at this.

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

Start with style-spec/expression/index.js, which the issue identifies as the expression compilation and execution entry point, then review the Map API method list. Define how an expression and feature are evaluated, including map-provided global properties such as zoom, and consider coverage for matching rendered and external results.

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
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.