textBlock.ts 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. /// <reference path="../../../dist/preview release/babylon.d.ts"/>
  2. module BABYLON.GUI {
  3. export class TextBlock extends Control {
  4. private _text = "";
  5. private _textY: number;
  6. private _textWrapping = false;
  7. private _textHorizontalAlignment = Control.HORIZONTAL_ALIGNMENT_CENTER;
  8. private _textVerticalAlignment = Control.VERTICAL_ALIGNMENT_CENTER;
  9. private _lines: any[];
  10. private _totalHeight: number;
  11. private _resizeToFit: boolean = false;
  12. /**
  13. * An event triggered after the text is changed
  14. * @type {BABYLON.Observable}
  15. */
  16. public onTextChangedObservable = new Observable<TextBlock>();
  17. get resizeToFit(): boolean {
  18. return this._resizeToFit;
  19. }
  20. set resizeToFit(value: boolean) {
  21. this._resizeToFit = value;
  22. if (this._resizeToFit) {
  23. this._width.ignoreAdaptiveScaling = true;
  24. this._height.ignoreAdaptiveScaling = true;
  25. }
  26. }
  27. public get textWrapping(): boolean {
  28. return this._textWrapping;
  29. }
  30. public set textWrapping(value: boolean) {
  31. if (this._textWrapping === value) {
  32. return;
  33. }
  34. this._textWrapping = value;
  35. this._markAsDirty();
  36. }
  37. public get text(): string {
  38. return this._text;
  39. }
  40. public set text(value: string) {
  41. if (this._text === value) {
  42. return;
  43. }
  44. this._text = value;
  45. this._markAsDirty();
  46. this.onTextChangedObservable.notifyObservers(this);
  47. }
  48. public get textHorizontalAlignment(): number {
  49. return this._textHorizontalAlignment;
  50. }
  51. public set textHorizontalAlignment(value: number) {
  52. if (this._textHorizontalAlignment === value) {
  53. return;
  54. }
  55. this._textHorizontalAlignment = value;
  56. this._markAsDirty();
  57. }
  58. public get textVerticalAlignment(): number {
  59. return this._textVerticalAlignment;
  60. }
  61. public set textVerticalAlignment(value: number) {
  62. if (this._textVerticalAlignment === value) {
  63. return;
  64. }
  65. this._textVerticalAlignment = value;
  66. this._markAsDirty();
  67. }
  68. constructor(public name?: string, text: string = "") {
  69. super(name);
  70. this.text = text;
  71. }
  72. protected _getTypeName(): string {
  73. return "TextBlock";
  74. }
  75. private _drawText(text: string, textWidth: number, y: number, context: CanvasRenderingContext2D): void {
  76. var width = this._currentMeasure.width;
  77. var x = 0;
  78. switch (this._textHorizontalAlignment) {
  79. case Control.HORIZONTAL_ALIGNMENT_LEFT:
  80. x = 0
  81. break;
  82. case Control.HORIZONTAL_ALIGNMENT_RIGHT:
  83. x = width - textWidth;
  84. break;
  85. case Control.HORIZONTAL_ALIGNMENT_CENTER:
  86. x = (width - textWidth) / 2;
  87. break;
  88. }
  89. context.fillText(text, this._currentMeasure.left + x, y);
  90. }
  91. public _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void {
  92. context.save();
  93. this._applyStates(context);
  94. if (this._processMeasures(parentMeasure, context)) {
  95. // Render lines
  96. this._renderLines(context);
  97. }
  98. context.restore();
  99. }
  100. protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void {
  101. this._lines = [];
  102. var _lines = this.text.split("\n");
  103. if (this._textWrapping && !this._resizeToFit) {
  104. for(var _line of _lines) {
  105. this._lines.push(this._parseLineWithTextWrapping(_line, context));
  106. }
  107. } else {
  108. for(var _line of _lines) {
  109. this._lines.push(this._parseLine(_line, context));
  110. }
  111. }
  112. }
  113. protected _parseLine(line: string='', context: CanvasRenderingContext2D): object {
  114. return {text: line, width: context.measureText(line).width};
  115. }
  116. protected _parseLineWithTextWrapping(line: string='', context: CanvasRenderingContext2D): object {
  117. var words = line.split(' ');
  118. var width = this._currentMeasure.width;
  119. var lineWidth = 0;
  120. for(var n = 0; n < words.length; n++) {
  121. var testLine = n > 0 ? line + " " + words[n] : words[0];
  122. var metrics = context.measureText(testLine);
  123. var testWidth = metrics.width;
  124. if (testWidth > width && n > 0) {
  125. this._lines.push({text: line, width: lineWidth});
  126. line = words[n];
  127. lineWidth = context.measureText(line).width;
  128. }
  129. else {
  130. lineWidth = testWidth;
  131. line = testLine;
  132. }
  133. }
  134. return {text: line, width: lineWidth};
  135. }
  136. protected _renderLines(context: CanvasRenderingContext2D): void {
  137. var width = this._currentMeasure.width;
  138. var height = this._currentMeasure.height;
  139. if (!this._fontOffset) {
  140. this._fontOffset = Control._GetFontOffset(context.font);
  141. }
  142. var rootY = 0;
  143. switch (this._textVerticalAlignment) {
  144. case Control.VERTICAL_ALIGNMENT_TOP:
  145. rootY = this._fontOffset.ascent;
  146. break;
  147. case Control.VERTICAL_ALIGNMENT_BOTTOM:
  148. rootY = height - this._fontOffset.height * (this._lines.length - 1) - this._fontOffset.descent;
  149. break;
  150. case Control.VERTICAL_ALIGNMENT_CENTER:
  151. rootY = this._fontOffset.ascent + (height - this._fontOffset.height * this._lines.length) / 2;
  152. break;
  153. }
  154. rootY += this._currentMeasure.top;
  155. var maxLineWidth: number = 0;
  156. for (var line of this._lines) {
  157. this._drawText(line.text, line.width, rootY, context);
  158. rootY += this._fontOffset.height;
  159. if (line.width > maxLineWidth) maxLineWidth = line.width;
  160. }
  161. if (this._resizeToFit) {
  162. this.width = this.paddingLeftInPixels + this.paddingRightInPixels + maxLineWidth + 'px';
  163. this.height = this.paddingTopInPixels + this.paddingBottomInPixels + this._fontOffset.height * this._lines.length + 'px';
  164. }
  165. }
  166. dispose(): void {
  167. super.dispose();
  168. this.onTextChangedObservable.clear();
  169. }
  170. }
  171. }