HTML5/Canvas onDrop event isn't firing? - javascript

I'm playing with file upload, drag and drop, and canvas, but for some reason the ondrop function never seems to run, here's the fiddle I'm working in: http://jsfiddle.net/JKirchartz/E4yRv/
the relevant code is :
canvas.ondrop = function(e) {
e.preventDefault();
var file = e.dataTransfer.files[0],
reader = new FileReader();
reader.onload = function(event) {
var img = new Image(),
imgStr = event.target.result;
state.innerHTML += ' Image Uploaded: <a href="' +
imgStr + '" target="_blank">view image</a><br />';
img.src = event.target.result;
img.onload = function(event) {
context.height = canvas.height = this.height;
context.width = canvas.width = this.width;
context.drawImage(this, 0, 0);
state.innerHTML += ' Canvas Loaded: view canvas<br />';
};
};
reader.readAsDataURL(file);
return false;
};
why doesn't this event fire? I've tried it in firefox and chrome.

In order to get the drop event to fire at all you need to have an ondragover function:
canvas.ondragover = function(e) {
e.preventDefault();
return false;
};
If you try to drag your cat picture into the canvas it'll still not work, this error is reported in the Firefox console:
[04:16:42.298] uncaught exception: [Exception... "Component returned failure code: 0x80004003 (NS_ERROR_INVALID_POINTER) [nsIDOMFileReader.readAsDataURL]" nsresult: "0x80004003 (NS_ERROR_INVALID_POINTER)" location: "JS frame :: http://fiddle.jshell.net/_display/ :: <TOP_LEVEL> :: line 57" data: no]
However it will work if you drag an image from your desktop. I think for images in the page you should use regular DOM access methods, the File API is only needed for external files dragged into the browser.

As far as I can tell, robertc's answer is how browsers continue to behave, you have to have an ondragover function set.
But to expand on it slightly, the function must return false and not true or undefined-- no-op functions will return undefined. It doesn't seem to matter whether you prevent default, the ondrop event handler will trigger. You will want a preventDefault in the ondrop function, otherwise the file will be immediately downloaded to your browser's default download folder:
document.getElementById('drop-zone').ondragover = function(e) {
return false;
}
document.getElementById('drop-zone').ondrop = function(e) {
e.preventDefault();
console.log('ondrop', e);
}
#drop-zone {
border: solid;
height: 3em;
width: 10em;
}
<div id="drop-zone">Drop zone</div>

Related

Cannot read drag and dropped file with FileReader

I am attempting to allow for an image to be uploaded to my site via a drag and drop to my site by dragging and dropping an image onto a specific div on the page:
<div class="container" (drop)="onDrop($event)" (dragover)="onDragOver($event)" (dragleave)="onDragLeave($event)">
<img id="blah" [src]="url || 'http://placehold.it/180'" alt="your image" />
</div>
I have all of the drop related events fiting, I however been unable to actually get the image from FileReader:
What am I doing wrong? my drop related functions from the controller are below for reference.
onDrop(event) {
event.preventDefault();
event.stopPropagation();
this.file = event.dataTransfer.files[0];
const reader = new FileReader();
reader.onload = e => {
this.url = reader.result;
console.log(this.url);
};
reader.readAsDataURL(this.file);
this.fileDraggedOverDiv = false;
}
onDragOver(event) {
event.stopPropagation();
event.preventDefault();
this.fileDraggedOverDiv = true;
return false;
}
onDragLeave(event) {
event.stopPropagation();
event.preventDefault();
this.fileDraggedOverDiv = false;
return false;
}
You are actually successfully passing the file to the onDrop event. Its just that you can't see it when console.log(JSON.stringify(event)); executes, because inherited properties, and non-enumerable properties, are left out as pointed out in this discussion.
To get the image from the event you need to do as follows.
onDrop(event) {
event.preventDefault();
const file = event.dataTransfer.files[0];
}
See this stackblitz for a full working example.

Electron works unexpectedly with updating component's style

The code below works perfectly in browser, but not in Electron env.
function listenFileInput() {
fileInput.addEventListener('change', ev => {
startProgress();
const file = ev.target.files[0];
if (!file) return clearProgress();
loadImage(file);
});
}
function loadImage(file) {
const image = new Image();
image.onload = function() {
const src = cropImage(this);
cardImage.src = src;
clearProgress();
};
image.src = window.URL.createObjectURL(file);
}
function startProgress() {
fileBtn.setAttribute('disabled', true);
fileInput.setAttribute('disabled', true);
progress.style.display = 'flex';
}
function clearProgress() {
fileBtn.removeAttribute('disabled');
fileInput.removeAttribute('disabled');
progress.style.display = 'none';
}
In Electron env, when the file is loaded, the progress doesn't show up.
After do some tests, I found some interesting phenomenon:
If I comment the image.onload = function() {...} block, it works properly.
If I add alert() in onChange event callback or startProgress function, after alerting, the progress appears as expected.
If I comment clearProgress(); in image.onload callback, after the image was loaded, the progress appears.
So, it seems that the setAttribute and style.display didn't work (or Electron didn't re-render the page) until the image was loaded, unless there's an alert disturbs the process.
I've pushed the complete code to GitHub (/lib/file.js).

FileReader not working on iOS 8

I can't get FileReader to work in iOS 8. The following demo illustrates this (jsFiddle link for iOS - http://jsfiddle.net/gys6rubg/1/):
var file = document.getElementById('file-input');
file.addEventListener('change', function(event) {
var file = this.files[0];
if(!file) {
alert('No file');
return;
}
var reader = new FileReader();
var timeout = setTimeout(function() {
alert('FileReader not functioning');
}, 500);
reader.onload = function(event) {
clearTimeout(timeout);
alert('Base64 length - ' + event.target.result.length);
};
reader.readAsDataURL(file);
});
<form>
<input id="file-input" type="file" />
</form>
This console.log's the length of the Base64 string in most browsers, but on iOS 8 Safari it console.log's 'FileReader not functioning'.
Is there any way around this, or anything I'm doing wrong?
I am having the same problem with Safari on iPhone (but the problem is not present on Chrome for iPhone!).
If you add the error event handler:
reader.onerror = function (e) {
alert("error " + e.target.error.code + " \n\niPhone iOS8 Permissions Error.");
}
you will get error code 4.
According to HTMLGoodies - Responding to HTML5 FileReader Events
Error Code 4 = NOT_READABLE_ERR: The file could not be read because of a change to permissions since the file was acquired - likely because the file was locked by another program.
it's a bug
should be fixed in the next release

image.onload event and browser cache

I want to create an alert box after an image is loaded, but if the image is saved in the browser cache, the .onload event will not be fired.
How do I trigger an alert when an image has been loaded regardless of whether the image has been cached or not?
var img = new Image();
img.src = "img.jpg";
img.onload = function () {
alert("image is loaded");
}
As you're generating the image dynamically, set the onload property before the src.
var img = new Image();
img.onload = function () {
alert("image is loaded");
}
img.src = "img.jpg";
Fiddle - tested on latest Firefox and Chrome releases.
You can also use the answer in this post, which I adapted for a single dynamically generated image:
var img = new Image();
// 'load' event
$(img).on('load', function() {
alert("image is loaded");
});
img.src = "img.jpg";
Fiddle
If the src is already set then the event is firing in the cached case before you even get the event handler bound. So, you should trigger the event based off .complete also.
code sample:
$("img").one("load", function() {
//do stuff
}).each(function() {
if(this.complete || /*for IE 10-*/ $(this).height() > 0)
$(this).load();
});
There are two possible solutions for these kind of situations:
Use the solution suggested on this post
Add a unique suffix to the image src to force browser downloading it again, like this:
var img = new Image();
img.src = "img.jpg?_="+(new Date().getTime());
img.onload = function () {
alert("image is loaded");
}
In this code every time adding current timestamp to the end of the image URL you make it unique and browser will download the image again
I have met the same issue today. After trying various method, I realize that just put the code of sizing inside $(window).load(function() {}) instead of document.ready would solve part of issue (if you are not ajaxing the page).
I found that you can just do this in Chrome:
$('.onload-fadein').each(function (k, v) {
v.onload = function () {
$(this).animate({opacity: 1}, 2000);
};
v.src = v.src;
});
Setting the .src to itself will trigger the onload event.

js syntax error when invoking mouseover callback

I have some javascript code that creates an img tag with a mouseover callback, and adds the img tag to the page. The problem is that a javascript syntax error happens (in the Firefox Console) whenever the callback is invoked.
This code demonstrates the problem...
var imgUrl = 'http://sstatic.net/so/img/logo.png';
var img = document.createElement('img');
img.setAttribute('src', imgUrl);
img.setAttribute('onmouseover', function() {
alert('mouseover ' + imgUrl);
});
document.body.appendChild(img);
The syntax error even happens when the callback function is an empty function.
Can anyone explain what's causing the syntax error and how to fix it?
(I'm using FF 3.5.2 on Win XP.)
You're passing in a function where a string is expected. Try this instead:
var imgUrl = 'http://sstatic.net/so/img/logo.png';
var img = document.createElement('img');
img.src = imgUrl;
img.onmouseover = function() {
alert('mouseover ' + imgUrl);
};
document.body.appendChild(img);

Categories

Resources