1 | {"version":3,"file":"SVGResource.js","sources":["../../../src/textures/resources/SVGResource.ts"],"sourcesContent":["import { settings } from '@pixi/settings';\nimport { uid } from '@pixi/utils';\nimport { BaseImageResource } from './BaseImageResource';\n\nimport type { ISize } from '@pixi/math';\nimport type { ICanvas } from '@pixi/settings';\n\nexport interface ISVGResourceOptions\n{\n source?: string;\n scale?: number;\n width?: number;\n height?: number;\n autoLoad?: boolean;\n crossorigin?: boolean | string;\n}\n/**\n * Resource type for SVG elements and graphics.\n * @memberof PIXI\n */\nexport class SVGResource extends BaseImageResource\n{\n /** Base64 encoded SVG element or URL for SVG file. */\n public readonly svg: string;\n\n /** The source scale to apply when rasterizing on load. */\n public readonly scale: number;\n\n /** A width override for rasterization on load. */\n public readonly _overrideWidth: number;\n\n /** A height override for rasterization on load. */\n public readonly _overrideHeight: number;\n\n /** Call when completely loaded. */\n private _resolve: () => void;\n\n /** Promise when loading */\n private _load: Promise<this>;\n\n /** Cross origin value to use */\n private _crossorigin?: boolean | string;\n\n /**\n * @param sourceBase64 - Base64 encoded SVG element or URL for SVG file.\n * @param {object} [options] - Options to use\n * @param {number} [options.scale=1] - Scale to apply to SVG. Overridden by...\n * @param {number} [options.width] - Rasterize SVG this wide. Aspect ratio preserved if height not specified.\n * @param {number} [options.height] - Rasterize SVG this high. Aspect ratio preserved if width not specified.\n * @param {boolean} [options.autoLoad=true] - Start loading right away.\n */\n constructor(sourceBase64: string, options?: ISVGResourceOptions)\n {\n options = options || {};\n\n super(settings.ADAPTER.createCanvas());\n this._width = 0;\n this._height = 0;\n\n this.svg = sourceBase64;\n this.scale = options.scale || 1;\n this._overrideWidth = options.width;\n this._overrideHeight = options.height;\n\n this._resolve = null;\n this._crossorigin = options.crossorigin;\n this._load = null;\n\n if (options.autoLoad !== false)\n {\n this.load();\n }\n }\n\n load(): Promise<this>\n {\n if (this._load)\n {\n return this._load;\n }\n\n this._load = new Promise((resolve): void =>\n {\n // Save this until after load is finished\n this._resolve = (): void =>\n {\n this.update();\n resolve(this);\n };\n\n // Convert SVG inline string to data-uri\n if (SVGResource.SVG_XML.test(this.svg.trim()))\n {\n if (!btoa)\n {\n throw new Error('Your browser doesn\\'t support base64 conversions.');\n }\n (this as any).svg = `data:image/svg+xml;base64,${btoa(unescape(encodeURIComponent(this.svg)))}`;\n }\n\n this._loadSvg();\n });\n\n return this._load;\n }\n\n /** Loads an SVG image from `imageUrl` or `data URL`. */\n private _loadSvg(): void\n {\n const tempImage = new Image();\n\n BaseImageResource.crossOrigin(tempImage, this.svg, this._crossorigin);\n tempImage.src = this.svg;\n\n tempImage.onerror = (event): void =>\n {\n if (!this._resolve)\n {\n return;\n }\n\n tempImage.onerror = null;\n this.onError.emit(event);\n };\n\n tempImage.onload = (): void =>\n {\n if (!this._resolve)\n {\n return;\n }\n\n const svgWidth = tempImage.width;\n const svgHeight = tempImage.height;\n\n if (!svgWidth || !svgHeight)\n {\n throw new Error('The SVG image must have width and height defined (in pixels), canvas API needs them.');\n }\n\n // Set render size\n let width = svgWidth * this.scale;\n let height = svgHeight * this.scale;\n\n if (this._overrideWidth || this._overrideHeight)\n {\n width = this._overrideWidth || this._overrideHeight / svgHeight * svgWidth;\n height = this._overrideHeight || this._overrideWidth / svgWidth * svgHeight;\n }\n width = Math.round(width);\n height = Math.round(height);\n\n // Create a canvas element\n const canvas = this.source as ICanvas;\n\n canvas.width = width;\n canvas.height = height;\n (canvas as any)._pixiId = `canvas_${uid()}`;\n\n // Draw the Svg to the canvas\n canvas\n .getContext('2d')\n .drawImage(tempImage, 0, 0, svgWidth, svgHeight, 0, 0, width, height);\n\n this._resolve();\n this._resolve = null;\n };\n }\n\n /**\n * Get size from an svg string using a regular expression.\n * @param svgString - a serialized svg element\n * @returns - image extension\n */\n static getSize(svgString?: string): ISize\n {\n const sizeMatch = SVGResource.SVG_SIZE.exec(svgString);\n const size: any = {};\n\n if (sizeMatch)\n {\n size[sizeMatch[1]] = Math.round(parseFloat(sizeMatch[3]));\n size[sizeMatch[5]] = Math.round(parseFloat(sizeMatch[7]));\n }\n\n return size;\n }\n\n /** Destroys this texture. */\n dispose(): void\n {\n super.dispose();\n this._resolve = null;\n this._crossorigin = null;\n }\n\n /**\n * Used to auto-detect the type of resource.\n * @param {*} source - The source object\n * @param {string} extension - The extension of source, if set\n * @returns {boolean} - If the source is a SVG source or data file\n */\n static test(source: unknown, extension?: string): boolean\n {\n // url file extension is SVG\n return extension === 'svg'\n // source is SVG data-uri\n || (typeof source === 'string' && source.startsWith('data:image/svg+xml'))\n // source is SVG inline\n || (typeof source === 'string' && SVGResource.SVG_XML.test(source));\n }\n\n /**\n * Regular expression for SVG XML document.\n * @example <?xml version=\"1.0\" encoding=\"utf-8\" ?><!-- image/svg --><svg\n * @readonly\n */\n static SVG_XML = /^(<\\?xml[^?]+\\?>)?\\s*(<!--[^(-->)]*-->)?\\s*\\<svg/m;\n\n /**\n * Regular expression for SVG size.\n * @example <svg width=\"100\" height=\"100\"></svg>\n * @readonly\n */\n static SVG_SIZE = /<svg[^>]*(?:\\s(width|height)=('|\")(\\d*(?:\\.\\d+)?)(?:px)?('|\"))[^>]*(?:\\s(width|height)=('|\")(\\d*(?:\\.\\d+)?)(?:px)?('|\"))[^>]*>/i; // eslint-disable-line max-len\n}\n"],"names":["_SVGResource","BaseImageResource","settings","uid"],"mappings":";;AAoBO,MAAM,eAAN,MAAMA,sBAAoBC,oCACjC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA8BI,YAAY,cAAsB,SAClC;AACI,cAAU,WAAW,IAEf,MAAAC,SAAA,SAAS,QAAQ,aAAc,CAAA,GACrC,KAAK,SAAS,GACd,KAAK,UAAU,GAEf,KAAK,MAAM,cACX,KAAK,QAAQ,QAAQ,SAAS,GAC9B,KAAK,iBAAiB,QAAQ,OAC9B,KAAK,kBAAkB,QAAQ,QAE/B,KAAK,WAAW,MAChB,KAAK,eAAe,QAAQ,aAC5B,KAAK,QAAQ,MAET,QAAQ,aAAa,MAErB,KAAK;EAEb;AAAA,EAEA,OACA;AACQ,WAAA,KAAK,QAEE,KAAK,SAGhB,KAAK,QAAQ,IAAI,QAAQ,CAAC,YAC1B;AAEI,UAAA,KAAK,WAAW,MAChB;AACS,aAAA,OAAA,GACL,QAAQ,IAAI;AAAA,MAAA,GAIZF,cAAY,QAAQ,KAAK,KAAK,IAAI,KAAA,CAAM,GAC5C;AACI,YAAI,CAAC;AAEK,gBAAA,IAAI,MAAM,kDAAmD;AAEtE,aAAa,MAAM,6BAA6B,KAAK,SAAS,mBAAmB,KAAK,GAAG,CAAC,CAAC,CAAC;AAAA,MACjG;AAEA,WAAK,SAAS;AAAA,IAAA,CACjB,GAEM,KAAK;AAAA,EAChB;AAAA;AAAA,EAGQ,WACR;AACU,UAAA,YAAY,IAAI;AAEtBC,sBAAA,kBAAkB,YAAY,WAAW,KAAK,KAAK,KAAK,YAAY,GACpE,UAAU,MAAM,KAAK,KAErB,UAAU,UAAU,CAAC,UACrB;AACS,WAAK,aAKV,UAAU,UAAU,MACpB,KAAK,QAAQ,KAAK,KAAK;AAAA,IAAA,GAG3B,UAAU,SAAS,MACnB;AACI,UAAI,CAAC,KAAK;AAEN;AAGJ,YAAM,WAAW,UAAU,OACrB,YAAY,UAAU;AAExB,UAAA,CAAC,YAAY,CAAC;AAER,cAAA,IAAI,MAAM,sFAAsF;AAI1G,UAAI,QAAQ,WAAW,KAAK,OACxB,SAAS,YAAY,KAAK;AAE1B,OAAA,KAAK,kBAAkB,KAAK,qBAE5B,QAAQ,KAAK,kBAAkB,KAAK,kBAAkB,YAAY,UAClE,SAAS,KAAK,mBAAmB,KAAK,iBAAiB,WAAW,YAEtE,QAAQ,KAAK,MAAM,KAAK,GACxB,SAAS,KAAK,MAAM,MAAM;AAG1B,YAAM,SAAS,KAAK;AAEpB,aAAO,QAAQ,OACf,OAAO,SAAS,QACf,OAAe,UAAU,UAAUE,MAAAA,IAAK,CAAA,IAGzC,OACK,WAAW,IAAI,EACf,UAAU,WAAW,GAAG,GAAG,UAAU,WAAW,GAAG,GAAG,OAAO,MAAM,GAExE,KAAK,SAAS,GACd,KAAK,WAAW;AAAA,IAAA;AAAA,EAExB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,OAAO,QAAQ,WACf;AACI,UAAM,YAAYH,cAAY,SAAS,KAAK,SAAS,GAC/C,OAAY;AAEd,WAAA,cAEA,KAAK,UAAU,CAAC,CAAC,IAAI,KAAK,MAAM,WAAW,UAAU,CAAC,CAAC,CAAC,GACxD,KAAK,UAAU,CAAC,CAAC,IAAI,KAAK,MAAM,WAAW,UAAU,CAAC,CAAC,CAAC,IAGrD;AAAA,EACX;AAAA;AAAA,EAGA,UACA;AACI,UAAM,QACN,GAAA,KAAK,WAAW,MAChB,KAAK,eAAe;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,OAAO,KAAK,QAAiB,WAC7B;AAEI,WAAO,cAAc,SAEb,OAAO,UAAW,YAAY,OAAO,WAAW,oBAAoB,KAEpE,OAAO,UAAW,YAAYA,cAAY,QAAQ,KAAK,MAAM;AAAA,EACzE;AAAA;AAeJ;AA7Ma,aAqMF,UAAU;AAAA;AAAA;AAAA;AAAA;AArMR,aA4MF,WAAW;AA5Mf,IAAM,cAAN;;"} |