美文网首页
Use canvas to draw graphics

Use canvas to draw graphics

作者: yilinUnique | 来源:发表于2019-10-26 11:31 被阅读0次

The recent project is about "Augmented Reality"(Features: Information integration in the real world and the virtual world; Real-time interactivity; Adding a positioning virtual object in a three-dimensional scale space), we need to draw some graphics (including Point/Image, Line, Polygon, Text, Arrow, and Circle) with canvas in the videos.

graphics.png
//画线
function paintPolyline (ctx, points, attribute, bSelected, offsetX, offsetY) {
  var ox = offsetX;
  var oy = offsetY;
  var i = 0;
  if (points.length == 0) {
    return;
  }

  var polylineWidth = lineWidth;
  var lineColor = defaultColor;

  if (!!attribute) {
    if (attribute.lineWidth != undefined) {
      polylineWidth = attribute.lineWidth;
    }
    if (attribute.color != undefined) {
      lineColor = attribute.color;
    }
  }
  if (bSelected) {
    lineColor = selectedColor;
  }

  ctx.beginPath(); //开始新的路径
  ctx.moveTo(points[0][0] + ox, points[0][1] + oy);

  for (i = 1; i < points.length; i++) {
    ctx.lineTo(points[i][0] + ox, points[i][1] + oy);
  }
  ctx.lineWidth = polylineWidth;
  ctx.strokeStyle = lineColor;
  ctx.stroke();
  ctx.closePath(); //关闭路径
  // 画出图形的所有点选中范围(半径为3的圆)
  if (bSelected) {
    ctx.beginPath();
    ctx.lineWidth = polylineWidth;
    ctx.globalAlpha = 1;
    ctx.strokeStyle = lineColor;
    ctx.fillStyle = nodeColor;
    for (i = 0; i < points.length; i++) {
      ctx.beginPath();
      //选中时增加显示节点圆
      ctx.arc(points[i][0] + ox, points[i][1] + oy, 3, 0, 2 * Math.PI, true);
      ctx.stroke();
      ctx.fill();
      ctx.closePath(); //关闭路径
    }
  }
}
//画多边形
function paintPolygon(ctx, points, attribute, bSelected, offsetX, offsetY) {
  var ox = offsetX;
  var oy = offsetY;
  var i = 0;
  if (points.length == 0) {
    return;
  }
  var polylineWidth = lineWidth;
  var lineColor = defaultColor;
  var fillColor = defaultFillColor;
  var fillOpacity = defaultFillOpacity;

  if (!!attribute) {
    if (attribute.lineWidth != undefined) {
      polylineWidth = attribute.lineWidth;
    }
    if (attribute.color != undefined) {
      lineColor = attribute.color;
    }
    if (attribute.fillColor != undefined) {
      fillColor = attribute.fillColor;
    }
    if (attribute.fillOpacity != undefined) {
      fillOpacity = attribute.fillOpacity;
    }
  }
  if (bSelected) {
    lineColor = selectedColor;
  }

  ctx.beginPath(); //开始新的路径
  ctx.moveTo(points[0][0] + ox, points[0][1] + oy);

  for (i = 1; i < points.length - 1; i++) {
    ctx.lineTo(points[i][0] + ox, points[i][1] + oy);
  }

  //封闭最后一个点成面
  i = points.length - 1;
  var xDis = points[i][0] - points[0][0];
  var yDis = points[i][1] - points[0][1];
  // 近似封闭
  if (xDis < 3 && xDis > -3 && yDis < 3 && yDis > -3) {
    ctx.lineTo(points[0][0] + ox, points[0][1] + oy);
  }
  // 严格封闭
  else if (points[i][0] === points[0][0] && points[i][1] === points[0][1]) {
    ctx.lineTo(points[i][0] + ox, points[i][1] + oy);
  }
  // 不封闭,自动补线
  else {
    ctx.lineTo(points[i][0] + ox, points[i][1] + oy);
    ctx.lineTo(points[0][0] + ox, points[0][1] + oy);
  }

  ctx.lineWidth = polylineWidth;
  ctx.strokeStyle = lineColor;
  ctx.stroke();
  ctx.closePath();
  // 画出图形的所有点选中范围(半径为3的圆)
  if (bSelected) {
    ctx.globalAlpha = fillOpacity;
    ctx.fillStyle = fillColor;
    ctx.fill();

    ctx.beginPath();
    ctx.lineWidth = polylineWidth;
    ctx.globalAlpha = 1; //选中节点不透明
    ctx.strokeStyle = lineColor;
    ctx.fillStyle = nodeColor;
    for (i = 0; i < points.length; i++) {
      ctx.beginPath();
      //选中时增加显示节点圆
      ctx.arc(points[i][0] + ox, points[i][1] + oy, 3, 0, 2 * Math.PI, true);

      ctx.stroke();
      ctx.fill();
      ctx.closePath();
    }
  } else {
    ctx.globalAlpha = fillOpacity;
    ctx.fillStyle = fillColor;
    ctx.fill();
  }
}
/**
 * 绘制带有箭头的直线
 * @param ctx画布变量
 * @param fromX/fromY 起点坐标
 * @param toX/toY 终点坐标
 * @param color 线与箭头颜色
 **/
function drawLineArrow(ctx, points, attribute, bSelected) {
  var ox = offsetX;
  var oy = offsetY;

  var lineArrowWidth = lineWidth;
  var color = defaultColor;
  var fillColor = defaultFillColor;
  var fillOpacity = defaultFillOpacity;

  if (!!attribute) {
    if (attribute.lineWidth != undefined) {
      lineArrowWidth = attribute.lineWidth;
    }
    if (attribute.color != undefined) {
      color = attribute.color;
    }
    if (attribute.fillColor != undefined) {
      fillColor = attribute.fillColor;
    }
    if (attribute.fillOpacity != undefined) {
      fillOpacity = attribute.fillOpacity;
    }
  }

  if (bSelected) {
    color = selectedColor;
  }
  //console.log(JSON.stringify(points),"标记点位==============");
  if (points.length === 0) {
    return;
  }
  //fromX, fromY, toX, toY
  var i = 0;
  var fromX = points[0][0];
  var fromY = points[0][1];
  var toX, toY;

  if (points.length === 1) {
    toX = fromX;
    toY = fromY;
  } else {
    for (i = 1; i < points.length; i++) {
      toX = points[i][0];
      toY = points[i][1];
    }
  }

  var headlen = 50; //自定义箭头线的长度
  var theta = 30; //自定义箭头线与直线的夹角
  var arrowX_top, arrowY_top, arrowX_bottom, arrowY_bottom; //箭头线终点坐标
  // 计算各角度和对应的箭头终点坐标(Math.atan2(y,x)得出的是弧度 再转为角度)
  var angle;
  if (fromX == toX && fromY == toY) {
    angle = 90; //AR页面中在一个点鼠标按下并抬起,呈90°
  } else {
    angle = (Math.atan2(fromY - toY, fromX - toX) * 180) / Math.PI;
  }
  var angle1 = ((angle + theta) * Math.PI) / 180;
  var angle2 = ((angle - theta) * Math.PI) / 180;
  var topX = headlen * Math.cos(angle1);
  var topY = headlen * Math.sin(angle1);
  var botX = headlen * Math.cos(angle2);
  var botY = headlen * Math.sin(angle2);

  arrowX_top = toX + topX;
  arrowY_top = toY + topY;
  arrowX_bottom = toX + botX;
  arrowY_bottom = toY + botY;

  //中点坐标公式X=(X1+X2)/2  Y=(Y1+Y2)/2
  //已知点A(arrowX_top,arrowY_top);
  //已知点B(arrowX_bottom,arrowY_bottom);
  //设C为中点(middle_x,middle_y)
  var middle_c_x = (arrowX_top + arrowX_bottom) / 2;
  var middle_c_y = (arrowY_top + arrowY_bottom) / 2;

  // 设D为A,C中点(middle_d_x,middle_d_y)
  var middle_d_x = (arrowX_top + middle_c_x) / 2;
  var middle_d_y = (arrowY_top + middle_c_y) / 2;

  // 设E为B,C中点(middle_e_x,middle_e_y)
  var middle_e_x = (arrowX_bottom + middle_c_x) / 2;
  var middle_e_y = (arrowY_bottom + middle_c_y) / 2;

  //以起始点为圆心 画半径为5的实心圆
  ctx.beginPath();
  ctx.arc(fromX, fromY, 5, 0, 2 * Math.PI);
  ctx.strokeStyle = color;
  ctx.stroke();
  ctx.fillStyle = color;
  ctx.fill();

  //虚线(中间那条长线)
  ctx.beginPath();
  //        ctx.setLineDash([15, 5]);//虚线 ***************This method was introduced in QtQuick 2.11
  //画虚直线(画到了三角形和虚线交点处,不是画到头的)
  ctx.moveTo(fromX, fromY);
  ctx.lineTo(middle_c_x, middle_c_y);
  //        ctx.strokeStyle = "rgb(130, 210, 210)";
  ctx.strokeStyle = color; //"lightblue";//因为QtQuick 2.11 才支持虚线 先用不同色进行一个区分 看出效果
  ctx.stroke();

  //实线(所有边线)
  ctx.beginPath();
  ctx.lineWidth = lineArrowWidth;
  //        ctx.setLineDash([]);//实线 *******************This method was introduced in QtQuick 2.11

  //画上边箭头线
  ctx.moveTo(toX, toY);
  ctx.lineTo(arrowX_top, arrowY_top); //上箭头坐标
  ctx.lineTo(middle_d_x, middle_d_y); //上箭头中间点坐标
  ctx.lineTo(fromX, fromY);
  //画下边箭头线
  ctx.lineTo(middle_e_x, middle_e_y); //下箭头中间点坐标
  ctx.lineTo(arrowX_bottom, arrowY_bottom); //下箭头坐标
  ctx.lineTo(toX, toY);
  ctx.strokeStyle = color;
  ctx.stroke();

  // 画出图形的所有点选中范围(半径为3的圆)
  if (bSelected) {
    ctx.globalAlpha = fillOpacity;
    ctx.fillStyle = fillColor;
    ctx.fill();

    ctx.beginPath();
    ctx.lineWidth = lineArrowWidth;
    ctx.globalAlpha = 1; //选中节点不透明
    ctx.strokeStyle = color;
    ctx.fillStyle = nodeColor;

    //选中时增加显示节点圆
    ctx.arc(fromX + ox, fromY + oy, 3, 0, 2 * Math.PI, true);
    ctx.stroke();
    ctx.fill();
    ctx.closePath();

    //            ctx.beginPath();
    //            ctx.arc(middle_d_x + ox, middle_d_y + oy, 3, 0, 2*Math.PI, true)
    //            ctx.stroke();
    //            ctx.fill();
    //            ctx.closePath();

    ctx.beginPath();
    ctx.arc(arrowX_top + ox, arrowY_top + oy, 3, 0, 2 * Math.PI, true);
    ctx.stroke();
    ctx.fill();
    ctx.closePath();

    ctx.beginPath();
    ctx.arc(toX + ox, toY + oy, 3, 0, 2 * Math.PI, true);
    ctx.stroke();
    ctx.fill();
    ctx.closePath();

    ctx.beginPath();
    ctx.arc(arrowX_bottom + ox, arrowY_bottom + oy, 3, 0, 2 * Math.PI, true);
    ctx.stroke();
    ctx.fill();
    ctx.closePath();

    //            ctx.beginPath();
    //            ctx.arc(middle_e_x + ox, middle_e_y + oy, 3, 0, 2*Math.PI, true)
    //            ctx.stroke();
    //            ctx.fill();
    //            ctx.closePath();
  } else {
    ctx.globalAlpha = fillOpacity;
    ctx.fillStyle = fillColor;
    ctx.fill();
  }
}
//画圆形
function drawCircle(ctx, points, attribute, bSelected) {
  if (bSelected) {
    ctx.stroke();
    ctx.globalAlpha = 0.5;
    ctx.fillStyle = "lightgrey";
    ctx.fill();

    ctx.beginPath();
    ctx.lineWidth = lineWidth;
    ctx.globalAlpha = 1;
    ctx.strokeStyle = "lightgrey";
    ctx.fillStyle = "lightgrey";
    for (i = 0; i < points.length; i++) {
      ctx.arc(
        points[i][0] + ox,
        points[i][1] + oy,
        3,
        0,
        2 * Math.PI,
        true
      );
      ctx.fill();
      ctx.stroke();
      ctx.beginPath();
      ctx.lineWidth = lineWidth;
      ctx.strokeStyle = "lightgrey";
      ctx.fillStyle = "lightgrey";
    }
    ctx.fill();
  } else {
    ctx.stroke();
    ctx.globalAlpha = 0.5;
    ctx.fillStyle = "lightgrey";
    ctx.fill();
  }
}
//画点(图标、文字)
function paintPoint(ctx, points, attribute, bSelected) {
  if (points.length == 0) {
    return;
  }
  var left = points[0][0];
  var top = points[0][1];

  var type = "";
  if (!!attribute) {
    type = attribute.type;
    //图标
    if (type == "image") {
      if (
        !!attribute.icon &&
        !!attribute.width &&
        attribute.height &&
        attribute.offset
      ) {
        ctx.drawImage(
          attribute.icon,
          left + attribute.offset.x,
          top + attribute.offset[1],
          attribute.width,
          attribute.height
        );
      }
      if (!!attribute.name) {
      }
    } else if (type == "text") {
      //文字
      var text = attribute.text;
      var font = defaultFont;
      if (!!attribute.font) {
        font = "";
        if (!!attribute.font.size) {
          font = attribute.font.size + "px";
        }
        if (!!attribute.font.family) {
          font += " " + attribute.font.family;
        } else {
          font += " 微软雅黑";
        }
      }
      //    console.log("font", font);

      var textAlign = !!attribute.textAlign
        ? attribute.textAlign
        : defaultTextAlign;
      var baseLine = !!attribute.textBaseline
        ? attribute.textBaseline
        : defaultTextBaseline;
      var color = !!attribute.color ? attribute.color : defaultColor;

      ctx.beginPath();
      ctx.textAlign = textAlign;
      ctx.font = font;
      ctx.textBaseline = baseLine;
      ctx.fillStyle = color;
      if (!!attribute.rotate) {
        ctx.save(); //保存画笔当前状态
        ctx.translate(left, top); // 将画布的原点移动到正中央
        ctx.rotate((attribute.rotate * Math.PI) / 180);
        ctx.fillText(text, 0, 0);
        ctx.restore(); //复位画笔之前的状态
      } else {
        ctx.fillText(text, left, top);
      }

      ctx.closePath();
    }
  }
}
//判断一个点是否在多边形内
//isPointInPolygon(curPoint, pointsArr);
function isPointInPolygon(point, polygon) {
  var x = point[0],
    y = point[1];

  var inside = false;
  for (var i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
    var xi = polygon[i][0],
      yi = polygon[i][1];
    var xj = polygon[j][0],
      yj = polygon[j][1];

    var intersect =
      yi > y != yj > y && x < ((xj - xi) * (y - yi)) / (yj - yi) + xi;
    if (intersect) inside = !inside;
  }

  return inside;
}
// 判断形状是否被选中
//(w = 20)
function checkInLine(x1, y1, x2, y2, x, y, w) {
  var l = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
  var l1 = Math.sqrt((x1 - x) * (x1 - x) + (y1 - y) * (y1 - y));
  var l2 = Math.sqrt((x - x2) * (x - x2) + (y - y2) * (y - y2));
  var l3 = Math.sqrt(w * w + l * l);
  var h =
    Math.abs((y2 - y1) * x + (x1 - x2) * y - x1 * y2 + x2 * y1) /
    Math.sqrt((y2 - y1) * (y2 - y1) + (x1 - x2) * (x1 - x2));

  if (
    (l1 <= l3 && l2 <= l3 && h <= w) ||
    (Math.abs(x1 - x) <= w && Math.abs(y1 - y) <= w) ||
    (Math.abs(x2 - x) <= w && Math.abs(y2 - y) <= w)
  ) {
    return true;
  } else {
    return false;
  }
}
// 判断点是否被选中
//(d = 20)
function checkInPoint(x1, y1, x, y, d) {
  if (Math.abs(x1 - x) <= d && Math.abs(y1 - y) <= d) {
    return true;
  } else {
    return false;
  }
}

function checkInImage(x1, y1, x, y, width, height) {
  return x >= x1 && x <= x1 + width && y >= y1 && y <= y1 + height;
}

相关文章

网友评论

      本文标题:Use canvas to draw graphics

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