mxGraph實現魚骨圖(因果圖)(轉自CSDN,鏈接附於文中)
阿新 • • 發佈:2018-10-30
view rto https bind right drawpath point sub nta
魚骨圖由日本管理大師石川馨先生所發明,故又名石川圖。魚骨圖是一種發現問題“根本原因”的方法,它也可以稱之為“Ishikawa”或者“因果圖”。其特點是簡捷實用,深入直觀。它看上去有些象魚骨,問題或缺陷(即後果)標在"魚頭"外。在魚骨上長出魚刺,上面按出現機會多寡列出產生生產問題的可能原因,有助於說明各個原因之間如何相互影響。
這玩意兒就體現了一個什麽5w1h的管理方法,經過我將近4周的時間搗鼓。由於原先想實現的過於復雜(主要由於本人數學知識淺薄),後來放棄了原先的兩個方案。一是分支斜線擴展;二是分支上下、左右擴展。
不知道寫點個啥,直接上代碼吧。
---------------------
作者:海闊山遙-未知何處是瀟湘
來源:轉自CSDN
原文鏈接:https://blog.csdn.net/gua_381091614/article/details/38982675
/** * Created by numen_huang on 2014/8/6. */ $(function () { if (!mxClient.isBrowserSupported()) { // Displays an error message if the browser is not supported. mxUtils.error(‘Browser is not supported!‘, 200, false); } else { document.oncontextmenu = function () { return false; } var fish=new fishBone(); fish.init(); } }); var fishBone=function(){}; fishBone.prototype.graph=null; fishBone.prototype.init=function(){ this.resetSourceCode(); this.buildCanvas(); this.setCanvasStyle(); this.buildContextMenu(); this.createFishBone(); }; fishBone.prototype.resetSourceCode=function(){ var _this=this; mxCellRenderer.prototype.createLabel = function(state, value) { var graph = state.view.graph; var isEdge = graph.getModel().isEdge(state.cell); if (state.style[mxConstants.STYLE_FONTSIZE] > 0 || state.style[mxConstants.STYLE_FONTSIZE] == null) { var isForceHtml = (graph.isHtmlLabel(state.cell) || (value != null && mxUtils.isNode(value))) && graph.dialect == mxConstants.DIALECT_SVG; var h=‘‘; var spacingRight=-30; var spacingLeft=1; if(state.cell.id==‘fishboneHead‘){ h=‘horizontal‘; spacingRight=spacingLeft=0; } if(state.cell.level%2==0 && state.cell.id!=‘fishboneHead‘){ h=‘horizontal‘; if(_this.getSelfTopParent(state.cell).direction==‘bottom‘) { spacingLeft = -25; }else{ spacingLeft = 0; } } var background=state.style[mxConstants.STYLE_LABEL_BACKGROUNDCOLOR]; var borderColor=state.style[mxConstants.STYLE_LABEL_BORDERCOLOR]; var color=state.style[mxConstants.STYLE_FONTCOLOR]; if(state.cell.level==1){ background=‘#B3D9D9‘; borderColor=‘#005757‘; color=‘#336666‘; }else{ background=‘#F3F3F3‘; borderColor=‘#005757‘; color=‘#336666‘; } state.text = new mxText(value, null, (state.style[mxConstants.STYLE_ALIGN] || mxConstants.ALIGN_CENTER), graph.getVerticalAlign(state),color, state.style[mxConstants.STYLE_FONTFAMILY], state.style[mxConstants.STYLE_FONTSIZE], state.style[mxConstants.STYLE_FONTSTYLE], state.style[mxConstants.STYLE_SPACING], spacingLeft, 10, spacingRight, 10, h, background, borderColor, graph.isWrapping(state.cell), graph.isLabelClipped(state.cell), state.style[mxConstants.STYLE_OVERFLOW]); state.text.opacity = state.style[mxConstants.STYLE_TEXT_OPACITY]; state.text.dialect = (isForceHtml) ? mxConstants.DIALECT_STRICTHTML: state.view.graph.dialect; this.initializeLabel(state); var getState = function(evt) { var result = state; if (mxClient.IS_TOUCH) { var x = mxEvent.getClientX(evt); var y = mxEvent.getClientY(evt); var pt = mxUtils.convertPoint(graph.container, x, y); result = graph.view.getState(graph.getCellAt(pt.x, pt.y)); } return result; }; var md = (mxClient.IS_TOUCH) ? ‘touchstart‘: ‘mousedown‘; var mm = (mxClient.IS_TOUCH) ? ‘touchmove‘: ‘mousemove‘; var mu = (mxClient.IS_TOUCH) ? ‘touchend‘: ‘mouseup‘; mxEvent.addListener(state.text.node, md, mxUtils.bind(this, function(evt) { if (this.isLabelEvent(state, evt)) { graph.fireMouseEvent(mxEvent.MOUSE_DOWN, new mxMouseEvent(evt, state)); } })); mxEvent.addListener(state.text.node, mm, mxUtils.bind(this, function(evt) { if (this.isLabelEvent(state, evt)) { graph.fireMouseEvent(mxEvent.MOUSE_MOVE, new mxMouseEvent(evt, getState(evt))); } })); mxEvent.addListener(state.text.node, mu, mxUtils.bind(this, function(evt) { if (this.isLabelEvent(state, evt)) { graph.fireMouseEvent(mxEvent.MOUSE_UP, new mxMouseEvent(evt, getState(evt))); } })); mxEvent.addListener(state.text.node, ‘dblclick‘, mxUtils.bind(this, function(evt) { if (this.isLabelEvent(state, evt)) { graph.dblClick(evt, state.cell); mxEvent.consume(evt); } })); } }; mxTriangle.prototype.redrawPath = function(path, x, y, w, h) { if (this.direction == mxConstants.DIRECTION_NORTH) { path.moveTo(0, h); path.lineTo(0.5 * w, 0); path.lineTo(w, h); } else if (this.direction == mxConstants.DIRECTION_SOUTH) { path.moveTo(0, 0); path.lineTo(0.5 * w, h); path.lineTo(w, 0); } else if (this.direction == mxConstants.DIRECTION_WEST) { path.moveTo(0, 0); path.lineTo(w, 0.5 * h); path.lineTo(0, h); } else if(this.direction == ‘east‘){ path.moveTo(0, 0); path.quadTo(w, 0.25 * h,w+1,0.5*h); path.quadTo(w+1, 0.75 * h,0,h); } else{ path.moveTo(0, 0); path.lineTo(w, 0.5 * h); path.lineTo(0, h); } path.close(); }; mxGraphSelectionModel.prototype.singleSelection = true; mxGraph.prototype.foldingEnabled=false; mxGraph.prototype.selectCellForEvent = function(cell, evt) { if(cell.id!=‘fishboneEnd‘ && cell.id!=‘fishboneBody‘ && !cell.isEdge()) { var isSelected = this.isCellSelected(cell); if (this.isToggleEvent(evt)) { if (isSelected) { this.removeSelectionCell(cell); } else { this.addSelectionCell(cell); } } else if (!isSelected || this.getSelectionCount() != 1) { this.setSelectionCell(cell); } } }; mxGraph.prototype.moveCells = function(cells, dx, dy, clone, target, evt) { if(cells==null || cells.length>1){ return false; } var cell=cells[0]; if (dx != 0 || dy != 0 || clone || target != null) { this.getModel().beginUpdate(); try { if (clone) { return false; } if(cell.level==1){ var fishHead=_this.getCellById(‘fishboneHead‘); var fishBody=_this.getCellById(‘fishboneBody‘); var fishEnd=_this.getCellById(‘fishboneEnd‘); if(cell.geometry.x+dx>fishHead.geometry.x-100){ cell.geometry.x+=dx; var size=cell.geometry.x-fishHead.geometry.x; fishHead.geometry.x+=size+100; fishBody.geometry.width+=size+100; } else if(cell.geometry.x+dx<fishEnd.geometry.x+fishEnd.geometry.width+100){ cell.geometry.x+=dx; var size=cell.geometry.x-(fishEnd.geometry.x+fishEnd.geometry.width); fishBody.geometry.width+=Math.abs(size-100); fishEnd.geometry.x+=size-100; fishBody.geometry.x+=size-100; } else{ cell.geometry.x+=dx; } } else if(cell.id==‘fishboneHead‘){ var fishHead=_this.getCellById(‘fishboneHead‘); var fishBody=_this.getCellById(‘fishboneBody‘); var children=_this.getChildSubject(fishHead); var maxX=children.length>0?children[0].geometry.x:fishHead.geometry.x-30; for(var i=0;i<children.length;i++){ if(children[i].geometry.x>maxX){ maxX=children[i].geometry.x; } } var oldX=fishHead.geometry.x; fishHead.geometry.x+=dx; var size=fishHead.geometry.x-oldX; if(fishHead.geometry.x<maxX+100){ fishHead.geometry.x=maxX+100; size = fishHead.geometry.x-oldX; } fishBody.geometry.width+=size; } else if(cell.id==‘fishboneEnd‘){ var fishHead=_this.getCellById(‘fishboneHead‘); var fishBody=_this.getCellById(‘fishboneBody‘); var fishEnd=_this.getCellById(‘fishboneEnd‘); var children=_this.getChildSubject(fishHead); var minX=children.length>0?children[0].geometry.x:fishEnd.geometry.x-100; for(var i=0;i<children.length;i++){ if(children[i].geometry.x<minX){ minX=children[i].geometry.x; } } var oldX=fishEnd.geometry.x; fishEnd.geometry.x+=dx; var size=fishEnd.geometry.x-oldX; if(fishEnd.geometry.x>minX-100){ fishEnd.geometry.x=minX-100; size=fishEnd.geometry.x-oldX; } fishBody.geometry.x=fishEnd.geometry.x+fishEnd.geometry.width; fishBody.geometry.width-=size; } else if (cell.direction == ‘top‘ || cell.direction == ‘bottom‘) { if(cell.parent.children.length==1){ cell.geometry.x=0; cell.parent.geometry.width-=dx; cell.parent.geometry.x+=dx; if(cell.parent.geometry.width<=70){ cell.parent.geometry.width=70; cell.parent.geometry.x=-70; } } else{ if(cell.geometry.x==0){ if(dx<0){ for(var i=0;i<cell.parent.children.length;i++){ if(cell.parent.children[i].id!=cell.id){ cell.parent.children[i].geometry.x-=dx; } } cell.parent.geometry.width-=dx; cell.parent.geometry.x+=dx; cell.geometry.x=0; } else{ if(cell.parent.children.length==1){ if(cell.geometry.x+dx<cell.parent.geometry.width-70){ cell.geometry.x+=dx; }else{ cell.geometry.x=cell.parent.geometry.width-70; } } else{ var children=cell.parent.children; var temp1=children[0];//最小y坐標的cell var t=0; for (var i = 0; i < children.length; i++) { if (children[i].geometry.x < temp1.geometry.x) { temp1 = children[i]; } if(children[i].geometry.x==0){ t++; } } var temp2=null;//第二小x坐標的cell for (var i = 0; i < children.length; i++) { if (children[i].geometry.x > cell.geometry.x && !temp2) { temp2=children[i]; continue; }else if(temp2) { if (children[i].geometry.x < temp2.geometry.x && children[i].id != cell.id) { temp2 = children[i]; } } } if(temp2 && t==1) { //沒有超過第二小x坐標 if (temp2.geometry.x - dx > 0) { for (var k = 0; k < cell.parent.children.length; k++) { if (cell.parent.children[k].id != cell.id) { cell.parent.children[k].geometry.x -= dx; } } cell.geometry.x += dx; cell.parent.geometry.width -= dx; cell.parent.geometry.x += dx; cell.geometry.x = 0; } //超過第二小x坐標 else { if(cell.parent.geometry.width-temp2.geometry.x==70){ for (var k = 0; k < cell.parent.children.length; k++) { cell.parent.children[k].geometry.x=0; } cell.parent.geometry.width=70; cell.parent.geometry.x=-70; }else { var size = dx - temp2.geometry.x; var pSize = cell.parent.geometry.width - temp2.geometry.x; for (var k = 0; k < cell.parent.children.length; k++) { if (cell.parent.children[k].id != temp2.id && cell.parent.children[k].id != cell.id) { cell.parent.children[k].geometry.x -= temp2.geometry.x; } } cell.parent.geometry.width -= temp2.geometry.x; cell.parent.geometry.x += temp2.geometry.x; temp2.geometry.x = 0; if(size-pSize>0){ cell.geometry.x = cell.parent.geometry.width-70; } else { cell.geometry.x = size; } } } } else if(t>1){ if(cell.geometry.x+dx<cell.parent.geometry.width-70){ cell.geometry.x+=dx; }else{ cell.geometry.x=cell.parent.geometry.width-70; } } } } } else{ if(cell.geometry.x+dx<0){ var size = 0-(cell.geometry.x+dx); for (var i = 0; i < cell.parent.children.length; i++) { if (cell.parent.children[i].id !=cell.id) { cell.parent.children[i].geometry.x+=size; } } cell.parent.geometry.x-=size; cell.parent.geometry.width+=size; cell.geometry.x=0; } else if(cell.geometry.x+dx==0){ cell.geometry.x=0; } else if(cell.geometry.x+dx>0 && cell.geometry.x+dx<cell.parent.geometry.width-70){ cell.geometry.x+=dx; } else{ cell.geometry.x=cell.parent.geometry.width-70; } } } } else if(cell.direction == ‘left‘){ var py = 0; var myCell=cell; if(cell.parent.direction==‘bottom‘) { cell.geometry.y += dy; for (var i = 0; i < cell.parent.children.length; i++) { if (cell.parent.children[i].geometry.y > py) py = cell.parent.children[i].geometry.y; } if(py>70) { cell.parent.geometry.height = py; }else{ cell.parent.geometry.height = 70; } if(cell.geometry.y<70){ cell.geometry.y=70; } } else{ if(cell.geometry.y==0){ if(dy<0) { for (var i = 0; i < cell.parent.children.length; i++) { if (cell.parent.children[i].id != cell.id) { cell.parent.children[i].geometry.y -= dy; } } cell.parent.geometry.y += dy; cell.parent.geometry.height -= dy; } else{ //只有一個子集的時候 if(cell.parent.children.length==1){ var fishBody=_this.getCellById(‘fishboneBody‘); //拖動超過父級label的位置 if(!(cell.geometry.y==0 && cell.parent.geometry.height==70)) { if (cell.parent.geometry.height - dy < 70) { if(cell.parent.parent.id==1){ cell.parent.geometry.y = fishBody.geometry.y - 68; }else{ cell.parent.geometry.y = cell.parent.parent.geometry.y - 70; } cell.parent.geometry.height = 70; } else { cell.parent.geometry.height -= dy; cell.parent.geometry.y += dy; } cell.geometry.y = 0; } } else {//超過一個子集 var children=cell.parent.children; var temp1=children[0];//最小y坐標的cell var t=0; for (var i = 0; i < children.length; i++) { if (children[i].geometry.y < temp1.geometry.y) { temp1 = children[i]; } if(children[i].geometry.y==0){ t++; } } var temp2=null;//第二小y坐標的cell for (var i = 0; i < children.length; i++) { if (children[i].geometry.y > temp1.geometry.y && !temp2) { temp2=children[i]; continue; }else if(temp2) { if (children[i].geometry.y < temp2.geometry.y && children[i].id != temp1.id) { temp2 = children[i]; } } } //當沒有超過第二小y坐標時。 if(temp2 && t==1) { if (cell.geometry.y + dy < temp2.geometry.y) { for (var k = 0; k < cell.parent.children.length; k++) { if (cell.parent.children[k].id != cell.id) { cell.parent.children[k].geometry.y -= dy; } } cell.parent.geometry.height -= dy; cell.parent.geometry.y += dy; cell.geometry.y = 0; } //當超過第二小y坐標時候 else { cell.geometry.y += dy; var py = cell.parent.geometry.height - (cell.parent.geometry.height - temp2.geometry.y); for (var k = 0; k < cell.parent.children.length; k++) { if (cell.parent.children[k].id != temp2.id) { cell.parent.children[k].geometry.y -= py; } } cell.parent.geometry.height -= temp2.geometry.y; cell.parent.geometry.y += temp2.geometry.y; temp2.geometry.y = 0; for (var j = 0; j < cell.parent.children.length; j++) { if (cell.parent.geometry.height - cell.parent.children[j].geometry.y < 70) { cell.parent.children[j].geometry.y = cell.parent.geometry.height - 70; } } } } else if(t>1){ if(cell.parent.geometry.height>70) { if (cell.parent.geometry.height - dy < 70) { cell.geometry.y = 70; } else { cell.geometry.y = dy; } } } } } } else{ if(cell.geometry.y+dy>0){ if(cell.parent.geometry.height-(cell.geometry.y+dy)<=70){ cell.geometry.y=cell.parent.geometry.height-70; }else { cell.geometry.y += dy; } }else{ for (var i = 0; i < cell.parent.children.length; i++) { if (cell.parent.children[i].id != cell.id) { cell.parent.children[i].geometry.y -= (cell.geometry.y+dy); } } cell.parent.geometry.y += (cell.geometry.y+dy); cell.parent.geometry.height -= cell.geometry.y+dy; cell.geometry.y=0; } } } } } finally { this.getModel().endUpdate(); this.refresh(); } } return cells; }; mxGraph.prototype.dblClick = function(evt, cell) { if(cell.id!=‘fishboneEnd‘ && cell.id!=‘fishboneBody‘ && !cell.isEdge()) { var mxe = new mxEventObject(mxEvent.DOUBLE_CLICK, ‘event‘, evt, ‘cell‘, cell); this.fireEvent(mxe); if (this.isEnabled() && !mxEvent.isConsumed(evt) && !mxe.isConsumed() && cell != null && this.isCellEditable(cell)) { this.startEditingAtCell(cell, evt); } } }; // mxGraph.prototype.labelChanged = function(cell, value, evt) { // this.model.beginUpdate(); // var geo=cell.geometry; // try { // this.cellLabelChanged(cell, value, true); // this.fireEvent(new mxEventObject(mxEvent.LABEL_CHANGED, ‘cell‘, cell, ‘value‘, value, ‘event‘, evt)); // geo.height =geo.height+((value.length-5>0)? (value.length-5)*18:0); // cell.geometry=geo; // if(cell.level>1){ //// var myEdge = cell.edges[0]; //// var point = myEdge.geometry.points[0]; //// point.x=0; //// myEdge.geometry.points=[point]; // } // } finally { // this.model.endUpdate(); // } // return cell; // }; mxCellEditor.prototype.init = function() { this.textarea = document.createElement(‘input‘); this.textarea.className = ‘mxCellEditor‘; this.textarea.style.position = ‘absolute‘; this.textarea.style.overflow = ‘visible‘; this.textarea.setAttribute(‘type‘, ‘textbox‘); if (false) { this.textarea.style.resize = ‘none‘; } mxEvent.addListener(this.textarea, ‘blur‘, mxUtils.bind(this, function(evt) { this.stopEditing(!this.graph.isInvokesStopCellEditing()); })); mxEvent.addListener(this.textarea, ‘keydown‘, mxUtils.bind(this, function(evt) { if (!mxEvent.isConsumed(evt)) { if (evt.keyCode == 113 || (this.graph.isEnterStopsCellEditing() && evt.keyCode == 13 && !mxEvent.isControlDown(evt) && !mxEvent.isShiftDown(evt))) { this.graph.stopEditing(false); mxEvent.consume(evt); } else if (evt.keyCode == 27) { this.graph.stopEditing(true); mxEvent.consume(evt); } else { if (this.clearOnChange) { this.clearOnChange = false; this.textarea.value = ‘‘; } this.setModified(true); } } })); }; mxGraphHandler.prototype.selectEnabled=false; }; fishBone.prototype.buildCanvas=function(){ var container = document.createElement(‘div‘); container.style.position = ‘absolute‘; container.style.overflow = ‘hidden‘; container.style.left = ‘0px‘; container.style.top = ‘0px‘; container.style.right = ‘0px‘; container.style.bottom = ‘0px‘; document.body.appendChild(container); var node = mxUtils.load(‘config/keyhandler-commons.xml‘).getDocumentElement(); this.editor = new mxEditor(node); this.editor.graph=new mxGraph(container); this.graph = this.editor.graph; var outline = document.getElementById(‘outlineContainer‘); new mxOutline(this.graph, outline); if (mxClient.IS_IE) { new mxDivResizer(container); new mxDivResizer(outline); } this.graph.clearSelection(); this.graph.setEnabled(true); this.graph.setTooltips(false); this.graph.setConnectable(false); this.graph.setPanning(true); this.graph.setCellsResizable(false); }; fishBone.prototype.setCanvasStyle=function(){ var graph=this.graph; var style = graph.getStylesheet().getDefaultVertexStyle(); style[mxConstants.STYLE_FONTCOLOR] = ‘black‘; style[mxConstants.STYLE_STROKECOLOR] = ‘#8E8E8E‘; style[mxConstants.STYLE_FILLCOLOR] = ‘white‘; style[mxConstants.STYLE_ROUNDED] = true; style[mxConstants.STYLE_FONTSTYLE] = 1; style[mxConstants.STYLE_FONTFAMILY] = ‘微軟雅黑‘; // Sets the default style for edges style = graph.getStylesheet().getDefaultEdgeStyle(); style[mxConstants.STYLE_ROUNDED] = true; style[mxConstants.STYLE_EDGE] = mxEdgeStyle.STRAIGHT; // Enables rubberband selection and key handling var rubberband = new mxRubberband(graph); var keyHandler = new mxKeyHandler(graph); }; fishBone.prototype.buildContextMenu=function(){ var fish=this; mxPopupMenu.prototype.submenuImage = ‘src/images/submenu.gif‘; this.graph.panningHandler.factoryMethod = function (menu, cell, evt) { if (cell != null && !cell.isEdge() && cell.id!=‘fishboneEnd‘ && cell.id!=‘fishboneBody‘) { var item= menu.addItem(‘插入‘,‘src/images/maximize.gif‘); menu.addItem(‘插入主題‘,‘src/images/maximize.gif‘, function () { fish.createSubject(cell); fish.graph.clearSelection(); },item); menu.addItem(‘插入子主題‘,‘src/images/normalize.gif‘, function () { fish.createSubject(cell,true); fish.graph.clearSelection(); },item); menu.addItem(‘刪除‘,‘images/delete2.png‘, function () { fish.graph.removeCells([cell]); }); menu.addItem(‘編輯‘,‘images/icons48/tab.png‘, function () { fish.graph.startEditingAtCell(cell); }); }else{ this.graph.clearSelection(); }; }; }; fishBone.prototype.createFishBone=function(){ var xml = ‘ <mxGraphModel> <root> <mxCell id="0"/> <mxCell id="1" parent="0"/> <mxCell id="fishboneEnd" value="" parent="1" vertex="1" style="shape=triangle;direction=east1;fillColor=#CEFFCE;gradientColor=#93FF93;"> <mxGeometry x="510" y="240" width="40" height="110" as="geometry"/> </mxCell> <mxCell id="fishboneBody" value="" vertex="1" parent="1" style="shape=triangle;direction=west;fillColor=#4F4F4F;"> <mxGeometry x="550" y="290" width="800" height="10" as="geometry"/> </mxCell> <mxCell id="fishboneHead" level="0" value="需要解決的問題" vertex="1" parent="1" style="shape=triangle;direction=east;fillColor=#CEFFCE;gradientColor=#93FF93;fontSize=18;"> <mxGeometry x="1351" y="252" width="150" height="80" as="geometry"/> </mxCell> </root> </mxGraphModel> ‘; doc = mxUtils.parseXml(xml); var codec = new mxCodec(doc); //mxShape.prototype.direction = mxConstants.DIRECTION_NORTH; codec.decode(doc.documentElement, this.graph.getModel()); var items=[‘人員‘,‘管理‘,‘過程‘,‘環境‘,‘設備‘,‘材料‘]; var cell=this.getCellById(‘fishboneHead‘); for(var i=0;i<items.length;i++) { this.createSubject(cell, true,items[i]); }; }; fishBone.prototype.createSubject=function(cell,isSub,text){ var model=this.graph.getModel(); var graph=this.graph; var fish=this; var x = 0, y = 0, py = 0, px = 0; var myChild = fish.getChildSubject(cell); if(!cell.children)cell.children=[]; //子主題在下方,插入子主題方向錯誤 //子主題在右側,插入子主題方向錯誤 /*水平方向子主題*/ var insertHorizontalSubLevel=function(){ var selfTopParent = fish.getSelfTopParent(cell); if (!text)text = ‘分支主題‘ + (cell.children.length + 1); x = -70; if(selfTopParent.direction==‘bottom‘) { if (cell.children.length == 0) { y = 70; } else { y += cell.geometry.height+70; } var myCell = graph.insertVertex(cell, null, text, x, y, 70, 1, ‘shape=line;verticalAlign=top;align=right;strokeWidth=1;strokeColor=#BB3D00;‘); myCell.level = cell.level + 1; myCell.direction = ‘left‘; myCell.geometry.x -= 70; if (myCell.parent.parent.direction == ‘left‘) { myCell.parent.parent.geometry.height = 1; } var resize = function (cell) { if (cell.parent.direction == ‘bottom‘ && cell.parent.level > 1) { if (cell.parent.parent.children.length > 1 && cell.parent.children.length == 1 && cell.parent.geometry.x > 0) { for (var k = 0; k < cell.parent.parent.children.length; k++) { if (cell.parent.parent.children[k].geometry.x >= cell.parent.geometry.x && cell.parent.children.length == 1) { cell.parent.parent.children[k].geometry.x += 50; cell.parent.parent.geometry.x -= 50; cell.parent.parent.geometry.width += 50; } } } cell.parent.geometry.height = cell.parent.children[cell.parent.children.length - 1].geometry.y; } else { cell.parent.geometry.height = 1; } if (cell.parent.level != 1) { resize(cell.parent); } else { cell.parent.geometry.height = cell.parent.children[cell.parent.children.length - 1].geometry.y; } }; resize(myCell); } else{ y = 0; for(var i=0;i<cell.children.length;i++){ cell.children[i].geometry.y+=70; } if(cell.children.length>0) { cell.geometry.height += 70; cell.geometry.y -= 70; } var myCell = graph.insertVertex(cell, null, text, x, y, 70, 1, ‘shape=line;verticalAlign=top;align=right;strokeWidth=1;strokeColor=#BB3D00;‘); myCell.level = cell.level + 1; myCell.direction = ‘left‘; myCell.geometry.x -= 70; if (myCell.parent.parent.direction == ‘left‘) { myCell.parent.parent.geometry.height = 1; } var resize = function (cell) { if(cell.direction==‘top‘ && cell.level!=1 && cell.children.length==1){ for(var k=cell.parent.children.length-1;k>=0;k--){ if(cell.parent.children[k].geometry.x>=cell.geometry.x){ cell.parent.children[k].geometry.x+=cell.children[0].geometry.width; } } cell.geometry.x-=myCell.geometry.width; } }; resize(myCell.parent); } }; /*垂直方向子主題*/ var insertVerticalSubLevel=function(){ var selfTopParent = fish.getSelfTopParent(cell); var leftTopParents=fish.getLeftTopParent(selfTopParent,true); if (!text)text = ‘分支主題‘+(cell.children.length+1); if(cell.children.length==0) x=0; else { var maxX=0; for(var i=0;i<cell.children.length;i++){ if(cell.children[i].geometry.x>maxX){ maxX=cell.children[i].geometry.x; } } x = 50 + maxX; } var align=‘right‘; var direction=‘bottom‘; if(selfTopParent.direction==‘bottom‘) { y = 1; }else{ y=0; align=‘left‘; direction=‘top‘; } var myCell = graph.insertVertex(cell, null, text, x, y, 1, 70, ‘shape=line;direction=north;verticalAlign=top;align=‘+align+‘;spacingBottom=10;strokeWidth=1;strokeColor=#BB3D00;‘); myCell.parentId = cell.id; myCell.level=cell.level+1; myCell.direction=direction; if(selfTopParent.direction==‘bottom‘) { if (cell.children.length == 1) { var t = 0; for (var i = 0; i < cell.parent.children.length; i++) { if (cell.parent.children[i].id != cell.id && cell.parent.children[i].geometry.y > cell.geometry.y) { cell.parent.children[i].geometry.y += myCell.geometry.height; t++; } } if (t > 0) { selfTopParent.geometry.height += myCell.geometry.height; } }; var resize = function (cell) { var parent = cell.parent; if(parent.id!=1) { if (cell.direction == ‘left‘)cell.geometry.height = 1; if (parent.direction == ‘left‘) { parent.geometry.height = 1; if (parent.children.length > 1 && cell.geometry.x > 0) { parent.geometry.width += 50; parent.geometry.x -= 50; } resize(parent); } else { parent.geometry.height = parent.children[parent.children.length - 1].geometry.y; if (parent.level != 1 && parent.parent.children.length > 1 && cell.parent.geometry.x > 0) { for (var k = 0; k < parent.parent.children.length; k++) { if (parent.parent.children[k].geometry.x >= parent.geometry.x) parent.parent.children[k].geometry.x += 50; } } resize(parent); } } }; resize(myCell); } else{ myCell.geometry.y-=70; var t=0; if (cell.children.length == 1&&cell.geometry.y>0) { for (var i = 0; i < cell.parent.children.length; i++) { if(cell.parent.children[i].geometry.y>0 && cell.parent.children[i].geometry.y>=cell.geometry.y){ cell.parent.children[i].geometry.y+=cell.geometry.height; t++; } } cell.parent.geometry.height += myCell.geometry.height; cell.parent.geometry.y -= myCell.geometry.height; }; var resize = function (cell) { if (cell.direction == ‘left‘) { cell.geometry.height = 1; if(cell.children.length>1){ for (var k = 0; k < cell.children.length; k++) { if (cell.children[k].geometry.x <= cell.geometry.x) cell.children[k].geometry.x += 50; } cell.geometry.x-=50; cell.geometry.width+=50; } } else { if(cell.children.length>1){ for (var k = 0; k < cell.children.length; k++) { if (cell.children[k].geometry.x >= cell.geometry.x) cell.children[k].geometry.x += 50; } cell.geometry.x-=50; } } }; resize(myCell.parent); } }; var insertTopLevel=function(){ var direction=‘bottom‘; if(myChild.length%2==0){ direction=‘top‘; } model.beginUpdate(); x = cell.geometry.x - (myChild.length / 2 * 100) - (myChild.length + 1) * 30; if(myChild.length>0) { x = myChild[0].geometry.x; for (var t = 0; t < myChild.length; t++) { if (myChild[t].geometry.x < x) { x = myChild[t].geometry.x; } } } x-=100; if (myChild.length % 2 == 0) { y = cell.geometry.y - 30; } else { y = cell.geometry.y + 45; } if (!text)text = ‘分支主題‘; var vAlign=‘top‘; var dir=‘north‘; var align=‘right‘; if (myChild.length % 2 == 0) { vAlign=‘bottom‘; dir=‘south‘; align=‘left‘; } var myCell = graph.insertVertex(graph.getDefaultParent(), null, text, x, y, 1, 70, ‘shape=line;align=‘+align+‘;verticalAlign=‘+vAlign+‘;direction=‘+dir+‘;verticalLabelPosition=middle;fontSize=18;strokeWidth=1;strokeColor=#8C8C00;‘); myCell.parentId = cell.id; myCell.level=cell.level+1; myCell.direction=direction; model.endUpdate(); graph.clearSelection(); }; var insert=function(){ if(cell.level==0){ insertTopLevel(); }else{ if(isSub){ insertSubLevel(); }else{ insertSameLevel(); } } }; var insertSameLevel=function(){ if(cell.level){ if(cell.level==1){ cell=fish.getCellById(‘fishboneHead‘); myChild = fish.getChildSubject(cell); insertTopLevel(); }else{ cell=cell.parent; myChild = cell.children; insertSubLevel(); } }else{ cell=cell.parent; myChild = cell.children; insertTopLevel(); } }; var insertSubLevel=function(){ switch (cell.direction){ case ‘left‘: insertVerticalSubLevel(); break; case ‘top‘: case ‘bottom‘: insertHorizontalSubLevel(); break; } graph.refresh(); }; insert(); }; fishBone.prototype.getChildSubject=function(cell){ var allCells=this.graph.model.root.children[0].children; var children=[]; for(var i=0;i<allCells.length;i++){ if(allCells[i].parentId==cell.id){ children.push(allCells[i]); } } return children; }; fishBone.prototype.getCellById=function(id){ var allCells=this.graph.model.root.children[0].children; for(var i=0;i<allCells.length;i++){ if(allCells[i].id==id){ return allCells[i]; } } return null; }; /* * 獲取當前主題的1級主題 * */ fishBone.prototype.getSelfTopParent=function(cell){ if(cell.level==1){ return cell; }else{ if(cell.parent.level==1){ return cell.parent; }else{ return this.getSelfTopParent(cell.parent); } } }; /* * 獲取左側所有1級主題 * */ fishBone.prototype.getLeftTopParent=function(selfParentCell,isBottom){ var allCells=this.graph.model.root.children[0].children; var arr=[]; for(var i=0;i<allCells.length;i++){ if(isBottom){ if(allCells[i].level==1 && allCells[i].direction==‘bottom‘ && allCells[i].geometry.x<selfParentCell.geometry.x){ arr.push(allCells[i]); } }else{ } } return arr; }; /* * 獲取除自己以外的1級主題 * */ fishBone.prototype.getOtherTopParentCell=function(selfParentCell){ var allCells=this.graph.model.root.children[0].children; var allTopParentCell=[]; for(var i=0;i<allCells.length;i++){ if(allCells[i].level==1 && allCells[i].id!=selfParentCell.id){ allTopParentCell.push(allCells[i]); } } return allTopParentCell; }
mxGraph實現魚骨圖(因果圖)(轉自CSDN,鏈接附於文中)