123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368 |
- /**
- * Explore plugin.
- */
- Draw.loadPlugin(function(ui)
- {
- // Adds resource for action
- mxResources.parse('exploreFromHere=Explore from here...');
-
- // Max number of edges per page
- var pageSize = 20;
- var uiCreatePopupMenu = ui.menus.createPopupMenu;
- ui.menus.createPopupMenu = function(menu, cell, evt)
- {
- uiCreatePopupMenu.apply(this, arguments);
-
- var graph = ui.editor.graph;
-
- if (graph.model.isVertex(graph.getSelectionCell()))
- {
- this.addMenuItems(menu, ['-', 'exploreFromHere'], null, evt);
- }
- };
- //
- // Main function
- //
- function exploreFromHere(selectionCell)
- {
- var sourceGraph = ui.editor.graph;
-
- var container = document.createElement('div');
- container.style.position = 'absolute';
- container.style.display = 'block';
- container.style.background = '#ffffff';
- container.style.width = '100%';
- container.style.height = '100%';
- container.style.left = '0px';
- container.style.top = '0px';
- container.style.zIndex = 2;
- var deleteImage = document.createElement('img');
- deleteImage.setAttribute('src', IMAGE_PATH + '/delete.png');
- deleteImage.style.position = 'absolute';
- deleteImage.style.cursor = 'pointer';
- deleteImage.style.right = '10px';
- deleteImage.style.top = '10px';
- container.appendChild(deleteImage);
-
- var closeLabel = document.createElement('div');
- closeLabel.style.position = 'absolute';
- closeLabel.style.cursor = 'pointer';
- closeLabel.style.right = '38px';
- closeLabel.style.top = '14px';
- closeLabel.style.textAlign = 'right';
- closeLabel.style.verticalAlign = 'top';
- mxUtils.write(closeLabel, mxResources.get('close'));
- container.appendChild(closeLabel);
- document.body.appendChild(container);
-
- var keyHandler = function(evt)
- {
- if (evt.keyCode == 27)
- {
- deleteImage.click();
- }
- };
-
- mxEvent.addListener(document, 'keydown', keyHandler);
-
- // Global variable to make sure each cell in a response has
- // a unique ID throughout the complete life of the program,
- // in a real-life setup each cell should have an external
- // ID on the business object or else the cell ID should be
- // globally unique for the lifetime of the graph model.
- var requestId = 0;
-
- function main(container)
- {
- // Checks if browser is supported
- if (!mxClient.isBrowserSupported())
- {
- // Displays an error message if the browser is
- // not supported.
- mxUtils.error('Browser is not supported!', 200, false);
- }
- else
- {
- // Creates the graph inside the given container
- var graph = new Graph(container);
- graph.keepEdgesInBackground = true;
- graph.isCellResizable = function()
- {
- return false;
- };
- // Workaround to hide custom handles
- graph.isCellRotatable = function()
- {
- return false;
- };
-
- // Shows hand cursor for all vertices
- graph.getCursorForCell = function(cell)
- {
- if (this.model.isVertex(cell))
- {
- return 'pointer';
- }
-
- return null;
- };
-
- graph.getFoldingImage = function()
- {
- return null;
- };
-
- var closeHandler = function()
- {
- mxEvent.removeListener(document, 'keydown', keyHandler);
- container.parentNode.removeChild(container);
-
- // FIXME: Does not work
- sourceGraph.scrollCellToVisible(selectionCell);
- };
-
- mxEvent.addListener(deleteImage, 'click', closeHandler);
- mxEvent.addListener(closeLabel, 'click', closeHandler);
-
- // Disables all built-in interactions
- graph.setEnabled(false);
- // Handles clicks on cells
- graph.click = function(me)
- {
- var evt = me.getEvent();
- var cell = me.getCell();
-
- if (cell != null && cell != graph.rootCell)
- {
- load(graph, cell);
- }
- };
-
- // Gets the default parent for inserting new cells. This
- // is normally the first child of the root (ie. layer 0).
- var parent = graph.getDefaultParent();
- var cx = graph.container.scrollWidth / 2;
- var cy = graph.container.scrollHeight / 3;
- graph.model.beginUpdate();
- var cell = graph.importCells([selectionCell])[0];
- cell.sourceCellId = selectionCell.id;
- cell.geometry.x = cx - cell.geometry.width / 2;
- cell.geometry.y = cy - cell.geometry.height / 2;
- graph.model.endUpdate();
- // Animates the changes in the graph model
- graph.getModel().addListener(mxEvent.CHANGE, function(sender, evt)
- {
- var changes = evt.getProperty('edit').changes;
- var prev = mxText.prototype.enableBoundingBox;
- mxText.prototype.enableBoundingBox = false;
- graph.labelsVisible = false;
-
- mxEffects.animateChanges(graph, changes, function()
- {
- mxText.prototype.prev = true;
- graph.labelsVisible = true;
- graph.refresh();
- graph.tooltipHandler.hide();
- });
- });
- load(graph, cell);
- }
- };
- // Loads the links for the given cell into the given graph
- // by requesting the respective data in the server-side
- // (implemented for this demo using the server-function)
- function load(graph, cell)
- {
- if (graph.getModel().isVertex(cell))
- {
- var cx = graph.container.scrollWidth / 2;
- var cy = graph.container.scrollHeight / 3;
-
- // Gets the default parent for inserting new cells. This
- // is normally the first child of the root (ie. layer 0).
- var parent = graph.getDefaultParent();
- graph.rootCell = cell.referenceCell || cell;
- // Adds cells to the model in a single step
- graph.getModel().beginUpdate();
- try
- {
- var cells = rootChanged(graph, cell);
- // Removes all cells except the new root
- for (var key in graph.getModel().cells)
- {
- var tmp = graph.getModel().getCell(key);
-
- if (tmp != graph.rootCell && graph.getModel().isVertex(tmp))
- {
- graph.removeCells([tmp]);
- }
- }
- // Merges the response model with the client model
- //graph.getModel().mergeChildren(model.getRoot().getChildAt(0), parent);
- graph.addCells(cells);
- // Moves the given cell to the center
- var geo = graph.getModel().getGeometry(graph.rootCell);
- if (geo != null)
- {
- geo = geo.clone();
-
- geo.x = cx - geo.width / 2;
- geo.y = cy - geo.height / 3;
- graph.getModel().setGeometry(graph.rootCell, geo);
- }
-
- // Creates a list of the new vertices, if there is more
- // than the center vertex which might have existed
- // previously, then this needs to be changed to analyze
- // the target model before calling mergeChildren above
- var vertices = [];
-
- for (var key in graph.getModel().cells)
- {
- var tmp = graph.getModel().getCell(key);
-
- if (tmp != graph.rootCell && graph.getModel().isVertex(tmp) &&
- graph.getModel().getParent(tmp) == graph.getDefaultParent())
- {
- vertices.push(tmp);
- // Changes the initial location "in-place"
- // to get a nice animation effect from the
- // center to the radius of the circle
- var geo = graph.getModel().getGeometry(tmp);
- if (geo != null)
- {
- geo.x = cx - geo.width / 2;
- geo.y = cy - geo.height / 2;
- }
- }
- }
-
- // Arranges the response in a circle
- var cellCount = vertices.length;
- var phi = 2 * Math.PI / cellCount;
- var r = Math.min(graph.container.scrollWidth / 3 - 80,
- graph.container.scrollHeight / 3 - 80);
-
- for (var i = 0; i < cellCount; i++)
- {
- var geo = graph.getModel().getGeometry(vertices[i]);
-
- if (geo != null)
- {
- geo = geo.clone();
- geo.x += r * Math.sin(i * phi);
- geo.y += r * Math.cos(i * phi);
- graph.getModel().setGeometry(vertices[i], geo);
- }
- }
-
- // Keeps parallel edges apart
- var layout = new mxParallelEdgeLayout(graph);
- layout.spacing = 60;
- layout.execute(graph.getDefaultParent());
- }
- finally
- {
- // Updates the display
- graph.getModel().endUpdate();
- }
- }
- };
- // Gets the edges from the source cell and adds the targets
- function rootChanged(graph, cell)
- {
- // TODO: Keep existing cells, probably best via XML to redirect IDs
- var realCell = cell.referenceCell || cell;
- var sourceCell = sourceGraph.model.getCell(realCell.sourceCellId);
- var edges = sourceGraph.getEdges(sourceCell, null, true, true, false, true);
- var cells = edges;
-
- // Paging by selecting a window in the edges array
- if (cell.startIndex != null || (pageSize > 0 && edges.length > pageSize))
- {
- var start = cell.startIndex || 0;
-
- cells = edges.slice(Math.max(0, start), Math.min(edges.length, start + pageSize));
- }
-
- cells = cells.concat(sourceGraph.getOpposites(cells, sourceCell));
- var clones = graph.cloneCells(cells);
-
- var edgeStyle = ';curved=1;noEdgeStyle=1;entryX=none;entryY=none;exitX=none;exitY=none;';
- var btnStyle = 'fillColor=green;fontColor=white;strokeColor=green;';
-
- for (var i = 0; i < cells.length; i++)
- {
- clones[i].sourceCellId = cells[i].id;
-
- if (graph.model.isEdge(clones[i]))
- {
- // Removes waypoints, edge styles, constraints and centers the label
- clones[i].geometry.x = 0;
- clones[i].geometry.y = 0;
- clones[i].geometry.points = null;
- clones[i].setStyle(clones[i].getStyle() + edgeStyle);
- clones[i].setTerminal(realCell, clones[i].getTerminal(true) == null);
- }
- }
- if (cell.startIndex > 0)
- {
- var backCell = graph.createVertex(null, null, 'Back...', 0, 0, 80, 30, btnStyle);
- backCell.referenceCell = realCell;
- backCell.startIndex = Math.max(0, (cell.startIndex || 0) - pageSize);
- clones.splice(0, 0, backCell);
- }
-
- if (edges.length > (cell.startIndex || 0) + pageSize)
- {
- var moreCell = graph.createVertex(null, null, 'More...', 0, 0, 80, 30, btnStyle);
- moreCell.referenceCell = realCell;
- moreCell.startIndex = (cell.startIndex || 0) + pageSize;
- clones.splice(0, 0, moreCell);
- }
-
- return clones;
- };
-
- main(container);
- };
-
- // Adds action
- ui.actions.addAction('exploreFromHere', function()
- {
- exploreFromHere(ui.editor.graph.getSelectionCell());
- });
-
- // Click handler for chromeless mode
- if (ui.editor.chromeless)
- {
- ui.editor.graph.click = function(me)
- {
- if (ui.editor.graph.model.isVertex(me.getCell()) &&
- ui.editor.graph.model.getEdgeCount(me.getCell()) > 0)
- {
- exploreFromHere(me.getCell());
- }
- };
- }
- });
|