本WIKI编辑权限开放,正由 恋与深空Evol攻略组 搭建基础框架ing,期待更多猎人加入WIKI建设!
反馈留言 • 收藏方法 • 加入我们
Widget:混沌深网流程图
<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 = `
`;
break; case '头像在右':
unitHtml = `
`;
break; case '旁白':
unitHtml = `
`;
break; case '按钮组':
unitHtml = `
';
isFirstInlineContent = true; break; case '节点内选项内容':
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 += `
`;
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>
- container {
width: 100%; height: 100%; overflow: auto;
}
- 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>