Event Listeners MSPointer are not firing - javascript

I am currently trying to learn Javascript and doing the following tutorial (http://www.sitepoint.com/creating-a-simple-windows-8-game-with-javascript-input-and-sound/) however I have run into an issue that I cannot get past.
I have created a canvas element, attached three listeners to the canvas to work with mouse clicks:
canvas.addEventListener("MSPointerUp", endAim, false);
canvas.addEventListener("MSPointerMove", adjustAim, false);
canvas.addEventListener("MSPointerDown", beginAim, false);
But my functions are never being called on PointerUp or Down or Move.
Below are the functions in question, also note that I have done "console.log" just to debug.. None of those are being even recorded to the console, which is why I am thinking that the events are not being triggered..
function beginAim(event){
console.log("Aim ahoy");
if (playerTurn == 1) {
if (!isAiming) {
aimStart = new createjs.Point(event.x, event.y);
isAiming = true;
}
}
}
function adjustAim(event){
console.log("adjustAim event called");
if (isAiming) {
var aimCurrent = new createjs.Point(event.x, event.y);
aimVector = calculateAim(aimStart, aimCurrent);
//ToDo: write text / show aim arror
console.log("Aiming... " + aimVector.x + "/" + aimVector.y);
}
}
function endAim(event){
if (isAiming) {
console.log("endAim Function called");
isAiming = false;
var aimCurrent = new createjs.Point(event.x, event.y);
aimVector = calculateAim(aimStart, aimCurrent);
playerFire = true;
}
}
function calculateAim(start, end){
var aim = new createjs.Point(
(end.x - start.x) / 80,
(end.y - start.y) / 80);
aim.x = Math.min(MAX_SHOT_POWER, aim.x);
aim.x = Math.max(0, aim.x);
aim.y = Math.max(-MAX_SHOT_POWER, aim.y);
aim.y = Math.min(0, aim.y);
return aim;
}
I knew this was going to be a simple issue.. The MSPointerUp /Down / Move are all for Windows8, this is why they never triggered.
I ended up switching to mousedown, mouseup, and mousemove to get the same results.

add to body or canvas to route touch events to JavaScript:
body, canvas {
-ms-user-select: none;
touch-action: none;
}
Then, you'll need to create a MSGesture object, set its target to canvas, also create a pointerdown listener:
var gesture = new MSGesture();
gesture.target = canvas;
canvas.addEventListener("pointerdown", beginAim, false)
in beginAim add a handler for pointerdown and add it to gesture like this:
if (event.type == "pointerdown") {
gesture.addPointer(e.pointerId);
return
}

Related

Intercept calls to HTML5 canvas element

I have a WEB application, that renders it's entire User Interface in an HTML5 canvas.
Note that I can't change the current application.
Currently, this application is being tested using Selenium.
This is done by simulating a click event at a given location in the browser window.
After the click has been executed, a sleep of 2 seconds is being performed to ensure that the entire UI is ready before moving to the next step.
Due to all the 'wait' statements, testing the application is very slow.
Therefore, I thought it was an idea to intercept all calls to the HTML5 canvas.
That way I can rely on the triggered events to know if the UI is ready to move to the next step.
Assume that I have the following code in my application that renders the canvas.
var canvas = document.getElementById("canvasElement");
var ctx = canvas.getContext("2d");
ctx.fillStyle = "green";
ctx.fillRect(10, 10, 100, 100);
Is there a way to intercept the 'fillRect' event?
I tought something along the lines:
var canvasProxy = document.getElementById("canvasElement");
canvasProxy.addEventListener("getContext", function(event) {
console.log("Hello");
});
var canvas = document.getElementById("canvasElement");
var ctx = canvas.getContext("2d");
ctx.fillStyle = "green";
ctx.fillRect(10, 10, 100, 100);
Unforuntately this is not working.
I've created a JSFiddle to play with the example.
https://jsfiddle.net/5cknym74/4/
Amy toughts?
I played a bit around with the JS API and it seems that the following might be working:
// SECTION: Store a reference to all the HTML5 'canvas' element methods.
HTMLCanvasElement.prototype._captureStream = HTMLCanvasElement.prototype.captureStream;
HTMLCanvasElement.prototype._getContext = HTMLCanvasElement.prototype.getContext;
HTMLCanvasElement.prototype._toDataURL = HTMLCanvasElement.prototype.toDataURL;
HTMLCanvasElement.prototype._toBlob = HTMLCanvasElement.prototype.toBlob;
HTMLCanvasElement.prototype._transferControlToOffscreen = HTMLCanvasElement.prototype.transferControlToOffscreen;
HTMLCanvasElement.prototype._mozGetAsFile = HTMLCanvasElement.prototype.mozGetAsFile;
// SECTION: Patch the HTML5 'canvas' element methods.
HTMLCanvasElement.prototype.captureStream = function(frameRate) {
console.log('INTERCEPTING: HTMLCanvasElement.prototype.captureStream');
return this._captureStream(frameRate);
}
HTMLCanvasElement.prototype.getContext = function(contextType, contextAttributes) {
console.log('INTERCEPTING: HTMLCanvasElement.prototype.getContext');
console.log('PROPERTIES:');
console.log(' contextType: ' + contextType);
return this._getContext(contextType, contextAttributes);
}
HTMLCanvasElement.prototype.toDataURL = function(type, encoderOptions) {
console.log('INTERCEPTING: HTMLCanvasElement.prototype.toDataURL');
return this._toDataURL(type, encoderOptions);
}
HTMLCanvasElement.prototype.toBlob = function(callback, mimeType, qualityArgument) {
console.log('INTERCEPTING: HTMLCanvasElement.prototype.toBlob');
return this._toBlob(callback, mimeType, qualityArgument);
}
HTMLCanvasElement.prototype.transferControlToOffscreen = function() {
console.log('INTERCEPTING: HTMLCanvasElement.prototype.transferControlToOffscreen');
return this._transferControlToOffscreen();
}
HTMLCanvasElement.prototype.mozGetAsFile = function(name, type) {
console.log('INTERCEPTING: HTMLCanvasElement.prototype.mozGetAsFile');
return this._mozGetAsFile(name, type);
}
Now that I can intercept the calls, I can find out which calls are responsible that draw a button and react accordingly.

Trigger mousemove event using Jquery or Javascript

Hi I know we can trigger click event . but I want to know that can we trigger mousemove event without any actual mouse movement by user.
Description :
I want to show a message when user select something. on canvas ,my canvas is of full height and width,when user click on a button the canvas shows up. when user do mouse movement he see a message "Click and drag on any part of the web page". this message follows the mouse movement of the user.
What I want to do :
When user click the button he should see the message that "Click and drag on any part of the web page". and message must follow wherever user moves the mouse.
Problem :
User is not able to see the message after click until he/she moves his mouse.
Code:
function activateCanvas() {
var documentWidth = jQ(document).width(),
documentHeight = jQ(document).height();
jQ('body').prepend('<canvas id="uxa-canvas-container" width="' + documentWidth + '" height="' + documentHeight + '" ></canvas><form method="post" id="uxa-annotations-container"></form>');
canvas = new UXAFeedback.Canvas('uxa-canvas-container', {
containerClass: 'uxa-canvas-container',
selection: false,
defaultCursor: 'crosshair'
});
jQ(function() {
var canvas = jQ('.upper-canvas').get(0);
var ctx = canvas.getContext('2d');
var x,y;
var tooltipDraw = function(e) {
ctx.save();
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.restore();
x = e.pageX - canvas.offsetLeft;
y = e.pageY - canvas.offsetTop;
var str = 'Click and drag on any part of the webpage.';
ctx.fillStyle = '#ddd';
ctx.fillRect(x + 10, y - 60, 500, 40);
ctx.fillStyle = 'rgb(12, 106, 185)';
ctx.font = 'bold 24px verdana';
ctx.fillText(str, x + 20, y - 30, 480);
};
canvas.addEventListener('onfocus',tooltipDraw,0);
canvas.addEventListener('mousemove',tooltipDraw,0);
canvas.addEventListener('mousedown', function() {
canvas.removeEventListener('mousemove', tooltipDraw, false);
ctx.save();
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.restore();
}, false);
});
}
jQ('body').on('click', '.mood_img_div', function() {
// alert("soemthing");
toggleOverlay();
activateCanvas();
});
I have made a function which is called after click but the message is not visible. Is there any way to call it for the first time with message and show is everytime when user uses mouse.
I have replaced jQuery with jQ because I am making my own plugin(this is not causing the problem)
A good native approach is to use dispatchEvent method on EventTarget.
It dispatches an Event at the specified EventTarget, invoking the affected EventListeners in the appropriate order. The normal event processing rules (including the capturing and optional bubbling phase) also apply to events dispatched manually with dispatchEvent().
Try
// 1. Add an event listener first
canvas.addEventListener('mousemove', tooltipDraw ,0);
// 2. Trigger this event wherever you wish
canvas.dispatchEvent(new Event('mousemove'));
in your case it should trigger mousemove event on canvas element.
(Triggering events in vanilla JavaScript article can be also useful):
var elem = document.getElementById('elementId');
elem.addEventListenter('mousemove', function() {
// Mousemove event callback
}, 0);
var event = new Event('mousemove'); // (*)
elem.dispatchEvent(event);
// Line (*) is equivalent to:
var event = new Event(
'mousemove',
{ bubbles: false, cancelable: false });
jQuery:
Try this with jQuery trigger method:
$('body').bind('mousemove',function(e){
// Mousemove event triggered!
});
$(function(){
$('body').trigger('mousemove');
});
OR (if you need triggering with coords)
event = $.Event('mousemove');
// coordinates
event.pageX = 100;
event.pageY = 100;
// trigger event
$(document).trigger(event);
OR
Try using .mousemove() jQuery method
let coordX = 0; // Moving from the left side of the screen
let coordY = window.innerHeight / 2; // Moving in the center
function move() {
// Move step = 20 pixels
coordX += 20;
// Create new mouse event
let ev = new MouseEvent("mousemove", {
view: window,
bubbles: true,
cancelable: true,
clientX: coordX,
clientY: coordY
});
// Send event
document.querySelector('Put your element here!').dispatchEvent(ev);
// If the current position of the fake "mouse" is less than the width of the screen - let's move
if (coordX < window.innerWidth) {
setTimeout(() => {
move();
}, 10);
}
}
// Starting to move
move();
Albeit it is probably possible to mimic such an event as shown in Andrii Verbytskyi's answer, most of the time, when you want to do it, it is because of an "X-Y problem".
If we take OP's case for instance, here we absolutely don't need to trigger this mousemove event.
Pseudo-code of current implementation :
function mousemoveHandler(evt){
do_something_with(evt.pageX, e.pageY);
}
element.addEventListener('mousemove', mousemoveHandler)
function clickHandler(evt){
do_something_else();
}
element.addEventListener('click', clickHandler);
And what we want is to also call do_something_with in the click handler.
So OP spends some time to find a way to trigger a fake mousemove, spends another amount of time trying to implement it, while all that is needed is to add a call to do_something_with in clickHandler.
Both mousemove and click events have these pageX and pageY properties, so the event can be passed has is, but in other case, we could also just want to pass it with a fake object containing required properties.
function mousemoveHandler(evt){
do_something_with(evt.pageX, evt.pageY);
}
element.addEventListener('mousemove', mousemoveHandler)
function clickHandler(evt){
do_something_else();
do_something_with(evt.pageX, evt.pageY);
}
element.addEventListener('click', clickHandler);
// here we won't have pageX nor pageY properties
function keydownHandler(evt){
do_something_else();
// create a fake object, which doesn't need to be an Event
var fake_evt = {pageX: someValue, pageY: someValue};
do_something_with(fake_evt.pageX, fake_evt.pageY);
}
element.addEventListener('keydown', keydownHandler);
Note : you are mixing jQuery.on and element.addEventListener, so you might need to pass the originalEvent property of the jQuery event object.

EaselJS: add child with mousedown triggered

The basic functionality I'm going for is...
Tap (mousedown) on the stage to create and add a child at that location.
*EDIT: I'm also trying to solve for multitouch, so multiple balls can be created at the same time.
As you hold down you can drag (pressmove) that child around and it grows (using regX/regY/scaleX/scaleY) until you release (pressup), at which point it falls (using a tick cycle).
I have everything sort of working, but I've hit a snag wherein I can't add a child and have it immediately register mousedown without releasing and pressing again.
Is there a way to manually trigger mousedown after adding, or some other workaround that makes more sense? dispatchEvent doesn't seem to be working.
Here's my stage event listener and touch bits:
stage.enableMouseOver(10);
createjs.Touch.enable(stage, false, false);
stage.preventSelection = false;
stage.addEventListener("stagemousedown", spawnsnowball);
And here are my functions. The spawnsnowball one includes displayObject event listeners verging on desperate, but the only way I've been able to get the pressmove and pressup working is to click on the same snowball again. releasesnowball right now just releases all instances of them (using a 'stagemouseup' listener), but if I can get it triggering off of pressup then I'll rewrite it to target just the event target.
function spawnsnowball(evt){
var ball = new createjs.Bitmap(loader.getResult("snowball"));
ball.crossOrigin="Anonymous";
ball.name="ball";
ball.scaleX = 0.5;
ball.scaleY = ball.scaleX;
ball.regX = ball.image.width/2;
ball.regY = ball.image.height/2;
ball.x = evt.stageX;
ball.y = evt.stageY;
ball.type = balltype;
ball.holding = 1;
ball.velX = 0;
ball.velY = 0;
ball.addEventListener("pressup",releasesnowball);
ball.addEventListener("pressmove",dragsnowball);
ball.onPress = function(mouseEvent) {};
stage.addChild(ball);
ball.dispatchEvent("mousedown");
ball.dispatchEvent("pressdown");
}
function dragsnowball(evt){
evt.target.x = evt.stageX;
evt.target.y = evt.stageY;
}
function releasesnowball(evt){
for(var i=0;i<stage.getNumChildren();i++){
var shape = stage.getChildAt(i);
if(shape.type == balltype){
if(shape.holding){
shape.holding = 0;
var dX = shape.x - shape.oldX;
var dY = shape.y - shape.oldY;
if(Math.abs(dY)>8)
dY = 8*dY/Math.abs(dY);
if(Math.abs(dX)>3)
dX = 3*dX/Math.abs(dX);
}
}
}
}
The pressmove event is special because it basically stores off the target of the last mousedown event, and then remembers it for pressmove and pressup events.
This means you can't really fake the event by forcing mouse events. Dispatching a mouse event from the target will not do the trick.
Instead, consider just handling the initial drag manually. You already know what you want to be the target of the pressmove, so you can listen for the stagemousemove event, and handle it yourself:
// Listen to the stagemousemove and manually call the event.
var initialDrag = stage.on("stagemousemove", function(event) {
event.target = ball; // Re-target the event so your other method works fine.
dragsnowball(event);
});
// When done, remove the move listener.
// The off() method supports a "once" parameter so you don't have to unsubscribe that listener.
stage.on("stagemouseup", function(event) {
stage.off("stagemousemove", initialDrag);
}, null, true); // Fires one time
Here is a quick sample using your code as the base: http://jsfiddle.net/3qhmur82/
I also added some comments in the demo which might be useful.
Hope that helps!

setAbstractView() prevents mousedown events from propagating to KmlFeatures

Using the Google Earth plugin, I want to be able to allow the user to select placemarks on the ground while the camera is moving, but am not sure how this is possible. It seems that when you call setAbstractView(), even with the flyToSpeed set to SPEED_TELEPORT, the Google Earth plugin ignores any mouse down events except for those to the GEGlobe.
Here's the code, altered slightly (from http://code.google.com/apis/ajax/playground/#draggable_placemark) to illustrate my issue:
var ge;
var placemark;
var dragInfo = null;
var la;
var lat = 37;
var lon = -122;
google.load("earth", "1");
function init() {
google.earth.createInstance('map3d', initCallback, failureCallback);
}
function tick() {
la.set(lat, lon,
0, // altitude
ge.ALTITUDE_RELATIVE_TO_GROUND,
0, // heading
0, // straight-down tilt
5000 // range (inverse of zoom)
);
ge.getView().setAbstractView(la);
lon = lon + 0.00000001;
}
function initCallback(instance) {
ge = instance;
ge.getWindow().setVisibility(true);
// add a navigation control
ge.getNavigationControl().setVisibility(ge.VISIBILITY_AUTO);
// add some layers
ge.getLayerRoot().enableLayerById(ge.LAYER_BORDERS, true);
ge.getLayerRoot().enableLayerById(ge.LAYER_ROADS, true);
// create the placemark
placemark = ge.createPlacemark('');
var point = ge.createPoint('');
point.setLatitude(lat);
point.setLongitude(lon);
placemark.setGeometry(point);
// add the placemark to the earth DOM
ge.getFeatures().appendChild(placemark);
// look at the placemark we created
la = ge.createLookAt('');
placemark.setName('Drag Me!');
ge.getOptions().setFlyToSpeed(ge.SPEED_TELEPORT);
tick();
// Comment this next line out and the drag works as expected.
google.earth.addEventListener(ge, "frameend", tick);
// listen for mousedown on the window (look specifically for point placemarks)
google.earth.addEventListener(ge.getWindow(), 'mousedown', function(event) {
console.log("target type = " + event.getTarget().getType());
if (event.getTarget().getType() == 'KmlPlacemark' &&
event.getTarget().getGeometry().getType() == 'KmlPoint') {
//event.preventDefault();
var placemark = event.getTarget();
dragInfo = {
placemark: event.getTarget(),
dragged: false
};
}
});
// listen for mousemove on the globe
google.earth.addEventListener(ge.getGlobe(), 'mousemove', function(event) {
if (dragInfo) {
event.preventDefault();
var point = dragInfo.placemark.getGeometry();
point.setLatitude(event.getLatitude());
point.setLongitude(event.getLongitude());
dragInfo.dragged = true;
}
});
// listen for mouseup on the window
google.earth.addEventListener(ge.getWindow(), 'mouseup', function(event) {
if (dragInfo) {
if (dragInfo.dragged) {
// if the placemark was dragged, prevent balloons from popping up
event.preventDefault();
}
dragInfo = null;
}
});
document.getElementById('installed-plugin-version').innerHTML =
ge.getPluginVersion().toString();
}
function failureCallback(errorCode) {
}
​
If you comment out line 56, where tick() is called at each frameend, everything works as in the unaltered code: you can successfully drag the place mark. But when line 56 is in, you can't. So the problem is really with setAbstractView keeping mousedown events from propagating to either the globe or whatever placemark or feature was being clicked.
Any ideas? Is there a workaround for this?
The issue isn't caused by the setAbstractView method, it is caused because of the repeated calls to the tick method via framend.
To explain, you have set up the tick method as an event handler for the frameend event.
Then the tick method updates the view immediately, triggering the frameend event, ad infinitum ...
This pattern causes an issue with the browser message loop, in effect it is blocking the other drag events. Think of it like a very tight loop that is causing a deadlock. To work it you can use setTimeout with a value of 0 to execute the code. This way the animation won't be processed until all other pending drag messages are processed.
The key part is a the modification to your tick() method.
function tick() {
// prevent deadlock
setTimeout(function () {
la.set(lat, lon, 0, ge.ALTITUDE_RELATIVE_TO_GROUND, 0, 0, 5000);
ge.getView().setAbstractView(la);
lon += 0.00001;
}, 0);
};
Here, I made a fully working example for you http://jsfiddle.net/fraser/JFLaT/
I tested it and it is working in Chrome, IE, Firefox on Windows 8 and Chrome, Safari, Firefox on OSX.

Ask for microphone on onclick event

The other day I stumbled upon with this example of a Javascript audio recorder:
http://webaudiodemos.appspot.com/AudioRecorder/index.html
Which I ended up using for implementing my own. The problem I'm having is that in this file:
var audioContext = new webkitAudioContext();
var audioInput = null,
realAudioInput = null,
inputPoint = null,
audioRecorder = null;
var rafID = null;
var analyserContext = null;
var canvasWidth, canvasHeight;
var recIndex = 0;
/* TODO:
- offer mono option
- "Monitor input" switch
*/
function saveAudio() {
audioRecorder.exportWAV( doneEncoding );
}
function drawWave( buffers ) {
var canvas = document.getElementById( "wavedisplay" );
drawBuffer( canvas.width, canvas.height, canvas.getContext('2d'), buffers[0] );
}
function doneEncoding( blob ) {
Recorder.forceDownload( blob, "myRecording" + ((recIndex<10)?"0":"") + recIndex + ".wav" );
recIndex++;
}
function toggleRecording( e ) {
if (e.classList.contains("recording")) {
// stop recording
audioRecorder.stop();
e.classList.remove("recording");
audioRecorder.getBuffers( drawWave );
} else {
// start recording
if (!audioRecorder)
return;
e.classList.add("recording");
audioRecorder.clear();
audioRecorder.record();
}
}
// this is a helper function to force mono for some interfaces that return a stereo channel for a mono source.
// it's not currently used, but probably will be in the future.
function convertToMono( input ) {
var splitter = audioContext.createChannelSplitter(2);
var merger = audioContext.createChannelMerger(2);
input.connect( splitter );
splitter.connect( merger, 0, 0 );
splitter.connect( merger, 0, 1 );
return merger;
}
function toggleMono() {
if (audioInput != realAudioInput) {
audioInput.disconnect();
realAudioInput.disconnect();
audioInput = realAudioInput;
} else {
realAudioInput.disconnect();
audioInput = convertToMono( realAudioInput );
}
audioInput.connect(inputPoint);
}
function cancelAnalyserUpdates() {
window.webkitCancelAnimationFrame( rafID );
rafID = null;
}
function updateAnalysers(time) {
if (!analyserContext) {
var canvas = document.getElementById("analyser");
canvasWidth = canvas.width;
canvasHeight = canvas.height;
analyserContext = canvas.getContext('2d');
}
// analyzer draw code here
{
var SPACING = 3;
var BAR_WIDTH = 1;
var numBars = Math.round(canvasWidth / SPACING);
var freqByteData = new Uint8Array(analyserNode.frequencyBinCount);
analyserNode.getByteFrequencyData(freqByteData);
analyserContext.clearRect(0, 0, canvasWidth, canvasHeight);
analyserContext.fillStyle = '#F6D565';
analyserContext.lineCap = 'round';
var multiplier = analyserNode.frequencyBinCount / numBars;
// Draw rectangle for each frequency bin.
for (var i = 0; i < numBars; ++i) {
var magnitude = 0;
var offset = Math.floor( i * multiplier );
// gotta sum/average the block, or we miss narrow-bandwidth spikes
for (var j = 0; j< multiplier; j++)
magnitude += freqByteData[offset + j];
magnitude = magnitude / multiplier;
var magnitude2 = freqByteData[i * multiplier];
analyserContext.fillStyle = "hsl( " + Math.round((i*360)/numBars) + ", 100%, 50%)";
analyserContext.fillRect(i * SPACING, canvasHeight, BAR_WIDTH, -magnitude);
}
}
rafID = window.webkitRequestAnimationFrame( updateAnalysers );
}
function gotStream(stream) {
// "inputPoint" is the node to connect your output recording to.
inputPoint = audioContext.createGainNode();
// Create an AudioNode from the stream.
realAudioInput = audioContext.createMediaStreamSource(stream);
audioInput = realAudioInput;
audioInput.connect(inputPoint);
// audioInput = convertToMono( input );
analyserNode = audioContext.createAnalyser();
analyserNode.fftSize = 2048;
inputPoint.connect( analyserNode );
audioRecorder = new Recorder( inputPoint );
zeroGain = audioContext.createGainNode();
zeroGain.gain.value = 0.0;
inputPoint.connect( zeroGain );
zeroGain.connect( audioContext.destination );
updateAnalysers();
}
function initAudio() {
if (!navigator.webkitGetUserMedia)
return(alert("Error: getUserMedia not supported!"));
navigator.webkitGetUserMedia({audio:true}, gotStream, function(e) {
alert('Error getting audio');
console.log(e);
});
}
window.addEventListener('load', initAudio );
As you might be able to see, the initAudio() function (the one wich ask the user for permission to use his/her microphone) is called inmediately when the page is loaded (read the last line) with this method:
window.addEventListener('load', initAudio );
Now, I have this code in the HTML:
<script type="text/javascript" >
$(function() {
$("#recbutton").on("click", function() {
$("#entrance").hide();
$("#live").fadeIn("slow");
toggleRecording(this);
$(this).toggle();
return $("#stopbutton").toggle();
});
return $("#stopbutton").on("click", function() {
audioRecorder.stop();
$(this).toggle();
$("#recbutton").toggle();
$("#live").hide();
return $("#entrance").fadeIn("slow");
});
});
</script>
And as you can see, I call the toggleRecording(this) function (the one wich starts the recording process) only after the #recbutton is pressed. Now, everything works fine with this code BUT, the user gets prompted for microphone permission as soon as the page is loaded and I want to ask them for permission to use the microphone ONLY AFTER they clicked the #recbutton Do you understand me? I tought that if I remove the last line of the first file:
window.addEventListener('load', initAudio );
and modify my embedded script like this:
<script type="text/javascript" >
$(function() {
$("#recbutton").on("click", function() {
$("#entrance").hide();
$("#live").fadeIn("slow");
initAudio();
toggleRecording(this);
$(this).toggle();
return $("#stopbutton").toggle();
});
return $("#stopbutton").on("click", function() {
audioRecorder.stop();
$(this).toggle();
$("#recbutton").toggle();
$("#live").hide();
return $("#entrance").fadeIn("slow");
});
});
</script>
I might be able to achieve what I wanted, and actually I am, the user doesn't get prompted for his/her microphone until they click the #recbutton. The problem is, the audio never get's recorded, when you try to download it, the resulting WAV it is empty.
How can I fix this?
My project's code is at: https://github.com/Jmlevick/html-recorder
No, your problem is that getUserMedia() has an asynchronous callback (gotMedia()); you need to have the rest of your code logic in the startbutton call (the toggleRecording bit, in particular) inside that callback, because right now it's getting executed before getUserMedia returns (and sets up the audio nodes).
I found an elegant & easy solution for this (or at least I see it that way):
What I did was toss "main.js" and "recorder.js" inside a getScript call that is executed only when a certain button (#button1) is clicked by the user... These scripts do not get loaded with the webpage itself until the button it's pressed, but we need some more nifty tricks to make it work the way I described and wanted above:
in main.js, I changed:
window.addEventListener('load', initAudio );
for:
window.addEventListener('click', initAudio );
So when the scripts are loaded into the page with getScript the "main.js" file now listens for a click event in the webpage to ask the user for the microphone. Next, I had to create a hidden button (#button2) on the page wich is fakely clicked by jQuery exactly right after the scripts are loaded on the page, so it triggers the "ask for microphone permisson" event and then, just below that line of code wich generates the fake click I added:
window.removeEventListener("click", initAudio, false);
so the "workflow" for this trick ends up as follows:
User presses a button wich loads the necesary js files into the page with getScript, it's worth mentioning that now the "main.js" file listens for a click event on the window instead of a load one.
We have a hidden button wich is "fakely clicked" by jQuery just in the moment you click the first one, so it triggers the permisson event for the user.
Once this event is triggered, the click event listener is removed from the window, so it never fires the "ask for permisson" event again when the user clicks anywhere on the page.
And basically that's all folks! :) now when the user goes into the page he/she never get asked for microphone permisson until they click a "Rec" button on the page just as I wanted. With one click of the user we do 3 things in jQuery, but for the user it seems like nothing happened other that the "microphone permisson message" appearing on the screen instantly right after they click the "Rec" Button.

Categories

Resources