3
votes

I'm working on implementing better text sizing and believe with interpolation I maybe able to update my current text labeling to a much more efficient format. Currently we are creating "static text", essentially we get the ideal text-size for a particular zoom level, then scale it at each zoom level using stops like so:


'text-size': {
    "stops": [
        [10, 0],
        [11, ((Math.pow(2, 11 - map.getZoom()) * uniqueFonts[i]))],
        [12, ((Math.pow(2, 12 - map.getZoom()) * uniqueFonts[i]))],
        [13, ((Math.pow(2, 13 - map.getZoom()) * uniqueFonts[i]))],
        [14, ((Math.pow(2, 14 - map.getZoom()) * uniqueFonts[i]))],
        [15, ((Math.pow(2, 15 - map.getZoom()) * uniqueFonts[i]))],
        [16, ((Math.pow(2, 16 - map.getZoom()) * uniqueFonts[i]))],
        [17, ((Math.pow(2, 17 - map.getZoom()) * uniqueFonts[i]))],
        [18, ((Math.pow(2, 18 - map.getZoom()) * uniqueFonts[i]))],
        [19, ((Math.pow(2, 19 - map.getZoom()) * uniqueFonts[i]))],
        [20, ((Math.pow(2, 20 - map.getZoom()) * uniqueFonts[i]))],
        [21, ((Math.pow(2, 21 - map.getZoom()) * uniqueFonts[i]))],
        [22, ((Math.pow(2, 22 - map.getZoom()) * uniqueFonts[i]))],
        [23, ((Math.pow(2, 23 - map.getZoom()) * uniqueFonts[i]))],
        [24, ((Math.pow(2, 24 - map.getZoom()) * uniqueFonts[i]))],
        [25, ((Math.pow(2, 25 - map.getZoom()) * uniqueFonts[i]))],
        [26, ((Math.pow(2, 26 - map.getZoom()) * uniqueFonts[i]))],
        [27, ((Math.pow(2, 27 - map.getZoom()) * uniqueFonts[i]))],
        [28, ((Math.pow(2, 28 - map.getZoom()) * uniqueFonts[i]))],
        [29, ((Math.pow(2, 29 - map.getZoom()) * uniqueFonts[i]))],
        [30, ((Math.pow(2, 30 - map.getZoom()) * uniqueFonts[i]))]
    ]
}

Now this works great, we get text that remains the same size even as we zoom. We have polygons we want to limit our text within and this allows us to keep the text sized with the polygon itself. Thus zooming the text scales with the polygon.

The downside to this method is we need a label layer for every uniquefont size. As you can't reference the features specific font with "{textSize}" or ["get", "textsize"] within a stop we had to adapt. But with the interpolation code that's been added since our initial implementation of our labels it seems that this may now be possible.

Doing the following with interpolation enabled works to an extent. But it does not seem to work for all zoom levels. It seems to work as expect at zooms 15+, but anything before scales oddly. Below is code utilizing the interpolate methodology:


'text-size': [
    "interpolate", ["linear"], ["zoom"],
    10, 0,
    11, [ "*", [ "^", [ "-", 11, map.getZoom()], 2], ["get", "textsize"]],
    12, [ "*", [ "^", [ "-", 12, map.getZoom()], 2], ["get", "textsize"]],
    13, [ "*", [ "^", [ "-", 13, map.getZoom()], 2], ["get", "textsize"]],
    14, [ "*", [ "^", [ "-", 14, map.getZoom()], 2], ["get", "textsize"]],
    15, [ "*", [ "^", [ "-", 15, map.getZoom()], 2], ["get", "textsize"]],
    16, [ "*", [ "^", [ "-", 16, map.getZoom()], 2], ["get", "textsize"]],
    17, [ "*", [ "^", [ "-", 17, map.getZoom()], 2], ["get", "textsize"]],
    18, [ "*", [ "^", [ "-", 18, map.getZoom()], 2], ["get", "textsize"]],
    19, [ "*", [ "^", [ "-", 19, map.getZoom()], 2], ["get", "textsize"]],
    20, [ "*", [ "^", [ "-", 20, map.getZoom()], 2], ["get", "textsize"]],
    21, [ "*", [ "^", [ "-", 21, map.getZoom()], 2], ["get", "textsize"]],
    22, [ "*", [ "^", [ "-", 22, map.getZoom()], 2], ["get", "textsize"]],
    23, [ "*", [ "^", [ "-", 23, map.getZoom()], 2], ["get", "textsize"]],
    24, [ "*", [ "^", [ "-", 24, map.getZoom()], 2], ["get", "textsize"]],
    25, [ "*", [ "^", [ "-", 25, map.getZoom()], 2], ["get", "textsize"]],
    26, [ "*", [ "^", [ "-", 26, map.getZoom()], 2], ["get", "textsize"]],
    27, [ "*", [ "^", [ "-", 27, map.getZoom()], 2], ["get", "textsize"]],
    28, [ "*", [ "^", [ "-", 28, map.getZoom()], 2], ["get", "textsize"]],
    29, [ "*", [ "^", [ "-", 29, map.getZoom()], 2], ["get", "textsize"]],
    30, [ "*", [ "^", [ "-", 30, map.getZoom()], 2], ["get", "textsize"]],
]

As this interpolate does not work as expected, I'm curious if i'm doing anything particularly wrong? Is there a way to mimic the above stop behavior while using data-driven styles on text-size? If so how can it be done?

2

2 Answers

3
votes

So I figured this out already. I was using ['linear'] when I should use ['exponential', 2]. I also needed to start at 1,0, with the next value being Math.ceil(map.getZoom()) + 1. So for my map.getZoom() coming back as ~13.5, it looks like the following:

'text-size': [
        "interpolate", ["exponential", 2], ["zoom"],
        1, 0,
        15, [ "*", [ "^", [ "-", 15, map.getZoom()], 2], ["get", "font"]],
        16, [ "*", [ "^", [ "-", 16, map.getZoom()], 2], ["get", "font"]],
        17, [ "*", [ "^", [ "-", 17, map.getZoom()], 2], ["get", "font"]],
        18, [ "*", [ "^", [ "-", 18, map.getZoom()], 2], ["get", "font"]],
        19, [ "*", [ "^", [ "-", 19, map.getZoom()], 2], ["get", "font"]],
        20, [ "*", [ "^", [ "-", 20, map.getZoom()], 2], ["get", "font"]],
        21, [ "*", [ "^", [ "-", 21, map.getZoom()], 2], ["get", "font"]],
        22, [ "*", [ "^", [ "-", 22, map.getZoom()], 2], ["get", "font"]],
        23, [ "*", [ "^", [ "-", 23, map.getZoom()], 2], ["get", "font"]],
        24, [ "*", [ "^", [ "-", 24, map.getZoom()], 2], ["get", "font"]],
        25, [ "*", [ "^", [ "-", 25, map.getZoom()], 2], ["get", "font"]],
        26, [ "*", [ "^", [ "-", 26, map.getZoom()], 2], ["get", "font"]],
        27, [ "*", [ "^", [ "-", 27, map.getZoom()], 2], ["get", "font"]],
        28, [ "*", [ "^", [ "-", 28, map.getZoom()], 2], ["get", "font"]],
        29, [ "*", [ "^", [ "-", 29, map.getZoom()], 2], ["get", "font"]],
        30, [ "*", [ "^", [ "-", 30, map.getZoom()], 2], ["get", "font"]],
]
2
votes

Just to add to @Stooky answer. This works really well when your zooming in. But not so well when your zooming out. I wanted the text to keep a relative size to the zoom. Like when your zooming in and out of AutoCAD. I had to pick an optimum zoom level and font size for that zoom. Then I worked down and up from that. My optimum zoom level for this was 17. I changed a couple other things also.

'text-size':[
    'interpolate', ['linear'], ['zoom'],
    14, 1,
    15, 2,
    16, 4,
    16.5, 8,
    17, 14,
    18, 16,
    18.5, [ "*", [ "^", [ "-", 18.5, map.getZoom()], 1.5], 14],
    19, [ "*", [ "^", [ "-", 19, map.getZoom()], 1.5], 14],
    20, [ "*", [ "^", [ "-", 20, map.getZoom()], 1.5], 14],
    21, [ "*", [ "^", [ "-", 21, map.getZoom()], 1.5], 14],
    30,24
]

It would be nice if there was a way to generate this list using code but not sure what the algorithm would be.

Maybe a function like this...

'text-size': ZoomBasedTextSizes([optimum-font-size], [optimum-zoom-level]);