while searching that How can I made a moving circle using php, I found this question.But as I am not much expert in php so most of the things were not being understandable by me.So I thought now I must consult the experts :)
I want to Draw a circle which will move in circular motion on my php page.
MY EFFORT : I have tried alot to figure this out but the only thing I found that It would be achieved by canvas HTML5.But I got stuck in cartesian , radius etc.These things are really confusing me.
Anhy suggestions please.
The mathematics behind is:
x = centerX + radius * Math.cos(angle * Math.PI / 180);
y = centerY + radius * Math.sin(angle * Math.PI / 180);
Now you can input the result to a div element which contains the ball:
var element = document.getElementById('ball');
var angle = 0;
var x = 0;
var y = 0;
var w = (window.innerWidth - 50) / 2;
var h = (window.innerHeight - 50) / 2;
function ballCircle() {
x = w + w * Math.cos(angle * Math.PI / 180);
y = h + h * Math.sin(angle * Math.PI / 180);
ball.style.left = x + 'px';
ball.style.top = y + 'px';
angle++;
if (angle > 360) {
angle = 0;
}
setTimeout(ballCircle,20);
}
ballCircle();
I made a demo on jsfiddle here: http://jsfiddle.net/AqKYC/
PHP is a server-side programming language. It sounds like what you want to do is animate a circle in the browser. PHP does not run in the browser, so you cannot use PHP to animate a circle.
You can, however, create a <canvas> and use JavaScript to animate it. Here is a MDN tutorial on canvas, including animations.
As an alternative to canvas, you could use a simple <div>, turn it into a circle with CSS border-radius: 50%, and then animate it with either pure JavaScript, or jQuery.
Here's a jsfiddle with the circle drawn and using jQuery.animate to move it right, left, and right again.
jQuery.animate is fully documented here.
Here is a sample for a html5 moving circle with a tutorial explaining the code and how it's done. The code is under gplv3 license so obviously free too.
https://www.youtube.com/watch?v=6j4Y14TEO6s
Snippet in focus
ctx.strokeStyle = 'rgb(255,0,0)';
ctx.lineWidth = 10;
ctx.beginPath();
ctx.arc(x, y, radius, 0, Math.PI * 2, false);
ctx.closePath();
ctx.stroke();
Another sample is as follows where it shows the animated perspective of the same if that's what you are looking for.
https://www.youtube.com/watch?v=eKDeKFFZDNo
The focus is to break the animation at some point and thus the below snippet in focus in the redraw section of the code.
if (!ctx.isPointInPath(300,500)) {
x = x + 1;
y = y + 2;
ctx.strokeStyle = colorToHex(getRandom(255),getRandom(255),getRandom(255));
ctx.lineWidth = 10;
ctx.beginPath();
ctx.arc(x, y, radius, 0, Math.PI * 2, false);
ctx.closePath();
ctx.stroke();
}
Related
I'm trying to rotate two rectangles the same amount around the same point. The point is arbitrary, so for simplicity, I'm using the top-left (0, 0)
Unfortunately, the result seems slightly off, and I'm not sure what's causing it. Here is a full reproduction of the issue:
let canvas = document.querySelector("canvas");
let ctx = canvas.getContext("2d");
class Rectangle {
constructor(x, y, w, h, theta) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.theta = theta;
}
}
function drawRectangle(r) {
ctx.beginPath();
ctx.rect(r.x, r.y, r.w, r.h);
ctx.stroke();
}
function degreesToRadians(degrees) { return degrees * (Math.PI / 180); }
function rotateCanvas(radians, centerX, centerY) {
ctx.translate(centerX, centerY);
ctx.rotate(radians);
ctx.translate(-centerX, -centerY);
}
function drawRotatedRectangle(r) {
let rXCenter = r.x + (r.w / 2);
let rYCenter = r.y + (r.h / 2);
alert(rXCenter);
rotateCanvas(r.theta, rXCenter, rYCenter);
drawRectangle(r);
rotateCanvas(-r.theta, rXCenter, rYCenter);
}
let r1 = new Rectangle(100, 52, 90, 30, degreesToRadians(-20));
let r2 = new Rectangle(140, 80, 25, 25, degreesToRadians(10));
function simpleRotate(r, theta) {
let transX = Math.cos(theta) * r.x - Math.sin(theta) * r.y;
let transY = Math.sin(theta) * r.x + Math.cos(theta) * r.y;
return new Rectangle(transX, transY, r.w, r.h, r.theta + theta);
}
drawRotatedRectangle(r1);
drawRotatedRectangle(r2);
let r1AABB = simpleRotate(r1, -r1.theta);
let r2Rotate = simpleRotate(r2, -r1.theta);
ctx.strokeStyle = "#ff0000";
drawRotatedRectangle(r1AABB);
drawRotatedRectangle(r2Rotate);
body { margin: 0; overflow: hidden; }
<canvas width="600" height="600"></canvas>
The black rectangles are the two rectangles before being rotated, and the red rectangles are the two rectangles after being rotated.
As you can see, the two black rectangles are touching (colliding) before being rotated. Then, I rotate them both by the same amount around the same point (0, 0). However, afterwards they are no longer touching (as you can see the red rectangles are no longer colliding.
Why is this? I followed this code for rotating a point, but I seem to be getting inaccurate results.
If I take a screenshot of the black rectangles, open it up an image editor, box select them, and rotate them, then they stay together (colliding). How can I emulate this in my code example posted above?
This may let it work as you expect.
function simpleRotate(r, theta) {
let transX = Math.cos(theta) * (r.x + r.w / 2) - Math.sin(theta) * (r.y + r.h / 2) - r.w / 2;
let transY = Math.sin(theta) * (r.x + r.w / 2) + Math.cos(theta) * (r.y + r.h / 2) - r.h / 2;
return new Rectangle(transX, transY, r.w, r.h, r.theta + theta);
}
Other otherwise, if you'd like to change center, use following form.
function simpleRotate(r, theta, centerX, centerY) {
let transX = Math.cos(theta) * (r.x + r.w / 2 - centerX) - Math.sin(theta) * (r.y + r.h / 2 - centerY) - r.w / 2 + centerX;
let transY = Math.sin(theta) * (r.x + r.w / 2 - centerX) + Math.cos(theta) * (r.y + r.h / 2 - centerY) - r.h / 2 + centerY;
return new Rectangle(transX, transY, r.w, r.h, r.theta + theta);
}
Then
let r1AABB = simpleRotate(r1, -r1.theta, 145, 67);
let r2Rotate = simpleRotate(r2, -r1.theta, 145, 67);
How these work
In general, 2d rotational transform with offset consists of translation and rotation. Then, in that setup rotation is to be applied via drawRotatedRectangle() afterwards. Therefore all what you have to do is to compose appropriate translation. Inspecting simpleRotate() function carefully, you'll notice what's actually done there is calculation of translation (transX, transY ... though sin/cos are being used).
Then, as you know, since drawRotatedRectangle() rotates the rectangle around its center, by composing translation to move the center to the appropriate position, you can obtain rotational transform you need.
Initial state → Translate each item by simpleRotate() → Rotate each item by drawRotatedRectangle() → Final state.
I'm trying to create a little circular "equalizer" effect using JavaScript and HTML canvas for a little project I'm working on, and it works great, except one little thing. It's just a series of rectangular bars moving in time to an mp3 - nothing overly fancy, but at the moment all the bars point in one direction (i.e. 0 radians, or 90 degrees).
I want each respective rectangle around the edge of the circle to point directly away from the center point, rather than to the right. I have 360 bars, so naturally, each one should be 1 degree more rotated than the previous.
I thought that doing angle = i*Math.PI/180 would fix that, but it doesn't seem to matter what I do with the rotate function - they always end up pointing in weird and wonderful directions, and being translated a million miles from where they were. And I can't see why. Can anyone see where I'm going wrong?
My frame code, for reference, is as follows:
function frames() {
// Clear the canvas and get the mp3 array
window.webkitRequestAnimationFrame(frames);
musicArray = new Uint8Array(analyser.frequencyBinCount);
analyser.getByteFrequencyData(musicArray);
ctx.clearRect(0, 0, canvas.width, canvas.height);
bars = 360;
for (var i = 0; i < bars; i++) {
// Find the rectangle's position on circle edge
distance = 100;
var angle = i * ((Math.PI * 2) / bars);
var x = Math.cos(angle) * distance + (canvas.width / 2);
var y = Math.sin(angle) * distance + (canvas.height / 2);
barWidth = 5;
barHeight = (musicArray[i] / 4);
// Fill with a blue-green gradient
var grd = ctx.createLinearGradient(x, 0, x + 40, 0);
grd.addColorStop(0, "#00CCFF");
grd.addColorStop(1, "#00FF7F");
ctx.fillStyle = grd;
// Rotate the rectangle according to position
// ctx.rotate(i*Math.PI/180); - DOESN'T WORK
// Draw the rectangle
ctx.fillRect(x, y, barHeight, barWidth);
}
For clarity I've removed part of your code. I'm using rotate as you intended. Also I'm using barHeight = (Math.random()* 50); instead your (musicArray[i]/4); because I wanted to have something to show.
Also I've changed your bars to 180. It's very probable that you won't have 360 bars but 32 or 64 or 128 or 256 . . . Now you can change the numbers of bare to one of these numbers to see the result.
I'm drawing everything around the origin of the canvas and translating the context in the center.
I hope it helps.
const canvas = document.getElementById("c");
const ctx = canvas.getContext("2d");
let cw = canvas.width = 400;
let ch = canvas.height = 400;
let bars = 180;
let r = 100;
ctx.translate(cw / 2, ch / 2)
for (var i = 0; i < 360; i += (360 / bars)) {
// Find the rectangle's position on circle edge
var angle = i * ((Math.PI * 2) / bars);
//var x = Math.cos(angle)*r+(canvas.width/2);
//var y = Math.sin(angle)*r+(canvas.height/2);
barWidth = 2 * Math.PI * r / bars;
barHeight = (Math.random() * 50);
ctx.fillStyle = "green";
// Rotate the rectangle according to position
// ctx.rotate(i*Math.PI/180); - DOESN'T WORK
// Draw the rectangle
ctx.save();
ctx.rotate(i * Math.PI / 180);
ctx.fillRect(r, -barWidth / 2, barHeight, barWidth);
//ctx.fillRect(r ,0, barHeight, barWidth);
ctx.restore();
}
canvas {
border: 1px solid
}
<canvas id="c"></canvas>
Here is another solution, I'm preserving your initial trigonometry approach.
But instead of rectangles I used lines, I don't think it makes a difference for you, if what you need is bars moving in time to an mp3 all you need to do is change the var v = Math.random() + 1; to a reading from the Amplitude, and those bars will be dancing.
const canvas = document.getElementById("c");
canvas.width = canvas.height = 170;
const ctx = canvas.getContext("2d");
ctx.translate(canvas.width / 2, canvas.height / 2)
ctx.lineWidth = 2;
let r = 40;
let bars = 180;
function draw() {
ctx.clearRect(-100, -100, 200, 200)
for (var i = 0; i < 360; i += (360 / bars)) {
var angle = i * ((Math.PI * 2) / bars);
var x = Math.cos(angle) * r;
var y = Math.sin(angle) * r;
ctx.beginPath();
var v = Math.random() + 1;
ctx.moveTo(x, y);
ctx.lineTo(x * v, y * v)
grd = ctx.createLinearGradient(x, y, x*2, y*2);
grd.addColorStop(0, "blue");
grd.addColorStop(1, "red");
ctx.strokeStyle = grd;
ctx.stroke();
}
}
setInterval(draw, 100)
<canvas id="c"></canvas>
I'm trying to manipulate a simple rectangle on a HTML5 canvas. The Javascript that does this is here:
var canvas = document.getElementById("mainCanvas");
var ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, windowWidth, windowHeight);
var halfWidth = (iconWidth / 2);
var halfHeight = (iconHeight / 2);
var centreX = x + halfWidth;
var centreY = y + halfHeight;
ctx.fillStyle = "#FF0000";
ctx.translate(centreX, centreY);
ctx.rotate(rotationDegree * Math.PI / 180);
ctx.fillRect(-halfWidth, -halfHeight, iconWidth, iconHeight);
ctx.translate(-centreX, -centreY);
As I increase y, I can see the rectangle travelling along the screen and, if I rotate the rectangle, it rotates and moves along the new trajectory; however, in order to stop the rectangle leaving the screen, I had a basic boundary check, which was just not working (the rectangle was travelling off the screen, and being "bounced" where it had not reached the edge.
As an experiment, I then tried the following:
var canvas = document.getElementById("mainCanvas");
var ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, windowWidth, windowHeight);
var halfWidth = (iconWidth / 2);
var halfHeight = (iconHeight / 2);
var centreX = x + halfWidth;
var centreY = y + halfHeight;
ctx.save();
ctx.fillStyle = "#FF0000";
ctx.translate(centreX, centreY);
ctx.rotate(rotationDegree * Math.PI / 180);
ctx.fillRect(-halfWidth, -halfHeight, iconWidth, iconHeight);
// ctx.translate(-centreX, -centreY);
ctx.restore();
This works, but the rotation no longer guides the rectangle. My conclusion is that the rotate function rotates the canvas, but then leaves it in the new, rotated form (like rotating a piece of paper underneath a pen). So, the bug I had was that the rotation was not being reset; however, apart from the boundary check, this "bugged" behaviour was what I was actually aiming for.
Is there a way to get from a canvas 2d context the absolute position, taking into account the rotation so that, even if I leave the canvas in its "rotated" state, I can perform a boundary check?
Here is a fiddle of the site.
To transform a point from local space (the transformed space) to screen space create a matrix that is a shadow (copy) of the context transform then multiply the point with that matrix
function getTransformToScreen(x,y,rotation,posX,posY){
var xAx = Math.cos(rotation); // x axis x
var xAy = Math.sin(rotation); // x axis y
// the equivalent to
// ctx setTransform(xAx, xAy ,-xAy, xAx, posX, posY);
// second two values (y Axis) is at 90 deg of x Axis if it is
// not at 90 (skewed) then you need to calculate the skewed axis (y axis) direction
return {
x : x * xAx - y * xAy + posX,
y : x * xAy + y * xAx + posY
}
}
To use
// your code
ctx.translate(centreX, centreY);
ctx.rotate(rotationDegree * Math.PI / 180);
ctx.fillRect(-halfWidth, -halfHeight, iconWidth, iconHeight);
// get the top left
var topLeft = getTransformToScreen(
-halfWidth, -halfHeight,
rotationDegree * Math.PI / 180,
centreX, centreY
);
I wrote this algorithm to draw a regular polygon:
var sides = 6,
radius = 50;
ctx.beginPath();
ctx.moveTo(x, y - radius);
for(n = 1; n <= sides; n++)
ctx.lineTo(
x + (radius * Math.sin(n * 2 * Math.PI / sides)),
y + (-1 * radius * Math.cos(n * 2 * Math.PI / sides))
);
ctx.stroke();
It works wonderfully, but I need to incorporate a way to rotate the polygon, without using the ctx.rotate() function.
Thanks for your help. If you down vote, please tell me why so I can improve this question.
Here's code to generate a regular polygon with the first vertex at zero-angle-right-of-center:
The code uses trigonometry to rotate the polygon instead of context.rotate.
function regularPolygon(cx,cy,sides,radius,radianRotation){
var deltaAngle=Math.PI*2/sides;
var x=function(rAngle){return(cx+radius*Math.cos(rAngle-radianRotation));}
var y=function(rAngle){return(cy+radius*Math.sin(rAngle-radianRotation));}
ctx.beginPath();
ctx.moveTo(x(0),y(0));
for(n = 1; n <= sides; n++){
var angle=deltaAngle*n;
ctx.lineTo(x(angle),y(angle));
}
ctx.closePath();
ctx.stroke();
}
The title kind of says it all, I am trying to move an object forward depending on the angle it is at.
Here is my relevant code:
xView = this.x-this.width/2;
yView = this.y-this.height/2;
playerCtx.drawImage(imgSprite, 0, 0, this.width, this.height, xView, yView, this.width, this.height);
playerCtx.save();
playerCtx.clearRect(0, 0, game.width, game.height);
playerCtx.translate(xView, yView);
playerCtx.rotate(angle *Math.PI/180);
playerCtx.drawImage(imgSprite, 0, 0, this.width, this.height, -xView, -yView, this.width, this.height);
playerCtx.restore();
}
if(Game.controls.left) {
angle-=1;
if(Game.controls.up){
this.x += this.speed * Math.cos(angle * Math.PI / 180);
this.y -= this.speed * Math.sin(angle * Math.PI / 180);
}
The object doesn't move corresponding to the var angle.
EDIT
I couldn't figure out why my code wasn't working so I instead used a sprite sheet containing 36 different angles. This works, however the rotation is too fast. If anyone could tell me why the above isn't working properly, or how I would go about making the following function go slower:
if(Game.controls.right) {
currentFrame++;
angle+=10;
}
By slower I mean when the left key is held down, angle+10; currentFrame++; are raising to fast, and adding more Frames may take too long.
EDIT
Added a Jfiddle for my original question, the angle variable moves with the rotation, for an example if the object is facing Right, angle will equal 90, but the object still doesn't look like its moving to the right, although the camera does.
Try to change cos and sin around as well as the sign:
this.x += this.speed * Math.cos(angle * Math.PI / 180);
this.y += this.speed * Math.sin(angle * Math.PI / 180);
To make your rotation (in the edited part of the question) you need to reduce the steps basically as well as provide more sprites. More sprites won't be slower but will use more memory and increase initial load time a tad.
UPDATE
Ok, there are a few things you need to correct (the above is one of them and they are corrected in the fiddle).
Modified fiddle
The other things are in:
In your update() method:
// Add both here as angle with correctly use neg/pos
if (Game.controls.up) {
this.x += this.speed * Math.cos(angle * Math.PI / 180);
this.y += this.speed * Math.sin(angle * Math.PI / 180);
}
/// Sub both here as angle with correctly use neg/pos
if (Game.controls.down) {
this.x -= this.speed * Math.cos(angle * Math.PI / 180);
this.y -= this.speed * Math.sin(angle * Math.PI / 180);
}
As the angle will determine the negative or positive value you just need to add or subtract depending on the intention, so for up add both values, for down subtract both value. The angle will make sure the delta is correctly signed.
In your draw function there are a few things:
Player.prototype.draw = function (context, xView, yView) {
// Add the half width instead of subtract it
xView = this.x + this.width / 2;
yView = this.y + this.height / 2;
// not needed as you clear the canvas in the next step
//playerCtx.drawImage(imgSprite, 0, 0, ....
playerCtx.save();
playerCtx.clearRect(0, 0, game.width, game.height);
// make sure pivot is moved to center before rotation
playerCtx.translate(xView, yView);
// rotate, you should make new sprite where direction
// points to the right. I'm add 90 here to compensate
playerCtx.rotate((angle + 90) * Math.PI / 180);
// translate back before drawing the sprite as we draw
// from the corner and not the center of the image
playerCtx.translate(-xView, -yView);
playerCtx.drawImage(imgSprite, 0, 0, this.width, this.height, this.x, this.y, this.width, this.height);
playerCtx.restore();
}
Now you will see the things works.
You images should always be drawn pointing right. This is because that is always angle at 0 degrees. This will save you some trouble. I compensated for this is the draw function by adding 90 degrees to the angle but this should rather be adjusted in the sprite itself.
In addition I modified your key handler (see demo for details).