- moved gitgraph.js to web_src and made it importable and es6-compatible - created new webpack chunk for gitgraph - enabled CSS loader in webpack - enabled async/await syntax via regenerator-runtime - added script to ensure webpack chunks are loaded correctly - disable terser's comment extraction to prevent .LICENCE files gitgraph.js has many issues: 1. it is incompatible with ES6 because of strict-mode violations 1. it does not export anything 1. it's css has weird styles like for `body` 1. it is not available on npm I fixed points 1-3 in our version so it's now loadable in webpack. We should eventually consider alternatives.for-closed-social
@ -1 +1,2 @@ | |||
/public/js/semantic.dropdown.custom.js | |||
/web_src/js/vendor/** |
@ -1,435 +0,0 @@ | |||
/* | |||
* @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD 3-Clause | |||
* Copyright (c) 2011, Terrence Lee <kill889@gmail.com> | |||
* All rights reserved. | |||
* | |||
* Redistribution and use in source and binary forms, with or without | |||
* modification, are permitted provided that the following conditions are met: | |||
* * Redistributions of source code must retain the above copyright | |||
* notice, this list of conditions and the following disclaimer. | |||
* * Redistributions in binary form must reproduce the above copyright | |||
* notice, this list of conditions and the following disclaimer in the | |||
* documentation and/or other materials provided with the distribution. | |||
* * Neither the name of the <organization> nor the | |||
* names of its contributors may be used to endorse or promote products | |||
* derived from this software without specific prior written permission. | |||
* | |||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | |||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
* DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY | |||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
*/ | |||
var gitGraph = function (canvas, rawGraphList, config) { | |||
if (!canvas.getContext) { | |||
return; | |||
} | |||
if (typeof config === "undefined") { | |||
config = { | |||
unitSize: 20, | |||
lineWidth: 3, | |||
nodeRadius: 4 | |||
}; | |||
} | |||
var flows = []; | |||
var graphList = []; | |||
var ctx = canvas.getContext("2d"); | |||
var devicePixelRatio = window.devicePixelRatio || 1; | |||
var backingStoreRatio = ctx.webkitBackingStorePixelRatio || | |||
ctx.mozBackingStorePixelRatio || | |||
ctx.msBackingStorePixelRatio || | |||
ctx.oBackingStorePixelRatio || | |||
ctx.backingStorePixelRatio || 1; | |||
var ratio = devicePixelRatio / backingStoreRatio; | |||
var init = function () { | |||
var maxWidth = 0; | |||
var i; | |||
var l = rawGraphList.length; | |||
var row; | |||
var midStr; | |||
for (i = 0; i < l; i++) { | |||
midStr = rawGraphList[i].replace(/\s+/g, " ").replace(/^\s+|\s+$/g, ""); | |||
maxWidth = Math.max(midStr.replace(/(\_|\s)/g, "").length, maxWidth); | |||
row = midStr.split(""); | |||
graphList.unshift(row); | |||
} | |||
var width = maxWidth * config.unitSize; | |||
var height = graphList.length * config.unitSize; | |||
canvas.width = width * ratio; | |||
canvas.height = height * ratio; | |||
canvas.style.width = width + 'px'; | |||
canvas.style.height = height + 'px'; | |||
ctx.lineWidth = config.lineWidth; | |||
ctx.lineJoin = "round"; | |||
ctx.lineCap = "round"; | |||
ctx.scale(ratio, ratio); | |||
}; | |||
var genRandomStr = function () { | |||
var chars = "0123456789ABCDEF"; | |||
var stringLength = 6; | |||
var randomString = '', rnum, i; | |||
for (i = 0; i < stringLength; i++) { | |||
rnum = Math.floor(Math.random() * chars.length); | |||
randomString += chars.substring(rnum, rnum + 1); | |||
} | |||
return randomString; | |||
}; | |||
var findFlow = function (id) { | |||
var i = flows.length; | |||
while (i-- && flows[i].id !== id) {} | |||
return i; | |||
}; | |||
var findColomn = function (symbol, row) { | |||
var i = row.length; | |||
while (i-- && row[i] !== symbol) {} | |||
return i; | |||
}; | |||
var findBranchOut = function (row) { | |||
if (!row) { | |||
return -1 | |||
} | |||
var i = row.length; | |||
while (i-- && | |||
!(row[i - 1] && row[i] === "/" && row[i - 1] === "|") && | |||
!(row[i - 2] && row[i] === "_" && row[i - 2] === "|")) {} | |||
return i; | |||
}; | |||
var findLineBreak = function (row) { | |||
if (!row) { | |||
return -1 | |||
} | |||
var i = row.length; | |||
while (i-- && | |||
!(row[i - 1] && row[i - 2] && row[i] === " " && row[i - 1] === "|" && row[i - 2] === "_")) {} | |||
return i; | |||
}; | |||
var genNewFlow = function () { | |||
var newId; | |||
do { | |||
newId = genRandomStr(); | |||
} while (findFlow(newId) !== -1); | |||
return {id:newId, color:"#" + newId}; | |||
}; | |||
//Draw methods | |||
var drawLine = function (moveX, moveY, lineX, lineY, color) { | |||
ctx.strokeStyle = color; | |||
ctx.beginPath(); | |||
ctx.moveTo(moveX, moveY); | |||
ctx.lineTo(lineX, lineY); | |||
ctx.stroke(); | |||
}; | |||
var drawLineRight = function (x, y, color) { | |||
drawLine(x, y + config.unitSize / 2, x + config.unitSize, y + config.unitSize / 2, color); | |||
}; | |||
var drawLineUp = function (x, y, color) { | |||
drawLine(x, y + config.unitSize / 2, x, y - config.unitSize / 2, color); | |||
}; | |||
var drawNode = function (x, y, color) { | |||
ctx.strokeStyle = color; | |||
drawLineUp(x, y, color); | |||
ctx.beginPath(); | |||
ctx.arc(x, y, config.nodeRadius, 0, Math.PI * 2, true); | |||
ctx.fill(); | |||
}; | |||
var drawLineIn = function (x, y, color) { | |||
drawLine(x + config.unitSize, y + config.unitSize / 2, x, y - config.unitSize / 2, color); | |||
}; | |||
var drawLineOut = function (x, y, color) { | |||
drawLine(x, y + config.unitSize / 2, x + config.unitSize, y - config.unitSize / 2, color); | |||
}; | |||
var draw = function (graphList) { | |||
var colomn, colomnIndex, prevColomn, condenseIndex, breakIndex = -1; | |||
var x, y; | |||
var color; | |||
var nodePos; | |||
var tempFlow; | |||
var prevRowLength = 0; | |||
var flowSwapPos = -1; | |||
var lastLinePos; | |||
var i, l; | |||
var condenseCurrentLength, condensePrevLength = 0, condenseNextLength = 0; | |||
var inlineIntersect = false; | |||
//initiate color array for first row | |||
for (i = 0, l = graphList[0].length; i < l; i++) { | |||
if (graphList[0][i] !== "_" && graphList[0][i] !== " ") { | |||
flows.push(genNewFlow()); | |||
} | |||
} | |||
y = (canvas.height / ratio) - config.unitSize * 0.5; | |||
//iterate | |||
for (i = 0, l = graphList.length; i < l; i++) { | |||
x = config.unitSize * 0.5; | |||
currentRow = graphList[i]; | |||
nextRow = graphList[i + 1]; | |||
prevRow = graphList[i - 1]; | |||
flowSwapPos = -1; | |||
condenseCurrentLength = currentRow.filter(function (val) { | |||
return (val !== " " && val !== "_") | |||
}).length; | |||
if (nextRow) { | |||
condenseNextLength = nextRow.filter(function (val) { | |||
return (val !== " " && val !== "_") | |||
}).length; | |||
} else { | |||
condenseNextLength = 0; | |||
} | |||
//pre process begin | |||
//use last row for analysing | |||
if (prevRow) { | |||
if (!inlineIntersect) { | |||
//intersect might happen | |||
for (colomnIndex = 0; colomnIndex < prevRowLength; colomnIndex++) { | |||
if (prevRow[colomnIndex + 1] && | |||
(prevRow[colomnIndex] === "/" && prevRow[colomnIndex + 1] === "|") || | |||
((prevRow[colomnIndex] === "_" && prevRow[colomnIndex + 1] === "|") && | |||
(prevRow[colomnIndex + 2] === "/"))) { | |||
flowSwapPos = colomnIndex; | |||
//swap two flow | |||
tempFlow = {id:flows[flowSwapPos].id, color:flows[flowSwapPos].color}; | |||
flows[flowSwapPos].id = flows[flowSwapPos + 1].id; | |||
flows[flowSwapPos].color = flows[flowSwapPos + 1].color; | |||
flows[flowSwapPos + 1].id = tempFlow.id; | |||
flows[flowSwapPos + 1].color = tempFlow.color; | |||
} | |||
} | |||
} | |||
if (condensePrevLength < condenseCurrentLength && | |||
((nodePos = findColomn("*", currentRow)) !== -1 && | |||
(findColomn("_", currentRow) === -1))) { | |||
flows.splice(nodePos - 1, 0, genNewFlow()); | |||
} | |||
if (prevRowLength > currentRow.length && | |||
(nodePos = findColomn("*", prevRow)) !== -1) { | |||
if (findColomn("_", currentRow) === -1 && | |||
findColomn("/", currentRow) === -1 && | |||
findColomn("\\", currentRow) === -1) { | |||
flows.splice(nodePos + 1, 1); | |||
} | |||
} | |||
} //done with the previous row | |||
prevRowLength = currentRow.length; //store for next round | |||
colomnIndex = 0; //reset index | |||
condenseIndex = 0; | |||
condensePrevLength = 0; | |||
breakIndex = -1; //reset break index | |||
while (colomnIndex < currentRow.length) { | |||
colomn = currentRow[colomnIndex]; | |||
if (colomn !== " " && colomn !== "_") { | |||
++condensePrevLength; | |||
} | |||
//check and fix line break in next row | |||
if (colomn === "/" && currentRow[colomnIndex - 1] && currentRow[colomnIndex - 1] === "|") { | |||
if ((breakIndex = findLineBreak(nextRow)) !== -1) { | |||
nextRow.splice(breakIndex, 1); | |||
} | |||
} | |||
//if line break found replace all '/' with '|' after breakIndex in previous row | |||
if (breakIndex !== - 1 && colomn === "/" && colomnIndex > breakIndex) { | |||
currentRow[colomnIndex] = "|"; | |||
colomn = "|"; | |||
} | |||
if (colomn === " " && | |||
currentRow[colomnIndex + 1] && | |||
currentRow[colomnIndex + 1] === "_" && | |||
currentRow[colomnIndex - 1] && | |||
currentRow[colomnIndex - 1] === "|") { | |||
currentRow.splice(colomnIndex, 1); | |||
currentRow[colomnIndex] = "/"; | |||
colomn = "/"; | |||
} | |||
//create new flow only when no intersect happened | |||
if (flowSwapPos === -1 && | |||
colomn === "/" && | |||
currentRow[colomnIndex - 1] && | |||
currentRow[colomnIndex - 1] === "|") { | |||
flows.splice(condenseIndex, 0, genNewFlow()); | |||
} | |||
//change \ and / to | when it's in the last position of the whole row | |||
if (colomn === "/" || colomn === "\\") { | |||
if (!(colomn === "/" && findBranchOut(nextRow) === -1)) { | |||
if ((lastLinePos = Math.max(findColomn("|", currentRow), | |||
findColomn("*", currentRow))) !== -1 && | |||
(lastLinePos < colomnIndex - 1)) { | |||
while (currentRow[++lastLinePos] === " ") {} | |||
if (lastLinePos === colomnIndex) { | |||
currentRow[colomnIndex] = "|"; | |||
} | |||
} | |||
} | |||
} | |||
if (colomn === "*" && | |||
prevRow && | |||
prevRow[condenseIndex + 1] === "\\") { | |||
flows.splice(condenseIndex + 1, 1); | |||
} | |||
if (colomn !== " ") { | |||
++condenseIndex; | |||
} | |||
++colomnIndex; | |||
} | |||
condenseCurrentLength = currentRow.filter(function (val) { | |||
return (val !== " " && val !== "_") | |||
}).length; | |||
//do some clean up | |||
if (flows.length > condenseCurrentLength) { | |||
flows.splice(condenseCurrentLength, flows.length - condenseCurrentLength); | |||
} | |||
colomnIndex = 0; | |||
//a little inline analysis and draw process | |||
while (colomnIndex < currentRow.length) { | |||
colomn = currentRow[colomnIndex]; | |||
prevColomn = currentRow[colomnIndex - 1]; | |||
if (currentRow[colomnIndex] === " ") { | |||
currentRow.splice(colomnIndex, 1); | |||
x += config.unitSize; | |||
continue; | |||
} | |||
//inline interset | |||
if ((colomn === "_" || colomn === "/") && | |||
currentRow[colomnIndex - 1] === "|" && | |||
currentRow[colomnIndex - 2] === "_") { | |||
inlineIntersect = true; | |||
tempFlow = flows.splice(colomnIndex - 2, 1)[0]; | |||
flows.splice(colomnIndex - 1, 0, tempFlow); | |||
currentRow.splice(colomnIndex - 2, 1); | |||
colomnIndex = colomnIndex - 1; | |||
} else { | |||
inlineIntersect = false; | |||
} | |||
color = flows[colomnIndex].color; | |||
switch (colomn) { | |||
case "_" : | |||
drawLineRight(x, y, color); | |||
x += config.unitSize; | |||
break; | |||
case "*" : | |||
drawNode(x, y, color); | |||
break; | |||
case "|" : | |||
drawLineUp(x, y, color); | |||
break; | |||
case "/" : | |||
if (prevColomn && | |||
(prevColomn === "/" || | |||
prevColomn === " ")) { | |||
x -= config.unitSize; | |||
} | |||
drawLineOut(x, y, color); | |||
x += config.unitSize; | |||
break; | |||
case "\\" : | |||
drawLineIn(x, y, color); | |||
break; | |||
} | |||
++colomnIndex; | |||
} | |||
y -= config.unitSize; | |||
} | |||
}; | |||
init(); | |||
draw(graphList); | |||
}; | |||
// @end-license |
@ -1,15 +0,0 @@ | |||
/* globals gitGraph */ | |||
$(() => { | |||
const graphList = []; | |||
if (!document.getElementById('graph-canvas')) { | |||
return; | |||
} | |||
$('#graph-raw-list li span.node-relation').each(function () { | |||
graphList.push($(this).text()); | |||
}); | |||
gitGraph(document.getElementById('graph-canvas'), graphList); | |||
}); |
@ -0,0 +1,16 @@ | |||
$(async () => { | |||
const graphCanvas = document.getElementById('graph-canvas'); | |||
if (!graphCanvas) return; | |||
const [{ default: gitGraph }] = await Promise.all([ | |||
import(/* webpackChunkName: "gitgraph" */'../vendor/gitgraph.js/gitgraph.custom.js'), | |||
import(/* webpackChunkName: "gitgraph" */'../vendor/gitgraph.js/gitgraph.custom.css'), | |||
]); | |||
const graphList = []; | |||
$('#graph-raw-list li span.node-relation').each(function () { | |||
graphList.push($(this).text()); | |||
}); | |||
gitGraph(graphCanvas, graphList); | |||
}); |
@ -0,0 +1,12 @@ | |||
/* This sets up webpack's chunk loading to load resources from the same | |||
directory where it loaded index.js from. This file must be imported | |||
before any lazy-loading is being attempted. */ | |||
if (document.currentScript && document.currentScript.src) { | |||
const url = new URL(document.currentScript.src); | |||
__webpack_public_path__ = `${url.pathname.replace(/\/[^/]*$/, '')}/`; | |||
} else { | |||
// compat: IE11 | |||
const script = document.querySelector('script[src*="/index.js"]'); | |||
__webpack_public_path__ = `${script.getAttribute('src').replace(/\/[^/]*$/, '')}/`; | |||
} |
@ -0,0 +1,419 @@ | |||
/* | |||
* @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD 3-Clause | |||
* Copyright (c) 2011, Terrence Lee <kill889@gmail.com> | |||
* All rights reserved. | |||
* | |||
* Redistribution and use in source and binary forms, with or without | |||
* modification, are permitted provided that the following conditions are met: | |||
* * Redistributions of source code must retain the above copyright | |||
* notice, this list of conditions and the following disclaimer. | |||
* * Redistributions in binary form must reproduce the above copyright | |||
* notice, this list of conditions and the following disclaimer in the | |||
* documentation and/or other materials provided with the distribution. | |||
* * Neither the name of the <organization> nor the | |||
* names of its contributors may be used to endorse or promote products | |||
* derived from this software without specific prior written permission. | |||
* | |||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | |||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
* DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY | |||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
*/ | |||
export default function gitGraph(canvas, rawGraphList, config) { | |||
if (!canvas.getContext) { | |||
return; | |||
} | |||
if (typeof config === 'undefined') { | |||
config = { | |||
unitSize: 20, | |||
lineWidth: 3, | |||
nodeRadius: 4 | |||
}; | |||
} | |||
const flows = []; | |||
const graphList = []; | |||
const ctx = canvas.getContext('2d'); | |||
const devicePixelRatio = window.devicePixelRatio || 1; | |||
const backingStoreRatio = ctx.webkitBackingStorePixelRatio | |||
|| ctx.mozBackingStorePixelRatio | |||
|| ctx.msBackingStorePixelRatio | |||
|| ctx.oBackingStorePixelRatio | |||
|| ctx.backingStorePixelRatio || 1; | |||
const ratio = devicePixelRatio / backingStoreRatio; | |||
const init = function () { | |||
let maxWidth = 0; | |||
let i; | |||
const l = rawGraphList.length; | |||
let row; | |||
let midStr; | |||
for (i = 0; i < l; i++) { | |||
midStr = rawGraphList[i].replace(/\s+/g, ' ').replace(/^\s+|\s+$/g, ''); | |||
maxWidth = Math.max(midStr.replace(/(_|\s)/g, '').length, maxWidth); | |||
row = midStr.split(''); | |||
graphList.unshift(row); | |||
} | |||
const width = maxWidth * config.unitSize; | |||
const height = graphList.length * config.unitSize; | |||
canvas.width = width * ratio; | |||
canvas.height = height * ratio; | |||
canvas.style.width = `${width}px`; | |||
canvas.style.height = `${height}px`; | |||
ctx.lineWidth = config.lineWidth; | |||
ctx.lineJoin = 'round'; | |||
ctx.lineCap = 'round'; | |||
ctx.scale(ratio, ratio); | |||
}; | |||
const genRandomStr = function () { | |||
const chars = '0123456789ABCDEF'; | |||
const stringLength = 6; | |||
let randomString = '', rnum, i; | |||
for (i = 0; i < stringLength; i++) { | |||
rnum = Math.floor(Math.random() * chars.length); | |||
randomString += chars.substring(rnum, rnum + 1); | |||
} | |||
return randomString; | |||
}; | |||
const findFlow = function (id) { | |||
let i = flows.length; | |||
while (i-- && flows[i].id !== id); | |||
return i; | |||
}; | |||
const findColomn = function (symbol, row) { | |||
let i = row.length; | |||
while (i-- && row[i] !== symbol); | |||
return i; | |||
}; | |||
const findBranchOut = function (row) { | |||
if (!row) { | |||
return -1; | |||
} | |||
let i = row.length; | |||
while (i-- | |||
&& !(row[i - 1] && row[i] === '/' && row[i - 1] === '|') | |||
&& !(row[i - 2] && row[i] === '_' && row[i - 2] === '|')); | |||
return i; | |||
}; | |||
const findLineBreak = function (row) { | |||
if (!row) { | |||
return -1; | |||
} | |||
let i = row.length; | |||
while (i-- | |||
&& !(row[i - 1] && row[i - 2] && row[i] === ' ' && row[i - 1] === '|' && row[i - 2] === '_')); | |||
return i; | |||
}; | |||
const genNewFlow = function () { | |||
let newId; | |||
do { | |||
newId = genRandomStr(); | |||
} while (findFlow(newId) !== -1); | |||
return { id: newId, color: `#${newId}` }; | |||
}; | |||
// Draw methods | |||
const drawLine = function (moveX, moveY, lineX, lineY, color) { | |||
ctx.strokeStyle = color; | |||
ctx.beginPath(); | |||
ctx.moveTo(moveX, moveY); | |||
ctx.lineTo(lineX, lineY); | |||
ctx.stroke(); | |||
}; | |||
const drawLineRight = function (x, y, color) { | |||
drawLine(x, y + config.unitSize / 2, x + config.unitSize, y + config.unitSize / 2, color); | |||
}; | |||
const drawLineUp = function (x, y, color) { | |||
drawLine(x, y + config.unitSize / 2, x, y - config.unitSize / 2, color); | |||
}; | |||
const drawNode = function (x, y, color) { | |||
ctx.strokeStyle = color; | |||
drawLineUp(x, y, color); | |||
ctx.beginPath(); | |||
ctx.arc(x, y, config.nodeRadius, 0, Math.PI * 2, true); | |||
ctx.fill(); | |||
}; | |||
const drawLineIn = function (x, y, color) { | |||
drawLine(x + config.unitSize, y + config.unitSize / 2, x, y - config.unitSize / 2, color); | |||
}; | |||
const drawLineOut = function (x, y, color) { | |||
drawLine(x, y + config.unitSize / 2, x + config.unitSize, y - config.unitSize / 2, color); | |||
}; | |||
const draw = function (graphList) { | |||
let colomn, colomnIndex, prevColomn, condenseIndex, breakIndex = -1; | |||
let x, y; | |||
let color; | |||
let nodePos; | |||
let tempFlow; | |||
let prevRowLength = 0; | |||
let flowSwapPos = -1; | |||
let lastLinePos; | |||
let i, l; | |||
let condenseCurrentLength, condensePrevLength = 0; | |||
let inlineIntersect = false; | |||
// initiate color array for first row | |||
for (i = 0, l = graphList[0].length; i < l; i++) { | |||
if (graphList[0][i] !== '_' && graphList[0][i] !== ' ') { | |||
flows.push(genNewFlow()); | |||
} | |||
} | |||
y = (canvas.height / ratio) - config.unitSize * 0.5; | |||
// iterate | |||
for (i = 0, l = graphList.length; i < l; i++) { | |||
x = config.unitSize * 0.5; | |||
const currentRow = graphList[i]; | |||
const nextRow = graphList[i + 1]; | |||
const prevRow = graphList[i - 1]; | |||
flowSwapPos = -1; | |||
condenseCurrentLength = currentRow.filter((val) => { | |||
return (val !== ' ' && val !== '_'); | |||
}).length; | |||
// pre process begin | |||
// use last row for analysing | |||
if (prevRow) { | |||
if (!inlineIntersect) { | |||
// intersect might happen | |||
for (colomnIndex = 0; colomnIndex < prevRowLength; colomnIndex++) { | |||
if (prevRow[colomnIndex + 1] | |||
&& (prevRow[colomnIndex] === '/' && prevRow[colomnIndex + 1] === '|') | |||
|| ((prevRow[colomnIndex] === '_' && prevRow[colomnIndex + 1] === '|') | |||
&& (prevRow[colomnIndex + 2] === '/'))) { | |||
flowSwapPos = colomnIndex; | |||
// swap two flow | |||
tempFlow = { id: flows[flowSwapPos].id, color: flows[flowSwapPos].color }; | |||
flows[flowSwapPos].id = flows[flowSwapPos + 1].id; | |||
flows[flowSwapPos].color = flows[flowSwapPos + 1].color; | |||
flows[flowSwapPos + 1].id = tempFlow.id; | |||
flows[flowSwapPos + 1].color = tempFlow.color; | |||
} | |||
} | |||
} | |||
if (condensePrevLength < condenseCurrentLength | |||
&& ((nodePos = findColomn('*', currentRow)) !== -1 | |||
&& (findColomn('_', currentRow) === -1))) { | |||
flows.splice(nodePos - 1, 0, genNewFlow()); | |||
} | |||
if (prevRowLength > currentRow.length | |||
&& (nodePos = findColomn('*', prevRow)) !== -1) { | |||
if (findColomn('_', currentRow) === -1 | |||
&& findColomn('/', currentRow) === -1 | |||
&& findColomn('\\', currentRow) === -1) { | |||
flows.splice(nodePos + 1, 1); | |||
} | |||
} | |||
} // done with the previous row | |||
prevRowLength = currentRow.length; // store for next round | |||
colomnIndex = 0; // reset index | |||
condenseIndex = 0; | |||
condensePrevLength = 0; | |||
breakIndex = -1; // reset break index | |||
while (colomnIndex < currentRow.length) { | |||
colomn = currentRow[colomnIndex]; | |||
if (colomn !== ' ' && colomn !== '_') { | |||
++condensePrevLength; | |||
} | |||
// check and fix line break in next row | |||
if (colomn === '/' && currentRow[colomnIndex - 1] && currentRow[colomnIndex - 1] === '|') { | |||
if ((breakIndex = findLineBreak(nextRow)) !== -1) { | |||
nextRow.splice(breakIndex, 1); | |||
} | |||
} | |||
// if line break found replace all '/' with '|' after breakIndex in previous row | |||
if (breakIndex !== -1 && colomn === '/' && colomnIndex > breakIndex) { | |||
currentRow[colomnIndex] = '|'; | |||
colomn = '|'; | |||
} | |||
if (colomn === ' ' | |||
&& currentRow[colomnIndex + 1] | |||
&& currentRow[colomnIndex + 1] === '_' | |||
&& currentRow[colomnIndex - 1] | |||
&& currentRow[colomnIndex - 1] === '|') { | |||
currentRow.splice(colomnIndex, 1); | |||
currentRow[colomnIndex] = '/'; | |||
colomn = '/'; | |||
} | |||
// create new flow only when no intersect happened | |||
if (flowSwapPos === -1 | |||
&& colomn === '/' | |||
&& currentRow[colomnIndex - 1] | |||
&& currentRow[colomnIndex - 1] === '|') { | |||
flows.splice(condenseIndex, 0, genNewFlow()); | |||
} | |||
// change \ and / to | when it's in the last position of the whole row | |||
if (colomn === '/' || colomn === '\\') { | |||
if (!(colomn === '/' && findBranchOut(nextRow) === -1)) { | |||
if ((lastLinePos = Math.max(findColomn('|', currentRow), | |||
findColomn('*', currentRow))) !== -1 | |||
&& (lastLinePos < colomnIndex - 1)) { | |||
while (currentRow[++lastLinePos] === ' '); | |||
if (lastLinePos === colomnIndex) { | |||
currentRow[colomnIndex] = '|'; | |||
} | |||
} | |||
} | |||
} | |||
if (colomn === '*' | |||
&& prevRow | |||
&& prevRow[condenseIndex + 1] === '\\') { | |||
flows.splice(condenseIndex + 1, 1); | |||
} | |||
if (colomn !== ' ') { | |||
++condenseIndex; | |||
} | |||
++colomnIndex; | |||
} | |||
condenseCurrentLength = currentRow.filter((val) => { | |||
return (val !== ' ' && val !== '_'); | |||
}).length; | |||
// do some clean up | |||
if (flows.length > condenseCurrentLength) { | |||
flows.splice(condenseCurrentLength, flows.length - condenseCurrentLength); | |||
} | |||
colomnIndex = 0; | |||
// a little inline analysis and draw process | |||
while (colomnIndex < currentRow.length) { | |||
colomn = currentRow[colomnIndex]; | |||
prevColomn = currentRow[colomnIndex - 1]; | |||
if (currentRow[colomnIndex] === ' ') { | |||
currentRow.splice(colomnIndex, 1); | |||
x += config.unitSize; | |||
continue; | |||
} | |||
// inline interset | |||
if ((colomn === '_' || colomn === '/') | |||
&& currentRow[colomnIndex - 1] === '|' | |||
&& currentRow[colomnIndex - 2] === '_') { | |||
inlineIntersect = true; | |||
tempFlow = flows.splice(colomnIndex - 2, 1)[0]; | |||
flows.splice(colomnIndex - 1, 0, tempFlow); | |||
currentRow.splice(colomnIndex - 2, 1); | |||
colomnIndex -= 1; | |||
} else { | |||
inlineIntersect = false; | |||
} | |||
color = flows[colomnIndex].color; | |||
switch (colomn) { | |||
case '_': | |||
drawLineRight(x, y, color); | |||
x += config.unitSize; | |||
break; | |||
case '*': | |||
drawNode(x, y, color); | |||
break; | |||
case '|': | |||
drawLineUp(x, y, color); | |||
break; | |||
case '/': | |||
if (prevColomn | |||
&& (prevColomn === '/' | |||
|| prevColomn === ' ')) { | |||
x -= config.unitSize; | |||
} | |||
drawLineOut(x, y, color); | |||
x += config.unitSize; | |||
break; | |||
case '\\': | |||
drawLineIn(x, y, color); | |||
break; | |||
} | |||
++colomnIndex; | |||
} | |||
y -= config.unitSize; | |||
} | |||
}; | |||
init(); | |||
draw(graphList); | |||
} | |||
// @end-license |