"Canvas 2D for generating text labels" for new script

Tutorial: Canvas Text was very useful for me.

But I can’t find update code of it for new script.
So I do it like below.
one function is added. if you want change the text string, you will fire event with new text and name.
By this, same named objects are update at once. How about this?

var Text = pc.createScript('text');

Text.attributes.add("text", {
    type: "string",
    default: "hello world",
});

Text.attributes.add("name", {
    type: "string",
    default: "text",
});

// initialize code called once per entity
Text.prototype.initialize = function() {
    var self = this;
    
   // fires only for `text` attribute
    this.on("attr:text", function (value, prev) {
        this.updateText();
    });
    
    // Create a canvas to do the text rendering
    this.canvas = document.createElement('canvas');
    this.canvas.height = 128;
    this.canvas.width = 512;
    this.context = this.canvas.getContext('2d');

    this.texture = new pc.Texture(app.graphicsDevice, {
        format: pc.PIXELFORMAT_R8_G8_B8,
        autoMipmap: true
    });
    this.texture.setSource(this.canvas);
    this.texture.minFilter = pc.FILTER_LINEAR_MIPMAP_LINEAR;
    this.texture.magFilter = pc.FILTER_LINEAR;
    this.texture.addressU = pc.ADDRESS_CLAMP_TO_EDGE;
    this.texture.addressV = pc.ADDRESS_CLAMP_TO_EDGE;

    this.updateText();

    var material = this.entity.model.material;
    material.emissiveMap = this.texture;
    material.opacityMap = this.texture;
    material.blendType = pc.BLEND_NORMAL;
    material.update();
    
    //regist eventhandler
    this.app.off("updateText");
    this.app.on("updateText", function(name, newText){
        //if only name is matched, it will update text
        if(self.name === name){
            self.text = newText;
        }
    });
};

// update code called every frame
Text.prototype.update = function(dt) {
    
};

// swap method called for script hot-reloading
// inherit your script state here
Text.prototype.swap = function(old) {
    
};

Text.prototype.updateText = function () {
    var ctx = this.context;
    var w = ctx.canvas.width;
    var h = ctx.canvas.height;

    // Clear the context to transparent
    ctx.fillStyle = 'black';
    ctx.fillRect(0, 0, w, h);

    // Write white text
    ctx.fillStyle = 'white';
    ctx.font = 'bold 48px Verdana';
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle';
    ctx.fillText(this.text, w / 2, h / 2);

    // Copy the canvas into the texture
    this.texture.upload();
};


// to learn more about script anatomy, please read:
// http://developer.playcanvas.com/en/
1 Like

I think you should call self.updateText(); instead.

Better to remove those functions if you don’t use them for better performance.

1 Like

Wow, I’m very ashamed.
It have been updated.
I did as a misunderstanding
Please close this topic. :sweat:

@vaios, thank you.

I think that if it update the view only, the text attribute value will not change.
So I write as this.

at this project, I use this code.
https://playcanvas.com/project/416595/overview/workshop0824cedec2016

now I have updated the code by your suggestion.
Very thanks.

I found a bug here.

“app.graphicsDevice” is not correct.
That code run success at booting from lauch button. but at publish, that code run as error.

“this.app.graphicsDevice” is good.

1 Like

Yes, it shall be this.app, there is a global variable called app in launcher, we have a ticket to rename it so to avoid this unpleasant collision here.

I’ve tried using this to draw text, however it only seems to work with bright colors, such as white, red and yellow. Anything dark like blue or black gets blended away, essentially disappears.

Hi @standardcombo. Can you post the link to a small reproducible case that shows this issue? I can seem to reproduce it myself.