列出来自 Google Fonts API 的所有可变字体?

问题描述 投票:0回答:2

我需要通过 Google Fonts API 获取所有可用可变字体的列表。

我可以从这个端点得到所有的字体名称。您可以添加一些参数,但我认为其中不包括可变字体过滤器: https://www.googleapis.com/webfonts/v1/webfonts?key=API_KEY&sort=popularity

我不认为我可以在进行 API 调用后过滤结果。这里“Open Sans”是一种可变字体,但我在响应中没有看到任何表明这一点的内容。

{
      "family": "Open Sans",
      "variants": [
        "300",
        "regular",
        "500",
        "600",
        "700",
        "800",
        "300italic",
        "italic",
        "500italic",
        "600italic",
        "700italic",
        "800italic"
      ],
      "subsets": [
        "cyrillic",
        "cyrillic-ext",
        "greek",
        "greek-ext",
        "hebrew",
        "latin",
        "latin-ext",
        "vietnamese"
      ],
      "version": "v34",
      "lastModified": "2022-09-22",
      "files": {
        "300": "http://fonts.gstatic.com/s/opensans/v34/memSYaGs126MiZpBA-UvWbX2vVnXBbObj2OVZyOOSr4dVJWUgsiH0C4nY1M2xLER.ttf",
        "regular": "http://fonts.gstatic.com/s/opensans/v34/memSYaGs126MiZpBA-UvWbX2vVnXBbObj2OVZyOOSr4dVJWUgsjZ0C4nY1M2xLER.ttf",
        "500": "http://fonts.gstatic.com/s/opensans/v34/memSYaGs126MiZpBA-UvWbX2vVnXBbObj2OVZyOOSr4dVJWUgsjr0C4nY1M2xLER.ttf",
        "600": "http://fonts.gstatic.com/s/opensans/v34/memSYaGs126MiZpBA-UvWbX2vVnXBbObj2OVZyOOSr4dVJWUgsgH1y4nY1M2xLER.ttf",
        "700": "http://fonts.gstatic.com/s/opensans/v34/memSYaGs126MiZpBA-UvWbX2vVnXBbObj2OVZyOOSr4dVJWUgsg-1y4nY1M2xLER.ttf",
        "800": "http://fonts.gstatic.com/s/opensans/v34/memSYaGs126MiZpBA-UvWbX2vVnXBbObj2OVZyOOSr4dVJWUgshZ1y4nY1M2xLER.ttf",
        "300italic": "http://fonts.gstatic.com/s/opensans/v34/memQYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWq8tWZ0Pw86hd0Rk5hkaVcUwaERZjA.ttf",
        "italic": "http://fonts.gstatic.com/s/opensans/v34/memQYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWq8tWZ0Pw86hd0Rk8ZkaVcUwaERZjA.ttf",
        "500italic": "http://fonts.gstatic.com/s/opensans/v34/memQYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWq8tWZ0Pw86hd0Rk_RkaVcUwaERZjA.ttf",
        "600italic": "http://fonts.gstatic.com/s/opensans/v34/memQYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWq8tWZ0Pw86hd0RkxhjaVcUwaERZjA.ttf",
        "700italic": "http://fonts.gstatic.com/s/opensans/v34/memQYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWq8tWZ0Pw86hd0RkyFjaVcUwaERZjA.ttf",
        "800italic": "http://fonts.gstatic.com/s/opensans/v34/memQYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWq8tWZ0Pw86hd0Rk0ZjaVcUwaERZjA.ttf"
      },
      "category": "sans-serif",
      "kind": "webfonts#webfont"
    },
google-font-api google-fonts
2个回答
1
投票

this网站列出了所有可变字体。在开发者控制台(F12)我看到它正在下载这个文件:

https://fonts.google.com/metadata/fonts

此文件包含所有字体。如果字体的“轴”数组不为空,那么它肯定是可变字体。也许您必须检查其他属性名称(我对可变字体不太熟悉)。


0
投票

开放API:添加能力参数“VF”

如果您使用的是开放式开发者 API,您还需要设置参数

capability=VF
以检索轴数据:

https://www.googleapis.com/webfonts/v1/webfonts?capability=VF&sort=style&key=${apiKey}

其他功能选项:

  • WOFF2
    :返回 woff2 字体文件 URLs
  • CAPABILITY_UNSPECIFIED
    :返回 ttf/truetype 字体文件 URLs

您可以组合这些选项来获取 woff2 可变字体 URL 或 truetype:

https://www.googleapis.com/webfonts/v1/webfonts?capability=VF&capability=WOFF2&sort=style&key=${apiKey}

但是,这不会将列表过滤为仅可变字体。所以你需要手动过滤项目数组。

(async ()=>{
// fetch font JSON
let listObj = await (await fetch(dataAPIStatic)).json();
// filter items with axes properties
let itemsVariable = listObj.items.filter(item => item.axes && item.axes.length);
output.value= JSON.stringify(itemsVariable, null, ' ');
})()

/**
 * static copy of
 * https://www.googleapis.com/webfonts/v1/webfonts?capability=VF&capability=CAPABILITY_UNSPECIFIED&sort=style&key=APIKEY
 */
let dataAPIStatic = "https://cdn.jsdelivr.net/gh/herrstrietzel/fonthelpers@main/json/gfontsAPI.json";


(async() => {
  // fetch font JSON
  let listObj = await (await fetch(dataAPIStatic)).json();
  // filter items with axes properties
  let itemsVariable = listObj.items.filter(item => item.axes && item.axes.length);
  output.value = JSON.stringify(itemsVariable, null, ' ');

})()
textarea {
  width: 100%;
  min-height: 75vh;
}
<textarea id="output"></textarea>

从元 JSON 中检索数据

如果您没有 API 密钥,您也可以从上述元 URL https://fonts.google.com/metadata/fonts.

获取所需的数据

但是您不能通过 javaScript fetch 直接检索数据,因为 URL 不允许跨源访问。

作为解决方法,您可以在本地或 cdn 上托管自己的副本。
显然,这个 JSON 不会自动更新,所以你需要偶尔更新一下文件。

元 JSON 也有一个不同的结构。
例如。轴的最小值和最大值存储如下:

{tag: 'wdth', min: 100.0, max: 200.0, defaultValue: 100.0}

API

{tag: 'wdth', start: 100, end: 200}

所以你需要调整你的过滤脚本。

示例:加载元数据或 API 数据助手

let apiKey = "your APi key";
let dataAPIStatic = "https://cdn.jsdelivr.net/gh/herrstrietzel/fonthelpers@main/json/gfontsAPI.json";
let dataMetaStatic = "https://cdn.jsdelivr.net/gh/herrstrietzel/fonthelpers@main/json/gfontsMeta.json";


// set query options
let options = {
  //apiKey: apiKey,
  format: 'woff2',
  variableFonts: true,
  staticURL: dataAPIStatic
};

// init
(async() => {
  let googleFontList = await getGoogleFontList(options);

  // generate autofill
  populateDatalist(datalistFonts, googleFontList)

  // get URLs
  let googleFontUrls = await getGoogleFontUrls(googleFontList);
  showLinkList(cssUrls, googleFontUrls)


  // filter fonts
  inputFonts.addEventListener('change', async e => {
    let family = e.currentTarget.value;
    let familyQuery = family.replaceAll(' ', '+');
    let item = googleFontList.filter(item => item.family === family);

    // update links
    googleFontUrls = await getGoogleFontUrls(item);
    showLinkList(cssUrls, googleFontUrls)
  });
})();


async function getGoogleFontList(options = {
  format: 'woff2',
  variableFonts: true,
  staticURL: ''
}) {
  let {
    apiKey,
    format,
    variableFonts,
    staticURL
  } = options;

  let capabilities = [];
  if (variableFonts) {
    capabilities.push('capability=VF');
  }
  if (format) {
    let fontFormat = (format === 'ttf' || format === 'truetype') ? 'CAPABILITY_UNSPECIFIED' : 'WOFF2';
    capabilities.push(`capability=${fontFormat}`);
  }

  let capabilityQuery = capabilities.join('&');
  let apiURL = `https://www.googleapis.com/webfonts/v1/webfonts?${capabilityQuery}&sort=style&key=${apiKey}`;

  // switch between API and static src
  let useStatic = !apiKey ? true : false;
  let listUrl = useStatic ? staticURL : apiURL;

  console.log(listUrl);

  // fetch font JSON
  let listObj = await (await fetch(listUrl)).json();
  let itemsVariable = listObj.items.filter(item => item.axes && item.axes.length);
  console.log(itemsVariable);
  console.log(listObj);




  /**
   * normalize meta formating 
   * and API structure
   */
  let listTypeMeta = listObj.familyMetadataList ? true : false;
  let items = listTypeMeta ? listObj.familyMetadataList : listObj.items;

  // filter variable fonts
  if (variableFonts) {
    items = items.filter(item => item.axes && item.axes.length);
  }

  if (listTypeMeta && variableFonts) {
    for (let i = 0; i < items.length; i++) {
      let item = items[i];
      let axes = item.axes;
      for (let a = 0; a < axes.length; a++) {
        let axis = axes[a];
        item.axes[a] = {
          tag: axis.tag,
          start: axis.min,
          end: axis.max,
          defaultValue: axis.defaultValue
        }
      }
    }
  }

  return items;
}



async function getGoogleFontUrls(googleFontList) {
  let urls = [];
  let gfontBase = `https://fonts.googleapis.com/css2?family=`;


  googleFontList.forEach(font => {
    let isVariable = font.axes && font.axes.length ? true : false;
    //console.log(isVariable);
    let family = font.family;
    let familyQuery = family.replaceAll(' ', '+');
    let queryPre = [];

    if (isVariable) {
      let axes = getAxes(font.axes);
      query = getAxesQuery(axes);
      urls.push(`${gfontBase}${familyQuery}:${query}`);

    }
    //static weights 
    else {
      let fonts;

      // normalize API style
      if (!font.fonts) {
        fonts = font.variants.map(weight => {
          return weight === 'regular' ? '400' : weight.replaceAll('italic', 'i')
        });
      } else {
        fonts = Object.keys(font.fonts);
      }

      let styles = [];
      let italics = fonts.map(weight => {
        return weight.includes('i') ? weight : ''
      }).filter(Boolean);
      let weights = fonts.map(weight => {
        return !weight.includes('i') ? weight : ''
      }).filter(Boolean);

      if (italics.length) {
        styles = fonts.map(weight => {
          return weight.includes('i') === false ? `0,${weight.replaceAll('i', '')}` : `1,${weight.replaceAll('i', '')}`
        }).filter(Boolean);
      } else {
        styles = fonts.map(weight => {
          return `${weight}`
        }).filter(Boolean);
      }

      if (italics.length && !queryPre.includes('ital')) {
        queryPre.push('ital')
      }
      if (weights.length && !queryPre.includes('wght')) {
        queryPre.push('wght')
      }

      query = queryPre.join(',') + '@' + styles.join(';')
      urls.push(`${gfontBase}${familyQuery}:${query}`);
    }
  })

  return urls;
}


function getAxes(axes) {
  // sort axes alphabetically
  axes = [axes.filter(item => item.tag.toLowerCase() === item.tag), axes.filter(item => item.tag.toUpperCase() === item.tag)].flat();
  return axes;
}

function getAxesQuery(axes, useStaticMeta) {
  let axesQuery;
  // we need to switch between different formats: google met takes min and max keys
  if (useStaticMeta) {
    axesQuery = axes.map(val => {
      return val.tag
    }).join(',') + '@' + axes.map(val => {
      return val.min + '..' + val.max
    }).join(',');
  } else {
    axesQuery = axes.map(val => {
      return val.tag
    }).join(',') + '@' + axes.map(val => {
      return val.start + '..' + val.end
    }).join(',');
  }
  return axesQuery;
}


function showLinkList(target, urls) {
  target.innerHTML = '';
  let urlList = '';
  urls.forEach(url => {
    urlList += `<li class="liUrl"><a href="${url}">${url}</li>`;
  })
  target.insertAdjacentHTML('beforeend', urlList)
}


function populateDatalist(target, list) {
  let fonts = list;
  let datalistOptions = '';
  fonts.forEach(font => {
    let option = document.createElement('option');
    //only VF
    if (font.axes) {
      datalistOptions += `<option >${font.family}</option>`;
    }
  });
  target.insertAdjacentHTML('beforeend', datalistOptions);
}
textarea {
  width: 100%;
  min-height: 20em;
}
<h1>Get variable font CSS URLS</h1>

<p><input type="text" list="datalistFonts" id="inputFonts" placeholder="Search google font"></p>
<datalist id="datalistFonts">
    </datalist>

<h3>CSS Urls</h3>
<ol id="cssUrls">
</ol>

© www.soinside.com 2019 - 2024. All rights reserved.