I have the code listed below. The code is on https://omegalords.ga/test.world.html. I want the item to not move beyond the canvas. How can I find how many units are in the canvas? I am aware of the other errors in the console. I specifically need the canvas's dimensions in reference to items placed on the canvas. The point of the code is to create a wolf and a deer that interact. The problem is that I need to ensure that the 2 don't leave the canvas.
<script src=../script/algebra-0.2.6.min.js></script>
<canvas id="myCanvas" style="width:100%; height:100%;">
</canvas>
<script>
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
console.log(document.body.style)
var findDis = function(x1,y1,x2,y2){
//Finds distance rounded to the nearest 1000th
return Math.trunc(((Math.sqrt((x1-x2) * (x1-x2) + (y1-y2) * (y1-y2)))*1000))/1000
}
var findIntersections = function(b,a,m,r){
var Fraction = algebra.Fraction;
var Expression = algebra.Expression;
var Equation = algebra.Equation;
var coords = {
l:[],
g:[]
}
//b^2 - 2bx + x^2 - 2bm^2x + b^2m^2 - r^2
var sl = algebra.parse(Math.pow(b,2)+" - "+2*b+"x + x^2 + "+Math.pow(m,2)+"x^2 -" + 2 * b * Math.pow(m,2) + "* x + " + Math.pow(b,2) * Math.pow(m,2) + " - " + Math.pow(r,2));
var sr = algebra.parse("0")
var eq = new Equation(sl, sr);
//Solves for x rounded to the nearest 1000
coords.l.push(Math.trunc((eq.solveFor("x")[0]*1000))/1000);
coords.g.push(Math.trunc((eq.solveFor("x")[1]*1000))/1000);
//Solves for y
coords.l.push(Math.trunc((eq.solveFor("x")[0] * m + a - (b * m))*1000)/1000);
coords.g.push(Math.trunc((eq.solveFor("x")[1] * m + a - (b * m))*1000)/1000);
return JSON.stringify(coords);
}
var findSlope = function(x1,y1,x2,y2){
//Finds Slope rounded to the nearest 1000th
return Math.trunc(((y1-y2)/(x1-x2))*1000)/1000;
}
var getRandomInt = function(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min)) + min;
}
var wolves = [];
var deers = [];
var animal = function(x,y){
this.age = 0
this.strength = 0;
this.x = x;
this.y = y;
this.hp = 100;
this.size = 10;
this.hunger = 0;
}
animal.prototype.move = function(){
this.nearbyPredators = [];
this.nearbyPrey = [];
for(var j = 0;j<this.predatorTypes.length;j++){
for(var i = 0;i < this.predatorTypes[j].length;i++){
if(findDis(this.predatorTypes[j][i].x,this.predatorTypes[j][i].y,this.x,this.y) < 40){
this.nearbyPredators.push(this.predatorTypes[j][i]);
}else{
console.log(findDis(this.predatorTypes[j][i].x,this.this.predatorTypes[j][i].y,this.x,this.y))
}
}
}
//finds all nearby prey
for(var j = 0;j<this.preyTypes.length;j++){
for(var i = 0;i < this.preyTypes[j].length;i++){
if(findDis(this.preyTypes[j][i].x,this.preyTypes[j][i].y,this.x,this.y) < 40){
this.nearbyPrey.push(this.preyTypes[j][i]);
}else{
console.log(findDis(this.preyTypes[j][i].x,this.preyTypes[j][i].y,this.x,this.y))
}
}
}
if(this.nearbyPredators.length == 0){
//If there are no nearby prey, move randomly
if(this.nearbyPrey.length === 0){
var tx = this.x + getRandomInt(-8,9);
var ty = this.y + getRandomInt(-9,8);
while(!(tx > (0 + this.size)) && !(ty > (0 + this.size)) && !(tx < (canvas.length - this.size)) && !(ty < (canvas.height - this.size))){
tx = this.x + getRandomInt(-8,9);
ty = this.y + getRandomInt(-9,8);
}
this.x = tx
this.y = ty
//If there is only one nearby prey, move towards it
}else if(this.nearbyPrey.length === 1){
this.nearestPrey = this.nearbyPrey[0]
var tempDis = findDis(this.x,this.y,this.nearestPrey.x,this.nearestPrey.y);
if(tempDis < 2*this.nearestPrey.size){
this.bite(this.nearestPrey)
}else {
var slope = findSlope(this.nearestPrey.x,this.nearestPrey.y,this.x,this.y);
var coords = JSON.parse(findIntersections(this.x,this.y,slope,0.125));
var ldis = findDis(this.x,this.y,coords.l[0],coords.l[1]);
var gdis = findDis(this.x,this.y,coords.g[0],coords.g[1]);
if(ldis > gdis){
this.x = coords.l[0]
this.y = coords.l[1]
}else {
this.x = coords.g[0]
this.y = coords.g[1]
}
}
//If there is more than 1, find the nearest prey and move towards it
}else {
for(var i = 0; i < this.nearbyPrey.length; i++){
this.tempDis = getDis(this.x,this.y,this.nearbyPrey[i].x,this.nearbyPrey[i].y)
if(typeof this.nearestPrey == 'undefined'){
this.nearestPrey = {
prey:this.nearbyPrey[i],
distance:this.tempDis
}
this.tempDis = undefined
}else {
if(this.tempDis > this.nearestPrey.distance){
this.nearestPrey = {
prey:this.nearbyPrey[i],
distance:this.tempDis
}
}
}
}
var slope = findSlope(this.nearestPrey.x,this.nearestPrey.y,this.x,this.y)
var coords = JSON.parse(findIntersections(this.nearestPrey.x,this.nearestPrey.y,slope,0.25));
var ldis = findDis(this.nearestPrey.x,this.nearestPrey.y,coords.l[0],coords.l[1]);
var gdis = findDis(this.nearestPrey.x,this.nearestPrey.y,coords.g[0],coords.g[1]);
if(ldis > gdis){
this.x = coords.l[0]
this.y = coords.l[1]
}else {
this.x = coords.g[0]
this.y = coords.g[1]
}
}
}else {
}
}
var grass = function(){
}
var deer = function(x,y){
animal.call(this,x,y)
deers.push(this);
this.preyTypes = [grass];
this.predatorTypes = [wolves];
}
var wolf = function(x,y){
animal.call(this,x,y)
wolves.push(this);
this.predatorTypes = [];
this.preyTypes = [deers]
}
deer.prototype = Object.create(animal.prototype);
wolf.prototype = Object.create(animal.prototype);
wolf.prototype.bite = function(prey){
prey.hp -= this.strength;
if(prey.hp < 0){
prey.die()
}
this.hunger += 40/100
console.log(this.hunger);
console.log(prey.hp)
}
new wolf(100,100)
new deer(50,50);
var init = function(){
ctx.translate(0.5, 0.5);
ctx.lineWidth = .5
window.setInterval(draw,250);
}
var draw = function(){
ctx.clearRect(0,0,canvas.width,canvas.height)
wolves[0].move();
for(var i=0;i<wolves.length;i++){
ctx.beginPath()
ctx.arc(wolves[i].x,wolves[i].y,10,0,2*Math.PI);
ctx.stroke();
}
for(var i=0; i<deers.length;i++){
ctx.beginPath();
ctx.arc(deers[i].x,deers[i].y,10,0,2*Math.PI);
ctx.stroke();
}
}
init()
</script>
var canvasHeight = canvas.clientHeight;
var canvasWidth = canvas.clientWidth;
Please note, this will also include any padding, but by default, the canvas has no padding.
Sources:
https://developer.mozilla.org/en-US/docs/Web/API/Element/clientHeight
https://developer.mozilla.org/en-US/docs/Web/API/Element/clientWidth
You can get the css properties:
var canvasWidth = canvas.style.width;
var canvasHeight = canvas.style.height;
Related
Using certain methods, I drew a 3D cube.
My task is to rotate it around the z axis. I also need to rotate the cube relative to the coordinates (0,0,0) (on my canvas, these will be the coordinates (150,150,0)). Now it rotates correctly, but only changes its angle relative to the 'top left corner of my canvas'.
I think the solution to my problem is as follows:
To rotate the cube relative to the given coordinates, the cube must first be translated to the negative coordinates of this point, and by changing the angle, it must be translated back, but only to the positive coordinates of this point.
In my case the pseudo code would be like this:
// if I want to flip the cube around the coordinates (150,150,0) (this is the center of my canvas), then I need to do the following
translate(-150,-150,0);
rotate();
translate(150,150,0);
In the commented parts of the code, I tried to do this, but when I translate the cube, it gets stuck somewhere in the corner and I don't know how to fix it.
function randInt(min, max) {
return Math.floor(Math.random() * (max - min + 1) ) + min;
}
function randomColor() {
return "rgb(" + randInt(0,255) + "," + randInt(0,255) + "," + randInt(0,255) + ")";
}
function ctg(x) {
return 1 / Math.tan(x);
}
function draw() {
let canvas = document.getElementById("canvas");
let context = canvas.getContext("2d");
let canvasWidth = 300;
canvas.width = canvas.height = canvasWidth;
function drawUW() {
context.lineWidth = 0.1;
context.beginPath();
context.moveTo(0,canvas.height/2);
context.lineTo(canvas.width,canvas.height/2);
context.moveTo(canvas.width/2,0);
context.lineTo(canvas.width/2,canvas.height);
context.stroke();
}
function updateCanvas() {
context.clearRect(0,0,canvas.width,canvas.height);
drawUW();
}
let x = 50, y = 50, z = 50;
let d = 100;
let x0 = canvas.width/2;
let y0 = canvas.height/2;
let x1 = x0+x;
let y1 = y0;
let x2 = x0;
let y2 = y0-y;
let x3 = x0+x;
let y3 = y0-y;
// x' = xd/(z+d)
// y' = yd/(z+d)
let x0p=x0*d/(z+d);
let y0p=y0*d/(z+d);
let x1p=x1*d/(z+d);
let y1p=y1*d/(z+d);
let x2p=x2*d/(z+d);
let y2p=y2*d/(z+d);
let x3p=x3*d/(z+d);
let y3p=y3*d/(z+d);
function getWalls() {
wall01 = [[x0,x2,x3,x1],[y0,y2,y3,y1]];
wall02 = [[x0p,x2p,x2,x0],[y0p,y2p,y2,y0]];
wall03 = [[x0p,x2p,x3p,x1p],[y0p,y2p,y3p,y1p]];
wall04 = [[x1p,x3p,x3,x1],[y1p,y3p,y3,y1]];
wall05 = [[x2,x2p,x3p,x3],[y2,y2p,y3p,y3]];
wall06 = [[x0,x0p,x1p,x1],[y0,y0p,y1p,y1]];
}
function drawWall(wall) {
context.fillStyle = randomColor();
context.strokeStyle = "black";
context.lineWidth = 0.5;
context.beginPath();
context.moveTo(wall[0][0],wall[1][0]);
context.lineTo(wall[0][1],wall[1][1]);
context.lineTo(wall[0][2],wall[1][2]);
context.lineTo(wall[0][3],wall[1][3]);
context.lineTo(wall[0][0],wall[1][0]);
context.fill();
context.stroke();
}
function rotatePoint(x,y,z,fi) {
fi*=Math.PI/180;
arr = [x,y,z,1];
newX = 0;
newY = 0;
newZ = 0;
tx = -150, ty = -150, tz = -150;
arrTranslate = [
[1,0,0,tx],
[0,1,0,ty],
[0,0,1,tz],
[0,0,0,1]
];
// z
arrRotate = [
[Math.cos(fi),-Math.sin(fi),0,0],
[Math.sin(fi),Math.cos(fi),0,0],
[0,0,1,0],
[0,0,0,1]
];
// translate
// for (let i = 0; i < arr.length; i++) {
// newX += arr[i] * arrTranslate[0][i];
// newY += arr[i] * arrTranslate[1][i];
// newZ += arr[i] * arrTranslate[2][i];
// }
//rotate
for (let i = 0; i < arr.length; i++) {
newX += arr[i] * arrRotate[0][i];
newY += arr[i] * arrRotate[1][i];
newZ += arr[i] * arrRotate[2][i];
}
tx = 150, ty = 150, tz = 150;
// translate
// for (let i = 0; i < arr.length; i++) {
// newX += arr[i] * arrTranslate[0][i];
// newY += arr[i] * arrTranslate[1][i];
// newZ += arr[i] * arrTranslate[2][i];
// }
x = newX;
y = newY;
z = newZ;
return [newX,newY,newZ];
}
function rotatePoints(fi) {
x0 = rotatePoint(x0,y0,z,fi)[0];
y0 = rotatePoint(x0,y0,z,fi)[1];
x1 = rotatePoint(x1,y1,z,fi)[0];
y1 = rotatePoint(x1,y1,z,fi)[1];
x2 = rotatePoint(x2,y2,z,fi)[0];
y2 = rotatePoint(x2,y2,z,fi)[1];
x3 = rotatePoint(x3,y3,z,fi)[0];
y3 = rotatePoint(x3,y3,z,fi)[1];
x0p = rotatePoint(x0p,y0p,z,fi)[0];
y0p = rotatePoint(x0p,y0p,z,fi)[1];
x1p = rotatePoint(x1p,y1p,z,fi)[0];
y1p = rotatePoint(x1p,y1p,z,fi)[1];
x2p = rotatePoint(x2p,y2p,z,fi)[0];
y2p = rotatePoint(x2p,y2p,z,fi)[1];
x3p = rotatePoint(x3p,y3p,z,fi)[0];
y3p = rotatePoint(x3p,y3p,z,fi)[1];
}
let inFi = document.getElementById("fi");
inFi.addEventListener("change", updateImage);
function updateImage() {
rotatePoints(inFi.value);
getWalls();
updateCanvas();
drawWall(wall06);
drawWall(wall04);
drawWall(wall03);
drawWall(wall02);
drawWall(wall05);
drawWall(wall01);
}
updateImage();
}
<body onload="draw();">
<canvas id="canvas"></canvas>
<div><input type="number" id="fi" value="0"></div>
</body>
Im making a small game where I move a ball onDeviceOrientation into holes. I generate holes(circles) in canvas and push them into an array called holes. When I'm trying to check for collision, the declared value let currentHole = this.holes[i]; shows this error. Can you tell me why the property of 0 is undefined? I couldn't understand checking other people's problems.
this is my JS code:
const canvas = document.querySelector('.canvas');
const hole = canvas.getContext('2d');
let scoreCount = 0;
let holes = [];
var hx = Math.random() * canvas.width;
var hy = Math.random() * canvas.height;
var radius = 25;
var sAngle = 0;
var eAngle = 2 * Math.PI;
let speedX = 0;
let speedY = 0;
let x = 200;
let y = 200;
window.addEventListener('deviceorientation', onDeviceOrientationChange);
const restart = document.querySelector('.restart');
document.querySelector('.start').addEventListener('click', onStartClick);
function onStartClick() {
const btn = document.querySelector('.start');
btn.classList.add('remove');
restart.classList.remove('remove');
const score = document.createElement('span');
score.classList.add('score');
score.innerHTML = 'SCORE: ' + scoreCount;
document.body.appendChild(score);
let ball = document.createElement('div');
ball.classList.add('ball');
document.body.appendChild(ball);
makeHoles();
onDeviceOrientationChange(event);
checkForCollision();
}
function onDeviceOrientationChange(event) {
let ball = document.querySelector('.ball');
speedX = event.alpha / 60; //alpha nie
speedY = event.beta / 60;
if ((innerWidth > speedX + x > 0)) {
x += speedX;
ball.style.left = x + 'px';
}
if (window.innerHeight > speedY + y > 0) {
y += speedY;
ball.style.top = y + 'px';
}
}
function makeHoles() {
for (let i = 1; i < canvas.width / 100; i++) {
hole.beginPath();
hole.arc(
hx,
hy,
radius,
sAngle,
eAngle,
);
hole.fillStyle = 'rgb(84, 93, 139)';
hole.fill();
hole.stroke();
hole.closePath();
holes.push(hole);
}
console.log(holes);
}
function checkForCollision() {
for (let i = 0; i < holes.length; i++) {
let currentHole = this.holes[i];
let ball = document.querySelector('.ball');
currentHole = {
radius: radius,
x: hx,
y: hy
};
ball = {
radius: 15,
x: x,
y: y
};
var dx = currentHole.x - ball.x;
var dy = currentHole.y - ball.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < currentHole.radius + ball.radius) {
scoreCount++;
}
}
}
You should use 'holes[i]', not 'this.holes[i]'.
On website https://omegalords.ga/world/test.html, I have a code that calculates 1 unit towards a target. In the code the slope is 1. so the x and y of the next spot to jump to should be the same. Why does it at some point change and the 2 coordinates. I have ran the numbers, but it doesn't work properly. Could someone explain hwy?
</canvas>
<script>
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var findDis = function(x1,y1,x2,y2){
//Finds distance rounded to the nearest 1000th
return Math.trunc(((Math.sqrt((x1-x2) * (x1-x2) + (y1-y2) * (y1-y2)))*1000))/1000
}
var findIntersections = function(b,a,m,r){
var Fraction = algebra.Fraction;
var Expression = algebra.Expression;
var Equation = algebra.Equation;
var coords = {
l:[],
g:[]
}
//b^2 - 2bx + x^2 - 2bm^2x + b^2m^2 - r^2
var sl = algebra.parse(Math.pow(b,2)+" - "+2*b+"x + x^2 + "+Math.pow(m,2)+"x^2 -" + 2 * b * Math.pow(m,2) + "* x + " + Math.pow(b,2) * Math.pow(m,2) + " - " + Math.pow(r,2));
var sr = algebra.parse("0")
var eq = new Equation(sl, sr);
//Solves for x rounded to the nearest 1000
coords.l.push(Math.trunc((eq.solveFor("x")[0]*1000))/1000);
coords.g.push(Math.trunc((eq.solveFor("x")[1]*1000))/1000);
//Solves for y
coords.l.push(Math.trunc((coords.l[0] * m + a - (b * m))*1000)/1000);
coords.g.push(Math.trunc((coords.g[0] * m + a - (b * m))*1000)/1000);
return JSON.stringify(coords);
}
var findSlope = function(x1,y1,x2,y2){
//Finds Slope rounded to the nearest 1000th
return Math.trunc(((y1-y2)/(x1-x2))*1000)/1000;
}
var getRandomInt = function(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min)) + min;
}
var wolves = [];
var deers = [];
var deer = function(x,y){
this.x = x;
this.y = y;
this.hp = 100;
this.size = 10;
this.hunger = 0*%;
this.preyTypes = [grass];
this.predatorTypes = [wolves];
deers.push(this);
}
var wolf = function(x,y){
this.x = x;
this.y = y;
this.hp = 100;
this.size = 10;
this.hunger = 0 * %;
wolves.push(this);
this.preyTypes = [deers]
}
wolf.prototype.move = function(){
this.nearbyPredators = [];
this.nearbyPrey = [];
//finds all nearby prey
for(var j = 0;j<this.preyTypes.length;j++){
for(var i = 0;i < this.preyTypes[j].length;i++){
if(findDis(this.preyTypes[j][i].x,this.preyTypes[j][i].y,this.x,this.y) < 40){
this.nearbyPrey.push(this.preyTypes[j][i]);
}else{
console.log(findDis(this.preyTypes[j][i].x,this.preyTypes[j][i].y,this.x,this.y))
}
}
}
//If there are no nearby prey, move randomly
if(this.nearbyPrey.length === 0){
wolf.x += getRandomInt(-8,9)
wolf.y -= getRandomInt(-9,8);
//If there is only one nearby prey, move towards it
}else if(this.nearbyPrey.length === 1){
this.nearestPrey = this.nearbyPrey[0]
var slope = findSlope(this.nearestPrey.x,this.nearestPrey.y,this.x,this.y);
console.log(slope);
var coords = JSON.parse(findIntersections(this.x,this.y,slope,1));
console.log(coords);
var ldis = findDis(this.x,this.y,coords.l[0],coords.l[1]);
var gdis = findDis(this.x,this.y,coords.g[0],coords.g[1]);
console.log(ldis,gdis)
if(ldis > gdis){
this.x = coords.l[0]
this.y = coords.l[1]
console.log(this.x,this.y)
}else {
this.x = coords.g[0]
this.y = coords.g[1]
console.log(this.x,this.y)
}
//If there is more than 1, find the nearest prey and move towards it
}else {
for(var i = 0; i < this.nearbyPrey.length; i++){
this.tempDis = getDis(this.x,this.y,this.nearbyPrey[i].x,this.nearbyPrey[i].y)
if(typeof this.nearestPrey == 'undefined'){
this.nearestPrey = {
prey:this.nearbyPrey[i],
distance:this.tempDis
}
this.tempDis = undefined
}else {
if(this.tempDis > this.nearestPrey.distance){
this.nearestPrey = {
prey:this.nearbyPrey[i],
distance:this.tempDis
}
}
}
}
var slope = findSlope(this.nearestPrey.x,this.nearestPrey.y,this.x,this.y)
var coords = JSON.parse(findIntersections(this.nearestPrey.x,this.nearestPrey.y,slope,1));
var ldis = findDis(this.nearestPrey.x,this.nearestPrey.y,coords.l[0],coords.l[1]);
var gdis = findDis(this.nearestPrey.x,this.nearestPrey.y,coords.g[0],coords.g[1]);
if(ldis > gdis){
this.x = coords.l[0]
this.y = coords.l[1]
}else {
this.x = coords.g[0]
this.y = coords.g[1]
}
}
}
wolf.prototype.bite = function(prey){
prey.hp -= this.strength;
this.hunger += 40 * %
console.log(this.hunger);
console.log(this.nearestPrey.hp)
}
new wolf(100,100)
new deer(80,80);
var init = function(){
ctx.translate(0.5, 0.5);
ctx.lineWidth = .5
window.setInterval(draw,1000);
}
var draw = function(){
ctx.clearRect(0,0,canvas.width,canvas.height)
wolves[0].move();
for(var i=0;i<wolves.length;i++){
ctx.beginPath();
ctx.arc(deers[0].x,deers[0].y,10,0,2*Math.PI);
ctx.stroke();
ctx.beginPath()
ctx.arc(wolves[i].x,wolves[i].y,10,0,2*Math.PI);
ctx.stroke();
}
}
init()
</script>
jsfiddle: https://jsfiddle.net/nragrkb8/3/
I'm trying to get a spectrogram drawn, works in chrome but draws nothing in all other browsers. I'm using getImageData and putImageData to move existing contents down by a pixel every time new data is pushed in. That new data is then drawn into an offscreen image and then putimagedata to apply it to the full canvas.
Spectrogram = (function() {
//constructor function
var Spectrogram = function(options) {
//compose options
this.canvas = options.canvas;
this.width = options.size; //the size of the FFT
this.height = options.length; //the number of FFT to keep
if (typeof options.min !== 'undefined' && typeof options.max !== 'undefined') {
this.rangeType = 'static';
this.min = options.min;
this.max = options.max;
} else {
this.rangeType = 'auto';
this.min = Infinity;
this.max = -Infinity;
}
//set the function used to determine a value's color
this.colorScaleFn = options.colorScaleFn || defaultColorScaling;
//precalculate the range used in color scaling
this.range = this.max - this.min;
//the 2d drawing context
this.ctx = this.canvas.getContext('2d', { alpha: false });
//single pixel image used to draw new data points
this.im = this.ctx.createImageData(this.width, 1);
this.canvas.width = this.width;
this.canvas.height = this.height;
//adds a new row of data to the edge of the spectrogram, shifting existing
//contents by 1px
this.addData = function (newData) {
if (newData.length != this.width) {
console.error('Unmatched dataset size. Expected ' + this.width + ', was + ' + newData.length);
return;
}
if (this.rangeType == 'auto') {
var changed = false;
for (var i = 0; i < newData.length; ++i) {
if (newData[i] < this.min) {
this.min = newData[i];
changed = true;
} else if (newData[i] > this.max) {
this.max = newData[i];
changed = true;
}
}
if (changed) {
this.range = this.max - this.min;
}
}
//move the current contents by 1px
var im = this.ctx.getImageData(0, 0, this.width, this.height - 1);
this.ctx.putImageData(im, 0, 1);
//draw the new data values into the temporary image
var j = 0;
for (var i = 0; i < newData.length; ++i) {
var c = this.colorScaleFn(newData[i]);
this.im.data[j] = c[0];
this.im.data[j + 1] = c[1];
this.im.data[j + 2] = c[2];
j += 4;
}
//put the new data colors into the full canvas
this.ctx.putImageData(this.im, 0, 0);
}
}
function defaultColorScaling(value) {
var x = (value - this.min) / this.range;
if (x < 0) {
x = 0;
} else if (x > 1) {
x = 1;
}
var g = Math.pow(x, 2);
var b = 0.75 - 1.5 * Math.abs(x - 0.45);
var r = 0;
return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
}
return Spectrogram;
})();
const size = 1024;
const length = 200;
const dataMax = 100;
const velMax = 1;
const canvas = document.getElementById('spec');
canvas.width = size;
canvas.height = length;
const spec = new Spectrogram({
canvas: canvas,
size: size,
length: length
});
const data = [];
const vel = [];
for (var i = 0; i < size; ++i) {
data.push(0);
vel.push(0);
}
setInterval(function() {
for (var i = 0; i < size; ++i) {
data[i] += vel[i];
if (i > 0) data[i] += vel[i - 1];
if (i < size - 1) data[i] += vel[i + 1];
if (data[i] >= dataMax) {
data[i] = dataMax;
vel[i] = 0;
} else if (data[i] <= -dataMax) {
data[i] = -dataMax;
vel[i] = 0;
}
if (vel[i] == 0) {
vel[i] = (Math.random() - 0.5) * 100;
}
}
spec.addData(data);
}, 100);
Your problem was induced by a misconception:
getContext('2d', {alpha: false}) should have no incidence on createImageData function, so you still have to set the alpha value of your ImageData to something else than 0.
There are also other things in your code that don't go well, even if unrealted with your current issue:
You should avoid at all costs an high frequency setInterval where you perform a task that can take more than the interval (and in your case it can), but rather use something like a requestAnimationFrame loop.
Don't use getImageData + putImageData to draw your context on itself, simply use ctx.drawImage(ctx.canvas, x, y).
There might be other things to fix in your code, but here is an update with these three major things:
Spectrogram = (function() {
//constructor function
var Spectrogram = function(options) {
//compose options
this.canvas = options.canvas;
this.width = options.size; //the size of the FFT
this.height = options.length; //the number of FFT to keep
if (typeof options.min !== 'undefined' && typeof options.max !== 'undefined') {
this.rangeType = 'static';
this.min = options.min;
this.max = options.max;
} else {
this.rangeType = 'auto';
this.min = Infinity;
this.max = -Infinity;
}
//set the function used to determine a value's color
this.colorScaleFn = options.colorScaleFn || defaultColorScaling;
//precalculate the range used in color scaling
this.range = this.max - this.min;
//the 2d drawing context
this.ctx = this.canvas.getContext('2d', {
alpha: false
});
//single pixel image used to draw new data points
this.im = this.ctx.createImageData(this.width, 1);
this.canvas.width = this.width;
this.canvas.height = this.height;
//adds a new row of data to the edge of the spectrogram, shifting existing
//contents by 1px
this.addData = function(newData) {
if (newData.length != this.width) {
console.error('Unmatched dataset size. Expected ' + this.width + ', was + ' + newData.length);
return;
}
if (this.rangeType == 'auto') {
var changed = false;
for (var i = 0; i < newData.length; ++i) {
if (newData[i] < this.min) {
this.min = newData[i];
changed = true;
} else if (newData[i] > this.max) {
this.max = newData[i];
changed = true;
}
}
if (changed) {
this.range = this.max - this.min;
}
}
//move the current contents by 1px
this.ctx.drawImage(this.ctx.canvas, 0, 1)
//draw the new data values into the temporary image
var j = 0;
for (var i = 0; i < newData.length; ++i) {
var c = this.colorScaleFn(newData[i]);
this.im.data[j] = c[0];
this.im.data[j + 1] = c[1];
this.im.data[j + 2] = c[2];
// don't forget the alpha channel, createImageData is always full of zeroes
this.im.data[j + 3] = 255;
j += 4;
}
this.ctx.putImageData(this.im, 0, 0);
}
}
function defaultColorScaling(value) {
var x = (value - this.min) / this.range;
if (x < 0) {
x = 0;
} else if (x > 1) {
x = 1;
}
var g = Math.pow(x, 2);
var b = 0.75 - 1.5 * Math.abs(x - 0.45);
var r = 0;
return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
}
return Spectrogram;
})();
const size = 1024;
const length = 200;
const dataMax = 100;
const velMax = 1;
const canvas = document.getElementById('spec');
canvas.width = size;
canvas.height = length;
const spec = new Spectrogram({
canvas: canvas,
size: size,
length: length
});
const data = [];
const vel = [];
for (var i = 0; i < size; ++i) {
data.push(0);
vel.push(0);
}
// our animation loop
function draw() {
for (var i = 0; i < size; ++i) {
data[i] += vel[i];
if (i > 0) data[i] += vel[i - 1];
if (i < size - 1) data[i] += vel[i + 1];
if (data[i] >= dataMax) {
data[i] = dataMax;
vel[i] = 0;
} else if (data[i] <= -dataMax) {
data[i] = -dataMax;
vel[i] = 0;
}
if (vel[i] == 0) {
vel[i] = (Math.random() - 0.5) * 100;
}
}
spec.addData(data);
requestAnimationFrame(draw);
}
draw();
<div style="width: 100%; height: 100%; padding: 0; margin: 0;">
<canvas style="width: 100%; height: 100%;" id="spec"></canvas>
</div>
function randomXToY(minVal,maxVal,floatVal)
{
var randVal = minVal+(Math.random()*(maxVal-minVal));
return typeof floatVal=='undefined'?Math.round(randVal):randVal.toFixed(floatVal);
}
Ball = (function() {
// constructor
function Ball(x,y,radius,color){
this.center = {x:x, y:y};
this.radius = radius;
this.color = color;
this.dx = 2;
this.dy = 2;
this.boundaryHeight = $('#ground').height();
this.boundaryWidth = $('#ground').width();
this.dom = $('<p class="circle"></p>').appendTo('#ground');
// the rectange div a circle
this.dom.width(radius*2);
this.dom.height(radius*2);
this.dom.css({'border-radius':radius,background:color});
this.placeAtCenter(x,y);
}
// Place the ball at center x, y
Ball.prototype.placeAtCenter = function(x,y){
this.dom.css({top: Math.round(y- this.radius), left: Math.round(x - this.radius)});
this.center.x = Math.round(x);
this.center.y = Math.round(y);
};
Ball.prototype.setColor = function(color) {
if(color) {
this.dom.css('background',color);
} else {
this.dom.css('background',this.color);
}
};
// move and bounce the ball
Ball.prototype.move = function(){
var diameter = this.radius * 2;
var radius = this.radius;
if (this.center.x - radius < 0 || this.center.x + radius > this.boundaryWidth ) {
this.dx = -this.dx;
}
if (this.center.y - radius < 0 || this.center.y + radius > this.boundaryHeight ) {
this.dy = -this.dy;
}
this.placeAtCenter(this.center.x + this.dx ,this.center.y +this.dy);
};
return Ball;
})();
var number_of_balls = 5;
var balls = [];
$('document').ready(function(){
for (i = 0; i < number_of_balls; i++) {
var boundaryHeight = $('#ground').height();
var boundaryWidth = $('#ground').width();
var y = randomXToY(30,boundaryHeight - 50);
var x = randomXToY(30,boundaryWidth - 50);
var radius = randomXToY(15,30);
balls.push(new Ball(x,y,radius, '#'+Math.floor(Math.random()*16777215).toString(16)));
}
loop();
});
loop = function(){
for (var i = 0; i < balls.length; i++){
balls[i].move();
}
setTimeout(loop, 8);
};
I have never used in oops concepts in javascript. How do I change the ball color when the balls touches each other?
This is the link : http://jsbin.com/imofat/1/edit
You currently don't have any interaction with the balls. What you can do is checking whether two balls are "inside" each other, and change colors in that case: http://jsbin.com/imofat/1491/.
// calculates distance between two balls
var d = function(a, b) {
var dx = b.center.x - a.center.x;
var dy = b.center.y - a.center.y;
return Math.sqrt(dx*dx + dy*dy);
};
and:
// for each ball
for(var i = 0; i < balls.length; i++) {
// check against rest of balls
for(var j = i + 1; j < balls.length; j++) {
var a = balls[i];
var b = balls[j];
// distance is smaller than their radii, so they are inside each other
if(d(a, b) < a.radius + b.radius) {
// set to some other color using your random color code
a.setColor('#'+Math.floor(Math.random()*16777215).toString(16));
b.setColor('#'+Math.floor(Math.random()*16777215).toString(16));
}
}
}
Still, there are things for improvement:
Balls are changing colors as long as they are inside each other, not just once.
If you want them to "touch", you might want to implement some kind of bouncing effect to make it more realistic.