0

Background :

We are displaying two Masks inside container....

User click on both Masks & upload the image....

Now Edit Text is displaying on both images....

Once user click on Edit Text, we are displaying pop up box....

There we can see Zoomin & Zoomout buttons are displaying....

Steps to Reproduce the Issue :

1.Click on Zoomin for 1st image 5 times....

2.Now click on Zoomin for 2nd image....

Zoom value of 1st image is now equal to 2nd image....

But if we zoom one image, it should't change zoom value of other image....

Here is 16 seconds Video to show the issue

enter image description here

Requirement :

I can solve the issue statically by using multiple variables for each images....

but I need solution dynamically as i am using only one variable for zoom_in and zoom_out called scale....

Here is Codepen

Below is Snippet :

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

    let jsonData = {
        "layers": [{
            "x": 0,
            "height": 612,
            "layers": [{
                "x": 160,
                "src": "ax0HVTs.png",
                "y": 291,
                "height": 296,
                "width": 429,
                "name": "mask_1"
            },
                {
                    "x": 25,
                    "src": "hEM2kEP.png",
                    "height": 324,
                    "width": 471,
                    "y": 22,
                    "name": "mask_2"
                }
            ],
            "y": 0,
            "width": 612
        }]
    };

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

    $(function() {

        // Upload image onclick mask image

        containerElement.click(function(e) {
            var res = e.target;
            target = res.id;
            // console.log(target);
            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 mask = $(".container").mask({
                    imageUrl: imageUrl,

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

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

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

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

                    if (($(".masked-img" + newImageLoadedId + ' #renderImage').length) === 0) {
                        $('.masked-img' + newImageLoadedId).append("<img id='renderImage' style='width: 300px' src=" + imgView + ">");
                    } else {
                        $('#renderImage').attr('src', imgView);
                    }

                    //  Edit image - IGNORE this code

                    if ($(".masked-img" + newImageLoadedId).length === 1) {
                        $("<span class=\"pip pip" + newImageLoadedId + "\">" +
                            "<a onclick='document.getElementById(\"dark" + newImageLoadedId + "\").style.display=\"block\";'><span class=\"edit edit" + newImageLoadedId + "\" >Edit </span></a>" +
                            "</span>").insertAfter(".masked-img" + newImageLoadedId).css({
                            "left": ImagePosition[newImageLoadedId].x + (ImagePosition[newImageLoadedId].width / 2) + "px",
                            "top": ImagePosition[newImageLoadedId].y + (ImagePosition[newImageLoadedId].height / 2) + "px"
                        });;
                        $("<div id=\'dark" + newImageLoadedId + "\' class=\'dark_content\'>" +
                            $('#demoTemplate').html() +
                            "<a href=\"javascript:void(0)\" onclick=\"document.getElementById(\'dark" + newImageLoadedId + "\').style.display=\'none\'\">Close</a>" + "</div>").appendTo(".pip" + newImageLoadedId).css({
                            "left": $('.edit' + newImageLoadedId).width() + 2 + "px",
                            "top": "0px"
                        });
                    }
                    //  end
                };
                counter++;
            }
        }
        json(jsonData);
    }); // end of function

    // Image code

    (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.getImagePosition = function() {
                return {
                    x: settings.x,
                    y: settings.y,
                    scale: settings.scale
                };
            };

            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;
                    // console.log(image.src);
                    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 = $('#renderImage'); // new Image()
                img = new Image();
                img.setAttribute('crossOrigin', 'anonymous');
                img.src = settings.imageUrl;
                // console.log(image.src);
                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");
                settings.y = startY;
                settings.x = startX;
                // console.log(settings.y);
                // console.log(settings.x);
                prevX = prevY = 0;
                settings.imageUrl = imageUrl;
                // console.log(settings.imageUrl);
                initImage = true;
                container.updateStyle().then(renderInnerImage);
                // 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;
                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
            });
            // Edit image
            div.addClass('masked-img' + settings.id);
            // end
            return container;
        };
    }(jQuery));

    // zoom

    var angle = 0;
    var scale = 1;

    function zoom_in(data) {
        var getParent = data.parentElement.parentElement.parentElement;
        var getId = getParent.id.substring(getParent.id.length - 1);
        console.log(getId);
        scale += .25;
        $('.masked-img' + getId + ' #renderImage').css({
            transform: 'scale('+ scale +')'
        });
    }

    function zoom_out(data) {
        var getParent = data.parentElement.parentElement.parentElement;
        var getId = getParent.id.substring(getParent.id.length - 1);
        console.log(getId);
        scale -= .25;
        $('.masked-img' + getId + ' #renderImage').css({
            transform: 'scale('+ scale +')'
        });
    }
.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;
    }

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

    .edit:hover {
        background: white;
        color: black;
        position: absolute;
        z-index: 3;
    }

    .dark_content {
        display: none;
        position: relative;
        top: 25%;
        left: 25%;
        width: 250px;
        height: 250px;
        padding: 16px;
        border: 16px solid orange;
        background-color: white;
        z-index: 1002;
        overflow: auto;
    }
<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>

<template id='demoTemplate'>
   <span>
      <div class="btn-group">
         <button type="button" class="js-zoom-in" onclick="zoom_in(this)">Zoom In</button>
         <button type="button" class="js-zoom-out" onclick="zoom_out(this)">Zoom Out</button>
      </div>
      <img id="image" src ="" style ="display:none">
   </span>
</template>

1 Answers1

1

The problem is that you use the same var scale every time you call the functions, and every time the scale has the previous value assigned to it. So you could use an array of different scales for each element.

Create an empty array:

var scales = [];

Check if the var (for this element) exists already when you call the functions:

if (scales[getId] === undefined) {
    scales[getId] = 1.25;
} else {
    scales[getId] += 0.25;  
}

and

if (scales[getId] === undefined) {
    scales[getId] = 0.75;
} else {
    scales[getId] -= 0.25;  
}

Full code:

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

let jsonData = {
  "layers": [{
    "x": 0,
    "height": 612,
    "layers": [{
        "x": 160,
        "src": "ax0HVTs.png",
        "y": 291,
        "height": 296,
        "width": 429,
        "name": "mask_1"
      },
      {
        "x": 25,
        "src": "hEM2kEP.png",
        "height": 324,
        "width": 471,
        "y": 22,
        "name": "mask_2"
      }
    ],
    "y": 0,
    "width": 612
  }]
};

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

$(function() {

  // Upload image onclick mask image

  containerElement.click(function(e) {
    var res = e.target;
    target = res.id;
    // console.log(target);
    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 mask = $(".container").mask({
        imageUrl: imageUrl,

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

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

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

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

        if (($(".masked-img" + newImageLoadedId + ' #renderImage').length) === 0) {
          $('.masked-img' + newImageLoadedId).append("<img id='renderImage' style='width: 300px' src=" + imgView + ">");
        } else {
          $('#renderImage').attr('src', imgView);
        }

        //  Edit image - IGNORE this code

        if ($(".masked-img" + newImageLoadedId).length === 1) {
          $("<span class=\"pip pip" + newImageLoadedId + "\">" +
            "<a onclick='document.getElementById(\"dark" + newImageLoadedId + "\").style.display=\"block\";'><span class=\"edit edit" + newImageLoadedId + "\" >Edit </span></a>" +
            "</span>").insertAfter(".masked-img" + newImageLoadedId).css({
            "left": ImagePosition[newImageLoadedId].x + (ImagePosition[newImageLoadedId].width / 2) + "px",
            "top": ImagePosition[newImageLoadedId].y + (ImagePosition[newImageLoadedId].height / 2) + "px"
          });;
          $("<div id=\'dark" + newImageLoadedId + "\' class=\'dark_content\'>" +
            $('#demoTemplate').html() +
            "<a href=\"javascript:void(0)\" onclick=\"document.getElementById(\'dark" + newImageLoadedId + "\').style.display=\'none\'\">Close</a>" + "</div>").appendTo(".pip" + newImageLoadedId).css({
            "left": $('.edit' + newImageLoadedId).width() + 2 + "px",
            "top": "0px"
          });
        }
        //  end
      };
      counter++;
    }
  }
  json(jsonData);
}); // end of function

// Image code

(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.getImagePosition = function() {
      return {
        x: settings.x,
        y: settings.y,
        scale: settings.scale
      };
    };

    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;
        // console.log(image.src);
        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 = $('#renderImage'); // new Image()
      img = new Image();
      img.setAttribute('crossOrigin', 'anonymous');
      img.src = settings.imageUrl;
      // console.log(image.src);
      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");
      settings.y = startY;
      settings.x = startX;
      // console.log(settings.y);
      // console.log(settings.x);
      prevX = prevY = 0;
      settings.imageUrl = imageUrl;
      // console.log(settings.imageUrl);
      initImage = true;
      container.updateStyle().then(renderInnerImage);
      // 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;
      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
    });
    // Edit image
    div.addClass('masked-img' + settings.id);
    // end
    return container;
  };
}(jQuery));

// zoom

var angle = 0;
var scale = 1;

var scales = [];

function zoom_in(data) {
  var getParent = data.parentElement.parentElement.parentElement;
  var getId = getParent.id.substring(getParent.id.length - 1);

  console.log(getId);

  if (scales[getId] === undefined) {
    scales[getId] = 1.25;
  } else {
    scales[getId] += 0.25;
  }

  $('.masked-img' + getId + ' #renderImage').css({
    transform: 'scale(' + scales[getId] + ')'
  });
}

function zoom_out(data) {
  var getParent = data.parentElement.parentElement.parentElement;
  var getId = getParent.id.substring(getParent.id.length - 1);
  console.log(getId);

  if (scales[getId] === undefined) {
    scales[getId] = 0.75;
  } else {
    scales[getId] -= 0.25;
  }

  $('.masked-img' + getId + ' #renderImage').css({
    transform: 'scale(' + scales[getId] + ')'
  });
}
.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;
}

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

.edit:hover {
  background: white;
  color: black;
  position: absolute;
  z-index: 3;
}

.dark_content {
  display: none;
  position: relative;
  top: 25%;
  left: 25%;
  width: 250px;
  height: 250px;
  padding: 16px;
  border: 16px solid orange;
  background-color: white;
  z-index: 1002;
  overflow: auto;
}
<input id="fileup" name="fileup" type="file" style="display:none">

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

<template id='demoTemplate'>
   <span>
    <div class="btn-group">
     <button type="button" class="js-zoom-in" onclick="zoom_in(this)">Zoom In</button>
     <button type="button" class="js-zoom-out" onclick="zoom_out(this)">Zoom Out</button>
    </div>
    <img id="image" src ="" style ="display:none">
   </span>
  </template>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js">
</script>
Αntonis Papadakis
  • 1,210
  • 1
  • 12
  • 22
  • is that work in more than two images ? if yes, great solution – Nisharg Shah Apr 29 '19 at 20:27
  • What do you mean more images? Write your html. I gave you an answer about this specific question, if you want something else please edit the question :) – Αntonis Papadakis Apr 29 '19 at 20:53
  • i m not asking this question, like if there is more than 3 mask images that work or not ? – Nisharg Shah Apr 29 '19 at 20:55
  • @ΑntonisPapadakis Thanks a lot for your valuable time, is there any way to replace `inside image by outside image` as [here](https://stackoverflow.com/questions/55902972/replace-the-inside-image-by-outside-image) –  Apr 30 '19 at 05:25
  • @NishargShah Yes, its working fine for more images : https://codepen.io/kidsdial/pen/oOOOPP –  Apr 30 '19 at 05:25