跳轉到內容

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 應用

除非另有說明,否則本頁上的所有示例原始碼均授予公有領域。
華夏公益教科書