Skip to content

Change Map Style

In this guide you will learn how to change the map style used to render an interactive map.
Graphic control interface using ImGui.

ChangeMapStyle - cpp example screenshot

Setup

First, get an API key token, see the Getting Started guide.

Prerequisites

It is required that you complete the Environment Setup - CPP Examples guide before starting this guide.

Setting your API key token

To set your API key token, define it like this:

#define API_TOKEN "YOUR_API_KEY_TOKEN"

replacing YOUR_API_KEY_TOKEN with your actual API key token text, within the quotes.

This can be done in the main() function, before the following line:

#if defined(API_TOKEN)

or outside the main() function, further up, or in a header file.

Although it is also possible to define your API key token as the text value of the GEM_TOKEN environment variable, this is not recommended, as it is not secure.

Build and run

In Visual Studio, right-click on the ChangeMapStyle project, and select Set as Startup Project then press F5 to run.

How it works

 1int main( int argc, char** argv )
 2{
 3   std::string projectApiToken = "";
 4#define API_TOKEN "YOUR_API_KEY_TOKEN"
 5#if defined(API_TOKEN)
 6   projectApiToken = std::string( API_TOKEN );
 7#endif
 8   // Sdk objects can be created & used below this line
 9   Environment::SdkSession session(projectApiToken, { argc > 1 ? argv[1] : "" });
10
11   // Create an interactive map view
12   CTouchEventListener pTouchEventListener;
13   gem::StrongPointer<gem::MapView> mapView = gem::MapView::produce(session.produceOpenGLContext(
14      Environment::WindowFrameworks::ImGUI, "ChangeMapStyle", &pTouchEventListener, getUiRender()));
15   if ( !mapView )
16   {
17      GEM_LOGE( "Error creating gem::MapView: %d", GEM_GET_API_ERROR() );
18   }
19   WAIT_UNTIL_WINDOW_CLOSE();
20   return 0;
21}

First, the API key token is set.

Next, the SDK environment is initialized, passing in the API key token string, and the SDK API debug logging path.
Environment::SdkSession session(projectApiToken, { argc > 1 ? argv[1] : "" });
The debug logging path is set from the first command line argument, if there is one, otherwise it can be given as a hardcoded string.
A touch event listener is instantiated, to support touch input for the interactive map, such as pan and zoom.
CTouchEventListener pTouchEventListener;
The MapView interactive map instance is created, using an OpenGL context for rendering, and selecting ImGui for the graphic control interface.
gem::StrongPointer<gem::MapView> mapView = gem::MapView::produce(session.produceOpenGLContext(Environment::WindowFrameworks::ImGUI,
The window title is specified, and the touch event listener instanced is passed in.
"ChangeMapStyle", &pTouchEventListener, getUiRender()));

Finally, the getUiRender() function is passed in, which uses ImGui to render GUI elements, capture user control input, and call the appropriate SDK functions.

 1auto getUiRender()
 2{
 3   return std::bind([](gem::StrongPointer<gem::MapView> mapView)
 4   {
 5      static bool isNightStyle = false;
 6      ImGuiIO& io = ImGui::GetIO();
 7      const ImGuiViewport* main_viewport = ImGui::GetMainViewport();
 8      ImGui::SetNextWindowPos(ImVec2(main_viewport->WorkPos.x + 0, main_viewport->WorkPos.y + 20), ImGuiCond_FirstUseEver);
 9      ImGui::Begin("panel", nullptr, ImGuiWindowFlags_NoMove
10          | ImGuiWindowFlags_NoDecoration
11          | ImGuiWindowFlags_AlwaysAutoResize
12          | ImGuiWindowFlags_NoSavedSettings);
13      if ( ImGui::Button( "Click to apply map style" ) )
14      {
15          ImGui::SameLine();
16          ImGui::Text("Getting map style...");
17          isNightStyle = !isNightStyle;
18
19          ProgressListener listener;
20          auto searchAndApply = [&]()
21          {
22              auto styles = gem::ContentStore().getStoreContentList( gem::EContentType::CT_ViewStyleLowRes ).first;
23              gem::ContentStoreItem nightStyle;
24              gem::ContentStoreItem dayStyle;
25              // Find first night map style
26              for ( auto style : styles )
27              {
28                  auto backGroundColor = style.getContentParameters().findParameter( "Background-Color" );
29                  if ( backGroundColor && !gem::Rgba( backGroundColor.getValue<int>() ).isLight() )
30                  {
31                      // Night map style found - download if needed
32                      if ( style.getStatus() == gem::EContentStoreItemStatus::CIS_Unavailable )
33                      {
34                          listener.Reset();
35                          style.asyncDownload( &listener );
36
37                          WAIT_UNTIL( std::bind( &ProgressListener::IsFinished, &listener ), INT_MAX );
38                      }
39                      nightStyle = style;
40                      break;
41                  }
42              }
43              // Find first day map style
44              for ( auto style : styles )
45              {
46                  auto backGroundColor = style.getContentParameters().findParameter( "Background-Color" );
47                  if ( backGroundColor && gem::Rgba( backGroundColor.getValue<int>() ).isLight() )
48                  {
49                      // Day map style found - download if needed
50                      if ( style.getStatus() == gem::EContentStoreItemStatus::CIS_Unavailable )
51                      {
52                          listener.Reset();
53                          style.asyncDownload( &listener );
54
55                          WAIT_UNTIL( std::bind( &ProgressListener::IsFinished, &listener ), INT_MAX );
56                      }
57                      dayStyle = style;
58                      break;
59                  }
60              }
61              if ( isNightStyle && nightStyle && nightStyle.isCompleted() )
62                  return GEM_TEST_NOEXCEPT(mapView->preferences().setMapStyle( nightStyle )) == gem::KNoError;
63              else if ( !isNightStyle && dayStyle && dayStyle.isCompleted() )
64                  return GEM_TEST_NOEXCEPT(mapView->preferences().setMapStyle( dayStyle )) == gem::KNoError;
65              else
66                  return false;
67          };
68          // Try with local list
69          if ( !searchAndApply() )
70          {
71              // Get available content store map styles
72              gem::ContentStore().asyncGetStoreContentList( gem::EContentType::CT_ViewStyleLowRes, &listener );
73              WAIT_UNTIL( std::bind( &ProgressListener::IsFinished, &listener ), INT_MAX );
74              searchAndApply();
75          }
76      }
77      ImGui::SameLine();
78      ImGui::Text("%s", isNightStyle ? "Night map style set!" : "Day map style set!");
79      //ImGui::Text( "Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate );
80      ImGui::End();
81   }
82   , std::placeholders::_1);
83}

First, the main ImGui viewport is obtained, and the x,y position of the ImGui window, with the identifier “panel”, in pixels, is set within the SDK OpenGL viewport.

The ImGui graphical control elements are within the ImGui window/panel, rendered on top of the SDK OpenGL viewport, which contains the interactive map. The ImGui panel is created using the ImGui::Begin() function.
The first control element in this case, is an ImGui::Button() which the user can click to set a map style. Each subsequent click toggles the map style between a day style and a night style.
There is also an ImGui::Text() element which displays whether a day or night map style was just set by the last tap/click on the button.
Get available map styles from the content store:
auto styles = gem::ContentStore().getStoreContentList( gem::EContentType::CT_ViewStyleLowRes ).first;
Iterate through the map styles, get the background color, and check if it is NOT light - that means it is a dark/night map style:
auto backGroundColor = style.getContentParameters().findParameter( "Background-Color" );
if ( backGroundColor && !gem::Rgba( backGroundColor.getValue<int>() ).isLight() )
Once the first night map style is found, check if it is available locally:
if ( style.getStatus() == gem::EContentStoreItemStatus::CIS_Unavailable )
If it is not already downloaded, download it, and use a listener to enable waiting for the download to complete:
listener.Reset();
style.asyncDownload( &listener );
Use the WAIT_UNTIL() macro to wait for the download to complete
WAIT_UNTIL( std::bind( &ProgressListener::IsFinished, &listener ), INT_MAX );
Then save a pointer to the night map style:
nightStyle = style;

Repeat the above steps to get a pointer to the first day map style, except check that it IS a light colored map style.

Use the setMapStyle() function to set a previously downloaded map style to be used for rendering the interactive map:
return GEM_TEST_NOEXCEPT(mapView->preferences().setMapStyle( nightStyle )) == gem::KNoError;

The WAIT_UNTIL macro is used to wait for the route calculation to complete and check the success/error status, and whether the resulting route list has at least one route.

C++ Examples

Maps SDK for C++ Examples can be downloaded or cloned with Git