Canvas only last added object has cursor pointer - javascript

I have a small issue on canvas, when mouse is over element (object) it should change cursor to pointer, when leaves - back to default, but my code doesn't work that way, I've ran out of ideas.
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var canvasOffset = $("#canvas").offset();
var offsetX = canvasOffset.left;
var offsetY = canvasOffset.top;
var rectList = [];
var cursors = ['default', 'pointer'],
currentCursor = 0;
function createRectangle( id, x, y, width, height, fillColor ) {
var newRectangle = {
x,
y,
id,
width,
height,
fillColor,
mouseX: null,
mouseY: null,
isHighlighted: false,
isClicked: false,
cursor: 0, // 0 default, 1 pointer
draw( ) {
drawRect( this.x, this.y, this.width, this.height, this.fillColor )
},
highlight( ) {
crosshair( this.x, this.y, this.width, this.height, 20, 25, 6, 1, 2, 2, 2, 2, 2, '#E15258', '#E15258', '#C25975' );
},
isPointInside( ) {
return (this.mouseX >= this.x && this.mouseX <= this.x + this.width && this.mouseY >= this.y && this.mouseY <= this.y + this.height);
}
}
rectList.push( newRectangle );
}
function crosshair( x, y, width, height, radius1, radius2, endLineWidth, circle1Width, circle2Width, topLineWidth, rightLineWidth, bottomLineWidth, leftLineWidth, circle1Color, circle2Color, linesColor) {
drawCircle(x + width/2, y + height/2, radius1, circle1Width, circle1Color);
drawCircle(x + width/2, y + height/2, radius2, circle2Width, circle2Color);
drawLine(x + radius1 + width/2, y + height/2, x + (radius2 + endLineWidth) + width/2, y + height/2, linesColor, leftLineWidth);
drawLine(x - radius1 + width/2, y + height/2, x - (radius2 + endLineWidth) + width/2, y + height/2, linesColor, rightLineWidth);
drawLine(x + width/2, y + radius1 + height/2, x + width/2, y + (radius2 + endLineWidth) + height/2, linesColor, bottomLineWidth);
drawLine(x + width/2, y - radius1 + height/2, x + width/2, y - (radius2 + endLineWidth) + height/2, linesColor, topLineWidth);
}
function drawLine(startX, startY, endX, endY, color, width) {
ctx.save();
ctx.strokeStyle = color;
ctx.lineWidth = width;
ctx.beginPath();
ctx.moveTo(startX,startY);
ctx.lineTo(endX,endY);
ctx.stroke();
ctx.restore();
}
function drawCircle( x, y, radius, lineWidth, strokeColor ) {
ctx.save();
ctx.beginPath();
ctx.arc( x, y, radius, 0, 2 * Math.PI, false);
ctx.lineWidth = lineWidth;
ctx.strokeStyle = strokeColor;
ctx.stroke();
ctx.restore();
}
function drawBorder( x, y, width, height, lineWidth, strokeColor ) {
ctx.save();
ctx.lineWidth = lineWidth;
ctx.strokeStyle = strokeColor;
ctx.strokeRect( x, y, width, height);
ctx.restore();
}
function drawRect( x, y, width, height, fillColor ) {
ctx.save();
ctx.fillStyle = fillColor;
ctx.fillRect( x, y, width, height );
ctx.restore();
}
document.onmousemove = function( mouse ) {
var mouseX = parseInt(mouse.clientX - offsetX);
var mouseY = parseInt(mouse.clientY - offsetY);
rectList.forEach( rect => {
rect.mouseX = mouseX;
rect.mouseY = mouseY;
if(rect.isPointInside()) {
currentCursor = 1;
if(rect.isClicked) {
rect.isHighlighted = false;
} else {
rect.isHighlighted = true;
}
} else {
rect.isHighlighted = false;
currentCursor = 0;
}
});
canvas.style.cursor = cursors[currentCursor];
}
document.onclick = function( mouse ) {
var mouseX = parseInt(mouse.clientX - offsetX);
var mouseY = parseInt(mouse.clientY - offsetY);
rectList.forEach( rect => {
rect.mouseX = mouseX;
rect.mouseY = mouseY;
if(rect.isPointInside()) {
if(rect.isHighlighted) {
rect.isHighlighted = false;
rect.isClicked = true;
} else {
rect.isClicked = false;
}
} else {
rect.isClicked = false;
}
});
}
function update() {
ctx.clearRect( 0, 0, canvas.width, canvas.height);
rectList.forEach( rect => {
if( rect.isHighlighted ) {
rect.draw();
rect.highlight();
} else {
rect.draw();
}
if( rect.isClicked ) {
rect.draw();
rect.highlight();
} else {
rect.draw();
}
});
requestAnimationFrame(update);
}
function startNewGame() {
createRectangle( 'orange', 25, 25, 30/2, 30/2, 'orange' );
createRectangle( 'green', 50, 50, 30/2, 30/2, 'green' );
createRectangle( 'blue', 75, 75, 30/2, 30/2, 'blue' );
createRectangle( 'yellow', 100, 100, 30/2, 30/2, 'yellow' );
createRectangle( 'lightgreen', 125, 125, 30/2, 30/2, 'lightgreen' );
requestAnimationFrame(update);
}
startNewGame();
canvas {
border: 1px solid black;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<canvas id="canvas" width="400" height="200"></canvas>
I hope this is a small issue and won't cause you a headache. Thanks in advance!

When the mouse is over any other then the last rectangle you set currentCursor directly back to 0 in the next iteration of the ForEach in the onmousemove function.
I fixed it by setting currentCursor to 0 before the loop.
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var canvasOffset = $("#canvas").offset();
var offsetX = canvasOffset.left;
var offsetY = canvasOffset.top;
var rectList = [];
var cursors = ['default', 'pointer'];
function createRectangle( id, x, y, width, height, fillColor ) {
var newRectangle = {
x,
y,
id,
width,
height,
fillColor,
mouseX: null,
mouseY: null,
isHighlighted: false,
isClicked: false,
cursor: 0, // 0 default, 1 pointer
draw( ) {
drawRect( this.x, this.y, this.width, this.height, this.fillColor )
},
highlight( ) {
crosshair( this.x, this.y, this.width, this.height, 20, 25, 6, 1, 2, 2, 2, 2, 2, '#E15258', '#E15258', '#C25975' );
},
isPointInside( ) {
return (this.mouseX >= this.x && this.mouseX <= this.x + this.width && this.mouseY >= this.y && this.mouseY <= this.y + this.height);
}
}
rectList.push( newRectangle );
}
function crosshair( x, y, width, height, radius1, radius2, endLineWidth, circle1Width, circle2Width, topLineWidth, rightLineWidth, bottomLineWidth, leftLineWidth, circle1Color, circle2Color, linesColor) {
drawCircle(x + width/2, y + height/2, radius1, circle1Width, circle1Color);
drawCircle(x + width/2, y + height/2, radius2, circle2Width, circle2Color);
drawLine(x + radius1 + width/2, y + height/2, x + (radius2 + endLineWidth) + width/2, y + height/2, linesColor, leftLineWidth);
drawLine(x - radius1 + width/2, y + height/2, x - (radius2 + endLineWidth) + width/2, y + height/2, linesColor, rightLineWidth);
drawLine(x + width/2, y + radius1 + height/2, x + width/2, y + (radius2 + endLineWidth) + height/2, linesColor, bottomLineWidth);
drawLine(x + width/2, y - radius1 + height/2, x + width/2, y - (radius2 + endLineWidth) + height/2, linesColor, topLineWidth);
}
function drawLine(startX, startY, endX, endY, color, width) {
ctx.save();
ctx.strokeStyle = color;
ctx.lineWidth = width;
ctx.beginPath();
ctx.moveTo(startX,startY);
ctx.lineTo(endX,endY);
ctx.stroke();
ctx.restore();
}
function drawCircle( x, y, radius, lineWidth, strokeColor ) {
ctx.save();
ctx.beginPath();
ctx.arc( x, y, radius, 0, 2 * Math.PI, false);
ctx.lineWidth = lineWidth;
ctx.strokeStyle = strokeColor;
ctx.stroke();
ctx.restore();
}
function drawBorder( x, y, width, height, lineWidth, strokeColor ) {
ctx.save();
ctx.lineWidth = lineWidth;
ctx.strokeStyle = strokeColor;
ctx.strokeRect( x, y, width, height);
ctx.restore();
}
function drawRect( x, y, width, height, fillColor ) {
ctx.save();
ctx.fillStyle = fillColor;
ctx.fillRect( x, y, width, height );
ctx.restore();
}
document.onmousemove = function( mouse ) {
var mouseX = parseInt(mouse.clientX - offsetX);
var mouseY = parseInt(mouse.clientY - offsetY);
var currentCursor = 0;
rectList.forEach(rect => {
rect.mouseX = mouseX;
rect.mouseY = mouseY;
if(rect.isPointInside()) {
currentCursor = 1;
if(rect.isClicked) {
rect.isHighlighted = false;
} else {
rect.isHighlighted = true;
}
} else {
rect.isHighlighted = false;
}
});
canvas.style.cursor = cursors[currentCursor];
}
document.onclick = function( mouse ) {
var mouseX = parseInt(mouse.clientX - offsetX);
var mouseY = parseInt(mouse.clientY - offsetY);
rectList.forEach( rect => {
rect.mouseX = mouseX;
rect.mouseY = mouseY;
if(rect.isPointInside()) {
if(rect.isHighlighted) {
rect.isHighlighted = false;
rect.isClicked = true;
} else {
rect.isClicked = false;
}
} else {
rect.isClicked = false;
}
});
}
function update() {
ctx.clearRect( 0, 0, canvas.width, canvas.height);
rectList.forEach( rect => {
if( rect.isHighlighted ) {
rect.draw();
rect.highlight();
} else {
rect.draw();
}
if( rect.isClicked ) {
rect.draw();
rect.highlight();
} else {
rect.draw();
}
});
requestAnimationFrame(update);
}
function startNewGame() {
createRectangle( 'orange', 25, 25, 30/2, 30/2, 'orange' );
createRectangle( 'green', 50, 50, 30/2, 30/2, 'green' );
createRectangle( 'blue', 75, 75, 30/2, 30/2, 'blue' );
createRectangle( 'yellow', 100, 100, 30/2, 30/2, 'yellow' );
createRectangle( 'lightgreen', 125, 125, 30/2, 30/2, 'lightgreen' );
requestAnimationFrame(update);
}
startNewGame();
canvas {
border: 1px solid black;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<canvas id="canvas" width="400" height="200"></canvas>

Related

Using Canvas to draw multiple polygons but can not get color to be different for polygons

I an issue with the implementation of drawing multiple polygons on a canvas.
I draw the two polygons,
when I move the mouse into the 2nd polygon it turns red and so does the first polygon (the first polygon should be blue). When I move the mouse into the 1st polygon it turns red and so does the 2nd polygon (the 2nd polygon should be blue).
I found the issue with research of each canvas call; adding a ctx.beginPath() fixed the issue. See below:
<canvas id="myCanvas" width=600 height=600 ></canvas>
<script>
canvas = document.getElementById('myCanvas');
ctx = canvas.getContext('2d');
myimage = new Image();
myimage.src = 'https://i.postimg.cc/SNjPPZGJ/farms-map.png';
myimage.onload = draw
const rect = canvas.getBoundingClientRect();
const polypoints1 = [{x: 200, y: 29}, {x: 500, y: 19}, {x: 465, y: 146}, {x: 130, y: 150}];
const polypoints2 = [{x: 200, y: 229}, {x: 500, y: 219}, {x: 465, y: 346}, {x: 130, y: 350}];
var polyColor = [];
var dragPoint = null;
draw();
canvas.addEventListener('mousedown', onMouseDown);
canvas.addEventListener('mousemove', function(evt) {
polyColor[0]="blue";
polyColor[1]="blue";
if (inside({x:evt.clientX - rect.left, y:(evt.clientY + window.scrollY) - rect.top}, polypoints1)){
polyColor[0]="red";
polyColor[1]="blue";}
if (inside({x:evt.clientX - rect.left, y:(evt.clientY + window.scrollY) - rect.top}, polypoints2)){
polyColor[0]="blue";
polyColor[1]="red";}
draw()
}, false);
function inside(p, vs) {
var inside = false;
for (var i = 0, j = vs.length - 1; i < vs.length; j = i++) {
var xi = vs[i].x, yi = vs[i].y;
var xj = vs[j].x, yj = vs[j].y;
var intersect = ((yi > p.y) != (yj > p.y)) && (p.x < (xj - xi) * (p.y - yi) / (yj - yi) + xi);
if (intersect) inside = !inside;
}
return inside;
};
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
if (myimage) {
ctx.drawImage(myimage, 1, 1)
}
drawLines();
polypoints1.forEach(p => drawPoint(p));
polypoints2.forEach(p => drawPoint(p));
}
function drawPoint(p) {
ctx.beginPath();
ctx.globalAlpha = 1
ctx.fillStyle = "black";
ctx.lineWidth = 2;
ctx.arc(p.x, p.y, 5, 0, 2 * Math.PI, false);
ctx.stroke();
ctx.fill();
}
function drawLines() {
ctx.beginPath();
ctx.lineWidth = 2;
polypoints1.forEach(p => ctx.lineTo(p.x, p.y));
ctx.lineTo(polypoints1[0].x, polypoints1[0].y);
ctx.stroke();
if (!dragPoint) {
ctx.globalAlpha = 0.2
ctx.fillStyle = polyColor[0];
ctx.fill();
}
ctx.beginPath();
ctx.lineWidth = 2;
polypoints2.forEach(p => ctx.lineTo(p.x, p.y));
ctx.lineTo(polypoints2[0].x, polypoints2[0].y);
ctx.stroke();
if (!dragPoint) {
ctx.globalAlpha = 0.2
ctx.fillStyle = polyColor[1];
ctx.fill();
}
}
function findDragPoint(x, y) {
for (i = 0; i < polypoints1.length; i++) {
if (hitTest(polypoints1[i], x, y)) return polypoints1[i];
if (hitTest(polypoints2[i], x, y)) return polypoints2[i];
};
return null;
}
function onMouseDown(event) {
dragPoint = findDragPoint(event.clientX - canvas.offsetLeft, event.clientY - canvas.offsetTop + window.scrollY);
if (dragPoint) {
dragPoint.x = event.clientX - canvas.offsetLeft;
dragPoint.y = event.clientY - canvas.offsetTop + window.scrollY;
draw();
canvas.addEventListener("mousemove", onMouseMove);
canvas.addEventListener("mouseup", onMouseUp);
}
}
function onMouseMove(event) {
dragPoint.x = event.clientX - canvas.offsetLeft;
dragPoint.y = event.clientY - canvas.offsetTop+ window.scrollY;
draw();
}
function onMouseUp() {
dragPoint = null;
draw();
canvas.removeEventListener("mousemove", onMouseMove);
canvas.removeEventListener("mouseup", onMouseUp);
}
function hitTest(p, x, y) {
var dx = p.x - x, dy = p.y - y;
return Math.sqrt(dx * dx + dy * dy) <= 10;
}
</script>
I found that you have to use ctx.beginPath() before you start to set up the second polygon. This seems to have addressed the issue.

How to change order of text to appear on arc - context 2d, and stop fill style overwriting on the canvas 2d (using with chart.js)?

So I trying to get build an arc with text on it as rounded rectangle in context 2d but the text is going under it and is getting hidden, also, the fill style for arc is getting overridden by the fill style for text. Here is what I am getting and what I want:
Here is the js fiddle with the code : https://jsfiddle.net/abhishek_soni/vzs6dLy9/19/
Here is the same code :
Html code :
<canvas></canvas>
Js code :
var roundRect = function(ctx, x, y, w, h, r) {
var x2 = x + w;
var y2 = y + h;
if (w < 2 * r) r = w / 2;
if (h < 2 * r) r = h / 2;
ctx.beginPath();
ctx.moveTo(x + r, y);
ctx.arcTo(x2, y, x2, y2, r);
ctx.arcTo(x2, y2, x, y2, r);
ctx.arcTo(x, y2, x, y, r);
ctx.arcTo(x, y, x2, y, r);
};
var canvas = document.querySelector('canvas');
var context = canvas.getContext('2d');
context.save();
roundRect(context, 0, 0, 50, 60, 20);
context.fillStyle = 'red'; // This should work, but it doesn't
context.fill();
context.restore();
context.fillStyle = 'green';
context.fillText('Hey', 50, 80) // if I change this to 50 it hides behind the arc, which I don't want.
context.textAlign = "center";
context.fill();
context.save();
roundRect(context, 100, 100, 50, 90, 20);
context.fillStyle = 'red'; // This should work, but it doesn't
context.fill();
context.restore();
context.fillStyle = 'green';
context.fillText('Hey', 90, 100) // if I change this to 50 it hides behind the arc, which I don't want.
context.textAlign = "center";
context.fill();
context.save();
roundRect(context, 300, 100, 50, 120, 20);
context.fillStyle = 'red'; // This should work, but it doesn't
context.fill();
context.restore();
context.fillStyle = 'green';
context.fillText('Hey', 90, 130) // if I change this to 50 it hides behind the arc, which I don't want.
context.textAlign = "center";
context.fill();
The problem is you are calling fill() after you create the text which you don't need. That fill() is being applied to the shape drawn previously. The purpose of methods like fillText() and fillRect() are to allow you to draw without the need to call fill() after.
Don't call fill after the text and it works.
Next to align your text in the center of the shape I would calculate the center and place the text there and then use context.textAlign = 'center'; to center it.
Here's an example
var canvas = document.querySelector('canvas');
var context = canvas.getContext('2d');
canvas.width = innerWidth;
canvas.height = innerHeight;
let center = {}
var roundRect = function(ctx, x, y, w, h, r) {
var x2 = x + w;
var y2 = y + h;
center = {x: x + w/2, y: y + h/2}
if (w < 2 * r) r = w / 2;
if (h < 2 * r) r = h / 2;
ctx.beginPath();
ctx.moveTo(x + r, y);
ctx.arcTo(x2, y, x2, y2, r);
ctx.arcTo(x2, y2, x, y2, r);
ctx.arcTo(x, y2, x, y, r);
ctx.arcTo(x, y, x2, y, r);
ctx.closePath();
};
context.fillStyle = 'red';
roundRect(context, 0, 0, 50, 60, 20);
context.fill();
context.fillStyle = 'green';
context.textAlign = 'center';
context.fillText('Hey', center.x, center.y);
context.textAlign = "center";
context.fillStyle = 'red';
roundRect(context, 100, 100, 50, 90, 20);
context.fill();
context.fillStyle = 'green';
context.textAlign = 'center';
context.fillText('Hey', center.x, center.y)
context.textAlign = "center";
context.fillStyle = 'red';
roundRect(context, 300, 100, 50, 120, 20);
context.fill();
context.fillStyle = 'green';
context.textAlign = 'center';
context.fillText('Hey', center.x, center.y);
context.textAlign = "center";
<canvas id="canvas"></canvas>
I'm also going to add an example using a class to do this. I prefer this over the other method. If you don't need different color shapes you can get rid of the color argument. And if you want different color text you can add one for that.
var canvas = document.querySelector("canvas");
var ctx = canvas.getContext("2d");
canvas.width = innerWidth;
canvas.height = innerHeight;
class roundRect {
constructor(x, y, w, h, r, c) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.x2 = this.x + this.w;
this.y2 = this.y + this.h;
this.center = { x: x + w / 2, y: y + h / 2 };
this.r = r;
this.color = c;
}
drawShape() {
if (this.w < 2 * this.r) this.r = this.w / 2;
if (this.h < 2 * this.r) this.r = this.h / 2;
ctx.fillStyle = this.color;
ctx.beginPath();
ctx.moveTo(this.x + this.r, this.y);
ctx.arcTo(this.x2, this.y, this.x2, this.y2, this.r);
ctx.arcTo(this.x2, this.y2, this.x, this.y2, this.r);
ctx.arcTo(this.x, this.y2, this.x, this.y, this.r);
ctx.arcTo(this.x, this.y, this.x2, this.y, this.r);
ctx.closePath();
ctx.fill();
}
drawText() {
ctx.fillStyle = 'green';
ctx.textAlign = "center";
ctx.textBaseline = 'middle';
ctx.fillText("Hey", this.center.x, this.center.y);
}
}
let rect1 = new roundRect(0, 0, 50, 60, 20, 'red', 'Text')
let rect2 = new roundRect(60, 0, 50, 80, 20, 'lightblue', 'Text')
let rect3 = new roundRect(120, 0, 50, 100, 20, 'lightgreen', 'Text')
rect1.drawShape();
rect1.drawText();
rect2.drawShape();
rect2.drawText();
rect3.drawShape();
rect3.drawText();
<canvas id="canvas"></canvas>
EDIT:
To rotate your text use the following.
var canvas = document.querySelector('canvas');
var context = canvas.getContext('2d');
canvas.width = innerWidth;
canvas.height = innerHeight;
let center = {}
var roundRect = function(ctx, x, y, w, h, r) {
var x2 = x + w;
var y2 = y + h;
center = {x: x + w/2, y: y + h/2}
if (w < 2 * r) r = w / 2;
if (h < 2 * r) r = h / 2;
ctx.beginPath();
ctx.moveTo(x + r, y);
ctx.arcTo(x2, y, x2, y2, r);
ctx.arcTo(x2, y2, x, y2, r);
ctx.arcTo(x, y2, x, y, r);
ctx.arcTo(x, y, x2, y, r);
ctx.closePath();
};
context.fillStyle = 'red';
roundRect(context, 0, 0, 50, 60, 20);
context.fill();
context.fillStyle = 'green';
context.textAlign = 'center';
context.fillText('Hey', center.x, center.y);
context.textAlign = "center";
context.fillStyle = 'red';
roundRect(context, 100, 100, 50, 90, 20);
context.fill();
context.fillStyle = 'green';
context.textAlign = 'center';
context.textBaseline = 'middle';
context.save() //save before you transform something
context.translate(center.x, center.y) //use this to position
context.rotate(degToRad(90)) //rotate here using degrees
context.fillText('Hey', 0, 0) //draw this a (0, 0)
context.fillStyle = 'lightblue'; //delete this
context.fillRect(0, 0, canvas.width, canvas.height) //and this
context.restore() //restore when done with all objects you want affected
context.textAlign = "center";
context.fillStyle = 'red';
roundRect(context, 300, 100, 50, 120, 20);
context.fill();
context.fillStyle = 'green';
context.textAlign = 'center';
context.fillText('Hey', center.x, center.y);
context.textAlign = "center";
function degToRad(deg) {
return deg * (Math.PI/180)
}
<canvas id="canvas"></canvas>

How to add element with circular motion on HTML5 canvas using JavaScript that provides function when something goes near it?

Here is my current HTML file
<!DOCTYPE html>
<html>
<head>
<title>Space Ship</title>
<style type="text/css">
canvas{
border: 1px solid black;
}
body{
margin: 0;
}
</style>
</head>
<body>
<canvas id="game"></canvas>
<script src="game.js"></script>
</body>
</html>
And here is my current JS file which is where I make all the changes to the canvas
(function () {
const canvas = document.getElementById('game');
const context = canvas.getContext('2d');
const SPACESHIP_SIZE = { width: 15, height: 25 };
const SPACESHIP_POSITION = { x: window.innerWidth/2, y: window.innerHeight/2};
const GRAVITY = 0;
//Update thrust constant
const THRUST = 15;
class SpaceShip {
constructor(size, position) {
this.color = 'yellow';
this.size = size;
this.position = position;
this.angle = 0;
this.engineOn = false;
this.rotatingLeft = false;
this.rotatingRight = false;
this.velocity = {
x: 0,
y: 0,
};
}
draw() {
const triangleCenterX = this.position.x + 0.5 * this.size.width;
const triangleCenterY = this.position.y + 0.5 * this.size.height;
context.save();
context.translate(triangleCenterX, triangleCenterY);
context.rotate(this.angle);
context.lineWidth = 5;
context.beginPath();
// Triangle
context.moveTo(0, -this.size.height / 2);
context.lineTo(-this.size.width / 2, this.size.height / 2);
context.lineTo(this.size.width / 2, this.size.height / 2);
context.closePath();
context.strokeStyle = this.color;
context.stroke();
context.fillStyle = "red";
context.fill();
// Flame for engine
if (this.engineOn) {
const fireYPos = this.size.height / 2 + 4;
const fireXPos = this.size.width * 0.25;
context.beginPath();
context.moveTo(-fireXPos, fireYPos);
context.lineTo(fireXPos, fireYPos);
context.lineTo(0, fireYPos + Math.random() * 100);
context.lineTo(-fireXPos, fireYPos);
context.closePath();
context.fillStyle = 'orange';
context.fill();
}
context.restore();
}
moveSpaceShip() {
// Angle has to be in radians
const degToRad = Math.PI / 180;
// Change the position based on velocity
this.position.x += this.velocity.x;
this.position.y += this.velocity.y;
// Move spaceship to other side when leaving screen
this.position.x = (canvas.width + this.position.x) % canvas.width;
this.position.y = (canvas.height + this.position.y) % canvas.height;
/*
Adding floating point numbers to the end of the
rotaion handling to make roation faster
*/
if (this.rotatingLeft) this.angle -= (degToRad+.1);
if (this.rotatingRight) this.angle += (degToRad+.1);
// Acceleration
if (this.engineOn) {
this.velocity.x += (THRUST / 100) * Math.sin(this.angle);
this.velocity.y -= (THRUST / 100) * Math.cos(this.angle);
}
// Update the velocity depending on gravity
this.velocity.y += GRAVITY / 2500;
}
}
const spaceShip = new SpaceShip(SPACESHIP_SIZE, SPACESHIP_POSITION);
function handleKeyInput(event) {
const { keyCode, type } = event;
const isKeyDown = type === 'keydown' ? true : false;
if (keyCode === 37) spaceShip.rotatingLeft = isKeyDown;
if (keyCode === 39) spaceShip.rotatingRight = isKeyDown;
if (keyCode === 38) spaceShip.engineOn = isKeyDown;
}
function draw() {
console.log('drawing');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
// Clear screen
context.fillStyle = 'rgb(0, 10, 60)';
context.fillRect(0, 0, window.innerWidth, canvas.height);
context.font = "30px Arial";
context.fillText("Hello World", window.innerWidth, window.innerHeight);
//Loading small stars
for (var i = 1; i<window.innerWidth; i+=100){
for(var j = 1; j<window.innerHeight; j+=100){
context.beginPath();
context.arc(i, j, 1, 0, Math.PI*2, false);
context.fillStyle = 'white';
context.fill();
context.stroke();
}
}
//loading medium stars
for (var i = 1; i<window.innerWidth; i+=150){
for(var j = 1; j<window.innerHeight; j+=150){
context.beginPath();
context.arc(i, j, 2, 0, Math.PI*2, false);
context.fillStyle = 'white';
context.fill();
context.stroke();
}
}
//loading larger stars
for (var i = 1; i<window.innerWidth; i+=225){
for(var j = 1; j<window.innerHeight; j+=225){
context.beginPath();
context.arc(i, j, 3, 0, Math.PI*2, false);
context.fillStyle = 'white';
context.fill();
context.stroke();
}
}
spaceShip.moveSpaceShip();
// Begin drawing
spaceShip.draw();
// Repeats
requestAnimationFrame(draw);
}
// Event Listeners
document.addEventListener('keydown', handleKeyInput);
document.addEventListener('keyup', handleKeyInput);
// Start the game
draw();
})();
The output works and looks like this...
Little rocket that flies around in space and it works perfectly fine
Now the issue I have is that I want to add elements that represent black holes which spin in a circular motion. When the spaceship which is controlled by the arrow keys hovers over one of these spinning "black hole" like objects, I want to prompt the user to click "enter" in order to go to a new area and space which means they will be redirected to a new canvas (which will just be a different version of the one you see here.
I have no ideas on how to go about adding one of these objects onto the canvas and then give it this function. Does anyone know how to?
Im sure its not as difficult as i'm making it seem, I just don't have that much experience using JavaScript and an HTML5 canvas. Thanks.
const canvas = document.getElementById('game');
const ctx = canvas.getContext('2d');
canvas.width = window.innerWidth - 4;
canvas.height = window.innerHeight - 4;
ctx.font = "30px Arial";
ctx.shadowColor = "rgba(255,255,255,.6)";
// Constants in objects doesnt work cause objects passing as reference and will by modified!
// If you want constant constant, use primitives
const SPACESHIP_SIZE = { width: 15, height: 25 };
const SPACESHIP_POSITION = { x: window.innerWidth/2, y: window.innerHeight/2};
const GRAVITY = 0;
const HOVER_TICKS = 80;
//Update thrust constant
const THRUST = 15;
const Systems = {
'main': {
holes:[
{x: 100, y: 350, size: 20, dest: 'J204853'},
{x: 550, y: 50, size: 20, dest: 'J111000'},
{x: 400, y: 150, size: 30, dest: 'J235456'},
{x: 300, y: 100, size: 20, dest: 'Jita'},
{x: 200, y: 400, size: 10, dest: 'Amarr'},
{x: 450, y: 300, size: 20, dest: 'Thera'},
]
},
'J204853': {holes:[{x: 550, y: 50, size: 30, dest: 'main'}]},
'J235456': {holes:[{x: 350, y: 70, size: 20, dest: 'main'}]},
'J111000': {holes:[{x: 150, y: 150, size: 10, dest: 'main'}]},
'Amarr': {holes:[{x: 350, y: 270, size: 30, dest: 'main'}]},
'Thera': {holes:[{x: 250, y: 170, size: 40, dest: 'main'}]},
'Jita': {holes:[{x: 450, y: 250, size: 20, dest: 'main'}]},
};
let spaceShip;
let currentSystem = 'main';
const spaceObjects = [];
class SpaceObject {
constructor(size, position, color = 'black', angle = 0) {
this.color = color;
this.size = size;
this.position = position;
this.angle = angle;
spaceObjects.push(this);
}
tick() {
this.update();
this.draw();
}
update() {}
draw() {}
isAbove({x, y}) {
return Math.abs(this.position.x - x) < this.size && Math.abs(this.position.y - y) < this.size;
}
destroy() {
spaceObjects.splice(spaceObjects.indexOf(this), 1);
}
}
class SpaceShip extends SpaceObject {
constructor(size, position) {
super(size, position, 'yellow');
this.aboveHole = 0;
this.engineOn = false;
this.rotatingLeft = false;
this.rotatingRight = false;
this.velocity = {x: 0, y: 0};
}
draw() {
const triangleCenterX = this.position.x + 0.5 * this.size.width;
const triangleCenterY = this.position.y + 0.5 * this.size.height;
ctx.shadowBlur = 0;
ctx.save();
ctx.translate(triangleCenterX, triangleCenterY);
ctx.rotate(this.angle);
ctx.lineWidth = 5;
ctx.beginPath();
// Triangle
ctx.moveTo(0, -this.size.height / 2);
ctx.lineTo(-this.size.width / 2, this.size.height / 2);
ctx.lineTo(this.size.width / 2, this.size.height / 2);
ctx.closePath();
ctx.strokeStyle = this.color;
ctx.stroke();
ctx.fillStyle = "red";
ctx.fill();
// Flame for engine
if (this.engineOn) {
const fireYPos = this.size.height / 2 + 4;
const fireXPos = this.size.width * 0.25;
ctx.beginPath();
ctx.moveTo(-fireXPos, fireYPos);
ctx.lineTo(fireXPos, fireYPos);
ctx.lineTo(0, fireYPos + Math.random() * 100);
ctx.lineTo(-fireXPos, fireYPos);
ctx.closePath();
ctx.fillStyle = 'orange';
ctx.fill();
}
ctx.restore();
}
update() {
this.moveSpaceShip();
this.checkAboveHole();
}
moveSpaceShip() {
// Angle has to be in radians
const degToRad = Math.PI / 180;
// Change the position based on velocity
this.position.x += this.velocity.x;
this.position.y += this.velocity.y;
// Move spaceship to other side when leaving screen
this.position.x = (canvas.width + this.position.x) % canvas.width;
this.position.y = (canvas.height + this.position.y) % canvas.height;
/*
Adding floating point numbers to the end of the
rotaion handling to make roation faster
*/
if (this.rotatingLeft) this.angle -= (degToRad+.1);
if (this.rotatingRight) this.angle += (degToRad+.1);
// Acceleration
if (this.engineOn) {
this.velocity.x += (THRUST / 100) * Math.sin(this.angle);
this.velocity.y -= (THRUST / 100) * Math.cos(this.angle);
}
// Update the velocity depending on gravity
this.velocity.y += GRAVITY / 2500;
}
checkAboveHole() {
const hole = spaceObjects.find(spaceObject => spaceObject !== this && spaceObject.isAbove(this.position));
if(hole) {
this.aboveHole++;
if(this.aboveHole > HOVER_TICKS) {
confirm(`Jump to system ${hole.dest}?`) && jump(hole);
this.aboveHole = 0;
}
} else {
this.aboveHole = 0;
}
}
}
const circle = (ctx, x, y, radius, color = 'white') => {
ctx.beginPath();
ctx.arc(x, y, radius, 0, Math.PI*2, false);
ctx.fillStyle = color;
ctx.fill();
ctx.stroke();
ctx.closePath();
};
class BlackHole extends SpaceObject {
constructor(size, position, dest) {
super(size, position);
this.dest = dest;
}
update() {
// Spin?
this.angle+=.01;
}
draw() {
// Shadow
ctx.shadowBlur = this.size >>> 2;
circle(ctx, this.position.x, this.position.y, this.size + 1, `rgba(255, 255, 255, .6)`);
// Hole
circle(ctx, this.position.x, this.position.y, this.size, this.color);
// Spinning view
circle(ctx, this.position.x + (this.size * Math.sin(this.angle) - 1), this.position.y + (this.size * Math.cos(this.angle) - 1), 2, 'gray');
circle(ctx, this.position.x - (this.size * Math.sin(this.angle) - 1), this.position.y - (this.size * Math.cos(this.angle) - 1), 2, 'gray');
}
}
function handleKeyInput(event) {
const { keyCode, type } = event;
const isKeyDown = type === 'keydown' ? true : false;
if (keyCode === 37) spaceShip.rotatingLeft = isKeyDown;
if (keyCode === 39) spaceShip.rotatingRight = isKeyDown;
if (keyCode === 38) spaceShip.engineOn = isKeyDown;
}
function jump({dest}) {
currentSystem = dest || 'main';
while(spaceObjects.length) spaceObjects[0].destroy();
Systems[currentSystem].holes.forEach(hole => new BlackHole(hole.size, {x: hole.x, y: hole.y}, hole.dest));
spaceShip = new SpaceShip(SPACESHIP_SIZE, SPACESHIP_POSITION);
}
function draw() {
// Clear screen
ctx.fillStyle = 'rgb(0, 10, 60)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = 'rgb(150, 150, 150)';
ctx.fillText(`You are in system ${currentSystem}`, 40, 40);
//Loading small stars
ctx.shadowBlur = 1;
for (var i = 1, j = 1; j<canvas.height; i+=100, i > canvas.width && (i=1, j+=100), circle(ctx, i, j, 1));
//loading medium stars
ctx.shadowBlur = 2;
for (var i = 1, j = 1; j<canvas.height; i+=150, i > canvas.width && (i=1, j+=150), circle(ctx, i, j, 2));
//loading larger stars
ctx.shadowBlur = 3;
for (var i = 1, j = 1; j<canvas.height; i+=225, i > canvas.width && (i=1, j+=225), circle(ctx, i, j, 3));
// tick all objects
spaceObjects.forEach(spaceObject => spaceObject.tick());
// Repeats
requestAnimationFrame(draw);
}
// Event Listeners
document.addEventListener('keydown', handleKeyInput);
document.addEventListener('keyup', handleKeyInput);
// Start the game
jump({dest: 'main'});
draw();
<!DOCTYPE html>
<html>
<head>
<title>Space Ship</title>
<style type="text/css">
canvas{
border: 1px solid black;
}
body{
margin: 0;
}
</style>
</head>
<body>
<canvas id="game"></canvas>
</body>
</html>

mouse coordinates in canvas not working

var canvas=document.getElementById('canvas');
var ctx=canvas.getContext("2d");
var mouseX=0;
var mouseY=0;
var canvasPos=getPosition(canvas);
ctx.addEventListener("mousemove",setMousePosition,false);
function getPosition(e1) {
var xPosition = 0;
var yPosition = 0;
while (e1) {
xPosition += (e1.offsetLeft - e1.scrollLeft + e1.clientLeft);
yPosition += (e1.offsetTop - e1.scrollTop + e1.clientTop);
e1 = e1.offsetParent;
}
return { x: xPosition, y: yPosition };
}
function setMousePosition(e) {
mouseX = e.clientX - canvasPos.x;
mouseY = e.clientY - canvasPos.y;
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.beginPath();
ctx.arc(mouseX, mouseY, 50, 0, 2 * Math.PI, true);
ctx.fillStyle = "#FF6A6A";
ctx.fill();
ctx.closePath();
}
function getPosition(e1) {
var xPosition=0;
var yPosition=0;
while(e1) {
xPosition+=(e1.offsetLeft-e1.scrollLeft+e1.clientLeft);
yPosition+=(e1.offsetTop-e1.scrollTop+e1.clientTop);
e1=e1.offsetParent;
}
return {
x: xPosition,
y: yPosition
};
}
<canvas id="canvas"></canvas>
The goal is for a canvas element to follow the mouse movement. My attempt is pasted above. I tried retrieving the exact mouse coordinates and used it to re-draw the element. I don't seem to be getting any output, only a blank canvas. Any help is appreciated.
You had 2 typos:
var context...
ctx.addEventListener(...)
The: ctx.addEventListener() is not possible because of the context has no events.
The canvas does have those.
var canvas=document.getElementById('canvas');
// edit from context to ctx
var ctx=canvas.getContext("2d");
var mouseX=0;
var mouseY=0;
var canvasPos=getPosition(canvas);
// edit ctx to canvas
canvas.addEventListener("mousemove",setMousePosition,false);
function getPosition(e1) {
var xPosition = 0;
var yPosition = 0;
while (e1) {
xPosition += (e1.offsetLeft - e1.scrollLeft + e1.clientLeft);
yPosition += (e1.offsetTop - e1.scrollTop + e1.clientTop);
e1 = e1.offsetParent;
}
return { x: xPosition, y: yPosition };
}
function setMousePosition(e) {
mouseX = e.clientX - canvasPos.x;
mouseY = e.clientY - canvasPos.y;
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.beginPath();
ctx.arc(mouseX, mouseY, 50, 0, 2 * Math.PI, true);
ctx.fillStyle = "#FF6A6A";
ctx.fill();
ctx.closePath();
}
function getPosition(e1) {
var xPosition=0;
var yPosition=0;
while(e1) {
xPosition+=(e1.offsetLeft-e1.scrollLeft+e1.clientLeft);
yPosition+=(e1.offsetTop-e1.scrollTop+e1.clientTop);
e1=e1.offsetParent;
}
return {
x: xPosition,
y: yPosition
};
}
<canvas id="canvas"></canvas>
You've to add event listener to canvas not to its context
var canvas=document.getElementById('canvas');
var ctx=canvas.getContext("2d");
var mouseX=0;
var mouseY=0;
var canvasPos=getPosition(canvas);
canvas.addEventListener("mousemove",setMousePosition,false); // <-- this
function getPosition(e1) {
var xPosition = 0;
var yPosition = 0;
while (e1) {
xPosition += (e1.offsetLeft - e1.scrollLeft + e1.clientLeft);
yPosition += (e1.offsetTop - e1.scrollTop + e1.clientTop);
e1 = e1.offsetParent;
}
return { x: xPosition, y: yPosition };
}
function setMousePosition(e) {
mouseX = e.clientX - canvasPos.x;
mouseY = e.clientY - canvasPos.y;
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.beginPath();
ctx.arc(mouseX, mouseY, 50, 0, 2 * Math.PI, true);
ctx.fillStyle = "#FF6A6A";
ctx.fill();
ctx.closePath();
}
function getPosition(e1) {
var xPosition=0;
var yPosition=0;
while(e1) {
xPosition+=(e1.offsetLeft-e1.scrollLeft+e1.clientLeft);
yPosition+=(e1.offsetTop-e1.scrollTop+e1.clientTop);
e1=e1.offsetParent;
}
return {
x: xPosition,
y: yPosition
};
}
<canvas id="canvas"></canvas>

HTML5 Canvas Javascript how to make smooth brush

Hello i need make smooth brush likes this:
I try to create it, i make circle and fill it, but result not successful:
Can be seen circles.. this is not smooth like first example
my example code:
function distanceBetween(point1, point2) {
return Math.sqrt(Math.pow(point2.x - point1.x, 2) + Math.pow(point2.y - point1.y, 2));
}
function angleBetween(point1, point2) {
return Math.atan2( point2.x - point1.x, point2.y - point1.y );
}
var el = document.getElementById('c');
var ctx = el.getContext('2d');
//ctx.fillStyle = "rgba('255, 0, 0, 0.1')";
ctx.fillStyle = "red";
ctx.strokeStyle = "red";
ctx.globalAlpha = "0.05";
ctx.lineWidth = 0;
ctx.globalCompositeOperation = "source-over";
var isDrawing, lastPoint;
el.onmousedown = function(e) {
isDrawing = true;
lastPoint = { x: e.clientX, y: e.clientY };
};
el.onmousemove = function(e) {
if (!isDrawing) return;
var currentPoint = { x: e.clientX, y: e.clientY };
var dist = distanceBetween(lastPoint, currentPoint);
var angle = angleBetween(lastPoint, currentPoint);
for (var i = 0; i < dist; i+=5) {
x = lastPoint.x + (Math.sin(angle) * i) - 25;
y = lastPoint.y + (Math.cos(angle) * i) - 25;
ctx.beginPath();
ctx.arc(x+10, y+10, 20, false, Math.PI * 2, false);
ctx.closePath();
ctx.fill();
ctx.stroke();
}
lastPoint = currentPoint;
};
el.onmouseup = function() {
isDrawing = false;
};
function clearit() {
ctx.clearRect(0,0, 1000, 1000);
}
canvas { border: 1px solid #ccc }
<canvas id="c" width="500" height="300"></canvas>
<input type="button" id="clear-btn" value="Clear it" onclick="clearit()">
http://codepen.io/anon/pen/NPjwry
Try with a smaller globalAlpha and decrease the stepping (so you draw more circles)
function distanceBetween(point1, point2) {
return Math.sqrt(Math.pow(point2.x - point1.x, 2) + Math.pow(point2.y - point1.y, 2));
}
function angleBetween(point1, point2) {
return Math.atan2( point2.x - point1.x, point2.y - point1.y );
}
var el = document.getElementById('c');
var ctx = el.getContext('2d');
//ctx.fillStyle = "rgba('255, 0, 0, 0.1')";
ctx.fillStyle = "red";
ctx.strokeStyle = "red";
ctx.globalAlpha = "0.01";
ctx.lineWidth = 0;
ctx.globalCompositeOperation = "source-over";
var isDrawing, lastPoint;
el.onmousedown = function(e) {
isDrawing = true;
lastPoint = { x: e.clientX, y: e.clientY };
};
el.onmousemove = function(e) {
if (!isDrawing) return;
var currentPoint = { x: e.clientX, y: e.clientY };
var dist = distanceBetween(lastPoint, currentPoint);
var angle = angleBetween(lastPoint, currentPoint);
for (var i = 0; i < dist; i+=3) {
x = lastPoint.x + (Math.sin(angle) * i) - 25;
y = lastPoint.y + (Math.cos(angle) * i) - 25;
ctx.beginPath();
ctx.arc(x+10, y+10, 20, false, Math.PI * 2, false);
ctx.closePath();
ctx.fill();
ctx.stroke();
}
lastPoint = currentPoint;
};
el.onmouseup = function() {
isDrawing = false;
};
function clearit() {
ctx.clearRect(0,0, 1000, 1000);
}
canvas { border: 1px solid #ccc }
<canvas id="c" width="500" height="300"></canvas>
<input type="button" id="clear-btn" value="Clear it" onclick="clearit()">
Updated codepen: http://codepen.io/gpetrioli/pen/ramqBz
There is more simple solution: just set width of line to 25px
let ctx = this.d.transparentUpdateImage.getContext('2d');
if (!this.lastPos) {
this.lastPos = {x: x, y: y};
return
}
ctx.beginPath();
ctx.moveTo(this.lastPos.x, this.lastPos.y);
ctx.lineCap = 'round';
ctx.lineJoin = 'round';
ctx.strokeStyle = 'red';
ctx.lineWidth = 25;
ctx.lineTo(x, y);
ctx.stroke();
ctx.closePath();
this.lastPos = {x: x, y: y};

Categories

Resources