Skip to content
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

[FEATURE] Example for bing map usage? #1197

Closed
2 of 6 tasks
xyzbilal opened this issue Mar 24, 2022 · 12 comments
Closed
2 of 6 tasks

[FEATURE] Example for bing map usage? #1197

xyzbilal opened this issue Mar 24, 2022 · 12 comments
Assignees
Labels
feature This issue requests a new feature invalid This bug could not be reproduced or does not exist, or is very low quality

Comments

@xyzbilal
Copy link

xyzbilal commented Mar 24, 2022

Describe The Problem
Trying to implement bing maps in tile layer options but white screen only

Describe Your Solution

Provide an example for usage for it.

Alternatives/Workarounds

no workaround


Additional Information
I m trying to implement a map without titles, roads etc. bing maps gives me this opportunity but I m getting white screen instead

my FlutterMap implementation

 FutureBuilder(
        future: getBingUrlTemplate(
            'http://dev.virtualearth.net/REST/V1/Imagery/Metadata/RoadOnDemand?output=json&include=ImageryProviders&key=$bingMapKey'),
        builder: (context, snapshot) {
          if (snapshot.hasData) {
          String url = snapshot.data! as String;
          print(url);
          url = url.replaceAll("en-US", "tr-TR");
          url = url.replaceAll("it=G,L&shading=hill","it=A,G,RL&shading=t");
          print(url);
   
        return FlutterMap(
                  mapController: c.mapController,
                  options: MapOptions(
                      zoom: 11.0,
                      onTap: (tap, points) {
                        // my Logic
                      }),
                  layers: [
                    TileLayerOptions(
                      urlTemplate:snapshot.data as String,
                      attributionBuilder: (_) {
                        return SizedBox(); //Material(child:Text("© OpenStreetMap contributors"));
                      },
                    ),
                    PolygonLayerOptions(polygons:polies),


                  ],
                );
          }else{
            return SizedBox();
          }
          })

function to get link

Future<String?> getBingUrlTemplate(String url) async {
  final Response response = await GetConnect().get(url);
  assert(response.statusCode == 200, 'Invalid key');

  if (response.statusCode == 200) {
    final Map<String, dynamic> decodedJson = response.body ;
    late String imageUrl;
    late String imageUrlSubDomains;
    if (decodedJson['authenticationResultCode'] == 'ValidCredentials') {
      for (final String key in decodedJson.keys) {

  

        if (key == 'resourceSets') {
          // ignore: avoid_as
          final List<dynamic> resourceSets = decodedJson[key] as List<dynamic>;
          for (final dynamic key in resourceSets[0].keys) {
            if (key == 'resources') {
              final List<dynamic> resources =
                  // ignore: avoid_as
                  (resourceSets[0])[key] as List<dynamic>;
              final Map<String, dynamic> resourcesMap =
                  // ignore: avoid_as
                  resources[0] as Map<String, dynamic>;
              imageUrl = resourcesMap['imageUrl'].toString();
              final List<dynamic> subDomains =
                  // ignore: avoid_as
                  resourcesMap['imageUrlSubdomains'] as List<dynamic>;
              imageUrlSubDomains = subDomains[0].toString();
              break;
            }
          }
          break;
        }
      }

      final List<String> splitUrl = imageUrl.split('{subdomain}');
      return splitUrl[0] + imageUrlSubDomains + splitUrl[1];
    }
  }
  return null;
}

Applicable Platforms
Select platforms that this request applies to.

  • All/any
  • Android
  • iOS
  • Web
  • Windows
  • Others (beta platforms)
@xyzbilal xyzbilal added the feature This issue requests a new feature label Mar 24, 2022
@JaffaKetchup
Copy link
Member

Thanks for your report. Can you check the following things, which may lead to a similar error:

  • Is Bing Maps (or whatever tile server you're using) serving static raster tiles, as opposed to vector tiles? You'll likely find this in the documentation.
  • Do the network calls actually get made to the correct URL? You can use the DevTools Network tab for this purpose.
  • If you change the URL to the OpenStreetMaps one used in the examples, does the map work then? If not, this would indicate something not obvious wrong.

Many thanks!

@xyzbilal
Copy link
Author

Is Bing Maps (or whatever tile server you're using) serving static raster tiles, as opposed to vector tiles? You'll likely find this in the documentation.
*** Yes. it works. I tried bingmaps service syncfusion_flutter_maps package and everything works fine.**
Do the network calls actually get made to the correct URL? You can use the DevTools Network tab for this purpose.
*** Yes. I tried syncfusion_flutter_maps with same urls and on web my urls provide me correct data I need.**

If you change the URL to the OpenStreetMaps one used in the examples, does the map work then? If not, this would indicate something not obvious wrong.
*** OpenStreet map works fine as you can see in picture below**
I get reference to from this link to implement bing maps to my project.

Link

Simulator Screen Shot - iPhone SE (2nd generation) - 2022-03-25 at 09 44 49

@ibrierley
Copy link
Collaborator

Can you paste what snapshot.data contains.

@xyzbilal
Copy link
Author

Hi Thanks for interest, Now I received an error after cleaning and rebuilding app
says that Exception: No value provided for variable quadkey when I search for it in syncfusion_maps there is getTileUrl and _getQuadKey functions to replace quadKey comes with url . my snapshot.data is http://ak.dynamic.t0.tiles.virtualearth.net/comp/ch/{quadkey}?mkt=en-US&it=G,L&shading=hill&og=1790&n=z

I thing there would be a solution in the link below but I am not that professional to solve and contribute to project. Plase check the link for the purpos. thanks. Link

@ibrierley
Copy link
Collaborator

Quadkeys are shown here https://docs.microsoft.com/en-us/bingmaps/articles/bing-maps-tile-system on how to calculate.

@ibrierley
Copy link
Collaborator

Just wondering if you managed to solve this ?

@xyzbilal
Copy link
Author

xyzbilal commented Apr 1, 2022

unfortunately I couldn't solve it by myself then I start to work on syncfusion maps. I m stranger for the terms and english is not my native language, so I couldnt understand the concept exactly.

@JaffaKetchup
Copy link
Member

OK, no problem. Feel free to ask for more help if you start using flutter_map again :)

@JaffaKetchup JaffaKetchup added the invalid This bug could not be reproduced or does not exist, or is very low quality label Apr 2, 2022
@luka-glusica
Copy link

Hi guys,

This is how I managed to integrate BingMaps. Of course, there are many things to improve, such as handling Bing REST API potential errors, fallback Tiles, using locale-based culture code, subdomain is hard-coded in my example etc.

First, create custom TileProvider that will handle custom urlTemplate (instead of {x}, {y}, {z} you will now have, at least in minimalistic implementation, {subdomain}, {quadKey} and {culture}. The quadKey is a String of numeric characters calculated based on Tile coordinates (see BingMaps instructions):

class BingTileProvider extends TileProvider {
  BingTileProvider({
    super.headers,
  });

  String _getQuadKey(int x, int y, int z) {
    final StringBuffer quadKey = StringBuffer();
    for (int i = z; i > 0; i--) {
      int digit = 0;
      final int mask = 1 << (i - 1);
      if ((x & mask) != 0) {
        digit++;
      }
      if ((y & mask) != 0) {
        digit++;
        digit++;
      }
      quadKey.write(digit);
    }
    return quadKey.toString();
  }

  @override
  String getTileUrl(Coords<num> coords, TileLayer options) {
    String url = options.urlTemplate ?? '';

    return url.replaceAll('{subdomain}', 't0').replaceAll('{quadkey}',
            _getQuadKey(coords.x.toInt(), coords.y.toInt(), coords.z.toInt()))
        .replaceAll('{culture}', 'en-US');
  }

  @override
  ImageProvider<Object> getImage(Coords<num> coords, TileLayer options) {
    return NetworkImage(getTileUrl(coords, options));
  }
}

Secondly, you create a new Bing layer (Road, Aerial or whichever you choose to visualize) as a Stateless widget. You need FutureBuilder to call REST API with your Bing Maps API key for specific layer, to get all the necessary metadata, such as attribution, subdomains, image URL template, etc.

class BingRoadLayer extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
      future: http.get(Uri.parse(
          'http://dev.virtualearth.net/REST/V1/Imagery/Metadata/RoadOnDemand?output=json&include=ImageryProviders&key=[YOUR_API_KEY]')),
      builder: (context, response) {
        if (response.connectionState == ConnectionState.waiting) {
          return SizedBox();
        }

        return TileLayer(
          maxZoom: 21,
          urlTemplate: jsonDecode(response.data!.body)['resourceSets'][0]
              ['resources'][0]['imageUrl'],
          tileProvider: BingTileProvider(),
        );
      },
    );
  }
}

Now you can use your new layer in a FlutterMap children list, just as you would use any kind of TileLayer.

@JaffaKetchup I noticed that when I use retinaMode: true with the above-written implementation, something happens with coordinates projection. Points which are normally in Europe, get distorted and translated somewhere near Antarctica. So that is maybe something to check, I would appreciate some advice and suggestions on the subject.

@victor0402
Copy link

@luka-glusica Thanks for sharing your solution, it also worked for me

@TROJANALE
Copy link

@luka-glusica Your solution worked perfectly. Thank you.

PS: In the BingTileProvider class, replace the method:

 @override
  String getTileUrl(Coords<num> coords, TileLayer options) {
    String url = options.urlTemplate ?? '';
 return url.replaceAll('{subdomain}', 't0').replaceAll('{quadkey}',
            _getQuadKey(coords.x.toInt(), coords.y.toInt(), coords.z.toInt()))
        .replaceAll('{culture}', 'en-US');
  }

with the one below. I changed 'Coords' to 'TitleCoordinates'.


@override
  String getTileUrl(TileCoordinates coordinates, TileLayer options) {
    String url = options.urlTemplate ?? `'';`
    return url.replaceAll('{subdomain}', 't0').replaceAll('{quadkey}',
        getQuadKey(coordinates.x.toInt(), coordinates.y.toInt(), coordinates.z.toInt()))
        .replaceAll('{culture}', 'en-US');
  }

@JaffaKetchup
Copy link
Member

As this seems to be working, I'll add it to the docs. Thanks @luka-glusica :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature This issue requests a new feature invalid This bug could not be reproduced or does not exist, or is very low quality
Projects
None yet
Development

No branches or pull requests

6 participants