Trying to select lines or rectangles on a canvas - javascript

I want to be able to click any line(muscle) and new line then highlight it in my program like I can do with the nodes right now. I want to use context.isPointInPath(), but I feel like that will be too limiting in the fact that the lines are only 1 pixel wide. And now I want to look at changing the lines to rectangles. Because then I would be able to just see if the mouseclick is within the rectangle height and width. But, I'm having trouble finding out a way to connect the rectangle to two nodes like I have it with the strokes right now.
My program so far:
/*jshint esversion: 6 */
//draw everything on canvas
//TODO: Change use of canvas to a container and moving elements around to avoid the buffer of frame drawing
//Node class
class Node {
constructor(x, y, r, color, highlight, highlightColor) {
this.x = x;
this.y = y;
this.r = r || 20;
this.color = color || "#ff0";
this.highlight = highlight || false;
this.highlightColor = highlightColor || "#0000FF";
}
}
//Muscle class
class Muscle {
constructor(node1, node2, width, color) {
this.node1 = node1;
this.node2 = node2;
this.width = width || 5;
this.color = color || "#f00";
//Properties of the nodes this muscle attaches to
Object.defineProperties(this, {
node1x: {
"get": () => this.node1.x,
"set": x => {
this.node1.x = x;
}
},
node1y: {
"get": () => this.node1.y,
"set": y => {
this.node1.y = y;
}
},
node2x: {
"get": () => this.node2.x,
"set": x => {
this.node2.x = x;
}
},
node2y: {
"get": () => this.node2.y,
"set": y => {
this.node2.x = y;
}
}
});
}
}
function setParentForNodes() {
this.nodes.forEach(node => {
node.parentCreature = this;
});
}
class Creature {
constructor(nodes, muscles, nodeColors) {
this.nodes = nodes;
this.muscles = muscles;
this.nodeColors = nodeColors || "#ff0";
setParentForNodes.call(this);
Object.defineProperties(this, {
creatureNumber: {
"get": () => creatures.indexOf(this),
}
});
}
addNewNode(newNode) {
newNode.parentCreature = this;
this.nodes.push(newNode);
}
addNewNodes(newNodes) {
newNodes.forEach(function(node) {
node.parentCreature = this;
}, this);
this.nodes = this.nodes.concat(newNodes);
}
}
var nodes = [
new Node(100, 100),
new Node(200, 200)
];
var muscles = [
new Muscle(nodes[0], nodes[1])
];
var creatures = [
new Creature(nodes, muscles)
];
var addNodePressed = false;
var attachMusclePressed = false;
var addLimbPressed = false;
function draw(container, ctx, nodes, creatureMuscles) {
//draw in the container
ctx.fillStyle = "#000000";
ctx.fillRect(container.y, container.x, container.width, container.height);
// for loop to draw all objects of nodes
for (let i = 0; i < creatures.length; i++) {
var creatureNodes = creatures[i].nodes;
for (let i = 0; i < creatureNodes.length; i++) {
ctx.beginPath();
ctx.arc(creatureNodes[i].x, creatureNodes[i].y, creatureNodes[i].r, 0, 2 * Math.PI);
ctx.fillStyle = creatureNodes[i].color;
ctx.closePath();
ctx.fill();
//check if node needs to be highlighted
if (creatureNodes[i].highlight == true) {
ctx.beginPath();
ctx.arc(creatureNodes[i].x, creatureNodes[i].y, creatureNodes[i].r, 0, 2 * Math.PI);
ctx.strokeStyle = creatureNodes[i].highlightColor;
ctx.lineWidth = 5; // for now
ctx.closePath();
ctx.stroke();
}
}
creatureMuscles = creatures[i].muscles;
//loop and draw every muscle
for (let i = 0; i < creatureMuscles.length; i++) {
ctx.beginPath();
ctx.moveTo(creatureMuscles[i].node1x, creatureMuscles[i].node1y);
ctx.lineTo(creatureMuscles[i].node2x, creatureMuscles[i].node2y);
ctx.strokeStyle = creatureMuscles[i].color;
ctx.lineWidth = creatureMuscles[i].width;
ctx.closePath();
ctx.stroke();
}
}
}
//Handle moving a node with mousedrag
function handleMouseDrag(canvas, creatureNodes) {
var isDrag = false;
var dragNode;
var offset = {
x: 0,
y: 0,
x0: 0,
y0: 0
};
canvas.addEventListener("mousedown", function(e) {
//mousedown then save the position in var x and y
var x = e.offsetX,
y = e.offsetY;
//loop through all the nodes to find the first node that is within radius of the mouse click
for (let i = 0; i < creatures.length; i++) {
var creatureNodes = creatures[i].nodes;
for (let i = 0; i < creatureNodes.length; i++) {
if (Math.pow(x - creatureNodes[i].x, 2) + Math.pow(y - creatureNodes[i].y, 2) < Math.pow(creatureNodes[i].r, 2)) {
isDrag = true;
dragNode = creatureNodes[i];
//offset.x&y = where the node is currently
//offset x0&y0 = where the user clicked
offset = {
x: dragNode.x,
y: dragNode.y,
x0: x,
y0: y
};
return;
}
}
}
});
// when mouse moves and isDrag is true, move the node's position
canvas.addEventListener("mousemove", function(e) {
/*when the user moves the mouse, take the difference of where his mouse is right now and where the user clicked.
Then, add that to where the node is right now to find the correct placement of the node without centering on your mouse
*/
if (isDrag) {
dragNode.x = e.offsetX - offset.x0 + offset.x; // where the mouse is right now - where the user mousedown + where the node is right now
dragNode.y = e.offsetY - offset.y0 + offset.y;
}
});
canvas.addEventListener("mouseup", function(e) {
isDrag = false;
});
canvas.addEventListener("mouseleave", function(e) {
isDrag = false;
});
}
//Handle highlighting and button functionality
function handleMouseClick(canvas, nodes, muscles) {
var highlighted;
var highlightedNode;
canvas.addEventListener("mousedown", function(e) {
var x = e.offsetX,
y = e.offsetY;
var loopbreak = false;
for (let i = 0; i < creatures.length; i++) {
var creatureNodes = creatures[i].nodes;
for (let i = 0; i < creatureNodes.length; i++) {
// check if click is within radius of a node, if it is, highlight and set highlight boolean to true.
if (Math.pow(x - creatureNodes[i].x, 2) + Math.pow(y - creatureNodes[i].y, 2) < Math.pow(creatureNodes[i].r, 2)) {
var clickedNode = creatureNodes[i];
if (addNodePressed) {
console.log("Not valid. Cannot add a node on top of another node.");
loopbreak = true;
break;
} else if (addLimbPressed) {
console.log("Not valid. Cannot add a limb on top of another node.");
loopbreak = true;
break;
} else if (attachMusclePressed) {
if (highlightedNode == clickedNode) {
console.log("Not valid. Cannot attach muscle to the same node.");
loopbreak = true;
break;
} else {
var newMuscle;
if (highlightedNode.parentCreature.creatureNumber == clickedNode.parentCreature.creatureNumber) {
newMuscle = new Muscle(highlightedNode, clickedNode);
highlightedNode.parentCreature.muscles.push(newMuscle);
attachMuscle();
highlightedNode.highlight = false;
highlighted = false;
devTools(true, false, false, false);
} else {
var newNodes = [];
var newMuscles = [];
if (highlightedNode.parentCreature.creatureNumber > clickedNode.parentCreature.creatureNumber) {
highlightedNode.parentCreature.nodes.forEach(function(node) {
newNodes.push(node);
});
highlightedNode.parentCreature.muscles.forEach(function(muscle) {
newMuscles.push(muscle);
});
newMuscle = new Muscle(highlightedNode, clickedNode);
clickedNode.parentCreature.muscles.push(newMuscle);
clickedNode.parentCreature.muscles = clickedNode.parentCreature.muscles.concat(newMuscles);
creatures.splice(creatures.indexOf(highlightedNode.parentCreature), 1);
clickedNode.parentCreature.addNewNodes(newNodes);
} else {
clickedNode.parentCreature.nodes.forEach(function(node) {
newNodes.push(node);
console.log("Clicked node is bigger.");
});
clickedNode.parentCreature.muscles.forEach(function(muscle) {
newMuscles.push(muscle);
});
newMuscle = new Muscle(highlightedNode, clickedNode);
highlightedNode.parentCreature.muscles.push(newMuscle);
highlightedNode.parentCreature.muscles = highlightedNode.parentCreature.muscles.concat(newMuscles);
creatures.splice(creatures.indexOf(clickedNode.parentCreature), 1);
highlightedNode.parentCreature.addNewNodes(newNodes);
}
highlightedNode.highlight = false;
attachMuscle();
devTools(true, false, false, false);
}
}
}
//no button pressed - highlight/unhighlight node
else {
if (highlighted || creatureNodes[i].highlight) {
if (highlightedNode != creatureNodes[i]) {
highlightedNode.highlight = false;
highlightedNode = creatureNodes[i];
highlightedNode.highlight = true;
devTools(false, true, true, true);
} else {
highlightedNode = creatureNodes[i];
highlightedNode.highlight = false;
highlighted = false;
highlightedNode = undefined;
devTools(true, false, false, false);
}
} else {
highlightedNode = creatureNodes[i];
highlightedNode.highlight = true;
highlighted = true;
devTools(false, true, true, true);
}
loopbreak = true;
break;
}
}
}
}
// if click was not in radius of any nodes then check for add limb or create node button press.
if (!loopbreak) {
loopbreak = false;
var newNode;
if (addNodePressed) {
newNode = new Node(x, y);
let newNodes = [];
let newMuscles = [];
newNodes.push(newNode);
var newCreature = new Creature(newNodes, newMuscles);
creatures.push(newCreature);
addNode();
addNodePressed = false;
devTools(true, false, false, false);
} else if (addLimbPressed) {
newNode = new Node(x, y);
let newMuscle = new Muscle(newNode, highlightedNode);
highlightedNode.parentCreature.addNewNode(newNode);
highlightedNode.parentCreature.muscles.push(newMuscle);
addLimb();
addLimbPressed = false;
highlightedNode.highlight = false;
highlighted = false;
highlightedNode = undefined;
devTools(true, false, false, false);
}
}
});
}
//Handle Devtools
function devTools(addNode, removeNode, attachMuscle, addLimb) {
var creatureNumberHTML = document.getElementById("creatureNumber");
var selectedHTML = document.getElementById("selected");
var addNodeB = document.getElementById("addNode");
var removeNodeB = document.getElementById("removeNode");
var attachMuscleB = document.getElementById("attachMuscle");
var addLimbB = document.getElementById("addLimb");
addNodeB.disabled = (addNode) ? false : true;
removeNodeB.disabled = (removeNode) ? false : true;
attachMuscleB.disabled = (attachMuscle) ? false : true;
addLimbB.disabled = (addLimb) ? false : true;
for (let i = 0; i < creatures.length; i++) {
var creatureNumber = i;
var creatureNodes = creatures[i].nodes;
for (let i = 0; i < creatureNodes.length; i++) {
if (creatureNodes[i].highlight == true) {
selectedHTML.innerHTML = `Selected: ${i} node`;
creatureNumberHTML.innerHTML = `Creature number: ${creatureNumber}`;
return;
} else {
creatureNumberHTML.innerHTML = "Creature number: -";
selectedHTML.innerHTML = "Selected: None";
}
}
}
}
//Handle add node button
function addNode() {
var addNodeB = document.getElementById("addNode");
if (addNodePressed) {
addNodePressed = false;
addNodeB.style.background = "";
} else {
addNodePressed = true;
addNodeB.style.backgroundColor = "#808080";
//and unhighlight
}
}
//Handle remove node button
function removeNode() {
for (let i = 0; i < creatures.length; i++) {
var creatureNodes = creatures[i].nodes;
var creatureMuscles = creatures[i].muscles;
for (let i = 0; i < creatureNodes.length; i++) {
if (creatureNodes[i].highlight == true) {
let highlightedNode = creatureNodes[i];
for (let i = 0; i < creatureMuscles.length; i++) {
if (creatureMuscles[i].node1 == highlightedNode || creatureMuscles[i].node2 == highlightedNode) {
creatureMuscles.splice(i, 1);
i--;
}
}
creatureNodes.splice(i, 1);
}
}
}
devTools(true, false, false, false);
}
//Handle attach muscle button
function attachMuscle() {
var attachMuscleB = document.getElementById("attachMuscle");
if (attachMusclePressed) {
attachMusclePressed = false;
attachMuscleB.style.background = "";
} else {
attachMusclePressed = true;
attachMuscleB.style.backgroundColor = "#808080";
}
}
//Handle add limb button
function addLimb() {
var addLimbB = document.getElementById("addLimb");
if (addLimbPressed) {
addLimbPressed = false;
addLimbB.style.background = "";
} else {
addLimbPressed = true;
addLimbB.style.backgroundColor = "#808080";
}
}
//Main - Grabs document elements to draw a canvas on, init node and muscle arrays and then continuously updates frame to redraw
function main() {
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var container = {
x: 0,
y: 0,
get width() {
return canvas.width;
},
get height() {
return canvas.height;
}
};
handleMouseDrag(canvas, nodes);
handleMouseClick(canvas, nodes, muscles);
// refresh and redraw with new properties in an updateframe infinite loop
function updateFrame() {
ctx.save();
draw(container, ctx, nodes, muscles);
ctx.restore();
requestAnimationFrame(updateFrame);
}
updateFrame();
}
main();
#canvas {
display: block;
}
#info {
display: inline-block;
text-overflow: clip;
overflow: hidden;
margin-right: 200px;
}
#commands {
display: inline-block;
text-align: center;
margin-left: 200px;
}
#devTools {
background-color: aqua;
width: 1500px;
}
section {
width: 200px;
height: 200px;
background-color: grey;
vertical-align: top;
}
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" type="text/css" href="styles.css" />
</head>
<body>
<!--TODO: Adjust the size of the canvas to fit the window-->
<canvas id="canvas" width="1500" , height="600"></canvas>
<!--TODO: Create buttons for all devtools under the canvas-->
<!--TODO: Make a container for all devtools under the canvas, then add all the functionality to it after-->
<div id="devTools">
<section id="info">
<p>Info</p>
<p id="creatureNumber">Creature Number: -</p>
<p id="selected">Selected: </p>
</section>
<section id="commands">
<p>Commands</p>
<button type="button" id="addNode" onclick="addNode()">Add node</button>
<button type="button" id="removeNode" disabled=true onclick="removeNode()">Remove node</button>
<button type="button" id="attachMuscle" disabled=true onclick="attachMuscle()">Attach muscle</button>
<button type="button" id="addLimb" disabled=true onclick="addLimb()">Add Limb</button>
<div id="muscleLength">
<button type="button" id="increaseLengthB">↑</button>
<p>Muscle Length</p>
<button type="button" id="decreaseLengthB">↓</button>
</div>
</section>
</div>
<script src="scripts/script.js"></script>
</body>
</html>

Another way to solve this is to use a thicker line-width and use isPointInStroke() instead.
var ctx = c.getContext("2d");
var path = new Path2D(); // to store and reuse path
var onLine = false; // state (for demo)
path.moveTo(10, 10); // store a line on path
path.lineTo(200, 100);
ctx.lineWidth = 16; // line width
render(); // initial render
function render() {
ctx.clearRect(0,0,300,150);
ctx.strokeStyle = onLine ? "#09f" : "#000"; // color based on state
ctx.stroke(path); // stroke path
}
c.onmousemove = function(e) { // demo: is mouse on stroke?
onLine = ctx.isPointInStroke(path, e.clientX, e.clientY);
render();
};
body, html {margin:0}
<canvas id=c></canvas>
Note: IE11 does not support the path argument - for it you will need to use ordinary path on the context itself (ctx.moveTo etc.)

Related

Canvas overlay after creating object

After drawing a shape, i would like to automaticly create overlay(or just add color to rest of the screen) outside the object (It will be locked so user can create only one shape - as for now i dont know how to code that also)
My code:
<body>
<label class="btn btn--primary" id="btnRoof"><b>Click to draw</b> </label>
<canvas id="canvas" class="canvas" width="800" height="800"></canvas>
<script>
var roof = null;
var roofPoints = [];
var lines = [];
var lineCounter = 0;
var drawingObject = {};
drawingObject.type = "";
drawingObject.background = "";
drawingObject.border = "";
function Point(x, y) {
this.x = x;
this.y = y;
}
$("#btnRoof").click(function () {
if (drawingObject.type == "roof") {
drawingObject.type = "";
lines.forEach(function (value, index, ar) {
canvas.remove(value);
});
//canvas.remove(lines[lineCounter - 1]);
roof = makeRoof(roofPoints);
canvas.add(roof);
canvas.renderAll();
} else {
drawingObject.type = "roof"; // roof type
}
});
// canvas Drawing
var canvas = new fabric.Canvas('canvas');
var x = 0;
var y = 0;
fabric.util.addListener(window, 'dblclick', function () {
drawingObject.type = "";
lines.forEach(function (value, index, ar) {
canvas.remove(value);
});
//canvas.remove(lines[lineCounter - 1]);
roof = makeRoof(roofPoints);
canvas.add(roof);
canvas.renderAll();
console.log("double click");
//clear arrays
roofPoints = [];
lines = [];
lineCounter = 0;
});
canvas.on('mouse:down', function (options) {
if (drawingObject.type == "roof") {
canvas.selection = false;
setStartingPoint(options); // set x,y
roofPoints.push(new Point(x, y));
var points = [x, y, x, y];
lines.push(new fabric.Line(points, {
strokeWidth: 2,
selectable: false,
stroke: 'blue'
}).setOriginX(x).setOriginY(y));
canvas.add(lines[lineCounter]);
lineCounter++;
canvas.on('mouse:up', function (options) {
canvas.selection = true;
});
}
});
canvas.on('mouse:move', function (options) {
if (lines[0] !== null && lines[0] !== undefined && drawingObject.type == "roof") {
setStartingPoint(options);
lines[lineCounter - 1].set({
x2: x,
y2: y
});
canvas.renderAll();
}
});
function setStartingPoint(options) {
var offset = $('#canvas').offset();
x = options.e.pageX - offset.left;
y = options.e.pageY - offset.top;
}
function makeRoof(roofPoints) {
var left = findLeftPaddingForRoof(roofPoints);
var top = findTopPaddingForRoof(roofPoints);
roofPoints.push(new Point(roofPoints[0].x, roofPoints[0].y))
var roof = new fabric.Polyline(roofPoints, {
fill: 'rgba(0,230,64,0.5)',
stroke: 'green',
strokeWidth: 2,
});
roof.set({
left: left,
top: top,
});
return roof;
}
function findTopPaddingForRoof(roofPoints) {
var result = 999999;
for (var f = 0; f < lineCounter; f++) {
if (roofPoints[f].y < result) {
result = roofPoints[f].y;
}
}
return Math.abs(result);
}
function findLeftPaddingForRoof(roofPoints) {
var result = 999999;
for (var i = 0; i < lineCounter; i++) {
if (roofPoints[i].x < result) {
result = roofPoints[i].x;
}
}
return Math.abs(result);
}
</script>
</body>
</html>
For now i can lock shape with doubleclick, but have no idea how to add overlay outside of it.

Animated canvas background flashing?

I'm attempting to make a typing game with moving words on a canvas, which move left to right and lives are lost if they leave the canvas however i'm trying to animate a simple looping background image for my canvas, I have gotten it working and looping and moving left, however for some reason when this is in use my entire canvas is flashing as if it is constantly redrawing in a strange way or something I don't really know.
var canvas;
var canvasContext;
let x=20;
var string;
let score = 0;
let highscore = 0;
var lives = 3;
var WordID;
var difficultyWordID
var bg = new Image();
bg.src = "client/img/stars.jpg";
window.onload = function(){
canvas = document.getElementById('typingCanvas');
var typeval = document.getElementById("typingValue"); //user typed value.
canvasContext = canvas.getContext('2d');
document.getElementById("Button2").style.display = "none";
document.getElementById("gameOver").style.display = "none";
document.getElementById("scoreText").style.display = "none";
let fps=40;
setInterval(function(){
if(x==20){
string = getWord()
}
moveEverything()
drawEverything(x,string);
if (x>900) {
lives--;
} else if (lives<1) {
canvas.style.display="none";
document.getElementById("Button2").style.display = "block";
document.getElementById("GameTable").style.display = "none";
document.getElementById("gameHR2").style.display = "none";
document.getElementById("gameHR3").style.display = "none";
document.getElementById("gameOver").style.display = "block";
document.getElementById("scoreText").style.display = "block";
document.getElementById("GameHeading").textContent = "Results below: ";
document.getElementById("scoreText").textContent = "Your Score: " + score;
function updateUserScore() {
fetch("/leaderboard/update", {method: 'post', body: formData}
).then(response => response.json()
).then(responseData => {
if (responseData.hasOwnProperty('error')) {
alert(responseData.error);
} else {
}
});
}
}
if(x>900 || check()){
x=20;
document.getElementById("val").value = ''; //if inputed value get match then blank the input box.
}
},1000/fps)
}
function drawEverything(x,string ){ // draws text etc
canvasContext.fillStyle="rgba(0,0,200,0)"; // background colour
canvasContext.border="white"
canvasContext.fillRect(20,20,canvas.width,canvas.height);
drawString(x,string);
scoreBoard(score);
highScoreBoard(highscore);
}
function moveEverything(){
x+=4; // movement speed of the word
}
function drawString(x,string) {
canvasContext.font="30px Verdana";
canvasContext.fillStyle='gray';
canvasContext.fillText(string,x,280); // place of text appearing.
}
function Background(){ // sets background
this.x = 0, this.y = 0, this.w = bg.width, this.h = bg.height;
this.render = function(){
canvasContext.drawImage(bg, this.x--, 0);
if(this.x <= -499){
this.x = 0;
}
}
}
var background = new Background(); // actual background animation
function animate(){
background.render();
}
var animateInterval = setInterval(animate, 40);
function getWord(WordID) {
WordID = Math.floor(Math.random()*30) +1
difficultyWordID = WordID
if (WordID === null) {
} else
fetch("/words/single/" + WordID, {method: 'get'}
).then(response => response.json()
).then(responseData => {
if (responseData.hasOwnProperty('error')) {
alert(responseData.error);
} else {
string = responseData.Definition;
}
});
}
function check(WordID){
var userVal = document.getElementById("val").value;
if(userVal==string){
return true;
}
return false;
}
function scoreVal(){
if(check()){
fetch("/words/single/" + difficultyWordID, {method: 'get'}
).then(response => response.json()
).then(responseData => {
if (responseData.hasOwnProperty('error')) {
alert(responseData.error);
} else {
let difficultyScore = 1;
difficultyScore = responseData.Difficulty;
score=score + difficultyScore;
}
});
}
}
function highScoreVal(){
if(score>highscore){
highscore=score;
}
}
function scoreBoard(score){
scoreVal(WordID);
canvasContext.fillStyle = "White";
canvasContext.font = "40px hot_sauceitalic";
canvasContext.fillText("Your Score: ",50,60);
canvasContext.fillStyle = "White";
canvasContext.fillText(score, 250, 60);
}
function highScoreBoard(highscore){
highScoreVal();
canvasContext.fillStyle = "White";
canvasContext.fillText("Lives:",750,60);
canvasContext.fillStyle = "White";
canvasContext.font = "40px hot_sauceitalic";
canvasContext.fillText(lives, 850, 60);
}
I am unsure how to go about fixing this as I cant really work out the problem myself, I am assuming that it is to do with how it is drawing the background alongside the moving words.
EDIT - Tried using background-image and got this instead.
https://i.stack.imgur.com/UhNai.png

Converting jquery controls to 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
}
});

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

Jquery stopped working

I'm developping this mobile app and I'm usint this (https://github.com/krisrak/appframework-templates/blob/master/template-CarouselViewApp.html) as a carousel to change through content on a page. http://jsfiddle.net/nafis56/qCkqb/
So for this I need to mess around in HTML, CSS and Jquery. Unfortonetly I'm still very green at javascript so I need your help. I changed an ID to a Class because I need to call it more than once in the same page. In the original template I refeered to, it comes as an ID. So I did this to change it:
Changed matching code on html to call it as a Class.
<div class="panel" title="Desiree Charms" id="desiree_charms" style="overflow: hidden;"
data-appbuilder-object="page">
<div class="carousel">
<div class="carousel_page">
<h2>Desiree Charms</h2>
<p><img src="images/desiree_charms.jpg" style="width: 85%; height: 85%; display: block; margin-left: auto; margin-right: auto "
data-appbuilder-object="image" class="" title="">
</p>
</div>
<div class="carousel_page">
<h2>Page Two</h2>
<p>Text and images for Page Two goes here. Swipe to go to the
next page.</p>
</div>
</div>
<div class="carousel_dots"></div>
</div>
also this on the html.
<script>
$.ui.autoLaunch = false;
$.ui.animateHeaders = false;
$(document).ready(function(){
$.ui.launch();
});
$.ui.ready(function(){
carouselSetup();
});
function carouselSetup(){
// set size of carousel
$(".carousel").width($(".carousel").closest(".panel").width());
$(".carousel").height($(".carousel").closest(".panel").height()-25);
var options={
vertical:false, // page up/down
horizontal:true, // page left/right
pagingDiv:"carousel_dots", // div to hold the dots for paging
pagingCssName:"carousel_paging", //classname for the paging dots
pagingCssNameSelected: "carousel_paging_selected", //classname for the selected page dots
wrap:true //Creates a continuous carousel
}
var carousel = $(".carousel").carousel(options);
}
Changed # to . on Css.
.carousel {
overflow:hidden;
margin:0 -10px;
}
.carousel_page {
overflow: auto;
-webkit-scrolling:touch;
padding:0 10px;
}
.carousel_dots {
text-align: center;
margin-left: auto;
margin-right: auto;
clear: both;
position:relative;
top:0;
z-index:200;
}
.carousel_paging {
border-radius: 10px;
background: #ccc;
width: 10px;
height: 10px;
display:inline-block;
}
.carousel_paging_selected {
border-radius: 10px;
background: #000;
width: 10px;
height: 10px;
display:inline-block;
}
.carousel h2 {
text-align: center;
}
This is the jquery ( I didn't change anything)
/**
* af.web.carousel - a carousel library for App Framework apps
* #copyright 2011 - Intel
*
*/
(function($) {
var cache = [];
var objId=function(obj){
if(!obj.afmCarouselId) obj.afmCarouselId=$.uuid();
return obj.afmCarouselId;
}
$.fn.carousel = function(opts) {
var tmp, id;
for (var i = 0; i < this.length; i++) {
//cache system
id = objId(this[i]);
if(!cache[id]){
tmp = new carousel(this[i], opts);
cache[id] = tmp;
} else {
tmp = cache[id];
}
}
return this.length == 1 ? tmp : this;
};
var carousel = (function() {
var translateOpen =$.feat.cssTransformStart;
var translateClose = $.feat.cssTransformEnd;
var carousel = function(containerEl, opts) {
if (typeof containerEl === "string" || containerEl instanceof String) {
this.container = document.getElementById(containerEl);
} else {
this.container = containerEl;
}
if (!this.container) {
alert("Error finding container for carousel " + containerEl);
return;
}
if (this instanceof carousel) {
for (var j in opts) {
if (opts.hasOwnProperty(j)) {
this[j] = opts[j];
}
}
} else {
return new carousel(containerEl, opts);
}
var that = this;
af(this.container).bind('destroy', function(e){
var id = that.container.afmCarouselId;
//window event need to be cleaned up manually, remaining binds are automatically killed in the dom cleanup process
window.removeEventListener("orientationchange", that.orientationHandler, false);
if(cache[id]) delete cache[id];
e.stopPropagation();
});
this.pagingDiv = this.pagingDiv ? document.getElementById(this.pagingDiv) : null;
// initial setup
this.container.style.overflow = "hidden";
if (this.vertical) {
this.horizontal = false;
}
var el = document.createElement("div");
this.container.appendChild(el);
var $el=$(el);
var $container=$(this.container);
var data = Array.prototype.slice.call(this.container.childNodes);
while(data.length>0)
{
var myEl=data.splice(0,1);
myEl=$container.find(myEl);
if(myEl.get(0)==el)
continue;
$el.append(myEl.get(0));
}
if (this.horizontal) {
el.style.display = "block";
el.style['float']="left";
}
else {
el.style.display = "block";
}
this.el = el;
this.refreshItems();
var afEl = af(el);
afEl.bind('touchmove', function(e) {that.touchMove(e);});
afEl.bind('touchend', function(e) {that.touchEnd(e);});
afEl.bind('touchstart', function(e) {that.touchStart(e);});
this.orientationHandler = function() {that.onMoveIndex(that.carouselIndex,0);};
window.addEventListener("orientationchange", this.orientationHandler, false);
};
carousel.prototype = {
wrap:true,
startX: 0,
startY: 0,
dx: 0,
dy: 0,
glue: false,
myDivWidth: 0,
myDivHeight: 0,
cssMoveStart: 0,
childrenCount: 0,
carouselIndex: 0,
vertical: false,
horizontal: true,
el: null,
movingElement: false,
container: null,
pagingDiv: null,
pagingCssName: "carousel_paging",
pagingCssNameSelected: "carousel_paging_selected",
pagingFunction: null,
lockMove:false,
okToMove: false,
// handle the moving function
touchStart: function(e) {
this.okToMove = false;
this.myDivWidth = numOnly(this.container.clientWidth);
this.myDivHeight = numOnly(this.container.clientHeight);
this.lockMove=false;
if (e.touches[0].target && e.touches[0].target.type !== undefined) {
var tagname = e.touches[0].target.tagName.toLowerCase();
if (tagname === "select" || tagname === "input" || tagname === "button") // stuff we need to allow
{
return;
}
}
if (e.touches.length === 1) {
this.movingElement = true;
this.startY = e.touches[0].pageY;
this.startX = e.touches[0].pageX;
var cssMatrix=$.getCssMatrix(this.el);
if (this.vertical) {
try {
this.cssMoveStart = numOnly(cssMatrix.f);
} catch (ex1) {
this.cssMoveStart = 0;
}
} else {
try {
this.cssMoveStart = numOnly(cssMatrix.e);
} catch (ex1) {
this.cssMoveStart = 0;
}
}
}
},
touchMove: function(e) {
if(!this.movingElement)
return;
if (e.touches.length > 1) {
return this.touchEnd(e);
}
var rawDelta = {
x: e.touches[0].pageX - this.startX,
y: e.touches[0].pageY - this.startY
};
if (this.vertical) {
var movePos = { x: 0, y: 0 };
this.dy = e.touches[0].pageY - this.startY;
this.dy += this.cssMoveStart;
movePos.y = this.dy;
e.preventDefault();
//e.stopPropagation();
} else {
if ((!this.lockMove&&isHorizontalSwipe(rawDelta.x, rawDelta.y))||Math.abs(this.dx)>5) {
var movePos = {x: 0,y: 0};
this.dx = e.touches[0].pageX - this.startX;
this.dx += this.cssMoveStart;
e.preventDefault();
// e.stopPropagation();
movePos.x = this.dx;
}
else
return this.lockMove=true;
}
var totalMoved = this.vertical ? ((this.dy % this.myDivHeight) / this.myDivHeight * 100) * -1 : ((this.dx % this.myDivWidth) / this.myDivWidth * 100) * -1; // get a percentage of movement.
if (!this.okToMove) {
oldStateOkToMove= this.okToMove;
this.okToMove = this.glue ? Math.abs(totalMoved) > this.glue && Math.abs(totalMoved) < (100 - this.glue) : true;
if (this.okToMove && !oldStateOkToMove) {
$.trigger(this,"movestart",[this.el]);
}
}
if (this.okToMove && movePos)
this.moveCSS3(this.el, movePos);
},
touchEnd: function(e) {
if (!this.movingElement) {
return;
}
$.trigger(this,"movestop",[this.el]);
// e.preventDefault();
// e.stopPropagation();
var runFinal = false;
// try {
var cssMatrix=$.getCssMatrix(this.el);
var endPos = this.vertical ? numOnly(cssMatrix.f) : numOnly(cssMatrix.e);
if (1==2&&endPos > 0) {
this.moveCSS3(this.el, {
x: 0,
y: 0
}, "300");
} else {
var totalMoved = this.vertical ? ((this.dy % this.myDivHeight) / this.myDivHeight * 100) * -1 : ((this.dx % this.myDivWidth) / this.myDivWidth * 100) * -1; // get a percentage of movement.
// Only need
// to drag 3% to trigger an event
var currInd = this.carouselIndex;
if (endPos < this.cssMoveStart && totalMoved > 3) {
currInd++; // move right/down
} else if ((endPos > this.cssMoveStart && totalMoved < 97)) {
currInd--; // move left/up
}
var toMove=currInd;
//Checks for infinite - moves to placeholders
if(this.wrap){
if (currInd > (this.childrenCount - 1)) {
currInd = 0;
toMove=this.childrenCount;
}
if (currInd < 0) {
currInd = this.childrenCount-1;
toMove=-1;
}
}
else {
if(currInd<0)
currInd=0;
if(currInd>this.childrenCount-1)
currInd=this.childrenCount-1;
toMove=currInd;
}
var movePos = {
x: 0,
y: 0
};
if (this.vertical) {
movePos.y = (toMove * this.myDivHeight * -1);
}
else {
movePos.x = (toMove * this.myDivWidth * -1);
}
this.moveCSS3(this.el, movePos, "150");
if (this.pagingDiv && this.carouselIndex !== currInd) {
document.getElementById(this.container.id + "_" + this.carouselIndex).className = this.pagingCssName;
document.getElementById(this.container.id + "_" + currInd).className = this.pagingCssNameSelected;
}
if (this.carouselIndex != currInd)
runFinal = true;
this.carouselIndex = currInd;
//This is for the infinite ends - will move to the correct position after animation
if(this.wrap){
if(toMove!=currInd){
var that=this;
window.setTimeout(function(){
that.onMoveIndex(currInd,"1ms");
},155);
}
}
}
//} catch (e) {
// console.log(e);
// }
this.dx = 0;
this.movingElement = false;
this.startX = 0;
this.dy = 0;
this.startY = 0;
if (runFinal && this.pagingFunction && typeof this.pagingFunction == "function")
this.pagingFunction(this.carouselIndex);
},
onMoveIndex: function(newInd,transitionTime) {
this.myDivWidth = numOnly(this.container.clientWidth);
this.myDivHeight = numOnly(this.container.clientHeight);
var runFinal = false;
if(document.getElementById(this.container.id + "_" + this.carouselIndex))
document.getElementById(this.container.id + "_" + this.carouselIndex).className = this.pagingCssName;
var newTime = Math.abs(newInd - this.carouselIndex);
var ind = newInd;
if (ind < 0)
ind = 0;
if (ind > this.childrenCount - 1) {
ind = this.childrenCount - 1;
}
var movePos = {
x: 0,
y: 0
};
if (this.vertical) {
movePos.y = (ind * this.myDivHeight * -1);
}
else {
movePos.x = (ind * this.myDivWidth * -1);
}
var time =transitionTime?transitionTime: 50 + parseInt((newTime * 20));
this.moveCSS3(this.el, movePos, time);
if (this.carouselIndex != ind)
runFinal = true;
this.carouselIndex = ind;
if (this.pagingDiv) {
var tmpEl = document.getElementById(this.container.id + "_" + this.carouselIndex);
if(tmpEl) tmpEl.className = this.pagingCssNameSelected;
}
if (runFinal && this.pagingFunction && typeof this.pagingFunction == "function")
this.pagingFunction(currInd);
},
moveCSS3: function(el, distanceToMove, time, timingFunction) {
if (!time)
time = 0;
else
time = parseInt(time);
if (!timingFunction)
timingFunction = "linear";
el.style[$.feat.cssPrefix+"Transform"] = "translate" + translateOpen + distanceToMove.x + "px," + distanceToMove.y + "px" + translateClose;
el.style[$.feat.cssPrefix+"TransitionDuration"] = time + "ms";
el.style[$.feat.cssPrefix+"BackfaceVisibility"] = "hidden";
el.style[$.feat.cssPrefix+"TransitionTimingFunction"] = timingFunction;
},
addItem: function(el) {
if (el && el.nodeType) {
this.container.childNodes[0].appendChild(el);
this.refreshItems();
}
},
refreshItems: function() {
var childrenCounter = 0;
var that = this;
var el = this.el;
$(el).children().find(".prevBuffer").remove();
$(el).children().find(".nextBuffer").remove();
n = el.childNodes[0];
var widthParam;
var heightParam = "100%";
var elems = [];
for (; n; n = n.nextSibling) {
if (n.nodeType === 1) {
elems.push(n);
childrenCounter++;
}
}
//Let's put the buffers at the start/end
if(this.wrap){
var prep=$(elems[elems.length-1]).clone().get(0);
$(el).prepend(prep);
var tmp=$(elems[0]).clone().get(0);
$(el).append(tmp);
elems.push(tmp);
elems.unshift(prep);
tmp.style.position="absolute";
prep.style.position="absolute";
}
var param = (100 / childrenCounter) + "%";
this.childrenCount = childrenCounter;
widthParam = parseFloat(100 / childrenCounter) + "%";
for (var i = 0; i < elems.length; i++) {
if (this.horizontal) {
elems[i].style.width = widthParam;
elems[i].style.height = "100%";
elems[i].style['float']="left";
}
else {
elems[i].style.height = widthParam;
elems[i].style.width = "100%";
elems[i].style.display = "block";
}
}
//Clone the first and put it at the end
this.moveCSS3(el, {
x: 0,
y: 0
});
if (this.horizontal) {
el.style.width = Math.ceil((this.childrenCount) * 100) + "%";
el.style.height = "100%";
el.style['min-height'] = "100%"
if(this.wrap){
prep.style.left="-"+widthParam;
tmp.style.left="100%";
}
}
else {
el.style.width = "100%";
el.style.height = Math.ceil((this.childrenCount) * 100) + "%";
el.style['min-height'] = Math.ceil((this.childrenCount) * 100) + "%";
if(this.wrap){
prep.style.top="-"+widthParam;
tmp.style.top="100%";
}
}
// Create the paging dots
if (this.pagingDiv) {
this.pagingDiv.innerHTML = ""
for (i = 0; i < this.childrenCount; i++) {
var pagingEl = document.createElement("div");
pagingEl.id = this.container.id + "_" + i;
pagingEl.pageId = i;
if (i !== this.carouselIndex) {
pagingEl.className = this.pagingCssName;
}
else {
pagingEl.className = this.pagingCssNameSelected;
}
pagingEl.onclick = function() {
that.onMoveIndex(this.pageId);
};
var spacerEl = document.createElement("div");
spacerEl.style.width = "20px";
if(this.horizontal){
spacerEl.style.display = "inline-block";
spacerEl.innerHTML = " ";
}
else{
spacerEl.innerHTML=" ";
spacerEl.style.display="block";
}
this.pagingDiv.appendChild(pagingEl);
if (i + 1 < (this.childrenCount))
this.pagingDiv.appendChild(spacerEl);
pagingEl = null;
spacerEl = null;
}
if(this.horizontal){
this.pagingDiv.style.width = (this.childrenCount) * 50 + "px";
this.pagingDiv.style.height = "25px";
}
else {
this.pagingDiv.style.height = (this.childrenCount) * 50 + "px";
this.pagingDiv.style.width = "25px";
}
}
this.onMoveIndex(this.carouselIndex);
}
};
return carousel;
})();
function isHorizontalSwipe(xAxis, yAxis) {
var X = xAxis;
var Y = yAxis;
var Z = Math.round(Math.sqrt(Math.pow(X,2)+Math.pow(Y,2))); //the distance - rounded - in pixels
var r = Math.atan2(Y,X); //angle in radians
var swipeAngle = Math.round(r*180/Math.PI); //angle in degrees
if ( swipeAngle < 0 ) { swipeAngle = 360 - Math.abs(swipeAngle); } // for negative degree values
if (((swipeAngle <= 215) && (swipeAngle >= 155)) || ((swipeAngle <= 45) && (swipeAngle >= 0)) || ((swipeAngle <= 360) && (swipeAngle >= 315))) // horizontal angles with threshold
{return true; }
else {return false}
}
})(af);
Now, on the CSS file when I change .carousel_dots to #carousel_dots as it was originally. The carousel starts working. The problem is I need it as a class not an ID.
I'm pretty sure the problem is in the jquery, somewhere in there I need to set carousel_dots as a class and not an ID, but where?
Any help will be much apreciated, thanks.
jQuery is designed to trigger on HTML selectors, either elements, ID's or Class's. It's very common for it to trigger on ID's because, as you identified, they occur once and that isolates the action to that particular item.
I know that you changed the ID's to Class's because you want to use the CSS class multiple times. You can do this by using Class's. But, to maintain the jQuery logic, you should not change the ID's to Class's for that purpose. Use the ID's to synch with jQuery. Use Class's to control your CSS.
It's difficult to advise you regarding the case you displayed because you didn't identify the initial status and exactly how you changed it. If you can do that, we can be specific about what changes you should make. Good luck.

Categories

Resources