跳转到内容

Canvas 2D Web 应用/静态按钮

来自维基教科书,开放的书籍,为开放的世界

本章讨论了使用 cui2d 实现按钮的最基本方法。这当然不是实现按钮的唯一方法,但它非常灵活,定义按钮外观和功能的代码只是一个简单的 if 语句,它检查用户事件是否发生在按钮区域,并指定如何对这些事件做出反应。在本章中,按钮的外观是静态的;根据用户事件(例如,鼠标悬停)改变其外观的按钮将在关于 响应式按钮 的章节中讨论。

示例:选择颜色

[编辑 | 编辑源代码]

本章的示例显示了三个分别标记为“红色”、“绿色”和“蓝色”的按钮,以及一个颜色补丁,其颜色根据点击的按钮而变化。按钮使用位图图像渲染,允许任意按钮设计。该示例可 在线 获得,并且还可 在线 获得可在移动设备上下载的版本。如果你想在本地计算机上试用该示例,你还需要将文件 cui2d.js 和图像 selected.png 下载到与 HTML 文件相同的目录中。

<!DOCTYPE HTML>
<html>
  <head>
    <meta http-equiv="Content-type" content="text/html;charset=UTF-8">
    <meta name="viewport"
      content="width=device-width, initial-scale=1.0, user-scalable=no">

    

    <script>
      function init() {
        // get image
        imageFocusedButton.src = "selected.png";
        imageFocusedButton.onload = cuiRepaint;

        // deactivate single-finger dragging for myPage
        myPage.interactionBits = cuiConstants.isTransformableWithTwoFingers;

        // set defaults for all pages
        cuiBackgroundFillStyle = "#000000";
        cuiDefaultFont = "bold 20px Helvetica, sans-serif";
        cuiDefaultFillStyle = "#FFFFFF";

        // initialize cui2d and start with myPage
        cuiInit(myPage);
      }

      // create an image for the button
      var imageFocusedButton = new Image();

      // create a color
      var myColor = "#000000"; 

      // create a new page of size 400x300 and attach myPageProcess
      var myPage = new cuiPage(400, 300, myPageProcess);

      // a function to repaint the canvas and return false (if null == event) 
      // or to process user events (if null != event) and return true
      // if the event has been processed
      function myPageProcess(event) {

        // draw and react to buttons
        if (cuiIsInsideRectangle(event, 50, 50, 80, 50, "red", imageFocusedButton)) {
          if ("mouseup" == event.type || "touchend" == event.type) {
            myColor = "#FF0000";
            cuiRepaint(); 
            return true;
          }
        } 
        if (cuiIsInsideRectangle(event, 150, 50, 80, 50, "green", imageFocusedButton)) {
          if ("mouseup" == event.type || "touchend" == event.type) {
            myColor = "#00FF00";
            cuiRepaint(); 
            return true;
          }
        } 
        if (cuiIsInsideRectangle(event, 250, 50, 80, 50, "blue", imageFocusedButton)) {
          if ("mouseup" == event.type || "touchend" == event.type) {
            myColor = "#0000FF";
            cuiRepaint(); 
            return true;
          }
        } 

        // click on background?
        if (null != event) {
          if ("mouseup" == event.type || "touchend" == event.type) { 
            myColor = "#000000";
            cuiRepaint(); 
            return true;
          }
        }
        
        // repaint this page?
        if (null == event) { 
          // draw color box 
          cuiContext.fillStyle = myColor; 
          cuiContext.fillRect(150, 150, 80, 80);

          // background
          cuiContext.fillStyle = "#404040";
          cuiContext.fillRect(0, 0, this.width, this.height);
        }

        return false; // event has not been processed 
      }
    </script>
  </head>
 
  <body bgcolor="#000000" onload="init()" 
    style="-webkit-user-drag:none; -webkit-user-select:none; ">
    <span style="color:white;">A canvas element cannot be displayed.</span>
  </body>
</html>


本讨论假设您熟悉第 框架入门 章中讨论的代码示例。

该示例使用位图图像绘制按钮。该图像分配给全局变量 imageFocusedButton

      // create an image for the button
      var imageFocusedButton = new Image();

然后在 init() 函数中指定图像文件

        // get image
        imageFocusedButton.src = "selected.png";
        imageFocusedButton.onload = cuiRepaint;

通过将 onload 设置为 cuiRepaint,我们可以确保在图像完全加载之前,如果画布已被渲染,则重新绘制画布。

该示例定义了一个全局变量 myColor 来存储用户选择的颜色

      // create a color
      var myColor = "#000000";

由于该示例使用背景上的点击将 myColor 设置为黑色,因此这些“单指”事件不应由页面处理。因此,该示例通过仅允许此页面的双指手势来禁用单指拖动

        // deactivate single-finger dragging for myPage
        myPage.interactionBits = cuiConstants.isTransformableWithTwoFingers;

为了重新绘制按钮并处理按钮上的点击,该示例使用了三次对 cuiIsInsideRectangle() 的调用

        // draw and react to buttons
        if (cuiIsInsideRectangle(event, 50, 50, 80, 50, "red", imageFocusedButton)) {
          if ("mouseup" == event.type || "touchend" == event.type) {
            myColor = "#FF0000";
            cuiRepaint(); 
            return true;
          }
        } 
        if (cuiIsInsideRectangle(event, 150, 50, 80, 50, "green", imageFocusedButton)) {
          if ("mouseup" == event.type || "touchend" == event.type) {
            myColor = "#00FF00";
            cuiRepaint(); 
            return true;
          }
        } 
        if (cuiIsInsideRectangle(event, 250, 50, 80, 50, "blue", imageFocusedButton)) {
          if ("mouseup" == event.type || "touchend" == event.type) {
            myColor = "#0000FF";
            cuiRepaint(); 
            return true;
          }
        }

cuiIsInsideRectangle() 的定义将在下面讨论。这里,重要的是它与处理函数的工作方式类似

  • 如果 eventnullcuiIsInsideRectangle() 会在指定的矩形中写入一个字符串("red""green""blue"),然后在其下方绘制 imageFocusedButton
  • 如果 event 不为 null,则它会检查此用户事件是否在指定的矩形内,如果在矩形内,则返回 true。在这种情况下,将检查事件的类型,在 mouseuptouchend 事件的情况下,myColor 将更改为某种颜色(取决于按钮),并使用 cuiRepaint() 请求重新绘制以确保新颜色用于绘制。此外,该函数将返回 true 以指示事件已处理。

以下代码检查其他地方是否发生了 mouseuptouchend,在这种情况下,它将 myColor 设置为黑色

        // click on background?
        if (null != event) {
          if ("mouseup" == event.type || "touchend" == event.type) { 
            myColor = "#000000";
            cuiRepaint(); 
            return true;
          }
        }

最后,该函数检查 event 是否为 null,如果是,则它使用颜色 myColor 和灰色背景重新绘制一个正方形矩形

        // repaint this page?
        if (null == event) { 
          // draw color box 
          cuiContext.fillStyle = myColor; 
          cuiContext.fillRect(150, 150, 80, 80);

          // background
          cuiContext.fillStyle = "#404040";
          cuiContext.fillRect(0, 0, this.width, this.height);
        }

然后,该函数返回 false 以指示事件未处理。

当你尝试这个示例时,你可能会意识到它感觉非常静态,即使你可以通过点击按钮和背景来改变颜色。第 响应式按钮 章中的示例感觉更加动态,因为按钮的外观会对用户事件做出反应。

cuiIsInsideRectangle() 的实现

[编辑 | 编辑源代码]

函数 cuiIsInsideRectangle()cui2d.js 中定义

/** 
 * Either determine whether the event's position is inside a rectangle (if event != null) 
 * or draw an image in the rectangle with a text string on top of it (if event == null).
 */ 
function cuiIsInsideRectangle(event, x, y, width, height, text, image) {
  if (null == event) { // draw button
    if (null != text) {
      cuiContext.fillText(text, x + width / 2, y + height / 2);
    }
    if (null != image) {
      cuiContext.drawImage(image, x, y, width, height);
    } 
    return false;
  }
  else { // if (null != event) 
    if (event.eventX >= x && event.eventX < x + width &&
      event.eventY >= y && event.eventY < y + height) {
      return true;
    }
    return false;
  }
}

实现非常简单:如果 eventnull,则除非 textnull,否则 text 将写入矩形的中心。同样,除非 imagenull,否则 image 将绘制到矩形中。另一方面(如果 event 不为 null),该函数会检查事件中的坐标 eventXeventY 是否在矩形内,并返回结果。

请注意,eventXeventY 是 cui2d 特有的:这些坐标位于页面的坐标系中,这与 HTML 使用的任何坐标系都不同,并且如果用户使用双指手势变换页面,它也会发生变化。


< Canvas 2D Web 应用

除非另有说明,否则本页上的所有示例源代码均授予公有领域。
华夏公益教科书