English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
前言
RequireJS的出现让前端代码模块化变得容易,当前端项目越来越大,代码越来越多的时候,模块化代码让项目结构更清晰,不仅在开发时让我们的思路更清晰,而且后期维护起来也更容易。下面是我学习RequireJS后使用RequireJS开发的一款简易绘图程序,运行在浏览器中如下图所示:
如果你对RequireJS还不是很了解,可以看我的RequireJS学习笔记:http://blog.csdn.net/yubo_725/article/details/52913853
开始
这个简易绘图程序的项目结构如下图所示:
其中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' } })
Principalmente configuró el directorio raíz del proyecto como 'js/lib', luego configuró una ruta llamada 'app', la ruta es '../'app', es decir, 'js/directorio 'app'.
2. Escribir código de módulo
Los módulos principales de este proyecto son: point.js, line.js, rect.js, arc.js, utils.js, se explicarán uno por uno a continuación:
point.js:
El módulo point.js representa un punto (x, y), el código es el siguiente:
/** punto */ 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; }; }; })
El código anterior define el módulo de punto utilizando define, devuelve una clase en la función de callback, esta clase tiene dos parámetros x, y y un método equals para comparar si dos puntos son iguales.
Para usar este módulo, podemos usar el siguiente código:
require(['app/point], function(Point) { //Crear un objeto de la clase punto var point = new Point(3, 5); })
Es importante tener en cuenta que el primer parámetro de require() es un array, la clase Point en la función de callback representa nuestra clase de punto, se crea un objeto de la clase Point mediante new Point().
line.js:
El módulo line.js representa una línea, el código es el siguiente:
/** línea */ 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(); } } })
La definición del módulo de línea es similar a la del módulo de punto, ambas devuelven una clase en la función de callback de define, el constructor de la clase de línea tiene dos parámetros de clase de punto, que representan el punto de inicio y el punto final de la línea, la clase de línea también tiene un método drawMe, que toma un objeto context como parámetro para dibujar la línea.
rect.js:
rect.js módulo representa un rectángulo, el código es el siguiente:
/** rectángulo */ 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.dibujarMe(context); } function drawArc(context, arc) { arc.dibujarMe(context); } /** agregar una trayectoria de dibujo */ function addHistory(item) { historial.push(item); } /** dibujar rastro histórico */ function drawHistory(context) { for(var i = 0; i < historial.length; i++) { var obj = historial[i]; obj.dibujarMe(context); } } /** eliminar rastro histórico */ function clearHistory() { historial = []; } return { drawLine: drawLine, drawRect: drawRect, drawArc: drawArc, addHistory: addHistory, drawHistory: drawHistory, clearHistory: clearHistory }; })
Tercero, escribir código de interfaz, manejar eventos del ratón
Ya se han definido todos los módulos de este programa de dibujo simple. Al dibujar gráficos, se utilizan solo esos pocos módulos. A continuación, comenzaré a escribir el código de la interfaz principal. La interfaz principal contiene cuatro botones y un lienzo grande para dibujar. Aquí está el código del archivo index.html:
<!DOCTYPE html> <html lang="es"> <head> <meta charset="UTF-8"> <title>Programa de dibujo simple</title> <style type="text/css"> lienzo { fondo-color: #ECECEC; cursor: default; /** establecer el cursor del ratón en el puntero predeterminado */ } .tool-bar { margen-abajo: 10px; } </style> </head> <body> <div class="tool-bar"> <button id="btn-line">dibujar línea</>botón> <button id="btn-rect">dibujar rectángulo</>botón> <button id="btn-oval">dibujar círculo</>botón> <button id="btn-clear">limpiar lienzo</>botón> <span id="hint" style="color: rojo;">Operación actual: dibujar línea</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; } 1) { rect = new Rect(new Point(downPoint.x, downPoint.y), 0, 0); } 2) { arc = new Arc(new Point(downPoint.x, downPoint.y), 0); } mouseDown = true; } /** Manejar el evento de mover el ratón */ 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 &63; (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); } } /** Manejar el evento de levantar el ratón */ 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); } } /** limpiar lienzo */ 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; } /** Vincular el evento de clic al elemento DOM correspondiente con el id */ function bindClick(domID, handler) { document.getElementById(domID).addEventListener('click', handler); } }); </script> </body> </html>
Hay mucho código en el archivo index.html, pero el código más importante es la escucha y el procesamiento de los tres eventos de presionar, mover y levantar el mouse, además, al obtener la posición del mouse en el canvas, hay un punto a tener en cuenta: ya que clientX y clientY obtenidos del objeto event son las coordenadas del mouse en relación con la página, para obtener las coordenadas del mouse en el canvas, es necesario obtener el rectángulo de área del canvas, y luego usar clientX-canvas.left, clientY-canvas.top para obtener la posición del mouse en el canvas.
Código fuente
El código fuente de este artículo de blog se ha alojado en github, haga clic aquí para verloCódigo fuente
Bug conocido
Al dibujar un círculo, es necesario arrastrar el mouse desde la esquina superior izquierda hasta la esquina inferior derecha para dibujar el círculo. De lo contrario, la posición del círculo tendrá problemas.
Esto es todo el contenido del artículo, espero que ayude en su aprendizaje y que todos nos apoyen en el tutorial de clamor.
Declaración: El contenido de este artículo se obtiene de Internet, es propiedad del autor original, el contenido se contribuye y carga de manera autónoma por los usuarios de Internet, este sitio no posee los derechos de propiedad, no ha sido editado por humanos y no asume ninguna responsabilidad legal relacionada. Si encuentra contenido sospechoso de copyright, por favor envíe un correo electrónico a: notice#oldtoolbag.com (al enviar un correo electrónico, reemplace # con @) para denunciar y proporcionar evidencia relevante. Una vez confirmado, este sitio eliminará inmediatamente el contenido sospechoso de infracción.