Advertisement
giovani-rubim

backup

Nov 28th, 2019
218
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 16.76 KB | None | 0 0
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <title></title>
  5. <meta charset="utf-8">
  6. <style type="text/css">
  7. body {
  8. margin: 0px;
  9. font-size: 0px;
  10. overflow: hidden;
  11. }
  12. </style>
  13. </head>
  14. <body>
  15. <canvas></canvas>
  16. </body>
  17. </html>
  18. <script type="text/javascript">
  19.  
  20. const PI = Math.PI;
  21. const TAU = Math.PI*2;
  22.  
  23. let canvas;
  24. let ctx;
  25.  
  26. let screen_sx;
  27. let screen_sy;
  28. let editor_sx;
  29. let editor_cx;
  30. let center_y;
  31. let inner_sx;
  32. let inner_sy;
  33. let start_x;
  34. let start_y;
  35. let end_x;
  36. let end_y;
  37.  
  38. let leftbar_sx = 200;
  39. let item_spacing = 4;
  40. let item_sy = 22;
  41. let item_padding = 5;
  42. let item_font = 14;
  43. let item_tab_sx = 15;
  44. let button_spacing = 5;
  45. let button_radius = 7;
  46. let plus_linewidth = 2;
  47. let plus_radius = button_radius*0.7;
  48. let ex_radius = plus_radius/Math.SQRT2;
  49. let min_dist = 3;
  50. let margin = 0.1;
  51. let node_radius = 5;
  52. let node_line_cut = 10;
  53.  
  54. let nodes_x;
  55. let space_sx;
  56. let space_sy;
  57. let space_x;
  58. let space_y;
  59.  
  60. const cylinders = [
  61. {w: 5, h: 10, x: null, y: null, sx: null, sy: null},
  62. {w: 20, h: 10, x: null, y: null, sx: null, sy: null},
  63. {w: 60, h: 10, x: null, y: null, sx: null, sy: null},
  64. {w: 20, h: 10, x: null, y: null, sx: null, sy: null},
  65. {w: 5, h: 50, x: null, y: null, sx: null, sy: null},
  66. {w: 20, h: 20, x: null, y: null, sx: null, sy: null},
  67. {w: 5, h: 30, x: null, y: null, sx: null, sy: null},
  68. {w: 10, h: 5, x: null, y: null, sx: null, sy: null},
  69. ];
  70. let cylinder_scale_x = 1;
  71. let cylinder_scale_y = 1;
  72.  
  73. const fixedNodes = [];
  74. const freeNodes = [];
  75.  
  76. cylinders.forEach((cylinder, index) => {
  77. fixedNodes.push({index, x: null, y: null, ex: null});
  78. if (index === cylinders.length - 1) {
  79. fixedNodes.push({index: index + 1, x: null, y: null, ex: null});
  80. }
  81. });
  82.  
  83. const udpateNodeCoords = node => {
  84. const nodes_x = (space_x + leftbar_sx)/2;
  85. const {index} = node;
  86. if (index === 0) {
  87. const cylinder = cylinders[0];
  88. node.x = nodes_x;
  89. node.y = cylinder.y;
  90. node.ex = cylinder.x;
  91. return;
  92. }
  93. if (index === cylinders.length) {
  94. const cylinder = cylinders[cylinders.length - 1];
  95. node.x = nodes_x;
  96. node.y = cylinder.y + cylinder.sy;
  97. node.ex = cylinder.x;
  98. return;
  99. }
  100. let a = cylinders[index];
  101. let b = cylinders[index - 1];
  102. node.x = nodes_x;
  103. node.y = a.y;
  104. node.ex = Math.min(a.x, b.x);
  105. };
  106.  
  107. const renderNodes = () => {
  108. ctx.fillStyle = '#444';
  109. fixedNodes.forEach(node => {
  110. udpateNodeCoords(node);
  111. const {x, y, ex} = node;
  112.  
  113. ctx.strokeStyle = '#f70';
  114. ctx.beginPath();
  115. ctx.arc(x, y, node_radius, 0, TAU);
  116. ctx.fill();
  117. ctx.stroke();
  118.  
  119. ctx.strokeStyle = '#333';
  120. ctx.beginPath();
  121. ctx.moveTo(x + node_line_cut, y);
  122. ctx.lineTo(ex - node_line_cut, y);
  123. ctx.stroke();
  124. });
  125. };
  126.  
  127. const renderCylinders = () => {
  128.  
  129. let total_w = 0;
  130. let total_h = 0;
  131. cylinders.forEach(cylinder => {
  132. const {w, h} = cylinder;
  133. total_w = Math.max(total_w, w);
  134. total_h += h;
  135. });
  136. let ratio = total_w/total_h;
  137. space_sx = Math.min(inner_sx, inner_sy*ratio);
  138. space_sy = space_sx/ratio;
  139. space_x = start_x + (inner_sx - space_sx)/2;
  140. space_y = start_y + (inner_sy - space_sy)/2;
  141. cylinder_scale_x = space_sx/total_w;
  142. cylinder_scale_y = space_sy/total_h;
  143.  
  144. let y = space_y;
  145. ctx.lineWidth = 1;
  146. ctx.strokeStyle = '#f70';
  147. ctx.fillStyle = 'rgba(255, 255, 255, 0.05)';
  148. cylinders.forEach(cylinder => {
  149. const sx = cylinder.w*cylinder_scale_x;
  150. const sy = cylinder.h*cylinder_scale_y;
  151. const x = editor_cx - sx/2;
  152. ctx.beginPath();
  153. ctx.rect(x, y, sx, sy);
  154. ctx.fill();
  155. ctx.stroke();
  156. cylinder.x = x;
  157. cylinder.y = y;
  158. cylinder.sx = sx;
  159. cylinder.sy = sy;
  160. y += sy;
  161. });
  162.  
  163. };
  164.  
  165. const toLabel = {
  166. 'axis': ['Eixo', 'Eixos'],
  167. 'disk': ['Disco', 'Discos'],
  168. };
  169.  
  170. let lastId = 0;
  171. const newId = () => ++ lastId;
  172.  
  173. const project = {
  174. database: {
  175. axis: [],
  176. disk: [],
  177. mga: [],
  178. mgb: [],
  179. mec: [],
  180. axis_instance: [],
  181. disk_instance: [],
  182. mga_instance: [],
  183. mgb_instance: [],
  184. mec_instance: [],
  185. node: []
  186. },
  187. idTypeMap: {},
  188. add: (type, object) => {
  189. const array = project.database[type];
  190. array.push(object);
  191. project.idTypeMap[object.id] = type;
  192. return object;
  193. },
  194. remove: id => {
  195. const type = project.idTypeMap[id];
  196. if (!type) return false;
  197. const array = project.database[type];
  198. let index = -1;
  199. for (let i=0; i<array.length; ++i) {
  200. if (array[i].id == id) {
  201. index = i;
  202. break;
  203. }
  204. }
  205. if (index === -1) return false;
  206. const obj = array[index];
  207. array.splice(index, 1);
  208. delete project.idTypeMap[id];
  209. return [obj];
  210. },
  211. find: id => {
  212. const type = project.idTypeMap[id];
  213. if (!type) return false;
  214. const array = project.database[type];
  215. let index = -1;
  216. for (let i=0; i<array.length; ++i) {
  217. if (array[i].id == id) {
  218. index = i;
  219. break;
  220. }
  221. }
  222. if (index === -1) return false;
  223. return { type, object: array[index] };
  224. }
  225. };
  226.  
  227. const leftbar = {
  228. items: [],
  229. rendered_buttons: [],
  230. rendered_items: [],
  231. getButtonAt: (x, y) => {
  232. const array = leftbar.rendered_buttons;
  233. for (let i=0; i<array.length; ++i) {
  234. if (array[i].wraps(x, y)) {
  235. return array[i];
  236. }
  237. }
  238. return null;
  239. },
  240. groupMap: {},
  241. findItem: id => {
  242. let compare = '#' + id;
  243. const search = item => {
  244. if (item.name === compare) {
  245. return item;
  246. }
  247. const {children} = item;
  248. for (let i=children.length; i--;) {
  249. const child = children[i];
  250. if (child.name === compare) {
  251. return child;
  252. }
  253. }
  254. return null;
  255. };
  256. const {items} = leftbar;
  257. for (let i=items.length; i--;) {
  258. const res = search(items[i]);
  259. if (res) return res;
  260. }
  261. return null;
  262. },
  263. getItemAt: (x, y) => {
  264. const array = leftbar.rendered_items;
  265. for (let i=array.length; i--;) {
  266. const item = array[i];
  267. if (item.wraps(x, y)) return item;
  268. }
  269. return null;
  270. }
  271. };
  272.  
  273. const drawPlus = (x, y, button) => {
  274. ctx.lineWidth = plus_linewidth;
  275. ctx.strokeStyle = '#ccc';
  276. ctx.beginPath();
  277. ctx.moveTo(x + plus_radius, y);
  278. ctx.lineTo(x - plus_radius, y);
  279. ctx.moveTo(x, y + plus_radius);
  280. ctx.lineTo(x, y - plus_radius);
  281. ctx.stroke();
  282. };
  283.  
  284. const drawDelete = (x, y, button) => {
  285. ctx.lineWidth = plus_linewidth;
  286. ctx.strokeStyle = '#ccc';
  287. ctx.beginPath();
  288. ctx.moveTo(x + ex_radius, y + ex_radius);
  289. ctx.lineTo(x - ex_radius, y - ex_radius);
  290. ctx.moveTo(x + ex_radius, y - ex_radius);
  291. ctx.lineTo(x - ex_radius, y + ex_radius);
  292. ctx.stroke();
  293. };
  294.  
  295. const drawToggle = (x, y, button) => {
  296. const item = button.parent;
  297. ctx.fillStyle = '#ccc';
  298. ctx.beginPath();
  299. if (item.open) {
  300. ctx.moveTo(x, y + 5);
  301. ctx.lineTo(x - 5, y - 5);
  302. ctx.lineTo(x + 5, y - 5);
  303. } else {
  304. ctx.moveTo(x - 5, y);
  305. ctx.lineTo(x + 5, y - 5);
  306. ctx.lineTo(x + 5, y + 5);
  307. }
  308. ctx.closePath();
  309. ctx.fill();
  310. };
  311.  
  312. class Button {
  313. constructor(name, draw, pull_right) {
  314. this.draw = draw;
  315. this.name = name;
  316. this.visible = true;
  317. this.x = null;
  318. this.y = null;
  319. this.pull_right = pull_right || false;
  320. this.parent = null;
  321. }
  322. render(x, y) {
  323. if (!this.visible) return this;
  324. const {draw} = this;
  325. if (draw) {
  326. draw(x, y, this);
  327. } else {
  328. ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
  329. ctx.beginPath();
  330. ctx.arc(x, y, button_radius, 0, TAU);
  331. ctx.fill();
  332. }
  333. this.x = x;
  334. this.y = y;
  335. return this;
  336. }
  337. wraps(tx, ty) {
  338. const {x, y} = this;
  339. const dx = x - tx;
  340. const dy = y - ty;
  341. return Math.sqrt(dx*dx + dy*dy) <= button_radius;
  342. }
  343. }
  344.  
  345. class LBItem {
  346. constructor(title, name) {
  347. this.parent = null;
  348. this.x = null;
  349. this.y = null;
  350. this.sx = null;
  351. this.sy = null;
  352. this.visible = true;
  353. this.title = title;
  354. this.name = name;
  355. this.children = [];
  356. this.buttons = [];
  357. this.open = true;
  358. this.buttonMap = {};
  359. }
  360. addButton(button) {
  361. button.parent = this;
  362. this.buttons.push(button);
  363. this.buttonMap[button.name] = button;
  364. return this;
  365. }
  366. wraps(tx, ty) {
  367. const {x, y, sx, sy} = this;
  368. return (tx >= x && ty >= y && tx < x + sx && ty < y + sy);
  369. }
  370. render(x, y) {
  371. if (!this.visible) return 0;
  372. leftbar.rendered_items.push(this);
  373.  
  374. let sx = leftbar_sx - item_spacing - x;
  375. let sy = item_sy;
  376.  
  377. this.x = x;
  378. this.y = y;
  379. this.sx = sx;
  380. this.sy = sy;
  381.  
  382. let ax = x + item_padding;
  383. let bx = x + sx - item_padding;
  384. let cy = y + sy*0.5;
  385.  
  386. if (this.parent === null) {
  387. ctx.fillStyle = '#333';
  388. ctx.fillRect(x, y, sx, sy);
  389. }
  390.  
  391. ctx.font = item_font + 'px monospace';
  392. ctx.fillStyle = '#ccc';
  393. ctx.textAlign = 'left';
  394. ctx.textBaseline = 'middle';
  395. ctx.fillText(this.title, ax, y + sy*0.55);
  396. ax += ctx.measureText(this.title).width + button_spacing;
  397.  
  398. const {buttons} = this;
  399. buttons.forEach(button => {
  400. if (button.visible) {
  401. leftbar.rendered_buttons.push(button);
  402. if (button.pull_right) {
  403. button.render(bx - button_radius, cy);
  404. bx -= button_radius*2 + button_spacing;
  405. } else {
  406. button.render(ax + button_radius, cy);
  407. ax += button_radius*2 + button_spacing;
  408. }
  409. }
  410. });
  411.  
  412. y += sy;
  413.  
  414. const {children} = this;
  415. if (this.open && children.length) {
  416. children.forEach(child => {
  417. y += item_spacing;
  418. sy += item_spacing;
  419. const height = child.render(x + item_tab_sx, y);
  420. y += height;
  421. sy += height;
  422. });
  423. }
  424.  
  425. return sy;
  426. }
  427. append(child) {
  428. if (this.buttonMap.toggle) {
  429. this.buttonMap.toggle.visible = true;
  430. }
  431. child.parent = this;
  432. this.children.push(child);
  433. return this;
  434. }
  435. removeChild(child) {
  436. const {children} = this;
  437. const index = children.indexOf(child);
  438. if (index === -1) return this;
  439. children.splice(index, 1);
  440. if (children.length === 0 && this.buttonMap.toggle) {
  441. this.buttonMap.toggle.visible = false;
  442. }
  443. return this;
  444. }
  445. remove() {
  446. if (!this.parent) return this;
  447. this.parent.removeChild(this);
  448. this.parent = null;
  449. return this;
  450. }
  451. };
  452.  
  453. const readUserData = (formTitle, fields) => new Promise((done) => {
  454. const data = {};
  455. for (let i=0; i<fields.length; ++i) {
  456. const field = fields[i];
  457. const {name, title, type} = field;
  458. const answ = prompt(`[${formTitle}]\n${title} (${type})`);
  459. if (answ === null) {
  460. done(null);
  461. return;
  462. }
  463. data[name] = answ;
  464. }
  465. done(data);
  466. });
  467.  
  468. const requiredFields = {
  469. axis: [
  470. {name: 'name', title: 'Nome', type: 'string'},
  471. {name: 'inner_diameter', title: 'Diâmetro interno', type: 'number'},
  472. {name: 'outer_diameter', title: 'Diâmetro externo', type: 'number'}
  473. ],
  474. disk: [
  475. {name: 'name', title: 'Nome', type: 'string'},
  476. {name: 'diameter', title: 'Diâmetro', type: 'number'},
  477. {name: 'density', title: 'Densidade', type: 'number'}
  478. ]
  479. };
  480.  
  481. const addPropGroup = (label, name) => {
  482. const group = new LBItem(label, name);
  483. group.addButton(new Button('add', drawPlus));
  484. group.addButton(new Button('toggle', drawToggle, true));
  485. group.buttonMap.toggle.visible = false;
  486. leftbar.items.push(group);
  487. leftbar.groupMap[name] = group;
  488. };
  489.  
  490. const fillLeftbar = () => {
  491. addPropGroup(toLabel.axis[1], 'axis');
  492. addPropGroup(toLabel.disk[1], 'disk');
  493. };
  494.  
  495. const updateMeasures = () => {
  496. const {innerWidth, innerHeight} = window;
  497. if (screen_sx === innerWidth && screen_sy === innerHeight) {
  498. return false;
  499. }
  500. screen_sx = innerWidth;
  501. screen_sy = innerHeight;
  502. editor_sx = screen_sx - leftbar_sx;
  503. editor_cx = leftbar_sx + editor_sx/2;
  504. center_y = screen_sy/2;
  505. // const m = Math.min(margin*editor_sx, margin*screen_sy);
  506. const m = 90;
  507. inner_sx = editor_sx - m*2;
  508. inner_sy = screen_sy - m*2;
  509. start_x = leftbar_sx + (editor_sx - inner_sx)/2;
  510. start_y = (screen_sy - inner_sy)/2;
  511. end_x = start_x + inner_sx;
  512. end_y = start_y + inner_sy;
  513. return true;
  514. };
  515.  
  516. const renderLeftbarItems = () => {
  517. const array = leftbar.items;
  518. let y = item_spacing;
  519. array.forEach(item => {
  520. y += item.render(item_spacing, y) + item_spacing;
  521. });
  522. };
  523.  
  524. const renderLeftbar = () => {
  525. ctx.fillStyle = '#262626';
  526. ctx.fillRect(0, 0, leftbar_sx, screen_sy);
  527. leftbar.rendered_buttons.length = 0;
  528. leftbar.rendered_items.length = 0;
  529. renderLeftbarItems();
  530. };
  531.  
  532. const clearCanvas = () => {
  533. ctx.fillStyle = '#171717';
  534. ctx.fillRect(0, 0, screen_sx, screen_sy);
  535. };
  536.  
  537. const render = () => {
  538. clearCanvas();
  539. renderLeftbar();
  540. renderCylinders();
  541. renderNodes();
  542. };
  543.  
  544. const handleResize = () => {
  545. if (updateMeasures()) {
  546. canvas.width = screen_sx;
  547. canvas.height = screen_sy;
  548. render();
  549. }
  550. };
  551.  
  552. const create = {
  553. axis: data => {
  554. const id = newId();
  555. const prop = {
  556. inner_diameter: data.inner_diameter,
  557. outer_diameter: data.outer_diameter,
  558. density: data.density,
  559. mod_e: null,
  560. mod_g: null
  561. };
  562. const object = {
  563. id,
  564. name: data.name || 'Unnamed',
  565. description: '',
  566. prop
  567. };
  568. project.add('axis', object);
  569. const item = new LBItem(data.name, '#' + id);
  570. object.item = item;
  571. item.addButton(new Button('remove', drawDelete));
  572. leftbar.groupMap['axis'].append(item);
  573. return object;
  574. },
  575. disk: data => {
  576. const id = newId();
  577. const prop = {
  578. diameter: data.diameter,
  579. density: data.density,
  580. };
  581. const object = {
  582. id,
  583. name: data.name || 'Unnamed',
  584. description: '',
  585. prop
  586. };
  587. project.add('disk', object);
  588. const item = new LBItem(data.name, '#' + id);
  589. object.item = item;
  590. item.addButton(new Button('remove', drawDelete));
  591. leftbar.groupMap['disk'].append(item);
  592. return object;
  593. }
  594. };
  595.  
  596. const handleLeftbarButtonClick = (button) => {
  597. const {name} = button;
  598. if (name === 'add') {
  599. const {parent} = button;
  600. const {name} = parent;
  601. readUserData('Novo ' + toLabel[name][0], requiredFields[name])
  602. .then(data => {
  603. if (!data) return;
  604. create[name](data);
  605. render();
  606. });
  607. return;
  608. }
  609. if (name === 'remove') {
  610. const {parent} = button;
  611. const id = parent.name.substr(1);
  612. const res = project.find(id);
  613. if (!res) return;
  614. const {object, type} = res;
  615. const {name} = object;
  616. if (!confirm(`Deseja mesmo excluir ${toLabel[type][0].toLowerCase()} "${name}"?`)) return;
  617. const array = project.remove(id);
  618. if (array) {
  619. array.forEach(object => {
  620. const item = leftbar.findItem(object.id);
  621. if (item) item.remove();
  622. });
  623. render();
  624. }
  625. }
  626. if (name === 'toggle') {
  627. const item = button.parent;
  628. item.open = !item.open;
  629. render();
  630. }
  631. };
  632.  
  633. const handleLeftbarClick = (x, y, buttonCode) => {
  634. if (buttonCode !== 0) return;
  635. const button = leftbar.getButtonAt(x, y);
  636. if (button) {
  637. handleLeftbarButtonClick(button);
  638. return;
  639. }
  640. const item = leftbar.getItemAt(x, y);
  641. };
  642.  
  643. const handleLeftbarDblclick = (x, y, button) => {
  644.  
  645. };
  646.  
  647. const handleClick = (x, y, button) => {
  648. if (x < leftbar_sx) {
  649. handleLeftbarClick(x, y, button);
  650. }
  651. };
  652.  
  653. let curr_event = null;
  654. let click_start = null;
  655.  
  656. const buttonToMask = [1, 4, 2];
  657.  
  658. const handleMousedown = (x, y, button) => {
  659. if (click_start === null) {
  660. click_start = { x, y, button, target: null };
  661. }
  662. };
  663.  
  664. const handleMouseup = (x, y, button) => {
  665. if (click_start && click_start.button === button) {
  666. click_start = null;
  667. }
  668. };
  669.  
  670. const handleMousemove = (x, y, buttons) => {
  671. if (click_start) {
  672. const {button} = click_start;
  673. if (!(buttonToMask[button] & buttons)) {
  674. handleMouseup(x, y, button);
  675. }
  676. }
  677. };
  678.  
  679. const handleDblclick = (x, y, button) => {
  680. if (x < leftbar_sx) {
  681. handleLeftbarDblclick(x, y);
  682. }
  683. };
  684.  
  685. fillLeftbar();
  686.  
  687. window.addEventListener('load', () => {
  688. canvas = document.querySelector('canvas');
  689. ctx = canvas.getContext('2d');
  690. window.addEventListener('resize', handleResize);
  691. canvas.addEventListener('click', e => {
  692. const {offsetX, offsetY, button} = e;
  693. handleClick(offsetX, offsetY, button);
  694. });
  695. canvas.addEventListener('mousedown', e => {
  696. const {offsetX, offsetY, button} = e;
  697. handleMousedown(offsetX, offsetY, button);
  698. });
  699. canvas.addEventListener('mousemove', e => {
  700. const {offsetX, offsetY, buttons} = e;
  701. handleMousemove(offsetX, offsetY, buttons);
  702. });
  703. canvas.addEventListener('mouseup', e => {
  704. const {offsetX, offsetY, button} = e;
  705. handleMouseup(offsetX, offsetY, button);
  706. });
  707. canvas.addEventListener('dblclick', e => {
  708. const {offsetX, offsetY, button} = e;
  709. handleDblclick(offsetX, offsetY, button);
  710. });
  711. create.axis({
  712. name: 'largo',
  713. inner_diameter: '5',
  714. outer_diameter: '60'
  715. });
  716. handleResize();
  717. });
  718.  
  719. </script>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement