0

Once user click on Mask image, we are allowing user to upload custom image.... Along with image, we are displaying text "Remove Image"....

Issue :

Onclick on that text, i want to delete the uploaded image like in this codepen1.... but right now only text is removing when i used below code :

var target;
var imageUrl = "https://i.imgur.com/RzEm1WK.png";

let jsonData = {  
  "layers" : [
    {
      "x" : 0,
      "height" : 612,   
      "layers" : [
        {
          "x" : 0,          
          "y" : 0,         
          "name" : "L2a"
        },
        {
          "x" : 160,         
          "layers" : [
            {
              "x" : 0,            
              "src" : "ax0HVTs.png",
              "y" : 0,              
              "name" : "L2b-1"
            },
            {
              
              "x" : 0,
              "y" : 0,             
              "name" : "L2b-2"
            }
          ],
          "y" : 291,         
          "name" : "user_image_1"
        },
        {
          "x" : 25,         
          "layers" : [
            {
              "x" : 0,             
              "src" : "hEM2kEP.png",
              "y" : 0,             
              "name" : "L2C-1"
            },
            {            
              "x" : 0,
              "y" : 0,            
              "name" : "L2C-2"
            }
          ],
          "y" :22,         
          "name" : "L2"
        }
      ],
      "y" : 0, 
      "width" : 612,   
      "name" : "L1"
    }
  ]
};

$(document).ready(function() {

    // below code will upload image onclick mask image

   $('.container').click(function(e) {

        var res = e.target;
        target = res.id;
        console.log(target);
        if (e.target.getContext) 
  {            
                setTimeout(() => {
                    $('#fileup').click();
                }, 20);           
        }
    });
 
 // Below code will fetch mask images from json file
 
    function getAllSrc(layers) {
        let arr = [];
        layers.forEach(layer => {
            if (layer.src) {
                arr.push({
                    src: layer.src,
                    x: layer.x,
                    y: layer.y,
     name: layer.name
                });
            } else if (layer.layers) {
                let newArr = getAllSrc(layer.layers);
                if (newArr.length > 0) {
                    newArr.forEach(({
                        src,
                        x,
                        y,
      name
                    }) => {
                        arr.push({
                            src,
                            x: (layer.x + x),
                            y: (layer.y + y),
       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 = [];

            for (let {
                    src,
                    x,
                    y,
     name
                } of arr) {
                $(".container").css('width', width + "px").css('height', height + "px").addClass('temp');
                if(name.indexOf('mask_') !== -1){
                    var imageUrl1 = imageUrl;
                }else{
                    var imageUrl1 = '';
                }    
                var mask = $(".container").mask({                
       imageUrl: imageUrl1,     
                    maskImageUrl: 'https://i.imgur.com/' + src,
                    onMaskImageCreate: function(img) {

                        img.css({
                            "position": "absolute",
                            "left": x + "px",
                            "top": y + "px"
                        });

                    },
                    id: counter
                });
                table.push(mask);
                fileup.onchange = function() {

                    let mask2 = table[target];
                    mask2.loadImage(URL.createObjectURL(fileup.files[0]));
                    document.getElementById('fileup').value = "";
     
     // Below code to Remove image

                $("<span class=\"pip\">" +
                    "<img src='https://i.imgur.com/' + src  />" +
                    "<br/><span class=\"remove\">Remove image</span>" +
                    "</span>").insertAfter("#fileup");

                $(".remove").click(function() {
                    $(this).parent(".pip").remove();
                });

                // Remove image code ended here.... 
                };
                counter++;
    // get the text
    
            }
        }
json(jsonData);
}); // end of document ready

// jq plugin 

(function($) {
    var 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);


        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.onDragStart = function(evt) {
            if (evt.target.getContext) {
                var pixel = evt.target.getContext('2d').getImageData(evt.offsetX, evt.offsetY, 1, 1).data;

                $(canvas).attr("active", "true");
                container.selected(evt);
                prevX = evt.clientX;
                prevY = evt.clientY;
                var img = new Image();
                evt.originalEvent.dataTransfer.setDragImage(img, 10, 10);
                evt.originalEvent.dataTransfer.setData('text/plain', 'anything');

            }
        };

        container.getImagePosition = function() {
            return {
                x: settings.x,
                y: settings.y,
                scale: settings.scale
            };
        };

        container.onDragOver = function(evt) {

            if (evt.target.getContext) {
                var pixel = evt.target.getContext('2d').getImageData(evt.offsetX, evt.offsetY, 1, 1).data;
                if (pixel[3] === 255) {
                    if (draggable && $(canvas).attr("active") === "true") {
                        var x = settings.x + evt.clientX - prevX;
                        var y = settings.y + evt.clientY - prevY;
                        if (x == settings.x && y == settings.y)
                            return; // position has not changed
                        settings.x += evt.clientX - prevX;
                        settings.y += evt.clientY - prevY;
                        prevX = evt.clientX;
                        prevY = evt.clientY;
                        clearTimeout(timeout);
                        timeout = setTimeout(function() {
                            container.updateStyle();
                            renderInnerImage();
                        }, 20);
                    }
                } else {
                    evt.stopPropagation();
                    return false;
                }
            }
        };

        container.updateStyle = function() {
            return new Promise((resolve, reject) => {
                context.beginPath();
                context.globalCompositeOperation = "source-over";
                image = new Image();
                image.setAttribute('crossOrigin', 'anonymous');
                image.src = settings.maskImageUrl;
                image.onload = function()
                {
                    canvas.width = image.width;
                    canvas.height = image.height;
                    context.drawImage(image, 0, 0, image.width, image.height);
                    div.css({
                        "width": image.width,
                        "height": image.height
                    });
                    resolve();
                };
            });
        };

        function renderInnerImage() {
            img = new Image();
            img.setAttribute('crossOrigin', 'anonymous');
            img.src = settings.imageUrl;
            img.onload = function() {
                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.drawImage(img, settings.x, settings.y, img.width * settings.scale, img.height * settings.scale);
                initImage = false;
            };
        }

        // change the draggable image
        container.loadImage = function(imageUrl) {
             console.log("load");
            //if (img)
               // img.remove();
            // reset the code.
            settings.y = startY;
            settings.x = startX;
            prevX = prevY = 0;
            settings.imageUrl = imageUrl;
            initImage = true;
            container.updateStyle().then(renderInnerImage);
        };

        // change the masked Image
         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;
            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);
        };
        container.loadMaskImage(settings.maskImageUrl);
        JQmasks.push({
            item: container,
            id: settings.id
        })
        return container;
    };
}(jQuery));
.temp {}

.container {
 background: gold;
  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;
}

.txtContainer{ position:absolute;  text-align:center; color:#FFF}

.pip {
  display: inline-block;
  margin: 10px 10px 0 0;
}
.remove {
  display: block;
  background: #444;
  border: 1px solid black;
  color: white;
  text-align: center;
  cursor: pointer;
}
.remove:hover {
  background: white;
  color: black;
}
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>

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

<div class="container">

</div>

Please let me know if you need any other information....

  • $(".remove").click(function(e){ $('.masked-img').empty() }) – Deepak A Mar 22 '19 at 06:33
  • @Deepak thanks, Its removing both the mask images , but i need to remove only uploaded image of particular mask..... –  Mar 22 '19 at 06:36
  • @Deepak i created codepen https://codepen.io/kidsdial/pen/oVQKya for your code...... –  Mar 22 '19 at 06:39
  • You will need two remove buttons to remove the two images or do you want the button to remove the last image uploaded? – DEVCNN Mar 25 '19 at 10:56
  • @DEVCNN if there are 2 images , i need 2 buttons, if there are 3 images , than 3 buttons , i need 1 button/1 image in dynamic way..... –  Mar 25 '19 at 11:00
  • @DEVCNN in this case, 9 images= > https://codepen.io/kidsdial/pen/XGGaPj , so 9 buttons, i need dynamic solution.... –  Mar 25 '19 at 11:04

1 Answers1

4

So to start with you should tackle 2 different problems:

1) Some how have a reference to your image in the button.

Buttons are not very smart and you will need to add some magic. As if you follow your code, when you load an image basically you are uploading a canvas with a new draw, so it is not easy to identify what to delete. One problem of this approach is that is difficult for you to find the image to delete. But you could, once the image is loaded, return the information about this image in the canvas and then adding it to an array.

As far as I can see there would be only one image per canvas, or at least it will draw over the last one, so the easiest solution is to clean the whole canvas. First, we return the id of the canvas that contains the image:

// change the draggable image
    container.loadImage = function(imageUrl) {
         console.log("load");
        //if (img)
           // img.remove();
        // reset the code.
        settings.y = startY;
        settings.x = startX;
        prevX = prevY = 0;
        settings.imageUrl = imageUrl;
        initImage = true;
        container.updateStyle().then(renderInnerImage);

        // Add this
        return settings.id;
    };

Then you can save it in this line: const newImageLoadedId = mask2.loadImage(URL.createObjectURL(fileup.files[0]));

Second step in this challenge is to basically add this as the id of the button (this is not the recommended way though, but is the one that will make you modify your code the less):

$("<br/><span id=\"" + newImageLoadedId + "\" class=\"remove\">Remove image</span>").insertAfter("#fileup");

Now your button has a reference to the image that you uploaded.

2) Actually delete it.

This problem is easier though, you just need to clear the image in the canvas:

$("canvas#" + id).getContext('2d').clearReact(...)

And this is all, I would suggest you refactor and clean a bit your code. And you could add some improvements like.

IF you want to upload more than one image to a canvas then this method is not the best one to delete a unique image, but your code also does not allow you to do it correctly right now. If you want to keep several images I suggest you check this answer, so basically you need to keep track of every image as a new layer.

Handling the click event with a closure instead of saving the id to the button (this makes the ID not being unique but rather exist in both, the button and the canvas). Making the load image process a bit more intuitive, even, for example, use the counter instead of the time stamp.

Disclaimer: This solution does not improve your code base, it just offers you a possible solution to the problem you are having and the proposed solution just touch as little number of lines as possible. I suggest few things at the end, but with time and more experience with jQuery / JavaScript, you will tackle this problem in a better way.

SirPeople
  • 4,248
  • 26
  • 46
  • Thanks for the explaination, i tried your code : https://codepen.io/kidsdial/pen/zbVymQ , but its not removing the uploaded images..... –  Mar 28 '19 at 05:42
  • I missunderstood you code, I updated the answer with more info and a different approach. – SirPeople Mar 28 '19 at 06:22
  • can you please tell what code changes i need to do ? or can you please change the code in codepen : https://codepen.io/kidsdial/pen/zbVymQ –  Mar 28 '19 at 06:25
  • also i checked [link](https://stackoverflow.com/questions/2142535/how-to-clear-the-canvas-for-redrawing/54153800#54153800) , but did't got how to implement that in my code, please help me to make related code changes..... –  Mar 28 '19 at 06:28
  • Here I edited your jsfiddle: https://jsfiddle.net/2yq5tvze/. Basically you need to fill everything with a white rectangle to reset the image. About implementing what they explain in the video, is not totally straight forward. You need to first, keep track of all the images, an example that does this is: http://jsfiddle.net/3MPrT/7/ . And secondly, whenever you delete something, you need to redraw the whole canvas layer by layer (so if i remove the 3rd image and I have 4, I have to render again 1st image, 2nd and 4th in that order) – SirPeople Mar 28 '19 at 07:53
  • Thanks , its deleting the latest uploaded image, but if i click on `1st Remove image` button , then it should delete first image, if i click on `2nd Remove image` button , then it should delete 2nd image, what i will do is i will display those `Remove images` text inside the mask images instead of outside as in this [link](https://stackoverflow.com/questions/55371271/display-text-inside-mask-image) , so please help me to delete the images according to `Remove image` text - 1st and 2nd..... –  Mar 28 '19 at 07:59
  • i am trying similar to this [link](https://www.greetingsisland.com/design/invitations/multi-photo/201-16182) , please upload images in that link and delete it, i want similar like that..... –  Mar 28 '19 at 08:02
  • I will check on this in few hours and help you add the button on the image – SirPeople Mar 28 '19 at 08:04