首頁  >  文章  >  web前端  >  RequireJS簡易繪圖程式開發

RequireJS簡易繪圖程式開發

高洛峰
高洛峰原創
2016-12-08 14:11:311149瀏覽

前言

RequireJS的出現讓前端程式碼模組化變得容易,當前端專案越來越大,程式碼越來越多的時候,模組化程式碼讓專案結構更清晰,不僅在開發時讓我們的思路更清晰,而且後製維護起來也更容易。以下是我學習RequireJS後使用RequireJS開發的簡易繪圖程序,運行在瀏覽器中如下圖所示: 

RequireJS簡易繪圖程式開發

開始

這個簡易繪圖程式的專案架構如下圖所示: 

這個簡易繪圖程式的專案結構如下圖所示: 

這個簡易繪圖程式的專案結構如下圖所示: .html是專案的主頁,js目錄下存放所有js文件,js/app目錄為我們自訂的模組文件,js/lib目錄中暫時沒有文件,當我們的專案裡用到一些其他前端框架如jquery等時,js/lib目錄就存放這些框架的js文件,js/main.js為requirejs的設定文件,主要是配置一些路徑,js/require.min.js是RequireJS框架的文件。下面請跟我一步一步完成這個簡易的繪圖程式吧!

一、設定requirejs

本專案的設定檔程式碼放在js/main.js中,程式碼內容如下:

require.config({
  baseUrl: 'js/lib',
  paths: {
    app: '../app'
  }
})

   

主要是設定了專案目錄為'js/lib'配置了一個名為'app'的路徑,路徑為'../app',即'js/app'目錄。

二、寫模組程式碼

這個專案中的模組主要有以下幾個:point.js, line.js, rect.js, arc.js, utils.js,下面一一說明:

point.js :

point.js這個模組代表一個點(x, y),程式碼如下:

/** 点 */
define(function() {
  return function(x, y) {
    this.x = x;
    this.y = y;
    this.equals = function(point) {
      return this.x === point.x && this.y === point.y;
    };
  };
})

   


上面的程式碼中使用define定義了點這個模組,在回呼函數中傳回了一個類別,該類別類別有兩個參數x,y,還有一個equals方法用來比較兩個點是否相等。

要使用這個模組,我們可以使用以下程式碼:

require(['app/point'], function(Point) {
  //新建一个点类的对象
  var point = new Point(3, 5);
})

   

這裡需要注意require()函數的第一個參數是一個數組,回呼函數中的Point就代表了我們的點類,透過new Point()的方式建立點類別的物件。

line.js:

line.js模組代表的是一條直線,程式碼如下:

/** 直线 */
define(function() {
  return function(startPoint, endPoint) {
    this.startPoint = startPoint;
    this.endPoint = endPoint;
    this.drawMe = function(context) {
      context.strokeStyle = "#000000";
      context.beginPath();
      context.moveTo(this.startPoint.x, this.startPoint.y);
      context.lineTo(this.endPoint.x, this.endPoint.y);
      context.closePath();
      context.stroke();
    }
  }
})

   

直線模組的定義類,這個直線類的建​​構方法中有兩個點類的參數,代表直線的起點和終點,直線類還有一個drawMe方法,透過傳入一個context對象,將自己畫出來。

rect.js:

rect.js模組代表一個矩形,程式碼如下:

/** 矩形 */
define(['app/point'], function() {
  return function(startPoint, width, height) {
    this.startPoint = startPoint;
    this.width = width;
    this.height = height;
    this.drawMe = function(context) {
      context.strokeStyle = "#000000";
      context.strokeRect(this.startPoint.x, this.startPoint.y, this.width, this.height);
    }
  }
})

其中startPoint是矩形左上角的點的座標,是一個points,width和height分別代表矩形的寬高,同時還有一個drawMe方法將矩形自身畫出來。

arc.js:

arc.js模組代表一個圓形,代碼如下:

/** 圆形 */
define(function() {
  return function(startPoint, radius) {
    this.startPoint = startPoint;
    this.radius = radius;
    this.drawMe = function(context) {
      context.beginPath();
      context.arc(this.startPoint.x, this.startPoint.y, this.radius, 0, 2 * Math.PI);
      context.closePath();
      context.stroke();
    }
  }
})

   


其中startPoint代表圓形所在的矩形的矩形的點的座標,radius代表圓的半徑, drawMe方法是畫圓的方法。

在以上幾個模組中,直線類別、矩形類別、圓形類別都包含有drawMe()方法,這裡涉及到了canvas繪圖的知識,如果有不太清楚的,可以查一下文件:HTML 5 Canvas 參考手冊

utils.js

utils.js模組主要是用來處理各種圖形繪製的工具類,包括直線、矩形、圓形的繪製,也包括記錄繪製軌跡、清除繪製軌跡,程式碼如下:

/** 管理绘图的工具 */
define(function() {
  var history = []; //用来保存历史绘制记录的数组,里面存储的是直线类、矩形类或者圆形类的对象
 
  function drawLine(context, line) {
    line.drawMe(context);
  }
 
  function drawRect(context, rect) {
    rect.drawMe(context);
  }
 
  function drawArc(context, arc) {
    arc.drawMe(context);
  }
 
  /** 添加一条绘制轨迹 */
  function addHistory(item) {
    history.push(item);
  }
 
  /** 画出历史轨迹 */
  function drawHistory(context) {
    for(var i = 0; i < history.length; i++) {
      var obj = history[i];
      obj.drawMe(context);     
    }
  }
 
  /** 清除历史轨迹 */
  function clearHistory() {
    history = [];
  }
 
  return {
    drawLine: drawLine,
    drawRect: drawRect,
    drawArc: drawArc,
    addHistory: addHistory,
    drawHistory: drawHistory,
    clearHistory: clearHistory
  };
})

三、編寫介面程式碼,處理滑鼠事件

上面已經將本次簡易繪圖程式的模組都定義完了,在繪製圖形時用到的也就是上面幾個模組,下面要開始編寫主介面的程式碼了,主介面裡包含四個按鈕,還有一塊大的畫布用來繪圖,下面直接上index.html檔案的程式碼:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>简易绘图程序</title>
  <style type="text/css">
    canvas {
      background-color: #ECECEC;
      cursor: default; /** 鼠标设置成默认的指针 */
    }
    .tool-bar {
      margin-bottom: 10px;
    }
  </style>
</head>
<body>
  <div class="tool-bar">
    <button id="btn-line">画直线</button>
    <button id="btn-rect">画矩形</button>
    <button id="btn-oval">画圆形</button>
    <button id="btn-clear">清空画布</button>
    <span id="hint" style="color: red;">当前操作:画直线</span>
  </div>
  <canvas id="canvas" width="800" height="600"></canvas>
  <script type="text/javascript" src="js/require.min.js" data-main="js/main"></script>
  <script type="text/javascript">
    require([&#39;app/point&#39;, &#39;app/line&#39;, &#39;app/rect&#39;, &#39;app/arc&#39;, &#39;app/utils&#39;],
      function(Point, Line, Rect, Arc, Utils) {
 
      var canvas = document.getElementById("canvas");
      var context = canvas.getContext(&#39;2d&#39;);
      var canvasRect = canvas.getBoundingClientRect(); //得到canvas所在的矩形
      canvas.addEventListener(&#39;mousedown&#39;, handleMouseDown);
      canvas.addEventListener(&#39;mousemove&#39;, handleMouseMove);
      canvas.addEventListener(&#39;mouseup&#39;, handleMouseUp);
      bindClick(&#39;btn-clear&#39;, menuBtnClicked);
      bindClick(&#39;btn-line&#39;, menuBtnClicked);
      bindClick(&#39;btn-rect&#39;, menuBtnClicked);
      bindClick(&#39;btn-oval&#39;, menuBtnClicked);
 
      var mouseDown = false;
      var selection = 1; // 0, 1, 2分别代表画直线、画矩形、画圆
 
      var downPoint = new Point(0, 0),
        movePoint = new Point(0, 0),
        upPoint = new Point(0, 0);
      var line;
      var rect;
      var arc;
 
      /** 处理鼠标按下的事件 */
      function handleMouseDown(event) {
        downPoint.x = event.clientX - canvasRect.left;
        downPoint.y = event.clientY - canvasRect.top;
        if(selection === 0) {
          line = new Line(downPoint, downPoint);
          line.startPoint = downPoint;
        } else if(selection === 1) {
          rect = new Rect(new Point(downPoint.x, downPoint.y), 0, 0);
        } else if(selection === 2) {
          arc = new Arc(new Point(downPoint.x, downPoint.y), 0);
        }
        mouseDown = true;
      }
 
      /** 处理鼠标移动的事件 */
      function handleMouseMove(event) {
        movePoint.x = event.clientX - canvasRect.left;
        movePoint.y = event.clientY - canvasRect.top;
        if(movePoint.x == downPoint.x && movePoint.y == downPoint.y) {
          return ;
        }
        if(movePoint.x == upPoint.x && movePoint.y == upPoint.y) {
          return ;
        }
        if(mouseDown) {
          clearCanvas();
          if(selection == 0) {
            line.endPoint = movePoint;
            Utils.drawLine(context, line);
          } else if(selection == 1) {
            rect.width = movePoint.x - downPoint.x;
            rect.height = movePoint.y - downPoint.y;
            Utils.drawRect(context, rect);
          } else if(selection == 2) {
            var x = movePoint.x - downPoint.x;
            var y = movePoint.y - downPoint.y;
            arc.radius = x > y ? (y / 2) : (x / 2);
            if(arc.radius < 0) {
              arc.radius = -arc.radius;
            }
            arc.startPoint.x = downPoint.x + arc.radius;
            arc.startPoint.y = downPoint.y + arc.radius;
            Utils.drawArc(context, arc);
          }
          Utils.drawHistory(context);
        }
      }
 
      /** 处理鼠标抬起的事件 */
      function handleMouseUp(event) {
        upPoint.x = event.clientX - canvasRect.left;
        upPoint.y = event.clientY - canvasRect.top;
 
        if(mouseDown) {
          mouseDown = false;
          if(selection == 0) {
            line.endPoint = upPoint; 
            if(!downPoint.equals(upPoint)) {
              Utils.addHistory(new Line(new Point(downPoint.x, downPoint.y),
                new Point(upPoint.x, upPoint.y)));
            } 
          } else if(selection == 1) {
            rect.width = upPoint.x - downPoint.x;
            rect.height = upPoint.y - downPoint.y;
            Utils.addHistory(new Rect(new Point(downPoint.x, downPoint.y), rect.width, rect.height));
          } else if(selection == 2) {
            Utils.addHistory(new Arc(new Point(arc.startPoint.x, arc.startPoint.y), arc.radius));
          }
          clearCanvas();
          Utils.drawHistory(context);
        }
      }
 
      /** 清空画布 */
      function clearCanvas() {
        context.clearRect(0, 0, canvas.width, canvas.height);
      }
 
      /** 菜单按钮的点击事件处理 */
      function menuBtnClicked(event) {
        var domID = event.srcElement.id;
        if(domID === &#39;btn-clear&#39;) {
          clearCanvas();
          Utils.clearHistory();
        } else if(domID == &#39;btn-line&#39;) {
          selection = 0;
          showHint(&#39;当前操作:画直线&#39;);
        } else if(domID == &#39;btn-rect&#39;) {
          selection = 1;
          showHint(&#39;当前操作:画矩形&#39;);
        } else if(domID == &#39;btn-oval&#39;) {
          selection = 2;
          showHint(&#39;当前操作:画圆形&#39;);
        }
      }
 
      function showHint(msg) {
        document.getElementById(&#39;hint&#39;).innerHTML = msg;
      }
 
      /** 给对应id的dom元素绑定点击事件 */
      function bindClick(domID, handler) {
        document.getElementById(domID).addEventListener(&#39;click&#39;, handler);
      }
    });
  </script>
</body>
</html>

   

index.html檔案中的程式碼比較多,但最主要的程式碼還是對滑鼠按下、移動、抬起三種事件的監聽和處理,另外,取得滑鼠在canvas中的座標位置需要注意一點:由於event物件中取得的clientX和clientY是滑鼠相對於頁面的座標,為了取得滑鼠在canvas中的座標,需要取得canvas所在的矩形區域,然後用clientX-canvas.left,clientY-canvas.top,來取得滑鼠在canvas中的位置。

已知bug

在畫圓形時需要滑鼠從左上角拖曳到右下角畫圓,如果不是這樣,圓的位置會有問題。 🎜🎜🎜🎜
陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn