Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <!DOCTYPE html>
- <html>
- <head>
- <title></title>
- <meta charset="utf-8">
- <style type="text/css">
- body {
- margin: 0px;
- font-size: 0px;
- overflow: hidden;
- }
- </style>
- </head>
- <body>
- <canvas></canvas>
- </body>
- </html>
- <script type="text/javascript">
- const PI = Math.PI;
- const TAU = Math.PI*2;
- let canvas;
- let ctx;
- let screen_sx;
- let screen_sy;
- let editor_sx;
- let editor_cx;
- let center_y;
- let inner_sx;
- let inner_sy;
- let start_x;
- let start_y;
- let end_x;
- let end_y;
- let leftbar_sx = 200;
- let item_spacing = 4;
- let item_sy = 22;
- let item_padding = 5;
- let item_font = 14;
- let item_tab_sx = 15;
- let button_spacing = 5;
- let button_radius = 7;
- let plus_linewidth = 2;
- let plus_radius = button_radius*0.7;
- let ex_radius = plus_radius/Math.SQRT2;
- let min_dist = 3;
- let margin = 0.1;
- let node_radius = 5;
- let node_line_cut = 10;
- let nodes_x;
- let space_sx;
- let space_sy;
- let space_x;
- let space_y;
- const cylinders = [
- {w: 5, h: 10, x: null, y: null, sx: null, sy: null},
- {w: 20, h: 10, x: null, y: null, sx: null, sy: null},
- {w: 60, h: 10, x: null, y: null, sx: null, sy: null},
- {w: 20, h: 10, x: null, y: null, sx: null, sy: null},
- {w: 5, h: 50, x: null, y: null, sx: null, sy: null},
- {w: 20, h: 20, x: null, y: null, sx: null, sy: null},
- {w: 5, h: 30, x: null, y: null, sx: null, sy: null},
- {w: 10, h: 5, x: null, y: null, sx: null, sy: null},
- ];
- let cylinder_scale_x = 1;
- let cylinder_scale_y = 1;
- const fixedNodes = [];
- const freeNodes = [];
- cylinders.forEach((cylinder, index) => {
- fixedNodes.push({index, x: null, y: null, ex: null});
- if (index === cylinders.length - 1) {
- fixedNodes.push({index: index + 1, x: null, y: null, ex: null});
- }
- });
- const udpateNodeCoords = node => {
- const nodes_x = (space_x + leftbar_sx)/2;
- const {index} = node;
- if (index === 0) {
- const cylinder = cylinders[0];
- node.x = nodes_x;
- node.y = cylinder.y;
- node.ex = cylinder.x;
- return;
- }
- if (index === cylinders.length) {
- const cylinder = cylinders[cylinders.length - 1];
- node.x = nodes_x;
- node.y = cylinder.y + cylinder.sy;
- node.ex = cylinder.x;
- return;
- }
- let a = cylinders[index];
- let b = cylinders[index - 1];
- node.x = nodes_x;
- node.y = a.y;
- node.ex = Math.min(a.x, b.x);
- };
- const renderNodes = () => {
- ctx.fillStyle = '#444';
- fixedNodes.forEach(node => {
- udpateNodeCoords(node);
- const {x, y, ex} = node;
- ctx.strokeStyle = '#f70';
- ctx.beginPath();
- ctx.arc(x, y, node_radius, 0, TAU);
- ctx.fill();
- ctx.stroke();
- ctx.strokeStyle = '#333';
- ctx.beginPath();
- ctx.moveTo(x + node_line_cut, y);
- ctx.lineTo(ex - node_line_cut, y);
- ctx.stroke();
- });
- };
- const renderCylinders = () => {
- let total_w = 0;
- let total_h = 0;
- cylinders.forEach(cylinder => {
- const {w, h} = cylinder;
- total_w = Math.max(total_w, w);
- total_h += h;
- });
- let ratio = total_w/total_h;
- space_sx = Math.min(inner_sx, inner_sy*ratio);
- space_sy = space_sx/ratio;
- space_x = start_x + (inner_sx - space_sx)/2;
- space_y = start_y + (inner_sy - space_sy)/2;
- cylinder_scale_x = space_sx/total_w;
- cylinder_scale_y = space_sy/total_h;
- let y = space_y;
- ctx.lineWidth = 1;
- ctx.strokeStyle = '#f70';
- ctx.fillStyle = 'rgba(255, 255, 255, 0.05)';
- cylinders.forEach(cylinder => {
- const sx = cylinder.w*cylinder_scale_x;
- const sy = cylinder.h*cylinder_scale_y;
- const x = editor_cx - sx/2;
- ctx.beginPath();
- ctx.rect(x, y, sx, sy);
- ctx.fill();
- ctx.stroke();
- cylinder.x = x;
- cylinder.y = y;
- cylinder.sx = sx;
- cylinder.sy = sy;
- y += sy;
- });
- };
- const toLabel = {
- 'axis': ['Eixo', 'Eixos'],
- 'disk': ['Disco', 'Discos'],
- };
- let lastId = 0;
- const newId = () => ++ lastId;
- const project = {
- database: {
- axis: [],
- disk: [],
- mga: [],
- mgb: [],
- mec: [],
- axis_instance: [],
- disk_instance: [],
- mga_instance: [],
- mgb_instance: [],
- mec_instance: [],
- node: []
- },
- idTypeMap: {},
- add: (type, object) => {
- const array = project.database[type];
- array.push(object);
- project.idTypeMap[object.id] = type;
- return object;
- },
- remove: id => {
- const type = project.idTypeMap[id];
- if (!type) return false;
- const array = project.database[type];
- let index = -1;
- for (let i=0; i<array.length; ++i) {
- if (array[i].id == id) {
- index = i;
- break;
- }
- }
- if (index === -1) return false;
- const obj = array[index];
- array.splice(index, 1);
- delete project.idTypeMap[id];
- return [obj];
- },
- find: id => {
- const type = project.idTypeMap[id];
- if (!type) return false;
- const array = project.database[type];
- let index = -1;
- for (let i=0; i<array.length; ++i) {
- if (array[i].id == id) {
- index = i;
- break;
- }
- }
- if (index === -1) return false;
- return { type, object: array[index] };
- }
- };
- const leftbar = {
- items: [],
- rendered_buttons: [],
- rendered_items: [],
- getButtonAt: (x, y) => {
- const array = leftbar.rendered_buttons;
- for (let i=0; i<array.length; ++i) {
- if (array[i].wraps(x, y)) {
- return array[i];
- }
- }
- return null;
- },
- groupMap: {},
- findItem: id => {
- let compare = '#' + id;
- const search = item => {
- if (item.name === compare) {
- return item;
- }
- const {children} = item;
- for (let i=children.length; i--;) {
- const child = children[i];
- if (child.name === compare) {
- return child;
- }
- }
- return null;
- };
- const {items} = leftbar;
- for (let i=items.length; i--;) {
- const res = search(items[i]);
- if (res) return res;
- }
- return null;
- },
- getItemAt: (x, y) => {
- const array = leftbar.rendered_items;
- for (let i=array.length; i--;) {
- const item = array[i];
- if (item.wraps(x, y)) return item;
- }
- return null;
- }
- };
- const drawPlus = (x, y, button) => {
- ctx.lineWidth = plus_linewidth;
- ctx.strokeStyle = '#ccc';
- ctx.beginPath();
- ctx.moveTo(x + plus_radius, y);
- ctx.lineTo(x - plus_radius, y);
- ctx.moveTo(x, y + plus_radius);
- ctx.lineTo(x, y - plus_radius);
- ctx.stroke();
- };
- const drawDelete = (x, y, button) => {
- ctx.lineWidth = plus_linewidth;
- ctx.strokeStyle = '#ccc';
- ctx.beginPath();
- ctx.moveTo(x + ex_radius, y + ex_radius);
- ctx.lineTo(x - ex_radius, y - ex_radius);
- ctx.moveTo(x + ex_radius, y - ex_radius);
- ctx.lineTo(x - ex_radius, y + ex_radius);
- ctx.stroke();
- };
- const drawToggle = (x, y, button) => {
- const item = button.parent;
- ctx.fillStyle = '#ccc';
- ctx.beginPath();
- if (item.open) {
- ctx.moveTo(x, y + 5);
- ctx.lineTo(x - 5, y - 5);
- ctx.lineTo(x + 5, y - 5);
- } else {
- ctx.moveTo(x - 5, y);
- ctx.lineTo(x + 5, y - 5);
- ctx.lineTo(x + 5, y + 5);
- }
- ctx.closePath();
- ctx.fill();
- };
- class Button {
- constructor(name, draw, pull_right) {
- this.draw = draw;
- this.name = name;
- this.visible = true;
- this.x = null;
- this.y = null;
- this.pull_right = pull_right || false;
- this.parent = null;
- }
- render(x, y) {
- if (!this.visible) return this;
- const {draw} = this;
- if (draw) {
- draw(x, y, this);
- } else {
- ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
- ctx.beginPath();
- ctx.arc(x, y, button_radius, 0, TAU);
- ctx.fill();
- }
- this.x = x;
- this.y = y;
- return this;
- }
- wraps(tx, ty) {
- const {x, y} = this;
- const dx = x - tx;
- const dy = y - ty;
- return Math.sqrt(dx*dx + dy*dy) <= button_radius;
- }
- }
- class LBItem {
- constructor(title, name) {
- this.parent = null;
- this.x = null;
- this.y = null;
- this.sx = null;
- this.sy = null;
- this.visible = true;
- this.title = title;
- this.name = name;
- this.children = [];
- this.buttons = [];
- this.open = true;
- this.buttonMap = {};
- }
- addButton(button) {
- button.parent = this;
- this.buttons.push(button);
- this.buttonMap[button.name] = button;
- return this;
- }
- wraps(tx, ty) {
- const {x, y, sx, sy} = this;
- return (tx >= x && ty >= y && tx < x + sx && ty < y + sy);
- }
- render(x, y) {
- if (!this.visible) return 0;
- leftbar.rendered_items.push(this);
- let sx = leftbar_sx - item_spacing - x;
- let sy = item_sy;
- this.x = x;
- this.y = y;
- this.sx = sx;
- this.sy = sy;
- let ax = x + item_padding;
- let bx = x + sx - item_padding;
- let cy = y + sy*0.5;
- if (this.parent === null) {
- ctx.fillStyle = '#333';
- ctx.fillRect(x, y, sx, sy);
- }
- ctx.font = item_font + 'px monospace';
- ctx.fillStyle = '#ccc';
- ctx.textAlign = 'left';
- ctx.textBaseline = 'middle';
- ctx.fillText(this.title, ax, y + sy*0.55);
- ax += ctx.measureText(this.title).width + button_spacing;
- const {buttons} = this;
- buttons.forEach(button => {
- if (button.visible) {
- leftbar.rendered_buttons.push(button);
- if (button.pull_right) {
- button.render(bx - button_radius, cy);
- bx -= button_radius*2 + button_spacing;
- } else {
- button.render(ax + button_radius, cy);
- ax += button_radius*2 + button_spacing;
- }
- }
- });
- y += sy;
- const {children} = this;
- if (this.open && children.length) {
- children.forEach(child => {
- y += item_spacing;
- sy += item_spacing;
- const height = child.render(x + item_tab_sx, y);
- y += height;
- sy += height;
- });
- }
- return sy;
- }
- append(child) {
- if (this.buttonMap.toggle) {
- this.buttonMap.toggle.visible = true;
- }
- child.parent = this;
- this.children.push(child);
- return this;
- }
- removeChild(child) {
- const {children} = this;
- const index = children.indexOf(child);
- if (index === -1) return this;
- children.splice(index, 1);
- if (children.length === 0 && this.buttonMap.toggle) {
- this.buttonMap.toggle.visible = false;
- }
- return this;
- }
- remove() {
- if (!this.parent) return this;
- this.parent.removeChild(this);
- this.parent = null;
- return this;
- }
- };
- const readUserData = (formTitle, fields) => new Promise((done) => {
- const data = {};
- for (let i=0; i<fields.length; ++i) {
- const field = fields[i];
- const {name, title, type} = field;
- const answ = prompt(`[${formTitle}]\n${title} (${type})`);
- if (answ === null) {
- done(null);
- return;
- }
- data[name] = answ;
- }
- done(data);
- });
- const requiredFields = {
- axis: [
- {name: 'name', title: 'Nome', type: 'string'},
- {name: 'inner_diameter', title: 'Diâmetro interno', type: 'number'},
- {name: 'outer_diameter', title: 'Diâmetro externo', type: 'number'}
- ],
- disk: [
- {name: 'name', title: 'Nome', type: 'string'},
- {name: 'diameter', title: 'Diâmetro', type: 'number'},
- {name: 'density', title: 'Densidade', type: 'number'}
- ]
- };
- const addPropGroup = (label, name) => {
- const group = new LBItem(label, name);
- group.addButton(new Button('add', drawPlus));
- group.addButton(new Button('toggle', drawToggle, true));
- group.buttonMap.toggle.visible = false;
- leftbar.items.push(group);
- leftbar.groupMap[name] = group;
- };
- const fillLeftbar = () => {
- addPropGroup(toLabel.axis[1], 'axis');
- addPropGroup(toLabel.disk[1], 'disk');
- };
- const updateMeasures = () => {
- const {innerWidth, innerHeight} = window;
- if (screen_sx === innerWidth && screen_sy === innerHeight) {
- return false;
- }
- screen_sx = innerWidth;
- screen_sy = innerHeight;
- editor_sx = screen_sx - leftbar_sx;
- editor_cx = leftbar_sx + editor_sx/2;
- center_y = screen_sy/2;
- // const m = Math.min(margin*editor_sx, margin*screen_sy);
- const m = 90;
- inner_sx = editor_sx - m*2;
- inner_sy = screen_sy - m*2;
- start_x = leftbar_sx + (editor_sx - inner_sx)/2;
- start_y = (screen_sy - inner_sy)/2;
- end_x = start_x + inner_sx;
- end_y = start_y + inner_sy;
- return true;
- };
- const renderLeftbarItems = () => {
- const array = leftbar.items;
- let y = item_spacing;
- array.forEach(item => {
- y += item.render(item_spacing, y) + item_spacing;
- });
- };
- const renderLeftbar = () => {
- ctx.fillStyle = '#262626';
- ctx.fillRect(0, 0, leftbar_sx, screen_sy);
- leftbar.rendered_buttons.length = 0;
- leftbar.rendered_items.length = 0;
- renderLeftbarItems();
- };
- const clearCanvas = () => {
- ctx.fillStyle = '#171717';
- ctx.fillRect(0, 0, screen_sx, screen_sy);
- };
- const render = () => {
- clearCanvas();
- renderLeftbar();
- renderCylinders();
- renderNodes();
- };
- const handleResize = () => {
- if (updateMeasures()) {
- canvas.width = screen_sx;
- canvas.height = screen_sy;
- render();
- }
- };
- const create = {
- axis: data => {
- const id = newId();
- const prop = {
- inner_diameter: data.inner_diameter,
- outer_diameter: data.outer_diameter,
- density: data.density,
- mod_e: null,
- mod_g: null
- };
- const object = {
- id,
- name: data.name || 'Unnamed',
- description: '',
- prop
- };
- project.add('axis', object);
- const item = new LBItem(data.name, '#' + id);
- object.item = item;
- item.addButton(new Button('remove', drawDelete));
- leftbar.groupMap['axis'].append(item);
- return object;
- },
- disk: data => {
- const id = newId();
- const prop = {
- diameter: data.diameter,
- density: data.density,
- };
- const object = {
- id,
- name: data.name || 'Unnamed',
- description: '',
- prop
- };
- project.add('disk', object);
- const item = new LBItem(data.name, '#' + id);
- object.item = item;
- item.addButton(new Button('remove', drawDelete));
- leftbar.groupMap['disk'].append(item);
- return object;
- }
- };
- const handleLeftbarButtonClick = (button) => {
- const {name} = button;
- if (name === 'add') {
- const {parent} = button;
- const {name} = parent;
- readUserData('Novo ' + toLabel[name][0], requiredFields[name])
- .then(data => {
- if (!data) return;
- create[name](data);
- render();
- });
- return;
- }
- if (name === 'remove') {
- const {parent} = button;
- const id = parent.name.substr(1);
- const res = project.find(id);
- if (!res) return;
- const {object, type} = res;
- const {name} = object;
- if (!confirm(`Deseja mesmo excluir ${toLabel[type][0].toLowerCase()} "${name}"?`)) return;
- const array = project.remove(id);
- if (array) {
- array.forEach(object => {
- const item = leftbar.findItem(object.id);
- if (item) item.remove();
- });
- render();
- }
- }
- if (name === 'toggle') {
- const item = button.parent;
- item.open = !item.open;
- render();
- }
- };
- const handleLeftbarClick = (x, y, buttonCode) => {
- if (buttonCode !== 0) return;
- const button = leftbar.getButtonAt(x, y);
- if (button) {
- handleLeftbarButtonClick(button);
- return;
- }
- const item = leftbar.getItemAt(x, y);
- };
- const handleLeftbarDblclick = (x, y, button) => {
- };
- const handleClick = (x, y, button) => {
- if (x < leftbar_sx) {
- handleLeftbarClick(x, y, button);
- }
- };
- let curr_event = null;
- let click_start = null;
- const buttonToMask = [1, 4, 2];
- const handleMousedown = (x, y, button) => {
- if (click_start === null) {
- click_start = { x, y, button, target: null };
- }
- };
- const handleMouseup = (x, y, button) => {
- if (click_start && click_start.button === button) {
- click_start = null;
- }
- };
- const handleMousemove = (x, y, buttons) => {
- if (click_start) {
- const {button} = click_start;
- if (!(buttonToMask[button] & buttons)) {
- handleMouseup(x, y, button);
- }
- }
- };
- const handleDblclick = (x, y, button) => {
- if (x < leftbar_sx) {
- handleLeftbarDblclick(x, y);
- }
- };
- fillLeftbar();
- window.addEventListener('load', () => {
- canvas = document.querySelector('canvas');
- ctx = canvas.getContext('2d');
- window.addEventListener('resize', handleResize);
- canvas.addEventListener('click', e => {
- const {offsetX, offsetY, button} = e;
- handleClick(offsetX, offsetY, button);
- });
- canvas.addEventListener('mousedown', e => {
- const {offsetX, offsetY, button} = e;
- handleMousedown(offsetX, offsetY, button);
- });
- canvas.addEventListener('mousemove', e => {
- const {offsetX, offsetY, buttons} = e;
- handleMousemove(offsetX, offsetY, buttons);
- });
- canvas.addEventListener('mouseup', e => {
- const {offsetX, offsetY, button} = e;
- handleMouseup(offsetX, offsetY, button);
- });
- canvas.addEventListener('dblclick', e => {
- const {offsetX, offsetY, button} = e;
- handleDblclick(offsetX, offsetY, button);
- });
- create.axis({
- name: 'largo',
- inner_diameter: '5',
- outer_diameter: '60'
- });
- handleResize();
- });
- </script>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement