单scale变量下多图片独立缩放问题的动态解决方案问询
Hey there! The core issue here is that you're relying on a single global scale variable that's shared across both images. When you zoom one image, it updates this global value—so when you interact with the second image, it uses that same modified scale, causing the unwanted syncing.
Here's a dynamic fix that doesn't require creating separate static variables for each image. We'll use jQuery's data() method to store each image's unique scale value directly on its own DOM element, keeping everything tied to the image it belongs to:
Key Modifications Explained
- Remove the global
scalevariable – we no longer need it since each image will track its own scale. - Initialize per-image scale data – when loading a new image, set an initial scale value of
1stored in the image'sdataattributes. - Update zoom functions to use element-specific scale – in
zoom_inandzoom_out, retrieve the current scale from the target image's data, modify it, save it back, then apply the transform.
Modified Full Code
<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> <script> 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 + ">"); // Initialize scale data for the new image $('.masked-img' + newImageLoadedId + ' #renderImage').data('scale', 1); } else { $('#renderImage').attr('src', imgView); // Reset scale when replacing the image $('#renderImage').data('scale', 1); } // 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; function zoom_in(data) { var getParent = data.parentElement.parentElement.parentElement; var getId = getParent.id.substring(getParent.id.length - 1); var $img = $('.masked-img' + getId + ' #renderImage'); // Get current scale (default to 1 if not set) var currentScale = $img.data('scale') || 1; currentScale += .25; // Save updated scale back to the image $img.data('scale', currentScale); $img.css({ transform: 'scale('+ currentScale +')' }); } function zoom_out(data) { var getParent = data.parentElement.parentElement.parentElement; var getId = getParent.id.substring(getParent.id.length - 1); var $img = $('.masked-img' + getId + ' #renderImage'); var currentScale = $img.data('scale') || 1; // Prevent scale from dropping below 0.25 to avoid invisible images currentScale = Math.max(0.25, currentScale - .25); $img.data('scale', currentScale); $img.css({ transform: 'scale('+ currentScale +')' }); } </script> <style> .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; } </style>
Now each image will maintain its own independent scale value, so zooming one won't affect the other. We also added a check in zoom_out to prevent the scale from going too low (0.25 minimum) so the image doesn't disappear entirely.
内容的提问来源于stack exchange,提问作者user8444404




