最新文章专题视频专题问答1问答10问答100问答1000问答2000关键字专题1关键字专题50关键字专题500关键字专题1500TAG最新视频文章推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37视频文章20视频文章30视频文章40视频文章50视频文章60 视频文章70视频文章80视频文章90视频文章100视频文章120视频文章140 视频2关键字专题关键字专题tag2tag3文章专题文章专题2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章专题3
问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501
当前位置: 首页 - 科技 - 知识百科 - 正文

RequireJS简易绘图程序开发

来源:懂视网 责编:小采 时间:2020-11-27 20:28:43
文档

RequireJS简易绘图程序开发

RequireJS简易绘图程序开发:前言RequireJS的出现让前端代码模块化变得容易,当前端项目越来越大,代码越来越多的时候,模块化代码让项目结构更清晰,不仅在开发时让我们的思路更清晰,而且后期维护起来也更容易。下面是我学习RequireJS后使用RequireJS开发的一款简易绘图程序,运行在浏
推荐度:
导读RequireJS简易绘图程序开发:前言RequireJS的出现让前端代码模块化变得容易,当前端项目越来越大,代码越来越多的时候,模块化代码让项目结构更清晰,不仅在开发时让我们的思路更清晰,而且后期维护起来也更容易。下面是我学习RequireJS后使用RequireJS开发的一款简易绘图程序,运行在浏
前言

RequireJS的出现让前端代码模块化变得容易,当前端项目越来越大,代码越来越多的时候,模块化代码让项目结构更清晰,不仅在开发时让我们的思路更清晰,而且后期维护起来也更容易。下面是我学习RequireJS后使用RequireJS开发的一款简易绘图程序,运行在浏览器中如下图所示:

20161028154506320.gif

开始

这个简易绘图程序的项目结构如下图所示:

其中index.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();
 }
 }
})

直线模块的定义跟点模块的定义类似,都是在define的回调函数中返回一个类,这个直线类的构造方法中有两个点类的参数,代表直线的起点和终点,直线类还有一个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是矩形左上角的点的坐标,是一个point类,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(['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分别代表画直线、画矩形、画圆
 
 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 === 'btn-clear') {
 clearCanvas();
 Utils.clearHistory();
 } else if(domID == 'btn-line') {
 selection = 0;
 showHint('当前操作:画直线');
 } else if(domID == 'btn-rect') {
 selection = 1;
 showHint('当前操作:画矩形');
 } else if(domID == 'btn-oval') {
 selection = 2;
 showHint('当前操作:画圆形');
 }
 }
 
 function showHint(msg) {
 document.getElementById('hint').innerHTML = msg;
 }
 
 /** 给对应id的dom元素绑定点击事件 */
 function bindClick(domID, handler) {
 document.getElementById(domID).addEventListener('click', handler);
 }
 });
 </script>
</body>
</html>

index.html文件中的代码比较多,但最主要的代码还是对鼠标按下、移动、抬起三种事件的监听和处理,另外,获取鼠标在canvas中的坐标位置需要注意一点:由于event对象中获取的clientX和clientY是鼠标相对于页面的坐标,为了获取鼠标在canvas中的坐标,需要获得canvas所在的矩形区域,然后用clientX-canvas.left,clientY-canvas.top,来获取鼠标在canvas中的位置。

已知bug

在画圆形时需要鼠标从左上角拖到右下角画圆,如果不是这样,圆的位置会有问题。

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

文档

RequireJS简易绘图程序开发

RequireJS简易绘图程序开发:前言RequireJS的出现让前端代码模块化变得容易,当前端项目越来越大,代码越来越多的时候,模块化代码让项目结构更清晰,不仅在开发时让我们的思路更清晰,而且后期维护起来也更容易。下面是我学习RequireJS后使用RequireJS开发的一款简易绘图程序,运行在浏
推荐度:
标签: 软件 开发 js
  • 热门焦点

最新推荐

猜你喜欢

热门推荐

专题
Top