代码之家  ›  专栏  ›  技术社区  ›  Eric G

如何将svg文本元素垂直居中?

  •  0
  • Eric G  · 技术社区  · 1 年前

    在下面的代码中,我能够确定 yOffset 通过反复试验得出的价值。

    我更喜欢计算值,这样文本就会垂直居中。

    我该怎么做?

    文件 SVG Text 元素说:

    文本基线起点的y坐标,或y 如果提供了值列表,则每个单独字形的坐标。 值类型:列表(|);默认值:0; 可动画化:是

    因此,我需要能够确定解决这个问题的基线是什么。我该怎么做?

    function measureSVGText(text, fontSize, fontFamily) {
      // Create an offscreen SVG element
      const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
      
      svg.setAttribute("xmlns", "http://www.w3.org/2000/svg");
      svg.setAttribute("width", "0");
      svg.setAttribute("height", "0");
      svg.style.position = "absolute";
      svg.style.top = "-9999px";
      svg.style.left = "-9999px";
    
      // Create a text element
      const textElement = document.createElementNS(
        "http://www.w3.org/2000/svg",
        "text"
      );
      
      textElement.setAttribute("x", "0");
      textElement.setAttribute("y", "0");
      textElement.style.fontSize = fontSize;
      textElement.style.fontFamily = fontFamily;
      textElement.textContent = text;
    
      // Append the text element to the SVG
      svg.appendChild(textElement);
      document.body.appendChild(svg);
    
      // Get the bounding box of the text element
      const bbox = textElement.getBBox();
      const roundedBBox = svg.createSVGRect();
    
      roundedBBox.width = Math.ceil(bbox.width);
      roundedBBox.height = Math.ceil(bbox.height);
    
      // Remove the SVG element from the DOM
      document.body.removeChild(svg);
    
      return roundedBBox;
    }
    
    function createSVGLabel(text) {
      const padding = 4;
      const fontSize = 10;
      const fontFamily = "Roboto";
      const bbox = measureSVGText(text, `${fontSize}px`, fontFamily);
    
      const svgWidth = bbox.width + padding * 2;
      const svgHeight = bbox.height + padding * 2;
      const yOffset = 13;
      
      const svg =
        '<?xml version="1.0"?>' +
        `<svg width="${svgWidth}" height="${svgHeight}" viewBox="0 0 ${svgWidth} ${svgHeight}" version="1.1" xmlns="http://www.w3.org/2000/svg">` +
        `<rect width="${svgWidth}" height="${svgHeight}" rx="10" ry="10" style="fill:white" />` +
        `<text x="4" y="${yOffset}" font-family="${fontFamily}" font-size="${fontSize}" fill="black">${text}</text>` +
        "</svg>";
    
      return svg;
    }
    
    const label = createSVGLabel("00000");
    
    const parser = new DOMParser();
    const labelDocument = parser.parseFromString(label, "image/svg+xml");
    const labelNode = labelDocument.getElementsByTagName("svg")[0];
    const container = document.getElementById("container");
    
    container.appendChild(labelNode);
    <div id="container" style="width: 200px; height: 200px; background-color: black;">
    </div>
    1 回复  |  直到 1 年前
        1
  •  1
  •   Robert Longson    1 年前

    只需设置主导基线=“中心”

    function measureSVGText(text, fontSize, fontFamily) {
      // Create an offscreen SVG element
      const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
      
      svg.setAttribute("xmlns", "http://www.w3.org/2000/svg");
      svg.setAttribute("width", "0");
      svg.setAttribute("height", "0");
      svg.style.position = "absolute";
      svg.style.top = "-9999px";
      svg.style.left = "-9999px";
    
      // Create a text element
      const textElement = document.createElementNS(
        "http://www.w3.org/2000/svg",
        "text"
      );
      
      textElement.setAttribute("x", "0");
      textElement.setAttribute("y", "0");
      textElement.style.fontSize = fontSize;
      textElement.style.fontFamily = fontFamily;
      textElement.textContent = text;
    
      // Append the text element to the SVG
      svg.appendChild(textElement);
      document.body.appendChild(svg);
    
      // Get the bounding box of the text element
      const bbox = textElement.getBBox();
      const roundedBBox = svg.createSVGRect();
    
      roundedBBox.width = Math.ceil(bbox.width);
      roundedBBox.height = Math.ceil(bbox.height);
    
      // Remove the SVG element from the DOM
      document.body.removeChild(svg);
    
      return roundedBBox;
    }
    
    function createSVGLabel(text) {
      const padding = 4;
      const fontSize = 10;
      const fontFamily = "Roboto";
      const bbox = measureSVGText(text, `${fontSize}px`, fontFamily);
    
      const svgWidth = bbox.width + padding * 2;
      const svgHeight = bbox.height + padding * 2;
      
      const svg =
        '<?xml version="1.0"?>' +
        `<svg width="${svgWidth}" height="${svgHeight}" viewBox="0 0 ${svgWidth} ${svgHeight}" version="1.1" xmlns="http://www.w3.org/2000/svg">` +
        `<rect width="${svgWidth}" height="${svgHeight}" rx="10" ry="10" style="fill:white" />` +
        `<text x="4" y="${svgHeight / 2}" font-family="${fontFamily}" font-size="${fontSize}" fill="black" dominant-baseline="central">${text}</text>` +
        "</svg>";
    
      return svg;
    }
    
    const label = createSVGLabel("00000");
    
    const parser = new DOMParser();
    const labelDocument = parser.parseFromString(label, "image/svg+xml");
    const labelNode = labelDocument.getElementsByTagName("svg")[0];
    const container = document.getElementById("container");
    
    container.appendChild(labelNode);
    <div id="container" style="width: 200px; height: 200px; background-color: black;">
    </div>