I am trying to make simple 1:1 video conferencing app with Agora web SDK, i started with their basic demo and currently am trying to implement audio/video mute/unmute functionality. I read and tried other SO answers on the same but they too didn't worked.
Here is my index.html file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Video Call Demo</title>
<link rel="stylesheet" href="./styles/style.css">
</head>
<body>
<h1>
Video Call Demo<br><small style="font-size: 14pt">Powered by Agora.io</small>
</h1>
<h4>My Feed :</h4>
<div id="me"></div>
<button onclick="myFunc()">Mute</button> <!-- button for muting -->
<p id="demo"></p> <!-- this works for onclick action of above button -->
<h4>Remote Feeds :</h4>
<div id="remote-container">
</div>
<h4>Canvas :</h4>
<div id="canvas-container">
</div>
<script src="scripts/AgoraRTCSDK-2.4.0.js"></script>
<script src="scripts/script.js"></script>
<script src="https://cdn.agora.io/sdk/release/AgoraRTCSDK-3.2.1.js"></script>
</body>
</html>
Here is script.js file where actual logic is implemented
/**
* #name handleFail
* #param err - error thrown by any function
* #description Helper function to handle errors
*/
let handleFail = function(err){
console.log("Error : ", err);
};
// Queries the container in which the remote feeds belong
let remoteContainer= document.getElementById("remote-container");
let canvasContainer =document.getElementById("canvas-container");
/**
* #name addVideoStream
* #param streamId
* #description Helper function to add the video stream to "remote-container"
*/
function addVideoStream(streamId){
let streamDiv=document.createElement("div"); // Create a new div for every stream
streamDiv.id=streamId; // Assigning id to div
streamDiv.style.transform="rotateY(180deg)"; // Takes care of lateral inversion (mirror image)
remoteContainer.appendChild(streamDiv); // Add new div to container
}
/**
* #name removeVideoStream
* #param evt - Remove event
* #description Helper function to remove the video stream from "remote-container"
*/
function removeVideoStream (evt) {
let stream = evt.stream;
stream.stop();
let remDiv=document.getElementById(stream.getId());
remDiv.parentNode.removeChild(remDiv);
console.log("Remote stream is removed " + stream.getId());
}
function addCanvas(streamId){
let canvas=document.createElement("canvas");
canvas.id='canvas'+streamId;
canvasContainer.appendChild(canvas);
let ctx = canvas.getContext('2d');
let video=document.getElementById(`video${streamId}`);
video.addEventListener('loadedmetadata', function() {
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
});
video.addEventListener('play', function() {
const $this = this; //cache
(function loop() {
if (!$this.paused && !$this.ended) {
ctx.drawImage($this, 0, 0);
setTimeout(loop, 1000 / 30); // drawing at 30fps
}
})();
}, 0);
}
// Client Setup
// Defines a client for RTC
let client = AgoraRTC.createClient({
mode: 'live',
codec: "h264"
});
// Client Setup
// Defines a client for Real Time Communication
client.init("d2684f11650c446faaeb289d973e2dd3",() => console.log("AgoraRTC client initialized") ,handleFail);
let localStream = AgoraRTC.createStream({
// streamID: uid,
audio: true,
video: true,
screen: false,
camera: {
camId: '',
micId: '',
stream: {}
}
});
// The client joins the channel
client.join(null,"any-channel",null, (uid)=>{
localStorage.streamID = uid
// Stream object associated with your web cam is initialized
// let localStream = AgoraRTC.createStream({
// streamID: uid,
// audio: true,
// video: true,
// screen: false
// });
// Associates the stream to the client
localStream.init(function() {
//Plays the localVideo
localStream.play('me');
//Publishes the stream to the channel
client.publish(localStream, handleFail);
},handleFail);
},handleFail);
//When a stream is added to a channel
client.on('stream-added', function (evt) {
client.subscribe(evt.stream, handleFail);
});
//When you subscribe to a stream
client.on('stream-subscribed', function (evt) {
let stream = evt.stream;
addVideoStream(stream.getId());
stream.play(stream.getId());
addCanvas(stream.getId());
});
// this is the function for muting
function myFunc(){
document.getElementById("demo").innerHTML="yay" // p tag works
let x = localStream.muteVideo(); // from docs
console.log(x);
// taken from one of the answers but it isn't working
client.on("mute-video", function (evt) {
const remoteId = evt.uid;
localStream.camera.stream.muteVideo();
});
}
//When a person is removed from the stream
client.on('stream-removed',removeVideoStream);
client.on('peer-leave',removeVideoStream);
There are JavaScript scope errors for a few variables and objects you have given. I would recommend fixing those. You have also tried to import two versions of the SDK (2.x and 3.x) in the HTML file.
For example: script.js:62 Uncaught ReferenceError: AgoraRTC is not defined. Try to debug all such errors you see in the console.
I would recommend following the Agora documentation for setting up a working video call and the muteAudio and the muteVideo functions for muting audio and video.
Simple Sample App: https://github.com/AgoraIO/Basic-Video-Call/tree/master/One-to-One-Video/Agora-Web-Tutorial-1to1
Fully Professional Sample App: https://github.com/akshatvg/speakOut
Related
Hi im developing activex control to manage webcam in IE, everything works but i need to refresh the image when a new frame is captures, up to now i display images on click, but i want to listen "Captured frame event" in JS to refresh my html view.
I have seen a lot of samples but all of these are using Object tag in html
<object id="Control" classid="CLSID:id"/>
<script for="Control" event="myEvent()">
alert("hello");
</script>
is there a way to listen activex events using pure JS? using :
Ob = new ActivexObject('PROG.ID');
No, it's not working in purly JavaScript you can only use JScript.
JScript only works in Internet Explorer and there it only works, if the user confirms to execute the scripts, ussualy you use it in an .hta Hyper Text (Markup Language) Application
Example:
<script language="JScript">
"use strict";
function openFile(strFileName) {
var fso = new ActiveXObject("Scripting.FileSystemObject");
var f = fso.OpenTextFile(strFileName, 1);
if (f.AtEndOfStream) {
return;
}
var file = f.ReadAll();
f.close();
return file;
}
function writeFile(filename, content) {
var fso = new ActiveXObject("Scripting.FileSystemObject");
var f = fso.OpenTextFile(filename, 2, true);
f.Write(content);
f.Close();
}
</script>
<script language="javascript">
"use strict";
var native_db;
function init() {
var file = openFile("./Natives.json");
native_db = JSON.parse(file);
displayNamespaces();
};
I also would have as alternate an example how it works in modern Browsers, if it helps you out there:
<video id="webcam"></video>
<input type="button" value="activate webcam" onclick="test()">
<script>
function test() {
navigator.mediaDevices.getUserMedia({video: true, audio: true}).then((stream) => { // get access to webcam
const videoElement = document.getElementById('webcam');
videoElement.srcObject = stream; // set our stream, to the video element
videoElement.play();
// This creates a Screenshot on click, as you mentioned
videoElement.addEventListener('click', function(event) {
const canvas = document.createElement('canvas');
canvas.width = videoElement.videoWidth;
canvas.height = videoElement.videoHeight;
const context = canvas.getContext('2d');
context.drawImage(videoElement, 0, 0, videoElement.videoWidth, videoElement.videoHeight);
// you could just do this, to display the canvas:
// document.body.appendChild(canvas);
canvas.toBlob(function (blob) { // we automatlicly download the screenshot
const a = document.createElement('a');
a.href = URL.createObjectURL(blob); // creates a Datastream Handle Link in your Browser
a.download = 'screenshot.png'; // the name we have to define here now, since it will not use the url name
document.body.appendChild(a); // some Browsers don't like operating with Events of Objects which aren't on DOM
setTimeout(function() { // so we timeout a ms
a.click(); // trigger the download
URL.revokeObjectURL(a.href); // release the Handle
document.body.removeChild(a); // remove the element again
}, 1);
});
});
}).catch(console.error);
}
</script>
I ended up using timer, when i click enable button in the view i call the method startRecord, in this method i read Activex value every 70 ms, I would rather not use timer but it works.
private async startRecord() {
while (this.banCapturing) {
await new Promise(res => setTimeout(res, 70)); //14 ~ 15 fps
this.foto = this.Ob.imageBase64; //Read Activex Value, DLL is updating imageBase64 on camera event.
}
}
as a follow-up on this post: How to rapidly play multiple copies of a soundfile in javascript I created a small demo page to illustrate the core of my problem.
My goal is to rapidly play the same audiofile over and over again while a user holds down a button, without crashing the browser ;-) (second line in the fiddle)
My initial method uses clone node to create multiple audio objects in the DOM. This works actually fine in chrome and edge, but safari and firefox run into problems after a while. This leads to dis-synchronized audios, and audios that keep on starting after the user has released the button.
So Codebreaker007 proposed to use audio-context instead, which resulted in a couple of different problems. Chrome replies:
The AudioContext was not allowed to start. It must be resumed (or created) after a user gesture on the page.
Chrome and firefox don't play the audio file. I then followed the google guide and got at least the error messages to be gone, but still no audible audio. Using the web audio plugin for chrome I could at one point see that the audio nodes are being created correctly. How can I make them audible? How can I get the Audio Context to start?
I think I'm quite close to the solution, so let's fix this together.
<!doctype html>
<html class="h-100" lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
<title>Test</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script>
AudioContext:true;
var clickingBuffer = null;
var timer
var inStart = 0
var inStop = 0
var timer = null
var type = ""
window.AudioContext = window.AudioContext || window.webkitAudioContext;
var context = new AudioContext();
// =========== Variant 1: Clone Node ========== //
var sound = new Audio("https://sounds4email.com/wav/hellobaby.mp3");
sound.preload = 'auto';
sound.load();
function triggersound(){
console.log("triggerSound")
var click=sound.cloneNode();
click.volume=1;
click.play();
}
// =========== Variant 2: AudioContext ========== //
function loadClickSound(url) {
console.log("loading sound")
var request = new XMLHttpRequest();
request.open('GET', url, true);
request.responseType = 'arraybuffer';
// Decode asynchronously
request.onload = function() {
context.decodeAudioData(request.response, function(buffer) {
if (!buffer) {
console.log('Error decoding file data: ' + url);
return;
}
clickingBuffer = buffer;
});
request.onerror = function() {
console.log('BufferLoader: XHR error');
};
console.og("sound buffered")
request.send();
};
}
function playSound(buffer, time, volume) {
console.log("playSound")
context.resume().then(() => {
var source = context.createBufferSource(); // creates a sound source
source.buffer = buffer; // tell the source which sound to play
source.connect(context.destination); // connect the source to the context's destination (the speakers)
var gainNode = context.createGain(); // Create a gain node
source.connect(gainNode); // Connect the source to the gain node
gainNode.connect(context.destination); // Connect the gain node to the destination
gainNode.gain.value = volume; // Set the volume
source.start(time); // play the source at the deisred time 0=now
console.log('Playback resumed successfully');
});
}
// =========== RAPID FIRE ========== //
function stop() {
console.log("stop")
inStop = 1
}
// Initializing the spinning sequence. Blocking other user interaction
function start(tp) {
type = tp
console.log("active")
context.resume().then(() => {
console.log('Playback resumed successfully');
if (null === timer) {
timer = setInterval(timerCallback, 200)
inStart = 1
}
});
}
/**
* Timer callback
*/
function timerCallback() {
console.log(type + " " + inStart + " " + inStop)
if (inStart) {
if(type==="node"){
triggersound()
} else if(type==="context"){
playSound(clickingBuffer, 0, 1)
}
}
if (inStop) {
inStop = 0
clearTimeout(timer)
timer = null
console.log("stopped")
}
}
// =========== DOC READY ========== //
$( document ).ready(function() {
console.log( "ready!" );
// You call with in your document ready
loadClickSound("https://sounds4email.com/wav/hellobaby.mp3");
// Fix up prefixi
});
// =================================================================================//
</script>
</head>
<body class="d-flex flex-column align-content-center align-items-center justify-content-center w-100 h-100" >
<div class="row p-1 w-100">
<div class="col">
Click once:
</div>
<button id="clickNode" style="width: 100px; height: 100px;" class="col m-1" onclick="triggersound()">
Clone Node
</button>
<button id="clickContext" style="width: 100px; height: 100px;" class="col m-1" onclick="playSound(clickingBuffer, 0, 1)">
Audio Context
</button>
</div>
<div class="row p-1 w-100">
<div class="col">
Press and hold:
</div>
<button id="autoNode" style="width: 100px; height: 100px;" class="col m-1" onmousedown="start('node')" onmouseup="stop()">
Auto Clone Node
</button>
<button id="autoContext" style="width: 100px; height: 100px;" class="col m-1" onmousedown="start('context')" onmouseup="stop()">
Auto Audio Context
</button>
</div>
</body>
</html>
Ok here is the code you want for your function. This code can use a local file to test with to rule out all kind of security issues (the xhr code is included). It uses plain JS ES5 and has been tested with firefox and chrome on different OS. Please put this into an audio_test.html as it is to verify the function. One word of warning, don't mix html tags and java script function calls, use event listeners as I demostrate it in the code.The stop button function is just a starter, to relock after play extra code is necessary I didn't bother to write.
Do not try to create buffers in an ongoing way because this fills up memory and crashes the browsers/OS. If you want overlapping sound this means using buffer arrays, but thats would be an other question.
<!DOCTYPE html>
<!-- Author: codebreaker007 # stackoverflow -->
<html class="h-100" lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
<title>Web Audio API: load + play</title>
</head>
<body>
<p>Example of using the Web Audio API to load a sound file and </br>play once, play continous on mousedown or stop play
and start playing on user-click.</p>
Tested in Firefox and Chrome</p>
<input type="file" accept="audio/*" value="">
<button id="playonce" disabled=disabled>Play once</button>
<button id="playstop" disabled=disabled>Stop play</button>
<button id="playcont" disabled=disabled>Play cont</button>
<script>
/* global AudioContext:true,
*/
window.AudioContext = window.AudioContext || window.webkitAudioContext;
var context = new AudioContext();
var source = null;
var clickingBuffer = null;
var mouseIsDown = false;
var buttonPo = document.getElementById("playonce");
var buttonPs = document.getElementById("playstop");
var buttonPc = document.getElementById("playcont");
if (document.readyState!="loading") docReady();
/* Modern browsers */
else document.addEventListener("DOMContentLoaded", docReady);
function docReady() {
buttonPo.addEventListener("click", function(e){
playSound(clickingBuffer, 0, 0, 0.8);
buttonPs.disabled = false;
});
buttonPs.addEventListener("click", function(e){
if (source) {
source.stop(0);
}
buttonPs.disabled = true;
});
buttonPc.addEventListener("mousedown", function(e){
playSound(clickingBuffer, 1, 0, 1);
// while(mouseIsDown) playSound(clickingBuffer, 0, 1);
});
buttonPc.addEventListener("mouseup", function(e){
if (source) {
source.stop(0);
}
});
}
function playSound(buffer2play, isLoop, time, volume) {
console.log("playsound called");
source = context.createBufferSource(); // creates a sound source
source.buffer = buffer2play; // tell the source which sound to play
if (isLoop) source.loop = true;
else source.loop = false;
source.connect(context.destination); // connect the source to the context's destination (the speakers)
var gainNode = context.createGain(); // Create a gain node
source.connect(gainNode); // Connect the source to the gain node
gainNode.connect(context.destination); // Connect the gain node to the destination
gainNode.gain.value = volume; // Set the volume
source.start(time); // play the source at the deisred time 0=now
console.log("playSound");
}
function initSound(arrayBuffer) {
context.decodeAudioData(arrayBuffer, function(buffer) {
// clickingBuffer is global to reuse the decoded audio later.
clickingBuffer = buffer;
// Test routine activate buttons
buttonPo.disabled = false;
buttonPc.disabled = false;
}, function(e) {
console.log('Error decoding file', e);
});
}
// User selects file, read it as an ArrayBuffer and pass to the API.
var fileInput = document.querySelector('input[type="file"]');
fileInput.addEventListener('change', function(e) {
var reader = new FileReader();
reader.onload = function(e) {
initSound(this.result);
};
reader.readAsArrayBuffer(this.files[0]);
}, false);
// Load file from a URL as an ArrayBuffer.
// Example: loading via xhr2: loadSoundFile('sounds/test.mp3');
function loadClickSound(url) {
console.log("loading sound");
var request = new XMLHttpRequest();
request.open('GET', url, true);
request.responseType = 'arraybuffer';
// Decode asynchronously
request.onload = function() {
// Decode asynchronously
initSound(this.response); // this.response is an ArrayBuffer.
};
xhr.send();
}
</script>
</body>
</html>
I am attempting to make a Spotify visualizer as a personal project, but can't seem to find a way to analyze the sound before it is played through the browser. I have the Spotify player playing music through the browser, and the visualizer is working with mp3 files stored on my machine. I just don't have the slightest clue on how to connect the two. Additionally, I looked through the Spotify API and couldn't seem to find anything there either.
If there is no way to analyze a Dpotify track directly, is there any way to capture the sound played through the browser first, then play through the p5.js loadSound() function?
Here are the code snippets for reference:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.2/p5.js">
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.2/addons/p5.dom.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.2/addons/p5.sound.js"></script>
</head>
<body>
<script src="https://sdk.scdn.co/spotify-player.js"></script>
<script>
window.onSpotifyWebPlaybackSDKReady = () => {
const token =
'redacted';
const player = new Spotify.Player({
name: 'Web Playback SDK Quick Start Player',
getOAuthToken: cb => {
cb(token);
}
});
// Error handling
player.addListener('initialization_error', ({
message
}) => {
console.error(message);
});
player.addListener('authentication_error', ({
message
}) => {
console.error(message);
});
player.addListener('account_error', ({
message
}) => {
console.error(message);
});
player.addListener('playback_error', ({
message
}) => {
console.error(message);
});
// Playback status updates
player.addListener('player_state_changed', state => {
console.log(state);
});
// Ready
player.addListener('ready', ({
device_id
}) => {
console.log('Ready with Device ID', device_id);
});
// Not Ready
player.addListener('not_ready', ({
device_id
}) => {
console.log('Device ID has gone offline', device_id);
});
// Connect to the player!
player.connect();
};
</script>
<script src="visualizer.js"></script>
var spotifyToken = ""
//["streaming", "user-read-birthdate", "user-read-email", "user-read-private"]
var song;
var amp;
var button;
var volHistory = [];
function toggleSong(){
if (song.isPlaying()){
song.pause();
} else {
song.play();
}
}
function preload(){
soundFormats('mp3');
song = loadSound('backgroundsong.mp3')
}
function setup(){
var canvas = createCanvas(window.innerWidth/2, 100);
//canvas.parent('div id')
canvas.position(0, (windowHeight - height) / 2)
//var canvasLeft = createCanvas(window.innerWidth/2, 100);
//canvasLeft.position(windowWidth/2, (windowHeight - height) / 2)
//createCanvas(window.innerWidth, window.innerHeight);
masterVolume(0.002,0,0);
button = createButton('toggle');
button.mousePressed(toggleSong);
song.loop();
amp = new p5.Amplitude();
}
function draw(){
background(0);
var volume = amp.getLevel();
volHistory.push(volume * 400);
beginShape();
stroke(0, 255, 0);
strokeWeight(3);
strokeCap(ROUND);
strokeJoin(ROUND);
noFill();
for (var i = 0; i < volHistory.length; i++) {
var y = map(volHistory[i], 0, 1, height, 0);
vertex(i*1.5, y);
if (i*1.5 > width) {
volHistory.splice(0, 1);
}
}
endShape();
//ellipse(400, 400, volume * 800, volume * 800);
}
Processing raw data samples is not possible using Spotify's Web Playback SDK. As seen in the following quote Spotify uses Encrypted Media Extensions in order to make playback possible within the browser.
The Web Playback SDK is client-side JavaScript library which allows you to create a new player in Spotify Connect and play any audio track from Spotify in the browser via Encrypted Media Extensions.
You could use this Spotify Web API endpoint and try to visualize one of those properties. There are no actual samples (which would be the amplitude you asked for) but maybe something those data sets include will fit your needs.
I found a reddit thread where some people showed off some visualizations mostly using the before mentioned API endpoint.
Another option is to use Spotify's Android or iOS SDK where you have access to raw data samples though I am not sure if it is allowed by Spotify's terms of service to process those samples. But due to you are looking for something client-sided within the browser this won't fit your needs.
Currently i am working on a open webapp camera, right now i have implemented the camera setup(live stream as viewport, take picture button, capture, display taken picture in corner... etc) but now i am running into the issue of how to save that picture for the user to their device or computer, this app is currently being designed for mobile b2g primarily. I know most people are gonna tell me security issues!!! i dont mean tell the device exactly where to put it. I mean something like
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<script type="text/javascript">
window.onload = function () {
var img = document.getElementById('embedImage');
var button = document.getElementById('saveImage');
img.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA'+
'AAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO'+
'9TXL0Y4OHwAAAABJRU5ErkJggg==';
img.onload = function () {
button.removeAttribute('disabled');
};
button.onclick = function () {
window.location.href = img.src.replace('image/png', 'image/octet-stream');
};
};
</script>
</head>
<body>
<img id="embedImage" alt="Red dot"/>
<input id="saveImage" type="button" value="save image" disabled="disabled"/>
</body>
</html>
that specific code executed on mobile triggers the file to automatically be saved on click of the button. now what i want to do is use that to take my picture from its var its in and save it as that file, for example that will be in downloads folder.
this is what my code is currently https://github.com/1Jamie/1Jamie.github.io
any help would be appreciated and this is the current running implementation if you want to take a working look http://1Jamie.github.io
This worked for me when I was playing around with getUserMedia - I did notice that you did not have the name of the method in the proper case and it is a method of the navigator.mediaDevices interface - not a method of the window directly...
References:
[Navigator for mozilla]https://developer.mozilla.org/en-US/docs/Mozilla/B2G_OS/API/Navigator
https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices
[mediaDevices for chrome and android]https://developers.google.com/web/updates/2015/10/media-devices?hl=en
var video = document.getElementById('monitor');
var canvas1 = document.getElementById('photo1');
var img1 = document.getElementById('canvasImg');
navigator.mediaDevices.getUserMedia({
video: true
}).then(function (stream) {
video.srcObject = stream;
video.onloadedmetadata = function () {
canvas1.width = video.videoWidth;
canvas1.height = video.videoHeight;
document.getElementById('splash').hidden = true;
document.getElementById('app').hidden = false;
};
}).catch(function (reason) {
document.getElementById('errorMessage').textContent = 'No camera available.';
});
function snapshot1() {
canvas1.getContext('2d').drawImage(video, 0, 0);
}
"save_snap" is the id of a button - Disclaimer I am using jQuery- but you should easily see where this corresponds to your code:
$("#save_snap").click(function (event){
// save canvas image as data url (png format by default)
var dataURL = canvas2.toDataURL();
// set canvasImg image src to dataURL
// so it can be saved as an image
$('#canvasImg').attr("src" , dataURL);
$('#downloader').attr("download" , "download.png");
$('#downloader').attr("href" , dataURL);
//* trying to force download - jQuery trigger does not apply
//Use CustomEvent Vanilla js: https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent
// In particular
var event1 = new MouseEvent('click', {
'view': window,
'bubbles': true,
'cancelable': true
});
//NOW we are effectively clicking the element with the href attribute:
//Could use jQuery selector but then we would have to unwrap it
// to expose it to the native js function...
document.getElementById('downloader').dispatchEvent(event1);
});
I am trying to get a simple Pong game going from Chris Bowen's MSDN blog:
http://blogs.msdn.com/b/cbowen/archive/2012/09/19/using-createjs-in-your-javascript-based-windows-store-game.aspx
I am at his "Setting the Stage" section and theoretically I should be able to launch the app and have the ball and paddles in my Pong game, but instead when I run the codes in Visual Studio 2012, I get the below error:
Exception is about to be caught by JavaScript library code at line 42, column 87 in ms-appx://521809a7-6594-45ba-a60e-bb529eac1299/js/createjs/easeljs-0.5.0.min.js
0x800a139e - JavaScript runtime error: TypeMismatchError
The program '[3756] WWAHost.exe' has exited with code 0 (0x0).
Unfortunately the easeljs-0.5.0.min.js file is minimized so it is ugly, but I believe this is the one causing the problem at the mentioned line and column:
var d=this._ctx.createPattern(a,b||"");
Below is my default.js file:
(function () {
"use strict";
WinJS.Binding.optimizeBindingReferences = true;
var app = WinJS.Application;
var activation = Windows.ApplicationModel.Activation;
app.onactivated = function (args) {
if (args.detail.kind === activation.ActivationKind.launch) {
if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {
// TODO: This application has been newly launched. Initialize
// your application here.
} else {
// TODO: This application has been reactivated from suspension.
// Restore application state here.
}
args.setPromise(WinJS.UI.processAll().then(init()));
}
};
var ball, paddle1, paddle2;
var stage;
function init() {
stage = new createjs.Stage("gameCanvas");
ball = new createjs.Shape();
ball.graphics.beginFill("White");
ball.graphics.drawCircle(0, 0, 10);
ball.x = 400;
ball.y = 300;
paddle1 = new createjs.Shape();
paddle1.graphics.beginBitmapFill("White");
paddle1.graphics.drawRect(0, 0, 20, 100);
paddle1.x = 20;
paddle1.y = 300;
paddle2 = new createjs.Shape();
paddle2.graphics.beginBitmapFill("White");
paddle2.graphics.drawRect(0, 0, 20, 100);
paddle2.x = 760;
paddle2.y = paddle1.y;
stage.addChild(ball, paddle1, paddle2);
stage.update();
}
app.oncheckpoint = function (args) {
// TODO: This application is about to be suspended. Save any state
// that needs to persist across suspensions here. You might use the
// WinJS.Application.sessionState object, which is automatically
// saved and restored across suspension. If you need to complete an
// asynchronous operation before your application is suspended, call
// args.setPromise().
};
app.start();
})();
My simple default.html file:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Pong</title>
<!-- WinJS references -->
<link href="//Microsoft.WinJS.1.0/css/ui-dark.css" rel="stylesheet" />
<script src="//Microsoft.WinJS.1.0/js/base.js"></script>
<script src="//Microsoft.WinJS.1.0/js/ui.js"></script>
<!-- Pong references -->
<link href="/css/default.css" rel="stylesheet" />
<script src="/js/default.js"></script>
<script src="js/createjs/easeljs-0.5.0.min.js"></script>
</head>
<body>
<canvas id="gameCanvas" width="800" height="600"></canvas>
</body>
</html>
You changed the paddle code to beginBitmapFill versus beginFill, but are still passing a color name into the call, and that's causing the type mismatch,
Per the documentation,
Graphics beginBitmapFill ( image , repetition )
Begins a pattern fill using the specified image. This ends the current subpath.
Parameters:
image <object> The Image, Canvas, or Video object to use as the pattern.
repetition <String> Optional. Indicates whether to repeat the image in the fill area.
One of "repeat", "repeat-x", "repeat-y", or "no-repeat".
Defaults to "repeat".
Returns:
Graphics The Graphics instance the method is called on (useful for chaining calls.)