1

In ReactJS I have an interface that allows a user to make customizations to an SVG block. There are three components within the SVG: a rectangle (for background), text, and an SVG path image.

The SVG is rendered as such, with props coming from a parent component's state:

renderLogo() {
    let style = this.props.logoStyle;

    return (
        <svg width="300" height="100" className={"logo"} xmlns="http://www.w3.org/2000/svg">

            <g>
                <rect id="background" x="0" y="0" width="300" height="100" rx={style.bgBorderRadius} ry={style.bgBorderRadius} 
                fill={style.backgroundColor} stroke="2" />
            </g>

            <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>

        <g>             
            <text 
                x="90" 
                y="58" 
                fontSize={style.fontSize}
                fontFamily={style.fontFamily}
                fontWeight={style.fontWeight}
                stroke={style.fontStrokeColor}
                strokeWidth={style.fontStrokeWidth}
                fill={style.fontColor}
                textAlign="right"
                >{style.companyName}</text>
          </g>          
        </svg>
    );
}

render() {
    let style = this.props.logoStyle;
    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>
    );
}

The button triggers function onDownload() which then attempts to paint to the #canvas, and then launches a download of the PNG

onDownload() {

    var svg = document.querySelector('svg.logo');

// This function is from here that I hoped would help with the issue: https://github.com/lukehorvat/computed-style-to-inline-style 
    var computedToInline = require('computed-style-to-inline-style');
    computedToInline(svg, true);


    var canvas = document.querySelector('canvas');

     var ctx = canvas.getContext('2d');
     var data = (new XMLSerializer()).serializeToString(svg);

    var DOMURL = window.URL || window.webkitURL || window;

     var img = new Image();
     var svgBlob = new Blob([data], {type: 'image/svg+xml;charset=utf-8'});
     var url = DOMURL.createObjectURL(svgBlob);

      img.onload = () => {
        // clip and scale up
        ctx.drawImage(img, 0, 0, 300, 100, 0, 0, 900, 300);
        DOMURL.revokeObjectURL(url);

        var imgURI = canvas
            .toDataURL('image/png')
            .replace('image/png', 'image/octet-stream');

          this.triggerDownload(imgURI);

      };

      img.src = url;
}

triggerDownload(imgURI) {
    console.log("triggerDownload");
    var evt = new MouseEvent('click', {
        view: window,
        bubbles: false,
        cancelable: true
    });


    var a = document.createElement('a');
    a.setAttribute('download', 'imageFile.png');
    a.setAttribute('href', imgURI);
    a.setAttribute('target','_blank');

    a.dispatchEvent(evt);
}

The issue:

When drawing it to the canvas, the icon is rendering correctly, but the background (SVG component ) is removed, and the attributes (ex. font-family) are defaulting to Helvetica Neue instead of the selected fonts / attributes. This carries into the download file.

EDIT:

As mentioned one of the issues is the fonts, and these do come from Google. From the link provided in the comments, it seems I need to reference these via data URIs inline. I have encoded them using FontSquirrel.com, but I am unsure how to reference them in the SVG inline, in React:

@font-face {
font-family: 'pacificoregular';
src: url(data:application/font-woff2;charset=utf-8;base64,d09GMgA...),
     url(data:application/font-woff;charset=utf-8;base64,d09Grg...) format('woff');
font-weight: normal;
font-style: normal;
}

I tried inserting this into an element in <defs><style>...</style></defs> but it errors. I tried converting to React syntax like so, but it also fails:

<style>
@fontFace {
fontFamily: 'pacificoregular';
src: url(data:application/font-woff2;charset=utf-8;base64,d09GMgA...),
     url(data:application/font-woff;charset=utf-8;base64,d09Grg...) format('woff');
fontWeight: normal;
fontStyle: normal;
}
</style>

How can I reference the font inline to the SVG if I cannot use @font-face? Or is there actually a proper way to utilize @font-face here?

EDIT 2:

Removed <def> tags, and used @fontFace{} syntax:

Error when attempting this syntax I receive a syntax error that is complaining about the ":" after 'fontFamily' in:

@fontFace {
fontFamily: 'pacificoregular';
...
}
trm313
  • 81
  • 1
  • 9
  • You'd have to convert the fonts to data URL so that their data is internal to the SVG file. – Robert Longson Jan 10 '17 at 21:03
  • Thanks for linking that thread, I hadn't come across that one yet. I'm setting out down that path, and will report back! Thanks again for the tip – trm313 Jan 11 '17 at 17:25
  • Hi Rob, I did some research into converting the fonts to data URI so that they are internal to the SVG file, but am facing some issues referencing that data URI inline. I edited my post at the bottom to update with some of what I've tried. Any ideas here? I could not find any React-specific examples, and I'm afraid that the React syntax needs (removing hyphenated words, replacing with camelCase) is playing a role here syntactically – trm313 Jan 11 '17 at 21:45
  • You put @fontFace in style tags, defs is not required. Your open and close tags are misordered anyway. – Robert Longson Jan 11 '17 at 21:49
  • Whoops, I typed that block by hand in the editor. Removed the altogether now, but I'm still unable to execute the code. it errors like so (Edited the bottom of the post because code formatting wasn't working well in the comment – trm313 Jan 11 '17 at 21:54
  • Errors with what message? Where's your react code that's creating this error message? – Robert Longson Jan 11 '17 at 21:57
  • it's an error coming from the node module build (webpack): ERROR in ./src/components/logo-preview.js Module build failed: SyntaxError: Unexpected token, expected } (The unexpected token is referring to the ":" after fontFamily) – trm313 Jan 11 '17 at 22:04
  • it's '@font-face' not '@font-family' – Robert Longson Jan 11 '17 at 22:11
  • Gosh, so sorry - all over the place with these typos right now. Yes, I used @fontFace{} (also tried @font-face{}) and inside of the curly brackets I have the paramter 'font-family' (also tried fontFamily) which is attempting to initiate the web font. It is with this internal reference of fontFamily that brings the syntax issue – trm313 Jan 11 '17 at 22:14

0 Answers0