首頁 web前端 js教程 RequireJS簡易繪圖程式開發

RequireJS簡易繪圖程式開發

Dec 08, 2016 pm 02:11 PM

前言

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

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

<🎜>:泡泡膠模擬器無窮大 - 如何獲取和使用皇家鑰匙
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系統,解釋
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
Mandragora:巫婆樹的耳語 - 如何解鎖抓鉤
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1665
14
CakePHP 教程
1424
52
Laravel 教程
1322
25
PHP教程
1270
29
C# 教程
1250
24
JavaScript引擎:比較實施 JavaScript引擎:比較實施 Apr 13, 2025 am 12:05 AM

不同JavaScript引擎在解析和執行JavaScript代碼時,效果會有所不同,因為每個引擎的實現原理和優化策略各有差異。 1.詞法分析:將源碼轉換為詞法單元。 2.語法分析:生成抽象語法樹。 3.優化和編譯:通過JIT編譯器生成機器碼。 4.執行:運行機器碼。 V8引擎通過即時編譯和隱藏類優化,SpiderMonkey使用類型推斷系統,導致在相同代碼上的性能表現不同。

Python vs. JavaScript:學習曲線和易用性 Python vs. JavaScript:學習曲線和易用性 Apr 16, 2025 am 12:12 AM

Python更適合初學者,學習曲線平緩,語法簡潔;JavaScript適合前端開發,學習曲線較陡,語法靈活。 1.Python語法直觀,適用於數據科學和後端開發。 2.JavaScript靈活,廣泛用於前端和服務器端編程。

從C/C到JavaScript:所有工作方式 從C/C到JavaScript:所有工作方式 Apr 14, 2025 am 12:05 AM

從C/C 轉向JavaScript需要適應動態類型、垃圾回收和異步編程等特點。 1)C/C 是靜態類型語言,需手動管理內存,而JavaScript是動態類型,垃圾回收自動處理。 2)C/C 需編譯成機器碼,JavaScript則為解釋型語言。 3)JavaScript引入閉包、原型鍊和Promise等概念,增強了靈活性和異步編程能力。

JavaScript和Web:核心功能和用例 JavaScript和Web:核心功能和用例 Apr 18, 2025 am 12:19 AM

JavaScript在Web開發中的主要用途包括客戶端交互、表單驗證和異步通信。 1)通過DOM操作實現動態內容更新和用戶交互;2)在用戶提交數據前進行客戶端驗證,提高用戶體驗;3)通過AJAX技術實現與服務器的無刷新通信。

JavaScript在行動中:現實世界中的示例和項目 JavaScript在行動中:現實世界中的示例和項目 Apr 19, 2025 am 12:13 AM

JavaScript在現實世界中的應用包括前端和後端開發。 1)通過構建TODO列表應用展示前端應用,涉及DOM操作和事件處理。 2)通過Node.js和Express構建RESTfulAPI展示後端應用。

了解JavaScript引擎:實施詳細信息 了解JavaScript引擎:實施詳細信息 Apr 17, 2025 am 12:05 AM

理解JavaScript引擎內部工作原理對開發者重要,因為它能幫助編寫更高效的代碼並理解性能瓶頸和優化策略。 1)引擎的工作流程包括解析、編譯和執行三個階段;2)執行過程中,引擎會進行動態優化,如內聯緩存和隱藏類;3)最佳實踐包括避免全局變量、優化循環、使用const和let,以及避免過度使用閉包。

Python vs. JavaScript:社區,圖書館和資源 Python vs. JavaScript:社區,圖書館和資源 Apr 15, 2025 am 12:16 AM

Python和JavaScript在社區、庫和資源方面的對比各有優劣。 1)Python社區友好,適合初學者,但前端開發資源不如JavaScript豐富。 2)Python在數據科學和機器學習庫方面強大,JavaScript則在前端開發庫和框架上更勝一籌。 3)兩者的學習資源都豐富,但Python適合從官方文檔開始,JavaScript則以MDNWebDocs為佳。選擇應基於項目需求和個人興趣。

Python vs. JavaScript:開發環境和工具 Python vs. JavaScript:開發環境和工具 Apr 26, 2025 am 12:09 AM

Python和JavaScript在開發環境上的選擇都很重要。 1)Python的開發環境包括PyCharm、JupyterNotebook和Anaconda,適合數據科學和快速原型開發。 2)JavaScript的開發環境包括Node.js、VSCode和Webpack,適用於前端和後端開發。根據項目需求選擇合適的工具可以提高開發效率和項目成功率。

See all articles