优秀的编程知识分享平台

网站首页 > 技术文章 正文

Canvas | 点击矩形在右侧弹出状态操作区,选择状态修改矩形背景色

nanyue 2024-08-28 19:03:24 技术文章 6 ℃

说明

在Canvas中绘制了多个矩形(位置互不重叠),点击矩形在矩形右侧弹出操作框,操作框内含有多个状态操作按钮,点击状态操作按钮后修改对应的矩形的背景色为与状态对应的颜色。

思路

1、使用数组存储多个矩形的信息,矩形信息中包含ID、位置、宽高、状态、文本,遍历数组绘制多个矩形;

2、给整个Canvas元素绑定单击事件,获取鼠标单击的位置信息;

3、遍历矩形数组,获取鼠标点中的矩形;如果有点中矩形,则在矩形右侧显示状态操作框,并将点中的矩形赋值给全局变量target;如果没有点中矩形且状态操作框处于显示状态则隐藏状态操作框;

4、点击状态操作按钮,遍历矩形数组修改与全局变量target的ID相同的矩形的状态;

5、遍历矩形数组重新绘制所有矩形。

实现步骤

1、创建文件骨架,引入 jquery;

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <title>Canvas</title>
  </head>
  <body>
    <canvas id="canvas" width="500" height="500"></canvas>
    <script type="text/javascript" src="jquery.min.js"></script>
    <script type="text/javascript">
      // ...
    </script>
  </body>
</html>

2、全局变量

// 获取 Canvas 对象
var canvas = document.getElementById("canvas");
// 获取上下文环境对象
var ctx = canvas.getContext("2d");

// 状态与矩形背景色映射关系
var statusStyleMap = {
  0: "#fffbf0",
  1: "#45C552",
  2: "#F45454",
  3: "#FFE960",
  4: "#5EB1FF",
};

// 需要绘制的矩形信息列表,含ID、坐标位置、宽度、高度、状态
var rectList = [
  {
    id: 1,
    x: 50,
    y: 50,
    width: 200,
    height: 30,
    status: 0,
  },
  {
    id: 2,
    x: 200,
    y: 100,
    width: 200,
    height: 30,
    status: 0,
  },
];

// 当前点中的矩形
var targetRect = null;

全局变量中我们定义了Canvas对象、上下文环境对象、状态与矩形背景色映射关系、需要绘制的矩形信息列表、当前点中的矩形。

3、定义绘制矩形的方法

// 绘制矩形
function drawRect(rect) {
  ctx.strokeStyle = "#FDCC6B";
  ctx.strokeRect(rect.x, rect.y, rect.width, rect.height);
  
  var fileStyle = statusStyleMap[rect.status];
  ctx.fillStyle = fileStyle;
  ctx.fillRect(rect.x, rect.y, rect.width, rect.height);
  
  // 绘制文本
  ctx.textAlign = "left";
  ctx.fillStyle = "#333333";
  ctx.font = "18px 'Microsoft YaHei'";
  //
  ctx.fillText("Click Me.", rect.x + 10, rect.y + 18 + 4);
  
  ctx.stroke();
}

页面加载完成后初始绘制所有矩形。

$(function () {
  // 初始绘制矩形
  for (var i = 0; i < rectList.length; i++) {
    drawRect(rectList[i]);
  }
});

所有矩形成功渲染后的效果图如下:


4、Canvas元素单击事件处理

// 画布点击事件绑定、处理
canvas.onclick = function (e) {
  console.log("## canvas click ##");
  // 控制台打印点击位置坐标信息
  console.log("x: " + e.offsetX + ", y: " + e.offsetY);
  // 获取点击的矩形
  var target = rectList.find((item, index) => {
    return (
      e.offsetX >= item.x &&
      e.offsetX <= item.x + item.width &&
      e.offsetY >= item.y &&
      e.offsetY <= item.y + item.height
    );
  });
  // 如果获取到了矩形信息
  if (target) {
    targetRect = target;
    // 设置状态操作区位置
    $(".item-operations").css({
      position: "absolute",
      top: targetRect.y + $("#canvas").offset().top + "px",
      left:
        targetRect.x +
        targetRect.width +
        $("#canvas").offset().left +
        "px",
    });
    // 显示状态操作区
    $(".item-operations").show();
  } else {
    // 如果点击的是画布其它位置(非矩形上)则清空选中的矩形、隐藏状态操作区
    targetRect = null;
    $(".item-operations").hide();
  }
};

Canvas中的矩形点击之后的效果图如下:

5、状态操作按钮单击事件处理

// 状态操作按钮单击事件绑定、处理
$(".item-operations li").click(function () {
  console.log("## operation click ##");
  var targetStatus = $(this).attr("data-status");
  targetRect.status = targetStatus;
  for (var i = 0; i < rectList.length; i++) {
    if (rectList[i].id === targetRect.id) {
      rectList[i].status = targetRect.status;
    }
    console.log("id: " + targetRect.id);
    console.log(rectList[i]);
    drawRect(rectList[i]);
  }
  $(".item-operations").hide();
});

选择状态后的效果图如下:

完整代码:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <title>Canvas - 处理单击事件</title>
  </head>
  <body>
    <canvas id="canvas" width="500" height="500"></canvas>
    <ul class="item-operations" style="display: none">
      <li data-status="1">通过</li>
      <li data-status="2">不通过</li>
      <li data-status="3">拒绝</li>
      <li data-status="4">无条件</li>
      <li data-status="0">未选择</li>
    </ul>
    <script type="text/javascript" src="jquery.min.js"></script>
    <script type="text/javascript">
      var canvas = document.getElementById("canvas");
      var ctx = canvas.getContext("2d");

      // 状态与fillStyle对应关系
      var statusStyleMap = {
        0: "#fffbf0",
        1: "#45C552",
        2: "#F45454",
        3: "#FFE960",
        4: "#5EB1FF",
      };

      // 需要绘制的矩形信息列表,含ID、坐标位置、宽度、高度、状态
      var rectList = [
        {
          id: 1,
          x: 50,
          y: 50,
          width: 200,
          height: 30,
          status: 0,
        },
        {
          id: 2,
          x: 200,
          y: 100,
          width: 200,
          height: 30,
          status: 0,
        },
      ];

      // 选择(点击)的矩形
      var targetRect = null;

      $(function () {
        // 初始绘制矩形
        for (var i = 0; i < rectList.length; i++) {
          drawRect(rectList[i]);
        }
        // 状态操作按钮单击事件绑定、处理
        $(".item-operations li").click(function () {
          console.log("## operation click ##");
          var targetStatus = $(this).attr("data-status");
          targetRect.status = targetStatus;
          for (var i = 0; i < rectList.length; i++) {
            if (rectList[i].id === targetRect.id) {
              rectList[i].status = targetRect.status;
            }
            console.log("id: " + targetRect.id);
            console.log(rectList[i]);
            drawRect(rectList[i]);
          }
          $(".item-operations").hide();
        });
      });

      // 画布点击事件绑定、处理
      canvas.onclick = function (e) {
        console.log("## canvas click ##");
        // 控制台打印点击位置坐标信息
        console.log("x: " + e.offsetX + ", y: " + e.offsetY);
        // 获取点击的矩形
        var target = rectList.find((item, index) => {
          return (
            e.offsetX >= item.x &&
            e.offsetX <= item.x + item.width &&
            e.offsetY >= item.y &&
            e.offsetY <= item.y + item.height
          );
        });
        // 如果获取到了矩形信息
        if (target) {
          targetRect = target;
          // 设置状态操作区位置
          $(".item-operations").css({
            position: "absolute",
            top: targetRect.y + $("#canvas").offset().top + "px",
            left:
              targetRect.x +
              targetRect.width +
              $("#canvas").offset().left + "px",
          });
          // 显示状态操作区
          $(".item-operations").show();
        } else {
          // 如果点击的是画布其它位置(非矩形上)则清空选中的矩形、隐藏状态操作区
          targetRect = null;
          $(".item-operations").hide();
        }
      };

      // 绘制矩形
      function drawRect(rect) {
        ctx.strokeStyle = "#FDCC6B";
        ctx.strokeRect(rect.x, rect.y, rect.width, rect.height);

        var fileStyle = statusStyleMap[rect.status];
        ctx.fillStyle = fileStyle;
        ctx.fillRect(rect.x, rect.y, rect.width, rect.height);

        // 绘制文本
        ctx.textAlign = "left";
        ctx.fillStyle = "#333333";
        ctx.font = "18px 'Microsoft YaHei'";
        //
        ctx.fillText("Click Me.", rect.x + 10, rect.y + 18 + 4);

        ctx.stroke();
      }
    </script>
    <style>
      .item-operations {
        list-style: none;
        margin: 0;
        padding: 0;
        width: 100px;
        height: 124px;
        background: #ffffff;
        box-shadow: 0px 4px 10px 0px rgba(51, 51, 51, 0.1);
        border-radius: 0px 0px 0px 0px;
        border: 1px solid #fdcd6c;
      }
      .item-operations li {
        height: 24px;
        line-height: 24px;
        text-align: center;
        border-radius: 0px 0px 0px 0px;
        cursor: pointer;
      }
      .item-operations li:hover {
        background-color: #fdcd6c;
      }
      /* #FDCD6C */
    </style>
  </body>
</html>
最近发表
标签列表