I am half way through the drum machine project on freecodecamp and just came across a finished work built by someone here with the record and playback features. However, this feature only plays back the musical notes captured at the unchangeable tempo. If I click the keypads at various rhythms, this pattern won't be captured. For example, if I click "Q" keypad 10 times in two seconds and then hit "W" keypad twice at the speed of 1 hit per second on recording mode, this hit versus time pattern isn't recorded. Does anyone have any idea on how this can be achieved?
playSound(e) {
//console.log('In playSound power = ' + this.props.power);
if (this.props.power) {
const sound = document.getElementById(this.props.keyTrigger);
sound.currentTime = 0;
sound.play();
const button = document.getElementById(this.props.id);
button.style.backgroundColor = "#00c7ec";
setTimeout(() => { button.style.backgroundColor = '#012839'; }, 500);
this.props.updateDisplay(this.props.id, 500);
if (this.props.){
// record key in array
recordArray.push(this.props.keyCode);
}
}
}
Related
I'm trying to create a game that demonstrates the different instruments in a band. I've managed it in AS3, but I'm struggling in Javascript.
You can either listen to all the instruments playing a piece of music, or click on an instrument to enable or disable it, thus bringing it in or taking it out of the mix.
I have 8 tracks that play simultaneously when the play button (play_btn) is pressed. But whether each instument plays or is muted depends on whether another button (e.g. congas_btn) is pressed. If it isn't pressed, the conga player, for example, (congaPlayer_mc) is greyed out and the conga audio track is muted. If it is pressed, the conga player has full alpha and is unmuted.
Each instrument should be able to be muted or unmuted at will whilst the track is playing.
What actually happens is that whichever state I choose (muted or unmuted) before I click play, determines whether the track plays muted or unmuted. But once the track has started, the congas_btn doesn't have any more effect on the volume. It just toggles its alpha value.
How do I get it to carry on affecting the volume for as long as the track is playing?
Thanks.
This is my code:
let root = this
let congasActive = false
let audioPlaying = false
this.congaPlayer_mc.alpha = 0.5
this.play_btn.addEventListener("click", playAudio.bind(this))
function playAudio() {
const playCongas = createjs.Sound.play("congas")
if(!audioPlaying){
audioPlaying = true
if(congasActive){
playCongas.volume = 1
} else {
playCongas.volume = 0
}
} else {
audioPlaying = false
const stopCongas = createjs.Sound.stop("congas")
}
}
this.congas_btn.addEventListener("click", activateCongas.bind(this))
function activateCongas() {
if(!congasActive){
congasActive = true
root.congaPlayer_mc.alpha = 1
} else {
congasActive = false
root.congaPlayer_mc.alpha = 0.5
}
}
I am creating a monopoly(a board game played with dice) using react. I have made the rolling system for the game. Now I want to test that.
There are two buttons in my game
Roll Button:
Its initially enabled
When user clicks it the dices are rolled. Piece of player moves
Now there are two cases
If doubles are rolled then player gets another turn to roll and this button stays enabled
If doubles are not rolled this becomes disabled and other one becomes enabled.
End turn button:
Initially its disabled.
If die is rolled and doubles are not rolled then this one becomes enabled.
When we click this turn changes and for new turn this becomes disabled and roll button becomes enabled again.
Now I am using cypress to test this. I have written the test and it works for fine but just for 1 time. When I use a loop to run the test multiple time it fails
describe("Rolling System", function () {
//The required test
it("disables button correctly", function () {
//Visits the page
cy.visit("localhost:3000").then(() => {
//A variable which tell if doubles were rolled at last roll or not
let isRollDisabled = false;
for (let i = 0; i < 10; i++) {
//If roll is over then end the turn
if (isRollDisabled) {
cy.get(".btn-end-turn").click();
}
//If roll button is enabled then click it.
else {
console.log(isRollDisabled);
//Get and click button
cy.get(".btn-roll")
.click()
.then((x) => {
//Get the dice elements
cy.get(".dice").then((dices) => {
//Get the rolls of both die
let roll1 = dices[0].children.length;
let roll2 = dices[1].children.length;
//If not doubles
if (roll1 !== roll2) {
cy.get(".btn-roll").should("be.disabled");
console.log("roll disabled changed");
isRollDisabled = true;
}
//If doubles are rolled
else {
cy.get(".btn-roll").should("not.be.disabled");
isRollDisabled = false;
}
});
});
}
}
});
});
});
Notice the two logs in above code console.log(isRollDisabled); and console.log("roll disabled changed");
In the log I see that false is logged 10 times and then after that "roll disabled change" is logged.
I think I have make code such that one test runs after another but I can't fix it.
Remove the loops from inside the test body and use cypress-repeat from command line instead.
I have a use case where we donot want the user who is taking a test get sleep timeout while in test which is of 3 hrs. I was looking at nosleep.js but i has cpu overuse problem as it was not working in windows.
I was wondering how test taking apps do it, also how youtube achieves this.
Any help on this is really appreciated
Wake Lock API arrives in Chrome 79. However none of the other browser support this as of now.
https://developers.google.com/web/updates/2019/12/nic79#wake-lock
YouTube handles this by simply playing video. When you play a video with sound in the browser, the browser requests a wake lock automatically so as not to interrupt the user.
It isn't clear from your question what your specific requirements are, but if playing a video is possible, try that.
So after dealing with the pain of this problem for nice afternoon. I'm posting my solution. I'm using modules so delete export statements if you're not. My goal was to minimize effect on battery. So I play empty video file (10 x 10px, 1 frame lenght with empty audio track) every 10 seconds. I play it for the first time when user first clicks so the browser will allow me to play it. There are still side effects though. I.e. in Safari, the audio icon will blink and on iPhone lockscreen, the page will be shown as the last one playing video/audio.
let noSleep = null
let video = null
// --- Public ---
export function activate() {
if (!noSleep) noSleep = new NoSleep()
}
export function deactivate() {
if (noSleep) {
noSleep.stop()
noSleep = null
}
}
// --- Private ---
class NoSleep {
constructor() {
this._noSleep = true
this._keepAwake()
}
stop() {
this._noSleep = false
}
async _keepAwake() {
while(this._noSleep) {
if (video) video.play()
document.body.innerHTML += "<br>Played"
await wait(10000)
}
}
}
window.addEventListener("click", function enable() {
window.removeEventListener("click", enable)
// Initialize video element
video = document.createElement("video")
video.setAttribute("playsinline", "")
// Add mp4 source
let source = document.createElement("source")
source.src = mp4Src
source.type = "video/mp4"
video.append(source)
// Add webm source
source = document.createElement("source")
source.src = webmSrc
source.type = "video/webm"
video.append(source)
// Play it as a result of user interaction
video.play()
document.body.innerHTML = "Activated"
activate()
})
function wait(milliseconds) {
return new Promise(resolve => setTimeout(resolve, milliseconds))
}
const mp4Src = "data:video/mp4;base64,AAAAHGZ0eXBpc29tAAACAGlzb21pc28ybXA0MQAAAyBtb292AAAAbG12aGQAAAAAAAAAAAAAAAAAAAPoAAAAGwABAAABAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAACSnRyYWsAAABcdGtoZAAAAAMAAAAAAAAAAAAAAAEAAAAAAAAAGwAAAAAAAAAAAAAAAQEAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAACRlZHRzAAAAHGVsc3QAAAAAAAAAAQAAABoAAAgAAAEAAAAAAcJtZGlhAAAAIG1kaGQAAAAAAAAAAAAAAAAAAKxEAAAEgFXEAAAAAAAxaGRscgAAAAAAAAAAc291bgAAAAAAAAAAAAAAAENvcmUgTWVkaWEgQXVkaW8AAAABaW1pbmYAAAAQc21oZAAAAAAAAAAAAAAAJGRpbmYAAAAcZHJlZgAAAAAAAAABAAAADHVybCAAAAABAAABLXN0YmwAAAB7c3RzZAAAAAAAAAABAAAAa21wNGEAAAAAAAAAAQAAAAAAAAAAAAIAEAAAAACsRAAAAAAAM2VzZHMAAAAAA4CAgCIAAQAEgICAFEAVAAAAAAJ/9wACf/cFgICAAhIQBoCAgAECAAAAFGJ0cnQAAAAAAAJ/9wACf/cAAAAgc3R0cwAAAAAAAAACAAAAAwAABAAAAAABAAAAgAAAABxzdHNjAAAAAAAAAAEAAAABAAAABAAAAAEAAAAkc3RzegAAAAAAAAAAAAAABAAAAXMAAAF0AAABcwAAAXQAAAAUc3RjbwAAAAAAAAABAAADTAAAABpzZ3BkAQAAAHJvbGwAAAACAAAAAf//AAAAHHNiZ3AAAAAAcm9sbAAAAAEAAAAEAAAAAQAAAGJ1ZHRhAAAAWm1ldGEAAAAAAAAAIWhkbHIAAAAAAAAAAG1kaXJhcHBsAAAAAAAAAAAAAAAALWlsc3QAAAAlqXRvbwAAAB1kYXRhAAAAAQAAAABMYXZmNTguNzYuMTAwAAAACGZyZWUAAAXWbWRhdCERRQAUUAFG//EKWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaXemCFLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS8IRFFABRQAUb/8QpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpd6aIUtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS8IRFFABRQAUb/8QpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpd6YIUtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLwhEUUAFFABRv/xClpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWl3pohS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLw="
const webmSrc = "data:video/webm;base64,GkXfo59ChoEBQveBAULygQRC84EIQoKEd2VibUKHgQRChYECGFOAZwEAAAAAAANXEU2bdLpNu4tTq4QVSalmU6yBoU27i1OrhBZUrmtTrIHYTbuMU6uEElTDZ1OsggE/TbuMU6uEHFO7a1OsggNB7AEAAAAAAABZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVSalmsirXsYMPQkBNgI1MYXZmNTguNzYuMTAwV0GNTGF2ZjU4Ljc2LjEwMESJiEBBAAAAAAAAFlSua+KuAQAAAAAAAFnXgQFzxYjHh4Jmxpm3C5yBACK1nIN1bmSGhkFfT1BVU1aqg2MuoFa7hATEtACDgQLhkZ+BArWIQOdwAAAAAABiZIEYY6KTT3B1c0hlYWQBAjgBgLsAAAAAABJUw2dB03NzAQAAAAAAAQ5jwIBnyAEAAAAAAAAVRaOLTUFKT1JfQlJBTkREh4RxdCAgZ8gBAAAAAAAAFEWjjU1JTk9SX1ZFUlNJT05Eh4EwZ8gBAAAAAAAAG0WjkUNPTVBBVElCTEVfQlJBTkRTRIeEcXQgIGfIAQAAAAAAABlFo4hUSU1FQ09ERUSHizAwOjAwOjAwOjAwZ8gBAAAAAAAAKkWjn0NPTS5BUFBMRS5RVUlDS1RJTUUuRElTUExBWU5BTUVEh4VlbXB0eWfIAQAAAAAAACRFo5lDT00uQVBQTEUuUVVJQ0tUSU1FLlRJVExFRIeFZW1wdHlnyAEAAAAAAAAaRaOHRU5DT0RFUkSHjUxhdmY1OC43Ni4xMDBzcwEAAAAAAACxY8CLY8WIx4eCZsaZtwtnyAEAAAAAAAAiRaOMSEFORExFUl9OQU1FRIeQQ29yZSBNZWRpYSBBdWRpb2fIAQAAAAAAABtFo4lWRU5ET1JfSUREh4xbMF1bMF1bMF1bMF1nyAEAAAAAAAAjRaOHRU5DT0RFUkSHlkxhdmM1OC4xMzQuMTAwIGxpYm9wdXNnyKJFo4hEVVJBVElPTkSHlDAwOjAwOjAwLjAzNDAwMDAwMAAAH0O2daTngQCjh4EAAID8//6gAQAAAAAAAA+hh4EAFQD8//51ooNwiJgcU7trkbuPs4EAt4r3gQHxggMY8IED"
Implementation is made so multiple calls to activate()/deactivate() have no effect (which was beneficial in my use case). I create NoSleep object to make sure that it's gonna deactivate (operation may take up to 10 seconds to deactivate). Without it quick successive activations and deactivations could result in multiple wake cycles to run at the same time without quiting themselves eventually.
Play looped VIDEO or AUDIO on your page
You can use this a quick example to add a Fake looped video to your page and prevent mobile device from sleep:
// Create the root video element
var video = document.createElement('video');
video.setAttribute('loop', '');
// Add some styles if needed
video.setAttribute('style', 'position: fixed;');
// A helper to add sources to video
function addSourceToVideo(element, type, dataURI) {
var source = document.createElement('source');
source.src = dataURI;
source.type = 'video/' + type;
element.appendChild(source);
}
// A helper to concat base64
var base64 = function(mimeType, base64) {
return 'data:' + mimeType + ';base64,' + base64;
};
// Add Fake sourced
addSourceToVideo(video,'webm', base64('video/webm', 'GkXfo0AgQoaBAUL3gQFC8oEEQvOBCEKCQAR3ZWJtQoeBAkKFgQIYU4BnQI0VSalmQCgq17FAAw9CQE2AQAZ3aGFtbXlXQUAGd2hhbW15RIlACECPQAAAAAAAFlSua0AxrkAu14EBY8WBAZyBACK1nEADdW5khkAFVl9WUDglhohAA1ZQOIOBAeBABrCBCLqBCB9DtnVAIueBAKNAHIEAAIAwAQCdASoIAAgAAUAmJaQAA3AA/vz0AAA='));
addSourceToVideo(video, 'mp4', base64('video/mp4', 'AAAAHGZ0eXBpc29tAAACAGlzb21pc28ybXA0MQAAAAhmcmVlAAAAG21kYXQAAAGzABAHAAABthADAowdbb9/AAAC6W1vb3YAAABsbXZoZAAAAAB8JbCAfCWwgAAAA+gAAAAAAAEAAAEAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAIVdHJhawAAAFx0a2hkAAAAD3wlsIB8JbCAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAQAAAAAAIAAAACAAAAAABsW1kaWEAAAAgbWRoZAAAAAB8JbCAfCWwgAAAA+gAAAAAVcQAAAAAAC1oZGxyAAAAAAAAAAB2aWRlAAAAAAAAAAAAAAAAVmlkZW9IYW5kbGVyAAAAAVxtaW5mAAAAFHZtaGQAAAABAAAAAAAAAAAAAAAkZGluZgAAABxkcmVmAAAAAAAAAAEAAAAMdXJsIAAAAAEAAAEcc3RibAAAALhzdHNkAAAAAAAAAAEAAACobXA0dgAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAIAAgASAAAAEgAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABj//wAAAFJlc2RzAAAAAANEAAEABDwgEQAAAAADDUAAAAAABS0AAAGwAQAAAbWJEwAAAQAAAAEgAMSNiB9FAEQBFGMAAAGyTGF2YzUyLjg3LjQGAQIAAAAYc3R0cwAAAAAAAAABAAAAAQAAAAAAAAAcc3RzYwAAAAAAAAABAAAAAQAAAAEAAAABAAAAFHN0c3oAAAAAAAAAEwAAAAEAAAAUc3RjbwAAAAAAAAABAAAALAAAAGB1ZHRhAAAAWG1ldGEAAAAAAAAAIWhkbHIAAAAAAAAAAG1kaXJhcHBsAAAAAAAAAAAAAAAAK2lsc3QAAAAjqXRvbwAAABtkYXRhAAAAAQAAAABMYXZmNTIuNzguMw=='));
// Append the video to where ever you need
document.body.appendChild(video);
// Start playing video after any user interaction.
// NOTE: Running video.play() handler without a user action may be blocked by browser.
var playFn = function() {
video.play();
document.body.removeEventListener('touchend', playFn);
};
document.body.addEventListener('touchend', playFn);
I'm creating a 'catch falling items' game, and have successfully drawn the 'catcher' image and the 'falling items' images onto the canvas. But I'd like to also show an image (x.png) when a falling image is not caught and hits the base of my html5 canvas. The generateX function is called from the animate function and when a falling image hits the base of the canvas. The sound.play() is working. The console.logs in the generateX function log the following - 2,3 | 1,3 | 1,3 - so I know that the image is not completely loaded the first time this function runs. Everything seems to be working EXCEPT for the actual image displaying. I tried to structure it in ways that other threads have suggested, but nothing is working. Any help is much appreciated!
generateX: function() {
console.log('inside generateX func');
var imgX = new Image();
imgX.src = 'assets/x.png';
function drawX() {
console.log(3);
counter+=20;
context.drawImage(imgX, xIcon.x + counter, xIcon.y, xIcon.width, xIcon.height);
xArr.push(imgX);
console.log('xArr', xArr);
}
if (imgX.complete) {
console.log(1);
drawX();
} else {
console.log(2);
imgX.onload = drawX;
}
helper.checkMisses();
}
animate: function() {
var sound;
if (continueAnimating) {
requestAnimationFrame(helper.animate);
}
for (var i = 0; i < surveys.length; i++) {
var survey = surveys[i];
if (helper.isColliding(survey, dinoSaurus)) {
sound = new Audio("audio/coinSound.mp3");
sound.play();
score += 5;
helper.resetSurvey(survey);
}
survey.y += survey.speed;
// if the survey is below the canvas,
if (survey.y > canvas.height) {
sound = new Audio("audio/buzzerSound.mp3");
sound.play();
helper.generateX();
helper.resetSurvey(survey);
}
}
// redraw everything
helper.drawAll();
}
--
resetSurvey: function(survey) {
// randomly position survey near the top of canvas
survey.x = Math.random() * (canvas.width - surveyWidth);
survey.y = 40 + Math.random() * 30;
survey.speed = (0.55 + Math.random()) * 0.9;
}
Try loading your image earlier
If I understand your situation correctly, I think the issue is that you need to load the image earlier so that it is easily ready by the time you want to draw it, rather than waiting to load it only inside generateX. The way you are currently coding it, you are loading the image (imgX.src = ...) and then immediately trying to draw it. True, you are checking if the loading is complete and, if not, trying again shortly after. However, a better strategy is to load the image much earlier, e.g. during game initialization.
Demo
The code snippet below demonstrates the difference that this makes. It loads 2 different images. The only difference between the two is that one (on the left) is loaded ahead of time and the other (on the right) is only loaded inside generateX. The former image displays properly the 1st time through the game cycle while the latter image is missing the 1st time and only displays properly the 2nd time through.
function loadLeftImageWellBeforeRunningGenerateX() { // correct timing
imgs[0] = new Image();
imgs[0].src = 'http://placehold.it/200x100.png';
}
function loadRightImageInsideGenerateX() { // incorrect timing
imgs[1] = new Image();
imgs[1].src = 'http://placehold.it/100x50.png';
}
function generateX() {
loadRightImageInsideGenerateX();
log('--inside generateX func');
imgs.forEach(function(imgX, num) { // same as your original code, just done for 2 different images
if (imgX.complete) {
log("----image #" + num + " (" + side[num] + "); " + 1 + ", i.e. image complete");
drawX(imgX, num);
} else {
log("----image #" + num + " (" + side[num] + "); " + 2 + ", i.e. image not complete");
imgX.onload = drawX(imgX, num);
}
});
}
function drawX(imgX, num) { // same as your original code, just allows placement of 2 images side-by-side
log("----image #" + num + " (" + side[num] + "); " + 3 + ", i.e. drawing image (" + prefix[num] + "successfully)");
context.drawImage(imgX, num * 150 + 10, 10, 100, 50);
if (num === 1) {prefix[1] = "";}
}
var
imgs = [],
numClicks = 0,
side = ["left", "right"],
prefix = ["", "un"],
button = document.querySelector("button"),
canvas = document.getElementById('myCanvas'),
context = canvas.getContext('2d');
context.fillStyle = "yellow";
context.fillRect(0, 0, 300, 150);
// as far as game logic goes, the only important lines below are marked with arrows
// the rest is just "fluff" to make the demo more understandable to the user
button.addEventListener("click", function() {
numClicks += 1;
if (numClicks === 1) {
log("You must clear your browser's recent cache every time you run this snippet " +
"in order for it to demonstrate the problems and solutions " +
"associated with loading images in this code.");
button.innerHTML = "Clear browser cache and click here again to start game initialization";
} else if (numClicks === 2) {
loadLeftImageWellBeforeRunningGenerateX(); // <----- ***
log("Game initializes. No images should yet be visible, " +
"but image #0 (left) should be loading/loaded now, i.e. ahead of time. " +
"Image #1 (right) is not yet loading/loaded. Click again to 'play game'.");
button.innerHTML = "Do NOT clear the browser cache and click here again to start playing game";
} else {
button.innerHTML = "Do NOT clear the browser cache and click here again to continue playing game";
if (numClicks === 3) {
log("Game begins. Images are required for the first time. Only the pre-loaded left image shows " +
"even though loading both is attempted.");
} else {
log("Game continues. On second and subsequent re-draws, both images are now available and visible.");
}
generateX(); // <----- ***
}
});
function log(msg) {
document.body.appendChild(document.createElement("p")).innerHTML = msg;
}
p {
margin: 0.2em;
}
<canvas id="myCanvas" width="300" height="80"></canvas>
<div>
<button>Click here to begin demo</button>
</div>
Your browser's cache can hide this bug
By the way, if and when you try to debug this kind of thing, be aware that many/most/all browsers cache images, making it potentially difficult to replicate this kind of bug if you're not aware of what's going on. For example, you might run your buggy code and the image is missing the first time through the game cycle. You study your code, make a change to try to fix the bug and run the code a second time. Voila, it looks like the problem is fixed because the image now appears the first time through the game cycle. However, it may, in fact, only be showing up in that first cycle not because the bug is fixed but because the browser is able to use the cached image even in the first game cycle, eliminating the need to load it from its source. In short, if you're trying to debug an issue like this where you suspect the timing of file loading is important but the bug only appears sometimes, try clearing your browser's recent cache to see if that makes the bug more apparent.
To clear a browser's cache:
Firefox (for Mac or Windows, v44...): click "History" / click "Clear Recent History..." / click to open "Details" if necessary / check "Cache" / click "Clear now"
Chrome (for Mac, v48...) "Chrome" (left menu item) / "Clear Browsing Data..." / select "Cached images and files" / click "Clear browsing data"
Chrome (for Windows, v48...) click customize-and-control icon (at the right) / click "More tools..." / click "Clear browsing data..." / click "Clear browsing data"
Internet Explorer (for Windows, v11...) click "Tools" / click "Delete browsing history" / select "Download history" / click "Delete"
I'm creating an app for Android and iOS with titanium which sends a new Geolocation to a server every 5 seconds for as long as the server runs. On iOS however the app stops sending those locations after a random interval. Although i myself are not completely convinced this is due to the fact that the app pauses in iOS(Since it stops randomly and not on a fixed time) i'm still eager to try and be certain.
However; i really have NO CLUE to do this whatsoever. I've created a background service in an eventListener to see what happens and it starts logging right away(I've put a console log in it for now). Nonetheless, my geolocation is still ticking normally aswell.
Now, could someone please give me some pointers on how to get through this? Do i want to stop my normal geolocation listener and let the BG service take over? Or does the BGservice keep the geolocation eventlistener in my normal code active now?
At this point i'm afraid to say that i'm pretty much desperate to get any help, haha!
Here's my geolocation handling now, along with the BGservice:
//Start button. listens to an eventHandler in location.js
btnStart.addEventListener('click', function (e) {
if( Titanium.Geolocation.locationServicesEnabled === false ) {
GPSSaved.text = 'Your device has GPS turned off. Please turn it on.';
} else {
if (Titanium.Network.online) {
GPSSaved.text = "GPS zoeken...";
//Empty interval and text to make a clean (re)start
clearInterval(interval);
//Set a half second timer on the stop button appearing(So people can't double tap the buttons)
stopTimeout = setTimeout(showStopButton, 1000);
//Switch the textlabels and buttons from startview to stopview
stopText.show();
startText.hide();
btnStart.hide();
//Locationhandler
location.start({
action: function (e) {
//Ti.API.info(e.coords.longitude);
if (e.coords) {
//If the newly acquired location is not the same as the last acquired it is allowed
if (e.coords.longitude != lastLon && e.coords.latitude != lastLat) {
//set the last acquired locations+other info to their variables so they can be checked(and used)
lastLat = e.coords.latitude;
lastLon = e.coords.longitude;
lastKnownAltitude = e.coords.altitude;
lastKnownHeading = e.coords.heading;
lastKnownSpeed = e.coords.speed;
if (lastLat != 0 && lastLon != 0) {
setGPSholder(lastLat, lastLon, lastKnownAltitude, lastKnownHeading, lastKnownSpeed);
} else {
GPSSaved.text = 'Geen coordinaten.';
}
}
}
}
});
/*
A second interval which shows a counter to the user and makes sure a location is sent
roughly every 5 seconds(setInterval isn't accurate though)
A lot of counters are tracked for several reasons:
minuteInterval: Counter which makes sure the last location is sent after a minute if no new one is found in the meantime
secondsLastSent: The visual counter showing the user how long its been for the last save(Is reset to 0 after a succesful save)
*/
interval = setInterval(function () {
minuteInterval++;
minuteIntervalTest++;
secondsLastSent++;
counterBlock.text = "De laatste locatie is " + secondsLastSent + " seconden geleden verstuurd";
//If the counter is higher than 5 send a new coordinate. If at the same time the minuteInterval is over a minute
//The last location is put in the array before calling the sendCoordinates
if (counter >= 5) {
if (minuteInterval > 60) {
if (lastLat != 0 && lastLon != 0) {
setGPSholder(lastLat, lastLon, lastKnownAltitude, lastKnownHeading, lastKnownSpeed);
}
}
counter = 0;
sendCoordinates();
Ti.API.info(1);
} else {
counter++;
}
if (minuteIntervalTest > 60) {
sendTestRequest();
}
}, 1000);
if (Titanium.Platform.osname == 'iphone' || Titanium.Platform.osname == 'ipad') {
//var service = Ti.App.iOS.registerBackgroundService({url:'send_geolocation_service.js'});
var service;
// Ti.App.iOS.addEventListener('notification',function(e){
// You can use this event to pick up the info of the noticiation.
// Also to collect the 'userInfo' property data if any was set
// Ti.API.info("local notification received: "+JSON.stringify(e));
// });
// fired when an app resumes from suspension
Ti.App.addEventListener('resume',function(e){
Ti.API.info("app is resuming from the background");
});
Ti.App.addEventListener('resumed',function(e){
Ti.API.info("app has resumed from the background");
// this will unregister the service if the user just opened the app
// is: not via the notification 'OK' button..
if(service!=null){
service.stop();
service.unregister();
}
Titanium.UI.iPhone.appBadge = null;
});
Ti.App.addEventListener('pause',function(e){
Ti.API.info("app was paused from the foreground");
service = Ti.App.iOS.registerBackgroundService({url:'send_geolocation_service.js'});
Ti.API.info("registered background service = "+service);
});
}
} else {
stopGPS();
GPSSaved.text = "Geen internetverbinding.";
}
}
});
As you can see there's some counters running in an interval to decide if a geolocation should be sent every 5 seconds or every minute(If no new location since the last is found)
tl;dr: I want geolocations to be sent every 5 seconds but somehow iOS(iPhone 4s and 5 tested) stop sending after a random timeperiod and restart sending the moment i get the phone out of standby.
actually background service has a limitation to stop after 10 mins so if you want to catch location when device is in background mode then you need to set mode tag in tiapp.xml file.
just refer this online doc for how it works.
http://docs.appcelerator.com/titanium/3.0/#!/guide/tiapp.xml_and_timodule.xml_Reference-section-29004921_tiapp.xmlandtimodule.xmlReference-LegacyiPhonesection