npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@md5crypt/layout-pixi

v2.0.6

Published

pixi support for @md5crypt/layout

Downloads

118

Readme

PIXI layout engine

This package builds on top of @md5crypt/layout to provide a layout engine for PIXI.js. Reading that package's docs is recommended before starting doing anything with this one.

Layout elements

The following layout elements are available:

| type | class | description | |:---|:---:|:---| | container | ContainerElement | container for other elements | | graphic | GraphicElement | allows drawing shapes with PIXI.Graphics | | sprite | SpriteElement | for displaying textures | | sprite-sliced | SlicedSpriteElement | a 9-slice mesh element | | sprite-tiling | TiledSpriteElement | allows drawing repeated backgrounds | | text | TextElement | renders text using PIXI.Text | | - | RootElement | meant to be used as the layout root element |

BaseElement

abstract class BaseElement extends LayoutElement

Configuration reference

| filed | type | default | description | |:---|:---:|:---:|:---| | mask | boolean | false | when set to true a PIXI mask is used to clip the element's content to it's size. | | sorted | boolean | false | enables z-index sorting of children for this container. Note that z-index sorting works only for direct children | | zIndex | number | 0 | z-index value of the element, only meangfull if parent has z-index sorting enabled | | alpha | number | 1 | opacity of the element | | rotation | number | 0 | rotation around the center of the element, value in degrees | | flipped | false "vertical" "horizontal" | false | should the element be mirrored vertically / horizontally | | interactive | boolean | false | enables interaction events on the underling PIXI object | | noPropagation | boolean | false | sets interactiveChildren to false on the underling PIXI object disabling interaction event propagation | | anchor | number [number, number] | 0 | sets the anchor point (0.5 being the center) used for element positioning. If a single number is provided it is used for both axis. This not the same as PIXI's anchor property its used only for positioning, the pivot point used for rotation and scaling is set always to the element's center.

Properties reference

| filed | type | description | |:---|:---:|:---| | handle | PIXI.DisplayObject | (readonly) a reference to the underlying PIXI object that this element is using. | | sorted | boolean | see sorted in configuration | | zIndex | number | see zIndex in configuration | | alpha | number | see alpha in configuration | | rotation | number | see rotation in configuration | | flipped | false "vertical" "horizontal" | see flipped in configuration | | interactive | boolean | see interactive in configuration | | noPropagation | boolean | see noPropagation in configuration | | mask | boolean | see mask in configuration | | anchor | [number, number] | see anchor in configuration | | scale | number | (readonly) the scale of the current element | | globalScale | number | (readonly) the global scale of the current element (relative to the layout's root element) | | globalBoundingBox | {top: number, left: number, width: number, height: number} | (readonly) the global position of the object (relative to the layout's root element) |

Function reference

| name | signature | description | |:---|:---:|:---| | setAnchor | (x: number, y?: number) => void | an alternative way to set the anchor property | | on | (event: string, callback: Function) => void | passthrough to the underlying PIXI object's on function.

ContainerElement (container)

class ContainerElement extends BaseElement

Configuration reference

| filed | type | default | description | |:---|:---:|:---:|:---| | scale | boolean | 1 | The element's scale. The scale does not change the element's dimensions, it's applied after the layout has been computed.

Properties reference

| filed | type | description | |:---|:---:|:---| | handle | PIXI.Container | (readonly) reference to the underlying PIXI object. | scale | boolean | see scale in configuration |

GraphicElement (graphic)

class GraphicElement extends BaseElement

Configuration reference

| filed | type | default | description | |:---|:---:|:---:|:---| | onDraw | (self: GraphicElement) => void | undefined | A callback called every time the objects needs to be redrawn. Clear is called automatically before calling onDraw.

Properties reference

| filed | type | description | |:---|:---:|:---| | handle | PIXI.GraphicElement | (readonly) reference to the underlying PIXI object. | onDraw | (self: GraphicElement) => void | see onDraw in configuration |

SpriteElement (sprite)

class SpriteElement extends BaseElement

Configuration reference

| filed | type | default | description | |:---|:---:|:---:|:---| | image | string PIXI.Texture null | null | Texture the element should use, see the LayoutFactory documentation below to see how string value are resolved. When null Texture.WHITE is used. | | scaling | ScalingType | "none" | controls how the texture is scaled to fit the layout element. See ScalingType description in the section below. | | verticalAlign | "top" "middle" "bottom" | "top" | controls how the texture should be positioned inside the container. | | horizontalAlign | "left" "center" "right" | "left" | controls how the texture should be positioned inside the container. | | tint | number | 0xFFFFFF | tint applied to the texture |

Properties reference

| filed | type | description | |:---|:---:|:---| | handle | PIXI.Sprite | (readonly) reference to the underlying PIXI object. | image | string PIXI.Texture null | see image in configuration | | scaling | ScalingType | see scaling in configuration | | verticalAlign | "top" "middle" "bottom" | see verticalAlign in configuration | | horizontalAlign | "left" "center" "right" | see horizontalAlign in configuration | | tint | number | see tint in configuration |

Texture scaling modes

| mode | description | |:---:|:---| | none | texture is positioned inside the element based on verticalAlign and horizontalAlign and no additional transformations are applied | | clipped | same as none but the texture is cropped to the element size after positioning. The same can be achieved using mask = true but the scaling mode is more efficient as it does not interrupt batch rendering with masks. | | stretch | stretch the texture to fit the element, verticalAlign and horizontalAlign are ignored | | contain | scale the image maintaining aspect ratio in such a way that the entire image is visible. verticalAlign and horizontalAlign are used to position the texture. | | cover | scale and crop the image maintaining the aspect ratio in such a way that the entire element is filled. verticalAlign and horizontalAlign are used to position the texture before cropping. |

SlicedSpriteElement (sprite-sliced)

class SlicedSpriteElement extends BaseElement

Configuration reference

| filed | type | default | description | |:---|:---:|:---:|:---| | image | string PIXI.Texture null | null | Texture the element should use, see the LayoutFactory documentation below to see how string value are resolved. When null Texture.WHITE is used. | | tint | number | 0xFFFFFF | tint applied to the texture | | slices | PositioningBox | 0 | the slicing regions, uses PositioningBox from @md5crypt/layout. |

Properties reference

| filed | type | description | |:---|:---:|:---| | handle | PIXI.NineSlicePlane | (readonly) reference to the underlying PIXI object. | image | string PIXI.Texture null | see image in configuration | | tint | number | see tint in configuration |

Function reference

| name | signature | description | |:---|:---:|:---| | setSlices | (slices: PositioningBox) => void | allows updating the slicing regions |

TiledSpriteElement (sprite-tiled)

class TiledSpriteElement extends BaseElement

Configuration reference

| filed | type | default | description | |:---|:---:|:---:|:---| | image | string PIXI.Texture null | null | Texture the element should use, see the LayoutFactory documentation below to see how string value are resolved. When null Texture.WHITE is used. | | tint | number | 0xFFFFFF | tint applied to the texture |

Properties reference

| filed | type | description | |:---|:---:|:---| | handle | PIXI.TilingSprite | (readonly) reference to the underlying PIXI object. | image | string PIXI.Texture null | see image in configuration | | tint | number | see tint in configuration |

TextElement (text)

class TextElement extends BaseElement

Configuration reference

| filed | type | default | description | |:---|:---:|:---:|:---| | text | string | "" | Text to render. | | fit | boolean | true | Should the text be shrank to fit the element. See text fitting section below for more details. | | verticalAlign | "top" "bottom" "middle" | "top" | controls how the text is positioned inside the element. For horizontal control set text align in text style. | | style | PIXI.ITextStyle | {} | The text style to use for the text. | | resolution | number | 1 | the resolution the text should be rendered at. The actual text resolution is computed based on the element's global scale, this value multiplies that value allowing for oversampling. | | roundPixels | boolean | false | sets roundPixels in the underlying PIXI object. In theory this can improve text readability. |

Properties reference

| filed | type | description | |:---|:---:|:---| | handle | PIXI.Text | (readonly) reference to the underlying PIXI object. | text | string | see text in configuration | | fit | boolean | see fit in configuration | | verticalAlign | "top" "bottom" "middle" | see verticalAlign in configuration | | resolution | number | see resolution in configuration | | roundPixels | boolean | see roundPixels in configuration |

Function reference

| name | signature | description | |:---|:---:|:---| | setStyle | (style: Partial<ITextStyle>) => void | sets the text style. | | updateStyle | (style: Partial<ITextStyle>) => void | updates the current style by merging it with the provided object. | | setText | setText(text: string, style?: Partial<ITextStyle>) => void | A convenience function that allows setting the text and style at the same time. |

Text fitting

If text fitting is enabled the text font size will be automatically decreased to fit the element size. Text fitting will never increase the configured font size it will only decrease it.

Text fitting operates in two modes:

  • If word wrap is disabled, a single iteration is made to compute the target font size, as no re-flow is needed.
  • If word wrap is enabled, a binary search is executed to find the target font size. The search is capped at 8 iterations.

RootElement (root)

class RootElement extends BaseElement

The RootElement class is meant to be used as the layout root. It can not be crated via the factory and is meant to be crated by its constructor.

RootElement has a pre-configured layout config of volatile = true, a hardcoded name @root and type equal to root.

Note that RootElement does not have to be used as the root element. For example a ContainerElement will do just as well.

Properties reference

| filed | type | description | |:---|:---:|:---| | handle | PIXI.Container | (readonly) reference to the underlying PIXI object. | scale | boolean | sets the base scale for the entire layout |

Function reference

| name | signature | description | |:---|:---:|:---| | constructor | (factory: LayoutFactory, config?: BaseConfig) => RootElement | the intended way of creating a RootElement instance |

Layout factory

The layout factory shipped with this package extends the LayoutFactory from @md5crypt/layout with a few additional features.

Default values

Default config / layout values can be set for created elements. The defaults can be set for all elements or for specific element types individually. This can be done by calling setDefaults on a factory instance.

Texture resolver

Layout elements using textures allow them to be reference via string names. These string names will be resolved using the factories resolveAsset function, which by default will fail with an exception.

To use this feature a onResolveAsset callback must be set that accepts string names and returns texture instances.

Properties reference

| filed | type | description | |:---|:---:|:---| | onResolveAsset | (key: string) => Texture | the texture resolver callback used by resolveAsset

Function reference

| name | signature | description | |:---|:---:|:---| | setDefaults | (defaults: ElementDefaults): void | sets default values for all created elements. | | setDefaults | (type: string, defaults: ElementDefaults): void | sets default values for created elements of a given type. |

Using the module

There are two ways to use this library. The simplest one is to just import layoutFactory from @md5crypt/layout-pixi. This will create a default LayoutFactory instance with all the element types registered.

For some applications this can be unwanted as it will bloat the output code with all the element implementations and their underlying PIXI objects.

To avoid this, the individual elements can be imported one by one and registered to a custom factory instance. For example, if all we need is the container and sprite elements, we can do the following:

import ContainerElement from "@md5crypt/layout-pixi/ContainerElement"
import SpriteElement from "@md5crypt/layout-pixi/SpriteElement"
import LayoutFactory from "@md5crypt/layout-pixi/LayoutFactory"

const layoutFactory = new LayoutFactory()

ContainerElement.register(layoutFactory)
SpriteElement.register(layoutFactory)

Using JSX for writing layouts

JSX bindings are provided as an alternative way for writing the layout configurations.

To use the provided JSX bindings where intended to be used with typescript (tsconfig.json should have jsx set to react).

To use the bindings simply cerate a .tsx file and add the following import:

import React from "@md5crypt/layout-pixi/JSXSupport"

JSX.Element is assignable to LayoutElementJSON and can be passed directly to the layout factory.

One gotcha to watch out for is a top level React.Fragment which will result with a element of type jsx-fragment that the factory will refuse to create. To solve this React.toArray can be used. For more details about this function see the reference section below.

Basic syntax

The tag names are mapped to element types, so <container/> will be compiled into {type: "container"}.

All keys from layout and config objects are merged into a single property namespace, together with name and metadata.

So <sprite name="hello" width={100} image="foo" /> will be compiled into

{
    "type": "sprite",
    "name": "hello",
    "layout": {
        "width": 100
    },
    "config": {
        "image": "foo"
    }
}

This (obviously) means that config and layout keys can not overlap.

Components

Stateless function components are supported, see example below:

const Foo = (props: {name: string, children?: React.ReactNode}) => (
    <container name={props.name}>
        {props.children}
    </container>
)

<Foo name="bar">
    <sprite image="foo-bar" />
</Foo>

This will be compiled to:

{
    "type": "container",
    "name": "bar",
    "children": [
        {
            "type": "sprite",
            "config": {
                "image": "foo-bar"
            }
        }
    ]
}

Slots

As a bonus basic slot support was added, see example below:

const Foo = (props: {children?: React.ReactNode}, slots: React.Slots<"bar">) => (
    <container name={props.name}>
        {slots.bar}
        <container>
            {props.children}
        </container>
    </container>
)

<Foo>
    <React.Slot name="bar">
        <sprite image="rab-oof" />
    </React.Slot>
    <sprite image="foo-bar" />
</Foo>

This will be compiled to:

{
    "type": "container",
    "children": [
        {
            "type": "container",
            "children": [
                {
                    "type": "sprite",
                    "config": {
                        "image": "rab-oof"
                    }
                }
            ]
        },
        {
            "type": "sprite",
            "config": {
                "image": "foo-bar"
            }
        }
    ]
}

Function reference

| name | signature | description | |:---|:---:|:---| | React.Fragment | (props: {children?: ReactNode}) => JSX.Element | The build-in Fragment component | | React.Slot | (props: {name: string, children?: ReactNode}) => JSX.Element | The build-in Slot Component | | React.isFragment | (element: JSX.Element) => boolean | returns true if the passed element is a top-level fragment element | | React.toArray | (element: JSX.Element) => JSX.Element[] | for a top-level fragment will return its children. For other elements will return the same element by wrapped in an array. This function is needed to unpack a top-level React.Fragment as layout factory will refuse to render it. | | React.createElement | (type, props, ...children) => JSX.Element | the internal function JSX gets compiled into |

Type reference

| name | description | |:---:|:---| | React.ReactNode | Type to use for JSX children | | React.Slots<T> | Type to use for the slot parameter, T should be a union of literal strings that will be used as keys. | | React.ComponentProps<T> | Gets the type of properties of the given component. Works for intrinsic elements (like "sprite") as well as for user defined function components. |

Implementing new elements

New element types can be easily added outside the module's code. Let's use the following example implementation of an simple AnimatedSpriteElement to explain the process.


import {
    // our new element will extend BaseElement so it needs to be imported
    BaseElement,

    // the new element's config will extend BaseElement config
    BaseConfig,

    // this is the type of BaseElement's constructor parameter
    BaseConstructorProperties
} from "@md5crypt/layout-pixi/BaseElement"

// we need that type for the register function
import type LayoutFactory from "@md5crypt/layout-pixi/LayoutFactory"

// PIXI stuff that will be needed
import { Texture } from "@pixi/core"
import { AnimatedSprite } from "@pixi/sprite-animated"

// Here we define the element's config properties that will be available in LayoutElementJSON
export interface AnimatedSpriteElementConfig extends BaseConfig {
    images?: (Texture | string)[]
    playing?: boolean
}

export class AnimatedSpriteElement extends BaseElement {
    // we must override handle type to match the PIXI object that this element will use
    declare public handle: AnimatedSprite

    // the static register function that is used to add the element to the layout factory
    public static register(layoutFactory: LayoutFactory) {
        layoutFactory.register("sprite-animated", (factory, name, config) => new this({
            factory,
            name,
            config,
            type: "sprite-animated",
            // the PIXI object instance this element will be using
            handle: new AnimatedSprite([])
        }))
    }

    constructor(props: BaseConstructorProperties<AnimatedSpriteElementConfig>) {
        super(props)
    
        // BaseElement expects all PIXI object's to anchored at the center
        this.handle.anchor.set(0.5, 0.5)
        const config = props.config

        // apply config (if provided)
        if (config) {
            if (config.images) {
                this.images = config.images
            }
            if (config.playing) {
                this.handle.play()
            }
        }
    }

    public set images(value: (Texture | null | string)[]) {
        // here we resolve the string names to Textures using factory.resolveAsset
        this.handle.textures = value.map(x => this.factory.resolveAsset(x))

        // changing the texture can change the element dimensions so we must notify
        // the underlying LayoutElement that its layout must be recalculated
        this.setDirty()
    }

    public get playing() {
        return this.handle.playing
    }

    public set playing(value: boolean) {
        if (value) {
            this.handle.play()
        } else {
            this.handle.stop()
        }
    }

    // this is called every time the layout has changed
    protected onUpdate() {        
        super.onUpdate()

        // we must set the PIXI object's position
        // in most cases the computedLeft / computedTop helper properties from BaseElement can be used
        this.handle.position.set(this.computedLeft, this.computedTop)

        // no fancy scaling options, just stretch the sprite to size
        this.handle.width = this.innerWidth
        this.handle.height = this.innerHeight
    }

    // we must override contentHeight and contentWidth to let the layout know what size
    // is this element's content (in this case the texture dimensions)

    public get contentHeight() {
        return (this.handle.textures[0] as Texture).height
    }

    public get contentWidth() {
        return (this.handle.textures[0] as Texture).width
    }
}

export default AnimatedSpriteElement

// we must inject the new element to the type system by adding
// it to a special interface declared inside the layout-pixi package
declare module "@md5crypt/layout-pixi/ElementTypes" {
    export interface ElementTypes {
        "sprite-animated": {
            config: AnimatedSpriteElementConfig,
            element: AnimatedSpriteElement
        }
    }
}

Remember that the created AnimatedSpriteElement class must be registered in a LayoutFactory instance using AnimatedSpriteElement.register.

If the element type was correctly injected into ElementTypes LayoutElementJSON and JSX elements should automatically recognize the new element type.