리버티게임:언사이라이터: 두 판 사이의 차이
백괴게임>BANIP 잔글편집 요약 없음 |
백괴게임>BANIP 잔글편집 요약 없음 |
||
55번째 줄: | 55번째 줄: | ||
== 예시 == | == 예시 == | ||
{{글 숨김|기본 예시|제목색=tranparent|테두리색=tranparent}} | {{글 숨김|기본 예시|제목색=tranparent|테두리색=tranparent}} | ||
[[파일:언사이라이터 예시 역.png]] | |||
인터페이스에 장착되어있는 기본 예시입니다. 이 내용을 실행한 결과는 [[백괴게임:언사이라이터/예시/역]]에서 확인 가능합니다. | |||
{{글 숨김 끝}} | {{글 숨김 끝}} | ||
== 인터페이스 == | == 인터페이스 == | ||
{{플러그인|사용자:BANIP/자동문서작성/플러그인|틀}} | {{플러그인|사용자:BANIP/자동문서작성/플러그인|틀}} |
2018년 3월 29일 (목) 01:28 판
언사이라이터는 비슷비슷한 내용의 백괴게임 문서를 작성할때 도움을 줄 수 있는 특수문서 아닌 특수문서입니다. 기차나 지하철이나 고속도로게임같이 문서 내용은 좀만 다르고 대부분의 양식은 클릭이랑 드래그 몇번만 하면 뿅하고 만들어집니다.
사용법
아래 인터페이스 보시면 왼쪽에는 그림으로 되어있고 오른쪽엔 버튼이나 텍스트박스로 이루어져 있습니다. 각각 나누어서 기능을 설명하겠습니다.
캔버스
캔버스를 잘 보시면 네모와 화살표로 이루어져 있습니다. 네모(이하 노드라고 부르겠습니다)클릭하면 노란색으로 바뀝니다. 선택된 노드는 명령팔레트에서 삭제가 가능합니다. 한 노드를 마우스로 드래그해서 다른 노드에 갖다 붙이는것으로 화살표를 이을 수 있습니다. 또한 오른쪽 마우스로 갖다 붙이는 행위로 이어진 화살표를 지우는것이 가능합니다.
명령 팔레트
새로운 노드 추가 탭의 텍스트박스에 노드 네임을 입력하고 추가를 누르는 것으로 노드 이름을 추가할 수 있습니다. 캔버스에서 선택한 노드를 기존 노드 수정 탭에서 삭제가 가능합니다. 노드 작성 완료 및 생성 파트가 좀 복잡하고 제일 중요한 부분인데 설명이 쫌 딸릴 수 있지만 제 말빨 필력 다 동원해서 최대한 열심히 설명해 보도록 할게요.
여기서 문서를 생성할때 각 문서는 캔버스의 노드와 대응합니다. 노드를 5개 만들었으면 다섯개 문서가 생성이되고 100개 만들었음 백개가 생성이 되요. 백괴사전에서 PAGENAME이나 USERNAME같은 틀 쓸때 대괄호 두개 쓰는것처럼 여기선 대괄호와 꺽쇠괄호를 조합해 여러 변수들을 사용 가능합니다. 노드네임 페이지네임은 인터페이스에 간단하게 적혀있으니 장황하게 설명안해도 대충 이해가 가실거라 믿구요,
링크는 첫번째 파라미터 안에 있는 문법이, 문서에 해당되는 노드가 다른 노드에 링크된 갯수만큼 반복됩니다. 무슨 소리냐 하면 부산노드가 서울과 대구 총 두개가 이어져 있으면 두번씩 반복되구요 서울로는 다른노드가 이어지기만 했지 다른노드로 링크되진 않으므로 출력되지 않습니다. 또한 이 함수 내부에서 링크노드네임이나 링크페이지네임 변수를 사용 가능한데, 이 링크함수가 반복될때 해당 노드에 대응되는 링크문서의 페이지명과 노드이름을 출력 할 수 있습니다.
어떻게든 열심히 설명해봤는데 내가봐도 뭔소린지 잘 모르겠네요 작성자가 필력이 딸려서 설명을 구성지게 못하겠습니다 죄송합니다. 대신 예시 몇개 남겨놓을테니 대충대충 끄적여보고 감 잡으시길 바랍니다 화이팅
참고로 인터페이스도 이것저것 만져보고 테스트해보라고 노드 몇개랑 추가해놓고 템플릿 양식 적어놓은거구요 직접 사용할때 모든 노드 지워주시면 됩니다. 참고로 모바일 지원은 아직 생각하지 않고 있습니다.
예시
기본 예시
인터페이스
/**
* 시간에 따라 바뀌는 유동적인 값을 반환합니다. cos함수, 혹은 그의 절대값 형태를 띕니다. * @param start 최소값 * @param height 진폭 * @param wavelength 파장 * @param isAbs 절대값인가 아닌가 */
var getFluidValue = function (start, height, wavelength, isAbs) {
if (isAbs === void 0) { isAbs = true; } var now = Date.now() / Math.PI / wavelength; var amplitude = Math.cos(now) * height; return start + (isAbs ? Math.abs(amplitude) : amplitude);
}; /**
* 뷰에 해당하는 클래스, 캔버스와 연동해 노드들의 관계를 보여줌 */
var GUI = /** @class */ (function () {
/** * 생성자, 컨텍스트를 가져오기 위한 용도인 getcdtx를 정의 * @param canvas 그림판으로 사용할 캔버스 객체 */ function GUI(canvas) { if (canvas === void 0) { canvas = document.querySelector("#nodemap"); } var _this = this; this.canvas = canvas; this.nodeCache = []; this.selectedNode = null; this.isUnlinkNode = false; this.dragInfo = null; /** * 캔버스에서 사용할 각종 수치 */ this.elemUnit = { wrap: { marginX: 50, marginY: 20 }, node: { intervalY: 20, width: 100, height: 50, getctx: null, selectNodeColor: "yellow" }, branch: { width: 100, weight: 3, getctx: null } }; this.elemUnit.node.getctx = function () { var ctx = _this.canvas.getContext("2d"); ctx.textAlign = "center"; ctx.textBaseline = "middle"; ctx.font = "30px sans-serif"; ctx.lineWidth = 5; ctx.setLineDash([]); ctx.strokeStyle = "black"; return ctx; }; this.elemUnit.branch.getctx = function () { var ctx = _this.canvas.getContext("2d"); ctx.strokeStyle = "black"; ctx.setLineDash([]); return ctx; }; } /** * 특정 노드의 위치 획득 * @param nodeList 위치를 획득할 노드가 속하는 집단 * @param node 위치를 획득할 노드 */ GUI.prototype.getPosition = function (nodeList, node) { var thisPosition; nodeList.every(function (currentNode, i) { thisPosition = i; if (currentNode === node) return false; return true; }); return thisPosition; }; /** * 수정 대상이 될 노드 지정 * @param node 수정 대상이 될 노드 */ GUI.prototype.nodeSelect = function (node, isUnlinkNode) { this.isUnlinkNode = isUnlinkNode; this.selectedNode = node; }; GUI.prototype.getNodeByAxis = function (axis) { var _a = this.elemUnit, wrap = _a.wrap, node = _a.node, branch = _a.branch; var nodeContainerSize = node.intervalY + node.height; var isSafeX = axis.x >= branch.width + wrap.marginX && axis.x <= branch.width + wrap.marginX + node.width; if (!isSafeX) return null; var p = parseInt((axis.y - wrap.marginY) / nodeContainerSize + ""); if (p === -1) return null; return this.nodeCache[p]; }; GUI.prototype.setNodeList = function (nodeList) { this.nodeCache = nodeList; }; GUI.prototype.setDragInfo = function (axis) { this.dragInfo = axis; }; /** * 캔버스에 출력 */ GUI.prototype.draw = function () { var _this = this; var nodeList = this.nodeCache; this.initCanvasSize(nodeList.length); nodeList.forEach(function (node, i) { _this.drawNode(node, i); node.getLinked().forEach(function (linkednode) { var j = _this.getPosition(nodeList, linkednode); _this.drawbranch(i, j); }); }); this.drawbranch(this.selectedNode, this.dragInfo, function () { var ctx = _this.elemUnit.branch.getctx(); ctx.setLineDash([7, 3]); ctx.lineDashOffset = Date.now() / 100 % 100; ctx.strokeStyle = _this.isUnlinkNode ? "red" : "blue"; return ctx; }); }; GUI.prototype.initCanvasSize = function (nodeCount) { var _a = this.elemUnit, wrap = _a.wrap, node = _a.node, branch = _a.branch; var width = wrap.marginX * 2 + node.width + branch.width * 2; var height = wrap.marginY * 2 + (node.height * nodeCount) + node.intervalY * (nodeCount - 1); this.canvas.width = width; this.canvas.height = height; }; GUI.prototype.getNodePosition = function (position, hori, vert) { if (hori === void 0) { hori = "left"; } if (vert === void 0) { vert = "top"; } var _a = this.elemUnit, wrap = _a.wrap, node = _a.node, branch = _a.branch; var getBonusWidth = function (hori) { if (hori == "left") return 0; if (hori == "center") return node.width / 2; if (hori == "right") return node.width; }; var getBonusHeight = function (vert) { if (vert === "top") return 0; if (vert === "middle") return node.height / 2; if (vert === "bottom") return node.height; }; return [ wrap.marginX + branch.width + getBonusWidth(hori), wrap.marginY + (node.intervalY + node.height) * position + getBonusHeight(vert) ]; }; GUI.prototype.drawNode = function (node, position) { var nodeSize = this.elemUnit.node; var ctx = nodeSize.getctx(); var axis = this.getNodePosition(position); if (node === this.selectedNode) { ctx.fillStyle = nodeSize.selectNodeColor; ctx.fillRect.apply(ctx, this.getNodePosition(position).concat([nodeSize.width, nodeSize.height])); ctx.fillStyle = "black"; } ctx.strokeRect.apply(ctx, this.getNodePosition(position).concat([nodeSize.width, nodeSize.height])); ctx.fillText.apply(ctx, [node.getName()].concat(this.getNodePosition(position, "center", "middle"))); }; GUI.prototype.getBranchAxis = function (startPosition, endPosition) { var _this = this; var getAxisY = function (axis) { if (axis instanceof DocNode) axis = _this.getPosition(_this.nodeCache, axis); if (typeof axis == "number") return _this.getNodePosition(axis, "center", "middle")[1]; return axis.y; }; var _a = [getAxisY(startPosition), getAxisY(endPosition)], startAxisY = _a[0], endAxisY = _a[1]; var direction = startAxisY > endAxisY ? "left" : "right"; var isDirectionLeft = direction === "left"; var axisX = this.getNodePosition(0, direction, "middle")[0]; var start = [axisX, startAxisY]; var end = [axisX, endAxisY]; return [start, end]; }; GUI.prototype.drawbranch = function (startPosition, endPosition, getctx) { if (getctx === void 0) { getctx = this.elemUnit.branch.getctx; } if (startPosition === null || endPosition === null) return; var _a = this.getBranchAxis(startPosition, endPosition), start = _a[0], end = _a[1]; var max = start[1] > end[1] ? end : start; var isDirectionLeft = max === end; var radius = Math.abs((end[1] - start[1]) / 2); var arrowSize = (isDirectionLeft ? -1 : 1) * 15; var ctx = getctx(); ctx.beginPath(); ctx.arc(max[0], max[1] + radius, radius, isDirectionLeft ? Math.PI * 1 / 2 : Math.PI * 3 / 2, isDirectionLeft ? Math.PI * 3 / 2 : Math.PI * 1 / 2); ctx.moveTo.apply(ctx, end); ctx.lineTo(end[0] + arrowSize, end[1] + arrowSize); ctx.moveTo.apply(ctx, end); ctx.lineTo(end[0] + arrowSize, end[1] - arrowSize); ctx.stroke(); }; return GUI;
}()); var NodeInput = /** @class */ (function () {
function NodeInput(gui, nodeList) { if (gui === void 0) { gui = new GUI(); } this.gui = gui; this.nodeList = nodeList; this.selectedNode = null; this.$$ = document.querySelector.bind(document); this.initEventListener(); this.initCanvasEventListener(); } NodeInput.prototype.initEventListener = function () { var _this = this; var $$ = this.$$; // addNode var addNodeListener = function (e) { var nodenameNode = $$(".inp_addnodename"); var nodeName = nodenameNode.value; nodenameNode.value = ""; _this.nodeList.addNode(nodeName); }; $$(".btn_addnode").addEventListener("click", addNodeListener); $$(".inp_addnodename").addEventListener("keydown", function (e) { if (e.key === "Enter") { addNodeListener(e); } }); $$(".btn_removenode").addEventListener("click", function (e) { if (_this.selectedNode === null) throw Error("삭제할 노드를 선택 해 주세요."); _this.nodeList.removeNode(_this.selectedNode.getName()); var lastNode = _this.nodeList.getNodeList().slice(-1)[0]; console.log(lastNode); _this.gui.nodeSelect(lastNode, false); _this.selectedNode = lastNode; }); var createDocListener = function (e) { var sendMessage = function (message) { return $$(".btn_create_message").innerHTML = message; }; $$(".btn_create_create").removeEventListener("click", createDocListener); sendMessage("문서 생성 요청을 보냈습니다. 준비할때까지 좀만 기다려주세요"); var prefix = $$(".inp_create_target").value; var template = $$(".inp_create_form").value; if (prefix.slice(-1) !== "/") prefix += "/"; DocFactory.create(_this.nodeList, template, prefix, sendMessage); }; $$(".btn_create_create").addEventListener("click", createDocListener); }; NodeInput.prototype.initCanvasEventListener = function () { var _this = this; var $$ = this.$$; var getAxis = function (e) { return ({ x: e.offsetX, y: e.offsetY }); }; var setSelectedNode = function (node, isUnlinkMode) { _this.selectedNode = node; _this.setSelectedNode(node); _this.gui.nodeSelect(_this.selectedNode, isUnlinkMode); }; var isMouseDown = false; // selectNode $$("#nodemap").addEventListener("mousedown", function (e) { var axis = getAxis(e); isMouseDown = true; setSelectedNode(_this.gui.getNodeByAxis(axis), e.button == 2); }); // searchTarget $$("#nodemap").addEventListener("mousemove", function (e) { if (isMouseDown === false) return _this.gui.setDragInfo(null); ; var axis = getAxis(e); _this.gui.getNodeByAxis(axis); _this.gui.setDragInfo(axis); }); // setTarget $$("#nodemap").addEventListener("mouseup", function (e) { var selectedNode = _this.selectedNode; isMouseDown = false; var axis = getAxis(e); var throwNode = _this.gui.getNodeByAxis(axis); if (selectedNode === null || throwNode === null) return; if (e.button == 0) { _this.nodeList.linkNode(throwNode.getName(), selectedNode.getName()); } else if (e.button == 2) { _this.nodeList.unLinkNode(throwNode.getName(), selectedNode.getName()); } }); // removePreventEvent $$("#nodemap").addEventListener("contextmenu", function (e) { e.preventDefault(); }); }; NodeInput.prototype.setSelectedNode = function (node) { var $$ = this.$$; this.selectedNode = node; $$(".spn_nodename").innerHTML = node.getName(); }; return NodeInput;
}()); var DocFactory = /** @class */ (function () {
function DocFactory() { } DocFactory.setTemplateVariable = function (template, templateVariable) { var _a = templateVariable.shift(), searchValue = _a[0], replaceValue = _a[1]; template = template.replace("{[" + searchValue + "]}", replaceValue); if (templateVariable.length != 0) return DocFactory.setTemplateVariable(template, templateVariable); return template; }; DocFactory.setLinkNoding = function (node, template, prefix) { var nodeName = node.getName(); return template.replace(/\{\[링크\|([^]+)\]\}/g, function (matchedStr) { matchedStr = matchedStr.replace(/\{\[링크\|\s*([^]+)\s*\]\}/g, "$1"); return node.getLinked().map(function (linkedNode) { var templateVariable = [ ["링크노드네임", linkedNode.getName()], ["링크페이지네임", prefix + linkedNode.getName()] ]; return DocFactory.setTemplateVariable(matchedStr, templateVariable.slice()); }).join("\n"); }); }; DocFactory.setOtherVariable = function (node, template, prefix) { var nodeName = node.getName(); var templateVariable = [ ["노드네임", nodeName], ["페이지네임", prefix + nodeName] ]; return DocFactory.setTemplateVariable(template, templateVariable); }; DocFactory.create = function (docNodeList, template, prefix, messageCallback) { var nodeList = docNodeList.getNodeList(); var docQueue = nodeList.map(function (node) { var docString = template; var nodeName = node.getName(); docString = DocFactory.setLinkNoding(node, docString, prefix); docString = DocFactory.setOtherVariable(node, docString, prefix); return { title: prefix + nodeName, content: docString }; }); DocFactory.makeDoc(messageCallback, docQueue); }; DocFactory.makeDoc = function (messageCallback, docQueue) { var api = MediaWikiAPI(); var makeDocIntervar = setInterval(function () { if (docQueue.length === 0) { messageCallback("\uBAA8\uB4E0 \uBB38\uC11C\uB97C \uC791\uC131\uD588\uC2B5\uB2C8\uB2E4. \uCD5C\uADFC \uBC14\uB01C\uC744 \uD655\uC778 \uD574 \uC8FC\uC2ED\uC1FC"); clearInterval(makeDocIntervar); } var nextDoc = docQueue.pop(); api.changeDocument(nextDoc.title, "템플릿 문서작성 스크립트 실행중", nextDoc.content, true); messageCallback("\uBB38\uC11C\uB97C \uBAA8\uB450 \uC791\uC131\uD558\uAE30\uAE4C\uC9C0 \uC55E\uC73C\uB85C " + docQueue.length + "\uAC1C \uB0A8\uC558\uC2B5\uB2C8\uB2E4."); }, 3000); }; return DocFactory;
}()); var DocNodeList = /** @class */ (function () {
function DocNodeList(gui) { if (gui === void 0) { gui = new GUI(); } this.gui = gui; this.nodeList = {}; } DocNodeList.prototype.sendDraw = function () { this.gui.setNodeList(Object.values(this.nodeList)); }; DocNodeList.prototype.hasNotNode = function (node) { return typeof node === "undefined"; }; DocNodeList.prototype.linkNode = function (forNodename, toNodename) { var _a = this, hasNotNode = _a.hasNotNode, nodeList = _a.nodeList; var forNode = nodeList[forNodename]; var toNode = nodeList[toNodename]; if (hasNotNode(forNode) || hasNotNode(toNode)) throw Error("존재하지 않는 노드입니다."); toNode.link(forNode); this.sendDraw(); }; DocNodeList.prototype.unLinkNode = function (forNodename, toNodename) { if (toNodename === void 0) { toNodename = null; } var _a = this, hasNotNode = _a.hasNotNode, nodeList = _a.nodeList; var forNode = nodeList[forNodename]; var toNode = nodeList[toNodename]; if (hasNotNode(forNode)) throw Error("존재하지 않는 노드입니다."); if (hasNotNode(toNodename)) { this.getNodeList().forEach(function (currentNode) { currentNode.unLink(forNode); forNode.unLink(currentNode); }); } else { toNode.unLink(forNode); } this.sendDraw(); }; DocNodeList.prototype.addNode = function (nodename) { var nodeList = this.nodeList; if (nodeList[nodename] instanceof Node) throw Error("이미 존재하는 노드입니다"); else { nodeList[nodename] = new DocNode(nodename); this.sendDraw(); } }; DocNodeList.prototype.removeNode = function (nodename) { var nodeList = this.nodeList; var targetNode = nodeList[nodename]; if (this.hasNotNode(targetNode)) throw Error("존재하지 않는 노드입니다."); delete nodeList[nodename]; this.getNodeList().forEach(function (node) { return node.unLink(targetNode); }); this.sendDraw(); }; DocNodeList.prototype.getNodeList = function () { return Object.values(this.nodeList); }; return DocNodeList;
}()); var DocNode = /** @class */ (function () {
function DocNode(name) { this.name = name; this.linkedNode = []; } DocNode.prototype.link = function (node) { if (node === this) return; //throw Error("연결하려는 노드가 자신입니다."); if (this.linkedNode.some(function (currentNode) { return currentNode === node; })) throw Error("이미 연결된 노드입니다."); this.linkedNode.push(node); }; DocNode.prototype.unLink = function (node) { var _this = this; this.linkedNode.forEach(function (currentNode, i) { if (currentNode === node) _this.linkedNode.splice(i, 1); }); }; DocNode.prototype.getLinked = function () { return this.linkedNode; }; DocNode.prototype.getName = function () { return this.name; }; DocNode.prototype.setName = function (name) { return this.name = name; }; return DocNode;
}()); var initHTML = function () {
$("#content").append(`
노드 스케치 조작법
\n- \n
- 노드 선택: 선택하고 싶은 노드 클릭 \n
- 노드 링킹: 링크하고 싶은 노드 클릭 후 링크 대상이 되는 노드에 갖다 끌기 \n
- 노드 링킹 해제: 해제하고 싶은 노드 클릭 후 링크 대상이 되는 노드에 갖다 끌기 \n
새로운 노드 추가
\n 노드 이름 <input class="inp_addnodename"/> <button class="btn_addnode" placeholder="노드의 제목을 입력해주세요..." > 추가 </button>\n기존 노드 수정
\n 현재 선택된 노드: 선택되지 않음 \n <button class="btn_removenode"> 노드 삭제 </button> \n\n노드 작성 완료 및 문서 생성
\n\n 아래 텍스트 에리어에 각 문서에 생성될 템플릿을 입력 해 주세요. 템플릿에서 사용 가능한 특수 문법은 다음과 같습니다.\n {[노드네임]} : 노드 이름을 출력합니다.\n {[페이지네임]} : 페이지 이름을 출력합니다.\n {[링크| .... ]} : 다른 노드와 링크된 갯수만큼 파라미터 안의 내용을 반복합니다.\n {[링크노드네임]} : 링크함수 내부에 쓰이는 변수입니다. 링크된 노드의 이름을 출력합니다.\n {[링크페이지네임]} : 링크함수 내부에 쓰이는 변수입니다. 링크된 페이지의 이름을 출력합니다.\n\n 최상위 문서 제목<input class="inp_create_target" value="리버티게임:언사이라이터/테스트" size="40" />\n\n <textarea class="inp_create_form"> \n현재역은 {[노드네임]}입니다.\n== 선택지 ==\n{[링크|\n* [[{[링크페이지네임]}|{[링크노드네임]}역으로]]\n]}\n </textarea>\n <button class="btn_create_create"> 생성 </button>\n \n</section>
`);
}; var test = (function () {
initHTML(); var gui = new GUI(); var nodeList = new DocNodeList(gui); var nodeInput = new NodeInput(gui, nodeList); nodeList.addNode("서울"); nodeList.addNode("부산"); nodeList.addNode("인천"); nodeList.addNode("대구"); nodeList.linkNode("서울", "부산"); nodeList.linkNode("서울", "인천"); nodeList.linkNode("서울", "대구"); nodeList.linkNode("대구", "부산"); setInterval(function () { return gui.draw(); }, 50); //nodeList.removeNode("미남")
})();