2907 lines
97 KiB
HTML
2907 lines
97 KiB
HTML
<!--
|
||
Copyright (c) 2021, Zhang Shen
|
||
|
||
CZ Open Spice Schematic .
|
||
-->
|
||
<html>
|
||
<head>
|
||
<title>CZ Open Spice Schematic </title>
|
||
|
||
<!-- Sets the basepath for the library if not in same directory -->
|
||
<script type="text/javascript">
|
||
mxBasePath = 'static/schematic/src';
|
||
</script>
|
||
|
||
<!-- Loads and initializes the library -->
|
||
<script type="text/javascript" src="static/schematic/src/js/mxClient.js"></script>
|
||
|
||
<link href="static/schematic/css/tab.css" rel="stylesheet" type="text/css"/>
|
||
|
||
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-2.2.3.min.js"></script>
|
||
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-widgets-2.2.3.min.js"></script>
|
||
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-tables-2.2.3.min.js"></script>
|
||
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-api-2.2.3.min.js"></script>
|
||
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-api-2.2.3.min.js"></script>
|
||
<script type="text/javascript" src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.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('static/schematic/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("static/schematic/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_att = ParseAttribute(Value_raw);
|
||
var Value_show = '';
|
||
if(Value_att['Name'] == 'unknown'){
|
||
if(Value_att['name'] != 'unknown'){
|
||
Value_show = Value_att['name'];
|
||
}
|
||
}
|
||
else{
|
||
Value_show = Value_att['Name'];
|
||
}
|
||
|
||
// var Value_show = Value_att['name'] == 'unknown' ? '' : Value_att['name'];
|
||
|
||
return Value_show;
|
||
|
||
};
|
||
// 暂时不允许在此进行修改
|
||
var cellLabelChanged = graph.cellLabelChanged;
|
||
graph.cellLabelChanged = function(cell, new_value, autoSize)
|
||
{
|
||
|
||
// // Clones the value for correct undo/redo
|
||
// var elt = cell.value.cloneNode(true);
|
||
|
||
// newValue = elt;
|
||
// autoSize = false;
|
||
|
||
// 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,value)
|
||
{
|
||
var vertex = new mxCell(null, new mxGeometry(0, 0, w, h), style);
|
||
vertex.setVertex(true);
|
||
vertex.setValue(value);
|
||
|
||
addToolbarItem(graph, toolbar, vertex, icon);
|
||
};
|
||
|
||
addVertex_2('static/schematic/icon_ee/res.ico', 80, 30, 'shape=resistor;verticalLabelPosition=top;verticalAlign=bottom','Name=R;Value=10 Ohm;');
|
||
addVertex_2('static/schematic/icon_ee/cap.ico', 40, 30, 'shape=capacitor;verticalLabelPosition=top;verticalAlign=bottom','Name=C;Value=10 pF;');
|
||
addVertex_2('static/schematic/icon_ee/nmos.ico', 60, 60, 'shape=n_mosfet;verticalLabelPosition=top;verticalAlign=bottom','Name=M_NMOS;Model=NMOS;Length=1um;Width=20um;');
|
||
addVertex_2('static/schematic/icon_ee/pmos.ico', 60, 60, 'shape=p_mosfet;verticalLabelPosition=top;verticalAlign=bottom','Name=M_PMOS;Model=PMOS;Length=1um;Width=20um;');
|
||
addVertex_2('static/schematic/icon_ee/vdd.ico', 40, 30, 'shape=vdd;verticalLabelPosition=top;verticalAlign=bottom','Name=Vdd;');
|
||
addVertex_2('static/schematic/icon_ee/gnd.ico', 40, 40, 'shape=gnd;verticalLabelPosition=bottom;verticalAlign=top','Name=Gnd;');
|
||
addVertex_2('static/schematic/icon_ee/pin.ico', 40, 40, 'shape=pin;verticalLabelPosition=top;verticalAlign=bottom','Name=Pin;');
|
||
addVertex_2('static/schematic/icon_ee/pout.ico', 40, 40, 'shape=pout;verticalLabelPosition=top;verticalAlign=bottom','Name=Pout;');
|
||
addVertex_2('static/schematic/icon_ee/vdc.ico', 40, 40, 'shape=vdc;labelPosition=left;align=right','Name=Vdc;DC=1 V;');
|
||
addVertex_2('static/schematic/icon_ee/vac.ico', 40, 40, 'shape=vac;labelPosition=left;align=right','Name=Vac;DC=0 V;ACMAG=1 V;ACPHASE=0 deg;');
|
||
addVertex_2('static/schematic/icon_ee/vsin.ico', 40, 40, 'shape=vsin;labelPosition=left;align=right','Name=Vsin;V0=0 V;VA=1 V;FREQ=1k Hz;TD=0 ;THEAT=0 ;PHASE=0 ;');
|
||
addVertex_2('static/schematic/icon_ee/vpulse.ico', 40, 40, 'shape=vpulse;labelPosition=left;align=right','Name=Vpulse;V1=0 V;V2=1 V;TD=0u s;TR=0u s;TF=0u s;PW=10u s;PER=20u s;');
|
||
|
||
|
||
toolbar.addLine();
|
||
|
||
click_handler(graph);
|
||
ports_handler(graph);
|
||
style_handler(graph);
|
||
Clipboard_Handler(graph);
|
||
bottom_bar(graph);
|
||
|
||
// create a window
|
||
var lorem_1 = "Welcom to use CZ_SPICE,here is the user help manual !";
|
||
var lorem_2 = "To be continued......";
|
||
var content = document.createElement('div');
|
||
mxUtils.writeln(content, lorem_1);
|
||
mxUtils.writeln(content, lorem_2);
|
||
wnd = new mxWindow('Help', 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/javascript">
|
||
// 获取属性
|
||
function ParseAttribute(value)
|
||
{
|
||
value = value||"Name=unknown;" ;
|
||
// value = value.toLowerCase();
|
||
var attribute = {} ;
|
||
v = value.replace(" ","");
|
||
var v_split = v.split(";");
|
||
for(var i = 0; i<v_split.length; i++)
|
||
{
|
||
if(v_split[i].length > 0)
|
||
{
|
||
var pro = v_split[i].split("=");
|
||
attribute[pro[0]] = pro[1];
|
||
}
|
||
}
|
||
return attribute;
|
||
};
|
||
|
||
// 初步从xml中提取有用信息
|
||
function ParseSpice(circuit_xml){
|
||
var encoder = new mxCodec();
|
||
var node = encoder.encode(circuit_xml);
|
||
var content = "";
|
||
var term = "";
|
||
|
||
let reg_1 = /<mxcell.+?\/>/ig;
|
||
let reg_2 = /<mxcell.+?\/mxcell>/ig;
|
||
let reg_3 = /<mxGeometry.+?\/>/ig;
|
||
let reg_4 = /<mxGeometry.+?<\/mxGeometry>/ig;
|
||
let reg_5 = /vertex="1"/ig;
|
||
|
||
let reg_id = /id="(.*?)"/i;
|
||
let reg_value = /value="(.+?)"/i;
|
||
let reg_style = /style="(.+?)"/i;
|
||
let reg_parent = /parent="(.+?)"/i;
|
||
|
||
let reg_edge = /edge="(.+?)"/i;
|
||
let reg_source = /source="(.+?)"/i;
|
||
let reg_target = /target="(.+?)"/i;
|
||
|
||
|
||
let element_list = [];
|
||
let wires_list = [];
|
||
let element = [];
|
||
let wires = [];
|
||
let result = {};
|
||
|
||
content += mxUtils.getXml(node);
|
||
// remove heading text
|
||
term = content.match(reg_1);
|
||
content = content.replace(term[0],'');
|
||
content = content.replace(term[1],'');
|
||
// remove each element_list's geometry
|
||
term = content.match(reg_2);
|
||
for(var i=0 ; i<term.length; i++){
|
||
var geometry = term[i].match(reg_4);
|
||
if(geometry != null){
|
||
term[i] = term[i].replace(geometry,'');
|
||
}
|
||
else{
|
||
geometry = term[i].match(reg_3);
|
||
term[i] = term[i].replace(geometry,'');
|
||
}
|
||
}
|
||
// remove some text
|
||
for(var i=0; i<term.length; i++){
|
||
term[i] = term[i].replace("<mxCell","");
|
||
term[i] = term[i].replace("</mxCell>","");
|
||
term[i] = term[i].replace(">","");
|
||
}
|
||
|
||
// divide term into element_list and wires_list
|
||
for(var i=0 ; i<term.length; i++){
|
||
var vertex = term[i].match(reg_5);
|
||
if(vertex != null){
|
||
term[i] = term[i].replace(vertex,"")
|
||
element_list.push(term[i]);
|
||
}
|
||
else{
|
||
wires_list.push(term[i]);
|
||
}
|
||
}
|
||
// full elements
|
||
for(var i=0; i<element_list.length; i++){
|
||
let ele = {};
|
||
let ele_v = {};
|
||
let ele_s = {};
|
||
let temp_ele ;
|
||
// get id
|
||
ele['id'] = element_list[i].match(reg_id)[1] ;
|
||
// get value
|
||
temp_ele = element_list[i].match(reg_value)[1] ;
|
||
temp_ele = temp_ele.split(";");
|
||
for(var j=0; j<temp_ele.length ;j++){
|
||
let tem = temp_ele[j].split("=");
|
||
ele_v[tem[0]] = tem[1];
|
||
}
|
||
ele['value'] = ele_v ;
|
||
// get style
|
||
temp_ele = element_list[i].match(reg_style)[1] ;
|
||
temp_ele = temp_ele.split(";");
|
||
for(var j=0; j<temp_ele.length; j++){
|
||
let tem = temp_ele[j].split("=");
|
||
ele_s[tem[0]] = tem[1];
|
||
}
|
||
ele['style'] = ele_s ;
|
||
// get parent
|
||
ele['parent'] = element_list[i].match(reg_parent)[1] ;
|
||
|
||
element.push(ele);
|
||
}
|
||
// full wires
|
||
for(var i=0; i<wires_list.length ; i++){
|
||
let ele = {};
|
||
let ele_s = {};
|
||
let temp_ele ;
|
||
|
||
// get id
|
||
ele['id'] = wires_list[i].match(reg_id)[1] ;
|
||
|
||
// get style
|
||
temp_ele = wires_list[i].match(reg_style)[1] ;
|
||
temp_ele = temp_ele.split(";");
|
||
for(var j=0; j<temp_ele.length; j++){
|
||
let tem = temp_ele[j].split("=");
|
||
ele_s[tem[0]] = tem[1];
|
||
}
|
||
ele['style'] = ele_s ;
|
||
|
||
// get edge
|
||
ele['edge'] = wires_list[i].match(reg_edge)[1];
|
||
|
||
// get source
|
||
ele['source'] = wires_list[i].match(reg_source)[1];
|
||
|
||
// get target
|
||
ele['target'] = wires_list[i].match(reg_target)[1];
|
||
|
||
wires.push(ele);
|
||
}
|
||
|
||
result['elements'] = element;
|
||
result['wires'] = wires;
|
||
|
||
return result ;
|
||
};
|
||
|
||
function NormalizeXML(info){
|
||
let circuit = [];
|
||
let netlist = [];
|
||
let nodes = [];
|
||
|
||
for(var i=0; i<info['elements'].length; i++)
|
||
{
|
||
let temp = {};
|
||
temp['id'] = info['elements'][i]['id'];
|
||
temp['name'] = info['elements'][i]['value']['Name'];
|
||
temp['type'] = info['elements'][i]['style']['shape'];
|
||
if(temp['type'] == 'vdd'){
|
||
temp['port'] = {'vdd': 'vdd'};
|
||
temp['port_keys'] = ['vdd'];
|
||
}
|
||
else if(temp['type'] == 'gnd'){
|
||
temp['port'] = {'gnd': 'gnd'};
|
||
temp['port_keys'] = ['gnd'];
|
||
}
|
||
else if(temp['type'] == 'n_mosfet' || temp['type'] == 'p_mosfet'){
|
||
temp['port'] = {'drain': 'd', 'gate': 'g', 'source': 's', 'bulk': 's' };
|
||
temp['port_keys'] = ['drain','gate','source','bulk'];
|
||
temp['value'] = {'model' : info['elements'][i]['value']['Model'],
|
||
'length': info['elements'][i]['value']['Length'],
|
||
'width' : info['elements'][i]['value']['Width']};
|
||
}
|
||
else if(temp['type'] == 'resistor'){
|
||
temp['port'] = {'pos':'pos', 'neg':'neg'};
|
||
temp['port_keys'] = ['pos','neg'];
|
||
temp['value'] = {'value': info['elements'][i]['value']['Value']}
|
||
}
|
||
else if(temp['type'] == 'capacitor'){
|
||
temp['port'] = {'pos':'pos', 'neg':'neg'};
|
||
temp['port_keys'] = ['pos','neg'];
|
||
temp['value'] = {'value': info['elements'][i]['value']['Value']}
|
||
}
|
||
else if(temp['type'] == 'pin'){
|
||
temp['port'] = {'pin': 'pin'};
|
||
temp['port_keys'] = ['pin'];
|
||
}
|
||
else if(temp['type'] == 'pout'){
|
||
temp['port'] = {'pout': 'pout'};
|
||
temp['port_keys'] = ['pout'];
|
||
}
|
||
else if(temp['type'] == 'vdc'){
|
||
temp['port'] = {'pos': 'pos', 'neg':'neg'};
|
||
temp['port_keys'] = ['pos','neg'];
|
||
temp['value'] = {'DC': info['elements'][i]['value']['DC'] }
|
||
}
|
||
else if(temp['type'] == 'vac'){
|
||
temp['port'] = {'pos': 'pos', 'neg':'neg'};
|
||
temp['port_keys'] = ['pos','neg'];
|
||
temp['value'] = {'ACMAG': info['elements'][i]['value']['ACMAG'],
|
||
'ACPHASE': info['elements'][i]['value']['ACPHASE'],
|
||
'DC':info['elements'][i]['value']['DC']}
|
||
}
|
||
else if(temp['type'] == 'vsin'){
|
||
temp['port'] = {'pos': 'pos', 'neg':'neg'};
|
||
temp['port_keys'] = ['pos','neg'];
|
||
temp['value'] = {'V0': info['elements'][i]['value']['V0'],
|
||
'VA': info['elements'][i]['value']['VA'],
|
||
'FREQ': info['elements'][i]['value']['FREQ'],
|
||
'TD': info['elements'][i]['value']['TD'],
|
||
'THEAT': info['elements'][i]['value']['THEAT'],
|
||
'PHASE': info['elements'][i]['value']['PHASE']
|
||
}
|
||
}
|
||
else if(temp['type'] == 'vpulse'){
|
||
temp['port'] = {'pos': 'pos', 'neg':'neg'};
|
||
temp['port_keys'] = ['pos','neg'];
|
||
temp['value'] = {'V1': info['elements'][i]['value']['V1'],
|
||
'V2': info['elements'][i]['value']['V2'],
|
||
'TD': info['elements'][i]['value']['TD'],
|
||
'TR': info['elements'][i]['value']['TR'],
|
||
'TF': info['elements'][i]['value']['TF'],
|
||
'PW': info['elements'][i]['value']['PW'],
|
||
'PER': info['elements'][i]['value']['PER']
|
||
}
|
||
}
|
||
circuit.push(temp);
|
||
}
|
||
|
||
for(var i=0; i<info['wires'].length; i++)
|
||
{
|
||
let temp = {};
|
||
temp['id'] = info['wires'][i]['id'];
|
||
temp['node_source'] = info['wires'][i]['source'] +" "+ info['wires'][i]['style']['sourcePort'];
|
||
temp['node_target'] = info['wires'][i]['target'] +" ";
|
||
if(info['wires'][i]['style']['targetPort'] != null){
|
||
temp['node_target'] += info['wires'][i]['style']['targetPort'];
|
||
}
|
||
else{
|
||
temp['node_target'] += 'null';
|
||
}
|
||
netlist.push(temp);
|
||
}
|
||
|
||
for(var i=0; i<netlist.length; i++){
|
||
let temp = [];
|
||
let index_s = 0;
|
||
let index_t = 0;
|
||
let source = netlist[i]['node_source'];
|
||
let target = netlist[i]['node_target'];
|
||
if(target.indexOf('null') != -1){
|
||
let target_id = target.split(" ")[0];
|
||
let index_id = SearchID(netlist,target_id);
|
||
index_s = SearchExit(nodes,netlist[index_id]['node_source']);
|
||
if(index_s == -1){
|
||
index_t = SearchExit(nodes,netlist[index_id]['node_target']);
|
||
if(index_t == -1){
|
||
temp.push(source);
|
||
temp.push(netlist[index_id]['node_source']);
|
||
temp.push(netlist[index_id]['node_target']);
|
||
nodes.push(temp);
|
||
}
|
||
else{
|
||
nodes[index_t].push(source);
|
||
}
|
||
}
|
||
else{
|
||
nodes[index_s].push(source);
|
||
}
|
||
}
|
||
else{
|
||
index_s = SearchExit(nodes,source);
|
||
index_t = SearchExit(nodes,target);
|
||
if(index_s == -1){
|
||
if(index_t == -1){
|
||
temp.push(source);
|
||
temp.push(target);
|
||
nodes.push(temp);
|
||
}
|
||
else{
|
||
nodes[index_t].push(source);
|
||
}
|
||
}
|
||
else{
|
||
if(index_t == -1){
|
||
nodes[index_s].push(target);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
let count = 1 ;
|
||
let node_str = '';
|
||
let flag_gnd = false;
|
||
let flag_vdd = false;
|
||
for(var i=0; i<nodes.length; i++){
|
||
node_str = String(count);
|
||
for(var j=0; j<nodes[i].length; j++){
|
||
let node_info = nodes[i][j].split(" ");
|
||
let node_id = node_info[0];
|
||
let node_port = node_info[1];
|
||
let node_index = SearchID(circuit,node_id);
|
||
if(node_port == 'gnd'){
|
||
flag_gnd = true;
|
||
}
|
||
else if(node_port == 'vdd'){
|
||
flag_vdd = true ;
|
||
}
|
||
else{
|
||
if(node_index != -1){
|
||
circuit[node_index]['port'][node_port] = node_str;
|
||
|
||
if(node_port == 'source'){
|
||
circuit[node_index]['port']['bulk'] = circuit[node_index]['port']['source'];
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if(flag_gnd){
|
||
flag_gnd = false;
|
||
for(var j=0; j<nodes[i].length; j++){
|
||
let node_info = nodes[i][j].split(" ");
|
||
let node_id = node_info[0];
|
||
let node_port = node_info[1];
|
||
let node_index = SearchID(circuit,node_id);
|
||
node_str = "0";
|
||
if(node_index != -1){
|
||
circuit[node_index]['port'][node_port] = node_str;
|
||
|
||
if(node_port == 'source'){
|
||
circuit[node_index]['port']['bulk'] = circuit[node_index]['port']['source'];
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else if(flag_vdd){
|
||
flag_vdd = false;
|
||
for(var j=0; j<nodes[i].length; j++){
|
||
let node_info = nodes[i][j].split(" ");
|
||
let node_id = node_info[0];
|
||
let node_port = node_info[1];
|
||
let node_index = SearchID(circuit,node_id);
|
||
node_str = "vdd";
|
||
if(node_index != -1){
|
||
circuit[node_index]['port'][node_port] = node_str;
|
||
|
||
if(node_port == 'source'){
|
||
circuit[node_index]['port']['bulk'] = circuit[node_index]['port']['source'];
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else{
|
||
count += 1;
|
||
}
|
||
|
||
}
|
||
return circuit;
|
||
};
|
||
|
||
function SearchID(array,id){
|
||
for(var i=0; i<array.length; i++){
|
||
if(array[i]['id'] == id){
|
||
return i;
|
||
}
|
||
}
|
||
return -1;
|
||
}
|
||
|
||
function SearchExit(array,element){
|
||
for(var i=0; i<array.length; i++){
|
||
if(array[i].includes(element)){
|
||
return i;
|
||
}
|
||
}
|
||
return -1;
|
||
};
|
||
|
||
// 根据从xml提取出来的info生成spice网表
|
||
function ExtractSpice(circuit){
|
||
let spice = "";
|
||
let key ;
|
||
for(var i=0; i<circuit.length;i++){
|
||
spice += circuit[i]['name'] + " ";
|
||
for(var j=0; j<circuit[i]['port_keys'].length; j++){
|
||
spice += circuit[i]['port'][circuit[i]['port_keys'][j]] + " ";
|
||
}
|
||
spice += circuit[i]['type'] + " ";
|
||
for(key in circuit[i]['value']){
|
||
spice += circuit[i]['value'][key] + " ";
|
||
}
|
||
spice += "\n";
|
||
}
|
||
return spice;
|
||
};
|
||
// 根据从xml提取出来的info生成spice网表
|
||
function ExtractSpice_2(circuit){
|
||
let spice = "";
|
||
let key ;
|
||
for(var i=0; i<circuit.length;i++){
|
||
if((circuit[i]['type']=='gnd') || (circuit[i]['type']=='vdd')){
|
||
continue;
|
||
}
|
||
else if((circuit[i]['type']=='pin') || (circuit[i]['type']=='pout')){
|
||
continue;
|
||
}
|
||
else if((circuit[i]['type']=='p_mosfet') || (circuit[i]['type']=='n_mosfet')){
|
||
spice += circuit[i]['name'] + " ";
|
||
for(var j=0; j<circuit[i]['port_keys'].length; j++){
|
||
spice += circuit[i]['port'][circuit[i]['port_keys'][j]] + " ";
|
||
}
|
||
spice += circuit[i]['value']['model'] + " ";
|
||
spice += 'l=' + circuit[i]['value']['length'] + " ";
|
||
spice += 'w=' + circuit[i]['value']['width'] + " ";
|
||
spice += "\n";
|
||
}
|
||
else if(circuit[i]['type']=='vdc'){
|
||
spice += circuit[i]['name'] + " ";
|
||
for(var j=0; j<circuit[i]['port_keys'].length; j++){
|
||
spice += circuit[i]['port'][circuit[i]['port_keys'][j]] + " ";
|
||
}
|
||
spice += 'DC' + " ";
|
||
spice += (circuit[i]['value']['DC'].replace(" ","")).replace("V","") + " ";
|
||
spice += "\n";
|
||
}
|
||
else if(circuit[i]['type']=='vac'){
|
||
spice += circuit[i]['name'] + " ";
|
||
for(var j=0; j<circuit[i]['port_keys'].length; j++){
|
||
spice += circuit[i]['port'][circuit[i]['port_keys'][j]] + " ";
|
||
}
|
||
spice += 'DC' + " ";
|
||
spice += (circuit[i]['value']['DC'].replace(" ","")).replace("V","") + " ";
|
||
spice += 'AC' + " ";
|
||
spice += (circuit[i]['value']['ACMAG'].replace(" ","")).replace("V","") + " ";
|
||
if(circuit[i]['value']['ACPHASE'].replace(" ","").replace("deg","") != "0"){
|
||
spice += circuit[i]['value']['ACPHASE'].replace(" ","").replace("deg","") + " ";
|
||
}
|
||
spice += "\n";
|
||
}
|
||
else if(circuit[i]['type']=='vsin'){
|
||
spice += circuit[i]['name'] + " ";
|
||
for(var j=0; j<circuit[i]['port_keys'].length; j++){
|
||
spice += circuit[i]['port'][circuit[i]['port_keys'][j]] + " ";
|
||
}
|
||
spice += "SIN(" + " ";
|
||
spice += circuit[i]['value']['V0'].replace(" ","").replace("V","") + " ";
|
||
spice += circuit[i]['value']['VA'].replace(" ","").replace("V","") + " ";
|
||
spice += circuit[i]['value']['FREQ'].replace(" ","").replace("Hz","") + " ";
|
||
spice += ")";
|
||
spice += "\n";
|
||
|
||
}
|
||
else if(circuit[i]['type']=='vpulse'){
|
||
spice += circuit[i]['name'] + " ";
|
||
for(var j=0; j<circuit[i]['port_keys'].length; j++){
|
||
spice += circuit[i]['port'][circuit[i]['port_keys'][j]] + " ";
|
||
}
|
||
spice += "PULSE(" + " ";
|
||
for(key in circuit[i]['value']){
|
||
spice += circuit[i]['value'][key].replace(" ","") + " ";
|
||
}
|
||
spice += ")";
|
||
spice += "\n";
|
||
}
|
||
else{
|
||
spice += circuit[i]['name'] + " ";
|
||
for(var j=0; j<circuit[i]['port_keys'].length; j++){
|
||
spice += circuit[i]['port'][circuit[i]['port_keys'][j]] + " ";
|
||
}
|
||
spice += circuit[i]['type'] + " ";
|
||
for(key in circuit[i]['value']){
|
||
spice += circuit[i]['value'][key] + " ";
|
||
}
|
||
spice += "\n";
|
||
}
|
||
}
|
||
return spice;
|
||
};
|
||
|
||
|
||
function get_spice(graph){
|
||
|
||
var node = ParseSpice(graph.getModel());
|
||
var circuit = NormalizeXML(node);
|
||
let spice = ExtractSpice_2(circuit);
|
||
return spice;
|
||
|
||
};
|
||
|
||
</script>
|
||
|
||
|
||
<!-- Simulator 窗口模式选择 -->
|
||
<script>
|
||
|
||
function openMode(evt, tabMode) {
|
||
var i, tabcontent, tablinks;
|
||
tabcontent = document.getElementsByClassName("tabcontent");
|
||
for (i = 0; i < tabcontent.length; i++) {
|
||
tabcontent[i].style.display = "none";
|
||
}
|
||
tablinks = document.getElementsByClassName("tablinks");
|
||
for (i = 0; i < tablinks.length; i++) {
|
||
tablinks[i].className = tablinks[i].className.replace(" active", "");
|
||
}
|
||
document.getElementById(tabMode).style.display = "block";
|
||
evt.currentTarget.className += " active";
|
||
|
||
};
|
||
|
||
|
||
</script>
|
||
|
||
|
||
<!-- 向服务器传递数据 -->
|
||
<script type="text/javascript">
|
||
function ajax_message(data) {
|
||
var data = new Object();
|
||
data["name"] = "XerCis";
|
||
data["message"] = "This is the message from ajax(spice2) !";
|
||
$.ajax({
|
||
type: 'POST',
|
||
url: "/test",
|
||
data: data,
|
||
success: function (response) {
|
||
alert(response);
|
||
}
|
||
});
|
||
}
|
||
|
||
// 由于ajax传递参数时,无法直接进行List的传递,故将属性List转换为了string然后进行传递
|
||
function Simulator(sim_type, spice){
|
||
|
||
// var properties = [];
|
||
var properties_send = "";
|
||
var sel = $("#"+sim_type+" input");
|
||
|
||
// alert(sim_type);
|
||
|
||
sel.each(function(){
|
||
var new_element = {};
|
||
var n = $(this)[0].name;
|
||
var v = $(this)[0].value;
|
||
|
||
properties_send += n + "=" + v + ";";
|
||
// new_element[n] = v ;
|
||
// properties.push(new_element);
|
||
});
|
||
|
||
|
||
var data = new Object();
|
||
data["sim_type"] = sim_type;
|
||
data["properties"] = properties_send;
|
||
data['spice'] = spice;
|
||
// alert(spice);
|
||
|
||
// for(var i=0; i<properties.length; i++){
|
||
// var key = Object.keys(properties[i])[0];
|
||
// var val = Object.values(properties[i])[0];
|
||
// alert(key + " "+ val);
|
||
// }
|
||
|
||
$.ajax({
|
||
type: 'POST',
|
||
url: "/simulation",
|
||
data: data,
|
||
success: function (response) {
|
||
alert(response);
|
||
}
|
||
});
|
||
|
||
};
|
||
|
||
|
||
</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.getValue();
|
||
var attribute = ParseAttribute(value);
|
||
var Text_attribute = {};
|
||
for(x in attribute){
|
||
Text_attribute[x] = form.addText(x, attribute[x]);
|
||
}
|
||
// var value_cell = form.addText('value', cell.getValue());
|
||
function AssembleAttribute(){
|
||
var Str_attribute = '';
|
||
for(x in attribute){
|
||
Str_attribute += x + '=' + Text_attribute[x].value + ';';
|
||
}
|
||
return Str_attribute ;
|
||
}
|
||
|
||
var okFunction = mxUtils.bind(this, function(){
|
||
|
||
cell.setValue(AssembleAttribute());
|
||
|
||
// graph.cellLabelChanged(cell,AssembleAttribute(),false);
|
||
|
||
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);
|
||
|
||
}
|
||
};
|
||
|
||
</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', 'static/schematic/editors/images/image.gif', function()
|
||
{
|
||
showProperties(graph,cell);
|
||
});
|
||
}
|
||
else
|
||
{
|
||
menu.addItem('No-Cell Item', 'static/schematic/editors/images/image.gif', function()
|
||
{
|
||
mxUtils.alert('MenuItem2');
|
||
});
|
||
}
|
||
menu.addSeparator();
|
||
menu.addItem('MenuItem3', 'static/schematic/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();
|
||
}
|
||
}
|
||
}
|
||
}));
|
||
|
||
document.body.appendChild(mxUtils.button('Show info', function()
|
||
{
|
||
var node = ParseSpice(graph.getModel());
|
||
var circuit = NormalizeXML(node);
|
||
let spice = ExtractSpice(circuit);
|
||
mxUtils.popup(spice, true);
|
||
}));
|
||
|
||
document.body.appendChild(mxUtils.button('Show Spice', function()
|
||
{
|
||
|
||
var node = ParseSpice(graph.getModel());
|
||
var circuit = NormalizeXML(node);
|
||
let spice = ExtractSpice_2(circuit);
|
||
mxUtils.popup(spice, true);
|
||
}));
|
||
|
||
document.body.appendChild(mxUtils.button('Send Spice', function()
|
||
{
|
||
var node = ParseSpice(graph.getModel());
|
||
var circuit = NormalizeXML(node);
|
||
let spice = ExtractSpice_2(circuit);
|
||
|
||
var data = new Object();
|
||
data["name"] = "Spice";
|
||
data["spice"] = spice;
|
||
$.ajax({
|
||
type: 'POST',
|
||
url: "/spice",
|
||
data: data,
|
||
success: function (response) {
|
||
alert(response);
|
||
}
|
||
});
|
||
|
||
}));
|
||
|
||
document.body.appendChild(mxUtils.button('simulator', function(){
|
||
|
||
// let spice = get_spice(graph);
|
||
|
||
var frame = document.createElement('div');
|
||
frame.setAttribute('id','bokeh_02');
|
||
|
||
// var x = document.createElement('script');
|
||
// x.setAttribute('src','static/spice/bokeh_02.js');
|
||
// frame.appendChild(x);
|
||
|
||
var div_tab = document.createElement('div');
|
||
div_tab.setAttribute('class','tab');
|
||
|
||
|
||
var sim_mode = ['transient', 'dc', 'ac'];
|
||
|
||
var sim_mode_content = {
|
||
'transient': {
|
||
"key" :[ 'step_time', 'end_time', 'start_time','max_time','use_initial_condition'],
|
||
"value" :[ '0.1 us', '20 us', '0', 'None', 'False']
|
||
},
|
||
'dc': {
|
||
"key" :[ "src","start","stop","step"],
|
||
"value" :[ "","","",""]
|
||
},
|
||
'ac': {
|
||
"key" :[ "variation", "number_of_points", "start_frequency", "stop_frequency"],
|
||
"value" :[ "","","",""]
|
||
}
|
||
};
|
||
|
||
for(var i=0; i<sim_mode.length; i++){
|
||
var div_mode = document.createElement('button');
|
||
div_mode.setAttribute('class',"tablinks");
|
||
div_mode.setAttribute('onclick',"openMode(event, '"+ sim_mode[i] +"')");
|
||
|
||
div_mode.innerHTML = sim_mode[i] ;
|
||
div_tab.appendChild(div_mode);
|
||
}
|
||
|
||
frame.appendChild(div_tab);
|
||
|
||
for(var i=0; i<sim_mode.length; i++){
|
||
var div_mode = document.createElement('div');
|
||
div_mode.setAttribute('class',"tabcontent");
|
||
div_mode.setAttribute('id',sim_mode[i]);
|
||
|
||
var div_h3 = document.createElement('h3');
|
||
div_h3.innerHTML = sim_mode[i];
|
||
div_mode.appendChild(div_h3);
|
||
|
||
var table = document.createElement('table');
|
||
|
||
var the_mode = sim_mode_content[sim_mode[i]];
|
||
for(var j=0; j<the_mode['key'].length; j++ ){
|
||
var form_div = document.createElement('tr');
|
||
|
||
var td_name = document.createElement('td');
|
||
td_name.innerHTML = the_mode['key'][j] ;
|
||
form_div.appendChild(td_name);
|
||
|
||
var td_input = document.createElement('td');
|
||
|
||
var input = document.createElement('input');
|
||
input.setAttribute('name', the_mode['key'][j]);
|
||
input.setAttribute("class","simulator_input");
|
||
input.setAttribute('type', "text");
|
||
input.setAttribute('value', the_mode['value'][j] );
|
||
td_input.appendChild(input);
|
||
|
||
form_div.appendChild(td_input);
|
||
|
||
table.appendChild(form_div);
|
||
}
|
||
|
||
var confirm = document.createElement('button');
|
||
confirm.setAttribute("type","submit");
|
||
confirm.setAttribute("class",sim_mode[i]);
|
||
// confirm.setAttribute('onclick',"Simulator('"+sim_mode[i] +"'; ");
|
||
confirm.onclick = function(){
|
||
let spice = get_spice(graph);
|
||
Simulator(this.className,spice);
|
||
};
|
||
confirm.innerHTML = "Confirm";
|
||
|
||
table.appendChild(confirm);
|
||
|
||
div_mode.appendChild(table);
|
||
|
||
frame.appendChild(div_mode);
|
||
};
|
||
|
||
|
||
|
||
var w = document.body.clientWidth;
|
||
var h = (document.body.clientHeight || document.documentElement.clientHeight);
|
||
var wnd = new mxWindow('Title', frame, (w-200)/2, (h-200)/3, 400, 400, true, true);
|
||
|
||
wnd.setVisible(true);
|
||
wnd.setScrollable(true);
|
||
wnd.setResizable(true);
|
||
wnd.setVisible(true);
|
||
wnd.setClosable(true);
|
||
|
||
}));
|
||
|
||
document.body.appendChild(mxUtils.button('show result', function()
|
||
{
|
||
|
||
var frame = document.createElement('div');
|
||
frame.setAttribute('id','bokeh_01');
|
||
|
||
var x = document.createElement('script');
|
||
x.setAttribute('src','static/spice/show_result.js');
|
||
|
||
frame.appendChild(x);
|
||
|
||
var w = document.body.clientWidth;
|
||
var h = (document.body.clientHeight || document.documentElement.clientHeight);
|
||
var wnd = new mxWindow('Title', frame, (w-200)/2, (h-200)/3, 400, 400, true, true);
|
||
|
||
wnd.setVisible(true);
|
||
wnd.setScrollable(true);
|
||
wnd.setResizable(true);
|
||
wnd.setVisible(true);
|
||
wnd.setClosable(true);
|
||
|
||
}));
|
||
|
||
|
||
|
||
// 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(\'static/schematic/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;
|
||
};
|
||
|
||
|
||
|
||
// 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;
|
||
}
|
||
}));
|
||
|
||
|
||
// 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();
|
||
});
|
||
|
||
// Removes cells when [DELETE] is pressed
|
||
var keyHandler = new mxKeyHandler(graph);
|
||
keyHandler.bindKey(46, function(evt)
|
||
{
|
||
if (graph.isEnabled())
|
||
{
|
||
graph.removeCells();
|
||
}
|
||
});
|
||
|
||
}
|
||
|
||
</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 * 3/8);
|
||
path.lineTo(w * 5/8 , h * 1/4);
|
||
path.moveTo(w * 6/8 , h * 1/8);
|
||
path.lineTo(w * 5/8 , h * 1/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();
|
||
}
|
||
};
|
||
|
||
function Capacitor_Shape() { };
|
||
Capacitor_Shape.prototype = new mxCylinder();
|
||
Capacitor_Shape.prototype.constructor = Capacitor_Shape;
|
||
Capacitor_Shape.prototype.redrawPath = function(path, x, y, w, h, isForeground)
|
||
{
|
||
if (isForeground)
|
||
{
|
||
path.moveTo(w * 3/8, h * 0);
|
||
path.lineTo(w * 3/8, h * 1);
|
||
path.moveTo(w * 3/8, h * 1/2);
|
||
path.lineTo(w * 0 , h * 1/2);
|
||
|
||
path.moveTo(w * 5/8, h * 0);
|
||
path.lineTo(w * 5/8, h * 1);
|
||
path.moveTo(w * 5/8, h * 1/2);
|
||
path.lineTo(w * 1 , h * 1/2);
|
||
|
||
path.end();
|
||
}
|
||
};
|
||
|
||
function Pin_Shape() { };
|
||
Pin_Shape.prototype = new mxCylinder();
|
||
Pin_Shape.prototype.constructor = Pin_Shape;
|
||
Pin_Shape.prototype.redrawPath = function(path, x, y, w, h, isForeground)
|
||
{
|
||
if (isForeground)
|
||
{
|
||
path.moveTo(w * 0 , h * 1/4);
|
||
path.lineTo(w * 3/4, h * 1/4);
|
||
path.lineTo(w * 1 , h * 1/2);
|
||
path.lineTo(w * 3/4, h * 3/4);
|
||
path.lineTo(w * 0 , h * 3/4);
|
||
path.lineTo(w * 0 , h * 1/4);
|
||
|
||
path.end();
|
||
}
|
||
};
|
||
|
||
function Pout_Shape() { };
|
||
Pout_Shape.prototype = new mxCylinder();
|
||
Pout_Shape.prototype.constructor = Pout_Shape;
|
||
Pout_Shape.prototype.redrawPath = function(path, x, y, w, h, isForeground)
|
||
{
|
||
if (isForeground)
|
||
{
|
||
path.moveTo(w * 1 , h * 1/4);
|
||
path.lineTo(w * 1/4, h * 1/4);
|
||
path.lineTo(w * 0 , h * 1/2);
|
||
path.lineTo(w * 1/4, h * 3/4);
|
||
path.lineTo(w * 1 , h * 3/4);
|
||
path.lineTo(w * 1 , h * 1/4);
|
||
|
||
path.end();
|
||
}
|
||
};
|
||
|
||
function Vdc_Shape() { };
|
||
Vdc_Shape.prototype = new mxCylinder();
|
||
Vdc_Shape.prototype.constructor = Vdc_Shape;
|
||
Vdc_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/8);
|
||
path.moveTo(w * 1/2, h * 1);
|
||
path.lineTo(w * 1/2, h * 7/8);
|
||
// path.moveTo(w * 1/2, h * 1/8);
|
||
// path.arcTo(3/8*w,3/8*w,180,true,true,w*1/2,h*1/2);
|
||
|
||
path.moveTo(w * 1/2, h * 1/8);
|
||
path.curveTo(w * 1/2, h * 1/8,
|
||
w * 7/8, h * 1/8,
|
||
w * 7/8, h * 1/2);
|
||
|
||
path.moveTo(w * 1/2, h * 1/8);
|
||
path.curveTo(w * 1/2, h * 1/8,
|
||
w * 1/8, h * 1/8,
|
||
w * 1/8, h * 1/2);
|
||
|
||
path.moveTo(w * 1/2, h * 7/8);
|
||
path.curveTo(w * 1/2, h * 7/8,
|
||
w * 7/8, h * 7/8,
|
||
w * 7/8, h * 1/2);
|
||
|
||
path.moveTo(w * 1/2, h * 7/8);
|
||
path.curveTo(w * 1/2, h * 7/8,
|
||
w * 1/8, h * 7/8,
|
||
w * 1/8, h * 1/2);
|
||
|
||
path.moveTo(w * 1/2, h * 3/16);
|
||
path.lineTo(w * 1/2, h * 7/16);
|
||
path.moveTo(w * 3/8, h * 5/16);
|
||
path.lineTo(w * 5/8, h * 5/16);
|
||
path.moveTo(w * 3/8, h * 11/16);
|
||
path.lineTo(w * 5/8, h * 11/16);
|
||
|
||
path.end();
|
||
}
|
||
};
|
||
|
||
function Vac_Shape() { };
|
||
Vac_Shape.prototype = new mxCylinder();
|
||
Vac_Shape.prototype.constructor = Vac_Shape;
|
||
Vac_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/8);
|
||
path.moveTo(w * 1/2, h * 1);
|
||
path.lineTo(w * 1/2, h * 7/8);
|
||
|
||
path.moveTo(w * 1/2, h * 1/8);
|
||
path.curveTo(w * 1/2, h * 1/8,
|
||
w * 7/8, h * 1/8,
|
||
w * 7/8, h * 1/2);
|
||
|
||
path.moveTo(w * 1/2, h * 1/8);
|
||
path.curveTo(w * 1/2, h * 1/8,
|
||
w * 1/8, h * 1/8,
|
||
w * 1/8, h * 1/2);
|
||
|
||
path.moveTo(w * 1/2, h * 7/8);
|
||
path.curveTo(w * 1/2, h * 7/8,
|
||
w * 7/8, h * 7/8,
|
||
w * 7/8, h * 1/2);
|
||
|
||
path.moveTo( w * 1/2, h * 7/8);
|
||
path.curveTo(w * 1/2, h * 7/8,
|
||
w * 1/8, h * 7/8,
|
||
w * 1/8, h * 1/2);
|
||
// +
|
||
path.moveTo(w * 1/2, h * 3/16);
|
||
path.lineTo(w * 1/2, h * 7/16);
|
||
path.moveTo(w * 3/8, h * 5/16);
|
||
path.lineTo(w * 5/8, h * 5/16);
|
||
// -
|
||
path.moveTo(w * 3/8, h * 11/16);
|
||
path.lineTo(w * 5/8, h * 11/16);
|
||
|
||
// ac
|
||
path.moveTo( w * 2/8, h * 9/16);
|
||
path.curveTo(w * 2/8, h * 9/16,
|
||
w * 2/8 , h * 8/16,
|
||
w * 3/8, h * 8/16);
|
||
|
||
path.moveTo( w * 3/8, h * 8/16);
|
||
path.curveTo(w * 3/8, h * 8/16,
|
||
w * 4/8 , h * 8/16,
|
||
w * 4/8 , h * 9/16);
|
||
|
||
path.moveTo( w * 4/8, h * 9/16);
|
||
path.curveTo(w * 4/8, h * 9/16,
|
||
w * 4/8 , h * 10/16,
|
||
w * 5/8 , h * 10/16);
|
||
|
||
path.moveTo( w * 5/8, h * 10/16);
|
||
path.curveTo(w * 5/8, h * 10/16,
|
||
w * 6/8 , h * 10/16,
|
||
w * 6/8 , h * 9/16);
|
||
|
||
path.end();
|
||
}
|
||
};
|
||
|
||
function Vsin_Shape() { };
|
||
Vsin_Shape.prototype = new mxCylinder();
|
||
Vsin_Shape.prototype.constructor = Vsin_Shape;
|
||
Vsin_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/8);
|
||
path.moveTo(w * 1/2, h * 1);
|
||
path.lineTo(w * 1/2, h * 7/8);
|
||
|
||
path.moveTo(w * 1/2, h * 1/8);
|
||
path.curveTo(w * 1/2, h * 1/8,
|
||
w * 7/8, h * 1/8,
|
||
w * 7/8, h * 1/2);
|
||
|
||
path.moveTo(w * 1/2, h * 1/8);
|
||
path.curveTo(w * 1/2, h * 1/8,
|
||
w * 1/8, h * 1/8,
|
||
w * 1/8, h * 1/2);
|
||
|
||
path.moveTo(w * 1/2, h * 7/8);
|
||
path.curveTo(w * 1/2, h * 7/8,
|
||
w * 7/8, h * 7/8,
|
||
w * 7/8, h * 1/2);
|
||
|
||
path.moveTo( w * 1/2, h * 7/8);
|
||
path.curveTo(w * 1/2, h * 7/8,
|
||
w * 1/8, h * 7/8,
|
||
w * 1/8, h * 1/2);
|
||
|
||
// ac
|
||
path.moveTo( w * 2/8, h * 9/16);
|
||
path.curveTo(w * 2/8, h * 9/16,
|
||
w * 2/8 , h * 8/16,
|
||
w * 3/8, h * 8/16);
|
||
|
||
path.moveTo( w * 3/8, h * 8/16);
|
||
path.curveTo(w * 3/8, h * 8/16,
|
||
w * 4/8 , h * 8/16,
|
||
w * 4/8 , h * 9/16);
|
||
|
||
path.moveTo( w * 4/8, h * 9/16);
|
||
path.curveTo(w * 4/8, h * 9/16,
|
||
w * 4/8 , h * 10/16,
|
||
w * 5/8 , h * 10/16);
|
||
|
||
path.moveTo( w * 5/8, h * 10/16);
|
||
path.curveTo(w * 5/8, h * 10/16,
|
||
w * 6/8 , h * 10/16,
|
||
w * 6/8 , h * 9/16);
|
||
|
||
path.end();
|
||
}
|
||
};
|
||
|
||
function Vpulse_Shape() { };
|
||
Vpulse_Shape.prototype = new mxCylinder();
|
||
Vpulse_Shape.prototype.constructor = Vpulse_Shape;
|
||
Vpulse_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/8);
|
||
path.moveTo(w * 1/2, h * 1);
|
||
path.lineTo(w * 1/2, h * 7/8);
|
||
|
||
path.moveTo(w * 1/2, h * 1/8);
|
||
path.curveTo(w * 1/2, h * 1/8,
|
||
w * 7/8, h * 1/8,
|
||
w * 7/8, h * 1/2);
|
||
|
||
path.moveTo(w * 1/2, h * 1/8);
|
||
path.curveTo(w * 1/2, h * 1/8,
|
||
w * 1/8, h * 1/8,
|
||
w * 1/8, h * 1/2);
|
||
|
||
path.moveTo(w * 1/2, h * 7/8);
|
||
path.curveTo(w * 1/2, h * 7/8,
|
||
w * 7/8, h * 7/8,
|
||
w * 7/8, h * 1/2);
|
||
|
||
path.moveTo( w * 1/2, h * 7/8);
|
||
path.curveTo(w * 1/2, h * 7/8,
|
||
w * 1/8, h * 7/8,
|
||
w * 1/8, h * 1/2);
|
||
|
||
// pulse
|
||
path.moveTo(w * 2/8 , h * 5/8 );
|
||
path.lineTo(w * 2/8 , h * 3/8 );
|
||
path.lineTo(w * 1/2 , h * 3/8 );
|
||
path.lineTo(w * 1/2 , h * 5/8 );
|
||
path.lineTo(w * 6/8 , h * 5/8 );
|
||
path.lineTo(w * 6/8 , h * 3/8 );
|
||
|
||
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);
|
||
mxCellRenderer.registerShape('capacitor', Capacitor_Shape);
|
||
mxCellRenderer.registerShape('pin' , Pin_Shape);
|
||
mxCellRenderer.registerShape('pout' , Pout_Shape);
|
||
mxCellRenderer.registerShape('vdc' , Vdc_Shape);
|
||
mxCellRenderer.registerShape('vac' , Vac_Shape);
|
||
mxCellRenderer.registerShape('vsin' , Vsin_Shape);
|
||
mxCellRenderer.registerShape('vpulse' , Vpulse_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;
|
||
};
|
||
|
||
// for n mosfet
|
||
var ports_resistor = new Array();
|
||
ports_resistor['pos'] = {x: 0, y: 0.5, perimeter: true, constraint: 'west'};
|
||
ports_resistor['neg'] = {x: 1, y: 0.5, perimeter: true, constraint: 'east'};
|
||
|
||
ResistorShape.prototype.getPorts = function()
|
||
{
|
||
return ports_resistor;
|
||
};
|
||
|
||
// for n mosfet
|
||
var ports_nmosfet = new Array();
|
||
ports_nmosfet['gate'] = {x: 0, y: 0.5, perimeter: true, constraint: 'west'};
|
||
ports_nmosfet['drain'] = {x: 1, y: 0.25, perimeter: true, constraint: 'east'};
|
||
ports_nmosfet['source'] = {x: 1, y: 0.75, perimeter: true, constraint: 'east'};
|
||
|
||
N_Mosfet_Shape.prototype.getPorts = function(){
|
||
return ports_nmosfet;
|
||
};
|
||
// for p mosfet
|
||
var ports_pmosfet = new Array();
|
||
ports_pmosfet['gate'] = {x: 0, y: 0.5, perimeter: true, constraint: 'west'};
|
||
ports_pmosfet['source'] = {x: 1, y: 0.25, perimeter: true, constraint: 'east'};
|
||
ports_pmosfet['drain'] = {x: 1, y: 0.75, perimeter: true, constraint: 'east'};
|
||
|
||
P_Mosfet_Shape.prototype.getPorts = function(){
|
||
return ports_pmosfet;
|
||
};
|
||
// for vdd
|
||
var ports_vdd = new Array();
|
||
ports_vdd['vdd'] = {x: 0.5, y: 1, perimeter: true, constraint: 'south'};
|
||
|
||
Vdd_Shape.prototype.getPorts = function(){
|
||
return ports_vdd;
|
||
};
|
||
// for gnd
|
||
var ports_gnd = new Array();
|
||
ports_gnd['gnd'] = {x: 0.5, y: 0, perimeter: true, constraint: 'north'};
|
||
|
||
Gnd_Shape.prototype.getPorts = function(){
|
||
return ports_gnd;
|
||
};
|
||
|
||
// for capatiance
|
||
var ports_capatiance = new Array();
|
||
ports_capatiance['pos'] = {x: 0.0, y: 0.5, perimeter: true, constraint: 'west'};
|
||
ports_capatiance['neg'] = {x: 1.0, y: 0.5, perimeter: true, constraint: 'east'};
|
||
|
||
Capacitor_Shape.prototype.getPorts = function(){
|
||
return ports_capatiance;
|
||
};
|
||
|
||
// for port_pin
|
||
var ports_pin = new Array();
|
||
ports_pin['pin'] = {x: 1.0, y: 0.5, perimeter: true, constraint: 'east'};
|
||
|
||
Pin_Shape.prototype.getPorts = function(){
|
||
return ports_pin;
|
||
};
|
||
// for port_out
|
||
var ports_pout = new Array();
|
||
ports_pout['pout'] = {x: 0.0, y: 0.5, perimeter: true, constraint: 'west'};
|
||
|
||
Pout_Shape.prototype.getPorts = function(){
|
||
return ports_pout;
|
||
};
|
||
// for Vdc
|
||
var ports_vdc = new Array();
|
||
ports_vdc['pos'] = {x: 0.5, y: 0.0, perimeter: true, constraint: 'north'};
|
||
ports_vdc['neg'] = {x: 0.5, y: 1.0, perimeter: true, constraint: 'south'};
|
||
|
||
Vdc_Shape.prototype.getPorts = function(){
|
||
return ports_vdc;
|
||
};
|
||
// for Vac
|
||
var ports_vac = new Array();
|
||
ports_vac['pos'] = {x: 0.5, y: 0.0, perimeter: true, constraint: 'north'};
|
||
ports_vac['neg'] = {x: 0.5, y: 1.0, perimeter: true, constraint: 'south'};
|
||
|
||
Vac_Shape.prototype.getPorts = function(){
|
||
return ports_vac;
|
||
};
|
||
|
||
// for Vsin
|
||
var ports_vsin = new Array();
|
||
ports_vsin['pos'] = {x: 0.5, y: 0.0, perimeter: true, constraint: 'north'};
|
||
ports_vsin['neg'] = {x: 0.5, y: 1.0, perimeter: true, constraint: 'south'};
|
||
|
||
Vsin_Shape.prototype.getPorts = function(){
|
||
return ports_vsin;
|
||
};
|
||
|
||
// for Vsin
|
||
var ports_vpulse = new Array();
|
||
ports_vpulse['pos'] = {x: 0.5, y: 0.0, perimeter: true, constraint: 'north'};
|
||
ports_vpulse['neg'] = {x: 0.5, y: 1.0, perimeter: true, constraint: 'south'};
|
||
|
||
Vpulse_Shape.prototype.getPorts = function(){
|
||
return ports_vpulse;
|
||
};
|
||
|
||
|
||
</script>
|
||
|
||
|
||
</head>
|
||
|
||
<!-- Calls the main function after the page has loaded. Container is dynamically created. -->
|
||
<body onload="main();">
|
||
</body>
|
||
</html>
|