Skip to content

Add new draw and loadSVG methods to the SvgRenderer #107

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jan 3, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 54 additions & 19 deletions src/svg-renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

/**
Expand All @@ -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();
});
}

/**
Expand Down Expand Up @@ -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 <img> 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 <img> 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:
Expand Down Expand Up @@ -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) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one should stay as this._cachedImage === null to avoid creating duplicate images

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;
Expand All @@ -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();
}
}
}

Expand Down