2016-04-19 10 views
1

Ich versuche, ein Farbeimer-Werkzeug mit Undo und Redo-Funktionalität zu implementieren. Das Problem besteht darin, dass Rückgängig und Wiederherstellen beim ersten Mal richtig funktionieren, aber wenn ich mehrfach Wiederholen rückgängig mache, schlägt der Code fehl. Kann mir jemand helfen, das Problem herauszufinden? Auch der Zoom funktioniert, aber das Malen nach dem Zoom funktioniert nicht richtig. Dies ist mein vollständiger Code. Sie können einfach einfügen kopieren und es wird an Ihrem Ende funktionieren.Rückgängig/Wiederherstellen funktioniert nicht richtig und Malen nach Zoom funktioniert nicht richtig

<!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> 

Antwort

1

Leinwand Größen & Zustandsgeschichte

Canvas Größe

Wenn Sie schon einmal einen Blick um in dem DOM haben, werden Sie feststellen, dass viele Elemente sowohl eine Höhe und Breite als ein Attribut und eine Höhe und eine Breite als Stil-Attribut.

Für die Leinwand haben diese zwei verschiedene Bedeutungen. So können wir eine Leinwand erstellen.

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

Jetzt kann die Breite und Höhe des Canvas-Elements festgelegt werden. Dies definiert dann Anzahl von Pixeln in der Leinwand Bild (die Auflösung)

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

standardmäßig, wenn ein Bild (Leinwand ist nur ein Bild) in dem DOM angezeigt wird es mit einer 00.59 Pixelgröße dargestellt wird. Das bedeutet, dass für jedes Pixel im Bild ein Pixel auf der Seite vorhanden ist.

Sie können dies durch die Leinwand Stil Breite und Höhe ändern Diese nicht die Leinwand Auflösung ändern, nur die Displaygröße

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

Einstellung. Für jedes Pixel in der Zeichenfläche werden jetzt 4 Pixel auf der Seite benötigt.

Dies wird zu einem Problem, wenn Sie die Maus verwenden, um auf die Leinwand zu zeichnen, da die Mauskoordinaten in Bildschirmpixeln sind, die nicht mehr mit der Leinwandauflösung übereinstimmen.

Um dies zu beheben. Und als Beispiel aus dem OP-Code. Sie müssen die Mauskoordinaten neu skalieren, damit sie der Leinwandauflösung entsprechen. Dies wurde dem OP mousedown-Ereignis-Listener hinzugefügt. Es erhält zuerst die Anzeige Breite/Höhe dann die Auflösung Breite und Höhe. Es normalisiert die Mauskoordinaten, indem es durch die Anzeigebreite/-höhe dividiert. Dies bringt die Mauskoordinaten zu einem Bereich von 0 < = Maus < 1, die wir dann multiplizieren, um die Leinwandpixelkoordinaten zu erhalten. Da die Pixel an ganzzahligen Stellen (ganze Zahlen) liegen müssen, müssen Sie das Ergebnis unterteilen.

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

Das wird Ihr Skalierungsproblem beheben. Aber wenn Sie sich Ihren Code ansehen, ist das ein Chaos und Sie sollten nicht jedes Mal den Knotenbaum durchsuchen, um den Kontext zu erhalten. Ich bin überrascht, dass es funktioniert, aber das könnte Jquery sein (ich weiß nicht, wie ich es nie benutze) oder es könnte sein, dass du es woanders rendierst.

State History

Der aktuelle Zustand eines Computerprogramms ist es, alle Bedingungen und Daten, die den aktuellen Zustand definieren .. Wenn Sie etwas speichern Sie einen Zustand speichern, und wenn Sie laden Sie den Zustand wiederherstellen .

History ist nur eine Möglichkeit zum Speichern und Laden von Zuständen ohne das Herumspielen im Dateisystem. Es gibt einige Konventionen, die sagen, dass die Statistiken als Stapel gespeichert sind. Der erste Eintrag ist der letzte Eintrag, er hat einen Wiederholungsstapel, mit dem Sie vorherige Undos wiederherstellen können, aber um den korrekten Zustand beizubehalten, und da Zustände von vorherigen Zuständen abhängig sind, kann der Wiederherstellungsvorgang nur aus assoziierten Zuständen wiederhergestellt werden. Wenn Sie also rückgängig machen und dann etwas zeichnen, machen Sie vorhandene Redo-Zustände ungültig und sie sollten ausgegeben werden.

Auch der gespeicherte Zustand, sei es auf der Festplatte, oder der Rückgängig-Stapel muss vom aktuellen Zustand getrennt werden. Wenn Sie Änderungen am aktuellen Status vornehmen, möchten Sie nicht, dass diese Änderungen den gespeicherten Status beeinflussen.

Dies ist meiner Meinung nach, wo Sie falsch OP ging, wie Sie die colorLayerData verwendet haben zu füllen (Farbe), wenn Sie eine Undo bekam oder Sie wiederholen, wo gemalt mit der referenzierten Daten, die somit in den Undo/Redo-Puffer blieben, wenn Sie Sie haben die Daten im Undo-Puffer geändert.

History Manager

Dies ist ein allgemeiner Zustand Manager Zweck und funktioniert für jede Undo/Redo Bedürfnisse, alles, was Sie tun müssen, ist sicherzustellen, dass Sie den aktuellen Zustand zu einem einzigen Objekt zu sammeln.

Um zu helfen habe ich einen einfachen Geschichtsmanager geschrieben. Es hat zwei Puffer als Stapel einen für Undos und einen für Redos. Es hält auch den aktuellen Zustand, der der letzte Zustand ist, den er kennt.

Wenn Sie die Geschichte Manager schieben wird es den aktuellen Stand bringen Sie es kennt und schieben Sie es auf den Rückgängig-Stapel, den aktuellen Zustand speichern, und ungültig machen alle Redo-Daten (was die Redo-Feldlänge 0)

Wenn Sie den Vorgang rückgängig machen, wird der aktuelle Status auf den Redo-Stapel verschoben, ein Status aus dem Rückgängig-Stapel wird in den aktuellen Status versetzt, und der aktuelle Status wird zurückgegeben.

Wenn Sie den Vorgang wiederholen, wird der aktuelle Status auf den Rückgängig-Stapel geschoben, ein Status aus dem Wiederherstellungs-Stapel wird in den aktuellen Status versetzt, und der aktuelle Status wird zurückgegeben.

Es ist wichtig, dass Sie eine Kopie des Status erstellen, der von den Statusmanagern zurückgegeben wird, damit Sie die in den Puffern gespeicherten Daten nicht versehentlich ändern.

Sie können fragen. "Warum kann der Staatsanwalt nicht sicherstellen, dass die Daten eine Kopie sind?" Eine gute Frage, aber das ist nicht die Rolle eines staatlichen Managers, es spart Staaten und es muss tun, egal was es zu speichern hat, es ist von Natur aus völlig unwissend über die Bedeutung der Daten, die es speichert. Auf diese Weise kann es für Bilder, Text, Spielstände, alles verwendet werden, genauso wie das Dateisystem, es kann (sollte) nicht der Bedeutung bewusst sein und weiß daher, wie man sinnvolle Kopien erstellt. Die Daten, die Sie an den Status-Manager senden, sind nur eine einzige Referenz (64 Bit) für die Pixeldaten oder Sie können jedes Byte der Pixeldaten verschieben, da sie den Unterschied nicht kennen.

Auch OP Ich habe einige UI-Kontrolle zum Zustandsmanager hinzugefügt. Dies ermöglicht es, den aktuellen Status anzuzeigen, deaktiviert die Schaltflächen zum Rückgängigmachen und aktiviert sie. Es ist immer wichtig für gutes UI-Design, Feedback zu geben.

Der Code

Sie müssen alle folgenden Änderungen an Ihrem Code machen, die Geschichte Manager zu verwenden. Sie können das tun oder einfach als Anleitung verwenden und Ihre eigenen schreiben. Ich habe dies geschrieben, bevor ich deinen Fehler entdeckt habe. Wenn das der einzige Fehler ist, müssen Sie möglicherweise nur ändern.

Entfernen Sie den gesamten Code, den Sie für das Rückgängig/Wiederherstellen haben.

Ändern Sie die Rückgängig/Wiederherstellen-Schaltflächen am oberen Rand der Seite auf, mit einer einzigen Funktion, um beide Ereignisse zu behandeln.

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

Fügen Sie die folgenden zwei Funktionen zur Code

 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);    
     } 

In der Neuzeichnung Funktion können Sie das Zeug haben, ersetzen Sie Undo hatte und diese Zeile an der gleichen Stelle hinzuzufügen. Dies speichert den aktuellen Status im Verlaufsmanager.

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

In der Startfunktion müssen Sie dem Zustandsverwalter die UI-Elemente hinzufügen. Dies liegt bei Ihnen und kann ignoriert werden. Der Statistik-Manager ignoriert sie nur, wenn sie nicht definiert sind.

  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")); 
      } 

Und natürlich die History seiner Selbst. Es kapselt die Daten so ein, dass Sie nur über die Schnittstelle auf ihren internen Zustand zugreifen können.

Die Historymanager (hM) API

  • hM.UI Der ui-Manager nur Updates und ordnet Knopf deaktiviert/aktiviert Staaten
  • hM.UI.assignUndoButton(element) die Undo-Element
  • hM.UI.assignRedoButton(element) die Redo-Element
  • nM.UI.update() gesetzt Aktualisiert die Schaltflächenzustände, um den aktuellen internen Status widerzuspiegeln. Alle internen Status werden automatisch so aufgerufen nur benötigt, wenn Sie die Redo/Rückgängig-Schaltflächen ändern Statistiken
  • hM.reset() Setzt den History Manager zurückgesetzt alle Stapel und aktuellen gespeicherten Staaten. Rufen Sie dies auf, wenn Sie ein neues Projekt laden oder erstellen.
  • nM.push(data) Fügen Sie die bereitgestellten Daten zum Verlauf hinzu.
  • nM.undo() den vorherigen Verlauf Zustand abrufen und die gespeicherten Daten zurückgeben. Wenn keine Daten vorhanden sind, wird dies undefiniert zurückgegeben.
  • nM.redo() erhalten Sie den nächsten Verlaufsstatus und geben die gespeicherten Daten zurück. Wenn keine Daten vorhanden sind, wird dies undefiniert zurückgegeben.

Die Selbst rufenden Funktion erstellt die Geschichte Manager, die Schnittstelle über die Variable Historymanager zugegriffen wird

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

Das Ihr Zoom Problem und die Undo-Problem zu beheben. Viel Glück mit Ihrem Projekt.

+0

Nun lass mich ein bisschen damit spielen. Ich lasse es dich wissen. –

+0

Dies sortiert beide Probleme. Ich danke dir sehr. Du bist ein Lebensretter. Ich danke dir sehr. –

+0

Eine letzte Sache. Beim Zoomen arbeitet der Zoom am Chrom, aber nicht am Firefox. Was könnte das Problem sein? –

1

Diese Funktion matchOutlineColor nimmt 4 Zahlen auf, die eine RGBA-Farbe darstellen.

Rot, Grün, Blau, Alpha (wie transparent die Farbe ist)

RGBA Farben reichen von 0 bis 255, also von 0 (keine Farbe) sind auf 255 (Vollfarbdruck) mit weißen wobei rgba (255,255,255,255), schwarz ist rgba (0,0,0,255) und transparent sein rgba (0,0,0,0).

Dieser Code prüft nicht, ob eine Farbe schwarz ist, nur dass die zusammengesetzten Farben Rot + Grün + Gelb mindestens weniger als 100 (von insgesamt 750) sind. Ich vermute, dass die Funktion prüft, ob die Farbe eine dunkle Farbe ist.

Zum Beispiel wird das alles passieren wahr:

<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>

Wenn Sie überprüfen wollen, ob die Grenze schwarz ist, dass Sie die Funktion

ändern
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

Wie werden hellgraue Pixel behandelt? –