I wrote this code to try to get the myCanvas to move towards myCanvas1. I tried doing this using the Math.atan2() method. However it doesn't work. Any ideas?
Please don't use any JQuery.
HTML:
<canvas id="myCanvas"></canvas>
<canvas id="myCanvas1"></canvas>
JS:
var follower = document.getElementById('myCanvas');
var flw = follower.getContext('2d');
var runner = document.getElementById('myCanvas1');
var rnr = runner.getContext('2d');
document.addEventListener('keydown', moveShot);
//Cordinates of sPositions 1 and two
var sPosition0 = [700, 700];
var sPosition1 = [400, 400];
var xPosition0 = sPosition0[0], yPosition0 = sPosition0[1];
var xPosition1 = sPosition1[0], yPosition1 = sPosition1[1];
//This should be the arctan between sPosition0 and sPosition1
var angleRadians0 = Math.atan2(sPosition0[0] - sPosition1[0], sPosition0[1] - Position1[1]);
/*The speed of the object is 4. To get it to move diagonally towards sPosition1 I need to divide dy with the angle arctan between the two objects */
var dx = 4;
var dy = 4 / angleRadians0;
function moveShot(){
// Deleting the "old" square
flw.clearRect(0, 0, 700, 700);
//Drawing the square at its appropriate position
flw.fillRect(xPosition0, yPosition0, 100, 100);
//Adding the movement after every frame
xPosition0 += dx;
yPosition0 += dy;
setTimeout(moveShot, 20);
}
CSS:
#myCanvas1{
height: 100px;
width: 100px;
background-color: '#ff0000';
}
Thanks!
EDIT:
As to what actually happens, I'm very confused. Nothing happens at all, I didn't say that because it's 3am and I thought someone would point out some very obvious mistake I've made and everything would make sence. So, what happens is well, nothing, I cannot understand why. Then again though, its 3am and I might have screwed up somewhere but I don't see where.
Here's a fiddle https://jsfiddle.net/Snubben/15tf0svd/3/
Well, the reason NOTHING happens, is that your canvas is using the default size. 300x150;
Your initial position is drawing the square OUTSIDE the canvas, and then your dx and dy variables are adding to x and y, making it move even further away (down and to the right).
See the following for an example of keeping it within the container and moving the square up and to the left.
var follower = document.getElementById('myCanvas');
var flw = follower.getContext('2d');
var runner = document.getElementById('myCanvas1');
var rnr = runner.getContext('2d');
document.addEventListener('keydown', moveShot);
//Cordinates of sPositions 1 and two
var sPosition0 = [70, 70]; //within the canvas
var sPosition1 = [40, 40]; //within the canvas
var xPosition0 = sPosition0[0],
yPosition0 = sPosition0[1];
var xPosition1 = sPosition1[0],
yPosition1 = sPosition1[1];
//This should be the arctan between sPosition0 and sPosition1
var angleRadians0 = Math.atan2(sPosition0[0] - sPosition1[0], sPosition0[1] - sPosition1[1]);
/*The speed of the object is 4. To get it to move diagonally towards sPosition1 I need to divide dy with the angle arctan between the two objects */
var dx = 4;
var dy = 4 / angleRadians0;
function moveShot() {
if(yPosition0 < 10) return;
// Deleting the "old" square
flw.fillStyle = "green";
flw.clearRect(0, 0, 700, 700);
//Drawing the square at its appropriate position
flw.fillRect(xPosition0, yPosition0, 10, 10);
//Adding the movement after every frame
xPosition0 -= dx; //move left
yPosition0 -= dy; //move up.
setTimeout(moveShot, 20);
}
#myCanvas1 {
height: 100px;
width: 100px;
background-color: #ff0000;
}
#myCanvas {
width: 300px;
height: 300px;
background-color: blue;
}
<canvas id="myCanvas" height="300" width="300"></canvas>
<canvas id="myCanvas1" height="100" width="100"></canvas>
press a key to make it work.
Related
I am working on a project where I would like to have darkness covering the screen and the character glowing in the darkness. I tried to animate the scene then draw darkness over it using this code:
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var canvasWidth = canvas.width;
var canvasHeight = canvas.height;
var pixelSize = 30;
var width = canvasWidth/pixelSize;
var height = canvasHeight/pixelSize;
var lightX = canvasWidth/2;
var lightY = canvasHeight/2;
var lightDiameter = 100;
var a = lightDiameter*pixelSize;
for(var x = 0; x < width; x++) {
for(var y = 0; y < height; y++) {
var alpha = 1.25 - a/(Math.pow(x*30 - lightX, 2) + Math.pow(y*30 -
lightY, 2));
ctx.fillStyle = "rgba( 25, 25, 30," + alpha + ")";
ctx.fillRect(x*pixelSize, y*pixelSize, pixelSize, pixelSize);
}
}
This worked pretty well and I liked the way it looked, but when this was repeatedly animated alongside the other code it slowed the rest down significantly. I think a possible solution may be to somehow draw a gradient with a lower "quality?", another solution I have considered is to save this drawing in a separate canvas and drawing it translated to the players location but that would make it impossible to add multiple sources of light, which I would like to do by simply adding their effect. I may just have to deal with the lag and I'm a noob at this stuff, but if anyone can help me that would be wonderful.
To clarify, I am using this code in the drawing loop, and also it is re-calculated in every iteration. I would prefer to recalculate this way so I can have multiple moving sources of light.
This is because fillRect is pretty slow compared to other methods. You could probably speed things up by using ImageData objects instead.
The way to do this would be to render everything to the canvas, get the corresponding ImageData, modify its contents and put it back onto the canvas:
var ctx = canvas.getContext("2d");
// render stuff here
var imageData = ctx.getImageData(0,0,canvasWidth,canvasHeight);
for (let x=0;x<canvasWidth;x++){
for (let y=0;y<canvasHeight;y++){
let i = (x+y*canvasWidth)*4;
let alpha = calculateAlpha(x,y); // your method here (should result in a value between 0 and 1)
imageData.data[i] = (1-alpha)*imageData.data[i]+alpha*25;
imageData.data[i+1] = (1-alpha)*imageData.data[i+1]+alpha*25;
imageData.data[i+2] = (1-alpha)*imageData.data[i+2]+alpha*30;
imageData.data[i+3] = 1-(1-alpha)*(1-imageData.data[i+3]);
}
}
ctx.putImageData(imageData,0,0);
This should do the lighting on a per-pixel basis, and much faster than using clearRect all the time. However, it might still slow things down, as you're doing a lot of calculations each frame. In that case, you could speed thing up by doing the lighting in a second canvas that is positioned over your main canvas using css:
<div id="container">
<canvas id="canvas"></canvas>
<canvas id="lightingCanvas"></canvas>
</div>
Css:
#container {
position: relative;
}
#canvas, #lightingCanvas {
position: absolute;
top: 0;
left: 0;
}
#container, #canvas, #lightingCanvas {
width: 480px;
height: 360px;
}
Javascript:
var canvas = document.getElementById("lightingCanvas")
var ctx = canvas.getContext("2d");
ctx.fillStyle = "rgb(25,25,30)";
ctx.fillRect(0,0,canvas.width,canvas.height);
var imageData = ctx.getImageData(0,0,canvasWidth,canvasHeight);
for (let x=0;x<canvasWidth;x++){
for (let y=0;y<canvasHeight;y++){
let i = (x+y*canvasWidth)*4;
let alpha = calculateAlpha(x,y); // your method here (should result in a value between 0 and 1)
imageData.data[i+3] = 255*alpha;
}
}
ctx.putImageData(imageData,0,0);
This way the browser takes care of the blending for you and you just need to plug in the correct alpha values - so rendering should be even faster now.
This will also allow you to bring the large pixels back in - just use a lower resolution on the second canvas and use some css effect like image-rendering: -webkit-crisp-edges to make the canvas pixelated when scaled up.
ok here is the deal, I want a circle to grow on a canvas depending on how long you hold your mouse button. I was able to make it draw a circle of fixed width where my mouse was when I clicked, but I want to be able to determine size based on how long I hold. Ideally, you will be able to see it grow as you hold.
CODE
var c = document.getElementById("canvas");
var ctx = c.getContext('2d');
document.addEventListener("mousedown", draw);
document.addEventListener("mousedown", time1);
document.addEventListener("mouseup", time2);
//Size
function time1(event) {
var a = new Date().getTime() + 1;
return a;
}
function time2(event) {
var b = new Date().getTime() + 4;
return b;
}
var c ="Time: " + (time2 - time1);
document.getElementById("time").innerHTML = c;
function draw(event, a , b) {
//Cords
var x = event.clientX;
var y = event.clientY;
//Fill
ctx.fillStyle = "#0c67f9";
//Draw
ctx.beginPath();
ctx.arc(x ,y ,(b - a),0,Math.PI * 2, true);
ctx.fill();
}
function showCoords(event) {
var x = event.clientX;
var y = event.clientY;
var coords = "X coords: " + x + ", Y coords: " + y;
document.getElementById("demo").innerHTML = coords;
}
/*function grow(event) {
var z = event.time;
}*/
<canvas id="canvas" width="690" height="651" onclick="showCoords(event)" style ="border: 1px solid #e21313"></canvas>
<p id="demo"></p>
<p id="time"></p>
Here is your groing circle:
Here
But I don't want to give you the copy & paste solution.
So with my help I believe you can figure it out.
First of all you need to change the event listener so it doesn't get triggered if you hold down your mouse somewhere in the html area (like it is now). Set it from $("html") to $("#your-canvas").
Since you also don't want to see your circle the whole time and it can't have a static position you also want to change the CSS attributes of the .dot class. I believe display: none; and position: absolute; will do.
The last thing you want to do is to get the exact mouse position (with offset and everything) and set it as CSS attributes top and left (don't forget to set the display: none to display: block).
Boom you got your growing circle.
However I didn't really understand what you mean by:
but I want to be able to determine size based on how long I hold.
So i'm adding some image manipulation functions to one of our company projects. Part of the feature is an image cropper with the desire to 'auto-detect' the cropped image to some degree. If our guess is bad they can just drag & drop the cropper points, but most images people should be able to be auto-cropped.
My issue is when i'm putting the data back into the canvas indexes that work don't seem make any sense to me based on the documentation. I'm trying to take the rect I find and convert he canvas to a single image size that will now contain my whole rect.
let width = right - left + 1, height = bottom - top + 1;
canvas.width = width;
canvas.height = height;
ctx.putImageData(imageBuffer, -left, -top, left, top, width,height);
This gives me the correct image. I would have expected based on the documentation that the below code would be correct. I verified in mspaint that my indexes for the rect are correct so I know it isn't my algorithm coming up with weird numbers.
let width = right - left + 1, height = bottom - top + 1;
canvas.width = width;
canvas.height = height;
ctx.putImageData(imageBuffer, 0, 0, left, top, width,height);
Why do you have to put a negative indexing for the 2nd & 3rd argument? I've verified it behaves like this in both Chrome & Firefox.
Yes, it might be a bit confusing, but when you putImageData, the destinationWidth and destinationHeight you would have in e.g drawImage, are always equal to the ImageData's width and height.
The 4 last params of putImageData(), dirtyX, dirtyY, dirtyWidth and dirtyHeight values are relative to the ImageData's boundaries.
So with the first two params, you just set the position of the ImageData's boundaries, with the 4 others, you set the position of your pixels in this ImageData's boundary.
var ctx = canvas.getContext('2d');
var imgBound = {
x: 10,
y: 10,
width: 100,
height: 100
},
innerImg = {
x: 20,
y: 20,
width: 200,
height: 200
};
// a new ImageData, the size of our canvas
var img = ctx.createImageData(imgBound.width, imgBound.height);
// fill it with noise
var d = new Uint32Array(img.data.buffer);
for(var i=0;i<d.length; i++)
d[i] = Math.random() * 0xFFFFFFFF;
function draw() {
ctx.putImageData(img,
imgBound.x,
imgBound.y,
innerImg.x,
innerImg.y,
innerImg.width,
innerImg.height
);
// the ImageData's boundaries
ctx.strokeStyle = 'blue';
ctx.strokeRect(imgBound.x, imgBound.y, imgBound.width, imgBound.height);
// our pixels boundaries relative to the ImageData's bbox
ctx.strokeStyle = 'green';
ctx.strokeRect(
// for stroke() we need to add the ImageData's translation
innerImg.x + imgBound.x,
innerImg.y + imgBound.y,
innerImg.width,
innerImg.height
);
}
var inner_direction = -1,
imgBound_direction = -1;
function anim() {
innerImg.width += inner_direction;
innerImg.height += inner_direction;
if(innerImg.width <= -50 || innerImg.width > 200) inner_direction *= -1;
imgBound.x += imgBound_direction;
if(imgBound.x <= 0 || imgBound.x > 200)
imgBound_direction *= -1;
ctx.clearRect(0,0,canvas.width,canvas.height);
draw();
requestAnimationFrame(anim);
}
anim();
canvas{border: 1px solid;}
<canvas id="canvas" width="300" height="300"></canvas>
I'm working on a script which is supposed to do the following. You lock your mouse to a canvas. It will show you an "artificial" cursor instead that you can also move by using your mouse. Under this cursor, you will have a circle which also moves with the mouse.
All of this worked perfectly fine with my script which was until I added another nice feature: I want to have an Arrow in the middle of the canvas which stays there, exact same size, but rotates according to your cursor movement. To give you an idea what I'm talking about, I made these example graphs (don't worry about dimensions and colour).
https://i.stack.imgur.com/poO6n.jpg
https://i.stack.imgur.com/twXhY.jpg
https://i.stack.imgur.com/RFFBe.jpg
I did some calculations to do this, implemented them, hoped for the best, but it doesn't work. I thought when it works, it will be a cool feature for everyone to have on this site. But so far I didn't see where my mistake is. If you have a clue, I'm absolutely grateful for every answer.
Many thanks!
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>ArrowSpin</title>
<style>
html, body {
margin: 0;
padding: 0;
}
html {
font-family: sans-serif;
}
canvas {
display: block;
margin: 0 auto;
border: 1px solid black;
}
.information {
width: 640px;
margin: 0 auto 50px;
}
#tracker {
position: absolute;
top: 0;
right: 10px;
background-color: white;
}
h1 {
font-size: 200%;
}
</style>
</head>
<body>
<div class="information">
<img id="mousecursor" hidden="true" width="13" height="20.5" src="mousecursor.png" alt="Cursor">
<p id="demo" style="color: black" oncl></p>
<p id="Message" style="color: black" oncl></p>
<canvas id="myCanvas" width="640" height="360">
Your browser does not support HTML5 canvas
</canvas>
<div id="tracker"></div>
</div>
<script>
try {
// helper functions
const RADIUS = 20;
// this image is you mousecursor
var img = document.getElementById("mousecursor");
// degree to radians
function degToRad(degrees) {
var result = Math.PI / 180 * degrees;
return result;
}
// generate a random number, later on, mouse cursor should start at random position, now unused
function generateRandomNumber() {
var minangle = 0;
var maxangle = 2*Math.PI;
randangle = Math.random() * (maxangle- minangle) + minangle;
return randangle;
};
//this function draws the actual arrow
function drawArrow(fromx, fromy, tox, toy, colourarrow){
//variables to be used when creating the arrow
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var headlen = 3;
var angle = Math.atan2(toy-fromy,tox-fromx);
//starting path of the arrow from the start square to the end square and drawing the stroke
ctx.beginPath();
ctx.moveTo(fromx, fromy);
ctx.lineTo(tox, toy);
ctx.strokeStyle = colourarrow;
ctx.lineWidth = 20;
ctx.stroke();
//starting a new path from the head of the arrow to one of the sides of the point
ctx.beginPath();
ctx.moveTo(tox, toy);
ctx.lineTo(tox-headlen*Math.cos(angle-Math.PI/7),toy-headlen*Math.sin(angle-Math.PI/7));
//path from the side point of the arrow, to the other side point
ctx.lineTo(tox-headlen*Math.cos(angle+Math.PI/7),toy-headlen*Math.sin(angle+Math.PI/7));
//path from the side point back to the tip of the arrow, and then again to the opposite side point
ctx.lineTo(tox, toy);
ctx.lineTo(tox-headlen*Math.cos(angle-Math.PI/7),toy-headlen*Math.sin(angle-Math.PI/7));
//draws the paths created above
ctx.strokeStyle = colourarrow;
ctx.lineWidth = 20;
ctx.stroke();
ctx.fillStyle = colourarrow
ctx.fill();
}
// this function calculates the current angle of the cursor from the exact middle of the canvas (x0,y0) by using two simple assumptions which are a) radius=sqrt(sqr(xfrom)+sqr(y)) b) x=x0+radius*cos(alpha) <=> alpha=arccos((x-x0)/radius)
function CursorAngle() {
var currentrad=Math.sqrt([Math.pow(x-canvas.width/2)+Math.pow(y+canvas.height)]);
var currentangle=Math.acos([(x-canvas.width/2)/currentrad]);
return currentangle
}
//in this function I use the just calculated cursor angle to now calculate where my arrow shall begin and end, again I use x=x0+radius*cos(alpha) and y=y0+radius*sin(alpha). In this case I always want my arrow to have a radius of 50 and I always want it to be drawn in the center of the canvas.
function ProbeAngle(alpha) {
var x1 = canvas.width/2+50*cos(alpha)
var y1 = canvas.width/2+50*sin(alpha)
var x2 = canvas.width/2+50*cos(alpha+Math.PI)
var y2 = canvas.width/2+50*sin(alpha+Math.PI)
return [x1; y1; x2; y2]
}
// setup of the canvas
var canvas = document.querySelector('canvas');
var ctx = canvas.getContext('2d');
var x = canvas.width/2;
var y = canvas.height/2;
//refresh the canvas
function canvasDraw() {
ctx.fillStyle = "black";
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "#f00";
ctx.beginPath();
ctx.arc(x, y, RADIUS, 0, degToRad(360), true);
ctx.fill();
ctx.drawImage(img, x, y);
}
canvasDraw();
// pointer lock object forking for cross browser
canvas.requestPointerLock = canvas.requestPointerLock ||
canvas.mozRequestPointerLock;
document.exitPointerLock = document.exitPointerLock ||
document.mozExitPointerLock;
canvas.onclick = function() {
canvas.requestPointerLock();
canvasDraw();
};
// pointer lock event listeners
// Hook pointer lock state change events for different browsers
document.addEventListener('pointerlockchange', lockChangeAlert, false);
document.addEventListener('mozpointerlockchange', lockChangeAlert, false);
function lockChangeAlert() {
if (document.pointerLockElement === canvas ||
document.mozPointerLockElement === canvas) {
console.log('The pointer lock status is now locked');
document.addEventListener("mousemove", updatePosition, false);
} else {
console.log('The pointer lock status is now unlocked');
document.removeEventListener("mousemove", updatePosition, false);
}
}
//tracker shows x and y coordinates of "pseudo" cursor
var tracker = document.getElementById('tracker');
//border protection for our image not to move out of the canvas
var animation;
function updatePosition(e) {
x += e.movementX;
y += e.movementY;
if (x > canvas.width) {
x = canvas.width;
}
if (y > canvas.height) {
y = canvas.height;
}
if (x < 0) {
x = 0;
}
if (y < 0) {
y = 0;
}
tracker.textContent = "X position: " + x + ", Y position: " + y;
if (!animation) {
animation = requestAnimationFrame(function() {
animation = null;
canvasDraw();
//receive the ProbeCoords by using the functions CursorAngle and ProbeAngle and draw it!
var ProbeCoord = ProbeAngle(CursorAngle());
drawArrow(ProbeCoord[0],ProbeCoord[1],ProbeCoord[2],ProbeCoord[3],'white')
});
}
}
}
catch(err) {
document.getElementById("demo").innerHTML = err.message;
}
document.getElementById("Message").innerHTML = "potential Errorcode above";
</script>
</body>
</html>
Have you tried using Fabric JS? In the linked example you can click an object and a handle appears at the top. After that you can click handle and it will follow the mouse. I'm suggesting this because most likely there is a way to change the click event to a hover event and then get the handle to follow the mouse.
I'm currently learning canvas touch event function,I 'm able to draw line on the canvas, now I want to get the x and y coordinates when I draw any lines and show on the screen.please help and teach me how to get the x and y values, thank You!
here is the coding
<!DOCTYPE html>
<html><head>
<style>
#contain {
width: 500px;
height: 120px;
top : 15px;
margin: 0 auto;
position: relative;
}
</style>
<script>
var canvas;
var ctx;
var lastPt=null;
var letsdraw = false;
var offX = 10, offY = 20;
function init() {
var touchzone = document.getElementById("layer1");
touchzone.addEventListener("touchmove", draw, false);
touchzone.addEventListener("touchend", end, false);
ctx = touchzone.getContext("2d");
}
function draw(e) {
e.preventDefault();
if (lastPt != null) {
ctx.beginPath();
ctx.moveTo(lastPt.x, lastPt.y);
ctx.lineTo(e.touches[0].pageX - offX,
e.touches[0].pageY - offY);
ctx.stroke();
}
lastPt = {
x: e.touches[0].pageX - offX,
y: e.touches[0].pageY - offY
};
}
function end(e) {
var touchzone = document.getElementById("layer1");
e.preventDefault();
// Terminate touch path
lastPt = null;
}
function clear_canvas_width ()
{
var s = document.getElementById ("layer1");
var w = s.width;
s.width = 10;
s.width = w;
}
</script>
</head>
<body onload="init()">
<div id="contain">
<canvas id="layer1" width="450" height="440"
style="position: absolute; left: 0; top: 0;z-index:0; border: 1px solid #ccc;"></canvas>
</div>
</body>
</html>
Still not entirely confident I understand your question.
In the code you posted, you are already obtaining coordinates using e.touches[0].pageX/Y. The main problem with that is that the pageX/Y values are relative to the page origin. You are then subtracting fixed offX/Y in your code to try and convert these to canvas-relative coordinates. Right idea, wrong values. You need to subtract off the position of the canvas element which can be obtained by summing the offsetX/Y values as you traverse the tree upward using the offsetParent reference.
Something like:
offX=0;offY=0;
node = document.getElementById ("layer1");
do {
offX += node.offsetX;
offY += node.offsetY;
node = node.offsetParent;
} while(node);
should give you a better value for offX and offY.
If you just want to locate the actual drawing at the end, it would be easiest just to track a bounding box while the user draws.