You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

createSVG.js 3.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. var fs = require("fs"),
  2. path = require("path");
  3. function htmlspecialchars(str) {
  4. //Hum, hum... Could do better
  5. if (typeof str !== "string") return "";
  6. return str.replace(/&/g, "&")
  7. .replace(/</g, "&lt;")
  8. .replace(/>/g, "&gt;")
  9. .replace(/"/g, "&quot;")
  10. .replace(/'/g, "&#039;");
  11. }
  12. function renderPath(el, pathstring) {
  13. return '<path ' +
  14. 'id="' + htmlspecialchars(el.id || "l") + '" ' +
  15. 'stroke-width="' + (el.size | 0) + '" ' +
  16. 'stroke="' + htmlspecialchars(el.color || "#000") + '" ' +
  17. 'd="' + pathstring + '" ' +
  18. '/>';
  19. }
  20. var Tools = {
  21. "Text": function (el) {
  22. return '<text ' +
  23. 'id="' + htmlspecialchars(el.id || "t") + '" ' +
  24. 'x="' + (el.x | 0) + '" ' +
  25. 'y="' + (el.y | 0) + '" ' +
  26. 'font-size="' + (el.size | 0) + '" ' +
  27. 'fill="' + htmlspecialchars(el.color || "#000") + '" ' +
  28. '>' + htmlspecialchars(el.txt || "") + '</text>';
  29. },
  30. "Pencil": function (el) {
  31. if (!el._children) return "";
  32. switch (el._children.length) {
  33. case 0: return "";
  34. case 1:
  35. var pathstring = "M" + el._children[0].x + " " + el._children[0].y +
  36. "L" + el._children[0].x + " " + el._children[0].y;
  37. break;
  38. default:
  39. var pathstring = "M" + el._children[0].x + " " + el._children[0].y + "L";
  40. for (var i = 1; i < el._children.length; i++) {
  41. pathstring += (+el._children[i].x) + " " + (+el._children[i].y) + " ";
  42. }
  43. }
  44. return renderPath(el, pathstring);
  45. },
  46. "Rectangle": function (el) {
  47. var pathstring =
  48. "M" + el.x + " " + el.y +
  49. "L" + el.x + " " + el.y2 +
  50. "L" + el.x2 + " " + el.y2 +
  51. "L" + el.x2 + " " + el.y +
  52. "L" + el.x + " " + el.y;
  53. return renderPath(el, pathstring);
  54. },
  55. "Ellipse": function (el) {
  56. const cx = Math.round((el.x2 + el.x)/2);
  57. const cy = Math.round((el.y2 + el.y)/2);
  58. let rx, ry;
  59. if (el.shape === "Circle") {
  60. rx = ry = Math.round(Math.sqrt(Math.pow(el.x2 - el.x,2)+Math.pow(el.y2 - el.y,2))/2);
  61. } else {
  62. rx = Math.abs(el.x2 - el.x)/2;
  63. ry = Math.abs(el.y2 - el.y)/2;
  64. }
  65. const pathstring =
  66. "M" + cx + " " + cy +
  67. "m" + -rx + ", 0" +
  68. "a" + rx + "," + ry + " 0 1,0 " + (rx * 2) + ",0" +
  69. "a" + rx + "," + ry + " 0 1,0 " + (rx * -2) + ",0";
  70. return renderPath(el, pathstring);
  71. },
  72. "Straight line": function (el) {
  73. var pathstring = "M" + el.x + " " + el.y + "L" + el.x2 + " " + el.y2;
  74. return renderPath(el, pathstring);
  75. }
  76. };
  77. function toSVG(obj) {
  78. var margin = 500, maxelems = 1e4;
  79. var elements = "", i = 0, w = 500, h = 500;
  80. var t = Date.now();
  81. var elems = Object.values(obj);
  82. while (elems.length > 0) {
  83. if (++i > maxelems) break;
  84. var elem = elems.pop();
  85. elems = elems.concat(elem._children || []);
  86. if (elem.x && elem.x + margin > w) w = elem.x + margin;
  87. if (elem.y && elem.y + margin > h) h = elem.y + margin;
  88. var renderFun = Tools[elem.tool];
  89. if (renderFun) elements += renderFun(elem);
  90. }
  91. console.error(i + " elements treated in " + (Date.now() - t) + "ms.");
  92. var svg = '<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="' + w + '" height="' + h + '">' +
  93. '<defs><style type="text/css"><![CDATA[' +
  94. 'text {font-family:"Arial"}' +
  95. 'path {fill:none;stroke-linecap:round;stroke-linejoin:round;}' +
  96. ']]></style></defs>' +
  97. elements +
  98. '</svg>';
  99. return svg;
  100. }
  101. function renderBoard(file, callback) {
  102. var t = Date.now();
  103. fs.readFile(file, function (err, data) {
  104. if (err) return callback(err);
  105. try {
  106. var board = JSON.parse(data);
  107. console.warn("JSON parsed in " + (Date.now() - t) + "ms.");
  108. var svg = toSVG(board);
  109. console.warn("Board rendered in " + (Date.now() - t) + "ms.");
  110. callback(null, svg);
  111. }
  112. catch (err) { return callback(err) }
  113. });
  114. }
  115. if (require.main === module) {
  116. const config = require("./configuration.js")
  117. var HISTORY_FILE = process.argv[2] || path.join(config.HISTORY_DIR, "board-anonymous.json");
  118. renderBoard(HISTORY_FILE, function (err, rendered) {
  119. console.log(rendered);
  120. });
  121. } else {
  122. module.exports = { 'renderBoard': renderBoard };
  123. }