1852 lines
62 KiB
HTML
1852 lines
62 KiB
HTML
<!--
|
||
Copyright (c) 2006-2013, JGraph Ltd
|
||
|
||
Toolbar example for mxGraph. This example demonstrates using
|
||
existing cells as templates for creating new cells.
|
||
-->
|
||
<html>
|
||
<head>
|
||
<title>Toolbar example for mxGraph</title>
|
||
|
||
<!-- Sets the basepath for the library if not in same directory -->
|
||
<script type="text/javascript">
|
||
mxBasePath = '../src';
|
||
</script>
|
||
|
||
<!-- Loads and initializes the library -->
|
||
<script type="text/javascript" src="../src/js/mxClient.js"></script>
|
||
|
||
<!-- Example code -->
|
||
<script type="text/javascript">
|
||
// Program starts here. Creates a sample graph in the
|
||
// DOM node with the specified ID. This function is invoked
|
||
// from the onLoad event handler of the document (see below).
|
||
function main()
|
||
{
|
||
// Defines an icon for creating new connections in the connection handler.
|
||
// This will automatically disable the highlighting of the source vertex.
|
||
// mxConnectionHandler.prototype.connectImage = new mxImage('images/connector.gif', 16, 16);
|
||
|
||
// If connect preview is not moved away then getCellAt is used to detect the cell under
|
||
// the mouse if the mouse is over the preview shape in IE (no event transparency), ie.
|
||
// the built-in hit-detection of the HTML document will not be used in this case.
|
||
mxConnectionHandler.prototype.movePreviewAway = false;
|
||
mxConnectionHandler.prototype.waypointsEnabled = true;
|
||
mxGraph.prototype.resetEdgesOnConnect = false;
|
||
mxConstants.SHADOWCOLOR = '#C0C0C0';
|
||
|
||
// Replaces the port image
|
||
mxConstraintHandler.prototype.pointImage = new mxImage('images/dot.gif', 10, 10);
|
||
|
||
// Enables guides
|
||
mxGraphHandler.prototype.guidesEnabled = true;
|
||
|
||
// Alt disables guides
|
||
mxGuide.prototype.isEnabledForEvent = function(evt)
|
||
{
|
||
return !mxEvent.isAltDown(evt);
|
||
};
|
||
|
||
// Enables snapping waypoints to terminals
|
||
mxEdgeHandler.prototype.snapToTerminals = true;
|
||
|
||
|
||
// 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 div for the toolbar
|
||
var tbContainer = document.createElement('div');
|
||
tbContainer.style.position = 'absolute';
|
||
tbContainer.style.overflow = 'hidden';
|
||
tbContainer.style.padding = '2px';
|
||
tbContainer.style.left = '0px';
|
||
tbContainer.style.top = '26px';
|
||
tbContainer.style.width = '24px';
|
||
tbContainer.style.bottom = '0px';
|
||
|
||
document.body.appendChild(tbContainer);
|
||
|
||
// Creates new toolbar without event processing
|
||
var toolbar = new mxToolbar(tbContainer);
|
||
toolbar.enabled = false
|
||
|
||
// Creates the div for the graph
|
||
container = document.createElement('div');
|
||
container.style.position = 'absolute';
|
||
container.style.overflow = 'hidden';
|
||
container.style.left = '24px';
|
||
container.style.top = '26px';
|
||
container.style.right = '0px';
|
||
container.style.bottom = '0px';
|
||
container.style.background = 'url("images/wires-grid.gif")';
|
||
|
||
document.body.appendChild(container);
|
||
|
||
// Workaround for Internet Explorer ignoring certain styles
|
||
if (mxClient.IS_QUIRKS)
|
||
{
|
||
document.body.style.overflow = 'hidden';
|
||
new mxDivResizer(tbContainer);
|
||
new mxDivResizer(container);
|
||
}
|
||
|
||
// Creates the model and the graph inside the container
|
||
// using the fastest rendering available on the browser
|
||
var model = new mxGraphModel();
|
||
var graph = new mxGraph(container, model);
|
||
graph.setConnectable(true);
|
||
graph.setPortsEnabled(false);
|
||
graph.setTooltips(true);
|
||
|
||
graph.view.scale = 1;
|
||
graph.setPanning(true);
|
||
// graph.setConnectable(true);
|
||
graph.setConnectableEdges(true);
|
||
graph.setDisconnectOnMove(false);
|
||
graph.foldingEnabled = false;
|
||
|
||
//Maximum size
|
||
graph.maximumGraphBounds = new mxRectangle(0, 0, 800, 600)
|
||
graph.border = 50;
|
||
|
||
// Panning handler consumed right click so this must be
|
||
// disabled if right click should stop connection handler.
|
||
graph.panningHandler.isPopupTrigger = function() { return false; };
|
||
|
||
// Enables return key to stop editing (use shift-enter for newlines)
|
||
graph.setEnterStopsCellEditing(true);
|
||
|
||
// 只显示名字,其他的value进行隐藏
|
||
// Overrides method to provide a cell label in the display
|
||
graph.convertValueToString = function(cell)
|
||
{
|
||
var Value_raw = cell.getValue();
|
||
var Value_show = '';
|
||
if (Value_raw != null){
|
||
Value_show = Value_raw.substring(0,4);
|
||
}
|
||
|
||
return Value_show;
|
||
|
||
};
|
||
// 暂时不允许在此进行修改
|
||
var cellLabelChanged = graph.cellLabelChanged;
|
||
graph.cellLabelChanged = function(cell, newValue, autoSize)
|
||
{
|
||
// if (mxUtils.isNode(cell.value))
|
||
// {
|
||
// // Clones the value for correct undo/redo
|
||
// var elt = cell.value.cloneNode(true);
|
||
// elt.setAttribute('label', newValue);
|
||
// newValue = elt;
|
||
// }
|
||
// cellLabelChanged.apply(this, arguments);
|
||
};
|
||
|
||
graph.getTooltipForCell = function(cell)
|
||
{
|
||
return 'Doubleclick and right- or shiftclick';
|
||
}
|
||
// Installs a popupmenu handler using local function (see below).
|
||
graph.popupMenuHandler.factoryMethod = function(menu, cell, evt)
|
||
{
|
||
return createPopupMenu(graph, menu, cell, evt);
|
||
};
|
||
|
||
// Stops editing on enter or escape keypress
|
||
var keyHandler = new mxKeyHandler(graph);
|
||
var rubberband = new mxRubberband(graph);
|
||
|
||
// Add Vertex
|
||
var addVertex = function(icon, w, h, style)
|
||
{
|
||
var vertex = new mxCell(null, new mxGeometry(0, 0, w, h), style);
|
||
vertex.setVertex(true);
|
||
|
||
addToolbarItem(graph, toolbar, vertex, icon);
|
||
};
|
||
var addVertex_2 = function(icon, w, h, style)
|
||
{
|
||
var vertex = new mxCell(null, new mxGeometry(0, 0, w, h), style);
|
||
vertex.setVertex(true);
|
||
vertex.setValue('Name=NMOS;Length=100nm;Width=20nm');
|
||
|
||
addToolbarItem(graph, toolbar, vertex, icon);
|
||
};
|
||
addVertex('editors/images/swimlane.gif', 120, 160, 'shape=swimlane;startSize=20;');
|
||
addVertex('editors/images/rectangle.gif', 100, 40, '');
|
||
addVertex('editors/images/rounded.gif', 100, 40, 'shape=rounded');
|
||
addVertex('editors/images/ellipse.gif', 40, 40, 'shape=ellipse');
|
||
addVertex('editors/images/rhombus.gif', 40, 40, 'shape=rhombus');
|
||
addVertex('editors/images/triangle.gif', 40, 40, 'shape=triangle');
|
||
addVertex('editors/images/cylinder.gif', 40, 40, 'shape=cylinder');
|
||
addVertex('editors/images/actor.gif', 30, 40, 'shape=actor');
|
||
addVertex('editors/images/actor.gif', 80, 30, 'shape=resistor;verticalLabelPosition=top;verticalAlign=bottom');
|
||
addVertex('editors/images/actor.gif', 60, 60, 'shape=n_mosfet;verticalLabelPosition=top;verticalAlign=bottom');
|
||
addVertex('editors/images/actor.gif', 60, 60, 'shape=p_mosfet;verticalLabelPosition=top;verticalAlign=bottom');
|
||
addVertex('editors/images/actor.gif', 30, 30, 'shape=vdd;verticalLabelPosition=top;verticalAlign=bottom');
|
||
addVertex('editors/images/actor.gif', 30, 30, 'shape=gnd;verticalLabelPosition=top;verticalAlign=bottom');
|
||
addVertex_2('editors/images/actor.gif', 60, 60, 'shape=n_mosfet;verticalLabelPosition=top;verticalAlign=bottom');
|
||
|
||
toolbar.addLine();
|
||
|
||
click_handler(graph);
|
||
ports_handler(graph);
|
||
style_handler(graph);
|
||
Clipboard_Handler(graph);
|
||
bottom_bar(graph);
|
||
|
||
// create a window
|
||
var lorem = 'Lorem ipsum dolor sit amet, consectetur adipisici elit, sed eiusmod tempor incidunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquid ex ea commodi consequat. Quis aute iure reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint obcaecat cupiditat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. ';
|
||
var content = document.createElement('div');
|
||
mxUtils.write(content, lorem);
|
||
wnd = new mxWindow('Test', content, 520, 50, 220, 200, true, true);
|
||
wnd.setMaximizable(true);
|
||
wnd.setScrollable(true);
|
||
wnd.setResizable(true);
|
||
wnd.setVisible(true);
|
||
wnd.setClosable(true);
|
||
|
||
showOutline(graph);
|
||
|
||
mxLog.show();
|
||
}
|
||
}
|
||
</script>
|
||
<script type="text/javacript">
|
||
function ParseValue(value){
|
||
|
||
};
|
||
|
||
</script>
|
||
|
||
|
||
<script type="text/javascript">
|
||
function showProperties(graph,cell)
|
||
{
|
||
|
||
cell = cell || graph.getSelectionCell();
|
||
|
||
// Uses the root node for the properties dialog
|
||
// if not cell was passed in and no cell is
|
||
// selected
|
||
if (cell == null)
|
||
{
|
||
cell = graph.getCurrentRoot();
|
||
|
||
if (cell == null)
|
||
{
|
||
cell = graph.getModel().getRoot();
|
||
}
|
||
}
|
||
|
||
if (cell != null)
|
||
{
|
||
// Makes sure there is no in-place editor in the
|
||
// graph and computes the location of the dialog
|
||
graph.stopEditing(true);
|
||
|
||
var form = new mxForm('properties');
|
||
var id = form.addText('ID', cell.getId());
|
||
id.setAttribute('readonly', 'true');
|
||
var value_cell = form.addText('value', cell.getValue());
|
||
|
||
var okFunction = mxUtils.bind(this, function(){
|
||
|
||
cell.setValue(value_cell.value);
|
||
wnd.destroy();
|
||
// cell.value = value ;
|
||
});
|
||
|
||
var cancelFunction = mxUtils.bind(this, function()
|
||
{
|
||
// Hides the dialog
|
||
wnd.destroy();
|
||
});
|
||
|
||
form.addButtons(okFunction, cancelFunction);
|
||
|
||
var wnd = new mxWindow(
|
||
'Properties',
|
||
form.table, 800, 320, 200, 150, true,true);
|
||
wnd.setMaximizable(true);
|
||
wnd.setScrollable(true);
|
||
wnd.setResizable(true);
|
||
wnd.setVisible(true);
|
||
wnd.setClosable(true);
|
||
|
||
}
|
||
};
|
||
|
||
function createProperties( graph, cell ){
|
||
|
||
|
||
};
|
||
|
||
</script>
|
||
|
||
|
||
<script type="text/javascript">
|
||
function showOutline(graph)
|
||
{
|
||
var create = true;
|
||
|
||
if (create)
|
||
{
|
||
var div = document.createElement('div');
|
||
|
||
div.style.overflow = 'hidden';
|
||
div.style.position = 'relative';
|
||
div.style.width = '100%';
|
||
div.style.height = '100%';
|
||
div.style.background = 'white';
|
||
div.style.cursor = 'move';
|
||
|
||
if (document.documentMode == 8)
|
||
{
|
||
div.style.filter = 'progid:DXImageTransform.Microsoft.alpha(opacity=100)';
|
||
}
|
||
|
||
var wnd = new mxWindow(
|
||
'Outline',
|
||
div, 1000, 20, 200, 150, false);
|
||
|
||
// Creates the outline in the specified div
|
||
// and links it to the existing graph
|
||
var outline = new mxOutline(graph, div);
|
||
wnd.setMaximizable(true);
|
||
wnd.setScrollable(true);
|
||
wnd.setVisible(true);
|
||
wnd.setClosable(true);
|
||
wnd.setResizable(true);
|
||
wnd.destroyOnClose = false;
|
||
|
||
wnd.addListener(mxEvent.RESIZE_END, function()
|
||
{
|
||
outline.update();
|
||
});
|
||
|
||
this.outline = wnd;
|
||
this.outline.outline = outline;
|
||
}
|
||
|
||
// Finally shows the outline
|
||
this.outline.setVisible(true);
|
||
this.outline.outline.update(true);
|
||
};
|
||
|
||
</script>
|
||
|
||
<script type="text/javascript">
|
||
|
||
function addToolbarItem(graph, toolbar, prototype, image)
|
||
{
|
||
// Function that is executed when the image is dropped on
|
||
// the graph. The cell argument points to the cell under
|
||
// the mousepointer if there is one.
|
||
var funct = function(graph, evt, cell)
|
||
{
|
||
graph.stopEditing(false);
|
||
|
||
var pt = graph.getPointForEvent(evt);
|
||
var vertex = graph.getModel().cloneCell(prototype);
|
||
vertex.geometry.x = pt.x;
|
||
vertex.geometry.y = pt.y;
|
||
|
||
graph.setSelectionCells(graph.importCells([vertex], 0, 0, cell));
|
||
}
|
||
|
||
// Creates the image which is used as the drag icon (preview)
|
||
var img = toolbar.addMode(null, image, funct);
|
||
mxUtils.makeDraggable(img, graph, funct);
|
||
}
|
||
|
||
</script>
|
||
|
||
|
||
<script type="text/javascript">
|
||
// Function to create the entries in the popupmenu
|
||
function createPopupMenu(graph, menu, cell, evt)
|
||
{
|
||
if (cell != null)
|
||
{
|
||
menu.addItem('Properities', 'editors/images/image.gif', function()
|
||
{
|
||
showProperties(graph,cell);
|
||
});
|
||
}
|
||
else
|
||
{
|
||
menu.addItem('No-Cell Item', 'editors/images/image.gif', function()
|
||
{
|
||
mxUtils.alert('MenuItem2');
|
||
});
|
||
}
|
||
menu.addSeparator();
|
||
menu.addItem('MenuItem3', '../src/images/warning.gif', function()
|
||
{
|
||
mxUtils.alert('MenuItem3: '+graph.getSelectionCount()+' selected');
|
||
});
|
||
};
|
||
</script>
|
||
|
||
|
||
<!-- click listener -->
|
||
<script type="text/javascript">
|
||
function click_handler(graph){
|
||
// Installs a handler for click events in the graph
|
||
// that toggles the overlay for the respective cell
|
||
graph.addListener(mxEvent.CLICK, function(sender, evt)
|
||
{
|
||
var cell = evt.getProperty('cell');
|
||
|
||
if (cell != null)
|
||
{
|
||
var overlays = graph.getCellOverlays(cell);
|
||
|
||
if (overlays == null)
|
||
{
|
||
// Creates a new overlay with an image and a tooltip
|
||
var overlay = new mxCellOverlay(
|
||
new mxImage('editors/images/overlays/check.png', 16, 16),
|
||
'Overlay tooltip');
|
||
|
||
// Installs a handler for clicks on the overlay
|
||
overlay.addListener(mxEvent.CLICK, function(sender, evt2)
|
||
{
|
||
mxUtils.alert('Overlay clicked');
|
||
});
|
||
|
||
// Sets the overlay for the cell in the graph
|
||
graph.addCellOverlay(cell, overlay);
|
||
}
|
||
else
|
||
{
|
||
graph.removeCellOverlays(cell);
|
||
}
|
||
}
|
||
});
|
||
|
||
// Installs a handler for double click events in the graph
|
||
// that shows an alert box
|
||
graph.addListener(mxEvent.DOUBLE_CLICK, function(sender, evt)
|
||
{
|
||
var cell = evt.getProperty('cell');
|
||
showProperties(graph,cell);
|
||
// var cell = evt.getProperty('cell');
|
||
// mxUtils.alert('Doubleclick: '+((cell != null) ? 'Cell' : 'Graph'));
|
||
// evt.consume();
|
||
});
|
||
}
|
||
|
||
</script>
|
||
|
||
<script type="text/javascript">
|
||
function bottom_bar(graph){
|
||
document.body.appendChild(mxUtils.button('Zoom In', function()
|
||
{
|
||
graph.zoomIn();
|
||
}));
|
||
|
||
document.body.appendChild(mxUtils.button('Zoom Out', function()
|
||
{
|
||
graph.zoomOut();
|
||
}));
|
||
|
||
document.body.appendChild(mxUtils.button('Zoom Actual', function()
|
||
{
|
||
graph.zoomActual();
|
||
}));
|
||
// Undo/redo
|
||
var undoManager = new mxUndoManager();
|
||
var listener = function(sender, evt)
|
||
{
|
||
undoManager.undoableEditHappened(evt.getProperty('edit'));
|
||
};
|
||
graph.getModel().addListener(mxEvent.UNDO, listener);
|
||
graph.getView().addListener(mxEvent.UNDO, listener);
|
||
|
||
document.body.appendChild(mxUtils.button('Undo', function()
|
||
{
|
||
undoManager.undo();
|
||
}));
|
||
|
||
document.body.appendChild(mxUtils.button('Redo', function()
|
||
{
|
||
undoManager.redo();
|
||
}));
|
||
|
||
document.body.appendChild(mxUtils.button('Delete', function()
|
||
{
|
||
graph.removeCells();
|
||
}));
|
||
document.body.appendChild(mxUtils.button('FlipH', function()
|
||
{
|
||
graph.toggleCellStyles(mxConstants.STYLE_FLIPH);
|
||
}));
|
||
|
||
document.body.appendChild(mxUtils.button('FlipV', function()
|
||
{
|
||
graph.toggleCellStyles(mxConstants.STYLE_FLIPV);
|
||
}));
|
||
document.body.appendChild(mxUtils.button('Rotate', function()
|
||
{
|
||
var cell = graph.getSelectionCell();
|
||
|
||
if (cell != null)
|
||
{
|
||
var geo = graph.getCellGeometry(cell);
|
||
|
||
if (geo != null)
|
||
{
|
||
graph.getModel().beginUpdate();
|
||
try
|
||
{
|
||
// Rotates the size and position in the geometry
|
||
geo = geo.clone();
|
||
geo.x += geo.width / 2 - geo.height / 2;
|
||
geo.y += geo.height / 2 - geo.width / 2;
|
||
var tmp = geo.width;
|
||
geo.width = geo.height;
|
||
geo.height = tmp;
|
||
graph.getModel().setGeometry(cell, geo);
|
||
|
||
// Reads the current direction and advances by 90 degrees
|
||
var state = graph.view.getState(cell);
|
||
|
||
if (state != null)
|
||
{
|
||
var dir = state.style[mxConstants.STYLE_DIRECTION] || 'east'/*default*/;
|
||
|
||
if (dir == 'east')
|
||
{
|
||
dir = 'south';
|
||
}
|
||
else if (dir == 'south')
|
||
{
|
||
dir = 'west';
|
||
}
|
||
else if (dir == 'west')
|
||
{
|
||
dir = 'north';
|
||
}
|
||
else if (dir == 'north')
|
||
{
|
||
dir = 'east';
|
||
}
|
||
|
||
graph.setCellStyles(mxConstants.STYLE_DIRECTION, dir, [cell]);
|
||
}
|
||
}
|
||
finally
|
||
{
|
||
graph.getModel().endUpdate();
|
||
}
|
||
}
|
||
}
|
||
}));
|
||
// Shows XML for debugging the actual model
|
||
document.body.appendChild(mxUtils.button('Show XML', function()
|
||
{
|
||
var encoder = new mxCodec();
|
||
var node = encoder.encode(graph.getModel());
|
||
mxUtils.popup(mxUtils.getPrettyXml(node), true);
|
||
}));
|
||
|
||
document.body.appendChild(mxUtils.button('Create toolbar entry from selection', function()
|
||
{
|
||
if (!graph.isSelectionEmpty())
|
||
{
|
||
// Creates a copy of the selection array to preserve its state
|
||
var cells = graph.getSelectionCells();
|
||
var bounds = graph.getView().getBounds(cells);
|
||
|
||
// Function that is executed when the image is dropped on
|
||
// the graph. The cell argument points to the cell under
|
||
// the mousepointer if there is one.
|
||
var funct = function(graph, evt, cell)
|
||
{
|
||
graph.stopEditing(false);
|
||
|
||
var pt = graph.getPointForEvent(evt);
|
||
var dx = pt.x - bounds.x;
|
||
var dy = pt.y - bounds.y;
|
||
|
||
graph.setSelectionCells(graph.importCells(cells, dx, dy, cell));
|
||
}
|
||
|
||
// Creates the image which is used as the drag icon (preview)
|
||
var img = toolbar.addMode(null, 'editors/images/outline.gif', funct);
|
||
mxUtils.makeDraggable(img, graph, funct);
|
||
}
|
||
}));
|
||
|
||
// Wire-mode
|
||
var checkbox = document.createElement('input');
|
||
checkbox.setAttribute('type', 'checkbox');
|
||
|
||
document.body.appendChild(checkbox);
|
||
mxUtils.write(document.body, 'Wire Mode');
|
||
|
||
// Starts connections on the background in wire-mode
|
||
var connectionHandlerIsStartEvent = graph.connectionHandler.isStartEvent;
|
||
graph.connectionHandler.isStartEvent = function(me)
|
||
{
|
||
return checkbox.checked || connectionHandlerIsStartEvent.apply(this, arguments);
|
||
};
|
||
|
||
// Avoids any connections for gestures within tolerance except when in wire-mode
|
||
// or when over a port
|
||
var connectionHandlerMouseUp = graph.connectionHandler.mouseUp;
|
||
graph.connectionHandler.mouseUp = function(sender, me)
|
||
{
|
||
if (this.first != null && this.previous != null)
|
||
{
|
||
var point = mxUtils.convertPoint(graph.container, me.getX(), me.getY());
|
||
var dx = Math.abs(point.x - this.first.x);
|
||
var dy = Math.abs(point.y - this.first.y);
|
||
|
||
if (dx < graph.tolerance && dy < graph.tolerance)
|
||
{
|
||
// Selects edges in non-wire mode for single clicks, but starts
|
||
// connecting for non-edges regardless of wire-mode
|
||
if (!checkbox.checked && graph.getModel().isEdge(this.previous.cell))
|
||
{
|
||
this.reset();
|
||
}
|
||
|
||
return;
|
||
}
|
||
}
|
||
|
||
connectionHandlerMouseUp.apply(this, arguments);
|
||
};
|
||
|
||
// Grid
|
||
var checkbox2 = document.createElement('input');
|
||
checkbox2.setAttribute('type', 'checkbox');
|
||
checkbox2.setAttribute('checked', 'true');
|
||
|
||
document.body.appendChild(checkbox2);
|
||
mxUtils.write(document.body, 'Grid');
|
||
|
||
mxEvent.addListener(checkbox2, 'click', function(evt)
|
||
{
|
||
if (checkbox2.checked)
|
||
{
|
||
container.style.background = 'url(\'images/wires-grid.gif\')';
|
||
}
|
||
else
|
||
{
|
||
container.style.background = '';
|
||
}
|
||
|
||
container.style.backgroundColor = (invert) ? 'black' : 'white';
|
||
});
|
||
|
||
mxEvent.disableContextMenu(container);
|
||
};
|
||
|
||
</script>
|
||
|
||
|
||
<script type="text/javascript">
|
||
function style_handler(graph){
|
||
|
||
// Switch for black background and bright styles
|
||
var invert = false;
|
||
|
||
if (invert)
|
||
{
|
||
container.style.backgroundColor = 'black';
|
||
|
||
// White in-place editor text color
|
||
mxCellEditorStartEditing = mxCellEditor.prototype.startEditing;
|
||
mxCellEditor.prototype.startEditing = function (cell, trigger)
|
||
{
|
||
mxCellEditorStartEditing.apply(this, arguments);
|
||
|
||
if (this.textarea != null)
|
||
{
|
||
this.textarea.style.color = '#FFFFFF';
|
||
}
|
||
};
|
||
|
||
mxGraphHandler.prototype.previewColor = 'white';
|
||
}
|
||
var joinNodeSize = 7;
|
||
var strokeWidth = 2;
|
||
var labelBackground = (invert) ? '#000000' : '#FFFFFF';
|
||
var fontColor = (invert) ? '#FFFFFF' : '#000000';
|
||
var strokeColor = (invert) ? '#C0C0C0' : '#000000';
|
||
var fillColor = (invert) ? 'none' : '#FFFFFF';
|
||
|
||
var style = graph.getStylesheet().getDefaultEdgeStyle();
|
||
delete style['endArrow'];
|
||
style['strokeColor'] = strokeColor;
|
||
style['labelBackgroundColor'] = labelBackground;
|
||
style['edgeStyle'] = 'wireEdgeStyle';
|
||
style['fontColor'] = fontColor;
|
||
style['fontSize'] = '9';
|
||
style['movable'] = '0';
|
||
style['strokeWidth'] = strokeWidth;
|
||
//style['rounded'] = '1';
|
||
|
||
// Sets join node size
|
||
style['startSize'] = joinNodeSize;
|
||
style['endSize'] = joinNodeSize;
|
||
|
||
style = graph.getStylesheet().getDefaultVertexStyle();
|
||
style['gradientDirection'] = 'south';
|
||
//style['gradientColor'] = '#909090';
|
||
style['strokeColor'] = strokeColor;
|
||
//style['fillColor'] = '#e0e0e0';
|
||
style['fillColor'] = 'none';
|
||
style['fontColor'] = fontColor;
|
||
style['fontStyle'] = '1';
|
||
style['fontSize'] = '12';
|
||
style['resizable'] = '0';
|
||
style['rounded'] = '1';
|
||
style['strokeWidth'] = strokeWidth;
|
||
|
||
|
||
}
|
||
</script>
|
||
|
||
|
||
<script type="text/javascript">
|
||
// Computes the position of edge to edge connection points.
|
||
mxGraphView.prototype.updateFixedTerminalPoint = function(edge, terminal, source, constraint)
|
||
{
|
||
var pt = null;
|
||
|
||
if (constraint != null)
|
||
{
|
||
pt = this.graph.getConnectionPoint(terminal, constraint);
|
||
}
|
||
|
||
if (source)
|
||
{
|
||
edge.sourceSegment = null;
|
||
}
|
||
else
|
||
{
|
||
edge.targetSegment = null;
|
||
}
|
||
|
||
if (pt == null)
|
||
{
|
||
var s = this.scale;
|
||
var tr = this.translate;
|
||
var orig = edge.origin;
|
||
var geo = this.graph.getCellGeometry(edge.cell);
|
||
pt = geo.getTerminalPoint(source);
|
||
|
||
// Computes edge-to-edge connection point
|
||
if (pt != null)
|
||
{
|
||
pt = new mxPoint(s * (tr.x + pt.x + orig.x),
|
||
s * (tr.y + pt.y + orig.y));
|
||
|
||
// Finds nearest segment on edge and computes intersection
|
||
if (terminal != null && terminal.absolutePoints != null)
|
||
{
|
||
var seg = mxUtils.findNearestSegment(terminal, pt.x, pt.y);
|
||
|
||
// Finds orientation of the segment
|
||
var p0 = terminal.absolutePoints[seg];
|
||
var pe = terminal.absolutePoints[seg + 1];
|
||
var horizontal = (p0.x - pe.x == 0);
|
||
|
||
// Stores the segment in the edge state
|
||
var key = (source) ? 'sourceConstraint' : 'targetConstraint';
|
||
var value = (horizontal) ? 'horizontal' : 'vertical';
|
||
edge.style[key] = value;
|
||
|
||
// Keeps the coordinate within the segment bounds
|
||
if (horizontal)
|
||
{
|
||
pt.x = p0.x;
|
||
pt.y = Math.min(pt.y, Math.max(p0.y, pe.y));
|
||
pt.y = Math.max(pt.y, Math.min(p0.y, pe.y));
|
||
}
|
||
else
|
||
{
|
||
pt.y = p0.y;
|
||
pt.x = Math.min(pt.x, Math.max(p0.x, pe.x));
|
||
pt.x = Math.max(pt.x, Math.min(p0.x, pe.x));
|
||
}
|
||
}
|
||
}
|
||
// Computes constraint connection points on vertices and ports
|
||
else if (terminal != null && terminal.cell.geometry.relative)
|
||
{
|
||
pt = new mxPoint(this.getRoutingCenterX(terminal),
|
||
this.getRoutingCenterY(terminal));
|
||
}
|
||
|
||
// Snaps point to grid
|
||
/*if (pt != null)
|
||
{
|
||
var tr = this.graph.view.translate;
|
||
var s = this.graph.view.scale;
|
||
|
||
pt.x = (this.graph.snap(pt.x / s - tr.x) + tr.x) * s;
|
||
pt.y = (this.graph.snap(pt.y / s - tr.y) + tr.y) * s;
|
||
}*/
|
||
}
|
||
|
||
edge.setAbsoluteTerminalPoint(pt, source);
|
||
};
|
||
</script>
|
||
<!--
|
||
Overrides methods to preview and create new edges.
|
||
-->
|
||
<script type="text/javascript">
|
||
// Sets source terminal point for edge-to-edge connections.
|
||
mxConnectionHandler.prototype.createEdgeState = function(me)
|
||
{
|
||
var edge = this.graph.createEdge();
|
||
|
||
if (this.sourceConstraint != null && this.previous != null)
|
||
{
|
||
edge.style = mxConstants.STYLE_EXIT_X+'='+this.sourceConstraint.point.x+';'+
|
||
mxConstants.STYLE_EXIT_Y+'='+this.sourceConstraint.point.y+';';
|
||
}
|
||
else if (this.graph.model.isEdge(me.getCell()))
|
||
{
|
||
var scale = this.graph.view.scale;
|
||
var tr = this.graph.view.translate;
|
||
var pt = new mxPoint(this.graph.snap(me.getGraphX() / scale) - tr.x,
|
||
this.graph.snap(me.getGraphY() / scale) - tr.y);
|
||
edge.geometry.setTerminalPoint(pt, true);
|
||
}
|
||
|
||
return this.graph.view.createState(edge);
|
||
};
|
||
|
||
// Uses right mouse button to create edges on background (see also: lines 67 ff)
|
||
mxConnectionHandler.prototype.isStopEvent = function(me)
|
||
{
|
||
return me.getState() != null || mxEvent.isRightMouseButton(me.getEvent());
|
||
};
|
||
|
||
// Updates target terminal point for edge-to-edge connections.
|
||
mxConnectionHandlerUpdateCurrentState = mxConnectionHandler.prototype.updateCurrentState;
|
||
mxConnectionHandler.prototype.updateCurrentState = function(me)
|
||
{
|
||
mxConnectionHandlerUpdateCurrentState.apply(this, arguments);
|
||
|
||
if (this.edgeState != null)
|
||
{
|
||
this.edgeState.cell.geometry.setTerminalPoint(null, false);
|
||
|
||
if (this.shape != null && this.currentState != null &&
|
||
this.currentState.view.graph.model.isEdge(this.currentState.cell))
|
||
{
|
||
var scale = this.graph.view.scale;
|
||
var tr = this.graph.view.translate;
|
||
var pt = new mxPoint(this.graph.snap(me.getGraphX() / scale) - tr.x,
|
||
this.graph.snap(me.getGraphY() / scale) - tr.y);
|
||
this.edgeState.cell.geometry.setTerminalPoint(pt, false);
|
||
}
|
||
}
|
||
};
|
||
|
||
// Updates the terminal and control points in the cloned preview.
|
||
mxEdgeSegmentHandler.prototype.clonePreviewState = function(point, terminal)
|
||
{
|
||
var clone = mxEdgeHandler.prototype.clonePreviewState.apply(this, arguments);
|
||
clone.cell = clone.cell.clone();
|
||
|
||
if (this.isSource || this.isTarget)
|
||
{
|
||
clone.cell.geometry = clone.cell.geometry.clone();
|
||
|
||
// Sets the terminal point of an edge if we're moving one of the endpoints
|
||
if (this.graph.getModel().isEdge(clone.cell))
|
||
{
|
||
// TODO: Only set this if the target or source terminal is an edge
|
||
clone.cell.geometry.setTerminalPoint(point, this.isSource);
|
||
}
|
||
else
|
||
{
|
||
clone.cell.geometry.setTerminalPoint(null, this.isSource);
|
||
}
|
||
}
|
||
|
||
return clone;
|
||
};
|
||
|
||
var mxEdgeHandlerConnect = mxEdgeHandler.prototype.connect;
|
||
mxEdgeHandler.prototype.connect = function(edge, terminal, isSource, isClone, me)
|
||
{
|
||
var result = null;
|
||
var model = this.graph.getModel();
|
||
var parent = model.getParent(edge);
|
||
|
||
model.beginUpdate();
|
||
try
|
||
{
|
||
result = mxEdgeHandlerConnect.apply(this, arguments);
|
||
var geo = model.getGeometry(result);
|
||
|
||
if (geo != null)
|
||
{
|
||
geo = geo.clone();
|
||
var pt = null;
|
||
|
||
if (model.isEdge(terminal))
|
||
{
|
||
pt = this.abspoints[(this.isSource) ? 0 : this.abspoints.length - 1];
|
||
pt.x = pt.x / this.graph.view.scale - this.graph.view.translate.x;
|
||
pt.y = pt.y / this.graph.view.scale - this.graph.view.translate.y;
|
||
|
||
var pstate = this.graph.getView().getState(
|
||
this.graph.getModel().getParent(edge));
|
||
|
||
if (pstate != null)
|
||
{
|
||
pt.x -= pstate.origin.x;
|
||
pt.y -= pstate.origin.y;
|
||
}
|
||
|
||
pt.x -= this.graph.panDx / this.graph.view.scale;
|
||
pt.y -= this.graph.panDy / this.graph.view.scale;
|
||
}
|
||
|
||
geo.setTerminalPoint(pt, isSource);
|
||
model.setGeometry(edge, geo);
|
||
}
|
||
}
|
||
finally
|
||
{
|
||
model.endUpdate();
|
||
}
|
||
|
||
return result;
|
||
};
|
||
</script>
|
||
<!--
|
||
Adds in-place highlighting for complete cell area (no hotspot).
|
||
-->
|
||
<script type="text/javascript">
|
||
mxConnectionHandlerCreateMarker = mxConnectionHandler.prototype.createMarker;
|
||
mxConnectionHandler.prototype.createMarker = function()
|
||
{
|
||
var marker = mxConnectionHandlerCreateMarker.apply(this, arguments);
|
||
|
||
// Uses complete area of cell for new connections (no hotspot)
|
||
marker.intersects = function(state, evt)
|
||
{
|
||
return true;
|
||
};
|
||
|
||
// Adds in-place highlighting
|
||
mxCellHighlightHighlight = mxCellHighlight.prototype.highlight;
|
||
marker.highlight.highlight = function(state)
|
||
{
|
||
if (this.state != state)
|
||
{
|
||
if (this.state != null)
|
||
{
|
||
this.state.style = this.lastStyle;
|
||
|
||
// Workaround for shape using current stroke width if no strokewidth defined
|
||
this.state.style['strokeWidth'] = this.state.style['strokeWidth'] || '1';
|
||
this.state.style['strokeColor'] = this.state.style['strokeColor'] || 'none';
|
||
|
||
if (this.state.shape != null)
|
||
{
|
||
this.state.view.graph.cellRenderer.configureShape(this.state);
|
||
this.state.shape.redraw();
|
||
}
|
||
}
|
||
|
||
if (state != null)
|
||
{
|
||
this.lastStyle = state.style;
|
||
state.style = mxUtils.clone(state.style);
|
||
state.style['strokeColor'] = '#00ff00';
|
||
state.style['strokeWidth'] = '3';
|
||
|
||
if (state.shape != null)
|
||
{
|
||
state.view.graph.cellRenderer.configureShape(state);
|
||
state.shape.redraw();
|
||
}
|
||
}
|
||
|
||
this.state = state;
|
||
}
|
||
};
|
||
|
||
return marker;
|
||
};
|
||
|
||
mxEdgeHandlerCreateMarker = mxEdgeHandler.prototype.createMarker;
|
||
mxEdgeHandler.prototype.createMarker = function()
|
||
{
|
||
var marker = mxEdgeHandlerCreateMarker.apply(this, arguments);
|
||
|
||
// Adds in-place highlighting when reconnecting existing edges
|
||
marker.highlight.highlight = this.graph.connectionHandler.marker.highlight.highlight;
|
||
|
||
return marker;
|
||
}
|
||
</script>
|
||
<!--
|
||
Adds oval markers for edge-to-edge connections.
|
||
-->
|
||
<script type="text/javascript">
|
||
mxGraphGetCellStyle = mxGraph.prototype.getCellStyle;
|
||
mxGraph.prototype.getCellStyle = function(cell)
|
||
{
|
||
var style = mxGraphGetCellStyle.apply(this, arguments);
|
||
|
||
if (style != null && this.model.isEdge(cell))
|
||
{
|
||
style = mxUtils.clone(style);
|
||
|
||
if (this.model.isEdge(this.model.getTerminal(cell, true)))
|
||
{
|
||
style['startArrow'] = 'oval';
|
||
}
|
||
|
||
if (this.model.isEdge(this.model.getTerminal(cell, false)))
|
||
{
|
||
style['endArrow'] = 'oval';
|
||
}
|
||
}
|
||
|
||
return style;
|
||
};
|
||
</script>
|
||
|
||
<script type="text/javascript">
|
||
function ports_handler(graph){
|
||
// 禁止拖拽连线
|
||
// Disables floating connections (only connections via ports allowed)
|
||
// graph.connectionHandler.isConnectableCell = function(cell)
|
||
// {
|
||
// return false;
|
||
// };
|
||
// mxEdgeHandler.prototype.isConnectableCell = function(cell)
|
||
// {
|
||
// return graph.connectionHandler.isConnectableCell(cell);
|
||
// };
|
||
// Disables existing port functionality
|
||
graph.view.getTerminalPort = function(state, terminal, source)
|
||
{
|
||
return terminal;
|
||
};
|
||
// Returns all possible ports for a given terminal
|
||
graph.getAllConnectionConstraints = function(terminal, source)
|
||
{
|
||
if (terminal != null && terminal.shape != null &&
|
||
terminal.shape.stencil != null)
|
||
{
|
||
// for stencils with existing constraints...
|
||
if (terminal.shape.stencil != null)
|
||
{
|
||
return terminal.shape.stencil.constraints;
|
||
}
|
||
}
|
||
else if (terminal != null && this.model.isVertex(terminal.cell))
|
||
{
|
||
if (terminal.shape != null)
|
||
{
|
||
var ports = terminal.shape.getPorts();
|
||
var cstrs = new Array();
|
||
|
||
for (var id in ports)
|
||
{
|
||
var port = ports[id];
|
||
|
||
var cstr = new mxConnectionConstraint(new mxPoint(port.x, port.y), port.perimeter);
|
||
cstr.id = id;
|
||
cstrs.push(cstr);
|
||
}
|
||
|
||
return cstrs;
|
||
}
|
||
}
|
||
|
||
return null;
|
||
};
|
||
|
||
// Makes sure non-relative cells can only be connected via constraints
|
||
graph.connectionHandler.isConnectableCell = function(cell)
|
||
{
|
||
if (this.graph.getModel().isEdge(cell))
|
||
{
|
||
return true;
|
||
}
|
||
else
|
||
{
|
||
var geo = (cell != null) ? this.graph.getCellGeometry(cell) : null;
|
||
|
||
return (geo != null) ? geo.relative : false;
|
||
}
|
||
};
|
||
mxEdgeHandler.prototype.isConnectableCell = function(cell)
|
||
{
|
||
return graph.connectionHandler.isConnectableCell(cell);
|
||
};
|
||
|
||
// Sets the port for the given connection
|
||
graph.setConnectionConstraint = function(edge, terminal, source, constraint)
|
||
{
|
||
if (constraint != null)
|
||
{
|
||
var key = (source) ? mxConstants.STYLE_SOURCE_PORT : mxConstants.STYLE_TARGET_PORT;
|
||
|
||
if (constraint == null || constraint.id == null)
|
||
{
|
||
this.setCellStyles(key, null, [edge]);
|
||
}
|
||
else if (constraint.id != null)
|
||
{
|
||
this.setCellStyles(key, constraint.id, [edge]);
|
||
}
|
||
}
|
||
};
|
||
|
||
// Returns the port for the given connection
|
||
graph.getConnectionConstraint = function(edge, terminal, source)
|
||
{
|
||
var key = (source) ? mxConstants.STYLE_SOURCE_PORT : mxConstants.STYLE_TARGET_PORT;
|
||
var id = edge.style[key];
|
||
|
||
if (id != null)
|
||
{
|
||
var c = new mxConnectionConstraint(null, null);
|
||
c.id = id;
|
||
|
||
return c;
|
||
}
|
||
|
||
return null;
|
||
};
|
||
|
||
// Returns the actual point for a port by redirecting the constraint to the port
|
||
graphGetConnectionPoint = graph.getConnectionPoint;
|
||
graph.getConnectionPoint = function(vertex, constraint)
|
||
{
|
||
if (constraint.id != null && vertex != null && vertex.shape != null)
|
||
{
|
||
var port = vertex.shape.getPorts()[constraint.id];
|
||
|
||
if (port != null)
|
||
{
|
||
constraint = new mxConnectionConstraint(new mxPoint(port.x, port.y), port.perimeter);
|
||
}
|
||
}
|
||
|
||
return graphGetConnectionPoint.apply(this, arguments);
|
||
};
|
||
|
||
}
|
||
|
||
</script>
|
||
|
||
|
||
|
||
<!-- 复制粘贴剪切 -->
|
||
<script type="text/javascript">
|
||
function Clipboard_Handler(graph){
|
||
// Public helper method for shared clipboard.
|
||
mxClipboard.cellsToString = function(cells)
|
||
{
|
||
var codec = new mxCodec();
|
||
var model = new mxGraphModel();
|
||
var parent = model.getChildAt(model.getRoot(), 0);
|
||
|
||
for (var i = 0; i < cells.length; i++)
|
||
{
|
||
model.add(parent, cells[i]);
|
||
}
|
||
|
||
return mxUtils.getXml(codec.encode(model));
|
||
};
|
||
|
||
// Focused but invisible textarea during control or meta key events
|
||
var textInput = document.createElement('textarea');
|
||
mxUtils.setOpacity(textInput, 0);
|
||
textInput.style.width = '1px';
|
||
textInput.style.height = '1px';
|
||
var restoreFocus = false;
|
||
var gs = graph.gridSize;
|
||
var lastPaste = null;
|
||
var dx = 0;
|
||
var dy = 0;
|
||
|
||
// Workaround for no copy event in IE/FF if empty
|
||
textInput.value = ' ';
|
||
|
||
// Shows a textare when control/cmd is pressed to handle native clipboard actions
|
||
mxEvent.addListener(document, 'keydown', function(evt)
|
||
{
|
||
// No dialog visible
|
||
var source = mxEvent.getSource(evt);
|
||
|
||
if (graph.isEnabled() && !graph.isMouseDown && !graph.isEditing() && source.nodeName != 'INPUT')
|
||
{
|
||
if (evt.keyCode == 224 /* FF */ || (!mxClient.IS_MAC && evt.keyCode == 17 /* Control */) ||
|
||
(mxClient.IS_MAC && (evt.keyCode == 91 || evt.keyCode == 93) /* Left/Right Meta */))
|
||
{
|
||
// Cannot use parentNode for check in IE
|
||
if (!restoreFocus)
|
||
{
|
||
// Avoid autoscroll but allow handling of events
|
||
textInput.style.position = 'absolute';
|
||
textInput.style.left = (graph.container.scrollLeft + 10) + 'px';
|
||
textInput.style.top = (graph.container.scrollTop + 10) + 'px';
|
||
graph.container.appendChild(textInput);
|
||
|
||
restoreFocus = true;
|
||
textInput.focus();
|
||
textInput.select();
|
||
}
|
||
}
|
||
}
|
||
});
|
||
|
||
// Restores focus on graph container and removes text input from DOM
|
||
mxEvent.addListener(document, 'keyup', function(evt)
|
||
{
|
||
if (restoreFocus && (evt.keyCode == 224 /* FF */ || evt.keyCode == 17 /* Control */ ||
|
||
evt.keyCode == 91 || evt.keyCode == 93 /* Meta */))
|
||
{
|
||
restoreFocus = false;
|
||
|
||
if (!graph.isEditing())
|
||
{
|
||
graph.container.focus();
|
||
}
|
||
|
||
textInput.parentNode.removeChild(textInput);
|
||
}
|
||
});
|
||
|
||
// Inserts the XML for the given cells into the text input for copy
|
||
var copyCells = function(graph, cells)
|
||
{
|
||
if (cells.length > 0)
|
||
{
|
||
var clones = graph.cloneCells(cells);
|
||
|
||
// Checks for orphaned relative children and makes absolute
|
||
for (var i = 0; i < clones.length; i++)
|
||
{
|
||
var state = graph.view.getState(cells[i]);
|
||
|
||
if (state != null)
|
||
{
|
||
var geo = graph.getCellGeometry(clones[i]);
|
||
|
||
if (geo != null && geo.relative)
|
||
{
|
||
geo.relative = false;
|
||
geo.x = state.x / state.view.scale - state.view.translate.x;
|
||
geo.y = state.y / state.view.scale - state.view.translate.y;
|
||
}
|
||
}
|
||
}
|
||
|
||
textInput.value = mxClipboard.cellsToString(clones);
|
||
}
|
||
|
||
textInput.select();
|
||
lastPaste = textInput.value;
|
||
};
|
||
|
||
// // Deletes the XML for the given cells
|
||
// var deleteCells = function(graph, cells)
|
||
// {
|
||
// if (cells.length > 0)
|
||
// {
|
||
// var clones = graph.cloneCells(cells);
|
||
|
||
// // Checks for orphaned relative children and makes absolute
|
||
// for (var i = 0; i < clones.length; i++)
|
||
// {
|
||
// var state = graph.view.getState(cells[i]);
|
||
|
||
// if (state != null)
|
||
// {
|
||
// var geo = graph.getCellGeometry(clones[i]);
|
||
|
||
// if (geo != null && geo.relative)
|
||
// {
|
||
// geo.relative = false;
|
||
// geo.x = state.x / state.view.scale - state.view.translate.x;
|
||
// geo.y = state.y / state.view.scale - state.view.translate.y;
|
||
// }
|
||
// }
|
||
// }
|
||
// textInput.value = mxClipboard.cellsToString(clones);
|
||
// }
|
||
// textInput.select();
|
||
// lastPaste = textInput.value;
|
||
// };
|
||
|
||
// Handles copy event by putting XML for current selection into text input
|
||
mxEvent.addListener(textInput, 'copy', mxUtils.bind(this, function(evt)
|
||
{
|
||
if (graph.isEnabled() && !graph.isSelectionEmpty())
|
||
{
|
||
copyCells(graph, mxUtils.sortCells(graph.model.getTopmostCells(graph.getSelectionCells())));
|
||
dx = 0;
|
||
dy = 0;
|
||
}
|
||
}));
|
||
|
||
// Handles cut event by removing cells putting XML into text input
|
||
mxEvent.addListener(textInput, 'cut', mxUtils.bind(this, function(evt)
|
||
{
|
||
if (graph.isEnabled() && !graph.isSelectionEmpty())
|
||
{
|
||
copyCells(graph, graph.removeCells());
|
||
dx = -gs;
|
||
dy = -gs;
|
||
}
|
||
}));
|
||
|
||
// // Handles cut event by removing cells putting XML into text input
|
||
// mxEvent.addListener(textInput, 'delete', mxUtils.bind(this, function(evt)
|
||
// {
|
||
// if (graph.isEnabled() && !graph.isSelectionEmpty())
|
||
// {
|
||
// deleteCells(graph, graph.removeCells());
|
||
// }
|
||
// }));
|
||
|
||
// Merges XML into existing graph and layers
|
||
var importXml = function(xml, dx, dy)
|
||
{
|
||
dx = (dx != null) ? dx : 0;
|
||
dy = (dy != null) ? dy : 0;
|
||
var cells = []
|
||
|
||
try
|
||
{
|
||
var doc = mxUtils.parseXml(xml);
|
||
var node = doc.documentElement;
|
||
|
||
if (node != null)
|
||
{
|
||
var model = new mxGraphModel();
|
||
var codec = new mxCodec(node.ownerDocument);
|
||
codec.decode(node, model);
|
||
|
||
var childCount = model.getChildCount(model.getRoot());
|
||
var targetChildCount = graph.model.getChildCount(graph.model.getRoot());
|
||
|
||
// Merges existing layers and adds new layers
|
||
graph.model.beginUpdate();
|
||
try
|
||
{
|
||
for (var i = 0; i < childCount; i++)
|
||
{
|
||
var parent = model.getChildAt(model.getRoot(), i);
|
||
|
||
// Adds cells to existing layers if not locked
|
||
if (targetChildCount > i)
|
||
{
|
||
// Inserts into active layer if only one layer is being pasted
|
||
var target = (childCount == 1) ? graph.getDefaultParent() : graph.model.getChildAt(graph.model.getRoot(), i);
|
||
|
||
if (!graph.isCellLocked(target))
|
||
{
|
||
var children = model.getChildren(parent);
|
||
cells = cells.concat(graph.importCells(children, dx, dy, target));
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// Delta is non cascading, needs separate move for layers
|
||
parent = graph.importCells([parent], 0, 0, graph.model.getRoot())[0];
|
||
var children = graph.model.getChildren(parent);
|
||
graph.moveCells(children, dx, dy);
|
||
cells = cells.concat(children);
|
||
}
|
||
}
|
||
}
|
||
finally
|
||
{
|
||
graph.model.endUpdate();
|
||
}
|
||
}
|
||
}
|
||
catch (e)
|
||
{
|
||
alert(e);
|
||
throw e;
|
||
}
|
||
|
||
return cells;
|
||
};
|
||
|
||
// Parses and inserts XML into graph
|
||
var pasteText = function(text)
|
||
{
|
||
var xml = mxUtils.trim(text);
|
||
var x = graph.container.scrollLeft / graph.view.scale - graph.view.translate.x;
|
||
var y = graph.container.scrollTop / graph.view.scale - graph.view.translate.y;
|
||
|
||
if (xml.length > 0)
|
||
{
|
||
if (lastPaste != xml)
|
||
{
|
||
lastPaste = xml;
|
||
dx = 0;
|
||
dy = 0;
|
||
}
|
||
else
|
||
{
|
||
dx += gs;
|
||
dy += gs;
|
||
}
|
||
|
||
// Standard paste via control-v
|
||
if (xml.substring(0, 14) == '<mxGraphModel>')
|
||
{
|
||
graph.setSelectionCells(importXml(xml, dx, dy));
|
||
graph.scrollCellToVisible(graph.getSelectionCell());
|
||
}
|
||
}
|
||
};
|
||
|
||
// Cross-browser function to fetch text from paste events
|
||
var extractGraphModelFromEvent = function(evt)
|
||
{
|
||
var data = null;
|
||
|
||
if (evt != null)
|
||
{
|
||
var provider = (evt.dataTransfer != null) ? evt.dataTransfer : evt.clipboardData;
|
||
|
||
if (provider != null)
|
||
{
|
||
if (document.documentMode == 10 || document.documentMode == 11)
|
||
{
|
||
data = provider.getData('Text');
|
||
}
|
||
else
|
||
{
|
||
data = (mxUtils.indexOf(provider.types, 'text/html') >= 0) ? provider.getData('text/html') : null;
|
||
|
||
if (mxUtils.indexOf(provider.types, 'text/plain' && (data == null || data.length == 0)))
|
||
{
|
||
data = provider.getData('text/plain');
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return data;
|
||
};
|
||
|
||
|
||
|
||
// Handles paste event by parsing and inserting XML
|
||
mxEvent.addListener(textInput, 'paste', function(evt)
|
||
{
|
||
// Clears existing contents before paste - should not be needed
|
||
// because all text is selected, but doesn't hurt since the
|
||
// actual pasting of the new text is delayed in all cases.
|
||
textInput.value = '';
|
||
|
||
if (graph.isEnabled())
|
||
{
|
||
var xml = extractGraphModelFromEvent(evt);
|
||
|
||
if (xml != null && xml.length > 0)
|
||
{
|
||
pasteText(xml);
|
||
}
|
||
else
|
||
{
|
||
// Timeout for new value to appear
|
||
window.setTimeout(mxUtils.bind(this, function()
|
||
{
|
||
pasteText(textInput.value);
|
||
}), 0);
|
||
}
|
||
}
|
||
|
||
textInput.select();
|
||
});
|
||
}
|
||
|
||
</script>
|
||
|
||
|
||
|
||
|
||
<script type="text/javascript">
|
||
mxEdgeStyle.WireConnector = function(state, source, target, hints, result)
|
||
{
|
||
// Creates array of all way- and terminalpoints
|
||
var pts = state.absolutePoints;
|
||
var horizontal = true;
|
||
var hint = null;
|
||
|
||
// Gets the initial connection from the source terminal or edge
|
||
if (source != null && state.view.graph.model.isEdge(source.cell))
|
||
{
|
||
horizontal = state.style['sourceConstraint'] == 'horizontal';
|
||
}
|
||
else if (source != null)
|
||
{
|
||
horizontal = source.style['portConstraint'] != 'vertical';
|
||
|
||
// Checks the direction of the shape and rotates
|
||
var direction = source.style[mxConstants.STYLE_DIRECTION];
|
||
|
||
if (direction == 'north' || direction == 'south')
|
||
{
|
||
horizontal = !horizontal;
|
||
}
|
||
}
|
||
|
||
// Adds the first point
|
||
// TODO: Should move along connected segment
|
||
var pt = pts[0];
|
||
|
||
if (pt == null && source != null)
|
||
{
|
||
pt = new mxPoint(state.view.getRoutingCenterX(source), state.view.getRoutingCenterY(source));
|
||
}
|
||
else if (pt != null)
|
||
{
|
||
pt = pt.clone();
|
||
}
|
||
|
||
var first = pt;
|
||
|
||
// Adds the waypoints
|
||
if (hints != null && hints.length > 0)
|
||
{
|
||
// FIXME: First segment not movable
|
||
/*hint = state.view.transformControlPoint(state, hints[0]);
|
||
mxLog.show();
|
||
mxLog.debug(hints.length,'hints0.y='+hint.y, pt.y)
|
||
|
||
if (horizontal && Math.floor(hint.y) != Math.floor(pt.y))
|
||
{
|
||
mxLog.show();
|
||
mxLog.debug('add waypoint');
|
||
|
||
pt = new mxPoint(pt.x, hint.y);
|
||
result.push(pt);
|
||
pt = pt.clone();
|
||
//horizontal = !horizontal;
|
||
}*/
|
||
|
||
for (var i = 0; i < hints.length; i++)
|
||
{
|
||
horizontal = !horizontal;
|
||
hint = state.view.transformControlPoint(state, hints[i]);
|
||
|
||
if (horizontal)
|
||
{
|
||
if (pt.y != hint.y)
|
||
{
|
||
pt.y = hint.y;
|
||
result.push(pt.clone());
|
||
}
|
||
}
|
||
else if (pt.x != hint.x)
|
||
{
|
||
pt.x = hint.x;
|
||
result.push(pt.clone());
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
hint = pt;
|
||
}
|
||
|
||
// Adds the last point
|
||
pt = pts[pts.length - 1];
|
||
|
||
// TODO: Should move along connected segment
|
||
if (pt == null && target != null)
|
||
{
|
||
pt = new mxPoint(state.view.getRoutingCenterX(target), state.view.getRoutingCenterY(target));
|
||
}
|
||
|
||
if (horizontal)
|
||
{
|
||
if (pt.y != hint.y && first.x != pt.x)
|
||
{
|
||
result.push(new mxPoint(pt.x, hint.y));
|
||
}
|
||
}
|
||
else if (pt.x != hint.x && first.y != pt.y)
|
||
{
|
||
result.push(new mxPoint(hint.x, pt.y));
|
||
}
|
||
};
|
||
|
||
mxStyleRegistry.putValue('wireEdgeStyle', mxEdgeStyle.WireConnector);
|
||
|
||
// This connector needs an mxEdgeSegmentHandler
|
||
mxGraphCreateHandler = mxGraph.prototype.createHandler;
|
||
mxGraph.prototype.createHandler = function(state)
|
||
{
|
||
var result = null;
|
||
|
||
if (state != null)
|
||
{
|
||
if (this.model.isEdge(state.cell))
|
||
{
|
||
var style = this.view.getEdgeStyle(state);
|
||
|
||
if (style == mxEdgeStyle.WireConnector)
|
||
{
|
||
return new mxEdgeSegmentHandler(state);
|
||
}
|
||
}
|
||
}
|
||
|
||
return mxGraphCreateHandler.apply(this, arguments);
|
||
};
|
||
</script>
|
||
|
||
<!-- 注册元件属性 -->
|
||
<!-- <script type="text/javascript">
|
||
// Note that these XML nodes will be enclosing the
|
||
// mxCell nodes for the model cells in the output
|
||
var doc = mxUtils.createXmlDocument();
|
||
|
||
var N_Mosfet = doc.createElement('N_Mos');
|
||
// N_Mosfet.prototype.vertex = ;
|
||
|
||
N_Mosfet.setAttribute('Length', '100 nm');
|
||
N_Mosfet.setAttribute('Width', '50 nm');
|
||
|
||
// var P_Mosfet = doc.createElement('P_Mos');
|
||
// P_Mosfet.setAttribute('Length', '100 nm');
|
||
// P_Mosfet.setAttribute('Width', '50 nm');
|
||
|
||
</script> -->
|
||
|
||
|
||
<!-- 添加元件图形 -->
|
||
<script type="text/javascript">
|
||
function ResistorShape() { };
|
||
ResistorShape.prototype = new mxCylinder();
|
||
ResistorShape.prototype.constructor = ResistorShape;
|
||
ResistorShape.prototype.redrawPath = function(path, x, y, w, h, isForeground)
|
||
{
|
||
var dx = w / 16;
|
||
|
||
if (isForeground)
|
||
{
|
||
path.moveTo(0, h / 2);
|
||
path.lineTo(2 * dx, h / 2);
|
||
path.lineTo(3 * dx, 0);
|
||
path.lineTo(5 * dx, h);
|
||
path.lineTo(7 * dx, 0);
|
||
path.lineTo(9 * dx, h);
|
||
path.lineTo(11 * dx, 0);
|
||
path.lineTo(13 * dx, h);
|
||
path.lineTo(14 * dx, h / 2);
|
||
path.lineTo(16 * dx, h / 2);
|
||
|
||
path.end();
|
||
}
|
||
};
|
||
function N_Mosfet_Shape() { };
|
||
N_Mosfet_Shape.prototype = new mxCylinder();
|
||
N_Mosfet_Shape.prototype.constructor = N_Mosfet_Shape;
|
||
N_Mosfet_Shape.prototype.redrawPath = function(path, x, y, w, h, isForeground)
|
||
{
|
||
if (isForeground)
|
||
{
|
||
path.moveTo(w * 0 , h * 1/2);
|
||
path.lineTo(w * 3/8, h * 1/2);
|
||
path.moveTo(w * 3/8, h * 1/4);
|
||
path.lineTo(w * 3/8, h * 3/4);
|
||
path.moveTo(w * 5/8, h * 0);
|
||
path.lineTo(w * 5/8, h * 1);
|
||
path.moveTo(w * 5/8, h * 3/4);
|
||
path.lineTo(w * 1 , h * 3/4);
|
||
path.moveTo(w * 5/8, h * 1/4);
|
||
path.lineTo(w * 1 , h * 1/4);
|
||
path.moveTo(w * 13/16, h * 5/8);
|
||
path.lineTo(w * 1 , h * 3/4);
|
||
path.moveTo(w * 13/16, h * 7/8);
|
||
path.lineTo(w * 1 , h * 3/4);
|
||
path.end();
|
||
}
|
||
};
|
||
|
||
function P_Mosfet_Shape() { };
|
||
P_Mosfet_Shape.prototype = new mxCylinder();
|
||
P_Mosfet_Shape.prototype.constructor = P_Mosfet_Shape;
|
||
P_Mosfet_Shape.prototype.redrawPath = function(path, x, y, w, h, isForeground)
|
||
{
|
||
if (isForeground)
|
||
{
|
||
path.moveTo(w * 0 , h * 1/2);
|
||
path.lineTo(w * 3/8, h * 1/2);
|
||
path.moveTo(w * 3/8, h * 1/4);
|
||
path.lineTo(w * 3/8, h * 3/4);
|
||
path.moveTo(w * 5/8, h * 0);
|
||
path.lineTo(w * 5/8, h * 1);
|
||
path.moveTo(w * 5/8, h * 3/4);
|
||
path.lineTo(w * 1 , h * 3/4);
|
||
path.moveTo(w * 5/8, h * 1/4);
|
||
path.lineTo(w * 1 , h * 1/4);
|
||
// arrow
|
||
path.moveTo(w * 6/8 , h * 5/8);
|
||
path.lineTo(w * 5/8 , h * 3/4);
|
||
path.moveTo(w * 6/8 , h * 7/8);
|
||
path.lineTo(w * 5/8 , h * 3/4);
|
||
path.end();
|
||
}
|
||
};
|
||
|
||
function Vdd_Shape() { };
|
||
Vdd_Shape.prototype = new mxCylinder();
|
||
Vdd_Shape.prototype.constructor = Vdd_Shape;
|
||
Vdd_Shape.prototype.redrawPath = function(path, x, y, w, h, isForeground)
|
||
{
|
||
if (isForeground)
|
||
{
|
||
path.moveTo(w * 0 , h * 0);
|
||
path.lineTo(w * 1 , h * 0);
|
||
path.moveTo(w * 1/4, h * 1/2);
|
||
path.lineTo(w * 3/4, h * 1/2);
|
||
path.moveTo(w * 1/2, h * 1/2);
|
||
path.lineTo(w * 1/2, h * 1);
|
||
path.end();
|
||
}
|
||
};
|
||
|
||
function Gnd_Shape() { };
|
||
Gnd_Shape.prototype = new mxCylinder();
|
||
Gnd_Shape.prototype.constructor = Gnd_Shape;
|
||
Gnd_Shape.prototype.redrawPath = function(path, x, y, w, h, isForeground)
|
||
{
|
||
if (isForeground)
|
||
{
|
||
path.moveTo(w * 1/2, h * 0);
|
||
path.lineTo(w * 1/2, h * 1/2);
|
||
path.moveTo(w * 0 , h * 1/2);
|
||
path.lineTo(w * 1 , h * 1/2);
|
||
path.lineTo(w * 1/2, h * 1);
|
||
path.lineTo(w * 0 , h * 1/2);
|
||
|
||
path.end();
|
||
}
|
||
};
|
||
mxCellRenderer.registerShape('resistor', ResistorShape);
|
||
mxCellRenderer.registerShape('n_mosfet', N_Mosfet_Shape);
|
||
mxCellRenderer.registerShape('p_mosfet', P_Mosfet_Shape);
|
||
mxCellRenderer.registerShape('vdd' , Vdd_Shape);
|
||
mxCellRenderer.registerShape('gnd' , Gnd_Shape);
|
||
</script>
|
||
|
||
<!-- 进行端口限制 -->
|
||
<script type="text/javascript">
|
||
// Ports are equal for all shapes...
|
||
var ports = new Array();
|
||
|
||
// NOTE: Constraint is used later for orthogonal edge routing (currently ignored)
|
||
ports['w'] = {x: 0, y: 0.5, perimeter: true, constraint: 'west'};
|
||
ports['e'] = {x: 1, y: 0.5, perimeter: true, constraint: 'east'};
|
||
ports['n'] = {x: 0.5, y: 0, perimeter: true, constraint: 'north'};
|
||
ports['s'] = {x: 0.5, y: 1, perimeter: true, constraint: 'south'};
|
||
ports['nw'] = {x: 0, y: 0, perimeter: true, constraint: 'north west'};
|
||
ports['ne'] = {x: 1, y: 0, perimeter: true, constraint: 'north east'};
|
||
ports['sw'] = {x: 0, y: 1, perimeter: true, constraint: 'south west'};
|
||
ports['se'] = {x: 1, y: 1, perimeter: true, constraint: 'south east'};
|
||
|
||
// Extends shapes classes to return their ports
|
||
mxShape.prototype.getPorts = function()
|
||
{
|
||
return ports;
|
||
};
|
||
// ... except for triangles
|
||
var ports2 = new Array();
|
||
|
||
// NOTE: Constraint is used later for orthogonal edge routing (currently ignored)
|
||
ports2['in1'] = {x: 0, y: 0, perimeter: true, constraint: 'west'};
|
||
ports2['in2'] = {x: 0, y: 0.25, perimeter: true, constraint: 'west'};
|
||
ports2['in3'] = {x: 0, y: 0.5, perimeter: true, constraint: 'west'};
|
||
ports2['in4'] = {x: 0, y: 0.75, perimeter: true, constraint: 'west'};
|
||
ports2['in5'] = {x: 0, y: 1, perimeter: true, constraint: 'west'};
|
||
|
||
ports2['out1'] = {x: 0.5, y: 0, perimeter: true, constraint: 'north east'};
|
||
ports2['out2'] = {x: 1, y: 0.5, perimeter: true, constraint: 'east'};
|
||
ports2['out3'] = {x: 0.5, y: 1, perimeter: true, constraint: 'south east'};
|
||
|
||
mxTriangle.prototype.getPorts = function()
|
||
{
|
||
return ports2;
|
||
};
|
||
|
||
// ... except for n mosfet
|
||
var ports_resistor = new Array();
|
||
ports_resistor['w'] = {x: 0, y: 0.5, perimeter: true, constraint: 'west'};
|
||
ports_resistor['e'] = {x: 1, y: 0.5, perimeter: true, constraint: 'east'};
|
||
|
||
ResistorShape.prototype.getPorts = function()
|
||
{
|
||
return ports_resistor;
|
||
};
|
||
|
||
// ... except for n mosfet
|
||
var ports_nmosfet = new Array();
|
||
ports_nmosfet['g'] = {x: 0, y: 0.5, perimeter: true, constraint: 'west'};
|
||
ports_nmosfet['s'] = {x: 1, y: 0.25, perimeter: true, constraint: 'east'};
|
||
ports_nmosfet['d'] = {x: 1, y: 0.75, perimeter: true, constraint: 'east'};
|
||
|
||
N_Mosfet_Shape.prototype.getPorts = function(){
|
||
return ports_nmosfet;
|
||
};
|
||
// ... except for p mosfet
|
||
var ports_pmosfet = new Array();
|
||
ports_pmosfet['g'] = {x: 0, y: 0.5, perimeter: true, constraint: 'west'};
|
||
ports_pmosfet['s'] = {x: 1, y: 0.25, perimeter: true, constraint: 'east'};
|
||
ports_pmosfet['d'] = {x: 1, y: 0.75, perimeter: true, constraint: 'east'};
|
||
|
||
P_Mosfet_Shape.prototype.getPorts = function(){
|
||
return ports_pmosfet;
|
||
};
|
||
// ... except for vdd
|
||
var ports_vdd = new Array();
|
||
ports_vdd['s'] = {x: 0.5, y: 1, perimeter: true, constraint: 'south'};
|
||
|
||
Vdd_Shape.prototype.getPorts = function(){
|
||
return ports_vdd;
|
||
};
|
||
// ... except for gnd
|
||
var ports_gnd = new Array();
|
||
ports_gnd['n'] = {x: 0.5, y: 0, perimeter: true, constraint: 'north'};
|
||
|
||
Gnd_Shape.prototype.getPorts = function(){
|
||
return ports_gnd;
|
||
}
|
||
</script>
|
||
|
||
|
||
</head>
|
||
|
||
<!-- Calls the main function after the page has loaded. Container is dynamically created. -->
|
||
<body onload="main();">
|
||
</body>
|
||
</html>
|