-
-
Notifications
You must be signed in to change notification settings - Fork 4.7k
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
feat: [7877] Allow loading SVG with viewBox only #7878
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -116,6 +116,8 @@ export class SVGResource extends BaseImageResource | |
resolve(this); | ||
}; | ||
|
||
const svgString = this.svg; | ||
|
||
// Convert SVG inline string to data-uri | ||
if (SVGResource.SVG_XML.test(this.svg.trim())) | ||
{ | ||
|
@@ -126,18 +128,19 @@ export class SVGResource extends BaseImageResource | |
(this as any).svg = `data:image/svg+xml;base64,${btoa(unescape(encodeURIComponent(this.svg)))}`; | ||
} | ||
|
||
this._loadSvg(); | ||
this._loadSvg(svgString); | ||
}); | ||
|
||
return this._load; | ||
} | ||
|
||
/** | ||
* Loads an SVG image from `imageUrl` or `data URL`. | ||
* | ||
* @param {string} svgString - the raw string of SVG for falling back to | ||
* viewBox when width or height is not specified. This happens in Firefox. | ||
* @private | ||
*/ | ||
private _loadSvg(): void | ||
private _loadSvg(svgString: string): void | ||
{ | ||
const tempImage = new Image(); | ||
|
||
|
@@ -162,12 +165,21 @@ export class SVGResource extends BaseImageResource | |
return; | ||
} | ||
|
||
const svgWidth = tempImage.width; | ||
const svgHeight = tempImage.height; | ||
let svgWidth = tempImage.width; | ||
let svgHeight = tempImage.height; | ||
|
||
if (!svgWidth || !svgHeight) | ||
{ | ||
throw new Error('The SVG image must have width and height defined (in pixels), canvas API needs them.'); | ||
const size = SVGResource.parseWidthHeightFromViewBox(svgString); | ||
|
||
svgWidth = size.width; | ||
svgHeight = size.height; | ||
} | ||
|
||
if (!svgWidth || !svgHeight) | ||
{ | ||
throw new Error('The SVG image must have width, height' | ||
+ 'or viewBox defined (in pixels), canvas API needs them.'); | ||
} | ||
|
||
// Set render size | ||
|
@@ -199,6 +211,46 @@ export class SVGResource extends BaseImageResource | |
}; | ||
} | ||
|
||
/** | ||
* This function gets the width and height from the viewBox attribute from | ||
* provided SVG. | ||
* @param {string} svg - the string of the SVG, not base64 encoded. | ||
* @param {ISize} scaleTo - optional, if provide, will try to scale viewBox | ||
* the provided size. | ||
* @return {PIXI.ISize} scaled viewBox size if parse success, return (0, 0) | ||
* otherwise. | ||
*/ | ||
static parseWidthHeightFromViewBox(svg: string, scaleTo?: ISize): ISize | ||
{ | ||
const size: ISize = { width: 0, height: 0 }; | ||
|
||
try | ||
{ | ||
const parser = new DOMParser(); | ||
const svgDocument = parser.parseFromString(svg, 'image/svg+xml'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My only problem with this is parsing SVG with DOMParser is that it isn't supported in IE9. We have not yet dropped support for this browser, so we need to find another approach. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When I check on MDN it says fully supported on IE9. I don't really have access to IE9 to verify which one. Quick google shows something about it works on IE9. Do you have recommended method to verify it on IE9? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of parsing, would you suggest a simple RegExp to grab the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, that would work |
||
const element = svgDocument.querySelector('svg'); | ||
|
||
size.width = element.viewBox.baseVal.width; | ||
size.height = element.viewBox.baseVal.height; | ||
if (scaleTo === null || scaleTo === undefined) return size; | ||
|
||
const factor = scaleTo.height < scaleTo.width | ||
? scaleTo.height / size.height : scaleTo.width / size.width; | ||
|
||
size.width *= factor; | ||
size.height *= factor; | ||
|
||
return size; | ||
} | ||
catch (err) | ||
{ | ||
size.width = 0; | ||
size.height = 0; | ||
|
||
return size; | ||
} | ||
} | ||
|
||
/** | ||
* Get size from an svg string using regexp. | ||
* | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you make this
private
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, this name is pretty verbose, why not
parseViewBoxSize
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
About unit test, I had something similar to load svg inline.
However, it will not really test this particular issue since it is a Firefox issue.
When I invoke the unit test framework, it is running on chrome, by default chrome will never use this.
Any suggestion?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Understood that this is only specific to Firefox, that's fine.