Converting jquery controls to javascript - javascript

So i am trying to implement simple touch controls on a javascript game. I have the following answer from a search:
Snake Game with Controller Buttons for Mobile Use **UPDATED**
However I was trying to change this jquery into javascript so that it would work with my game
Jquery:
$(document).on('click', '.button-pad > button', function(e) {
if ($(this).hasClass('left-btn')) {
e = 37;
}
Javascript:
var contoller = document.getElementById("button-pad").on('click',
'.button-pad > button', function(e) {
if ('.button-pad > button'(this).hasClass('btn-left')) {
e = 37;
}
I thought I had it sorted but it is not working at all
Codepen here:
https://codepen.io/MrVincentRyan/pen/VqpMrJ?editors=1010

Your existing code has some problems with it, but it was close enough where I could translate it. However, your current code seems to want to reassign the event argument being passed to the click handler (e) to 37. This makes no sense. Most likely you just want another variable set to 37 and that's what I've done below:
spaceInvader(window, document.getElementById('space-invader'));
window.focus();
let game = null;
let ship = null;
function spaceInvader (window, canvas) {
canvas.focus();
var context = canvas.getContext('2d');
/* GAME */
function Game () {
this.message = '';
this.rebel = [];
this.republic = [];
this.other = [];
this.size = {x: canvas.width, y: canvas.height};
this.wave = 0;
this.refresh = function () {
this.update();
this.draw();
requestAnimationFrame(this.refresh);
}.bind(this);
this.init();
}
Game.MESSAGE_DURATION = 1500;
Game.prototype.init = function () {
this.ship = new Ship(this);
this.addRebel(this.ship);
this.refresh();
};
Game.prototype.update = function () {
this.handleCollisions();
this.computeElements();
this.elements.forEach(Element.update);
if (!this.rebel.length) {
this.showText('Gatwick closed', true);
return;
}
if (!this.republic.length) this.createWave();
};
Game.prototype.draw = function () {
context.clearRect(0, 0, this.size.x, this.size.y);
this.elements.forEach(Element.draw);
Alien.drawLife(this.republic);
if (this.message) {
context.save();
context.font = '30px Arial';
context.textAlign='center';
context.fillStyle = '#FFFFFF';
context.fillText(this.message, canvas.width / 2, canvas.height / 2);
context.restore();
}
};
Game.prototype.computeElements = function () {
this.elements = this.other.concat(this.republic, this.rebel);
};
Game.prototype.addRebel = function (element) {
this.rebel.push(element);
};
Game.prototype.addRepublic = function (element) {
this.republic.push(element);
};
Game.prototype.addOther = function (element) {
this.other.push(element);
};
Game.prototype.handleCollisions = function () {
this.rebel.forEach(function(elementA) {
this.republic.forEach(function (elementB) {
if (!Element.colliding(elementA, elementB)) return;
elementA.life--;
elementB.life--;
var sizeA = elementA.size.x * elementA.size.y;
var sizeB = elementB.size.x * elementB.size.y;
this.addOther(new Explosion(this, sizeA > sizeB ? elementA.pos : elementB.pos));
}, this);
}, this);
this.republic = this.republic.filter(Element.isAlive);
this.rebel = this.rebel.filter(Element.isAlive);
this.other = this.other.filter(Element.isAlive);
this.republic = this.republic.filter(this.elementInGame, this);
this.rebel = this.rebel.filter(this.elementInGame, this);
};
Game.prototype.elementInGame = function (element) {
return !(element instanceof Bullet) || (
element.pos.x + element.halfWidth > 0 &&
element.pos.x - element.halfWidth < this.size.x &&
element.pos.y + element.halfHeight > 0 &&
element.pos.y - element.halfHeight < this.size.x
);
};
Game.prototype.createWave = function () {
this.ship.life = Ship.MAX_LIFE;
this.ship.fireRate = Math.max(50, Ship.FIRE_RATE - 50 * this.wave);
this.wave++;
this.showText('Wave: ' + this.wave);
var waveSpeed = Math.ceil(this.wave / 2);
var waveProb = (999 - this.wave * 2) / 1000;
var margin = {x: Alien.SIZE.x + 10, y: Alien.SIZE.y + 10};
for (var i = 0; i < 2; i++) {
var x = margin.x + (i % 8) * margin.x;
var y = -200 + (i % 3) * margin.y;
this.addRepublic(new Alien(this, {x: x, y: y}, waveSpeed, waveProb));
}
};
Game.prototype.showText = function (message, final) {
this.message = message;
if (!final) setTimeout(this.showText.bind(this, '', true), Game.MESSAGE_DURATION);
};
/* GENERIC ELEMENT */
function Element (game, pos, size) {
this.game = game;
this.pos = pos;
this.size = size;
this.halfWidth = Math.floor(this.size.x / 2);
this.halfHeight = Math.floor(this.size.y / 2);
}
Element.update = function (element) {
element.update();
};
Element.draw = function (element) {
element.draw();
};
Element.isAlive = function (element) {
return element.life > 0;
};
Element.colliding = function (elementA, elementB) {
return !(
elementA === elementB ||
elementA.pos.x + elementA.halfWidth < elementB.pos.x - elementB.halfWidth ||
elementA.pos.y + elementA.halfHeight < elementB.pos.y - elementB.halfHeight ||
elementA.pos.x - elementA.halfWidth > elementB.pos.x + elementB.halfWidth ||
elementA.pos.y - elementA.halfHeight > elementB.pos.y + elementB.halfHeight
);
};
/* SHIP */
function Ship(game) {
var pos = {
x: Math.floor(game.size.x / 2) - Math.floor(Ship.SIZE.x / 2),
y: game.size.y - Math.floor(Ship.SIZE.y / 2)
};
Element.call(this, game, pos, Ship.SIZE);
this.kb = new KeyBoard();
this.speed = Ship.SPEED;
this.allowShooting = true;
this.life = Ship.MAX_LIFE;
this.fireRate = Ship.FIRE_RATE;
}
Ship.SIZE = {x: 67, y: 100};
Ship.SPEED = 8;
Ship.MAX_LIFE = 5;
Ship.FIRE_RATE = 200;
Ship.prototype.update = function () {
if (this.kb.isDown(KeyBoard.KEYS.LEFT) && this.pos.x - this.halfWidth > 0) {
this.pos.x -= this.speed;
} else if (this.kb.isDown(KeyBoard.KEYS.RIGHT) && this.pos.x + this.halfWidth < this.game.size.x) {
this.pos.x += this.speed;
}
if (this.allowShooting && this.kb.isDown(KeyBoard.KEYS.SPACE)) {
var bullet = new Bullet(
this.game,
{x: this.pos.x, y: this.pos.y - this.halfHeight },
{ x: 0, y: -Bullet.SPEED },
true
);
this.game.addRebel(bullet);
this.toogleShooting();
}
};
Ship.prototype.draw = function () {
var img = document.getElementById('ship');
context.save();
context.translate(this.pos.x - this.halfWidth, this.pos.y - this.halfHeight);
context.drawImage(img, 0, 0);
context.restore();
this.drawLife();
};
Ship.prototype.drawLife = function () {
context.save();
context.fillStyle = 'white';
context.fillRect(this.game.size.x -112, 10, 102, 12);
context.fillStyle = 'red';
context.fillRect(this.game.size.x -111, 11, this.life * 100 / Ship.MAX_LIFE, 10);
context.restore();
};
Ship.prototype.toogleShooting = function (final) {
this.allowShooting = !this.allowShooting;
if (!final) setTimeout(this.toogleShooting.bind(this, true), this.fireRate);
};
/* ALIENS */
function Alien(game, pos, speed, shootProb) {
Element.call(this, game, pos, Alien.SIZE);
this.speed = speed;
this.shootProb = shootProb;
this.life = 3;
this.direction = {x: 1, y: 1};
}
Alien.SIZE = {x: 51, y: 60};
Alien.MAX_RANGE = 350;
Alien.CHDIR_PRO = 0.990;
Alien.drawLife = function (array) {
array = array.filter(function (element) {
return element instanceof Alien;
});
context.save();
context.fillStyle = 'white';
context.fillRect(10, 10, 10 * array.length + 2, 12);
array.forEach(function (alien, idx) {
switch (alien.life) {
case 3:
context.fillStyle = 'green';
break;
case 2:
context.fillStyle = 'yellow';
break;
case 1:
context.fillStyle = 'red';
break;
}
context.fillRect(10 * idx + 11, 11, 10, 10);
});
context.restore();
};
Alien.prototype.update = function () {
if (this.pos.x - this.halfWidth <= 0) {
this.direction.x = 1;
} else if (this.pos.x + this.halfWidth >= this.game.size.x) {
this.direction.x = -1;
} else if (Math.random() > Alien.CHDIR_PRO) {
this.direction.x = -this.direction.x;
}
if (this.pos.y - this.halfHeight <= 0) {
this.direction.y = 1;
} else if (this.pos.y + this.halfHeight >= Alien.MAX_RANGE) {
this.direction.y = -1;
} else if (Math.random() > Alien.CHDIR_PRO) {
this.direction.y = -this.direction.y;
}
this.pos.x += this.speed * this.direction.x;
this.pos.y += this.speed * this.direction.y;
if (Math.random() > this.shootProb) {
var bullet = new Bullet(
this.game,
{x: this.pos.x, y: this.pos.y + this.halfHeight },
{ x: Math.random() - 0.5, y: Bullet.SPEED },
false
);
this.game.addRepublic(bullet);
}
};
Alien.prototype.draw = function () {
var img = document.getElementById('fighter');
context.save();
context.translate(this.pos.x + this.halfWidth, this.pos.y + this.halfHeight);
context.rotate(Math.PI);
context.drawImage(img, 0, 0);
context.restore();
};
/* BULLET */
function Bullet(game, pos, direction, isRebel) {
Element.call(this, game, pos, Bullet.SIZE);
this.direction = direction;
this.isRebel = isRebel;
this.life = 1;
try {
var sound = document.getElementById('sound-raygun');
sound.load();
sound.play().then(function () {}, function () {});
}
catch (e) {
// only a sound issue
}
}
Bullet.SIZE = {x: 6, y: 20};
Bullet.SPEED = 3;
Bullet.prototype.update = function () {
this.pos.x += this.direction.x;
this.pos.y += this.direction.y;
};
Bullet.prototype.draw = function () {
context.save();
var img;
if (this.isRebel) {
context.translate(this.pos.x - this.halfWidth, this.pos.y - this.halfHeight);
img = document.getElementById('rebel-bullet');
}
else {
context.translate(this.pos.x + this.halfWidth, this.pos.y + this.halfHeight);
img = document.getElementById('republic-bullet');
context.rotate(Math.PI);
}
context.drawImage(img, 0, 0);
context.restore();
};
/* EXPLOSION */
function Explosion(game, pos) {
Element.call(this, game, pos, Explosion.SIZE);
this.life = 1;
this.date = new Date();
try {
var sound = document.getElementById('sound-explosion');
sound.load();
sound.play().then(function () {}, function () {});
}
catch (e) {
// only a sound issue
}
}
Explosion.SIZE = {x: 115, y: 100};
Explosion.DURATION = 150;
Explosion.prototype.update = function () {
if (new Date() - this.date > Explosion.DURATION) this.life = 0;
};
Explosion.prototype.draw = function () {
var img = document.getElementById('explosion');
context.save();
context.translate(this.pos.x - this.halfWidth, this.pos.y - this.halfHeight);
context.drawImage(img, 0, 0);
context.restore();
};
/* KEYBOARD HANDLING */
function KeyBoard() {
var state = {};
window.addEventListener('keydown', function(e) {
state[e.keyCode] = true;
});
window.addEventListener('keyup', function(e) {
state[e.keyCode] = false;
});
this.isDown = function (key) {
return state[key];
};
}
KeyBoard.KEYS = {
LEFT: 37,
RIGHT: 39,
SPACE: 32
};
window.addEventListener('load', function() {
game = new Game();
});
// Get all the button elements that are children of elements that have
// the .button-pad class and convert the resulting node list into an Array
let elements =
Array.prototype.slice.call(document.querySelectorAll('.button-pad button'));
// Loop over the array
elements.forEach(function(el){
el.textContent = "XXXX";
// Set up a click event handler for the current element being iterated:
el.addEventListener('click', function(e) {
// When the element is clicked, check to see if it uses the left-btn class
if(this.classList.contains('left-btn')) {
// Perform whatever actions you need to:
ship.update();
}
});
});
}
<h1>Gatwick invaders</h1>
<p>Press <b>left arrow</b> to go left, <b>right arrow</b> to go right, and <b>space</b> to shoot...</p>
<canvas id="space-invader" width="640" height="500" tabindex="0"></canvas>
<img id="fighter" src="https://raw.githubusercontent.com/MrVIncentRyan/assets/master/drone1.png" />
<img id="ship" src="https://raw.githubusercontent.com/MrVIncentRyan/assets/master/cop1.png" />
<img id="rebel-bullet" src="https://raw.githubusercontent.com/OlivierB-OB/starwars-invader/master/rebelBullet.png" />
<img id="republic-bullet" src="https://raw.githubusercontent.com/OlivierB-OB/starwars-invader/master/republicBullet.png" />
<img id="explosion" src="https://raw.githubusercontent.com/OlivierB-OB/starwars-invader/master/explosion.png" />
<audio id="sound-explosion" src="https://raw.githubusercontent.com/OlivierB-OB/starwars-invader/master/explosion.mp3"></audio>
<audio id="sound-raygun" src="https://raw.githubusercontent.com/OlivierB-OB/starwars-invader/master/raygun.mp3"></audio>
</div>
<div class="button-pad">
<div class="btn-up">
<button type="submit" class="up">
<img src="http://aaronblomberg.com/sites/ez/images/btn-up.png" />
</button>
</div>
<div class="btn-right">
<button type="submit" class="right">
<img src="http://aaronblomberg.com/sites/ez/images/btn-right.png" />
</button>
</div>
<div class="btn-down">
<button type="submit" class="down">
<img src="http://aaronblomberg.com/sites/ez/images/btn-down.png" />
</button>
</div>
<div class="btn-left">
<button type="submit" class="left">
<img src="http://aaronblomberg.com/sites/ez/images/btn-left.png" />
</button>
</div>
</div>

A custom solution for emulating keypresses on mobile in both vanilla Javascript as well as jQuery!
// jQuery (edge), for use with ES2015-19
/*
$(document).on("click", ".example-btn", e => { // Click event handler
if($(this).hasClass("example-btn")) { // Verifying that element has class
e = 37
jQuery.event.trigger({type: "keypress", which: character.charCodeAt(e)}) // Simulating keystroke
// The following is simply for debugging, remove if needed
alert("Button validation confirmed!")
console.log("E: ", e)
}
})
*/
// Pure Javascript (ECMA Standard)
document.querySelector(".example-btn").addEventListener("click", function(e) { // Click event handler
if(this.classList.contains("example-btn")) { // Verifying that element has class
e = 37
if(document.createEventObject) {
var eventObj = document.createEventObject();
eventObj.keyCode = e;
document.querySelector(".example-btn").fireEvent("onkeydown", eventObj);
} else if(document.createEvent) {
var eventObj2 = document.createEvent("Events");
eventObj2.initEvent("keydown", true, true);
eventObj2.which = e;
document.querySelector(".example-btn").dispatchEvent(eventObj2);
}
// The following is simply for debugging, remove if needed
alert("Button validation confirmed!");
console.log("E: ", e);
}
});
// ---------------------------------------------------------------------------------------------------
/*
You can not use the "this" statement when referring to an embedded element. In your previous code "this" would refer to ".button-container > .example-btn" which the compiler will interpret as only the parent element, being .button-container (.button-pad in your code) not the child element in which you want. Also there is no such thing as returning a character code and expecting it to automatically know what to do with it. I assume you are doing this to emulate a keystroke on a mobile device and I assure you that this design works although it might be flawed. Give it a try and I hope it does something to at least help if not solve your problem.
*/
// ---------------------------------------------------------------------------------------------------

When an event listener is attached to an element, that listener is not unique for the element, but it propagates to its children.
This functionality is enabled in jQuery by adding a parameter on an event listener a parameter that targets the element that we want.
This is not case in vanillaJS, but using e.target we can inspect in which elements the event is executed.
Probably your are looking something like this. However, I would prefer to add an id in the button so you can more easily work with it.
document.addEventListener('click', function(e){
if(e.target.tagName === 'BUTTON' && e.target.classList.value.includes('btn-left')){
// execute your code
}
});

Related

How would I add a level system for the score increasing?

I am making a slight Tetris remake and I wanted to add a leveling system for when my score reaches, for example, 100, the speed that the blocks go down will also increase. How would I go about doing this? I have the entirety of the javascript code right here so please let me know what I can do to fix it:
//-------------------------------------------------------------------------
// base helper methods
//-------------------------------------------------------------------------
function get(id) { return document.getElementById(id); }
function hide(id) { get(id).style.visibility = 'hidden'; }
function show(id) { get(id).style.visibility = null; }
function html(id, html) { get(id).innerHTML = html; }
function timestamp() { return new Date().getTime(); }
function random(min, max) { return (min + (Math.random() * (max - min))); }
function randomChoice(choices) { return choices[Math.round(random(0, choices.length-1))]; }
if (!window.requestAnimationFrame) { // http://paulirish.com/2011/requestanimationframe-for-smart-animating/
window.requestAnimationFrame = window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(callback, element) {
window.setTimeout(callback, 1000 / 60);
}
}
//-------------------------------------------------------------------------
// game constants
//-------------------------------------------------------------------------
var KEY = { ESC: 27, SPACE: 32, LEFT: 37, UP: 38, RIGHT: 39, DOWN: 40 },
DIR = { UP: 0, RIGHT: 1, DOWN: 2, LEFT: 3, MIN: 0, MAX: 3 },
stats = new Stats(),
canvas = get('canvas'),
ctx = canvas.getContext('2d'),
ucanvas = get('upcoming'),
uctx = ucanvas.getContext('2d'),
speed = { start: 0.6, decrement: 0.005, min: 0.1 }, // how long before piece drops by 1 row (seconds)
nx = 10, // width of tetris court (in blocks)
ny = 20, // height of tetris court (in blocks)
nu = 5; // width/height of upcoming preview (in blocks)
//-------------------------------------------------------------------------
// game variables (initialized during reset)
//-------------------------------------------------------------------------
var dx, dy, // pixel size of a single tetris block
blocks, // 2 dimensional array (nx*ny) representing tetris court - either empty block or occupied by a 'piece'
actions, // queue of user actions (inputs)
playing, // true|false - game is in progress
dt, // time since starting this game
current, // the current piece
next, // the next piece
score, // the current score
vscore, // the currently displayed score (it catches up to score in small chunks - like a spinning slot machine)
rows, // number of completed rows in the current game
step; // how long before current piece drops by 1 row
//-------------------------------------------------------------------------
// tetris pieces
//
// blocks: each element represents a rotation of the piece (0, 90, 180, 270)
// each element is a 16 bit integer where the 16 bits represent
// a 4x4 set of blocks, e.g. j.blocks[0] = 0x44C0
//
// 0100 = 0x4 << 3 = 0x4000
// 0100 = 0x4 << 2 = 0x0400
// 1100 = 0xC << 1 = 0x00C0
// 0000 = 0x0 << 0 = 0x0000
// ------
// 0x44C0
//
//-------------------------------------------------------------------------
var i = { size: 4, blocks: [0x0F00, 0x2222, 0x00F0, 0x4444], color: 'cyan' };
var j = { size: 3, blocks: [0x44C0, 0x8E00, 0x6440, 0x0E20], color: 'blue' };
var l = { size: 3, blocks: [0x4460, 0x0E80, 0xC440, 0x2E00], color: 'orange' };
var o = { size: 2, blocks: [0xCC00, 0xCC00, 0xCC00, 0xCC00], color: 'yellow' };
var s = { size: 3, blocks: [0x06C0, 0x8C40, 0x6C00, 0x4620], color: 'lime' };
var t = { size: 3, blocks: [0x0E40, 0x4C40, 0x4E00, 0x4640], color: 'purple' };
var z = { size: 3, blocks: [0x0C60, 0x4C80, 0xC600, 0x2640], color: 'red' };
var p = { size: 3, blocks: [0x0F00, 0x2222, 0x00F0,], color: 'maroon' };
//------------------------------------------------
// do the bit manipulation and iterate through each
// occupied block (x,y) for a given piece
//------------------------------------------------
function eachblock(type, x, y, dir, fn) {
var bit, result, row = 0, col = 0, blocks = type.blocks[dir];
for(bit = 0x8000 ; bit > 0 ; bit = bit >> 1) {
if (blocks & bit) {
fn(x + col, y + row);
}
if (++col === 4) {
col = 0;
++row;
}
}
}
//-----------------------------------------------------
// check if a piece can fit into a position in the grid
//-----------------------------------------------------
function occupied(type, x, y, dir) {
var result = false
eachblock(type, x, y, dir, function(x, y) {
if ((x < 0) || (x >= nx) || (y < 0) || (y >= ny) || getBlock(x,y))
result = true;
});
return result;
}
function unoccupied(type, x, y, dir) {
return !occupied(type, x, y, dir);
}
//-----------------------------------------
// start with 4 instances of each piece and
// pick randomly until the 'bag is empty'
//-----------------------------------------
var pieces = [];
function randomPiece() {
if (pieces.length == 0)
pieces = [i,i,i,i,j,j,j,j,l,l,l,l,o,o,o,o,s,s,s,s,t,t,t,t,z,z,z,z,p,p,p,p];
var type = pieces.splice(random(0, pieces.length-1), 1)[0];
return { type: type, dir: DIR.UP, x: Math.round(random(0, nx - type.size)), y: 0 };
}
//-------------------------------------------------------------------------
// GAME LOOP
//-------------------------------------------------------------------------
function run() {
showStats(); // initialize FPS counter
addEvents(); // attach keydown and resize events
var last = now = timestamp();
function frame() {
now = timestamp();
update(Math.min(1, (now - last) / 1000.0)); // using requestAnimationFrame have to be able to handle large delta's caused when it 'hibernates' in a background or non-visible tab
draw();
stats.update();
last = now;
requestAnimationFrame(frame, canvas);
}
resize(); // setup all our sizing information
reset(); // reset the per-game variables
frame(); // start the first frame
}
function showStats() {
stats.domElement.id = 'stats';
get('menu').appendChild(stats.domElement);
}
function addEvents() {
document.addEventListener('keydown', keydown, false);
window.addEventListener('resize', resize, false);
}
function resize(event) {
canvas.width = canvas.clientWidth; // set canvas logical size equal to its physical size
canvas.height = canvas.clientHeight; // (ditto)
ucanvas.width = ucanvas.clientWidth;
ucanvas.height = ucanvas.clientHeight;
dx = canvas.width / nx; // pixel size of a single tetris block
dy = canvas.height / ny; // (ditto)
invalidate();
invalidateNext();
}
function keydown(ev) {
var handled = false;
if (playing) {
switch(ev.keyCode) {
case KEY.LEFT: actions.push(DIR.LEFT); handled = true; break;
case KEY.RIGHT: actions.push(DIR.RIGHT); handled = true; break;
case KEY.UP: actions.push(DIR.UP); handled = true; break;
case KEY.DOWN: actions.push(DIR.DOWN); handled = true; break;
case KEY.ESC: lose(); handled = true; break;
}
}
else if (ev.keyCode == KEY.SPACE) {
play();
handled = true;
}
if (handled)
ev.preventDefault(); // prevent arrow keys from scrolling the page (supported in IE9+ and all other browsers)
}
//-------------------------------------------------------------------------
// GAME LOGIC
//-------------------------------------------------------------------------
function play() { hide('start'); reset(); playing = true; }
function lose() { show('start'); setVisualScore(); playing = false; }
function setVisualScore(n) { vscore = n || score; invalidateScore(); }
function setScore(n) { score = n; setVisualScore(n); }
function addScore(n) { score = score + n; }
function clearScore() { setScore(0); }
function clearRows() { setRows(0); }
function setRows(n) { rows = n; step = Math.max(speed.min, speed.start - (speed.decrement*rows)); invalidateRows(); }
function addRows(n) { setRows(rows + n); }
function getBlock(x,y) { return (blocks && blocks[x] ? blocks[x][y] : null); }
function setBlock(x,y,type) { blocks[x] = blocks[x] || []; blocks[x][y] = type; invalidate(); }
function clearBlocks() { blocks = []; invalidate(); }
function clearActions() { actions = []; }
function setCurrentPiece(piece) { current = piece || randomPiece(); invalidate(); }
function setNextPiece(piece) { next = piece || randomPiece(); invalidateNext(); }
function reset() {
dt = 0;
clearActions();
clearBlocks();
clearRows();
clearScore();
setCurrentPiece(next);
setNextPiece();
}
function update(idt) {
if (playing) {
if (vscore < score)
setVisualScore(vscore + 1);
handle(actions.shift());
dt = dt + idt;
if (dt > step) {
dt = dt - step;
drop();
}
}
}
function handle(action) {
switch(action) {
case DIR.LEFT: move(DIR.LEFT); break;
case DIR.RIGHT: move(DIR.RIGHT); break;
case DIR.UP: rotate(); break;
case DIR.DOWN: drop(); break;
}
}
function move(dir) {
var x = current.x, y = current.y;
switch(dir) {
case DIR.RIGHT: x = x + 1; break;
case DIR.LEFT: x = x - 1; break;
case DIR.DOWN: y = y + 1; break;
}
if (unoccupied(current.type, x, y, current.dir)) {
current.x = x;
current.y = y;
invalidate();
return true;
}
else {
return false;
}
}
function rotate() {
var newdir = (current.dir == DIR.MAX ? DIR.MIN : current.dir + 1);
if (unoccupied(current.type, current.x, current.y, newdir)) {
current.dir = newdir;
invalidate();
}
}
//This is how we make the piece drop down and place:
function drop() {
if (!move(DIR.DOWN)) {
addScore(10);
dropPiece();
removeLines();
setCurrentPiece(next);
setNextPiece(randomPiece());
clearActions();
if (occupied(current.type, current.x, current.y, current.dir)) {
lose();
}
}
}
function dropPiece() {
eachblock(current.type, current.x, current.y, current.dir, function(x, y) {
setBlock(x, y, current.type);
});
}
function removeLines() {
var x, y, complete, n = 0;
for(y = ny ; y > 0 ; --y) {
complete = true;
for(x = 0 ; x < nx ; ++x) {
if (!getBlock(x, y))
complete = false;
}
if (complete) {
removeLine(y);
y = y + 1; // recheck same line
n++;
}
}
if (n > 0) {
addRows(n);
addScore(100*Math.pow(2,n-1)); // 1: 100, 2: 200, 3: 400, 4: 800
}
}
function removeLine(n) {
var x, y;
for(y = n ; y >= 0 ; --y) {
for(x = 0 ; x < nx ; ++x)
setBlock(x, y, (y == 0) ? null : getBlock(x, y-1));
}
}
//-------------------------------------------------------------------------
// RENDERING
//-------------------------------------------------------------------------
var invalid = {};
function invalidate() { invalid.court = true; }
function invalidateNext() { invalid.next = true; }
function invalidateScore() { invalid.score = true; }
function invalidateRows() { invalid.rows = true; }
function draw() {
ctx.save();
ctx.lineWidth = 1;
ctx.translate(0.5, 0.5); // for crisp 1px black lines
drawCourt();
drawNext();
drawScore();
drawRows();
ctx.restore();
}
function drawCourt() {
if (invalid.court) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
if (playing)
drawPiece(ctx, current.type, current.x, current.y, current.dir);
var x, y, block;
for(y = 0 ; y < ny ; y++) {
for (x = 0 ; x < nx ; x++) {
if (block = getBlock(x,y))
drawBlock(ctx, x, y, block.color);
}
}
ctx.strokeRect(0, 0, nx*dx - 1, ny*dy - 1); // court boundary
invalid.court = false;
}
}
function drawNext() {
if (invalid.next) {
var padding = (nu - next.type.size) / 2; // half-complete attempt at centering next piece display
uctx.save();
uctx.translate(0.5, 0.5);
uctx.clearRect(0, 0, nu*dx, nu*dy);
drawPiece(uctx, next.type, padding, padding, next.dir);
uctx.strokeStyle = 'black';
uctx.strokeRect(0, 0, nu*dx - 1, nu*dy - 1);
uctx.restore();
invalid.next = false;
}
}
function drawScore() {
if (invalid.score) {
html('score', ("00000" + Math.floor(vscore)).slice(-5));
invalid.score = false;
}
}
function drawRows() {
if (invalid.rows) {
html('rows', rows);
invalid.rows = false;
}
}
function drawPiece(ctx, type, x, y, dir) {
eachblock(type, x, y, dir, function(x, y) {
drawBlock(ctx, x, y, type.color);
});
}
function drawBlock(ctx, x, y, color) {
ctx.fillStyle = color;
ctx.fillRect(x*dx, y*dy, dx, dy);
ctx.strokeRect(x*dx, y*dy, dx, dy)
}
//-------------------------------------------------------------------------
// FINALLY, lets run the game
//-------------------------------------------------------------------------
run();
You have a function called addScore that seems to be used to update the user's score. You could add a conditional block inside this function that will update the game speed when the new score is above the threshold you choose. Alternatively, if you would prefer to keep addScore purely focused on updating the value of the score, you could add this conditional block wherever you're calling addScore.

Letter tracing game with javascript

I want to create game like this. But I have some problem with painting SVG inside canvas. Initially I try to create levels with vanilla js (I use only vuejs), but I got a lot of bugs (I show my code below). After that I try p5js library, but I didn't found how I can fill my SVG with animation. I try to use pixijs, but it so big framework. Also I did not find a solution with createjs library. I'm tired of wasting time looking, can anyone advise me on a framework suitable for my task.
My vanilla code:
new class Game {
constructor() {
this.c = document.querySelector('canvas')
this.cx = this.c.getContext('2d')
this.init()
this.c.addEventListener('mousedown', this.onmousedown, false);
this.c.addEventListener('mouseup', this.onmouseup, false);
this.c.addEventListener('mousemove', this.onmousemove.bind(this), false);
}
init () {
this.c.height = 480;
this.c.width = 320;
this.cx.strokeStyle = 'rgb(0, 0, 50)';
this.drawletter('5');
this.pixels = this.cx.getImageData(0, 0, this.c.width, this.c.height);
this.letterpixels = this.getpixelamount(255, 0, 0);
}
pixelthreshold() {
if (this.getpixelamount(0, 0, 50) / this.letterpixels > 0.35) {
console.log('you got it!');
}
}
showerror(error) {
this.mousedown = false;
console.log(error)
}
getpixelcolour(x, y) {
const index = ((y * (this.pixels.width * 4)) + (x * 4));
return {
r: this.pixels.data[index],
g: this.pixels.data[index + 1],
b: this.pixels.data[index + 2],
a: this.pixels.data[index + 3]
};
}
paint(x, y) {
const colour = this.getpixelcolour(x, y);
if (colour.a === 0) {
this.showerror('you are outside');
} else {
this.cx.beginPath();
if ((this.oldx > 0 && this.oldy > 0) &&
(Math.abs(this.oldx - x) < this.cx.lineWidth / 2 && Math.abs(this.oldy - y) < this.cx.lineWidth / 2)) {
this.cx.moveTo(this.oldx, this.oldy);
}
this.cx.lineTo(x, y);
this.cx.stroke();
this.cx.closePath();
this.oldx = x;
this.oldy = y;
}
}
onmousedown(ev) {
this.mousedown = true;
ev.preventDefault();
}
onmouseup(ev) {
this.mousedown = false;
this.pixelthreshold();
ev.preventDefault();
}
onmousemove(e) {
const x = Math.round(e.clientX - this.c.getBoundingClientRect().left);
const y = Math.round(e.clientY - this.c.getBoundingClientRect().top);
// const x = ev.clientX;
// const y = ev.clientY;
if (this.mousedown) {
this.paint(x, y);
}
}
getpixelamount(r, g, b) {
const pixels = this.cx.getImageData(0, 0, this.c.width, this.c.height);
const all = pixels.data.length;
let amount = 0;
for (let i = 0; i < all; i += 4) {
if (pixels.data[i] === r &&
pixels.data[i + 1] === g &&
pixels.data[i + 2] === b) {
amount++;
}
}
return amount;
}
drawletter(letter) {
const centerx = (this.c.width - this.cx.measureText(letter).width) / 2;
const centery = this.c.height / 2;
// this.cx.fillText(letter, centerx, centery);
// debugger
const path = new Path2D('M60.4248047,180.541992 C73.445638,180.541992 84.9405924,177.693685 94.909668,171.99707 C104.878743,166.300456 112.508138,158.610026 117.797852,148.925781 C123.087565,139.241536 125.732422,128.499349 125.732422,116.699219 C125.732422,108.561198 124.267578,100.952148 121.337891,93.8720703 C118.408203,86.7919922 114.379883,80.6681315 109.25293,75.5004883 C104.125977,70.3328451 98.1648763,66.2841797 91.3696289,63.3544922 C84.5743815,60.4248047 77.2705078,58.9599609 69.4580078,58.9599609 C59.6923828,58.9599609 49.0315755,62.0524089 37.4755859,68.2373047 L37.4755859,68.2373047 L44.4335938,28.6865234 L102.416992,28.6865234 C108.439128,28.6865234 112.996419,27.3844401 116.088867,24.7802734 C119.181315,22.1761068 120.727539,18.758138 120.727539,14.5263672 C120.727539,4.8421224 114.379883,0 101.68457,0 L101.68457,0 L37.2314453,0 C30.2327474,0 25.1871745,1.58691406 22.0947266,4.76074219 C19.0022786,7.93457031 16.8863932,13.0208333 15.7470703,20.0195312 L15.7470703,20.0195312 L5.49316406,78.4912109 C4.59798177,83.6181641 4.15039062,86.3850911 4.15039062,86.7919922 C4.15039062,90.4541016 5.69661458,93.7296549 8.7890625,96.6186523 C11.8815104,99.5076497 15.4215495,100.952148 19.4091797,100.952148 C23.0712891,100.952148 27.730306,98.815918 33.3862305,94.543457 C39.0421549,90.2709961 43.375651,87.2802734 46.3867188,85.5712891 C49.3977865,83.8623047 54.4026693,83.0078125 61.4013672,83.0078125 C67.0979818,83.0078125 72.265625,84.370931 76.9042969,87.097168 C81.5429688,89.8234049 85.2457682,93.9534505 88.0126953,99.4873047 C90.7796224,105.021159 92.1630859,111.694336 92.1630859,119.506836 C92.1630859,126.749674 90.8813477,133.219401 88.3178711,138.916016 C85.7543945,144.61263 82.1126302,149.088542 77.3925781,152.34375 C72.672526,155.598958 67.179362,157.226562 60.9130859,157.226562 C54.0771484,157.226562 47.8922526,155.212402 42.3583984,151.184082 C36.8245443,147.155762 32.430013,141.520182 29.1748047,134.277344 C25.8382161,126.383464 20.7519531,122.436523 13.9160156,122.436523 C9.92838542,122.436523 6.61214193,123.860677 3.96728516,126.708984 C1.32242839,129.557292 0,132.568359 0,135.742188 C0,140.950521 1.89208984,147.033691 5.67626953,153.991699 C9.46044922,160.949707 15.8894857,167.114258 24.9633789,172.485352 C34.0372721,177.856445 45.8577474,180.541992 60.4248047,180.541992 Z');
this.cx.translate(centerx, centery);
this.cx.stroke(path);
}
}
<canvas id=canvas></canvas>
I update my code, not problem insert SVG in canvas. I don't understand how to fill this by touch with animation like in example game.
new class Game {
constructor() {
this.c = document.querySelector('canvas')
this.cx = this.c.getContext('2d')
this.init()
this.c.addEventListener('mousedown', this.onmousedown.bind(this), false);
this.c.addEventListener('mouseup', this.onmouseup.bind(this), false);
this.c.addEventListener('mousemove', this.onmousemove.bind(this), false);
}
init() {
this.c.height = 190;
this.c.width = 140;
this.cx.fillStyle = 'rgb(200, 200, 250)';
this.drawletter('5');
this.cx.fillStyle = 'rgb(0, 0, 50)';
this.letterpixels = this.getpixelamount(200, 200, 250);
}
pixelthreshold() {
if (this.getpixelamount(0, 0, 50) / this.letterpixels > 0.75) {
console.log('you got it!');
}
}
showerror(error) {
this.mousedown = false;
console.log(error)
}
getpixelcolour(x, y) {
const pixels = this.cx.getImageData(0, 0, this.c.width, this.c.height);
const index = ((y * (pixels.width * 4)) + (x * 4));
return {
r: pixels.data[index],
g: pixels.data[index + 1],
b: pixels.data[index + 2],
a: pixels.data[index + 3]
};
}
paint(x, y) {
const colour = this.getpixelcolour(x, y);
if (colour.a === 0) {
this.showerror('you are outside');
} else {
const fillRange = 20;
const stack = [[x, y]];
while (stack.length > 0) {
const pixel = stack.pop();
if (pixel[0] < 0 || pixel[0] >= this.c.width) continue;
if (pixel[1] < 0 || pixel[1] >= this.c.height) continue;
if(((x - pixel[0]) ** 2 + (y - pixel[1]) ** 2) ** .5 > fillRange) continue;
const color = this.getpixelcolour(...pixel);
if (color.a === 0) continue;
if (color.r === 0 && color.g === 0 && color.b === 50) continue;
this.cx.fillRect(pixel[0], pixel[1], 1, 1);
if(pixel[0] >= x) stack.push([pixel[0] + 1, pixel[1]]);
if(pixel[0] <= x) stack.push([pixel[0] - 1, pixel[1]]);
if(pixel[1] >= y) stack.push([pixel[0], pixel[1] + 1]);
if(pixel[1] <= y) stack.push([pixel[0], pixel[1] - 1]);
}
}
}
onmousedown(ev) {
this.mousedown = true;
ev.preventDefault();
}
onmouseup(ev) {
this.mousedown = false;
this.pixelthreshold();
ev.preventDefault();
}
onmousemove(e) {
const x = Math.round(e.clientX - this.c.getBoundingClientRect().left);
const y = Math.round(e.clientY - this.c.getBoundingClientRect().top);
if (this.mousedown) {
this.paint(x, y);
} else {
// console.log(this.getpixelcolour(x, y));
}
}
getpixelamount(r, g, b) {
const pixels = this.cx.getImageData(0, 0, this.c.width, this.c.height);
const all = pixels.data.length;
let amount = 0;
for (let i = 0; i < all; i += 4) {
if (pixels.data[i] === r && pixels.data[i + 1] === g && pixels.data[i + 2] === b) {
amount++;
}
}
return amount;
}
drawletter(letter) {
const path = new Path2D('M60.4248047,180.541992 C73.445638,180.541992 84.9405924,177.693685 94.909668,171.99707 C104.878743,166.300456 112.508138,158.610026 117.797852,148.925781 C123.087565,139.241536 125.732422,128.499349 125.732422,116.699219 C125.732422,108.561198 124.267578,100.952148 121.337891,93.8720703 C118.408203,86.7919922 114.379883,80.6681315 109.25293,75.5004883 C104.125977,70.3328451 98.1648763,66.2841797 91.3696289,63.3544922 C84.5743815,60.4248047 77.2705078,58.9599609 69.4580078,58.9599609 C59.6923828,58.9599609 49.0315755,62.0524089 37.4755859,68.2373047 L37.4755859,68.2373047 L44.4335938,28.6865234 L102.416992,28.6865234 C108.439128,28.6865234 112.996419,27.3844401 116.088867,24.7802734 C119.181315,22.1761068 120.727539,18.758138 120.727539,14.5263672 C120.727539,4.8421224 114.379883,0 101.68457,0 L101.68457,0 L37.2314453,0 C30.2327474,0 25.1871745,1.58691406 22.0947266,4.76074219 C19.0022786,7.93457031 16.8863932,13.0208333 15.7470703,20.0195312 L15.7470703,20.0195312 L5.49316406,78.4912109 C4.59798177,83.6181641 4.15039062,86.3850911 4.15039062,86.7919922 C4.15039062,90.4541016 5.69661458,93.7296549 8.7890625,96.6186523 C11.8815104,99.5076497 15.4215495,100.952148 19.4091797,100.952148 C23.0712891,100.952148 27.730306,98.815918 33.3862305,94.543457 C39.0421549,90.2709961 43.375651,87.2802734 46.3867188,85.5712891 C49.3977865,83.8623047 54.4026693,83.0078125 61.4013672,83.0078125 C67.0979818,83.0078125 72.265625,84.370931 76.9042969,87.097168 C81.5429688,89.8234049 85.2457682,93.9534505 88.0126953,99.4873047 C90.7796224,105.021159 92.1630859,111.694336 92.1630859,119.506836 C92.1630859,126.749674 90.8813477,133.219401 88.3178711,138.916016 C85.7543945,144.61263 82.1126302,149.088542 77.3925781,152.34375 C72.672526,155.598958 67.179362,157.226562 60.9130859,157.226562 C54.0771484,157.226562 47.8922526,155.212402 42.3583984,151.184082 C36.8245443,147.155762 32.430013,141.520182 29.1748047,134.277344 C25.8382161,126.383464 20.7519531,122.436523 13.9160156,122.436523 C9.92838542,122.436523 6.61214193,123.860677 3.96728516,126.708984 C1.32242839,129.557292 0,132.568359 0,135.742188 C0,140.950521 1.89208984,147.033691 5.67626953,153.991699 C9.46044922,160.949707 15.8894857,167.114258 24.9633789,172.485352 C34.0372721,177.856445 45.8577474,180.541992 60.4248047,180.541992 Z');
this.cx.fill(path);
}
}
<canvas id=canvas></canvas>
const ctx = canvas.getContext('2d');
canvas.width = 400;
canvas.height = 300;
const svg = new Image();
svg.onload = () => ctx.drawImage(svg, 0, 0);
svg.src = "http://graphing.ru/examples/butterfly.svg";
<canvas id=canvas></canvas>

Two signature pads in one form

I want to implement two signature pads in ONE form. One signature is for the applicant and the other one is for the evaluator.
The first pad works but the second pad is unresponsive. I am using JavaScript for the signature pads but it only works for the first pad. The signature will be saved to the database when the submit button is clicked. That is why id="save-signature-btn" is together with the code for the 'Submit' button.
form.blade.php
#extends('layouts.app')
#section('content')
<!doctype html>
<html lang="en">
<head>
</head>
<body>
{!! Form::open(['url' => 'page3/submit']) !!}
<h4 style="text-decoration: underline; font-weight: bold">Approved By:</h4>
<table class="table table-bordered">
<tr>
<th colspan="3">Approved By:</th>
</tr>
<tr>
<th colspan="1">Name</th>
<th colspan="1">Signature</th>
<th colspan="1">Date</th>
</tr>
<tr colspan=4>
<td colspan="1">
<div class="form-group">
{{Form::text('Officer_Name', '', ['class' => 'form-control', 'placeholder' => 'John Smith'])}}
</div>
</td>
<td colspan="1">
<div class="form-group">
<canvas id="signature-canvas" style="width:375px;height:150px;max-width:100%;border:8px #CCC solid;background-color: white;"></canvas>
<div id="signature-message"></div>
<div id="signature-buttons">
<input type="button" id="clear-signature-btn" value="Clear">
</div>
<input type="hidden" name="officer_signature" id="signature-data" value="">
</div>
</td>
<td>
<div class="form-group">
{{Form::date('Approval_Date', '', ['class' => 'form-control'])}}
</div>
</td>
</tr>
</table>
<br/>
<h4 style="text-decoration: underline; font-weight: bold">Applicant Signature:</h4>
<div class="form-group">
<canvas id="signature-canvas2" style="width:375px;height:150px;max-width:100%;border:8px #CCC solid;background-color: white;"></canvas>
<div id="signature-message2"></div>
<div id="signature-buttons2">
<input type="button" id="clear-signature-btn2" value="Clear">
</div>
<input type="hidden" name="applicant_signature" id="signature-data2" value="">
</div>
<br>
<div class="signature_pad_save">
<button type="submit" class="btn btn-primary" id="save-signature-btn">Submit</button>
</div>
<script src="js/signature_pad.js"></script>
<script src="js/signature_data.js"></script>
</body>
</html>
#endsection('content')
signature data.js
var clearButton = document.getElementById('clear-signature-btn'),
saveButton = document.getElementById('save-signature-btn'),
canvas = document.getElementById('signature-canvas'),
signaturePad;
function resizeCanvas() {
var ratio = Math.max(window.devicePixelRatio || 1, 1);
canvas.width = canvas.offsetWidth * ratio;
canvas.height = canvas.offsetHeight * ratio;
canvas.getContext("2d").scale(ratio, ratio);
}
window.onresize = resizeCanvas;
resizeCanvas();
signaturePad = new SignaturePad(canvas);
clearButton.addEventListener('click', function (event) {
signaturePad.clear();
});
saveButton.addEventListener('click', function (event) {
if (signaturePad.isEmpty()) {
alert('Signature pad is blank. Please draw your signature.');
} else {
var sdata = signaturePad.toDataURL();
document.getElementById('signature-data').value = sdata;
document.getElementById('signature-form').submit();
}
});
signature pad.js
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global.SignaturePad = factory());
}(this, (function () { 'use strict';
function Point(x, y, time) {
this.x = x;
this.y = y;
this.time = time || new Date().getTime();
}
Point.prototype.velocityFrom = function (start) {
return this.time !== start.time ? this.distanceTo(start) / (this.time - start.time) : 1;
};
Point.prototype.distanceTo = function (start) {
return Math.sqrt(Math.pow(this.x - start.x, 2) + Math.pow(this.y - start.y, 2));
};
Point.prototype.equals = function (other) {
return this.x === other.x && this.y === other.y && this.time === other.time;
};
function Bezier(startPoint, control1, control2, endPoint) {
this.startPoint = startPoint;
this.control1 = control1;
this.control2 = control2;
this.endPoint = endPoint;
}
// Returns approximated length.
Bezier.prototype.length = function () {
var steps = 10;
var length = 0;
var px = void 0;
var py = void 0;
for (var i = 0; i <= steps; i += 1) {
var t = i / steps;
var cx = this._point(t, this.startPoint.x, this.control1.x, this.control2.x, this.endPoint.x);
var cy = this._point(t, this.startPoint.y, this.control1.y, this.control2.y, this.endPoint.y);
if (i > 0) {
var xdiff = cx - px;
var ydiff = cy - py;
length += Math.sqrt(xdiff * xdiff + ydiff * ydiff);
}
px = cx;
py = cy;
}
return length;
};
/* eslint-disable no-multi-spaces, space-in-parens */
Bezier.prototype._point = function (t, start, c1, c2, end) {
return start * (1.0 - t) * (1.0 - t) * (1.0 - t) + 3.0 * c1 * (1.0 - t) * (1.0 - t) * t + 3.0 * c2 * (1.0 - t) * t * t + end * t * t * t;
};
/* eslint-disable */
// http://stackoverflow.com/a/27078401/815507
function throttle(func, wait, options) {
var context, args, result;
var timeout = null;
var previous = 0;
if (!options) options = {};
var later = function later() {
previous = options.leading === false ? 0 : Date.now();
timeout = null;
result = func.apply(context, args);
if (!timeout) context = args = null;
};
return function () {
var now = Date.now();
if (!previous && options.leading === false) previous = now;
var remaining = wait - (now - previous);
context = this;
args = arguments;
if (remaining <= 0 || remaining > wait) {
if (timeout) {
clearTimeout(timeout);
timeout = null;
}
previous = now;
result = func.apply(context, args);
if (!timeout) context = args = null;
} else if (!timeout && options.trailing !== false) {
timeout = setTimeout(later, remaining);
}
return result;
};
}
function SignaturePad(canvas, options) {
var self = this;
var opts = options || {};
this.velocityFilterWeight = opts.velocityFilterWeight || 0.7;
this.minWidth = opts.minWidth || 0.5;
this.maxWidth = opts.maxWidth || 2.5;
this.throttle = 'throttle' in opts ? opts.throttle : 16; // in miliseconds
this.minDistance = 'minDistance' in opts ? opts.minDistance : 5;
if (this.throttle) {
this._strokeMoveUpdate = throttle(SignaturePad.prototype._strokeUpdate, this.throttle);
} else {
this._strokeMoveUpdate = SignaturePad.prototype._strokeUpdate;
}
this.dotSize = opts.dotSize || function () {
return (this.minWidth + this.maxWidth) / 2;
};
this.penColor = opts.penColor || 'black';
this.backgroundColor = opts.backgroundColor || 'rgba(0,0,0,0)';
this.onBegin = opts.onBegin;
this.onEnd = opts.onEnd;
this._canvas = canvas;
this._ctx = canvas.getContext('2d');
this.clear();
// We need add these inline so they are available to unbind while still having
// access to 'self' we could use _.bind but it's not worth adding a dependency.
this._handleMouseDown = function (event) {
if (event.which === 1) {
self._mouseButtonDown = true;
self._strokeBegin(event);
}
};
this._handleMouseMove = function (event) {
if (self._mouseButtonDown) {
self._strokeMoveUpdate(event);
}
};
this._handleMouseUp = function (event) {
if (event.which === 1 && self._mouseButtonDown) {
self._mouseButtonDown = false;
self._strokeEnd(event);
}
};
this._handleTouchStart = function (event) {
if (event.targetTouches.length === 1) {
var touch = event.changedTouches[0];
self._strokeBegin(touch);
}
};
this._handleTouchMove = function (event) {
// Prevent scrolling.
event.preventDefault();
var touch = event.targetTouches[0];
self._strokeMoveUpdate(touch);
};
this._handleTouchEnd = function (event) {
var wasCanvasTouched = event.target === self._canvas;
if (wasCanvasTouched) {
event.preventDefault();
self._strokeEnd(event);
}
};
// Enable mouse and touch event handlers
this.on();
}
// Public methods
SignaturePad.prototype.clear = function () {
var ctx = this._ctx;
var canvas = this._canvas;
ctx.fillStyle = this.backgroundColor;
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillRect(0, 0, canvas.width, canvas.height);
this._data = [];
this._reset();
this._isEmpty = true;
};
SignaturePad.prototype.fromDataURL = function (dataUrl) {
var _this = this;
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var image = new Image();
var ratio = options.ratio || window.devicePixelRatio || 1;
var width = options.width || this._canvas.width / ratio;
var height = options.height || this._canvas.height / ratio;
this._reset();
image.src = dataUrl;
image.onload = function () {
_this._ctx.drawImage(image, 0, 0, width, height);
};
this._isEmpty = false;
};
SignaturePad.prototype.toDataURL = function (type) {
var _canvas;
switch (type) {
case 'image/svg+xml':
return this._toSVG();
default:
for (var _len = arguments.length, options = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
options[_key - 1] = arguments[_key];
}
return (_canvas = this._canvas).toDataURL.apply(_canvas, [type].concat(options));
}
};
SignaturePad.prototype.on = function () {
this._handleMouseEvents();
this._handleTouchEvents();
};
SignaturePad.prototype.off = function () {
this._canvas.removeEventListener('mousedown', this._handleMouseDown);
this._canvas.removeEventListener('mousemove', this._handleMouseMove);
document.removeEventListener('mouseup', this._handleMouseUp);
this._canvas.removeEventListener('touchstart', this._handleTouchStart);
this._canvas.removeEventListener('touchmove', this._handleTouchMove);
this._canvas.removeEventListener('touchend', this._handleTouchEnd);
};
SignaturePad.prototype.isEmpty = function () {
return this._isEmpty;
};
// Private methods
SignaturePad.prototype._strokeBegin = function (event) {
this._data.push([]);
this._reset();
this._strokeUpdate(event);
if (typeof this.onBegin === 'function') {
this.onBegin(event);
}
};
SignaturePad.prototype._strokeUpdate = function (event) {
var x = event.clientX;
var y = event.clientY;
var point = this._createPoint(x, y);
var lastPointGroup = this._data[this._data.length - 1];
var lastPoint = lastPointGroup && lastPointGroup[lastPointGroup.length - 1];
var isLastPointTooClose = lastPoint && point.distanceTo(lastPoint) < this.minDistance;
// Skip this point if it's too close to the previous one
if (!(lastPoint && isLastPointTooClose)) {
var _addPoint = this._addPoint(point),
curve = _addPoint.curve,
widths = _addPoint.widths;
if (curve && widths) {
this._drawCurve(curve, widths.start, widths.end);
}
this._data[this._data.length - 1].push({
x: point.x,
y: point.y,
time: point.time,
color: this.penColor
});
}
};
SignaturePad.prototype._strokeEnd = function (event) {
var canDrawCurve = this.points.length > 2;
var point = this.points[0]; // Point instance
if (!canDrawCurve && point) {
this._drawDot(point);
}
if (point) {
var lastPointGroup = this._data[this._data.length - 1];
var lastPoint = lastPointGroup[lastPointGroup.length - 1]; // plain object
// When drawing a dot, there's only one point in a group, so without this check
// such group would end up with exactly the same 2 points.
if (!point.equals(lastPoint)) {
lastPointGroup.push({
x: point.x,
y: point.y,
time: point.time,
color: this.penColor
});
}
}
if (typeof this.onEnd === 'function') {
this.onEnd(event);
}
};
SignaturePad.prototype._handleMouseEvents = function () {
this._mouseButtonDown = false;
this._canvas.addEventListener('mousedown', this._handleMouseDown);
this._canvas.addEventListener('mousemove', this._handleMouseMove);
document.addEventListener('mouseup', this._handleMouseUp);
};
SignaturePad.prototype._handleTouchEvents = function () {
// Pass touch events to canvas element on mobile IE11 and Edge.
this._canvas.style.msTouchAction = 'none';
this._canvas.style.touchAction = 'none';
this._canvas.addEventListener('touchstart', this._handleTouchStart);
this._canvas.addEventListener('touchmove', this._handleTouchMove);
this._canvas.addEventListener('touchend', this._handleTouchEnd);
};
SignaturePad.prototype._reset = function () {
this.points = [];
this._lastVelocity = 0;
this._lastWidth = (this.minWidth + this.maxWidth) / 2;
this._ctx.fillStyle = this.penColor;
};
SignaturePad.prototype._createPoint = function (x, y, time) {
var rect = this._canvas.getBoundingClientRect();
return new Point(x - rect.left, y - rect.top, time || new Date().getTime());
};
SignaturePad.prototype._addPoint = function (point) {
var points = this.points;
var tmp = void 0;
points.push(point);
if (points.length > 2) {
// To reduce the initial lag make it work with 3 points
// by copying the first point to the beginning.
if (points.length === 3) points.unshift(points[0]);
tmp = this._calculateCurveControlPoints(points[0], points[1], points[2]);
var c2 = tmp.c2;
tmp = this._calculateCurveControlPoints(points[1], points[2], points[3]);
var c3 = tmp.c1;
var curve = new Bezier(points[1], c2, c3, points[2]);
var widths = this._calculateCurveWidths(curve);
// Remove the first element from the list,
// so that we always have no more than 4 points in points array.
points.shift();
return { curve: curve, widths: widths };
}
return {};
};
SignaturePad.prototype._calculateCurveControlPoints = function (s1, s2, s3) {
var dx1 = s1.x - s2.x;
var dy1 = s1.y - s2.y;
var dx2 = s2.x - s3.x;
var dy2 = s2.y - s3.y;
var m1 = { x: (s1.x + s2.x) / 2.0, y: (s1.y + s2.y) / 2.0 };
var m2 = { x: (s2.x + s3.x) / 2.0, y: (s2.y + s3.y) / 2.0 };
var l1 = Math.sqrt(dx1 * dx1 + dy1 * dy1);
var l2 = Math.sqrt(dx2 * dx2 + dy2 * dy2);
var dxm = m1.x - m2.x;
var dym = m1.y - m2.y;
var k = l2 / (l1 + l2);
var cm = { x: m2.x + dxm * k, y: m2.y + dym * k };
var tx = s2.x - cm.x;
var ty = s2.y - cm.y;
return {
c1: new Point(m1.x + tx, m1.y + ty),
c2: new Point(m2.x + tx, m2.y + ty)
};
};
SignaturePad.prototype._calculateCurveWidths = function (curve) {
var startPoint = curve.startPoint;
var endPoint = curve.endPoint;
var widths = { start: null, end: null };
var velocity = this.velocityFilterWeight * endPoint.velocityFrom(startPoint) + (1 - this.velocityFilterWeight) * this._lastVelocity;
var newWidth = this._strokeWidth(velocity);
widths.start = this._lastWidth;
widths.end = newWidth;
this._lastVelocity = velocity;
this._lastWidth = newWidth;
return widths;
};
SignaturePad.prototype._strokeWidth = function (velocity) {
return Math.max(this.maxWidth / (velocity + 1), this.minWidth);
};
SignaturePad.prototype._drawPoint = function (x, y, size) {
var ctx = this._ctx;
ctx.moveTo(x, y);
ctx.arc(x, y, size, 0, 2 * Math.PI, false);
this._isEmpty = false;
};
SignaturePad.prototype._drawCurve = function (curve, startWidth, endWidth) {
var ctx = this._ctx;
var widthDelta = endWidth - startWidth;
var drawSteps = Math.floor(curve.length());
ctx.beginPath();
for (var i = 0; i < drawSteps; i += 1) {
// Calculate the Bezier (x, y) coordinate for this step.
var t = i / drawSteps;
var tt = t * t;
var ttt = tt * t;
var u = 1 - t;
var uu = u * u;
var uuu = uu * u;
var x = uuu * curve.startPoint.x;
x += 3 * uu * t * curve.control1.x;
x += 3 * u * tt * curve.control2.x;
x += ttt * curve.endPoint.x;
var y = uuu * curve.startPoint.y;
y += 3 * uu * t * curve.control1.y;
y += 3 * u * tt * curve.control2.y;
y += ttt * curve.endPoint.y;
var width = startWidth + ttt * widthDelta;
this._drawPoint(x, y, width);
}
ctx.closePath();
ctx.fill();
};
SignaturePad.prototype._drawDot = function (point) {
var ctx = this._ctx;
var width = typeof this.dotSize === 'function' ? this.dotSize() : this.dotSize;
ctx.beginPath();
this._drawPoint(point.x, point.y, width);
ctx.closePath();
ctx.fill();
};
SignaturePad.prototype._fromData = function (pointGroups, drawCurve, drawDot) {
for (var i = 0; i < pointGroups.length; i += 1) {
var group = pointGroups[i];
if (group.length > 1) {
for (var j = 0; j < group.length; j += 1) {
var rawPoint = group[j];
var point = new Point(rawPoint.x, rawPoint.y, rawPoint.time);
var color = rawPoint.color;
if (j === 0) {
// First point in a group. Nothing to draw yet.
// All points in the group have the same color, so it's enough to set
// penColor just at the beginning.
this.penColor = color;
this._reset();
this._addPoint(point);
} else if (j !== group.length - 1) {
// Middle point in a group.
var _addPoint2 = this._addPoint(point),
curve = _addPoint2.curve,
widths = _addPoint2.widths;
if (curve && widths) {
drawCurve(curve, widths, color);
}
} else {
// Last point in a group. Do nothing.
}
}
} else {
this._reset();
var _rawPoint = group[0];
drawDot(_rawPoint);
}
}
};
SignaturePad.prototype._toSVG = function () {
var _this2 = this;
var pointGroups = this._data;
var canvas = this._canvas;
var ratio = Math.max(window.devicePixelRatio || 1, 1);
var minX = 0;
var minY = 0;
var maxX = canvas.width / ratio;
var maxY = canvas.height / ratio;
var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
svg.setAttributeNS(null, 'width', canvas.width);
svg.setAttributeNS(null, 'height', canvas.height);
this._fromData(pointGroups, function (curve, widths, color) {
var path = document.createElement('path');
// Need to check curve for NaN values, these pop up when drawing
// lines on the canvas that are not continuous. E.g. Sharp corners
// or stopping mid-stroke and than continuing without lifting mouse.
if (!isNaN(curve.control1.x) && !isNaN(curve.control1.y) && !isNaN(curve.control2.x) && !isNaN(curve.control2.y)) {
var attr = 'M ' + curve.startPoint.x.toFixed(3) + ',' + curve.startPoint.y.toFixed(3) + ' ' + ('C ' + curve.control1.x.toFixed(3) + ',' + curve.control1.y.toFixed(3) + ' ') + (curve.control2.x.toFixed(3) + ',' + curve.control2.y.toFixed(3) + ' ') + (curve.endPoint.x.toFixed(3) + ',' + curve.endPoint.y.toFixed(3));
path.setAttribute('d', attr);
path.setAttribute('stroke-width', (widths.end * 2.25).toFixed(3));
path.setAttribute('stroke', color);
path.setAttribute('fill', 'none');
path.setAttribute('stroke-linecap', 'round');
svg.appendChild(path);
}
}, function (rawPoint) {
var circle = document.createElement('circle');
var dotSize = typeof _this2.dotSize === 'function' ? _this2.dotSize() : _this2.dotSize;
circle.setAttribute('r', dotSize);
circle.setAttribute('cx', rawPoint.x);
circle.setAttribute('cy', rawPoint.y);
circle.setAttribute('fill', rawPoint.color);
svg.appendChild(circle);
});
var prefix = 'data:image/svg+xml;base64,';
var header = '<svg' + ' xmlns="http://www.w3.org/2000/svg"' + ' xmlns:xlink="http://www.w3.org/1999/xlink"' + (' viewBox="' + minX + ' ' + minY + ' ' + maxX + ' ' + maxY + '"') + (' width="' + maxX + '"') + (' height="' + maxY + '"') + '>';
var body = svg.innerHTML;
// IE hack for missing innerHTML property on SVGElement
if (body === undefined) {
var dummy = document.createElement('dummy');
var nodes = svg.childNodes;
dummy.innerHTML = '';
for (var i = 0; i < nodes.length; i += 1) {
dummy.appendChild(nodes[i].cloneNode(true));
}
body = dummy.innerHTML;
}
var footer = '</svg>';
var data = header + body + footer;
return prefix + btoa(data);
};
SignaturePad.prototype.fromData = function (pointGroups) {
var _this3 = this;
this.clear();
this._fromData(pointGroups, function (curve, widths) {
return _this3._drawCurve(curve, widths.start, widths.end);
}, function (rawPoint) {
return _this3._drawDot(rawPoint);
});
this._data = pointGroups;
};
SignaturePad.prototype.toData = function () {
return this._data;
};
return SignaturePad;
})));
In your javascript code you are working only with
canvas = document.getElementById('signature-canvas')
So that is the problem.
You should add a class on both signature canvases in html code for example signature like this:
<canvas id="signature-canvas" class="signature" style="width:375px;height:150px;max-width:100%;border:8px #CCC solid;background-color: white;"></canvas>
<canvas id="signature-canvas2" class="signature" style="width:375px;height:150px;max-width:100%;border:8px #CCC solid;background-color: white;"></canvas>
And then in javascript add one more pair of commands for second signature pad for control buttons (submit and reset) for second canvas.

Game Collision-detection FIX

I am making a game where it's about clicking on the nearest yellow dot from the green dot.
I got a list named dots.
You can check out my codepen to see the code I'm using.
My problem is that when you're playing the game, sometimes some of the yellow dots are too close to each other. So I am thinking if it's possible to make a collision-detection or something else, to check if the yellow dots collides?
Here is a picture of my game...
I made a red circle around the problem:
The link to my codepen project: /lolkie02/pen/PJVOdy?editors=0010
If you wanna try the game, it only works through iPhone or Android browser since I made the buttons etc. 'touchstart' in the javascript.
function getDistance(obj1, obj2) {
return Math.floor(
Math.sqrt(Math.pow(obj1.cx - obj2.cx, 2) + Math.pow(obj1.cy - obj2.cy, 2))
);
}
function getRandomArbitrary(min, max) {
return Math.floor(Math.random() * (max - min) + min);
}
function comparator(a, b) {
if (a[1] < b[1]) return -1;
if (a[1] > b[1]) return 1;
return 0;
}
function difference(source, toRemove) {
return source.filter(function(value) {
return toRemove.indexOf(value) == -1;
});
}
////////////////
// global vars
////////////////
var svg = document.getElementById("svg");
var dotMatrix = document.createElementNS(
"http://www.w3.org/2000/svg",
"circle"
);
var lineMatrix = document.createElementNS("http://www.w3.org/2000/svg", "line");
var screenW = window.innerWidth;
var screenH = window.innerHeight;
var totalDist = document.getElementById("distance");
////////////////
// line constructor
////////////////
function Line(x1, y1, x2, y2) {
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
this.el = document.createElementNS("http://www.w3.org/2000/svg", "line");
this.class = "line";
this.update = function(x1, y1, x2, y2) {
this.el.setAttribute("x1", x1 || this.x1);
this.el.setAttribute("y1", y1 || this.y1);
this.el.setAttribute("x2", x2 || this.x2);
this.el.setAttribute("y2", y2 || this.y2);
this.setAttr("class", this.class);
};
this.setAttr = function(attr, value) {
this.el.setAttribute(attr, value);
};
this.append = function() {
svg.insertBefore(this.el, svg.firstChild);
};
}
////////////////
// dot constructor
////////////////
function Dot(r, cx, cy) {
this.r = r;
this.cx = cx;
this.cy = cy;
this.el = document.createElementNS("http://www.w3.org/2000/svg", "circle");
this.class = "dot";
this.update = function() {
this.el.setAttribute("r", this.r);
this.el.setAttribute("cx", this.cx);
this.el.setAttribute("cy", this.cy);
this.setAttr("class", this.class);
};
// activates a dot
this.activate = function() {
for (i = 0; i < dots.num; i++) {
dots.list[i].setAttr("data-selected", "false");
}
this.setAttr("data-selected", "true");
};
this.visited = function() {
this.setAttr("data-visited", "true");
};
// sets attribute to element
this.setAttr = function(attr, value) {
this.el.setAttribute(attr, value);
};
// gets attribute to element
this.getAttr = function(attr) {
return this.el.getAttribute(attr);
};
// appends element to svg and attaches event listeners
this.append = function() {
svg.appendChild(this.el);
this.el.addEventListener("touchstart", this.onClick);
};
// on click on element
this.onClick = function(event) {
//gets the id and the coords of the dot
var thisId = Number(event.target.getAttribute("data-id").substr(3, 2));
var thisCx = dots.list[thisId].cx;
var thisCy = dots.list[thisId].cy;
// calculates the distance between dots
var distances = [];
for (i = 0; i < dots.num; i++) {
distances[i] = [i, getDistance(dots.selected, dots.list[i])];
}
distances.sort(comparator);
distances.splice(0, 1);
var distancesLeft = [];
for (i = 0; i < distances.length; i++) {
if (dots.left.includes(distances[i][0])) {
distancesLeft.push(distances[i][0]);
}
}
//if the element is the nearest
if (thisId == distancesLeft[0] && dots.left.includes(thisId)) {
// calculates distances
var newDistance = getDistance(dots.list[thisId], dots.selected);
app.score.update(1); // punteggio x numero di poi
// app.score.update(newDistance); punteggio x distanza
//sets the active class to the selected dot
dots.list[thisId].activate();
dots.list[thisId].visited();
// creates the line
lines.list.push(
new Line(
dots.selected.cx,
dots.selected.cy,
dots.list[thisId].cx,
dots.list[thisId].cy
)
);
lines.list[lines.list.length - 1].update();
lines.list[lines.list.length - 1].append();
// creates the preview line
//TODO: eliminare le vecchie preline che rimangono vive
svg.addEventListener("mousemove", function prelineMove(e) {
mouseX = e.pageX;
mouseY = e.pageY;
app.preline.update(thisCx, thisCy, mouseX, mouseY);
});
//saves the selected dots coordinates
dots.selected.id = thisId;
dots.selected.cx = thisCx;
dots.selected.cy = thisCy;
//removes the dot from the list of remaining dots
for (i = 0; i < dots.left.length; i++) {
if (dots.left[i] === thisId) {
dots.left.splice(i, 1);
}
}
if (dots.left.length == 0) {
app.end(true);
}
} else {
app.end(false);
}
};
}
////////////////
// lines group
////////////////
var lines = {
list: []
};
////////////////
// dots group
////////////////
var dots = {};
dots.num = 20;
dots.list = [];
dots.start = 0;
dots.selected = {};
dots.selected.id = dots.start;
dots.left = [];
dots.preline;
////////////////
// app
////////////////
var app = {};
app.level = 2;
app.score = {};
app.score.number = 0;
app.score.el = document.getElementById("score");
app.score.update = function(score) {
app.score.number += score;
app.score.el.textContent = app.score.number;
};
app.score.reset = function() {
app.score.number = 0;
app.score.update(0);
};
app.results = function(points) {
if (points == "reset") {
sessionStorage.setItem("results", 0);
} else {
if (!sessionStorage.getItem("results")) {
sessionStorage.setItem("results", points);
} else {
var newscore = points;
sessionStorage.setItem("results", newscore);
}
}
};
app.launchScreen = function(lastScore, title, description, btnText) {
app.launchScreen.el = document.getElementById("launch-screen");
app.launchScreen.el.setAttribute("class", "is-visible");
var launchScreenTitle = document.getElementById("launch-screen__title");
launchScreenTitle.textContent = title;
var launchScreenDescription = document.getElementById(
"launch-screen__description"
);
launchScreenDescription.textContent = description;
app.launchScreen.btn = document.getElementById("start-btn");
app.launchScreen.btn.textContent = btnText;
app.launchScreen.btn.addEventListener("touchstart", function lauch() {
app.launchScreen.el.setAttribute("class", "");
app.start(app.level);
document.getElementById("score2").style.display = "block";
app.launchScreen.btn.removeEventListener("touchstart", lauch);
});
};
app.preline = new Line(0, 0, 200, 200);
app.preline.setAttr("id", "preline");
app.start = function(dotsNum) {
dots.num = dotsNum;
for (i = 0; i < dots.num; i++) {
var cx = getRandomArbitrary(45, screenW - 45);
var cy = getRandomArbitrary(45, screenH - 45);
dots.list[i] = new Dot(14, cx, cy);
dots.list[i].setAttr("data-id", "id-" + i);
dots.list[i].setAttr(
"style",
"animation-delay:" + i / 10 + "s; transform-origin: " + cx + 'px ' + cy + 'px;');
dots.list[i].update();
dots.list[i].append();
dots.left.push(i);
if (i == dots.start) {
dots.selected.cx = dots.list[dots.start].cx;
dots.selected.cy = dots.list[dots.start].cy;
dots.list[dots.start].setAttr("class", "dot dot--starting");
dots.left.splice(i, 1);
}
// adds the preline
app.preline.update(
dots.selected.cx,
dots.selected.cy,
dots.selected.cx,
dots.selected.cy
);
app.preline.append();
svg.addEventListener("mousemove", function prelineMove(e) {
mouseX = e.pageX;
mouseY = e.pageY;
app.preline.update(dots.selected.cx, dots.selected.cy, mouseX, mouseY);
});
}
// sets starting point
dots.list[dots.start].setAttr("data-selected", "true");
};
app.end = function(win) {
if (win) {
app.level += 2;
app.results(app.score.number);
} else {
app.level = 2;
}
dots.list = [];
dots.selected = {};
dots.left.length = 0;
svg.innerHTML = "";
if (win) {
app.launchScreen(
app.score.number,
"", //"Sådan!",
"", //"Din score er nu: " + sessionStorage.getItem("results") + ' Det næste level vil blive endnu hårdere.',
"NÆSTE LEVEL"
);
} else {
app.launchScreen(
0,
"", //"ARGH!",
"", //"Din endelige score blev: " + sessionStorage.getItem("results"),
"PRØV IGEN"
);
app.results("reset");
app.score.reset();
var score2 = document.getElementById('score2');
var number = score2.innerHTML;
number = 0;
score2.innerHTML = number;
document.getElementById("score2").style.display = "none";
}
};
app.launchScreen(
0,
"STIFINDER",
"Find den tætteste gule prik",
"SPIL"
);
$('.btn').on('touchstart',function(e,data) {
var score2 = document.getElementById('score2');
var number = score2.innerHTML;
number++;
score2.innerHTML = number;
});
Use Pythagorean theorem to determine whether the distance of the centers of two dots are closer (or equal) to the sum of their radii - in that case you have collision.
My answer to the similar question :https://stackoverflow.com/a/46973584/4154250

HTML5 Canvas slider

Trying to create a slider class that lets you easily and quickly customize values. You can drag the handle or click on any part of the slider to move the handle there, and it works... sort of. You can click as many times as you want, but... if you even click once or if you drag, then let go and try again, it only goes down (never up) a tiny bit. That probably sounds confusing, so here's the fiddle.
var Slider = createEntity({
init: function (args) {
args = args || {};
this.x = args.x || 0;
this.y = args.y || 0;
this.width = args.width || 10;
this.height = args.height || 100;
this.min = args.min || 0;
this.max = args.max || 100;
this.value = args.value || 50;
this.rotation = args.rotation || 0;
this.on = args.on || function () {};
var backFill = randHsla();
args.back = args.back || {};
this.back = args.back;
args.back.fill = args.back.fill || backFill;
this.back.fill = args.back.fill;
args.back.borderFill = args.back.borderFill || backFill;
this.back.borderFill = args.back.borderFill;
args.back.width = args.back.width || 5;
this.back.width = args.back.width;
args.back.x = args.back.x || this.width / 2 - this.back.width / 2;
this.back.x = args.back.x;
var handleColor = randHsla();
args.handle = args.handle || {};
this.handle = args.handle;
args.handle.fill = args.handle.fill || handleColor;
this.handle.fill = args.handle.fill;
args.handle.borderStroke = args.handle.borderStroke || handleColor;
this.handle.borderStroke = args.handle.borderStroke;
args.handle.height = args.handle.height || 5;
this.handle.height = args.handle.height;
args.handle.y = args.handle.y || 0;
this.handle.y = args.handle.y;
this.updatePos();
},
draw: function (fx) {
fx.save();
fx.translate(this.x, this.y);
fx.rotate(this.rotation);
fx.fillStyle = this.back.fill;
fx.beginPath();
fx.fillRect(this.back.x, 0, this.back.width, this.height);
fx.closePath();
fx.fillStyle = this.handle.fill;
fx.strokeStyle = this.handle.borderStroke;
fx.beginPath();
fx.rect(0, this.handle.y, this.width, this.handle.height);
fx.closePath();
fx.fill();
fx.stroke();
fx.restore();
},
updateVal: function () {
var oldVal = this.value,
handleRange = this.height - this.handle.height,
valRange = this.max - this.min;
this.value = (handleRange - this.handle.y) / handleRange * valRange + this.min;
if (this.on instanceof Function && this.value !== oldVal) {
this.on();
}
return this;
},
updatePos: function () {
var handleRange = this.height - this.handle.height,
valRange = this.max - this.min;
this.handle.y = handleRange - ((this.value - this.min) / valRange) * handleRange;
return this;
},
getMouse: function (map) {
var self = this,
mouse = getMouse(map),
bounds = {};
setBounds();
map.addEventListener('mousedown', function (event) {
if (hasPoint(bounds, mouse.x, mouse.y)) {
map.addEventListener('mousemove', onMouseMove);
map.addEventListener('mouseup', onMouseUp);
} else if (hasPoint(self, mouse.x, mouse.y)) {
var y = mouse.y - self.y;
self.handle.y = Math.min(self.height - self.handle.height, Math.max(y, 0));
self.updateVal();
}
});
function onMouseUp(event) {
map.removeEventListener('mousemove', onMouseMove, false);
map.removeEventListener('mouseup', onMouseUp, false);
}
function onMouseMove(event) {
var y = mouse.y - self.y;
self.handle.y = Math.min(self.height - self.handle.height, Math.max(y, 0));
self.updateVal();
}
function setBounds() {
bounds.x = self.x;
bounds.y = self.y + self.handle.y;
bounds.width = self.width;
bounds.height = self.handle.height;
}
return this;
}
});
External functions such as createEntity and hasPoint can be found here.
How would I make it work after clicking the slider and letting go after the first?
Add the event listeners if the user clicks on the handle as well, to enable dragging.
map.addEventListener('mousedown', function(event) {
if (hasPoint(bounds, mouse.x, mouse.y)) {
map.addEventListener('mousemove', onMouseMove);
map.addEventListener('mouseup', onMouseUp);
} else if (hasPoint(self, mouse.x, mouse.y)) {
map.addEventListener('mousemove', onMouseMove);
map.addEventListener('mouseup', onMouseUp);
var y = mouse.y - self.y;
self.handle.y = Math.min(self.height - self.handle.height, Math.max(y, 0));
self.updateVal();
}
});

Categories

Resources