I have a red circle with a blue circle circling around it. I am trying to move the red circle in the direction of the blue circle when the mouse button is pressed.
But it currently only moves once.
I would like to have it moving continually while I press the mouse button, so that it keeps moving towards the direction of where the blue circle happens to be, keeping the blue circle ahead of it (and not circling) for as long as the mouse button is down.
Here is my code. Click the mouse button to see the reaction of the red circle:
const canvas = document.getElementById('canvas1');
const ctx = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
let positionX = 100;
let positionY = 100;
let X = 50;
let Y = 50;
let angle = 0;
canvas.addEventListener('mousedown', function(){
X += positionX;
Y += positionY;
})
function circle(){
ctx.fillStyle = 'red';
ctx.beginPath();
ctx.arc(X, Y, 20, 0, Math.PI*2);
ctx.closePath();
ctx.fill();
}
function direction(){
ctx.fillStyle = 'blue';
ctx.beginPath();
ctx.arc(positionX + X, positionY + Y, 10, 0, Math.PI*2);
ctx.closePath();
positionX = 35 * Math.sin(angle);
positionY = 35 * Math.cos(angle);
angle += 0.1;
ctx.fill();
}
function animate(){
ctx.clearRect(0,0, canvas.width, canvas.height);
circle();
direction();
requestAnimationFrame(animate);
}
animate();
#canvas1{
position: absolute;
top:0;
left: 0;
width: 100%;
height: 100%;
}
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="style.css">
</head>
<body>
<canvas id="canvas1"></canvas>
<script src="script.js"></script>
</body>
</html>
If you want to continually have the red circle move towards the blue one, for as long as the mouse button is down, then you need to maintain the state of the mouse button. You can do that by keeping a global flag updated with a handler for the mousedown and the mouseup event.
Then move the code that updates X and Y into the animation loop: make that update when the flag is true (when the mouse button is down). On the other hand, only update the angle (for the blue circle) when the mouse button is not down:
const canvas = document.getElementById('canvas1');
const ctx = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
let positionX = 100;
let positionY = 100;
let X = 50;
let Y = 50;
let angle = 0;
let mouseButtonDown = false;
document.addEventListener('mousedown', () => mouseButtonDown = true);
document.addEventListener('mouseup', () => mouseButtonDown = false);
function circle(){
ctx.fillStyle = 'red';
ctx.beginPath();
ctx.arc(X, Y, 20, 0, Math.PI*2);
ctx.closePath();
ctx.fill();
}
function direction(){
ctx.fillStyle = 'blue';
ctx.beginPath();
ctx.arc(positionX + X, positionY + Y, 10, 0, Math.PI*2);
ctx.closePath();
positionX = 35 * Math.sin(angle);
positionY = 35 * Math.cos(angle);
ctx.fill();
}
function animate(){
if (mouseButtonDown) {
X += positionX / 10;
Y += positionY / 10;
} else {
angle += 0.1;
}
ctx.clearRect(0,0, canvas.width, canvas.height);
circle();
direction();
requestAnimationFrame(animate);
}
animate();
#canvas1{
position: absolute;
top:0;
left: 0;
width: 100%;
height: 100%;
}
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="style.css">
</head>
<body>
<canvas id="canvas1"></canvas>
<script src="script.js"></script>
</body>
</html>
I have resizable rectangle, and I wish to have right-aligned text (day numbers) next to it.
what I have now:
(also when resizing the text does not really align vertically)
what I wish to have:
Is there a way to fill the text and align it inside a drawn rectangle? Other suggestions are welcome too.
js.do code
function dayRect(day) {
const days = ["I","II","III","IV","V","VI","VII"];
context.beginPath();
//maybe align the text inside this rect somehow
context.rect(0, day*h/7, 3*w/27, h/7);
context.stroke();
context.font = "0.5rem Arial";
context.fillStyle = "#fff";
context.fillText(days[day], 0, (day+1)*h/7);
}
I've changed a few things in your code since I wasn't able to see anything. You need to use context.textAlign="right" for your text and move it to a different position. I hope it helps.
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
var canvas = document.getElementById("posHourCanvas");
var context = canvas.getContext('2d');
canvas.width=600,canvas.height=300;
var boxes = [];
function init() {
context.clearRect(0, 0, canvas.width, canvas.height);
boxes.length = 0;
const strokeWidth = 0.6;
//canvas.width = $('#two')[0].clientWidth;
var cellSize = canvas.width/27;
canvas.height = 7/27 * canvas.width;
var x = y = 0;
draw(x,y,canvas.width,canvas.height,cellSize,strokeWidth);
}
function Box(x, y, day, hour) {
this.x = x;
this.y = y;
this.day = day;
this.hour = hour;
}
function draw(x, y, w, h, cellSize, strokeWidth) {
let onePixel = cellSize * strokeWidth;
cellSize = cellSize * (1 - strokeWidth);
context.beginPath();
context.lineWidth = 1;
context.strokeStyle = 'rgba(0, 0, 0, 1)';
const rectCoordinates = {
x: x+3*w/27,
y: y,
w: w-3*w/27,
h: h
}
context.rect(rectCoordinates.x, y, rectCoordinates.w, h);
context.fillStyle = 'white';
context.fill();
context.stroke();
let offX = rectCoordinates.w/24 + rectCoordinates.x;
let offY = h/7;
for (let i = 0; i < 7; i++) {
dayRect(i);
context.beginPath();
context.moveTo(0, offY);
context.lineTo(w, offY);
context.strokeStyle = "black";
context.stroke();
offY+=h/7;
}
for (let i = 0; i < 24; i++) {
context.beginPath();
context.moveTo(offX, 0);
context.lineTo(offX, h);
context.stroke();
offX+=rectCoordinates.w/24;
}
function dayRect(day) {
const days = ["I","II","III","IV","V","VI","VII"];
context.beginPath();
context.rect(0, day*h/7, 3*w/27, h/7);
context.stroke();
context.font = "0.5rem Arial";
context.fillStyle = "#fff";
context.textAlign="right";
context.fillText(days[day], 60, (day+1)*h/7);
}
}
init();
body {
margin: auto;
color: white;
background-color: black;
min-height: 100vh;
}
<div id="parent">
<div>text above</div>
<div id="two">
<canvas id="posHourCanvas" width="600" height="300"></canvas>
</div>
<div>text under</div>
</div>
I drew various shapes and text on my canvas, but nothing is showing in the browser. There are no errors in Chrome's console. I opened it in another browser, thinking it may have been a problem with cache, but still nothing except the "Draw Canvas" button shows. Here it is in jsfiddle: https://jsfiddle.net/0Lakv2do/
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
#content-wrapper {
width: 600px;
margin: 0 auto;
text-align: center;
}
#canvasRun {
background-color: #c00;
border: 0;
color: #fff;
}
</style>
</head>
<body>
<div id="content-wrapper">
<button id="canvasRun">Draw Canvas</button><br><br>
<canvas id="myCanvas" width="600" height="450"></canvas>
</div>
<script type="text/javascript">
var contentWrapper = document.getElementById('contentWrapper');
var runButton = document.getElementById('canvasRun');
var canvas = document.getElementById('myCanvas');
myCanvas.style.visibility="hidden";
runButton.addEventListener('click', showCanvas, false);
function showCanvas() {
myCanvas.style.visibility = "visible";
if (myCanvas.getContext){
var logo = new Image();
logo.src = 'IIT_SAT_stack_186_white.png';
function renderMyCanvas() {
var ctx = canvas.getContext('2d');
var linearGrad = ctx.createLinearGradient(0,0,0,450);
linearGrad.addColorStop(0, 'white');
linearGrad.addColorStop(1, 'black');
ctx.fillStyle=linearGrad;
ctx.fillRect(0,20,600,450);
ctx.font = "32px sans-serif";
ctx.fillStyle = 'red';
ctx.fillText("ITMD 565 Canvas Lab", 135, 75);
ctx.beginPath();
ctx.moveTo(15, 90);
ctx.lineTo(580, 90);
ctx.lineWidth = 3;
ctx.strokeStyle = 'red';
ctx.closePath();
ctx.stroke();
ctx.font = "14px sans-serif";
ctx.fillStyle = 'white';
ctx.fillText("", 15, 410);
ctx.fillText("", 15, 430);
ctx.drawImage(logo, 300, 360, 250, 60);
ctx.fillStyle= 'white';
ctx.fillRect(250, 250, 310, 100);
var x = canvas.width / 2;
var y = canvas.height / 2;
var radius = 75;
var startAngle = 1.1 * Math.PI;
var endAngle = 1.9 * Math.PI;
var counterClockwise = false;
ctx.beginPath();
ctx.arc(x, y, radius, startAngle, endAngle, counterClockwise);
ctx.lineWidth = 15;
ctx.arc.strokeStyle = 'yellow';
ctx.stroke();
ctx.setLineDash([10, 10]);
ctx.beginPath();
ctx.moveTo(270,300);
ctx.quadraticCurveTo(330, 220, 395, 300, 395, 300);
ctx.strokeStyle = 'black';
ctx.stroke();
ctx.beginPath();
ctx.moveTo(395, 300);
ctx.quadraticCurveTo(450, 375, 540, 300);
ctx.strokeStyle = 'black';
ctx.stroke();
}
}
}
</script>
</body>
</html>
You have just copy/pasted a function inside your other function and you don't ever call it. You also have a different variable canvas there while in the outer one you have myCanvas.
When copy/pasting make sure you actually know what you are copying and how it works.
See a Fiddle with the function definition removed and the variable name fixed.
I am trying to make a screen following the player so that the player is in the middle of the screen. I have already made it in another game, but here it doesn't work. Here is my code :
var c = document.getElementById("main");
var ctx = c.getContext("2d");
var screen = document.getElementById("screen").getContext("2d");
var WhatUSeeWidth = document.getElementById("screen").width;
var WhatUSeeHeight = document.getElementById("screen").height;
ctx.beginPath();
for (i = 0; i < 100; i ++) {
if (i % 2) {
ctx.fillStyle = "red";
}
else {
ctx.fillStyle = "blue";
}
ctx.fillRect(0, i * 100, 500, 100);
}
var player = {
x : 700,
y : 800
}
setInterval(tick, 100);
function tick() {
screen.beginPath();
screen.drawImage(c, player.x - WhatUSeeWidth / 2, player.y - WhatUSeeHeight / 2, WhatUSeeWidth, WhatUSeeHeight, 0, 0, WhatUSeeWidth, WhatUSeeHeight);
}
canvas {
border: 2px solid black;
}
<canvas id="main" width="500" height="500"h></canvas>
<canvas id="screen" width="500" height="500"></canvas>
I want to draw The Blue and red canvas in The "screen" canvas Using drawImage
Ok , from your comment I understood what you are looking for. But the problem is that you probably start by an example without having understood. I try to give you my interpretation of what you do , but you should look for a good guide that starts with the basics and deepen animations (for example this: http://www.html5canvastutorials.com/).
HTML
<canvas id="canvasLayer" width="500" height="500"></canvas>
Javascript
var canvas = document.getElementById("canvasLayer");
var context = canvas.getContext("2d");
var WhatUSeeWidth = document.getElementById("canvasLayer").width;
var WhatUSeeHeight = document.getElementById("canvasLayer").height;
var player = {
x : 0,
y : 0
}
function drawBackground() {
for (i = 0; i < 100; i ++) {
if (i % 2) {
context.fillStyle = "red";
}
else {
context.fillStyle = "blue";
}
context.fillRect(0, i * 100, 500, 100);
}
}
function playerMove() {
context.beginPath();
var radius = 5;
context.arc(player.x, player.y, radius, 0, 2 * Math.PI, false);
context.fillStyle = 'green';
context.fill();
context.lineWidth = 1;
context.strokeStyle = '#003300';
context.stroke();
}
setInterval(tick, 100);
function tick() {
context.clearRect(0, 0, canvas.width, canvas.height);
drawBackground();
player.x++;
player.y++;
playerMove();
}
This is the JSFiddle.
EDIT WITH THE CORRECT ANSWER
The error is in the position of the object "player". It is located outside of the canvas, width:500 height:500 and the "player" is in position x:700 y:800.
Changing the position of the player your copy will appear.
var player = {
x : 50,
y : 50
}
Here the jsfiddle example.
I've got some code which draws a rectangle on a canvas, but I want that rectangle to change color when I hover the mouse over it.
The problem is after I've drawn the rectangle I'm not sure how I select it again to make the adjustment.
What I want to do:
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
ctx.rect(20,20,150,100);
ctx.stroke();
$('c.[rectangle]').hover(function(this){
this.fillStyle = 'red';
this.fill();
});
You can't do this out-of-the-box with canvas. Canvas is just a bitmap, so the hover logic has to be implemented manually.
Here is how:
Store all the rectangles you want as simple object
For each mouse move on the canvas element:
Get mouse position
Iterate through the list of objects
use isPointInPath() to detect a "hover"
Redraw both states
Example
var canvas = document.querySelector("canvas"),
ctx = canvas.getContext("2d"),
rects = [
{x: 10, y: 10, w: 200, h: 50},
{x: 50, y: 70, w: 150, h: 30} // etc.
], i = 0, r;
// render initial rects.
while(r = rects[i++]) ctx.rect(r.x, r.y, r.w, r.h);
ctx.fillStyle = "blue"; ctx.fill();
canvas.onmousemove = function(e) {
// important: correct mouse position:
var rect = this.getBoundingClientRect(),
x = e.clientX - rect.left,
y = e.clientY - rect.top,
i = 0, r;
ctx.clearRect(0, 0, canvas.width, canvas.height); // for demo
while(r = rects[i++]) {
// add a single rect to path:
ctx.beginPath();
ctx.rect(r.x, r.y, r.w, r.h);
// check if we hover it, fill red, if not fill it blue
ctx.fillStyle = ctx.isPointInPath(x, y) ? "red" : "blue";
ctx.fill();
}
};
<canvas/>
This is a stable code in base of #K3N answer. The basic problem of his code is because when one box is over the another the two may get mouse hover at same time. My answer perfectly solves that adding a 'DESC' to 'ASC' loop.
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d");
var map = [
{x: 20, y: 20, w: 60, h: 60},
{x: 30, y: 50, w: 76, h: 60}
];
var hover = false, id;
var _i, _b;
function renderMap() {
for(_i = 0; _b = map[_i]; _i ++) {
ctx.fillStyle = (hover && id === _i) ? "red" : "blue";
ctx.fillRect(_b.x, _b.y, _b.w, _b.h);
}
}
// Render everything
renderMap();
canvas.onmousemove = function(e) {
// Get the current mouse position
var r = canvas.getBoundingClientRect(),
x = e.clientX - r.left, y = e.clientY - r.top;
hover = false;
ctx.clearRect(0, 0, canvas.width, canvas.height);
for(var i = map.length - 1, b; b = map[i]; i--) {
if(x >= b.x && x <= b.x + b.w &&
y >= b.y && y <= b.y + b.h) {
// The mouse honestly hits the rect
hover = true;
id = i;
break;
}
}
// Draw the rectangles by Z (ASC)
renderMap();
}
<canvas id="canvas"></canvas>
You may have to track the mouse on the canvas using JavaScript and see when it is over your rectangle and change the color then. See code below from my blog post
<!DOCTYPE html>
<html>
<body>
<canvas id="myCanvas" width="700" height="500" style="border:1px solid #c3c3c3;">
Your browser does not support the HTML5 canvas tag.
</canvas>
<script>
var myRect={x:150, y:75, w:50, h:50, color:"red"};
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.fillStyle = myRect.color;
ctx.fillRect(myRect.x, myRect.y, myRect.w, myRect.h);
c.addEventListener("mousemove", function(e){
if ((e.clientX>=myRect.x)&(e.clientX<=myRect.x+myRect.w)&(e.clientY>=myRect.y)&(e.clientY<=myRect.y+myRect.h)){
myRect.color = "green";}
else{
myRect.color = "red";}
updateCanvas();
}, false);
function updateCanvas(){
ctx.fillStyle = myRect.color;
ctx.fillRect(myRect.x, myRect.y, myRect.w, myRect.h);
}
</script>
</body>
</html>
I believe this is a slightly more in-depth answer that would work better for you, especially if you are interested in game design with the canvas element.
The main reason this would work better for you is because it focuses more on an OOP (object orientated programming) approach. This allows for objects to be defined, tracked and altered at a later time via some event or circumstance. It also allows for easy scaling of your code and in my opinion is just more readable and organized.
Essentially what you have here is two shapes colliding. The cursor and the individual point / object it hovers over. With basic squares, rectangles or circles this isn't too bad. But, if you are comparing two more unique shapes, you'll need to read up more on Separating Axis Theorem (SAT) and other collision techniques. At that point optimizing and performance will become a concern, but for now I think this is the optimal approach.
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
const width = canvas.width = window.innerWidth;
const height = canvas.height = window.innerHeight;
const cx = width / 2;
const cy = height / 2;
const twoPie = Math.PI * 2;
const points = []; // This will be the array we store our hover points in later
class Point {
constructor(x, y, r) {
this.x = x;
this.y = y;
this.r = r || 0;
}
}
class HoverPoint extends Point {
constructor(x, y, r, color, hoverColor) {
super(x, y, r);
this.color = color;
this.hoverColor = hoverColor;
this.hovered = false;
this.path = new Path2D();
}
draw() {
this.hovered ? ctx.fillStyle = this.hoverColor : ctx.fillStyle = this.color;
this.path.arc(this.x, this.y, this.r, 0, twoPie);
ctx.fill(this.path);
}
}
class Cursor extends Point {
constructor(x, y, r) {
super(x, y, r);
}
collisionCheck(points) {
// This is the method that will be called during the animate function that
// will check the cursors position against each of our objects in the points array.
document.body.style.cursor = "default";
points.forEach(point => {
point.hovered = false;
if (ctx.isPointInPath(point.path, this.x, this.y)) {
document.body.style.cursor = "pointer";
point.hovered = true;
}
});
}
}
function createPoints() {
// Create your points and add them to the points array.
points.push(new HoverPoint(cx, cy, 100, 'red', 'coral'));
points.push(new HoverPoint(cx + 250, cy - 100, 50, 'teal', 'skyBlue'));
// ....
}
function update() {
ctx.clearRect(0, 0, width, height);
points.forEach(point => point.draw());
}
function animate(e) {
const cursor = new Cursor(e.offsetX, e.offsetY);
update();
cursor.collisionCheck(points);
}
createPoints();
update();
canvas.onmousemove = animate;
There is one more thing that I would like to suggest. I haven't done tests on this yet but I suspect that using some simple trigonometry to detect if our circular objects collide would preform better over the ctx.IsPointInPath() method.
However if you are using more complex paths and shapes, then the ctx.IsPointInPath() method would most likely be the way to go. if not some other more extensive form of collision detection as I mentioned earlier.
The resulting change would look like this...
class Cursor extends Point {
constructor(x, y, r) {
super(x, y, r);
}
collisionCheck(points) {
document.body.style.cursor = "default";
points.forEach(point => {
let dx = point.x - this.x;
let dy = point.y - this.y;
let distance = Math.hypot(dx, dy);
let dr = point.r + this.r;
point.hovered = false;
// If the distance between the two objects is less then their combined radius
// then they must be touching.
if (distance < dr) {
document.body.style.cursor = "pointer";
point.hovered = true;
}
});
}
}
here is a link containing examples an other links related to collision detection
I hope you can see how easily something like this can be modified and used in games and whatever else. Hope this helps.
Below code adds shadow to canvas circle on hovering it.
<html>
<body>
<canvas id="myCanvas" width="1000" height="500" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>
</body>
<script>
var canvas = document.getElementById("myCanvas"),
ctx = canvas.getContext("2d"),
circle = [{
x: 60,
y: 50,
r: 40,
},
{
x: 100,
y: 150,
r: 50,
} // etc.
];
// render initial rects.
for (var i = 0; i < circle.length; i++) {
ctx.beginPath();
ctx.arc(circle[i].x, circle[i].y, circle[i].r, 0, 2 * Math.PI);
ctx.fillStyle = "blue";
ctx.fill();
}
canvas.onmousemove = function(e) {
var x = e.pageX,
y = e.pageY,
i = 0,
r;
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (let i = 0; i < circle.length; i++) {
if ((x > circle[i].x - circle[i].r) && (y > circle[i].y - circle[i].r) && (x < circle[i].x + circle[i].r) && (y < circle[i].y + circle[i].r)) {
ctx.beginPath();
ctx.arc(circle[i].x, circle[i].y, circle[i].r, 0, 2 * Math.PI);
ctx.fillStyle = "blue";
ctx.fill();
ctx.shadowBlur = 10;
ctx.lineWidth = 3;
ctx.strokeStyle = 'rgb(255,255,255)';
ctx.shadowColor = 'grey';
ctx.stroke();
ctx.shadowColor = 'white';
ctx.shadowBlur = 0;
} else {
ctx.beginPath();
ctx.arc(circle[i].x, circle[i].y, circle[i].r, 0, 2 * Math.PI);
ctx.fillStyle = "blue";
ctx.fill();
ctx.shadowColor = 'white';
ctx.shadowBlur = 0;
}
}
};
</script>
</html>
I know this is old, but I am surprised no one has mentioned JCanvas. It adds to the simplicity of animating canvas on events. More documentation here https://projects.calebevans.me/jcanvas/docs/mouseEvents/
<html lang="en">
<head>
<!-- css and other -->
</head>
<body onload="draw();">
<canvas id = "canvas" width="500" height="500" style= border:1px solid #000000;"> </canvas>
<script>
function draw() {
$('canvas').drawRect({
layer: true,
fillStyle:'#333',
x:100, y: 200,
width: 600,
height: 400,
mouseover: function(layer) {
$(this).animateLayer(layer, {
fillStyle: 'green'
}, 1000, 'swing');
}
});
}
<script src="https://code.jquery.com/jquery-3.3.1.min.js" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jcanvas/21.0.1/jcanvas.js" crossorigin="anonymous"></script>
</body>
</html>
Consider this following code:
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
ctx.rect(20,20,150,100);
ctx.stroke();
c.addEventListener("mouseover", doMouseOver, false);//added event to canvas
function doMouseOver(e){
ctx.fillStyle = 'red';
ctx.fill();
}
DEMO
You could use canvas.addEventListener
var canvas = document.getElementById('canvas0');
canvas.addEventListener('mouseover', function() { /*your code*/ }, false);
It worked on google chrome
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
ctx.rect(20,20,150,100);
ctx.stroke();
$(c).hover(function(e){
ctx.fillStyle = 'red';
ctx.fill();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<canvas id="myCanvas"/>