text.js 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. import BoundingRect from '../core/BoundingRect';
  2. import { createCanvas } from '../core/util';
  3. import LRU from '../core/LRU';
  4. var textWidthCache = {};
  5. export var DEFAULT_FONT = '12px sans-serif';
  6. var _ctx;
  7. var _cachedFont;
  8. function defaultMeasureText(text, font) {
  9. if (!_ctx) {
  10. _ctx = createCanvas().getContext('2d');
  11. }
  12. if (_cachedFont !== font) {
  13. _cachedFont = _ctx.font = font || DEFAULT_FONT;
  14. }
  15. return _ctx.measureText(text);
  16. }
  17. var methods = {
  18. measureText: defaultMeasureText
  19. };
  20. export function $override(name, fn) {
  21. methods[name] = fn;
  22. }
  23. export function getWidth(text, font) {
  24. font = font || DEFAULT_FONT;
  25. var cacheOfFont = textWidthCache[font];
  26. if (!cacheOfFont) {
  27. cacheOfFont = textWidthCache[font] = new LRU(500);
  28. }
  29. var width = cacheOfFont.get(text);
  30. if (width == null) {
  31. width = methods.measureText(text, font).width;
  32. cacheOfFont.put(text, width);
  33. }
  34. return width;
  35. }
  36. export function innerGetBoundingRect(text, font, textAlign, textBaseline) {
  37. var width = getWidth(text, font);
  38. var height = getLineHeight(font);
  39. var x = adjustTextX(0, width, textAlign);
  40. var y = adjustTextY(0, height, textBaseline);
  41. var rect = new BoundingRect(x, y, width, height);
  42. return rect;
  43. }
  44. export function getBoundingRect(text, font, textAlign, textBaseline) {
  45. var textLines = ((text || '') + '').split('\n');
  46. var len = textLines.length;
  47. if (len === 1) {
  48. return innerGetBoundingRect(textLines[0], font, textAlign, textBaseline);
  49. }
  50. else {
  51. var uniondRect = new BoundingRect(0, 0, 0, 0);
  52. for (var i = 0; i < textLines.length; i++) {
  53. var rect = innerGetBoundingRect(textLines[i], font, textAlign, textBaseline);
  54. i === 0 ? uniondRect.copy(rect) : uniondRect.union(rect);
  55. }
  56. return uniondRect;
  57. }
  58. }
  59. export function adjustTextX(x, width, textAlign) {
  60. if (textAlign === 'right') {
  61. x -= width;
  62. }
  63. else if (textAlign === 'center') {
  64. x -= width / 2;
  65. }
  66. return x;
  67. }
  68. export function adjustTextY(y, height, verticalAlign) {
  69. if (verticalAlign === 'middle') {
  70. y -= height / 2;
  71. }
  72. else if (verticalAlign === 'bottom') {
  73. y -= height;
  74. }
  75. return y;
  76. }
  77. export function getLineHeight(font) {
  78. return getWidth('国', font);
  79. }
  80. export function measureText(text, font) {
  81. return methods.measureText(text, font);
  82. }
  83. export function parsePercent(value, maxValue) {
  84. if (typeof value === 'string') {
  85. if (value.lastIndexOf('%') >= 0) {
  86. return parseFloat(value) / 100 * maxValue;
  87. }
  88. return parseFloat(value);
  89. }
  90. return value;
  91. }
  92. export function calculateTextPosition(out, opts, rect) {
  93. var textPosition = opts.position || 'inside';
  94. var distance = opts.distance != null ? opts.distance : 5;
  95. var height = rect.height;
  96. var width = rect.width;
  97. var halfHeight = height / 2;
  98. var x = rect.x;
  99. var y = rect.y;
  100. var textAlign = 'left';
  101. var textVerticalAlign = 'top';
  102. if (textPosition instanceof Array) {
  103. x += parsePercent(textPosition[0], rect.width);
  104. y += parsePercent(textPosition[1], rect.height);
  105. textAlign = null;
  106. textVerticalAlign = null;
  107. }
  108. else {
  109. switch (textPosition) {
  110. case 'left':
  111. x -= distance;
  112. y += halfHeight;
  113. textAlign = 'right';
  114. textVerticalAlign = 'middle';
  115. break;
  116. case 'right':
  117. x += distance + width;
  118. y += halfHeight;
  119. textVerticalAlign = 'middle';
  120. break;
  121. case 'top':
  122. x += width / 2;
  123. y -= distance;
  124. textAlign = 'center';
  125. textVerticalAlign = 'bottom';
  126. break;
  127. case 'bottom':
  128. x += width / 2;
  129. y += height + distance;
  130. textAlign = 'center';
  131. break;
  132. case 'inside':
  133. x += width / 2;
  134. y += halfHeight;
  135. textAlign = 'center';
  136. textVerticalAlign = 'middle';
  137. break;
  138. case 'insideLeft':
  139. x += distance;
  140. y += halfHeight;
  141. textVerticalAlign = 'middle';
  142. break;
  143. case 'insideRight':
  144. x += width - distance;
  145. y += halfHeight;
  146. textAlign = 'right';
  147. textVerticalAlign = 'middle';
  148. break;
  149. case 'insideTop':
  150. x += width / 2;
  151. y += distance;
  152. textAlign = 'center';
  153. break;
  154. case 'insideBottom':
  155. x += width / 2;
  156. y += height - distance;
  157. textAlign = 'center';
  158. textVerticalAlign = 'bottom';
  159. break;
  160. case 'insideTopLeft':
  161. x += distance;
  162. y += distance;
  163. break;
  164. case 'insideTopRight':
  165. x += width - distance;
  166. y += distance;
  167. textAlign = 'right';
  168. break;
  169. case 'insideBottomLeft':
  170. x += distance;
  171. y += height - distance;
  172. textVerticalAlign = 'bottom';
  173. break;
  174. case 'insideBottomRight':
  175. x += width - distance;
  176. y += height - distance;
  177. textAlign = 'right';
  178. textVerticalAlign = 'bottom';
  179. break;
  180. }
  181. }
  182. out = out || {};
  183. out.x = x;
  184. out.y = y;
  185. out.align = textAlign;
  186. out.verticalAlign = textVerticalAlign;
  187. return out;
  188. }