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.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441
  1. window.onload = function () {
  2. var paper = Raphael("holder");
  3. //var curve = paper.ellipse(100, 100, 1, 1).attr({"stroke-width": 0, fill: Color.red});
  4. var text = "Betty Botter bought some butter but, she said, the butter's bitter. If I put it in my batter, it will make my batter bitter. But a bit of better butter will make my batter better. So, she bought a bit of butter, better than her bitter butter, and she put it in her batter, and the batter was not bitter. It was better Betty Botter bought a bit better butter.";
  5. var font = {font: "11px Arial", "font-style":"italic", opacity: 1, "fill": LABEL_COLOR, stroke: LABEL_COLOR, "stroke-width":.3};
  6. var font = {font: "11px Arial", opacity: 1, "fill": LABEL_COLOR};
  7. var boxWidth = 100
  8. var AttributedStringIterator = function(text){
  9. //this.text = this.rtrim(this.ltrim(text));
  10. text = text.replace(/(\s)+/, " ");
  11. this.text = this.rtrim(text);
  12. /*
  13. if (beginIndex < 0 || beginIndex > endIndex || endIndex > length()) {
  14. throw new IllegalArgumentException("Invalid substring range");
  15. }
  16. */
  17. this.beginIndex = 0;
  18. this.endIndex = this.text.length;
  19. this.currentIndex = this.beginIndex;
  20. //console.group("[AttributedStringIterator]");
  21. var i = 0;
  22. var string = this.text;
  23. var fullPos = 0;
  24. //console.log("string: \"" + string + "\", length: " + string.length);
  25. this.startWordOffsets = [];
  26. this.startWordOffsets.push(fullPos);
  27. // TODO: remove i 1000
  28. while (i<1000) {
  29. var pos = string.search(/[ \t\n\f-\.\,]/);
  30. if (pos == -1)
  31. break;
  32. // whitespace start
  33. fullPos += pos;
  34. string = string.substr(pos);
  35. ////console.log("fullPos: " + fullPos + ", pos: " + pos + ", string: ", string);
  36. // remove whitespaces
  37. var pos = string.search(/[^ \t\n\f-\.\,]/);
  38. if (pos == -1)
  39. break;
  40. // whitespace end
  41. fullPos += pos;
  42. string = string.substr(pos);
  43. ////console.log("fullPos: " + fullPos);
  44. this.startWordOffsets.push(fullPos);
  45. i++;
  46. }
  47. //console.log("startWordOffsets: ", this.startWordOffsets);
  48. //console.groupEnd();
  49. };
  50. AttributedStringIterator.prototype = {
  51. getEndIndex: function(pos){
  52. if (typeof(pos) == "undefined")
  53. return this.endIndex;
  54. var string = this.text.substr(pos, this.endIndex - pos);
  55. var posEndOfLine = string.search(/[\n]/);
  56. if (posEndOfLine == -1)
  57. return this.endIndex;
  58. else
  59. return pos + posEndOfLine;
  60. },
  61. getBeginIndex: function(){
  62. return this.beginIndex;
  63. },
  64. isWhitespace: function(pos){
  65. var str = this.text[pos];
  66. var whitespaceChars = " \t\n\f";
  67. return (whitespaceChars.indexOf(str) != -1);
  68. },
  69. isNewLine: function(pos){
  70. var str = this.text[pos];
  71. var whitespaceChars = "\n";
  72. return (whitespaceChars.indexOf(str) != -1);
  73. },
  74. preceding: function(pos){
  75. //console.group("[AttributedStringIterator.preceding]");
  76. for(var i in this.startWordOffsets) {
  77. var startWordOffset = this.startWordOffsets[i];
  78. if (pos < startWordOffset && i>0) {
  79. //console.log("startWordOffset: " + this.startWordOffsets[i-1]);
  80. //console.groupEnd();
  81. return this.startWordOffsets[i-1];
  82. }
  83. }
  84. //console.log("pos: " + pos);
  85. //console.groupEnd();
  86. return this.startWordOffsets[i];
  87. },
  88. following: function(pos){
  89. //console.group("[AttributedStringIterator.following]");
  90. for(var i in this.startWordOffsets) {
  91. var startWordOffset = this.startWordOffsets[i];
  92. if (pos < startWordOffset && i>0) {
  93. //console.log("startWordOffset: " + this.startWordOffsets[i]);
  94. //console.groupEnd();
  95. return this.startWordOffsets[i];
  96. }
  97. }
  98. //console.log("pos: " + pos);
  99. //console.groupEnd();
  100. return this.startWordOffsets[i];
  101. },
  102. ltrim: function(str){
  103. var patt2=/^\s+/g;
  104. return str.replace(patt2, "");
  105. },
  106. rtrim: function(str){
  107. var patt2=/\s+$/g;
  108. return str.replace(patt2, "");
  109. },
  110. getLayout: function(start, limit){
  111. return this.text.substr(start, limit - start);
  112. },
  113. getCharAtPos: function(pos) {
  114. return this.text[pos];
  115. }
  116. };
  117. /*
  118. var TextMeasurer = function(paper, text, fontAttrs){
  119. this.text = text;
  120. this.paper = paper;
  121. this.fontAttrs = fontAttrs;
  122. this.fStart = this.text.getBeginIndex();
  123. };
  124. TextMeasurer.prototype = {
  125. getLineBreakIndex: function(start, maxAdvance){
  126. var localStart = start - this.fStart;
  127. },
  128. getLayout: function(){
  129. }
  130. }
  131. */
  132. var LineBreakMeasurer = function(paper, text, fontAttrs){
  133. this.paper = paper;
  134. this.text = new AttributedStringIterator(text);
  135. this.fontAttrs = fontAttrs;
  136. if (this.text.getEndIndex() - this.text.getBeginIndex() < 1) {
  137. throw {message: "Text must contain at least one character.", code: "IllegalArgumentException"};
  138. }
  139. //this.measurer = new TextMeasurer(paper, this.text, this.fontAttrs);
  140. this.limit = this.text.getEndIndex();
  141. this.pos = this.start = this.text.getBeginIndex();
  142. this.rafaelTextObject = this.paper.text(100, 100, this.text.text).attr(fontAttrs).attr("text-anchor", "start");
  143. this.svgTextObject = this.rafaelTextObject[0];
  144. };
  145. LineBreakMeasurer.prototype = {
  146. nextOffset: function(wrappingWidth, offsetLimit, requireNextWord) {
  147. //console.group("[nextOffset]");
  148. var nextOffset = this.pos;
  149. if (this.pos < this.limit) {
  150. if (offsetLimit <= this.pos) {
  151. throw {message: "offsetLimit must be after current position", code: "IllegalArgumentException"};
  152. }
  153. var charAtMaxAdvance = this.getLineBreakIndex(this.pos, wrappingWidth);
  154. //charAtMaxAdvance --;
  155. //console.log("charAtMaxAdvance:", charAtMaxAdvance, ", [" + this.text.getCharAtPos(charAtMaxAdvance) + "]");
  156. if (charAtMaxAdvance == this.limit) {
  157. nextOffset = this.limit;
  158. //console.log("charAtMaxAdvance == this.limit");
  159. } else if (this.text.isNewLine(charAtMaxAdvance)) {
  160. console.log("isNewLine");
  161. nextOffset = charAtMaxAdvance+1;
  162. } else if (this.text.isWhitespace(charAtMaxAdvance)) {
  163. // TODO: find next noSpaceChar
  164. //return nextOffset;
  165. nextOffset = this.text.following(charAtMaxAdvance);
  166. } else {
  167. // Break is in a word; back up to previous break.
  168. /*
  169. var testPos = charAtMaxAdvance + 1;
  170. if (testPos == this.limit) {
  171. console.error("hbz...");
  172. } else {
  173. nextOffset = this.text.preceding(charAtMaxAdvance);
  174. }
  175. */
  176. nextOffset = this.text.preceding(charAtMaxAdvance);
  177. if (nextOffset <= this.pos) {
  178. nextOffset = Math.max(this.pos+1, charAtMaxAdvance);
  179. }
  180. }
  181. }
  182. if (nextOffset > offsetLimit) {
  183. nextOffset = offsetLimit;
  184. }
  185. //console.log("nextOffset: " + nextOffset);
  186. //console.groupEnd();
  187. return nextOffset;
  188. },
  189. nextLayout: function(wrappingWidth) {
  190. //console.groupCollapsed("[nextLayout]");
  191. if (this.pos < this.limit) {
  192. var requireNextWord = false;
  193. var layoutLimit = this.nextOffset(wrappingWidth, this.limit, requireNextWord);
  194. //console.log("layoutLimit:", layoutLimit);
  195. if (layoutLimit == this.pos) {
  196. //console.groupEnd();
  197. return null;
  198. }
  199. var result = this.text.getLayout(this.pos, layoutLimit);
  200. //console.log("layout: \"" + result + "\"");
  201. // remove end of line
  202. //var posEndOfLine = this.text.getEndIndex(this.pos);
  203. //if (posEndOfLine < result.length)
  204. // result = result.substr(0, posEndOfLine);
  205. this.pos = layoutLimit;
  206. //console.groupEnd();
  207. return result;
  208. } else {
  209. //console.groupEnd();
  210. return null;
  211. }
  212. },
  213. getLineBreakIndex: function(pos, wrappingWidth) {
  214. //console.group("[getLineBreakIndex]");
  215. //console.log("pos:"+pos + ", text: \""+ this.text.text.replace(/\n/g, "_").substr(pos, 1) + "\"");
  216. var bb = this.rafaelTextObject.getBBox();
  217. var charNum = -1;
  218. try {
  219. var svgPoint = this.svgTextObject.getStartPositionOfChar(pos);
  220. //var dot = this.paper.ellipse(svgPoint.x, svgPoint.y, 1, 1).attr({"stroke-width": 0, fill: Color.blue});
  221. svgPoint.x = svgPoint.x + wrappingWidth;
  222. //svgPoint.y = bb.y;
  223. //console.log("svgPoint:", svgPoint);
  224. //var dot = this.paper.ellipse(svgPoint.x, svgPoint.y, 1, 1).attr({"stroke-width": 0, fill: Color.red});
  225. charNum = this.svgTextObject.getCharNumAtPosition(svgPoint);
  226. } catch (e){
  227. console.warn("getStartPositionOfChar error, pos:" + pos);
  228. /*
  229. var testPos = pos + 1;
  230. if (testPos < this.limit) {
  231. return testPos
  232. }
  233. */
  234. }
  235. //console.log("charNum:", charNum);
  236. if (charNum == -1) {
  237. //console.groupEnd();
  238. return this.text.getEndIndex(pos);
  239. } else {
  240. // When case there is new line between pos and charnum then use this new line
  241. var newLineIndex = this.text.getEndIndex(pos);
  242. if (newLineIndex < charNum ) {
  243. console.log("newLineIndex <= charNum, newLineIndex:"+newLineIndex+", charNum:"+charNum, "\"" + this.text.text.substr(newLineIndex+1).replace(/\n/g, "↵") + "\"");
  244. //console.groupEnd();
  245. return newLineIndex;
  246. }
  247. //var charAtMaxAdvance = this.text.text.substring(charNum, charNum + 1);
  248. var charAtMaxAdvance = this.text.getCharAtPos(charNum);
  249. //console.log("!!charAtMaxAdvance: " + charAtMaxAdvance);
  250. //console.groupEnd();
  251. return charNum;
  252. }
  253. },
  254. getPosition: function() {
  255. return this.pos;
  256. }
  257. };
  258. // ******
  259. function drawMultilineText(text, x, y, boxWidth, boxHeight, options) {
  260. var TEXT_PADDING = 3;
  261. var width = boxWidth - (2 * TEXT_PADDING);
  262. if (boxHeight)
  263. var height = boxHeight - (2 * TEXT_PADDING);
  264. var layouts = [];
  265. var measurer = new LineBreakMeasurer(paper, text, font);
  266. var lineHeight = measurer.rafaelTextObject.getBBox().height;
  267. console.log("text: ", text.replace(/\n/g, "↵"));
  268. if (height) {
  269. var availableLinesCount = parseInt(height/lineHeight);
  270. console.log("availableLinesCount: " + availableLinesCount);
  271. }
  272. var i = 1;
  273. while (measurer.getPosition() < measurer.text.getEndIndex()) {
  274. var layout = measurer.nextLayout(width);
  275. //console.log("LAYOUT: " + layout + ", getPosition: " + measurer.getPosition());
  276. if (layout != null) {
  277. if (!availableLinesCount || i < availableLinesCount) {
  278. layouts.push(layout);
  279. } else {
  280. layouts.push(fitTextToWidth(layout + "...", boxWidth));
  281. break;
  282. }
  283. }
  284. i++;
  285. };
  286. console.log(layouts);
  287. measurer.rafaelTextObject.attr({"text": layouts.join("\n")});
  288. //measurer.rafaelTextObject.attr({"text-anchor": "end"});
  289. //measurer.rafaelTextObject.attr({"text-anchor": "middle"});
  290. if (options)
  291. measurer.rafaelTextObject.attr({"text-anchor": options["text-anchor"]});
  292. var bb = measurer.rafaelTextObject.getBBox();
  293. //measurer.rafaelTextObject.attr({"x": x + boxWidth/2});
  294. if (options["vertical-align"] == "top")
  295. measurer.rafaelTextObject.attr({"y": y + bb.height/2 + TEXT_PADDING});
  296. else
  297. measurer.rafaelTextObject.attr({"y": y + height/2});
  298. //var bb = measurer.rafaelTextObject.getBBox();
  299. if (measurer.rafaelTextObject.attr("text-anchor") == "middle" )
  300. measurer.rafaelTextObject.attr("x", x + boxWidth/2 + TEXT_PADDING/2);
  301. else if (measurer.rafaelTextObject.attr("text-anchor") == "end" )
  302. measurer.rafaelTextObject.attr("x", x + boxWidth + TEXT_PADDING/2);
  303. else
  304. measurer.rafaelTextObject.attr("x", x + boxWidth/2 - bb.width/2 + TEXT_PADDING/2);
  305. var boxStyle = {stroke: Color.LightSteelBlue2, "stroke-width": 1.0, "stroke-dasharray": "- "};
  306. /*
  307. var box = paper.rect(x+.0 + boxWidth/2 - bb.width/2+ TEXT_PADDING/2, y + .5 + boxHeight/2 - bb.height/2, width, height).attr(boxStyle);
  308. box.attr("height", bb.height);
  309. */
  310. //var box = paper.rect(bb.x - .5 + bb.width/2 + TEXT_PADDING, bb.y + bb.height/2, bb.width, bb.height).attr(boxStyle);
  311. var textAreaCX = x + boxWidth/2;
  312. var textAreaCY = y + height/2;
  313. var dotLeftTop = paper.ellipse(x, y, 3, 3).attr({"stroke-width": 0, fill: Color.LightSteelBlue, stroke: "none"});
  314. var dotCenter = paper.ellipse(textAreaCX, textAreaCY, 3, 3).attr({fill: Color.LightSteelBlue2, stroke: "none"});
  315. /*
  316. // real bbox
  317. var bb = measurer.rafaelTextObject.getBBox();
  318. var rect = paper.rect(bb.x+.5, bb.y + .5, bb.width, bb.height).attr({"stroke-width": 1});
  319. */
  320. var boxStyle = {stroke: Color.LightSteelBlue2, "stroke-width": 1.0, "stroke-dasharray": "- "};
  321. var rect = paper.rect(x+.5, y + .5, boxWidth, boxHeight).attr(boxStyle);
  322. }
  323. /*
  324. for (var i=0; i<1; i++) {
  325. var t = text;
  326. //var t = "Высококвалифицирова";
  327. var text = paper.text(300, 100, t).attr(font).attr("text-anchor", "start");
  328. var bbText = text.getBBox();
  329. paper.rect(300+.5, 100 + .5, bbText.width, bbText.height).attr({"stroke-width": 1});
  330. console.log("t: ", t.replace(/\n/g, "↵"));
  331. while (measurer.getPosition() < measurer.text.getEndIndex()) {
  332. var layout = measurer.nextLayout(width);
  333. //console.log("LAYOUT: " + layout + ", getPosition: " + measurer.getPosition());
  334. if (layout != null)
  335. layouts.push(layout);
  336. };
  337. measurer.rafaelTextObject.attr("text", layouts.join("\n"));
  338. var bb = measurer.rafaelTextObject.getBBox();
  339. var rect = paper.rect(bb.x+.5, bb.y + .5, bb.width, bb.height).attr({"stroke-width": 1});
  340. lay.push(layouts);
  341. console.log(layouts);
  342. }
  343. */
  344. var fitTextToWidth = function(original, width) {
  345. var text = original;
  346. // TODO: move attr on parameters
  347. var attr = {font: "11px Arial", opacity: 0};
  348. // remove length for "..."
  349. var dots = paper.text(0, 0, "...").attr(attr).hide();
  350. var dotsBB = dots.getBBox();
  351. var maxWidth = width - dotsBB.width;
  352. var textElement = paper.text(0, 0, text).attr(attr).hide();
  353. var bb = textElement.getBBox();
  354. // it's a little bit incorrect with "..."
  355. while (bb.width > maxWidth && text.length > 0) {
  356. text = text.substring(0, text.length - 1);
  357. textElement.attr({"text": text});
  358. bb = textElement.getBBox();
  359. }
  360. // remove element from paper
  361. textElement.remove();
  362. if (text != original) {
  363. text = text + "...";
  364. }
  365. return text;
  366. }
  367. var x=100, y=90, height=20;
  368. var options = {"text-anchor": "middle", "boxHeight": 150, "vertical-align": "top"};
  369. var options = {"boxHeight": 150, "vertical-align": "top"};
  370. drawMultilineText(text, x, y, 150, 100, options);
  371. };