简单程序流程图
import QtQuick 2.12
import QtQuick.Window 2.12
Window {
visible: true
width: 640
height: 700
title: qsTr("Hello World")
//style 0圆角矩形 1矩形 2菱形 非012的为平行四边形
property var padding: 20
property var bgc: "#0C283C"
property var fs: 30
property var name: ""
property var lc: "#ffffff"
property var fc: "#ffffff"
property var strokeColor: "#ffffff"
property var fillColor: "#00BFFF"
property var data1: JSON.stringify([
{
"nextNodeID": "1",
// "lc": "255,0,0",
// "fc": "255,0,0",
"style": "0",
"nodeText": "开\t始",
"nodeID": "0"
},
{
"nextNodeID": "2",
"linetext": "",
// "lc": "255,0,0",
// "fc": "255,0,0",
"style": "4",
"nodeText": "初始数据",
"nodeID": "1"
},
{
"nextNodeID": "3",
"linetext": "否",
// "lc": "255,0,0",
// "fc": "255,0,0",
"style": "2",
"nodeText": "初始数据?",
"nodeID": "2"
},
{
"nextNodeID": "4",
"linetext": "是",
// "lc": "255,0,0",
"style": "2",
"nodeText": "",
"nodeID": "2"
},
{
"nextNodeID": "5",
// "lc": "255,0,0",
// "fc": "255,0,0",
"style": "1",
"nodeText": "初始数据",
"nodeID": "3"
},
{
"nextNodeID": "6",
// "lc": "255,0,0",
// "fc": "255,0,0",
"style": "0",
"nodeText": "初始数据",
"nodeID": "4"
},
{
"nextNodeID": "6",
"linetext": "是",
// "lc": "255,0,0",
// "fc": "255,0,0",
"style": "2",
"nodeText": "初始数据",
"nodeID": "5"
},
{
"nextNodeID": "3",
"linetext": "否",
// "lc": "255,0,0",
"style": "2",
"nodeText": "",
"nodeID": "5"
},
{
"nextNodeID": "7",
"linetext": "",
// "lc": "255,0,0",
// "fc": "255,0,0",
"style": "1",
"nodeText": "初始数据",
"nodeID": "6"
},
{
"nextNodeID": "-1",
"linetext": "",
// "lc": "255,0,0",
// "fc": "255,0,0",
"style": "0",
"nodeText": "结\t束",
"nodeID": "7"
}
])
function repeatNum(item,arr){
var count =0;
for(var i=0;i<arr.length;i++){
if(arr[i]==item){
count++
}
}
return count;
}
function colorChange(rgbColor) {
// RGB颜色值的正则
if(rgbColor==undefined){
return "#ffffff"
}
rgbColor = "rgb("+rgbColor+")";
var reg = /^(rgb|RGB)/;
var color = rgbColor;
if (reg.test(color)) {
var strHex = "#";
// 把RGB的3个数值变成数组
var colorArr = color.replace(/(?:\(|\)|rgb|RGB)*/g, "").split(",");
// 转成16进制
for (var i = 0; i < colorArr.length; i++) {
var hex = Number(colorArr[i]).toString(16);
if(hex.length==1){
hex = "0"+hex
}
if (hex === "0") {
hex += hex;
}
strHex += hex;
}
return strHex;
} else {
return String(color);
}
}
Rectangle{
id:bg
width: 1000
height: 700
color: "#0C283C"
anchors.centerIn: parent
Canvas{
id:myCanvas
width: parent.width
height: parent.height
anchors.fill: parent
onPaint: {
var ctx = getContext("2d");
ctx.clearRect(0,0,myCanvas.width,myCanvas.height)
//先对json处理分离成主干-分支-多连线
//存储主干节点
var dataJson = JSON.parse(data1)
console.log("canvasjson:",data1)
var gridModel = [];
var norepeatArr = []
var repeatArr = []
var repeatNextNodeID = []
var leftArr = []
var rightArr = []
for(var i=0;i<dataJson.length;i++){
if(repeatNum(dataJson[i].nodeID,norepeatArr)==0){
if(repeatNum(dataJson[i].nodeID,repeatNextNodeID)==0){
norepeatArr.push(dataJson[i].nodeID)
gridModel.push(dataJson[i])
}else{
rightArr.push(dataJson[i])
}
}else{
repeatArr.push(dataJson[i])
repeatNextNodeID.push(dataJson[i].nextNodeID)
}
}
for(var i=0;i<repeatArr.length;i++){
if(repeatNum(repeatArr[i].nextNodeID,norepeatArr)!=0){
leftArr.push(repeatArr[i])
}else{
for(var j=0;j<rightArr.length;j++){
if(repeatArr[i].nextNodeID==rightArr[j].nodeID){
rightArr[j].parentID = repeatArr[i].nodeID
rightArr[j].linetext = repeatArr[i].linetext
rightArr[j].plc = repeatArr[i].lc
rightArr[j].pfc = repeatArr[i].fc
}
}
}
}
console.log(JSON.stringify(gridModel))
console.log(JSON.stringify(norepeatArr))
console.log(JSON.stringify(repeatArr))
console.log(JSON.stringify(repeatNextNodeID))
console.log(JSON.stringify(leftArr))
console.log(JSON.stringify(rightArr))
//文字宽高 间隔 字体大小 左右分支距离间隔 箭头长度
var w = myCanvas.width/8
var h = myCanvas.height/gridModel.length/2
var interval = myCanvas.height/gridModel.length
var fontpx = h/2
var branchInterval = myCanvas.width/4
var arrowLen = interval/6
//绘制主干
for(var i=0;i<gridModel.length;i++){
var val = gridModel[i]
if(val.style == 0){
ctx.beginPath()
drawRadiusRec(ctx,myCanvas.width/2-w/2,i*interval,w,h,5,val.nodeText,fontpx,colorChange(val.fc))
if(parseInt(val.nextNodeID)>0){
drawArrow(ctx,myCanvas.width/2, interval*i+h, myCanvas.width/2,(i+1)*interval,30,arrowLen,2,colorChange(val.lc),"m",val.linetext?val.linetext:"",fontpx,colorChange(val.fc));
}
ctx.closePath()
}else if(val.style == 1){
ctx.beginPath()
drawRec(ctx,myCanvas.width/2-w/2,i*interval,w,h,val.nodeText,fontpx,colorChange(val.fc))
drawArrow(ctx,myCanvas.width/2, interval*i+h, myCanvas.width/2,(i+1)*interval,30,arrowLen,2,colorChange(val.lc),"m",val.linetext?val.linetext:"",fontpx,colorChange(val.fc));
ctx.closePath()
}
else if(val.style == 2){
ctx.beginPath()
drawLing(ctx,myCanvas.width/2-w/2,i*interval,w,h,val.nodeText,fontpx,colorChange(val.fc))
drawArrow(ctx,myCanvas.width/2, interval*i+h, myCanvas.width/2,(i+1)*interval,30,arrowLen,2,colorChange(val.lc),"m",val.linetext?val.linetext:"",fontpx,colorChange(val.fc));
ctx.closePath()
}
else {
ctx.beginPath()
drawSibianxing(ctx,myCanvas.width/2-w/2,i*interval,w,h,val.nodeText,fontpx,colorChange(val.fc))
drawArrow(ctx,myCanvas.width/2, interval*i+h, myCanvas.width/2,(i+1)*interval,30,arrowLen,2,colorChange(val.lc),"m",val.linetext?val.linetext:"",fontpx,colorChange(val.fc));
ctx.closePath()
}
}
//需要一左一右显示,合并左右数组,间隔添加属性pos为左还是右
var ary1 = JSON.parse(JSON.stringify(leftArr));//深拷贝,否则改变原数组
var ary2 = JSON.parse(JSON.stringify(rightArr));
for (var i = 0; i < ary2.length; i++) {
ary1.splice(1 + 2*i, 0, ary2[i]);
}
console.log(ary1);
for(var i=0;i<ary1.length;i++){
if(i%2==0){
ary1[i].pos="left";
}else{
ary1[i].pos="right";
}
}
//绘制带节点分支
for(var n=0;n<rightArr.length;n++){
var pos = "left";
for(var m=0;m<ary1.length;m++){
if(ary1[m].nodeID==rightArr[n].nodeID){
pos = ary1[m].pos
}
}
var posVal = pos =="left"?-1:1;
var rightX = myCanvas.width/2 +branchInterval*(n+1)*posVal
//暂定分支只能是矩形1 否则再判断是画哪种图形
ctx.beginPath()
//取父节点和子节点在主干的下标,除2取整
var pInd,sInd;
for(var i=0;i<gridModel.length;i++){
if(rightArr[n].parentID==gridModel[i].nodeID){
pInd = i
rightArr[n].parentNodedata = gridModel[i].nodeText
}else if(gridModel[i].nodeID==rightArr[n].nextNodeID){
sInd = i
rightArr[n].sonNodedata = gridModel[i].nodeText
}
}
var midInd = parseInt((parseFloat(pInd)+parseFloat(sInd))/2)
//通过rightarr的下标,更改下y,实现同侧避让
//绘制右分支上箭头
var pX = [rightX+w/2*posVal]
var pY = [interval*pInd+h/2]
//解决因为节点图形因为文字自适应宽度导致箭头起点不对
var fromX = myCanvas.width/2+w/2*posVal
rightArr[n].parentNodedata = rightArr[n].parentNodedata.replace("\t"," ")
if(getTextLen(rightArr[n].parentNodedata,fontpx)+80>w){
fromX = fromX+(getTextLen(rightArr[n].parentNodedata,fontpx)+80-w)/2*posVal
}
//参数说明:canvas对象,起点x,起点y,终点x,终点y,箭头角度,箭头长度,线宽,颜色,节点位置,线文字,拐点个数,拐点x(array),拐点y(array)
drawArrow(ctx,fromX, interval*pInd+h-h/2,rightX+w/2*posVal,interval*midInd,30,arrowLen,2,colorChange(rightArr[n].plc),"r",rightArr[n].linetext,fontpx,colorChange(rightArr[n].pfc),1,pX,pY);
//绘制右分支下箭头
var sX = [rightX+w/2*posVal]
var sY = [interval*sInd+h/2]
var toX = myCanvas.width/2+w/2*posVal
rightArr[n].sonNodedata = rightArr[n].sonNodedata.replace("\t"," ")
if(getTextLen(rightArr[n].sonNodedata,fontpx)>w){
toX = toX+(getTextLen(rightArr[n].sonNodedata,fontpx)-w)/2*posVal
}
//下箭头方向改变,起点终点xy调换
drawArrow(ctx,rightX+w/2*posVal,interval*midInd,toX, interval*sInd+h/2, 30,arrowLen,2,colorChange(rightArr[n].lc),"r","",fontpx,colorChange(rightArr[n].fc),1,sX,sY);
var x1 = posVal==1?rightX:rightX-w
drawRec(ctx,x1,midInd*interval,w,h,rightArr[n].nodeText,fontpx,colorChange(rightArr[n].fc))
ctx.closePath()
}
//绘制无节点分支,只有箭头连线
for(var i=0;i<leftArr.length;i++){
var pos1 = "left";
for(var m=0;m<ary1.length;m++){
if(ary1[m].nodeID==leftArr[i].nodeID){
pos1 = ary1[m].pos
}
}
var posVal1 = pos1 =="left"?1:-1;
var leftX = myCanvas.width/2 -branchInterval*(i+1)*posVal1
//取父节点和子节点在主干的下标,除2取整
var tInd,bInd;
for(var j=0;j<gridModel.length;j++){
if(leftArr[i].nodeID==gridModel[j].nodeID){
leftArr[i].parentNodedata = gridModel[j].nodeText
bInd = j
}else if(gridModel[j].nodeID==leftArr[i].nextNodeID){
leftArr[i].sonNodedata = gridModel[j].nodeText
tInd = j
}
}
var fromX1 = myCanvas.width/2-w/2*posVal1
leftArr[i].parentNodedata = leftArr[i].parentNodedata.replace("\t"," ")
if(getTextLen(leftArr[i].parentNodedata,fontpx)+80>w){
fromX1 = fromX1-(getTextLen(leftArr[i].parentNodedata,fontpx)+80-w)/2*posVal1
}
var toX1 = myCanvas.width/2-w/2*posVal1
leftArr[i].sonNodedata = leftArr[i].sonNodedata.replace("\t"," ")
if(getTextLen(leftArr[i].sonNodedata,fontpx)>w){
toX1 = toX1-(getTextLen(leftArr[i].sonNodedata,fontpx)-w)/2*posVal1
}
//无节点的情况下为两拐点
var lX = [leftX-w/2*posVal1,leftX-w/2*posVal1]
var lY = [interval*bInd+h/2,interval*tInd+h/2]
drawArrow(ctx,fromX1,interval*bInd+h/2,toX1, interval*tInd+h/2, 30,arrowLen,2,colorChange(leftArr[i].lc),"l",leftArr[i].linetext,fontpx,colorChange(leftArr[i].fc),2,lX,lY);
}
}
}
}
function getTextLen(str,fs){
if(str == undefined||fs==undefined){
return 0
}
return str.replace(/[\u0391-\uFFE5]/g,"aa").length*fs/2; //先把中文替换成两个字节的英文,在计算长度
}
// (x,y):圆角矩形起始坐标; width: 矩形宽度; height: 矩形高度; r: 矩形圆角;
function drawRadiusRec(ctx, x, y, width, height, r,text,ifs,ifc){
console.log("indexof",text.indexOf("\t")!=-1)
if(text.indexOf("\t")!=-1){
text = text.replace("\t"," ")
}
if(ifs == undefined){
ifs = fs
}
if(ifc == undefined){
if(typeof fc == "object"){
ifc = fc
}else{
if(fc.indexOf(",")!=-1){
ifc = colorChange(fc)
}else{
ifc = fc
}
}
}
if(getTextLen(text,ifs)>width){
x -=(getTextLen(text,ifs)-width)/2
width = getTextLen(text,ifs)
}
ctx.beginPath();
ctx.moveTo(x + r, y);
ctx.lineWidth = 2;
ctx.strokeStyle = strokeColor;//矩形填充颜色
ctx.fillStyle = fillColor;//矩形填充颜色
ctx.lineTo(x + width - r, y);
ctx.arc(x + width - r, y + r, r, Math.PI*1.5, Math.PI*2);
ctx.lineTo(x + width, y + height - r);
ctx.arc(x + width - r, y + height - r, r, 0, Math.PI*0.5);
ctx.lineTo(x + r, y + height);
ctx.arc(x + r, y + height - r, r, Math.PI*0.5, Math.PI);
ctx.lineTo(x, y + r);
ctx.arc(x + r, y + r, r, Math.PI, Math.PI*1.5);
ctx.stroke();
ctx.fill();
ctx.font = ifs+"px bold 黑体";
// 设置颜色
ctx.fillStyle = ifc;
// 设置水平对齐方式
ctx.textAlign = "center";
// 设置垂直对齐方式
ctx.textBaseline = "middle";
// 绘制文字(参数:要写的字,x坐标,y坐标)
ctx.fillText(text, x+width/2, y+height/2);
}
function drawRec(ctx,x,y,width,height,text,ifs,ifc){
if(text.indexOf("\t")!=-1){
text = text.replace("\t"," ")
}
if(ifs == undefined){
ifs = fs
}
if(ifc == undefined){
if(typeof fc == "object"){
ifc = fc
}else{
if(fc.indexOf(",")!=-1){
ifc = colorChange(fc)
}else{
ifc = fc
}
}
}
if(getTextLen(text,ifs)>width){
x -=(getTextLen(text,ifs)-width)/2
width = getTextLen(text,ifs)
}
ctx.fillStyle=fillColor; //fillStyle设置填充颜色
ctx.strokeStyle=strokeColor; //strokeStyle设置边框颜色
ctx.lineWidth=2;
ctx.fillRect(x,y,width,height);
ctx.strokeRect(x,y,width,height);
ctx.font = ifs+"px bold 黑体";
// 设置颜色
ctx.fillStyle = ifc;
// 设置水平对齐方式
ctx.textAlign = "center";
// 设置垂直对齐方式
ctx.textBaseline = "middle";
// 绘制文字(参数:要写的字,x坐标,y坐标)
ctx.fillText(text, x+width/2, y+height/2);
}
//画四边形
function drawSibianxing(ctx,x,y,width,height,text,ifs,ifc){
if(text.indexOf("\t")!=-1){
text = text.replace("\t"," ")
}
if(ifs == undefined){
ifs = fs
}
if(ifc == undefined){
if(typeof fc == "object"){
ifc = fc
}else{
if(fc.indexOf(",")!=-1){
ifc = colorChange(fc)
}else{
ifc = fc
}
}
}
if(getTextLen(text,ifs)>width){
x -=(getTextLen(text,ifs)-width)/2
width = getTextLen(text,ifs)
}
ctx.lineWidth = 2;
ctx.fillStyle = fillColor;
ctx.strokeStyle = strokeColor;
ctx.beginPath();
ctx.moveTo(x,y+height);
ctx.lineTo(x+10,y);
ctx.lineTo(x+10+width,y);
ctx.lineTo(x+width,y+height);
ctx.closePath();
ctx.stroke();
ctx.fill();
ctx.font = ifs+"px bold 黑体";
// 设置颜色
ctx.fillStyle = ifc;
// 设置水平对齐方式
ctx.textAlign = "center";
// 设置垂直对齐方式
ctx.textBaseline = "middle";
// 绘制文字(参数:要写的字,x坐标,y坐标)
ctx.fillText(text, x+width/2, y+height/2);
}
//画菱形
function drawLing(ctx,x,y,width,height,text,ifs,ifc){
if(text.indexOf("\t")!=-1){
text = text.replace("\t"," ")
}
if(ifs == undefined){
ifs = fs
}
if(ifc == undefined){
if(typeof fc == "object"){
ifc = fc
}else{
if(fc.indexOf(",")!=-1){
ifc = colorChange(fc)
}else{
ifc = fc
}
}
}
if(getTextLen(text,ifs)+80>width){
x -=(getTextLen(text,ifs)+80-width)/2
width = getTextLen(text,ifs)+80
}
ctx.lineWidth = 2;
ctx.fillStyle = fillColor;
ctx.strokeStyle = strokeColor;
ctx.beginPath();
ctx.moveTo(x,y+height/2);
ctx.lineTo(x+width/2,y);
ctx.lineTo(x+width,y+height/2);
ctx.lineTo(x+width/2,y+height);
ctx.closePath();
ctx.stroke();
ctx.fill();
ctx.font = ifs+"px bold 黑体";
// 设置颜色
ctx.fillStyle = ifc;
// 设置水平对齐方式
ctx.textAlign = "center";
// 设置垂直对齐方式
ctx.textBaseline = "middle";
// 绘制文字(参数:要写的字,x坐标,y坐标)
ctx.fillText(text, x+width/2, y+height/2);
}
// 画箭头
//参数说明:canvas对象,起点x,起点y,终点x,终点y,箭头角度,箭头长度,线宽,线色,节点位置,线文字,字体大小,字体颜色,拐点个数,拐点x(array),拐点y(array)当字体大小及颜色未传值时,root属性fc及lc才会生效
function drawArrow(ctx, fromX, fromY, toX, toY, theta, headlen, width, color,nodePox,lineText,ifs,ifc,pointNum,pointX,pointY) {
theta = typeof (theta) != 'undefined' ? theta : 30;
headlen = typeof (theta) != 'undefined' ? headlen : 10;
width = typeof (width) != 'undefined' ? width : 1;
// color = typeof (color) != 'color' ? color : '#000';
if(ifs == undefined){
ifs = fs
}
if(ifc == undefined){
if(typeof fc == "object"){
ifc = fc
}else{
if(fc.indexOf(",")!=-1){
ifc = colorChange(fc)
}else{
ifc = fc
}
}
}
if(color == undefined){
if(typeof lc == "object"){
color = lc
}else{
if(lc.indexOf(",")!=-1){
color = colorChange(lc)
}else{
color = lc
}
}
}
// 计算各角度和对应的P2,P3坐标
var angle;
if(pointX==undefined){
angle = Math.atan2(fromY - toY, fromX - toX) * 180 / Math.PI
}else{
angle = Math.atan2(parseInt(pointY[pointY.length-1])-toY, parseInt(pointX[pointX.length-1]) - toX)* 180 / Math.PI
}
var angle1 = (angle + theta) * Math.PI / 180,
angle2 = (angle - theta) * Math.PI / 180,
topX = headlen * Math.cos(angle1),
topY = headlen * Math.sin(angle1),
botX = headlen * Math.cos(angle2),
botY = headlen * Math.sin(angle2);
ctx.save();
ctx.beginPath();
var arrowX = fromX - topX,
arrowY = fromY - topY;
ctx.moveTo(arrowX, arrowY);
ctx.moveTo(fromX, fromY);
if(pointNum!=undefined){
for(var i=0;i<pointX.length;i++){
ctx.lineTo(pointX[i], pointY[i]);
}
}
ctx.lineTo(toX, toY);
arrowX = toX + topX;
arrowY = toY + topY;
ctx.moveTo(arrowX, arrowY);
ctx.lineTo(toX, toY);
arrowX = toX + botX;
arrowY = toY + botY;
ctx.lineTo(arrowX, arrowY);
ctx.strokeStyle = color;
ctx.lineWidth = width;
ctx.stroke();
ctx.restore();
ctx.font = ifs+"px bold 黑体";
// 设置水平对齐方式
ctx.textAlign = nodePox=="r"?"right":"left";
// 设置颜色
ctx.fillStyle = ifc;
// 绘制文字(参数:要写的字,x坐标,y坐标)
var posX;
console.log('drawText');
if(pointNum!=undefined){
posX = pointX[0]
}else {
posX = (toX-fromX)/2+fromX
}
ctx.fillText(lineText, posX, (toY-fromY)/2+fromY);
}
}