項目中須要使用G6-Editor。現寫個文章記錄下。
思路:
到github上面將官網的例子下下來(官網使用react寫,項目是使用vue寫,可是二者差很少)。接着結合官網的例子和api,弄個demo出來。而後一步步優化和完善。html
步驟:
界面佈局->toolbar->itemPanel->minimap->page->detailpannel->contextmenu->優化完善vue
參考官網的例子時,有如下須要注意:
1.樣式也要引入。 官網的一些效果和例子也有關係的。好比detailPanel面板。我一開始作的時候只引入了代碼,樣式文件沒引入。這樣是沒有點擊node顯示node相關的面板,點擊edge顯示edge相關的面板這種效果(個人效果是detailPanel那邊的內容所有顯示,不會根據node、edge動態區分)。後面找了半天才發現是本身樣式沒引入致使的。(官網的樣式默認detailPanel那邊隱藏起來,display:none。可是這個我沒寫)。
2.demo是使用react寫的,使用的是react語法,不能直接搬運。 我參考例子的時候,寫了個XX.setState()。 而後就報錯了。一開始沒有想到是react的專有語法,還覺得本身用的哪裏不對,而後又使用g6 1.2.8版本去寫編輯器,後面忽然反應過來的,而後又換成g6-editor來寫。
這兩點都說明在寫的時候須要細心點。
3.g6-editor 的api很短。因此不少東西須要去官方的demo裏面找,g6的demo裏面找。(沒辦法,誰讓他api很不完善。找着找着也就會玩了。) 還有一個辦法是打debugger。在editor和page那邊打debugger。而後在控制檯那邊顯示出來,看看他們有哪些屬性和方法。node
但願g6-editor的文檔儘快完善,如今真的不怎麼方便。react
最後效果:git
代碼:github
<template xmlns="http://www.w3.org/1999/html"> <div class="container-fluid" ref = "container"> <div class="editor"> <!-- 工具欄 DOM 結構規約參考 Toolbar API --> <div id="toolbar"> <i data-command="back" class="command iconfont icon-back" title="返回" ></i> <span class="separator"></span> <i data-command="undo" class="command iconfont icon-undo" title="撤銷"></i> <i data-command="redo" class="command iconfont icon-redo" title="重作"></i> <span class="separator"></span> <i data-command="addBeginNode" class="command iconfont icon-add-begin-node" title="新增起始節點"></i> <i data-command="copy" class="command iconfont icon-copy-o" title="複製"></i> <i data-command="paste" class="command iconfont icon-paster-o" title="粘貼"></i> <i data-command="delete" class="command iconfont icon-delete-o" title="刪除"></i> <i data-command="clear" class="command iconfont icon-clear" title="清空畫布"></i> <span class="separator"></span> <i data-command="zoomIn" class="command iconfont icon-zoom-in-o" title="放大"></i> <i data-command="zoomOut" class="command iconfont icon-zoom-out-o" title="縮小"></i> <i data-command="autoZoom" class="command iconfont icon-fit" title="適應畫布"></i> <i data-command="resetZoom" class="command iconfont icon-actual-size-o" title="實際尺寸"></i> <span class="separator"></span> <i data-command="toBack" class="command iconfont icon-to-back" title="層級後置"></i> <i data-command="toFront" class="command iconfont icon-to-front" title="層級前置"></i> <span class="separator"></span> <i data-command="multiSelect" class="command iconfont icon-select" title="多選"></i> <span class="separator"></span> <i data-command="save" class="command iconfont icon-save" title="保存"></i> </div> <div style="height:42px;"></div> <div class="editor-content"> <!-- 元素面板欄 DOM 結構規約參考 Itempannel API --> <div id="itempannel"> <div class="getItem" data-type="node" data-shape="flow-rect" data-size="120*48" data-color="#1890FF"> <img draggable="false" src="../../../assets/images/condition-node.png"/> </div> <div class="getItem" data-type="node" data-shape="flow-capsule" data-size="80*48" data-color="#FD0DFF"> <img draggable="false" src="../../../assets/images/message-node.png"/> </div> </div> <div class="right-side"> <!-- 詳情面板欄 DOM 結構規約參考 Detailpannel API --> <div id="detailpannel"> <div data-status="node-selected" class="pannel"> <div class="pannel-title">節點屬性欄</div> <div class="pannel-container"> <el-form ref="form" label-width="80px"> <el-form-item label="條件" v-if="showCond"> <el-select v-model="condType" placeholder="請選擇條件" @change="condTypeSelectChange"> <el-option v-for="(cItem, cIndex) in conditionList" :label="cItem.name" :value="cItem.code" :key="cIndex"></el-option> </el-select> </el-form-item> <el-form-item label="判斷方法" v-if="showOperator"> <el-select v-model="operator" @change="enableChangeData"> <el-option v-for="(oItem, oIndex) in operatorList" :label="oItem.name" :value="oItem.code" :key="oIndex"></el-option> </el-select> </el-form-item> <el-form-item label="值" v-if="showValue"> <el-select v-model="value" @change="enableChangeData" filterable> <el-option v-for="(vItem, vIndex) in valueList" :label="vItem.name" :value="vItem.code" :key="vItem.code"></el-option> </el-select> </el-form-item> <el-form-item label="疾病" v-if="showDisease"> <el-badge :value="diseaseSelectedLength" class="item"> <div title="選擇既往史" class="btn btn-disease-setting" @click = "showDiseaseDialog"><i class="ti-settings"></i></div> </el-badge> </el-form-item> <el-form-item label="級別" v-if="showGrade"> <el-col :span="11"> <el-select v-model="grade" @change="enableChangeData"> <el-option v-for="(gItem, gIndex) in gradeList" :label="gItem.name" :value="gItem.code" :key="gIndex"></el-option> </el-select> </el-col> <el-col class="line" :span="2"></el-col> <el-col :span="11"> <el-color-picker v-model="color" size="medium" :disabled="true"></el-color-picker> </el-col> </el-form-item> <el-form-item label="程度" v-if="showGrade"> <el-col :span="9"> <el-select v-model="level" @change="enableChangeData"> <el-option v-for="(lItem, lIndex) in levelList" :label="lItem.name" :value="lItem.code" :key="lIndex"></el-option> </el-select> </el-col> <el-col class="line" :span="6">字體</el-col> <el-col :span="9"> <el-input v-model="fontSize" :disabled="true"> </el-input> </el-col> </el-form-item> </el-form> </div> </div> <div data-status="edge-selected" class="pannel"> <div class="pannel-title">邊屬性欄</div> <div class="pannel-container"></div> </div> <div data-status="group-selected" class="pannel"> <div class="pannel-title">羣組屬性欄</div> <div class="pannel-container"></div> </div> <div data-status="canvas-selected" class="pannel"> <div class="pannel-title">畫布屬性欄</div> <div class="pannel-container"></div> </div> <div data-status="multi-selected" class="pannel"> <div class="pannel-title">多選時屬性欄</div> <div class="pannel-container"></div> </div> </div> <div id="navigator"> <div class="pannel-title">縮略圖</div> <!-- 縮略圖 DOM 結構規約參考 Minimap API --> <div id="minimap"></div> <div class="zoom-slider"> <div class="slider-outer-ctn"> <el-slider v-model="zoomSlider" :format-tooltip="formatTooltip" @change="changeZoom" :min="minZoom * 100" :max="maxZoom * 100"></el-slider> </div> <el-dropdown class="dropdown-inner-ctn" @command="handleDropdownChange"> <span class="el-dropdown-link"> {{Math.ceil(curZoom * 100)}} %<i class="el-icon-arrow-down el-icon--right"></i> </span> <el-dropdown-menu slot="dropdown"> <el-dropdown-item command="0.5">50%</el-dropdown-item> <el-dropdown-item command="1">100%</el-dropdown-item> <el-dropdown-item command="1.5">150%</el-dropdown-item> <el-dropdown-item command="2">200%</el-dropdown-item> </el-dropdown-menu> </el-dropdown> </div> </div> </div> <!-- 右鍵菜單欄 DOM 結構規約參考 Contextmenu API --> <div id="contextmenu"> <div data-status="node-selected" class="menu"> <div data-command="copy" class="command">複製</div> <div data-command="paste" class="command">粘貼</div> <div data-command="delete" class="command">刪除</div> </div> <div data-status="edge-selected" class="menu"> <div ton data-command="delete" class="command">刪除</div> </div> <div data-status="group-selected" class="menu"> <div data-command="copy" class="command">複製</div> <div data-command="paste" class="command">粘貼</div> <div data-command="unGroup" class="command">解組</div> <div data-command="delete" class="command">刪除</div> </div> <div data-status="canvas-selected" class="menu"> <div data-command="undo" class="command">撤銷</div> <div data-command="redo" class="command disable">重作</div> </div> <div data-status="multi-selected" class="menu"> <div data-command="copy" class="command">複製</div> <div data-command="paste" class="command">粘貼</div> </div> </div> <!-- 參考 Flow、Mind API --> <div id="page"></div> </div> </div> <!--疾病選擇彈窗 start--> <el-dialog :custom-class = "diseaseDialogClass" title="選擇疾病" :visible.sync="diseaseDialogVisible" @closed = "diseaseDialogClosed" > <base-table :columns="diseaseColumns" :tableClass = "diseaseTableClass" ref="diseaseTable" :hasSelect = "true" :isInitTableOnInit = "false" :url = "diseaseUrl" :getParamsFn = "diseaseGetParamsFn" :height = "250" :tableHeadClass = "diseaseTableHeadClass" @afterRenderData = "afterRenderData" @select = "diseaseSelect" @selectAll = "diseaseSelectAll" > </base-table> <div class = "select-disease-title" >已選擇項</div> <div class = "select-disease-list" > <el-tag v-for="(item, index) in selectDiseases" :key="item.id" @close="handleDiseaseClose(item, index)" closable> {{item.name}} </el-tag> </div> <span slot="footer" class="dialog-footer"> <el-button @click="diseaseDialogVisible = false">取 消</el-button> <el-button type="primary" @click="submitSelectDisease">確 定</el-button> </span> </el-dialog> <!--疾病選擇彈窗 end--> </div> </template> <script type="text/ecmascript-6"> import {isEmptyStr, objCopy, errorMsg, successMsg} from '@/common/public' import G6Editor from '@antv/g6-editor'; import G6 from '@antv/g6'; import '@antv/g6/build/plugin.tool.tooltip'; import BaseTable from 'components/base/table/baseTable' /** * anchor某些狀況下不起做用(尤爲是本身畫的圖很亂時,g6會本身調節) */ //http://localhost:8080/#/IntelligentKnowledge/diseaseGradeRuleEditor?diseaseId=3a026d64-0b3f-4a19-9872-cff095742e0d&diseaseName=%E5%94%87%E6%81%B6%E6%80%A7%E8%82%BF%E7%98%A4 export default { components : { BaseTable }, data() { return { conditionList : [], //條件列表 operatorList : [], //操做符列表 valueList : [], //條件的值列表 operatorMap : {}, //操做符對象 valueMap : {}, //條件值對象 gradeList : [ { name : "Ⅰ級", code : 1 }, { name : "Ⅱ級", code : 2 }, { name : "Ⅲ級", code : 3 }, { name : "Ⅳ級", code : 4 } ], //級別列表 levelList : [ { name : "1級", code : 1 }, { name : "2級", code : 2 }, { name : "3級", code : 3 }, { name : "4級", code : 4 } ], //程度列表 colorList : [ "#CC0033", "#F51C0A", "#B0085D", "#FF6666" ], //級別顏色列表 fontSizeList : [24, 20, 16, 12], editor : null, selectedModel : {}, // 當前選中項數據模型 curZoom : 1, // 當前縮放比率 minZoom : 0.5, // 最小縮放比率 maxZoom : 2, // 最大縮放比率 condType : "", operator : "", value : "", grade : "", level : "", fontSize : "", color : "red", /*控制右側詳情面板的內容顯現 start*/ showGrade : false, showOperator : false, showCond : false, showValue : true, showDisease : false, /*控制右側詳情面板的內容顯現 end*/ changeData : false, zoomSlider : 100, //默認滑塊取值爲100 valueFilterable : false, //值下拉框是否能夠檢索 /*疾病選擇彈窗 start*/ diseaseDialogVisible : false, //顯示疾病選擇彈窗 diseaseDialogClass : "disease-select-dialog", diseaseTableClass : "disease-select-table", diseaseTableHeadClass : "no-margin", diseaseColumns : [ { label : "名稱", prop : "name" }, { label : "編碼", prop : "code", width : "200" } ], diseaseUrl : "/diagnosisClassify/getClassifyToBeGradedPage", selectDiseases : [], //已選疾病列表 /*疾病選擇彈窗 end*/ values : [], names : [], diseaseId : this.$route.query.diseaseId, //當前疾病id diseaseName : this.$route.query.diseaseName, //當前疾病名稱 diseaseSelectedLength : 0, //當前已選疾病的條數 hasInitNode : false //是否已經初始化node } }, created(){ this.getAllConditions(); //獲取全部的條件 }, mounted() { this.setEditorHeight(); //設置寬度和高度 this.initG6Editor (true); }, watch : { condType( curValue, oldValue ){ if(this.changeData){ if(curValue == "1"){ this.valueFilterable = true; }else{ this.valueFilterable = false; } if(!isEmptyStr(curValue)) { let label = this.getGraphLabel(); this.updateGraph ({ "condType": curValue, "label" : label } ); } } }, operator( curValue, oldValue ){ if(this.changeData) { if ( !isEmptyStr ( curValue ) ) { let label = this.getGraphLabel(); this.updateGraph ( { "operator": curValue, "label" : label } ); } } }, grade( curValue, oldValue ){ if(this.changeData) { if ( !isEmptyStr ( curValue ) ) { let label = ""; let gradeObj = this.gradeList.find((item)=>{ return item.code == curValue; }); label = gradeObj.name; this.color = this.colorList[curValue - 1]; this.updateGraph({ "label": label, "grade": curValue, "color": this.color }); } } }, level( curValue, oldValue ){ if(this.changeData) { if ( !isEmptyStr ( curValue ) ) { let gradeObj = this.gradeList.find((item)=>{ return item.code == this.grade; }); this.fontSize = this.fontSizeList[this.level - 1]; this.updateGraph({ "level": curValue, "label" : { text : gradeObj.name, fontSize: this.fontSize } }); } } }, value( curValue, oldValue ){ if(this.changeData) { if ( !isEmptyStr ( curValue ) ) { let valueObj = this.valueList.find((item)=>{ return item.code == curValue; }); let label = this.getGraphLabel(); this.updateGraph ({ "label" : label, "value": curValue, "values": [curValue], "names": [valueObj.name] }); } } } }, methods : { setEditorHeight(){ const bodyHeight = document.documentElement.clientHeight || document.body.clientHeight; let containarHeight = bodyHeight - 70; containarHeight = containarHeight < 510 ? 510 : containarHeight; this.$refs['container'].style.height = containarHeight + "px"; }, /** * 獲取全部的條件 */ getAllConditions(){ const _self = this; _self.$http({ url: '/intelliDiag/diseaseGradingRule/getAllConditions', method: 'get', success(res){ _self.conditionList = res.result; _self.getEachOperatorAndValue(); //獲取每一個條件下對應的operator和值 } }); }, /** *根據條件列表,依次獲取各條件下對應的operator和值(目的:將他們緩存起來,減小請求) */ getEachOperatorAndValue(){ this.conditionList.forEach((item, index) =>{ this.getOprsByCondi(item.code); this.getValsByCondi(item.code) }); }, /** * 根據條件獲取操做列表 * @param condiIdx 條件index */ getOprsByCondi(condiIdx){ const _self = this; _self.$http({ url: '/intelliDiag/diseaseGradingRule/getOprsByCondi', method: 'get', data : { condiIdx : condiIdx }, success (res){ _self.operatorMap[condiIdx] = res.result; } }); }, /** * 獲取條件的值列表 */ getValsByCondi( condiIdx, keyWord ){ const _self = this; let size = condiIdx == 4 ? 20 : 0; //既往病史特殊處理 _self.$http ( { url : '/intelliDiag/diseaseGradingRule/getValsByCondi', method : 'get', data : { condiIdx : condiIdx, keyWord : keyWord, size : size }, success( res ){ _self.valueMap[condiIdx] = res.result; } } ); }, getNodesByDiseaseId(diseaseId){ const _self = this; _self.$http({ url: '/intelliDiag/diseaseGradingRule/getNodesByDiseaseId', method: 'get', data : { diseaseId : diseaseId }, success(res){ let nodes = []; let edges = []; const length = res.result.length; const flag = length > 0; //標誌數據是從接口獲取的,仍是自動生成的 if(flag) { for ( let i = 0 ; i < length ; i++ ) { let item = res.result[ i ]; let shape = ""; let color = ""; let label = ""; switch ( item.category ) { case 0 : //起始節點 shape = "circle"; color = "#FA8C16"; label = item.diseaseName; break; case 1 : //條件節點 shape = "flow-rect"; color = "#1890FF"; let conditionObj = _self.conditionList.find ( ( cItem )=> { return cItem.code == item.cond_type; } ); label = conditionObj.name + item.operatorName; if ( item.cond_type == "4" ) { label += ":"; } for ( let k = 0, vlength = item.values.length ; k < vlength ; k++ ) { if ( k === 0 ) { label += item.names[ k ]; } if ( k === 1 ) { label += "(" + item.names[ k ]; } if ( k == 5 ) { //最多顯示前5個疾病 label += ")等" + vlength + "個疾病"; break; } if ( k > 1 ) { label += "、" + item.names[ k ]; } if ( k < 5 && k === vlength - 1 && k >= 1 ) { label += ")"; } } label = _self.transformLabel ( label ).label; break; case 2 : //葉子節點 shape = "flow-capsule"; color = _self.colorList[ item.grade - 1 ]; label = { text : _self.gradeList[ item.grade - 1 ].name, fontSize : _self.fontSizeList[ item.level - 1 ] }; break; } nodes.push ( { id : item.id, label : label, shape : shape, color : color, condType : item.cond_type, cond_type : item.cond_type, disease_id : item.disease_id, grade : item.grade, level : item.level, operator : item.operator, operatorName : item.operatorName, size : item.size, values : item.values, names : item.names, x : item.xaxis, y : item.yaxis, source_anchor : item.source_anchor, target_anchor : item.target_anchor, category : item.category } ); if ( !isEmptyStr ( item.parent_id ) ) { edges.push ({ target : item.id, source : item.parent_id, sourceAnchor : item.source_anchor, targetAanchor : item.target_anchor }); } } }else{ let rootWidth = _self.diseaseName.length * 13; rootWidth = rootWidth < 72 ? 72 : rootWidth; nodes.push({ category : 0, id : _self.diseaseId, shape : "circle", color : "#FA8C16", label : _self.diseaseName, x : 100, y : 100, size : rootWidth + "*72" }); } let data = { nodes : nodes, edges : edges }; const curPage = _self.editor.getCurrentPage (); curPage.read(data); if(flag){ curPage.getGraph().setFitView("autoZoom"); //使圖適應畫布 } _self.hasInitNode = true; } }); }, /** * 設置自定義命令 */ setCustomCommand(){ const _self = this; const Command = G6Editor.Command; //返回上一頁命令 Command.registerCommand("back", { queue: false, // 命令是否進入隊列,默認是 true // 命令是否可用 enable(eidtor) { return true; }, // 正向命令 execute(eidtor) { _self.$router.push("/IntelligentKnowledge/diseaseGradeRule"); } }); //保存命令 Command.registerCommand("save", { queue: false, // 命令是否進入隊列,默認是 true // 命令是否可用 enable(eidtor) { return true; }, // 正向命令 execute(eidtor) { _self.saveGraph(); }, shortcutCodes : [["ctrlKey", "shiftKey", "s"]] //快捷鍵:Ctrl+shirt+s }); //新增起始節點命令 Command.registerCommand("addBeginNode", { queue: true, // 命令是否進入隊列,默認是 true // 命令是否可用 enable(editor) { const curPage = editor.getCurrentPage (); let beginNode = curPage.find(_self.diseaseId); if(!beginNode && _self.hasInitNode){ //起始節點不存在 return true; }else{ return false; } }, // 正向命令 execute(editor) { let rootWidth = _self.diseaseName.length * 13; rootWidth = rootWidth < 72 ? 72 : rootWidth; const curPage = editor.getCurrentPage (); curPage.add("node", { id : _self.diseaseId, shape : "circle", color : "#FA8C16", label : _self.diseaseName, x : 100, y : 100, size : rootWidth + "*72", category : 0 }); }, //反向命令 back(editor){ const curPage = editor.getCurrentPage (); curPage.remove(_self.diseaseId); } }); //清空畫布命令 Command.registerCommand("clear", { // 命令是否可用 enable(eidtor) { return true; } }); }, /** * 初始化g6Editor * @param flag true 從接口獲取圖表數據;false:從緩存中獲取圖表數據(界面側邊欄收縮、展開) */ initG6Editor(flag){ const _self = this; let tempData = []; if(!flag){ tempData = this.editor.getCurrentPage ().save(); this.editor.destroy(); } this.editor = new G6Editor (); this.setCustomCommand(); const minimap = new G6Editor.Minimap ( { container : 'minimap' } ); const toolbar = new G6Editor.Toolbar ( { container : 'toolbar' } ); const contextmenu = new G6Editor.Contextmenu ( { container : 'contextmenu' } ); const itempannel = new G6Editor.Itempannel ( { container : 'itempannel' } ); const detailpannel = new G6Editor.Detailpannel ( { container : 'detailpannel' } ); const tooltip = new G6.Plugins['tool.tooltip']({ getTooltip({item}) { if(item && item.isNode){ let result = ""; const model = item.getModel(); let label = typeof model.label === "object" ? model.label.text : model.label; if(item.getModel().shape == "flow-capsule"){ result = '<div class = "tooltip-custom"><div>級別:' + label + '</div><div>程度:' + _self.levelList[model.level - 1].name + '</div></div>' }else{ result = '<div class = "tooltip-custom">' + label + '</div>'; } return result; } } }); const page = new G6Editor.Flow ( { graph : { container : 'page', plugins: [ tooltip ] }, shortcut : { save : true }, noEndEdge : false //不容許懸空邊 } ); page.getGraph().edge({ shape: "flow-polyline-round" }); // page.getGraph().node({ // tooltip(model) { // return [ // ['id', model.id] // ] // } // }); this.editor.add ( minimap ); this.editor.add ( toolbar ); this.editor.add ( contextmenu ); this.editor.add ( itempannel ); this.editor.add ( detailpannel ); this.editor.add ( page ); this.setEventListenner(); //設置事件監聽 if(flag){ this.getNodesByDiseaseId(this.diseaseId); }else{ curPage.read(tempData); } }, /** * 設置事件監聽 */ setEventListenner(){ const _self = this; const curPage = this.editor.getCurrentPage (); curPage.on('hoveranchor:beforeaddedge', ev => { //等級節點不能有子節點 if(ev.item.model.shape == "flow-capsule"){ ev.cancel = true; } }); curPage.on('dragedge:beforeshowanchor', ev => { let source = ev.source; let sourceId = ev.source.id; let target = ev.target; let targetId = target.model.id; //起始節點不能做爲源節點 if(ev.target.model.shape == "circle"){ ev.cancel = true; } //每一個結點不能連自身 if(sourceId == targetId){ ev.cancel = true; } //每一個結點最多隻有一個父節點 let inEdges = target.getInEdges(); //輸入的邊 if(inEdges.length > 0){ ev.cancel = true; } //每一個結點只有一個等級節點 let isHasGradeNode = false; //標識源節點是否已經有等級節點 let outEdges = source.getOutEdges(); if(outEdges.length > 0){ for(let j = 0, oLength = outEdges.length; j < oLength; j++ ){ if(outEdges[j].target.model && outEdges[j].target.model.shape == "flow-capsule"){ isHasGradeNode = true; break; } } } if(isHasGradeNode && target.model.shape == "flow-capsule"){ ev.cancel = true; } }); curPage.on ( 'afteritemselected', ev => { if ( ev.item.isNode ) { let vm = ev.item.getModel (); _self.category = vm.category; //節點類型 _self.condType = vm.condType; //條件 _self.operator = vm.operator; //判斷方法 _self.grade = vm.grade; //級別 _self.level = vm.level; _self.changeData = false; _self.values = vm.values; _self.names = vm.names; if ( vm.shape == "circle" ) { //默認節點 _self.showValue = false; _self.showGrade = false; _self.showOperator = false; _self.showCond = false; _self.showDisease = false; } else if ( vm.shape == "flow-rect" ) { //條件節點 _self.showOperator = true; _self.showCond = true; _self.showGrade = false; if ( vm.condType == 4 ) { _self.showDisease = true; _self.showValue = false; } else { if(!isEmptyStr(vm.values) && vm.values.length > 0){ _self.value = parseInt(vm.values[0]); //數據庫存儲的code爲int型 } _self.showDisease = false; _self.showValue = true; } _self.operatorList = objCopy ( _self.operatorMap[ vm.condType ] ); _self.valueList = objCopy ( _self.valueMap[ vm.condType ] ); if ( _self.condType == "4" ) { //既往病史 let conditionObj = this.conditionList.find ( ( item )=> { return item.code == _self.condType; } ); let operatorObj = this.operatorList.find ( ( item )=> { return item.code == _self.operator; } ); let diseaseListStr = conditionObj.name + operatorObj.name + ":"; let length = _self.values.length; this.diseaseSelectedLength = length; for ( let i = 0 ; i < length ; i++ ) { if ( i === 0 ) { diseaseListStr += _self.names[ i ]; } if ( i === 1 ) { diseaseListStr += "(" + _self.names[ i ]; } if ( i == 5 ) { //最多顯示前5個疾病 diseaseListStr += ")等" + length + "個疾病"; break; } if ( i > 1 ) { diseaseListStr += "、" + _self.names[ i ]; } if ( i < 5 && i === length - 1 && i >= 1 ) { diseaseListStr += ")"; } } } } else { //等級節點 _self.showOperator = false; _self.showCond = false; _self.showGrade = true; _self.showValue = false; _self.showDisease = false; _self.level = vm.level; _self.color = _self.colorList[ _self.grade - 1 ]; _self.fontSize = _self.fontSizeList[ _self.level - 1 ]; } } } ); curPage.on ( 'afterzoom', ev => { let zoom = ev.updateMatrix[ 0 ]; _self.curZoom = zoom; _self.zoomSlider = zoom * 100; } ); this.editor.on('aftercommandexecute', ev=>{ if(ev.command.name === "add"){ switch(ev.command.addModel.shape){ case "circle" : //起始節點 break; case "flow-rect" : //條件節點 let condType = _self.conditionList[ 0 ].code; let operator = _self.operatorMap[condType][0].code; let valueList = _self.valueMap[ condType ]; let values = [valueList[0].code]; let names = [ valueList[0].name]; let label = _self.conditionList[ 0 ].name + _self.operatorMap[condType][0].name +valueList[0].name; curPage.update ( ev.command.addModel.id, { label : label, names : names, values : values, operator : operator, condType : condType, category : 1 } ); break; case "flow-capsule": let grade = 4; let color = _self.colorList[ 3 ]; let level = 4; let fontSize = _self.fontSizeList[ 3 ]; let templabel = { text : _self.gradeList[3].name, fontSize : fontSize }; curPage.update ( ev.command.addModel.id, { label : templabel, grade : grade, level : level, color : color, category : 2 } ); break; } } }); }, enableChangeData(){ this.changeData = true; }, condTypeSelectChange( value ){ this.operator = ""; if(value != 4){ this.value = ""; this.changeData = true; }else{ this.changeData = false; } this.operatorList = objCopy(this.operatorMap[value]); this.operator = this.operatorList[0].code; this.valueList = objCopy(this.valueMap[value]); if(value == 4){ this.showDisease = true; this.showValue = false; let values = [this.valueList[0].id]; let names = [this.valueList[0].name]; this.values = values; this.names = names; this.diseaseSelectedLength = 1; let conditionObj = this.conditionList.find((item)=>{ return item.code == value; }); let diseaseListStr = conditionObj.name + this.operatorList[0].name + ":" + this.valueList[0].name; let nodeWidth = diseaseListStr.length * 13; this.updateGraph({ "condType": value, "operator": this.operatorList[0].code, "values": values, "names": names, "label": diseaseListStr, "size": nodeWidth + "*48" }); }else{ this.showDisease = false; this.showValue = true; this.value = this.valueList[0].code; } }, /** * 更新當前選中的節點 * @param updateModel 須要更新的數據模型 object */ updateGraph( updateModel ) { const editor = this.editor; editor.executeCommand ( () => { const page = editor.getCurrentPage (); const selectedItems = page.getSelected (); selectedItems.forEach ( item => { page.update ( item, updateModel ); } ); } ); }, /** * 獲取圖形的label */ getGraphLabel(){ let result = ""; let conditionObj = this.conditionList.find((item)=>{ return item.code == this.condType; }); let operotorObj = this.operatorList.find((item)=>{ return item.code == this.operator; }); let valueObj = this.valueList.find((item)=>{ return item.code == this.value; }); if(!isEmptyStr(conditionObj)){ result += conditionObj.name; } if(!isEmptyStr(operotorObj)){ result += operotorObj.name; } if(!isEmptyStr(valueObj)){ result += valueObj.name; } return result; }, /** * 格式化滑塊的label * @param val 滑塊值 * @returns {number} 滑塊label */ formatTooltip(val) { return val + "%"; }, /** * 修改zoom值 * @param value */ changeZoom(value){ const editor = this.editor; const page = editor.getCurrentPage(); let zoom = value / 100; page.zoom(zoom); }, /** * zoom下拉框值改變事件 * @param common */ handleDropdownChange(common){ let zoom = Number(common); const editor = this.editor; const page = editor.getCurrentPage(); this.zoomSlider = zoom * 100; page.zoom(zoom); this.curZoom = zoom; }, //顯示疾病列表彈窗 showDiseaseDialog(){ this.selectDiseases = []; for(let i = 0; i < this.values.length; i ++){ this.selectDiseases.push({ id : this.values[i], name : this.names[i] }); } this.diseaseDialogVisible = true; this.$nextTick(() => { //下面的方法須要在$nextTick後執行 this.$refs.diseaseTable.initTable(); //初始化疾病列表 }); }, /** *疾病表格渲染後事件(標識已選擇疾病) */ afterRenderData(curDiseaseData){ curDiseaseData.forEach((item, index, arr) => { for(let i = 0; i < this.selectDiseases.length; i++){ if(this.selectDiseases[i].id == item.id ){ this.$refs.diseaseTable.toggleRowSelection(item, true); break; } } }); }, /** * 疾病表格數據行checkbox點擊事件 */ diseaseSelect(selection, row){ if(!selection.includes(row)){ //取消選擇 for(let i = 0, lenth = this.selectDiseases.length; i < lenth; i++){ if(this.selectDiseases[i].id == row.id ){ this.selectDiseases.splice(i, 1); break; } } }else{ this.selectDiseases.push({ id : row.id, name : row.name }); } }, /** * 疾病表格全選按鈕點擊事件 */ diseaseSelectAll(selection){ let curDiseaseData = this.$refs.diseaseTable.getTableData(); if(selection.length == 0){ //取消全選 curDiseaseData.forEach((item, index, arr) => { for(let i = 0; i < this.selectDiseases.length; i++){ if(this.selectDiseases[i].id == item.id ){ this.selectDiseases.splice(i, 1); break; } } }); }else{ //全選 if(this.selectDiseases.length == 0){ //當前沒有已選疾病 curDiseaseData.forEach((item, index, arr) => { this.selectDiseases.push({ id : item.id, name : item.name }) }); }else{ //當前有已選疾病 curDiseaseData.forEach((item, index, arr) => { let flag = false; for(let i = 0; i < this.selectDiseases.length; i++){ if(this.selectDiseases[i].id == item.id ){ flag = true; break; } if(i == this.selectDiseases.length - 1 && !flag){ this.selectDiseases.push({ id : item.id, name : item.name }) } } }); } } }, /** * 移除已選擇的疾病 * @param disease 當前移除的疾病數據 */ handleDiseaseClose(disease, index){ this.selectDiseases.splice(index, 1); let curDiseaseData = this.$refs.diseaseTable.getTableData(); for(let i = 0; i < curDiseaseData.length; i ++ ){ if(disease.id == curDiseaseData[i].id ){ this.$refs.diseaseTable.toggleRowSelection(curDiseaseData[i], false); break; } } }, /** * 提交已選擇的疾病列表 */ submitSelectDisease(){ if(this.selectDiseases.length == 0){ errorMsg("請選擇疾病"); }else{ this.values = []; this.names = []; let conditionObj = this.conditionList.find((item)=>{ return item.code == this.condType; }); let diseaseListStr = conditionObj.name + this.operatorList[0].name + ":"; let length = this.selectDiseases.length; this.diseaseSelectedLength = length; for(let i = 0, length = this.selectDiseases.length ; i < length; i ++){ this.values.push(this.selectDiseases[i].id); this.names.push(this.selectDiseases[i].name); if(i === 0){ diseaseListStr += this.selectDiseases[i].name; } if(i === 1){ diseaseListStr += "(" + this.selectDiseases[i].name; } if(i == 5){ //最多顯示前5個疾病 diseaseListStr += ")等" + length + "個疾病"; } if(i > 1 && i < 5){ diseaseListStr += "、" + this.selectDiseases[i].name; } if(i < 5 &&i === length - 1 && i >= 1){ diseaseListStr += ")"; } } let transFormObj = this.transformLabel(diseaseListStr); let diseaseTrsLabel =transFormObj.label; let size = transFormObj.size; this.updateGraph({ "values": this.values, "names": this.names, "label": diseaseTrsLabel, "size": size }); this.diseaseDialogVisible = false; } }, diseaseDialogClosed(){ this.$refs.diseaseTable.clearSelection(); //清空選擇 this.$refs.diseaseTable.setLoading(true); this.$refs.diseaseTable.resetSearchKeyWord(); this.selectDiseases = []; }, diseaseGetParamsFn(){ return { condiIdx : this.condType, size : 20 } }, /** * 控制label 每行最多顯示15個字 * @param label * @returns {*} */ transformLabel(label){ let size = ""; //存儲size let result = "";//拼接加\n返回的類目項 let maxLength = 15;//每項顯示文字個數 let valLength = label.length;//X軸類目項的文字個數 let rowN = Math.ceil ( valLength / maxLength ); //類目項須要換行的行數 if ( rowN > 1 )//若是類目項的文字大於1, { for ( let i = 0 ; i < rowN ; i++ ) { let temp = "";//每次截取的字符串 let start = i * maxLength;//開始截取的位置 let end = start + maxLength;//結束截取的位置 //這裏也能夠加一個是不是最後一行的判斷,可是不加也沒有影響,那就不加吧 temp = label.substring ( start, end ) + "\n"; result += temp; //拼接最終的字符串 } let height = rowN > 2 ? (48 + ( rowN - 2 ) * 16) : 48; let size = (15 * 13) + "*" + height; return { label : result, size : size }; } else { return { label : label, size : (valLength * 13) + "*48" }; } }, //保存分級規則圖 saveGraph(){ const curPage = this.editor.getCurrentPage (); const graphData = curPage.save(); const nodes = graphData.nodes || []; const edges = graphData.edges || []; let list = []; let category = ""; let parentId = ""; let source_anchor = ""; let target_anchor = ""; let tempMap = null; const nodeList = curPage.getNodes(); nodes.forEach((item, index) => { category = ""; parentId = ""; source_anchor = ""; target_anchor = ""; tempMap = null; //只有新增/修改的錨點纔會在dataMap中 switch(item.shape){ case "circle": item.category = 0; break; case "flow-rect": item.category = 1; for ( let i = 0 ; i < edges.length ; i++ ) { if ( edges[ i ].target == item.id ) { item.parentId = edges[ i ].source; if(!isEmptyStr(edges[ i ].sourceAnchor)){ source_anchor = edges[ i ].sourceAnchor; }else{ source_anchor = item.source_anchor } if(!isEmptyStr(edges[ i ].targetAnchor)){ target_anchor = edges[ i ].targetAnchor; }else{ target_anchor = item.target_anchor; } break; } } break; case "flow-capsule": item.category = 2; for ( let i = 0 ; i < edges.length ; i++ ) { if ( edges[ i ].target == item.id ) { item.parentId = edges[ i ].source; if(!isEmptyStr(edges[ i ].sourceAnchor)){ source_anchor = edges[ i ].sourceAnchor; }else{ source_anchor = item.sourceAnchor } if(!isEmptyStr(edges[ i ].targetAnchor)){ target_anchor = edges[ i ].targetAnchor; }else{ target_anchor = item.targetAnchor; } break; } } break; } list.push({ id : item.id, category : item.category, cond_type : item.condType, operator : item.operator, values : item.values, codes : item.codes, names : item.names, parent_id : item.parentId, disease_id : this.diseaseId, diseaseName : this.diseaseName, grade : item.grade, level : item.level, x_axis : item.x, y_axis : item.y, size : item.size, source_anchor : source_anchor, target_anchor : target_anchor }); }); const _self = this; _self.$http({ url: '/intelliDiag/diseaseGradingRule/saveNodes', data : { diseaseId : this.diseaseId, list : JSON.stringify(list) }, method: 'post', success(res){ successMsg("疾病分級規則更新成功"); } }); }, sidebarTogglerFn(){ this.$nextTick(() => { //下面的方法須要在$nextTick後執行 this.initG6Editor(false); }); } } } </script>
樣式代碼不寫了,寫上去這裏會報錯,無法發佈。
樣式跟官方demo裏面的差很少,就是先將官方demo中的樣式所有拷貝過去,而後再按照本身的需求調節下便可。數據庫
目前有個問題:
保存所繪圖形以後,刷新頁面,根據從數據庫中讀取的數據重繪圖形。重繪的圖形和以前保存的不同(node位置同樣,可是edge的鏈接點位置不一樣)。存儲時保存了sourceAnchor和targetAnchor且存儲和讀取的數據都是同樣的,可是顯示出來有時候edge的連接點就是變了。感受g6-editor它本身調節了。
若是有誰知道這個應該怎麼解決的話,請解答下,謝謝canvas
問題描述:
保存時的界面:segmentfault
保存時的數據:經過save方法獲取api
nodes:[{category: 0,color: "#FA8C16",condType: null,cond_type: null,disease_id: "AWYaUvvf_Xy3-P03CHQR", grade: null,id: "AWYaUvvf_Xy3-P03CHQR",index: 0,label: "異常子宮出血",level: null,names: undefined, operator: null,operatorName: undefined,shape: "circle",size: "78*72",source_anchor: null,target_anchor: null, values: null,x: 174,y: 264}, {category: 1,color: "#1890FF",condType: 1,cond_type: 1,disease_id: "AWYaUvvf_Xy3-P03CHQR",grade: null, id: "4e0f1d7e",index: 1,label: "年齡=0歲",level: null,names: ["0歲"],operator: "equal",operatorName: "=", shape: "flow-rect",size: "120*48",source_anchor: 3,target_anchor: 3,values: ["0"],x: 337.56055,y: 559.5} ] edges:[{id: "ed9361ca",index: 2,shape: "flow-polyline-round",source: "AWYaUvvf_Xy3-P03CHQR",sourceAnchor: 3, target: "4e0f1d7e",targetAnchor: 3}]
從數據庫中獲取的數據:
node:[{category: 0,color: "#FA8C16",condType: null,cond_type: null,disease_id: "AWYaUvvf_Xy3-P03CHQR", grade: null,id: "AWYaUvvf_Xy3-P03CHQR",label: "異常子宮出血",level: null,names: undefined,operator: null, operatorName: undefined,shape: "circle",size: "78*72",source_anchor: null,target_anchor: null,values: null, x: 174,y: 264}, {category: 1,color: "#1890FF",condType: 1,cond_type: 1,disease_id: "AWYaUvvf_Xy3-P03CHQR",grade: null, id: "4e0f1d7e",label: "年齡=0歲",level: null,names: ["0歲"],operator: "equal",operatorName: "=", shape: "flow-rect",size: "120*48",source_anchor: 3,target_anchor: 3, values: ["0"],x: 337.56055,y: 559.5}] edge:[{source: "AWYaUvvf_Xy3-P03CHQR",sourceAnchor: 3,target: "4e0f1d7e",targetAanchor: 3}]
能夠看出保存和讀取的數據同樣,可是界面展現的效果是:
錨點位置有改變。
請問這個是什麼緣由呢?