本WIKI编辑权限开放,正由 恋与深空Evol攻略组 搭建基础框架ing,期待更多猎人加入WIKI建设!
反馈留言收藏方法加入我们

全站通知:

Widget:混沌深网流程图

来自恋与深空WIKI_BWIKI_哔哩哔哩
跳到导航 跳到搜索

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@logicflow/core/dist/style/index.css" /> <script src="https://cdn.jsdelivr.net/npm/@logicflow/core/dist/logic-flow.js"></script>

<link rel="stylesheet" href="/lysk/MediaWiki:CustomNode.css?action=raw&ctype=text/css" /> <script src="/lysk/index.php?title=MediaWiki:CustomNode.js&action=raw&ctype=text/javascript"></script>

<body>

</body> <script>

   const lf = new LogicFlow({
       container: document.querySelector("#container"),
       edgeType: 'plotNodeLine',
       stopZoomGraph: true,
       stopScrollGraph: true,
       //stopMoveGraph: true,
       adjustEdge: false,
       adjustEdgeStartAndEnd: false,
       adjustNodePosition: false,
       hideAnchors: true,
       nodeSelectedOutline: false,
       hoverOutline: false,
       nodeTextEdit: false,
       edgeTextEdit: false,
       textEdit: false,
   });
   lf.register(PlotNodeBox);
   lf.register(EndingNodeBox);
   lf.register(PlotNodeLine);
   lf.setTheme({
     arrow: {
       offset: 0,
       verticalLength: 0,
     },
     baseEdge: {
       stroke: "#f3f0c6",
       strokeWidth: 1,
     },
   });
   
   var graphData, graphModel, headImgURLArr;
   var currentNodeId;
   getFlowData();// 获取流程图json数据
   
   async function getFlowData(){
     graphData = await $.getJSON(`https://wiki.biligame.com/lysk/MediaWiki:.json?action=raw`);
     lf.render(graphData);  //渲染
     graphModel = lf.graphModel;
     if (graphData.nodes && graphData.nodes.length > 0) { initNodesOrder(graphData); }
     console.log('流程数据:', graphData);
     console.log('节点顺序:', nodesOrder);
     initNodeBg();   // 处理节点背景图片
     initCurrentNode();  // 处理当前节点样式
     initGraph();  //初始化画布
   }
   
   // 计算节点顺序
   function initNodesOrder() {
       nodesOrder = [graphData.nodes[0].id];
       for (let i = 0; i < nodesOrder.length; i++) {
           let nextOrder;
           if (typeof nodesOrder[i] == 'string') {
               nextOrder = setNodeOrder(nodesOrder[i]);
           }
           else {
               for (let j = 0; j < nodesOrder[i].length; j++) {
                   let tempOrder = setNodeOrder(nodesOrder[i][j]);
                   if (tempOrder) {
                       nextOrder = tempOrder;
                       break;
                   }
               }
           }
           if (nextOrder) {
               nodesOrder.push(nextOrder);
           }
       }
   }
 
   // 下一层节点顺序
   function setNodeOrder(nodeId) {
       if (lf.getNodeDataById(nodeId).type === 'ending-node') {
           return;
       }
       let nextNodes = graphModel.getNodeOutgoingNode(nodeId);
       if (nextNodes.length === 0) { return; }
       if (nextNodes.length === 1) {
           if (!nodesOrder.includes(nextNodes[0].id)) {
               return nextNodes[0].id;
           }
           else {
               return;
           }
       }
       else if (nextNodes.length === 2) {
           return [findLeftNodeId(nodeId), findRightNodeId(nodeId)];
       }
       else {
           let leftId = findLeftNodeId(nodeId), rightId = findRightNodeId(nodeId);
           return [leftId,
               nextNodes.filter(node => {
                   return node.id !== leftId && node.id !== rightId;
               })[0].id,
               rightId];
       }
   }
   
   // 寻找同级最左端的节点
   function findLeftNodeId(parentId) {
       const nextNodes = graphModel.getNodeOutgoingNode(parentId);
       let leftId = nextNodes[0].id;
       let minX = nextNodes[0].x;
       for (let i = 1; i < nextNodes.length; i++) {
           if (minX > nextNodes[i].x) {
               minX = nextNodes[i].x;
               leftId = nextNodes[i].id;
           }
       }
       return leftId;
   }
   // 寻找同级最右端的节点
   function findRightNodeId(parentId) {
       const nextNodes = graphModel.getNodeOutgoingNode(parentId);
       let rigthId = nextNodes[0].id;
       let maxX = nextNodes[0].x;
       for (let i = 1; i < nextNodes.length; i++) {
           if (maxX < nextNodes[i].x) {
               maxX = nextNodes[i].x;
               rigthId = nextNodes[i].id;
           }
       }
       return rigthId;
   }
   
   // 获取头像json数据
   $.getJSON('https://wiki.biligame.com/lysk/MediaWiki:HeadImg.json?action=raw')
     .then(response =>{ 
       //console.log('头像数据:',response);
       headImgURLArr = response;
     })
     .catch(error => {
       console.error('Error fetching data:', error);
     });
 
   function initGraph(){
       // 计算画布偏移和画布宽高
       let minY = graphData.nodes[0].y, maxY = graphData.nodes[0].y;
       for(let i = 0; i < graphData.nodes.length; i++){
         let node = graphData.nodes[i];
         minY = node.y < minY ? node.y : minY;
         maxY = node.y > maxY ? node.y : maxY;
       }
       let transX = $('#container')[0].clientWidth / 2 - graphData.nodes[0].x;
       let transY = 50 - minY;
       lf.translate(transX, transY);
       let height = maxY - minY + 100;
       $('#container>div')[0].style.height = height +'px';
       lf.updateEditConfig({ stopMoveGraph: true, });
   }
 
   // 初始化节点背景:根据同级节点个数
   function initNodeBg() {
       for (let i = 0; i < nodesOrder.length; i++) {
           if (typeof nodesOrder[i] === 'string') {
             if(lf.getNodeDataById(nodesOrder[i]).type === 'plot_node')
               $(`.plot-node#${nodesOrder[i]}`)[0].style.backgroundImage = "url(https://patchwiki.biligame.com/images/lysk/4/43/hx0pjs2s9mgh7egmn7bbla00nmv8uvx.png)"
           }
           else {
               for (let j = 0; j < nodesOrder[i].length; j++) {
                 if(lf.getNodeDataById(nodesOrder[i][j]).type === 'plot_node')
                   $(`.plot-node#${nodesOrder[i][j]}`)[0].style.backgroundImage = "url(https://patchwiki.biligame.com/images/lysk/9/94/0ueh2qo77mprdnyxylj8fc20cdh09gz.png)"
               }
           }
       }
   }    
 
   // 当前选中节点样式
   function initCurrentNode(){
       currentNodeId = graphData.nodes[0].id;
       changeCurrentNode();
       setTimeout(()=>{
           jsonToHtml();
       },200)
   }
   
   function changeCurrentNode() {
       $(`#${currentNodeId}`)[0].classList.add('active');
   }
   
  // 加载所有节点内容Html
   var displayArr = [], tempDisplayArr = [];
   function jsonToHtml() {
       let htmlStr = ;
       let parentFlag = ;
       let htmlOrders = [];
       for (let i = 0; i < nodesOrder.length; i++) {
           if (typeof nodesOrder[i] === 'string') {
               htmlOrders.push(nodesOrder[i]);
           }
           else {
               for (let j = 0; j < nodesOrder[i].length; j++) {
                   htmlOrders.push(nodesOrder[i][j]);
               }
           }
       }
       for (let i = 0; i < htmlOrders.length; i++) {
           let node = lf.getNodeDataById(htmlOrders[i]);
           let isBranch = node.properties.isBranchNode;  // 是否为分支节点
           let contents = node.properties.dialogContents;

let nodeHtml = `

`;
           if (!isBranch) {
               displayArr.push(node.id);
           }
           if (isBranch && node.properties.parentNode != parentFlag) {   //加载第一个分支节点
               parentFlag = node.properties.parentNode;
               displayArr.push(node.id);
           }
           if (contents && contents.length > 0) {   // 加载节点内容
               for (let i = 0; i < contents.length; i++) {
                   nodeHtml += transNodeHtml(contents[i]);
               }
           }
htmlStr += nodeHtml + '

';

       }
       const rightContainer = document.getElementsByClassName('plot-contents')[0];
       rightContainer.innerHTML = htmlStr;
       bindClickToButton();
       tempDisplayArr = JSON.parse(JSON.stringify(displayArr));
   }
   
   var isFirstInlineContent = false;
   function transNodeHtml(unitObj) {
       let unitHtml = ;
       switch (unitObj.unitType) {
           case '头像在左':

unitHtml = `

<img src="${headImgURLArr[unitObj.headImg]}">
<img src="https://patchwiki.biligame.com/images/lysk/5/5a/awebfh9m8ntsq3dt06zml6xmnxt39iu.png"/>
${unitObj.roleName}
${unitObj.unitText}

`;

               break;
           case '头像在右':

unitHtml = `

<img src="${headImgURLArr[unitObj.headImg]}">
<img src="https://patchwiki.biligame.com/images/lysk/5/5a/awebfh9m8ntsq3dt06zml6xmnxt39iu.png"/>
${unitObj.roleName}
${unitObj.unitText}

`;

               break;
           case '旁白':

unitHtml = `

${unitObj.unitText}

`;

               break;
           case '按钮组':

unitHtml = `

`;
               for (let i = 0; i < unitObj.buttonsArr.length; i++) {
                   let button = unitObj.buttonsArr[i];
unitHtml += `
${button.buttonText}
`;
               }
unitHtml += '

';

               isFirstInlineContent = true;
               break;
           case '节点内选项内容':

unitHtml = `

`;
               for (let i = 0; i < unitObj.dialogContents.length; i++) {
                   unitHtml += transNodeHtml(unitObj.dialogContents[i]);
               }
unitHtml += '

';

               isFirstInlineContent = false;
               break;
       }
       return unitHtml;
   }
   
   // 左侧节点点击事件
   lf.on("node:click", (node) => {
       console.log('节点数据:', node.data);
       let oldNode = document.getElementById(currentNodeId);  //旧的当前节点
       if (oldNode) $(`#${currentNodeId}`)[0].classList.remove('active');
       currentNodeId = node.data.id;
       changeCurrentNode();   // 当前节点样式  
       displayArr = JSON.parse(JSON.stringify(tempDisplayArr));
       // 点击分支节点切换显示
       if (node.data.properties.isBranchNode) {
           activeButton = $(`.button-dialog[button-trigger=${currentNodeId}]`)[0];
           if (activeButton) { changeCurrentButton(activeButton); }
       }
       changeDisplayContents();
       scrollToContent();
   });
   // 给选项按钮绑定点击事件
   function bindClickToButton() {
       const buttonArr = document.getElementsByClassName('button-dialog');
       for (let i = 0; i < buttonArr.length; i++) {
           buttonArr[i].addEventListener('click', function (event) {
               if (event.target.getAttribute('button-trigger')) {   //分支按钮
                   // 修改左侧节点样式
                   let oldNode = document.getElementById(currentNodeId);
                   $(`#${currentNodeId}`)[0].classList.remove('active');
                   currentNodeId = event.target.getAttribute('button-trigger');
                   changeCurrentNode();
               }
               displayArr = JSON.parse(JSON.stringify(tempDisplayArr));
               changeCurrentButton(event.target, event.target.getAttribute('is-inline-button') ? true : false);
               changeDisplayContents();
           })
       }
   }
   
   // 修改同级button样式 & 分支节点替换显示
   function changeCurrentButton(target, isInlineButton) {
       let buttonArr = target.parentElement.children;
       for (let i = 0; i < buttonArr.length; i++) {
           if (isInlineButton) {  // 隐藏节点内选项内容
               $(`.inline-button-contents[button-belong=${buttonArr[i].innerText}]`)[0].style.display = 'none';
           }
           // else { // 隐藏节点内容
           //     document.getElementsByClassName(buttonArr[i].getAttribute('button-trigger') + '_content')[0].style.display = 'none';
           // }
           if (buttonArr[i].classList.contains('active')) {
               buttonArr[i].classList.remove('active');
           }
       }
       target.classList.add('active');
       if (isInlineButton) {  // 显示节点内选项内容
           $(`.inline-button-contents[button-belong=${target.innerText}]`)[0].style.display = ;
       }
       // else { // 显示节点内容
       //     document.getElementsByClassName(target.getAttribute('button-trigger') + '_content')[0].style.display = ;
       // }
       // 隐藏结局节点之后的所有内容
       let node = lf.getNodeDataById(target.getAttribute('button-trigger'));
       if (node && node.type === 'ending_node') {
           let index = displayArr.indexOf(graphModel.getNodeIncomingNode(currentNodeId)[0].id);
           if (index !== -1) {
               displayArr.splice(index + 1, 1, currentNodeId);
               displayArr = displayArr.slice(0, index + 2);
           }
       }
       else {
           // 替换displayArr
           const index = displayArr.indexOf(graphModel.getNodeIncomingNode(currentNodeId)[0].id);
           if (index !== -1) {
               displayArr.splice(index + 1, 1, currentNodeId);
               tempDisplayArr = JSON.parse(JSON.stringify(displayArr));
           }
       }
   }
   // 遍历content
   function changeDisplayContents() {
       let contentArr = $('.plot-contents>div');
       for (let i = 0; i < contentArr.length; i++) {
           let content = contentArr[i];
           if (displayArr.indexOf(content.className.split('_content')[0]) !== -1) {
               content.style.display = ;
           }
           else {
               content.style.display = 'none';
           }
       }
   }


   // 滚动到当前节点位置
   function scrollToContent() {
       const container = $('.plot-contents')[0];
       const targetElement = $(`.${currentNodeId}_content`)[0];
       if(targetElement.offsetTop == 0){ return; }
       const targetOffsetTop = targetElement.offsetTop >= 10 ? targetElement.offsetTop - 10 : targetElement.offsetTop;
       // 将容器滚动到目标元素的位置
       container.scrollTo({
           top: targetOffsetTop,
           behavior: 'smooth'
       });
   }
 
   // tab切换绑定
   addTabListener();
   function addTabListener(){
     let tabList = $('.SwitchContainer>.BtnContainer>.btn');
     for(let i = 0; i < tabList.length; i++){
       tabList[i].addEventListener('click', function(event){
         if(event.target.innerText === '事件回想'){
           $('.right-container>.plot-contents')[0].style.display = 'block';
           $('.right-container>.accident-contents')[0].style.display = 'none';
         }
         else{
           $('.right-container>.plot-contents')[0].style.display = 'none';
           $('.right-container>.accident-contents')[0].style.display = 'block';
         }
       })
     }
   }
   
   var accidentData;
   getAccidentData();// 获取偶发事件json数据
   async function getAccidentData(){
     accidentData = await $.getJSON(`https://wiki.biligame.com/lysk/MediaWiki:.json?action=raw`);
     console.log('事件数据:', accidentData);
     setTimeout(()=>{
       // 写入HTML
       let accidentListHtml = "", accidentContentsHtml = ""; 
       let accList = Object.keys(accidentData);
       for(let i = 0; i < accList.length; i++){ //transNodeHtml
         let accContent = "";

accidentListHtml += `

${accList[i]}

`;

         for(let j = 0; j < accidentData[accList[i]].length; j++){
           accContent += transNodeHtml(accidentData[accList[i]][j]);
         }

accidentContentsHtml += `

`;

       }
       $('.accident-list')[0].innerHTML = accidentListHtml;
       $('.accident-contents')[0].innerHTML = accidentContentsHtml;
       // 处理默认选中
       $('.accident-list>.accident-module')[0].classList.add('active');
       $('.accident-contents>.accident-content')[0].style.display = "block";
       // 绑定点击事件
       let oldAccDiv = $('.accident-list>.accident-module')[0];
       let accDivList = $('.accident-list>.accident-module');
       for(let i = 0;i < accDivList.length; i++){
         accDivList[i].addEventListener("click", function(event){
           oldAccDiv.classList.remove('active');
           event.target.classList.add('active');
           $(`.accident-content[data-param=${oldAccDiv.innerText}]`)[0].style.display = "none";
           $(`.accident-content[data-param=${event.target.innerText}]`)[0].style.display = "block";
           oldAccDiv = event.target;
         })
       }
     },500)
   }


</script>

<style>

  1. container {
 width: 100%;
 height: 100%;
 overflow: auto;

}

  1. container>div{
 min-height: 100%;
 min-width: 370px;

} .lf-graph{

 background: transparent;

} text.lf-element-text {

   font-size: 14px;
   color: #cfebf9;
   font-family: 'SimSun', sans-serif;
   font-weight: bold;

}


.left-dialog {

   display: flex;
   flex-direction: row;
   gap: 5px;
   margin-bottom: 15px;
   padding: 5px;
   position: relative;

}

.accident-module:hover {

   text-shadow: 1px 0px 3px #e3f7ffad;

} .accident-module {

   width: 100%;
   height: 50px;
   color: #d4ebf4;
   background-image: url(https://patchwiki.biligame.com/images/lysk/7/77/f4cmrvlnryz0mj5vvi72tbu7ah7q943.png);
   background-size: 100% 100%;
   text-align: center;
   font-size: 16px;
   line-height: 47px;
   position: relative;

} .accident-module.active::before {

   content: "";
   position: absolute;
   width: 100%;
   height: 100%;
   top: 0;
   left: 0;
   background-image: url(https://patchwiki.biligame.com/images/lysk/1/19/fgcojpmsabediig497zgx1oxl7w1183.png);
   background-size: 100% 95%;
   background-repeat: no-repeat;

}

.right-dialog {

   display: flex;
   flex-direction: row-reverse;
   gap: 5px;    
   margin-bottom: 15px;
   padding: 5px;
   position: relative;

} .voiceover-dialog{

   margin-bottom: 10px;
   color: #6887a7;

}

.buttons-group {

   display: flex;
   flex-direction: column;
   align-items: center;

} .button-dialog{

   width: 50%;
   height: 50px;
   padding: 10px;
   text-align: center;
   cursor: pointer;
   box-sizing: border-box;
   margin-bottom: 10px;
   background-image: url(https://patchwiki.biligame.com/images/lysk/5/5a/dlw994nn9ke41wnre15utjrttdlwldm.png);
   color: #cfebf9;
   background-size: 100% 100%;

} .button-dialog.active {

   font-weight: bold;

} .button-dialog:not(.active):hover {

   color: #9fbac6;

}

.head-img {

   height: 70px;
   width: 70px;
   display: flex;
   align-items: flex-end;
   background-image: url(https://patchwiki.biligame.com/images/lysk/7/70/s3kgqr8k04kftquzm947mbjq2fppq3s.png);
   background-size: 100% 100%;
   padding: 5px;

}

.left-dialog>img {

   position: absolute;
   width: 65px;
   left: 10px;
   bottom: -5px;

}

.text-container {

   flex: 1; 

}

.right-dialog > .text-container {

   text-align: right;

} .right-dialog>img {

   position: absolute;
   width: 65px;
   right: 7px;
   bottom: -5px;

}

.role-name {

   color: #a1c6ea;
   font-size: 15px;
   font-weight: bold;
   position: relative;

} .role-name::before {

   content: "";
   width: 100%;
   height: 100%;
   left: 0;
   position: absolute;
   background-image: url(https://patchwiki.biligame.com/images/lysk/d/d8/cikfxl6ub7j5m6fj04sgwa6m9cm7xee.png);
   background-repeat: no-repeat;
   padding-left: 15px;
   background-size: auto 75%;
   background-position-y: 5px;

} .left-dialog .role-name {

   padding-left: 15px;

} .right-dialog .role-name {

   padding-right: 15px;

} .right-dialog .role-name::before {

   transform: scaleX(-1);

}

.unit-text {

   color: #d1e6f1;
   padding: 5px 10px;
   height: 100%;
   background: url(https://patchwiki.biligame.com/images/lysk/d/d7/2f97ck87p9vwsrwyc6a4q0x5ye1i1bv.png);
   background-size: 70%;
   background-repeat: no-repeat;
   text-align: left;

} .right-dialog .unit-text {

   margin-left: 70px;

} </style>