Block.js 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. 'use strict';
  2. function getElementCenter(e) {
  3. const rect = e.getBoundingClientRect();
  4. const parent_rect = e.parentElement.parentElement.parentElement.parentElement.getBoundingClientRect();
  5. return {
  6. 'x': rect.x - parent_rect.x + rect.width / 2,
  7. 'y': rect.y - parent_rect.y + rect.height / 2
  8. };
  9. }
  10. function getElementRelativeCenter(e) {
  11. const rect = e.getBoundingClientRect();
  12. return {
  13. 'x': rect.width / 2,
  14. 'y': rect.height / 2
  15. };
  16. }
  17. class Block extends React.Component {
  18. constructor(props) {
  19. console.log('block constructor');
  20. super(props);
  21. const type_info = props.getTypeInfo(props.type);
  22. this.state = {
  23. 'const_id': props.const_id,
  24. 'id': props.id,
  25. 'type': props.type,
  26. 'x': props.x,
  27. 'y': props.y,
  28. 'scale': props.scale,
  29. 'handleMouseDown': props.handleMouseDown,
  30. 'handleMouseMove': props.handleMouseMove,
  31. 'dragging': props.dragging || false,
  32. 'initital_dragging': props.dragging || false,
  33. 'gripX': undefined,
  34. 'gripY': undefined,
  35. 'inputs': props.inputs || props.type_info.inputs,
  36. 'outputs': props.outputs || props.type_info.outputs,
  37. 'inputs_groups': [...(props.inputs_groups || props.type_info.inputs_groups)],
  38. 'outputs_groups': [...(props.outputs_groups || props.type_info.outputs_groups)],
  39. 'onStateChange': props.onStateChange,
  40. 'onMount': props.onMount,
  41. 'onStopInitialDragging': props.onStopInitialDragging,
  42. 'removeBlock': props.removeBlock,
  43. 'startAddingWire': props.startAddingWire,
  44. 'handleMouseUpOnInputOutput': props.handleMouseUpOnInputOutput,
  45. 'removeWires': props.removeWires,
  46. 'wireHere': props.wireHere,
  47. 'updateInputsOutputsNames': props.updateInputsOutputsNames
  48. };
  49. this.handleMouseDown = this.handleMouseDown.bind(this);
  50. this.handleMouseUp = this.handleMouseUp.bind(this);
  51. this.handleMouseMove = this.handleMouseMove.bind(this);
  52. this.handleMouseLeave = this.handleMouseLeave.bind(this);
  53. this.handleMouseDownOnInputOutput = this.handleMouseDownOnInputOutput.bind(this);
  54. this._ref = React.createRef();
  55. this.input_connectors_refs = Array(Object.keys(this.state.inputs).length).fill(undefined).map(e => React.createRef());
  56. this.output_connectors_refs = Array(this.state.outputs.length).fill(undefined).map(e => React.createRef());
  57. }
  58. getInfo(state) {
  59. if (state == undefined) state = this.state;
  60. return {
  61. 'getInputsGroups': (() => this.state.inputs_groups).bind(this),
  62. 'getOutputsGroups': (() => this.state.outputs_groups).bind(this),
  63. 'setId': (id => this.state.id = id).bind(this),
  64. 'getInfo': this.getInfo.bind(this),
  65. 'type': state.type,
  66. 'id': state.id,
  67. 'const_id': state.const_id,
  68. 'x': state.x,
  69. 'y': state.y,
  70. 'inputs': state.inputs,
  71. 'outputs': state.outputs,
  72. 'outputs_groups': state.outputs_groups,
  73. 'inputs_groups': state.inputs_groups,
  74. 'input_connectors_coordinates': this.input_connectors_refs.slice(0, this.state.inputs_groups.length).map(r => getElementCenter(r.current)),
  75. 'output_connectors_coordinates': this.output_connectors_refs.slice(0, this.state.outputs_groups.length).map(r => getElementCenter(r.current))
  76. };
  77. }
  78. componentDidMount() {
  79. const content_element = this._ref.current.children[0];
  80. const name_element = this._ref.current.children[0].children[1];
  81. const ifDraggableByThis = (e, f) => e.target === content_element || e.target === name_element ? f(e) : null;
  82. this.state.event_listeners = [[this._ref.current.parentElement.parentElement, 'mousemove', this.handleMouseMove], [this._ref.current, 'mousedown', e => e.preventDefault()]];
  83. for (const e_l of this.state.event_listeners) e_l[0].addEventListener(e_l[1], e_l[2]);
  84. if (this.state.dragging) {
  85. const mouse_x = this.state.x;
  86. const mouse_y = this.state.y;
  87. const scale = this.state.scale;
  88. const self_rect = this._ref.current.getBoundingClientRect();
  89. const blocks_wrapper_element = this._ref.current.parentElement;
  90. const blocks_wrapper_rect = blocks_wrapper_element.getBoundingClientRect();
  91. const center = {
  92. 'x': (this.state.x - self_rect.width / 2 - blocks_wrapper_rect.x) / scale,
  93. 'y': (this.state.y - self_rect.height / 2 - blocks_wrapper_rect.y) / scale
  94. };
  95. this.setState(state => {
  96. state.x = center.x;
  97. state.y = center.y;
  98. return state;
  99. }, () => this.handleMouseDown({
  100. 'clientX': mouse_x,
  101. 'clientY': mouse_y,
  102. 'button': 0
  103. }, () => {
  104. const info = this.getInfo();
  105. this.state.onMount(info);
  106. this.state.onStateChange(info);
  107. }));
  108. } else {
  109. const info = this.getInfo();
  110. this.state.onMount(info);
  111. this.state.onStateChange(info);
  112. }
  113. }
  114. componentWillUnmount() {
  115. for (const e_l of this.state.event_listeners) e_l[0].removeEventListener(e_l[1], e_l[2]);
  116. }
  117. handleMouseDown(e, function_after) {
  118. this.state.handleMouseDown(this, e.clientX, e.clientY, e.button, function_after);
  119. }
  120. handleMouseUp(e) {
  121. if (this.state.initital_dragging) this.state.onStopInitialDragging(this.state.const_id);
  122. if (this.state.dragging) this.setState({
  123. 'dragging': false,
  124. 'initital_dragging': false
  125. });
  126. }
  127. handleMouseMove(e) {
  128. this.state.handleMouseMove(this, e.clientX, e.clientY);
  129. }
  130. handleMouseLeave(e) {
  131. this.handleMouseMove(e);
  132. }
  133. handleMouseDownOnInputOutput(type, i, e) {
  134. const blocks_wrapper_element = this._ref.current.parentElement;
  135. const blocks_wrapper_rect = blocks_wrapper_element.getBoundingClientRect();
  136. if (type == 'input') {
  137. if (e.button == 0) this.state.startAddingWire({
  138. 'group_size': this.state.inputs_groups[i],
  139. 'to_block_const_id': this.state.const_id,
  140. 'to_input_id': i,
  141. 'from_point': {
  142. 'x': e.clientX - blocks_wrapper_rect.x,
  143. 'y': e.clientY - blocks_wrapper_rect.y
  144. },
  145. 'to_point': getElementCenter(this.input_connectors_refs[i].current)
  146. });else if (e.button == 2) this.state.removeWires({
  147. 'to_block_const_id': this.state.const_id,
  148. 'to_input_id': i
  149. });
  150. } else if (type == 'output') {
  151. if (e.button == 0) this.state.startAddingWire({
  152. 'group_size': this.state.outputs_groups[i],
  153. 'from_block_const_id': this.state.const_id,
  154. 'from_output_id': i,
  155. 'from_point': getElementCenter(this.output_connectors_refs[i].current),
  156. 'to_point': {
  157. 'x': e.clientX - blocks_wrapper_rect.x,
  158. 'y': e.clientY - blocks_wrapper_rect.y
  159. }
  160. });else if (e.button == 2) this.state.removeWires({
  161. 'from_block_const_id': this.state.const_id,
  162. 'from_output_id': i
  163. });
  164. }
  165. }
  166. handleMouseWheelOnInputOutput(i, e) {
  167. if (!(this.state.type == 'INPUT' || this.state.type == 'OUTPUT')) return;
  168. const type = this.state.type == 'INPUT' ? 'output' : 'input';
  169. if (this.state.wireHere(this.state.const_id, type, i)) return;
  170. e.stopPropagation();
  171. const delta = -e.deltaY / 100;
  172. const groups_variable_name = {
  173. 'INPUT': 'outputs_groups',
  174. 'OUTPUT': 'inputs_groups'
  175. }[this.state.type];
  176. if (groups_variable_name == undefined) return;
  177. this.setState(state => {
  178. const new_value = state[groups_variable_name][0] + delta;
  179. if (new_value < 1) return state;
  180. state[groups_variable_name][0] = new_value;
  181. state.updateInputsOutputsNames(this.state.type, this.state.const_id, delta);
  182. return state;
  183. });
  184. }
  185. render() {
  186. const x = this.state.x;
  187. const y = this.state.y;
  188. const type = this.state.type;
  189. const name = this.state.id; // const visible_name = ((type == 'INPUT') || (type == 'OUTPUT')) ? name : type;
  190. const visible_name = name;
  191. const max_connectors = Math.max(this.state.inputs.length, this.state.outputs.length);
  192. return /*#__PURE__*/React.createElement("div", {
  193. ref: this._ref,
  194. className: "block",
  195. onMouseUp: e => e.button == 0 ? this.handleMouseUp(e) : null,
  196. onContextMenu: e => e.preventDefault(),
  197. style: {
  198. 'position': 'absolute',
  199. 'left': x,
  200. 'top': y,
  201. 'zIndex': this.state.dragging ? 101 : 0
  202. }
  203. }, /*#__PURE__*/React.createElement("div", {
  204. className: "content",
  205. onMouseDown: e => {
  206. if (e.target.classList.contains('content') || e.target.classList.contains('name')) this.handleMouseDown(e);
  207. }
  208. }, /*#__PURE__*/React.createElement("div", {
  209. className: "inputs"
  210. }, this.state.inputs_groups.map((input_group, i) => /*#__PURE__*/React.createElement("div", {
  211. ref: this.input_connectors_refs[i],
  212. key: i,
  213. className: "input",
  214. onMouseDown: e => this.handleMouseDownOnInputOutput('input', i, e),
  215. onMouseUp: e => e.button == 0 ? this.state.handleMouseUpOnInputOutput({
  216. 'group_size': input_group,
  217. 'to_block_const_id': this.state.const_id,
  218. 'to_input_id': i
  219. }) : null,
  220. onWheel: e => this.handleMouseWheelOnInputOutput(i, e)
  221. }, /*#__PURE__*/React.createElement("div", {
  222. className: "groupSize unselectable"
  223. }, input_group)))), /*#__PURE__*/React.createElement("div", {
  224. className: "name unselectable"
  225. }, visible_name), /*#__PURE__*/React.createElement("div", {
  226. className: "outputs"
  227. }, this.state.outputs_groups.map((output_group, i) => /*#__PURE__*/React.createElement("div", {
  228. ref: this.output_connectors_refs[i],
  229. key: i,
  230. className: "output",
  231. onMouseDown: e => this.handleMouseDownOnInputOutput('output', i, e),
  232. onMouseUp: e => e.button == 0 ? this.state.handleMouseUpOnInputOutput({
  233. 'group_size': output_group,
  234. 'from_block_const_id': this.state.const_id,
  235. 'from_output_id': i
  236. }) : null,
  237. onWheel: e => this.handleMouseWheelOnInputOutput(i, e)
  238. }, /*#__PURE__*/React.createElement("div", {
  239. className: "groupSize unselectable"
  240. }, output_group))))));
  241. }
  242. }