-
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
Make image operator compatible with styleimagemissing event #8775
Conversation
This is fairly close to being a working solution. I'm not sure how to fix the Flow error without casting to The two unit tests are caused because The render test is very odd. I don't see that failure on my local machine. I get 100% passing render tests. |
This isn't really something that can be unit tested. We should eventually add some end-to-end tests which would be more appropriate for testing this. I have done extensive manual testing in the browser however. All of these work as expected - a valid image produces the correct visual and an invalid image causes
This has been tested for |
From the overview explanation from @ryanhamley this seems good, we were just saying that it would be nice to have tests for this, but it's really difficult to create unit/integration tests for this given our current testing infrastructure. So instead it would be helpful to at least have a debug page with a style using this operator to verify that the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for adding the debug page @ryanhamley! Page looks good to me in Firefox & Chrome on Ubuntu, I also tested that it gives the "Image 'foo' could not be loaded" error if needed. I'm not super familiar with the expression parsing code but the changes look good from where I'm standing.
One question, does it make sense to have the actor stubbing in the tests be part of this PR or make it a separate one (since it seems like it doesn't have to do with this feature)? Not a big deal just wondering
The stub is actually required to get the tests passing. If |
There is one aspect of the I don't think this is a bad design choice, but I had to think about it a bit. Maybe I am just learning about a quirk of Part of me thinks that we should get an event per feature if we use data-driven expressions anywhere in the coalesce and it fails? To handle this though I think ideally we'd want to see "tried Fundamentally I wish we had a way to show or refer to individual features in the error console for a given Is this a concern we've had before with |
} | ||
|
||
toString(): string { | ||
return this.name; | ||
} | ||
|
||
static fromString(imageName: string): ResolvedImage { | ||
return new ResolvedImage(imageName); | ||
static fromString(options: ResolvedImageOptions): ResolvedImage { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Why do we have fromString
if it doesn't accept strings, and the plain constructor could be used with the same arguments?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, that's a good point. It's used in other places where it might be less straightforward to use the constructor though (https://github.com/mapbox/mapbox-gl-js/blob/master/src/style-spec/expression/definitions/coercion.js#L105). I'm inclined to leave this as is though because it follows the pattern of other expression types and this type and operator will likely be expanded significantly in the future as we add more image manipulation operators.
@ahk I'm not sure if we've had larger discussions about changing the way The way that this PR was implemented, we assumed a heuristic in which the first (left-most) image that was requested was assumed to be the most desirable one, therefore the one we emit a warning for. This behavior is analogous to the way a browser evaluates a font stack. I think it makes sense and works well. We could revisit it in the future if we get a lot of feedback on this issue. |
// this allows us to fire the styleimagemissing event if image evaluation returns null | ||
// the only way to distinguish between null returned from a coalesce statement with no valid images | ||
// and null returned because icon-image wasn't defined is to check whether or not iconImage.parameters is an empty object | ||
const hasIcon = iconImage.value.kind !== 'constant' || !!iconImage.value.value || Object.keys(iconImage.parameters).length > 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Part of this comment explains the high-level reasoning for retuning an object from the image
expression. That should be documented in the code for that expression, or expressly stated in the PR description (its not too late to do that yet).
This comment seems less of a clarification of what the code does here. Maybe replace it with:
// `iconImage.parameters` distinguishes between an unspecified `icon-image` property and specified but not found value. Check it here to trigger styleimagemissing events as appropriate
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ryanhamley found few issues while porting to native, please check if comments are valid.
min = min && min.name ? min.name : min; | ||
mid = mid && mid.name ? mid.name : mid; | ||
max = max && max.name ? max.name : max; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@asheemmamoowala @ryanhamley If min is null => patterns[null] = true?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wasn't null
a possible result here even before this change?
I can't remember exactly why I changed this now off the top of my head, but I think the ternary operator might have been more of a defensive guard. I'm not actually sure that min
can ever be null
at this point because any value supplied to *-pattern
properties will be coerced to a ResolvedImage type. If you tried to just do line-pattern: null
or something, you'd get a type error before it got to this point. But maybe there's a pathway I'm not thinking about/a better way to handle this to ensure we don't get patterns[null]
.
// we need to keep track of the first requested image in a coalesce statement | ||
// if coalesce can't find a valid image, we return the first image name so styleimagemissing can fire | ||
if (arg.type.kind === 'image' && !result.available) { | ||
if (!requestedImageName) requestedImageName = arg.evaluate(ctx).name; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ryanhamley @asheemmamoowala arg is already evaluated on line 60
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is an oversight which can be corrected
result = arg.evaluate(ctx); | ||
// we need to keep track of the first requested image in a coalesce statement | ||
// if coalesce can't find a valid image, we return the first image name so styleimagemissing can fire | ||
if (arg.type.kind === 'image' && !result.available) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ryanhamley Why type of arg is checked? I think it should it be type of coalesce itself and then check if evaluated result is an image.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changing the check to if (result && result instanceof ResolvedImage && !result.available)
seems to work fine. Is that what you had in mind?
Launch Checklist
fixes #8774
image
operator returnsnull
to force thestyleimagemissing
event to still fire