Generating SVG paths with the combination of svg.js and opentype.js

Greetings everyone! I have successfully managed to grab SVG path data using opentype.js, but I'm encountering some difficulties when trying to use that data with svg.js in order to render the path:

Below is the code snippet that I am currently working on. It creates an SVG element with an empty group <g></g>, whereas I was expecting the group to wrap around my path data.

I came across a suggestion in another post that advised me to utilize SVG.adopt() (which I have attempted below) but unfortunately it did not work as expected. Thank you in advance for your help.

const svg = new SVG().addTo('body').attr({
  viewBox: '0 0 100 100'
})

const createShape = (font,content) => {
  const fontPaths = font.getPaths(content,20,20,100)
  const paths = fontPaths.map(fontPath => {
    console.log(fontPath.toSVG())
    const path = SVG.adopt(fontPath.toSVG())
    // const svgPath = SVG(path)
    // // svgPath.fill('black')
    console.log(path)
    return path
  })
  const group = svg.group()
  group.add(paths).attr({
    fill: 'black'

  })
      return group
}

const draw = (font) => {
  createShape(font,'hello')
}

opentype.load('https://assets.codepen.io/1070/basiersquare-bold-webfont.woff',(err,font) => draw(font))

Answer №1

When using the opentype.js method fontPath.toSVG(), it will provide svg markup instead of nodes.
On the other hand, the group.add(paths) function expects the variable "paths" to contain nodes for appending.

If you prefer, I would recommend a simple javascript approach for generating SVGs.

An Example: Retrieving Glyph Paths and Appending SVG

const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
const g = document.createElementNS("http://www.w3.org/2000/svg", "g");
g.setAttribute('fill', 'black');
document.body.appendChild(svg);
svg.appendChild(g);

const createShape = (font, content) => {
  let pathMarkup = '';
  const fontPaths = font.getPaths(content, 0, 100, 100)
  const paths = fontPaths.map(fontPath => {
    let path = fontPath.toSVG();
    pathMarkup += path;
  })
  g.insertAdjacentHTML('beforeend', pathMarkup);
  //adjust viewBox
  let viewBox = svg.getBBox();
  svg.setAttribute('viewBox', [0, 0, (viewBox.width + viewBox.x).toFixed(2), (viewBox.height + viewBox.y).toFixed(2)].join(
    ' '));
}

const draw = (font) => {
  createShape(font, 'hello')
}

opentype.load('https://fonts.gstatic.com/s/firasans/v15/va9B4kDNxMZdWfMOD5VnZKveRhf8.woff', (err, font) => draw(font))
svg{
width: 50vw;
border: 1px solid #ccc
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/svg.js/3.1.2/svg.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/opentype.js@latest/dist/opentype.min.js"></script>

The example above essentially involves:

  • Appending an SVG and group element to the DOM
  • Combining the path markup provided by opentype.js
  • Inserting the markup into the SVG group
  • Adjusting the SVG viewBox to prevent overflows (using getBBox() to determine correct width and height values)

Edit: Approach using svg.js

As mentioned by @Fuzzyma, my initial answer may have been somewhat biased.

const svg = new SVG().addTo('body');
const group = svg.group();
const createShape = (font,content) => {
    let pathString = '';
  const fontPaths = font.getPaths(content,0,100,100)
  const paths = fontPaths.map(fontPath => {
    let path = fontPath.toSVG();
    pathString += path;
    return pathString
  })
  group.svg(pathString).attr({
    fill: 'black'
  })
      return group
}

svg.attr({
  viewBox: '0 0 226.10 101.50'
})

const draw = (font) => {
  createShape(font,'hello')
}

opentype.load('https://assets.codepen.io/1070/basiersquare-bold-webfont.woff',(err,font) => draw(font))
<script src="https://cdnjs.cloudflare.com/ajax/libs/svg.js/3.1.2/svg.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/opentype.js@latest/dist/opentype.min.js"></script>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What steps should I take to fix the WCF / AJAX problem I'm encountering? (Receiving a 400 Bad Request error

I am relatively new to AJAX and JavaScript, so I appreciate your patience. My goal is to use an AJAX call to send a new user object to a WCF C# method, which will then create the user in a SQL server database. Subsequently, the C# method will send back a v ...

Using AngularJS to convert a JSON object into an array

Hey there, I've got a JSON return object that looks like this: color_selected = [ { id: 4}, { id: 3} ]; Any tips on how I can convert it to the following format? color_selected = [4,3] Appreciate any help or s ...

Determine ng-checked according to an array

I am working with a select dropdown that creates checkboxes using ng-repeat based on the selected value. The goal is to have all values in the dropdown selected, corresponding checkboxes checked, and store them in an array. Each time a checkbox is changed ...

The function "Jest spyOn" does not exist

I’m currently facing an unfamiliar error while testing my React component using Jest. Here’s the code snippet for my <Row/> component: In my Row component, there are various methods like showDetailsPanel(), handleStatusChange(), handleModalCanc ...

Beware: The use of anonymous arrow functions in Next.js can disrupt Fast Refresh and lead to the loss of local component state

I am currently encountering a warning that is indicating an anonymous object in a configuration file, and even specifying a name for it does not resolve the warning. Below you will find the detailed warning message along with examples. Warning: Anonymous ...

Executing ws.send from the controller in a Node.js environment

In my project, I am looking to send a websocket using express-ws from a different controller rather than through a route. In my server.js file, I have the following code: var SocketController = require('./routes/ws.routes'); var app = express(); ...

The functionality of ZoneAwarePromise has been modified within the Meteor framework

After updating to the latest Angular 2.0.1 release on Meteor 1.4.1.1, I'm facing an error that says: Zone.js has detected that ZoneAwarePromise (window|global).Promise has been overwritten I've attempted running meteor update and meteor reset, b ...

Extracting information from an external website in the form of XML data

Trying to retrieve data from an XML feed on a remote website , I encountered issues parsing the XML content and kept receiving errors. Surprisingly, fetching JSON data from the same source at worked perfectly. The code snippet used for XML parsing is as f ...

Creating an 8-bit grayscale JPEG image using HTML5 and encoding it from a canvas source

Is there a simple method to convert an 8-bit grayscale JPEG from Canvas using client side technologies in a web browser (such as HTML5, canvas, WebGL, and JavaScript)? Are there any pre-made JavaScript libraries available for use, without requiring extens ...

Understanding Namespacing in Vuex with Vue.js

Trying to organize modules' getters, mutations, and actions with namespacing can be a bit challenging. I came across this document, but it didn't provide clear enough information for me. // types.js // Constants for namespacing getters, actio ...

Teach me how to utilize Import / require() in Static Folder

I've been attempting this task for a while, but I'm unsure how to incorporate import or require into the express static folder. When I try to use it, I receive an error stating "require not defined" which makes sense since these are not supported ...

Determining the Nearest Date in an Array Using JavaScript

In my array, I store information about each day as an object. For example: {day_year: "2012", day_month: "08", day_number: "03", day_name: "mon"} To enhance the day objects, I have included a timestamp attribute using the following function: function co ...

Issue with React component not updating content after state changes in Next.js framework

Currently, I am facing an issue with my Header component not updating its content on state change. The goal is to show the user's Profile once the state changes, but unfortunately, it does not update immediately; it only changes after a page refresh o ...

Adjusting Javascript code to launch a URL in a new window or new tab depending on the user's selection

I seem to be encountering a puzzling issue with a link on my website. When clicked normally, the link opens in a new window. However, if I right-click and select "open in new window" or "open in new tab," it just reloads the same page where the link was cl ...

How to iterate over an array within a prop of a JSX/React component

This one's a bit tricky so my apologies for any confusion. Within the component PersonalInfo.jsx, there are three Input.jsx components and one Button.jsx component. PersonalInfo.jsx utilizes the state [valid, setValid] = useState([]). Upon clicking ...

Regular Expression: do not include comments that are placed inside quotation marks

Using the regular expression /#(.*?)\r?\n|#(.*?)$/g, I was able to parse the following content. However, it also matches the comment within the quotes. How can I prevent this from happening? # # this is a comment # but this is '# not a c ...

Waiting for all promises to resolve: A step-by-step guide

I need to make two different API calls and perform calculations based on the results of both. To wait for both promises to resolve, I am using Promise.all(). const getHashTagList = async () => { loader.start(); try { await getAllHashTag ...

Creating a dynamic 3D camera view in three.js for navigating around the scene

As a newcomer to Three.js, I am looking to implement a fly-around camera in my scene. I have discovered that THREE.Geometry has a method called .computeBoundingSphere() and a property called .boundingSphere that provides me with the center and radius of t ...

Tips for preventing the overwriting of a JSON object in a React application

I'm trying to compare two JSON objects and identify the differing values in the second JSON object based on a specific key. My goal is to store these mismatched values in a new JSON object. The current issue I'm facing is that when there are mult ...

Utilize a locally stored VueJs file rather than importing it from an external source

Starting my journey with VueJs using single file application has been quite interesting. Initially, I had everything in a single html page with both javascript and CSS styles embedded within it. To avoid fetching VueJs features online, I downloaded the V ...