mapbox / mapbox/mapbox-maps-ios

Replacing a style image glitches when using SymbolLayer's `iconSize`

Open
#2,000 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

auto-triaged bug :beetle:
Dominant language
Swift
Stars
601
Forks
196
PR merge metrics
No merged PRs in 30d

Description

## Environment

- Xcode version: 14.3.1
- iOS version: 16.4
- Devices affected: All
- Maps SDK Version: 10.15.1 (also tested with 11 beta)

## Observed behavior and steps to reproduce

When loading style images asynchronously and replacing a synchronously returned image there is a visual glitch, if the symbol layer contains an `iconSize` (either static value or expression).
Once the asynchronously loaded image replaces the existing one it sort of blends with the previous one. This can be observed when double tapping the map (after loading), during the zoom in animation the old image is blended through the new image (see attached video). Once zooming in far enough it works properly.

Note: this behaviour is only present on a `UIImage` with a scale > 1 (so retina and super retina).

So to summarise:
I've got a SymbolLayer that has an `.iconSize` expression:
```swift
layer.iconSize = .expression(
Expression(.interpolate) {
Expression(.linear)
Expression(.zoom)
3
0.6
4
0.8
6
1.0
}
)
```
I load images asynchronously on the `.styleImageMissing` event:
```swift
mapView.mapboxMap.onEvery(event: .styleImageMissing) { [weak self] event in
// Provide initial image synchronously
let view = UIView(frame: .init(origin: .zero, size: .init(width: 50, height: 50)))
view.backgroundColor = .green
let image = view.convertToImage()
try! self?.mapView.mapboxMap.style.addImage(image, id: event.payload.id)

// Provide loaded image after 2s delay
DispatchQueue.main.asyncAfter(deadline: .now() + 2) { [weak self] in
let view = UIView(frame: .init(origin: .zero, size: .init(width: 50, height: 50)))
view.backgroundColor = .blue
view.layer.cornerRadius = 25
view.clipsToBounds = true
let image = view.convertToImage()
try! self?.mapView.mapboxMap.style.addImage(image, id: event.payload.id)
}
}
```
When double tapping to zoom in the original image is blended through the new image:

https://github.com/mapbox/mapbox-maps-ios/assets/3206952/668c3aa3-5910-401c-bf59-167577a30fec

When animating the camera manually in code the original image is also blended through the new image:

https://github.com/mapbox/mapbox-maps-ios/assets/3206952/a1233dc9-d158-4f2b-9847-f6fe6384b9ed

## Expected behavior

Only the last loaded image should be shown, they should not blend through each other

## Notes / preliminary analysis

I think it's all outlined above. The main points are:
- Loading a style image asynchronously
- Having the `.iconSize` property set on the `SymbolLayer`
- Having a scale factor of the image thats higher than 1

## Additional links and references

Sample project that reproduces this issue:
[IconBlending.zip](https://github.com/mapbox/mapbox-maps-ios/files/12311567/IconBlending.zip)

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 the linked IconBlending.zip sample project and reproduce the issue using SymbolLayer.iconSize with images supplied through the styleImageMissing event. Verify the behavior with asynchronously replaced images at scale greater than 1 during camera zoom animation; done means only the latest image is shown without blending.

Written by the indexing model from the issue text.

Assessment

Tech stack
ios, swift
Domain
computer-graphics, mobile
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.