Skip to content
This repository was archived by the owner on Jun 28, 2021. It is now read-only.

bad canvas.width calculation ? Cropping my text ??? #46

Closed
jonlepage opened this issue Jun 11, 2017 · 9 comments
Closed

bad canvas.width calculation ? Cropping my text ??? #46

jonlepage opened this issue Jun 11, 2017 · 9 comments

Comments

@jonlepage
Copy link

jonlepage commented Jun 11, 2017

Hi friend , firstly, thank you very much for your excellent work.
I am pleased to be able to exploit several color style in my project with pixi.js

I am confronted with a rather strange problem.
i have a stange CROP of my multiTextStyle

I suspect a bad calculation of canvas.width ?!
Given that you know your source code, do you have an idea why I get this bad resulta?
I put the result in the PINK background for more easy check the canva width.

sdsfsff

Here is your library that I use.

pixi-multistyle-text.zip

I will be very happy, if you could give me a idee on the current problem.
I have a bit of trouble reading and manipulating your source code.

@bluepichu
Copy link
Collaborator

Could you share the code that you're using to style the text? Being able to replicate the issue will make it a lot easier to solve.

@bluepichu bluepichu added the Bug label Jun 11, 2017
@jonlepage
Copy link
Author

The object sent to your Pixi source code is the following.
ascaegv
This object is sent to a function that does not affect the result.
This function identifies whether to use a pixi.js, or your pixiMultistyle.js
faefaegvgb

Then, a new Pixi class is called but with your source code from .pixi-multistyle-text.js
caefgvghe5

It is at this point that the calculation seems erroneous.
your pixi-multistyle-text.js used is this one
pixi-multistyle-text.zip
thank a lot

@jonlepage
Copy link
Author

jonlepage commented Jun 12, 2017

the basic code that build object MultiStyle is hard to reproduce , but is like thats.
But I do not think there is an error in the object at this stage.
``// global model style for all
$gameVariables._DefaultPixiMultiStyle = {
fontFamily: 'Anjelik',
fontSize: "20px",
fill: "#ffffff",
align: "left",
strokeThickness: 6,
letterSpacing: 2,
dropShadow: true,
dropShadowAngle: Math.PI / 6,
dropShadowDistance: 6,
dropShadowColor: 'rgba(0, 0, 0, 0.8)',
dropShadowBlur: 2,
};

// customise that use the global default styles
var defaultMultiStyles = $gameVariables._DefaultPixiMultiStyle; // default general pour tous les default
this.txtMultiStyle =[];
this.txtMultiStyle[0] = { // text description
"default": {wordWrap: true,wordWrapWidth: 460 },
"c0": {fontStyle: "italic",fill: "#ff8742"},
"c1": {fontStyle: "italic",fill: "#4281ff"},
"c2": {fontStyle: "italic",fill: "#4281ff"}
};
this.txtMultiStyle[1] = { // text description
"default": {fontSize: "17px",align: "right",letterSpacing: 3,strokeThickness: 5,},
"c0": {fontStyle: "italic",fill: "#b241f4"},
"c1": {fontStyle: "italic",fill: "#eb0e4b"},
"c2": {fontStyle: "italic",fill: "#a36506"},
"c3": {fontStyle: "italic",fill: "#f4eb41"}
};
for(var s=0;s<this.txtMultiStyle.length;s++){
for (var attrname in defaultMultiStyles) {
this.txtMultiStyle[s].default[attrname] = this.txtMultiStyle[s].default[attrname] || defaultMultiStyles[attrname];
}
}

console.log(' this.txtMultiStyle: ',  this.txtMultiStyle);

@bluepichu
Copy link
Collaborator

Taking a diff of the version you provided with the current version of this library, there's some interesting changes related to letter spacing:

-                maxLineWidth = Math.max(maxLineWidth, lineWidth);
+                // GAMEFALL CHANGES
+                var fnum = Number(sty.fontSize.match(/(\d+)/i)[0]);
+                if(sty.letterSpacing > 1) var quantity = lineWidth * (sty.letterSpacing / (1 + ((0.0315 * fnum) * (sty.letterSpacing / 2))));
+                else var quantity = lineWidth
+                maxLineWidth = Math.max(maxLineWidth, quantity);
+                //console.log(fnum);
+                //-----------------------------------------------------------------------------------------------------------------------------------
+                // ORIGINAL:
+                //maxLineWidth = Math.max(maxLineWidth, lineWidth);

I'm... dubious of the validity of these changes, and also can't really provide support if you're modifying the source. In particular, the lines you've added here have a direct impact on how wide the canvas is, so I'm going to guess there's a math error in here somewhere.

Does this perform as expected with an unmodified copy of this library? If not, I can try to figure out why not, but I wasn't able to reproduce the issue with any simple tests on an unmodified copy of PMT.

@jonlepage
Copy link
Author

thank but In fact there was too much bug and missing features.
I think your code was thinking for use in a website, but for a game, there was too much bugged.
I took a few days to completely rewrite a new, more powerful code.
He also work with sprite icon, and all align
awdcawcvawfv
acfdavavaweve

MVPixi_Text.prototype.addMultiText = function() {
    var pixiText = new PIXI.Container(); // ALPHA CONTAINER FOR MULTISTYLES (storing ALL CHILDREN TXT&STYLES)
    // put configu in the master container (will affect all child Setup)
    pixiText._text = this._text;
    pixiText._style = this._style;
    //variable
    pixiText.pixiId = this._id;
    pixiText.x = this._x;
    pixiText.y = this._y;
    pixiText.Map_X = this.Map_X;
    pixiText.Map_Y = this.Map_Y;
    //status
    pixiText._BindToMap = this._BindToMap;
    pixiText._bindToPicture = this._bindToPicture;
    pixiText._isMultiStyle = this._isMultiStyle;
    // add the data for multiStyles Only
    pixiText._result = this.result;
    pixiText._resultLine = this.resultLine;
    pixiText._dataLH = this.dataLH;
    pixiText._dataLW = this.dataLW;
    pixiText = this.initSetupMultiStyle(pixiText); //step1: Setup All pixi.text and variable (return this.masterMultiPixiTxt)
   
    //pixiText = this.configuAnchor(pixiText); // set Anchor by align type (TODO:)
    //pixiText = this.pixiTxtPositioning(); //step 2: calculation of all child text and Positioning with line result
    return SceneManager._scene._textContainer.addChild(pixiText); // add and return the objChid
};

MVPixi_Text.prototype.configuAnchor = function(pixiText) {
    var alignType = pixiText._style._align; // get info about align
    if (alignType === 'center') { pixiText.anchor._x = 0.5, pixiText.anchor._y = 0.5; } else
    if (alignType === 'right') { pixiText.anchor._x = 1; }
    return pixiText;
};

//□▼↓▼□═════════════════════════════════════□□═════════════════════════════════════════════════════════□↓↓↓
// MULTISTYLES □──────────────────────────-PROTOTYPE-───────────────────────────────────────────────┐
// ¦ □ initSetupMultiStyle □ build_dataChild □ outLimitCalculation □ positioningChild
// └─────────────────────────────────────────□□□□□□□□───────────────────────────────────────────────┘

MVPixi_Text.prototype.initSetupMultiStyle = function(pixiText) {
    var txt = pixiText._text, style = pixiText._style;
    style.primary.hasIcon = txt.match(/{i+(\d+?)\}/) && true || false; // txt has icon ?
    style.primary.hasLineBreak = txt.match(/\\n/) && true || false; // has custom //n ?
    for (var tag in style) { if(tag !== 'primary'){ style[tag] = new PIXI.TextStyle(style[tag]) }; }; // new pixi.Style for each Tag !primary
    //STEP:1 INITIALISE MATCHING STYLES TAG ↓↓↓ ////
    var re = /<s+\d\>(.*?)<\/s+\d>/, match, n, textBefore;
    while ((match = re.exec(txt)) !== null) {
        textBefore = match.input.slice(0, match.index);
        n = match[0].match(/\d+/)[0]; // get tagReference <s?n?>
        if(textBefore){ pixiText._result.push({ txt: textBefore, style: style.def, tag:'def' });}; // push the text beforeMatch (not TAGED)
        pixiText._result.push({ txt: match[1], style: style['s' + n], tag: 's' + n }); // push text from Match (<>TAGED)
        txt = txt.slice(match.index + match[0].length); // slice current txt for loop again Match
    };
    pixiText._result.push({ txt: txt, style: style.def, tag:'def' }); // push the text beforeMatch (not TAGED)
    //STEP:1 INITIALISE MATCHING STYLES TAG END ↑↑↑ ////
    //STEP:2 INITIALISE MATCHING ICONS ↓↓↓ ////
    if (style.primary.hasIcon) {
        var re = /{i+(\d+?)\}/; // regex dinamic: note:(\d?) permit to get the id
        for (var r = 0; r < pixiText._result.length; r++) { // check inside all result[?].txt if we have a icon tag ?
            var txt = pixiText._result[r].txt;
            var match = re.exec(pixiText._result[r].txt); // find if iconTag {i(ID)}, in this arrResult?
            if (match) { // we find icon in pixiText._result[r]
                var iconTxt = { isIcon: true, iconID: match[1], tag: pixiText._result[r].tag }; // create icon obj
                var textAfter = match.input.slice(match.index + match[0].length); // get text after icon tag >
                var afterIcon =  { txt: textAfter, style: pixiText._result[r].style, tag: pixiText._result[r].tag };
                pixiText._result[r].txt = match.input.slice(0, match.index); // redefine current (pixiText._result[?]) with sliced txt befor icon tag <
                pixiText._result.splice(++r, 0, iconTxt, afterIcon); // add after current _result[r], new array [iconTxt],[afterIcon]
            };
        };
    };
    //STEP:2 INITIALISE MATCHING ICONS END ↑↑↑ ////
    //STEP:3 INITIALISE MATCHING CUSTOM LINEBREAK ↓↓↓ ////
    if(style.primary.hasLineBreak){
        var re = /\\n/; // regex
        for (var r = 0; r < pixiText._result.length; r++) {
            var match = re.exec(pixiText._result[r].txt);
            if(match){
                var textAfter = match.input.slice(match.index + match[0].length); // get text after icon tag >
                var textNewLine =  { txt: textAfter, style: pixiText._result[r].style, tag: pixiText._result[r].tag, jumpLine:true };
                pixiText._result[r].txt = match.input.slice(0, match.index); // redefine current (pixiText._result[?]) with sliced txt befor icon tag <
                if(textAfter.length===0&&pixiText._result[r+1]){pixiText._result[r+1].jumpLine = true;} // bugfix when //n befor a Tag
                else{pixiText._result.splice(r+1, 0, textNewLine); // ADD AFTER this.result A NEW ARRAY TXT
                };
            };
        };
    };
    //STEP:3 INITIALISE MATCHING CUSTOM LINEBREAK END ↑↑↑ ////
    pixiText = this.build_dataChild(pixiText,style);// CREATE CHILD RESULT **(ALSO DATA FOR SAVE BANK)**
    pixiText = this.positioningChild(pixiText);// SET XY POSITION OF ALL CHILD TXT BY RESULT DATA
    return pixiText; // return pixiText (final pixi container)
};

MVPixi_Text.prototype.build_dataChild = function(pixiText,style) {
    var lineIndex = 0, inScopeWidth = 0;
    var wordWrap = style.primary.wordWrap && true || false;
    var wrapLimit = style.primary.wordWrapWidth;
    for(var r=0;r<pixiText._result.length;r++){
        var data = pixiText._result[r];
        if(data.jumpLine){ inScopeWidth = 0; lineIndex++; pixiText._resultLine[lineIndex]=[]; pixiText._dataLH[lineIndex] = 0; };
        var childTxt = !data.isIcon && new PIXI.Text(data.txt,data.style) || new PIXI.Sprite(Gamefall.PixiText.txtTextureIcon[data.iconID]);
        var childWidth = childTxt.width, childHeight = childTxt.height;
        if(wordWrap && (inScopeWidth+childWidth) > wrapLimit){ // if WORDWRAP ONLY
            if(data.isIcon){// jump icon to new line
                inScopeWidth = 0; lineIndex++; pixiText._resultLine[lineIndex]=[]; pixiText._dataLH[lineIndex] = 0;
            }else{ // need split and return the word exeed limit
                var exceedTXT = this.outLimitCalculation(childTxt,inScopeWidth,wrapLimit,data);
                childWidth = childTxt.width, childHeight = childTxt.height; // get new valur
                pixiText._result.splice(r+1, 0, exceedTXT); // ADD AFTER this.result A NEW ARRAY TXT
            };
        };
        data._width = childWidth, data._height = childHeight;
        data._x = inScopeWidth, data._line = lineIndex;
        pixiText._resultLine[lineIndex].push(data); // add to resulLine
        pixiText.addChild(childTxt);
        inScopeWidth+=childWidth;
        pixiText._dataLW[lineIndex] = inScopeWidth;
        var maxHeight = pixiText._dataLH[lineIndex];
        pixiText._dataLH[lineIndex] = childHeight>maxHeight && childHeight || maxHeight;
    };
    return pixiText;
};

MVPixi_Text.prototype.outLimitCalculation = function(childTxt,inScopeWidth,wrapLimit,data) {
    var letterWidth = childTxt.width / childTxt._text.length; // calculate width of all letter
    var afterLineResult = { txt: '', style: data.style, tag: data.tag, jumpLine:true };
    var re = /\w+\W+|\w+/g; //regexr (match all word + any ,')
    var match; var inLineTxt = '';
    while ((match = re.exec(childTxt._text)) !== null) {
        var resultWidh = inScopeWidth+(match[0].length+inLineTxt.length)*letterWidth;
        if (resultWidh > wrapLimit) {
            afterLineResult.txt = match.input.slice(match.index); break;}
        else { inLineTxt += match[0]; };
    };
    inLineTxt = inLineTxt.replace(/[\s]+$/,''); // remove endSpace
    childTxt.text = inLineTxt; data.txt = inLineTxt;
    return afterLineResult;
};

MVPixi_Text.prototype.positioningChild = function(pixiText) {
    var data = pixiText._resultLine;
    var pixiChild = pixiText.children;
    var lS = pixiText._style.primary.lineStyle;
    var lA = pixiText._style.primary.align;
    lS = lS==='middle'&& 0.5 || lS==='bottom'&& 1 || 0; // lineStyle
    lA = lA==='center'&& 0.5 || lA==='right'&& 1 || 0;  // lineAlign
    var limit = pixiText._style.primary.wordWrapWidth || pixiText.width;
    for (var R=0, id=0, lineMaxH=0, Y=0, alignX=0, LEN=data.length; R<LEN; R++) {
        if(lA){ alignX = (limit-pixiText._dataLW[R])*lA; };
        for (var r=0, len=data[R].length; r<len; r++, id++) {
            pixiChild[id].anchor.y = lS;
            pixiChild[id].x = data[R][r]._x+alignX;
            pixiChild[id].y = Y;
        };
        Y+=pixiText._dataLH[R];
    };
return pixiText
};

you can close , thanks

@bluepichu
Copy link
Collaborator

Could you elaborate on what bugs you were encountering? It would be nice to fix those in this library if possible :)

The ones I could pick out from your description were:

  • Proper line wrapping when a line has more than one word: pending fix in fix: styled text not wrapped correctly when breakWords is true #47 I think
  • Icons: not currently in-scope unless you have an icon font of some kind
  • Horizontal alignment: it looks like you have styles per line, which doesn't really match up with how the tagging system in this library works (e.g., what is the proper alignment of a line that contains both a tag with a left-align style and a tag with a right-align style?)
  • Vertical alignment: we already have "top" | "middle" | "bottom", and will add "baseline" | number whenever I get around to writing a PR for Vertical alignment #41

Given a good proposal of what the markup and implementation would look like, adding support for some kind of iconography and/or varied horizontal alignment could be doable.

@jonlepage
Copy link
Author

jonlepage commented Jun 29, 2017

Difficult to elaborate the bugs with your version, probably of the typeScript import !?
I was had , a lot of fps drop (about 40) when calling multystyle with your version,
But it would appear to be related to the import of the module in the node.js and pixi core i use.
in my side now , i build style like this. ( and also work if you add custom \n line break with wordWrap)

var styles = {
"primary":{lineStyle:'middle',align: 'left', lineHeight: 0,wordWrap:true,wordWrapWidth:600,}, // add here:primary, (see upperList)
"def": {strokeThickness: 4,fill: "#ffffff"}, // default no tag txt
"s0": {fontSize: "28px",fill: "#ff8742",strokeThickness: 10, letterSpacing:20,fontWeight:900}, // tag id txt
"s1": {fontSize: "18px",fill: "#f4415e",strokeThickness: 5, letterSpacing:4}, // tag id txt
};

after the caller are like this

var txt = '<s0>Hello world!</s0>{i3}\\n\\n\\n I am a simple amazing <s1>PIXI</s1> MULTISTYLE TEXT With a <s0>debugMode</s0> and work with linebreak with a wordWrap! ';
    Gamefall.PixiText.create(1, txt, styles, 400, 250, true,true);

so primary can not add inside a tag, or it will be ignore.

//□▼↓▼□═══════════════════════════════════════════════════□□═══════════════════════════════════════════════════□↓↓↓
 Here is the list of possible styles, with default values:
    align: 'right',   // 'left'||'center'||'right' //primary
    breakWords: false, //Break words between any two letters on wordWrap //primary
    dropShadow: false,
    dropShadowAngle: Math.PI / 6,
    dropShadowBlur: 0,
    dropShadowColor: '#000000',
    dropShadowDistance: 5,
    fill: 'black',
    fillGradientType: TEXT_GRADIENT.LINEAR_VERTICAL,
    fontFamily: 'Arial',
    fontSize: 26,
    fontStyle: 'normal', //normal|italic|oblique|initial|inherit
    fontVariant: 'normal', //normal|small-caps|initial|inherit
    fontWeight: 'normal', //normal|bold|bolder|lighter|number|initial|inherit|900|600|400
    letterSpacing: 0,
    lineHeight: 0, //primary
    lineJoin: 'miter', //"bevel|round|miter"
    miterLimit: 10,
    padding: 0,
    stroke: 'black',
    strokeThickness: 0,
    textBaseline: 'alphabetic', //"alphabetic|top|hanging|middle|ideographic|bottom"
    wordWrap: false, //primary
    wordWrapWidth: 100, //primary
    lineStyle:'middle', //'top'||'middle'||'bottom' //primary
//□▲↑▲□═══════════════════════════════════════════════════□□═══════════════════════════════════════════════════□↑↑↑

I also have just finished, a super efficient debug mode.
If this can inspire an improvement for your version.
It allows you to easily view your text with measurements.
t makes it very easy to customize each tag accordingly to what need.!

the debug mode use canvas.getContext('2d') in all childrend to painting!
aefaefgvv

@bluepichu
Copy link
Collaborator

TypeScript itself shouldn't add any bugs since it's just a type system on top of JS. I also haven't experienced any FPS drops due to PMT, but it's possible that there's some bottleneck somewhere that I haven't encountered. Are you changing the text or styles often (e.g. on each frame)? You also mention the import into Node being slow - are you doing some kind of server-side rendering?

As far as the features you've mentioned:

  • "Custom newlines": I'm not quite sure I'm following what you mean here; you seem to have double-escaped the backslash for the newline, is that signifying something? How does your version specify per-line horizontal alignment? (And am I correct in assuming the {i3} is how you've specified an icon?)
  • Line breaks with word wrapping: is something broken with our implementation? Newlines in word-wrapped blocks work fine for me.
  • Debug mode: that's actually a really great idea. I'll open up an issue for that; drawing bounding boxes and baselines would probably make it much easier to debug issues. Thank you!

@bluepichu bluepichu mentioned this issue Jun 30, 2017
@jonlepage
Copy link
Author

jonlepage commented Jun 30, 2017

I'm done a little video debug mode.
It also takes the frame, with or without word wrap.
if this can also give you some great idea.

you will understand the Custom newlines

Youtube debugMode PixiMultiStyle plugin

bluepichu added a commit to bluepichu/pixi-multistyle-text that referenced this issue Jul 16, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants