Skip to content

Commit

Permalink
feat: [#150] Support SVG images
Browse files Browse the repository at this point in the history
closes: #150
  • Loading branch information
eonarheim committed Oct 14, 2024
1 parent 2505a92 commit 6dea923
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 16 deletions.
38 changes: 38 additions & 0 deletions sandbox/src/game.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,12 +152,50 @@ cards2.draw(game.graphicsContext, 0, 0);

jump.volume = 0.3;

var svg = (tags: TemplateStringsArray) => tags[0];

var svgImage = ex.ImageSource.fromSvgString(svg`
<svg version="1.1"
id="svg2"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
sodipodi:docname="resize-full.svg" inkscape:version="0.48.4 r9939"
xmlns="http://www.w3.org/2000/svg"
width="800px" height="800px"
viewBox="0 0 1200 1200" enable-background="new 0 0 1200 1200" xml:space="preserve">
<path id="path18934" fill="#000000ff" inkscape:connector-curvature="0" d="M670.312,0l177.246,177.295L606.348,418.506l175.146,175.146
l241.211-241.211L1200,529.688V0H670.312z M418.506,606.348L177.295,847.559L0,670.312V1200h529.688l-177.246-177.295
l241.211-241.211L418.506,606.348z"/>
</svg>
`);

var svgActor = new ex.Actor({
name: 'svg',
pos: ex.vec(200, 200)
});
svgActor.graphics.add(
svgImage.toSprite({
destSize: {
width: 100,
height: 100
},
sourceView: {
x: 400,
y: 0,
width: 400,
height: 400
}
})
);
game.add(svgActor);

var boot = new ex.Loader();
// var boot = new ex.Loader({
// fullscreenAfterLoad: true,
// fullscreenContainer: document.getElementById('container')
// });
// boot.suppressPlayButton = true;
boot.addResource(svgImage);
boot.addResource(heartImageSource);
boot.addResource(heartTex);
boot.addResource(imageRun);
Expand Down
31 changes: 17 additions & 14 deletions src/engine/Graphics/ImageSource.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { Resource } from '../Resources/Resource';
import { Sprite } from './Sprite';
import { Sprite, SpriteOptions } from './Sprite';
import { Loadable } from '../Interfaces/Index';
import { Logger } from '../Util/Log';
import { ImageFiltering } from './Filtering';
import { Future } from '../Util/Future';
import { TextureLoader } from '../Graphics/Context/texture-loader';
import { ImageWrapping } from './Wrapping';
import { GraphicOptions } from './Graphic';

export interface ImageSourceOptions {
filtering?: ImageFiltering;
Expand Down Expand Up @@ -75,27 +76,27 @@ export class ImageSource implements Loadable<HTMLImageElement> {

/**
* The path to the image, can also be a data url like 'data:image/'
* @param path {string} Path to the image resource relative from the HTML document hosting the game, or absolute
* @param pathOrBase64 {string} Path to the image resource relative from the HTML document hosting the game, or absolute
* @param options
*/
constructor(path: string, options?: ImageSourceOptions);
constructor(pathOrBase64: string, options?: ImageSourceOptions);
/**
* The path to the image, can also be a data url like 'data:image/'
* @param path {string} Path to the image resource relative from the HTML document hosting the game, or absolute
* @param pathOrBase64 {string} Path to the image resource relative from the HTML document hosting the game, or absolute
* @param bustCache {boolean} Should excalibur add a cache busting querystring?
* @param filtering {ImageFiltering} Optionally override the image filtering set by {@apilink EngineOptions.antialiasing}
*/
constructor(path: string, bustCache: boolean, filtering?: ImageFiltering);
constructor(path: string, bustCacheOrOptions: boolean | ImageSourceOptions | undefined, filtering?: ImageFiltering) {
this.path = path;
constructor(pathOrBase64: string, bustCache: boolean, filtering?: ImageFiltering);
constructor(pathOrBase64: string, bustCacheOrOptions: boolean | ImageSourceOptions | undefined, filtering?: ImageFiltering) {
this.path = pathOrBase64;
let bustCache: boolean | undefined = false;
let wrapping: ImageWrapConfiguration | ImageWrapping | undefined;
if (typeof bustCacheOrOptions === 'boolean') {
bustCache = bustCacheOrOptions;
} else {
({ filtering, wrapping, bustCache } = { ...bustCacheOrOptions });
}
this._resource = new Resource(path, 'blob', bustCache);
this._resource = new Resource(pathOrBase64, 'blob', bustCache);
this.filtering = filtering ?? this.filtering;
if (typeof wrapping === 'string') {
this.wrapping = {
Expand All @@ -105,9 +106,9 @@ export class ImageSource implements Loadable<HTMLImageElement> {
} else {
this.wrapping = wrapping ?? this.wrapping;
}
if (path.endsWith('.gif')) {
if (pathOrBase64.endsWith('.gif')) {
this._logger.warn(
`Use the ex.Gif type to load gifs, you may have mixed results with ${path} in ex.ImageSource. Fully supported: svg, jpg, bmp, and png`
`Use the ex.Gif type to load gifs, you may have mixed results with ${pathOrBase64} in ex.ImageSource. Fully supported: svg, jpg, bmp, and png`
);
}
}
Expand Down Expand Up @@ -153,8 +154,10 @@ export class ImageSource implements Loadable<HTMLImageElement> {
return imageSource;
}

static fromSvgElement(image: SVGElement, options?: ImageSourceOptions) {
// TODO implement
static fromSvgString(svgSource: string, options?: ImageSourceOptions) {
const blob = new Blob([svgSource], { type: 'image/svg+xml' });
const url = URL.createObjectURL(blob);
return new ImageSource(url, options);
}

/**
Expand Down Expand Up @@ -222,8 +225,8 @@ export class ImageSource implements Loadable<HTMLImageElement> {
/**
* Build a sprite from this ImageSource
*/
public toSprite(): Sprite {
return Sprite.from(this);
public toSprite(options?: Omit<GraphicOptions & SpriteOptions, 'image'>): Sprite {
return Sprite.from(this, options);
}

/**
Expand Down
5 changes: 3 additions & 2 deletions src/engine/Graphics/Sprite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,10 @@ export class Sprite extends Graphic {
public destSize: DestinationSize;
private _dirty = true;

public static from(image: ImageSource): Sprite {
public static from(image: ImageSource, options?: Omit<GraphicOptions & SpriteOptions, 'image'>): Sprite {
return new Sprite({
image: image
image,
...options
});
}

Expand Down

0 comments on commit 6dea923

Please sign in to comment.