最近在做一个需求,根据数据动态生成以下类似的流程图,需要可以设置每个节点的颜色,每个节点可添加点击移动等相关的事件

代码中有做很多的注释和说明,相关的文档说明链接:https://9eb75i.axshare.com

drawFlowChart.js


//画所有的图形:画图和画对应的箭头
function drawFlowChart(context,canvas,flowdata,initTop, initSpaceH){//1、判断是否有需要平均计算x的数据flowdata.forEach(function(row){if(row.isAverage){row.data = calChartX(canvas.width,row.data, row.y);}});//2、先要画完所有的图形flowdata.forEach(function(row,rowIndex){row.y = row.y ? row.y : ( rowIndex==0 ? initTop + initSpaceH : initTop + initSpaceH*rowIndex);row = drawRowChart(context, row);  //画图形});//3、添加要指向的对象,必须要在画完所有图形之后flowdata.forEach(function(row){row.data.forEach(function(item){if(item.arrowArr && item.arrowArr.length){item.arrowArr.forEach(function(mItem){mItem = addToObj(mItem,flowdata);})}})});//4、给所有图形画上对应的画箭头,必须要在前两步完成之后flowdata.forEach(function(row,rowIndex){row.data.forEach(function(item){if(item.arrowArr && item.arrowArr.length){drawSingleArrow(context,item);//画箭头}})});//5、给所有元素添加点击和悬浮事件addMethod(canvas,flowdata)
}
//当一行有n个图形并且需要平均排列时用此方法计算每个图形的x
function calChartX(canvasW,data, dataY){var startW = 80;var stepW = 120;var CondW = 30;var count = 0;for(var i=0;i<data.length;i++){if(data[i].type == 'Step'){count += stepW;}else if(data[i].type == 'Start' || data[i].type == 'End'){count += startW;}else if(data[i].type == 'Condition'){count += CondW;}}//spaceW 计算一行中每个图形的平均间距var spaceW = parseInt((canvasW - count)/(data.length+1));//计算坐标xvar prevDiv = [], curW = 0;for(var i=0;i<data.length;i++){if(data[i].type == 'Step'){prevDiv.push(stepW);curW = stepW/2;}else if(data[i].type == 'Start' || data[i].type == 'End'){prevDiv.push(startW);curW = startW/2;}else if(data[i].type == 'Condition'){prevDiv.push(CondW);curW = CondW/2;}var preLength = 0;for(var j=0;j<i;j++){preLength += prevDiv[j];}var x = spaceW*(i+1)+preLength+curW;var y = data[i].y;data[i]['x'] = x;data[i]['y'] = y ? y : dataY;}return data;
}
//生成每列对应的图形
function drawRowChart(context, row){row.data.forEach(function(item,index){var s = null;item.y =  item.y ? item.y : row.y;if(item.type == 'Step'){s = new Step(context,item.x,item.y,item);}else if(item.type == 'Condition'){s = new Condition(context,item.x,item.y,item);}else if(item.type == 'End'){s = new End(context,item.x,item.y,item);}else if(item.type == 'Start'){s = new Start(context,item.x,item.y,item);}item.chartObj = s;})return row;
}
//绘制单个的图形
function drawSingleChart(context,item){var s = '';if(item.type == 'Step'){s = new Step(context,item.x,item.y,item);}else if(item.type == 'Condition'){s = new Condition(context,item.x,item.y,item);}else if(item.type == 'End'){s = new End(context,item.x,item.y,item);}else if(item.type == 'Start'){s = new Start(context,item.x,item.y,item);}item.chartObj = s;return item;
}
//每个对象的坐标范围
function calRange(obj){var newObj = {minX:obj.x-obj.w/2,maxX:obj.x+obj.w/2,minY:obj.y-obj.h/2,maxY:obj.y+obj.h/2}return newObj;
}
//处理每一个箭头需要指向的对象
function addToObj(arrObj,flowData){flowData.forEach(function(rows){rows.data.forEach(function(item){if(item.name == arrObj.to){arrObj.to = item.chartObj;}})})return arrObj;
}
//话每个图形的箭头指向
function drawSingleArrow(context,data){var step1 = data.chartObj;if(data.arrowArr && data.arrowArr.length){data.arrowArr.forEach(function(item){step1[item.arrow](item.to,context);})}
}
//清除单个图形
function repaintSingleChart(context,item){var range  = item.chartObj.range;//清除之前画的图形context.clearRect(range.minX-1,range.minY-1,item.chartObj.w+2,item.chartObj.h+3);}
//给所有图形添加事件
function addMethod(canvas,flowData){//给所有图形添加点击事件canvas.onclick=function(e){var curx = e.layerX;var cury = e.layerY;flowData.forEach(function(row,listIndex){row.data.forEach(function(item){var range  = item.chartObj.range;if(curx>=range.minX && curx<=range.maxX && cury>=range.minY && cury<=range.maxY){var clickMethod = null;if(row.method && row.method.onclick){ //如果每行定义了事件//判断每个元素是否有单独定义事件,如果有,取改元素定义的事件,如果没有取每行定义的事件if(item.method && item.method.onclick){clickMethod = item.method.onclick}else{clickMethod = row.method.onclick}}else{if(item.method && item.method.onclick){clickMethod = item.method.onclick}else{clickMethod = null;}}if(clickMethod instanceof Function){clickMethod(item);}}})});};var timer = null;//给所有图形添加mousemove事件canvas.onmousemove=function(e){var curx = e.layerX;var cury = e.layerY;clearTimeout(timer);flowData.forEach(function(row,listIndex){row.data.forEach(function(item){var range  = item.chartObj.range;if(curx>=range.minX && curx<=range.maxX && cury>=range.minY && cury<=range.maxY){var clickMethod = null;if(row.method && row.method.onmousemove){ //如果每行定义了事件//判断每个元素是否有单独定义事件,如果有,取改元素定义的事件,如果没有取每行定义的事件if(item.method && item.method.onmousemove){clickMethod = item.method.onmousemove}else{clickMethod = row.method.onmousemove}}else{if(item.method && item.method.onmousemove){clickMethod = item.method.onmousemove}else{clickMethod = null;}}if(clickMethod instanceof Function){timer = setTimeout(function(){clickMethod(item);},1000)}}})});}//给所有图形添加mouseleave事件canvas.onmouseleave=function(e){var curx = e.layerX;var cury = e.layerY;clearTimeout(timer);flowData.forEach(function(row){row.data.forEach(function(item){var range  = item.chartObj.range;if(curx>=range.minX && curx<=range.maxX && cury>=range.minY && cury<=range.maxY){var clickMethod = null;if(row.method && row.method.onmouseleave){ //如果每行定义了事件//判断每个元素是否有单独定义事件,如果有,取改元素定义的事件,如果没有取每行定义的事件if(item.method && item.method.onmouseleave){clickMethod = item.method.onmouseleave}else{clickMethod = row.method.onmouseleave}}else{if(item.method && item.method.onmouseleave){clickMethod = item.method.onmouseleave}else{clickMethod = null;}}if(clickMethod instanceof Function){clickMethod(item);}}})});}
}/基本画图形start
//画圆角矩形
function drawRoundRect(context, x, y, w, h, item, radius, tsw) {radius = radius || 20;context.beginPath();context.arc(x + radius, y + radius, radius, Math.PI, Math.PI * 3 / 2);context.lineTo(w - radius + x, y);context.arc(w - radius + x, radius + y, radius, Math.PI * 3 / 2, Math.PI * 2);context.lineTo(w + x, h + y - radius);context.arc(w - radius + x, h - radius + y, radius, 0, Math.PI * 1 / 2);context.lineTo(radius + x, h +y);context.arc(radius + x, h - radius + y, radius, Math.PI * 1 / 2, Math.PI);context.closePath();context.fillStyle = item.color ? (item.color.bgColor ? item.color.bgColor: 'rgba(91,155,213,0.5)'):'white' ; //背景颜色context.fill();context.strokeStyle= item.color ? (item.color.borderColor ? item.color.borderColor: '#5B9BD5'):'#5B9BD5' ; //边框颜色context.font = 'normal 14px 微软雅黑';var textStyle = textSize('14px','微软雅黑',item.text);tsw = tsw ? tsw : parseInt(textStyle.width/2);context.fillStyle = item.color ? (item.color.fontColor ? item.color.fontColor: '#5B9BD5'):'#5B9BD5' ; //文字颜色context.fillText(item.text, x+w/2-tsw, y+h/2+6);context.stroke();
}
//画菱形
function drawRhombus(context,x, y, l, item) {context.beginPath();context.moveTo(x, y + l);context.lineTo(x - l * 2, y);context.lineTo(x, y - l);context.lineTo(x + l * 2, y);context.closePath();context.strokeStyle= item.color ? (item.color.borderColor ? item.color.borderColor: '#5B9BD5'):'#5B9BD5' ; //边框颜色context.fillStyle = item.color ? (item.color.bgColor ? item.color.bgColor: 'rgba(91,155,213,0.5)'):'white' ; //背景颜色context.fill();context.fillStyle = '#5B9BD5'; //文字颜色context.font = 'normal 14px 微软雅黑';context.fillText(item.text, x, y+3);context.stroke();
}
//计算文本的宽高
function textSize(fontSize,fontFamily,text){var span = document.createElement("span");var result = {};result.width = span.offsetWidth;result.height = span.offsetHeight;span.style.visibility = "hidden";span.style.fontSize = fontSize;span.style.fontFamily = fontFamily;span.style.display = "inline-block";document.body.appendChild(span);if(typeof span.textContent != "undefined"){span.textContent = text;}else{span.innerText = text;}result.width = parseFloat(window.getComputedStyle(span).width) - result.width;result.height = parseFloat(window.getComputedStyle(span).height) - result.height;return result;
}
//Start 圆角矩形对象
function Start(context,x, y, item, h, w) {this.flag = 'start';this.h = h || 40;this.w = w || 2 * this.h;this.x = x;this.y = y;this.text = item.text;this.range = calRange(this);drawRoundRect(context,x - this.w / 2, y - this.h / 2, this.w, this.h, item);
}
//End 圆角矩形对象
function End(context, x, y, item, h, w) {this.flag = 'end';this.h = h || 40;this.w = w || 2 * this.h;this.x = x;this.y = y;this.text = item.text;this.range = calRange(this);drawRoundRect(context, x - this.w / 2, y - this.h / 2, this.w, this.h, item, 20, -2);
}
//Step 矩形对象
function Step(context,x, y, item) {this.flag = "step";this.h = 40;this.w = 2 * 60;this.x = x;this.y = y;this.text = item.text;this.range = calRange(this);context.strokeStyle= item.color ? (item.color.borderColor ? item.color.borderColor: '#5B9BD5'):'#5B9BD5' ; //边框颜色context.strokeRect(x - this.w / 2, y - this.h / 2, this.w, this.h);context.fillStyle = item.color ? (item.color.bgColor ? item.color.bgColor: 'rgba(91,155,213,0.5)'):'white' ; //背景颜色context.fillRect(x - this.w / 2, y - this.h / 2,this.w,this.h);context.fillStyle = item.color ? (item.color.fontColor ? item.color.fontColor: '#5B9BD5'):'#5B9BD5' ; //文字颜色context.textAlign = 'center';context.font = 'normal 14px 微软雅黑';if(item.text){context.fillText(item.text,x, y+4);}}
//Condition 菱形对象
function Condition(context, x, y, item) {this.flag = "condition";this.l = 30;this.h = 30;this.w = 30;this.x = x;this.y = y;this.text = item.text;this.range = calRange(this);drawRhombus(context,x, y, this.l, item);
}/基本画图形end画箭头/
//箭头从start圆角矩形bottom——>top
Start.prototype.drawBottomToTop = function(obj,context) {if(obj.flag == "step") {var arrow = new Arrow(this.x, this.y + this.h / 2, obj.x, obj.y - obj.h / 2);arrow.drawBottomToTop(context);} else if(obj.flag == "condition") {var arrow = new Arrow(this.x, this.y + this.h / 2, obj.x, obj.y - obj.l);arrow.drawBottomToTop(context);}
}//箭头从step矩形bottom——>right
Step.prototype.drawBottomToRight = function(obj,context) {var arrow = null;if(obj.flag == "step") {arrow = new Arrow(this.x, this.y + this.h / 2, obj.x + obj.w / 2 , obj.y);} else if(obj.flag == "condition") {arrow = new Arrow(this.x , this.y + this.h / 2, obj.x + obj.l*2 , obj.y);}else if(obj.flag == "start" || obj.flag == "end"){arrow = new Arrow(this.x , this.y + this.h / 2, obj.x + obj.w/2 , obj.y);}arrow.drawBottomToRight(context);
}
//箭头从step矩形bottom——>left
Step.prototype.drawBottomToLeft = function(obj,context) {var arrow = null;if(obj.flag == "step") {arrow = new Arrow(this.x, this.y + this.h / 2, obj.x - obj.w / 2 , obj.y);} else if(obj.flag == "condition") {arrow = new Arrow(this.x , this.y + this.h / 2, obj.x - obj.l*2 , obj.y);}else if(obj.flag == "start" || obj.flag == "end"){arrow = new Arrow(this.x , this.y + this.h / 2, obj.x - obj.w/2 , obj.y);}arrow.drawBottomToRight(context);
}
//箭头从step矩形bottom——>top
Step.prototype.drawBottomToTop = function(obj,context) {if(obj.flag == "step") {var arrow = new Arrow(this.x, this.y + this.h / 2, obj.x, obj.y - obj.h / 2);arrow.drawBottomToTop(context);} else if(obj.flag == "condition") {var arrow = new Arrow(this.x, this.y + this.h / 2, obj.x, obj.y - obj.l);arrow.drawBottomToTop(context);}
}
//箭头从step矩形right——>left
Step.prototype.drawRightToLeft = function(obj,context) {var arrow = null;if(obj.flag == "step") {arrow = new Arrow(this.x + this.w / 2, this.y, obj.x - obj.w / 2 , obj.y);} else if(obj.flag == "condition") {arrow = new Arrow(this.x + this.w / 2, this.y, obj.x-obj.l*2 , obj.y);}else if(obj.flag == "start" || obj.flag == "end"){arrow = new Arrow(this.x + this.w / 2, this.y, obj.x-obj.w/2 , obj.y);}arrow.drawLeftToRightOrRightToLeft(context);
}//箭头从Condition菱形Bottom——>top
Condition.prototype.drawBottomToTop = function(obj,context) {if(obj.flag == "step") {var arrow = new Arrow(this.x, this.y + this.l, obj.x, obj.y - obj.h / 2);arrow.drawBottomToTop(context);} else if(obj.flag == "condition") {var arrow = new Arrow(this.x, this.y + this.l, obj.x, obj.y - obj.l);arrow.drawBottomToTop(context);}
}
//箭头从Condition菱形right——>top
Condition.prototype.drawRightToTop = function(obj, context) {if(obj.flag == "step") {var arrow = new Arrow(this.x + this.l * 2, this.y, obj.x, obj.y - obj.h / 2);arrow.drawLeftOrRightToTop(context);} else if(obj.flag == "condition") {var arrow = new Arrow(this.x + this.l * 2, this.y, obj.x, obj.y - obj.l);arrow.drawLeftOrRightToTop(context);}
}
//箭头从Condition菱形left——>top
Condition.prototype.drawLeftToTop = function(obj,context) {if(obj.flag == "step") {var arrow = new Arrow(this.x - this.l * 2, this.y, obj.x, obj.y - obj.h / 2);arrow.drawLeftOrRightToTop(context);} else if(obj.flag == "condition") {var arrow = new Arrow(this.x - this.l * 2, this.y, obj.x, obj.y - obj.l);arrow.drawLeftOrRightToTop(context);}
}
//箭头从Condition菱形right——>left
Condition.prototype.drawRightToLeft = function(obj,context) {if(obj.flag == "step") {var arrow = new Arrow(this.x + this.l * 2, this.y, obj.x - this.w / 2, obj.y);arrow.drawLeftToRightOrRightToLeft(context);} else if(obj.flag == "condition") {var arrow = new Arrow(this.x + this.l * 2, this.y, obj.x - this.l * 2, obj.y);arrow.drawLeftToRightOrRightToLeft(context);}
}
//箭头从Condition菱形left——>right
Condition.prototype.drawLeftToRight = function(obj, context) {if(obj.flag == "step") {var arrow = new Arrow(this.x - this.l * 2, this.y, obj.x + this.w / 2, obj.y);arrow.drawLeftToRightOrRightToLeft(context);} else if(obj.flag == "condition") {var arrow = new Arrow(this.x - this.l * 2, this.y, obj.x + this.l * 2, obj.y);arrow.drawLeftToRightOrRightToLeft(context);}
}/画箭头start/
function Arrow(x1, y1, x2, y2) {this.x1 = x1;this.y1 = y1;this.x2 = x2;this.y2 = y2;this.tmpX1 = null;this.tmpY1 = null;this.tmpX2 = null;this.tmpY2 = null;this.color = "#5B9BD5";}
Arrow.prototype.setColor = function(color) {this.color=color;
}
/**** @param {Object} x1起始点横坐标* @param {Object} y1起始点纵坐标* @param {Object} x2结束点横坐标* @param {Object} y2结束点纵坐标*/
Arrow.prototype.setP = function(x1, y1, x2, y2) {this.x1 = x1;this.y1 = y1;this.x2 = x2;this.y2 = y2;
}
//第一个拐点
Arrow.prototype.setP1 = function(tmpX1,tmpY1) {this.tmpX1=tmpX1;this.tmpY1=tmpY1;
}
//第二个拐点
Arrow.prototype.setP2 = function(tmpX2,tmpY2) {this.tmpX2=tmpX2;this.tmpY2=tmpY2;
}
Arrow.prototype.drawBottomToTop = function(ctx) {if (this.x1 != this.x2) {this.setP1(this.x1,(this.y1+this.y2)/2);this.setP2(this.x2,(this.y1+this.y2)/2);this.draw(ctx);}else{this.draw(ctx);}
}
Arrow.prototype.drawLeftOrRightToTop = function(ctx) {this.setP1(this.x2,this.y1);this.draw(ctx);
}
Arrow.prototype.drawLeftToRightOrRightToLeft = function(ctx) {if (this.y1 != this.y2) {this.setP1((this.x1+this.x2)/2,this.y1);this.setP2((this.x1+this.x2)/2,this.y2);this.draw(ctx);}else{this.draw(ctx);}
}
Arrow.prototype.drawBottomToRight = function(ctx) {if (this.y1 != this.y2) {this.setP1(this.x1,this.y2);this.draw(ctx);}else{this.draw(ctx);}
}
Arrow.prototype.draw = function(ctx) {// arbitrary stylingctx.strokeStyle = this.color;ctx.fillStyle = this.color;// draw the linectx.beginPath();ctx.moveTo(this.x1, this.y1);if(this.tmpX1 != null && this.tmpY1 != null && this.tmpX2 != null && this.tmpY2 != null) {ctx.lineTo(this.tmpX1, this.tmpY1);ctx.closePath();ctx.stroke();ctx.beginPath();ctx.moveTo(this.tmpX1, this.tmpY1)ctx.lineTo(this.tmpX2, this.tmpY2);ctx.closePath();ctx.stroke();ctx.beginPath();ctx.moveTo(this.tmpX2, this.tmpY2);ctx.lineTo(this.x2, this.y2);ctx.closePath();ctx.stroke();var endRadians = Math.atan((this.y2 - this.tmpY2) / (this.x2 - this.tmpX2));endRadians += ((this.x2 >= this.tmpX2) ? 90 : -90) * Math.PI / 180;this.drawArrowhead(ctx, this.x2, this.y2, endRadians);} else if(this.tmpX1 != null && this.tmpY1 != null && this.tmpX2 == null && this.tmpY2 == null) {ctx.lineTo(this.tmpX1, this.tmpY1);ctx.closePath();ctx.stroke();ctx.beginPath();ctx.moveTo(this.tmpX1, this.tmpY1)ctx.lineTo(this.x2, this.y2);ctx.closePath();ctx.stroke();var endRadians = Math.atan((this.y2 - this.tmpY1) / (this.x2 - this.tmpX1));endRadians += ((this.x2 >= this.tmpX1) ? 90 : -90) * Math.PI / 180;this.drawArrowhead(ctx, this.x2, this.y2, endRadians);}else if(this.tmpX1 == null && this.tmpY1 == null && this.tmpX2 == null && this.tmpY2 == null){ctx.lineTo(this.x2, this.y2);ctx.closePath();ctx.stroke();var endRadians = Math.atan((this.y2 - this.y1) / (this.x2 - this.x1));endRadians += ((this.x2 >= this.x1) ? 90 : -90) * Math.PI / 180;this.drawArrowhead(ctx, this.x2, this.y2, endRadians);}
}
Arrow.prototype.drawArrowhead = function(ctx, x, y, radians) {ctx.save();ctx.beginPath();ctx.translate(x, y);ctx.rotate(radians);ctx.moveTo(0, 0);ctx.lineTo(5, 10);ctx.lineTo(-5, 10);ctx.closePath();ctx.restore();ctx.fill();
}
/画箭头end/

html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><link rel="stylesheet" href="public.css">
</head>
<body>
<div class="box"><canvas id="myCanvas" width="1000" height="800"></canvas>
</div>
<script type="text/javascript" src="drawFlowChart.js" ></script>
<script>var canvas = document.getElementById("myCanvas");var cxt = canvas.getContext('2d');var canWidth = cxt.canvas.clientWidth;var init = {top: 32, spaceH: 70};var row2 = {y:init.top+init.spaceH,data:[{type:'Step',text:'业务名称1',name:'step_2_1',arrowArr:[{arrow:'drawBottomToTop',to:'step_3_1'}],x:'',y:'',requestData:{}},{type:'Step',text:'业务名称2',name:'step_2_2',arrowArr:[{arrow:'drawBottomToLeft',to:'step_3_2'}]},{type:'Step',text:'业务名称3',name:'step_2_3',arrowArr:[{arrow:'drawBottomToRight',to:'step_3_2'}]},{type:'Step',name:'step_2_4',text:'业务名称4',arrowArr:[{arrow:'drawBottomToRight',to:'step_7_1'}]}]};row2.data = calChartX(canWidth,row2.data, row2.y);var flowData = [{row:1,y:init.top,data:[{type:'Start',text:'开始',name:'step_1_1',arrowArr:[{arrow:'drawBottomToTop',to:'step_2_1'},{arrow:'drawBottomToTop',to:'step_2_2'},{arrow:'drawBottomToTop',to:'step_2_3'}, {arrow:'drawBottomToTop',to:'step_2_4'}],x:canWidth/2,y:''}]},{row:2,y:init.top+init.spaceH,data:row2.data,method:{onmousemove:null,onmouseleave:null,onclick:hoverSingleChart}},{row:3,y:'',data:[{type:'Step',text:'业务名称4',x:row2.data[0].x,name:'step_3_1',arrowArr:[{arrow:'drawBottomToTop',to:'step_4_1'}]},{type:'Step',text:'业务名称5',name:'step_3_2',x:canWidth/2,arrowArr:[{arrow:'drawBottomToTop',to:'step_4_2'}]}]},{row:4,y:'',data:[{type:'Step',text:'业务名称6',x:row2.data[0].x,name:'step_4_1',arrowArr:[{arrow:'drawBottomToTop',to:'step_5_1'}]},{type:'Step',text:'业务名称7',name:'step_4_2',x:canWidth/2,arrowArr:[{arrow:'drawBottomToTop',to:'step_5_2'}]}]},{row:5,y:'',data:[{type:'Step',text:'业务名称8',x:row2.data[0].x,name:'step_5_1',arrowArr:[{arrow:'drawBottomToTop',to:'step_6_1'}]},{type:'Step',text:'业务名称9',name:'step_5_2',x:canWidth/2,arrowArr:[{arrow:'drawBottomToTop',to:'step_6_2'},{arrow:'drawBottomToTop',to:'step_6_3'}]}]},{row:6,y:'',data:[{type:'Step',text:'业务名称10',x:row2.data[0].x,name:'step_6_1',arrowArr:[{arrow:'drawBottomToLeft',to:'step_7_1'}]},{type:'Step',text:'业务名称11',name:'step_6_2',x:row2.data[1].x,arrowArr:[{arrow:'drawBottomToTop',to:'step_7_1'}]},{type:'Step',text:'业务名称12',name:'step_6_3',x:row2.data[2].x,arrowArr:[{arrow:'drawBottomToTop',to:'step_7_1'}]}]},{row:7,y:init.top+init.spaceH*6+10,data:[{type:'Condition',text:'判断条件',x:canWidth/2,name:'step_7_1',arrowArr:[{arrow:'drawBottomToTop',to:'step_8_1'}]}]},{row:8,y:init.top+init.spaceH*7+30,isAverage:true, //平均计算xdata:[{type:'Step',text:'业务名称12',name:'step_8_1',arrowArr:[{arrow:'drawRightToLeft',to:'step_8_2'}],requestData:{},method:{onmousemove:null,onmouseleave:null,onclick:null}},{type:'Step',text:'业务名称4',name:'step_8_2',arrowArr:[{arrow:'drawRightToLeft',to:'step_8_3'}]},{type:'Step',text:'业务名称4',name:'step_8_3',arrowArr:[{arrow:'drawRightToLeft',to:'step_8_4'}]},{type:'Step',name:'step_8_4',text:'业务名称4',arrowArr:[{arrow:'drawRightToLeft',to:'step_8_5'}]},{type:'Step',name:'step_8_5',text:'业务名称4',arrowArr:[{arrow:'drawRightToLeft',to:'step_8_6'}]},{type:'Step',name:'step_8_6',text:'业务名称4',arrowArr:[{arrow:'drawBottomToTop',to:'step_9_1'}]}]},{row:9,y:init.top+init.spaceH*8+30,isAverage:true,data:[{type:'Step',text:'业务名称4',name:'step_9_1',arrowArr:[{arrow:'drawRightToLeft',to:'step_9_2'}],requestData:{},method:{onmousemove:null,onmouseleave:null,onclick:hoverSingleChart}},{type:'Step',text:'业务名称4',name:'step_9_2',arrowArr:[{arrow:'drawRightToLeft',to:'step_9_3'}]},{type:'Step',text:'业务名称4',name:'step_9_3',arrowArr:[{arrow:'drawRightToLeft',to:'step_9_4'}]},{type:'Step',name:'step_9_4',text:'业务名称4',arrowArr:[{arrow:'drawRightToLeft',to:'step_9_5'}]},{type:'End',name:'step_9_5',text:'结束',arrowArr:[]}]}];drawFlowChart(cxt,canvas,flowData, init.top, init.spaceH);function hoverSingleChart(singleData){console.log("---------鼠标事件-----------");console.log(singleData);}</script>
</body>
</html>

参考博文:https://www.cnblogs.com/DurantSimpson/p/6146038.html/

转载于:https://www.cnblogs.com/fangnianqin/p/10882007.html

canvas绘制流程图相关推荐

  1. html css画流程图,css canvas 绘制流程图(1)

    //1.引入js //画流程图 //画所有的图形:画图和画对应的箭头 function drawFlowChart(context, canvas, flowdata, initTop, initSp ...

  2. VUE+bpmn.js+iview 页面绘制流程图

    前言:业务需求需要在页面绘制流程图,之前后台的同事都是在eclipse画的流程图,为了方便点希望能在页面上画. 我用的是iview的ui框架,用原生的话记得把按钮等标签改改. 如果用的是element ...

  3. activiti绘制流程图,线上显示文字,审批过的节点添加审批人的名字

    最有时间优化了一下activiti的绘制图片工具类,主要用于在领导审批的时候展示的漂亮,直接上代码吧, /** 放在我们的业务代码中,穿个流程实例id进来,返回一个字符数组,然后该怎么处理你们应该知道 ...

  4. 前端绘制流程图、泳道图

    技术栈 使用magicFlow插件绘制. 原生HTML页面也可以,vue或react前端框架也可以,官网有详细安装方法,本文章后面也会详细说明. 官网链接: MagicFlow官网地址 需求 前端绘制 ...

  5. canvas绘制的文字如何换行

    <html><head><title>canvas绘制的文字如何换行</title><style type="text/css" ...

  6. HTML5 canvas绘制雪花飘落

    Canvas是HTML5新增的组件,它就像一块幕布,可以用JavaScript在上面绘制各种图表.动画等.没有Canvas的年代,绘图只能借助Flash插件实现,页面不得不用JavaScript和Fl ...

  7. canvas绘制时钟

    听了慕课网Sliav Zhou 的课程canvas绘制时钟,记录下来的代码,每句做了注解便于以后学习,原先每次边听别的课边敲码,错误百出,明明原封不动复制的代码,就会出错,还找不到原因,今天可能运气好 ...

  8. canvas绘制圆形

    canvas绘制圆形的思路: 1.创建路径 XXX.beginpath(); 2.创建圆形的路径: 3.关闭路径:XXX.closepath(); 路径不关闭也能绘制出图形 4.设定绘制样式. 创建圆 ...

  9. python流程图-使用Graphviz快速绘制流程图

    简介 自己在绘制流程图的时候一般用到的是Visio,但是感觉连线以及框图位置调整起来很烦-经过一番了解之后发现了Graphviz可以使用Python代码来绘制流程图的软件,使用这个工具我们可以更专注于 ...

  10. java canvas 画图片_[Java教程][HTML5] Canvas绘制简单图片

    [Java教程][HTML5] Canvas绘制简单图片 0 2016-05-13 13:00:04 获取Image对象,new出来 定义Image对象的src属性,参数:图片路径 定义Image对象 ...

最新文章

  1. 解决“SCRIPT257: 由于出现错误 80020101 而导致此项操作无法完成。 ”
  2. vant图标怎么显示不出来_U盘插进电脑但不显示怎么解决
  3. 直角三角形的边角关系_华师大版九年级第四章解直角三角形,知识点讲解加经典例题分析...
  4. 小米登录协议分析_小米温湿度传感器协议分析
  5. android UI进阶之android中隐藏的layout 抽屉的运用
  6. D*路径搜索算法原理解析及Python实现
  7. 考研复试C程序设计基础
  8. java上传视频并播放_javaweb中上传视频,并且播放,用上传视频信息为例
  9. 吸人大法!最吸引人气的网吧LOL活动策划方案,此秘籍值得收藏!
  10. 爬取初试----猫眼电影,猫眼评分
  11. 威联通[vNAS內置虚拟机]体验评测 让企业实现无限可能
  12. app下载统计 php,如何统计app在各个渠道的下载量?
  13. python数据分析-常用数据分析库之Pandas(下)
  14. Stream 校验两个集合元素是否完全一致
  15. dting 手环 数据 获取 可视化
  16. Qt实现表格控件-支持多级列表头、多级行表头、单元格合并、字体设置等
  17. ue4 android联机,UE4 局域网联机(LAN)
  18. 计算机电磁兼容性设计方法,一文看懂电磁兼容性原理与方法及设计
  19. 使用Dism命令对Win7镜像进行操作
  20. DEDE教程:最新织梦搜索页如何调用arclist标签?

热门文章

  1. android游戏boss坐标,混沌与秩序2已知boss刷新点分布图详解(已更新到20号boss)...
  2. 蓝桥杯备战(一)3n+1问题
  3. Apache CXF 入门第一个示例
  4. LayaAir 位图添加遮罩与滤镜
  5. HTML5 音频 / 视频 DOM 操作
  6. cmd 获取ftp没反应_python笔记13-执行cmd指令
  7. ES6深入浅出_汇总贴
  8. Spring Boot_打造企业级微信点餐系统_汇总贴
  9. 【Android】怎样烧写qcn文件
  10. 洛谷P3233 [HNOI2014]世界树