diff --git a/src/svg-renderer.js b/src/svg-renderer.js index 3f042d0e..b789daa4 100644 --- a/src/svg-renderer.js +++ b/src/svg-renderer.js @@ -19,6 +19,7 @@ class SvgRenderer { this._context = this._canvas.getContext('2d'); this._measurements = {x: 0, y: 0, width: 0, height: 0}; this._cachedImage = null; + this.loaded = false; } /** @@ -35,10 +36,13 @@ class SvgRenderer { * @param {string} svgString String of SVG data to draw in quirks-mode. * @param {number} [scale] - Optionally, also scale the image by this factor. * @param {Function} [onFinish] Optional callback for when drawing finished. + * @deprecated Use the `loadSVG` method and public `draw` method instead. */ fromString (svgString, scale, onFinish) { - this.loadString(svgString); - this._draw(scale, onFinish); + this.loadSVG(svgString, false, () => { + this.draw(scale); + if (onFinish) onFinish(); + }); } /** @@ -113,6 +117,34 @@ class SvgRenderer { }; } + /** + * Load an SVG string, normalize it, and prepare it for (synchronous) rendering. + * @param {!string} svgString String of SVG data to draw in quirks-mode. + * @param {?boolean} fromVersion2 True if we should perform conversion from version 2 to version 3 svg. + * @param {Function} [onFinish] - An optional callback to call when the SVG is loaded and can be rendered. + */ + loadSVG (svgString, fromVersion2, onFinish) { + this.loadString(svgString, fromVersion2); + this._createSVGImage(onFinish); + } + + /** + * Creates an element for the currently loaded SVG string, then calls the callback once it's loaded. + * @param {Function} [onFinish] - An optional callback to call when the has loaded. + */ + _createSVGImage (onFinish) { + if (this._cachedImage === null) this._cachedImage = new Image(); + const img = this._cachedImage; + + img.onload = () => { + this.loaded = true; + if (onFinish) onFinish(); + }; + const svgText = this.toString(true /* shouldInjectFonts */); + img.src = `data:image/svg+xml;utf8,${encodeURIComponent(svgText)}`; + this.loaded = false; + } + /** * Transforms an SVG's text elements for Scratch 2.0 quirks. * These quirks include: @@ -366,32 +398,39 @@ class SvgRenderer { } /** - * Draw the SVG to a canvas. + * Synchronously draw the loaded SVG to this renderer's `canvas`. + * @param {number} [scale] - Optionally, also scale the image by this factor. + */ + draw (scale) { + if (!this.loaded) throw new Error('SVG image has not finished loading'); + this._drawFromImage(scale); + } + + /** + * Asynchronously draw the (possibly non-loaded) SVG to a canvas. * @param {number} [scale] - Optionally, also scale the image by this factor. * @param {Function} [onFinish] - An optional callback to call when the draw operation is complete. + * @deprecated Use the `loadSVG` and public `draw` method instead. */ _draw (scale, onFinish) { // Convert the SVG text to an Image, and then draw it to the canvas. - if (this._cachedImage) { - this._drawFromImage(scale, onFinish); + if (this._cachedImage === null) { + this._createSVGImage(() => { + this._drawFromImage(scale); + onFinish(); + }); } else { - const img = new Image(); - img.onload = () => { - this._cachedImage = img; - this._drawFromImage(scale, onFinish); - }; - const svgText = this.toString(true /* shouldInjectFonts */); - img.src = `data:image/svg+xml;utf8,${encodeURIComponent(svgText)}`; + this._drawFromImage(scale); + onFinish(); } } /** * Draw to the canvas from a loaded image element. * @param {number} [scale] - Optionally, also scale the image by this factor. - * @param {Function} [onFinish] - An optional callback to call when the draw operation is complete. **/ - _drawFromImage (scale, onFinish) { - if (!this._cachedImage) return; + _drawFromImage (scale) { + if (this._cachedImage === null) return; const ratio = Number.isFinite(scale) ? scale : 1; const bbox = this._measurements; @@ -405,10 +444,6 @@ class SvgRenderer { // Set the CSS style of the canvas to the actual measurements. this._canvas.style.width = bbox.width; this._canvas.style.height = bbox.height; - // All finished - call the callback if provided. - if (onFinish) { - onFinish(); - } } }