Touch area on the HTML5 canvas using native javascript code - javascript

I have a one canvas with fixed width and height, in that canvas I have drawn background image using drawImage() method. In the background image there are some objects like ants(static) when the user touches the ants then that particular area should clear(or ant image should disappear) or should through one alert box like you have found ant. I have searched for finding the particular touch area but I got only finding x and y co-ordinates by using touchstart event. I don't want to compare with x and y co-ordinates with ant position in image. I know the ants positions on image.
this code I got while searching
$('#id').on('touchstart', function(){
alert("Touched");
});
But I am not drawing images through html img tag.
Any help would appreciated lot.
In the touchstart event there are some radiousX and radiousY properties to find area but I did't get aany examples on those properties.
Here is one problem: Anybody through a solution for this problem???
For example there is one city image, in that I need to touch some buildings after touching a particular building, can we get alert box like you find your home???

Comparing the x and y coordinates of the touch with the coordinates of the ant is the right way to go. Yes, it's very hard to touch an exact spot, but you don't have to. You can check whether the touch coordinates are in a specific range, let's say at most 10 pixels away from the ant coordinate.
// touchX and touchY are the touch coordinates
// antX and antY are the ant's coordinates
// Is touchX between (antX - 10) and (antX + 10)?
if (touchX >= antX - 10 && touchX <= antX + 10) {
// Is touchY between (antY - 10) and (antY + 10)?
if (touchY >= antY - 10 && touchY <= antY + 10) {
// The user touched the ant
}
}

Here is my small project multi touch canvas2d js.
You can track all 10 fingers on mobile screen.
I made also detect rect area.
Source code
function MOBILE_CONTROL () {
this.X = null;
this.Y = null;
this.LAST_X_POSITION = null;
this.LAST_Y_POSITION = null;
this.MULTI_TOUCH = 'NO';
this.MULTI_TOUCH_X1 = null;
this.MULTI_TOUCH_X2 = null;
this.MULTI_TOUCH_X3 = null;
this.MULTI_TOUCH_X4 = null;
this.MULTI_TOUCH_X5 = null;
this.MULTI_TOUCH_Y1 = null;
this.MULTI_TOUCH_Y2 = null;
this.MULTI_TOUCH_Y3 = null;
this.MULTI_TOUCH_Y4 = null;
this.MULTI_TOUCH_Y5 = null;
this.MULTI_TOUCH_X6 = null;
this.MULTI_TOUCH_X7 = null;
this.MULTI_TOUCH_X8 = null;
this.MULTI_TOUCH_X9 = null;
this.MULTI_TOUCH_X10 = null;
this.MULTI_TOUCH_Y6 = null;
this.MULTI_TOUCH_Y7 = null;
this.MULTI_TOUCH_Y8 = null;
this.MULTI_TOUCH_Y9 = null;
this.MULTI_TOUCH_Y10 = null;
this.MULTI_TOUCH_INDEX = 1;
this.SCREEN = [window.innerWidth , window.innerHeight];
this.SCREEN.W = this.SCREEN[0];
this.SCREEN.H = this.SCREEN[1];
//Application general
this.AUTOR = "Nikola Lukic";
this.APPLICATION_NAME = "TestApplication";
this.SET_APPLICATION_NAME = function (value) {
if (typeof value != 'string')
throw 'APPLICATION_NAME must be a string!';
if (value.length < 2 || value.length > 20)
throw 'APPLICATION_NAME must be 2-20 characters long!';
this.APPLICATION_NAME = value;
};
this.APP = function(){/*construct*/};
this.APP.BODY = document.getElementsByTagName('body')[0];
this.APP.BODY.SET_STYLE = function (string) {this.style = string;}
this.APP.BODY.SET_BACKGROUND_COLOR = function (color) {this.style.backgroundColor = color;}
this.APP.BODY.SET_COLOR = function (color) {this.style.Color = color;}
this.APP.BODY.ADD_DIV = function (id , style , innerHTML) {
var n = document.createElement('div');
var divIdName = id;
n.setAttribute('id',divIdName);
n.setAttribute('style',style);
n.innerHTML = innerHTML;
this.appendChild(n);
};
this.APP.BODY.ADD_2DCANVAS = function (id,width_,height_) {
var n = document.createElement('canvas');
var divIdName = id;
n.setAttribute('id',divIdName);
n.setAttribute('width',width_);
n.setAttribute('height',height_);
//n.innerHTML = 'Element is here';
this.appendChild(n);
};
console.log('<MOBILE_CONTROL JavaScript class>');
console.log('status:MOBILE_CONTROL FINISH LOADING');
console.log('EASY_IMPLEMENTATION!');
}
function CANVAS_DRAW(){
var run = true;
var timer = null;
window.addEventListener('touchstart', MDPORT, false);
function MDPORT(){
if (run) {
clearInterval(timer);
run = false;
}
else {
timer = setInterval(makeHarmonograph, 1);
run = true;
}
}
var A1 = 200, f1 = 2, p1 = 1/16, d1 = 0.02;
var A2 = 10, f2 = 4, p2 = 3 / 2, d2 = 0.0315;
var A3 = 200, f3 = 4, p3 = 13 / 15, d3 = 0.00012;
var A4 = 10, f4 = 4, p4 = 1, d4 = 0.012;
var r = 10, g =10, b = 0;
var UPDOWN = 1,CONTROL_WIDTH = 0;
var ctx = document.getElementById("canvas").getContext("2d");
setInterval(randomColor, 5000);
timer = setInterval(makeHarmonograph, 1);
function randomColor() {
r = Math.floor(Math.random() * 256);
g = Math.floor(Math.random() * 256);
b = Math.floor(Math.random() * 256);
}
function makeHarmonograph() {
f1 = (f1 / 10) % 10;
f2 = (f2 / 40) % 10;
f3 = (f3 + Math.random() / 80) % 10;
f4 = (f4 + Math.random() / 411) % 10;
p1 += 0.5 % (Math.PI*2)
drawHarmonograph();
}
function drawHarmonograph() {
ctx.clearRect(0, 0, 850, 450);
ctx.save();
ctx.fillStyle = "#000000";
ctx.strokeStyle = "rgb(" + r + "," + g + "," + b + ")";
ctx.fillRect(0, 0, 1100, 400);
ctx.translate(511, 0);
ctx.rotate(1.57);
///////////
// Draw guides
ctx.strokeStyle = '#09f';
ctx.lineWidth = A1 ;
ctx.translate(111, 1);
ctx.rotate(0.01);
if (CONTROL_WIDTH == 0) { UPDOWN=UPDOWN+1;}
if (UPDOWN>51){CONTROL_WIDTH=1; }
if (CONTROL_WIDTH == 0) { UPDOWN=UPDOWN-0.1;}
if (UPDOWN<1){CONTROL_WIDTH=0; }
// Set line styles
ctx.strokeStyle = '#099909';
ctx.lineWidth = UPDOWN;
// check input
ctx.miterLimit = UPDOWN;
// Draw lines
ctx.beginPath();
ctx.moveTo(111,100);
for (i=0;i<121;i++){
var dy = i%2==0 ? 25 : -25 ;
ctx.lineTo(Math.pow(i,1.5)*2,75+dy);
}
ctx.stroke();
return false;
ctx.translate(444, 333);
ctx.fillStyle='lime';
ctx.font="30px Arial";
ctx.fillText("Overlapping harmonics with JavaScript, wait secund.",5,25);
ctx.stroke();
}
}
function CANVAS_DRAW_1(){
var run = true;
var timer = null;
timer = setInterval(makeHarmonograph, 1);
run = true;
var A1 = 200, f1 = 2, p1 = 1/16, d1 = 0.02;
var A2 = 10, f2 = 4, p2 = 3 / 2, d2 = 0.0315;
var A3 = 200, f3 = 4, p3 = 13 / 15, d3 = 0.00012;
var A4 = 10, f4 = 4, p4 = 1, d4 = 0.012;
var r = 10, g =10, b = 0;
var UPDOWN = 1,CONTROL_WIDTH = 0;
var ctx = document.getElementById("canvas_1").getContext("2d");
setInterval(randomColor, 5000);
timer = setInterval(makeHarmonograph, 1);
function randomColor() {
r = Math.floor(Math.random() * 256);
g = Math.floor(Math.random() * 256);
b = Math.floor(Math.random() * 256);
}
function makeHarmonograph() {
f1 = (f1 / 10) % 10;
f2 = (f2 / 40) % 10;
f3 = (f3 + Math.random() / 80) % 10;
f4 = (f4 + Math.random() / 411) % 10;
p1 += 0.5 % (Math.PI*2)
drawHarmonograph();
}
function drawHarmonograph() {
ctx.clearRect(0, 0, 850, 450);
ctx.save();
ctx.fillStyle = "#000000";
ctx.strokeStyle = "rgb(" + r + "," + g + "," + b + ")";
ctx.fillRect(0, 0, 800, 400);
ctx.translate(0, 250);
ctx.beginPath();
if (A1 > 100) {}
for (var t = 0; t < 100; t+=0.1) {
var x = A1 * Math.sin(f1 * t + Math.PI * p1) * Math.exp(-d1 * t) + A2 * Math.sin(f2 * t + Math.PI * p2) * Math.exp(-d2 * t);
var y = A3 * Math.sin(f3 * t + Math.PI * p1) * Math.exp(-d3 * t) + A4 * Math.sin(f4 * t + Math.PI * p4) * Math.exp(-d4 * t);
//ctx.lineTo(x*x, y/x);
ctx.lineTo(x*x+1, y+1/x);
}
ctx.stroke();
ctx.translate(A1, 0);
ctx.rotate(1.57);
ctx.beginPath();
for (var t = 0; t < 100; t+=0.1) {
var x = A1 * A3* Math.sin(f1 * t + Math.PI * p1) * Math.exp(-d1 * t) + A2 * Math.sin(f2 * t + Math.PI * p2) * Math.exp(-d2 * t);
var y = A3 * Math.sin(f3 * t + Math.PI * p1) * Math.exp(-d3 * t) + A4 * Math.sin(f4 * t + Math.PI * p4) * Math.exp(-d4 * t);
ctx.lineTo(x*x+1, y+1/x);
}
ctx.stroke();
ctx.restore();
///////////
// Draw guides
ctx.strokeStyle = '#09f';
ctx.lineWidth = A1 ;
if (CONTROL_WIDTH == 0) { UPDOWN=UPDOWN+1;}
if (UPDOWN>51){CONTROL_WIDTH=1; }
if (CONTROL_WIDTH == 0) { UPDOWN=UPDOWN-0.1;}
if (UPDOWN<1){CONTROL_WIDTH=0; }
// Set line styles
ctx.strokeStyle = '#099909';
ctx.lineWidth = UPDOWN;
// check input
ctx.miterLimit = 5;
// Draw lines
ctx.beginPath();
ctx.moveTo(0,100);
for (i=0;i<124;i++){
var dy = i%2==0 ? 25 : -25 ;
ctx.lineTo(Math.pow(i,1.5)*2,75+dy);
}
ctx.stroke();
return false;
ctx.translate(A1, 210);
ctx.fillStyle='lime';
ctx.font="30px Arial";
ctx.fillText("Overlapping harmonics with JavaScript, wait secund.",5,25);
}
}
function CANVAS_DRAW_2(){
var timer = null;
var A1 = 200, f1 = 2, p1 = 1/16, d1 = 0.02;
var A2 = 10, f2 = 4, p2 = 3 / 2, d2 = 0.0315;
var A3 = 200, f3 = 4, p3 = 13 / 15, d3 = 0.00012;
var A4 = 10, f4 = 4, p4 = 1, d4 = 0.012;
var r = 10, g =10, b = 0;
var ctx = document.getElementById("canvas_2").getContext("2d");
setInterval(randomColor, 5000);
timer = setInterval(t, 1);
function randomColor() {
r = Math.floor(Math.random() * 256);
g = Math.floor(Math.random() * 256);
b = Math.floor(Math.random() * 256);
}
function t() {
r1();
}
function r1() {
ctx.clearRect(0, 0, CONTROL.SCREEN.W, CONTROL.SCREEN.H);
ctx.save();
ctx.strokeStyle = "rgb(" + r + "," + g + "," + b + ")";
ctx.fillStyle = "#000000";
ctx.fillRect(0, 0, CONTROL.SCREEN.W, CONTROL.SCREEN.H);
ctx.beginPath();
var x = CONTROL.X;
var y = CONTROL.Y;
ctx.fillStyle = "rgb(" + r + "," + g + "," + b + ")";
ctx.fillRect(x, y-400, 1, 2500);
ctx.fillRect(x-400, y, 2500, 1);
ctx.fillText(" ( targetX:" + CONTROL.X + " ( targetY: "+ CONTROL.Y + " ) ",x,y);
ctx.fillStyle = "#00FF00";
ctx.font="10px Arial";
ctx.fillText(" JavaScript ",x- CONTROL.SCREEN.W/3,y - CONTROL.SCREEN.H/3.4);
ctx.fillText(" welcome here , canvas example with MOBILE_TOUCH() ",x - CONTROL.SCREEN.W/3,y - CONTROL.SCREEN.H/3.2);
ctx.fillText(" no css files need, pure js ",x - CONTROL.SCREEN.W/3,y - CONTROL.SCREEN.H/3);
if (CONTROL.X > CONTROL.SCREEN.W/2.2 && CONTROL.X < CONTROL.SCREEN.W/2.2 + 300 && CONTROL.Y > CONTROL.SCREEN.H/2.2 && CONTROL.Y < CONTROL.SCREEN.H/2.2 + 100) {
ctx.strokeStyle = "lime";
}
else{
ctx.strokeStyle = "red";
}
ctx.strokeRect( CONTROL.SCREEN.W/2.2, CONTROL.SCREEN.H/2.2, 300, 100);
ctx.fillText(" HUB DETECT ", CONTROL.SCREEN.W/2, CONTROL.SCREEN.H/2);
if (CONTROL.MULTI_TOUCH_X1 !== 'undefined'){
ctx.fillRect(CONTROL.MULTI_TOUCH_X1 , CONTROL.MULTI_TOUCH_Y1-400 , 1, 2500);
ctx.fillRect(CONTROL.MULTI_TOUCH_X1 -400 , CONTROL.MULTI_TOUCH_Y1 , 2500, 1);
}
if (CONTROL.MULTI_TOUCH_X2 !== 'undefined'){
ctx.fillRect(CONTROL.MULTI_TOUCH_X2 , CONTROL.MULTI_TOUCH_Y2-400 , 1, 2500);
ctx.fillRect(CONTROL.MULTI_TOUCH_X2 -400 , CONTROL.MULTI_TOUCH_Y2 , 2500, 1);
}
if (CONTROL.MULTI_TOUCH_X3 !== 'undefined'){
ctx.fillRect(CONTROL.MULTI_TOUCH_X3 , CONTROL.MULTI_TOUCH_Y3-400 , 1, 2500);
ctx.fillRect(CONTROL.MULTI_TOUCH_X3 -400 , CONTROL.MULTI_TOUCH_Y3 , 2500, 1);
}
if (CONTROL.MULTI_TOUCH_X4 !== 'undefined'){
ctx.fillRect(CONTROL.MULTI_TOUCH_X4 , CONTROL.MULTI_TOUCH_Y4-400 , 1, 2500);
ctx.fillRect(CONTROL.MULTI_TOUCH_X4 -400 , CONTROL.MULTI_TOUCH_Y4 , 2500, 1);
}
if (CONTROL.MULTI_TOUCH_X5 !== 'undefined'){
ctx.fillRect(CONTROL.MULTI_TOUCH_X5 , CONTROL.MULTI_TOUCH_Y5-400 , 1, 2500);
ctx.fillRect(CONTROL.MULTI_TOUCH_X5 -400 , CONTROL.MULTI_TOUCH_51 , 2500, 1);
}
if (CONTROL.MULTI_TOUCH_X6 !== 'undefined'){
ctx.fillRect(CONTROL.MULTI_TOUCH_X6 , CONTROL.MULTI_TOUCH_Y6-400 , 1, 2500);
ctx.fillRect(CONTROL.MULTI_TOUCH_X6 -400 , CONTROL.MULTI_TOUCH_Y6 , 2500, 1);
}
if (CONTROL.MULTI_TOUCH_X7 !== 'undefined'){
ctx.fillRect(CONTROL.MULTI_TOUCH_X7 , CONTROL.MULTI_TOUCH_Y8-400 , 1, 2500);
ctx.fillRect(CONTROL.MULTI_TOUCH_X7 -400 , CONTROL.MULTI_TOUCH_Y8 , 2500, 1);
}
if (CONTROL.MULTI_TOUCH_X9 !== 'undefined'){
ctx.fillRect(CONTROL.MULTI_TOUCH_X9 , CONTROL.MULTI_TOUCH_Y9-400 , 1, 2500);
ctx.fillRect(CONTROL.MULTI_TOUCH_X9 -400 , CONTROL.MULTI_TOUCH_Y9 , 2500, 1);
}
if (CONTROL.MULTI_TOUCH_X10 !== 'undefined'){
ctx.fillRect(CONTROL.MULTI_TOUCH_X10 , CONTROL.MULTI_TOUCH_Y10-400 , 1, 2500);
ctx.fillRect(CONTROL.MULTI_TOUCH_X10 -400 , CONTROL.MULTI_TOUCH_Y10 , 2500, 1);
}
// Draw lines
ctx.fillStyle='lime';
ctx.font="30px Arial";
ctx.fillText("MOBILE_TOUCH example ",5,25);
}
}
//definition
var CONTROL = new MOBILE_CONTROL();
//CONTROL.APP.BODY.ADD_2DCANVAS("canvas");
//CONTROL.APP.BODY.ADD_2DCANVAS("canvas_1");
CONTROL.APP.BODY.ADD_2DCANVAS("canvas_2",CONTROL.SCREEN.W,CONTROL.SCREEN.H);
CONTROL.APP.BODY.SET_STYLE('margin-left:-10px;padding:0;border:none;');
//CANVAS_DRAW();
//CANVAS_DRAW_1();
CANVAS_DRAW_2();
//<!-- SCREEN.prototype.sayHello = function(){alert ('hello' + "sss" );}; -->
//###################################################################
//EVENTS
//###################################################################
document.addEventListener('touchstart', function(event)
{
if (CONTROL.MULTI_TOUCH == 'NO') {
var touch = event.touches[0];
CONTROL.X = touch.pageX;
CONTROL.Y = touch.pageY;
console.log('TOUCH START AT:(X' + CONTROL.X + '),(' + CONTROL.Y + ')' );
}
else if (CONTROL.MULTI_TOUCH == 'YES') {
var touches_changed = event.changedTouches;
for (var i=0; i<touches_changed.length;i++) {
//CONTROL.MULTI_TOUCH_X1
console.log("multi touch : x" + CONTROL.MULTI_TOUCH_INDEX + ":(" +touches_changed[i].pageX + ")");
switch(CONTROL.MULTI_TOUCH_INDEX)
{
case 1:
CONTROL.MULTI_TOUCH_X1=touches_changed[i].pageX;
CONTROL.MULTI_TOUCH_Y1=touches_changed[i].pageY;
break;
case 2:
CONTROL.MULTI_TOUCH_X2=touches_changed[i].pageX;
CONTROL.MULTI_TOUCH_Y2=touches_changed[i].pageY;
break;
case 3:
CONTROL.MULTI_TOUCH_X3=touches_changed[i].pageX;
CONTROL.MULTI_TOUCH_Y3=touches_changed[i].pageY;
break;
case 4:
CONTROL.MULTI_TOUCH_X4=touches_changed[i].pageX;
CONTROL.MULTI_TOUCH_Y4=touches_changed[i].pageY;
break;
case 5:
CONTROL.MULTI_TOUCH_X5=touches_changed[i].pageX;
CONTROL.MULTI_TOUCH_Y5=touches_changed[i].pageY;
break;
case 6:
CONTROL.MULTI_TOUCH_X6=touches_changed[i].pageX;
CONTROL.MULTI_TOUCH_Y6=touches_changed[i].pageY;
break;
case 7:
CONTROL.MULTI_TOUCH_X7=touches_changed[i].pageX;
CONTROL.MULTI_TOUCH_Y7=touches_changed[i].pageY;
break;
case 8:
CONTROL.MULTI_TOUCH_X8=touches_changed[i].pageX;
CONTROL.MULTI_TOUCH_Y8=touches_changed[i].pageY;
break;
case 9:
CONTROL.MULTI_TOUCH_X9=touches_changed[i].pageX;
CONTROL.MULTI_TOUCH_Y9=touches_changed[i].pageY;
break;
case 10:
CONTROL.MULTI_TOUCH_X10=touches_changed[i].pageX;
CONTROL.MULTI_TOUCH_Y10=touches_changed[i].pageY;
break;
default:
//code to be executed if n is different from case 1 and 2
}
CONTROL.MULTI_TOUCH_INDEX = CONTROL.MULTI_TOUCH_INDEX + 1;
}
}
CONTROL.MULTI_TOUCH = 'YES';
},false);
////////////////////////////////////////////////////////
document.addEventListener('touchmove', function(event)
{
var touch = event.touches[0];
CONTROL.X = touch.pageX;
CONTROL.Y = touch.pageY;
console.log('TOUCH MOVE AT:(X' + CONTROL.X + '),(' + CONTROL.Y + ')' );
//#############
if (CONTROL.MULTI_TOUCH == 'YES') {
var touches_changed = event.changedTouches;
for (var i=0; i<touches_changed.length;i++) {
//CONTROL.MULTI_TOUCH_X1
console.log("multi touch : x" + CONTROL.MULTI_TOUCH_INDEX + ":(" +touches_changed[i].pageX + ")");
switch(i)
{
case 1:
CONTROL.MULTI_TOUCH_X1=touches_changed[i].pageX;
CONTROL.MULTI_TOUCH_Y1=touches_changed[i].pageY;
break;
case 2:
CONTROL.MULTI_TOUCH_X2=touches_changed[i].pageX;
CONTROL.MULTI_TOUCH_Y2=touches_changed[i].pageY;
break;
case 3:
CONTROL.MULTI_TOUCH_X3=touches_changed[i].pageX;
CONTROL.MULTI_TOUCH_Y3=touches_changed[i].pageY;
break;
case 4:
CONTROL.MULTI_TOUCH_X4=touches_changed[i].pageX;
CONTROL.MULTI_TOUCH_Y4=touches_changed[i].pageY;
break;
case 5:
CONTROL.MULTI_TOUCH_X5=touches_changed[i].pageX;
CONTROL.MULTI_TOUCH_Y5=touches_changed[i].pageY;
break;
case 6:
CONTROL.MULTI_TOUCH_X6=touches_changed[i].pageX;
CONTROL.MULTI_TOUCH_Y6=touches_changed[i].pageY;
break;
case 7:
CONTROL.MULTI_TOUCH_X7=touches_changed[i].pageX;
CONTROL.MULTI_TOUCH_Y7=touches_changed[i].pageY;
break;
case 8:
CONTROL.MULTI_TOUCH_X8=touches_changed[i].pageX;
CONTROL.MULTI_TOUCH_Y8=touches_changed[i].pageY;
break;
case 9:
CONTROL.MULTI_TOUCH_X9=touches_changed[i].pageX;
CONTROL.MULTI_TOUCH_Y9=touches_changed[i].pageY;
break;
case 10:
CONTROL.MULTI_TOUCH_X10=touches_changed[i].pageX;
CONTROL.MULTI_TOUCH_Y10=touches_changed[i].pageY;
break;
default:
//code to be executed if n is different from case 1 and 2
}
}}
//#############
event.preventDefault();
},false);
////////////////////////////////////////////////////////
document.addEventListener('touchend', function(event)
{
CONTROL.LAST_X_POSITION = CONTROL.X;
CONTROL.LAST_Y_POSITION = CONTROL.Y;
CONTROL.MULTI_TOUCH = 'NO';
CONTROL.MULTI_TOUCH_INDEX = 1;
CONTROL.MULTI_TOUCH_X1 = null;
CONTROL.MULTI_TOUCH_X2 = null;
CONTROL.MULTI_TOUCH_X3 = null;
CONTROL.MULTI_TOUCH_X4 = null;
CONTROL.MULTI_TOUCH_X5 = null;
CONTROL.MULTI_TOUCH_X6 = null;
CONTROL.MULTI_TOUCH_X7 = null;
CONTROL.MULTI_TOUCH_X8 = null;
CONTROL.MULTI_TOUCH_X9 = null;
CONTROL.MULTI_TOUCH_X10 = null;
CONTROL.MULTI_TOUCH_Y1 = null;
CONTROL.MULTI_TOUCH_Y2 = null;
CONTROL.MULTI_TOUCH_Y3 = null;
CONTROL.MULTI_TOUCH_Y4 = null;
CONTROL.MULTI_TOUCH_Y5 = null;
CONTROL.MULTI_TOUCH_Y6 = null;
CONTROL.MULTI_TOUCH_Y7 = null;
CONTROL.MULTI_TOUCH_Y8 = null;
CONTROL.MULTI_TOUCH_Y9 = null;
CONTROL.MULTI_TOUCH_Y10 = null;
console.log('LAST TOUCH POSITION AT:(X' + CONTROL.X + '),(' + CONTROL.Y + ')' );
},false);
////////////////////////////////////////////////////////
document.addEventListener("touchcancel", function(event)
{
console.log('BREAK - LAST TOUCH POSITION AT:(X' + CONTROL.X + '(,(' + CONTROL.Y + ')' );
}, false);
////////////////////////////////////////////////////////

Related

waterfall: HTML Canvas Waterfall and Spectrum Plot

I was trying to Build a spectrum and waterfall Plot HTML canvas. After a long research and googling i found this SOURCE CODE
Now i am trying to learn how this code works. i added 3 points on the spectrum using drawPoint2 function.
Can some one please Guild me. thank you.
"use strict";
var colors = [
"rgba(60, 229, 42, 0.31)",
"rgba(60, 229, 42, 0.31)",
"rgba(60, 229, 42, 0.31)",
"rgba(60, 229, 42, 0.31)",
"rgba(60, 229, 42, 0.31)",
"rgba(252, 182, 3, 0.31)",
"rgba(3, 103, 252, 0.31)",
"rgba(219, 3, 252, 0.31)",
"rgba(252, 3, 49, 0.31)",
"rgba(221, 48, 232, 0.31)",
];
var closeEnough = 5;
var crop = 150;
var data_sb = -10;
var canvas = document.getElementById("spectrumSM");
Spectrum.prototype.countDecimals = function (value) {
if (Math.floor(value) !== value)
return value.toString().split(".")[1].length || 0;
return 0;
};
Spectrum.prototype.map = function (x, in_min, in_max, out_min, out_max) {
return Math.round(
((x - in_min) * (out_max - out_min)) / (in_max - in_min) + out_min
);
};
Spectrum.prototype.updateSpectrumRatio = function () {
this.spectrumHeight = Math.round(
(this.canvas.height * this.spectrumPercent) / 100.0
);
// create a slop
this.gradient = this.ctx.createLinearGradient(0, 0, 0, this.spectrumHeight);
for (var i = 0; i < this.colormap.length; i++) {
var c = this.colormap[this.colormap.length - 1 - i];
this.gradient.addColorStop(
i / this.colormap.length,
"rgba(220,220,220,0.2)"
); //hardcode the patch above Xaxis
}
};
Spectrum.prototype.resize = function () {
var width = this.canvas.clientWidth;
var height = this.canvas.clientHeight;
if (this.canvas.width != width || this.canvas.height != height) {
this.canvas.width = width;
this.canvas.height = height;
this.updateSpectrumRatio();
for (var z = 0; z < this.tags.length; z++) {
this.tags[z].StayX = this.map(
this.tags[z].xval,
this.cutfromArray,
this.orignalArrayLength - this.cutfromArray,
0 + crop,
width
); ///////
}
}
if (this.axes.width != width || this.axes.height != this.spectrumHeight) {
this.axes.width = width;
this.axes.height = this.spectrumHeight;
this.updateAxes();
}
};
Spectrum.prototype.updateAxes = function () {
var width = this.ctx_axes.canvas.width + 100; //width of x axis izz
var height = this.ctx_axes.canvas.height;
this.maxScaleX = this.centerHz + this.spanHz / 2;
this.minScaleX = this.centerHz - this.spanHz / 2;
// Clear and fill with black
this.ctx_axes.fillStyle = "black";
this.ctx_axes.fillRect(0, 0, width, height);
// Draw axes
this.ctx_axes.font = "12px Arial";
this.ctx_axes.fillStyle = "white";
this.ctx_axes.textBaseline = "middle";
this.ctx_axes.textAlign = "center"; //change izz
var step = 10; //steps for y-axis
for (var i = this.max_db - 10; i >= this.min_db + 10; i -= step) {
var y = height - this.squeeze(i, 0, height);
this.ctx_axes.fillText(i, 20, y); // height - y
this.ctx_axes.beginPath();
this.ctx_axes.moveTo(22, y); //y axis stroked set izz
this.ctx_axes.lineTo(width, y);
this.ctx_axes.strokeStyle = "rgba(255, 255, 255, 0.15)"; //changed strokes izz
this.ctx_axes.stroke();
}
this.ctx_axes.textBaseline = "bottom";
// change X-axis
var x_axisSteps = 10;
for (var i = 0; i < x_axisSteps; i++) {
var x = Math.round((width - crop) / x_axisSteps - 1) * i + crop;
if (this.spanHz > 0) {
var adjust = 0;
if (i == 0) {
this.ctx_axes.textAlign = "left";
adjust = 3;
} else if (i == 10) {
this.ctx_axes.textAlign = "right";
adjust = -3;
} else {
this.ctx_axes.textAlign = "center";
}
//Graph points in whole points
var freq = this.centerHz + (this.spanHz / 10) * (i - 5);
if (freq > 1e9) {
freq = freq / 1e9;
if (this.countDecimals(freq) > 4) {
freq = freq.toFixed(0);
}
freq = freq + " GHz";
} else if (freq > 1e6) {
freq = freq / 1e6;
if (this.countDecimals(freq) > 4) {
freq = freq.toFixed(0);
}
freq = freq + " MHz"; //this function executed
} else {
if (this.countDecimals(freq) > 2) {
freq = freq.toFixed(0);
}
freq = freq + " MHz";
}
this.ctx_axes.fillText(freq, x - 130, height); // x axia height change izz plus values placment
}
//console.log("ctx_axes : ", this.ctx_axes);
this.ctx_axes.beginPath();
this.ctx_axes.moveTo(x, 0);
this.ctx_axes.lineTo(x, height);
this.ctx_axes.strokeStyle = "rgba(200, 200, 200, 0.2)"; //straight gridline on x axis izza
this.ctx_axes.stroke();
}
// const input = prompt("What's your name?");
};
Spectrum.prototype.toggleColor = function () {
this.colorindex++;
if (this.colorindex >= colormaps.length) this.colorindex = 0;
this.colormap = colormaps[this.colorindex];
this.updateSpectrumRatio();
};
Spectrum.prototype.setCenterHz = function (hz) {
this.centerHz = hz;
if (this.center != 0 && this.center != this.centerHz) {
this.centerHz = this.center;
}
this.updateAxes();
};
Spectrum.prototype.setSpanHz = function (hz) {
this.orignalSpanHz = hz;
this.spanHz = hz;
if (this.zoom != 0 && this.spanHz != this.zoom) {
this.spanHz = this.zoom;
}
this.updateAxes();
};
Spectrum.prototype.squeeze = function (value, out_min, out_max) {
if (value <= this.min_db) {
return out_min;
} else if (value >= this.max_db) {
return out_max;
} else {
return Math.round(
((value - this.min_db) / (this.max_db - this.min_db)) * out_max
);
}
};
Spectrum.prototype.squeeze2 = function (value, out_min, out_max) {
if (value <= 30000000) {
return out_min;
} else if (value >= 300000000) {
return out_max;
} else {
return Math.round(
((value - 30000000) / (300000000 - 30000000)) * out_max
);
}
};
Spectrum.prototype.drawRectSpectrogram = function (y, h) {
this.ctx.beginPath();
this.ctx.fillStyle = colors[this.rectColor]; //"rgba(60, 229, 42, 0.31)"; //rect color
this.ctx.strokeStyle = "green";
this.ctx.rect(this.clickRectX, y, this.clickRectWidth, h);
this.ctx.stroke();
this.ctx.fill();
this.ctx.closePath();
};
Spectrum.prototype.threshold = function (y, width, color) {
this.ctx.beginPath();
this.ctx.strokeStyle = color;
this.ctx.lineWidth = 2; //threshold line width
this.ctx.beginPath();
this.ctx.moveTo(0, y);
this.ctx.lineTo(width + crop, y);
this.ctx.stroke();
this.ctx.closePath();
this.ctx.lineWidth = 1;
};
function drawPoint2(can, x, y, label) {
can.beginPath();
can.arc(x, y, 5, 0, 2 * Math.PI);
can.fillStyle = "red";
can.fill();
can.fillText(label, x + 10, y);
can.stroke(); // it creates X axies and
}
Spectrum.prototype.drawSpectrum = function (bins) {
//get canvas height and width to draw spectrum ayaz
var width = this.ctx.canvas.width;
var height = this.ctx.canvas.height;
//console.log("spectrum width and height : "+width+" "+ height);
// width of Green Color ayaz
this.ctx.lineWidth = 1; //Amplitude green line width .
//All of the points are 119 nut few points are 118 and few 120 ayaz
if (!this.binsAverage || this.binsAverage.length != bins.length) {
//console.log('this.binsAverage ', this.binsAverage );
this.binsAverage = bins;
} else {
for (var i = 0; i < bins.length; i++) {
this.binsAverage[i] +=
(1 - this.averaging) * (bins[i] - this.binsAverage[i]);
}
}
bins = this.binsAverage;
//Do not draw anything if spectrum is not visible
if (this.ctx_axes.canvas.height < 1) return;
//////////////////////////////////////////////////////////////Creation of X and Y axis completed
// Copy axes from offscreen canvas
this.ctx.drawImage(this.ctx_axes.canvas, -1, -1); // create Spectrums X and Y axis
// // Scale for FFT
this.ctx.save(); // saves sppectrum previous stage
//////////////////////////////////////////////////////////////Creation of X and Y axis completed
this.ctx.scale(width / this.wf_size, 1); //green line visiblity izza
var peakY = this.spectrumHeight;
// Draw FFT bins
this.ctx.beginPath();
this.offset = Math.round(
this.map(crop, 0, this.ctx.canvas.width + 6000, 0, this.wf_size)
); // green line axis set izza
//console.log('this.offset : ', this.offset);
console.log(
"X and Y are : ",
-1 + this.offset + " " + this.spectrumHeight + 0
);
this.ctx.moveTo(-1 + this.offset, this.spectrumHeight + 0); //change for waterfall izza
// above line is the address of left bottom corner of spectrum
// console.log(
// "clkkkkkkkkkkkkkkk : ",
// this.clickRectX+
// crop+
// width+
// this.minScaleX+
// this.maxScaleX
// );
var rangeMin = this.map(
this.clickRectX,
crop,
width,
this.minScaleX,
this.maxScaleX
);
var rangeMax = this.map(
this.clickRectWidth + this.clickRectX,
crop,
width,
this.minScaleX,
this.maxScaleX
);
if (rangeMin > rangeMax) {
var temp;
temp = rangeMax;
rangeMax = rangeMin;
rangeMin = temp;
}
var max = 100000000;
this.scaleY = this.map(this.threshY, this.min_db, this.max_db, height / 2, 0); // 0, height/2 // height of threshold izza
this.detectedFrequency.length = 0;
// console.log('bins are ', bins);
//console.log('new array ');
for (var i = 0; i < bins.length; i++) {
// if ( parseFloat( bins[i]) > -100 ) {
// console.log("bins : ", bins[i]);
// const input = prompt("What's your name?");
// alert(`Your name is ${input}`);
// }
var y =
this.spectrumHeight - 1 - this.squeeze(bins[i], 0, this.spectrumHeight);
peakY = this.squeeze(bins[i], 0, this.spectrumHeight);
if (y > this.spectrumHeight - 1) {
y = this.spectrumHeight - 1;
console.log("Y has chnaged : ", y);
}
if (y < 0) {
y = 0;
console.log("y=0");
}
if (i == 0) {
this.ctx.lineTo(-1 + this.offset, y);//responsible for height of green line
}
// green lines are created here ayaz
// create green lines
// important
//drawPoint2(this.ctx ,i + this.offset, y);
this.ctx.lineTo(i + this.offset, y); // that what point we start drawing green horizental green line
// console.log(
// "Starting Line 1 i " +
// i +
// " X : " +
// parseInt(i + this.offset) +
// " y : " +
// y
// );
if (i == bins.length - 1) {
//drawPoint2(this.ctx ,i + this.offset, y);
this.ctx.lineTo(this.wf_size + 1 + this.offset, y);
// console.log(
// "Second 2 i == bins.length - 1 i " +
// i +
// " Drawingg -1 + this.offset : " +
// parseInt(i + this.offset) +
// " y : " +
// y
// );
}
for (var z = 0; z < this.tags.length; z++) {
if (
i + this.cutfromArray == this.tags[z].xval &&
this.check_click == true
) {
this.tags[z].tagY = y;
this.tags[z].yval = Math.round(bins[i]);
this.tags[z].displayX = Math.round(
this.map(i, 0, bins.length, this.minScaleX, this.maxScaleX)
);
}
}
if (y < max) {
max = y;
}
let newVal = Math.round(
this.map(i, 0, bins.length, this.minScaleX, this.maxScaleX)
);
if (this.check_bar) {
if (newVal < rangeMax && newVal > rangeMin) {
if (y < this.scaleY) {
var obj = new Object();
obj.x = newVal;
obj.y = Math.round(bins[i]);
obj.count = 1;
var check = true;
for (var j = 0; j < this.threshRange.length; j++) {
if (
this.threshRange[j].x == obj.x &&
this.threshRange[j].y == obj.y
) {
this.threshRange[j].count++;
check = false;
}
}
if (check) {
let tableRows = document
.getElementById("thresh-table-body")
.getElementsByTagName("tr").length;
if (tableRows < 100) {
this.threshRange.push(obj);
// filling table
let tbody = document.getElementById("thresh-table-body");
let tr = document.createElement("tr");
let td1 = document.createElement("td");
let td2 = document.createElement("td");
let td3 = document.createElement("td");
td1.innerHTML = obj.x; //+" Hz"
td2.innerHTML = obj.y;
td3.innerHTML = obj.count;
tr.appendChild(td1);
tr.appendChild(td2);
tr.appendChild(td3);
tbody.appendChild(tr);
}
} else {
// update table count
for (let c = 0; c < this.threshRange.length; c++) {
let tableRows =
document.getElementById("thresh-table-body").rows[c].cells;
if (
tableRows[0].innerHTML == obj.x &&
tableRows[1].innerHTML == obj.y
) {
let countValue = Number(tableRows[2].innerHTML);
countValue++;
tableRows[2].innerHTML = countValue;
}
}
}
}
}
} else {
if (y < this.scaleY) {
var obj = new Object();
obj.x = newVal;
obj.y = Math.round(bins[i]);
obj.count = 1;
var check = true;
for (var j = 0; j < this.threshRange.length; j++) {
if (
this.threshRange[j].x == obj.x &&
this.threshRange[j].y == obj.y
) {
this.threshRange[j].count++;
check = false;
}
}
}
}
}
// this.ctx.beginPath();
// this.ctx.arc(100, 75, 20, 0, 1 * Math.PI);
// this.ctx.stroke();
//this.ctx.strokeRect(1800,10, 40, 190);
function containsObject(obj, list) {
var i;
for (i = 0; i < list.length; i++) {
if (list[i] === obj) {
return true;
}
}
return false;
}
this.ctx.fillStyle = "rgba(0, 0, 0, 0.11)";
// drawPoint2(this.ctx ,
// this.wf_size + 1 + this.offset,
// this.spectrumHeight + 1
// );
this.ctx.lineTo(this.wf_size + 1 + this.offset, this.spectrumHeight + 1);
// console.log(
// "thired 3 this.wf_size + 1 + this.offset : " +
// parseInt(this.wf_size + 1 + this.offset) +
// " this.spectrumHeight + 1 : " +
// parseInt(this.spectrumHeight + 1)
// );
// drawPoint2(this.ctx ,
// this.wf_size + this.offset,
// this.spectrumHeight
// );
this.ctx.lineTo(this.wf_size + this.offset, this.spectrumHeight );
// console.log(
// "Forth this.wf_size + this.offset : " +
// parseInt(this.wf_size + this.offset) +
// " y : " +
// y
// );
if (y < 230 && y > 245) {
console.log("foundddddddddddddd");
}
this.ctx.closePath();
this.ctx.restore();
this.ctx.strokeStyle = "#259a00"; //color of spectrum green
this.ctx.stroke(); // it creates X axies and
/////////////////////////////////////////////////////////////////////////green ended
if (this.spectrumColorCheck) {
this.ctx.fillStyle = this.gradient; //chnage color of under line chart
} else {
this.ctx.fillStyle = "rgba(0, 0, 0, 0.0)";
}
this.ctx.fill();
if (this.check_bar) {
this.drawRectSpectrogram(0, height);
}
var colorTh = "#cc8315"; //By uncomment Change the threshold line color change
this.threshold(this.scaleY, width, colorTh); // yellow light
if (this.check_click == true) {
for (let c = 0; c < this.tags.length; c++) {
this.drawTag(
this.tags[c].StayX,
this.tags[c].tagY,
this.tags[c].displayX,
this.tags[c].yval
);
}
if (this.removeTagCheck == true) {
closeEnough = 30;
for (var z = 0; z < this.tags.length; z++) {
if (this.checkCloseEnough(this.StayX, this.tags[z].StayX + 15)) {
this.tags.splice(z, 1);
z--;
}
}
}
}
closeEnough = 5;
// span hz commented
if (this.updateValueCheck) {
if (this.countDecimals(this.threshY) > 2) {
this.threshY = this.threshY.toFixed(2);
}
this.updateValueCheck = false;
}
var arrt = [ -100000000 , 40000000,35000000];
this.spectrumWidth = Math.round(
(this.canvas.width * this.spectrumPercent) / 100.0
);
for (var k = 0; k < 4; k++) {
var alpha =
this.spectrumHeight - 620 - this.squeeze2(arrt[k], 0, this.spectrumWidth);
drawPoint2(this.ctx, alpha + 600, 150, "A");
}
// draw separate lines
// for (var k=0;k< 4; k++){
// drawPoint2(this.ctx, "200000000", "-80");
// drawPoint2(this.ctx,"100000000", "-80");
// drawPoint2(this.ctx,"35000000", "-80");
// }
//console.log('this.ctx : ',this.ctx);
};
Spectrum.prototype.addData = function (data, bmp) {
if (!this.paused) {
if (data.length > 32768) {
data = this.sequenceResize(data, 32767);
}
this.orignalArrayLength = data.length;
if (this.orignalSpanHz > this.spanHz) {
data = data.slice(
this.cutfromArray,
this.orignalArrayLength - this.cutfromArray
);
}
if (data.length != this.wf_size) {
this.wf_size = data.length;
if (data.length > 32767) {
this.ctx_wf.canvas.width = 32767;
} else {
this.ctx_wf.canvas.width = data.length;
}
this.ctx_wf.fillStyle = "black";
this.ctx_wf.fillRect(0, 0, this.wf.width, 0); //strokes of waterfall
for (var z = 0; z < this.tags.length; z++) {
this.tags[z].StayX = this.map(
this.tags[z].xval,
this.cutfromArray,
this.orignalArrayLength - this.cutfromArray,
crop,
this.ctx.canvas.width
);
}
}
this.drawSpectrum(data);
// this.addWaterfallRowBmp(bmp);
// this.addWaterfallRow(data);
this.resize();
}
};
function Spectrum(id, options) {
// Handle options
this.centerHz = options && options.centerHz ? options.centerHz : 0;
this.spanHz = options && options.spanHz ? options.spanHz : 0;
this.wf_size = options && options.wf_size ? options.wf_size : 0;
this.wf_rows = options && options.wf_rows ? options.wf_rows : 50;
this.spectrumPercent =
options && options.spectrumPercent ? options.spectrumPercent : 25;
this.spectrumPercentStep =
options && options.spectrumPercentStep ? options.spectrumPercentStep : 5;
this.averaging = options && options.averaging ? options.averaging : 0.5;
this.rectColor = options && options.rectColor ? options.rectColor : 0;
// Setup state
this.paused = false;
this.fullscreen = true;
this.min_db = -140;
this.max_db = -20;
this.spectrumHeight = 0;
// Colors
this.colorindex = 2;
this.colormap = colormaps[0];
// Create main canvas and adjust dimensions to match actual
this.canvas = document.getElementById("spectrumSM");
canvas.height = this.canvas.clientHeight;
this.canvas.width = this.canvas.clientWidth;
this.ctx = this.canvas.getContext("2d");
this.checkclick = false;
this.clickRectWidth = 1000;
this.dragL = true;
this.dragR = true;
// this.ctx.globalAlpha = 0.1;
this.drag = true;
this.click_x = 0;
this.click_y = 0;
this.check_click = true;
this.threshY = -70;
this.StayX = -10;
this.scaleY = 0;
//for change waterfall design
this.threshCheck = true;
this.removeTagCheck = true;
this.spectrumColorCheck = true;
this.check_bar = true;
this.updateValueCheck = true;
this.tags = [];
this.addTagsCheck = true;
this.maxScaleX = 0;
this.minScaleX = 0;
this.orignalArrayLength = 0;
this.zoom = this.spanHz;
this.center = this.centerHz;
this.threshRange = [];
this.detectedFrequency = [];
this.offset = 10;
this.arraySizeto = 0;
this.orignalSpanHz = 0;
this.cutfromArray = 0;
this.ctx.fillStyle = "black";
this.ctx.fillRect(10, 10, this.canvas.width, this.canvas.height);
// Create offscreen canvas for axes
this.axes = document.createElement("canvas");
this.axes.id = "myCheck";
this.axes.height = 1; // Updated later
this.axes.width = this.canvas.width;
this.ctx_axes = this.axes.getContext("2d");
function myFunction() {
this.style.fontSize = "40px";
}
// Create offscreen canvas for waterfall
this.wf = document.createElement("canvas");
this.wf.height = this.wf_rows;
this.wf.width = this.wf_size;
this.ctx_wf = this.wf.getContext("2d");
// Trigger first render
this.updateSpectrumRatio();
this.resize();
}
Here showing value of spectrum at specific point via click and zoom in/ zoom out functionality.
var closeEnough = 5;
var crop = 150;
var data_sb = -10;
var canvas = document.getElementById("spectrumSM");
Spectrum.prototype.mousedown = function (evt) {
this.checkclick = true;
if (this.checkCloseEnough(this.click_x-3, this.clickRectX)) {
this.dragR = false;
this.dragL = true;
} else if (
this.checkCloseEnough(this.click_x-3, this.clickRectX + this.clickRectWidth)
) {
this.dragR = true;
this.dragL = false;
} else if (this.checkCloseEnough(this.click_y-3, this.scaleY)) {
this.drag = true;
}
};
Spectrum.prototype.mouseup = function (evt) {
this.checkclick = false;
this.dragL = false;
this.dragR = false;
this.drag = false;
if (evt.button === "right") {
this.tags = [];
}
};
Spectrum.prototype.mousemove = function (evt) {
var rect = this.canvas.getBoundingClientRect();
this.click_x = evt.clientX - rect.left;
this.click_y = evt.clientY - rect.top;
closeEnough = Math.abs(this.clickRectWidth);
if (this.dragL == false && this.dragR == false && this.drag == false) {
if (
this.checkclick == true &&
this.checkCloseEnough(
this.click_x,
this.clickRectX + this.clickRectWidth / 2
)
) {
this.clickRectX = this.click_x - this.clickRectWidth / 2;
}
} else if (this.dragL) {
this.clickRectWidth += this.clickRectX - this.click_x;
this.clickRectX = this.click_x;
} else if (this.dragR) {
this.clickRectWidth = -(this.clickRectX - this.click_x);
} else if (this.drag && this.threshCheck) {
this.updateValueCheck = true;
this.threshY = this.map(
this.click_y,
this.canvas.height / 2,
0,
this.min_db,
this.max_db
); // this.max_db, this.min_db
}
closeEnough = 10;
};
Spectrum.prototype.click = function (evt) {
// change izza
this.check_click = true;
this.StayX = this.click_x;
console.log('tag list : ',this.addTagsCheck);
if (this.addTagsCheck == true && this.StayX > 3) {
var tag = {
StayX: this.click_x,
tagY: 0,
yval: 0,
xval: Math.round(
this.map(
this.click_x,
28,
this.ctx.canvas.width,
this.cutfromArray,
this.orignalArrayLength - this.cutfromArray
)
),
displayX: 0,
};
this.tags.push(tag);
}
};
Spectrum.prototype.wheel = function (evt) {
this.zoom = this.spanHz;
var inc;
if (this.arraySizeto == 0) {
inc = Math.round(this.orignalArrayLength * 0.05);
} else {
inc = Math.round(this.arraySizeto * 0.05);
}
let zoomInc = 0;
if (this.orignalSpanHz > this.orignalArrayLength) {
zoomInc = this.orignalSpanHz / this.orignalArrayLength;
} else {
zoomInc = this.orignalArrayLength / this.orignalSpanHz;
}
if (evt.deltaY > 0) {
if (
this.orignalSpanHz - (zoomInc * this.cutfromArray - inc * 2) <
this.orignalSpanHz &&
this.cutfromArray - inc >= 0
) {
this.cutfromArray = this.cutfromArray - inc;
this.zoom = this.orignalSpanHz - zoomInc * this.cutfromArray * 2;
} else if (
this.orignalSpanHz + zoomInc * this.cutfromArray * 2 >=
this.orignalSpanHz &&
this.cutfromArray - inc <= 0
) {
this.zoom = this.orignalSpanHz;
this.cutfromArray = 0;
}
} else if (evt.deltaY < 0) {
if (
this.orignalSpanHz - (zoomInc * this.cutfromArray + inc * 2) > inc &&
this.orignalArrayLength - this.cutfromArray * 2 - inc * 2 >
this.ctx.canvas.width
) {
this.cutfromArray = this.cutfromArray + inc;
this.zoom = this.orignalSpanHz - zoomInc * this.cutfromArray * 2;
}
}
this.arraySizeto = this.orignalArrayLength - this.cutfromArray * 2;
this.maxScaleX = this.centerHz + this.zoom / 20;
this.minScaleX = this.centerHz - this.zoom / 20;
};
Spectrum.prototype.undoTag = function () {
this.tags.pop();
};
Spectrum.prototype.checkCloseEnough = function (p1, p2) {
return Math.abs(p1 - p2) < closeEnough;
};
Spectrum.prototype.drawTag = function (locx, locy, xval, yval) {
this.ctx.beginPath();
this.ctx.strokeStyle = "#cc8315";
let freq = xval;
if (freq > 1e9) {
freq = freq / 1e9;
if (this.countDecimals(freq) > 2) {
freq = freq.toFixed(2);
}
freq = freq + " GHz";
} else if (freq > 1e6) {
freq = freq / 1e6;
if (this.countDecimals(freq) > 2) {
freq = freq.toFixed(2);
}
freq = freq + " MHz";
} else {
if (this.countDecimals(freq) > 2) {
freq = freq.toFixed(2);
}
}
var text = " ( " + freq + ", " + yval + ")";
var padding = 5;
var fontSize = 20;
var xPos = locx - padding;
var width = this.ctx.measureText(text).width + padding * 2;
var height = fontSize * 1.286;
var yPos = locy - height / 1.5;
this.ctx.lineWidth = 2;
this.ctx.fillStyle = "rgba(204, 131, 21, 0.8)";
// draw the rect
this.ctx.fillRect(xPos, yPos, width, height);
this.ctx.fillStyle = "white";
this.ctx.font = "bold 10pt droid_serif";
this.ctx.fillText(text, locx, locy);
this.ctx.fillStyle = "white";
this.ctx.beginPath();
this.ctx.arc(locx, locy, 2, 0, Math.PI * 2, true);
this.ctx.fill();
this.ctx.closePath();
};
The spectrum project you reference expects to receive regular updates of an array of data passed into drawSpectrum. Each time it renders that data as a new spectrum in drawFFT, with the data scaled by the numbers set in setRange. Each time it receives data, it also creates a new row of pixels for the waterfall in the rowToImageData function, again scaled by the numbers set in setRange. The previously created rows of pixels are shifted down by one row in addWaterfallRow.
I've made a fiddle that shows how data is handled by the Spectrum object: https://jsfiddle.net/40qun892/
If you run the fiddle it shows two examples, one with three points and another with 100 points of randomly generated data. This line shows how an x-axis is added to the graph:
const spectrumB = new Spectrum("spectrumCanvasB", {spanHz: 5000, centerHz: 2500});
The x-axis is only shown when spanHz is defined. It is generated by drawing 11 labels, equally distributed across the canvas. With the center label based on centerHz, and the remaining labels calculated based on spanHz.
As you can see from the spectrums generated by the fiddle, the x-axis labels are not connected to the data, they are just equally distributed across the canvas.
The graph behind the data is created by applying a scale to the graph so that using the array index will result in data stretched across the graph.
this.ctx.scale(width / <number of data points>, 1);
for (var i = 0; i < <number of data points>.length; i++) {
// lines removed
this.ctx.lineTo(i, y);
// lines removed
}
As you can see from the examples in the fiddle, this doesn't look very nice when there's only three datapoints, because the white lines are stretched in the x-direction but not the y-direction.
Spectrum doesn't care about x-coordinates. It just stretches whatever it is given to fit the canvas. If you give it a spanHz property, it will distribute some labels across the canvas too, but it does not associate them with the data.
The scaling seems to be slightly wrong in Spectrum (which is only noticeable if very few datapoints are used). If I make this change, the points are correctly stretched:
this.ctx.scale(width / (this.wf_size - 1), 1);
Then this change would set the x-axis labels to 100Mhz - 300Mhz:
const spectrumA = new Spectrum("spectrumCanvasA", {spanHz: 200000000, centerHz: 200000000});
Edit: (The relationship between frequency and data)
The only thing the code knows about the frequency is based on the spanHz anad centerHz.
The frequency at an array index is
(<array index> / <number of points on X axis> * <spanHz>) + (<centerHz> / 2)
The frequency at a pixel is
(<x coordinate> / <width of canvas> * <spanHz>) + (<centerHz> / 2)
If you want to convert a frequency to an array index (or a pixel) it would be slightly more complicated, because you would need to find the closest element to that frequency. For example, the pixel at a frequency is:
round((<frequency> - (<centerHz> / 2)) / <spanHz> * <width of canvas>)

How to add JavaScript file in angular cli application?

I am trying to replicate this effect - https://codepen.io/jonathasborges1/pen/YzryRpX in my angular app application.
But I'm having a hard time applying the effect
Someone can help me?
"use strict";
var LeafScene = function (el) {
this.viewport = el;
this.world = document.createElement("div");
this.leaves = [];
this.options = {
numLeaves: 60,
wind: {
magnitude: 1.2,
maxSpeed: 12,
duration: 300,
start: 0,
speed: 0
}
};
this.width = this.viewport.offsetWidth;
this.height = this.viewport.offsetHeight;
// animation helper
this.timer = 0;
this._resetLeaf = function (leaf) {
// place leaf towards the top left
leaf.x = this.width * 2 - Math.random() * this.width * 1.75;
leaf.y = -10;
leaf.z = Math.random() * 200;
if (leaf.x > this.width) {
leaf.x = this.width + 10;
leaf.y = (Math.random() * this.height) / 2;
}
// at the start, the leaf can be anywhere
if (this.timer == 0) {
leaf.y = Math.random() * this.height;
}
// Choose axis of rotation.
// If axis is not X, chose a random static x-rotation for greater variability
leaf.rotation.speed = Math.random() * 10;
var randomAxis = Math.random();
if (randomAxis > 0.5) {
leaf.rotation.axis = "X";
}
else if (randomAxis > 0.25) {
leaf.rotation.axis = "Y";
leaf.rotation.x = Math.random() * 180 + 90;
}
else {
leaf.rotation.axis = "Z";
leaf.rotation.x = Math.random() * 360 - 180;
// looks weird if the rotation is too fast around this axis
leaf.rotation.speed = Math.random() * 3;
}
// random speed
leaf.xSpeedVariation = Math.random() * 1 - 0.2;
leaf.ySpeed = Math.random();
return leaf;
};
this._updateLeaf = function (leaf) {
var leafWindSpeed = this.options.wind.speed(this.timer - this.options.wind.start, leaf.y);
var xSpeed = leafWindSpeed + leaf.xSpeedVariation;
leaf.x -= xSpeed;
leaf.y += leaf.ySpeed;
leaf.rotation.value += leaf.rotation.speed;
var t = "translateX( " +
leaf.x +
"px ) translateY( " +
leaf.y +
"px ) translateZ( " +
leaf.z +
"px ) rotate" +
leaf.rotation.axis +
"( " +
leaf.rotation.value +
"deg )";
if (leaf.rotation.axis !== "X") {
t += " rotateX(" + leaf.rotation.x + "deg)";
}
leaf.el.style.webkitTransform = t;
leaf.el.style.MozTransform = t;
leaf.el.style.oTransform = t;
leaf.el.style.transform = t;
// reset if out of view
if (leaf.x < -10 || leaf.y > this.height + 10) {
this._resetLeaf(leaf);
}
};
this._updateWind = function () {
if (this.timer === 0 ||
this.timer > this.options.wind.start + this.options.wind.duration) {
this.options.wind.magnitude = Math.random() * this.options.wind.maxSpeed;
this.options.wind.duration =
this.options.wind.magnitude * 50 + (Math.random() * 20 - 10);
this.options.wind.start = this.timer;
var screenHeight = this.height;
this.options.wind.speed = function (t, y) {
var a = ((this.magnitude / 2) * (screenHeight - (2 * y) / 3)) / screenHeight;
return (a *
Math.sin(((2 * Math.PI) / this.duration) * t + (3 * Math.PI) / 2) +
a);
};
}
};
};
LeafScene.prototype.init = function () {
for (var i = 0; i < this.options.numLeaves; i++) {
var leaf = {
el: document.createElement("div"),
x: 0,
y: 0,
z: 0,
rotation: {
axis: "X",
value: 0,
speed: 0,
x: 0
},
xSpeedVariation: 0,
ySpeed: 0,
path: {
type: 1,
start: 0
},
image: 1
};
this._resetLeaf(leaf);
this.leaves.push(leaf);
this.world.appendChild(leaf.el);
}
this.world.className = "leaf-scene";
this.viewport.appendChild(this.world);
// reset window height/width on resize
var self = this;
window.onresize = function (event) {
self.width = self.viewport.offsetWidth;
self.height = self.viewport.offsetHeight;
};
};
LeafScene.prototype.render = function () {
this._updateWind();
for (var i = 0; i < this.leaves.length; i++) {
this._updateLeaf(this.leaves[i]);
}
this.timer++;
requestAnimationFrame(this.render.bind(this));
};
// start up leaf scene
var leafContainer = document.querySelector(".falling-leaves"), leaves = new LeafScene(leafContainer);
leaves.init();
leaves.render();
You can create a file like <script> ..that js code.. </script> and save it as script.js and then add it to your index.html or dynamicly load it:
public loadScript(){
return new Promise(resolve => {
const scriptElement = document.createElement('script');
scriptElement.src = '/assets/js/script.js'
scriptElement.onload = resolve;
document.body.appendChild(scriptElement);
});
}
and then call and subscribe this function in your ts file to know when it is loaded or do something when its loaded in your page.

How to change the zoom factor to only zoom OUT on Ken Burns effect?

I am helping a friend with a website, and he is using the Ken Burns Effect with Javascript and Canvas from this site https://www.willmcgugan.com/blog/tech/post/ken-burns-effect-with-javascript-and-canvas/
for a slide-show. It works perfectly, but he would like to change the zoom effect to where all of the images zoom OUT, instead of alternating between zooming in and out.
After about a week of "scrambling" the code unsuccessfully, he posted a question about it on the site. The reply he received was (quote) "That's definitely possible, with a few tweaks of the code. Sorry, no time to give you guidance at the moment, but it shouldn't be all that difficult" (end quote).
I can't seem to figure it out either, so I'm hoping that someone here may be of help. Below is the code as posted on the willmcgugan.com website. Any help on how to change the zoom effect would be greatly appreciated.
(function($){
$.fn.kenburns = function(options) {
var $canvas = $(this);
var ctx = this[0].getContext('2d');
var start_time = null;
var width = $canvas.width();
var height = $canvas.height();
var image_paths = options.images;
var display_time = options.display_time || 7000;
var fade_time = Math.min(display_time / 2, options.fade_time || 1000);
var solid_time = display_time - (fade_time * 2);
var fade_ratio = fade_time - display_time
var frames_per_second = options.frames_per_second || 30;
var frame_time = (1 / frames_per_second) * 1000;
var zoom_level = 1 / (options.zoom || 2);
var clear_color = options.background_color || '#000000';
var images = [];
$(image_paths).each(function(i, image_path){
images.push({path:image_path,
initialized:false,
loaded:false});
});
function get_time() {
var d = new Date();
return d.getTime() - start_time;
}
function interpolate_point(x1, y1, x2, y2, i) {
// Finds a point between two other points
return {x: x1 + (x2 - x1) * i,
y: y1 + (y2 - y1) * i}
}
function interpolate_rect(r1, r2, i) {
// Blend one rect in to another
var p1 = interpolate_point(r1[0], r1[1], r2[0], r2[1], i);
var p2 = interpolate_point(r1[2], r1[3], r2[2], r2[3], i);
return [p1.x, p1.y, p2.x, p2.y];
}
function scale_rect(r, scale) {
// Scale a rect around its center
var w = r[2] - r[0];
var h = r[3] - r[1];
var cx = (r[2] + r[0]) / 2;
var cy = (r[3] + r[1]) / 2;
var scalew = w * scale;
var scaleh = h * scale;
return [cx - scalew/2,
cy - scaleh/2,
cx + scalew/2,
cy + scaleh/2];
}
function fit(src_w, src_h, dst_w, dst_h) {
// Finds the best-fit rect so that the destination can be covered
var src_a = src_w / src_h;
var dst_a = dst_w / dst_h;
var w = src_h * dst_a;
var h = src_h;
if (w > src_w)
{
var w = src_w;
var h = src_w / dst_a;
}
var x = (src_w - w) / 2;
var y = (src_h - h) / 2;
return [x, y, x+w, y+h];
}
function get_image_info(image_index, load_callback) {
// Gets information structure for a given index
// Also loads the image asynchronously, if required
var image_info = images[image_index];
if (!image_info.initialized) {
var image = new Image();
image_info.image = image;
image_info.loaded = false;
image.onload = function(){
image_info.loaded = true;
var iw = image.width;
var ih = image.height;
var r1 = fit(iw, ih, width, height);;
var r2 = scale_rect(r1, zoom_level);
var align_x = Math.floor(Math.random() * 3) - 1;
var align_y = Math.floor(Math.random() * 3) - 1;
align_x /= 2;
align_y /= 2;
var x = r2[0];
r2[0] += x * align_x;
r2[2] += x * align_x;
var y = r2[1];
r2[1] += y * align_y;
r2[3] += y * align_y;
if (image_index % 2) {
image_info.r1 = r1;
image_info.r2 = r2;
}
else {
image_info.r1 = r2;
image_info.r2 = r1;
}
if(load_callback) {
load_callback();
}
}
image_info.initialized = true;
image.src = image_info.path;
}
return image_info;
}
function render_image(image_index, anim, fade) {
// Renders a frame of the effect
if (anim > 1) {
return;
}
var image_info = get_image_info(image_index);
if (image_info.loaded) {
var r = interpolate_rect(image_info.r1, image_info.r2, anim);
var transparency = Math.min(1, fade);
if (transparency > 0) {
ctx.save();
ctx.globalAlpha = Math.min(1, transparency);
ctx.drawImage(image_info.image, r[0], r[1], r[2] - r[0], r[3] - r[1], 0, 0, width, height);
ctx.restore();
}
}
}
function clear() {
// Clear the canvas
ctx.save();
ctx.globalAlpha = 1;
ctx.fillStyle = clear_color;
ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
ctx.restore();
}
function update() {
// Render the next frame
var update_time = get_time();
var top_frame = Math.floor(update_time / (display_time - fade_time));
var frame_start_time = top_frame * (display_time - fade_time);
var time_passed = update_time - frame_start_time;
function wrap_index(i) {
return (i + images.length) % images.length;
}
if (time_passed < fade_time)
{
var bottom_frame = top_frame - 1;
var bottom_frame_start_time = frame_start_time - display_time + fade_time;
var bottom_time_passed = update_time - bottom_frame_start_time;
if (update_time < fade_time) {
clear();
} else {
render_image(wrap_index(bottom_frame), bottom_time_passed / display_time, 1);
}
}
render_image(wrap_index(top_frame), time_passed / display_time, time_passed / fade_time);
if (options.post_render_callback) {
options.post_render_callback($canvas, ctx);
}
// Pre-load the next image in the sequence, so it has loaded
// by the time we get to it
var preload_image = wrap_index(top_frame + 1);
get_image_info(preload_image);
}
// Pre-load the first two images then start a timer
get_image_info(0, function(){
get_image_info(1, function(){
start_time = get_time();
setInterval(update, frame_time);
})
});
};
})( jQuery );
If you want the simplest solution, I forked and modified your Codepen here:
http://codepen.io/jjwilly16/pen/NAovkp?editors=1010
I just removed a conditional that controls whether the zoom is moving out or in.
if (image_index % 2) {
image_info.r1 = r1;
image_info.r2 = r2;
}
else {
image_info.r1 = r2;
image_info.r2 = r1;
}
Changed to:
image_info.r1 = r2;
image_info.r2 = r1;
Now it only zooms out :)

Canvas Marching Squares Glitch / Scroll Integration

I'm attempting to teach myself how to work with canvas — and I'm probably in way over my head — but thought I'd ask if anyone has a solution to this issue I came across.
As a lesson I decided to try to start with this metaball idea:
http://codepen.io/ge1doot/pen/RNdwQB
and rework it so the metaballs are stationary but move upwards at varying rates as one scrolls down the page.
I sort of got it working here — displays much better on the fiddle than below.
https://jsfiddle.net/L7cr46px/2/
function getScrollOffsets() {
var doc = document, w = window;
var x, y, docEl;
if ( typeof w.pageYOffset === 'number' ) {
x = w.pageXOffset;
y = w.pageYOffset;
} else {
docEl = (doc.compatMode && doc.compatMode === 'CSS1Compat')?
doc.documentElement: doc.body;
x = docEl.scrollLeft;
y = docEl.scrollTop;
}
return {x:x, y:y};
}
var lava, ballData;
ballData = new Array();
(function() {
var metablobby = metablobby || {
screen: {
elem: null,
callback: null,
ctx: null,
width: 0,
height: 0,
left: 0,
top: 0,
init: function (id, callback, initRes) {
this.elem = document.getElementById(id);
this.callback = callback || null;
if (this.elem.tagName == "CANVAS") this.ctx = this.elem.getContext("2d");
window.addEventListener('resize', function () {
this.resize();
}.bind(this), false);
this.elem.onselectstart = function () { return false; }
this.elem.ondrag = function () { return false; }
initRes && this.resize();
return this;
},
resize: function () {
var o = this.elem;
this.width = o.offsetWidth;
this.height = o.offsetHeight;
for (this.left = 0, this.top = 0; o != null; o = o.offsetParent) {
this.left += o.offsetLeft;
this.top += o.offsetTop;
}
if (this.ctx) {
this.elem.width = this.width;
this.elem.height = this.height;
}
this.callback && this.callback();
},
pointer: {
screen: null,
elem: null,
callback: null,
pos: {x:0, y:0},
mov: {x:0, y:0},
drag: {x:0, y:0},
start: {x:0, y:0},
end: {x:0, y:0},
active: false,
touch: false,
move: function (e, touch) {
//this.active = true;
this.touch = touch;
e.preventDefault();
var pointer = touch ? e.touches[0] : e;
this.mov.x = pointer.clientX - this.screen.left;
this.mov.y = pointer.clientY - this.screen.top;
if (this.active) {
this.pos.x = this.mov.x;
this.pos.y = this.mov.y;
this.drag.x = this.end.x - (this.pos.x - this.start.x);
this.drag.y = this.end.y - (this.pos.y - this.start.y);
this.callback.move && this.callback.move();
}
},
scroll: function(e, touch){
run();
},
init: function (callback) {
this.screen = metablobby.screen;
this.elem = this.screen.elem;
this.callback = callback || {};
if ('ontouchstart' in window) {
// touch
this.elem.ontouchstart = function (e) { this.down(e, true); }.bind(this);
this.elem.ontouchmove = function (e) { this.move(e, true); }.bind(this);
this.elem.ontouchend = function (e) { this.up(e, true); }.bind(this);
this.elem.ontouchcancel = function (e) { this.up(e, true); }.bind(this);
}
document.addEventListener("mousemove", function (e) { this.move(e, false); }.bind(this), true);
document.addEventListener("scroll", function (e) { this.scroll(e, false); }.bind(this), true);
return this;
}
},
}
}
// ==== Point constructor ====
var Point = function(x, y) {
this.x = x;
this.y = y;
this.magnitude = x * x + y * y;
this.computed = 0;
this.force = 0;
}
Point.prototype.add = function(p) {
return new Point(this.x + p.x, this.y + p.y);
}
// ==== Ball constructor ====
var Ball = function(parent,i) {
var x = Math.floor(Math.random() * window.innerWidth) + 1;
var y = Math.floor(Math.random() * (window.innerHeight)*5) + 1;
var radius = (Math.floor(Math.random() * 65) + 15)
var drift = Math.random();
ballData[i]=[x,y,radius, drift];
this.vel = new Point(0,0);
this.pos = new Point(x,y);
this.size = radius;
this.width = parent.width;
this.height = parent.height;
}
// ==== move balls ====
Ball.prototype.move = function(i) {
// ---- interact with pointer ----
if (pointer.active) {
var dx = pointer.pos.x - this.pos.x;
var dy = pointer.pos.y - this.pos.y;
var a = Math.atan2(dy, dx);
var v = -Math.min(
10,
500 / Math.sqrt(dx * dx + dy * dy)
);
this.pos = this.pos.add(
new Point(
Math.cos(a) * v,
Math.sin(a) * v
)
);
}
var drift = ballData[i-1][3];
var pageOffset = getScrollOffsets().y;
this.pos.y = ballData[i-1][1] - (pageOffset*drift);
this.vel.y = 0 - (pageOffset*drift);
this.pos = this.pos.add(this.vel);
}
// ==== lavalamp constructor ====
var LavaLamp = function(width, height, numBalls) {
this.step = 4;
this.width = width;
this.height = height;
this.wh = Math.min(width, height);
this.sx = Math.floor(this.width / this.step);
this.sy = Math.floor(this.height / this.step);
this.paint = false;
this.metaFill = '#000000';
this.plx = [0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0];
this.ply = [0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1];
this.mscases = [0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 0, 2, 1, 1, 0];
this.ix = [1, 0, -1, 0, 0, 1, 0, -1, -1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1];
this.grid = [];
this.balls = [];
this.iter = 0;
this.sign = 1;
// ---- init grid ----
for (var i = 0; i < (this.sx + 2) * (this.sy + 2); i++) {
this.grid[i] = new Point(
(i % (this.sx + 2)) * this.step, (Math.floor(i / (this.sx + 2))) * this.step
)
}
// ---- create metaballs ----
for (var i = 0; i < 50; i++) {
this.balls[i] = new Ball(this,i);
}
}
// ==== compute cell force ====
LavaLamp.prototype.computeForce = function(x, y, idx) {
var force;
var id = idx || x + y * (this.sx + 2);
if (x === 0 || y === 0 || x === this.sx || y === this.sy) {
var force = 0.6 * this.sign;
} else {
var cell = this.grid[id];
var force = 0;
var i = 0,
ball;
while (ball = this.balls[i++]) {
force += ball.size * ball.size / (-2 * cell.x * ball.pos.x - 2 * cell.y * ball.pos.y + ball.pos.magnitude + cell.magnitude);
}
force *= this.sign
}
this.grid[id].force = force;
return force;
}
// ---- compute cell ----
LavaLamp.prototype.marchingSquares = function(next) {
var x = next[0];
var y = next[1];
var pdir = next[2];
var id = x + y * (this.sx + 2);
if(typeof this.grid[id] !== "undefined"){
if (this.grid[id].computed === this.iter) return false;
var dir, mscase = 0;
// ---- neighbors force ----
for (var i = 0; i < 4; i++) {
var idn = (x + this.ix[i + 12]) + (y + this.ix[i + 16]) * (this.sx + 2);
var force = this.grid[idn].force;
if ((force > 0 && this.sign < 0) || (force < 0 && this.sign > 0) || !force) {
// ---- compute force if not in buffer ----
force = this.computeForce(
x + this.ix[i + 12],
y + this.ix[i + 16],
idn
);
}
if (Math.abs(force) > 1) mscase += Math.pow(2, i);
}
if (mscase === 15) {
// --- inside ---
return [x, y - 1, false];
} else {
// ---- ambiguous cases ----
if (mscase === 5) dir = (pdir === 2) ? 3 : 1;
else if (mscase === 10) dir = (pdir === 3) ? 0 : 2;
else {
// ---- lookup ----
dir = this.mscases[mscase];
this.grid[id].computed = this.iter;
}
// ---- draw line ----
var ix = this.step / (
Math.abs(Math.abs(this.grid[(x + this.plx[4 * dir + 2]) + (y + this.ply[4 * dir + 2]) * (this.sx + 2)].force) - 1) /
Math.abs(Math.abs(this.grid[(x + this.plx[4 * dir + 3]) + (y + this.ply[4 * dir + 3]) * (this.sx + 2)].force) - 1) + 1
);
ctx.lineTo(
this.grid[(x + this.plx[4 * dir + 0]) + (y + this.ply[4 * dir + 0]) * (this.sx + 2)].x + this.ix[dir] * ix,
this.grid[(x + this.plx[4 * dir + 1]) + (y + this.ply[4 * dir + 1]) * (this.sx + 2)].y + this.ix[dir + 4] * ix
);
this.paint = true;
// ---- next ----
return [
x + this.ix[dir + 4],
y + this.ix[dir + 8],
dir
];
}
}
}
LavaLamp.prototype.renderMetaballs = function() {
var i = 0, ball;
while (ball = this.balls[i++]) ball.move(i);
// ---- reset grid ----
this.iter++;
this.sign = -this.sign;
this.paint = false;
ctx.fillStyle = '#FF0000';
ctx.beginPath();
// ---- compute metaballs ----
i = 0;
while (ball = this.balls[i++]) {
// ---- first cell ----
var next = [
Math.round(ball.pos.x / this.step),
Math.round(ball.pos.y / this.step), false
];
// ---- marching squares ----
do {
next = this.marchingSquares(next);
} while (next);
// ---- fill and close path ----
if (this.paint) {
ctx.fill();
ctx.closePath();
ctx.beginPath();
this.paint = false;
}
}
}
// ==== main loop ====
var run = function() {
//requestAnimationFrame(run);
ctx.clearRect(0, 0, screen.width, screen.height);
lava.renderMetaballs();
}
// ---- canvas ----
var screen = metablobby.screen.init("thedots", null, true),
ctx = screen.ctx,
pointer = screen.pointer.init();
screen.resize();
// ---- create LavaLamps ----
lava = new LavaLamp(screen.width, screen.height, 10);
// ---- start engine ----
run();
})();
html,body {
height: 100%;
width: 100%;
background-color: white;
}
body {
height: 500vh;
}
#thedots {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
z-index: 100;
pointer-events: none;
}
<canvas id="thedots" width="1203" height="363"></canvas>
but I'm getting insane rendering bugs as you'll see. Or maybe they're not rendering bugs and just some faulty code. Any help would be much appreciated.
Thanks!

multiple random images in let it snow plug-in

i've been playing with jason brown's let it snow plug-in.
his code only accommodates for a single custom image, and i've been trying to figure out how to change the code so it accommodates multiple custom images within a random range.
!function($){
var defaults = {
speed: 0,
interaction: true,
size: 2,
count: 200,
opacity: 0,
color: "#ffffff",
windPower: 0,
image: false
};
$.fn.let_it_snow = function(options){
var settings = $.extend({}, defaults, options),
el = $(this),
flakes = [],
canvas = el.get(0),
ctx = canvas.getContext("2d"),
flakeCount = settings.count,
mX = -100,
mY = -100;
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
(function() {
var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000 / 60);
};
window.requestAnimationFrame = requestAnimationFrame;
})();
function snow() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (var i = 0; i < flakeCount; i++) {
var flake = flakes[i],
x = mX,
y = mY,
minDist = 100,
x2 = flake.x,
y2 = flake.y;
var dist = Math.sqrt((x2 - x) * (x2 - x) + (y2 - y) * (y2 - y)),
dx = x2 - x,
dy = y2 - y;
if (dist < minDist) {
var force = minDist / (dist * dist),
xcomp = (x - x2) / dist,
ycomp = (y - y2) / dist,
deltaV = force / 2;
flake.velX -= deltaV * xcomp;
flake.velY -= deltaV * ycomp;
} else {
flake.velX *= .98;
if (flake.velY <= flake.speed) {
flake.velY = flake.speed
}
switch (settings.windPower) {
case false:
flake.velX += Math.cos(flake.step += .05) * flake.stepSize;
break;
case 0:
flake.velX += Math.cos(flake.step += .05) * flake.stepSize;
break;
default:
flake.velX += 0.01 + (settings.windPower/100);
}
}
var s = settings.color;
var patt = /^#([\da-fA-F]{2})([\da-fA-F]{2})([\da-fA-F]{2})$/;
var matches = patt.exec(s);
var rgb = parseInt(matches[1], 16)+","+parseInt(matches[2], 16)+","+parseInt(matches[3], 16);
flake.y += flake.velY;
flake.x += flake.velX;
if (flake.y >= canvas.height || flake.y <= 0) {
reset(flake);
}
if (flake.x >= canvas.width || flake.x <= 0) {
reset(flake);
}
if (settings.image == false) {
ctx.fillStyle = "rgba(" + rgb + "," + flake.opacity + ")"
ctx.beginPath();
ctx.arc(flake.x, flake.y, flake.size, 0, Math.PI * 2);
ctx.fill();
} else {
ctx.drawImage($("img#lis_flake").get(0), flake.x, flake.y, flake.size * 2, flake.size * 2);
}
}
requestAnimationFrame(snow);
};
function reset(flake) {
if (settings.windPower == false || settings.windPower == 0) {
flake.x = Math.floor(Math.random() * canvas.width);
flake.y = 0;
} else {
if (settings.windPower > 0) {
var xarray = Array(Math.floor(Math.random() * canvas.width), 0);
var yarray = Array(0, Math.floor(Math.random() * canvas.height))
var allarray = Array(xarray, yarray)
var selected_array = allarray[Math.floor(Math.random()*allarray.length)];
flake.x = selected_array[0];
flake.y = selected_array[1];
} else {
var xarray = Array(Math.floor(Math.random() * canvas.width),0);
var yarray = Array(canvas.width, Math.floor(Math.random() * canvas.height))
var allarray = Array(xarray, yarray)
var selected_array = allarray[Math.floor(Math.random()*allarray.length)];
flake.x = selected_array[0];
flake.y = selected_array[1];
}
}
flake.size = (Math.random() * 3) + settings.size;
flake.speed = (Math.random() * 1) + settings.speed;
flake.velY = flake.speed;
flake.velX = 0;
flake.opacity = (Math.random() * 0.5) + settings.opacity;
}
function init() {
for (var i = 0; i < flakeCount; i++) {
var x = Math.floor(Math.random() * canvas.width),
y = Math.floor(Math.random() * canvas.height),
size = (Math.random() * 3) + settings.size,
speed = (Math.random() * 1) + settings.speed,
opacity = (Math.random() * 0.5) + settings.opacity;
flakes.push({
speed: speed,
velY: speed,
velX: 0,
x: x,
y: y,
size: size,
stepSize: (Math.random()) / 30,
step: 0,
angle: 180,
opacity: opacity
});
}
snow();
}
if (settings.image != false) {
$("<img src='"+settings.image+"' style='display: none' id='lis_flake'>").prependTo("body")
}
init();
$(window).resize(function() {
if(this.resizeTO) clearTimeout(this.resizeTO);
this.resizeTO = setTimeout(function() {
el2 = el.clone();
el2.insertAfter(el);
el.remove();
el2.let_it_snow(settings);
}, 200);
});
if (settings.interaction == true) {
canvas.addEventListener("mousemove", function(e) {
mX = e.clientX,
mY = e.clientY
});
}}}(window.jQuery);
right at the top of the code, in the defaults properties, is where you point the url of the image. below is what i've put in, so it chooses between image1.jpeg and image2.jpeg
image: "img/image'+Math.floor((Math.random() * 2) + 1)+'.jpeg";
however, when the "snowflakes" respawn, the image stays the same instead of choosing a random number again. what do i have to change so that when a snowflake is created, it chooses a random image and becomes it?
i hope my questions is clear, let me know if you need more clarity. i'm new to j-script, any help would be appreciated.
The plugin author loads a single custom image into a hidden element with
if (settings.image != false) {
$("<img src='"+settings.image+"' style='display: none' id='lis_flake'>").prependTo("body")
}
and loads the snowflakes with this
ctx.drawImage($("img#lis_flake").get(0)
This solution hasn't been tested, but if you are willing to hack the plugin a bit, you could potentially make the following changes to use two optional images:
1) Add this just before the init(); function call. It adds another hidden image from settings.image2.
if (settings.image2) {
$("<img src='"+settings.image2+"' style='display: none' id='lis_flake2'>").prependTo("body")
}
2) Modify the function init() with
flakes.push({
// Create a new property called 'imgNum' to hold either "" or "2";
imgNum: (settings.image2 && Math.floor(Math.random() * 2) === 0 ? "2" : ""),
// rest of the code ...
speed: speed,
3) Change
ctx.drawImage($("img#lis_flake").get(0), flake.x, flake.y, flake.size * 2, flake.size * 2);
to
ctx.drawImage($("img#lis_flake" + flake.imgNum).get(0), flake.x, flake.y, flake.size * 2, flake.size * 2);
to chose the image based on the flake.imgNum set randomly in init().
4) Change the options you pass into the plugin like so:
options = {
// other options
image: "img/image1.jpeg",
image2: "img/image2.jpeg",
// other options
}
These changes should allow the plugin to still work if image2 isn't set.

Categories

Resources