From 047adab942866e5a55b6a8d77603a7163cae7f68 Mon Sep 17 00:00:00 2001 From: platxcngw Date: Wed, 16 Aug 2023 17:01:03 +0800 Subject: [PATCH] =?UTF-8?q?=E7=B3=BB=E7=BB=9F=E6=B5=81=E7=A8=8B=E5=9B=BEja?= =?UTF-8?q?vascript=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- flowchart.js | 616 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 616 insertions(+) create mode 100644 flowchart.js diff --git a/flowchart.js b/flowchart.js new file mode 100644 index 0000000..5b25d20 --- /dev/null +++ b/flowchart.js @@ -0,0 +1,616 @@ +/** + * 流程图绘制方法集 + * 作者:刘广文 + * 邮箱:liugw@imut.edu.cn + * 版本:20230813 + * 功能:基于canvas实现流程图的绘制 + */ +var tool = 1; +var current = -1; +var flag=false; +var mouseX= 0; +var mouseY= 0; +var mouseX1= 0; +var mouseY1= 0; +var aryPoint = []; +var aryObject = []; + +//加载工具 +function loadTools(target){ + target.innerHTML = "
开始
" + + "
处理
" + + "
" + + "
" + + "
条件?
" + + "
结束
" + + "
显示
" + + "
1
"; +} +//鼠标抬起响应动作 +function myMouseUp(e, page){ + flag=false; + pushTool(tool, mouseX, mouseY, mouseX1, mouseY1, text.value, color.value, bcolor.value, size.value); + updateTools(cxt); +} +//鼠标移动响应动作 +function myMouseMove(e, page){ + mouseX1= e.pageX-page.offsetLeft; + mouseY1= e.pageY-page.offsetTop; + if(flag){ + var aryPoint1 = []; + var i = 0; + while(i < aryPoint.length){ + aryPoint1.push(aryPoint[i]); + i ++; + } + updateTools(cxt); + aryPoint = []; + i = 0; + while(i < aryPoint1.length){ + aryPoint.push(aryPoint1[i]); + i ++; + } + if (tool == 4){ + var s = aryPoint[aryPoint.length - 1]; + ary = s.split(","); + var x = parseFloat(ary[0]), y = parseFloat(ary[1]); + if (Math.abs(x - mouseX1) > 10 || Math.abs(y - mouseY1) > 10) + aryPoint.push(mouseX1 + "," + mouseY1); + } + drawTool(cxt, tool, mouseX, mouseY, mouseX1, mouseY1, color.value, bcolor.value, size.value); + } +} + +//鼠标按下响应动作 +function myMouseDown(e, page) +{ + mouseX= e.pageX-page.offsetLeft; + mouseY= e.pageY-page.offsetTop; + aryPoint = []; + aryPoint.push(mouseX + "," + mouseY); + flag=true; +} +//保存 +function save(){ + var ary = []; + var i = 0; + while(i <= current){ + ary.push(aryObject[i]); + i ++; + } + aryObject = ary; + updateButton(); + const fileName = 'flowchart.txt'; + var str = ''; + i = 0; + while(i < aryObject.length){ + if (i == 0) + str = aryObject[i] + else{ + str += "\r\n" + str += aryObject[i] + } + i ++; + } + const content = str + const blob = new Blob([content], {type: 'application/text'}); + // 构造一个blob对象来处理数据 + // 对于标签,只有 Firefox 和 Chrome(内核) 支持 download 属性 + // IE10以上支持blob但是依然不支持download + if ('download' in document.createElement('a')) + { + // 支持a标签download的浏览器 + const link = document.createElement('a') + // 创建a标签 + link.download = fileName + // a标签添加属性 + link.style.display = 'none' + link.href = URL.createObjectURL(blob) + document.body.appendChild(link) + link.click() + // 执行下载 + URL.revokeObjectURL(link.href) + // 释放url + document.body.removeChild(link) + // 释放标签 + } else { + // 其他浏览器 + navigator.msSaveBlob(blob, fileName) + } +} +//撤销 +function undo(){ + if (current >= 0) + { + current --; + updateTools(); + } + updateButton(); +} +//刷新按钮状态 +function updateButton(){ + var undo = document.getElementById("undo"); + var redo = document.getElementById("redo"); + var save = document.getElementById("save"); + if (current >= 0) + { + save.disabled = false; + undo.disabled = false; + } + else + { + undo.disabled = true; + save.disabled = true; + } + if (current < aryObject.length - 1) + { + redo.disabled = false; + } + else { + redo.disabled = true; + } +} +//重做 +function redo(){ + if (current < aryObject.length - 1) + { + current ++; + updateTools(); + } + updateButton(); +} + +//选择工具 +function clickTool(o, tag){ + tool = tag; + for(var i = 0; i < tools.children.length; i ++){ + tools.children[i].style.border = '1px solid black'; + } + o.style.border = '2px solid red'; + text.hidden = true; + text.value = ""; + if (tag == 1) + { + text.hidden = false; + text.value = "开始"; + } + if (tag == 2) + { + text.hidden = false; + text.value = "处理"; + } + if (tag == 3 || tag == 4){ + text.hidden = false; + text.value = ""; + } + if (tag == 5) + { + text.hidden = false; + text.value = "条件"; + } + if (tag == 6) + { + text.hidden = false; + text.value = "结束"; + } + if (tag == 7) + { + text.hidden = false; + text.value = "显示信息"; + } + if (tag == 8) + { + text.hidden = false; + text.value = "1"; + } +} + +//绘制所有工具 +function updateTools(context){ + canvas.width = canvas.width; + var i = 0; + while (i <= current){ + var ary = aryObject[i].split('|'); + var type = parseInt(ary[0]); + var ary1 = ary[1].split(','); + var x1 = parseFloat(ary1[0]); + var y1 = parseFloat (ary1[1]); + var x2 = parseFloat(ary1[2]); + var y2 = parseFloat(ary1[3]); + var size = parseFloat(ary[5]); + var color = ary[3]; + var bcolor = ary[4]; + if(type == 4){ + x2 = parseFloat(ary1[ary1.length - 2]); + y2 = parseFloat(ary1[ary1.length - 1]); + aryPoint = []; + var j = 0; + while(j < ary1.length){ + var x = parseFloat(ary1[j]), y = parseFloat(ary1[j + 1]); + aryPoint.push(x + "," + y); + j += 2; + } + } + drawTool(cxt, type, x1, y1, x2, y2, color, bcolor, size); + drawText(cxt, type, x1, y1, x2, y2, ary[2], color); + i ++; + } +} +//保存当前的绘制 +function pushTool(type, x1, y1, x2, y2, text, color, bcolor, size){ + var ary = []; + var i = 0; + while(i <= current){ + ary.push(aryObject[i]); + i ++; + } + aryObject = ary; + var s = type + '|' + x1 + ',' + y1 + ',' + x2 + ',' + y2 + '|' + text + '|' + color + '|' + bcolor + '|' + size; + if(type == 4){ + s = type + '|'; + i = 0; + while(i < aryPoint.length){ + if (i > 0) + s += ","; + s += aryPoint[i]; + i ++; + } + s = s + '|' + text + '|' + color + '|' + bcolor + '|' + size; + } + aryObject.push(s); + current ++; + updateButton(); +} +//绘制文本 +function drawText(context, type, x1, y1, x2, y2, text, color){ + if (text == "" || context == null || type < 1) return; + switch(type){ + case 1: + case 2: + case 5: + case 6: + case 7: + case 8:{ + //绘制开始框 + //计算宽高 + var l = x1, t = y1; + var w = x2 - x1, h = y2 - y1; + if (w < 0) + { + l = x2; + w = x1 - x2; + } + if (h < 0){ + t = y2; + h = y1 - y2; + } + context.font = "10pt SimSun"; + //updateFont(context, w, h, text, 100); + var w1 = getFontWidth(context, text); + var h1 = getFontHeight(context, text); + context.fillStyle = color; + context.fillText(text, l + (w - w1) / 2, t + h1 / 4 + h / 2); + break; + } + case 3:{ + //绘制箭头 + //计算文字大小 + context.font = "10pt SimSun"; + var w = getFontWidth(context, text); + var h = getFontHeight(context, text); + //获得输出坐标 + var x = (x2 + x1) / 2; + var y = (y2 + y1) / 2; + context.fillStyle = color; + context.fillText(text, x, y); + break; + } + case 4:{ + //绘制箭头 + //计算文字大小 + context.font = "10pt SimSun"; + var w = getFontWidth(context, text); + var h = getFontHeight(context, text); + //获得输出坐标 + var px1 = x1, py1 = y1; + var i = 1; + var pp = 0; + while(i < aryPoint.length) + { + var ary = aryPoint[i].split(','); + var px = parseFloat(ary[0]), py = parseFloat(ary[1]); + var pp1 = 2; + if (Math.abs(px - px1) > Math.abs(py - py1)) pp1 = 1; + if (pp != 0 && pp1 != pp) break; + pp = pp1; + px1 = px; + py1 = py; + i ++; + } + var x = (px1 + x1) / 2; + var y = (py1 + y1) / 2; + context.fillStyle = color; + context.fillText(text, x, y); + break; + } + } + +} +//绘制当前工具 +function drawTool(context, type, x1, y1, x2, y2, color, bcolor, size){ + if (context == null || type < 1) return; + switch(type){ + case 1:{ + //绘制开始框 + //计算宽高 + var l = x1, t = y1; + var w = x2 - x1, h = y2 - y1; + if (w < 0) + { + l = x2; + w = x1 - x2; + } + if (h < 0){ + t = y2; + h = y1 - y2; + } + context.strokeStyle = color; + context.lineWidth = size; + context.beginPath(); + context.moveTo(l, t + h / 2); + context.lineTo(l + w * 0.15, t); + context.lineTo(l + w - w * 0.15, t); + context.lineTo(l + w, t + h / 2); + context.lineTo(l + w - w * 0.15, t + h); + context.lineTo(l + w * 0.15, t + h); + context.lineTo(l, t + h / 2); + context.closePath(); + context.fillStyle = bcolor; + context.fill(); + context.stroke(); + break; + } + case 2:{ + //绘制处理框 + //计算宽高 + var l = x1, t = y1; + var w = x2 - x1, h = y2 - y1; + if (w < 0) + { + l = x2; + w = x1 - x2; + } + if (h < 0){ + t = y2; + h = y1 - y2; + } + context.strokeStyle = color; + context.lineWidth = size; + context.beginPath(); + context.moveTo(l, t); + context.lineTo(l + w, t); + context.lineTo(l + w, t + h); + context.lineTo(l, t + h); + context.lineTo(l, t); + context.closePath(); + context.fillStyle = bcolor; + context.fill(); + context.stroke(); + break; + } + case 3:{ + //绘制连接箭头 + //计算箭头方向 + var ll = 10, ss = 30; + var a = Math.atan2((y2 - y1), (x2 - x1)); + var x3 = x2 - ll * Math.cos(a + ss * Math.PI/180); + var y3 = y2 - ll * Math.sin(a + ss * Math.PI/180); + var x4 = x2 - ll * Math.cos(a - ss * Math.PI/180); + var y4 = y2 - ll * Math.sin(a - ss * Math.PI/180); + context.strokeStyle = color; + context.lineWidth = size; + context.beginPath(); + context.moveTo(x1, y1); + context.lineTo(x2, y2); + context.lineTo(x3, y3); + context.moveTo(x2, y2); + context.lineTo(x4, y4) + context.closePath(); + context.stroke(); + break; + } + case 4:{ + //绘制折线连接箭头 + if (aryPoint.length < 3) + break; + var ary = aryPoint[aryPoint.length - 2].split(','); + var px1 = parseFloat(ary[0]), py1 = parseFloat(ary[1]); + ary = aryPoint[aryPoint.length - 1].split(','); + var px2 = parseFloat(ary[0]), py2 = parseFloat(ary[1]); + if (Math.abs(px2 - px1) > Math.abs(py2 - py1)) + py1 = py2; + else px1 = px2; + //计算箭头方向 + var ll = 10, ss = 30; + var a = Math.atan2((py2 - py1), (px2 - px1)); + var x3 = px2 - ll * Math.cos(a + ss * Math.PI/180); + var y3 = py2 - ll * Math.sin(a + ss * Math.PI/180); + var x4 = px2 - ll * Math.cos(a - ss * Math.PI/180); + var y4 = py2 - ll * Math.sin(a - ss * Math.PI/180); + context.strokeStyle = color; + context.lineWidth = size; + context.beginPath(); + context.lineTo(px2, py2); + context.lineTo(x3, y3); + context.moveTo(px2, py2); + context.lineTo(x4, y4) + context.moveTo(px2, py2); + context.lineTo(px1, py1); + var i = aryPoint.length - 3; + while(i >= 0){ + ary = aryPoint[i].split(','); + px2 = parseFloat(ary[0]), py2 = parseFloat(ary[1]); + if (Math.abs(px2 - px1) > Math.abs(py2 - py1)) + py2 = py1; + else px2 = px1; + context.moveTo(px1, py1); + context.lineTo(px2, py2); + px1 = px2; + py1 = py2; + i --; + } + context.closePath(); + context.stroke(); + break; + } + case 5:{ + //绘制判断框 + //计算宽高 + var l = x1, t = y1; + var w = x2 - x1, h = y2 - y1; + if (w < 0) + { + l = x2; + w = x1 - x2; + } + if (h < 0){ + t = y2; + h = y1 - y2; + } + context.strokeStyle = color; + context.lineWidth = size; + context.beginPath(); + context.moveTo(l, t + h / 2); + context.lineTo(l + w / 2, t); + context.lineTo(l + w, t + h / 2); + context.lineTo(l + w / 2, t + h); + context.lineTo(l, t + h / 2); + context.closePath(); + context.fillStyle = bcolor; + context.fill(); + context.stroke(); + break; + } + case 6:{ + //绘制结束框 + //计算宽高 + var l = x1, t = y1; + var w = x2 - x1, h = y2 - y1; + if (w < 0) + { + l = x2; + w = x1 - x2; + } + if (h < 0){ + t = y2; + h = y1 - y2; + } + context.strokeStyle = color; + context.lineWidth = size; + var r = w * 0.4; + if (h < w) + r = h * 0.4; + context.beginPath(); + context.moveTo(l + r, t); + context.arcTo(l + w, t, l + w, t + h, r); + context.arcTo(l + w, t + h, l, t + h, r); + context.arcTo(l, t + h, l, t, r); + context.arcTo(l, t, l + w, t, r); + context.closePath(); + context.fillStyle = bcolor; + context.fill(); + context.stroke(); + break; + } + case 7:{ + //绘制信息显示框 + //计算宽高 + var l = x1, t = y1; + var w = x2 - x1, h = y2 - y1; + if (w < 0) + { + l = x2; + w = x1 - x2; + } + if (h < 0){ + t = y2; + h = y1 - y2; + } + context.strokeStyle = color; + context.lineWidth = size; + var r = w * 0.4; + if (h < w) + r = h * 0.4; + context.beginPath(); + context.moveTo(l, t + h / 2); + context.lineTo(l + r, t); + context.lineTo(l + w - r, t); + context.arcTo(l + w, t, l + w, t + h, r); + context.arcTo(l + w, t + h, l, t + h, r); + context.lineTo(l + w - r, t + h); + context.lineTo(l + r, t + h); + context.lineTo(l, t + h / 2); + //context.arcTo(l, t + h, l, t, r); + //context.arcTo(l, t, l + w, t, r); + context.closePath(); + context.fillStyle = bcolor; + context.fill(); + context.stroke(); + break; + } + case 8:{ + //绘制连接框 + //计算宽高 + var l = x1, t = y1; + var w = x2 - x1, h = y2 - y1; + if (w < 0) + { + l = x2; + w = x1 - x2; + } + if (h < 0){ + t = y2; + h = y1 - y2; + } + context.strokeStyle = color; + context.lineWidth = size; + context.beginPath(); + context.arc(l + w / 2, t + h / 2, Math.min(w, h), 0, 360); + context.closePath(); + context.fillStyle = bcolor; + context.fill(); + context.stroke(); + break; + } + } +} + +//计算当前字体下的文本宽度 +function getFontWidth(context, txt) { + const metrics = context.measureText(txt); + const actual = Math.abs(metrics.actualBoundingBoxLeft ?? 0) + Math.abs(metrics.actualBoundingBoxRight ?? 0); + const width = Math.max(metrics.width, actual); + return width; +} +//计算当前字体下的文本高度 +function getFontHeight(context, txt) { + const metrics = context.measureText(txt); + const fontHeight = metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent; + //所有字在这个字体下的高度 + //const actualHeight = metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent; + return fontHeight; +} +//自动调整字体大小 +function updateFont(context, w, h, text, size){ + context.font = size + "pt SimSun"; + w1 = getFontWidth(context, text) * 2; + h1 = getFontHeight(context, text) * 2; + var s = size; + while (w1 > w || h1 > h){ + s = s - 1; + context.font = s + "pt SimSun"; + w1 = getFontWidth(context, text) * 2; + h1 = getFontHeight(context, text) * 2; + } + return s; +} \ No newline at end of file