Cache image element in the SVG renderer.

This commit is contained in:
Paul Kaplan
2018-01-17 09:42:20 -05:00
parent 89b5ed32d0
commit 8a04fcd541
2 changed files with 40 additions and 24 deletions

View File

@@ -88,7 +88,6 @@ class SVGSkin extends Skin {
}); });
} }
/** @todo re-render a scaled version if the requested scale is significantly larger than the current render */
return this._texture; return this._texture;
} }
@@ -103,7 +102,6 @@ class SVGSkin extends Skin {
this._svgRenderer.fromString(svgData, 1, () => { this._svgRenderer.fromString(svgData, 1, () => {
const gl = this._renderer.gl; const gl = this._renderer.gl;
this._textureScale = this._maxTextureScale = 1; this._textureScale = this._maxTextureScale = 1;
this._svgRenderer.extraScale = 1;
if (this._texture) { if (this._texture) {
gl.bindTexture(gl.TEXTURE_2D, this._texture); gl.bindTexture(gl.TEXTURE_2D, this._texture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this._svgRenderer.canvas); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this._svgRenderer.canvas);

View File

@@ -38,6 +38,7 @@ class SvgRenderer {
this._canvas = canvas || document.createElement('canvas'); this._canvas = canvas || document.createElement('canvas');
this._context = this._canvas.getContext('2d'); this._context = this._canvas.getContext('2d');
this._measurements = {x: 0, y: 0, width: 0, height: 0}; this._measurements = {x: 0, y: 0, width: 0, height: 0};
this._cachedImage = null;
} }
/** /**
@@ -89,6 +90,9 @@ class SvgRenderer {
* @param {string} svgString String of SVG data to draw in quirks-mode. * @param {string} svgString String of SVG data to draw in quirks-mode.
*/ */
_loadString (svgString) { _loadString (svgString) {
// New svg string invalidates the cached image
this._cachedImage = null;
// Parse string into SVG XML. // Parse string into SVG XML.
const parser = new DOMParser(); const parser = new DOMParser();
this._svgDom = parser.parseFromString(svgString, 'text/xml'); this._svgDom = parser.parseFromString(svgString, 'text/xml');
@@ -301,30 +305,44 @@ class SvgRenderer {
* @param {Function} [onFinish] - An optional callback to call when the draw operation is complete. * @param {Function} [onFinish] - An optional callback to call when the draw operation is complete.
*/ */
_draw (scale, onFinish) { _draw (scale, onFinish) {
// Convert the SVG text to an Image, and then draw it to the canvas.
if (this._cachedImage) {
this._drawFromImage(scale, onFinish);
} else {
const img = new Image();
img.onload = () => {
this._cachedImage = img;
this._drawFromImage(scale, onFinish);
};
const svgText = this._toString();
img.src = `data:image/svg+xml;utf8,${encodeURIComponent(svgText)}`;
}
}
/**
* Draw to the canvas from a loaded image element.
* @param {number} [scale] - Optionally, also scale the image by this factor (multiplied by `getDrawRatio()`).
* @param {Function} [onFinish] - An optional callback to call when the draw operation is complete.
**/
_drawFromImage (scale, onFinish) {
if (!this._cachedImage) return;
const ratio = this.getDrawRatio() * (Number.isFinite(scale) ? scale : 1); const ratio = this.getDrawRatio() * (Number.isFinite(scale) ? scale : 1);
const bbox = this._measurements; const bbox = this._measurements;
this._canvas.width = bbox.width * ratio;
// Convert the SVG text to an Image, and then draw it to the canvas. this._canvas.height = bbox.height * ratio;
const img = new Image(); this._context.clearRect(0, 0, this._canvas.width, this._canvas.height);
img.onload = () => { this._context.scale(ratio, ratio);
// Set up the canvas for drawing. this._context.drawImage(this._cachedImage, 0, 0);
this._canvas.width = bbox.width * ratio; // Reset the canvas transform after drawing.
this._canvas.height = bbox.height * ratio; this._context.setTransform(1, 0, 0, 1, 0, 0);
this._context.clearRect(0, 0, this._canvas.width, this._canvas.height); // Set the CSS style of the canvas to the actual measurements.
this._context.scale(ratio, ratio); this._canvas.style.width = bbox.width;
this._context.drawImage(img, 0, 0); this._canvas.style.height = bbox.height;
// Reset the canvas transform after drawing. // All finished - call the callback if provided.
this._context.setTransform(1, 0, 0, 1, 0, 0); if (onFinish) {
// Set the CSS style of the canvas to the actual measurements. onFinish();
this._canvas.style.width = bbox.width; }
this._canvas.style.height = bbox.height;
// All finished - call the callback if provided.
if (onFinish) {
onFinish();
}
};
const svgText = this._toString();
img.src = `data:image/svg+xml;utf8,${encodeURIComponent(svgText)}`;
} }
/** /**