用canvas 旋转坐标系绘制图形和文本,文本是倒置的问题

我把canvas的坐标系,变换成了笛卡尔坐标系(直角坐标系),但是变换之后,图形是对的,文字是倒着呢。图片 展示与代码展如下:
在这里插入图片描述

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <canvas id="canvas" width="1000" height="1000"></canvas>
  <script>
    const canvas = document.querySelector('#canvas');


    var ctx = canvas.getContext('2d');
    const data = JSON.parse(JSON.stringify({ "action": "submitResult", "data": { "flag": 1, "presetShape": { "points": [[2, 2], [5, 2]], "pointColor": "#FF0000", "sengmentColor": "#0000FF" }, "operation": [{ "type": "point", "point": [5, 5] }, { "type": "midpoint", "point": [5, 3.5], "text": 3 }, { "type": "midpoint", "point": [3.5, 2], "text": 3 }, { "type": "midpoint", "point": [3.5, 3.5], "text": 4.242640687119285 }], "widgetId": "exploreRelationshipBetweenPointsAndLines-123456" }, "time": 1713933866449 }));
    console.log(data);
    canvas.width = 400;
    canvas.height = 320;
    var squareSize = 20;
    ctx.setLineDash([5, 3]); // 设置虚线的样式,参数为实线长度和间隔长
    // 绘制横向虚线
    for (var i = 0; i <= 16; i++) {
      var y = i * squareSize;
      ctx.strokeStyle = "#cc7a7a";
      ctx.beginPath();
      ctx.moveTo(0, y);
      ctx.lineTo(canvas.width, y);
      ctx.stroke();
    }

    // 绘制纵向虚线
    for (var j = 0; j <= 22; j++) {
      var x = j * squareSize;
      ctx.strokeStyle = "#cc7a7a";
      ctx.beginPath();
      ctx.moveTo(x, 0);
      ctx.lineTo(x, canvas.height);
      ctx.stroke();
    }
    ctx.setLineDash([]); // 设置为实线样式,参数为空数组
    ctx.strokeStyle = "#ff0000";
    ctx.beginPath();
    ctx.moveTo(140, 0);
    ctx.lineTo(140, canvas.height);
    ctx.stroke();
    ctx.beginPath();
    ctx.moveTo(0, 200);
    ctx.lineTo(400, 200);
    ctx.stroke();
    ctx.save();

    ctx.translate(140, 200);
    ctx.scale(1, -1);
    ctx.fillStyle = '#d65c5c';
    const pointRaidus = 2;
    ctx.beginPath();
    ctx.arc(0, 0, pointRaidus, 0, 2 * Math.PI);
    ctx.fill();
    let pointColor = data.data.presetShape.pointColor;
    const sengmentColor = data.data.presetShape.sengmentColor;
    const points = data.data.presetShape.points;
    const operation = data.data.operation;

    ctx.setLineDash([]); // 设置为实线样式,参数为空数组
    ctx.strokeStyle = sengmentColor;
    ctx.lineWidth = 2
    ctx.beginPath();
    ctx.moveTo(points[0][0] * 20, points[0][1] * 20);
    ctx.lineTo(points[1][0] * 20, points[1][1] * 20);
    ctx.stroke();
    for (let i = 0; i < points.length; i++) {
      const element = points[i];
      console.log(element);
      ctx.fillStyle = pointColor;
      const pointRaidus = 3;
      ctx.beginPath();
      ctx.arc(element[0] * 20, element[1] * 20, pointRaidus, 0, 2 * Math.PI);
      ctx.fill();
    }
    for (let i = 0; i < operation.length; i++) {
      const element = operation[i];
      if (element.type == 'point') {
        ctx.strokeStyle = sengmentColor;
        ctx.lineWidth = 2
        ctx.beginPath();
        ctx.moveTo(element.point[0] * 20, element.point[1] * 20);
        ctx.lineTo(points[1][0] * 20, points[1][1] * 20);
        ctx.stroke();
        ctx.beginPath();
        ctx.moveTo(element.point[0] * 20, element.point[1] * 20);
        ctx.lineTo(points[0][0] * 20, points[0][1] * 20);
        ctx.stroke();
        console.log(element);
        const pointRaidus = 3;
        ctx.beginPath();
        ctx.arc(element.point[0] * 20, element.point[1] * 20, pointRaidus, 0, 2 * Math.PI);
        ctx.fill();
      }
      if (element.type == 'midpoint') {
        ctx.font = '10px Arial'; // 设置字体大小和字体样式
        ctx.fillStyle = 'black'; // 设置填充颜色
        const text = element.text.toFixed(2);
        ctx.fillText(text, element.point[0] * 20, element.point[1] * 20); // 在 (50, 50) 处填充文本
   
      }
    }

  </script>
</body>

</html>

解决这个问题的关键,就是 在平移和缩放之前,先保存一下前一个状态,

第一步

ctx.save()

当绘制文本之前 绘制平移旋转之前的状态,

第二步

ctx.restore()

然后重新计算坐标平移旋转缩放之后的位置,不计算直接绘制,文字不倒置了,但是文本显示的位置是错的,所以说我们重新计算 坐标的位置。

第三步

它接受参数包括文本内容、文本左下角的原始坐标、平移和缩放的偏移量,并返回在新坐标系中的文本位置:

function calculateTextPosition(text, originalX, originalY, translateX, translateY, scaleX, scaleY) {
    // 计算在新坐标系中的文本位置
    const newX = originalX * scaleX + translateX;
    const newY = originalY * scaleY + translateY;
    return { x: newX, y: newY };
}

在这里插入图片描述

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <canvas id="canvas" width="1000" height="1000"></canvas>
  <script>
    const canvas = document.querySelector('#canvas');


    var ctx = canvas.getContext('2d');
    const data = JSON.parse(JSON.stringify({ "action": "submitResult", "data": { "flag": 1, "presetShape": { "points": [[2, 2], [5, 2]], "pointColor": "#FF0000", "sengmentColor": "#0000FF" }, "operation": [{ "type": "point", "point": [5, 5] }, { "type": "midpoint", "point": [5, 3.5], "text": 3 }, { "type": "midpoint", "point": [3.5, 2], "text": 3 }, { "type": "midpoint", "point": [3.5, 3.5], "text": 4.242640687119285 }], "widgetId": "exploreRelationshipBetweenPointsAndLines-123456" }, "time": 1713933866449 }));
    console.log(data);
    canvas.width = 400;
    canvas.height = 320;
    var squareSize = 20;
    ctx.setLineDash([5, 3]); // 设置虚线的样式,参数为实线长度和间隔长
    // 绘制横向虚线
    for (var i = 0; i <= 16; i++) {
      var y = i * squareSize;
      ctx.strokeStyle = "#cc7a7a";
      ctx.beginPath();
      ctx.moveTo(0, y);
      ctx.lineTo(canvas.width, y);
      ctx.stroke();
    }

    // 绘制纵向虚线
    for (var j = 0; j <= 22; j++) {
      var x = j * squareSize;
      ctx.strokeStyle = "#cc7a7a";
      ctx.beginPath();
      ctx.moveTo(x, 0);
      ctx.lineTo(x, canvas.height);
      ctx.stroke();
    }
    ctx.setLineDash([]); // 设置为实线样式,参数为空数组
    ctx.strokeStyle = "#ff0000";
    ctx.beginPath();
    ctx.moveTo(140, 0);
    ctx.lineTo(140, canvas.height);
    ctx.stroke();
    ctx.beginPath();
    ctx.moveTo(0, 200);
    ctx.lineTo(400, 200);
    ctx.stroke();
    ctx.save();

    ctx.translate(140, 200);
    ctx.scale(1, -1);
    ctx.fillStyle = '#d65c5c';
    const pointRaidus = 2;
    ctx.beginPath();
    ctx.arc(0, 0, pointRaidus, 0, 2 * Math.PI);
    ctx.fill();
    let pointColor = data.data.presetShape.pointColor;
    const sengmentColor = data.data.presetShape.sengmentColor;
    const points = data.data.presetShape.points;
    const operation = data.data.operation;

    ctx.setLineDash([]); // 设置为实线样式,参数为空数组
    ctx.strokeStyle = sengmentColor;
    ctx.lineWidth = 2
    ctx.beginPath();
    ctx.moveTo(points[0][0] * 20, points[0][1] * 20);
    ctx.lineTo(points[1][0] * 20, points[1][1] * 20);
    ctx.stroke();
    for (let i = 0; i < points.length; i++) {
      const element = points[i];
      console.log(element);
      ctx.fillStyle = pointColor;
      const pointRaidus = 3;
      ctx.beginPath();
      ctx.arc(element[0] * 20, element[1] * 20, pointRaidus, 0, 2 * Math.PI);
      ctx.fill();
    }
    for (let i = 0; i < operation.length; i++) {
      const element = operation[i];
      if (element.type == 'point') {
        ctx.strokeStyle = sengmentColor;
        ctx.lineWidth = 2
        ctx.beginPath();
        ctx.moveTo(element.point[0] * 20, element.point[1] * 20);
        ctx.lineTo(points[1][0] * 20, points[1][1] * 20);
        ctx.stroke();
        ctx.beginPath();
        ctx.moveTo(element.point[0] * 20, element.point[1] * 20);
        ctx.lineTo(points[0][0] * 20, points[0][1] * 20);
        ctx.stroke();
        console.log(element);
        const pointRaidus = 3;
        ctx.beginPath();
        ctx.arc(element.point[0] * 20, element.point[1] * 20, pointRaidus, 0, 2 * Math.PI);
        ctx.fill();
      }
      ctx.restore();
      if (element.type == 'midpoint') {
        ctx.font = '10px Arial'; // 设置字体大小和字体样式
        ctx.fillStyle = 'black'; // 设置填充颜色
        // const text = element.text.toFixed(2);
        // ctx.fillText(text, element.point[0] * 20, element.point[1] * 20); // 在 (50, 50) 处填充文本
        const text = element.text.toFixed(2);
const textPosition = calculateTextPosition(text, element.point[0] * 20, element.point[1] * 20, 140, 200, 1, -1);
ctx.fillText(text, textPosition.x, textPosition.y);
     
      }
    }
    function calculateTextPosition(text, originalX, originalY, translateX, translateY, scaleX, scaleY) {
    // 计算在新坐标系中的文本位置
    const newX = originalX * scaleX + translateX;
    const newY = originalY * scaleY + translateY;
    return { x: newX, y: newY };
}
  </script>
</body>

</html>

如果能帮助到你,麻烦点个赞再走哈

  • 11
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值