//1.引入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') {
if (data[i].direction != undefined) {
stepW = -120;
}
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));
//计算坐标x
var 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 (ev) {
var ev = ev || window.event;
var ua = navigator.userAgent.toLowerCase();
var isIE = ua.indexOf("compatible") > -1 && ua.indexOf("msie") > -1 && !ua.indexOf("opera") > -1; //IE浏览器
var isEdge = ua.indexOf("Edge") > -1;
var isIE11 = ua.toLowerCase().match(/rv:([\d.]+)\) like gecko/);
var curx = (isIE || isEdge || isIE11) ? ev.offsetX : ev.layerX;
var cury = (isIE || isEdge || isIE11) ? ev.offsetY : ev.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 (ev) {
var ev = ev || window.event;
var ua = navigator.userAgent.toLowerCase();
var isIE = ua.indexOf("compatible") > -1 && ua.indexOf("msie") > -1 && !ua.indexOf("opera") > -1; //IE浏览器
var isEdge = ua.indexOf("Edge") > -1;
var isIE11 = ua.toLowerCase().match(/rv:([\d.]+)\) like gecko/);
var curx = (isIE || isEdge || isIE11) ? ev.offsetX : ev.layerX;
var cury = (isIE || isEdge || isIE11) ? ev.offsetY : ev.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 (ev) {
var ev = ev || window.event;
var ua = navigator.userAgent.toLowerCase();
var isIE = ua.indexOf("compatible") > -1 && ua.indexOf("msie") > -1 && !ua.indexOf("opera") > -1; //IE浏览器
var isEdge = ua.indexOf("Edge") > -1;
var isIE11 = ua.toLowerCase().match(/rv:([\d.]+)\) like gecko/);
var curx = (isIE || isEdge || isIE11) ? ev.offsetX : ev.layerX;
var cury = (isIE || isEdge || isIE11) ? ev.offsetY : ev.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) {
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.lineWidth = 2;
context.strokeStyle = item.color ? (item.color.borderColor ? item.color.borderColor : '#5B9BD5') : '#5B9BD5'; //边框颜色
context.font = 'normal 12px 微软雅黑';
context.fillStyle = item.color ? (item.color.fontColor ? item.color.fontColor : '#5B9BD5') : '#5B9BD5'; //文字颜色
context.textAlign = "center";
// context.fillText(item.text, x + w / 2, y + h / 2 + 6);
// context.stroke();
if (item.direction != undefined) {
var x = x + w / 2;
var y = y + 10;
let letterSpacing = 3; // 设置字间距
for (let i = 0; i < item.text.length; i++) {
const str = item.text.slice(i, i + 1).toString();
context.save();
context.textBaseline = 'top';
context.fillText(str, x, y);
context.restore();
y += context.measureText(str).width + letterSpacing; // 计算文字宽度
}
var str = item.num;
context.save();
context.textBaseline = 'top';
context.fillText(str, x, y);
context.restore();
y += context.measureText('人').width + letterSpacing; // 计算文字宽度
var str = item.unit;
context.save();
context.textBaseline = 'top';
context.fillText(str, x, y);
context.restore();
y += context.measureText(str).width + letterSpacing; // 计算文字宽度
context.stroke();
} else {
context.fillText(item.text, x + w / 2, y + h / 2 + 6);
context.stroke();
}
}
//画菱形
function drawRhombus(context, x, y, l, h, item) {
context.beginPath();
context.moveTo(x, y + h);
context.lineTo(x - l * 2 - 40, y);
context.lineTo(x, y - h);
context.lineTo(x + l * 2 + 40, 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 = item.color ? (item.color.fontColor ? item.color.fontColor : '#5B9BD5') : '#5B9BD5'; //文字颜色
context.font = 'normal 14px 微软雅黑';
context.fillText(item.text, x, y + 3);
context.stroke();
}
//计算文本的宽高
function textSize(fontSize, fontFamily, text) {
var span = document.createElement("span");
span.className = "text";
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;
var list = document.body.getElementsByClassName('text')[0];
document.body.removeChild(list);
return result;
}
//Start 圆角矩形对象
function Start(context, x, y, item, h, w) {
this.flag = 'start';
var textStyle = textSize('14px', '微软雅黑', item.text);
w = parseInt(textStyle.width) + 30;
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';
var textStyle = textSize('14px', '微软雅黑', item.text);
w = parseInt(textStyle.width) + 30;
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);
}
//Step 矩形对象
function Step(context, x, y, item) {
this.flag = "step";
var textStyle = textSize('14px', '微软雅黑', item.text);
// var w = parseInt(textStyle.width) + 30;
var w = parseInt(textStyle.width) + 30;
this.h = 40;
this.w = w;
this.x = x;
this.y = y;
this.text = item.text;
this.color = item.color;
this.direction = item.direction;
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);}
// drawRoundRect(context, x - this.w / 2, y - this.h / 2, this.w, this.h, item, 5);
if (item.direction != undefined) {
this.w = 40;
this.h = w+20;
drawRoundRect(context, x - this.w / 2, y - this.w / 2, this.w, this.h, item, 5);
} else {
drawRoundRect(context, x - this.w / 2, y - this.h / 2, this.w, this.h, item, 5);
}
}
//Condition 菱形对象
function Condition(context, x, y, item) {
this.flag = "condition";
var textStyle = textSize('14px', '微软雅黑', item.text);
var w = parseInt(textStyle.width) / 4;
this.l = w;
this.h = 40;
this.w = w;
this.x = x;
this.y = y;
this.text = item.text;
this.range = calRange(this);
drawRhombus(context, x, y, this.l, this.h, 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 + 40, 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 - 40, 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") {
if (obj.direction != undefined) {
var arrow = new Arrow(this.x, this.y + this.h / 2, obj.x, obj.y - obj.w / 2, obj.color.lineColor);
arrow.drawBottomToTop(context);
} else {
var arrow = new Arrow(this.x, this.y + this.h / 2, obj.x, obj.y - obj.h / 2, obj.color.lineColor);
arrow.drawBottomToTop(context);
}
} else if (obj.flag == "condition") {
var arrow = new Arrow(this.x, this.y + this.h / 2, obj.x, obj.y - obj.h);
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.h, 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, color) {
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";
this.color = color == undefined ? "#5B9BD5" : color;
}
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 styling
ctx.strokeStyle = this.color;
ctx.fillStyle = this.color;
// draw the line
ctx.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();
}
2.demo
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div class="box">
<canvas id="myCanvas" width="600" height="500"></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: 100 };
var row2 = {
y: init.top + init.spaceH,
data: [
{
type: 'Step',
text: '市委办局9999人',
name: 'step_2_1',
x: '',
y: '',
requestData: {},
color: {
bgColor: '#3D6667',
borderColor: "#4ee9a2",
fontColor: "#fff",
lineColor: '#59B6D9'
}
},
{
type: 'Step',
text: '区县级19999人',
name: 'step_2_2',
color: {
bgColor: '#3D6667',
borderColor: "#4ee9a2",
fontColor: "#fff",
lineColor: '#59B6D9'
},
arrowArr: [
{
arrow: 'drawBottomToTop',
to: 'step_3_1'
},
{
arrow: 'drawBottomToTop',
to: 'step_3_2'
},
{
arrow: 'drawBottomToTop',
to: 'step_3_3'
},
{
arrow: 'drawBottomToTop',
to: 'step_3_4'
}
]
},
{
type: 'Step',
text: '市级园区0人',
name: 'step_2_3',
color: {
bgColor: '#3D6667',
borderColor: "#4ee9a2",
fontColor: "#fff",
lineColor: '#59B6D9'
}
}
]
};
var row3 = {
y: init.top + init.spaceH * 2,
data: [
{
type: 'Step',
text: '区直属1234人',
name: 'step_3_1',
direction: 1,
// count: 1,
color: {
bgColor: '#4B4966',
borderColor: "#B75E55",
fontColor: "#fff",
lineColor: '#4ee9a2'
}
},
{
type: 'Step',
text: '乡镇街道1298人',
name: 'step_3_2',
direction: 1,
color: {
bgColor: '#4B4966',
borderColor: "#B75E55",
fontColor: "#fff",
lineColor: '#4ee9a2'
},
// count: 1.15,
},
{
type: 'Step',
text: '区委办局8752人',
name: 'step_3_3',
color: {
bgColor: '#4B4966',
borderColor: "#B75E55",
fontColor: "#fff",
lineColor: '#4ee9a2'
},
direction: 1,
// count: 0.95
},
{
type: 'Step',
text: '区县级园区9870人',
name: 'step_3_4',
color: {
bgColor: '#4B4966',
borderColor: "#B75E55",
fontColor: "#fff",
lineColor: '#4ee9a2'
},
direction: 1,
// count: 1
}
]
};
row2.data = calChartX(canWidth, row2.data, row2.y);
row3.data = calChartX(canWidth, row3.data, row3.y);
var flowData = [
{
row: 1,
y: init.top,
data: [
{
type: 'Step',
text: '网格员总人数3334人',
name: 'step_1_1',
color: {
bgColor: '#365F87',
borderColor: "#59B6D9",
fontColor: "#fff"
},
arrowArr: [
{
arrow: 'drawBottomToTop',
to: 'step_2_1'
},
{
arrow: 'drawBottomToTop',
to: 'step_2_2'
},
{
arrow: 'drawBottomToTop',
to: 'step_2_3'
}
],
x: canWidth / 2,
y: ''
}
],
method: {
onmousemove: null,
onmouseleave: null,
onclick: hoverSingleChart
}
},
{
row: 2,
y: init.top + init.spaceH,
data: row2.data,
method: {
onmousemove: null,
onmouseleave: null,
onclick: hoverSingleChart
}
},
{
row: 3,
y: init.top + init.spaceH * 2,
data: row3.data,
method: {
onmousemove: null,
onmouseleave: null,
onclick: hoverSingleChart
},
}
];
drawFlowChart(cxt, canvas, flowData, init.top, init.spaceH);
function hoverSingleChart(singleData) {
console.log(singleData);
alert('--');
}
</script>
</body>
</html>