Digital Office Automation System Backend
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

LineBreakMeasurer.js 8.6KB

il y a 1 jour
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. /**
  2. * Word wrapping
  3. *
  4. * @author (Javascript) Dmitry Farafonov
  5. */
  6. var AttributedStringIterator = function(text){
  7. //this.text = this.rtrim(this.ltrim(text));
  8. text = text.replace(/(\s)+/, " ");
  9. this.text = this.rtrim(text);
  10. /*
  11. if (beginIndex < 0 || beginIndex > endIndex || endIndex > length()) {
  12. throw new IllegalArgumentException("Invalid substring range");
  13. }
  14. */
  15. this.beginIndex = 0;
  16. this.endIndex = this.text.length;
  17. this.currentIndex = this.beginIndex;
  18. //console.group("[AttributedStringIterator]");
  19. var i = 0;
  20. var string = this.text;
  21. var fullPos = 0;
  22. //console.log("string: \"" + string + "\", length: " + string.length);
  23. this.startWordOffsets = [];
  24. this.startWordOffsets.push(fullPos);
  25. // TODO: remove i 1000
  26. while (i<1000) {
  27. var pos = string.search(/[ \t\n\f-\.\,]/);
  28. if (pos == -1)
  29. break;
  30. // whitespace start
  31. fullPos += pos;
  32. string = string.substr(pos);
  33. ////console.log("fullPos: " + fullPos + ", pos: " + pos + ", string: ", string);
  34. // remove whitespaces
  35. var pos = string.search(/[^ \t\n\f-\.\,]/);
  36. if (pos == -1)
  37. break;
  38. // whitespace end
  39. fullPos += pos;
  40. string = string.substr(pos);
  41. ////console.log("fullPos: " + fullPos);
  42. this.startWordOffsets.push(fullPos);
  43. i++;
  44. }
  45. //console.log("startWordOffsets: ", this.startWordOffsets);
  46. //console.groupEnd();
  47. };
  48. AttributedStringIterator.prototype = {
  49. getEndIndex: function(pos){
  50. if (typeof(pos) == "undefined")
  51. return this.endIndex;
  52. var string = this.text.substr(pos, this.endIndex - pos);
  53. var posEndOfLine = string.search(/[\n]/);
  54. if (posEndOfLine == -1)
  55. return this.endIndex;
  56. else
  57. return pos + posEndOfLine;
  58. },
  59. getBeginIndex: function(){
  60. return this.beginIndex;
  61. },
  62. isWhitespace: function(pos){
  63. var str = this.text[pos];
  64. var whitespaceChars = " \t\n\f";
  65. return (whitespaceChars.indexOf(str) != -1);
  66. },
  67. isNewLine: function(pos){
  68. var str = this.text[pos];
  69. var whitespaceChars = "\n";
  70. return (whitespaceChars.indexOf(str) != -1);
  71. },
  72. preceding: function(pos){
  73. //console.group("[AttributedStringIterator.preceding]");
  74. for(var i in this.startWordOffsets) {
  75. var startWordOffset = this.startWordOffsets[i];
  76. if (pos < startWordOffset && i>0) {
  77. //console.log("startWordOffset: " + this.startWordOffsets[i-1]);
  78. //console.groupEnd();
  79. return this.startWordOffsets[i-1];
  80. }
  81. }
  82. //console.log("pos: " + pos);
  83. //console.groupEnd();
  84. return this.startWordOffsets[i];
  85. },
  86. following: function(pos){
  87. //console.group("[AttributedStringIterator.following]");
  88. for(var i in this.startWordOffsets) {
  89. var startWordOffset = this.startWordOffsets[i];
  90. if (pos < startWordOffset && i>0) {
  91. //console.log("startWordOffset: " + this.startWordOffsets[i]);
  92. //console.groupEnd();
  93. return this.startWordOffsets[i];
  94. }
  95. }
  96. //console.log("pos: " + pos);
  97. //console.groupEnd();
  98. return this.startWordOffsets[i];
  99. },
  100. ltrim: function(str){
  101. var patt2=/^\s+/g;
  102. return str.replace(patt2, "");
  103. },
  104. rtrim: function(str){
  105. var patt2=/\s+$/g;
  106. return str.replace(patt2, "");
  107. },
  108. getLayout: function(start, limit){
  109. return this.text.substr(start, limit - start);
  110. },
  111. getCharAtPos: function(pos) {
  112. return this.text[pos];
  113. }
  114. };
  115. var LineBreakMeasurer = function(paper, x, y, text, fontAttrs){
  116. this.paper = paper;
  117. this.text = new AttributedStringIterator(text);
  118. this.fontAttrs = fontAttrs;
  119. if (this.text.getEndIndex() - this.text.getBeginIndex() < 1) {
  120. throw {message: "Text must contain at least one character.", code: "IllegalArgumentException"};
  121. }
  122. //this.measurer = new TextMeasurer(paper, this.text, this.fontAttrs);
  123. this.limit = this.text.getEndIndex();
  124. this.pos = this.start = this.text.getBeginIndex();
  125. this.rafaelTextObject = this.paper.text(x, y, this.text.text).attr(fontAttrs).attr("text-anchor", "start");
  126. this.svgTextObject = this.rafaelTextObject[0];
  127. };
  128. LineBreakMeasurer.prototype = {
  129. nextOffset: function(wrappingWidth, offsetLimit, requireNextWord) {
  130. //console.group("[nextOffset]");
  131. var nextOffset = this.pos;
  132. if (this.pos < this.limit) {
  133. if (offsetLimit <= this.pos) {
  134. throw {message: "offsetLimit must be after current position", code: "IllegalArgumentException"};
  135. }
  136. var charAtMaxAdvance = this.getLineBreakIndex(this.pos, wrappingWidth);
  137. //charAtMaxAdvance --;
  138. //console.log("charAtMaxAdvance:", charAtMaxAdvance, ", [" + this.text.getCharAtPos(charAtMaxAdvance) + "]");
  139. if (charAtMaxAdvance == this.limit) {
  140. nextOffset = this.limit;
  141. //console.log("charAtMaxAdvance == this.limit");
  142. } else if (this.text.isNewLine(charAtMaxAdvance)) {
  143. //console.log("isNewLine");
  144. nextOffset = charAtMaxAdvance+1;
  145. } else if (this.text.isWhitespace(charAtMaxAdvance)) {
  146. // TODO: find next noSpaceChar
  147. //return nextOffset;
  148. nextOffset = this.text.following(charAtMaxAdvance);
  149. } else {
  150. // Break is in a word; back up to previous break.
  151. /*
  152. var testPos = charAtMaxAdvance + 1;
  153. if (testPos == this.limit) {
  154. console.error("hbz...");
  155. } else {
  156. nextOffset = this.text.preceding(charAtMaxAdvance);
  157. }
  158. */
  159. nextOffset = this.text.preceding(charAtMaxAdvance);
  160. if (nextOffset <= this.pos) {
  161. nextOffset = Math.max(this.pos+1, charAtMaxAdvance);
  162. }
  163. }
  164. }
  165. if (nextOffset > offsetLimit) {
  166. nextOffset = offsetLimit;
  167. }
  168. //console.log("nextOffset: " + nextOffset);
  169. //console.groupEnd();
  170. return nextOffset;
  171. },
  172. nextLayout: function(wrappingWidth) {
  173. //console.groupCollapsed("[nextLayout]");
  174. if (this.pos < this.limit) {
  175. var requireNextWord = false;
  176. var layoutLimit = this.nextOffset(wrappingWidth, this.limit, requireNextWord);
  177. //console.log("layoutLimit:", layoutLimit);
  178. if (layoutLimit == this.pos) {
  179. //console.groupEnd();
  180. return null;
  181. }
  182. var result = this.text.getLayout(this.pos, layoutLimit);
  183. //console.log("layout: \"" + result + "\"");
  184. // remove end of line
  185. //var posEndOfLine = this.text.getEndIndex(this.pos);
  186. //if (posEndOfLine < result.length)
  187. // result = result.substr(0, posEndOfLine);
  188. this.pos = layoutLimit;
  189. //console.groupEnd();
  190. return result;
  191. } else {
  192. //console.groupEnd();
  193. return null;
  194. }
  195. },
  196. getLineBreakIndex: function(pos, wrappingWidth) {
  197. //console.group("[getLineBreakIndex]");
  198. //console.log("pos:"+pos + ", text: \""+ this.text.text.replace(/\n/g, "_").substr(pos, 1) + "\"");
  199. var bb = this.rafaelTextObject.getBBox();
  200. var charNum = -1;
  201. try {
  202. var svgPoint = this.svgTextObject.getStartPositionOfChar(pos);
  203. //var dot = this.paper.ellipse(svgPoint.x, svgPoint.y, 1, 1).attr({"stroke-width": 0, fill: Color.blue});
  204. svgPoint.x = svgPoint.x + wrappingWidth;
  205. //svgPoint.y = bb.y;
  206. //console.log("svgPoint:", svgPoint);
  207. //var dot = this.paper.ellipse(svgPoint.x, svgPoint.y, 1, 1).attr({"stroke-width": 0, fill: Color.red});
  208. charNum = this.svgTextObject.getCharNumAtPosition(svgPoint);
  209. } catch (e){
  210. console.warn("getStartPositionOfChar error, pos:" + pos);
  211. /*
  212. var testPos = pos + 1;
  213. if (testPos < this.limit) {
  214. return testPos
  215. }
  216. */
  217. }
  218. //console.log("charNum:", charNum);
  219. if (charNum == -1) {
  220. //console.groupEnd();
  221. return this.text.getEndIndex(pos);
  222. } else {
  223. // When case there is new line between pos and charnum then use this new line
  224. var newLineIndex = this.text.getEndIndex(pos);
  225. if (newLineIndex < charNum ) {
  226. console.log("newLineIndex <= charNum, newLineIndex:"+newLineIndex+", charNum:"+charNum, "\"" + this.text.text.substr(newLineIndex+1).replace(/\n/g, "?") + "\"");
  227. //console.groupEnd();
  228. return newLineIndex;
  229. }
  230. //var charAtMaxAdvance = this.text.text.substring(charNum, charNum + 1);
  231. var charAtMaxAdvance = this.text.getCharAtPos(charNum);
  232. //console.log("!!charAtMaxAdvance: " + charAtMaxAdvance);
  233. //console.groupEnd();
  234. return charNum;
  235. }
  236. },
  237. getPosition: function() {
  238. return this.pos;
  239. }
  240. };