2016-04-19 2 views
1

J'essaye d'implémenter un outil de seau de peinture avec des fonctions d'annulation et de rétablissement. Le problème est que l'annulation et le rétablissement fonctionnent correctement la première fois, mais quand je répète plusieurs fois, le code échoue. Quelqu'un peut-il m'aider à comprendre le problème? Le zoom fonctionne également, mais peindre après le zoom ne fonctionne pas correctement. Ceci est mon code complet. Vous pouvez simplement copier coller et cela fonctionnera à votre fin.Annuler/rétablir ne fonctionne pas correctement et peindre après que le zoom ne fonctionne pas correctement

<!DOCTYPE html> 
<html> 
    <head> 
     <title>Painitng</title> 
     <style> 
      body { 
       width: 100%; 
       height: auto; 
       text-align: center; 
      } 
      .colorpick { 
       widh: 100%; 
       height: atuo; 
      } 
      .pick { 
       display: inline-block; 
       width: 30px; 
       height: 30px; 
       margin: 5px; 
       cursor: pointer; 
      } 
      canvas { 
       border: 2px solid silver; 
      } 
     </style> 
    </head> 
    <body> 
     <button id="zoomin">Zoom In</button> 
     <button id="zoomout">Zoom Out</button> 
     <button onclick="undo()">Undo</button> 
     <button onclick="redo()">Redo</button> 
     <div id="canvasDiv"></div> 
     <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.js"></script> 
     <script type="text/javascript"> 
      var colorYellow = { 
       r: 255, 
       g: 207, 
       b: 51 
      }; 
      var context; 
      var canvasWidth = 500; 
      var canvasHeight = 500; 
      var myColor = colorYellow; 
      var curColor = myColor; 
      var outlineImage = new Image(); 
      var backgroundImage = new Image(); 
      var drawingAreaX = 0; 
      var drawingAreaY = 0; 
      var drawingAreaWidth = 500; 
      var drawingAreaHeight = 500; 
      var colorLayerData; 
      var outlineLayerData; 
      var totalLoadResources = 2; 
      var curLoadResNum = 0; 
      var undoarr = new Array(); 
      var redoarr = new Array(); 
      var uc = 0; 
      var rc = 0; 

      // Clears the canvas. 
      function clearCanvas() { 
       context.clearRect(0, 0, context.canvas.width, context.canvas.height); 
      } 

      function undo() { 
       if (undoarr.length <= 0) 
        return; 

       if (uc==0) { 
        redoarr.push(undoarr.pop()); 
        uc = 1; 
       } 
       var a = undoarr.pop(); 
       colorLayerData = a; 
       redoarr.push(a); 
       clearCanvas(); 
       context.putImageData(a, 0, 0); 
       context.drawImage(backgroundImage, 0, 0, canvasWidth, canvasHeight); 
       context.drawImage(outlineImage, 0, 0, drawingAreaWidth, drawingAreaHeight); 
       console.log(undoarr); 
      } 

      function redo() { 
       if (redoarr.length <= 0) 
        return; 
       if (rc==0) { 
        undoarr.push(redoarr.pop()); 
        rc = 1; 
       } 
       var a = redoarr.pop(); 
       colorLayerData = a; 
       undoarr.push(a); 
       clearCanvas(); 
       context.putImageData(a, 0, 0); 
       context.drawImage(backgroundImage, 0, 0, canvasWidth, canvasHeight); 
       context.drawImage(outlineImage, 0, 0, drawingAreaWidth, drawingAreaHeight); 
       console.log(redoarr); 
      } 
      // Draw the elements on the canvas 
      function redraw() { 
       uc = 0; 
       rc = 0; 
       var locX, 
         locY; 

       // Make sure required resources are loaded before redrawing 
       if (curLoadResNum < totalLoadResources) { 
        return; // To check if images are loaded successfully or not. 
       } 

       clearCanvas(); 
       // Draw the current state of the color layer to the canvas 
       context.putImageData(colorLayerData, 0, 0); 

       undoarr.push(context.getImageData(0, 0, canvasWidth, canvasHeight)); 
       console.log(undoarr); 
       redoarr = new Array(); 
       // Draw the background 
       context.drawImage(backgroundImage, 0, 0, canvasWidth, canvasHeight); 

       // Draw the outline image on top of everything. We could move this to a separate 
       // canvas so we did not have to redraw this everyime. 
       context.drawImage(outlineImage, 0, 0, drawingAreaWidth, drawingAreaHeight); 


      } 
      ; 

      function matchOutlineColor(r, g, b, a) { 

       return (r + g + b < 100 && a === 255); 
      } 
      ; 

      function matchStartColor(pixelPos, startR, startG, startB) { 

       var r = outlineLayerData.data[pixelPos], 
         g = outlineLayerData.data[pixelPos + 1], 
         b = outlineLayerData.data[pixelPos + 2], 
         a = outlineLayerData.data[pixelPos + 3]; 

       // If current pixel of the outline image is black 
       if (matchOutlineColor(r, g, b, a)) { 
        return false; 
       } 

       r = colorLayerData.data[pixelPos]; 
       g = colorLayerData.data[pixelPos + 1]; 
       b = colorLayerData.data[pixelPos + 2]; 

       // If the current pixel matches the clicked color 
       if (r === startR && g === startG && b === startB) { 
        return true; 
       } 

       // If current pixel matches the new color 
       if (r === curColor.r && g === curColor.g && b === curColor.b) { 
        return false; 
       } 

       return true; 
      } 
      ; 

      function colorPixel(pixelPos, r, g, b, a) { 
       colorLayerData.data[pixelPos] = r; 
       colorLayerData.data[pixelPos + 1] = g; 
       colorLayerData.data[pixelPos + 2] = b; 
       colorLayerData.data[pixelPos + 3] = a !== undefined ? a : 255; 
      } 
      ; 

      function floodFill(startX, startY, startR, startG, startB) { 
       var newPos, 
         x, 
         y, 
         pixelPos, 
         reachLeft, 
         reachRight, 
         drawingBoundLeft = drawingAreaX, 
         drawingBoundTop = drawingAreaY, 
         drawingBoundRight = drawingAreaX + drawingAreaWidth - 1, 
         drawingBoundBottom = drawingAreaY + drawingAreaHeight - 1, 
         pixelStack = [[startX, startY]]; 

       while (pixelStack.length) { 

        newPos = pixelStack.pop(); 
        x = newPos[0]; 
        y = newPos[1]; 

        // Get current pixel position 
        pixelPos = (y * canvasWidth + x) * 4; 

        // Go up as long as the color matches and are inside the canvas 
        while (y >= drawingBoundTop && matchStartColor(pixelPos, startR, startG, startB)) { 
         y -= 1; 
         pixelPos -= canvasWidth * 4; 
        } 

        pixelPos += canvasWidth * 4; 
        y += 1; 
        reachLeft = false; 
        reachRight = false; 

        // Go down as long as the color matches and in inside the canvas 
        while (y <= drawingBoundBottom && matchStartColor(pixelPos, startR, startG, startB)) { 
         y += 1; 

         colorPixel(pixelPos, curColor.r, curColor.g, curColor.b); 

         if (x > drawingBoundLeft) { 
          if (matchStartColor(pixelPos - 4, startR, startG, startB)) { 
           if (!reachLeft) { 
            // Add pixel to stack 
            pixelStack.push([x - 1, y]); 
            reachLeft = true; 
           } 

          } else if (reachLeft) { 
           reachLeft = false; 
          } 
         } 

         if (x < drawingBoundRight) { 
          if (matchStartColor(pixelPos + 4, startR, startG, startB)) { 
           if (!reachRight) { 
            // Add pixel to stack 
            pixelStack.push([x + 1, y]); 
            reachRight = true; 
           } 
          } else if (reachRight) { 
           reachRight = false; 
          } 
         } 

         pixelPos += canvasWidth * 4; 
        } 
       } 
      } 
      ; 

      // Start painting with paint bucket tool starting from pixel specified by startX and startY 
      function paintAt(startX, startY) { 

       var pixelPos = (startY * canvasWidth + startX) * 4, 
         r = colorLayerData.data[pixelPos], 
         g = colorLayerData.data[pixelPos + 1], 
         b = colorLayerData.data[pixelPos + 2], 
         a = colorLayerData.data[pixelPos + 3]; 

       if (r === curColor.r && g === curColor.g && b === curColor.b) { 
        // Return because trying to fill with the same color 
        return; 
       } 

       if (matchOutlineColor(r, g, b, a)) { 
        // Return because clicked outline 
        return; 
       } 

       floodFill(startX, startY, r, g, b); 

       redraw(); 
      } 
      ; 

      // Add mouse event listeners to the canvas 
      function createMouseEvents() { 

       $('#canvas').mousedown(function (e) { 
        // Mouse down location 
        var mouseX = e.pageX - this.offsetLeft, 
          mouseY = e.pageY - this.offsetTop; 

        if ((mouseY > drawingAreaY && mouseY < drawingAreaY + drawingAreaHeight) && (mouseX <= drawingAreaX + drawingAreaWidth)) { 
         paintAt(mouseX, mouseY); 
        } 
       }); 
      } 
      ; 

      resourceLoaded = function() { 

       curLoadResNum += 1; 
       //if (curLoadResNum === totalLoadResources) { 
       createMouseEvents(); 
       redraw(); 
       //} 
      }; 

      function start() { 

       var canvas = document.createElement('canvas'); 
       canvas.setAttribute('width', canvasWidth); 
       canvas.setAttribute('height', canvasHeight); 
       canvas.setAttribute('id', 'canvas'); 
       document.getElementById('canvasDiv').appendChild(canvas); 

       if (typeof G_vmlCanvasManager !== "undefined") { 
        canvas = G_vmlCanvasManager.initElement(canvas); 
       } 
       context = canvas.getContext("2d"); 
       backgroundImage.onload = resourceLoaded(); 
       backgroundImage.src = "images/t1.png"; 

       outlineImage.onload = function() { 
        context.drawImage(outlineImage, drawingAreaX, drawingAreaY, drawingAreaWidth, drawingAreaHeight); 

        try { 
         outlineLayerData = context.getImageData(0, 0, canvasWidth, canvasHeight); 
        } catch (ex) { 
         window.alert("Application cannot be run locally. Please run on a server."); 
         return; 
        } 
        clearCanvas(); 
        colorLayerData = context.getImageData(0, 0, canvasWidth, canvasHeight); 
        resourceLoaded(); 
       }; 
       outlineImage.src = "images/d.png"; 
      } 
      ; 

      getColor = function() { 

      }; 

     </script> 
     <script type="text/javascript"> $(document).ready(function() { 
       start(); 
      });</script> 
     <script language="javascript"> 
      $('#zoomin').click(function() { 
       if ($("#canvas").width()==500){ 
       $("#canvas").width(750); 
       $("#canvas").height(750); 
       var ctx = canvas.getContext("2d"); 
       ctx.drawImage(backgroundImage, 0, 0, 749, 749); 
       ctx.drawImage(outlineImage, 0, 0, 749, 749); 
       redraw(); 
       } else if ($("#canvas").width()==750){ 

       $("#canvas").width(1000); 
       $("#canvas").height(1000); 
       var ctx = canvas.getContext("2d"); 
       ctx.drawImage(backgroundImage, 0, 0, 999, 999); 
       ctx.drawImage(outlineImage, 0, 0, 999, 999); 
       redraw(); 
       } 
      }); 
      $('#zoomout').click(function() { 
       if ($("#canvas").width() == 1000) { 

       $("#canvas").width(750); 
       $("#canvas").height(750); 
       var ctx = canvas.getContext("2d"); 
       ctx.drawImage(backgroundImage, 0, 0, 749, 749); 
       ctx.drawImage(outlineImage, 0, 0, 749, 749); 
       redraw(); 
       } else if ($("#canvas").width() == 750) { 

       $("#canvas").width(500); 
       $("#canvas").height(500); 
       var ctx = canvas.getContext("2d"); 
       ctx.drawImage(backgroundImage, 0, 0, 499, 499); 
       ctx.drawImage(outlineImage, 0, 0, 499, 499); 
       redraw(); 
       } 
      }); 
     </script> 
     <div class="colorpick"> 
      <div class="pick" style="background-color:rgb(150, 0, 0);" onclick="hello(this.style.backgroundColor);"></div> 
      <div class="pick" style="background-color:rgb(0, 0, 152);" onclick="hello(this.style.backgroundColor);"></div> 
      <div class="pick" style="background-color:rgb(0, 151, 0);" onclick="hello(this.style.backgroundColor);"></div> 
      <div class="pick" style="background-color:rgb(255, 0, 5);" onclick="hello(this.style.backgroundColor);"></div> 
      <div class="pick" style="background-color:rgb(255, 255, 0);" onclick="hello(this.style.backgroundColor);"></div> 
      <div class="pick" style="background-color:rgb(0, 255, 255);" onclick="hello(this.style.backgroundColor);"></div> 
      <div class="pick" style="background-color:rgb(255, 0, 255);" onclick="hello(this.style.backgroundColor);"></div> 
      <div class="pick" style="background-color:rgb(255, 150, 0);" onclick="hello(this.style.backgroundColor);"></div> 
      <div class="pick" style="background-color:rgb(255, 0, 150);" onclick="hello(this.style.backgroundColor);"></div> 
      <div class="pick" style="background-color:rgb(0, 255, 150);" onclick="hello(this.style.backgroundColor);"></div> 
      <div class="pick" style="background-color:rgb(150, 0, 255);" onclick="hello(this.style.backgroundColor);"></div> 
      <div class="pick" style="background-color:rgb(0, 150, 255);" onclick="hello(this.style.backgroundColor);"></div> 
     </div> 
     <script> 
      function hello(e) { 
       var rgb = e.replace(/^(rgb|rgba)\(/, '').replace(/\)$/, '').replace(/\s/g, '').split(','); 
       myColor.r = parseInt(rgb[0]); 
       myColor.g = parseInt(rgb[1]); 
       myColor.b = parseInt(rgb[2]); 
       curColor = myColor; 
       console.log(curColor); 
      } 
     </script> 
    </body> 
</html> 

Répondre

1

Toile tailles & État Histoire

taille Canvas

Si vous avez déjà eu un coup d'oeil autour dans les DOM, vous remarquerez que de nombreux éléments ont à la fois une hauteur et la largeur comme un attribut et une hauteur et une largeur comme un attribut de style.

Pour la toile, ils ont deux significations différentes. Alors, créons une toile.

var canvas = document.createElement("canvas"); 

La largeur et la hauteur de l'élément canvas peuvent maintenant être définies. Ceci définit alors le nombre de pixels dans l'image de la toile (la résolution)

canvas.width = 500; 
canvas.height = 500; 

Par défaut lorsqu'une image (toile est simplement une image) est affiché dans le DOM il est affiché avec une pour une taille de pixel. Cela signifie que pour chaque pixel de l'image, il y a un pixel sur la page.

Vous pouvez modifier cela en définissant la largeur de style toile et hauteur

canvas.style.width = "1000px"; // Note you must add the unit type "px" in this case 
canvas.style.width = "1000px"; 

Cela ne change pas la résolution de la toile, juste la taille d'affichage. Maintenant, pour chaque pixel de la toile, il prend 4 pixels sur la page.

Cela devient un problème lorsque vous utilisez la souris pour dessiner sur le canevas car les coordonnées de la souris sont dans les pixels de l'écran qui ne correspondent plus à la résolution du canevas.

Pour résoudre ce problème. Et comme un exemple du code OP. Vous devez redimensionner les coordonnées de la souris pour correspondre à la résolution de la toile. Cela a été ajouté à l'écouteur d'événement Mousedown OP. Il obtient d'abord la largeur/hauteur de l'écran, puis la largeur et la hauteur de la résolution. Il normalise les coordonnées de la souris en divisant par la largeur/hauteur de l'affichage. Ceci amène les coordonnées de la souris à une plage de 0 < = mouse < 1 que nous multiplions ensuite pour obtenir les coordonnées des pixels de la toile. Comme les pixels doivent être à des emplacements entiers (nombres entiers), vous devez solder le résultat.

// assuming that the mouseX and mouseY are the mouse coords. 
if(this.style.width){ // make sure there is a width in the style 
         // (assumes if width is there then height will be too 
    var w = Number(this.style.width.replace("px","")); // warning this will not work if size is not in pixels 
    var h = Number(this.style.height.replace("px","")); // convert the height to a number 
    var pixelW = this.width; // get the canvas resolution 
    var pixelH = this.height; 
    mouseX = Math.floor((mouseX/w) * pixelW); // convert the mouse coords to pixel coords 
    mouseY = Math.floor((mouseY/h) * pixelH); 
} 

Cela résoudra votre problème de mise à l'échelle. Mais en regardant votre code, c'est un gâchis et vous ne devriez pas chercher le nodetree à chaque fois, pour obtenir le contexte. Je suis surpris que cela fonctionne, mais cela pourrait être Jquery (je ne sais pas car je ne l'utilise jamais) ou peut-être que vous êtes en train de rendre ailleurs.

Histoire État

L'état actuel d'un programme informatique est toutes les conditions et les données qui définissent l'état actuel .. Lorsque vous enregistrez quelque chose que vous enregistrez un état, et lorsque vous chargez vous restaurez l'état . L'historique est juste un moyen d'enregistrer et de charger des états sans avoir à se tromper dans le système de fichiers. Il y a quelques conventions qui disent que les stats sont stockées en pile. Le premier entré est le dernier sorti, il a une pile de rétablissement qui vous permet de refaire les annulations précédentes mais de maintenir l'état correct et parce que les états dépendent des états précédents, le rétablissement ne peut que refaire des états associés. Par conséquent, si vous annulez puis dessinez quelque chose, vous invalidez tous les états de rétablissement existants et ils devraient être jetés.

L'état sauvegardé, que ce soit sur le disque ou la pile d'annulation, doit également être dissocié de l'état actuel. Si vous modifiez l'état actuel, vous ne souhaitez pas que ces modifications affectent l'état enregistré.

Je pense que c'est là où vous vous êtes trompé OP, comme vous utilisiez le colorLayerData pour remplir quand vous avez obtenu une annulation ou une nouvelle utilisation des données référencées qui sont restées dans les tampons Annuler/Rétablir ainsi quand vous avez peint vous étiez en train de changer les données encore dans le tampon d'annulation.

History Manager

Ceci est un directeur général de l'État de but et travaillera pour tout Undo/Redo besoins, tout ce que vous avez à faire est de vous assurer que vous recueillez l'état actuel en un seul objet.

Pour aider j'ai écrit un simple gestionnaire d'historique. Il a deux tampons comme piles un pour undos et un pour redos. Il contient également l'état actuel, qui est l'état le plus récent dont il a connaissance.

Lorsque vous appuyez sur le gestionnaire de l'histoire, il prendra l'état actuel, il sait et le pousser à la pile undo, enregistrer l'état actuel et invalider les données redo (rendant la longueur du tableau de redo 0)

Lorsque vous annulez, l'état actuel est transféré sur la pile de rétablissement, un état de la pile d'annulation est placé et le statut actuel est rétabli, puis l'état actuel est rétabli.Lorsque vous refaites, l'état actuel est transféré sur la pile d'annulation, un état de la pile de rétablissement est rétabli et l'état actuel est rétabli, puis l'état actuel est rétabli.

Il est important de faire une copie de l'état renvoyé par les gestionnaires d'états afin de ne pas modifier par inadvertance les données stockées dans les tampons.

Vous pouvez demander. "Pourquoi le directeur de l'Etat ne peut-il pas s'assurer que les données sont une copie?" Une bonne question, mais ce n'est pas le rôle d'un gestionnaire d'État, il sauve des États et il doit le faire, peu importe ce qu'il doit sauver, il est par nature complètement inconscient de la signification des données qu'il stocke. De cette façon, il peut être utilisé pour des images, du texte, des états de jeu, n'importe quoi, tout comme le système de fichiers, il ne peut pas (ne devrait pas) être conscient du sens et donc savoir comment créer des copies significatives. Les données que vous apportez au gestionnaire d'état est juste une référence unique (64 bits) aux données de pixel ou vous pouvez pousser chaque octet des données de pixel, il ne connaît pas la différence.

De plus, j'ai ajouté un contrôle d'interface utilisateur au gestionnaire d'état. Cela lui permet d'afficher son état actuel Ie désactive et active les boutons d'annulation de rétablissement. C'est toujours important pour une bonne conception de l'interface utilisateur de fournir des commentaires.

Le code

Vous aurez besoin de faire toutes les modifications suivantes à votre code pour utiliser le gestionnaire de l'histoire. Vous pouvez le faire ou simplement l'utiliser comme guide et écrire le vôtre. J'ai écrit ceci avant que je ne détecte votre erreur. Si c'est la seule erreur, vous devrez seulement changer.

// your old code (from memory) 
    colorLayerData = undoArr.pop(); 
    context.putImageData(colorLayerData, 0, 0); 


    // the fix same applies to redo and just makes a copy rather than use 
    // the reference that is still stored in the undoe buff 
    context.putImageData(undoArr, 0, 0); // put the undo onto the canvas 
    colorLayerData = context.getImageData(0, 0, canvasWidth, canvaHeight); 

Supprimez tout le code que vous avez pour annuler/rétablir.

Modifiez les boutons Annuler/Rétablir en haut de la page sur, avec une seule fonction pour gérer les deux événements.

<button id = "undo-button" onclick="history('undo')">Undo</button> 
    <button id = "redo-button" onclick="history('redo')">Redo</button> 

Additionnez les deux fonctions à votre code ci-dessous

 function history(command){ // handles undo/redo button events. 
      var data; 
      if(command === "redo"){ 
       data = historyManager.redo(); // get data for redo 
      }else 
      if(command === "undo"){ 
       data = historyManager.undo(); // get data for undo 
      } 
      if(data !== undefined){ // if data has been found 
       setColorLayer(data); // set the data 
      } 
     } 

     // sets colour layer and creates copy into colorLayerData 
     function setColorLayer(data){ 
      context.putImageData(data, 0, 0); 
      colorLayerData = context.getImageData(0, 0, canvasWidth, canvasHeight); 
      context.drawImage(backgroundImage, 0, 0, canvasWidth, canvasHeight); 
      context.drawImage(outlineImage, 0, 0, drawingAreaWidth, drawingAreaHeight);    
     } 

Dans la fonction Redessiner vous remplacez les choses que vous aviez pour undo et ajoutez cette ligne au même endroit. Cela enregistre l'état actuel dans le gestionnaire d'historique.

  historyManager.push(context.getImageData(0, 0, canvasWidth, canvasHeight)); 

Dans la fonction de démarrage, vous devez ajouter les éléments de l'interface utilisateur au gestionnaire d'état. Ceci est à vous et peut être ignoré le gestionnaire de statistiques va simplement les ignorer s'ils ne sont pas définis.

  if(historyManager !== undefined){ 
       // only for visual feedback and not required for the history manager to function. 
       historyManager.UI.assignUndoButton(document.querySelector("#undo-button")); 
       historyManager.UI.assignRedoButton(document.querySelector("#redo-button")); 
      } 

Et bien sûr, l'histoireManager lui-même. Il encapsule les données de sorte que vous ne pouvez pas accéder à son état interne, sauf via l'interface fournit.

Le HistoryManager (hM) API

  • hM.UI Le gestionnaire ui seulement des mises à jour et cessionnaires bouton états désactivés/activés
  • hM.UI.assignUndoButton(element) définir l'élément undo
  • hM.UI.assignRedoButton(element) définir l'élément redo
  • nM.UI.update() Met à jour les états des boutons pour refléter l'état interne actuel. Tous les états internes sont appelés automatiquement, donc n'est nécessaire que si vous modifiez les boutons de rétablissement/annulation.
  • hM.reset() Réinitialise le gestionnaire d'historique en effaçant toutes les piles et les états enregistrés en cours. Appelez ceci lorsque vous chargez ou créez un nouveau projet.
  • nM.push(data) Ajoutez les données fournies à l'historique.
  • nM.undo() obtenir l'état de l'historique précédent et retourner les données stockées. Si pas de données, cela retournera indéfini. Obtenir l'état de l'historique suivant et renvoyer les données stockées.
  • nM.redo() Si pas de données, cela retournera indéfini.

La fonction auto invocateur crée le gestionnaire de l'histoire, l'interface est accessible via la variable HistoryManager

var historyManager = (function(){ // Anon for private (closure) scope 
    var uBuffer = []; // this is undo buff 
    var rBuffer = []; // this is redo buff 
    var currentState = undefined; // this holds the current history state 
    var undoElement = undefined; 
    var redoElement = undefined; 
    var manager = { 
     UI : { // UI interface just for disable and enabling redo undo buttons 
      assignUndoButton : function(element){ 
       undoElement = element; 
       this.update(); 
      }, 
      assignRedoButton : function(element){ 
       redoElement = element; 
       this.update(); 
      }, 
      update : function(){ 
       if(redoElement !== undefined){ 
        redoElement.disabled = (rBuffer.length === 0); 
       } 
       if(undoElement !== undefined){ 
        undoElement.disabled = (uBuffer.length === 0);         
       } 
      } 
     }, 
     reset : function(){ 
      uBuffer.length = 0; 
      rBuffer.length = 0; 
      currentState = undefined; 
      this.UI.update(); 
     }, 
     push : function(data){ 
      if(currentState !== undefined){ 
       uBuffer.push(currentState);       
      } 
      currentState = data; 
      rBuffer.length = 0; 
      this.UI.update(); 
     }, 
     undo : function(){ 
      if(uBuffer.length > 0){ 
       if(currentState !== undefined){ 
        rBuffer.push(currentState);       
       } 
       currentState = uBuffer.pop(); 
      } 
      this.UI.update(); 
      return currentState; // return data or unfefined 
     }, 
     redo : function(){ 
      if(rBuffer.length > 0){ 
       if(currentState !== undefined){ 
        uBuffer.push(currentState);       
       } 
       currentState = rBuffer.pop(); 
      } 
      this.UI.update();  
      return currentState; 
     }, 
    } 
    return manager; 
})(); 

Cela va résoudre votre problème de zoom et le problème undo. Bonne chance avec votre projet.

+0

Eh bien, laissez-moi jouer un peu. Je vous le ferai savoir. –

+0

Cela a résolu les deux problèmes. Merci beaucoup. Tu es un sauveur. Merci beaucoup. –

+0

Une dernière chose. En zoom, le zoom fonctionne sur chrome mais pas sur firefox. quel pourrait être le problème? –

1

Cette fonction matchOutlineColor prend en 4 chiffres qui représentent une couleur RGBA.

Rouge, Vert, Bleu, Alpha (le degré de transparence de la couleur est)

couleurs RGBA gamme 0-255, étant ainsi de 0 (pas de couleur) à 255 (couleur) avec le blanc étant rgba (255,255,255,255), le noir étant rgba (0,0,0255) et transparent étant rgba (0,0,0,0).

Ce code ne vérifie pas si une couleur est noire, mais simplement que les couleurs rouge + vert + jaune ajoutées ensemble sont au moins inférieures à 100 (sur un total de 750). Je soupçonne que la fonction vérifie si la couleur est une couleur foncée.

Par exemple tout cela changera vrai:

<div style="background-color:rgba(99,0,0,255)">Dark RED</div> 
 
<div style="background-color:rgba(0,99,0,255)">Dark GREEN</div> 
 
<div style="background-color:rgba(0,0,99,255)">Dark BLUE</div>

Si vous voulez vérifier si la frontière est noir, vous pouvez changer la fonction de

function matchOutlineColorBlack(r, g, b, a) { 
    //Ensures red + green + blue is none 
    return (r + g + b == 0 && a === 255); 
}; 

function matchOutlineColorWhite(r, g, b, a) { 
    //Checks that color is white (255+255+255=750) 
    return (r + g + b == 750 && a === 255); 
}; 
+0

Comment les pixels gris clair seront-ils traités? –