mapbox / mapbox-gl-native-ios

Interactive, thoroughly customizable maps for iOS powered by vector tiles and OpenGL
https://www.mapbox.com/mobile/
Other
210 stars 122 forks source link

[IOS] MGLSymbolStyleLayer text will not display if it contains letters or Numbers #122

Closed songyuyang0918 closed 4 years ago

songyuyang0918 commented 4 years ago

Platform: iOS Mapbox SDK version: 5.5.0 Xcode version: Version 10.1 (10B61) Devicemodels: iPad mini 3

Steps to trigger behavior:

1.I used GEOSwiftMapboxGL to convert the WKT into the pointAnno object of the MapBox through traversal. 2.The pointAnno data is then converted into an MGLPointFeature object and stored in an array. 3.Display the text label by generating MGLShapeSource and MGLSymbolStyleLayer.

屏幕快照 2019-12-20 下午5 45 57 屏幕快照 2019-12-20 下午5 34 49

Expected behavior Display all text on the map.

Actual behavior 1.When mglshapesource.text = @ "测试" shows, 2.When mglshapesource.text = @ "测试 123" does not display 3.When mglshapesource.text = @ "测试 ABC" is not displayed

and When text can be displayed, it is displayed at level >12, <12 is not displayed.

//1 71245379-8476fb00-234f-11ea-9112-10283a4f9844

//2,3 71245383-86d95500-234f-11ea-81f9-59a3f2d0efdf

songyuyang0918 commented 4 years ago

And I try to use the expression to manage MGLSymbolStyleLayer textOpacity, still we don't have any effect

屏幕快照 2019-12-31 上午11 40 56
julianrex commented 4 years ago

@songyuyang0918 have you tried this with Android?

/cc @jmkiley

jmkiley commented 4 years ago

Hey @songyuyang0918 -

Are you still seeing this issue with 5.6.0? Also, are all of the labels missing in that layer or just some of the labels?

I was able to partially reproduce this issue with the [clustering example](). When I set numbersLayer.text to NSExpression(format: "mgl_join({'测试', CAST(point_count, 'NSString')})"), some features within that layer did not appear. This also applies when I set the second string to a string written in a Latin script.

I did not notice the same behavior with the equivalent Android example.

songyuyang0918 commented 4 years ago

@julianrex I'm just an IOS developer. I'm not good at Android.

@jmkiley
Thank you very much for your testing, my requirements are not on the clustering function, I just want the real label text. I checked the operation method you used and tested it: Layer. text = [NSExpression expressionWithFormat:@"mgl_join({' 清远街道很长的测试 ', CAST(point_count, 'NSString')} "]; I can't splicing point_count because I'm using the mglstylstylelayer. Although the letters and Numbers are still not displayed in the test string, the words "清远街道很长的测试" are displayed comprehensively. However, the text content of my tag is mutable and is "jiedao" in the geojson property. I can't understand why when I use layer.text = [NSExpression expressionForKeyPath:@"jiedao"]; This expression, it's not going to show all of that, right?

1578301741621434 2020-01-06 17_15_06

And what do I do when you say "set the second string to be a Latin scripted string"?

jmkiley commented 4 years ago

Hi @songyuyang0918 -

Apologies for the confusion. The code in my comment was intended to help other people to reproduce the issue. Since you already are seeing the issue in your own code, you do not need to use the code in my comment.

Can you confirm whether you are seeing the behavior with Maps SDK v5.6.0? Are all labels within the layer missing or just some of the labels?

jmkiley commented 4 years ago

Noting that I don't see this issue if I add the following code to the [Style symbol layer]() example in iosapp:

    MGLSymbolStyleLayer *stateLayer = (MGLSymbolStyleLayer *)[self.mapView.style layerWithIdentifier:@"state-label"];
    stateLayer.text = [NSExpression expressionWithFormat:@"mgl_join:({'%@', '测试'})", [NSExpression expressionForKeyPath:@"name"]];
    stateLayer.textAllowsOverlap = [NSExpression expressionForConstantValue:@"true"];
    stateLayer.textColor = [NSExpression expressionForConstantValue:[UIColor redColor]];

@songyuyang0918 - Could you also confirm whether you see this issue when textAllowsOverlap is set to NSExpression expressionForConstantValue:@"true"] in your code?

songyuyang0918 commented 4 years ago

@jmkiley Thank you very much for your reply!

For SDK5.6.0 I use cocoapods to display timeout, I will continue to try tomorrow.

  1. I have also set textAllowsOverlap before, but that is not the effect I want. I think when the text conflicts, one of the text should be displayed, instead of two conflicting text not displayed.
  2. As for your expression, it doesn't work for me. I can't see anything.
  3. Text with letters and Numbers still cannot be displayed.

1 figure (test figure using [NSExpression expressionForKeyPath:@"jiedao"]) At level 7: no labels are displayed. At level 9: displays a tag. 51578475627_ pic_hd At level 12: successive labels are displayed. 61578475646_ pic_hd At level 14: 71578475656_ pic_hd It's like a BUG, and I don't think text conflicts should be left undisplayed.

The corresponding figure 2 layer.text = [NSExpression expressionWithFormat:@"mgl_join({'%@', '测试'})",[NSExpression expressionForKeyPath:@"jiedao"]]; Not for me, my geojson property "jiedao" is a string, and I can only display it through expressionForKeyPath, as shown in figure 1.

The third problem remains.

jmkiley commented 4 years ago

Hello @songyuyang0918 -

Could you provide a minimal test case that demonstrates the issue you are seeing? This would help us to investigate the issue.

songyuyang0918 commented 4 years ago

@jmkiley
In the process of making the demo, I found the problem. About label display. Use the Mapbox's default styleUrl, which displays everything. Using my own Url, I get the problem I'm describing. Why?

屏幕快照 2020-01-14 下午5 21 59 屏幕快照 2020-01-14 下午5 22 50

Here's the example I created that requires you to add your own AccessToken: https://pan.baidu.com/s/1j8WFWJWnzV7donCob6Eg2w

songyuyang0918 commented 4 years ago

Is there anyone else who can help me with this problem? @jmkiley Do you have any plans to help me find this problem?

jmkiley commented 4 years ago

Hi @songyuyang0918 -

Thank you for your patience. I haven't been able to repro your issue and am unable to download your sample app. Could you share the example via Github? If you are unable to share the sample app via Github, would you be able to send it to Mapbox support with a link to this issue?

songyuyang0918 commented 4 years ago

@jmkiley Thank you very much for your patience. The pods file in my example is too large to share with github. I have sent the problem to Mapbox support. During the process, I felt that my problem should be in the configuration file of the custom data source:

屏幕快照 2020-05-07 上午11 25 09

My full name in the question is Calm

ZiZasaurus commented 4 years ago

@jmkiley, @1ec5, it appears that if the style json is used as the style source, if the feature being referenced for the MGLSymbolLayer text contains mixed-script, none of the labels will show. However, if the tileset is added instead as a rasterSource over a Mapbox default or custom style, regardless of if the feature contains mixed-script, the labels will show with no issue. I've attached screenshots and the sample project I used to reproduce this below.

tileset url declared in style.json:

Screen Shot 2020-05-14 at 2 58 25 PM

as a rasterSource:

Screen Shot 2020-05-14 at 3 39 12 PM

Link to sample project with access token removed: https://drive.google.com/open?id=1DlwGjT6l42DJn2HA28NQW2Lc-51koIij

Note: if running my example, make sure to comment out the raster source and layer to test the json as a style source by itself. If you're running the example to test the rasterSource, the styleURL will need to be changed from the json or simply removed.

1ec5 commented 4 years ago

For clarity, the source.json in the project above is not a source but rather a style. If I understand the discussion above, the issue is that red labels such as “东海街道” and “环西指挥部 abc” appear if the map view is initialized with the Mapbox Streets style and OSM raster tiles are added at runtime, but not if the map view is initialized with a bundled JSON file as the style and that style contains an OSM raster tile layer baked right in.

Running the application results in this console output:

2020-05-19 09:15:58.012913-0700 MGLSymbolStyleLayer Text[10211:2395415] Task <8BF579D6-9380-4FA7-9905-E950CA5CD853>.<8> finished with error [-1002] Error Domain=NSURLErrorDomain Code=-1002 "unsupported URL" UserInfo={NSUnderlyingError=0x6000035bcdb0 {Error Domain=kCFErrorDomainCFNetwork Code=-1002 "(null)"}, NSErrorFailingURLStringKey=, NSErrorFailingURLKey=, NSLocalizedDescription=unsupported URL}

The issue is that source.json does not specify a glyphs property, so text cannot be rendered using any remotely rasterized glyphs. By default, CJK glyphs are rendered locally using system fonts, but currently it’s artificially restricted to just CJK characters: https://github.com/mapbox/mapbox-gl-native/issues/7862#issuecomment-613760767. So if a label requires any non-CJK characters, it requires remote glyphs, but source.json doesn’t specify where to get them, so all requests for glyphs fail from then on out.

A typical glyphs value looks like:

{
  "glyphs": "mapbox://fonts/mapbox/{fontstack}/{range}.pbf"
}

But if you need to load glyph PBFs locally for some reason, it’s also possible to specify something like "foobar://glyphs/{fontstack}/{range}.pbf" and implement -[MGLMapSnapshotterTests offlineStorage:URLForResourceOfKind:withURL:] to redirect that URL to a bundled PBF file:

- (NSURL *)offlineStorage:(MGLOfflineStorage *)storage URLForResourceOfKind:(MGLResourceKind)kind withURL:(NSURL *)url {
    if (kind == MGLResourceKindGlyphs && [url.scheme isEqualToString:@"foobar"]) {
        return [[NSBundle bundleForClass:[self class]] URLForResource:@"glyphs" withExtension:@"pbf"];
    }
    return url;
}
songyuyang0918 commented 4 years ago

@1ec5 The problem has been solved successfully. Thank you for your help!

songyuyang0918 commented 4 years ago

@1ec5 Hello! Is there any way for me to load the PBF directly locally? As for the mglmapsnaptertests you mentioned, I only found the corresponding MGLMapSnapshotter class in 5.5.0. My understanding is to load the offline map. But now I need to load the online map to achieve the MGLSymbolStyleLayer display. My clients may not want to get remote glyphs online. Can I get it locally using file: in a json file? If yes, for the PBF file specification or download address? I spent a day going to Google, but the requirements I found were obviously not in line with mine.

1ec5 commented 4 years ago

https://github.com/mapbox/mapbox-gl-native-ios/issues/122#issuecomment-630984774 shows how to load the PBF file directly from a local file URL, but we don’t have any documentation on the PBF file’s format or how to create one yourself. But if you’re interested in viewing the map offline, take a look at MGLOfflineStorage and MGLOfflinePack. By adding an offline pack, you’ll end up downloading all the resources required for a given style, including any glyph PBFs that the map would normally fetch from the Mapbox Fonts API.

1ec5 commented 4 years ago

If you have any questions about offline maps, please contact the Mapbox Support team. I’m closing this issue because there doesn’t seem to be a problem with the runtime styling API per se. Feel free to open separate issues about any bugs or missing features as you integrate offline maps.