Exploring font metrics for NSAttributedString using JavaScript in Automation

In macOS Sierra JavaScript for Automation, we can use the following code snippet to retrieve metrics for a specific string in the default Helvetica 12 font:

// helvetica12Width :: String -> Num
function helvetica12Width(str) {
    return $.NSAttributedString.alloc.init.initWithString(
            str
        )
        .size.width;
}

However, I have been struggling to pass in attributes for different fonts and sizes to obtain corresponding metrics. Has anyone found a solution using JXA or AppleScript?

Update: I have attempted an approach, but it does not seem to produce the desired results as changes in font size/name do not affect the output:

(() => {
    'use strict';

    ObjC.import('AppKit');

    return $.NSAttributedString.alloc.init.initWithStringAttributes(
            "Substantiation", {
                'NSFontAttributeName': $.NSFont.fontWithNameSize('Helvetica', 24)
            }
        )
        .size.width
})();

Answer №1

Here's the code snippet that appears to solve the problem:

(function () {
    'use strict';

    ObjC.import('AppKit');

    // display :: a -> String
    const display = x => JSON.stringify(x, null, 2);

    // textDimensionsInFontAtSize :: String -> String -> Num
    //                               -> {width:Num, height:Num}
    function textDimensionsInFontAtSize(text, fontName, size) {
        return $.NSAttributedString.alloc.init.initWithStringAttributes(
            text, $({
                'NSFont': $.NSFont.fontWithNameSize(fontName, size)
            })
        )
        .size;
    }

    // TEST -------------------------------------------------------------------
    return display([
        textDimensionsInFontAtSize("hello World", "Geneva", 32),
        textDimensionsInFontAtSize("hello World", "Geneva", 64),
        textDimensionsInFontAtSize("hello World", "Helvetica", 64),
    ]);
})();

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Checking the length of user input with JavaScript

To ensure that the user enters at least 4 letters in a text box and show an error if they don't, I need help with the following code. It is partially working but currently allows submission even after showing the error message. I want to prevent subm ...

How to Use Express.js to Stream Assets (JS/CSS/images) from Amazon S3

After successfully launching my Node.js blog on AppFog, I have the idea of utilizing an Amazon S3 bucket to host and stream all my assets such as javascript, stylesheets, and images. I am now wondering how I can configure Express.js to properly serve thes ...

How come this variable isn't recognized as 0 even though the debugger is indicating otherwise?

I am currently working on a React component that receives the total number of reviews as a prop. In cases where the number of reviews is 0, I intend to display an element indicating <div>No reviews yet.</div> If there are reviews available, I ...

What is the best way to modify the inline style width of a table td from pixels to percentage in order to make it

<table> <tr style="height:15pt;"> <td style="width:229pt;border-style:solid;border-width:0pt;padding:3pt 9pt 3pt 0pt;" valign="bottom" bgcolor="#c0c0c0"><p style="font-family:Times New Roman, serif;font-size:10pt;font-style:norm ...

Arranging based on the initial elements of the array

Could I please receive the arrangement ['H','H','A','A'] from the given input ['H','A','H','A'] Is there a way to organize it according to the first occurrence of each charact ...

What is the best way to fix multiple dropdown menus opening simultaneously in Vue.js?

I am working on an application that generates todo lists for tasks. These lists can be edited and deleted. I am trying to implement a dropdown menu in each list to provide options for updating or deleting the list individually. However, when I click on the ...

Manipulate Browser Navigation Behavior using JavaScript or AngularJS

How to Manage Browser Back Button Behavior Using AngularJS or JavaScript This is not a question, but rather a demonstration of how you can disable and manipulate the behavior of the browser's back button when using AngularJS or plain JavaScript. ...

What is the best way to retrieve data in Server Components?

In my current process of handling fetch, I am following the guidelines outlined in the document below: https://nextjs.org/docs/app/building-your-application/data-fetching/fetching-caching-and-revalidating#fetching-data-on-the-server-with-fetch async functi ...

Personalizing buttons on a carousel in React-bootstrap

I am facing an issue with my carousel and buttons placement. The buttons need to be outside of the carousel, but I'm unsure how to connect them effectively. React-Bootstrap's activeIndex option was suggested, but since my carousel is not cyclic l ...

The JSON file containing API data is stored within the _next folder, making it easily accessible to anyone without the need for security measures or a login in the Next

When accessing the protected user Listing page, we utilize SSR to call the api and retrieve all user records which are then rendered. However, if one were to check the Network tab in Chrome or Firefox, a JSON file containing all user data is generated and ...

Attempting to iterate over an array of objects is resulting in a TypeError: null is not an object when evaluating 'daysData.map'

Hi everyone, I hope you're all well. I've been searching for a specific solution to an issue I'm facing in ReactJS. I'm trying to map over an array that I fetch from my local system, but I keep encountering this error in the console: Ty ...

Adding jQuery namespace to AngularJS

I'm facing a bit of an issue here. I've implemented RequireJS to manage my modules and dependencies. To prevent cluttering the global namespace, I've set up the following configuration to avoid declaring $ or jQuery globally: require.confi ...

Issue: { error: 'Unrecognized interaction', error code: 10062} in discord.js version 14

Every command runs perfectly fine except for /rank, which triggers the "Unknown interaction" error. This only happens when there are no issues with error handling, such as providing a valid user id and rank id. When there are problems, it works fine. I pr ...

What is the best approach to decipher an obfuscated JavaScript file?

While browsing a site, I came across a javascript file that appears like this: eval(function(p,a,c,k,e,d){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,Str ...

The email validation UI dialog is failing to display any dialog

<html> <head> <link rel="stylesheet" href="//code.jquery.com/ui/1.11.1/themes/smoothness/jquery-ui.css"> <script src="//code.jquery.com/jquery-1.10.2.js"></script> <script src="//code.jquery.com/ui/1.11.1/jquery-ui.js"& ...

Uploading a Node.js Package to GitHub Packages - Issue ENEEDAUTH

Hello everyone, I am currently attempting to deploy my NPM package to GitHub packages using the following yaml configuration: # This workflow will run tests using node and then publish a package to GitHub Packages when a release is created # For m ...

Cannot find WoopraTracker within the custom event data

I am currently working on implementing Woopra custom event data upon page load by following their guidelines. I have attempted to push events when the page is ready, however, it keeps returning an error that woopratracker is not defined. Strangely, when ...

Inserting additional entries into a pre-established data table

Here is a code snippet that creates a new table: var html = '<table>'; $.each( results.d, function( index, record ) { html += '<tr><td>' + record.ClientCode + '</td></tr>'; }); html += ' ...

Having trouble with the click button flip function? It seems to be working in one section but not in

Currently, I am facing an issue with a card section that contains two buttons and a description. The first button adds an image which is working perfectly fine, as well as the description section. On the other hand, the second button adds a video and when ...

Looking for a demonstration using dust.js or handlebars.js in a two-page format with express3.x and node?

Currently, I am in the process of selecting a templating engine to use. While I have come across numerous single-page examples utilizing template engines, I am specifically searching for a practical example that demonstrates handling two distinct pages whi ...