LuciadRIA supports display scaling. Display scaling is a feature available in most modern operating systems and graphics cards, allowing users to adjust the size of text, apps, and other items on the screen. It lets you change the balance between readability and screen real estate — the amount of space available for displaying information.

Modern devices have high-resolution (HiDPI) displays which can pack pixels much closer together than older screens. With that higher screen density, images become sharper and text becomes crisper. Without adjustments though, all the elements on the screen — such as menus, icons, and text — appear smaller, which can make them harder to see and interact with.

4k 100 percent display scaling
Figure 1. A screenshot of a 4K HiDPI display with display scaling at 100%, which means there is no scaling. Text and icons are barely readable.

That’s where display scaling comes in: it scales up these elements, making them bigger and easier to see, without sacrificing the overall screen resolution.

4k 300 percent display scaling
Figure 2. A screenshot of a 4K HiDPI display scale with 300% display scaling. Text and icons are easy to read.
If you run a LuciadRIA version older than 2024.1 on monitors with high display scale settings, it will show a blurrier map.

Working with display scaling in LuciadRIA

Setting a fixed map display scale

You can set the display scale of a Map using Map.displayScale. Typical values for this display scale range from 1, for a 100% display scale, to 4, for a 400% display scale.

Display scaling is supported on WebGLMap only. On a non-WebGL Map, Map.displayScale is always 1.

The browser reports the operating system’s display scale through window.devicePixelRatio. You can pass these values directly to Map.displayScale.

Creation of a WebGLMap with a fixed display scale that matches the operating system’s display scale.
const map = new WebGLMap("map", {
  displayScale: window.devicePixelRatio
});

Note that this code sets the display scale once: at map creation time, it fixes the display scale to the one reported by the browser. That’s fine until the user drags the browser window to a monitor with a different display scale, or zooms the webpage, which also changes the browser’s display scale (window.devicePixelRatio). The display scale won’t adjust automatically to the change of monitor or page zoom level.

Automatically adjusting the map display scale

To allow the map to adjust the display scale automatically, enable autoAdjustDisplayScaling on your WebGLMap. This lets LuciadRIA track changes to window.devicePixelRatio. When it changes, Map.displayScale is automatically updated.

Creation of a WebGLMap with automatic display scale adjustment.
const map = new WebGLMap("map", {
  autoAdjustDisplayScale: true
});

map.on("DisplayScaleChanged", () => {
  // With autoAdjustDisplayScale, map.displayScale always matches window.devicePixelRatio
  console.log(`Map display scale is now: ${map.displayScale}`);
})

Understanding CSS pixels and physical pixels

In the context of display scaling, you can make a distinction between CSS pixels and physical pixels. A CSS pixel is defined as a single pixel on a 96 DPI display. A physical pixel is a single pixel on the device’s physical display. With a display scale of 100%, a single CSS pixel corresponds to a single physical pixel. On higher display scales, a single CSS pixel corresponds to multiple physical pixels. For example, with a display scaling of 200%, 1 CSS pixel amounts to 4 physical pixels. With 400% scaling, this number grows to 16 physical pixels.

CSS pixels are independent of display scale. This means that an image with a CSS width of 32px is always about the same width as a text character with a CSS size of 32px, even when the display scale is set to 400%, resulting in the use of 16 times the amount of physical pixels.

In the LuciadRIA API, everything is expressed in CSS pixels. For example, the Map.viewSize, LineStyle.width, IconStyle.width, IconStyle.height, and view coordinates (GestureEvent.viewPoint) are all expressed in CSS pixels. This corresponds to the coordinate system in use by the browser, for example for mouse coordinates. You typically don’t have to convert to or from physical pixel coordinates when working with scaled maps.

Drawing high-resolution icons

On maps with high display scale values, it’s best to render icons with a higher-resolution image. If you don’t do so, the icon might be blurry because a low-resolution image is rendered on more physical pixels. To render icons with a higher-resolution image, specify a higher-resolution image in the IconStyle.image:

Drawing high resolution icons based on display scale.
class HiResIconPainter extends FeaturePainter {

  paintBody(geoCanvas: GeoCanvas, feature: Feature, shape: Shape, layer: Layer, map: Map, paintState: PaintState) {

    geoCanvas.drawIcon(shape, {
      // generate a high-resolution icon image using the IconFactory in @luciad/ria-toolbox-core
      image: createStar({
        stroke: "black",
        fill: "yellow",
        width: 32 * map.displayScale,
        height: 32 * map.displayScale,
        strokeWidth: 2 * map.displayScale,
      }),
      // IconStyle.width and height are expressed in CSS pixels.
      // ie. they're always the same size on screen, regardless of display scale.
      width: "32px",
      height: "32px"
    });

  }

}
low-resolution icons
Figure 3. Low-resolution icons without map display scaling
high-resolution icons
Figure 4. High-resolution icons with map display scaling

If you’re using a UrlIconStyle, you can provide a URL to a different, higher-resolution icon image.

Drawing high resolution icons based on display scale, using UrlIconStyle.
class HiResUrlIconPainter extends FeaturePainter {

  paintBody(geoCanvas: GeoCanvas, feature: Feature, shape: Shape, layer: Layer, map: Map, paintState: PaintState) {

    geoCanvas.drawIcon(shape, {
      // provide a URL to a high-resolution icon image
      url: map.displayScale >= 2 ? "/images/star@2x.png" : "/images/star.png",
      // IconStyle.width and height are expressed in CSS pixels.
      // ie. they're always the same size on screen, regardless of display scale.
      width: "32px",
      height: "32px"
    });

  }

}

LuciadRIA invalidates the FeaturePainter automatically whenever Map.displayScale changes, so you don’t have to do anything else to draw icons with a higher resolution.

Drawing high-resolution raster tile sets

LuciadRIA will draw the same raster tiles as on a classic 96 DPI screen regardless of display scale for two reasons:

  • Compatibility: Text, icons and line widths will remain the same size on screen

  • Performance: Loading the same amount of raster tiles results in the same performance as before

To configure the RasterTileSetLayer to load higher or lower resolution tiles, you can configure the RasterTileSetLayer.detailFactor. The default value is 1 and if you increase it, the raster layer loads more detailed tiles at the cost of performance. Decreasing it, loads less detailed tiles, which improves performance. To display pixel-perfect tiles, make sure the RasterTileSetLayer.detailFactor is equal to Map.displayScale.

If you get a RasterTileSetModel that contains text — city or street labels, for example — from a tile service, it’s recommended to request a scaled version of the tile imagery. Otherwise, the text in the raster data will be too small. Most raster imagery providers expose API to control this scaling. For example, HERE Maps has a ppi URL parameter in their API. To use it, it should be applied to the HEREMapsTileSetModel as is done in the HereMapsDataLoader, which can be found in LuciadRIA’s toolbox. A similar URL parameter is applied to the GoogleTileSetModel and BingMapsTileSetModel in the toolbox. If you are using any other raster tileset with text in it, check with the imagery provider whether they support scaled tile images for high-density displays.

tile at 72 PPI
Figure 5. A labeled HERE Maps tile at 72 PPI (pixels per inch)
tile at 320 PPI
Figure 6. A labeled HERE Maps tile at 320 PPI (pixels per inch)

Performance considerations

Display scaling affects performance. With a display scale of 200%, LuciadRIA uses 4 times as many physical pixels to render the map. With a display scale of 400%, this goes up to 16 times the amount of physical pixels. If you enable display scaling on devices with a high display scale and a relatively low-powered GPU, such as mobile devices, the device performance will be strongly impacted. The map is rendered at a higher quality at the cost of performance.

As the pixel resolution of the map increases, the impact of map effects that scale with pixel resolution becomes stronger. Examples include MapEffects.antiAliasing and MapEffects.eyeDomeLighting.