The current version of Opentype.js doesn't include this method.
You could write a similar helper function to convert svg pathdata to opentype.js native command object.
You need to draw/align all your svg glyphs in a consistent layout similar to an EM Square (actually rather a rectangle) used in font design applications to define metrics like left and right sidebearings, descender etc.

The above illustration shows different letters all drawn in a viewBox with a height of 100 units and variable widths specifying the desired sidebearings of the glyph.
All glyphs are vertically aligned to the baseline (green line) at y=80.
Now we can use this design pattern to convert from svg to opentype commands.
Fonts use a Cartesian coordinate system:
Red dot: x/y = 0 in svg
Green dot: x/y = 0 in font (baseline position)
Flipping pathdata
So we need to flip svg y-coordinates and shift the glyph according to the glyphs bbox height.
I'm using getPathData()
polyfill to retrieve the path commands.
The following example converts all commands to absolute commands also converting quadratic and arc commands to cubic via normalize parameter:
// parse path and normalize to absolute
let pathData = el.getPathData({
normalize: true
});
If you need to keep e.g quadratic commands you could also parse the path without normalizing el.getPathData()
.
In this case your path data must not contain relative or shorthand commands. However you could also convert these as described here: "Convert SVG Path to Relative Commands"
// define descender, baseline respectively
let descender = -200;
/**
* define new glyphs
*/
let glyphs = [];
// .notdef glyph is recommended to be included
let notDefPath = new opentype.Path();
// svg path is aready scaled
notDefPath.commands = svgToOpentypeCommands('M100 0 L100 700 L600 700 L600 0 M200 100 L500 100 L500 600 L200 600')
let notdefGlyph = new opentype.Glyph({
name: '.notdef',
unicode: 0,
advanceWidth: 700,
path: notDefPath
});
glyphs.push(notdefGlyph)
//space
let space = new opentype.Glyph({
name: 'space',
unicode: 32,
advanceWidth: 500,
path: ''
});
glyphs.push(space)
let glyphPaths = document.querySelectorAll('path[data-glyph]');
glyphPaths.forEach(el => {
let svg = el.closest('svg');
let svgvB = svg.getAttribute('viewBox');
let svgH = svgvB ? svgvB.split(' ')[3] : 1000;
let scale = svgH != 1000 ? 1000 / svgH : 1;
//let descenderSvg = Math.abs(descender) / scale;
let svgW = svgvB ? svgvB.split(' ')[2] : 1000;
let svgGlyph = svgToGlyphData(el, svgW, svgH, scale);
glyphs.push(svgGlyph);
})
/**
* create new font
* containing previously aded glyphs
*/
let font = new opentype.Font({
familyName: 'New Font',
styleName: 'Normal',
unitsPerEm: 1000,
ascender: 800,
descender: descender,
glyphs: glyphs
});
//console.log(font);
let buffer = font.toArrayBuffer();
font = opentype.parse(buffer);
function svgToGlyphData(el, svgW, svgH, scale) {
let id = el.dataset.glyph ? el.dataset.glyph : el.id;
let yOff = svgH * scale + descender;
let charBB = el.getBBox();
// create new glyph
let newPath = new opentype.Path();
// convert svg commands to cartesian and scale
newPath.commands = svgToOpentypeCommands(el, scale, yOff);
console.log(newPath.commands);
let thisGlyph = new opentype.Glyph({
name: id,
unicode: id.charCodeAt(0),
advanceWidth: svgW * scale,
leftSideBearing: charBB.x * scale,
path: newPath
});
return thisGlyph;
};
function svgToOpentypeCommands(el, scale = 1, yOff = 0) {
/**
* is d pathdata
* create temporary path
*/
if (el instanceof SVGGeometryElement === false) {
let d = el;
let ns = 'http://www.w3.org/2000/svg';
let svgTmp = document.createElementNS(ns, 'svg');
el = document.createElementNS(ns, 'path');
el.setAttribute('d', d)
svgTmp.append(el)
document.body.append(svgTmp);
let bb = el.getBBox();
yOff = bb.height;
svgTmp.remove();
}
// parse path and normalize to absolute
let pathData = el.getPathData({
normalize: true
});
let commands = [];
pathData.forEach(function(el, p) {
let commandType = el.type;
//scale coordinates if viewBox < 1000 units
let coords = scale != 1 ? el.values.map(val => {
return val * scale
}) : el.values;
let thisCommand = {
'type': commandType
};
// convert svg commands
if (commandType == 'M' || commandType == 'L') {
thisCommand['x'] = coords[0];
thisCommand['y'] = yOff - coords[1];
} else if (commandType == 'C') {
thisCommand['x1'] = coords[0];
thisCommand['y1'] = yOff - coords[1];
thisCommand['x2'] = coords[2];
thisCommand['y2'] = yOff - coords[3];
thisCommand['x'] = coords[4];
thisCommand['y'] = yOff - coords[5];
} else if (commandType == 'Q') {
thisCommand['x1'] = coords[0];
thisCommand['y1'] = yOff - coords[1];
thisCommand['x'] = coords[2];
thisCommand['y'] = yOff - coords[3];
}
commands.push(thisCommand);
});
//console.log(commands);
return commands;
}
/**
* optional
* render preview on canvas
*/
renderFontPreview(font, fontPreview)
function renderFontPreview(font, target) {
target.innerHTML = '<h2>' + font.names.fontFamily.en + '</h2>';
for (let i = 0; i < font.glyphs.length; i++) {
let glyph = font.glyphs.get(i);
let ctx = createGlyphCanvas(target, glyph, 150);
let x = 50;
let y = 100;
let fontSize = 72;
glyph.draw(ctx, x, y, fontSize);
glyph.drawPoints(ctx, x, y, fontSize);
glyph.drawMetrics(ctx, x, y, fontSize);
}
}
function createGlyphCanvas(target, glyph, size) {
let canvasId, html, glyphsDiv, wrap, canvas, ctx;
canvasId = 'c' + glyph.index;
html = '<div class="wrapper" style="width:' + size + 'px"><canvas id="' + canvasId + '" width="' + size +
'" height="' + size + '"></canvas><span>' + glyph.name + '</span></div>';
target.insertAdjacentHTML('beforeend', html)
canvas = document.getElementById(canvasId);
ctx = canvas.getContext('2d');
return ctx;
}
body {
font: 13px Helvetica, arial, freesans, sans-serif;
line-height: 1.4;
color: #333;
margin: 2em padding: 0;
}
svg {
display: inline-block;
height: 40vh;
width: auto;
overflow: visible;
border: 1px solid #ccc
}
.svgWrp {
margin-bottom: 2em;
}
.wrapper {
display: inline-block;
margin: 5px;
border: 1px solid #ccc;
}
<script src="https://cdn.jsdelivr.net/npm/opentype.js@1.3.4/dist/opentype.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/path-data-polyfill@latest/path-data-polyfill.min.js"></script>
<div class="svgWrp">
<h2>SVG glyphs</h2>
<svg class="svgGlyph" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 54.3 100">
<path data-glyph="g"
d="M52.3 26.5 v5.1l-9.9 1.2c0.9 1.1 1.7 2.6 2.4 4.5s1.1 3.9 1.1 6.2c0 5.2-1.8 9.4-5.4 12.5s-8.5 4.7-14.7 4.7c-1.6 0-3.1-0.1-4.5-0.4c-3.5 1.8-5.2 4.1-5.2 6.9c0 1.5 0.6 2.6 1.8 3.3s3.3 1 6.2 1h9.5c5.8 0 10.2 1.2 13.3 3.7s4.7 6 4.7 10.6c0 5.9-2.4 10.5-7.1 13.6s-11.7 4.6-20.8 4.6c-7 0-12.4-1.3-16.2-3.9s-5.7-6.3-5.7-11c0-3.3 1-6.1 3.1-8.5s5-3.9 8.8-4.8c-1.4-0.6-2.5-1.6-3.4-2.9s-1.4-2.8-1.4-4.5c0-2 0.5-3.7 1.5-5.1s2.7-2.9 5-4.3c-2.8-1.1-5.1-3.1-6.8-5.8s-2.6-5.9-2.6-9.4c0-5.8 1.8-10.4 5.3-13.5s8.5-4.8 14.9-4.8c2.8 0 5.3 0.3 7.6 1h18.5zm-42.7 62.5c0 2.9 1.2 5.1 3.7 6.6s5.9 2.2 10.5 2.2c6.8 0 11.8-1 15.1-3s4.9-4.8 4.9-8.3c0-2.9-0.9-4.9-2.7-6s-5.2-1.7-10.1-1.7h-9.7c-3.7 0-6.6 0.9-8.6 2.6s-3.1 4.3-3.1 7.6zm4.4-45.4c0 3.8 1.1 6.6 3.2 8.5s5 2.9 8.8 2.9c7.9 0 11.9-3.8 11.9-11.5c0-8.1-4-12.1-12-12.1c-3.8 0-6.8 1-8.8 3.1s-3.1 5.1-3.1 9.1z" />
<line id="baseline" fill="none" stroke="green" stroke-dasharray="0 3" stroke-linecap="round" x1="0"
y1="80" x2="100%" y2="80" />
<circle cx="0" cy="0" r="2" fill="red" />
<circle cx="0" cy="80" r="2" fill="green" />
</svg>
<svg viewBox="0 0 53 100">
<path data-glyph="x"
d="M21.5 52.6l-18.6-26.1h9.2l14.1 20.5l14.1-20.5h9.1l-18.6 26.1l19.6 27.4h-9.2l-15-21.7l-15.1 21.7h-9.2l19.6-27.4z" />
<line id="baseline" fill="none" stroke="green" stroke-dasharray="0 3" stroke-linecap="round" x1="0"
y1="80" x2="100%" y2="80" />
</svg>
<svg viewBox="0 0 25 100">
<path data-glyph="1"
d="M7.9 12c0-1.9 0.5-3.2 1.4-4.1s2-1.3 3.4-1.3s2.4 0.4 3.4 1.3s1.4 2.3 1.4 4.1s-0.5 3.2-1.4 4.1s-2.1 1.3-3.4 1.3s-2.5-0.4-3.4-1.3s-1.4-2.3-1.4-4.1zm8.8 68h-8.1v-53.5h8.1v53.5z" />
<line id="baseline" fill="none" stroke="green" stroke-dasharray="0 3" stroke-linecap="round" x1="0"
y1="80" x2="100%" y2="80" />
</svg>
</div>
<div id="fontPreview"></div>
<button onclick="font.download()">Download Font</button>
See also example for writing fonts in opentype.js repository and documentation
Obviously you need to adjust the scaling and descender values according to your layout.