replace() in cropper js - javascript

My project is about saving the cropped image and show it in the view.
in my form when i cropped the image it works, but when i want to change the image so i crop it again and save. it create two rows with same image.
and when i change the image 3 times it create 3 rows with the same image and so on.
there is method called replace() that i have to use but i dont know how to use it.
this is my code
window.addEventListener('DOMContentLoaded', function () {
var avatar = document.getElementById('avatar');
var image = document.getElementById('image');
var input = document.getElementById('input');
var $progress = $('.progress');
var $progressBar = $('.progress-bar');
var $alert = $('.alert');
var $modal = $('#modal');
var cropper;
var title = $('#title');
var description = $('#description');
var arabic_title = $('#arabic_title');
var arabic_description = $('#arabic_description');
$('[data-toggle="tooltip"]').tooltip();
input.addEventListener('change', function (e) {
var files = e.target.files;
var done = function (url) {
input.value = '';
image.src = url;
// $alert.hide();
$modal.modal('show');
};
var reader;
var file;
var url;
if (files && files.length > 0) {
file = files[0];
if (FileReader) {
reader = new FileReader();
reader.onload = function (e) {
done(reader.result);
console.log('ok2');
};
reader.readAsDataURL(file);
console.log('ok3');
}
}
});
$modal.on('shown.bs.modal', function () {
cropper = new Cropper(image, {
aspectRatio: 1.7,
viewMode: 3,
});
}).on('hidden.bs.modal', function () {
cropper.destroy();
cropper = null;
});
document.getElementById('crop').addEventListener('click', function () {
var initialAvatarURL;
var canvas;
$modal.modal('hide');
if (cropper) {
canvas = cropper.getCroppedCanvas({
width: 400,
height: 400,
});
initialAvatarURL = avatar.src;
avatar.src = canvas.toDataURL();
$progress.show();
$alert.removeClass('alert-success alert-warning');
document.getElementById('save').addEventListener('click', function () {
canvas.toBlob(function (blob) {
var formData = new FormData();
formData.append('avatar', blob);
formData.append('title', title.val());
formData.append('description', description.val());
formData.append('arabic_title', arabic_title.val());
formData.append('arabic_description', arabic_description.val());
if (title.val() !== '' && description.val() !== '' && arabic_title.val() !== '' && arabic_description.val() !== '') {
for (let pair of formData.entries()) {
console.log(pair[0] + ', ' + pair[1]);
}
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
$.ajax("{{url('admin/services')}}", {
method: 'POST',
data: formData,
processData: false,
contentType: false,
xhr: function () {
var xhr = new XMLHttpRequest();
xhr.upload.onprogress = function (e) {
var percent = '0';
var percentage = '0%';
if (e.lengthComputable) {
percent = Math.round((e.loaded / e.total) * 100);
percentage = percent + '%';
$progressBar.width(percentage).attr('aria-valuenow', percent).text(percentage);
}
};
return xhr;
},
success: function (data) {
$alert.show().addClass('alert-success').text('Upload success');
console.log(data);
},
error: function (error) {
avatar.src = initialAvatarURL;
$alert.show().addClass('alert-warning').text('Upload error');
console.log(error);
},
complete: function () {
$progress.hide();
},
});
}
});
});
}
});
});

$service = 'No service';
if (isset($_FILES['img'])) {
$service = Service::create(['title'=>$request->title,
'description'=>$request->description,
'photo'=>$request->img]);
}
return $service;
Try this.

Your Form Should Be
<form action="files/upload" method="post" enctype="multipart/form-data">
<input type="file" name="photo"/>
</form
Your Controller Should Be like
if ($request->hasFile('photo')) {
// move file upload here
}

Related

Cropper.js getValue is not working every time I upload a photo

I am using cropper.js to upload an image in a form. Sometimes it works fine, but sometimes when I upload the image and I use cropper.getValue it displays an error: Uncaught TypeError: Cannot read property 'naturalWidth' of undefined. How can i fix this?
var imageForm = document.querySelector(".userImage");
var fileInput = document.querySelector("input[name=user_photo]");
fileInput.addEventListener("change", function(event){
var reader = new FileReader();
reader.onload = function(){
var output = document.querySelector('.croppr-image');
var submitImageCont = document.querySelector('#submitImage');
output.src = reader.result;
imageForm.insertBefore(output, submitImageCont);
var overlay = document.querySelector(".overlay")
overlay.classList.remove("displayNone");
var publicProfileForm = document.querySelector("form.publicProfile");
var cropper = new Croppr('#cropper', {
onInitialize: (instance) => { console.log(instance); },
onCropStart: (data) => { console.log('start', data); },
onCropEnd: (data) => { console.log('end', data); },
onCropMove: (data) => { console.log('move', data); }
});
var value = cropper.getValue();
publicProfileForm.querySelector("input[name=cropped_image_x]").value = value.x;
publicProfileForm.querySelector("input[name=cropped_image_y]").value = value.y;
publicProfileForm.querySelector("input[name=cropped_image_width]").value = value.width;
publicProfileForm.querySelector("input[name=cropped_image_height]").value = value.height;
}
}, false);
When you create an instance of Cropper you must destroy previuous instance. Calling .destroy() method. This unbind Cropper and you must start it over again. A short example:
var cropper = null;
fileInput.addEventListener("change", function(event){
// a lot of stuffs
if(cropper){
cropper.destroy();
}
cropper = new Croppr('#cropper', {
onInitialize: (instance) => { console.log(instance); },
onCropStart: (data) => { console.log('start', data); },
onCropEnd: (data) => { console.log('end', data); },
onCropMove: (data) => { console.log('move', data); }
});
// another stuffs
}, false);

How to pass asynchronous function result into ajax function as parameter in js/jquery?

I'm trying to save the base64 image code of a video snapshot...
To do that, I have a first function I found which builds the snapshot I want, this function, videoSnap, is asynchronous, and I'd like to send it through an ajax function for further actions.
Problem is that the result of my videoSnap is completed way after the ajax call, thus, anytime I'm trying to send the result as a parameter of the ajax function, the result stay undefined...
How can I do this to work? I thought about promise function with then() but still the same result... I keep getting the base64 code after the ajax call making it uneffective...
I'm starting to be short of solution and idea... ^^'
Thanks much in advance for your great help! :)
getTime = function (){
var t = new Date();
return t.getTime();
}
dump = function (r) {
var pre = document.createElement('pre');
pre.innerHTML = r;
document.body.appendChild(pre)
}
videoSnap = function (file){
var reader = new FileReader();
if (file.type.match('video')) {
reader.onload = function() {
var blob = new Blob([reader.result], {type: file.type});
var url = URL.createObjectURL(blob);
var video = document.createElement('video');
var timeupdate = function() {
var snap = snapImage();
if (snap.success) {
video.removeEventListener('timeupdate', timeupdate);
video.pause();
dump(getTime()+' : '+snap.image);
return snap.image;
}else{
return false;
}
};
video.addEventListener('loadeddata', function() {
var snap = snapImage();
if (snap.success) {
video.removeEventListener('timeupdate', timeupdate);
dump(getTime()+' : '+snap.image);
return snap.image;
}else{
return false;
}
});
var snapImage = function() {
var canvas = document.createElement('canvas');
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
canvas.getContext('2d').drawImage(video, 0, 0, canvas.width, canvas.height);
var image = canvas.toDataURL();
var success = image.length > 100000;
var result = { success: success, image: image };
return result;
};
video.addEventListener('timeupdate', timeupdate);
video.preload = 'metadata';
video.src = url;
// Load video in Safari / IE11
video.muted = true;
video.playsInline = true;
video.play();
};
reader.readAsArrayBuffer(file);
}else{
return false;
}
}
dump(getTime());
var base64Img = videoSnap(videoFile);
formData.append("videoSnap",base64Img);
/*
function videoSnapPromise(vid) {
return new Promise((resolve) => {
resolve(videoSnap(vid));
})
}
function appendResolve(resolve) {
formData.append("videoSnap",resolve);
}
const promise = videoSnap(videoFile);
promise.then(appendResolve);
*/
dump(getTime());
$.ajax({
type: 'POST',
url: 'uploadBase64Img.php',
timeout: 10000,
data: formData,
processData: false,
contentType: false,
dataType: "json",
complete: function() {
// complete function
}
});
dump(getTime());
One way to do this would be to create a callback function and send it to the first function as a parameter, then refactor your first function to call that callback and pass it the result of the operation instead of returning it.
something like this should work:
getTime = function() {
var t = new Date();
return t.getTime();
}
dump = function(r) {
var pre = document.createElement('pre');
pre.innerHTML = r;
document.body.appendChild(pre)
}
var videoSnap = function(file, callback) {
var reader = new FileReader();
if (file.type.match('video')) {
reader.onload = function() {
var blob = new Blob([reader.result], {
type: file.type
});
var url = URL.createObjectURL(blob);
var video = document.createElement('video');
var timeupdate = function() {
var snap = snapImage();
if (snap.success) {
video.removeEventListener('timeupdate', timeupdate);
video.pause();
dump(getTime() + ' : ' + snap.image);
callback(snap.image);
} else {
callback(false);
}
};
video.addEventListener('loadeddata', function() {
var snap = snapImage();
if (snap.success) {
video.removeEventListener('timeupdate', timeupdate);
dump(getTime() + ' : ' + snap.image);
callback(snap.image);
} else {
callback(false);
}
});
var snapImage = function() {
var canvas = document.createElement('canvas');
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
canvas.getContext('2d').drawImage(video, 0, 0, canvas.width, canvas.height);
var image = canvas.toDataURL();
var success = image.length > 100000;
var result = {
success: success,
image: image
};
callback(result);
};
video.addEventListener('timeupdate', timeupdate);
video.preload = 'metadata';
video.src = url;
// Load video in Safari / IE11
video.muted = true;
video.playsInline = true;
video.play();
};
reader.readAsArrayBuffer(file);
} else {
callback(false);
}
}
var doAjax = function(base64Img) {
var formData = FormData();
formData.append("videoSnap", base64Img);
$.ajax({
type: 'POST',
url: 'uploadBase64Img.php',
timeout: 10000,
data: formData,
processData: false,
contentType: false,
dataType: "json",
complete: function() {
// complete function
}
});
}
videoSnap(videoFile, doAjax);

Do 3 unified checks

I have a form with 3 file input fields, but Laravel is giving me this problem: link
So, I will check before sending the files, the maximum resolution will be 2000x2000, I got this code and modified, but it is still giving an error because one passes the other. I want to know how I can unify the 3 checks into one.
Here's my code:
$("#personal").change(function() {
var fr = new FileReader;
fr.onload = function() {
var imgPersonal = new Image;
imgPersonal.onload = function() {
if (imgPersonal.width > 2000 && this.height > 2000) {
$("#submitDocs").attr("disabled", true);
} else {
$("#submitDocs").removeAttr("disabled");
}
};
imgPersonal.src = fr.result;
};
fr.readAsDataURL(this.files[0]);
});
$("#self").change(function() {
var fr = new FileReader;
fr.onload = function() {
var imgSelf = new Image;
imgPersonal.onload = function() {
if (imgSelf.width > 2000 && this.height > 2000) {
$("#submitDocs").attr("disabled", true);
} else {
$("#submitDocs").removeAttr("disabled");
}
}
};
imgSelf.src = fr.result;
};
fr.readAsDataURL(this.files[0]);
});
$("#address").change(function() {
var fr = new FileReader;
fr.onload = function() {
var imgAddress = new Image;
imgPersonal.onload = function() {
if (imgAddress.width > 2000 && this.height > 2000) {
$("#submitDocs").attr("disabled", true);
} else {
$("#submitDocs").removeAttr("disabled");
}
}
};
imgAddress.src = fr.result;
};
fr.readAsDataURL(this.files[0]);
});
Try putting all the duplicate code in a single function, in keeping with DRY, and keeping a persistent object that checks to see if any of the uploaded images are invalid:
const checks = {
personal: true,
self: true,
address: true,
};
function validate(file, checkAttr) {
const fr = new FileReader();
fr.readAsDataURL(file);
fr.onload = function() {
const img = new Image();
img.onload = () => {
if (img.width > 2000 || img.height > 2000) checks[checkAttr] = true;
else checks[checkAttr] = false;
if (checks.personal && checks.self && checks.address) $("#submitDocs").removeAttr("disabled");
else $("#submitDocs").attr("disabled", true);
}
img.src = fr.result;
}
}
$("#personal").change(function() {
validate(this.files[0], 'personal');
});
// other handlers
#CertainPerformance, Thanks, I was able to do it your way, I did this function and I used onblur = "btndisabled();" in each input
function btndisabled() {
var sizePersonal = personal.files[0].size;
var sizeSelf = self.files[0].size;
var sizeAddress = address.files[0].size;
if (sizePersonal < 1000000 && sizeSelf < 1000000 && sizeAddress < 1000000) {
$("#submitDocs").removeAttr("disabled");
} else {
alert('File larger than 1MB');
$("#submitDocs").attr("disabled", true);
}
}

Execute ajax call only after javascript loop has finished

Below is the code I am using which basically passes multiple files to be uploaded. In the loop each file is resized client side and then uploaded.
I want to execute an ajax call after the loop is finished uploading the photos. The ajax call basically reloads a specific div and refreshes the photos.
How do I prevent the ajax call from executing until the loop has finished.
if (window.File && window.FileReader && window.FileList && window.Blob)
{
var files = document.getElementById('filesToUpload').files;
for(var i = 0; i < files.length; i++)
{
resizeAndUpload(files[i]);
}
// when loop finished, execute ajax call
$.ajax
({
type: "POST",
url: "photos.php",
data: dataString,
success: function(html)
{
$("#photo-body").html(html);
}
});
}
}
function resizeAndUpload(file)
{
var reader = new FileReader();
reader.onloadend = function()
{
var tempImg = new Image();
tempImg.src = reader.result;
tempImg.onload = function()
{
var MAX_WIDTH = 382.25;
var MAX_HEIGHT = 258.5;
var tempW = tempImg.width;
var tempH = tempImg.height;
if (tempW > tempH)
{
if (tempW > MAX_WIDTH)
{
tempH *= MAX_WIDTH / tempW;
tempW = MAX_WIDTH;
}
}
else
{
if (tempH > MAX_HEIGHT)
{
tempW *= MAX_HEIGHT / tempH;
tempH = MAX_HEIGHT;
}
}
var canvas = document.createElement('canvas');
canvas.width = tempW;
canvas.height = tempH;
var ctx = canvas.getContext("2d");
ctx.drawImage(this, 0, 0, tempW, tempH);
var dataURL = canvas.toDataURL("image/jpeg");
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(ev)
{
document.getElementById('filesInfo').innerHTML = 'Upload Complete';
};
xhr.open('POST', 'upload-resized-photos.php', true);
xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
var data = 'image=' + dataURL;
xhr.send(data);
}
}
reader.readAsDataURL(file);
}
var _validFileExtensions = [".jpg", ".jpeg", ".bmp", ".gif", ".png"];
function Validate(oForm)
{
var arrInputs = oForm.getElementsByTagName("input");
for (var i = 0; i < arrInputs.length; i++)
{
var oInput = arrInputs[i];
if (oInput.type == "file")
{
var sFileName = oInput.value;
if (sFileName.length > 0)
{
var blnValid = false;
for (var j = 0; j < _validFileExtensions.length; j++)
{
var sCurExtension = _validFileExtensions[j];
if (sFileName.substr(sFileName.length - sCurExtension.length, sCurExtension.length).toLowerCase() == sCurExtension.toLowerCase())
{
blnValid = true;
break;
}
}
if (!blnValid)
{
alert("Sorry, " + sFileName + " is invalid, allowed extensions are: " + _validFileExtensions.join(", "));
return false;
}
}
}
}
return true;
}
You can wrap the $ajax call in a function, and call the function at the end of the final loop.
(just the top part of your script)
if (window.File && window.FileReader && window.FileList && window.Blob) {
function loopFinished(){
$.ajax
({
type: "POST",
url: "photos.php",
data: dataString,
success: function(html)
{
$("#photo-body").html(html);
}
});
}
var files = document.getElementById('filesToUpload').files;
for(var i = 0; i < files.length; i++)
{
resizeAndUpload(files[i]);
if (files.length+1 == [i]){
loopFinished();
}
}
}
You can use any promise library to do this. Here is example of using jQuery promise
(function ($) {
var files = [1, 2, 3, 4],
allPromises = [];
for (var i = 0; i < files.length; i++) {
var promise = resizeAndUpload(files[i]);
allPromises.push(promise);
}
$.when.apply($, allPromises).done(function () {
makeAjaxCall();
});
function makeAjaxCall() {
console.log('Put Ajax call here');
}
function resizeAndUpload(file) {
var defer = $.Deferred();
//Set timeout simulates your long running process of processing file
setTimeout(function () {
console.log('processing file ' + file);
defer.resolve();
}, 2000);
return defer.promise();
}
})(jQuery);
Here is a jSFiddle http://jsfiddle.net/x6oh471f/2/
One or more of the methods in your resizeAndUpload() function must be happening asynchronously. Which means they'll do their thing in the background while the rest of your javascript is run and they should fire an event when they are complete. You will want to call the ajax method once the last one of these methods has complete and event fired. For example, the fileReader methods are asychronous. Which means you will probably need to do something like:
FileReader.onloadend = function(){
totalFilesLoaded = totalFilesLoaded + 1;
if (totalFilesLoaded == files.length){
//all files have been uploaded, run $ajax
}
}
EDIT: now you have uploaded the rest of your code, try something like this:
window.totalFilesLoaded = 0;
var files = document.getElementById('filesToUpload').files;
window.totalFilesToLoad = files;
if (window.File && window.FileReader && window.FileList && window.Blob)
{
for(var i = 0; i < files.length; i++)
{
resizeAndUpload(files[i]);
}
}
Separate ajax function:
window.runAjax = function(){
$.ajax
({
type: "POST",
url: "photos.php",
data: dataString,
success: function(html)
{
$("#photo-body").html(html);
}
});
}
function resizeAndUpload(file)
{
var reader = new FileReader();
reader.onloadend = function()
{
...
xhr.onreadystatechange = function(ev)
{
document.getElementById('filesInfo').innerHTML = 'Upload Complete';
window.totalFilesLoaded++;
if (window.totalFilesLoaded == window.totalFilesToLoad.length){
window.runAjax()
}
};
...
}
reader.readAsDataURL(file);
}

canvas.toDataURL to img src

I recently downloaded an open source webcam to gif script and when the gif is created it saves as a dataurl. Is their a way I can change this? I would rather it save in a folder on the server and be something like http://example.com/folder/image.gif
Code:
*global GIFEncoder,encode64*/
var encoder = new GIFEncoder(),
video = document.querySelector('video'),
canvas = document.querySelector('canvas'),
ctx = canvas.getContext('2d'),
localMediaStream = null,
snapshotPause = 0,
recording = true,
framesPause = 120,
maxFrames = 28,
totalFrames = 0,
t;
encoder.setSize(320, 240);
encoder.setRepeat(0);
encoder.setDelay(framesPause);
encoder.setQuality(90);
window.URL = window.URL || window.webkitURL;
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
if (navigator.getUserMedia) {
navigator.getUserMedia({
audio: true,
video: true
}, function (stream) {
$('#start-image, #start-fake').hide();
$('#video, #start').show();
video.src = window.URL.createObjectURL(stream);
localMediaStream = stream;
}, function (e) {
console.log('Error:', e);
}
);
} else {
console.log('not supported');
}
function snapshot() {
if (localMediaStream) {
ctx.drawImage(video, 0, 0, 320, 240);
encoder.addFrame(ctx);
var image = $('<img />').attr('src', canvas.toDataURL('image/gif'));
$('#thumbs').append(image);
totalFrames++;
if (totalFrames === maxFrames) {
recordingEnd();
}
}
}
function recordingEnd() {
var binaryGif = encoder.stream().getData(),
dataUrl = 'data:image/gif;base64,' + encode64(binaryGif),
gif = $('<img />').attr('src', dataUrl);
totalFrames = 0;
recording = !recording;
$('#start').html('Start');
clearInterval(t);
$('#indicator').hide();
encoder.finish();
$('#result-gif').html('').append(gif);
overlayShow('preview');
//b64 = encode64(binaryGif);
}
function overlayShow(panel) {
$('.panel').hide();
$('#' + panel).show();
$('#overlay-bg').show();
$('#overlay').show();
}
function overlayHide() {
$('#overlay-bg').hide();
$('#overlay').hide();
}
$('#start').click(function () {
if (recording) {
recording = !recording;
$('#thumbs-holder-close').show();
$('#thumbs-holder').animate({
'margin-left': '320px'
}, 300);
$('#thumbs').html('');
encoder.start();
$('#indicator').show().animate({
width: '100%'
}, snapshotPause, function () {
$('#indicator').css({
'width': '0'
});
});
t = setInterval(function () {
snapshot();
$('#indicator').animate({
width: '100%'
}, snapshotPause, function () {
$('#indicator').css({
'width': '0'
});
});
}, snapshotPause);
$(this).html('Stop');
} else {
recordingEnd();
}
});
$('#thumbs-holder-close').click(function () {
$(this).hide();
$('#thumbs-holder').animate({
'margin-left': 0
}, 300);
});
$('#overlay-close').click(function () {
overlayHide();
});
$('.new').click(function () {
overlayHide();
});
$('#showSettings').click(function () {
overlayShow('settings');
});
$('input[type=range]').change(function () {
var id = $(this).attr('id'),
val = $(this).val();
$(this).next().html(val);
window[id] = parseInt(val);
if (id === 'framesPause') {
framesPause = val;
encoder.setDelay(framesPause);
}
});
$('#save').click(function () {
$.ajax({
url: 'images/save.php',
method: 'POST',
data: {
image: b64
},
dataType: 'json',
success: function(data) {
var a = $('<a />').attr('href', "images/" + data.name).html('permalink');
$('#url').append(a);
},
error: function(err) {
console.log(err);
}
});
});
##Convert your dataUrl into Blobs
function dataURLtoBlob(dataURL) {
// Decode the dataURL
var binary = atob(dataURL.split(',')[1]);
// Create 8-bit unsigned array
var array = [];
for(var i = 0; i < binary.length; i++) {
array.push(binary.charCodeAt(i));
}
// Return our Blob object
return new Blob([new Uint8Array(array)], {type: 'image/gif'});
}
/* var file= dataURLtoBlob(dataURL); */
Now, you can add the Blob as FormData and send to server
Sending data as Blob instead of dataUrl.
As bergi pointed out, the encode.stream().getData() actually returns a binary string.
var array = [];
for(var i = 0; i < binaryGIF.length; i++) {
array.push(binaryGIF.charCodeAt(i));
}
// Return our Blob object
var file = new Blob([new Uint8Array(array)], {type: 'image/gif'});
// Create new form data
var fd = new FormData();
// Append our Canvas image file to the form data
fd.append("sample-image-name-for-name-attribute", file);
// And send it
$.ajax({
url: "my-rest-endpoint",
type: "POST",
data: fd,
processData: false,
contentType: false,
}).done(function(respond){
alert(respond);
});
Hope it helps. You should be able to use the file on the server as you handle a normal file upload.

Categories