DEV Community

Richard Fu for RF Game Dev

Posted on • Originally published at richardfu.net on

Optimizing Scalable UI Elements with Pixi.js NineSlicePlane

Transitioning from Unity to Pixi.js, one noticeable absence was the sliced sprites, especially when working on resizable UI elements like progress bars. Thankfully, Pixi.js offers a comparable component known as NineSlicePlane, which resembles Unity’s sliced sprites in function. Although there are few resources and examples available for NineSlicePlane, this article aims to delve deeper into its behavior and outline how it aligns with my expectations.

TL;DR: The code used in this article is available on CodePen.

Usage

Let’s consider the example of a progress bar. First, using Pixi’s Sprite:




<Sprite 
    image="progress_bar.png"
    width={103}
    height={44}
/>



Enter fullscreen mode Exit fullscreen mode

In this instance, I’m employing ReactPixi for code readability, setting the sprite’s dimensions to the exact texture size (103px × 44px).

Using NineSlicePlane is quite straightforward. We merely specify the width and height of both sides in pixels on the texture, effectively dividing the texture into nine segments. In this example, we use 20px width for both sides and 0px height (extending the progress bar horizontally):




<NineSlicePlane
    image="progress_bar.png"
    leftWidth={20}
    topHeight={0}
    rightWidth={20}
    bottomHeight={0}
    width={240}
    height={44}
/>



Enter fullscreen mode Exit fullscreen mode

This approach works well, allowing us to easily adjust the width to achieve the desired length for the progress bar.

Screenshot 1: Sprite & NineSlicePlane
Screenshot 1: Sprite & NineSlicePlane

Issue – Scaling

On occasion, we might need to scale up the width and height of the progress bar, making it fit within its parent container. For example, if we attempt to double the width and height:




<NineSlicePlane 
    image="progress_bar.png"
    leftWidth={20}
    topHeight={0}
    rightWidth={20}
    bottomHeight={0}
    width={480}
    height={88}
/>



Enter fullscreen mode Exit fullscreen mode

Drawing from Unity’s experience, I anticipated that this should work, and Pixi should simply scale the NineSlicePlane‘s size by a factor of 2. However, the edges do not extend as expected. In fact, NineSlicePlane maintains the length of the edges, which aligns with its document behavior:



areas 1 3 7 and 9 will remain unscaled


For further experimentation, what if we also scale up the edge options?




<NineSlicePlane 
    image="progress_bar.png"
    leftWidth={40}
    topHeight={0}
    rightWidth={40}
    bottomHeight={0}
    width={480}
    height={88}
/>



Enter fullscreen mode Exit fullscreen mode

This adjustment doesn’t alter anything or even results in more distortion depending on the texture. This is because the edge sizes should be relative to the texture sizes, not the actual canvas sizes.

Screenshot 2: Scaling up NineSlicePlane with width and height
Screenshot 2: Scaling up NineSlicePlane with width and height

Solution 1 – Adjust Texture Size

One workaround is to make the texture pixel-perfect, where texture sizes always match the sprite canvas size. In the example above, if we want to double the sprite canvas size, we must double the progress bar’s texture size as well. This makes the previous code work as expected.

From an artistic standpoint, this is a viable solution as scaling up the sprite in the canvas without scaling up the texture can lead to pixelation.

However, this solution is not scalable when we need various progress bar sizes, depending on the parent’s container or different sizes for desktop and mobile. It’s suitable only for fixed-size progress bars.

Solution 2 – Utilize scale

Similar to other Pixi components, NineSlicePlane features a scale option that allows us to achieve the desired scaling:




<NineSlicePlane 
    image="progress_bar.png"
    leftWidth={20}
    topHeight={0}
    rightWidth={20}
    bottomHeight={0}
    width={240}
    height={44}
    scale={[2, 2]}
/>



Enter fullscreen mode Exit fullscreen mode

Screenshot 3: Scaling up NineSlicePlane with scale
Screenshot 3: Scaling up NineSlicePlane with scale

However, this approach requires calculating the scale every time, if we only know the desired length:




scale = widthInCanvas / WIDTH_IN_TEXTURE



Enter fullscreen mode Exit fullscreen mode

A tradeoff here is that we cannot use the scale option in other scenarios. For instance, if we want a button within a NineSlicePlane to scale up or down when clicked, we’ll need to wrap the button in another Container.

Summary

NineSlicePlane operates somewhat differently from Unity’s sprite, necessitating some special considerations. Nevertheless, it remains a functional solution that we can easily work with. Once again, the example code is available on CodePen. Peace!

The post Optimizing Scalable UI Elements with Pixi.js NineSlicePlane appeared first on Richard Fu.

Top comments (0)