问题
User click on Mask & upload the image....
Its displaying same image two times, also Edit Text is displaying on image....
Once user click on Edit Text, we are displaying pop up box....
There we can see Zoomin & Zoomout buttons are displaying....
Issue :
Once we click on those buttons, its zooming the outside image, but not the inside image....
Requirement :
So I want to replace the Inside image by outside image & Delete the Inside image , so that zoom feature will work for uploaded image....
codepen : https://codepen.io/kidsdial/pen/OGGyYd
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:
You can replace your whole canvas code with CSS, so you will be able to use transform: scale(2)
with image inside mask:
var img = document.querySelector('img');
var zoom = 1;
document.querySelector('#zoom_in').addEventListener('click', function(e) {
zoom += 0.2;
img.style.transform = 'scale(' + zoom +')';
});
document.querySelector('#zoom_out').addEventListener('click', function(e) {
zoom -= 0.2;
img.style.transform = 'scale(' + zoom +')';
});
.clip {
-webkit-mask-image: url(https://i.imgur.com/ax0HVTs.png);
-webkit-mask-repeat: no-repeat;
mask-image: url(https://i.imgur.com/ax0HVTs.png);
mask-repeat: no-repeat;
mask: url(https://i.imgur.com/ax0HVTs.png);
}
<div class="clip">
<img src="http://placekitten.com/500/300"/>
</div>
<button id="zoom_in">+</button>
<button id="zoom_out">-</button>
Tested only in Chrome, if you want more browsers support you would probably need to investigate what are prefixes and how Cross-Browser code look like (if you can find it you can ask question about "cross browser CSS mask" it one is outdated Cross-browser clipping masks old and there're no good answers).
This article show more info about clip-path and mask https://css-tricks.com/clipping-masking-css/
This solution will not work in every browser (here is support https://caniuse.com/#feat=css-masks) but it may be of some use.
If you would like to make it with canvas it more complex and I don't think this is the right place to ask, you can probably hire someone to update the mask plugin for you to add support for zoom (because it need to be done in zoom plugin, maybe something like scale image on canvas and then apply the mask, Sorry didn't check how the mask plugin exactly work).
EDIT: this should create css file for files in directory:
const {promisify} = require('util');
const fs = require('fs');
const readFileAsync = promisify(fs.readFile);
const statAsync = promisify(fs.stat);
const writeFileAsync = promisify(fs.writeFile);
readFileAsync('./masks').then(async (data) =>
var css = [];
for (let file of data) {
const stat = await statAsync(file);
if (stat.isFile()) {
css.push(`.mask_${i} {
-webkit-mask-image: url(${file});
-webkit-mask-repeat: no-repeat;
mask-image: url(${file});
mask-repeat: no-repeat;
mask: url(${file});
}`);
}
}
await writeFileAsync('masks.css', css.join('\n'));
console.log(`css file written ${css.length} rules`);
});
来源:https://stackoverflow.com/questions/55902972/replace-the-inside-image-by-outside-image