來(lái)源:yubo_725 發(fā)布時(shí)間:2018-11-22 14:30:36 閱讀量:1084
前言
RequireJS的出現(xiàn)讓前端代碼模塊化變得容易,當(dāng)前端項(xiàng)目越來(lái)越大,代碼越來(lái)越多的時(shí)候,模塊化代碼讓項(xiàng)目結(jié)構(gòu)更清晰,不僅在開(kāi)發(fā)時(shí)讓我們的思路更清晰,而且后期維護(hù)起來(lái)也更容易。下面是我學(xué)習(xí)RequireJS后使用RequireJS開(kāi)發(fā)的一款簡(jiǎn)易繪圖程序,運(yùn)行在瀏覽器中如下圖所示:
如果你對(duì)RequireJS還不是很了解,可以看我的RequireJS學(xué)習(xí)筆記:http://blog.csdn.net/yubo_725/article/details/52913853
開(kāi)始
這個(gè)簡(jiǎn)易繪圖程序的項(xiàng)目結(jié)構(gòu)如下圖所示:
其中index.html是項(xiàng)目的主頁(yè),js目錄下存放所有js文件,js/app目錄為我們自定義的模塊文件,js/lib目錄中暫時(shí)沒(méi)有文件,當(dāng)我們的項(xiàng)目里用到一些其他前端框架如jquery等時(shí),js/lib目錄就存放這些框架的js文件,js/main.js為requirejs的配置文件,主要是配置一些路徑,js/require.min.js是RequireJS框架的文件。下面請(qǐng)跟我一步一步完成這個(gè)簡(jiǎn)易的繪圖程序吧!
一、配置requirejs
本項(xiàng)目的配置文件代碼放在js/main.js中,代碼內(nèi)容如下:
require.config({
baseUrl: 'js/lib',
paths: {
app: '../app'
}
})
1
2
3
4
5
6
主要就是配置了項(xiàng)目根目錄為’js/lib’,然后配置了一個(gè)名為’app’的路徑,路徑為’../app’,即’js/app’目錄。
二、編寫模塊代碼
這個(gè)項(xiàng)目中的模塊主要有如下幾個(gè):point.js, line.js, rect.js, arc.js, utils.js,下面一一說(shuō)明:
point.js:
point.js這個(gè)模塊代表一個(gè)點(diǎn)(x, y),代碼如下:
/** 點(diǎn) */
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;
};
};
})
1
2
3
4
5
6
7
8
9
10
上面的代碼中使用define定義了點(diǎn)這個(gè)模塊,在回調(diào)函數(shù)中返回了一個(gè)類,該類有兩個(gè)參數(shù)x,y,還有一個(gè)equals方法用于比較兩個(gè)點(diǎn)是否相等。
要使用這個(gè)模塊,我們可以使用如下代碼:
require(['app/point'], function(Point) {
//新建一個(gè)點(diǎn)類的對(duì)象
var point = new Point(3, 5);
})
1
2
3
4
這里需要注意require()函數(shù)的第一個(gè)參數(shù)是一個(gè)數(shù)組,回調(diào)函數(shù)中的Point就代表了我們的點(diǎn)類,通過(guò)new Point()的方式創(chuàng)建點(diǎn)類的對(duì)象。
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();
}
}
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
直線模塊的定義跟點(diǎn)模塊的定義類似,都是在define的回調(diào)函數(shù)中返回一個(gè)類,這個(gè)直線類的構(gòu)造方法中有兩個(gè)點(diǎn)類的參數(shù),代表直線的起點(diǎn)和終點(diǎn),直線類還有一個(gè)drawMe方法,通過(guò)傳入一個(gè)context對(duì)象,將自身畫(huà)出來(lái)。
rect.js:
rect.js模塊代表一個(gè)矩形,代碼如下:
/** 矩形 */
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);
}
}
})
1
2
3
4
5
6
7
8
9
10
11
12
其中startPoint是矩形左上角的點(diǎn)的坐標(biāo),是一個(gè)point類,width和height分別代表矩形的寬高,同時(shí)還有一個(gè)drawMe方法將矩形自身畫(huà)出來(lái)。
arc.js:
arc.js模塊代表一個(gè)圓形,代碼如下:
/** 圓形 */
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();
}
}
})
1
2
3
4
5
6
7
8
9
10
11
12
13
其中startPoint代表圓形所在的矩形的左上角的點(diǎn)的坐標(biāo),radius代表圓的半徑,drawMe方法是畫(huà)圓的方法。
在以上幾個(gè)模塊中,直線類、矩形類、圓形類都包含有drawMe()方法,這里涉及到了canvas繪圖的知識(shí),如果有不太清楚的,可以查一下文檔:HTML 5 Canvas 參考手冊(cè)
utils.js
utils.js模塊主要是用來(lái)處理各種圖形繪制的工具類,包括直線、矩形、圓形的繪制,也包括記錄繪制軌跡、清除繪制軌跡,代碼如下:
/** 管理繪圖的工具 */
define(function() {
var history = []; //用來(lái)保存歷史繪制記錄的數(shù)組,里面存儲(chǔ)的是直線類、矩形類或者圓形類的對(duì)象
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);
}
/** 畫(huà)出歷史軌跡 */
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
};
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
三、編寫界面代碼,處理鼠標(biāo)事件
上面已經(jīng)將本次簡(jiǎn)易繪圖程序的模塊都定義完了,在繪制圖形時(shí)用到的也就是上面幾個(gè)模塊,下面要開(kāi)始編寫主界面的代碼了,主界面里包含四個(gè)按鈕,還有一塊大的畫(huà)布用于繪圖,下面直接上index.html文件的代碼:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>簡(jiǎn)易繪圖程序</title>
<style type="text/css">
canvas {
background-color: #ECECEC;
cursor: default; /** 鼠標(biāo)設(shè)置成默認(rèn)的指針 */
}
.tool-bar {
margin-bottom: 10px;
}
</style>
</head>
<body>
<div>
<button id="btn-line">畫(huà)直線</button>
<button id="btn-rect">畫(huà)矩形</button>
<button id="btn-oval">畫(huà)圓形</button>
<button id="btn-clear">清空畫(huà)布</button>
<span id="hint" style="color: red;">當(dāng)前操作:畫(huà)直線</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(['app/point', 'app/line', 'app/rect', 'app/arc', 'app/utils'],
function(Point, Line, Rect, Arc, Utils) {
var canvas = document.getElementById("canvas");
var context = canvas.getContext('2d');
var canvasRect = canvas.getBoundingClientRect(); //得到canvas所在的矩形
canvas.addEventListener('mousedown', handleMouseDown);
canvas.addEventListener('mousemove', handleMouseMove);
canvas.addEventListener('mouseup', handleMouseUp);
bindClick('btn-clear', menuBtnClicked);
bindClick('btn-line', menuBtnClicked);
bindClick('btn-rect', menuBtnClicked);
bindClick('btn-oval', menuBtnClicked);
var mouseDown = false;
var selection = 1; // 0, 1, 2分別代表畫(huà)直線、畫(huà)矩形、畫(huà)圓
var downPoint = new Point(0, 0),
movePoint = new Point(0, 0),
upPoint = new Point(0, 0);
var line;
var rect;
var arc;
/** 處理鼠標(biāo)按下的事件 */
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;
}
/** 處理鼠標(biāo)移動(dòng)的事件 */
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);
}
}
/** 處理鼠標(biāo)抬起的事件 */
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);
}
}
/** 清空畫(huà)布 */
function clearCanvas() {
context.clearRect(0, 0, canvas.width, canvas.height);
}
/** 菜單按鈕的點(diǎn)擊事件處理 */
function menuBtnClicked(event) {
var domID = event.srcElement.id;
if(domID === 'btn-clear') {
clearCanvas();
Utils.clearHistory();
} else if(domID == 'btn-line') {
selection = 0;
showHint('當(dāng)前操作:畫(huà)直線');
} else if(domID == 'btn-rect') {
selection = 1;
showHint('當(dāng)前操作:畫(huà)矩形');
} else if(domID == 'btn-oval') {
selection = 2;
showHint('當(dāng)前操作:畫(huà)圓形');
}
}
function showHint(msg) {
document.getElementById('hint').innerHTML = msg;
}
/** 給對(duì)應(yīng)id的dom元素綁定點(diǎn)擊事件 */
function bindClick(domID, handler) {
document.getElementById(domID).addEventListener('click', handler);
}
});
</script>
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
index.html文件中的代碼比較多,但最主要的代碼還是對(duì)鼠標(biāo)按下、移動(dòng)、抬起三種事件的監(jiān)聽(tīng)和處理,另外,獲取鼠標(biāo)在canvas中的坐標(biāo)位置需要注意一點(diǎn):由于event對(duì)象中獲取的clientX和clientY是鼠標(biāo)相對(duì)于頁(yè)面的坐標(biāo),為了獲取鼠標(biāo)在canvas中的坐標(biāo),需要獲得canvas所在的矩形區(qū)域,然后用clientX-canvas.left,clientY-canvas.top,來(lái)獲取鼠標(biāo)在canvas中的位置。
---------------------
在線
客服
服務(wù)時(shí)間:周一至周日 08:30-18:00
選擇下列產(chǎn)品馬上在線溝通:
客服
熱線
7*24小時(shí)客服服務(wù)熱線
關(guān)注
微信
關(guān)注官方微信