phaserjs / phaser

Phaser is a fun, free and fast 2D game framework for making HTML5 games for desktop and mobile web browsers, supporting Canvas and WebGL rendering.
https://phaser.io
MIT License
37.16k stars 7.1k forks source link

add svg image in iOS not work #6855

Closed cy920820 closed 4 months ago

cy920820 commented 4 months ago

case: https://codepen.io/cy920820/pen/ExBYJZo

greptile-apps[bot] commented 4 months ago

For internal use only

To address the issue of SVG images not working on iOS, you can try the following steps:

  1. Modify SVGFile.js: Ensure that the SVG is correctly parsed and processed. Add a check for iOS and handle the SVG differently if needed.
// Inside SVGFile.js
onProcess: function () {
    this.state = CONST.FILE_PROCESSING;

    var text = this.xhrLoader.responseText;
    var svg = [ text ];
    var width = this.config.width;
    var height = this.config.height;
    var scale = this.config.scale;

    // Check for iOS
    var isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;

    resize: if (width && height || scale) {
        var xml = null;
        var parser = new DOMParser();
        xml = parser.parseFromString(text, 'text/xml');
        var svgXML = xml.getElementsByTagName('svg')[0];

        var hasViewBox = svgXML.hasAttribute('viewBox');
        var svgWidth = parseFloat(svgXML.getAttribute('width'));
        var svgHeight = parseFloat(svgXML.getAttribute('height'));

        if (!hasViewBox && svgWidth && svgHeight) {
            svgXML.setAttribute('viewBox', '0 0 ' + svgWidth + ' ' + svgHeight);
        } else if (hasViewBox && !svgWidth && !svgHeight) {
            var viewBox = svgXML.getAttribute('viewBox').split(/\s+|,/);
            svgWidth = viewBox[2];
            svgHeight = viewBox[3];
        }

        if (scale) {
            if (svgWidth && svgHeight) {
                width = svgWidth * scale;
                height = svgHeight * scale;
            } else {
                break resize;
            }
        }

        svgXML.setAttribute('width', width.toString() + 'px');
        svgXML.setAttribute('height', height.toString() + 'px');

        svg = [ (new XMLSerializer()).serializeToString(svgXML) ];
    }

    try {
        var blob = new window.Blob(svg, { type: 'image/svg+xml;charset=utf-8' });
    } catch (e) {
        this.onProcessError();
        return;
    }

    this.data = new Image();
    this.data.crossOrigin = this.crossOrigin;

    var _this = this;
    var retry = false;

    this.data.onload = function () {
        if (!retry) {
            File.revokeObjectURL(_this.data);
        }
        _this.onProcessComplete();
    };

    this.data.onerror = function () {
        if (!retry) {
            retry = true;
            File.revokeObjectURL(_this.data);
            _this.data.src = 'data:image/svg+xml,' + encodeURIComponent(svg.join(''));
        } else {
            _this.onProcessError();
        }
    };

    if (isIOS) {
        // Special handling for iOS
        this.data.src = 'data:image/svg+xml,' + encodeURIComponent(svg.join(''));
    } else {
        File.createObjectURL(this.data, blob, 'image/svg+xml');
    }
}
  1. Update LoaderPlugin.js: Ensure that the SVG file type is registered correctly.
// Inside LoaderPlugin.js
FileTypesManager.register('svg', function (key, url, svgConfig, xhrSettings) {
    if (Array.isArray(key)) {
        for (var i = 0; i < key.length; i++) {
            this.addFile(new SVGFile(this, key[i]));
        }
    } else {
        this.addFile(new SVGFile(this, key, url, svgConfig, xhrSettings));
    }
    return this;
});
  1. Check TextureManager.js: Ensure that the texture is added correctly.
// Inside TextureManager.js
addImage: function (key, source, dataSource) {
    var texture = null;
    if (this.checkKey(key)) {
        texture = this.create(key, source);
        Parser.Image(texture, 0);
        if (dataSource) {
            texture.setDataSource(dataSource);
        }
        this.emit(Events.ADD, key, texture);
        this.emit(Events.ADD_KEY + key, texture);
    }
    return texture;
}

These changes should help in handling SVG images on iOS devices.

References

/src/loader/filetypes/SVGFile.js /src/loader/LoaderPlugin.js /src/textures/TextureManager.js /src/gameobjects/image/Image.js

#### About Greptile This response provides a starting point for your research, not a precise solution. Help us improve! Please leave a ๐Ÿ‘ if this is helpful and ๐Ÿ‘Ž if it is irrelevant. [Ask Greptile](https://app.greptile.com/chat/github/phaserjs/phaser/master) ยท [Edit Issue Bot Settings](https://app.greptile.com/apps/github)
photonstorm commented 4 months ago

It can (see image below) - but you shouldn't load SVGs via load.image. Use load.svg for this, or use bitmap images. iOS does something weird when loading SVGs as Image data, which for some reason often takes a while for them to decode. In short, don't do it the way you're doing it.

image