Save multiple overlapped images as single image - javascript

I have two overlapped images, here an example:
This is the HTML:
<div class='image-wrapper drag-area fade1' id='cupcategory-productname-1' style='width: 300px; top: 50%; left: 50%'>
<div class='mydiv' id='drag-fronte'>
<div id='logo-container-fronte' class='mydivheader logo'>
<img id='cupcategory-productname-fronte' name='logo-container' style='width: 300px; top: 50%; left: 50%' src='../img/esempio_logo.png' onclick='saveImageWithLogo(this)'>
</div>
</div>
<div>
<img id='cupcategory-productname-fronte-fade' src='".$file."' alt='Candia Image' style='width:100%' class='image-one'>
</div>
</div>
This code is generated by PHP.
This is the CSS:
.image-wrapper {
/*position: relative;*/
z-index: 1;
/*cursor:pointer;*/
background-size:contain;
background-repeat:no-repeat;
display:inline-block;
/*width:200px;height:140px;*/
-webkit-transition: all 100ms ease-in;
-moz-transition: all 100ms ease-in;
transition: all 100ms ease-in;
-webkit-filter: brightness(1) grayscale(.5) opacity(1);
-moz-filter: brightness(1) grayscale(.5) opacity(1);
filter: brightness(1) grayscale(.5) opacity(1);
}
.image-wrapper .image-one {
/*border: 1px solid black;*/
/*position: relative;*/
width: 100%;
}
.image-wrapper .image-fronte {
/*width:151px;height:113px;*/
/*width: 15%; height: 15%;*/
/*width: 65px; height: 65px;*/
/*border: 1px solid black;*/
position: absolute;
top: 53%;
left: 50%;
transform: translate(-50%, 0);
}
.image-wrapper .logo {
/*width:151px;height:113px;*/
/*width: 15%; height: 15%;*/
/*width: 65px; height: 65px;*/
/*border: 1px solid black;*/
position: absolute;
top: 53%;
left: 50%;
transform: translate(-50%, 0);
}
.mydiv {
top: 50%;
left: 50%;
position: absolute;
z-index: 9;
text-align: center;
/*border: 1px solid #d3d3d3;*/
}
.mydivheader {
padding: 10px;
height: 100px;
width: 100px;
cursor: pointer;
z-index: 10;
/*border: 1px solid black;*/
}
And this is the JS:
function saveImageWithLogo(web_element)
{
var c=document.getElementById("myCanvas");
var image1 = web_element;
var image2 = document.getElementById(web_element.id + '-fade');
console.log(image2);
var ctx=c.getContext("2d");
var imageObj1 = new Image();
var imageObj2 = new Image();
imageObj1.src = image1.src;
imageObj1.onload = function() {
ctx.drawImage(imageObj1, 0, 0, 100, 100);
imageObj2.src = image2.src;
imageObj2.onload = function() {
ctx.drawImage(imageObj2, 0, 0, 300, 300);
var img = c.toDataURL("image/png");
image1.src = img;
//document.write('<img src="' + img + '" width="328" height="526"/>');
}
};
}
The image1 is the cup and it comes from my server, the image2 is the overlapped image that should be the logo of my user. Now, the scenario is this: The user sees the cup, upload his logo and wants to go ahead buying this cup with his logo. My problem is to show this Cup with logo on it in the recap page but I also need to save it on server because other reasons.
How can I do? I tryed with canvas drawing two images starting from coords 0, 0 but image2 cover the image1.
Edit
I've tried to do this:
var image_wrapper = document.getElementsByClassName('image-wrapper')[0];
console.log(image_wrapper);
html2canvas(image_wrapper, {
onrendered: function (canvas) {
console.log('saving...');
console.log(canvas);
var myImg = new Image();
myImg.src = canvas.toDataURL();
document.getElementById("gardenia-mug-fronte-fade").appendChild(myImg);
$('#hidden_input').val(myImg.src);
},
});
But anything happens, the function doesn't start. What I wrong?
Edit 2
Ok now I've solved in this way:
var image_wrapper = document.getElementsByClassName('image-wrapper')[0];
console.log(image_wrapper);
html2canvas(image_wrapper).then(function(canvas) {
console.log(canvas);
var myImg = new Image();
myImg.src = canvas.toDataURL();
document.getElementById("gardenia-mug-fronte-fade").appendChild(myImg);
$('#hidden_input').val(myImg.src)
});
But what I get is a white image. I need to get both images within the div with 'image-wrapper' class, of course I've to get them as shown in the above picture

I did that before with a friend, but idid the part of uploading the user image, then capture it as base:64 new image, and he was responsible for storing the output in the server.
i used html2canvas
a nice javascript library to capture any html content into an image, and it has a lot of good options
and that was an example of what the logic we did : -
capture the html content
then save it as base:64
print the image link inside a hidden input
user can submit the form, finally u receive that data
and here a piece of code i made for capture the image and print the output link inside hidden input
html2canvas($('.imgs_wrapper'), {
onrendered: function (canvas) {
var myImg = new Image();
myImg.src = canvas.toDataURL();
document.getElementById("image_reply").appendChild(myImg);
$('.hidden_input').val(myImg.src)
},
});

Related

How can i disappear my popup when my condition satisfies?

I have made a popup whenever the image was not loaded but the problem scenario was, I am getting my popup even the image is loaded for the first time. So, I need to refresh it for disappearing it. How can I resolve it?
enter image description here
The problem is that I have included the condition to check the image is loaded or not after the code of popup .so for the first time the popup was appearing even it satisfies the condition.
Help me out of it.
You should edit your question so as to include your code, so your problem is reproducible.
You can store your image as a variable and pass a function that hides your pop-up once the image is loaded.
var img1 = document.createElement("img");
img1.onload = function() {
document.getElementById("**popup_ID").style.display='none';
};
img1.src = "**your_image_path**"; //Edit suggested by #vanowm
Change "your_image_path" and "popup_ID" to match your code.
Image has complete property that would tell if it finished loading or not. You can use that to show/hide popup on startup.
However to detect if image was successfully loaded or error occur, you'd need setup event listeners.
Here is a little example that does that:
let timer;
const elLoadGood = document.getElementById("loadGood"),
elLoadBad = document.getElementById("loadBad"),
elPopup = document.getElementById("popup"),
elImg = document.getElementById("myimage"),
imgSrc = "https://cdn.spacetelescope.org/archives/images/publicationjpg/heic1502a.jpg?";
//set event handlers
elImg.onload = imageOnLoad;
elImg.onerror = imageOnError;
//load image
imageLoad(imgSrc);
elLoadGood.addEventListener("click", e=>
{
//hide image
elImg.removeAttribute("src");
//load image
imageLoad(imgSrc + Date());
});
elLoadBad.addEventListener("click", e=>
{
//hide image
elImg.removeAttribute("src");
//load image
imageLoad(Date());
});
function imageLoad(src)
{
elPopup.classList.add("loading");
elImg.classList.remove("error");
elPopup.firstChild.textContent = "loading... please wait";
//show popup
imageFinished({});
//load image
elImg.src = src;
}
function imageFinished(img)
{
//check if image finished loading
if (img.complete)
{
elPopup.firstChild.textContent = "Finished loading. Close popup in 2 seconds";
elPopup.classList.remove("loading");
}
clearTimeout(timer);
//hide popup
timer = setTimeout(() => elPopup.classList.toggle("hidden", !!img.complete), ~~img.complete * 2000);
}
function imageOnLoad(e)
{
e.target.classList.remove("error");
imageFinished(e.target);
}
function imageOnError(e)
{
e.target.classList.add("error");
imageFinished(e.target);
}
div.img
{
position: absolute;
left: 0;
top: 0;
line-height: 100vh;
text-align: center;
width: 100%;
z-index: -2;
}
img
{
vertical-align: middle;
max-height: 100%;
max-width: 100%;
}
img.error
{
animation: error infinite 1s ease-in-out alternate;
padding: 1em;
border-radius: 100%;
}
#popup
{
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
line-height: 100vh;
text-align: center;
z-index: -1;
background-color: transparent;
opacity: 1;
transition: background-color 1s, opacity .5s;
}
#popup>span
{
background-color: #ffffff7f;
color: black;
border: 1px solid;
padding: 1em;
}
#popup.loading
{
background-color: #0000007f;
}
#popup:not(.hidden) ~ *
{
filter: blur(5px);
}
#popup.loading ~ *
{
filter: blur(10px);
}
#popup.loading>span::before
{
content: "🗘";
width: 1em;
height: 1em;
line-height: 1em;
vertical-align: middle;
text-align: center;
animation: rotate infinite 1s linear;
display: inline-block;
}
#popup.hidden
{
opacity: 0;
}
#keyframes rotate {
from {transform: rotate(0deg);}
to {transform: rotate(360deg);}
}
#keyframes error {
to {box-shadow: 0 0 30px 0 red}
from {box-shadow: 0 0 1px 0 red}
}
<button id="loadGood">load good image</button>
<button id="loadBad">load bad image</button>
<div id="popup" class="hidden"><span></span></div>
<div class="img"><img id="myimage"></div>

Dynamically assign background of div to blend in with background of body

I have a grid of divs, each of which rotate to reveal another div. Currently the "front" divs have no background, but this makes the transition pretty bad (nothing happens, text goes away, backface is revealed). I'd like to assign them a background based on the portion of background they cover so that they will blend in but change when rotating. I'm not sure how to get the correct location of the background image.
HTML:
<section class='grid-1'>
<div class='day-1'>
<label>
<div class='door'>
<div class='front'>1</div>
<div class='back'></div>
</div>
</label>
</div>
</section>
CSS:
body{
background: url(...) no-repeat top center;
background-size: cover;
}
.day-1 .front{
background: url(...) no-repeat var(--offset-x) var(--offset-y);
}
JavaScript:
const setBgTest = () => {
const img = new Image();
img.src = [...];
const days = document.getElementsByClassName('day-1');
const day = days[0];
const dayRect = day.getBoundingClientRect();
const bodyRect = document.body.getBoundingClientRect();
const offX = ((dayRect.x-bodyRect.x)/document.body.clientWidth)*img.naturalWidth;
const offY = ((dayRect.y-bodyRect.y)/document.body.clientHeight)*img.naturalHeight;
}
setBgTest();
(This will be turned into a loop for all days and invoked on window resize)
This doesn't work, but I'm not sure how to calculate the correct offsets.
Updated: Calculates percentage offset within body and uses that percentage of original image size. It's close, but not quite right.
New answer
Well, you just added background-size: cover, so it's now clear your background size is dynamic. Since javascript can't know directly the size of the background you have to mimic the cover behaviour yourself, this can be achieved with the following steps:
download the original image through javascript to know its original size;
compute the scaling to let the image fit in the window;
apply the scaling to all the doors background along with the offset as in my previous answer.
Here is the full code:
$(function() {
var background = $('body');
var bgImg = background.css('background-image').replace(/^url\(['"](.+)['"]\)/, '$1');
const img = new Image();
$(img).load(function() {
var resizeHandler = function() {
var bgw = window.innerWidth;
var bgh = bgw * img.height / img.width;
background.css('background-size', bgw+'px '+bgh+'px');
var bgPos = background.offset();
bgPos.left -= parseInt(background.css('marginLeft'), 10);
bgPos.top -= parseInt(background.css('marginTop'), 10);
$('.day-1 .front').each(function() {
var elem = $(this);
var pos = elem.offset();
var x = pos.left - bgPos.left;
var y = pos.top - bgPos.top;
elem.css('background-position', (-x)+'px '+(-y)+'px');
elem.css('background-size', bgw+'px '+bgh+'px');
});
};
$(window).resize(resizeHandler);
resizeHandler();
});
img.src = bgImg;
});
body {
background: url('https://i.ibb.co/d2DJp02/wallpaper-2.jpg') no-repeat left top;
background-size: cover;
position: relative;
}
.door {
border: 1px solid #ff0000;
position: relative;
width: 60px;
height: 120px;
}
.door>div {
position: absolute;
width: 60px;
height: 120px;
}
.day-1 {
position: absolute;
left: 80px;
top: 90px;
}
.day-1 .front {
background: url('https://i.ibb.co/d2DJp02/wallpaper-2.jpg') no-repeat;
color: red;
text-align: center;
font-size: x-large;
font-weight: bold;
border: 1px solid black;
}
.door:hover .front {
transform-origin: top left;
transform: rotateY(85deg);
transition: transform .8s ease-in-out;
}
.day-1 .back {
background: black url('https://i.ibb.co/rZW5T2v/dog.jpg') no-repeat center center;
background-size: contain;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<section class='grid-1'>
<div class='day-1'>
<label>
<div class='door'>
<div class='back'></div>
<div class='front'>1</div>
</div>
</label>
</div>
</section>
Old answer
I've arranged this code using jquery, but you can rewrite using pure javascript. You can use the "offset" method to know where an element is within the document. If you subtract the door coordinates from the main element (the one which contains the whole background) coordinates, then you get the relative coordinates. Then just apply them as negative background-position:
$(function() {
var background = $('.grid-1');
var bgPos = background.offset();
var elem = $('.day-1 .front');
var elemPos = elem.offset();
var relPos = {left: elemPos.left - bgPos.left, top: elemPos.top - bgPos.top};
elem.css('background-position', (-relPos.left)+'px '+(-relPos.top)+'px');
});
.grid-1 {
height: 300px;
background: url('https://i.ibb.co/d2DJp02/wallpaper-2.jpg') no-repeat left top;
background-size: 400px 300px;
position: relative;
}
.door {
border: 3px solid #ff0000;
position: relative;
width: 60px;
height: 120px;
}
.door>div {
position: absolute;
width: 60px;
height: 120px;
}
.day-1 {
position: absolute;
left: 80px;
top: 90px;
}
.day-1 .front {
background: url('https://i.ibb.co/d2DJp02/wallpaper-2.jpg') no-repeat;
background-size: 400px 300px;
color: red;
text-align: center;
font-size: x-large;
font-weight: bold;
border: 1px solid black;
}
.door:hover .front {
transform-origin: top left;
transform: rotateY(85deg);
transition: transform .8s ease-in-out;
}
.day-1 .back {
background: url('https://i.ibb.co/rZW5T2v/dog.jpg') no-repeat center center;
background-size: contain;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<section class='grid-1'>
<div class='day-1'>
<label>
<div class='door'>
<div class='back'></div>
<div class='front'>1</div>
</div>
</label>
</div>
</section>

"Drop Zones" with Fabric.js?

Is there a way to create a "drop zone" like that of interact.js using fabric.js?
I haven't necessarily tried anything. I have my ideas as to how I would try to implement it, but thought I'd ask around and search the web for help, so I don't have to invent something if it's been done. I've searched on Google with no success.
*Note: I am trying to stay away from adding another library, especially if I am only going to use it to accomplish one thing in functionality, so yes, I could just use interact.js, but I'd rather not store or reference another library if at all possible.
Answer:
For those who are looking for a possible solution to this... It could be implemented via isContainedWithinObject(other, absoluteopt, calculateopt) → {Boolean}... I found this after reading the documentation on fabric.js.
You can use a classic input method and style it like a dropzone with css. See snippet below.
var canvas = new fabric.Canvas('canvas');
canvas.setHeight(300);
canvas.setWidth(400);
document.querySelector("#pdf-upload").addEventListener("change", function(e) {
var file = e.target.files[0]
if (file.type == "image/jpeg" || "image/png") {
var reader = new FileReader();
reader.onload = function(event) {
var data = event.target.result;
fabric.Image.fromURL(data, function(image) {
var imageObject = image;
canvas.setBackgroundImage(imageObject);
imageObject.scaleToHeight(300);
canvas.renderAll();
});
};
reader.readAsDataURL(file);
};
$("#canvas").css("visibility", "visible");
$(".dz").css("visibility", "hidden");
});
.dz-text {
position: absolute;
left: 50%;
margin-left: -100px;
top: 50%;
width: 200px;
text-align: center;
}
.dz-button {
position: absolute;
top: 50%;
margin-top: -50px;
left: 50%;
z-index: 3;
margin-left: -150px;
width: 300px;
position: absolute;
padding: 120px 0 0 0;
height: 100px;
overflow: hidden;
border: dotted 5px black;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
border-radius: 20px;
background-size: 60px 60px;
background-color: rgba(155, 105, 255, 0.2);
background-clip: padding-box;
}
.dz-button:hover {
background-color: rgba(155, 105, 255, 0.3);
}
#canvas {
border: solid 1px black;
z-index: 1;
visibility: hidden;
}
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/3.4.0/fabric.js"></script>
</head>
<body>
<div class="dz">
<div class="dz-text"><b>Drop image here</b></div>
<input class="dz-button" id="pdf-upload" type="file">
</div>
<canvas id="canvas"></canvas>
</body>
</html>

Save the original image + draggable blur mask applied to it

I was wondering if there is any way to save image original + Draggable blur mask over image
Here is an example of a draggable blur mask over the image : https://codepen.io/netsi1964/pen/AXRabW
$(function() {
$("#mask").draggable({
containment: "parent"
});
});
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
#mask {
width: 50px;
height: 50px;
border-radius: 100%;
overflow: hidden;
position: absolute;
top: calc(50% - 25px);
left: calc(50% - 25px);
}
#unblurred {
position: absolute;
top: 0;
left: 0;
z-index: 999;
width: 100%;
height: 100%;
overflow: hidden;
-webkit-filter: blur(0px);
}
#unblurred img {
position: fixed;
left: 0;
top: 0;
}
#blurred {
-webkit-filter: blur(20px);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
<div id="mask">
<div id="unblurred">
<img src="https://i.ytimg.com/vi/LRVsxe5OJVY/maxresdefault.jpg">
</div>
</div>
<img id="blurred" src="https://i.ytimg.com/vi/LRVsxe5OJVY/maxresdefault.jpg">
Wanted to save image with draggable blur mask over image... Maybe using canvas or something of the type
I think that I have a some what working solution, here is the JS code:
function saveMask() {
$("#blurred").hide()
html2canvas(document.querySelector("#mask"), {allowTaint: true}).then(h2c => {
var pos = $("#mask")[0].getBoundingClientRect();
$("#mask").hide()
var image = document.getElementById('blurred');
var canvas = document.createElement("canvas");
canvas.height = image.height;
canvas.width = image.width;
var ctx = canvas.getContext('2d')
ctx.filter = 'blur(20px)'
ctx.drawImage(image, 0, 0);
ctx.filter = 'none'
ctx.drawImage(h2c, pos.x, pos.y);
document.body.appendChild(canvas);
});
}
My idea here is to get as the mask using html2canvas and then we create a canvas with the blurred image and "paste" the mask on top of that.
I have a fully functional example here:
https://raw.githack.com/heldersepu/hs-scripts/master/HTML/html2canvas.html

Create several new Image() objects with dynamic src javascript

I'm appending a large image when it's done loading and fading it in which all works well. My problem is when there is more than one image. Then it's only the last small image that get replaced (with the first image). I can't seem to figure out how to separate them. The src URLs are retrieved trough a data-attribute. Codepen with two images. (with one image it works as intended).
window.onload = function() {
var ImageBlur = function (element) {
var self = this;
this.element = element;
this.$element = $(element);
};
var placeholder = $('.js-image-blur', this.$element);
var small = $('.js-small-image', placeholder);
// Load large image
var imgLarge = new Image();
imgLarge.src = placeholder.data('largeimage');
imgLarge.className = "is-large-image";
imgLarge.onload = function () {
$(imgLarge).addClass('is-loaded');
// Remove small image
setTimeout(function(){
$(small).remove();
}, 1200);
};
$(imgLarge).each(function() {
placeholder.append(this);
});
return ImageBlur;
};
I would rewrite the code like that:
$(function() {
$(".js-image-blur").each(function() {
var $this = $(this);
var $smallImage = $(".js-small-image", $this);
var $largeImage = $("<img>").attr({
src: $this.data("largeimage"),
class: "is-large-image"
}).load(function() {
$(this).addClass("is-loaded");
setTimeout(function() {
$smallImage.remove();
}, 1200);
});
$this.append($largeImage);
});
});
.image-blur {
background-color: transparent;
background-size: cover;
background-repeat: no-repeat;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
overflow: hidden;
}
.image-blur img {
position: absolute;
top: 50%;
left: 50%;
min-height: 100%;
width: auto;
min-width: 100%;
transition: opacity 1s linear;
-ms-transform: translate(-50%, -50%);
-webkit-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
}
.image-blur img.small-image {
-webkit-filter: blur(20px);
filter: blur(20px);
position: absolute;
}
.image-blur img.is-large-image {
opacity: 0;
}
.image-blur img.is-loaded {
opacity: 1;
}
body {
margin: 3em 0;
background: silver;
}
.container {
position: relative;
margin: 3em auto;
min-width: 320px;
min-height: 560px;
border-top: 3px solid black;
border-bottom: 3px solid black;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<section class="container">
<div class="image-blur js-image-blur" data-component="image-blur" data-largeimage="https://s3-us-west-2.amazonaws.com/s.cdpn.io/67710/1600-full.jpg">
<img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/67710/1600-small.jpg" alt="" class="small-image js-small-image" />
</div>
</section>
<section class="container">
<div class="image-blur js-image-blur" data-component="image-blur" data-largeimage="https://s3-us-west-2.amazonaws.com/s.cdpn.io/67710/1600-2-full.jpg">
<img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/67710/1600-2-small.jpg" alt="" class="small-image js-small-image" />
</div>
</section>
See updated Codepen.
If you want to load images silently and fade them in, a simple solution would be:
<img class="load-fade" src="url" />
And in your JavaScript:
$('.load-fade').hide().load(function() {
$(this).fadeIn(1000);
});

Categories