I previously made a post here: Converting SVG to PNG loses styling elements but my question was more broad - I think we identified the cause, but now I'm having issues implementing a solution.
I thought it would be beneficial to post a new question regarding specific React syntax to provide an inline custom font style to an SVG element
Here are my render() functions:
renderIcon() {
return this.props.logoStyle.iconGraphic.path.map((path) => {
return (
<path id={path.id} style={{"fill":this.props.logoStyle.iconColor}} d={path.d} />
);
});
}
renderLogo() {
let style = this.props.logoStyle;
return (
<svg width="300" height="100" className={"logo"} xmlns="http://www.w3.org/2000/svg">
<svg xmlns="http://www.w3.org/2000/svg">
<rect
id="background"
x="0"
y="0"
width="300"
height="100"
style={{fill: style.backgroundColor}}
/>
</svg>
<svg
xmlns="http://www.w3.org/2000/svg"
width={style.iconSize}
height={style.iconSize}
viewBox="0 0 1000 1000"
x="10"
y="13"
id="svg4272">
<g>
{this.renderIcon()}
</g>
</svg>
<svg xmlns="http://www.w3.org/2000/svg">
<text
style={{
fontSize:style.fontSize,
fontFamily: style.fontFamily,
fill: style.fontColor
}}
id="text"
x="90"
y="58"
fontSize={style.fontSize}
>{style.companyName}</text>
</svg>
</svg>
);
}
render() {
let style = this.props.logoStyle;
//console.log(style);
return (
<div className="logo-preview">
{this.renderLogo()}
<canvas id="canvas" width="900" height="300"></canvas>
<button className="btn btn-success" onClick={this.onDownload}>Download</button>
</div>
);
}
Everything looks good on the page, but when the user presses a button which then draws the SVG to the #canvas and triggers a download, it's clear that it loses styling elements, as they are not truly being rendered inline.
The icon (from this.renderIcon()) is the only thing that gets drawn correctly.
The <rect>
gets stripped entirely (or at least loses its fill), and the <text>
loses it's custom fonts (but correctly maintains fontSize and fill).
Speaking specifically to the custom fonts, I have found from various resources that I need to encode the font to data URI, and include that in line: Import: Using Google Fonts with SVG <object> dataURI: How to Include CSS style when converting svg to png
I've tried the following, but nothing has worked:
@font-face
<svg xmlns="http://www.w3.org/2000/svg">
<style>
@font-face { font-family: 'pacifico'; src: url(data:application/font-woff;charset-utf08;base64,d09GR...) format('woff'); font-weight: normal; font-style: normal; }
</style>
<text
style={{
fontSize:style.fontSize,
fontFamily: style.fontFamily,
fill: style.fontColor
}}
id="text"
x="90"
y="58"
fontSize={style.fontSize}
>{style.companyName}</text>
</svg>
@fontFace (camelCase for React)
<svg xmlns="http://www.w3.org/2000/svg">
<style>
@fontFace { fontFamily: 'pacifico'; src: url(data:application/font-woff;charset-utf08;base64,d09GR...) format('woff'); fontWeight: normal; fontStyle: normal; }
</style>
<text
style={{
fontSize:style.fontSize,
fontFamily: style.fontFamily,
fill: style.fontColor
}}
id="text"
x="90"
y="58"
fontSize={style.fontSize}
>{style.companyName}</text>
</svg>
This one throws a webpack error at 'fontFamily: ...' citing the colon ':' as an unexpected character, expecting a closing bracket '}'
@import
<svg xmlns="http://www.w3.org/2000/svg">
<style>
@import url('https://fonts.googleapis.com/css?family=Pacifico');
</style>
<text
style={{
fontSize:style.fontSize,
fontFamily: style.fontFamily,
fill: style.fontColor
}}
id="text"
x="90"
y="58"
fontSize={style.fontSize}
>{style.companyName}</text>
</svg>
EDIT:
I came across this thread that used backticks: Embedding SVG into ReactJS And tried this, but still did not work (tried with both camelCase and traditional syntax)
<style>
{ `@fontFace { fontFamily: 'pacifico'; src: url(data:application/font-woff2;charset=utf-8;base64,....; } ` }
</style>
It does not throw any errors but when drawn to canvas it is no different than before