English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Sviluppo di un programma di disegno semplice con RequireJS

Premessa

La comparsa di RequireJS rende facile la modularizzazione del codice front-end. Quando i progetti front-end diventano sempre più grandi e il codice aumenta, la modularizzazione del codice rende la struttura del progetto più chiara. Non solo chiarisce la nostra mente durante la sviluppo, ma rende anche più facile la manutenzione in seguito. Di seguito è un programma di disegno semplice sviluppato utilizzando RequireJS che viene eseguito nel browser come illustrato nella figura seguente:

Se non sei molto familiare con RequireJS, puoi leggere i miei appunti di studio su RequireJS:http://blog.csdn.net/yubo_725/article/details/52913853

Inizio

La struttura del progetto di questo programma di disegno semplice è illustrata nella figura seguente:

Dove index.html è la pagina principale del progetto, la directory js contiene tutti i file js, la directory js/app contiene i file moduli personalizzati, la directory js/lib contiene temporaneamente file, quando il nostro progetto utilizza alcune altre librerie frontend come jquery, la directory js/lib contiene questi file js, js/main.js è il file di configurazione di requirejs, principalmente configura alcuni percorsi, js/require.min.js è il file del framework RequireJS. Seguitemi passo passo per completare questo semplice programma di disegno!}

1. Configurazione di requirejs

Il codice del file di configurazione del progetto è contenuto in js/main.js, il contenuto del codice è il seguente:

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

Principalmente configura la directory di root del progetto come 'js/lib', quindi configura un percorso chiamato 'app', il percorso è '../app', ossia la directory 'js/app'.

2. Scrittura del codice del modulo

I moduli del progetto principali sono i seguenti: point.js, line.js, rect.js, arc.js, utils.js, che saranno spiegati uno ad uno:

point.js:

Il modulo point.js rappresenta un punto (x, y), il codice è il seguente:

/** Point */
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;
    };
  };
)

Il codice sopra utilizza define per definire il modulo Point, nel callback viene restituita una classe con due parametri x, y e un metodo equals per confrontare se due punti sono uguali.
Per utilizzare questo modulo, possiamo utilizzare il seguente codice:

require(['app/point'], function(Point) {
  // Creazione di un oggetto della classe Point
  var point = new Point(3, 5);
)

Occorre notare che il primo parametro della funzione require() è un array, la funzione di callback Point rappresenta la nostra classe Point, creata tramite new Point().

line.js:

Il modulo line.js rappresenta una retta, il codice è il seguente:

/** Line */
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 definizione del modulo linea è simile a quella del modulo punto, ovvero restituisce una classe in un callback di define, il costruttore della classe linea ha due parametri di tipo classe point, che rappresentano il punto di partenza e di arrivo della linea, la classe linea ha anche un metodo drawMe che disegna la linea stessa attraverso un oggetto context.

rect.js:

Il modulo rect.js rappresenta un rettangolo, il codice è il seguente:

/** Rettangolo */
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);
    }
  }
)

In cui startPoint rappresenta le coordinate del punto in alto a sinistra del rettangolo, è una classe point, width e height rappresentano la larghezza e l'altezza del rettangolo, e c'è anche un metodo drawMe che disegna il rettangolo stesso.

arc.js:

Il modulo arc.js rappresenta un cerchio, il codice è il seguente:

/** Cerchio */
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();
    }
  }
)

Lì, startPoint rappresenta le coordinate del punto in alto a sinistra del rettangolo in cui si trova il cerchio, radius rappresenta il raggio del cerchio e il metodo drawMe è il metodo per disegnare il cerchio.
In questi moduli, le classi retta, rettangolo e cerchio contengono tutti il metodo drawMe(), qui è coinvolto il sapere del disegno canvas, se non sei chiaro, puoi consultare la documentazione: Manuale di riferimento HTML 5 Canvas

utils.js

Il modulo utils.js è principalmente utilizzato per gestire vari strumenti di disegno grafico, inclusi il disegno di linee, rettangoli e cerchi, nonché la registrazione e l'eliminazione delle tracce di disegno, il codice è il seguente:

/** Strumenti di gestione del disegno */
define(function() { 
  var history = []; // Array utilizzato per salvare le tracce di disegno storiche, che contiene oggetti di tipo retta, rettangolo o cerchio
  function drawLine(context, line) {
    line.drawMe(context);
  }
  function drawRect(context, rect) {
    rect.drawMe(context);
  }
  function drawArc(context, arc) {
    arc.drawMe(context);
  }
  /** Aggiungere una traccia di disegno */
  function addHistory(item) {
    history.push(item);
  }
  /** Disegnare la traccia storica */
  function drawHistory(context) {
    for(var i = 0; i < history.length; i++) {
      var obj = history[i];
      obj.drawMe(context);      
    }
  }
  /** Eliminare la traccia storica */
  function clearHistory() {
    history = [];
  }
  return {
    drawLine: drawLine,
    drawRect: drawRect,
    drawArc: drawArc,
    addHistory: addHistory,
    drawHistory: drawHistory,
    clearHistory: clearHistory
  };
)

3. Scrivere il codice dell'interfaccia e gestire gli eventi del mouse

L'implementazione dei moduli del programma di disegno semplice è stata completata sopra, quelli utilizzati per disegnare i grafici sono proprio i moduli menzionati sopra, ora inizieremo a scrivere il codice dell'interfaccia principale, che include quattro pulsanti e un grande tavolo per il disegno, il codice del file index.html è il seguente:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Programma di disegno semplice</title>
  <style type="text/css">
    canvas {
      background-color: #ECECEC;
      cursor: default; /** Imposta il cursore come puntatore predefinito */
    }
    .tool-bar {
      margin-bottom: 10px;
    }
  </style>
</head>
<body>
  <div class="tool-bar">
    <button id="btn-line">Disegna una linea</button>
    <button id="btn-rect">Disegna un rettangolo</button>
    <button id="btn-oval">Disegna un cerchio</button>
    <button id="btn-clear">Svuota la lavagna</button>
    <span id="hint" style="color: red;">Operazione corrente: disegnare una linea</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(); // ottiene il rettangolo del 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 rappresentano rispettivamente disegnare una linea, disegnare un rettangolo, disegnare un cerchio
      var downPoint = new Point(0, 0), 
        movePoint = new Point(0, 0), 
        upPoint = new Point(0, 0);
      var line;
      var rect;
      var arc;
      /** Gestisce l'evento di pressione del mouse */
      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;
      }
      /** Gestisce l'evento di movimento del mouse */
      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);
        }
      }
      /** Gestisce l'evento di sollevamento del mouse */
      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);
        }
      }
      /** Svuotare la lavagna */
      function clearCanvas() {
        context.clearRect(0, 0, canvas.width, canvas.height);
      }
      /** Gestione dell'evento di clic del pulsante del menu */
      function menuBtnClicked(event) {
        var domID = event.srcElement.id;
        if(domID === 'btn-clear') {
          clearCanvas();
          Utils.clearHistory();
        } else if(domID == 'btn-line') {
          selection = 0;
          showHint('Operazione corrente: Disegnare una linea');
        } else if(domID == 'btn-rect') {
          selection = 1;
          showHint('Operazione corrente: Disegnare un rettangolo');
        } else if(domID == 'btn-oval') {
          selection = 2;
          showHint('Operazione corrente: Disegnare un cerchio');
        }
      }
      function showHint(msg) {
        document.getElementById('hint').innerHTML = msg;
      }
      /** Bind click event to the corresponding id dom element */
      function bindClick(domID, handler) {
        document.getElementById(domID).addEventListener('click', handler);
      }
    });
  </script>
</body>
</html>

Il file index.html contiene molto codice, ma il codice principale è l'ascolto e la gestione degli eventi di pressione, movimento e rilascio del mouse, inoltre, per ottenere la posizione del mouse nel canvas, è necessario notare un punto: poiché i clientX e clientY nel objeto event sono le coordinate del mouse rispetto alla pagina, per ottenere la posizione del mouse nel canvas, è necessario ottenere la regione rettangolare dell'area del canvas, quindi usare clientX-canvas.left, clientY-canvas.top per ottenere la posizione del mouse nel canvas.

Codice sorgente

Il codice sorgente di questo blog è stato depositato su github, clicca qui per vedereCodice sorgente

Bug noto

Quando si disegna un cerchio, è necessario trascinare il mouse dall'angolo in alto a sinistra all'angolo in basso a destra per disegnare un cerchio, altrimenti la posizione del cerchio potrebbe avere problemi.

Questo è tutto il contenuto dell'articolo, speriamo che sia utile per la tua apprendimento, e ti preghiamo di supportare e urlare la guida.

Dichiarazione: il contenuto di questo articolo è stato tratto da Internet, il copyright è di proprietà del rispettivo proprietario, il contenuto è stato contribuito e caricato autonomamente dagli utenti di Internet, questo sito non possiede il diritto di proprietà, non è stato editato manualmente e non assume alcuna responsabilità legale. Se trovi contenuti sospetti di copyright, ti preghiamo di inviare una e-mail a: notice#oldtoolbag.com (al momento dell'invio dell'e-mail, sostituisci # con @) per segnalare, fornendo prove pertinenti. Una volta verificata, questo sito rimuoverà immediatamente il contenuto sospetto di violazione del copyright.

Ti potrebbe interessare