美文网首页
2020-03-20 css canvas绘制流程图(2)

2020-03-20 css canvas绘制流程图(2)

作者: Mylovesunshine | 来源:发表于2020-03-20 16:58 被阅读0次

    0.效果图:(内容自己填充)


    WechatIMG9.jpeg

    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'){
            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.strokeStyle= item.color ? (item.color.borderColor ? item.color.borderColor: '#5B9BD5'):'#5B9BD5' ; //边框颜色
        context.font = 'normal 14px 微软雅黑';
        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();
      }
      //画菱形
      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");
        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';
        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;
        this.h = 40;
        this.w = w;
        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";
        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") {
          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.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) {
        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 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>
                            <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="ss.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, //平均计算x
                                    data:[
                                        {
                                            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>
    

    3.效果图:


    粘贴图片.png

    相关文章

      网友评论

          本文标题:2020-03-20 css canvas绘制流程图(2)

          本文链接:https://www.haomeiwen.com/subject/qcajyhtx.html