How to test html canvas experiments on Chrome locally - html

I wrote a simple canvas demo program but it doesn't seem to produce the required result.
Here is my code:-
window.onload = function(){
var canv = document.getElementById('canv');
var cxt = canv.getContext('2d');
if(cxt){
var myimg = document.getElementById('mypic');
setTimeout(function(){
cxt.drawImage(myimg,0,0,canv.width,canv.height);
var edit = cxt.getImageData(0,0,canv.width,canv.height);
var imgdata = edit.data;
for(var i=0;i<imgdata.length;i+=4){
imgdata[i] = 255;
imgdata[i++] = 255;
imgdata[i+3] = 127;
}
cxt.putImageData(imgdata,0,0);
}
,100);
$('<p>Canvas Created</p>').appendTo('body');
}
};

Most likely one of two things is going wrong.
You are not waiting for your image to finish loading which might be a problem.
Or you are running in to a security exception. Calling getImageData is now allowed if an image has been loaded on to the canvas from an outside source. Your hard-drive constitutes an outside source, even if you are running locally. To see if this is the case I'd suggest debugging in FireFox because its web console will actually tell you about this security error.

Related

Changing the pitch of the sound of an HTML5 audio node

I would like to change the pitch of a sound file using the HTML 5 Audio node.
I had a suggestion to use the setVelocity property and I have found this is a function of the Panner Node
I have the following code in which I have tried changing the call parameters, but with no discernible result.
Does anyone have any ideas, please?
I have the folowing code:
var gAudioContext = new AudioContext()
var gAudioBuffer;
var playAudioFile = function (gAudioBuffer) {
var panner = gAudioContext.createPanner();
gAudioContext.listener.dopplerFactor = 1000
source.connect(panner);
panner.setVelocity(0,2000,0);
panner.connect(gainNode);
gainNode.connect(gAudioContext.destination);
gainNode.gain.value = 0.5
source.start(0); // Play sound
};
var loadAudioFile = (function (url) {
var request = new XMLHttpRequest();
request.open('get', 'Sounds/English.wav', true);
request.responseType = 'arraybuffer';
request.onload = function () {
gAudioContext.decodeAudioData(request.response,
function(incomingBuffer) {
playAudioFile(incomingBuffer);
}
);
};
request.send();
}());
I'm trying to achieve something similar and I also failed at using PannerNode.setVelocity().
One working technique I found is by using the following package (example included in the README): https://www.npmjs.com/package/soundbank-pitch-shift
It is also possible with a biquad filter, available natively. See an example here: http://codepen.io/qur2/pen/emVQwW
I didn't find a simple sound to make it obvious (CORS restriction with ajax loading).
You can read more at http://chimera.labs.oreilly.com/books/1234000001552/ch04.html and https://developer.mozilla.org/en-US/docs/Web/API/BiquadFilterNode.
Hope this helps!

Clear html5 canvas, then re-initialize it

I'm working on an activity where a user would draw a line chart and check to see how close it is to an actual chart. I've got it working, but need help on 'resetting' the canvas. I can get it to clear, but I need to reinitialize it after it's cleared so the user can try again.
here is the reset code I have so far:
var clearCanvas = false;
function onFrame(event) {
if (clearCanvas && project.activeLayer.hasChildren()) {
project.activeLayer.removeChildren();
clearCanvas = false;
}
}
$('.clear').on('click', function() {
clearCanvas = true;
return false
})
Here is a jsfiddle
I've kinda hacked this code together, as I'm not a coder, so go easy if it's not the best way of doing things. If anyone has a cleaner/more efficient way of doing this I'm all ears!
Thanks in advance.
S
First, your jsfiddle is getting a 404 when it tries to use "http://paperjs.org/static/js/paper.js". Switching that to "https://raw.github.com/paperjs/paper.js/master/dist/paper.js" works for me.
Second, if you want the user to try again, they need to be able to place 7 (or however many) new points after the reset, so in your onFrame function you need to set maxPoints to 0 when clearing the canvas.
Third, the path that connects the users points will need to be re-initialized. That can be done by calling path.removeSegments() and then re-adding path to the activeLayer.
Fourth, once you have removed the children from the activeLayer, fullChart (the "answer") is no longer on the activeLayer. You will have to re-add it and re-set its opacity to 0 (if you want it hidden again).
Putting those together, this onFrame seems to do what you are attempting:
function onFrame(event) {
if (clearCanvas && project.activeLayer.hasChildren()) {
project.activeLayer.removeChildren();
fullChart.opacity = 0;
maxPoints = 0;
path.removeSegments();
project.activeLayer.addChildren([fullChart, path]);
clearCanvas = false;
}
}
Here's a jsfiddle.
Other notes:
I don't believe you have to separate your code like that; you could just clear the canvas in your button's callback instead of waiting for the onFrame. So all of the code in onFrame could go in the callback instead (just without the clearCanvas variable).
I would also recommend using the same Point objects for your myCircle and myPath instead of making new ones with the same coordinates. For example:
var point1 = new Point(72, 214);
var point2 = new Point(205, 177);
...
var point7 = new Point(868, 177);
var myCircle1 = new Path.Circle(point1, 10)
var myCircle2 = new Path.Circle(point2, 10)
....
var myCircle7 = new Path.Circle(point7, 10)
var myPath = new Path([point1, point2, ..., point7]);

chrome indexed database setVersion request filled with exceptions

I am trying to get the following code to work on chrom by using setVersion (as onupgradeneeded is not available yet).
The IDBVersionChangeRequest is filled with IDBDatabaseException. And the onsuccess function could not be called. I need to create an ObjectStore within the onsuccess function.
specifically this line: request = browserDatabase._db.setVersion(browserDatabase._dbVersion.toString());
Below is my code. Any help would be greatly appreciated...
browserDatabase._db = null;
browserDatabase._dbVersion = 4;
browserDatabase._dbName = "mediaStorageDB";
browserDatabase._storeName = "myStore";
var request = indexedDB.open(browserDatabase._dbName);
// database exist
request.onsuccess = function(e)
{
browserDatabase._db = e.target.result;
// this is specifically for chrome, because it does not support onupgradeneeded
if (browserDatabase._dbVersion != browserDatabase._db.version)
{
request = browserDatabase._db.setVersion(browserDatabase._dbVersion.toString());
request.onerror = function(e) { alert("error") };
request.onblocked = function(e)
{
b = 11; // for some reason the code goes here...
}
request.onsuccess = function(e)
{
browserDatabase._db.createObjectStore(browserDatabase._storeName, {autoIncrement: true});
}
}
}
In your code sample you say you come in to the onblocked callback. The only way you can get in this callback is when you have still open transactions/connections to your db. (aside the one you are working in.) This means you will have to close all other transactions/connections before you can call the setVersion.
When wired things happen to IndexedDB, I "Clear data from hosted apps", quit Chrome windows and take a cup of coffee. After that everything work fine. :-D
browserDatabase._dbVersion < browserDatabase._db.version. Downgrading is not possible. dbVersion = 4 should not be consider lightly. You might open other tab with dbVersion = 5, or browser may be waining your response elsewhere or itself updating. All these are not worth to trace the reasons behind.

How to get FFT from audio tag in HTML5

I want to get the FFT data from an <audio> tag, but it doesn't work without any syntax error. Looking at the Web Audio API document, I write a sample code, here is my code:
<audio id="aud" controls="controls" src="test.mp3"></audio>
<script type="text/javascript">
var audioElement = document.getElementById("aud");
var audioContext = new webkitAudioContext();
var streamingAudioSource = audioContext.createMediaElementSource(audioElement);
var jsProcessor = audioContext.createJavaScriptNode(4096,1,1);
jsProcessor.onaudioprocess = process;
var analyser = audioContext.createAnalyser();
analyser.fftSize = 2048;
//streaming:AudioSource->jsProcessor->analyser->destination
streamingAudioSource.connect(jsProcessor);
jsProcessor.connect(analyser);
analyser.connect(audioContext.destination);
//autoplay
audioElement.play();
function process(event){
var freqByteData = new Uint8Array(analyser.frequencyBinCount);
analyser.getByteFrequencyData(freqByteData);
document.getElementById("info").innerHTML=freqByteData[1];//show data in div
}
</script>
My Chrome version is 20.0.1096.1 dev-m and I think it works well. Through process(), I'm trying to write down freqByteData, but it shows 0, and all of them are always 0.
It must have something wrong of my code, and I want to know how to get frequency data from an audio tag.
It seems that createMediaSourceElement breaks if it's called before window.onload. There is a bug report about this issue: http://code.google.com/p/chromium/issues/detail?id=112368
There are currently two workarounds:
Wait the window load event before executing the whole javascript
window.addEventListener('load', function(){
// your code
}, false);
or
Create the MediaElementSource in a setTimeout with 0 delay
setTimeout(function (){
var streamingAudioSource = audioContext.createMediaElementSource(audioElement);
var jsProcessor = audioContext.createJavaScriptNode(4096,1,1);
// The rest of the code
}, 0);

context.getImageData() on localhost?

I have the following snippet of code and I'm trying to run it from localhost (OSX, running XAMPP):
var canvas = document.getElementById('mycanvas');
var cx = canvas.getContext('2d');
var myImg = new Image();
myImg.src = 'images/lion.jpg';
$(myImg).load(function() {
cx.drawImage(myImg, 0, 0);
var imgData = cx.getImageData(0,0,150,150);
});
But when I run it I get this error from the console:
Unable to get image data from canvas because the canvas has been tainted by cross-origin data.
site.js:11Uncaught Error: SECURITY_ERR: DOM Exception 18
I found some similar questions here and I know that this has something to do with the fact that I'm working locally and this wouldn't happen if I was trying to access the image from the same domain. I don't know if this makes sense, but it's what I understood.
My question is, how can I make this work in a local dev environment?
Serve your html with an HTTP server, for example, Apache or Nginx.
Mac OSX comes with Python installed, so you can simply start an HTTP server by opening a terminal, then input:
cd /path/to/my/work/
python -m SimpleHTTPServer
Then open http://localhost:8000/ in your browser. This should work.
Trying a different browser might help. This happened to me on Chromium and just by switching to Firefox I was able to continue debugging locally.
I ended up using a combo of solutions (see this other problem)
Steps:
Transform the image to base64 string.
Assign that as the src of the Image js object.
Draw on canvas
Code:
// helper to transform to base64
// see other question for more help
function toDataUrl(url, callback) {
var xhr = new XMLHttpRequest();
xhr.responseType = 'blob';
xhr.onload = function() {
var reader = new FileReader();
reader.onloadend = function() {
callback(reader.result);
};
reader.readAsDataURL(xhr.response);
};
xhr.open('GET', url);
xhr.send();
}
var canvas = document.querySelector("canvas");
var ctx = canvas.getContext("2d");
var png = new Image();
var backgroundSrc = ".....";
png.onload = function () {
ctx.drawImage(png, 0, 0);
};
toDataUrl(backgroundSrc, function(base64Img) {
png.src = base64Img;
});
I know this solution is NOT optimal, but it worked for me AND it helps when the image does not come from the same origin.
I'm posting this for anyone that encounters the same problem.