I am creating the script to show the preview of uploaded image on client side with the option to remove it.
I have done all of this but the problem with the UI part the position of close icon is not top-right aligned.
Here is the code and the JSfiddle link, to test it on JSfiddle add the image by browse button.
jQuery(function($) {
$('div').on('click', '.closeDiv', function() {
$(this).prev().remove();
$(this).remove();
$('#upload-file').val("");
});
var fileInput = document.getElementById("upload-file");
fileInput.addEventListener("change", function(e) {
var filesVAR = this.files;
showThumbnail(filesVAR);
}, false);
function showThumbnail(files) {
var file = files[0]
var $thumbnail = $('#thumbnail').get(0);
var $image = $("<img>", {
class: "imgThumbnail"
});
var $pDiv = $("<div>", {
class: "divThumbnail",
style: "float: left"
});
var $div = $("<div>", {
class: "closeDiv",
style: "float: right"
}).html('X');
$pDiv.append($image, $div).appendTo($thumbnail);
var reader = new FileReader()
reader.onload = function(e) {
$image[0].src = e.target.result;
}
var ret = reader.readAsDataURL(file);
var canvas = document.createElement("canvas");
ctx = canvas.getContext("2d");
$image.on('load', function() {
ctx.drawImage($image[0], 100, 100);
})
}
});
img {
width: 30%;
float: left;
height: 100px;
width: 100px;
}
.closeDiv {
width: 20px;
height: 21px;
background-color: rgb(35, 179, 119);
float: left;
cursor: pointer;
color: white;
box-shadow: 2px 2px 7px rgb(74, 72, 72);
text-align: center;
margin: 5px;
}
.pDiv {
float: left;
width: 100%
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.2/jquery.min.js"></script>
<div id="thumbnail"></div>
<input type="file" id="upload-file" accept="image/*" />
http://jsfiddle.net/r0taz01L/11/
You need to give
.divThumbnail {
position: relative;
}
and closeDiv to this style
.closeDiv {
position: absolute;
width: 20px;
height: 21px;
background-color: rgb(35, 179, 119);
float: right;
cursor: pointer;
color: white;
box-shadow: 2px 2px 7px rgb(74, 72, 72);
text-align: center;
margin: 5px;
right:0px;
}
here is completed solutions
http://jsfiddle.net/r0taz01L/12/
Related
I have JS code on a webpage that loads questions in from mysql db and displays the text . What happens is that it cuts off words at the end of the line and continues the word on the next line at the start. So all text across the screen starts/ends at the same point.
This seems to be the code where it displays the text.
For example the text will look like at the end of a line 'cont' and then on next line at the start 'inue'.
How do i fix this?
var questions = <?=$questions;?>;
// Initialize variables
//------------------------------------------------------------------
var tags;
var tagsClass = '';
var liTagsid = [];
var correctAns = 0;
var isscorrect = 0;
var quizPage = 1;
var currentIndex = 0;
var currentQuestion = questions[currentIndex];
var prevousQuestion;
var previousIndex = 0;
var ulTag = document.getElementsByClassName('ulclass')[0];
var button = document.getElementById('submit');
var questionTitle = document.getElementById('question');
//save class name so it can be reused easily
//if I want to change it, I have to change it one place
var classHighlight = 'selected';
// Display Answers and hightlight selected item
//------------------------------------------------------------------
function showQuestions (){
document.body.scrollTop = 0; // For Safari
document.documentElement.scrollTop = 0; // For Chrome, Firefox, IE and Opera
if (currentIndex != 0) {
// create again submit button only for next pages
ulTag.innerHTML ='';
button.innerHTML = 'Submit';
button.className = 'submit';
button.id = 'submit';
if(quizPage<=questions.length){
//update the number of questions displayed
document.getElementById('quizNumber').innerHTML = quizPage;
}
}
//Display Results in the final page
if (currentIndex == (questions.length)) {
ulTag.innerHTML = '';
document.getElementById('question').innerHTML = '';
if(button.id == 'submit'){
button.className = 'buttonload';
button.innerHTML = '<i class="fa fa-spinner fa-spin"></i>Loading';
}
showResults();
return
}
questionTitle.innerHTML = "Question No:" + quizPage + " "+currentQuestion.question.category_name +"<br/>"+ currentQuestion.question.text;
if(currentQuestion.question.filename !== ''){
var br = document.createElement('br');
questionTitle .appendChild(br);
var img = document.createElement('img');
img.src = currentQuestion.question.filename;
img.className = 'imagecenter';
img.width = 750;
img.height = 350;
questionTitle .appendChild(img);
}
// create a for loop to generate the options and display them in the page
for (var i = 0; i < currentQuestion.options.length; i++) {
// creating options
var newAns = document.createElement('li');
newAns.id = 'ans'+ (i+1);
newAns.className = "notSelected listyle";
var textAns = document.createTextNode(currentQuestion.options[i].optiontext);
newAns.appendChild(textAns);
if(currentQuestion.options[i].file !== ''){
var br = document.createElement('br');
newAns .appendChild(br);
var img1 = document.createElement('img');
img1.src = currentQuestion.options[i].file;
img1.className = 'optionimg';
img1.width = 250;
img1.height = 250;
newAns .appendChild(img1);
newAns .appendChild(br);
}
var addNewAnsHere = document.getElementById('options');
addNewAnsHere.appendChild(newAns);
}
//.click() will return the result of $('.notSelected')
var $liTags = $('.notSelected').click(function(list) {
list.preventDefault();
//run removeClass on every element
//if the elements are not static, you might want to rerun $('.notSelected')
//instead of the saved $litTags
$liTags.removeClass(classHighlight);
//add the class to the currently clicked element (this)
$(this).addClass(classHighlight);
//get id name of clicked answer
for (var i = 0; i < currentQuestion.options.length ; i++) {
// console.log(liTagsid[i]);
if($liTags[i].className == "notSelected listyle selected"){
//store information to check answer
tags = $liTags[i].id;
// tagsClass = $LiTags.className;
tagsClassName = $liTags[i];
}
}
});
//check answer once it has been submitted
button.onclick = function (){
if(button.id == 'submit'){
button.className = 'buttonload';
button.innerHTML = '<i class="fa fa-spinner fa-spin"></i>Loading';
}
setTimeout(function() { checkAnswer(); }, 100);
};
}
//self calling function
showQuestions();
The website is on my local now but i can upload a screenimage if need be and the whole code of the webpage. Or is the issue in html?
edit: here is html/css code
<style>
/*========================================================
Quiz Section
========================================================*/
/*styling quiz area*/
.main {
background-color: white;
margin: 0 auto;
margin-top: 30px;
padding: 30px;
box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.2), 0 5px 5px 0 rgba(0, 0, 0, 0.24);
/*white-space: nowrap;*/
}
/*Editing the number of questions*/
.spanclass {
font-size: x-large;
}
#pages{
border: 3px solid;
display: inline-flex;
border-radius: 0.5em;
float: right;
}
#question{
word-break: break-all;
}
/*format text*/
p {
text-align: left;
font-size: x-large;
padding: 10px 10px 0;
}
.optionimg{
border: 2px solid black;
border-radius: 1.5em;
}
/*Form area width*/
/*formatting answers*/
.listyle {
list-style-type: none;
text-align: left;
background-color: transparent;
margin: 10px 5px;
padding: 5px 10px;
border: 1px solid lightgray;
border-radius: 0.5em;
font-weight: normal;
font-size: x-large;
display: inline-grid;
width: 48%;
height: 300px;
overflow: auto;
}
.listyle:hover {
background: #ECEEF0;
cursor: pointer;
}
/*Change effect of question when the questions is selected*/
.selected, .selected:hover {
background: #FFDEAD;
}
/*change correct answer background*/
.correct, .correct:hover {
background: #9ACD32;
color: white;
}
/*change wrong answer background*/
.wrong, .wrong:hover {
background: #db3c3c;
color: white;
}
/*========================================================
Submit Button
========================================================*/
.main button {
text-transform: uppercase;
width: 20%;
border: none;
padding: 15px;
color: #FFFFFF;
}
.submit:hover, .submit:active, .submit:focus {
background: #43A047;
}
.submit {
background: #4CAF50;
min-width: 120px;
}
/*next question button*/
.next {
background: #fa994a;
min-width: 120px;
}
.next:hover, .next:active, .next:focus {
background: #e38a42;
}
.restart {
background-color:
}
/*========================================================
Results
========================================================*/
.circle{
position: relative;
margin: 0 auto;
width: 200px;
height: 200px;
background: #bdc3c7;
-webkit-border-radius: 100px;
-moz-border-radius: 100px;
border-radius: 100px;
overflow: hidden;
}
.fill{
position: absolute;
bottom: 0;
width: 100%;
height: 80%;
background: #31a2ac;
}
.score {
position: absolute;
width: 100%;
top: 1.7em;
text-align: center;
font-family: Arial, sans-serif;
color: #fff;
font-size: 40pt;
line-height: 0;
font-weight: normal;
}
.circle p {
margin: 400px;
}
/*========================================================
Confeeti Effect
========================================================*/
canvas{
position:absolute;
left:0;
top:11em;
z-index:0;
border:0px solid #000;
}
.imagecenter{
display: block;
margin: 0 auto;
}
.buttonload {
background-color: #04AA6D; /* Green background */
border: none; /* Remove borders */
color: white; /* White text */
padding: 12px 24px; /* Some padding */
font-size: 16px; /* Set a font-size */
}
/* Add a right margin to each icon */
.fa {
margin-left: -12px;
margin-right: 8px;
}
#media only screen and (max-width: 900px){
.listyle {
width: 100% !important;
height: auto !important;
}
.imagecenter {
width: 100% !important;
}
.listyle img{
width: inherit !important;
height: unset !important;
}
.ulclass
{
padding:0px !important;
}
}
</style>
<!-- Main page -->
<div class="main">
<!-- Number of Question -->
<div class="wrapper" id="pages">
<span class="spanclass" id="quizNumber">1</span><span class="spanclass">/<?=$count?></span>
</div>
<!-- Quiz Question -->
<div class="quiz-questions" id="display-area">
<p id="question"></p>
<ul class="ulclass" id="options">
</ul>
<div id="quiz-results" class="text-center">
<button type="button" name="button" class="submit" id="submit">Submit</button>
</div>
</div>
</div>
<canvas id="canvas"></canvas>
<script src="https://code.jquery.com/jquery-3.2.1.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script>
I'm guessing that #question{ word-break: break-all; } is probably the culprit then? –
CB..yes that fixed it:)
I have 10 links and each of them is different from the others.I want when user hovers on them background image of the div changes and a tooltip text be shown on top of the links with a fade-in animation .
i have tried to make several functions using JS and it works but it's a lot of code and mostly repetitive.I want a good shortcut through all of that useless coding.
document.getElementById("d1").onmouseover = function() {
mouseOver1()
};
document.getElementById("d2").onmouseover = function() {
mouseOver2()
};
document.getElementById("d3").onmouseover = function() {
mouseOver3()
};
document.getElementById("d1").onmouseout = function() {
mouseOut1()
};
document.getElementById("d2").onmouseout = function() {
mouseOut2()
};
document.getElementById("d3").onmouseout = function() {
mouseOut3()
};
function mouseOver1() {
document.getElementById("dogs").style.background = "blue";
document.getElementById("tooltiptext1").style.visibility = "visible";
}
function mouseOut1() {
document.getElementById("dogs").style.background = "black";
document.getElementById("tooltiptext1").style.visibility = "hidden";
}
function mouseOver2() {
document.getElementById("dogs").style.background = "green";
document.getElementById("tooltiptext2").style.visibility = "visible";
}
function mouseOut2() {
document.getElementById("dogs").style.background = "black";
document.getElementById("tooltiptext2").style.visibility = "hidden";
}
function mouseOver3() {
document.getElementById("dogs").style.background = "red";
document.getElementById("tooltiptext3").style.visibility = "visible";
}
function mouseOut3() {
document.getElementById("dogs").style.background = "black";
document.getElementById("tooltiptext3").style.visibility = "hidden";
}
#dogs {
float: right;
margin-top: 5%;
background: black;
width: 150px;
height: 150px;
}
#d-list {
color: white;
direction: ltr;
float: right;
width: 60%;
height: 60%;
}
#tooltiptext1,
#tooltiptext2,
#tooltiptext3 {
color: black;
background-color: gray;
width: 120px;
height: 30px;
border-radius: 6px;
text-align: center;
padding-top: 5px;
visibility: hidden;
}
<div id="animals">
<div id="dogs"></div>
<div id="d-list">
<pre style="font-size:22px; color:darkorange">dogs</pre><br />
<pre>white Husky</pre>
<p id="tooltiptext1">Tooltip text1</p>
<pre>black Bull</pre>
<p id="tooltiptext2">Tooltip text2</p>
<pre>brown Rex</pre>
<p id="tooltiptext3">Tooltip text3</p>
</div>
</div>
Please have in mind that all of links will change same outer div object and the idea is to change the background image of that div and the tooltip shoud appear on the top of the links....so,
any ideas?
edit: added animation requested.
CSS is almost always better done in script by using classes when multiple elements are being manipulated with similar functions so I used that here. Rather than put some complex set of logic in place I simply added data attributes for the colors - now it works for any new elements you wish to add as well.
I did find your markup to be somewhat strangely chosen and would have done it differently but that was not part of the question as stated.
I took the liberty of removing the style attribute from your dogs element and put it in the CSS also as it seemed to belong there and mixing markup and css will probably make it harder to maintain over time and puts all the style in one place.
Since you DID tag this with jQuery here is an example of that.
$(function() {
$('#d-list').on('mouseenter', 'a', function(event) {
$('#dogs').css('backgroundColor', $(this).data('colorin'));
$(this).parent().next('.tooltip').animate({
opacity: 1
});
}).on('mouseleave', 'a', function(event) {
$('#dogs').css('backgroundColor', $(this).data('colorout'));
$(this).parent().next('.tooltip').animate({
opacity: 0
});
});
});
#dogs {
float: right;
margin-top: 5%;
background: black;
width: 150px;
height: 150px;
}
#d-list {
color: white;
direction: ltr;
float: right;
width: 60%;
height: 60%;
}
.dog-header {
font-size: 22px;
color: darkorange;
margin-bottom: 2em;
}
.tooltip {
color: black;
background-color: gray;
width: 120px;
height: 30px;
border-radius: 6px;
text-align: center;
padding-top: 5px;
opacity: 0;
position:relative;
top:-4.5em;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<div id="animals">
<div id="dogs"></div>
<div id="d-list">
<pre class="dog-header">dogs</pre>
<pre>white Husky</pre>
<p id="tooltiptext1" class="tooltip">Tooltip text1</p>
<pre>black Bull</pre>
<p id="tooltiptext2" class="tooltip">Tooltip text2</p>
<pre>brown Rex</pre>
<p id="tooltiptext3" class="tooltip">Tooltip text3</p>
</div>
</div>
Updated
This answer was written before the question was edited to show the intended markup/styling and before all the details were included. The code has been updated to work with that structure.
I think the simplest thing is just to create a configuration object to detail the varying bits, and then use common code for the rest. Here's one approach:
const configs = [
['d1', 'tooltiptext1', 'blue'],
['d2', 'tooltiptext2', 'green'],
['d3', 'tooltiptext3', 'red'],
];
configs.forEach(([id, tt, color]) => {
const dogs = document.getElementById('dogs');
const el = document.getElementById(id);
const tip = document.getElementById(tt);
el.onmouseover = (evt) => {
dogs.style.background = color
tip.style.visibility = "visible";
}
el.onmouseout = (evt) => {
dogs.style.background = "black";
tip.style.visibility = "hidden";
}
})
#dogs{float:right;margin-top:5%;background:#000;width:150px;height:150px}#d-list{color:#fff;direction:ltr;float:right;width:60%;height:60%}#tooltiptext1,#tooltiptext2,#tooltiptext3{color:#000;background-color:gray;width:120px;height:30px;border-radius:6px;text-align:center;padding-top:5px;visibility:hidden}
<div id="animals"> <div id="dogs"></div><div id="d-list"> <pre style="font-size:22px; color:darkorange">dogs</pre><br/> <pre>white Husky</pre> <p id="tooltiptext1">Tooltip text1</p><pre>black Bull</pre> <p id="tooltiptext2">Tooltip text2</p><pre>brown Rex</pre> <p id="tooltiptext3">Tooltip text3</p></div></div>
Obviously you can extend this with new rows really easily. And if you want to add more varying properties, you can simply make the rows longer. If you need to add too many properties to each list, an array might become hard to read, and it might become better to switch to {id: 'demo', tt: 'dem', color: 'blue'} with the corresponding change to the parameters in the forEach callback. (That is, replacing configs.forEach(([id, tt, color]) => { with configs.forEach(({id, tt, color}) => {.) But with only three parameters, a short array seems cleaner.
Older code snippet based on my made-up markup.
const configs = [
['demo', 'dem', 'blue'],
['dd', 'dem1', 'green']
];
configs.forEach(([id1, id2, color]) => {
const a = document.getElementById(id1)
const b = document.getElementById(id2)
a.onmouseover = (evt) => {
a.style.background = color
b.style.visibility = "visible";
}
a.onmouseout = (evt) => {
a.style.background = "black";
b.style.visibility = "hidden";
}
})
div {width: 50px; height: 50px; float: left; margin: 10px; background: black; border: 1px solid #666; color: red; padding: 10px; text-align: center}
#dem , #dem1{visibility:hidden;}
<div id="demo">demo</div>
<div id="dem">dem</div>
<div id="dd">dd</div>
<div id="dem1">dem1</div>
my way of seeing that => zero Javascript:
div[data-info] {
display: inline-block;
margin:80px 20px 0 0;
border:1px solid red;
padding: 10px 20px;
position: relative;
}
div[data-bg=blue]:hover {
background-color: blue;
color: red;
}
div[data-bg=green]:hover {
background-color: green;
color: red;
}
div[data-info]:hover:after {
background: #333;
background: rgba(0, 0, 0, .8);
border-radius: 5px;
bottom: 46px;
color: #fff;
content: attr(data-info);
left: 20%;
padding: 5px 15px;
position: absolute;
z-index: 98;
min-width: 120px;
max-width: 220px;
}
div[data-info]:hover:before {
border: solid;
border-color: #333 transparent;
border-width: 6px 6px 0px 6px;
bottom: 40px;
content: "";
left: 50%;
position: absolute;
z-index: 99;
}
<div data-info="Tooltip for A Tooltip for A" data-bg="blue">with Tooltip CSS3 A</div>
<div data-info="Tooltip for B" data-bg="green" >with Tooltip CSS3 B</div>
Please see this code . In the following code user can upload images , they can move, resize, rotate uploaded images etc .
$(function() {
var inputLocalFont = $("#user_file");
inputLocalFont.change(previewImages);
function previewImages() {
var fileList = this.files;
var anyWindow = window.URL || window.webkitURL;
for (var i = 0; i < fileList.length; i++) {
var objectUrl = anyWindow.createObjectURL(fileList[i]);
var $newDiv = $("<div>", {
class: "img-div"
});
var $newImg = $("<img>", {
src: objectUrl,
class: "newly-added"
}).appendTo($newDiv);
$(".new-multiple").append($newDiv);
$newDiv.draggable();
$newDiv.rotatable();
$newDiv.resizable({
aspectRatio: true,
handles: "ne, nw, e, se, sw, w"
});
$newDiv.find(".ui-icon").removeClass("ui-icon ui-icon-gripsmall-diagonal-se");
window.URL.revokeObjectURL(fileList[i]);
}
$(".newly-added").on("click", function(e) {
$(".newly-added").removeClass("img-selected");
$(this).addClass("img-selected");
e.stopPropagation()
});
$(document).on("click", function(e) {
if ($(e.target).is(".newly-added") === false) {
$(".newly-added").removeClass("img-selected");
}
});
}
$(".user_submit").on("click",function(e){
e.preventDefault();
html2canvas($('.new-multiple'), {
allowTaint: true,
onrendered: function(canvas) {
document.body.appendChild(canvas);
}
});
});
});
.new-multiple {
width: 400px !important;
height: 400px !important;
background: white;
border: 2px solid red;
overflow: hidden;
}
.img-div {
width: 200px;
height: 200px;
}
.newly-added {
width: 100%;
height: 100%;
}
.img-selected {
box-shadow: 1px 2px 6px 6px rgb(206, 206, 206);
border: 2px solid rgb(145, 44, 94);
}
/*
.ui-resizable-handle.ui-resizable-se.ui-icon.ui-icon-gripsmall-diagonal-se {
background-color: white;
border: 1px solid tomato;
}
*/
.ui-resizable-handle {
border: 0;
border-radius: 50%;
background-color: #00CCff;
width: 14px;
height: 14px;
}
.ui-resizable-nw {
top: -7px;
left: -7px;
}
.ui-resizable-ne {
top: -7px;
right: -7px;
}
.ui-resizable-e {
top: calc(50% - 7px);
right: -7px;
}
.ui-resizable-w {
top: calc(50% - 7px);
left: -7px;
}
.ui-resizable-sw {
bottom: -7px;
left: -7px;
}
.ui-resizable-se {
right: -7px;
bottom: -7px;
}
.ui-resizable-se.ui-icon {
display: none;
}
.ui-rotatable-handle {
background-size: 14px;
background-repeat: no-repeat;
background-position: center;
border: 0;
border-radius: 50%;
background-color: #00CCff;
margin-left: calc(50% - 9px);
bottom: -5px;
width: 18px;
height: 18px;
}
<link href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css" rel="stylesheet"/>
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<link href="https://cdn.jsdelivr.net/gh/godswearhats/jquery-ui-rotatable#1.1/jquery.ui.rotatable.css" rel="stylesheet"/>
<script src="https://cdn.jsdelivr.net/gh/godswearhats/jquery-ui-rotatable#1.1/jquery.ui.rotatable.min.js"></script>
<script src="https://html2canvas.hertzen.com/build/html2canvas.js"></script>
<form method="post" action="">
<input name="user_file[]" id="user_file" style="position: relative;overflow: hidden" multiple="" type="file">
<div class="new-multiple"></div>
<input type="submit" name="submit" class="user_submit" value="submit" />
</form>
https://jsfiddle.net/s99kxydw/15/
After uploading images , and rotate , move then the user will press submit button . That time we need to generate the screenshot of the window, so that both user and we can understand that what are the changes user done . This is our requirement .
How we can generate this screenshot ?
We found one solution . That is html2canvas https://html2canvas.hertzen.com/
But the problem is that html2canvas not support the css transform property
As the result the rotation is not coming in the screenshot . How we can over ride this . Please check the code .
is there is any other method without using html2canvas ?
I understand what your problem is as I have done a similar thing with html2canvas. The problem with it. is that it can't save everything so it may not be entirely accurate, for example it cannot do css text clipping. This is what worked for me (I had it downloading the image but you can just as easily save it check out this link for how to do that ):
html2canvas($('.classOfElementToSave'), {
allowTaint: true,
onrendered: function(canvas) {
var dataURL = canvas.toDataURL();
$.ajax({
type: "POST",
url: "script.php",
data: {
imgBase64: dataURL
}
}).done(function(o) {
console.log('saved');
// If you want the file to be visible in the browser
// simply return the url previously saved
});
}
});
Then in your script.php or file (or whatever you file is called):
$img = $_POST['data'];
$img = str_replace('data:image/png;base64,', '', $img); //Because saved as a data image
$img = str_replace(' ', '+', $img);
$fileData = base64_decode($img);
//saving the image to server
$fileName = 'image.png';
file_put_contents($fileName, $fileData);
html2canvas does not support most css properties (except the basic ones), one of which is transform as you may have already know and there is also no workaround (using html2canvas) for that unfortunately.
However, you can use a JavaScript canvas library called FabricJS which seems to be the most suitable to serve your purpose, such as manipulating (move, resize, rotate etc.) user uploaded image(s).
The best part of using this library is that, you won't need to use html2canvas or any other additional libraries to take the screenshot. You can directly save the canvas (take screenshot) as image, since FabricJS is a canvas library by nature.
Here is a basic example demonstrating that :
var canvas = new fabric.Canvas('myCanvas', {
backgroundColor: 'white'
});
function renderImage(e) {
var imgUrl = URL.createObjectURL(e.target.files[0]);
fabric.Image.fromURL(imgUrl, function(img) {
// set default props
img.set({
width: 150,
height: 150,
top: 75,
left: 75,
transparentCorners: false
});
canvas.add(img);
canvas.renderAll();
});
}
function saveOnPC() {
var link = document.createElement('a');
link.href = canvas.toDataURL();
link.download = 'myImage.png';
link.click();
}
function saveOnServer() {
$.post('https://your-site-name.com/save-image.php', {
data: canvas.toDataURL()
}, function() {
console.log('Image saved on server!');
});
/* use the following PHP code for 'save-image.php' on server-side
<? php
$img = $_POST['data'];
$img = str_replace('data:image/png;base64,', '', $img);
$img = str_replace(' ', '+', $img);
$fileData = base64_decode($img);
$fileName = 'myImage.png';
file_put_contents($fileName, $fileData);
*/
}
canvas{border:1px solid red}input{margin-bottom:6px}button{margin:10px 3px 0 0}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.19/fabric.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="file" onchange="renderImage(event)">
<canvas id="myCanvas" width="300" height="300"></canvas>
<button onclick="saveOnPC()">Save on PC</button>
<button onclick="saveOnServer()">Save on Server</button>
To learn more about the FabricJS library refer to it's Official Documentation.
This will only be a half answer. As I commented, the other half will rely on what type of script you use to generate the new image.
This half shows how you can capture all the various details. Assuming your Red box is your viewport for the new image, this would collect the details as you make changes so that you can pass them along to the script that will construct the image.
I assumed the option to capture the following details:
File Name
File Size
Dimensions
Position
Rotation
You can, if you want, drop the file name and let the user assign a name value.
HTML
<form method="post" action="">
<button id="browse-btn">Browse Images</button>
<input name="user_file[]" id="user_file" style="display: none; position: relative;overflow: hidden" multiple="" type="file" />
<div class="new-multiple"></div>
<button id="submit-btn" type="submit">Submit</button>
<div class="meta-details">
<ul>
<li>
<label>Name:</label>
<span></span>
</li>
<li>
<label>Size:</label>
<span></span>
</li>
<li>
<label>Width:</label>
<span></span>
</li>
<li>
<label>Height:</label>
<span></span>
</li>
<li>
<label>Top:</label>
<span></span>
</li>
<li>
<label>Left:</label>
<span></span>
</li>
<li>
<label>Rotation:</label>
<span></span>
</li>
</ul>
</div>
</form>
CSS
form button {
margin: 3px;
}
.new-multiple {
width: 400px !important;
height: 400px !important;
background: white;
border: 2px solid #faa;
border-radius: 3px;
overflow: hidden;
}
.img-div {
width: 200px;
height: 200px;
}
.newly-added {
width: 100%;
height: 100%;
}
.img-selected {
box-shadow: 1px 2px 6px 6px rgb(206, 206, 206);
border: 2px solid rgb(145, 44, 94);
}
.ui-resizable-handle {
border: 0;
border-radius: 50%;
background-color: #00CCff;
width: 14px;
height: 14px;
}
.ui-resizable-nw {
top: -7px;
left: -7px;
}
.ui-resizable-ne {
top: -7px;
right: -7px;
}
.ui-resizable-e {
top: calc(50% - 7px);
right: -7px;
}
.ui-resizable-w {
top: calc(50% - 7px);
left: -7px;
}
.ui-resizable-sw {
bottom: -7px;
left: -7px;
}
.ui-resizable-se {
right: -7px;
bottom: -7px;
}
.ui-resizable-se.ui-icon {
display: none;
}
.ui-rotatable-handle {
background-size: 14px;
background-repeat: no-repeat;
background-position: center;
border: 0;
border-radius: 50%;
background-color: #00CCff;
margin-left: calc(50% - 9px);
bottom: -5px;
width: 18px;
height: 18px;
}
.meta-details ul {
padding: 0;
margin: 0;
list-style: none;
font-family: Arial, sans-serif;
font-size: 9px;
}
.meta-details ul li label {
display: inline-block;
width: 45px;
}
JavaScript
$(function() {
var inputLocalFont = $("#user_file");
inputLocalFont.change(previewImages);
function humanFileSize(bytes, si) {
var thresh = si ? 1000 : 1024;
if (Math.abs(bytes) < thresh) {
return bytes + ' B';
}
var units = si ? ['kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'] : ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB'];
var u = -1;
do {
bytes /= thresh;
++u;
} while (Math.abs(bytes) >= thresh && u < units.length - 1);
return bytes.toFixed(1) + ' ' + units[u];
}
function logMeta(d) {
var $m = $(".meta-details ul li span");
$m.eq(0).html(d.name);
$m.eq(1).html(humanFileSize(d.size));
$m.eq(2).html(d.width + " px");
$m.eq(3).html(d.height + " px");
$m.eq(4).html(d.top + " px");
$m.eq(5).html(d.left + " px");
$m.eq(6).html(d.rotateDeg + " °");
}
function previewImages() {
var fileList = this.files;
var fileMeta = [];
$.each(fileList, function(key, val) {
fileMeta[key] = {
name: val.name,
size: val.size,
modified: val.lastModified
};
});
var anyWindow = window.URL || window.webkitURL;
for (var i = 0; i < fileList.length; i++) {
var $list = fileList[i];
var $meta = fileMeta[i];
var objectUrl = anyWindow.createObjectURL(fileList[i]);
var $newDiv = $("<div>", {
class: "img-div"
});
var $newImg = $("<img>", {
src: objectUrl,
class: "newly-added"
}).appendTo($newDiv);
$meta['width'] = $newImg.width();
$meta['height'] = $newImg.height();
$meta['rotateDeg'] = 0.000;
$meta['top'] = $newImg.position().top;
$meta['left'] = $newImg.position().left;
$(".new-multiple").append($newDiv);
$newDiv.draggable({
drag: function(e, ui) {
$meta['top'] = ui.position.top;
$meta['left'] = ui.position.left;
logMeta($meta);
$newImg.data("meta", $meta);
}
});
$newDiv.rotatable({
rotate: function(e, ui) {
$meta['rotateDeg'] = Math.round(ui.angle.degrees * 10000) / 10000;
$meta['rotateRad'] = ui.angle.current;
logMeta($meta);
$newImg.data("meta", $meta);
}
});
$newDiv.resizable({
aspectRatio: true,
handles: "ne, nw, e, se, sw, w",
resize: function(e, ui) {
$meta['width'] = ui.size.width;
$meta['height'] = ui.size.height;
logMeta($meta);
$newImg.data("meta", $meta);
}
});
$newDiv.find(".ui-icon").removeClass("ui-icon ui-icon-gripsmall-diagonal-se");
window.URL.revokeObjectURL(fileList[i]);
console.log($meta);
logMeta($meta);
$newImg.data("meta", $meta);
}
$(".newly-added").on("click", function(e) {
$(".newly-added").removeClass("img-selected");
$(this).addClass("img-selected");
e.stopPropagation();
});
$(document).on("click", function(e) {
if ($(e.target).is(".newly-added") === false) {
$(".newly-added").removeClass("img-selected");
}
});
}
$("button").button();
$("#browse-btn").click(function(e) {
e.preventDefault();
$("#user_file").trigger("click");
});
$("#browse-btn").click(function(e) {
e.preventDefault();
$(this).parent().submit();
});
$("form").submit(function(e) {
e.preventDefault();
console.log("Prepared Meta Data:");
$(".newly-added").each(function() {
console.log($(this).data("meta"));
});
// AJAX Post Code will be entered here
});
});
First a ref to #mpen here from converting file size in bytes to human-readable string for the file size conversion function.
You can see we create an array to store the corresponding details that associate with the file(s). This gets updated as the item is dragged, resized, or rotated. You can submit these details along with the original image when you submit the form. So at least your User Interface is built now.
Your next step will be to see how you want to build and save the image from these details. So start looking at Image Processing for PHP. See which you want to use and start on that back-end script.
Following #ValfarDeveloper you can assign the value of the .src of the <img> to a data URI instead of a Blob URL and set the current HTML of ".new-multiple" at a <foreignObject> element within an <svg> string.
$(function() {
var inputLocalFont = $("#user_file");
inputLocalFont.change(previewImages);
async function previewImages() {
var fileList = this.files;
var anyWindow = window.URL || window.webkitURL;
for (var i = 0; i < fileList.length; i++) {
var objectUrl = await new Promise(resolve => {
var reader = new FileReader;
reader.onload = e => resolve(reader.result);
reader.readAsDataURL(fileList[i]);
});
var $newDiv = $("<div>", {
class: "img-div"
});
var $newImg = $("<img>", {
src: objectUrl,
class: "newly-added"
}).appendTo($newDiv);
$(".new-multiple").append($newDiv);
$newDiv.draggable();
$newDiv.rotatable();
$newDiv.resizable({
aspectRatio: true,
handles: "ne, nw, e, se, sw, w"
});
$newDiv.find(".ui-icon").removeClass("ui-icon ui-icon-gripsmall-diagonal-se");
}
$(".newly-added").on("click", function(e) {
$(".newly-added").removeClass("img-selected");
$(this).addClass("img-selected");
e.stopPropagation()
});
$(document).on("click", function(e) {
if ($(e.target).is(".newly-added") === false) {
$(".newly-added").removeClass("img-selected");
}
});
}
$(".user_submit").on("click",function(e){
e.preventDefault();
let html = $(".new-multiple").html();
let svg = `<?xml version="1.0" standalone="yes"?>
<svg xmlns="http://www.w3.org/2000/svg" width="400px" height="400px" viewBox="0 0 400 300">
<foreignObject width="400px" height="300px"
requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
<html xmlns="http://www.w3.org/1999/xhtml">
${html}
</html>
</foreignObject>
</svg>`;
$("body").append(svg);
});
});
.new-multiple {
width: 400px !important;
height: 400px !important;
background: white;
border: 2px solid red;
overflow: hidden;
}
.img-div {
width: 200px;
height: 200px;
}
.newly-added {
width: 100%;
height: 100%;
}
.img-selected {
box-shadow: 1px 2px 6px 6px rgb(206, 206, 206);
border: 2px solid rgb(145, 44, 94);
}
/*
.ui-resizable-handle.ui-resizable-se.ui-icon.ui-icon-gripsmall-diagonal-se {
background-color: white;
border: 1px solid tomato;
}
*/
.ui-resizable-handle {
border: 0;
border-radius: 50%;
background-color: #00CCff;
width: 14px;
height: 14px;
}
.ui-resizable-nw {
top: -7px;
left: -7px;
}
.ui-resizable-ne {
top: -7px;
right: -7px;
}
.ui-resizable-e {
top: calc(50% - 7px);
right: -7px;
}
.ui-resizable-w {
top: calc(50% - 7px);
left: -7px;
}
.ui-resizable-sw {
bottom: -7px;
left: -7px;
}
.ui-resizable-se {
right: -7px;
bottom: -7px;
}
.ui-resizable-se.ui-icon {
display: none;
}
.ui-rotatable-handle {
background-size: 14px;
background-repeat: no-repeat;
background-position: center;
border: 0;
border-radius: 50%;
background-color: #00CCff;
margin-left: calc(50% - 9px);
bottom: -5px;
width: 18px;
height: 18px;
}
<link href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css" rel="stylesheet"/>
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<link href="https://cdn.jsdelivr.net/gh/godswearhats/jquery-ui-rotatable#1.1/jquery.ui.rotatable.css" rel="stylesheet"/>
<script src="https://cdn.jsdelivr.net/gh/godswearhats/jquery-ui-rotatable#1.1/jquery.ui.rotatable.min.js"></script>
<script src="https://html2canvas.hertzen.com/build/html2canvas.js"></script>
<form method="post" action="">
<input name="user_file[]" id="user_file" style="position: relative;overflow: hidden" multiple="" type="file">
<div class="new-multiple"></div>
<input type="submit" name="submit" class="user_submit" value="submit" />
</form>
Have you tried rasterizeHTML ?
I'll quote it:
For security reasons rendering HTML into a canvas is severly limited... However it is possible by embedding the HTML into an SVG image as a and then drawing the resulting image via ctx.drawImage().
You can found the project on Github, there they explain how use it:
https://github.com/cburgmer/rasterizeHTML.js
The following code initially loads more content when the bottom button is clicked but I need it to work when the scroll reach the bottom of the page... I've tried the code under the words //HERE IS THE PROBLEM// but it seems not to work.... any idea?
var lazyload = lazyload || {};
(function($, lazyload) {
"use strict";
var page = 2,
buttonId = "#button-more",
loadingId = "#loading-div",
container = "#container";
//HERE IS THE PROBLEM
$(window).scroll(function() {
if($(window).scrollTop() + $(window).height() == $(document).height()) {
lazyload.load = function() {
var url = "./" + page + ".html";
$(buttonId).hide();
$(loadingId).show();
$.ajax({
url: url,
success: function(response) {
if (!response || response.trim() == "NONE") {
$(buttonId).fadeOut();
$(loadingId).text("No more entries to load!");
return;
}
appendContests(response);
},
error: function(response) {
$(loadingId).text("Sorry, there was some error with the request. Please refresh the page.");
}
});
};
}
});
var appendContests = function(response) {
var id = $(buttonId);
$(buttonId).show();
$(loadingId).hide();
$(response).appendTo($(container));
page += 1;
};
})(jQuery, lazyload);
body{
background-color: #ccc;
margin: 0;
}
#wrapper{
width:100%;
margin: 0 auto;
min-height: 500px;
background-color: #e9e9e9;
color: #333;
padding: 10px;
text-align: center;
}
#data-container{
margin: 10px;
}
#data-container .data-item{
background-color: #444444;
border-radius: 5px;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
padding: 105px;
margin: 5px;
color: #fff;
}
#loading-div{
display: none;
}
#button-more{
cursor: pointer;
margin: 0 auto;
background-color: #aeaeae;
color: #fff;
width: 200px;
height: 50px;
line-height: 50px;
}
.child{
width:100%;
height:1000px;
background-color:blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="wrapper">
<h1>Lazy Load Demo</h1>
<div id="container">
<div class="child">
</div>
</div>
<div id="button-more" onclick="lazyload.load()">
Load more items
</div>
<div id="loading-div">
loading more items
</div>
</div>
let more = document.querySelector("button");
let show = document.querySelector(".show");
let loading = document.querySelector(".loading");
let bottom = document.querySelector(".bottom");
let allowAjax = true;
function getAjax(){
loading.classList.add("show");
if(allowAjax === true){
allowAjax = false;
let xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
let back = xhttp.response;
back = JSON.parse(back);
let imgSrc = back.results[0].picture.large;
let imgEl = document.createElement("img");
imgEl.src = imgSrc;
show.appendChild(imgEl);
loading.classList.remove("show");
allowAjax = true;
}
};
xhttp.open("GET", "https://randomuser.me/api/", true);
xhttp.send();
}
}
window.addEventListener("scroll",function(){
let scrollPos = window.pageYOffset;
let bottomPos = bottom.offsetTop;
if(bottomPos / 1.5 <= scrollPos){
// Almost to the bottom of the page
getAjax();
}
});
more.addEventListener("click",function(){
getAjax();
});
img{
display: block;
width: 30em;
height: 30em;
}
.more{
position: fixed;
top: 1em;
right: 5em;
background: skyblue;
color: #FFF;
padding: 0.5em;
border: none;
cursor: pointer;
outline: none;
}
.loading{
width: 10em;
height: 10em;
display: none;
position: fixed;
top: 5em;
right: 1em;
background: #212323;
padding: 0.5em;
}
.loading.show{
display: block;
}
.show img{
display: block;
width: 30em;
height: 30em;
}
<img src="https://unsplash.it/300/300/?random" />
<img src="https://unsplash.it/300/300/?random" />
<img src="https://unsplash.it/300/300/?random" />
<img src="https://unsplash.it/300/300/?random" />
<div class="show"></div>
<div class="bottom"></div>
<button class="more">More</button>
<img src="http://www.lettersmarket.com/uploads/lettersmarket/blog/loaders/common_metal/ajax_loader_metal_512.gif"class="loading">
initially loads
Hello I'm stuck on how to add category for my to do list. When you click on Button of category need change class name. I don't understand how to correctly write if/else statement when button is clicked.
plan how it need to work
Write task name
Choose Category
Add new task
May be somebody can help me out ore give some advice how to solve this problem!
Sorry for my english and if my question is to badly explained!
var toDoList = function() {
var addNewTask = function() {
var input = document.getElementById("taks-input").value,
itemTexts = input,
colA = document.getElementById('task-col-a').children.length,
colB = document.getElementById('task-col-b').children.length,
taskBoks = document.createElement("div"),
work = document.getElementById("work"),
Category = "color-2",
taskCount = 1;
if (work.onclick === true) {
var Category = "color";
}
taskBoks.className = "min-box";
taskBoks.innerHTML = '<div class="col-3 chack" id="task_' + (taskCount++) + '"><i class="fa fa-star"></i></div><div class="col-8 task-text" id="taskContent"><p>' + itemTexts + '</p><span id="time-now"></span></div><div class="col-1 ' + (Category) + '"></div>'
if (colB < colA) {
var todolist = document.getElementById("task-col-b");
} else {
var todolist = document.getElementById("task-col-a");
}
//todolist.appendChild(taskBoks);
todolist.insertBefore(taskBoks, todolist.childNodes[0]);
},
addButton = function() {
var btn2 = document.getElementById("add-task-box");
btn2.onclick = addNewTask;
};
addButton()
}
toDoList();
p {
padding: 20px 20px 20px 45px;
}
.chack {
background-color: #4c4b62;
height: 100%;
width: 40px;
}
.task-text {
background-color: #55566e;
height: 100%;
width: 255px;
}
.color {
width: 5px;
height: 100%;
background-color: #fdcd63;
float: right;
}
.color-2 {
width: 5px;
height: 100%;
background-color: red;
float: right;
}
.color-3 {
width: 5px;
height: 100%;
background-color: purple;
float: right;
}
.task {
height: 100px;
width: 300px;
border: 1px solid #fff;
float: left;
}
.chack,
.task-text {
float: left;
}
.add-new-task {
margin-bottom: 50px;
height: 80px;
width: 588px;
background-color: rgb(85, 86, 110);
padding-top: 30px;
padding-left: 15px;
}
.min-box {
height: 100px;
border-bottom: 1px solid #fff;
}
.center {
padding-top: 20px;
padding-left: 50px;
}
.fa-star {
padding-left: 14px;
padding-top: 100%;
}
#add-task-box {
float: right;
margin-right: 10px;
margin-top: -7px;
border: none;
background-color: rgb(255, 198, 94);
padding: 10px;
}
#taks-input {
height: 30px;
width: 350px;
margin-top: -7px;
}
.category {
margin-top: 10px;
}
<div class="container">
<div class="add-new-task">
<input type="text" id="taks-input">
<button id="add-task-box">Add New Task box</button>
<div class="category">
<button class="catBtn" id="work">Work</button>
<button class="catBtn" id="home">Home</button>
<button class="catBtn" id="other">Other</button>
</div>
</div>
<div class="lg-task" id="bigTask"></div>
<div class="task" id="task-col-a"></div>
<div class="task" id="task-col-b"></div>
</div>
you need to bind click event to your buttons and store that value in Category, so in you js add this
var toDoList = function() {
// set to default
var Category = "color-3";
// attach event to buttons
var catButtons = document.getElementsByClassName("catBtn");
// assign value based on event
var myCatEventFunc = function() {
var attribute = this.getAttribute("id");
if (attribute === 'work') {
Category = 'color';
} else if (attribute === 'home') {
Category = 'color-2';
}
};
for (var i = 0; i < catButtons.length; i++) {
catButtons[i].addEventListener('click', myCatEventFunc, false);
}
Demo: Fiddle
and remove this code from addNewTask function
if (work.onclick === true) {
var Category = "color";
}
It is a bit hard to understand what you are doing, what you are going for (a module of some kind?). You were not that far away from a working state.
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>Task</title>
<style>
p {
padding: 20px 20px 20px 45px;
}
.chack {
background-color: #4c4b62;
height: 100%;
width: 40px;
}
.task-text {
background-color: #55566e;
height: 100%;
width: 255px;
}
.color {
width: 5px;
height: 100%;
background-color: #fdcd63;
float: right;
}
.color-2 {
width: 5px;
height: 100%;
background-color: red;
float: right;
}
.color-3 {
width: 5px;
height: 100%;
background-color: purple;
float: right;
}
.task {
height: 100px;
width: 300px;
border: 1px solid #fff;
float: left;
}
.chack,
.task-text {
float: left;
}
.add-new-task {
margin-bottom: 50px;
height: 80px;
width: 588px;
background-color: rgb(85, 86, 110);
padding-top: 30px;
padding-left: 15px;
}
.min-box {
height: 100px;
border-bottom: 1px solid #fff;
}
.center {
padding-top: 20px;
padding-left: 50px;
}
.fa-star {
padding-left: 14px;
padding-top: 100%;
}
#add-task-box {
float: right;
margin-right: 10px;
margin-top: -7px;
border: none;
background-color: rgb(255, 198, 94);
padding: 10px;
}
#taks-input {
height: 30px;
width: 350px;
margin-top: -7px;
}
.category {
margin-top: 10px;
}
</style>
<script>
var toDoList = function() {
var addNewTask = function() {
var input = document.getElementById("taks-input").value,
itemTexts = input,
colA = document.getElementById('task-col-a').children.length,
colB = document.getElementById('task-col-b').children.length,
taskBoks = document.createElement("div"),
work = document.getElementById("work"),
Category = "color-2",
taskCount = 1;
if (work.onclick === true) {
Category = "color";
}
taskBoks.className = "min-box";
taskBoks.innerHTML = '<div class="col-3 chack" id="task_'
+ (taskCount++) +
'"><i class="fa fa-star"></i></div><div class="col-8 task-text" id="taskContent"><p>'
+ itemTexts +
'</p><span id="time-now"></span></div><div class="col-1 '
+ (Category) + '"></div>'
if (colB < colA) {
var todolist = document.getElementById("task-col-b");
} else {
var todolist = document.getElementById("task-col-a");
}
//todolist.appendChild(taskBoks);
todolist.insertBefore(taskBoks, todolist.childNodes[0]);
},
// I don't know what to do with that?
addButton = function() {
var btn2 = document.getElementById("add-task-box");
btn2.onclick = addNewTask();
};
// return the stuff you want to have public
return {
addNewTask:addNewTask
};
}
var f;
// wait until all HTML is loaded and put the stuff from above into the variable `f`
// you can call it with f.someFunction() in your case f.addNewTask()
window.onload = function(){
f = toDoList();
}
</script>
</head>
<body>
<div class="container">
<div class="add-new-task">
<input type="text" id="taks-input">
<button id="add-task-box" onclick="f.addNewTask()">Add New Task box</button>
<div class="category">
<button class="catBtn" id="work" >Work</button>
<button class="catBtn" id="home">Home</button>
<button class="catBtn" id="other">Other</button>
</div>
</div>
<div class="lg-task" id="bigTask"></div>
<div class="task" id="task-col-a"></div>
<div class="task" id="task-col-b"></div>
</div>
</body>
</html
I hope you understood what I did?