10

There are 3 parts in below Mask image :

1.Outside Non-Transparent Part

2.Border

3.Inside Transparent part

enter image description here

Right now When user click on Transparaent or Non-Transparent part, i am allowing user to upload image....

Requirement :

when user click on Non-Transparent part, than it should not display dailogue box to upload image....

Here is https://codepen.io/kidsdial/pen/jJBVON

var mask;

let jsonData = {
    "path": " love shape\/",
    "info": {
        "author": "",
        "keywords": "",
        "file": "love shape",
        "date": "sRGB",
        "title": "",
        "description": "Normal",
        "generator": "Export Kit v1.2.8"
    },
    "name": "love shape",
    "layers": [{
        "x": 1,
        "height": 613,
        "layers": [{
                "x": 1,
                "color": "0xFFFFFF",
                "height": 612,
                "y": 30,
                "width": 612,
                "shapeType": "rectangle",
                "type": "shape",
                "name": "bg_rectangle_1"
            },
            {
                "x": 40,
                "height": 480,
                "layers": [{
                        "x": 10,
                        "height": 480,
                        "src": "ncdHNan.png",
                        "y": 10,
                        "width": 514,
                        "type": "image",
                        "name": "mask_image_1"
                    },
                    {
                        "radius": "27 \/ 27",
                        "color": "0xACACAC",
                        "x": 233,
                        "y": 205,
                        "height": 53,
                        "width": 53,
                        "shapeType": "ellipse",
                        "type": "shape",
                        "name": "useradd_ellipse1"
                    }
                ],
                "y": 1,
                "width": 514,
                "type": "group",
                "name": "user_image_1"
            }
        ],
        "y": 1,
        "width": 614,
        "type": "group",
        "name": "loveshape_18"
    }]
};

$(document).ready(function() {

    $('.container').click(function(e) {
        setTimeout(() => {
            $('#fileup').click();
        }, 20)
    });



    function getAllSrc(layers) {
        let arr = [];
        layers.forEach(layer => {
            if (layer.src) {
                arr.push({
                    src: layer.src,
                    x: layer.x,
                    y: layer.y
                });
            } else if (layer.layers) {
                let newArr = getAllSrc(layer.layers);
                if (newArr.length > 0) {
                    newArr.forEach(({
                        src,
                        x,
                        y
                    }) => {
                        arr.push({
                            src,
                            x: (layer.x + x),
                            y: (layer.y + y)
                        });
                    });
                }
            }
        });
        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;

        for (let {
                src,
                x,
                y
            } of arr) {
            $(".container").css('width', width + "px").css('height', height + "px").addClass('temp');

            var mask = $(".container").mask({
                maskImageUrl: 'https://i.imgur.com/' + src,
                onMaskImageCreate: function(img) {

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

            fileup.onchange = function() {
                mask.loadImage(URL.createObjectURL(fileup.files[0]));
            };
        }

    }
    json(jsonData);

}); // end of document ready

// jq plugin for mask
(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) {
            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 (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;
                container.updateStyle();
            }
        };

        container.updateStyle = function() {
            clearTimeout(timeout);
            timeout = setTimeout(function() {
                context.clearRect(0, 0, canvas.width, canvas.height);
                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
                    });
                };

                img = new Image();
                img.src = settings.imageUrl;
                img.setAttribute('crossOrigin', 'anonymous');
                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;
                };
            }, 0);
        };

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

        // change the masked Image
        container.loadMaskImage = function(imageUrl, from) {
            if (div)
                div.remove();
            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 {
background: black;
}

.container {
 background: black;
  position: relative;
 
}

.masked-img {
 overflow: hidden;
 margin-top: 30px;
 position: relative;
}
<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>

1 Answers1

9

In your question you say that the heart is transparent and the rest of the canvas is opaque. However your code draws the heart as opaque with the rest of the canvas remains transparent. I will be assuming the later situation below.

Since you're using a canvas element for the actual drawing, we can take advantage of that:

$('.container').click(function(e) {
  if(e.target.getContext) {
    var pixel = e.target.getContext('2d').getImageData(e.offsetX, e.offsetY, 1, 1).data;
    if(pixel[3] === 255) {
      setTimeout(() => {
          $('#fileup').click();
      }, 20);
    }
  }
});

e.target is the element that actually got clicked. Checking if it has the property getContext tells us if it's a canvas or not. If it's not, no file dialog.

If it is the canvas, we can move on to the next step. getContext('2d') grabs the canvas' drawing context from which we can pull raw pixel data via getImageData().

offsetX and offsetY from the event are the click coordinates relative to the element that was clicked. We use those in getImageData() to grab the canvas pixel data at the click location.

Pixel data is interleaved red, blue, green, and alpha (opacity) values, ranging from 0 to 255 for each. Since we grabbed a single pixel, it will have 4 values, the last one being alpha. We can then use that to determine whether or not we trigger the file dialog.

Ouroborus
  • 16,237
  • 4
  • 39
  • 62
  • Thanks , This is peRFect, it worked fine..... its working fine is there is single image, will it work for [multiple images](https://stackoverflow.com/questions/55000800/upload-image-onclick-on-multiple-mask-images) also ? –  Mar 08 '19 at 09:15
  • @vickeycolors Only if the canvases do not overlap. If they do overlap, the code in my answer would only consider the top-most canvas. This may or may not matter depending on whether or not the transparent area of one canvas overlaps the opaque area of a canvas under it. – Ouroborus Mar 08 '19 at 09:20
  • or can we use higher `z-index` for clicked canvas mask, so that image will upload for that canvas mask ? –  Mar 08 '19 at 09:24
  • @vickeycolors Please consider that this question and your other question, while related, are separate questions and should be treated accordingly with regards to answers. – Ouroborus Mar 08 '19 at 09:28
  • yes , i completely agree, both are separate questions, okay then once i get solution for that question, then i will check your solution for multiple images...... –  Mar 08 '19 at 09:29
  • hi, i checked for multiple images - > its working fine, but if they are overlapped, than one issue is there , if we click on 2nd mask image [overlapped part - top left ] https://prnt.sc/mx95d5 , than 1st time it dont open file upload dialogue box , but if we click on 2nd time, it will open.... please check that..... https://codepen.io/kidsdial/pen/VRywRy –  Mar 13 '19 at 11:22