4

getBBox()メソッドを使用してバウンディングボックスを取得することにより、テキストの幅と高さに応じてSVGテキスト要素を配置しようとしています。

テキストがウェブセーフフォントを使用している場合、これはさまざまなブラウザで適切に機能しますが、テキストが@ font-faceとカスタムウェブフォントを使用してスタイル設定されている場合、Firefox(Mac)とSafari( iOS)。Safari(Mac)とChrome(Mac)の両方で完全に機能します。

灰色のボックスの幅がテキストと同じである場合、そのブラウザで機能します。

すべてのブラウザでテキストバウンディングボックスの正しい幅を取得する方法について誰かが考えていますか?

4

2 に答える 2

3

ブラウザーは、ロード/適用が完了する前にバウンディング ボックスを計算して@font-faceいます。IE が必要ないと仮定すると、プロミス内に BBox 計算関数をラップできますdocument.fonts.ready...

document.fonts.ready.then(() => const bbox = textEl.getBBox());

問題と修正を示す実際の例を次に示します。

const xmlns = "http://www.w3.org/2000/svg";
const correct = document.getElementById("correct");
const incorrect = document.getElementById("incorrect");

visualizeBBox(incorrect);
document.fonts.ready.then(()=> visualizeBBox(correct));


function visualizeBBox(el){
  const bbox = el.getBBox();
  const rect = document.createElementNS(xmlns, "rect");
  for (prop in bbox) rect.setAttribute(prop, bbox[prop]);
  document.querySelector("svg").appendChild(rect);
}
svg text {
  font-family: 'Diplomata SC', serif;
}

svg rect {
   stroke: red;
   fill: none;
}
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Diplomata+SC&display=swap" rel="stylesheet">

<svg xmlns="https://www.w3.org/2000/svg" width="600" height="400">
  <text x="0" y="40" font-size="24" id="correct">Correct dimensions</text>
  <text y="100" font-size="24" id="incorrect">Incorrect dimensions</text>
<svg>

于 2012-09-20T15:54:37.350 に答える
1

今日、私は同様の問題に遭遇しました。外部フォントがまだロードされておらず、代わりに標準フォントが使用されているため、getBBox() が予期しない一時的なメトリックを返す可能性があるという Duopixel は正しいです。

WebKit の問題 (Chrome 24.0.1312.52 および 26.0.1389.0 canary でテスト済み) は、ページのどこかで最初に効果的に使用されるまで、ブラウザーが外部フォントの読み込みを延期することです。したがって、onreadystatechange が「完了」するのを待っても、getBBox() を呼び出すときにフォント メトリックが準備できているとは限りません。外部フォントでスタイル設定されたテキストをレンダリングし、それをドキュメントに挿入してすぐにその上で getBBox() (私の場合)。

mySVGInitCode() を直接呼び出す代わりに、私の回避策は次のとおりです。

$("body").append(
  $("<div/>")
    .attr("class", "force-external-font-loading")
    .attr("style", "font-family: \"xkcd\";visibility:hidden;position:absolute")
    .text("x")
  );
setTimeout(function(){ mySVGInitCode() }, 100); // 100ms is just arbitrary waiting time which should be sufficient for fetching the external font on a fast network, anyone has a better solution?

ご覧のとおり、絶対位置にスタイル設定されたテキストを動的に挿入して、外部フォントの読み込みを強制しています (ここでは、display:none ではなく、visibility:hidden が重要です)。次に、何かをレンダリングする可能性のある SVG コードを実行する前にしばらく待ってから、すぐにメトリックを要求します。

于 2013-01-22T02:27:08.353 に答える