Why is this dynamic HTML5 video thumbnail generation failing in IE11? - javascript

I have a Javascript function setup to dynamically generate thumbnails from a given embedded HTML5 video once it loads. This works fine on other browsers. The problem arises with IE11. For some reason, it's just not outputting anything despite working perfectly on Firefox and Chrome.
I have a section of the site which has several HTML5 videos and they need to generate their respective thumbnails based on the first frame. I've done a good bit of researching around and I can't seem to find any IE11 compatibility issues with my code.
Here is the code I have now:
var vids = document.querySelectorAll('[id^=video-]');
for(var i = 0; i < vids.length; i++){
if(vids[i].tagName == 'VIDEO'){
$("#video-" + (i+1)).on("loadeddata", generate_handler(i+1));
}
...
}
generate_handler calls the shoot function (had to do it this way because of scoping issues in the loop),
function generate_handler(j) {
return function(event) {
shoot(j);
};
}
and the shoot function goes as follows:
function shoot(num){
var video = document.getElementById('video-' + num);
var output = document.getElementById('videothumbnail-' + num);
if(output.childNodes.length == 1){
var canvas = capture(video);
output.appendChild(canvas);
}
}
and finally, the capture function is as follows:
function capture(video) {
var canvas = document.createElement('canvas');
var w = 48;
var h = 40;
canvas.width = w;
canvas.height = h;
canvas.style.marginTop = "4px";
canvas.style.width = w + "px";
canvas.style.height = h + "px";
canvas.style.zIndex = "-999";
var ctx = canvas.getContext('2d');
ctx.drawImage(video, 0, 0, w, h);
return canvas;
}
Essentially, as a TL;DR: When the data of the video is loaded, it calls this function to shoot a screengrab and add it to the thumbnail div. In order to do that, it draws the video to a canvas. This is the order the functions are called:
on('loadeddata', generate_handler()) -> shoot() -> capture()
What's strange is that after some simple tests with console.log, it actually is reaching the inside of capture(), which inclines me to believe it's a compatibility issue with something in there, or with appendChild().
What this should do (and does do on Firefox/Chrome) is draw a 48x44px thumbnail of the HTML5 video being loaded on the page. Instead, on IE11 it displays nothing.

Related

Images not displaying the first time in this object program in JS

I am making a battleship game with polar coordinates. After the user chooses two points, a battleship should be drawn in the middle. My Battleship constructor looks like this:
function Battleship(size, location, source){
this.size = size;
//initializing the image
this.image = new Image();
this.image.src = source;
this.getMiddlePoint = function(){
//get midpoint of ship
...
}
this.distanceBetween = function(t1, t2){
//dist between two points
}
this.display = function(){
var point = [this.radius];
point.push(this.getMiddlePoint());
point = polarToReal(point[0], point[1] * Math.PI / 12);
//now point has canvas coordinates of midpoint
var width = this.distanceBetween(this.info[0][0], this.info[this.info.length-1][0]);
var ratio = this.image.width / width;
ctx.drawImage(this.image, point[0] - width/2, point[1] - this.image.height / ratio / 2, width, this.image.height / ratio);
//draws the image
}
}
The display method of each ship gets called at a certain point (after the user has chosen the location). For some reason, the images do not show the first time I do this, but when I run this code at the very end:
for(var i = 0; i<playerMap.ships.length; i++){
playerMap.ships[i].display();
}
All ships are displayed correctly (not aligned well, but they are displayed). I think there is a problem with loading the images. I am not sure how to fix this. I tried using image.onload but I never got that to work. I also tried something like this:
var loadImage = function (url, ctx) {
var img = new Image();
img.src = url
img.onload = function () {
ctx.drawImage(img, 0, 0);
}
}
but the same problem kept happening. Please help me fix this problem. Here is the game in its current condition. If you place ships, nothing happens, but after you place 5 (or 10) ships, they suddenly all load.
EDIT:
I solved the problem by globally defining the images. This is still very bad practice, since I wanted this to be in the battleship object. This is my (temporary) solution:
var sub = [];
for(var i = 1; i<5; i++){
sub[i] = new Image();
sub[i].src = "/img/ships/battleship_"+i+".png";
}

Different behaviour of WebAudio API on Google Chrome

I'm doing a sound player with a spectrum visualizer. On Firefox works very well but in Google Chrome I'm getting problems. I came from this question I made the other day My previous question
On Firefox I can go forward or go previous on the track list all the times I want without a problem, but in Google Chrome I get this error when I press "next/previous"
Failed to execute 'createMediaElementSource' on 'BaseAudioContext':
HTMLMediaElement already connected previously to a different MediaElementSourceNode.
I don't know why Google Chrome complains and Firefox doesn't. The code of the visualizer it's:
function visualizer(audio) {
closeAudioContext = true;
let src = context.createMediaElementSource(audio); // Here fails on Google Chrome
let analyser = context.createAnalyser();
let canvas = document.getElementById("canvas");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
let ctx = canvas.getContext("2d");
src.connect(analyser);
analyser.connect(context.destination);
analyser.fftSize = 2048;
let bufferLength = analyser.frequencyBinCount;
let dataArray = new Uint8Array(bufferLength);
let WIDTH = ctx.canvas.width;
let HEIGHT = ctx.canvas.height;
let barWidth = (WIDTH / bufferLength) * 1.5;
let barHeight;
let x = 0;
let color = randomColor();
function renderFrame() {
requestAnimationFrame(renderFrame);
x = 0;
analyser.getByteFrequencyData(dataArray);
ctx.clearRect(0, 0, WIDTH, HEIGHT);
for (let i = 0; i < bufferLength; i++) {
barHeight = dataArray[i];
ctx.fillStyle = color;
ctx.fillRect(x, HEIGHT - barHeight, barWidth, barHeight);
x += barWidth + 1;
}
}
renderFrame();
}
And after press the "next/previous" button I do immediately:
if (closeAudioContext && context !== undefined) {
context.close();
}
context = new AudioContext();
And then:
visualizer(audio);
musicPlay();
So my question is, why in Firefox the audio player works fine but in Google Chrome crashes?
I'm using Bowser to check what browser the user is using because as the new policy of Chrome to mute all sounds if its activated the autoplay (in this case I set the autoPlay to false and if the user press play the sound it's not muted). So, if I have to make a different code for Google Chrome I can make an "if" with that code.
Regards.
That's a bug in Chrome; you can't cannot attach an HTMLMediaElement to another MediaElementAudioSourceNode. But since you close the context and create a new one, that's another different bug in Chrome.

I cannot resize the Canvas in JavaScript

Ok, so, I'm working on a project in HTML5 and JavaScript. I'm trying to resize a Canvas, but it won't work. I don't think it's my browser, though, because I am using the latest version of FireFox. I've also researched this issue for a while, and I am confident I'm doing this correctly. So, I don't know why it won't work.
Here's my Code:
var level = 1;
var levelImg = undefined;
var width = 0;
var height = 0;
var cnvs = document.getElementById("cnvs").getContext("2d");
width = window.innerWidth
|| document.documentElement.clientWidth
|| document.body.clientWidth;
height = window.innerHeight
|| document.documentElement.cleintHeight
|| document.body.cleintHeight;
cnvs.width = width;
cnvs.height = height;
window.onload = function Init(){
levelImg = document.getElementById("level" + level);
setInterval("Draw()", 3);
}
function Draw(){
//Clear the Screen
cnvs.clearRect(0, 0, width, height);
//Draw stuff
DrawLevel();
}
function DrawLevel(){
cnvs.fillRect(0, 0, 10, 10);
}
Any help is appreciated. Thanks.
First correct all the typos in you code.
Use the browser console to detect errors.
Difference between canvas and the context
var cnvs = document.getElementById("cnvs").getContext("2d");
cnvs variable is not a canvas but the context for the canvas.
Canvas is the element and context is the object used to write in the canvas.
To access the canvas you need to do this:
var canvas = document.getElementById("cnvs");
var cnvs = canvas.getContext('2d'); //context
Now when you are trying to change the canvas with, you use canvas, not cnvs.
canvas.width = width;
canvas.height = height;
SetInterval expects a function and a number value that represents milliseconds.
"Draw()" is a string, not a function, and 3 is a really small number between each time the browser draws on canvas. It works, but it's very inefficient.
Other point about setInterval. Avoid it by using requestAnimationFrame() instead.
Take a look here: setTimeout or setInterval or requestAnimationFrame
Defining var levelImg = undefined has no utility. It can be replaced by var levelImg;

Explorer - canvas image editing issue

I'm currently building a site that comes with a set of icons. They are white .png images with a transparent area. Each image is placed over a div whose background colour changes on mouseover/mouseout events.
I wrote a small JavaScript function that I can use to set the white portion of each .png to whatever the header background colour is so that the images blend in with the header and all you see is the transparent cut-away area change on mouse events - it's quite a nice effect.
So the white portion (not the transparent part) of the image should be changed to whatever the header background colour is, and the function works really great on Firefox, but for some reason doesn't work so well on Explorer (11).
Is there something I'm not seeing here? Here's the code that does the image editing - all I need to do is pass the id of the image and the hexadecimal colour string:
function setImageBg(
imageID,
imageColor
) {
var img = document.getElementById(imageID);
var canvas = document.createElement('canvas');
// Get the red, green and blue values from the hex color
// string.
var redMix = parseInt(imageColor.substr(1, 2), 16);
var greenMix = parseInt(imageColor.substr(2, 2), 16);
var blueMix = parseInt(imageColor.substr(5, 2), 16);
canvas.width = img.width;
canvas.height = img.height;
canvas.getContext('2d').drawImage(img, 0, 0, img.width, img.height);
// Get the image data...
var pixelData = canvas.getContext('2d').getImageData(0, 0, img.width, img.height);
var imgData = pixelData.data;
var ctx = canvas.getContext('2d');
var imgDataURL;
// Edit the image data.
for (imagePos = 0; imagePos < ((img.width * img.height) * 4); imagePos += 4) {
if (pixelData.data[(imagePos + 3)] <= 99)
continue;
imgData[imagePos] = redMix;
imgData[(imagePos + 1)] = greenMix;
imgData[(imagePos + 2)] = blueMix;
}
ctx.putImageData(pixelData, 0, 0);
imgDataURL = canvas.toDataURL();
document.getElementById(imageID).src = imgDataURL;
}
Like I say, it's great on Firefox - on Explorer all I see is the div, which still dutifully changes colour on mouse events. It's as though the entire image has been made transparent.
Any help would be greatly appreciate, much obliged.
UPDATE:
Ok, so I thought I'd cracked this...here's what happened.
The problem was that the image was loading and being edited in both IE and FF, when I noticed the image had loaded and rendered in IE I thought I'd found and fixed the bug...but after a refresh the image again disappeared.
I scratched my head over it for a bit then decided I'd wasted enough time on it and brushed it aside. Now everything else is in place and working, so I'm back to this and it's a proper head scratcher.
So - IE DOES actually load and edit/render the image, when you initially open the page that is. If you refresh the page, the image disappears...or does it?
I made some adjustments to the code, using alert()'s to try and diagnose the problem, I decided what I do was add some code to check the source file - instead of diving in and changing the pixel colours - I decided to check the image before it is being edited.
Seems that, on the second run of my function - the image loaded is completely black and completely transparent. All pixels have a value of 0!
What does this mean? There's definitely something there, but not what should be.
Is htis a cacheing issue? I messed about with it for a bit, it's odd that IE will load and display the image initially but will neglect to do so after a refresh, but Ff is fine. I tried a few tricks to disable cacheing but nothing works...so now I'm thinking, perhaps it's something else.
Any ideas would be greatly appreciated, I mean it's not a deal-breaker. Everything is fine without this single feature but it's a shame if I can't get it to work.
For anyone interested, here's the updated function after various changes/edits:
function setImageBg(
imageSource,
imageSrc,
imageDst,
imageColor
) {
var img = document.getElementById(imageSrc);
var canvas = document.createElement('canvas');
var redMix = parseInt(imageColor.substr(1, 2), 16);
var greenMix = parseInt(imageColor.substr(3, 2), 16);
var blueMix = parseInt(imageColor.substr(5, 2), 16);
canvas.width = img.width;
canvas.height = img.height;
canvas.getContext('2d').drawImage(img, 0, 0, img.width, img.height);
var pixelData = canvas.getContext('2d').getImageData(0, 0, img.width, img.height);
var imgData = pixelData.data;
var ctx = canvas.getContext('2d');
var imgDataURL;
// Here's a change I made - on the first call of this function
// when the page loads, all is good - on the second call after a
// refresh this always returns on IE - it's as though the loaded
// image (from file) is completely black and transparent
// (everything is 0)...problem is the image file is never actually
// altered - the loaded image is altered but the actual file never
// changed - very odd...
//
if (pixelData.data[0] == redMix) {
if (pixelData.data[1] == greenMix) {
if (pixelData.data[2] == blueMix) {
document.getElementById(imageDst).src = document.getElementById(imageSrc).src;
return;
}
}
}
for (imagePos = 0; imagePos < ((img.width * img.height) * 4); imagePos += 4) {
if (pixelData.data[(imagePos + 3)] <= 99)
continue;
pixelData.data[imagePos] = redMix;
pixelData.data[(imagePos + 1)] = greenMix;
pixelData.data[(imagePos + 2)] = blueMix;
}
ctx.putImageData(pixelData, 0, 0);
document.getElementById(imageDst).src = canvas.toDataURL();
return true;
}

HTML 5 Canvas Image Rendering

First time poster here but definitely not a first time reader.
My question is aimed directly at this portion of code I have. I am currently learning how HTML 5 canvases work and am designing my own RPG style game for a University project. After looking around I found some good tutorials on this guys blog, I have followed his code and triple checked it but images are now showing up.
I tried putting an alert() before and after when the image is called to the canvas under drawMap(). It works before the image is drawn but not after, leading me to believe it is something to do with my image rendering. Can someone double check my code and see what is going on? It's driving me insane!
<canvas id="game-viewport" width="760" height="440"></canvas>
<script>
window.onload = init;
var map = Array([0,0],[0,0],[0,0],[0,0]);
var tileSize = 40;
tileTypes = Array("grass.png");
tileImage = new Array();
var loaded = 0;
var loadTimer;
function loadImage(){
for(i = 0; i < tileTypes.length; i++){
tileImage[i] = new Image();
tileImage[i].src = "./game/lib/icons/own_icons/" + tileTypes[i];
tileImage[i].onload = function(){
loaded++;
}
}
}
function loadAll(){
if(loaded == tileTypes.length){
clearInterval(loadTimer);
drawMap();
}
}
function drawMap(){
var mapX = 80;
var mapY = 10;
for(i = 0; i < map.length; i++){
for(j = 0; j < map[i].length; j++){
var drawTile = map[i][j];
var xPos = (i - j) * tileSize;
var yPos = (i + j) * tileSize;
ctx.drawImage(tileImage[drawTile], xPos, yPos);
}
}
}
function init(){
var canvas = document.getElementById('game-viewport')
var ctx = canvas.getContext('2d');
loadImage();
loadTimer = setInterval(loadAll, 100);
}
</script>
The only problem is that ctx is not defined in your drawMap function.
Either pass ctx in to the function as an argument or make it a global variable.
I was lazy and did the second, but you should really do the first. Working code:
http://jsfiddle.net/YUddC/
You really should have the Chrome debugger (or whatever browser you use) on 100% of the time you're developing.. If you did, you'd see an error saying that ctx is not defined in drawMap. If you're using Chrome and press F12 to open developer tools and go to the scripts tab, you'd see this:
Which makes the problem pretty clear!

Categories