0

Once we click on Image , we are displaying File upload dialog box. User can able to upload image.

Issue :

Then when we click on "Remove" button, its clearing whole canvas.

Requirement :

but i need to delete only the uploaded image....

Remove Image Code :

$("<br/><span id=\"" + newImageLoadedId + "\" class=\"remove\">Remove</span>").insertAfter(".masked-img" + newImageLoadedId).css({
                    "left": ImagePosition[newImageLoadedId].x + (ImagePosition[newImageLoadedId].width / 2) + "px",
                    "top": ImagePosition[newImageLoadedId].y + (ImagePosition[newImageLoadedId].height / 2 + 25) + "px"
                });

                $(".remove").click(function(event) {
                    const canvasId = "canvas#" + event.currentTarget.id;
                    // Delete the uploaded image & icon
                    const ctx = $("canvas")[event.currentTarget.id].getContext("2d");
                    ctx.fillStyle = "white"
                    ctx.fillRect(0, 0, 500, 500)
                    $('#container').data('image_set' + event.currentTarget.id, false)

                    // Delete the Remove button
                    $(this).remove();
                });

Below is Code Snippet :

var target;
const imageUrl = "";

let jsonData = {
    "layers": [{
        "x": 0,
        "height": 612,
        "layers": [{
            "x": 10,
            "src": "bW5RSFA.png",
            "y": 10,
            "height": 296,
            "width": 429,
            "name": "mask_1"
        }],
        "y": 0,
        "width": 612
    }]
};

const containerElement = $('#container');
const fileUp = $('#fileup');
let mask;

$(function() {

    // Upload image onclick mask image 

    containerElement.click(function(e) {
        var res = e.target;
        target = res.id;
        if (e.target.getContext) {
            // click only inside Non Transparent part 
            var pixel = e.target.getContext('2d').getImageData(e.offsetX, e.offsetY, 1, 1).data;
            if (pixel[3] === 255) {
                setTimeout(() => {
                    $('#fileup').click();
                }, 20);
            }
        }
    });

    // Fetch mask images from json file - IGNORE this code 

    function getAllSrc(layers) {
        let arr = [];
        layers.forEach(layer => {
            if (layer.src) {
                arr.push({
                    src: layer.src,
                    x: layer.x,
                    y: layer.y,
                    height: layer.height,
                    width: layer.width,
                    name: layer.name
                });
            } else if (layer.layers) {
                let newArr = getAllSrc(layer.layers);
                if (newArr.length > 0) {
                    newArr.forEach(({
                        src,
                        x,
                        y,
                        height,
                        width,
                        name
                    }) => {
                        arr.push({
                            src,
                            x: (layer.x + x),
                            y: (layer.y + y),
                            height,
                            width,
                            name: (name)
                        });
                    });
                }
            }
        });
        return arr;
    }

    function json(data) {
        var width = 0;
        var height = 0;

        let arr = getAllSrc(data.layers);
        let layer1 = data.layers;
        width = layer1[0].width;
        height = layer1[0].height;
        let counter = 0;
        let table = [];

        // container dimensions 
        containerElement.css('width', width + "px").css('height', height + "px").addClass('temp');
        //end 

        for (let {
                src,
                x,
                y,
                name
            } of arr) {

            //Get Height and width of mask image [ edit button ] 
            var ImagePosition = arr;
            //code end 

            var imageUrl1 = imageUrl;

            var mask = $(".container").mask({
                imageUrl: name.indexOf('mask_') !== -1 ? imageUrl1 : undefined,

                // Fetch Mask images 
                maskImageUrl: 'http://i.imgur.com/' + src,
                // end 

                onMaskImageCreate: function(img) {
                    // Mask image positions 
                    img.css({
                        "position": "absolute",
                        "left": x + "px",
                        "top": y + "px"
                    });
                    // end 

                },
                id: counter
            });
            // here 

            ImagePosition.map(function(cur, index) {
                var available = cur.name.includes('mask_');

                if (!available) {
                    $('.masked-img' + index).css('pointer-events', 'none');
                }
            });

            table.push(mask);
            fileup.onchange = function() {

                let mask2 = table[target];
                const newImageLoadedId = mask2.loadImage(URL.createObjectURL(fileup.files[0]));
                document.getElementById('fileup').value = "";

            //  Remove image

                $("<br/><span id=\"" + newImageLoadedId + "\" class=\"remove\">Remove</span>").insertAfter(".masked-img" + newImageLoadedId).css({
                    "left": ImagePosition[newImageLoadedId].x + (ImagePosition[newImageLoadedId].width / 2) + "px",
                    "top": ImagePosition[newImageLoadedId].y + (ImagePosition[newImageLoadedId].height / 2 + 25) + "px"
                });

                $(".remove").click(function(event) {
                    const canvasId = "canvas#" + event.currentTarget.id;
                    // Delete the uploaded image & icon
                    const ctx = $("canvas")[event.currentTarget.id].getContext("2d");
                    ctx.fillStyle = "white"
                    ctx.fillRect(0, 0, 500, 500)
                    $('#container').data('image_set' + event.currentTarget.id, false)
                    
                    // Delete the Remove button
                    $(this).remove();
                });

                // Remove image code end here....

            };
            counter++;
        }
        return mask;
    }
    mask = json(jsonData);
}); // end of function 

// Image code 

(function($) {
    window.JQmasks = [];
    $.fn.mask = function(options) {
        // This is the easiest way to have default options. 
        var settings = $.extend({
            // These are the defaults. 
            maskImageUrl: undefined,
            imageUrl: undefined,
            scale: 1,
            id: new Date().getUTCMilliseconds().toString(),
            x: 0, // image start position 
            y: 0, // image start position 
            onMaskImageCreate: function(div) {},
        }, options);

        // Create the image properties
        settings.maskImage = new Image
        settings.image = new Image

        // set the cross-origin attributes
        settings.maskImage.setAttribute('crossOrigin', 'anonymous');
        settings.image.setAttribute('crossOrigin', 'anonymous');

        settings.maskImage.onload = function() {
            // once the mask is loaded, load the image
            container.loadImage(settings.imageUrl)
            container.drawMask()
        }

        settings.image.onload = function() {
            // once the image is loaded, render to canvas

            container.drawImage()
        }

        var container = $(this);

        let prevX = 0,
            prevY = 0,
            draggable = false,
            img,
            canvas,
            context,
            image,
            timeout,
            initImage = false,
            startX = settings.x,
            startY = settings.y,
            div;

        container.mousePosition = function(event) {
            return {
                x: event.pageX || event.offsetX,
                y: event.pageY || event.offsetY
            };
        }


         container.selected = function(ev) {
            var pos = container.mousePosition(ev);
            var item = $(".masked-img canvas").filter(function() {
                var offset = $(this).offset()
                var x = pos.x - offset.left;
                var y = pos.y - offset.top;
                var d = this.getContext('2d').getImageData(x, y, 1, 1).data;
                return d[0] > 0
            });

            JQmasks.forEach(function(el) {
                var id = item.length > 0 ? $(item).attr("id") : "";
                if (el.id == id)
                    el.item.enable();
                else el.item.disable();
            });
        };

        container.enable = function() {
            draggable = true;
            $(canvas).attr("active", "true");
            div.css({
                "z-index": 2
            });
        }

        container.disable = function() {
            draggable = false;
            $(canvas).attr("active", "false");
            div.css({
                "z-index": 1
            });
        }      

        container.drawMask = function() {
            if (!settings.maskImage) return true;
            canvas.width = settings.maskImage.width;
            canvas.height = settings.maskImage.height;
            context.save();
            context.beginPath();
            context.globalCompositeOperation = "source-over";
            // draw the masked image after scaling 
            if (settings.maskImage) context.drawImage(settings.maskImage, 0, 0, settings.maskImage.width, settings.maskImage.height);
            context.restore()
        };

         container.drawImage = function() {
            const img = settings.image

            settings.x = settings.x == 0 && initImage ? (canvas.width - (img.width * settings.scale)) / 2 : settings.x;
            settings.y = settings.y == 0 && initImage ? (canvas.height - (img.height * settings.scale)) / 2 : settings.y;

            context.globalCompositeOperation = 'source-atop';
            context.save();
            context.translate(settings.x + img.width / 2, settings.y + img.height / 2);
            context.rotate(settings.rotate);
            context.scale(settings.scale, settings.scale);
            context.translate(-(settings.x + img.width / 2), -(settings.y + img.height / 2));
            let width = img.width,
                height = img.height;
            if (img)
                context.drawImage(img, settings.x, settings.y, width, height);
            context.restore();
            initImage = false;           
        }
  
        container.loadImage = function(imageUrl) {
            if (!imageUrl) return true;
            settings.y = startY;
            settings.x = startX;
            prevX = prevY = 0;

            initImage = true;

            settings.image.src = imageUrl; // CHANGED

            // sirpepole Add this 
            return settings.id;
        };

        container.loadMaskImage = function(imageUrl, from) {

            canvas = document.createElement("canvas");
            context = canvas.getContext('2d');
            canvas.setAttribute("draggable", "true");
            canvas.setAttribute("id", settings.id);
            // settings.maskImageUrl = imageUrl;
            settings.maskImage.src = imageUrl // CHANGED

            div = $("<div/>", {
                "class": "masked-img"
            }).append(canvas);

            // div.find("canvas").on('touchstart mousedown', function(event) 
            div.find("canvas").on('dragstart', function(event) {
                if (event.handled === false) return;
                event.handled = true;
                container.onDragStart(event);
            });

            div.find("canvas").on('touchend mouseup', function(event) {
                if (event.handled === false) return;
                event.handled = true;
                container.selected(event);
            });

            div.find("canvas").bind("dragover", container.onDragOver);

            container.append(div);
            if (settings.onMaskImageCreate)
                settings.onMaskImageCreate(div);

            // container.loadImage(settings.imageUrl);
            // Moved this to the settings.maskImage.onload
        };
        if (settings.maskImageUrl) {
            container.loadMaskImage(settings.maskImageUrl);
        }
        JQmasks.push({
            item: container,
            id: settings.id
        })
        // Edit image 
        div.addClass('masked-img' + settings.id);
        div.attr('data-id', settings.id);
        // ends 
        return container;
    };
}(jQuery));
.container {
 background: silver;
 position: relative;
}

.container img {
 position: absolute;
 top: 0;
 bottom: 250px;
 left: 0;
 right: 0;
 margin: auto;
 z-index: 999;
}

.masked-img {
 overflow: hidden;
 position: relative;
}

.pip {
 display: inline-block;
 margin: 0;
 position: absolute;
}

.remove {
 background: #444;
 border: 1px solid black;
 color: white;
 text-align: center;
 cursor: pointer;
 position: absolute;
 z-index: 3;
}

.remove:hover {
 background: white;
 color: black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js">
</script>

<input id="fileup" name="fileup" type="file" style="display:none">

<div id="container" class="container">
</div>

Here is Code in Pastebin , Codepen , Fiddle

vickey colors
  • 171
  • 1
  • 10
  • 1
    Do you need something like this https://codepen.io/shivani30594/pen/EBGJMR ? – Shivani Sonagara Jul 10 '19 at 06:40
  • @ShivaniPatel Thanks for the codepen.... but you are deleting both `girl image` and `uploaded image`, but i want to delete only `uploaded image` & keep girl image as it is..... – vickey colors Jul 10 '19 at 06:42
  • @ShivaniPatel please let me know if you need any other information.... – vickey colors Jul 10 '19 at 10:19
  • I don't know much about canvas, but I looked into this and read that you may need to "rewrite" the canvas, as in you can't "remove" the image, per-say. https://stackoverflow.com/questions/3458244/removing-an-image-from-a-canvas-in-html5 – Souleste Jul 10 '19 at 21:15
  • Can you css `background-image` property instead of drawing the image directly in the canvas? – Mr. Brickowski Jul 12 '19 at 05:42
  • @Mr.Brickowski do i need to apply css for the uploaded image ? – vickey colors Jul 12 '19 at 05:55
  • I think no for your case. If only the uploaded image is supposed to be change, then you can keep the girl image as the background. It will be easier to maintain. Its because we can't remove a image from canvas. If there are image A,B,C on it and we need to remove B, we can only repaint the canvas with image A, C. – Mr. Brickowski Jul 12 '19 at 07:41
  • @Mr.Brickowski Thanks for suggestion , when user click on remove, can we keep the girl image as it is ? if so please help me with code..... – vickey colors Jul 12 '19 at 07:46
  • I have the technical solution but may not fit your business need. Your jsonData layers[0].layers[0].src, is it a must to be presented in canvas? – Mr. Brickowski Jul 12 '19 at 08:29
  • @Mr.Brickowski sorry for delay , Yes, i need to display all the data which is present in json , means all src - images, text..... – vickey colors Jul 12 '19 at 09:06

1 Answers1

2

Update the script as the following. Such on every remove, the canvas is clear followed by a mask repainted.

var container;
var target;
const imageUrl = "";

let jsonData = {
  "layers": [{
    "x": 0,
    "height": 612,
    "layers": [{
      "x": 10,
      "src": "bW5RSFA.png",
      "y": 10,
      "height": 296,
      "width": 429,
      "name": "mask_1"
    }],
    "y": 0,
    "width": 612
  }]
};

const containerElement = $('#container');
const fileUp = $('#fileup');
let mask;

$(function() {

  // Upload image onclick mask image 

  containerElement.click(function(e) {
    var res = e.target;
    target = res.id;
    if (e.target.getContext) {
      // click only inside Non Transparent part 
      var pixel = e.target.getContext('2d').getImageData(e.offsetX, e.offsetY, 1, 1).data;
      if (pixel[3] === 255) {
        setTimeout(() => {
          $('#fileup').click();
        }, 20);
      }
    }
  });

  // Fetch mask images from json file - IGNORE this code 

  function getAllSrc(layers) {
    let arr = [];
    layers.forEach(layer => {
      if (layer.src) {
        arr.push({
          src: layer.src,
          x: layer.x,
          y: layer.y,
          height: layer.height,
          width: layer.width,
          name: layer.name
        });
      } else if (layer.layers) {
        let newArr = getAllSrc(layer.layers);
        if (newArr.length > 0) {
          newArr.forEach(({
            src,
            x,
            y,
            height,
            width,
            name
          }) => {
            arr.push({
              src,
              x: (layer.x + x),
              y: (layer.y + y),
              height,
              width,
              name: (name)
            });
          });
        }
      }
    });
    return arr;
  }

  function json(data) {
    var width = 0;
    var height = 0;

    let arr = getAllSrc(data.layers);
    let layer1 = data.layers;
    width = layer1[0].width;
    height = layer1[0].height;
    let counter = 0;
    let table = [];

    // container dimensions 
    containerElement.css('width', width + "px").css('height', height + "px").addClass('temp');
    //end 

    for (let {
        src,
        x,
        y,
        name
      } of arr) {

      //Get Height and width of mask image [ edit button ] 
      var ImagePosition = arr;
      //code end 

      var imageUrl1 = imageUrl;

      var mask = $(".container").mask({
        imageUrl: name.indexOf('mask_') !== -1 ? imageUrl1 : undefined,

        // Fetch Mask images 
        maskImageUrl: 'http://i.imgur.com/' + src,
        // end 

        onMaskImageCreate: function(img) {
          // Mask image positions 
          img.css({
            "position": "absolute",
            "left": x + "px",
            "top": y + "px"
          });
          // end 

        },
        id: counter
      });
      // here 

      ImagePosition.map(function(cur, index) {
        var available = cur.name.includes('mask_');

        if (!available) {
          $('.masked-img' + index).css('pointer-events', 'none');
        }
      });

      table.push(mask);
      fileup.onchange = function() {

        let mask2 = table[target];
        const newImageLoadedId = mask2.loadImage(URL.createObjectURL(fileup.files[0]));
        document.getElementById('fileup').value = "";

        //  Remove image

        $("<br/><span id=\"" + newImageLoadedId + "\" class=\"remove\">Remove</span>").insertAfter(".masked-img" + newImageLoadedId).css({
          "left": ImagePosition[newImageLoadedId].x + (ImagePosition[newImageLoadedId].width / 2) + "px",
          "top": ImagePosition[newImageLoadedId].y + (ImagePosition[newImageLoadedId].height / 2 + 25) + "px"
        });

        $(".remove").click(function(event) {
          const canvasId = "canvas#" + event.currentTarget.id;
          // Delete the uploaded image & icon
          const ctx = $("canvas")[event.currentTarget.id].getContext("2d");

          ctx.clearRect(0, 0, 500, 500);
          $('#container').data('image_set' + event.currentTarget.id, false);
          container.drawMask();
          // Delete the Remove button
          $(this).remove();
        });

        // Remove image code end here....

      };
      counter++;
    }
    return mask;
  }
  mask = json(jsonData);
}); // end of function 

// Image code 

(function($) {
  window.JQmasks = [];
  $.fn.mask = function(options) {
    // This is the easiest way to have default options. 
    var settings = $.extend({
      // These are the defaults. 
      maskImageUrl: undefined,
      imageUrl: undefined,
      scale: 1,
      id: new Date().getUTCMilliseconds().toString(),
      x: 0, // image start position 
      y: 0, // image start position 
      onMaskImageCreate: function(div) {},
    }, options);

    // Create the image properties
    settings.maskImage = new Image
    settings.image = new Image

    // set the cross-origin attributes
    settings.maskImage.setAttribute('crossOrigin', 'anonymous');
    settings.image.setAttribute('crossOrigin', 'anonymous');

    settings.maskImage.onload = function() {
      // once the mask is loaded, load the image
      container.loadImage(settings.imageUrl)
      container.drawMask()
    }

    settings.image.onload = function() {
      // once the image is loaded, render to canvas

      container.drawImage()
    }

    container = $(this);

    let prevX = 0,
      prevY = 0,
      draggable = false,
      img,
      canvas,
      context,
      image,
      timeout,
      initImage = false,
      startX = settings.x,
      startY = settings.y,
      div;

    container.mousePosition = function(event) {
      return {
        x: event.pageX || event.offsetX,
        y: event.pageY || event.offsetY
      };
    }


    container.selected = function(ev) {
      var pos = container.mousePosition(ev);
      var item = $(".masked-img canvas").filter(function() {
        var offset = $(this).offset()
        var x = pos.x - offset.left;
        var y = pos.y - offset.top;
        var d = this.getContext('2d').getImageData(x, y, 1, 1).data;
        return d[0] > 0
      });

      JQmasks.forEach(function(el) {
        var id = item.length > 0 ? $(item).attr("id") : "";
        if (el.id == id)
          el.item.enable();
        else el.item.disable();
      });
    };

    container.enable = function() {
      draggable = true;
      $(canvas).attr("active", "true");
      div.css({
        "z-index": 2
      });
    }

    container.disable = function() {
      draggable = false;
      $(canvas).attr("active", "false");
      div.css({
        "z-index": 1
      });
    }

    container.drawMask = function() {
      if (!settings.maskImage) return true;
      canvas.width = settings.maskImage.width;
      canvas.height = settings.maskImage.height;
      context.save();
      context.beginPath();
      context.globalCompositeOperation = "source-over";
      // draw the masked image after scaling 
      if (settings.maskImage) context.drawImage(settings.maskImage, 0, 0, settings.maskImage.width, settings.maskImage.height);
      context.restore()
    };

    container.drawImage = function() {
      const img = settings.image

      settings.x = settings.x == 0 && initImage ? (canvas.width - (img.width * settings.scale)) / 2 : settings.x;
      settings.y = settings.y == 0 && initImage ? (canvas.height - (img.height * settings.scale)) / 2 : settings.y;

      context.globalCompositeOperation = 'source-atop';
      context.save();
      context.translate(settings.x + img.width / 2, settings.y + img.height / 2);
      context.rotate(settings.rotate);
      context.scale(settings.scale, settings.scale);
      context.translate(-(settings.x + img.width / 2), -(settings.y + img.height / 2));
      let width = img.width,
        height = img.height;
      if (img)
        context.drawImage(img, settings.x, settings.y, width, height);
      context.restore();
      initImage = false;
    }

    container.loadImage = function(imageUrl) {
      if (!imageUrl) return true;
      settings.y = startY;
      settings.x = startX;
      prevX = prevY = 0;

      initImage = true;

      settings.image.src = imageUrl; // CHANGED

      // sirpepole Add this 
      return settings.id;
    };

    container.loadMaskImage = function(imageUrl, from) {

      canvas = document.createElement("canvas");
      context = canvas.getContext('2d');
      canvas.setAttribute("draggable", "true");
      canvas.setAttribute("id", settings.id);
      // settings.maskImageUrl = imageUrl;
      settings.maskImage.src = imageUrl // CHANGED

      div = $("<div/>", {
        "class": "masked-img"
      }).append(canvas);

      // div.find("canvas").on('touchstart mousedown', function(event) 
      div.find("canvas").on('dragstart', function(event) {
        if (event.handled === false) return;
        event.handled = true;
        container.onDragStart(event);
      });

      div.find("canvas").on('touchend mouseup', function(event) {
        if (event.handled === false) return;
        event.handled = true;
        container.selected(event);
      });

      div.find("canvas").bind("dragover", container.onDragOver);

      container.append(div);
      if (settings.onMaskImageCreate)
        settings.onMaskImageCreate(div);

      // container.loadImage(settings.imageUrl);
      // Moved this to the settings.maskImage.onload
    };
    if (settings.maskImageUrl) {
      container.loadMaskImage(settings.maskImageUrl);
    }
    JQmasks.push({
      item: container,
      id: settings.id
    })
    // Edit image 
    div.addClass('masked-img' + settings.id);
    div.attr('data-id', settings.id);
    // ends 
    return container;
  };
}(jQuery));
.container {
  background: silver;
  position: relative;
}

.container img {
  position: absolute;
  top: 0;
  bottom: 250px;
  left: 0;
  right: 0;
  margin: auto;
  z-index: 999;
}

.masked-img {
  overflow: hidden;
  position: relative;
}

.pip {
  display: inline-block;
  margin: 0;
  position: absolute;
}

.remove {
  background: #444;
  border: 1px solid black;
  color: white;
  text-align: center;
  cursor: pointer;
  position: absolute;
  z-index: 3;
}

.remove:hover {
  background: white;
  color: black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js">
</script>

<input id="fileup" name="fileup" type="file" style="display:none">

<div id="container" class="container">
</div>
Mr. Brickowski
  • 1,134
  • 1
  • 8
  • 20
  • Thanks , i updated your code in [Codepen](https://codepen.io/kidsdial/pen/KjLLWw) , but still i am getting same results. means once i click on `remove` button , its clearing both uploaded image & mask image too as before..... – vickey colors Jul 15 '19 at 05:40
  • Thanks, its working for first time, when i try to upload image 2nd time, then image will not upload , means i upload image & click on `remove` button, then again i tried to upload image, but image not uploading, please check once.... – vickey colors Jul 16 '19 at 12:31
  • Is it a desired feature? https://imgur.com/FGsqrCG i.e. to paint the uploaded image to where it is overlapped with the mask – Mr. Brickowski Jul 18 '19 at 07:36
  • in that image , it should display girl image when we click on `remove` , but its displaying 3 boxes...... when we refresh the page, you can see girl image, once we upload image & click on remove & again if we reupload image, then it should display like refreshed page , please let me know if you have any doubts on this.... – vickey colors Jul 18 '19 at 07:39
  • oh, background image [box image] is not displaying now, it should display background image and girl image too..... – vickey colors Jul 18 '19 at 07:42
  • I mean, if i upload a solid white rectangle, it will be chopped 3 parts with 2 gaps. https://imgur.com/UOr22fj (the red arrow). Is it intended? – Mr. Brickowski Jul 18 '19 at 08:01
  • sorry for delay, now i got it, yes that's how client wanted it.... girl image is mask image..... once user upload image on girl image, it should display only on girl image.... – vickey colors Jul 18 '19 at 09:09
  • here is another example : https://codepen.io/kidsdial/pen/qeBNwK , once we click inside heart image in that codepen, then image will upload only inside heart..... – vickey colors Jul 18 '19 at 09:13