Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Justify text #2396

Closed
jdnichollsc opened this issue Mar 23, 2016 · 6 comments
Closed

Justify text #2396

jdnichollsc opened this issue Mar 23, 2016 · 6 comments

Comments

@jdnichollsc
Copy link
Contributor

Hi guys,

Is possible to justify text? I think that it's very useful for several games with Phaser 馃懐

Thanks in advance :)

@photonstorm
Copy link
Collaborator

No it's not possible I'm afraid. It's not even possible using native Canvas Text either! It's literally not in the canvas api. I can imagine it must be quite a challenge to code robustly.

@slashman
Copy link
Contributor

I think I could give it a go :)

@ForgeableSum
Copy link

I recommend using plain HTML/CSS if you want to have extremely granular control over the appearance of text in your game.

@jdnichollsc
Copy link
Contributor Author

Yes, you're right! 馃懐

@photonstorm
Copy link
Collaborator

I'm moving this to the Lazer wish-list for Bitmap Text objects (and for Text objects if someone fancies taking that huge challenge on!)

@PierreSydo
Copy link

I add the same issue for a project I was working on. I had to wrote my own methods to justify the text.

Basically the algorithm takes advantage of the PIXI's TextMetrics to split the text in lines and measure every word.

Then in each of the lines it measures the total length of the non-white characters. When you substract it to the length of the line, you obtain the remaining white space.

Finally you must add : totalWhitespace / (wordCount - 1) between each words to get your text justified.

Here is the implementation I used, I don't guarantee that it will work in every case but it solved my problem :

`let _line = function(container,txt,x,y,width,height,font,fontSize,bold,justify,center) {

const style = new PIXI.TextStyle({
	fontFamily: font,
	fontSize: fontSize,
	fontWeight: bold ? 'bold' : 'normal',
	fill: '#ffffff'
});

const metrics = PIXI.TextMetrics.measureText(txt,style,false);

if(center && !justify) {
	x -= metrics.width / 2;
	y -= metrics.lineHeight / 2;
}

//Important : always round coordinate to avoid blurry text !
x = Math.round(x);
y = Math.round(y);

// Does all justify calculation if needed
if(justify || typeof(justify) === 'undefined') {

	// Break the line into words
	const words = txt.split(' ');

	const wordCount = words.length;

	// Measures the width of the words
	let totalWordsWidth = 0;
	let wordsWidth = [];	// Caching words width to avoid multiple calculation

	for (let i = 0; i < wordCount; i++) {
		const wordWidth = (PIXI.TextMetrics.measureText(words[i],style,false)).width;
		totalWordsWidth += wordWidth;
		wordsWidth.push(wordWidth);
	}

	// Don't justify if the words aren't wide enough
	const MIN_RATIO = 0.5;
	if(totalWordsWidth / width < MIN_RATIO)
		return _line(txt,x,y,width,height,font,fontSize,bold,false,center);

	const wordSpacing = (width - totalWordsWidth) / (words.length - 1);

	// Draw each word
	let _x = x;
	for (let i = 0; i < wordCount; i++) {
		const _txt = container.addChild(new PIXI.Text(words[i], style));
		_txt.x =  Math.round(_x);
		_txt.y = y;

		_x += wordsWidth[i] + wordSpacing;
	}
}
// Fallbacks on default PIXI's method otherwise
else {
	const text = container.addChild(new PIXI.Text(txt,style));
	text.x = x;
	text.y = y;
}

if(justify)
	metrics.width = width;
return metrics;

}

let _text = function(container,txt,x,y,width,height,font,fontSize,bold) {

let _y = y;

if(typeof bold === 'undefined') bold = false;

const style = new PIXI.TextStyle({
	fontFamily: font,
	fontSize: fontSize,
	fontWeight: bold ? 'bold' : 'normal',
	fill: '#ffffff',
	wordWrapWidth: width
});

// Gets all the lines of the text
const textMetrics = PIXI.TextMetrics.measureText(txt,style,true);
let lines = textMetrics.lines;

// The last line won't get justified unless we force it
const lastLine = lines.pop();

// For each line...
lines.forEach(function(line) {
	_line(container,line, x, Math.round(_y),width,height,font,fontSize,bold,true);
	_y += textMetrics.lineHeight;
});

// Draw the last line (unjustified)
_line(container,lastLine, x, Math.round(_y),width,height,font,fontSize,bold,false);

return textMetrics;

};`

Hope that it can help someone ;-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants