Search code examples
javascriptjavahtmljavafxmaps

PTV Vector map text labels not displayed as expected


In my application based in Java on the front end and using WildFly Keycloack on the backend, we are displying a PTV Vector map in one of the application views using the following libraries:

  • ol.js
  • JavaFx
  • olms.js
  • require.js
  • PTV/MapBox implentations

The issue is that the small label for street names is not displayed correctly. It looks as if the center/position it has for street names is different to the rest of elements in the map since they are displayed correctly.

For instance, the following image shows two examples of text labels, one being displayed as expected and the issue for which this thread has been created. Map text labels

As per my observations, the following block of code in our standard.json file will display both text labels mentioned above.

{
            "id": "TSP_RoadLocal_Label",
            "type": "symbol",
            "source": "ptv",
            "source-layer": "LayerTransport",
            "minzoom": 13,
            "filter": [
                "all",
                [
                    "==",
                    "$type",
                    "LineString"
                ],
                [
                    "==",
                    "display_class",
                    5
                ]
            ],
            "layout": {
                "icon-rotation-alignment": "auto",
                "symbol-placement": "line",
                "text-font": [
                    "Noto Sans Regular"
                ],
                "text-size": {
                    "stops": [
                        [
                            10,
                            8
                        ],
                        [
                            20,
                            14
                        ]
                    ]
                },
                "text-letter-spacing": 0.1,
                "text-field": "{street_name}"
            },
            "paint": {
                "text-color": "#1B1C1F",
                "text-opacity": {
                    "stops": [
                        [
                            13,
                            0
                        ],
                        [
                            14,
                            1
                        ]
                    ]
                },
                "text-halo-color": "hsl(0, 0%, 100%)",
                "text-halo-width": 2
            }
        }

What I would like to know is why some text labels are not displayed correctly and some others are displayed as expected.

Following is the HTML code:

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge" charset='utf-8' />
<meta name="viewport"
    content="width= 100, initial-scale=1.0, user-scalable=no" />

<style type="text/css">
html {
    height: 100%
}

body {
    height: 100%;
    margin: 0;
    padding: 0
}

#map_canvas {
position:absolute; top:0; bottom:0; width:100%;
    height: 100%
}
</style>

<script src="libraries/ol.js"></script>
<script src="libraries/olms.js"></script>
<script src="libraries/require.js"></script>

<script
    src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
</head>

<body>
    <div id="map_canvas" style="height: 100%; width: 100%"></div>
    <script>

    var fromProjection;
    var toProjection;
    var zoom;

    var apiUrl = 'https://api.myptv.com/maps/v1/vector-tiles/{z}/{x}/{y}?apiKey=';
    var apiKey;
    var urlTemplate = apiUrl + apiKey;
    var jsonStyle;

    var map;

    function setApiKey(api) {
        apiKey = api;
        urlTemplate = apiUrl + apiKey;
    }

    function init() {

        try {

            if (map != null) {
                return;
            }

            map = new ol.Map({
                target: 'map_canvas',
                view: new ol.View({ center: ol.proj.transform([8.7528, 50.377], 'EPSG:4326', 'EPSG:3857'), zoom: 18}),
                controls:[]
            });

            const layer = new ol.layer.VectorTile({
                source: new ol.source.VectorTile({
                    format: new ol.format.MVT(),
                    url:
                        urlTemplate,
                    maxZoom: 18,
                }),
            });


            fetch('./libraries/standard.json')
            .then((response) => response.json())
            .then((json) => layer.setStyle(olms.stylefunction(layer,json, 'ptv')));
            
            map.addLayer(layer);

        } catch (e) {
            console.log(e);
        }
    }

    function getMap() {
        init();

        return map;
    }

    function getZoom() {

        return zoom;
    }

    function setZoom(zoomLvl) {

        zoom = zoomLvl;
        getMap().getView().setZoom(zoom);
    }

    function getCenterLat() {

        return ol.proj.transform(getMap().getView().getCenter(), 'EPSG:3857', 'EPSG:4326')[1];
    }

    function getCenterLng() {

        return ol.proj.transform(getMap().getView().getCenter(), 'EPSG:3857', 'EPSG:4326')[0];
    }

    function setCenter(lat, lng) {
        try {
            getMap().getView().setCenter(ol.proj.transform([lng, lat], 'EPSG:4326', 'EPSG:3857'));
        } catch (e) {
            console.log(e)
        }
    }

    </script>
</body>
</html>

Lastly, this is the renderer Java class:

import java.net.URL;
import java.util.Vector;
import javafx.application.Platform;

public class PTVDevVectorMapRenderer extends AbstractHtmlInteractiveMapRenderer {

  private static final long serialVersionUID = 1L;
  public String apiKey = KonstantenCache.getWertGCW("PTV_DEVELOPER", "PTV_API_KEY");
  
  public PTVDevVectorMapRenderer() {

    super();
    initializeMap();
  }

  /**
   * Initialize PTV Map
   */
  public void initializeMap() {
    final URL urlPTVMaps = getClass().getResource("PTVDevVectorMap.html");
    htmlRenderer.setContent(urlPTVMaps.toExternalForm());

    // Blocking call. Waits until WebEngine is loaded
    refresh();
    Platform.runLater(new Runnable() {

      @Override
      public void run() {

        setApiKey();
        String scriptInit = "init()";
        htmlRenderer.execute(scriptInit);
        
      }});
  }
  
  public void setApiKey() {
    String apiKey = KonstantenCache.getWertGCW("PTV_DEVELOPER", "PTV_API_KEY");
    String scriptApiKey = "setApiKey('" + apiKey + "')";
    //String.format("setApiKey('%s')", apiKey);
    htmlRenderer.execute(scriptApiKey);
  }

  @Override
  public void setCenter(
      double lat,
      double lng) {

    String scriptCenter = "setCenter(" + lat + "," + lng + ")";
    htmlRenderer.execute(scriptCenter);
  }

  @Override
  public double getCenterLat() {

    double centerLat = (double) htmlRenderer.executeAndReturn("getCenterLat()");
    return centerLat;
  }

  @Override
  public double getCenterLng() {

    double centerLng = (double) htmlRenderer.executeAndReturn("getCenterLng()");
    return centerLng;
  }


  @Override
  public int getZoom() {
    
    Object obj = htmlRenderer.executeAndReturn("getZoom()");
    
    if (obj instanceof String) {
      // String is "undefined", thus the map is not completely loaded yet.
      return 13;
    }

    return (int) obj;
  }

  @Override
  public void setZoom(
      int zoom) {

    String script = "setZoom(" + zoom + ")";
    htmlRenderer.execute(script);
  }

  @Override
  public int getMaxZoomLvl() {

    return 19;
  }

  @Override
  public int getMinZoomLvl() {

    return 3;
  }

  @Override
  public double getDistance(
      double[] objectPoint,
      double[] objectPoint2) {

    String script = "calcDistance(" + objectPoint[0] + "," + objectPoint[1] + "," + objectPoint2[0] + ","
        + objectPoint2[1] + ")";
    double distance = (double) htmlRenderer.executeAndReturn(script);
    return distance;
  }

  @Override
  public void setRoute(
      double[] objectPoint,
      double[] objectPoint2) {

  }

  @Override
  public Vector<?> getRoutePoints(
      double[] objectPoint,
      double[] objectPoint2) {

    return null;
  }

  @Override
  public Vector<double[]> getFahrtgebiet() {
    return null;
  }

  @Override
  public double[] getFahrtgebietPoint() {
    return null;
  }
}

Thanks a lot for your time and help!


Solution

  • here's some working example of the open layers driven Vector Map. Enter your API key and go for it...

    <html lang="en">
    <head>
        <title>PTV Vector Map OpenLayers Tutorial</title>
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/ol@v7.2.2/ol.css">
        <link rel="icon" href="../../favicon.ico" />
        <style>
            body { margin:5px; padding:5px; }
            #map { width:100%; height:100%; }
        </style>
    </head>
    <body>
    <div id="map"></div>
    <script type="text/javascript" src="https://unpkg.com/ol@7.2.2/dist/ol.js"></script>
    <script type="text/javascript" src="https://unpkg.com/ol-mapbox-style@10.5.0/dist/olms.js"></script>
    
    <script type="text/javascript">
        const apiKey = '';
        const map = new ol.Map({
          target: 'map',
          view: new ol.View({
            center: ol.proj.fromLonLat([8.4, 49]),
            zoom: 13
          })
        });
         
        olms.apply(map, `https://vectormaps-resources.myptv.com/styles/latest/standard.json`, {
          transformRequest(url, type) {
            if (type === 'Tiles') {
              return new Request(
                url + "?apiKey=" + apiKey
              );
            }
          }
        }).then((map) => {
          // you will get ol.Map instance here
        });
    
    </script>
    </body>
    </html>