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