-
Notifications
You must be signed in to change notification settings - Fork 2.2k
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
Evaluate an expression, outside of rendering #7670
Comments
@peterkhayes Thank you for the detailed issue description. If the You can implement
|
This would be a very useful method.@peterkhayes did you get a chance to take a stab? |
I unfortunately have not. If you'd like to, I would appreciate it for sure! |
I'm now experimenting with something like this: // Expression evaluation
// NOTE: This implementation does not accept a StylePropertySpecification. As a consequence of this
// decision, it will not check the type of the evaluation result and throw runtime evaluation errors.
// The caller should be aware that the result is untyped and wrap the expression in a type assertion
// if runtime type checking is desired.
export function evaluate(
expression: mixed,
globals: GlobalProperties,
feature?: Feature,
featureState?: FeatureState,
): any {
const parseResult = createExpression(expression);
if (parseResult.result === 'success') {
return parseResult.value.evaluate(globals, feature, featureState);
}
throw parseResult.value[0];
} |
Has there been any progress on making this a feature in Mapbox? There isn't really a way to unit test expressions right now, and I'm kind of surprised more people aren't worried about this. |
@SamuelDev Expression tests are part of our integration test-suite. You can see all the tests here and they can be run with |
Took me a couple minutes to dig for how those expression tests are evaluated, so I'll link it here: https://github.com/mapbox/mapbox-gl-js/blob/master/test/expression.test.js |
@ryanhamley Thanks for such a quick reply Ryan. I don't think that really helps us in our case though. We are consuming Mapbox through the npm package, and need to test an expression we have that has business logic inside of it. I can see if it is possible to extract some code from your integration test code base, but something like map.evaluateExpression would be super handy. |
@SamuelDev Thanks for letting us know your use case. I misunderstood and was trying to assuage any worries that expressions just weren't tested by the library. This request is something that's come up a few times. Right now, it's not on our immediate roadmap, but we do of course welcome pull requests if anyone wants to take a stab at it. Asheem laid out the general idea in #7670 (comment) cc @chloekraw There's some interest in a feature like this |
I wound up creating a TypeScript wrapper for Expression evaluation. If it's helpful to anyone, code is in this gist. One nice thing is that you get proper TypeScript types out if you specify an expected type for the expression: const r1 = Expression.parse(['+', 1, 2]).evaluate(null!); // type is any
const r2 = Expression.parse(['+', 1, 2], 'number').evaluate(null!); // type is number
const r3 = Expression.parse(['+', 1, 2], 'string').evaluate(null!); // throws |
@danvk I would be interested to use your solution within Angular, but I cannot omit compilation error:
Seems having @types/mapbox-gl installed it interferes. |
@marlag that error makes it sound like you haven't put |
@danvk Hmm, what I can say... blindness (as I wanted use only parsing part I even haven't looked on other files). Working fine now, thx a lot. |
I think a feature like this would be a huge boon to developers. I'm honestly surprised that more users of mapbox-gl haven't pushed harder for debugging or dev tooling around this. As a new user of Mapbox, the expressions are powerful but really hard to read. I find myself doing a lot of trial an error (requiring a re-render of the whole app to test) many permutations of rules until I reach a result that works or conclude it is impossible. When somethings fails, it is often difficult to know what caused the error. Seeing the result of expression evaluation against a particular feature/layer combo would be much nicer. I'll give some of the suggestions earlier in this thread a try. |
@danvk I have packaged up your Gist and released it as an NPM package mapbox-expression. Thanks so much for sharing that. So you can do:
|
@stevage Many thanks for creating this package, it seems to be exactly the thing we need to present a dynamic legend for our point layer radiuses (which are rendered differently at different zoom levels via an expression that linearly interpolates between max- and minzoom). We are trying to import and use the package in a Vue.js app, but we're faced with this error from npm when compiling: "export 'default' (imported as 'Expression') was not found in 'mapbox-expression". Perhaps it is something very simple that we have overlooked, but any help to get this to work would be greatly appreciated. |
@froghilda I think perhaps the required syntax is |
@rreusser Thanks for your reply! It was the syntax for how we import it, curly brackets seemed to have fixed the error when compiling with npm, big thanks!! |
@froghilda With a recent Mapbox GL update (I forget exactly which one) I had to update my import to use the CommonJS module, maybe this will help import {expression} from 'mapbox-gl/dist/style-spec/index.cjs';
const expr = expression.createExpression(...); |
Hi, is there a method which decides if expression is a Data expression? It must check for operators like 'get',... from docs. I don't know whole syntax and depth of expression, so I don't want to create such a method myself. something like:
Thanks |
Generally, data driven styles are arrays, so you can just use |
Yeah, I know it's simple to determine an expression, but I want to determine type of an expression. If it's using operators like |
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:
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 aszoom
) 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:
Concepts
Adding an entry under the list of methods here 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.The text was updated successfully, but these errors were encountered: