joint
根据传进来的数据,生成相应的树图,点击节点,出现弹窗,可以对节点进行增删和增加一条线,同事改变了数据,后台需要的数据直接传sharingMsg,这个数据是图当前的状态。效果图和代码如下
<!DOCTYPE HTML> <html> <head> <meta charset="UTF-8"> <title>实例</title> <link type="text/css" rel="stylesheet" href="assets/css/joint.css" /> <script type="text/javascript" src="jquery-1.12.4.js" ></script> <script type="text/JavaScript" src="lodash.js" ></script> <script type="text/javascript" src="assets/js/backbone-min.js" ></script> <script type="text/javascript" src="assets/js/joint.js" ></script> <style> .treeOperate{ position: absolute; width: 100px; height: 40px; padding: 20px; background: url("login_bg.jpg") no-repeat center/100% 100% content-box; } .treeOperate a{ position: absolute; } .treeOperate .addEle{ bottom: 0; left: 0; } .treeOperate .addLink{ bottom: 0; right: 0; } .treeOperate .deleteEle{ top: 0; left: 0; } </style> </head> <body> <p id="paper" class="paper"></p> </body> <script> //删除一个节点,要知道到父亲节点,删除父亲节点中相应childrenMsg中的元素以及linkMsg中相应元素。 //然后在用找到这个节点以及他的所有子节点,删除 //新增一个节点,要给sharingMsg中相应元素增加id,childrenMsg,linkMsg等信息 //还要insideMsg中增加相应内容 let graph = new joint.dia.Graph; let paper = new joint.dia.Paper({ el: document.getelementbyid('paper'), model: graph, width: 600, gridSize: 10, drawGrid: true, background: { color: 'rgba(0, 255, 0, 0.3)' } }); //生成节点,obj = {left,top,text} function createEle(obj) { let rect = new joint.shapes.standard.Rectangle(); rect.position(obj.left, obj.top); //位置 rect.resize(100, 40); //大小 rect.attr({ body: { fill: 'blue', rx:20, //rx,ry设置圆角 ry:20, }, label: { text: obj.text, fill: 'white' } }); return rect; } //生成线 根据位置 // custom link definition let CustomLink = joint.dia.Link.define('examples.CustomLink', { defaultLabel: { // attrs: { text: { text: '*' } } }, smooth: true }); //obj = {x1,y1,x2,y2} obj ={source,x2,y2} function createLink(obj) { let link = new CustomLink({ // source: { x: obj.x1, y: obj.y1 }, source: { id: obj.source.id }, target: { x: obj.x2, y: obj.y2 }, // router: { name: 'manhattan' }, }); return link; } //根据起始元素生成的线 function createLinkEle(source, target){ let link = new CustomLink({ source: { id: source.id }, target: { id: target.id }, // router: { name: 'manhattan' }, }); return link; } // graph.addCell(); //定义一个装删除元素id的数组,每当删除元素时,存入id,每当生成元素时,先取这里面的值作为id //为空时取sharingMsg的length作为id let hadDelEles = []; //这个信息是接收来自后台的数据,其中的cid,parentID都是会变的,不是固定的,只起到判断父子节点的作用 let sharingMsg = [ { id:1, text:'第一规则', sign:1000, //sign判断元素所在行,越上面的越大,确定元素所在y轴的位置 layer:1, //layer表示元素所在层级,确定元素所在x轴的位置 parentID:null, childrenMsg:[2,3,4], //连接信息,判断 linkMsg:['通过','拒绝','人工复核'] }, { id:2, parentID:1, text:'第2规则', sign:999, layer:2, childrenMsg:[5,6], linkMsg:['通过','拒绝'] }, { id:3, parentID:1, text:'第3规则', sign:1000, layer:2, childrenMsg:[], linkMsg:[] }, { id:4, parentID:1, text:'第4规则', sign:1001, layer:2, childrenMsg:[], linkMsg:[] }, { id:5, parentID:2, text:'第5规则', sign:998, layer:3, childrenMsg:[], linkMsg:[] }, { id:6, parentID:2, text:'第6规则', sign:999, layer:3, childrenMsg:[], linkMsg:[] } ]; //定义一个存放被删除元素id的数组,当新建时,从这里找,如果这个数组有,就从这个数组中取,如果没有,就从 //设为sharingMsg的length //这个数组存放界面中存在的节点 let insideMsg = []; //调整画布大小函数,返回一个对象,包含树的最大最小层,包含输的最大最小sign function adjustPaperSize() { //根据下面的值,判断画布大小,元素位置 let maxSign = 0, minSign = sharingMsg[0].sign, maxLayer = 0, minLayer = sharingMsg[0].layer; for(let i=0;i<sharingMsg.length;i++){ if(sharingMsg[i].layer<minLayer){ minLayer = sharingMsg[i].layer; } if(sharingMsg[i].layer>maxLayer){ maxLayer = sharingMsg[i].layer; } if(sharingMsg[i].sign<minSign){ minSign = sharingMsg[i].sign; } if(sharingMsg[i].sign>maxSign){ maxSign = sharingMsg[i].sign; } } paper.$el.css({ width:(maxSign - minSign + 1) * 150 +50, height:(maxLayer - minLayer + 1) * 100 + 40 }); return { maxSign:maxSign, minSign:minSign, maxLayer:maxLayer, minLayer:minLayer } } //打开界面时渲染生成树图 function newTreeChart() { //调整画布大小 let tempSize = adjustPaperSize(); let minSign = tempSize.minSign, minLayer = tempSize.minLayer; //生成元素 for(let i=0;i<sharingMsg.length;i++){ //一个元素长100,宽40,水平间隔50,第一个距离左侧50,垂直距离20,最上一个距离上边30; let left = (sharingMsg[i].sign - minSign) * 150 + 50; let top = (sharingMsg[i].layer - minLayer) * 100 + 30; let obj = { left:left, top:top, text:sharingMsg[i].text }; let ele = createEle(obj); insideMsg.push({ self:ele, }); //下面这句该变sharingMsg相应节点的cid,为了之后的操作 sharingMsg[i].cid = ele.cid; graph.addCell(ele) } //生成线 //遍历每个节点,判断是否要生成线 sharingMsg.foreach(function (item) { //如果节点存在孩子,进一步操作 if(item.childrenMsg.length>0){ //存在子元素,需要连线,先找到来源元素source let source = null; //insideMsg里面才存有真正的节点 for(let i=0;i<insideMsg.length;i++){ if(item.cid == insideMsg[i].self.cid){ source = insideMsg[i].self; break; } } console.log(source); let nowItem = item; //利用当前节点的childrenMsg中的子元素id从sharingMsg中找到相应点 item.childrenMsg.forEach(function (item,index) { console.log(3); //设置目标元素 let target = null; let tempTarget = null; //设置线条颜色 let color = nowItem.linkMsg[index]; for(let i=0;i<sharingMsg.length;i++){ if(item == sharingMsg[i].id){ tempTarget = sharingMsg[i]; //获取真正的target for(let j=0;j<insideMsg.length;j++){ if(tempTarget.cid == insideMsg[j].self.cid){ target = insideMsg[i].self; let link = createLinkEle(source,target); if(color == '通过'){ link.attr({ '.connection': { stroke: 'green'}, }); } if(color == '拒绝'){ link.attr({ '.connection': { stroke: 'red',}, }); } if(color == '人工复核'){ link.attr({ '.connection': { stroke: 'blue',}, }); } graph.addCell(link); break; } } } } }) } }); } newTreeChart(); //元素点击事件 paper.on('cell:pointerclick',function (e,d) { console.log(e); console.log(d); let target = null; for(let i=0;i<insideMsg.length;i++){ if(e.model.cid == insideMsg[i].self.cid){ target = insideMsg[i].self; } } newTreeOperate(target); d.stopPropagation(); }); //生成 function newTreeOperate(obj) { let html = '<p class="treeOperate">\n' + ' <a href="javascript:;" class="deleteEle">del</a>\n' + ' <a href="javascript:;" class="addEle">ele</a>\n' + ' <a href="javascript:;" class="addLink">link</a>\n' + '</p>'; $('body').APPend(html); $('.treeOperate').css({ //因为操作弹窗的直接父元素是body,$("body").append()所以位置要微调。 //因为操作弹窗的直接父元素是body,$("body").append()所以位置要微调。 left:obj.attributes.position.x - 12, top:obj.attributes.position.y - 12 }); $('body').on('click',function () { $('.treeOperate').remove(); }); $('.addEle').on('click',function () { let tempObj = { left:obj.attributes.position.x + 150, top:obj.attributes.position.y, text:'请选择规则', }; let cell = createEle(tempObj); cell.attr('text/fill','black'); cell.attr('rect/fill','#fff'); //新增节点后要给sharingMsg中这个节点的父亲的childrenMsg中加入此节点id //要在sharingMsg中加入此节点相应信息,在insideMsg中加入此节点相应信息 insideMsg.push({ self:cell }); let tempId = 0; if(hadDelEles.length>0){ tempId = hadDelEles.pop(); }else{ tempId = sharingMsg.length; } let tempParentID = 0, tempSign = 0, tempLayer = 0; //找到此节点的父亲节点,为父亲节点加上孩子节点(该节点)的信息(id) sharingMsg.forEach(function (item) { if(item.cid == obj.cid){ tempParentID = item.id; item.childrenMsg.push(tempId); tempSign = item.sign + 1; tempLayer = item.layer; } }); sharingMsg.push({ id:tempId, cid:cell.cid, //绑定和真正元素的联系 parentID:tempParentID, //这个id也要改 text:'请选择规则', sign:tempSign, layer:tempLayer, childrenMsg:[], linkMsg:[] }); graph.addCell(cell); let link = createLinkEle(obj, cell); graph.addCell(link); adjustPaperSize(); }); $('.addLink').on('click',function () { let tempObj = { source:obj, x2:obj.attributes.position.x + 150, y2:obj.attributes.position.y + 10 }; let link = createLink(tempObj); graph.addCell(link); }); $('.deleteEle').on('click',function () { //删除元素时,在sharingMsg中先删除父亲节点中childrenMsg中相应id,在删除该节点以及他的子节点,删除的节点先存入一个数组nowDel //根据nowDel数组中的节点,在insideMdg这个真正存在节点的数组中删除相应节点。 //这个a为需要删除的节点, let a = null; console.log(sharingMsg); for(let i=0;i<sharingMsg.length;i++){ if(obj.cid == sharingMsg[i].cid){ //真正的节点和sharingMsg是靠cid来绑定相关的 a = sharingMsg[i] } } console.log(1111); //在父元素中删除该子节点的id sharingMsg.forEach(function(item){ if(item.id == a.parentID){ let tempIndex = item.childrenMsg.indexof(a.id); item.childrenMsg.splice(tempIndex,1); } }); let nowDel = [a]; function fn(f) { //这里应该是可以优化的,push到nowDel的可以删除掉 f.childrenMsg.forEach(function(item,index,array){ let ThisItem = item; sharingMsg.forEach(function (item, index, array) { if(ThisItem == item.id){ nowDel.push(item); fn(item); } }) }); } fn(a); nowDel.forEach(function(item,index){ for(let i=insideMsg.length-1;i>=0;i--){ if(item.cid == insideMsg[i].self.cid){ console.log(22); insideMsg[i].self.remove(); insideMsg.splice(i,1); } } for(let i=sharingMsg.length-1;i>=0;i--){ if(item.id == sharingMsg.id){ sharingMsg.splice(i,1); } } }) }); } </script> </html>
相关阅读
微信小程序入门教程+案例demo 尊重原创,转载请注明出处:原文查看惊喜更多 http://blog.csdn.net/qq137722697 首
Tangram 2.0 VirtualView Demo 配置
天猫开源了一个动态UI的方案,包含https://github.com/alibaba/VirtualView-iOShttps://github.com/alibaba/tangram-ios简单来个De
更多资料请参考:www.woyaocha.net/product/express 查询说明 接口一:快递单号智能识别 快递单号智能识别,是根据查询的快递单号自
Demo地址:https://github.com/zGuangYuan/Androidstudio_example WebView介绍: Android WebView在Android平台上是一个特殊的
OLED:SSD1306#define OLED_SPI_RS PIO1//COMMAND/DATA#define OLED_SPI_RST PIO2//RESET#define SIZE 16#define XLevelL 0x02#de