1

EDIT (original post at bottom below code)**

Fiddle: https://jsfiddle.net/Tron4949/oezuz1g9/9/ (fiddle example will not have a background, it's unnecessary to demonstrate the issue, the console log shows more detail about which view you are on, what was just saved, etc.)

Here is my attempt based on the suggestions from below. It has changed forms many times - currently when the user loads an image, and positions it where they want, then toggles to another view, the uploaded image carries over to that other view (which is undesired - each view should have their own specific layout).

I added 'front', 'side', and 'back' buttons to correspond to different canvas views. When you toggle back and forth - I track the canvas view ("front", "side", or "back") in session storage, defaulting to "front" at the very beginning. Depending on which button is pressed (for which view), it redefines the string in sessionStorage so that we know what the previous view was supposed to be. It then saves the content of the canvas to storage as a dataURL according to the view it just came from. (*It then clears the canvas and accesses the dataURL for the correct position of the background picture that the user chose earlier on - this is not displayed in the fiddle).

From this point is where I keep having to re-configure things, and I can not find a solution to make it run properly, that is, to make it run without images carrying over.

As is, the image that the user uploaded not only carries over to the other views when you toggle between them, but anything I do with that image, or a newly uploaded one, continues to carry over as you toggle back and forth between views, to the point where each of the three uploaded images and positions are all the same(unexpected/undesired).

A stripped down version - The three click handlers for 'views' are basically the same:

HTML

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://rawgit.com/kangax/fabric.js/master/dist/fabric.min.js"></script>

<canvas id="c" width="740" height="500" style="border-left: 3px solid black; border-top: 3px solid black; border-radius: 10px;"></canvas>

<button class="btn" id="customer-chosen-background-image">Set A Background Image</button>
<input class="btn" type="file" id="files" name="files[]"/>
<button class="btn" id="sessionInfoClear">Clear My Session</button>

<hr>
<button class="btn view-btn" id="front-hat-view-button">Front</button>
<button class="btn view-btn" id="side-hat-view-button">Side</button>
<button class="btn view-btn" id="back-hat-view-button">Back</button>

<canvas id="d" width="740" height="250" style="border-left: 3px solid black; border-top: 3px solid black; border-radius: 10px;"></canvas>

JS

$(document).ready(function() {

  var canvas = new fabric.Canvas('c');
  var canvas2 = new fabric.Canvas('d');
  var scopeTesterOne = "testing scope";//SOMETHING I DO OCCASIONALLY

  document.getElementById('files').addEventListener("change", function (e) {
    var file = e.target.files[0];
    var reader = new FileReader();
    reader.onload = function (f) {
      var data = f.target.result;                    
      fabric.Image.fromURL(data, function (img) {
        var oImg = img.set({left: 350, top: 300, angle: 00,width:100, height:100}).scale(0.9);
        canvas.add(oImg).renderAll();
        var a = canvas.setActiveObject(oImg);
      });
    };
    reader.readAsDataURL(file);
    $('#files').css({'background-color': 'white', 'color': 'black', 'border': '2px solid black'});

  });

$('#customer-chosen-background-image').click(function() {
   var backgroundImageFilePath = 'http://store-1p9yfoynqe.mybigcommerce.com/product_images/Viewsforfiddle.png';
      // var backgroundURL = "url(" + backgroundImageFilePath + ")"
      canvas.setBackgroundImage(backgroundImageFilePath, canvas.renderAll.bind(canvas), {
        top: 0,
        left: 50,
        scaleY: .8,
        scaleX: .8
      });  
  });

var whatIsTheHatViewOnCanvas = function() {//INITIALLY THIS IS HOW WE TELL/TRACK/SET WHAT THE PREVIOUS VIEW WAS
    var doesTrackingDataExist = sessionStorage.getItem('viewForHatCanvas');
    if (doesTrackingDataExist) {
      console.log("traker has previous view data");
    } else {
      console.log("traker has no previous view data");
      sessionStorage.setItem('viewForHatCanvas', "front");

      var consoleTestttt = sessionStorage.getItem('viewForHatCanvas');
      console.log(consoleTestttt);
    }
  };
  whatIsTheHatViewOnCanvas();

  function loadCanvas(dataURL) { //THIS IS FOR THE MAIN CANVAS
    var canvas = document.getElementById('c');
    var context = canvas.getContext('2d');

    var imageObj = new Image();
    imageObj.onload = function() {
      context.drawImage(this, 0, 0);
    };
    imageObj.src = dataURL;
  }
  function loadPreviewCanvasFront(dataURL) {//IMAGES FOR THE 'PREVIEW' CANVAS
    var canvas2 = document.getElementById('d');
    var context = canvas2.getContext('2d');

    var imageObj = new Image();
    imageObj.onload = function() {
      context.drawImage(this, 0, 0, 185, 125);
    };
    imageObj.src = dataURL;
  }

  function loadPreviewCanvasSide(dataURL) {//IMAGES FOR THE 'PREVIEW' CANVAS
    var canvas2 = document.getElementById('d');
    var context = canvas2.getContext('2d');

    var imageObj = new Image();
    imageObj.onload = function() {
      context.drawImage(this, 185, 0, 185, 125);
    };
    imageObj.src = dataURL;
  }

  function loadPreviewCanvasBack(dataURL) {//IMAGES FOR THE 'PREVIEW' CANVAS
    var canvas2 = document.getElementById('d');
    var context = canvas2.getContext('2d');

    var imageObj = new Image();
    imageObj.onload = function() {
      context.drawImage(this, 370, 0, 185, 125);
    };
    imageObj.src = dataURL;
  }



  $('#front-hat-view-button').click(function() {
    console.log(scopeTesterOne);

    var context = canvas.getContext('2d');
    var previousHatView = sessionStorage.getItem('viewForHatCanvas');
    sessionStorage.setItem('viewForHatCanvas', "front");
    console.log("from " + previousHatView + " to front");

    canvas.deactivateAll().renderAll();  
    var savingCanvasContentF = canvas.toDataURL("image");

    if (previousHatView === "side") {
      sessionStorage.setItem('storedSideHatCreation', savingCanvasContentF);
      console.log("from " + previousHatView + " to front - STORED AS SIDE VIEW");
    }
    if (previousHatView === "back") {
      sessionStorage.setItem('storedBackHatCreation', savingCanvasContentF); 
      console.log("from " + previousHatView + " to back - STORED AS BACK VIEW");
    }
    // canvas.clear();
    context.clearRect(0, 0, canvas.width, canvas.height);

    var imgToLoadOnFrontView = sessionStorage.getItem('storedFrontHatCreation');
    //var backgroundImageFilePath = 
    //var backgroundURL = "url(" + backgroundImageFilePath + ")"
    //canvas.setBackgroundImage(backgroundImageFilePath, canvas.renderAll.bind(canvas), {
      //top: 0,
      //left: 50,
      //scaleY: .8,
      //scaleX: .8
    //});

    if (imgToLoadOnFrontView != null) {
      context.clearRect(0, 0, canvas.width, canvas.height);
      console.log("says there is an image to load on front");
      loadCanvas(imgToLoadOnFrontView);
      loadPreviewCanvasFront(imgToLoadOnFrontView);
    }
  });

$('#side-hat-view-button').click(function() {
  var context = canvas.getContext('2d');
  var previousHatView = sessionStorage.getItem('viewForHatCanvas');
  var currentHatView = "side";
  sessionStorage.setItem('viewForHatCanvas', "side");

  canvas.deactivateAll().renderAll();  
  var savingCanvasContentS = canvas.toDataURL("image");

  if (previousHatView === "front") {
    sessionStorage.setItem('storedFrontHatCreation', savingCanvasContentS);
    console.log("from " + previousHatView + " to side - STORED AS FRONT VIEW");
  }
  if (previousHatView === "back") {
    sessionStorage.setItem('storedBackHatCreation', savingCanvasContentS); 
    console.log("from " + previousHatView + " to side - STORED AS BACK VIEW");
  }
  // canvas.clear();
  context.clearRect(0, 0, canvas.width, canvas.height);


  var imgToLoadOnSideView = sessionStorage.getItem('storedSideHatCreation');
//  var backgroundImageFilePath = sessionStorage.getItem('hatImageLocation');
//  var backgroundURL = "url(" + backgroundImageFilePath + ")"
//  canvas.setBackgroundImage(backgroundImageFilePath, canvas.renderAll.bind(canvas), {
//    top: -560,
//    left: 50,
//    scaleY: .8,
//    scaleX: .8
//  });

  if (imgToLoadOnSideView != null) {
    context.clearRect(0, 0, canvas.width, canvas.height);
    console.log("says there is an image to load on side");
    loadCanvas(imgToLoadOnSideView);
    loadPreviewCanvasSide(imgToLoadOnSideView);
  } 
});

$('#back-hat-view-button').click(function() {
  var context = canvas.getContext('2d');
  var previousHatView = sessionStorage.getItem('viewForHatCanvas');
  sessionStorage.setItem('viewForHatCanvas', "back");
  console.log("from " + previousHatView + " to back");

  canvas.deactivateAll().renderAll();  
  var savingCanvasContentB = canvas.toDataURL("image");

  if (previousHatView === "front") {
    sessionStorage.setItem('storedFrontHatCreation', savingCanvasContentB);
    console.log("from " + previousHatView + " to back - STORED AS FRONT VIEW");
  }
  if (previousHatView === "side") {
    sessionStorage.setItem('storedSideHatCreation', savingCanvasContentB); 
    console.log("from " + previousHatView + " to back - STORED AS SIDE VIEW");
  }
  // canvas.clear();
  context.clearRect(0, 0, canvas.width, canvas.height);


  var imgToLoadOnBackView = sessionStorage.getItem('storedBackHatCreation');
  //var backgroundImageFilePath = sessionStorage.getItem('hatImageLocation');
  //var backgroundURL = "url(" + backgroundImageFilePath + ")"
  //canvas.setBackgroundImage(backgroundImageFilePath, canvas.renderAll.bind(canvas), {
  //  top: -1065,
  //  left: 50,
  //  scaleY: .8,
  //  scaleX: .8
  //});

  if (imgToLoadOnBackView != null) {
    context.clearRect(0, 0, canvas.width, canvas.height);
    console.log("says there is an image to load on back");
    loadCanvas(imgToLoadOnBackView);
    loadPreviewCanvasBack(imgToLoadOnBackView);
  } 
});

  $('#sessionInfoClear').click(function() {
    sessionStorage.clear();
    location.reload();
  });

});

ORIGINAL POST (below):

I have a canvas that users can interact with (to create a hat). It has one background image that has three 'sections' on it for front side and back. As of now, a user is able to upload their own images and manipulate them on the canvas to make their own designs - I am using Fabric.js for image manipulation.

My Goal: Although the background image is one large image with three 'sections' on it, I only want the user to be able to see one of those sections at a time, and then be able to switch back and forth between any of the three of them while they make their picture/creation (without a page load - page load removes the uploaded images).

My thoughts: Change the canvas's viewable area on a click - I can not figure out how to make a specific viewable area but I feel like this is the best option I can think of. I just need to be able to figure out how to have a 'viewing window' that is smaller than the canvas, and then I could use thumbnails or buttons to change whatever parameters I need to change so that it appears to be a different canvas (without a reload - it will remove the images).

Is this realistic and or possible? Is there a particular/better way that I have not considered? I really would like to keep the app (mostly) in-tact, but if I absolutely have to change everything, then I will, but I'm hoping someone knows how to do what I am proposing. Thanks so much for your time.

Tron
  • 167
  • 12
  • I am upvoted your question because I think its interesting, but you should add more details about your code implementation jsfiddle or runnable snippets, thanks – ale Sep 12 '16 at 18:21
  • @Infer, thanks for the suggestion and response, I didn't know if there would be any interest in the topic, or if what i'm proposing is possible in this way, or if it would help people to answer the question if I put together a fiddle, but I can throw together a simplified working model of what I currently have. – Tron Sep 12 '16 at 18:26
  • [Using multiple context for a single canvas is not supported](http://stackoverflow.com/a/8466663/2260614), I think using multiple `canvas` is your best shot. [Fabricjs Layering](https://github.com/kangax/fabric.js/wiki/How-fabric-canvas-layering-works) is based on same concept(multiple `canvas` element) – Bhavik Sep 12 '16 at 19:02
  • Can you elaborate a bit, I don't quite follow? Do you mean multiple 's? Different fabric canvases for each? Or are you suggesting a layering of the BG images with some sort of code that brings one or another to the front depending on (for example) a click? I need to be able to save them all as one image in the end also. Thank you for the reply. – Tron Sep 12 '16 at 20:21

1 Answers1

0

I think there is an easier solution then what you are trying to do. if you have the reference to the fabric instance you can get the whole object state out of it with: var currentCanvasData = canvas.toObject(). You will get a nice javascript object that you can pass in later to recreate the canvas. canvas.clear() will remove everything from the canvas and canvas.loadFromJSON(currentCanvasData) will load it all back up. Make sure to call canvas.renderAll() after loadFromJSON.

this will make it easy to switch bewteen 3 different work spaces for you and the user.

var canvas = new fabric.Canvas('c');
var currentView = 1;
var view1Save = {};
var view2Save = {};

var view1 = document.querySelector('.one');
var view2 = document.querySelector('.two');

view1.onclick = (function() {
  if (currentView === 2) {
    view2Save = canvas.toObject();
    canvas.clear();
    canvas.loadFromJSON(view1Save, canvas.renderAll.bind(canvas));
    currentView = 1;
    view1.disabled = true
    view2.disabled = false
  }
});

view2.onclick = (function() {
  if (currentView === 1) {
    view1Save = canvas.toObject();
    canvas.clear();
    canvas.loadFromJSON(view2Save, canvas.renderAll.bind(canvas));
    currentView = 2;
    view1.disabled = false
    view2.disabled = true
  }
});

var addRect = document.querySelector('.rect');
addRect.onclick = (function() {
  canvas.add(new fabric.Rect({
    left: 100,
    top: 100,
    width: 50,
    height: 50,
    fill: 'red'
  }));
});

var addImg = document.querySelector('.image');
addImg.onclick = (function() {
  var imgElement = new Image();
  imgElement.src = 'http://cdn.sstatic.net/Sites/stackoverflow/img/sprites.png';
  imgElement.onload = (function() {
    canvas.add(new fabric.Image(imgElement, {
      left: 100,
      top: 100,
      angle: 30,
      opacity: 0.85
    }));
  });
});
canvas { border: 1px solid #ccc; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.6.4/fabric.min.js"></script>
different views:
<button class="one" disabled>view 1</button>
<button class="two" >view 2</button>
<br />
<button class="rect">add rect</button>
<button class="image">add image</button>
<canvas id="c" width="600" height="600"></canvas>
StefanHayden
  • 3,569
  • 1
  • 31
  • 38
  • I will give this a shot. Assuming I can specify where on the canvas to put the loadFromJSON (So I can create one final image at the end), I think this might be the way to go. Thank you for the reply and I will post an update with my results. – Tron Sep 14 '16 at 20:32
  • I gave it the best I could but the end result was that the user-uploaded images won't save and dissappear when the user loads a new view. I will post my code above. – Tron Sep 19 '16 at 21:00
  • please make sure your code and run in a code example or jsfiddle – StefanHayden Sep 19 '16 at 23:09
  • https://jsfiddle.net/Tron4949/oezuz1g9/9/ STHayden and @infer-on , Here is a stripped down version put into a Fiddle - without background because I would have to deal with tainted canvas errors and other headaches, but you can still see the issue where the uploaded image/s carries over etc. – Tron Sep 20 '16 at 18:37
  • 1-Upload image, 2-place/manipulate the image, 3-Move to a different view (will not show because there isn't a background), 4-Move to a different view again, then go back to the original - there are different ways you can see the issue, but in any case, by the end, you will end up with three of the exact same images. – Tron Sep 20 '16 at 18:43
  • that jsfiddle is a ton of code. not sure if you can make it simpler. I have added a working example of what I tried to describe. you can add objects and switch between 2 views. – StefanHayden Sep 22 '16 at 04:33