Created
July 29, 2014 13:27
-
-
Save davidjgraph/9d997cdf81f438bbd725 to your computer and use it in GitHub Desktop.
explore.js draw.io plugin
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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); | |
} | |
}; | |
// Adds action | |
ui.actions.addAction('exploreFromHere', function() | |
{ | |
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.zIndex = 2; | |
var deleteImage = document.createElement('img'); | |
deleteImage.setAttribute('src', IMAGE_PATH + '/delete.png'); | |
deleteImage.style.position = 'absolute'; | |
deleteImage.style.right = '10px'; | |
deleteImage.style.top = '10px'; | |
container.appendChild(deleteImage); | |
document.body.appendChild(container); | |
// 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.setCellsResizable(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; | |
}; | |
mxEvent.addListener(deleteImage, 'click', function() | |
{ | |
container.parentNode.removeChild(container); | |
sourceGraph.setSelectionCell(sourceGraph.model.getCell(graph.rootCell.sourceCellId)); | |
// FIXME: Does not work | |
sourceGraph.scrollCellToVisible(sourceGraph.getSelectionCell()); | |
}); | |
// 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) | |
{ | |
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; | |
var sourceCell = sourceGraph.getSelectionCell(); | |
graph.model.beginUpdate(); | |
var cell = graph.importCells([sourceCell])[0]; | |
cell.sourceCellId = sourceCell.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.setSelectionCell(graph.rootCell); | |
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); | |
}); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment