actionsbuilder.contextMenu.ts 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. module ActionsBuilder {
  2. export interface ContextMenuElement {
  3. text: string;
  4. node: Node;
  5. action: string;
  6. }
  7. export class ContextMenu {
  8. public showing: boolean = false;
  9. public savedColor: RaphaelColor = Raphael.rgb(255, 255, 255);
  10. public overColor: RaphaelColor = Raphael.rgb(140, 200, 230);
  11. private _viewer: Viewer = null;
  12. private elements: Array<ContextMenuElement> = [
  13. { text: "Reduce", node: null, action: "onReduce" },
  14. { text: "Delete", node: null, action: "onRemoveNode" },
  15. { text: "Delete branch", node: null, action: "onRemoveBranch" },
  16. { text: "Connect / Disconnect", node: null, action: "onDetachAction" },
  17. { text: "Copy", node: null, action: "onCopyStructure" },
  18. { text: "Paste", node: null, action: "onPasteStructure" },
  19. // Add other elements here
  20. { text: "", node: null, action: null } // Color separator (top)
  21. ];
  22. /*
  23. * Constructor
  24. * @param viewer: the graph viewer
  25. */
  26. constructor(viewer: Viewer) {
  27. // Members
  28. this._viewer = viewer;
  29. // Configure
  30. this.attachControl(this._viewer.paper.canvas);
  31. }
  32. public attachControl(element: HTMLElement): void {
  33. var onClick = (event: MouseEvent) => {
  34. var x = this._viewer.mousex;
  35. var y = this._viewer.mousey;
  36. // Remove all context menu nodes, and run action if selected
  37. if (this.showing) {
  38. for (var i = 0; i < this.elements.length; i++) {
  39. var element = this.elements[i];
  40. if (element.action && element.node.rect.isPointInside(x, y)) {
  41. this._viewer.utils[element.action]();
  42. this._viewer.update();
  43. }
  44. element.node.rect.remove();
  45. element.node.text.remove();
  46. }
  47. }
  48. this.showing = false;
  49. };
  50. var onMouseMove = (event: MouseEvent) => {
  51. // Override context menu's node color if mouse is inside
  52. if (this.showing) {
  53. for (var i = 0; i < this.elements.length; i++) {
  54. var element = this.elements[i];
  55. if (element.text === "")
  56. continue;
  57. var x = this._viewer.mousex;
  58. var y = this._viewer.mousey;
  59. if (element.node.rect.isPointInside(x, y)) {
  60. element.node.rect.attr("fill", this.overColor);
  61. }
  62. else {
  63. element.node.rect.attr("fill", this.savedColor);
  64. }
  65. }
  66. }
  67. };
  68. var onRightClick = (event: MouseEvent) => {
  69. var x = this._viewer.mousex;
  70. var y = this._viewer.mousey;
  71. this._viewer.onClick(event);
  72. // Set selected node
  73. var result = this._viewer.traverseGraph(null, x, y, true);
  74. if (result.hit) {
  75. //this._viewer.selectedNode = result.element;
  76. }
  77. // Properly draw the context menu on the screen
  78. if (y + (Viewer.NODE_HEIGHT * this.elements.length) > this._viewer.viewerElement.offsetHeight + this._viewer.viewerElement.scrollTop) {
  79. y = (Viewer.NODE_HEIGHT * this.elements.length);
  80. }
  81. if (x + Viewer.NODE_WIDTH > this._viewer.viewerElement.offsetWidth + this._viewer.viewerElement.scrollLeft) {
  82. x -= Viewer.NODE_WIDTH;
  83. }
  84. if (!this.showing) {
  85. if (this._viewer.selectedNode === null)
  86. return;
  87. // Create elements
  88. var yOffset = 10;
  89. for (var i = 0; i < this.elements.length - 1; i++) {
  90. var element = this.elements[i];
  91. element.node = this._viewer._createNode(element.text, Type.OBJECT, true);
  92. element.node.rect.attr("fill", Raphael.rgb(216, 216, 216));
  93. element.node.rect.attr("x", x);
  94. element.node.rect.attr("y", y + yOffset);
  95. element.node.text.attr("x", x + 5);
  96. element.node.text.attr("y", y + yOffset + element.node.rect.attr("height") / 2);
  97. yOffset += Viewer.NODE_HEIGHT;
  98. }
  99. // Color separator
  100. var separator = this.elements[this.elements.length - 1];
  101. separator.node = this._viewer._createNode("", Type.OBJECT, true);
  102. separator.node.rect.attr("fill", this._viewer.getNodeColor(this._viewer.selectedNode.type, this._viewer.selectedNode.node.detached));
  103. separator.node.rect.attr("x", x);
  104. separator.node.rect.attr("y", y);
  105. separator.node.rect.attr("height", 10);
  106. // Finish
  107. this.showing = true;
  108. }
  109. else {
  110. onClick(event);
  111. onRightClick(event);
  112. }
  113. window.event.returnValue = false;
  114. };
  115. document.addEventListener("click", onClick);
  116. document.addEventListener("mousemove", onMouseMove);
  117. element.addEventListener("contextmenu", onRightClick);
  118. }
  119. }
  120. }