textBlock.ts 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  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. get resizeToFit(): boolean {
  13. return this._resizeToFit;
  14. }
  15. set resizeToFit(value: boolean) {
  16. this._resizeToFit = value;
  17. }
  18. public get textWrapping(): boolean {
  19. return this._textWrapping;
  20. }
  21. public set textWrapping(value: boolean) {
  22. if (this._textWrapping === value) {
  23. return;
  24. }
  25. this._textWrapping = value;
  26. this._markAsDirty();
  27. }
  28. public get text(): string {
  29. return this._text;
  30. }
  31. public set text(value: string) {
  32. if (this._text === value) {
  33. return;
  34. }
  35. this._text = value;
  36. this._markAsDirty();
  37. }
  38. public get textHorizontalAlignment(): number {
  39. return this._textHorizontalAlignment;
  40. }
  41. public set textHorizontalAlignment(value: number) {
  42. if (this._textHorizontalAlignment === value) {
  43. return;
  44. }
  45. this._textHorizontalAlignment = value;
  46. this._markAsDirty();
  47. }
  48. public get textVerticalAlignment(): number {
  49. return this._textVerticalAlignment;
  50. }
  51. public set textVerticalAlignment(value: number) {
  52. if (this._textVerticalAlignment === value) {
  53. return;
  54. }
  55. this._textVerticalAlignment = value;
  56. this._markAsDirty();
  57. }
  58. constructor(public name?: string, text: string = "") {
  59. super(name);
  60. this.text = text;
  61. }
  62. protected _getTypeName(): string {
  63. return "TextBlock";
  64. }
  65. private _drawText(text: string, textWidth: number, y: number, context: CanvasRenderingContext2D): void {
  66. var width = this._currentMeasure.width;
  67. var x = 0;
  68. switch (this._textHorizontalAlignment) {
  69. case Control.HORIZONTAL_ALIGNMENT_LEFT:
  70. x = 0
  71. break;
  72. case Control.HORIZONTAL_ALIGNMENT_RIGHT:
  73. x = width - textWidth;
  74. break;
  75. case Control.HORIZONTAL_ALIGNMENT_CENTER:
  76. x = (width - textWidth) / 2;
  77. break;
  78. }
  79. context.fillText(text, this._currentMeasure.left + x, y);
  80. }
  81. public _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void {
  82. context.save();
  83. this._applyStates(context);
  84. if (this._processMeasures(parentMeasure, context)) {
  85. // Render lines
  86. this._renderLines(context);
  87. }
  88. context.restore();
  89. }
  90. protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void {
  91. this._lines = [];
  92. var _lines = this.text.split("\n");
  93. if (this._textWrapping && !this._resizeToFit) {
  94. for(var _line of _lines) {
  95. this._lines.push(this._parseLineWithTextWrapping(_line, context));
  96. }
  97. } else {
  98. for(var _line of _lines) {
  99. this._lines.push(this._parseLine(_line, context));
  100. }
  101. }
  102. }
  103. public getRawFontSize(): object {
  104. var ignoreAdaptiveScaling: boolean = this._fontSize.ignoreAdaptiveScaling;
  105. this._fontSize.ignoreAdaptiveScaling = false;
  106. var maxLineWidth: number = 0;
  107. var _lines = this.text.split("\n").forEach(_line => {
  108. //can't get context here? if so, have 2 calculations in _additionalProcessing instead? one for with idealWidth and one without
  109. var lineWidth: number = this._parseLine(_line, context).width;
  110. if (lineWidth > maxLineWidth) maxLineWidth = lineWidth;
  111. });
  112. this._prepareFont();
  113. this._fontSize.ignoreAdaptiveScaling = ignoreAdaptiveScaling;
  114. this._prepareFont();
  115. return {
  116. width: maxLineWidth,
  117. height: this._fontOffset.height * this._lines.length + 'px'
  118. }
  119. }
  120. protected _parseLine(line: string='', context: CanvasRenderingContext2D): object {
  121. return {text: line, width: context.measureText(line).width};
  122. }
  123. protected _parseLineWithTextWrapping(line: string='', context: CanvasRenderingContext2D): object {
  124. var words = line.split(' ');
  125. var width = this._currentMeasure.width;
  126. var lineWidth = 0;
  127. for(var n = 0; n < words.length; n++) {
  128. var testLine = n > 0 ? line + " " + words[n] : words[0];
  129. var metrics = context.measureText(testLine);
  130. var testWidth = metrics.width;
  131. if (testWidth > width && n > 0) {
  132. this._lines.push({text: line, width: lineWidth});
  133. line = words[n];
  134. lineWidth = context.measureText(line).width;
  135. }
  136. else {
  137. lineWidth = testWidth;
  138. line = testLine;
  139. }
  140. }
  141. return {text: line, width: lineWidth};
  142. }
  143. protected _renderLines(context: CanvasRenderingContext2D): void {
  144. var width = this._currentMeasure.width;
  145. var height = this._currentMeasure.height;
  146. if (!this._fontOffset) {
  147. this._fontOffset = Control._GetFontOffset(context.font);
  148. }
  149. var rootY = 0;
  150. switch (this._textVerticalAlignment) {
  151. case Control.VERTICAL_ALIGNMENT_TOP:
  152. rootY = this._fontOffset.ascent;
  153. break;
  154. case Control.VERTICAL_ALIGNMENT_BOTTOM:
  155. rootY = height - this._fontOffset.height * (this._lines.length - 1) - this._fontOffset.descent;
  156. break;
  157. case Control.VERTICAL_ALIGNMENT_CENTER:
  158. rootY = this._fontOffset.ascent + (height - this._fontOffset.height * this._lines.length) / 2;
  159. break;
  160. }
  161. rootY += this._currentMeasure.top;
  162. var maxLineWidth: number = 0;
  163. for (var line of this._lines) {
  164. this._drawText(line.text, line.width, rootY, context);
  165. rootY += this._fontOffset.height;
  166. if (line.width > maxLineWidth) maxLineWidth = line.width;
  167. }
  168. if (this._resizeToFit) {
  169. this.width = maxLineWidth + 'px';
  170. this.height = this._fontOffset.height * this._lines.length + 'px';
  171. }
  172. //console.log('width', maxLineWidth);
  173. //console.log('height', rootY, this._fontOffset.height);
  174. }
  175. }
  176. }