首页 > 代码库 > mxGraph实现鱼骨图(因果图)
mxGraph实现鱼骨图(因果图)
鱼骨图由日本管理大师石川馨先生所发明,故又名石川图。鱼骨图是一种发现问题“根本原因”的方法,它也可以称之为“Ishikawa”或者“因果图”。其特点是简捷实用,深入直观。它看上去有些象鱼骨,问题或缺陷(即后果)标在"鱼头"外。在鱼骨上长出鱼刺,上面按出现机会多寡列出产生生产问题的可能原因,有助于说明各个原因之间如何相互影响。
这玩意儿就体现了一个什么5w1h的管理方法,经过我将近4周的时间捣鼓。由于原先想实现的过于复杂(主要由于本人数学知识浅薄),后来放弃了原先的两个方案。一是分支斜线扩展;二是分支上下、左右扩展。
不知道写点个啥,直接上代码吧。
/** * 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 = http://www.mamicode.com/'';>mxGraph实现鱼骨图(因果图)
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。