"Drop Zones" with Fabric.js? - javascript

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>

Related

How to apply custom styles to the HTML element of input type range for different browsers? [duplicate]

I want to style the bar before the thumb with a different color on a range input. I'v tried looking for a solution but I havent found a proper solution. This is what I need it to look like:
Chrome doesnt seem to support input[type='range']::-webkit-slider-thumb:before anymore and I am at a loss how to style it. Here's what I have so far:
input[type='range'] {
min-width: 100px;
max-width: 200px;
&::-webkit-slider-thumb {
-webkit-appearance: none !important;
background-color: #white;
border: 1px solid #gray-4;
height: 14px;
width: 14px;
&:hover,
&:focus,
&:active {
border-color: #blue;
background-color: #gray-2;
}
}
&::-webkit-slider-runnable-track {
background-color: #gray-2;
border: 1px solid #gray-4;
}
}
document.querySelectorAll(".__range").forEach(function(el) {
el.oninput =function(){
var valPercent = (el.valueAsNumber - parseInt(el.min)) /
(parseInt(el.max) - parseInt(el.min));
var style = 'background-image: -webkit-gradient(linear, 0% 0%, 100% 0%, color-stop('+ valPercent+', #29907f), color-stop('+ valPercent+', #f5f6f8));';
el.style = style;
};
el.oninput();
});
.__range{
margin:30px 0 20px 0;
-webkit-appearance: none;
background-color: #f5f6f8;
height: 3px;
width: 100%;
margin: 10px auto;
}
.__range:focus{
outline:none;
}
.__range::-webkit-slider-thumb{
-webkit-appearance: none;
width: 20px;
height: 20px;
background: #29907f;
border-radius: 50%;
cursor: -moz-grab;
cursor: -webkit-grab;
}
<input class="__range" id="rng" name="rng" value="30" type="range" max="100" min="1" value="100" step="1">
The trick in the post referenced by shambalambala is clever, but I don't think it will work in this case if you want to get something that looks exactly like the image you show. The approach there is to put a shadow on the thumb to create the different coloring to the left of the thumb. Since the shadow extends in the vertical, as well as the horizontal, direction, you also have to add overflow:hidden to the range or the track in order to clip the shadow. Unfortunately, this also clips the thumb. So if you want a thumb that extends beyond the track in the vertical dimension, such as in the image you show where the thumb is a circle with a diameter larger than the track width, this won't work.
I'm not sure there's a pure CSS solution to this problem. With JavaScript, one way around this is to make two range elements that overlap exactly. For one range element, you will see only the thumb and for one you will see only the track. You can use the shadow approach on the track element to get the different color before the thumb. You can style the thumb on the thumb range however you want, and since overflow is not set to hidden for this range element, it can extend beyond the width of the track. You can then use JavaScript to yoke the two range elements together, so that when you move the thumb on the thumb-visible element, the value of the track-visible element also changes.
For example (works in webkit browsers--will need some additional styling for other browsers):
<html>
<head>
<style>
.styled_range {
position: relative;
padding: 10px;
}
input[type=range] {
-webkit-appearance: none;
width: 600px;
background: transparent;
position: absolute;
top: 0;
left: 0;
}
input[type=range]::-webkit-slider-thumb {
-webkit-appearance: none;
}
input[type=range]:focus {
outline: none;
}
input[type=range]::-webkit-slider-runnable-track {
width: 100%;
height: 12px;
}
.track_range {
pointer-events: none;
}
.track_range::-webkit-slider-runnable-track {
background: #D0D0D0;
border-radius: 6px;
overflow: hidden;
}
.track_range::-webkit-slider-thumb {
-webkit-appearance: none;
background: transparent;
height: 1px;
width: 1px;
box-shadow: -600px 0 0 600px #666666;
}
.thumb_range::-webkit-slider-runnable-track {
background: transparent;
cursor: pointer;
}
.thumb_range::-webkit-slider-thumb {
-webkit-appearance: none;
border: 3px solid #ffffff;
border-radius: 20px;
height: 40px;
width: 40px;
background: #1180AD;
cursor: pointer;
margin: -12px 0px 0px 0px;
}
</style>
</head>
<body>
<form>
<div class="styled_range">
<input type="range" class="track_range"/>
<input type="range" class="thumb_range"/>
</div>
<br/>
<div class="styled_range">
<input type="range" class="track_range"/>
<input type="range" class="thumb_range"/>
</div>
</form>
</body>
<script>
window.onload = function() {
var styledRanges = document.getElementsByClassName('styled_range');
for (var i=0; i<styledRanges.length; i++) {
var thumbRange = null, trackRange = null;
for (var j=0; j<styledRanges[i].children.length; j++) {
var child = styledRanges[i].children[j];
if (child.className === 'thumb_range')
var thumbRange = child;
else if (child.className === 'track_range')
var trackRange = child;
}
thumbRange.oninput = function(thumbRange, trackRange) {
return function(e) {
trackRange.value = thumbRange.value;
};
}(thumbRange, trackRange);
}
}
</script>
</html>

How do you change a CSS property in a javascript file?

I am wondering how to change the border of lock:before to solid transparent when the correct password is entered.
My JavaScript is like this, I need a lock before value to change to solid transparent when the IF is triggered
function lock(){
alert("It's locked, you have to guess the password.");
var pass = prompt("");
if (pass == "opensesame") {
alert("Lock opened");
} else {
alert("Wrong password");
}
}
My CSS is like this, lock before needs to be changed to solid transparent by a javascript function.
body {
position: absolute;
color: #00ff80;
background: green;
top: 100px;
left: 200px;
}
#lock {
font-size: 8px;
position: relative;
width: 18em;
height: 13em;
border-radius: 2em;
top: 10em;
box-sizing: border-box;
border: 3.5em solid red;
border-right-width: 7.5em;
border-left-width: 7.5em;
margin: 0 0 6rem 0;
}
#lock:before {
content: "";
box-sizing: border-box;
position: absolute;
border: 2.5em solid red;
width: 14em;
height: 12em;
left: 50%;
margin-left: -7em;
top: -12em;
border-top-left-radius: 7em;
border-top-right-radius: 7em;
}
#lock:after {
content: "";
box-sizing: border-box;
position: absolute;
border: 1em solid red;
width: 5em;
height: 8em;
border-radius: 2.5em;
left: 50%;
top: -1em;
margin-left: -2.5em;
}
#button {
background: transparent;
}
My HTML is like this, all it does is make a button and some text.
<!DOCTYPE html>
<html>
<head>
<title>The lock</title>
</head>
<body>
<h1>Unlock the lock</h1>
<button id=button onclick="lock()"><div id=lock></div></button>
</body>
</html>
Try something like this..
var str = '1em solid transparent';
document.styleSheets[0].addRule('#lock:before','border: "'+str+'";');
the style of a pseudo-element can be changed by using a new class name. For example, add the class name unlocked to the #lock element once the entered password is valid.
You can add the following style for the new class:
#lock.unlocked::before {
border: 1em solid transparent;
/* Your style for unlocked goes here */
}
And your script with the new instruction which add the class .unlocked.
function lock() {
alert("It's locked, you have to guess the password.");
var pass = prompt("");
if (pass == "opensesame") {
alert("Lock opened");
document.getElementById("lock").classList.add("unlocked"); /* NEW */
} else {
alert("Wrong password");
}
}
Add and remove a class to and from the button. Pseudo elements can't be targeting directly from JavaScript so you have to use CSS to change the styling.
// Select the button
const button = document.querySelector('button');
function lock(){
alert("It's locked, you have to guess the password.");
var pass = prompt("");
if (pass == "opensesame") {
// Add the class.
button.classList.add('unlocked');
// If it already has the class..
} else if (button.classList.contains('unlocked')) {
//.. then remove it.
button.classList.remove('unlocked');
}
}
And in your CSS add the class with the styling you need.
#lock.unlocked::before {
border: 2.5em solid transparent;
}

How to access an inner function to gets its value to make a story flow

I'm trying to make a game simulation like the Voltage game just for fun, it has 4 main components, including the background, the character image, the character name and the text. I want to create a big function called startStory() which has smaller functions in there to represent different parts of the story.
How it works is that when the user clicks on the game screen the text/character name/image/background will change in order to create a story for the users. But when I tried to create the function startStory() and tried to run the inner function in it nothing happens.
Can someone help me explain why? And do you think that making different parts of the story smaller code a good idea or should I do something else? Here is my code so far
<style>
* {
margin: 0;
padding: 0;
font-family: 'Lora', serif;
}
.container {
top: 10px;
margin: 0 auto;
width: 70vw;
position: relative;
}
.background {
width: 70vw;
position:absolute;
top: 0px;
left: 0px;
z-index: 1;
border: 2px solid black;
}
.character {
width: 15vw;
position:absolute;
left: 400px;
top: 120px;
z-index: 2;
}
.label {
border: 2px solid black;
background-color: white;
padding: 30px;
position:absolute;
top: 400px;
left: 40px;
z-index: 2;
}
.text {
width: 60vw;
border: 2px solid black;
background-color: white;
padding: 30px;
position:absolute;
top: 470px;
left: 40px;
z-index: 2;
text-align: center;
}
</style>
<body>
<div class="container">
<img class="background" src="https://img.wallpapersafari.com/desktop/1920/1080/48/39/DtNh51.jpg">
<img class="character" src="https://www-en.voltage.co.jp/wp-content/uploads/sites/3/2019/07/190704_voltage_press2.jpg">
<div class="label">Leon</div>
<div class="text">Hi there</div>
</div>
</body>
<script>
var container = document.getElementsByClassName('container')[0];
var textHolder = document.getElementsByClassName('text')[0]
container.addEventListener('click', startStory)
function startStory() {
function introduceCharacter() {
textHolder.innerHTML = 'I\'m Leon. What\'s your name?';
}
}
</script>
Keep in mind that nested functions are local. So if you want to call the function introduceCharacter you have to add the event listener inside the scope of the function startStory().
function startStory() {
container.addEventListener('click', introduceCharacter) //local scope.
function introduceCharacter() {
textHolder.innerHTML = 'I\'m Leon. What\'s your name?';
}
}
However a better way is to simply remove the introduceCharacter function:
function startStory() {
textHolder.innerHTML = 'I\'m Leon. What\'s your name?';
}
In short: a function within a function is available in the scope it is declared. Nice game by the way, good luck!

How to take screenshot of the div that contain user Uploaded images in frontend?

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

Why am I unable to play this mp3 using jquery and the jquery ui library?

For some reason I'm unable to get the mp3 I want to be played to play with this code. Here's the fiddle:
http://jsfiddle.net/haGYL/
Here's the code:
<style>
#player {
width: 350px;
height: 50px;
position: relative;
margin: 0 auto;
top: 150px;
background: url('http://iviewsource.com/exercises/audioslider/images/volume-background.png') no-repeat left top;
}
#volume {
position: absolute;
left: 24px;
margin: 0 auto;
height:15px;
width: 300px;
background: url('http://iviewsource.com/exercises/audioslider/images/volume-empty.png') no-repeat left top;
border: none;
outline: none;
}
#volume .ui-slider-range-min {
height:15px;
width: 300px;
position: absolute;
background: url('http://iviewsource.com/exercises/audioslider/images/volume-full.png') no-repeat left top;
border: none;
outline: none;
}
#volume .ui-slider-handle {
width: 38px;
height:39px;
background: url('http://iviewsource.com/exercises/audioslider/images/volume-knob.png') no-repeat left top;
position: absolute;
margin-left: -15px;
cursor: pointer;
outline: none;
border: none;
}
</style>
<script>
$("#volume").slider({
min: 0,
max: 100,
value: 0,
range: "min",
animate: true,
slide: function(event, ui) {
setVolume((ui.value) / 100);
}
});
var myMedia = document.createElement('audio');
$('#player').append(myMedia);
myMedia.id = "myMedia";
playAudio('http://www.catholic.com/sites/default/files/audio/radioshows/ca140331b.mp3', 0);
function playAudio(fileName, myVolume) {
var mediaExt = (myMedia.canPlayType('audio/mp3')) ? '.mp3'
: (myMedia.canPlayType('audio/ogg')) ? '.ogg'
: '';
if (mediaExt) {
myMedia.src = fileName + mediaExt;
myMedia.setAttribute('loop', 'loop');
setVolume(myVolume);
myMedia.play();
}
}
function setVolume(myVolume) {
var myMedia = document.getElementById('myMedia');
myMedia.volume = myVolume;
}
</script>
<div id="player">
<div id="volume"></div>
</div>
Observe the following part of your code.
function playAudio(fileName, myVolume) {
// here you are checking if player can mp3 or ogg file
var mediaExt = (myMedia.canPlayType('audio/mp3')) ? '.mp3'
: (myMedia.canPlayType('audio/ogg')) ? '.ogg'
: '';
if (mediaExt) {
//here you are adding the extention that the player can play with the passed file url. So if url is www.xxx.com/myAudioFile and mediaExt is .mp3, here it will become www.xxx.com/myAudioFile.mp3
myMedia.src = fileName + mediaExt;
myMedia.setAttribute('loop', 'loop');
setVolume(myVolume);
myMedia.play();
}
}
And you are calling the above function as
playAudio('http://www.catholic.com/sites/default/files/audio/radioshows/ca140331b.mp3', 0);
Notice you are providing the extension also.
So while execution the playAudio method the effective file url is becoming like following
http://www.catholic.com/sites/default/files/audio/radioshows/ca140331b.mp3.mp3
OR
http://www.catholic.com/sites/default/files/audio/radioshows/ca140331b.mp3.ogg
So to run your code you just need to call the playAudio function as following
playAudio('http://www.catholic.com/sites/default/files/audio/radioshows/ca140331b', 0);
Notice I'm not passing the extension.
See the JSFiddle below.
Demo
here is your code working jsfiddle
$(document).ready(function() {
var myMedia = document.createElement('audio');
$('#player').append(myMedia);
myMedia.id = "myMedia";
playAudio('http://www.catholic.com/sites/default/files/audio/radioshows/ca140331b', 0);
});

Categories