mimshwright / pixi-tagged-text

A component for pixi similar to Text that supports multiple styles in a single component as well as inline images.
MIT License
31 stars 15 forks source link

Setting an anchor doesn't affect tagged text #268

Open wmike1987 opened 2 years ago

wmike1987 commented 2 years ago

Example from the demo:

            const basicText = `Let's make some
                  <ml>multiline</ml>
                  and <ms>multistyle</ms> text for
                  <pixi>Pixi.js!</pixi>`;

            const basicStyle = {
              default: {
                fontSize: "24px",
                fill: "#cccccc",
                align: "center",
              },
              ml: {
                fontStyle: "italic",
                fill: "#ff8888",
                fontSize: "40px",
              },
              ms: {
                fontWeight: "bold",
                fill: "#4488ff",
                fontSize: "40px",
              },
              pixi: {
                fontSize: "64px",
                fill: "#efefef",
              },
            };

            const basic = new TaggedText(basicText, basicStyle, {});

            //Added this line to the demo
            basic.anchor = {x: 0.5, y: 0.5};

Setting the anchor has no effect on the tagged-text placement.

mimshwright commented 2 years ago

Can you please add a description of what you expect to happen? If possible include an image or sketch.

On Thu, Jun 30, 2022, 07:05 wmike1987 @.***> wrote:

Example from the demo:

        const basicText = `Let's make some                  <ml>multiline</ml>                  and <ms>multistyle</ms> text for                  <pixi>Pixi.js!</pixi>`;

        const basicStyle = {
          default: {
            fontSize: "24px",
            fill: "#cccccc",
            align: "center",
          },
          ml: {
            fontStyle: "italic",
            fill: "#ff8888",
            fontSize: "40px",
          },
          ms: {
            fontWeight: "bold",
            fill: "#4488ff",
            fontSize: "40px",
          },
          pixi: {
            fontSize: "64px",
            fill: "#efefef",
          },
        };

        const basic = new TaggedText(basicText, basicStyle, {});

        //Added this line to the demo
        basic.anchor = {x: 0.5, y: 0.5};

Setting the anchor has no effect on the tagged-text placement.

— Reply to this email directly, view it on GitHub https://github.com/mimshwright/pixi-tagged-text/issues/268, or unsubscribe https://github.com/notifications/unsubscribe-auth/AABCU2GRSOKTVVY56VWQLZLVRWSSLANCNFSM52JPSTEA . You are receiving this because you are subscribed to this thread.Message ID: @.***>

wmike1987 commented 2 years ago

Here's a sample pixi playground with the effect of an anchor: https://www.pixiplayground.com/#/edit/EUqEbIdDK0gfM18V0_bLr

In my particular use-case, I'd like the tagged text to be centered at the position I give it (for other sprites and regular pixi Text, I use an anchor of 0.5 to achieve this).

mimshwright commented 2 years ago

This may be a little bit difficult. Both Sprite and Text define anchor based on the Texture used to render them. But TaggedText is a Container and Container doesn't have anchor. So i think it would be possible to either

  1. Make it a sprite instead of a container to see if that fixes (or breaks) it
  2. Manually implement anchor, at least for positioning, but maybe not for rotation (does it affect rotation?) But this could also be more complicated than it sounds.
  3. Might be possible to use the TaggedText instances pixel data to create a new texture for a sprite that would support anchor, or something like that.

Unfortunately, i am really busy at the moment moving house so it will be a while before j can fix it. Feel free to make a PR if you want to try it yourself.

On Thu, Jun 30, 2022, 08:50 wmike1987 @.***> wrote:

Here's a sample pixi playground with the effect of an anchor: https://www.pixiplayground.com/#/edit/EUqEbIdDK0gfM18V0_bLr

In my particular use-case, I'd like the tagged text to be centered at the position I give it (for other sprites and regular pixi Text, I use an anchor of 0.5 to achieve this).

— Reply to this email directly, view it on GitHub https://github.com/mimshwright/pixi-tagged-text/issues/268#issuecomment-1171386430, or unsubscribe https://github.com/notifications/unsubscribe-auth/AABCU2EZPZ7IIQ53ZLA4KJLVRW637ANCNFSM52JPSTEA . You are receiving this because you commented.Message ID: @.***>

mimshwright commented 2 years ago

Apologies. I am totally wrong. TaggedText extends Sprite not Container. I wrote that while I was away from my computer and should have checked first. So I gues that eliminates #1 and maybe #3.

I think next step is to create some tests or some way to figure out what the current behaviour is and why it's not working and what the behaviour should be.

neymanushka commented 1 year ago

any fixes or recipes how to make anchor work?)

nz771202 commented 7 months ago

The pivot of the container could be used for this. Basically just get the local bounds of the container, and multiply its width/height by the anchor to get the pivot. For example, this seems to work (in TS, overriding the TaggedText's anchor callback, so you can set the anchor as normal):

export class TaggedTextMod extends TaggedText {
    constructor(...args: ConstructorParameters<typeof TaggedText>) {
        super(...args);
        const origCb = this.anchor.cb;
        this.anchor.cb = function() {
            origCb.call(this);
            const bounds = this.getLocalBounds();
            this.pivot.set(bounds.width * this.anchor.x, bounds.height * this.anchor.y);
        };
    }
}

The drawback is that it doesn't update when the contents change. Maybe you could do the pivot update inside updateTransform, e.g.:

class TaggedTextMod extends TaggedText {
    private exitFlag = false; // prevent infinite recursive updateTransform calls

    public override updateTransform() {
        if (this.exitFlag) return;
        this.exitFlag = true;
        const bounds = this.getLocalBounds();
        this.exitFlag = false;
        this.pivot.set(bounds.width * this.anchor.x / this.scale.x, bounds.height * this.anchor.y / this.scale.y);
        super.updateTransform();
    }
}
geraldzm commented 3 weeks ago

@nz771202 thanks to your comment, I was able to get it working by doing this.


class TaggedTextMod extends TaggedText {
  constructor() {
    // any anchor you want
    this.anchor.set(0.5);
  }
  private _updateLock = false;

  public override updateTransform() {
    if (this._updateLock) return super.updateTransform();

    this._updateLock = true;

    // Store original properties
    const originalAnchor = this.anchor.clone();
    const originalPivot = this.pivot.clone();

    // Calculate and set the pivot
    const bounds = this.getLocalBounds();
    this.pivot.set(bounds.width * this.anchor.x, bounds.height * this.anchor.y);

    // Perform the transform
    super.updateTransform();

    // Restore original properties
    this.anchor.copyFrom(originalAnchor);
    this.pivot.copyFrom(originalPivot);

    // Adjust position to maintain visual position
    const dx = (this.anchor.x - originalAnchor.x) * this.width;
    const dy = (this.anchor.y - originalAnchor.y) * this.height;
    this.position.x +=
      dx * Math.cos(this.rotation) + dy * Math.sin(this.rotation);
    this.position.y +=
      -dx * Math.sin(this.rotation) + dy * Math.cos(this.rotation);

    this._updateLock = false;
  }
}