how to attach a range/input slider onto a canvas animation? - javascript

I am aiming to attach a slider onto this codepen animation, so the user can edit the speed of the animation.
At the moment, I am not getting any errors, but I am not getting the value from the input slider passed through to the animation.
this.speed = dotSpeed;
I am aiming to take the value from the slider, create a variable and put it through the "function Circle" properties.
var dotArray = [];
function threeDotSliderChangeSpeed (value) {
document.getElementById('threeDotSpeed').innerHTML = value;
dotSpeed = +value; // + will convert the string to number
for (var i = 0; i < dotArray.length; i++) {
dotArray[i].speed = Math.round(1 * dotSpeed);
}
}
var canvas = document.getElementById( 'canvas2' ),
c = canvas.getContext( '2d' ),
i = 0,
rowOne = [],
rowTwo = [],
rowThree = [],
length = canvas.width * 0.4,
origin = [ canvas.width / 2, canvas.height / 2 ],
angle = 90,
dotSpeed = 2,
loop;
function Circle( args ) {
this.position = [ 0, 0 ];
this.angle = 30;
this.speed = dotSpeed;
this.offset = 1;
this.length = 100;
this.size = 5;
this.color = '#fff';
this.direction = 'grow';
if ( 'undefined' !== typeof args.position )
this.position = args.position;
if ( 'undefined' !== typeof args.angle )
this.angle = args.angle;
if ( 'undefined' !== typeof args.speed )
this.speed = args.speed;
if ( 'undefined' !== typeof args.length )
this.length = args.length;
if ( 'undefined' !== typeof args.size )
this.size = args.size;
if ( 'undefined' !== typeof args.color )
this.color = args.color;
if ( 'undefined' !== typeof args.offset ) {
this.offset = args.offset;
this.length = canvas.width * this.offset * 0.03
}
}
Circle.prototype.render = function() {
this.move();
this.draw();
}
Circle.prototype.draw = function() {
c.fillStyle = this.color;
c.beginPath();
c.arc( this.position[0], this.position[1], ( this.size / 2 ), 0, Math.PI * 2, true );
c.closePath();
c.fill();
}
Circle.prototype.move = function() {
this.angle = ( this.angle < 360 ) ? this.angle + this.speed : 0;
if ( 'grow' == this.direction ) {
this.length++;
this.direction = ( 150 >= this.length ) ? 'grow' : 'shrink';
} else {
this.length--;
this.direction = ( 50 <= this.length ) ? 'shrink' : 'grow';
}
this.position[0] = this.length * Math.sin( this.angle * ( Math.PI / 180 ) );
this.position[1] = this.length * Math.cos( this.angle * ( Math.PI / 180 ) );
this.position[0] = this.position[0] + origin[0];
this.position[1] = this.position[1] + origin[1];
}
for ( i = 1; i < 10; i++ ) {
var offset = 1;
rowOne.push( new Circle( {
angle: 0,
offset: i
} ) );
rowTwo.push( new Circle( {
angle: 120,
offset: i
} ) );
rowThree.push( new Circle( {
angle: 240,
offset: i
} ) );
}
function render() {
c.fillStyle = 'rgba( 0, 0, 0, 0.025 )';
c.fillRect( 0, 0, canvas.width, canvas.height );
for ( i = 0; i < 9; i++ ) {
rowOne[i].render();
rowTwo[i].render();
rowThree[i].render();
}
}
(function animate() {
render();
loop = setTimeout( animate, 40 );
})();
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>CodePen - 3 dotted-line canvas animation.</title>
<link rel="stylesheet" href="css/style.css">
<script type="text/javascript" src="jquery-2.1.0.min.js"></script>
</head>
<body>
<canvas id="canvas2" width="400" height="400"></canvas>
<p id="attribute">Speed </p>
<span id="threeDotSpeed" class="sliderSpan">5</span>
<input type="range" min="0" max="10" value="5" step="1" onchange="threeDotSliderChangeSpeed(3)"/>
<br /> <br />
<script src="js/index.js"></script>
</body>
</html>
Here is a video of another one I got going, using the same method.
https://www.youtube.com/watch?v=vjZ6CfQ2WrY&feature=youtu.be

To get the value from the slider you need to get the value from the element
by using document.getElementById('rg').value on change event
js:
var dotArray = [];
function threeDotSliderChangeSpeed () {
var value = document.getElementById('rg').value;
alert(value);
document.getElementById('threeDotSpeed').innerHTML = value;
dotSpeed = +value; // + will convert the string to number
for (var i = 0; i < dotArray.length; i++) {
dotArray[i].speed = Math.round(1 * dotSpeed);
}
}
var canvas = document.getElementById( 'canvas2' ),
c = canvas.getContext( '2d' ),
i = 0,
rowOne = [],
rowTwo = [],
rowThree = [],
length = canvas.width * 0.4,
origin = [ canvas.width / 2, canvas.height / 2 ],
angle = 90,
dotSpeed = 2,
loop;
function Circle( args ) {
this.position = [ 0, 0 ];
this.angle = 30;
this.speed = dotSpeed;
this.offset = 1;
this.length = 100;
this.size = 5;
this.color = '#fff';
this.direction = 'grow';
if ( 'undefined' !== typeof args.position )
this.position = args.position;
if ( 'undefined' !== typeof args.angle )
this.angle = args.angle;
if ( 'undefined' !== typeof args.speed )
this.speed = args.speed;
if ( 'undefined' !== typeof args.length )
this.length = args.length;
if ( 'undefined' !== typeof args.size )
this.size = args.size;
if ( 'undefined' !== typeof args.color )
this.color = args.color;
if ( 'undefined' !== typeof args.offset ) {
this.offset = args.offset;
this.length = canvas.width * this.offset * 0.03
}
}
Circle.prototype.render = function() {
this.move();
this.draw();
}
Circle.prototype.draw = function() {
c.fillStyle = this.color;
c.beginPath();
c.arc( this.position[0], this.position[1], ( this.size / 2 ), 0, Math.PI * 2, true );
c.closePath();
c.fill();
}
Circle.prototype.move = function() {
this.angle = ( this.angle < 360 ) ? this.angle + this.speed : 0;
if ( 'grow' == this.direction ) {
this.length++;
this.direction = ( 150 >= this.length ) ? 'grow' : 'shrink';
} else {
this.length--;
this.direction = ( 50 <= this.length ) ? 'shrink' : 'grow';
}
this.position[0] = this.length * Math.sin( this.angle * ( Math.PI / 180 ) );
this.position[1] = this.length * Math.cos( this.angle * ( Math.PI / 180 ) );
this.position[0] = this.position[0] + origin[0];
this.position[1] = this.position[1] + origin[1];
}
for ( i = 1; i < 10; i++ ) {
var offset = 1;
rowOne.push( new Circle( {
angle: 0,
offset: i
} ) );
rowTwo.push( new Circle( {
angle: 120,
offset: i
} ) );
rowThree.push( new Circle( {
angle: 240,
offset: i
} ) );
}
function render() {
c.fillStyle = 'rgba( 0, 0, 0, 0.025 )';
c.fillRect( 0, 0, canvas.width, canvas.height );
for ( i = 0; i < 9; i++ ) {
rowOne[i].render();
rowTwo[i].render();
rowThree[i].render();
}
}
(function animate() {
render();
loop = setTimeout( animate, 40 );
})();
Html:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>CodePen - 3 dotted-line canvas animation.</title>
<link rel="stylesheet" href="css/style.css">
<script type="text/javascript" src="jquery-2.1.0.min.js"></script>
</head>
<body>
<canvas id="canvas2" width="400" height="400"></canvas>
<p id="attribute">Speed </p>
<span id="threeDotSpeed" class="sliderSpan">5</span>
<input type="range" min="0" max="10" value="5" step="1" id="rg" onchange="threeDotSliderChangeSpeed(3)"/>
<br />
<br />
<script src="js/index.js"></script>
</body>
</html>
i am able to get the slider value on alert
you can see output in codepin
http://codepen.io/anon/pen/aOOjXE

Related

Why does my vector splits in two vectors?

I'll try to explain as best I can.
I'm using canvas, and a basic vectors library I wrote in JS. Now my enemy object has a few vectors in it, the math seems right all the way through, but I end up seeing the enemy's weapon split into two and fire in both directions when I get too close to it.
Not close
Close
The player is the white circle with a green dot in the middle, and I use mousemove for the coordinates.
After looking at the images, I noticed that it creates two weapons that fire at the correct fireRate, one after the other. It doesn't show in the images, but when you look at it in the browser, there are two small red dots firing those yellow projectiles.
I looked over the code, and I can't find anything repeating itself that could cause the dot to split into two, and I started to wonder if it has anything to do with Math.atan2() or maybe something else.
Here's the enemy function:
function Enemy(enemyConfig){
this.enemyConfig = enemyConfig;
this.position = new Vector(enemyConfig.x, enemyConfig.y);
if(this.enemyConfig.hasVelocity){
this.velocity = new Vector(enemyConfig.vx, enemyConfig.vy);
}
this.radius = enemyConfig.radius;
this.hasWeapon = false;
if(enemyConfig.hasWeapon){
this.weaponId = enemyConfig.weaponId;
this.projectiles = [];
this.weapon = this.position.Copy();
this.weaponDistanceFromPosition = this.radius * .9;
this.weaponAngleToPlayer = 0;
this.weaponReloaded = true;
this.fireRate = enemyConfig.fireRate || .25;
this.reloadTimer = this.fireRate;
this.hasWeapon = true;
}
this.target = cfg.player;
};
Enemy.prototype.Draw = function(){
cfg.ctx.save();
cfg.ctx.beginPath();
cfg.ctx.fillStyle = "rgba(0, 0, 0, 1)";
cfg.ctx.strokeStyle = "rgba(255, 0, 0, 1)";
cfg.ctx.arc(this.position.x, this.position.y, this.radius, 0, PI*2, false);
cfg.ctx.fill();
cfg.ctx.stroke();
cfg.ctx.closePath();
cfg.ctx.restore();
if(this.hasWeapon){
cfg.ctx.save();
cfg.ctx.beginPath();
cfg.ctx.fillStyle = "rgba(255, 0, 0, 1)";
// cfg.ctx.strokeStyle = "rgba(0, 0, 0, 1)";
cfg.ctx.arc(this.weapon.x, this.weapon.y, 2, 0, PI*2, false);
cfg.ctx.fill();
// cfg.ctx.stroke();
cfg.ctx.closePath();
cfg.ctx.restore();
if(this.projectiles.length > 0 && this.projectiles){
this.projectiles.forEach((projectile, index, projectiles) => {
if(projectile.exists) projectile.Draw();
})
}
}
};
Enemy.prototype.Update = function(){
if(this.hasWeapon){
this.weaponAngleToPlayer = this.weapon.AngleTo(this.target.position);
this.weapon.Length = this.weaponDistanceFromPosition;
this.weapon.Angle = this.weaponAngleToPlayer;
this.weapon.AddTo(this.position);
this.weaponReloaded = (this.reloadTimer === 0);
if(!this.weaponReloaded){
this.reloadTimer -= Math.min(cfg.deltaTime / 1000, this.reloadTimer);
}else{
this.FireWeapon();
}
if(this.projectiles.length > 0){
this.projectiles.forEach((projectile, index, projectiles) => {
projectile.Update();
if(!projectile.exists) projectiles.splice(index, 1);
});
}
}
// console.log(this.projectiles);
// this.target = cfg.player;
// console.log(this.target.position);
};
Enemy.prototype.FireWeapon = function(){
var projectile = new Projectile();
projectile.position = this.weapon.Copy();
projectile.velocity = this.weapon.Copy();
projectile.velocity.Angle = this.weaponAngleToPlayer;
projectile.velocity.Limit(15);
projectile.exists = true;
this.projectiles.push(projectile);
this.reloadTimer = this.fireRate;
};
var PI = Math.PI;
var cfg = cfg || {};
var player;
cfg.expectedFPS = 60;
cfg.framesPerMs = cfg.expectedFPS / 1000;
cfg.deltaTime = 0;
cfg.previousTimeStamp = undefined;
cfg.direction = {
up: 1.5 * PI,
down: .5 * PI,
left: PI,
right: 0
};
cfg.mouse = {
x: 0,
y: 0,
radius: 2
};
cfg.projectiles = [];
cfg.player = null;
cfg.enemies = [];
function random(min, max = null){
if(max != null){
return Math.random() * (Math.max(min, max) - Math.min(min, max)) + Math.min(min, max);
}
return Math.random() * min;
};
function Background(config = {}){
var config = config;
cfg.ctx.fillStyle = "rgba(0, 0, 0, .5)";
cfg.ctx.fillRect(0, 0, cfg.canvas.width, cfg.canvas.height);
};
function KeepInCanvas(object){
if(object.position.x + object.radius >= cfg.canvas.width)
object.position.x = cfg.canvas.width - object.radius;
if(object.position.x - object.radius <= 0)
object.position.x = object.radius;
if(object.position.y + object.radius >= cfg.canvas.height)
object.position.y = cfg.canvas.height - object.radius;
if(object.position.y - object.radius <= 0)
object.position.y = object.radius;
};
function IsOutOfCanvas(object){
return (object.position.x + object.radius < 0 || object.position.x - object.radius > cfg.canvas.width
|| object.position.y + object.radius < 0 || object.position.y - object.radius > cfg.canvas.height);
};
function Vector(x = 0, y = 0){
this.x = x;
this.y = y;
};
Vector.prototype = {
get Length(){
return Math.sqrt(this.x * this.x + this.y * this.y);
},
set Length(length){
var angle = this.Angle;
this.x = Math.cos(angle) * length;
this.y = Math.sin(angle) * length;
},
get Angle(){
return Math.atan2(this.y, this.x);
},
set Angle(angle){
var length = this.Length;
this.x = Math.cos(angle) * length;
this.y = Math.sin(angle) * length;
},
Add: function(vector){ return new Vector(this.x + vector.x, this.y + vector.y); },
AddTo: function(vector){
this.x += vector.x;
this.y += vector.y;
},
Subtract: function(vector){ return new Vector(this.x - vector.x, this.y - vector.y); },
SubtractFrom: function(vector){
this.x -= vector.x;
this.y -= vector.y;
},
Multiply: function(factor){ return new Vector(this.x * factor, this.y * factor); },
MultiplyBy: function(factor){
this.x *= factor;
this.y *= factor;
},
DivideBy: function(factor){
this.x /= factor;
this.y /= factor;
},
AngleTo: function(vector){
return Math.atan2(vector.y - this.y, vector.x - this.x);
},
Copy: function(){ return new Vector(this.x, this.y); },
Normalize: function(arg = false){
if(this.Length > 0){
if(arg) return this.Divide(this.Length);
this.DivideBy(this.Length);
}
},
Limit: function(factor){
if(this.Length > factor){
this.Normalize();
this.MultiplyBy(factor);
}
}
};
function Player(){
this.position = new Vector(0, 0);
this.radius = 20;
};
Player.prototype.Draw = function(){
cfg.ctx.save();
cfg.ctx.beginPath();
cfg.ctx.fillStyle = "rgba(0, 180, 0, .35)";
cfg.ctx.strokeStyle = "rgba(255, 255, 255, 1)";
cfg.ctx.arc(this.position.x, this.position.y, this.radius, 0, PI*2, false);
cfg.ctx.fill();
cfg.ctx.stroke();
cfg.ctx.closePath();
cfg.ctx.restore();
};
Player.prototype.Update = function(){
this.position.x = cfg.mouse.x;
this.position.y = cfg.mouse.y;
KeepInCanvas(this);
};
function Projectile(){
this.position = new Vector(0, 0);
this.velocity;
this.radius = 5;
this.exists = false;
};
Projectile.prototype.SetInitialVelocity = function(angle, length){
var x = Math.cos(angle) * length,
y = Math.sin(angle) * length;
return new Vector(x, y);
};
Projectile.prototype.Draw = function(){
cfg.ctx.save();
cfg.ctx.beginPath();
cfg.ctx.fillStyle = "rgba(255, 160, 0, 1)";
cfg.ctx.arc(this.position.x, this.position.y, this.radius, 0, PI*2, false);
cfg.ctx.fill();
cfg.ctx.closePath();
cfg.ctx.restore();
};
Projectile.prototype.Update = function(){
this.position.AddTo(this.velocity.Multiply(cfg.framesPerMs).Multiply(cfg.deltaTime));
if(IsOutOfCanvas(this)) this.exists = false;
};
function Enemy(enemyConfig){
this.position = new Vector(enemyConfig.x, enemyConfig.y);
this.radius = enemyConfig.radius;
this.hasWeapon = false;
if(enemyConfig.hasWeapon){
this.projectiles = [];
this.weapon = this.position.Copy();
this.weaponAngleToPlayer;// = 0;
this.hasWeapon = true;
}
this.target = cfg.player;
};
Enemy.prototype.Draw = function(){
cfg.ctx.save();
cfg.ctx.beginPath();
cfg.ctx.fillStyle = "rgba(0, 0, 0, 1)";
cfg.ctx.strokeStyle = "rgba(255, 0, 0, 1)";
cfg.ctx.arc(this.position.x, this.position.y, this.radius, 0, PI*2, false);
cfg.ctx.fill();
cfg.ctx.stroke();
cfg.ctx.closePath();
cfg.ctx.restore();
if(this.hasWeapon){
cfg.ctx.save();
cfg.ctx.beginPath();
cfg.ctx.fillStyle = "rgba(255, 0, 0, 1)";
cfg.ctx.arc(this.weapon.x, this.weapon.y, 2, 0, PI*2, false);
cfg.ctx.fill();
cfg.ctx.closePath();
cfg.ctx.restore();
if(this.projectiles.length > 0 && this.projectiles){
this.projectiles.forEach(projectile => {
if(projectile.exists) projectile.Draw();
})
}
}
};
Enemy.prototype.Update = function(){
if(this.hasWeapon){
this.weaponAngleToPlayer = this.position.AngleTo(this.target.position);
// console.trace(this.weaponAngleToPlayer);
this.weapon.Length = this.radius * .9;
this.weapon.Angle = this.weaponAngleToPlayer;
this.weapon.AddTo(this.position);
this.FireWeapon();
if(this.projectiles.length > 0){
this.projectiles.forEach((projectile, index, projectiles) => {
projectile.Update();
if(!projectile.exists) projectiles.splice(index, 1);
});
}
}
};
Enemy.prototype.FireWeapon = function(){
var projectile = new Projectile();
projectile.position = this.weapon.Copy();
projectile.velocity = projectile.position.Copy();
projectile.velocity.Angle = this.weaponAngleToPlayer;
projectile.velocity.Limit(15);
projectile.exists = true;
// console.trace(projectile);
this.projectiles.push(projectile);
};
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Space Shooter</title>
</head>
<body>
<canvas id="gameCanvas"></canvas>
<script>
window.onload = function(){
cfg.canvas = document.getElementById("gameCanvas");
cfg.canvas.focus();
cfg.canvas.width = 760;
cfg.canvas.height = 1060;
cfg.canvas.style.cursor = "none";
cfg.ctx = cfg.canvas.getContext("2d");
cfg.canvasOffset = cfg.canvas.getBoundingClientRect();
cfg.player = player = new Player();
cfg.enemies[0] = new Enemy({
x: 200,
y: 500,
radius: 35,
hasWeapon: true
});
cfg.enemies[1] = new Enemy({
x: 500,
y: 200,
radius: 45,
hasWeapon: true
});
window.requestAnimationFrame(Game);
};
window.addEventListener("mousemove", function(e){
cfg.mouse.x = e.clientX - cfg.canvasOffset.x;
cfg.mouse.y = e.clientY - cfg.canvasOffset.y;
});
function Game(timestamp){
if(!cfg.previousTimeStamp) cfg.previousTimeStamp = timestamp;
cfg.deltaTime = timestamp - cfg.previousTimeStamp;
cfg.previousTimeStamp = timestamp;
Update();
Draw();
window.requestAnimationFrame(Game);
};
function Update(){
player.Update();
if(cfg.enemies.length > 0){
cfg.enemies.forEach(enemy => {
enemy.Update();
});
}
};
function Draw(){
Background();
if(cfg.enemies.length > 0){
cfg.enemies.forEach(enemy => {
enemy.Draw();
});
}
player.Draw();
};
</script>
</body>

Why does this canvas animation leave trails behind? How to prevent it?

I'm starting to work with some canvas animations and am having trouble understanding what's happening in a CodePen. Here is the animation in question: https://codepen.io/towc/pen/mJzOWJ
var w = c.width = window.innerWidth,
h = c.height = window.innerHeight,
ctx = c.getContext( '2d' ),
opts = {
len: 20,
count: 50,
baseTime: 10,
addedTime: 10,
dieChance: .05,
spawnChance: 1,
sparkChance: .1,
sparkDist: 10,
sparkSize: 2,
color: 'hsl(hue,100%,light%)',
baseLight: 50,
addedLight: 10, // [50-10,50+10]
shadowToTimePropMult: 6,
baseLightInputMultiplier: .01,
addedLightInputMultiplier: .02,
cx: w / 2,
cy: h / 2,
repaintAlpha: .04,
hueChange: .1
},
tick = 0,
lines = [],
dieX = w / 2 / opts.len,
dieY = h / 2 / opts.len,
baseRad = Math.PI * 2 / 6;
ctx.fillStyle = 'black';
ctx.fillRect( 0, 0, w, h );
function loop() {
window.requestAnimationFrame( loop );
++tick;
ctx.globalCompositeOperation = 'source-over';
ctx.shadowBlur = 0;
ctx.fillStyle = 'rgba(0,0,0,alp)'.replace( 'alp', opts.repaintAlpha );
ctx.fillRect( 0, 0, w, h );
ctx.globalCompositeOperation = 'lighter';
if( lines.length < opts.count && Math.random() < opts.spawnChance )
lines.push( new Line );
lines.map( function( line ){ line.step(); } );
}
function Line(){
this.reset();
}
Line.prototype.reset = function(){
this.x = 0;
this.y = 0;
this.addedX = 0;
this.addedY = 0;
this.rad = 0;
this.lightInputMultiplier = opts.baseLightInputMultiplier + opts.addedLightInputMultiplier * Math.random();
this.color = opts.color.replace( 'hue', tick * opts.hueChange );
this.cumulativeTime = 0;
this.beginPhase();
}
Line.prototype.beginPhase = function(){
this.x += this.addedX;
this.y += this.addedY;
this.time = 0;
this.targetTime = ( opts.baseTime + opts.addedTime * Math.random() ) |0;
this.rad += baseRad * ( Math.random() < .5 ? 1 : -1 );
this.addedX = Math.cos( this.rad );
this.addedY = Math.sin( this.rad );
if( Math.random() < opts.dieChance || this.x > dieX || this.x < -dieX || this.y > dieY || this.y < -dieY )
this.reset();
}
Line.prototype.step = function(){
++this.time;
++this.cumulativeTime;
if( this.time >= this.targetTime )
this.beginPhase();
var prop = this.time / this.targetTime,
wave = Math.sin( prop * Math.PI / 2 ),
x = this.addedX * wave,
y = this.addedY * wave;
ctx.shadowBlur = prop * opts.shadowToTimePropMult;
ctx.fillStyle = ctx.shadowColor = this.color.replace( 'light', opts.baseLight + opts.addedLight * Math.sin( this.cumulativeTime * this.lightInputMultiplier ) );
ctx.fillRect( opts.cx + ( this.x + x ) * opts.len, opts.cy + ( this.y + y ) * opts.len, 2, 2 );
if( Math.random() < opts.sparkChance )
ctx.fillRect( opts.cx + ( this.x + x ) * opts.len + Math.random() * opts.sparkDist * ( Math.random() < .5 ? 1 : -1 ) - opts.sparkSize / 2, opts.cy + ( this.y + y ) * opts.len + Math.random() * opts.sparkDist * ( Math.random() < .5 ? 1 : -1 ) - opts.sparkSize / 2, opts.sparkSize, opts.sparkSize )
}
loop();
window.addEventListener( 'resize', function(){
w = c.width = window.innerWidth;
h = c.height = window.innerHeight;
ctx.fillStyle = 'black';
ctx.fillRect( 0, 0, w, h );
opts.cx = w / 2;
opts.cy = h / 2;
dieX = w / 2 / opts.len;
dieY = h / 2 / opts.len;
});
canvas {
position: absolute;
top: 0;
left: 0;
}
<canvas id=c></canvas>
If you let the animation run for a while so the "sparks" spread out they leave behind a faint gray-ish trail. What is causing this trail and is it possible to prevent it?
Thank you!

not able to select a hexagon in a grid

I have been looking at my code for hours now , but still I can't figure out what's wrong with it exactly.
I have created a very simple version of hexagon grid system. Where I'd like to select any hexagon inside the grid. All the hexagons are being displayed correctly, it's just that when I click on the grid , an incorrect hexagon gets selected. It behaves, as if the mouse position was not correct, or
perhaps it may be the hexagons that have incorrect position data (?).
But how come they're positioned correctly?
////////// [ Hexagon ] ////////////////////
function Hexagon( options ){
if( options !== "undefined" ){
this.attributes = {
type : options.type || 0, //// 0 is cell , 1 player /// Default : 0 ////
id: options.id,
color : this.getColor(),
coords: [], //// [ r, q ] /// row / col ///
points: [],
pos: options.pos,
size: options.size
};
this.states = {
selected: false
};
//// make short-cuts to frequently used attributes ////
this.pos = this.attributes.pos;
this.coords = this.attributes.coords;
this.size = this.attributes.size;
this.points = this.attributes.points;
///// caclulate top_left, bottom and center points ////
this.TopLeftPoint = [ this.pos[0], this.pos[1] ];
this.BottomRightPoint = [ this.pos[0] + this.size.w, this.pos[1] + this.size.h ];
this.MidPoint = [ this.pos[0] + (this.size.w / 2), this.pos[1] + (this.size.h / 2) ];
///////// generate points ///////
this.generate();
}
}
Hexagon.prototype = {
constructor : Hexagon,
changeState: function( st_name, st_value ){
if( this.checkState( st_name ) ) {
this.states[st_name] = st_value;
}
},
checkState: function( st_name ){
if( typeof this.states[st_name] !== "undefined" ) {
return this.states[st_name];
}
return false;
},
isInHexBounds : function( p ){ /*Point*/
if(this.TopLeftPoint[0] < p[0] && this.TopLeftPoint[1] < p[1] && p[0] < this.BottomRightPoint[0] && p[1] < this.BottomRightPoint[0]){
return true;
}
return false;
},
contains: function( p ) {
var isIn = false;
if( this.isInHexBounds( p ) ){
var i, j = 0;
for (i = 0, j = this.points.length - 1; i < this.points.length; j = i++){
var iP = this.points[i];
var jP = this.points[j];
if (
( ((iP[1] <= p[1]) && (p[1] < jP[1])) || ((jP[1] <= p[1]) && (p[1] < iP[1]))) && (p[0] < (jP[0] - iP[0]) * (p[1] - iP[1]) / (jP[1] - iP[1]) + iP[0])
){
isIn = !isIn;
}
}
}
return isIn;
},
getColor: function( ){
switch( this.type ){
case 0:
return "blue";
case 1:
return "red";
default:
return "yellow";
}
},
trigger: function( e_name ){
this.events[ e_name ].call(this);
},
events: {
"select" : function(){
if( ! this.checkState( "selected" ) ){
this.changeState("selected", true);
//console.log( this.coords )
this.type = 1;
}
}
},
setType: function( type ){
this.attributes.type = type;
},
generate: function(){///// generate hexagon points //////
var x1 = (this.size.w - this.size.s)/2;
var y1 = (this.size.h / 2);
this.points.push(
[ x1 + this.pos[0], this.pos[1] ],
[ x1 + this.size.s + this.pos[0], this.pos[1] ],
[ this.size.w + this.pos[0], y1 + this.pos[1] ],
[ x1 + this.size.s + this.pos[0], this.size.h + this.pos[1] ],
[ x1 + this.pos[0], this.size.h + this.pos[1] ],
[ this.pos[0], y1 + this.pos[1] ]
);
},
draw : function( ctx ){
if( this.type > 0 ){
ctx.globalAlpha = 0.5;
ctx.fillStyle = this.color;
ctx.fill();
ctx.globalAlpha = 1.0;
}else{
ctx.strokeStyle = "grey";
}
//ctx.rect( this.BottomRightPoint[0],this.BottomRightPoint[1],4,4);
//ctx.stroke();
ctx.lineWidth = 1;
ctx.beginPath();
ctx.moveTo( this.points[0][0], this.points[0][1] );
for( var c=1; c < this.points.length; c++ ){
ctx.lineTo( this.points[c][0], this.points[c][1] );
}
ctx.closePath();
ctx.stroke();
this.draw_coords( ctx );
},
draw_coords: function( ctx ){
ctx.font="10px Georgia";
ctx.textAlign = "center";
ctx.textBaseline = 'middle';
ctx.fillStyle = "blue";
ctx.fillText(this.coords[0]+" , "+this.coords[1], this.MidPoint[0], this.MidPoint[1]);
}
}
///////// [ Grid ] /////////////////////
function Grid( options ){
if(typeof options !== "undefined"){
this.size = {
width: options.size[0],
height: options.size[1]
};
//this.mouse_pos = [];
this.pos = options.pos; //// position within the canvas /// [ x , y ] ////
this.ctx = options.ctx;
this.ctx_pos = options.ctx_pos; //// position of canvas element /// [ left, top] ///
this.hex_size = this.calculate_hex_size( options.hex_def );
this.hexagons = []; //// [ row, col ] ///// just a temporary array ////
this.grid2D = []; ///// includes all hexagons to be drawn ///
}
this.generate();
this.animate();
this.enable_mouse_events();
}
Grid.prototype = {
constructor : Grid,
generate : function(){
var hex_pos_x = 0.0, hex_pos_y = 0.0, row = 0, col = 0, offset = 0.0, h = null, h_id = 0;
while( (hex_pos_y + this.hex_size.h) <= this.size.height ){
col = 0; //// reset col
offset = 0.0; //// reset offset
if( (row % 2) == 1){
offset = ( ( this.hex_size.w - this.hex_size.s ) /2 ) + this.hex_size.s ;
col = 1;
}
hex_pos_x = offset;
while( (hex_pos_x + this.hex_size.w) <= this.size.width ){
h = new Hexagon( { pos : [ hex_pos_x, hex_pos_y ], size: this.hex_size , id: row+""+col, type: 0 });
h.coords[0] = col; //// set coord X ///
this.grid2D.push( h );
if( ! this.hexagons[col] ){
this.hexagons[col] = [];
}
this.hexagons[col].push( h );
col += 2;
hex_pos_x += (this.hex_size.w + this.hex_size.s);
}
row++;
hex_pos_y += (this.hex_size.h / 2);
}
////finally go through our list of hexagons by their x co-ordinate to assign the y co-ordinate
var coordX = 0, coordY = 0, h_l = this.hexagons.length, hex_arr = [];
for( ; coordX < h_l; coordX++ ){
hex_arr = this.hexagons[ coordX ];
coordY = Math.floor( (coordX / 2 ) + (coordX % 2) );
for( var h = 0, size = hex_arr.length; h < size; h++ ){
hex_arr[h].coords[1] = coordY++;
}
}
},
getHexAt: function( p ){ //// point [ x, y ]
for ( var h = 0, h_l = this.grid2D.length; h < h_l; h++ ){
if ( this.grid2D[h].contains( p ) ){
return this.grid2D[h];
}
}
return null;
},
animate: function(){
var self = this;
window.requestAnimationFrame( function(){
self.animate();
});
self.draw();
},
draw : function( ){
this.ctx.clearRect(0, 0, this.size.width, this.size.height);
for( var h = 0, h_l = this.grid2D.length; h < h_l; h++ ){
this.grid2D[h].draw( this.ctx );
}
},
calculate_hex_size : function( hex_def ){
return {
w: hex_def.radius * 2,
m: hex_def.margin,
h: (Math.sqrt(3) / 2) * ( hex_def.radius * 2),
r: hex_def.radius,
s: hex_def.radius
}
},
enable_mouse_events: function(){
var self = this;
var mouse_pos = [];
var cur_hex = null;
window.addEventListener( 'mousemove', function(e){
mouse_pos = [ ( e.clientX - self.ctx_pos[0] ), ( e.clientY - self.ctx_pos[1] )];
//self.mouse_pos = mouse_pos;
});
window.addEventListener( 'mousedown', function(e){
if( mouse_pos.length > 0 ){
cur_hex = self.getHexAt( mouse_pos );
if( cur_hex != null ){
cur_hex.trigger("select");
}
}
});
}
}
var c_el = document.getElementById("myCanvas");
var ctx = c_el.getContext("2d");
var nGrid = new Grid({
/// size : [ c_el.width, c_el.height ], /// [rows / cols ] //// 20 px x 10 px///
size : [ 70 , 70 ],
pos: [ 20, 20 ], /// [X, Y] ////
hex_def: {
radius: 20,
margin: 0
},
ctx : ctx,
ctx_pos: [ c_el.getBoundingClientRect().left, c_el.getBoundingClientRect().top ]
});
<body stye="width: 100%; height: 100%" >
<canvas id="myCanvas" width="750px" height="405px" style="margin:0; padding:0; border:1px solid #d3d3d3;"></canvas>
</body>
it turns out that I have mixed up the order of some context's methods. So it was calling the ctx.fill() before the ctx.begonPath()/ctx.closePath(). Which is wrong, so any previously drawn hexagon was being filled as a side effect of this mistake.
Once I added the ctx.fill() after the ctx.begonPath()/ctx.closePath()everything was working perfectly.
See the result below.
////////// [ Hexagon ] ////////////////////
function Hexagon( options ){
if( options !== "undefined" ){
this.attributes = {
type : options.type || 0, //// 0 is cell , 1 player /// Default : 0 ////
id: options.id,
color : this.getColor(),
coords: [], //// [ r, q ] /// row / col ///
points: [],
pos: options.pos,
size: options.size
};
this.states = {
selected: false
};
//// make short-cuts to frequently used attributes ////
this.pos = this.attributes.pos;
this.coords = this.attributes.coords;
this.size = this.attributes.size;
this.points = this.attributes.points;
///// caclulate top_left, bottom and center points ////
this.TopLeftPoint = [ this.pos[0], this.pos[1] ];
this.BottomRightPoint = [ this.pos[0] + this.size.w, this.pos[1] + this.size.h ];
this.MidPoint = [ this.pos[0] + (this.size.w / 2), this.pos[1] + (this.size.h / 2) ];
///////// generate points ///////
this.generate();
}
}
Hexagon.prototype = {
constructor : Hexagon,
changeState: function( st_name, st_value ){
if( this.checkState( st_name ) ) {
this.states[st_name] = st_value;
}
},
checkState: function( st_name ){
if( typeof this.states[st_name] !== "undefined" ) {
return this.states[st_name];
}
return false;
},
isInHexBounds : function( p ){ /*Point*/
if(this.TopLeftPoint[0] < p[0] && this.TopLeftPoint[1] < p[1] && p[0] < this.BottomRightPoint[0] && p[1] < this.BottomRightPoint[1]){
return true;
}
return false;
},
contains: function( p ) {
var isIn = false;
if( this.isInHexBounds( p ) ){
var i, j = 0;
for (i = 0, j = this.points.length - 1; i < this.points.length; j = i++){
var iP = this.points[i];
var jP = this.points[j];
if (
( ((iP[1] <= p[1]) && (p[1] < jP[1])) || ((jP[1] <= p[1]) && (p[1] < iP[1])) ) && (p[0] < (jP[0] - iP[0]) * (p[1] - iP[1]) / (jP[1] - iP[1]) + iP[0])
){
isIn = !isIn;
}
}
}
return isIn;
},
getColor: function( ){
switch( this.type ){
case 0:
return "blue";
case 1:
return "red";
default:
return "yellow";
}
},
trigger: function( e_name ){
this.events[ e_name ].call(this);
},
events: {
"select" : function(){
if( ! this.checkState( "selected" ) ){
this.changeState("selected", true);
//console.log( this.coords )
this.type = 1;
}
}
},
setType: function( type ){
this.attributes.type = type;
},
generate: function(){///// generate hexagon points //////
var x1 = (this.size.w - this.size.s)/2;
var y1 = (this.size.h / 2);
this.points.push(
[ x1 + this.pos[0], this.pos[1] ],
[ x1 + this.size.s + this.pos[0], this.pos[1] ],
[ this.size.w + this.pos[0], y1 + this.pos[1] ],
[ x1 + this.size.s + this.pos[0], this.size.h + this.pos[1] ],
[ x1 + this.pos[0], this.size.h + this.pos[1] ],
[ this.pos[0], y1 + this.pos[1] ]
);
},
draw : function( ctx ){
ctx.lineWidth = 1;
ctx.beginPath();
ctx.moveTo( this.points[0][0], this.points[0][1] );
for( var c=1; c < this.points.length; c++ ){
ctx.lineTo( this.points[c][0], this.points[c][1] );
}
ctx.closePath();
ctx.stroke();
if( this.type > 0 ){
ctx.globalAlpha = 0.5;
ctx.fillStyle = this.color;
ctx.fill();
ctx.globalAlpha = 1.0;
}else{
ctx.strokeStyle = "grey";
}
this.draw_coords( ctx );
},
draw_coords: function( ctx ){
ctx.font="10px Georgia";
ctx.textAlign = "center";
ctx.textBaseline = 'middle';
ctx.fillStyle = "blue";
ctx.fillText(this.coords[0]+" , "+this.coords[1], this.MidPoint[0], this.MidPoint[1]);
}
}
///////// [ Grid ] /////////////////////
function Grid( options ){
if(typeof options !== "undefined"){
this.size = {
width: options.size[0],
height: options.size[1]
};
//this.mouse_pos = [];
this.pos = options.pos; //// position within the canvas /// [ x , y ] ////
this.ctx = options.ctx;
this.ctx_pos = options.ctx_pos; //// position of canvas element /// [ left, top] ///
this.hex_size = this.calculate_hex_size( options.hex_def );
this.hexagons = []; //// [ row, col ] ///// just a temporary array ////
this.grid2D = []; ///// includes all hexagons to be drawn ///
}
this.generate();
this.animate();
this.enable_mouse_events();
}
Grid.prototype = {
constructor : Grid,
generate : function(){
var hex_pos_x = 0.0, hex_pos_y = 0.0, row = 0, col = 0, offset = 0.0, h = null, h_id = 0;
while( (hex_pos_y + this.hex_size.h) <= this.size.height ){
col = 0; //// reset col
offset = 0.0; //// reset offset
if( (row % 2) == 1){
offset = ( ( this.hex_size.w - this.hex_size.s ) /2 ) + this.hex_size.s ;
col = 1;
}
hex_pos_x = offset;
while( (hex_pos_x + this.hex_size.w) <= this.size.width ){
h = new Hexagon( { pos : [ hex_pos_x, hex_pos_y ], size: this.hex_size , id: row+""+col, type: 0 });
h.coords[0] = col; //// set coord X ///
this.grid2D.push( h );
if( ! this.hexagons[col] ){
this.hexagons[col] = [];
}
this.hexagons[col].push( h );
col += 2;
hex_pos_x += (this.hex_size.w + this.hex_size.s);
}
row++;
hex_pos_y += (this.hex_size.h / 2);
}
////finally go through our list of hexagons by their x co-ordinate to assign the y co-ordinate
var coordX = 0, coordY = 0, h_l = this.hexagons.length, hex_arr = [];
for( ; coordX < h_l; coordX++ ){
hex_arr = this.hexagons[ coordX ];
coordY = Math.floor( (coordX / 2 ) + (coordX % 2) );
for( var h = 0, size = hex_arr.length; h < size; h++ ){
hex_arr[h].coords[1] = coordY++;
}
}
},
getHexAt: function( p ){ //// point [ x, y ]
for ( var h = 0, h_l = this.grid2D.length; h < h_l; h++ ){
if ( this.grid2D[h].contains( p ) ){
return this.grid2D[h];
}
}
return null;
},
animate: function(){
var self = this;
window.requestAnimationFrame( function(){
self.animate();
});
self.draw();
},
draw : function( ){
this.ctx.clearRect(0, 0, this.size.width, this.size.height);
for( var h = 0, h_l = this.grid2D.length; h < h_l; h++ ){
this.grid2D[h].draw( this.ctx );
}
},
calculate_hex_size : function( hex_def ){
return {
w: hex_def.radius * 2,
m: hex_def.margin,
h: (Math.sqrt(3) / 2) * ( hex_def.radius * 2),
r: hex_def.radius,
s: hex_def.radius
}
},
enable_mouse_events: function(){
var self = this;
var mouse_pos = [];
var cur_hex = null;
window.addEventListener( 'mousemove', function(e){
mouse_pos = [ ( e.clientX - self.ctx_pos[0] ), ( e.clientY - self.ctx_pos[1] )];
//self.mouse_pos = mouse_pos;
});
window.addEventListener( 'mousedown', function(e){
if( mouse_pos.length > 0 ){
cur_hex = self.getHexAt( mouse_pos );
if( cur_hex != null ){
cur_hex.trigger("select");
}
}
});
}
}
var c_el = document.getElementById("myCanvas");
var ctx = c_el.getContext("2d");
var nGrid = new Grid({
/// size : [ c_el.width, c_el.height ], /// [rows / cols ] //// 20 px x 10 px///
size : [ 70 , 70 ],
pos: [ 20, 20 ], /// [X, Y] ////
hex_def: {
radius: 20,
margin: 0
},
ctx : ctx,
ctx_pos: [ c_el.getBoundingClientRect().left, c_el.getBoundingClientRect().top ]
});
<body stye="width: 100%; height: 100%" >
<canvas id="myCanvas" width="750px" height="405px" style="margin:0; padding:0; border:1px solid #d3d3d3;"></canvas>
</body>

jQuery click function to slidedown div

I am using the the forkit jQuery ribbon that drops down a curtain of additional content. I have managed to apply this and it works fine once the ribbon is pulled down as per the fiddle.
I want to modify it such that, the curtain also appears once a button is clicked.
Kindly help.
jQuery:
(function(){
var STATE_CLOSED = 0,
STATE_DETACHED = 1,
STATE_OPENED = 2,
TAG_HEIGHT = 30,
TAG_WIDTH = 200,
MAX_STRAIN = 40,
// Factor of page height that needs to be dragged for the
// curtain to fall
DRAG_THRESHOLD = 0.36;
VENDORS = [ 'Webkit', 'Moz', 'O', 'ms' ];
var dom = {
ribbon: null,
ribbonString: null,
ribbonTag: null,
curtain: null,
closeButton: null
},
// The current state of the ribbon
state = STATE_CLOSED,
// Ribbon text, correlates to states
closedText = '',
detachedText = '',
friction = 1.04;
gravity = 1.5,
// Resting position of the ribbon when curtain is closed
closedX = TAG_WIDTH * 0.4,
closedY = -TAG_HEIGHT * 0.5,
// Resting position of the ribbon when curtain is opened
openedX = TAG_WIDTH * 0.4,
openedY = TAG_HEIGHT,
velocity = 0,
rotation = 45,
curtainTargetY = 0,
curtainCurrentY = 0,
dragging = false,
dragTime = 0,
dragY = 0,
anchorA = new Point( closedX, closedY ),
anchorB = new Point( closedX, closedY ),
mouse = new Point();
function initialize() {
dom.ribbon = document.querySelector( '.forkit' );
dom.curtain = document.querySelector( '.forkit-curtain' );
dom.closeButton = document.querySelector( '.forkit-curtain .close-button' );
if( dom.ribbon ) {
// Fetch label texts from DOM
closedText = dom.ribbon.getAttribute( 'data-text' ) || '';
detachedText = dom.ribbon.getAttribute( 'data-text-detached' ) || closedText;
// Construct the sub-elements required to represent the
// tag and string that it hangs from
dom.ribbon.innerHTML = '<span class="string"></span><span class="tag">' + closedText + '</span>';
dom.ribbonString = dom.ribbon.querySelector( '.string' );
dom.ribbonTag = dom.ribbon.querySelector( '.tag' );
// Bind events
dom.ribbon.addEventListener( 'click', onRibbonClick, false );
document.addEventListener( 'mousemove', onMouseMove, false );
document.addEventListener( 'mousedown', onMouseDown, false );
document.addEventListener( 'mouseup', onMouseUp, false );
window.addEventListener( 'resize', layout, false );
if( dom.closeButton ) {
dom.closeButton.addEventListener( 'click', onCloseClick, false );
}
// Start the animation loop
animate();
}
}
function onMouseDown( event ) {
if( dom.curtain && state === STATE_DETACHED ) {
event.preventDefault();
dragY = event.clientY;
dragTime = Date.now();
dragging = true;
}
}
function onMouseMove( event ) {
mouse.x = event.clientX;
mouse.y = event.clientY;
}
function onMouseUp( event ) {
if( state !== STATE_OPENED ) {
state = STATE_CLOSED;
dragging = false;
}
}
function onRibbonClick( event ) {
if( dom.curtain ) {
event.preventDefault();
if( state === STATE_OPENED ) {
close();
}
else if( Date.now() - dragTime < 300 ) {
open();
}
}
}
function onCloseClick( event ) {
event.preventDefault();
close();
}
function layout() {
if( state === STATE_OPENED ) {
curtainTargetY = window.innerHeight;
curtainCurrentY = curtainTargetY;
}
}
function open() {
dragging = false;
state = STATE_OPENED;
}
function close() {
dragging = false;
state = STATE_CLOSED;
dom.ribbonTag.innerHTML = closedText;
}
function detach() {
state = STATE_DETACHED;
dom.ribbonTag.innerHTML = detachedText;
}
function animate() {
update();
render();
requestAnimFrame( animate );
}
function update() {
// Distance between mouse and top right corner
var distance = distanceBetween( mouse.x, mouse.y, window.innerWidth, 0 );
// If we're OPENED the curtainTargetY should ease towards page bottom
if( state === STATE_OPENED ) {
curtainTargetY = Math.min( curtainTargetY + ( window.innerHeight - curtainTargetY ) * 0.2, window.innerHeight );
}
else {
// Detach the tag when hovering close enough
if( distance < TAG_WIDTH * 1.5 ) {
detach();
}
// Re-attach the tag if the user moved away
else if( !dragging && state === STATE_DETACHED && distance > TAG_WIDTH * 2 ) {
close();
}
if( dragging ) {
// Updat the curtain position while dragging
curtainTargetY = Math.max( mouse.y - dragY, 0 );
// If the threshold is crossed, open the curtain
if( curtainTargetY > window.innerHeight * DRAG_THRESHOLD ) {
open();
}
}
else {
curtainTargetY *= 0.8;
}
}
// Ease towards the target position of the curtain
curtainCurrentY += ( curtainTargetY - curtainCurrentY ) * 0.3;
// If we're dragging or detached we need to simulate
// the physical behavior of the ribbon
if( dragging || state === STATE_DETACHED ) {
// Apply forces
velocity /= friction;
velocity += gravity;
var containerOffsetX = dom.ribbon.offsetLeft;
var offsetX = Math.max( ( ( mouse.x - containerOffsetX ) - closedX ) * 0.2, -MAX_STRAIN );
anchorB.x += ( ( closedX + offsetX ) - anchorB.x ) * 0.1;
anchorB.y += velocity;
var strain = distanceBetween( anchorA.x, anchorA.y, anchorB.x, anchorB.y );
if( strain > MAX_STRAIN ) {
velocity -= Math.abs( strain ) / ( MAX_STRAIN * 1.25 );
}
var dy = Math.max( mouse.y - anchorB.y, 0 ),
dx = mouse.x - ( containerOffsetX + anchorB.x );
// Angle the ribbon towards the mouse but limit it avoid extremes
var angle = Math.min( 130, Math.max( 50, Math.atan2( dy, dx ) * 180 / Math.PI ) );
rotation += ( angle - rotation ) * 0.1;
}
// Ease ribbon towards the OPENED state
else if( state === STATE_OPENED ) {
anchorB.x += ( openedX - anchorB.x ) * 0.2;
anchorB.y += ( openedY - anchorB.y ) * 0.2;
rotation += ( 90 - rotation ) * 0.02;
}
// Ease ribbon towards the CLOSED state
else {
anchorB.x += ( anchorA.x - anchorB.x ) * 0.2;
anchorB.y += ( anchorA.y - anchorB.y ) * 0.2;
rotation += ( 45 - rotation ) * 0.2;
}
}
function render() {
if( dom.curtain ) {
dom.curtain.style.top = - 100 + Math.min( ( curtainCurrentY / window.innerHeight ) * 100, 100 ) + '%';
}
dom.ribbon.style[ prefix( 'transform' ) ] = transform( 0, curtainCurrentY, 0 );
dom.ribbonTag.style[ prefix( 'transform' ) ] = transform( anchorB.x, anchorB.y, rotation );
var dy = anchorB.y - anchorA.y,
dx = anchorB.x - anchorA.x;
var angle = Math.atan2( dy, dx ) * 180 / Math.PI;
dom.ribbonString.style.width = anchorB.y + 'px';
dom.ribbonString.style[ prefix( 'transform' ) ] = transform( anchorA.x, 0, angle );
}
function prefix( property, el ) {
var propertyUC = property.slice( 0, 1 ).toUpperCase() + property.slice( 1 );
for( var i = 0, len = VENDORS.length; i < len; i++ ) {
var vendor = VENDORS[i];
if( typeof ( el || document.body ).style[ vendor + propertyUC ] !== 'undefined' ) {
return vendor + propertyUC;
}
}
return property;
}
function transform( x, y, r ) {
return 'translate('+x+'px,'+y+'px) rotate('+r+'deg)';
}
function distanceBetween( x1, y1, x2, y2 ) {
var dx = x1-x2;
var dy = y1-y2;
return Math.sqrt(dx*dx + dy*dy);
}
/**
* Defines a 2D position.
*/
function Point( x, y ) {
this.x = x || 0;
this.y = y || 0;
}
Point.prototype.distanceTo = function( x, y ) {
var dx = x-this.x;
var dy = y-this.y;
return Math.sqrt(dx*dx + dy*dy);
};
Point.prototype.clone = function() {
return new Point( this.x, this.y );
};
Point.prototype.interpolate = function( x, y, amp ) {
this.x += ( x - this.x ) * amp;
this.y += ( y - this.y ) * amp;
};
window.requestAnimFrame = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function( callback ){
window.setTimeout(callback, 1000 / 60);
};
})();
initialize();
})();
You need to add an event handler to a button that calls the open() method from the forkit plugin, like this:
$('#dropButton').bind('click', function(){
open();
});
Here is a working JSFiddle
Just add this to it - should work.
$('a.forkit').click(function(){
$('.forkit-curtain').slideDown();
});
https://jsfiddle.net/eaj5rvtm/1/

Blinking in canvas context

I'm using this code to draw something like waiting progress on page:
html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Preloaders</title>
<link rel="stylesheet" href="css/index.css" />
<link rel="stylesheet" href="css/preloaders.css" />
<script src="js/lib/requestAnimFrame.js"></script>
<script src="js/lib/timer.js"></script>
<script src="js/lib/preloaders.js"></script>
<script src="js/app.js"></script>
</head>
<body>
<div id="preloader1"></div>
</body>
</html>
index.css:
html, body{
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
preloader.css:
#preloader1 {
display: block;
width: 100%;
height: 15px;
margin: 0;
padding: 0;
}
requestAnimFrame.js:
window.requestAnimFrame = (function(callback) {
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000 / 60);
};
})();
timer.js:
var Timer = function(){
"use strict";
var prev = new Date().getTime();
var speed = 1;
this.start = function(){
prev = new Date().getTime();
}
this.setSpeed = function ( s ) {
speed = s;
}
this.getDelta = function( inSeconds ){
var now = new Date().getTime();
var delta = (now - prev) * speed;
if (inSeconds) delta /= 1000;
prev = now;
return delta;
}
}
preloaders.js:
var PRELOADERS = {
waiting1: function ( el ) {
"use strict";
var width = el.offsetWidth;
var height = el.offsetHeight;
var speed = 1;
var v = [0, 0, 0, 0]; // values
var e = [0, -0.5, -1, -1.5]; // elapsed
var canvas = document.createElement( "canvas" )
canvas.style.display = "block";
canvas.width = width;
canvas.height = height;
el.appendChild( canvas );
var ctx = canvas.getContext('2d');
var c = [ // colours
[255,60,60], // red
[255,200,60], // yellow
[80,220,40], // green
[40,120,220] // blue
]
var o = [0,1,2,3]; // order
var drawRect = function ( w /* width: 0..1 */, c /* colour: [r,g,b | a] */ ) {
if (c.length == 4) ctx.fillStyle = "rgba("+c[0]+","+c[1]+","+c[2]+","+c[3]+")";
else ctx.fillStyle = "rgb("+c[0]+","+c[1]+","+c[2]+")";
var hw = width / 2; // half-width
ctx.fillRect( hw-hw*w, 0, width*w, height );
}
var easing = function ( val ) {
return -val*(val -2)
}
var next = function ( ) {
var ot = o.slice(0);
o = [ot[1], ot[2], ot[3], ot[0]];
}
this.update = function ( delta ) {
for (var i = 0; i < 4; i++) {
e[i] += delta * speed;
if (e[i] > 2) {
e[i] = 0;
next();
}
v[i] = easing( Math.min(1, Math.max(0, e[i])) );
drawRect( v[o[i]], c[o[i]] );
}
}
this.setSpeed = function ( s ) {
speed = s;
}
}
}
app.js:
var init = function( ){
"use strict";
var timer = new Timer();
var preloader1 = new PRELOADERS.waiting1( document.getElementById( "preloader1" ) );
// preloader1.setSpeed(0.1);
var animate = function( ) {
render( );
requestAnimFrame( animate );
}
var render = function( ){
var delta = timer.getDelta( true );
preloader1.update( delta );
}
animate();
}
window.onload = init;
But sometimes rectangles on canvas are blinking.
Help me to catch this bug please.
The problem was in update function.
drawRect shoud be called in separate loop after all calculations:
this.update = function ( delta ) {
for (var i = 0; i < 4; i++) {
e[i] += delta * speed;
if (e[i] > 2) {
e[i] = 0;
next();
}
v[i] = easing( Math.min(1, Math.max(0, e[i])) );
}
for (i = 0; i < 4; i++) {
drawRect( v[o[i]], c[o[i]] );
}
}

Categories

Resources