vis.js is a dynamic, browser-based visualization library
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.

858 lines
23 KiB

  1. var Node = require('./components/Node').default;
  2. var Edge = require('./components/Edge').default;
  3. let util = require('../../util');
  4. /**
  5. * The handler for selections
  6. */
  7. class SelectionHandler {
  8. /**
  9. * @param {Object} body
  10. * @param {Canvas} canvas
  11. */
  12. constructor(body, canvas) {
  13. this.body = body;
  14. this.canvas = canvas;
  15. this.selectionObj = {nodes: [], edges: []};
  16. this.hoverObj = {nodes:{},edges:{}};
  17. this.options = {};
  18. this.defaultOptions = {
  19. multiselect: false,
  20. selectable: true,
  21. selectConnectedEdges: true,
  22. hoverConnectedEdges: true
  23. };
  24. util.extend(this.options, this.defaultOptions);
  25. this.body.emitter.on("_dataChanged", () => {
  26. this.updateSelection()
  27. });
  28. }
  29. /**
  30. *
  31. * @param {Object} [options]
  32. */
  33. setOptions(options) {
  34. if (options !== undefined) {
  35. let fields = ['multiselect','hoverConnectedEdges','selectable','selectConnectedEdges'];
  36. util.selectiveDeepExtend(fields,this.options, options);
  37. }
  38. }
  39. /**
  40. * handles the selection part of the tap;
  41. *
  42. * @param {{x: number, y: number}} pointer
  43. * @returns {boolean}
  44. */
  45. selectOnPoint(pointer) {
  46. let selected = false;
  47. if (this.options.selectable === true) {
  48. let obj = this.getNodeAt(pointer) || this.getEdgeAt(pointer);
  49. // unselect after getting the objects in order to restore width and height.
  50. this.unselectAll();
  51. if (obj !== undefined) {
  52. selected = this.selectObject(obj);
  53. }
  54. this.body.emitter.emit("_requestRedraw");
  55. }
  56. return selected;
  57. }
  58. /**
  59. *
  60. * @param {{x: number, y: number}} pointer
  61. * @returns {boolean}
  62. */
  63. selectAdditionalOnPoint(pointer) {
  64. let selectionChanged = false;
  65. if (this.options.selectable === true) {
  66. let obj = this.getNodeAt(pointer) || this.getEdgeAt(pointer);
  67. if (obj !== undefined) {
  68. selectionChanged = true;
  69. if (obj.isSelected() === true) {
  70. this.deselectObject(obj);
  71. }
  72. else {
  73. this.selectObject(obj);
  74. }
  75. this.body.emitter.emit("_requestRedraw");
  76. }
  77. }
  78. return selectionChanged;
  79. }
  80. /**
  81. * Create an object containing the standard fields for an event.
  82. *
  83. * @param {Event} event
  84. * @param {{x: number, y: number}} pointer Object with the x and y screen coordinates of the mouse
  85. * @returns {{}}
  86. * @private
  87. */
  88. _initBaseEvent(event, pointer) {
  89. let properties = {};
  90. properties['pointer'] = {
  91. DOM: {x: pointer.x, y: pointer.y},
  92. canvas: this.canvas.DOMtoCanvas(pointer)
  93. };
  94. properties['event'] = event;
  95. return properties;
  96. }
  97. /**
  98. * Generate an event which the user can catch.
  99. *
  100. * This adds some extra data to the event with respect to cursor position and
  101. * selected nodes and edges.
  102. *
  103. * @param {string} eventType Name of event to send
  104. * @param {Event} event
  105. * @param {{x: number, y: number}} pointer Object with the x and y screen coordinates of the mouse
  106. * @param {Object|undefined} oldSelection If present, selection state before event occured
  107. * @param {boolean|undefined} [emptySelection=false] Indicate if selection data should be passed
  108. */
  109. _generateClickEvent(eventType, event, pointer, oldSelection, emptySelection = false) {
  110. let properties = this._initBaseEvent(event, pointer);
  111. if (emptySelection === true) {
  112. properties.nodes = [];
  113. properties.edges = [];
  114. }
  115. else {
  116. let tmp = this.getSelection();
  117. properties.nodes = tmp.nodes;
  118. properties.edges = tmp.edges;
  119. }
  120. if (oldSelection !== undefined) {
  121. properties['previousSelection'] = oldSelection;
  122. }
  123. if (eventType == 'click') {
  124. // For the time being, restrict this functionality to
  125. // just the click event.
  126. properties.items = this.getClickedItems(pointer);
  127. }
  128. this.body.emitter.emit(eventType, properties);
  129. }
  130. /**
  131. *
  132. * @param {Object} obj
  133. * @param {boolean} [highlightEdges=this.options.selectConnectedEdges]
  134. * @returns {boolean}
  135. */
  136. selectObject(obj, highlightEdges = this.options.selectConnectedEdges) {
  137. if (obj !== undefined) {
  138. if (obj instanceof Node) {
  139. if (highlightEdges === true) {
  140. this._selectConnectedEdges(obj);
  141. }
  142. }
  143. obj.select();
  144. this._addToSelection(obj);
  145. return true;
  146. }
  147. return false;
  148. }
  149. /**
  150. *
  151. * @param {Object} obj
  152. */
  153. deselectObject(obj) {
  154. if (obj.isSelected() === true) {
  155. obj.selected = false;
  156. this._removeFromSelection(obj);
  157. }
  158. }
  159. /**
  160. * retrieve all nodes overlapping with given object
  161. * @param {Object} object An object with parameters left, top, right, bottom
  162. * @return {number[]} An array with id's of the overlapping nodes
  163. * @private
  164. */
  165. _getAllNodesOverlappingWith(object) {
  166. let overlappingNodes = [];
  167. let nodes = this.body.nodes;
  168. for (let i = 0; i < this.body.nodeIndices.length; i++) {
  169. let nodeId = this.body.nodeIndices[i];
  170. if (nodes[nodeId].isOverlappingWith(object)) {
  171. overlappingNodes.push(nodeId);
  172. }
  173. }
  174. return overlappingNodes;
  175. }
  176. /**
  177. * Return a position object in canvasspace from a single point in screenspace
  178. *
  179. * @param {{x: number, y: number}} pointer
  180. * @returns {{left: number, top: number, right: number, bottom: number}}
  181. * @private
  182. */
  183. _pointerToPositionObject(pointer) {
  184. let canvasPos = this.canvas.DOMtoCanvas(pointer);
  185. return {
  186. left: canvasPos.x - 1,
  187. top: canvasPos.y + 1,
  188. right: canvasPos.x + 1,
  189. bottom: canvasPos.y - 1
  190. };
  191. }
  192. /**
  193. * Get the top node at the passed point (like a click)
  194. *
  195. * @param {{x: number, y: number}} pointer
  196. * @param {boolean} [returnNode=true]
  197. * @return {Node | undefined} node
  198. */
  199. getNodeAt(pointer, returnNode = true) {
  200. // we first check if this is an navigation controls element
  201. let positionObject = this._pointerToPositionObject(pointer);
  202. let overlappingNodes = this._getAllNodesOverlappingWith(positionObject);
  203. // if there are overlapping nodes, select the last one, this is the
  204. // one which is drawn on top of the others
  205. if (overlappingNodes.length > 0) {
  206. if (returnNode === true) {
  207. return this.body.nodes[overlappingNodes[overlappingNodes.length - 1]];
  208. }
  209. else {
  210. return overlappingNodes[overlappingNodes.length - 1];
  211. }
  212. }
  213. else {
  214. return undefined;
  215. }
  216. }
  217. /**
  218. * retrieve all edges overlapping with given object, selector is around center
  219. * @param {Object} object An object with parameters left, top, right, bottom
  220. * @param {number[]} overlappingEdges An array with id's of the overlapping nodes
  221. * @private
  222. */
  223. _getEdgesOverlappingWith(object, overlappingEdges) {
  224. let edges = this.body.edges;
  225. for (let i = 0; i < this.body.edgeIndices.length; i++) {
  226. let edgeId = this.body.edgeIndices[i];
  227. if (edges[edgeId].isOverlappingWith(object)) {
  228. overlappingEdges.push(edgeId);
  229. }
  230. }
  231. }
  232. /**
  233. * retrieve all nodes overlapping with given object
  234. * @param {Object} object An object with parameters left, top, right, bottom
  235. * @return {number[]} An array with id's of the overlapping nodes
  236. * @private
  237. */
  238. _getAllEdgesOverlappingWith(object) {
  239. let overlappingEdges = [];
  240. this._getEdgesOverlappingWith(object,overlappingEdges);
  241. return overlappingEdges;
  242. }
  243. /**
  244. * Get the edges nearest to the passed point (like a click)
  245. *
  246. * @param {{x: number, y: number}} pointer
  247. * @param {boolean} [returnEdge=true]
  248. * @return {Edge | undefined} node
  249. */
  250. getEdgeAt(pointer, returnEdge = true) {
  251. // Iterate over edges, pick closest within 10
  252. var canvasPos = this.canvas.DOMtoCanvas(pointer);
  253. var mindist = 10;
  254. var overlappingEdge = null;
  255. var edges = this.body.edges;
  256. for (var i = 0; i < this.body.edgeIndices.length; i++) {
  257. var edgeId = this.body.edgeIndices[i];
  258. var edge = edges[edgeId];
  259. if (edge.connected) {
  260. var xFrom = edge.from.x;
  261. var yFrom = edge.from.y;
  262. var xTo = edge.to.x;
  263. var yTo = edge.to.y;
  264. var dist = edge.edgeType.getDistanceToEdge(xFrom, yFrom, xTo, yTo, canvasPos.x, canvasPos.y);
  265. if(dist < mindist){
  266. overlappingEdge = edgeId;
  267. mindist = dist;
  268. }
  269. }
  270. }
  271. if (overlappingEdge !== null) {
  272. if (returnEdge === true) {
  273. return this.body.edges[overlappingEdge];
  274. }
  275. else {
  276. return overlappingEdge;
  277. }
  278. }
  279. else {
  280. return undefined;
  281. }
  282. }
  283. /**
  284. * Add object to the selection array.
  285. *
  286. * @param {Object} obj
  287. * @private
  288. */
  289. _addToSelection(obj) {
  290. if (obj instanceof Node) {
  291. this.selectionObj.nodes[obj.id] = obj;
  292. }
  293. else {
  294. this.selectionObj.edges[obj.id] = obj;
  295. }
  296. }
  297. /**
  298. * Add object to the selection array.
  299. *
  300. * @param {Object} obj
  301. * @private
  302. */
  303. _addToHover(obj) {
  304. if (obj instanceof Node) {
  305. this.hoverObj.nodes[obj.id] = obj;
  306. }
  307. else {
  308. this.hoverObj.edges[obj.id] = obj;
  309. }
  310. }
  311. /**
  312. * Remove a single option from selection.
  313. *
  314. * @param {Object} obj
  315. * @private
  316. */
  317. _removeFromSelection(obj) {
  318. if (obj instanceof Node) {
  319. delete this.selectionObj.nodes[obj.id];
  320. this._unselectConnectedEdges(obj);
  321. }
  322. else {
  323. delete this.selectionObj.edges[obj.id];
  324. }
  325. }
  326. /**
  327. * Unselect all. The selectionObj is useful for this.
  328. */
  329. unselectAll() {
  330. for(let nodeId in this.selectionObj.nodes) {
  331. if(this.selectionObj.nodes.hasOwnProperty(nodeId)) {
  332. this.selectionObj.nodes[nodeId].unselect();
  333. }
  334. }
  335. for(let edgeId in this.selectionObj.edges) {
  336. if(this.selectionObj.edges.hasOwnProperty(edgeId)) {
  337. this.selectionObj.edges[edgeId].unselect();
  338. }
  339. }
  340. this.selectionObj = {nodes:{},edges:{}};
  341. }
  342. /**
  343. * return the number of selected nodes
  344. *
  345. * @returns {number}
  346. * @private
  347. */
  348. _getSelectedNodeCount() {
  349. let count = 0;
  350. for (let nodeId in this.selectionObj.nodes) {
  351. if (this.selectionObj.nodes.hasOwnProperty(nodeId)) {
  352. count += 1;
  353. }
  354. }
  355. return count;
  356. }
  357. /**
  358. * return the selected node
  359. *
  360. * @returns {number}
  361. * @private
  362. */
  363. _getSelectedNode() {
  364. for (let nodeId in this.selectionObj.nodes) {
  365. if (this.selectionObj.nodes.hasOwnProperty(nodeId)) {
  366. return this.selectionObj.nodes[nodeId];
  367. }
  368. }
  369. return undefined;
  370. }
  371. /**
  372. * return the selected edge
  373. *
  374. * @returns {number}
  375. * @private
  376. */
  377. _getSelectedEdge() {
  378. for (let edgeId in this.selectionObj.edges) {
  379. if (this.selectionObj.edges.hasOwnProperty(edgeId)) {
  380. return this.selectionObj.edges[edgeId];
  381. }
  382. }
  383. return undefined;
  384. }
  385. /**
  386. * return the number of selected edges
  387. *
  388. * @returns {number}
  389. * @private
  390. */
  391. _getSelectedEdgeCount() {
  392. let count = 0;
  393. for (let edgeId in this.selectionObj.edges) {
  394. if (this.selectionObj.edges.hasOwnProperty(edgeId)) {
  395. count += 1;
  396. }
  397. }
  398. return count;
  399. }
  400. /**
  401. * return the number of selected objects.
  402. *
  403. * @returns {number}
  404. * @private
  405. */
  406. _getSelectedObjectCount() {
  407. let count = 0;
  408. for(let nodeId in this.selectionObj.nodes) {
  409. if(this.selectionObj.nodes.hasOwnProperty(nodeId)) {
  410. count += 1;
  411. }
  412. }
  413. for(let edgeId in this.selectionObj.edges) {
  414. if(this.selectionObj.edges.hasOwnProperty(edgeId)) {
  415. count += 1;
  416. }
  417. }
  418. return count;
  419. }
  420. /**
  421. * Check if anything is selected
  422. *
  423. * @returns {boolean}
  424. * @private
  425. */
  426. _selectionIsEmpty() {
  427. for(let nodeId in this.selectionObj.nodes) {
  428. if(this.selectionObj.nodes.hasOwnProperty(nodeId)) {
  429. return false;
  430. }
  431. }
  432. for(let edgeId in this.selectionObj.edges) {
  433. if(this.selectionObj.edges.hasOwnProperty(edgeId)) {
  434. return false;
  435. }
  436. }
  437. return true;
  438. }
  439. /**
  440. * check if one of the selected nodes is a cluster.
  441. *
  442. * @returns {boolean}
  443. * @private
  444. */
  445. _clusterInSelection() {
  446. for(let nodeId in this.selectionObj.nodes) {
  447. if(this.selectionObj.nodes.hasOwnProperty(nodeId)) {
  448. if (this.selectionObj.nodes[nodeId].clusterSize > 1) {
  449. return true;
  450. }
  451. }
  452. }
  453. return false;
  454. }
  455. /**
  456. * select the edges connected to the node that is being selected
  457. *
  458. * @param {Node} node
  459. * @private
  460. */
  461. _selectConnectedEdges(node) {
  462. for (let i = 0; i < node.edges.length; i++) {
  463. let edge = node.edges[i];
  464. edge.select();
  465. this._addToSelection(edge);
  466. }
  467. }
  468. /**
  469. * select the edges connected to the node that is being selected
  470. *
  471. * @param {Node} node
  472. * @private
  473. */
  474. _hoverConnectedEdges(node) {
  475. for (let i = 0; i < node.edges.length; i++) {
  476. let edge = node.edges[i];
  477. edge.hover = true;
  478. this._addToHover(edge);
  479. }
  480. }
  481. /**
  482. * unselect the edges connected to the node that is being selected
  483. *
  484. * @param {Node} node
  485. * @private
  486. */
  487. _unselectConnectedEdges(node) {
  488. for (let i = 0; i < node.edges.length; i++) {
  489. let edge = node.edges[i];
  490. edge.unselect();
  491. this._removeFromSelection(edge);
  492. }
  493. }
  494. /**
  495. * Remove the highlight from a node or edge, in response to mouse movement
  496. *
  497. * @param {Event} event
  498. * @param {{x: number, y: number}} pointer object with the x and y screen coordinates of the mouse
  499. * @param {Node|vis.Edge} object
  500. * @private
  501. */
  502. emitBlurEvent(event, pointer, object) {
  503. let properties = this._initBaseEvent(event, pointer);
  504. if (object.hover === true) {
  505. object.hover = false;
  506. if (object instanceof Node) {
  507. properties.node = object.id;
  508. this.body.emitter.emit("blurNode", properties);
  509. }
  510. else {
  511. properties.edge = object.id;
  512. this.body.emitter.emit("blurEdge", properties);
  513. }
  514. }
  515. }
  516. /**
  517. * Create the highlight for a node or edge, in response to mouse movement
  518. *
  519. * @param {Event} event
  520. * @param {{x: number, y: number}} pointer object with the x and y screen coordinates of the mouse
  521. * @param {Node|vis.Edge} object
  522. * @returns {boolean} hoverChanged
  523. * @private
  524. */
  525. emitHoverEvent(event, pointer, object) {
  526. let properties = this._initBaseEvent(event, pointer);
  527. let hoverChanged = false;
  528. if (object.hover === false) {
  529. object.hover = true;
  530. this._addToHover(object);
  531. hoverChanged = true;
  532. if (object instanceof Node) {
  533. properties.node = object.id;
  534. this.body.emitter.emit("hoverNode", properties);
  535. }
  536. else {
  537. properties.edge = object.id;
  538. this.body.emitter.emit("hoverEdge", properties);
  539. }
  540. }
  541. return hoverChanged;
  542. }
  543. /**
  544. * Perform actions in response to a mouse movement.
  545. *
  546. * @param {Event} event
  547. * @param {{x: number, y: number}} pointer | object with the x and y screen coordinates of the mouse
  548. */
  549. hoverObject(event, pointer) {
  550. let object = this.getNodeAt(pointer);
  551. if (object === undefined) {
  552. object = this.getEdgeAt(pointer);
  553. }
  554. let hoverChanged = false;
  555. // remove all node hover highlights
  556. for (let nodeId in this.hoverObj.nodes) {
  557. if (this.hoverObj.nodes.hasOwnProperty(nodeId)) {
  558. if (object === undefined || (object instanceof Node && object.id != nodeId) || object instanceof Edge) {
  559. this.emitBlurEvent(event, pointer, this.hoverObj.nodes[nodeId]);
  560. delete this.hoverObj.nodes[nodeId];
  561. hoverChanged = true;
  562. }
  563. }
  564. }
  565. // removing all edge hover highlights
  566. for (let edgeId in this.hoverObj.edges) {
  567. if (this.hoverObj.edges.hasOwnProperty(edgeId)) {
  568. // if the hover has been changed here it means that the node has been hovered over or off
  569. // we then do not use the emitBlurEvent method here.
  570. if (hoverChanged === true) {
  571. this.hoverObj.edges[edgeId].hover = false;
  572. delete this.hoverObj.edges[edgeId];
  573. }
  574. // if the blur remains the same and the object is undefined (mouse off) or another
  575. // edge has been hovered, or another node has been hovered we blur the edge.
  576. else if (object === undefined || (object instanceof Edge && object.id != edgeId) || (object instanceof Node && !object.hover)) {
  577. this.emitBlurEvent(event, pointer, this.hoverObj.edges[edgeId]);
  578. delete this.hoverObj.edges[edgeId];
  579. hoverChanged = true;
  580. }
  581. }
  582. }
  583. if (object !== undefined) {
  584. hoverChanged = hoverChanged || this.emitHoverEvent(event, pointer, object);
  585. if (object instanceof Node && this.options.hoverConnectedEdges === true) {
  586. this._hoverConnectedEdges(object);
  587. }
  588. }
  589. if (hoverChanged === true) {
  590. this.body.emitter.emit('_requestRedraw');
  591. }
  592. }
  593. /**
  594. *
  595. * retrieve the currently selected objects
  596. * @return {{nodes: Array.<string>, edges: Array.<string>}} selection
  597. */
  598. getSelection() {
  599. let nodeIds = this.getSelectedNodes();
  600. let edgeIds = this.getSelectedEdges();
  601. return {nodes:nodeIds, edges:edgeIds};
  602. }
  603. /**
  604. *
  605. * retrieve the currently selected nodes
  606. * @return {string[]} selection An array with the ids of the
  607. * selected nodes.
  608. */
  609. getSelectedNodes() {
  610. let idArray = [];
  611. if (this.options.selectable === true) {
  612. for (let nodeId in this.selectionObj.nodes) {
  613. if (this.selectionObj.nodes.hasOwnProperty(nodeId)) {
  614. idArray.push(this.selectionObj.nodes[nodeId].id);
  615. }
  616. }
  617. }
  618. return idArray;
  619. }
  620. /**
  621. *
  622. * retrieve the currently selected edges
  623. * @return {Array} selection An array with the ids of the
  624. * selected nodes.
  625. */
  626. getSelectedEdges() {
  627. let idArray = [];
  628. if (this.options.selectable === true) {
  629. for (let edgeId in this.selectionObj.edges) {
  630. if (this.selectionObj.edges.hasOwnProperty(edgeId)) {
  631. idArray.push(this.selectionObj.edges[edgeId].id);
  632. }
  633. }
  634. }
  635. return idArray;
  636. }
  637. /**
  638. * Updates the current selection
  639. * @param {{nodes: Array.<string>, edges: Array.<string>}} selection
  640. * @param {Object} options Options
  641. */
  642. setSelection(selection, options = {}) {
  643. let i, id;
  644. if (!selection || (!selection.nodes && !selection.edges))
  645. throw 'Selection must be an object with nodes and/or edges properties';
  646. // first unselect any selected node, if option is true or undefined
  647. if (options.unselectAll || options.unselectAll === undefined) {
  648. this.unselectAll();
  649. }
  650. if (selection.nodes) {
  651. for (i = 0; i < selection.nodes.length; i++) {
  652. id = selection.nodes[i];
  653. let node = this.body.nodes[id];
  654. if (!node) {
  655. throw new RangeError('Node with id "' + id + '" not found');
  656. }
  657. // don't select edges with it
  658. this.selectObject(node, options.highlightEdges);
  659. }
  660. }
  661. if (selection.edges) {
  662. for (i = 0; i < selection.edges.length; i++) {
  663. id = selection.edges[i];
  664. let edge = this.body.edges[id];
  665. if (!edge) {
  666. throw new RangeError('Edge with id "' + id + '" not found');
  667. }
  668. this.selectObject(edge);
  669. }
  670. }
  671. this.body.emitter.emit('_requestRedraw');
  672. }
  673. /**
  674. * select zero or more nodes with the option to highlight edges
  675. * @param {number[] | string[]} selection An array with the ids of the
  676. * selected nodes.
  677. * @param {boolean} [highlightEdges]
  678. */
  679. selectNodes(selection, highlightEdges = true) {
  680. if (!selection || (selection.length === undefined))
  681. throw 'Selection must be an array with ids';
  682. this.setSelection({nodes: selection}, {highlightEdges: highlightEdges});
  683. }
  684. /**
  685. * select zero or more edges
  686. * @param {number[] | string[]} selection An array with the ids of the
  687. * selected nodes.
  688. */
  689. selectEdges(selection) {
  690. if (!selection || (selection.length === undefined))
  691. throw 'Selection must be an array with ids';
  692. this.setSelection({edges: selection});
  693. }
  694. /**
  695. * Validate the selection: remove ids of nodes which no longer exist
  696. * @private
  697. */
  698. updateSelection() {
  699. for (let nodeId in this.selectionObj.nodes) {
  700. if (this.selectionObj.nodes.hasOwnProperty(nodeId)) {
  701. if (!this.body.nodes.hasOwnProperty(nodeId)) {
  702. delete this.selectionObj.nodes[nodeId];
  703. }
  704. }
  705. }
  706. for (let edgeId in this.selectionObj.edges) {
  707. if (this.selectionObj.edges.hasOwnProperty(edgeId)) {
  708. if (!this.body.edges.hasOwnProperty(edgeId)) {
  709. delete this.selectionObj.edges[edgeId];
  710. }
  711. }
  712. }
  713. }
  714. /**
  715. * Determine all the visual elements clicked which are on the given point.
  716. *
  717. * All elements are returned; this includes nodes, edges and their labels.
  718. * The order returned is from highest to lowest, i.e. element 0 of the return
  719. * value is the topmost item clicked on.
  720. *
  721. * The return value consists of an array of the following possible elements:
  722. *
  723. * - `{nodeId:number}` - node with given id clicked on
  724. * - `{nodeId:number, labelId:0}` - label of node with given id clicked on
  725. * - `{edgeId:number}` - edge with given id clicked on
  726. * - `{edge:number, labelId:0}` - label of edge with given id clicked on
  727. *
  728. * ## NOTES
  729. *
  730. * - Currently, there is only one label associated with a node or an edge,
  731. * but this is expected to change somewhere in the future.
  732. * - Since there is no z-indexing yet, it is not really possible to set the nodes and
  733. * edges in the correct order. For the time being, nodes come first.
  734. *
  735. * @param {point} pointer mouse position in screen coordinates
  736. * @returns {Array.<nodeClickItem|nodeLabelClickItem|edgeClickItem|edgeLabelClickItem>}
  737. * @private
  738. */
  739. getClickedItems(pointer) {
  740. let point = this.canvas.DOMtoCanvas(pointer);
  741. var items = [];
  742. // Note reverse order; we want the topmost clicked items to be first in the array
  743. // Also note that selected nodes are disregarded here; these normally display on top
  744. let nodeIndices = this.body.nodeIndices;
  745. let nodes = this.body.nodes;
  746. for (let i = nodeIndices.length - 1; i >= 0; i--) {
  747. let node = nodes[nodeIndices[i]];
  748. let ret = node.getItemsOnPoint(point);
  749. items.push.apply(items, ret); // Append the return value to the running list.
  750. }
  751. let edgeIndices = this.body.edgeIndices;
  752. let edges = this.body.edges;
  753. for (let i = edgeIndices.length - 1; i >= 0; i--) {
  754. let edge = edges[edgeIndices[i]];
  755. let ret = edge.getItemsOnPoint(point);
  756. items.push.apply(items, ret); // Append the return value to the running list.
  757. }
  758. return items;
  759. }
  760. }
  761. export default SelectionHandler;