9

I am using svg.js as well as svgdom on a node / express server to try to manage to manipulate an svg and then later turning it into a PNG to build a PDF out of.

Currently, I've made it this far

const window = require('svgdom');
const SVG = require('svg.js')(window);
const document = window.document;
const draw = SVG(document.documentElement);
const fs = require('fs');
const tag = fs.readFileSync(`images/name-tag-1-with-name.svg`,'utf8');
const svg = draw.svg(tag);

Here is the layout of the SVG

<svg id="name-tag" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 216 288">
  <defs>
    <style>
      .cls-1,
      .cls-2 {
        fill: #414042;
      }

      .cls-2 {
        opacity: 0.95;
      }

      .cls-3,
      .first-name,
      .last-name {
        fill: #fff;
      }

      .cls-4 {
        fill: none;
        stroke: #fff;
        stroke-miterlimit: 10;
      }

      .first-name,
      .last-name {
        font-size: 30.87px;
        font-family: Gibson-SemiBold, Gibson;
        font-weight: 700;
      }

      .cls-6 {
        letter-spacing: -0.01em;
      }

      .last-name {
        letter-spacing: -0.01em;
      }

      .cls-8 {
        letter-spacing: 0em;
      }
    </style>
  </defs>
  <polygon class="cls-1" points="0 0 0 288 216 0 0 0" />
  <polygon class="cls-2" points="0 288 216 288 216 0 0 288" />
  <polygon class="cls-3" points="119.35 66.27 109.12 17.38 98.95 66.02 72.4 85.51 72.4 101.58 72.41 101.61 109 74.78 145.5 101.58 145.5 85.45 119.35 66.27"
  />
  <polygon class="cls-3" points="109 82.28 108.97 82.25 72.4 109.08 72.4 125.15 72.41 125.19 109 98.37 145.5 125.15 145.5 109.04 109 82.25 109 82.28"
  />
  <polygon class="cls-3" points="109 105.85 108.97 105.83 72.4 132.66 72.4 148.75 72.41 148.77 109 121.95 145.5 148.75 145.5 132.63 109 105.83 109 105.85"
  />
  <line class="cls-4" x1="11.95" y1="183" x2="206.53" y2="183" />
  <text class="first-name" transform="translate(76.22 228.16)">
    First
  </text>
  <text class="last-name" transform="translate(47.47 266.32)">
    Last
  </text>
</svg>

I see that there is a get() method that accepts an index but the only way I can get at the first text elements is like this...

const fName = svg.get(2).get(8)

I'm not sure why I have to select a second element first and then the actual index of the element I'm trying to get

Also, I'm not sure what I do with a set which is what the .select() method is supposed to return, can I select the text element with it's class name somehow and then be able to get it's index or somehow change the text?

Also trying to change the text of that element at this point doesn't work

fName.plain(firstName)

Gives me this error

TypeError: fName.plain is not a function

I'm just trying to change the text for the .first-name and .last-name text elements in this SVG file and then I'll be able to pass that along to a function that converts it to a PNG that will go into a PDF page being generated.

Can anyone help me understand how to accomplish this in this library? I have been at this for hours

EDIT

I loaded in cheerio and am able to get at the element this way but am still struggling with how to use this to change the text. I can't seem to get a reference to an SVG.js element from this still

const cheerio = require('cheerio')
const $ = cheerio.load(tag);
const firstNameTag = $('text.first-name')
const lastNameTag = $('text.last-name')
Jordan
  • 2,393
  • 4
  • 30
  • 60
  • http://svgjs.com/referencing/ – Robert Longson Dec 25 '17 at 08:36
  • @RobertLongson I added `cheerio` to my node.js server and was able to get to my element but still can't seem to get to an element to manipulate from here, I updated my question with the changes I've made – Jordan Dec 25 '17 at 14:46

2 Answers2

8

To your cheerio-edit, you can change the text-content of the nodes with

firstNameTag.text('This is the new first-name-text');
lastNameTag.text('This is the new last-name-text');

And then get the string of the entire updated file with

const updatedSvg = $.html();
niorad
  • 1,330
  • 10
  • 14
0

Side questions

When you import svg content from a file into your svg, it looks like this after import:

// svg from svgdom
<svg>
    <defs>...</defs>
    // parser object, svg.js needs it
    <svg></svg>
    // imported svg
    <svg></svg>
</svg>

With svg.get(2) you get back your svg instance. With the following get(8) you have your text element.

The SVG.Set you get back from select() is more or less a fancy array. svg.js has quite a good documentation at svgjs.dev where this is well explained. You can access elements of a set with get(index), first(), last().

Solution to the real question

However, what you are trying to achieve is quite easy. Just get the elements directly by ID:

SVG.get('first-name').text('New text')
SVG.get('last-name').text('New text')
wout
  • 2,477
  • 2
  • 21
  • 32
Fuzzyma
  • 7,619
  • 6
  • 28
  • 60