Reinier68
Reinier68

Reputation: 3242

How to add a custom label title to <svg> content generated with Javascript?

In my project I got a feature where the user can generate some content in a <textarea>. I take that content and generate individual <text> elements from that content and display it in a <svg> so that the user can preview what they typed. Here is a Codesandbox dispaying my problem.

When the user starts typing, I'd like to add a label only once (for example Recipes) to the preview. When the content in the textarea is cleared, I also would like for the label to be deleted.

How can I make it so that a label or title can be generated once to display above the user generated content?

Code for Reference:

import "./styles.css";
import { useState } from "react";

export default function App() {
  const [dummyText, setDummyText] = useState("");

  const updateContent = (e) => {
    setDummyText(e.target.value);
  };

  function calculateWordWidths() {
    const words = dummyText.split(/\s+/);
    let svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
    let text = document.createElementNS("http://www.w3.org/2000/svg", "text");
    text.style =
      "font: 13pt LiberationSans, Helvetica, Arial, sans-serif; white-space: pre;";
    svg.appendChild(text);
    document.body.appendChild(svg);

    const wordsWithComputedWidth = words.map((word) => {
      text.textContent = word;
      return { word, width: text.getComputedTextLength() };
    });

    text.textContent = "\u00A0"; // Unicode space
    const spaceWidth = text.getComputedTextLength();

    document.body.removeChild(svg);

    return { wordsWithComputedWidth, spaceWidth };
  }

  let { wordsWithComputedWidth, spaceWidth } = calculateWordWidths();

  const content = [[]];
  let xPos = 0;
  let yPos = 60;
  let page = 1;

  let i = 0,
    len = wordsWithComputedWidth.length;

  while (i < len) {
    if (yPos > 97) {
      content.push([]);
      page++;
      xPos = 0;
      yPos = 16;
    }

    //How do I add this label only once and automatically delete it once
    //the content in the text area is also deleted? Now it gets added
    //everytime a new letter is typed
    content[page - 1].push(
      <text
        x="0"
        y="24"
        key="1203"
        style={{
          font: "bold 17pt LiberationSans, Helvetica, Arial, sans-serif",
          whiteSpace: "pre"
        }}
      >
        Recipes
      </text>
    );

    //Push new text elements to the content array
    content[page - 1].push(
      <text
        x={xPos}
        y={yPos}
        key={i}
        style={{
          font: "13pt LiberationSans, Helvetica, Arial, sans-serif",
          whiteSpace: "pre"
        }}
      >
        {wordsWithComputedWidth[i].word}
      </text>
    );
    xPos += wordsWithComputedWidth[i].width + spaceWidth;
    if (xPos > 100) {
      yPos += 16;
      xPos = 0;
    }

    // console.log("xPos: ", xPos);
    // console.log("yPos: ", yPos);
    i++;
  }

  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <div className="container">
        <div className="content">
          <div>Content</div>
          <textarea
            rows="6"
            cols="24"
            onChange={(e) => updateContent(e)}
            style={{ marginTop: "50px" }}
          />
        </div>
        <div className="preview">
          <div>Preview</div>
          <>
            {content.map((resumePage, idx) => (
              <svg
                viewBox="0 0 595.28 100.89"
                xmlns="http://www.w3.org/2000/svg"
                style={{ border: "1px solid #aaa" }}
                key={idx}
              >
                {content[idx]}
              </svg>
            ))}
          </>
        </div>
      </div>
    </div>
  );
}

Upvotes: 1

Views: 311

Answers (1)

Drew Reese
Drew Reese

Reputation: 202836

You could conditionally push it into the array based on the dummyText state being populated.

!!dummyText && content[page - 1].push(
  <text
    x="0"
    y="24"
    key="1203"
    style={{
      font: "bold 17pt LiberationSans, Helvetica, Arial, sans-serif",
      whiteSpace: "pre"
    }}
  >
    Recipes
  </text>
);

Edit how-to-add-a-custom-label-title-to-svg-content-generated-with-javascript

Upvotes: 1

Related Questions