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.
 
 
 

304 lines
6.2 KiB

  1. define([
  2. 'js/tplNode',
  3. 'js/events',
  4. 'js/client',
  5. 'js/input'
  6. ], function (
  7. tplNode,
  8. events,
  9. client,
  10. input
  11. ) {
  12. return {
  13. links: [],
  14. nodes: [],
  15. mode: 'none',
  16. init: function () {
  17. events.on('onAreaSelect', this.events.onAreaSelect.bind(this));
  18. events.on('onMouseMove', this.events.onMouseMove.bind(this));
  19. },
  20. findNode: function (x, y) {
  21. let res = this.nodes.find(n => ((n.pos.x == x) && (n.pos.y == y)));
  22. if (!res) {
  23. res = this.nodes.find(function (n) {
  24. return ((n.size > 0) && (Math.abs(n.pos.x - x) <= 1) && (Math.abs(n.pos.y - y) <= 1));
  25. });
  26. }
  27. return res;
  28. },
  29. callAction: function (action, options = {}) {
  30. let node = options.node || this.findNode(options.x, options.y);
  31. options.node = node;
  32. return !this.actions[action].call(this, options);
  33. },
  34. getSelected: function (single) {
  35. let selected = this.nodes.filter(n => n.selected);
  36. if ((single) && (selected.length != 1))
  37. return null;
  38. if (single)
  39. return selected[0];
  40. return selected;
  41. },
  42. serialize: function () {
  43. return JSON.stringify({
  44. nodes: this.nodes,
  45. links: this.links.map(function (l) {
  46. return {
  47. from: {
  48. id: l.from.id
  49. },
  50. to: {
  51. id: l.to.id
  52. }
  53. };
  54. })
  55. });
  56. },
  57. getData: function () {
  58. return {
  59. nodes: this.nodes.map(function (n) {
  60. let res = {
  61. id: n.id,
  62. pos: n.pos
  63. };
  64. ['size', 'color', 'stats', 'spiritStart'].forEach(function (s) {
  65. if (n[s] !== undefined)
  66. res[s] = n[s];
  67. });
  68. return res;
  69. }),
  70. links: this.links.map(function (l) {
  71. return {
  72. from: l.from.id,
  73. to: l.to.id
  74. };
  75. })
  76. };
  77. },
  78. getNextId: function () {
  79. for (var i = 0; i < this.nodes.length; i++) {
  80. if (!this.nodes.some(n => (n.id == i)))
  81. return i;
  82. }
  83. return this.nodes.length;
  84. },
  85. setMode: function (mode) {
  86. this.mode = mode;
  87. },
  88. actions: {
  89. reset: function () {
  90. this.nodes = [];
  91. this.links = [];
  92. events.emit('onNew');
  93. },
  94. load: function (data) {
  95. this.nodes = data.nodes;
  96. this.nodes.forEach(function (n) {
  97. if ((n.group) && (!n.group.push))
  98. n.group = [n.group];
  99. });
  100. this.links = data.links.map(function (l) {
  101. l.from = this.nodes.find(n => (n.id == l.from.id));
  102. l.to = this.nodes.find(n => (n.id == l.to.id));
  103. return l;
  104. }, this);
  105. events.emit('onTreeLoaded', {
  106. nodes: this.nodes,
  107. links: this.links
  108. });
  109. },
  110. selectNode: function (options) {
  111. if (
  112. (
  113. (!options.node) ||
  114. (!this.nodes.some(n => ((n.selected) && (n == options.node))))
  115. ) &&
  116. (
  117. (!input.isKeyDown('shift')) ||
  118. (options.force)
  119. )
  120. )
  121. this.nodes.forEach(n => (n.selected = false));
  122. if (options.node)
  123. options.node.selected = true;
  124. else if (options instanceof Array)
  125. options.forEach(n => (n.selected = true));
  126. events.emit('onSelectNode', this.nodes.filter(n => n.selected));
  127. if (options.node)
  128. events.emit('onFocusNode', options.node);
  129. return !options.node;
  130. },
  131. addNode: function (options) {
  132. this.nodes.push(tplNode.build({
  133. id: this.getNextId(),
  134. x: options.x,
  135. y: options.y
  136. }));
  137. this.callAction('selectNode');
  138. },
  139. connectNode: function (options) {
  140. let node = options.node;
  141. if (!node) {
  142. this.callAction('selectNode');
  143. return true;
  144. }
  145. let singleSelected = this.getSelected(true);
  146. if ((singleSelected) && (input.isKeyDown('ctrl'))) {
  147. if (options.shiftDown) {
  148. this.links.spliceWhere(l => (
  149. (
  150. (l.from == node) ||
  151. (l.to == node)
  152. ) &&
  153. (
  154. (l.from == singleSelected) ||
  155. (l.to == singleSelected)
  156. ) &&
  157. (node != singleSelected)
  158. ));
  159. } else {
  160. this.links.push({
  161. from: singleSelected,
  162. to: node
  163. });
  164. }
  165. this.callAction('selectNode', {
  166. force: true
  167. });
  168. this.callAction('selectNode', {
  169. node: options.node
  170. });
  171. } else {
  172. return this.callAction('selectNode', {
  173. node: node
  174. });
  175. }
  176. },
  177. moveNode: function (options) {
  178. let selected = this.getSelected();
  179. if (!selected.length)
  180. return true;
  181. if (selected.length == 0)
  182. return;
  183. selected.sort(function (a, b) {
  184. let distanceA = Math.abs(a.pos.x - options.x) + Math.abs(a.pos.y - options.y);
  185. let distanceB = Math.abs(b.pos.x - options.x) + Math.abs(b.pos.y - options.y);
  186. return (distanceA > distanceB) ? 1 : -1;
  187. });
  188. let deltaX = selected[0].pos.x - options.x;
  189. let deltaY = selected[0].pos.y - options.y;
  190. selected.forEach(function (s) {
  191. s.pos.x -= deltaX;
  192. s.pos.y -= deltaY;
  193. });
  194. },
  195. deleteNode: function (options) {
  196. let selected = this.getSelected();
  197. selected.forEach(function (s) {
  198. this.nodes.spliceWhere(n => (n == s));
  199. this.links.spliceWhere(n => ((n.from == s) || (n.to == s)));
  200. s.selected = false;
  201. events.emit('onDeleteNode', s);
  202. }, this);
  203. },
  204. recolorNode: function () {
  205. let selected = this.getSelected(true);
  206. if (!selected)
  207. return true;
  208. selected.color = (selected.color + 1) % 7;
  209. },
  210. resizeNode: function () {
  211. let selected = this.getSelected(true);
  212. if (!selected)
  213. return true;
  214. selected.size = (selected.size + 1) % 3;
  215. }
  216. },
  217. events: {
  218. onAreaSelect: function (from, to) {
  219. if (!input.isKeyDown('ctrl'))
  220. this.nodes.forEach(n => (n.selected = false));
  221. let lowX = Math.min(from.x, to.x);
  222. let lowY = Math.min(from.y, to.y);
  223. let highX = Math.max(from.x, to.x);
  224. let highY = Math.max(from.y, to.y);
  225. for (let i = lowX; i <= highX; i++) {
  226. for (let j = lowY; j <= highY; j++) {
  227. let node = this.findNode(i, j);
  228. if (!node)
  229. continue;
  230. node.selected = true;
  231. }
  232. }
  233. events.emit('onSelectNode', this.nodes.filter(n => n.selected));
  234. },
  235. onMouseMove: function (e) {
  236. let hoverNode = this.findNode(e.x, e.y);
  237. if (hoverNode) {
  238. let text = '';
  239. let stats = hoverNode.stats || {};
  240. for (let s in stats)
  241. text += s + ': ' + stats[s] + '<br />';
  242. text = text.substr(0, text.length - 6);
  243. if (text.length > 0)
  244. events.emit('onShowTooltip', e, text);
  245. } else
  246. events.emit('onHideTooltip');
  247. }
  248. }
  249. };
  250. });