Skip to content

Instantly share code, notes, and snippets.

@davidjgraph
Created July 29, 2014 13:27
Show Gist options
  • Star 10 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save davidjgraph/9d997cdf81f438bbd725 to your computer and use it in GitHub Desktop.
Save davidjgraph/9d997cdf81f438bbd725 to your computer and use it in GitHub Desktop.
explore.js draw.io plugin
/**
* 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