How to work with fonts using our APIs: known issues and clarifications

Bluescape has a few inconsistencies with text fontSize that require clarification to help developers understand how Bluescape deals with fonts and fontSize.

1. Font Point and Pixel units

In our UI the font size is displayed as font POINT size, and the API uses fontSize in Pixels.

For example, when in the web client UI and selecting text, it shows 12 point.

However, when using an API to query the fontSize of the text element, it returns fontSize = 16 in pixels

{
    "data": {
        "elements": [
            {
                "__typename": "Text",
                "id": "652fe5d61230370e47f723bc",
                "traits": null,
                "pinned": false,
                "transform": {
                    "scaleX": 1,
                    "scaleY": 1,
                    "x": -195.53751,
                    "y": -207.554938
                },
                "text": "My Text",
                "style": {
                    "textTransform": "none",
                    "fontSize": 16,
                    "fontFamily": "Source Sans Pro",
                    "verticalAlign": "top",
                    "width": 58.53751,
                    "height": 20
                },
                "blocks": [
                    {
                        "align": "left",
                        "content": [
                            {
                                "text": "My Text"
                            }
                        ]
                    }
                ]
            }
        ]
    }
}

2. Known Issue: fontSize can be returned as Float

The graphQL schema shows element query text fontSize should return fontSize pixels as INT, but it can sometimes return a FLOAT. Additionally, fontSize for element mutation input requires INT only. If a float is used as the input, an error is returned.

The issue with float is due to Point to Pixel conversion.

For example:
6 pixel is 6 * (72/96) = 4.5 point
7 pixel is 7 * (72/96) = 5.25 point

Or point to pixels:
5pt * (96/72) = 6.66667px

Expected result:

  • fontSize should never be a FLOAT. It is defined by graphQL schema as INT

Actual result:

  • fontSize can return as a FLOAT rather than an INT under certain scenarios

Workaround: When using fontSize from a query response in an element input, round the output fontSize to ensure you do not pass a float as the mutation fontSize input.

3. Global text style fontSize vs span fontSize

We have a fontSize that is used for the entire text element which is found in style.fontSize, but we can also have fontSize in a text block as span.fontSize. If there is ever a span.fontSize, it is used. If there isn’t a span.fontSize, the style.fontSize is used.

For Example

We have one line of text, “My Text” at 112 point font size:

When we query this text element, we can see both style.fontSize:16 and span.fontSize:149.3333 (note the known issue of Float returned as fontSize). You would use the span.fontSize rather than the style.fontSize, due to span.fontSize always being given priority over style.fontSize.

{
                "type": "Text",
                "id": "65255aad8906e1844913b42c",
                "transform": {
                    "x": 153.76057433936785,
                    "y": -2425,
                    "scaleX": 1,
                    "scaleY": 1,
                    "rotateZ": 0
                },
                "text": "My Text",
                "style": {
                    "textTransform": "none",
                    "fontSize": 16,
                    "fontFamily": "Source Sans Pro",
                    "verticalAlign": "top",
                    "width": 608,
                    "height": 188
                },
                "myTextBlock": [
                    {
                        "align": "left",
                        "content": [
                            {
                                "span": {
                                    "fontSize": 149.3333,
                                    "content": [
                                        {
                                            "text": "My Text"
                                        }
                                    ]
                                }
                            }
                        ]
                    }
                ]
            }

4. Scaling text does not change API fontSize pixels

It is possible to scale text elements in both the workspace UI and API. If a user is in the webUI and scales the text by dragging the corner of the element, the font point size also increases in the webUI.

WebUI shows 21 point without scale, width = 97 and height = 37:

API query returns fontSize pixels as fontSize:28 and both scaleX:1 and scaleY:1

{
    "data": {
        "elements": [
            {
                "__typename": "Text",
                "id": "652ff386f0060266cfbb8cc0",
                "transform": {
                    "scaleX": 1,
                    "scaleY": 1,
                    "x": -735,
                    "y": -2098.909905
                },
                "boundingBox": {
                    "width": 97,
                    "height": 35,
                    "x": -735,
                    "y": -2098.909905
                },
                "text": "My Text",
                "style": {
                    "textTransform": "none",
                    "fontSize": 28,
                    "fontFamily": "Source Sans Pro",
                    "verticalAlign": "top",
                    "width": 97,
                    "height": 35
                },
                "blocks": [
                    {
                        "align": "left",
                        "content": [
                            {
                                "text": "My Text"
                            }
                        ]
                    }
                ]
            }
        ]
    }
}

After scaling up the text from 21pt in the web UI to 113pt:

Note: The text API query returns original fontSize, width/height. You can calculate the fontSize px by multiplying fontSize by scaleX/scaleY. To get the size of the text element on screen use the boundingBox object.

{
    "data": {
        "elements": [
            {
                "__typename": "Text",
                "id": "652ff386f0060266cfbb8cc0",
                "transform": {
                    "scaleX": 5.360824742268041,
                    "scaleY": 5.360824742857143,
                    "x": -735,
                    "y": -2098.909905
                },
                "boundingBox": {
                    "width": 520,
                    "height": 187.62886600000002,
                    "x": -735,
                    "y": -2098.909905
                },
                "text": "My Text",
                "style": {
                    "textTransform": "none",
                    "fontSize": 28,
                    "fontFamily": "Source Sans Pro",
                    "verticalAlign": "top",
                    "width": 97,
                    "height": 35
                },
                "blocks": [
                    {
                        "align": "left",
                        "content": [
                            {
                                "text": "My Text"
                            }
                        ]
                    }
                ]
            }
        ]
    }
}

For Example: You can use the query output to recreate scaled text with the following createText mutation:

mutation createTextScaledText($ws: String! $textInput:CreateTextInput!) {
    createText(
        workspaceId: $ws
        input:$textInput
    ){
        id
        text
        transform {x, y}
        boundingBox{x, y, width, height}
    }
}

Variables with query output from above:

{
    "ws": "{{workspaceID}}",
    "textInput": {
        "transform": {
            "scaleX": 5.360824742268041,
            "scaleY": 5.360824742857143,
            "x": -135,
            "y": -2098.909905
        },
        "style": {
            "textTransform": "none",
            "fontSize": 28,
            "fontFamily": "Source Sans Pro",
            "verticalAlign": "top",
            "width": 97,
            "height": 35
        },
        "blocks": [{
            "block":{
                "align": "left",
                "content": [
                {
                    "text": "My Text"
                }]
            }
        }]
    }
}

Known Issue: There are some edge cases where using the query output params when creating a new text can have point size in the webUI off by 1pt due to math rounding.