editor.js 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948
  1. var editor = {
  2. wall: function (start, end, type, thick) {
  3. this.thick = thick;
  4. this.start = start;
  5. this.end = end;
  6. this.type = type;
  7. this.parent = null;
  8. this.child = null;
  9. this.angle = 0;
  10. this.equations = {};
  11. this.coords = [];
  12. this.backUp = false;
  13. },
  14. // RETURN OBJECTS ARRAY INDEX OF WALLS [WALL1, WALL2, n...] WALLS WITH THIS NODE, EXCEPT PARAM = OBJECT WALL
  15. getWallNode: function (coords, except = false) {
  16. var nodes = [];
  17. for (var k in WALLS) {
  18. if (!isObjectsEquals(WALLS[k], except)) {
  19. if (isObjectsEquals(WALLS[k].start, coords)) {
  20. nodes.push({ wall: WALLS[k], type: "start" });
  21. }
  22. if (isObjectsEquals(WALLS[k].end, coords)) {
  23. nodes.push({ wall: WALLS[k], type: "end" });
  24. }
  25. }
  26. }
  27. if (nodes.length == 0) return false;
  28. else return nodes;
  29. },
  30. wallsComputing: function (WALLS, action = false) {
  31. // IF ACTION == MOVE -> equation2 exist !!!!!
  32. $('#boxwall').empty();
  33. $('#boxArea').empty();
  34. for (var vertice = 0; vertice < WALLS.length; vertice++) {
  35. var wall = WALLS[vertice];
  36. if (wall.parent != null) {
  37. if (!isObjectsEquals(wall.parent.start, wall.start) && !isObjectsEquals(wall.parent.end, wall.start)) {
  38. wall.parent = null;
  39. }
  40. }
  41. if (wall.child != null) {
  42. if (!isObjectsEquals(wall.child.start, wall.end) && !isObjectsEquals(wall.child.end, wall.end)) {
  43. wall.child = null;
  44. }
  45. }
  46. }
  47. for (var vertice = 0; vertice < WALLS.length; vertice++) {
  48. var wall = WALLS[vertice];
  49. if (wall.parent != null) {
  50. if (isObjectsEquals(wall.parent.start, wall.start)) {
  51. var previousWall = wall.parent;
  52. var previousWallStart = previousWall.end;
  53. var previousWallEnd = previousWall.start;
  54. }
  55. if (isObjectsEquals(wall.parent.end, wall.start)) {
  56. var previousWall = wall.parent;
  57. var previousWallStart = previousWall.start;
  58. var previousWallEnd = previousWall.end;
  59. }
  60. }
  61. else {
  62. var S = editor.getWallNode(wall.start, wall);
  63. // if (wallInhibation && isObjectsEquals(wall, wallInhibation)) S = false;
  64. for (var k in S) {
  65. var eqInter = editor.createEquationFromWall(S[k].wall);
  66. var angleInter = 90; // TO PASS TEST
  67. if (action == "move") {
  68. angleInter = qSVG.angleBetweenEquations(eqInter.A, equation2.A);
  69. }
  70. if (S[k].type == 'start' && S[k].wall.parent == null && angleInter > 20 && angleInter < 160) {
  71. wall.parent = S[k].wall;
  72. S[k].wall.parent = wall;
  73. var previousWall = wall.parent;
  74. var previousWallStart = previousWall.end;
  75. var previousWallEnd = previousWall.start;
  76. }
  77. if (S[k].type == 'end' && S[k].wall.child == null && angleInter > 20 && angleInter < 160) {
  78. wall.parent = S[k].wall;
  79. S[k].wall.child = wall;
  80. var previousWall = wall.parent;
  81. var previousWallStart = previousWall.start;
  82. var previousWallEnd = previousWall.end;
  83. }
  84. }
  85. }
  86. if (wall.child != null) {
  87. if (isObjectsEquals(wall.child.end, wall.end)) {
  88. var nextWall = wall.child;
  89. var nextWallStart = nextWall.end;
  90. var nextWallEnd = nextWall.start;
  91. }
  92. else {
  93. var nextWall = wall.child;
  94. var nextWallStart = nextWall.start;
  95. var nextWallEnd = nextWall.end;
  96. }
  97. }
  98. else {
  99. var E = editor.getWallNode(wall.end, wall);
  100. // if (wallInhibation && isObjectsEquals(wall, wallInhibation)) E = false;
  101. for (var k in E) {
  102. var eqInter = editor.createEquationFromWall(E[k].wall);
  103. var angleInter = 90; // TO PASS TEST
  104. if (action == "move") {
  105. angleInter = qSVG.angleBetweenEquations(eqInter.A, equation2.A);
  106. }
  107. if (E[k].type == 'end' && E[k].wall.child == null && angleInter > 20 && angleInter < 160) {
  108. wall.child = E[k].wall;
  109. E[k].wall.child = wall;
  110. var nextWall = wall.child;
  111. var nextWallStart = nextWall.end;
  112. var nextWallEnd = nextWall.start;
  113. }
  114. if (E[k].type == 'start' && E[k].wall.parent == null && angleInter > 20 && angleInter < 160) {
  115. wall.child = E[k].wall;
  116. E[k].wall.parent = wall;
  117. var nextWall = wall.child;
  118. var nextWallStart = nextWall.start;
  119. var nextWallEnd = nextWall.end;
  120. }
  121. }
  122. }
  123. var angleWall = Math.atan2(wall.end.y - wall.start.y, wall.end.x - wall.start.x);
  124. wall.angle = angleWall;
  125. var wallThickX = (wall.thick / 2) * Math.sin(angleWall);
  126. var wallThickY = (wall.thick / 2) * Math.cos(angleWall);
  127. var eqWallUp = qSVG.createEquation(wall.start.x + wallThickX, wall.start.y - wallThickY, wall.end.x + wallThickX, wall.end.y - wallThickY);
  128. var eqWallDw = qSVG.createEquation(wall.start.x - wallThickX, wall.start.y + wallThickY, wall.end.x - wallThickX, wall.end.y + wallThickY);
  129. var eqWallBase = qSVG.createEquation(wall.start.x, wall.start.y, wall.end.x, wall.end.y);
  130. wall.equations = { up: eqWallUp, down: eqWallDw, base: eqWallBase };
  131. var dWay;
  132. // WALL STARTED
  133. if (wall.parent == null) {
  134. var eqP = qSVG.perpendicularEquation(eqWallUp, wall.start.x, wall.start.y);
  135. var interUp = qSVG.intersectionOfEquations(eqWallUp, eqP, "object");
  136. var interDw = qSVG.intersectionOfEquations(eqWallDw, eqP, "object");
  137. wall.coords = [interUp, interDw];
  138. dWay = "M" + interUp.x + "," + interUp.y + " L" + interDw.x + "," + interDw.y + " ";
  139. }
  140. else {
  141. var eqP = qSVG.perpendicularEquation(eqWallUp, wall.start.x, wall.start.y);
  142. // var previousWall = wall.parent;
  143. // var previousWallStart = previousWall.start;
  144. // var previousWallEnd = previousWall.end;
  145. var anglePreviousWall = Math.atan2(previousWallEnd.y - previousWallStart.y, previousWallEnd.x - previousWallStart.x);
  146. var previousWallThickX = (previousWall.thick / 2) * Math.sin(anglePreviousWall);
  147. var previousWallThickY = (previousWall.thick / 2) * Math.cos(anglePreviousWall);
  148. var eqPreviousWallUp = qSVG.createEquation(previousWallStart.x + previousWallThickX, previousWallStart.y - previousWallThickY, previousWallEnd.x + previousWallThickX, previousWallEnd.y - previousWallThickY);
  149. var eqPreviousWallDw = qSVG.createEquation(previousWallStart.x - previousWallThickX, previousWallStart.y + previousWallThickY, previousWallEnd.x - previousWallThickX, previousWallEnd.y + previousWallThickY);
  150. if (Math.abs(anglePreviousWall - angleWall) > 0.09) {
  151. var interUp = qSVG.intersectionOfEquations(eqWallUp, eqPreviousWallUp, "object");
  152. var interDw = qSVG.intersectionOfEquations(eqWallDw, eqPreviousWallDw, "object");
  153. if (eqWallUp.A == eqPreviousWallUp.A) {
  154. interUp = { x: wall.start.x + wallThickX, y: wall.start.y - wallThickY };
  155. interDw = { x: wall.start.x - wallThickX, y: wall.start.y + wallThickY };
  156. }
  157. var miter = qSVG.gap(interUp, { x: previousWallEnd.x, y: previousWallEnd.y });
  158. if (miter > 1000) {
  159. var interUp = qSVG.intersectionOfEquations(eqP, eqWallUp, "object");
  160. var interDw = qSVG.intersectionOfEquations(eqP, eqWallDw, "object");
  161. }
  162. }
  163. if (Math.abs(anglePreviousWall - angleWall) <= 0.09) {
  164. var interUp = qSVG.intersectionOfEquations(eqP, eqWallUp, "object");
  165. var interDw = qSVG.intersectionOfEquations(eqP, eqWallDw, "object");
  166. }
  167. wall.coords = [interUp, interDw];
  168. dWay = "M" + interUp.x + "," + interUp.y + " L" + interDw.x + "," + interDw.y + " ";
  169. }
  170. // WALL FINISHED
  171. if (wall.child == null) {
  172. var eqP = qSVG.perpendicularEquation(eqWallUp, wall.end.x, wall.end.y);
  173. var interUp = qSVG.intersectionOfEquations(eqWallUp, eqP, "object");
  174. var interDw = qSVG.intersectionOfEquations(eqWallDw, eqP, "object");
  175. wall.coords.push(interDw, interUp);
  176. dWay = dWay + "L" + interDw.x + "," + interDw.y + " L" + interUp.x + "," + interUp.y + " Z";
  177. }
  178. else {
  179. var eqP = qSVG.perpendicularEquation(eqWallUp, wall.end.x, wall.end.y);
  180. // var nextWall = wall.child;
  181. // var nextWallStart = nextWall.start;
  182. // var nextWallEnd = nextWall.end;
  183. var angleNextWall = Math.atan2(nextWallEnd.y - nextWallStart.y, nextWallEnd.x - nextWallStart.x);
  184. var nextWallThickX = (nextWall.thick / 2) * Math.sin(angleNextWall);
  185. var nextWallThickY = (nextWall.thick / 2) * Math.cos(angleNextWall);
  186. var eqNextWallUp = qSVG.createEquation(nextWallStart.x + nextWallThickX, nextWallStart.y - nextWallThickY, nextWallEnd.x + nextWallThickX, nextWallEnd.y - nextWallThickY);
  187. var eqNextWallDw = qSVG.createEquation(nextWallStart.x - nextWallThickX, nextWallStart.y + nextWallThickY, nextWallEnd.x - nextWallThickX, nextWallEnd.y + nextWallThickY);
  188. if (Math.abs(angleNextWall - angleWall) > 0.09) {
  189. var interUp = qSVG.intersectionOfEquations(eqWallUp, eqNextWallUp, "object");
  190. var interDw = qSVG.intersectionOfEquations(eqWallDw, eqNextWallDw, "object");
  191. if (eqWallUp.A == eqNextWallUp.A) {
  192. interUp = { x: wall.end.x + wallThickX, y: wall.end.y - wallThickY };
  193. interDw = { x: wall.end.x - wallThickX, y: wall.end.y + wallThickY };
  194. }
  195. var miter = qSVG.gap(interUp, { x: nextWallStart.x, y: nextWallStart.y });
  196. if (miter > 1000) {
  197. var interUp = qSVG.intersectionOfEquations(eqWallUp, eqP, "object");
  198. var interDw = qSVG.intersectionOfEquations(eqWallDw, eqP, "object");
  199. }
  200. }
  201. if (Math.abs(angleNextWall - angleWall) <= 0.09) {
  202. var interUp = qSVG.intersectionOfEquations(eqWallUp, eqP, "object");
  203. var interDw = qSVG.intersectionOfEquations(eqWallDw, eqP, "object");
  204. }
  205. wall.coords.push(interDw, interUp);
  206. dWay = dWay + "L" + interDw.x + "," + interDw.y + " L" + interUp.x + "," + interUp.y + " Z";
  207. }
  208. wall.graph = editor.makeWall(dWay);
  209. $('#boxwall').append(wall.graph);
  210. }
  211. },
  212. makeWall: function (way) {
  213. var wallScreen = qSVG.create('none', 'path', {
  214. d: way,
  215. stroke: "none",
  216. fill: colorWall,
  217. "stroke-width": 1,
  218. "stroke-linecap": "butt",
  219. "stroke-linejoin": "miter",
  220. "stroke-miterlimit": 4,
  221. "fill-rule": "nonzero"
  222. });
  223. return wallScreen;
  224. },
  225. invisibleWall: function (wallToInvisble = false) {
  226. if (!wallToInvisble) wallToInvisble = binder.wall;
  227. // Use the provided wall instead of an external variable to avoid undefined access
  228. var objWall = editor.objFromWall(wallToInvisble);
  229. if (objWall.length == 0) {
  230. wallToInvisble.type = "separate";
  231. wallToInvisble.backUp = wallToInvisble.thick;
  232. wallToInvisble.thick = 0.07;
  233. editor.architect(WALLS);
  234. mode = "select_mode";
  235. $('#panel').show(200);
  236. save();
  237. return true;
  238. }
  239. else {
  240. $('#boxinfo').html('Les murs contenant des portes ou des fenêtres ne peuvent être une séparation !');
  241. return false;
  242. }
  243. },
  244. visibleWall: function (wallToInvisble = false) {
  245. if (!wallToInvisble) wallToInvisble = binder.wall;
  246. wallToInvisble.type = "normal";
  247. wallToInvisble.thick = wallToInvisble.backUp;
  248. wallToInvisble.backUp = false;
  249. editor.architect(WALLS);
  250. mode = "select_mode";
  251. $('#panel').show(200);
  252. save();
  253. return true;
  254. },
  255. architect: function (WALLS) {
  256. editor.wallsComputing(WALLS);
  257. Rooms = qSVG.polygonize(WALLS);
  258. $('#boxRoom').empty();
  259. $('#boxSurface').empty();
  260. editor.roomMaker(Rooms);
  261. return true;
  262. },
  263. splitWall: function (wallToSplit = false) {
  264. if (!wallToSplit) wallToSplit = binder.wall;
  265. var eqWall = editor.createEquationFromWall(wallToSplit);
  266. var wallToSplitLength = qSVG.gap(wallToSplit.start, wallToSplit.end);
  267. var newWalls = [];
  268. for (var k in WALLS) {
  269. var eq = editor.createEquationFromWall(WALLS[k]);
  270. var inter = qSVG.intersectionOfEquations(eqWall, eq, 'obj');
  271. if (qSVG.btwn(inter.x, binder.wall.start.x, binder.wall.end.x, 'round') && qSVG.btwn(inter.y, binder.wall.start.y, binder.wall.end.y, 'round') && qSVG.btwn(inter.x, WALLS[k].start.x, WALLS[k].end.x, 'round') && qSVG.btwn(inter.y, WALLS[k].start.y, WALLS[k].end.y, 'round')) {
  272. var distance = qSVG.gap(wallToSplit.start, inter);
  273. if (distance > 5 && distance < wallToSplitLength) newWalls.push({ distance: distance, coords: inter });
  274. }
  275. }
  276. newWalls.sort(function (a, b) {
  277. return (a.distance - b.distance).toFixed(2);
  278. });
  279. var initCoords = wallToSplit.start;
  280. var initThick = wallToSplit.thick;
  281. // CLEAR THE WALL BEFORE PIECES RE-BUILDER
  282. for (var k in WALLS) {
  283. if (isObjectsEquals(WALLS[k].child, wallToSplit)) WALLS[k].child = null;
  284. if (isObjectsEquals(WALLS[k].parent, wallToSplit)) { WALLS[k].parent = null; }
  285. }
  286. WALLS.splice(WALLS.indexOf(wallToSplit), 1);
  287. var wall;
  288. for (var k in newWalls) {
  289. wall = new editor.wall(initCoords, newWalls[k].coords, "normal", initThick);
  290. WALLS.push(wall);
  291. wall.child = WALLS[WALLS.length];
  292. initCoords = newWalls[k].coords;
  293. }
  294. // LAST WALL ->
  295. wall = new editor.wall(initCoords, wallToSplit.end, "normal", initThick);
  296. WALLS.push(wall);
  297. editor.architect(WALLS);
  298. mode = "select_mode";
  299. $('#panel').show(200);
  300. save();
  301. return true;
  302. },
  303. nearWallNode: function (snap, range = Infinity, except = ['']) {
  304. var best;
  305. var bestWall;
  306. var scan;
  307. var i = 0;
  308. var scanDistance;
  309. var bestDistance = Infinity;
  310. for (var k = 0; k < WALLS.length; k++) {
  311. if (except.indexOf(WALLS[k]) == -1) {
  312. scanStart = WALLS[k].start;
  313. scanEnd = WALLS[k].end;
  314. scanDistance = qSVG.measure(scanStart, snap);
  315. if (scanDistance < bestDistance) {
  316. best = scanStart;
  317. bestDistance = scanDistance;
  318. bestWall = k;
  319. }
  320. scanDistance = qSVG.measure(scanEnd, snap);
  321. if (scanDistance < bestDistance) {
  322. best = scanEnd;
  323. bestDistance = scanDistance;
  324. bestWall = k;
  325. }
  326. }
  327. }
  328. if (bestDistance <= range) {
  329. return ({
  330. x: best.x,
  331. y: best.y,
  332. bestWall: bestWall
  333. });
  334. } else {
  335. return false;
  336. }
  337. },
  338. // USING WALLS SUPER WALL OBJECTS ARRAY
  339. rayCastingWall: function (snap) {
  340. var wallList = [];
  341. for (var i = 0; i < WALLS.length; i++) {
  342. // Defensive: skip walls without full coords
  343. if (!WALLS[i] || !WALLS[i].coords || WALLS[i].coords.length < 4) continue;
  344. var polygon = [];
  345. for (var pp = 0; pp < 4; pp++) {
  346. polygon.push({ x: WALLS[i].coords[pp].x, y: WALLS[i].coords[pp].y }); // FOR Z
  347. }
  348. if (qSVG.rayCasting(snap, polygon)) {
  349. wallList.push(WALLS[i]); // Return EDGES Index
  350. }
  351. }
  352. if (wallList.length == 0) return false;
  353. else {
  354. if (wallList.length == 1) return wallList[0];
  355. else return wallList;
  356. }
  357. },
  358. stickOnWall: function (snap) {
  359. if (WALLS.length == 0) return false;
  360. var wallDistance = Infinity;
  361. var wallSelected = {};
  362. var result;
  363. if (WALLS.length == 0) return false;
  364. for (var e = 0; e < WALLS.length; e++) {
  365. var eq1 = qSVG.createEquation(WALLS[e].coords[0].x, WALLS[e].coords[0].y, WALLS[e].coords[3].x, WALLS[e].coords[3].y);
  366. result1 = qSVG.nearPointOnEquation(eq1, snap);
  367. var eq2 = qSVG.createEquation(WALLS[e].coords[1].x, WALLS[e].coords[1].y, WALLS[e].coords[2].x, WALLS[e].coords[2].y);
  368. result2 = qSVG.nearPointOnEquation(eq2, snap);
  369. if (result1.distance < wallDistance && qSVG.btwn(result1.x, WALLS[e].coords[0].x, WALLS[e].coords[3].x) && qSVG.btwn(result1.y, WALLS[e].coords[0].y, WALLS[e].coords[3].y)) {
  370. wallDistance = result1.distance;
  371. wallSelected = { wall: WALLS[e], x: result1.x, y: result1.y, distance: result1.distance };
  372. }
  373. if (result2.distance < wallDistance && qSVG.btwn(result2.x, WALLS[e].coords[1].x, WALLS[e].coords[2].x) && qSVG.btwn(result2.y, WALLS[e].coords[1].y, WALLS[e].coords[2].y)) {
  374. wallDistance = result2.distance;
  375. wallSelected = { wall: WALLS[e], x: result2.x, y: result2.y, distance: result2.distance };
  376. }
  377. }
  378. var vv = editor.nearVertice(snap);
  379. if (vv.distance < wallDistance) {
  380. var eq1 = qSVG.createEquation(vv.number.coords[0].x, vv.number.coords[0].y, vv.number.coords[3].x, vv.number.coords[3].y);
  381. result1 = qSVG.nearPointOnEquation(eq1, vv);
  382. var eq2 = qSVG.createEquation(vv.number.coords[1].x, vv.number.coords[1].y, vv.number.coords[2].x, vv.number.coords[2].y);
  383. result2 = qSVG.nearPointOnEquation(eq2, vv);
  384. if (result1.distance < wallDistance && qSVG.btwn(result1.x, vv.number.coords[0].x, vv.number.coords[3].x) && qSVG.btwn(result1.y, vv.number.coords[0].y, vv.number.coords[3].y)) {
  385. wallDistance = result1.distance;
  386. wallSelected = { wall: vv.number, x: result1.x, y: result1.y, distance: result1.distance };
  387. }
  388. if (result2.distance < wallDistance && qSVG.btwn(result2.x, vv.number.coords[1].x, vv.number.coords[2].x) && qSVG.btwn(result2.y, vv.number.coords[1].y, vv.number.coords[2].y)) {
  389. wallDistance = result2.distance;
  390. wallSelected = { wall: vv.number, x: result2.x, y: result2.y, distance: result2.distance };
  391. }
  392. }
  393. return wallSelected;
  394. },
  395. // RETURN OBJDATA INDEX LIST FROM AN WALL
  396. objFromWall: function (wall, typeObj = false) {
  397. var objList = [];
  398. // Defensive: if wall is undefined or malformed, return empty list
  399. if (!wall || !wall.start || !wall.end) return objList;
  400. for (var scan = 0; scan < OBJDATA.length; scan++) {
  401. var search;
  402. if (OBJDATA[scan].family == 'inWall') {
  403. var eq = qSVG.createEquation(wall.start.x, wall.start.y, wall.end.x, wall.end.y);
  404. search = qSVG.nearPointOnEquation(eq, OBJDATA[scan]);
  405. if (search.distance < 0.01 && qSVG.btwn(OBJDATA[scan].x, wall.start.x, wall.end.x) && qSVG.btwn(OBJDATA[scan].y, wall.start.y, wall.end.y)) objList.push(OBJDATA[scan]);
  406. // WARNING 0.01 TO NO COUNT OBJECT ON LIMITS OF THE EDGE !!!!!!!!!!!! UGLY CODE( MOUSE PRECISION)
  407. // TRY WITH ANGLE MAYBE ???
  408. }
  409. }
  410. return objList;
  411. },
  412. createEquationFromWall: function (wall) {
  413. return qSVG.createEquation(wall.start.x, wall.start.y, wall.end.x, wall.end.y);
  414. },
  415. // WALLS SUPER ARRAY
  416. rayCastingWalls: function (snap) {
  417. var wallList = [];
  418. for (var i = 0; i < WALLS.length; i++) {
  419. // Defensive: skip walls without full coords
  420. if (!WALLS[i] || !WALLS[i].coords || WALLS[i].coords.length < 4) continue;
  421. var polygon = [];
  422. for (var pp = 0; pp < 4; pp++) {
  423. polygon.push({ x: WALLS[i].coords[pp].x, y: WALLS[i].coords[pp].y }); // FOR Z
  424. }
  425. if (qSVG.rayCasting(snap, polygon)) {
  426. wallList.push(WALLS[i]); // Return EDGES Index
  427. }
  428. }
  429. if (wallList.length == 0) return false;
  430. else {
  431. if (wallList.length == 1) return wallList[0];
  432. else return wallList;
  433. }
  434. },
  435. inWallRib2: function (wall, option = false) {
  436. if (!option) $('#boxRib').empty();
  437. ribMaster = [];
  438. var emptyArray = [];
  439. ribMaster.push(emptyArray);
  440. ribMaster.push(emptyArray);
  441. var inter;
  442. var distance;
  443. var cross;
  444. var angleTextValue = wall.angle * (180 / Math.PI);
  445. var objWall = editor.objFromWall(wall); // LIST OBJ ON EDGE
  446. ribMaster[0].push({ wall: wall, crossObj: false, side: 'up', coords: wall.coords[0], distance: 0 });
  447. ribMaster[1].push({ wall: wall, crossObj: false, side: 'down', coords: wall.coords[1], distance: 0 });
  448. for (var ob in objWall) {
  449. var objTarget = objWall[ob];
  450. objTarget.up = [
  451. qSVG.nearPointOnEquation(wall.equations.up, objTarget.limit[0]),
  452. qSVG.nearPointOnEquation(wall.equations.up, objTarget.limit[1])
  453. ];
  454. objTarget.down = [
  455. qSVG.nearPointOnEquation(wall.equations.down, objTarget.limit[0]),
  456. qSVG.nearPointOnEquation(wall.equations.down, objTarget.limit[1])
  457. ];
  458. distance = qSVG.measure(wall.coords[0], objTarget.up[0]) / meter;
  459. ribMaster[0].push({ wall: wall, crossObj: ob, side: 'up', coords: objTarget.up[0], distance: distance.toFixed(2) });
  460. distance = qSVG.measure(wall.coords[0], objTarget.up[1]) / meter;
  461. ribMaster[0].push({ wall: wall, crossObj: ob, side: 'up', coords: objTarget.up[1], distance: distance.toFixed(2) });
  462. distance = qSVG.measure(wall.coords[1], objTarget.down[0]) / meter;
  463. ribMaster[1].push({ wall: wall, crossObj: ob, side: 'down', coords: objTarget.down[0], distance: distance.toFixed(2) });
  464. distance = qSVG.measure(wall.coords[1], objTarget.down[1]) / meter;
  465. ribMaster[1].push({ wall: wall, crossObj: ob, side: 'down', coords: objTarget.down[1], distance: distance.toFixed(2) });
  466. }
  467. distance = qSVG.measure(wall.coords[0], wall.coords[3]) / meter;
  468. ribMaster[0].push({ wall: wall, crossObj: false, side: 'up', coords: wall.coords[3], distance: distance });
  469. distance = qSVG.measure(wall.coords[1], wall.coords[2]) / meter;
  470. ribMaster[1].push({ wall: wall, crossObj: false, side: 'down', coords: wall.coords[2], distance: distance });
  471. ribMaster[0].sort(function (a, b) {
  472. return (a.distance - b.distance).toFixed(2);
  473. });
  474. ribMaster[1].sort(function (a, b) {
  475. return (a.distance - b.distance).toFixed(2);
  476. });
  477. for (var t in ribMaster) {
  478. for (var n = 1; n < ribMaster[t].length; n++) {
  479. var found = true;
  480. var shift = -5;
  481. var valueText = Math.abs(ribMaster[t][n - 1].distance - ribMaster[t][n].distance);
  482. var angleText = angleTextValue;
  483. if (found) {
  484. if (ribMaster[t][n - 1].side == 'down') { shift = -shift + 10; }
  485. if (angleText > 89 || angleText < -89) {
  486. angleText -= 180;
  487. if (ribMaster[t][n - 1].side == 'down') { shift = -5; }
  488. else shift = -shift + 10;
  489. }
  490. sizeText[n] = document.createElementNS('http://www.w3.org/2000/svg', 'text');
  491. var startText = qSVG.middle(ribMaster[t][n - 1].coords.x, ribMaster[t][n - 1].coords.y, ribMaster[t][n].coords.x, ribMaster[t][n].coords.y);
  492. // Check for valid coordinates before setting attributes
  493. if (startText && !isNaN(startText.x) && !isNaN(startText.y)) {
  494. sizeText[n].setAttributeNS(null, 'x', startText.x);
  495. sizeText[n].setAttributeNS(null, 'y', (startText.y) + shift);
  496. sizeText[n].setAttributeNS(null, 'text-anchor', 'middle');
  497. sizeText[n].setAttributeNS(null, 'font-family', 'roboto');
  498. sizeText[n].setAttributeNS(null, 'stroke', '#ffffff');
  499. sizeText[n].textContent = valueText.toFixed(2);
  500. if (sizeText[n].textContent < 1) {
  501. sizeText[n].setAttributeNS(null, 'font-size', '0.8em');
  502. sizeText[n].textContent = sizeText[n].textContent.substring(1, sizeText[n].textContent.length);
  503. }
  504. else sizeText[n].setAttributeNS(null, 'font-size', '1em');
  505. sizeText[n].setAttributeNS(null, 'stroke-width', '0.4px');
  506. sizeText[n].setAttributeNS(null, 'fill', '#666666');
  507. sizeText[n].setAttribute("transform", "rotate(" + angleText + " " + startText.x + "," + (startText.y) + ")");
  508. } else {
  509. // Skip creating text element if coordinates are invalid
  510. console.warn('Invalid coordinates for size text element:', startText);
  511. }
  512. $('#boxRib').append(sizeText[n]);
  513. }
  514. }
  515. }
  516. },
  517. // value can be "text label", "step number in stair", etc...
  518. obj2D: function (family, classe, type, pos, angle, angleSign, size, hinge = 'normal', thick, value) {
  519. this.family = family // inWall, stick, collision, free
  520. this.class = classe; // door, window, energy, stair, measure, text ?
  521. this.type = type; // simple, double, simpleSlide, aperture, doubleSlide, fixed, switch, lamp....
  522. this.x = pos.x;
  523. this.y = pos.y;
  524. this.angle = angle;
  525. this.angleSign = angleSign;
  526. this.limit = [];
  527. this.hinge = hinge; // normal, reverse
  528. this.graph = qSVG.create('none', 'g');
  529. this.scale = { x: 1, y: 1 };
  530. this.value = value;
  531. this.size = size;
  532. this.thick = thick;
  533. this.width = (this.size / meter).toFixed(2);
  534. this.height = (this.thick / meter).toFixed(2);
  535. // Validate size and thick values before calling carpentryCalc
  536. var validSize = isNaN(size) ? 60 : size;
  537. var validThick = isNaN(thick) ? 20 : thick;
  538. var cc = carpentryCalc(classe, type, validSize, validThick, value);
  539. var blank;
  540. for (var tt = 0; tt < cc.length; tt++) {
  541. if (cc[tt].path) {
  542. // Validate path string before creating SVG element
  543. var pathString = cc[tt].path;
  544. if (pathString && !pathString.includes('NaN')) {
  545. blank = qSVG.create('none', 'path', {
  546. d: pathString,
  547. "stroke-width": 1,
  548. fill: cc[tt].fill,
  549. stroke: cc[tt].stroke,
  550. 'stroke-dasharray': cc[tt].strokeDashArray,
  551. opacity: cc[tt].opacity
  552. });
  553. } else {
  554. console.warn('Skipping path creation due to NaN values:', pathString);
  555. continue;
  556. }
  557. }
  558. if (cc[tt].text) {
  559. blank = qSVG.create("none", "text", {
  560. x: cc[tt].x,
  561. y: cc[tt].y,
  562. 'font-size': cc[tt].fontSize,
  563. stroke: cc[tt].stroke,
  564. "stroke-width": cc[tt].strokeWidth,
  565. 'font-family': 'roboto',
  566. 'text-anchor': 'middle',
  567. fill: cc[tt].fill
  568. });
  569. blank[0].textContent = cc[tt].text;
  570. }
  571. this.graph.append(blank);
  572. } // ENDFOR
  573. var bbox = this.graph.get(0).getBoundingClientRect();
  574. bbox.x = (bbox.x * factor) - (offset.left * factor) + originX_viewbox;
  575. bbox.y = (bbox.y * factor) - (offset.top * factor) + originY_viewbox;
  576. bbox.origin = { x: this.x, y: this.y };
  577. this.bbox = bbox;
  578. this.realBbox = [{ x: -this.size / 2, y: -this.thick / 2 }, { x: this.size / 2, y: -this.thick / 2 }, { x: this.size / 2, y: this.thick / 2 }, { x: -this.size / 2, y: this.thick / 2 }];
  579. if (family == "byObject") this.family = cc.family;
  580. this.params = cc.params; // (bindBox, move, resize, rotate)
  581. cc.params.width ? this.size = cc.params.width : this.size = size;
  582. cc.params.height ? this.thick = cc.params.height : this.thick = thick;
  583. this.update = function () {
  584. this.width = (this.size / meter).toFixed(2);
  585. this.height = (this.thick / meter).toFixed(2);
  586. // Validate size and thick values before calling carpentryCalc
  587. var validSize = isNaN(this.size) ? 60 : this.size;
  588. var validThick = isNaN(this.thick) ? 20 : this.thick;
  589. cc = carpentryCalc(this.class, this.type, validSize, validThick, this.value);
  590. for (var tt = 0; tt < cc.length; tt++) {
  591. if (cc[tt].path) {
  592. // Validate path string before setting attribute
  593. var pathString = cc[tt].path;
  594. if (pathString && !pathString.includes('NaN')) {
  595. this.graph.find('path')[tt].setAttribute("d", pathString);
  596. } else {
  597. console.warn('Invalid path string with NaN values:', pathString);
  598. }
  599. }
  600. else {
  601. // this.graph.find('text').context.textContent = cc[tt].text;
  602. }
  603. }
  604. var hingeStatus = this.hinge; // normal - reverse
  605. var hingeUpdate;
  606. if (hingeStatus == 'normal') hingeUpdate = 1;
  607. else hingeUpdate = -1;
  608. this.graph.attr({ "transform": "translate(" + (this.x) + "," + (this.y) + ") rotate(" + this.angle + ",0,0) scale(" + hingeUpdate + ", 1)" });
  609. var bbox = this.graph.get(0).getBoundingClientRect();
  610. bbox.x = (bbox.x * factor) - (offset.left * factor) + originX_viewbox;
  611. bbox.y = (bbox.y * factor) - (offset.top * factor) + originY_viewbox;
  612. bbox.origin = { x: this.x, y: this.y };
  613. this.bbox = bbox;
  614. if (this.class == "text" && this.angle == 0) {
  615. this.realBbox = [
  616. { x: this.bbox.x, y: this.bbox.y }, { x: this.bbox.x + this.bbox.width, y: this.bbox.y }, { x: this.bbox.x + this.bbox.width, y: this.bbox.y + this.bbox.height }, { x: this.bbox.x, y: this.bbox.y + this.bbox.height }];
  617. this.size = this.bbox.width;
  618. this.thick = this.bbox.height;
  619. }
  620. var angleRadian = -(this.angle) * (Math.PI / 180);
  621. this.realBbox = [{ x: -this.size / 2, y: -this.thick / 2 }, { x: this.size / 2, y: -this.thick / 2 }, { x: this.size / 2, y: this.thick / 2 }, { x: -this.size / 2, y: this.thick / 2 }];
  622. var newRealBbox = [{ x: 0, y: 0 }, { x: 0, y: 0 }, { x: 0, y: 0 }, { x: 0, y: 0 }];
  623. newRealBbox[0].x = (this.realBbox[0].y * Math.sin(angleRadian) + this.realBbox[0].x * Math.cos(angleRadian)) + this.x;
  624. newRealBbox[1].x = (this.realBbox[1].y * Math.sin(angleRadian) + this.realBbox[1].x * Math.cos(angleRadian)) + this.x;
  625. newRealBbox[2].x = (this.realBbox[2].y * Math.sin(angleRadian) + this.realBbox[2].x * Math.cos(angleRadian)) + this.x;
  626. newRealBbox[3].x = (this.realBbox[3].y * Math.sin(angleRadian) + this.realBbox[3].x * Math.cos(angleRadian)) + this.x;
  627. newRealBbox[0].y = (this.realBbox[0].y * Math.cos(angleRadian) - this.realBbox[0].x * Math.sin(angleRadian)) + this.y;
  628. newRealBbox[1].y = (this.realBbox[1].y * Math.cos(angleRadian) - this.realBbox[1].x * Math.sin(angleRadian)) + this.y;
  629. newRealBbox[2].y = (this.realBbox[2].y * Math.cos(angleRadian) - this.realBbox[2].x * Math.sin(angleRadian)) + this.y;
  630. newRealBbox[3].y = (this.realBbox[3].y * Math.cos(angleRadian) - this.realBbox[3].x * Math.sin(angleRadian)) + this.y;
  631. this.realBbox = newRealBbox;
  632. return true;
  633. }
  634. },
  635. roomMaker: function (Rooms) {
  636. globalArea = 0;
  637. var oldVertexNumber = [];
  638. if (Rooms.polygons.length == 0) ROOM = [];
  639. for (var pp = 0; pp < Rooms.polygons.length; pp++) {
  640. var foundRoom = false;
  641. var roomId;
  642. for (var rr = 0; rr < ROOM.length; rr++) {
  643. roomId = rr;
  644. var countCoords = Rooms.polygons[pp].coords.length;
  645. var diffCoords = qSVG.diffObjIntoArray(Rooms.polygons[pp].coords, ROOM[rr].coords);
  646. if (Rooms.polygons[pp].way.length == ROOM[rr].way.length) {
  647. if (qSVG.diffArray(Rooms.polygons[pp].way, ROOM[rr].way).length == 0 || diffCoords == 0) {
  648. countCoords = 0;
  649. }
  650. }
  651. if (Rooms.polygons[pp].way.length == ROOM[rr].way.length + 1) {
  652. if (qSVG.diffArray(Rooms.polygons[pp].way, ROOM[rr].way).length == 1 || diffCoords == 2) {
  653. countCoords = 0;
  654. }
  655. }
  656. if (Rooms.polygons[pp].way.length == ROOM[rr].way.length - 1) {
  657. if (qSVG.diffArray(Rooms.polygons[pp].way, ROOM[rr].way).length == 1) {
  658. countCoords = 0;
  659. }
  660. }
  661. if (countCoords == 0) {
  662. foundRoom = true;
  663. ROOM[rr].area = Rooms.polygons[pp].area;
  664. ROOM[rr].inside = Rooms.polygons[pp].inside;
  665. ROOM[rr].coords = Rooms.polygons[pp].coords;
  666. ROOM[rr].coordsOutside = Rooms.polygons[pp].coordsOutside;
  667. ROOM[rr].way = Rooms.polygons[pp].way;
  668. ROOM[rr].coordsInside = Rooms.polygons[pp].coordsInside;
  669. break;
  670. }
  671. }
  672. if (!foundRoom) {
  673. ROOM.push({ coords: Rooms.polygons[pp].coords, coordsOutside: Rooms.polygons[pp].coordsOutside, coordsInside: Rooms.polygons[pp].coordsInside, inside: Rooms.polygons[pp].inside, way: Rooms.polygons[pp].way, area: Rooms.polygons[pp].area, surface: '', name: '', color: 'gradientWhite', showSurface: true, action: 'add' });
  674. }
  675. }
  676. var toSplice = [];
  677. for (var rr = 0; rr < ROOM.length; rr++) {
  678. var found = true;
  679. for (var pp = 0; pp < Rooms.polygons.length; pp++) {
  680. var countRoom = ROOM[rr].coords.length;
  681. var diffCoords = qSVG.diffObjIntoArray(Rooms.polygons[pp].coords, ROOM[rr].coords);
  682. if (Rooms.polygons[pp].way.length == ROOM[rr].way.length) {
  683. if (qSVG.diffArray(Rooms.polygons[pp].way, ROOM[rr].way).length == 0 || diffCoords == 0) {
  684. countRoom = 0;
  685. }
  686. }
  687. if (Rooms.polygons[pp].way.length == ROOM[rr].way.length + 1) {
  688. if (qSVG.diffArray(Rooms.polygons[pp].way, ROOM[rr].way).length == 1 || diffCoords == 2) {
  689. countRoom = 0;
  690. }
  691. }
  692. if (Rooms.polygons[pp].way.length == ROOM[rr].way.length - 1) {
  693. if (qSVG.diffArray(Rooms.polygons[pp].way, ROOM[rr].way).length == 1) {
  694. countRoom = 0;
  695. }
  696. }
  697. if (countRoom == 0) { found = true; break; }
  698. else found = false;
  699. }
  700. if (!found) toSplice.push(rr);
  701. }
  702. toSplice.sort(function (a, b) {
  703. return b - a;
  704. });
  705. for (var ss = 0; ss < toSplice.length; ss++) {
  706. ROOM.splice(toSplice[ss], 1);
  707. }
  708. $('#boxRoom').empty();
  709. $('#boxSurface').empty();
  710. $('#boxArea').empty();
  711. for (var rr = 0; rr < ROOM.length; rr++) {
  712. if (ROOM[rr].action == 'add') globalArea = globalArea + ROOM[rr].area;
  713. var pathSurface = ROOM[rr].coords;
  714. var pathCreate = "M" + pathSurface[0].x + "," + pathSurface[0].y;
  715. for (var p = 1; p < pathSurface.length; p++) {
  716. pathCreate = pathCreate + " " + "L" + pathSurface[p].x + "," + pathSurface[p].y;
  717. }
  718. if (ROOM[rr].inside.length > 0) {
  719. for (var ins = 0; ins < ROOM[rr].inside.length; ins++) {
  720. pathCreate = pathCreate + " M" + Rooms.polygons[ROOM[rr].inside[ins]].coords[Rooms.polygons[ROOM[rr].inside[ins]].coords.length - 1].x + "," + Rooms.polygons[ROOM[rr].inside[ins]].coords[Rooms.polygons[ROOM[rr].inside[ins]].coords.length - 1].y;
  721. for (var free = Rooms.polygons[ROOM[rr].inside[ins]].coords.length - 2; free > -1; free--) {
  722. pathCreate = pathCreate + " L" + Rooms.polygons[ROOM[rr].inside[ins]].coords[free].x + "," + Rooms.polygons[ROOM[rr].inside[ins]].coords[free].y;
  723. }
  724. }
  725. }
  726. qSVG.create('boxRoom', 'path', {
  727. d: pathCreate,
  728. fill: 'url(#' + ROOM[rr].color + ')',
  729. 'fill-opacity': 1, stroke: 'none', 'fill-rule': 'evenodd', class: 'room'
  730. });
  731. qSVG.create('boxSurface', 'path', {
  732. d: pathCreate,
  733. fill: '#fff', 'fill-opacity': 1, stroke: 'none', 'fill-rule': 'evenodd', class: 'room'
  734. });
  735. var centroid = qSVG.polygonVisualCenter(ROOM[rr]);
  736. if (ROOM[rr].name != '') {
  737. var styled = { color: '#343938' };
  738. if (ROOM[rr].color == 'gradientBlack' || ROOM[rr].color == 'gradientBlue') styled.color = 'white';
  739. qSVG.textOnDiv(ROOM[rr].name, centroid, styled, 'boxArea');
  740. }
  741. if (ROOM[rr].name != '') centroid.y = centroid.y + 20;
  742. var area = ((ROOM[rr].area) / (meter * meter)).toFixed(2) + ' m²';
  743. var styled = { color: '#343938', fontSize: '18px', fontWeight: 'normal' };
  744. if (ROOM[rr].surface != '') {
  745. styled.fontWeight = 'bold';
  746. area = ROOM[rr].surface + ' m²';
  747. }
  748. if (ROOM[rr].color == 'gradientBlack' || ROOM[rr].color == 'gradientBlue') styled.color = 'white';
  749. if (ROOM[rr].showSurface) qSVG.textOnDiv(area, centroid, styled, 'boxArea');
  750. }
  751. if (globalArea <= 0) {
  752. globalArea = 0;
  753. $('#areaValue').html('');
  754. }
  755. else {
  756. $('#areaValue').html('<i class="fa fa-map-o" aria-hidden="true"></i> ' + (globalArea / 3600).toFixed(1) + ' m²');
  757. }
  758. },
  759. rayCastingRoom: function (point) {
  760. var x = point.x, y = point.y;
  761. var roomGroup = [];
  762. for (var polygon = 0; polygon < ROOM.length; polygon++) {
  763. var inside = qSVG.rayCasting(point, ROOM[polygon].coords);
  764. if (inside) {
  765. roomGroup.push(polygon);
  766. }
  767. }
  768. if (roomGroup.length > 0) {
  769. var bestArea = ROOM[roomGroup[0]].area;
  770. var roomTarget;
  771. for (var siz = 0; siz < roomGroup.length; siz++) {
  772. if (ROOM[roomGroup[siz]].area <= bestArea) {
  773. bestArea = ROOM[roomGroup[siz]].area;
  774. roomTarget = ROOM[roomGroup[siz]];
  775. }
  776. }
  777. return roomTarget;
  778. }
  779. else {
  780. return false;
  781. }
  782. },
  783. nearVertice: function (snap, range = 10000) {
  784. var bestDistance = Infinity;
  785. var bestVertice;
  786. for (var i = 0; i < WALLS.length; i++) {
  787. var distance1 = qSVG.gap(snap, { x: WALLS[i].start.x, y: WALLS[i].start.y });
  788. var distance2 = qSVG.gap(snap, { x: WALLS[i].end.x, y: WALLS[i].end.y });
  789. if (distance1 < distance2 && distance1 < bestDistance) {
  790. bestDistance = distance1;
  791. bestVertice = { number: WALLS[i], x: WALLS[i].start.x, y: WALLS[i].start.y, distance: Math.sqrt(bestDistance) };
  792. }
  793. if (distance2 < distance1 && distance2 < bestDistance) {
  794. bestDistance = distance2;
  795. bestVertice = { number: WALLS[i], x: WALLS[i].end.x, y: WALLS[i].end.y, distance: Math.sqrt(bestDistance) };
  796. }
  797. }
  798. if (bestDistance < range * range) return bestVertice;
  799. else return false;
  800. },
  801. nearWall: function (snap, range = Infinity) {
  802. var wallDistance = Infinity;
  803. var wallSelected = {};
  804. var result;
  805. if (WALLS.length == 0) return false;
  806. for (var e = 0; e < WALLS.length; e++) {
  807. var eq = qSVG.createEquation(WALLS[e].start.x, WALLS[e].start.y, WALLS[e].end.x, WALLS[e].end.y);
  808. result = qSVG.nearPointOnEquation(eq, snap);
  809. if (result.distance < wallDistance && qSVG.btwn(result.x, WALLS[e].start.x, WALLS[e].end.x) && qSVG.btwn(result.y, WALLS[e].start.y, WALLS[e].end.y)) {
  810. wallDistance = result.distance;
  811. wallSelected = { wall: WALLS[e], x: result.x, y: result.y, distance: result.distance };
  812. }
  813. }
  814. var vv = editor.nearVertice(snap);
  815. if (vv.distance < wallDistance) {
  816. wallDistance = vv.distance;
  817. wallSelected = { wall: vv.number, x: vv.x, y: vv.y, distance: vv.distance };
  818. }
  819. if (wallDistance <= range) return wallSelected;
  820. else return false;
  821. },
  822. showScaleBox: function () {
  823. if (ROOM.length > 0) {
  824. var minX, minY, maxX, maxY;
  825. for (var i = 0; i < WALLS.length; i++) {
  826. var px = WALLS[i].start.x;
  827. var py = WALLS[i].start.y;
  828. if (!i || px < minX) minX = px;
  829. if (!i || py < minY) minY = py;
  830. if (!i || px > maxX) maxX = px;
  831. if (!i || py > maxY) maxY = py;
  832. var px = WALLS[i].end.x;
  833. var py = WALLS[i].end.y;
  834. if (!i || px < minX) minX = px;
  835. if (!i || py < minY) minY = py;
  836. if (!i || px > maxX) maxX = px;
  837. if (!i || py > maxY) maxY = py;
  838. }
  839. var width = maxX - minX;
  840. var height = maxY - minY;
  841. var labelWidth = ((maxX - minX) / meter).toFixed(2);
  842. var labelHeight = ((maxY - minY) / meter).toFixed(2);
  843. var sideRight = 'm' + (maxX + 40) + ',' + minY;
  844. sideRight = sideRight + ' l60,0 m-40,10 l10,-10 l10,10 m-10,-10';
  845. sideRight = sideRight + ' l0,' + height;
  846. sideRight = sideRight + ' m-30,0 l60,0 m-40,-10 l10,10 l10,-10';
  847. sideRight = sideRight + 'M' + (minX) + ',' + (minY - 40);
  848. sideRight = sideRight + ' l0,-60 m10,40 l-10,-10 l10,-10 m-10,10';
  849. sideRight = sideRight + ' l' + width + ',0';
  850. sideRight = sideRight + ' m0,30 l0,-60 m-10,40 l10,-10 l-10,-10';
  851. $('#boxScale').empty();
  852. qSVG.create('boxScale', 'path', {
  853. d: sideRight,
  854. stroke: "#555",
  855. fill: "none",
  856. "stroke-width": 0.3,
  857. "stroke-linecap": "butt",
  858. "stroke-linejoin": "miter",
  859. "stroke-miterlimit": 4,
  860. "fill-rule": "nonzero"
  861. });
  862. var text = document.createElementNS('http://www.w3.org/2000/svg', 'text');
  863. text.setAttributeNS(null, 'x', (maxX + 70));
  864. text.setAttributeNS(null, 'y', ((maxY + minY) / 2) + 35);
  865. text.setAttributeNS(null, 'fill', '#555');
  866. text.setAttributeNS(null, 'text-anchor', 'middle');
  867. text.textContent = labelHeight + ' m';
  868. text.setAttribute("transform", "rotate(270 " + (maxX + 70) + "," + (maxY + minY) / 2 + ")");
  869. $('#boxScale').append(text);
  870. var text = document.createElementNS('http://www.w3.org/2000/svg', 'text');
  871. text.setAttributeNS(null, 'x', (maxX + minX) / 2);
  872. text.setAttributeNS(null, 'y', (minY - 95));
  873. text.setAttributeNS(null, 'fill', '#555');
  874. text.setAttributeNS(null, 'text-anchor', 'middle');
  875. text.textContent = labelWidth + ' m';
  876. $('#boxScale').append(text);
  877. }
  878. }
  879. // END EDITOR
  880. }