Create an Arc and a Pie using DIV DOM element - javascript

I have a created an ellipse using div DOM element.
var body = document.querySelector('body');
var div = document.createElement('div');
div.style.borderRadius = '50%';
div.style.border = '1px solid red';
div.style.left = '60px';
div.style.top = '60px';
div.style.width = '100px';
div.style.height = '100px';
body.appendChild(div);
It looks like the image below:
I want also to create an arc and a pie.
In the second image above, the user will just input the starting angle and the end angle of the arc. In our case, the starting angle is 180 degrees and the ending angle is 360 degrees.
I want also to create a pie, wherein the user must input the inside radius of the circle/ellipse, starting angle and ending angle.
In the third picture, the inside radius is 50% of the width of the circle/ellipse, the starting angle is 90 degrees and the ending angle is 360 also.
Is it possible?
P.S: I don't want to draw it in the canvas or use svg.

As i said canvas is very good solution to draw this kind of things.however since you don't want to use canvas you can use border styles to draw arcs but angle of arc should be 90deg multiples like 0 90 180 270 360.however start angle can be any angle 0,5,10,7...
here is an example.
to get the effect of 2nd arc you given, enter start angle as 0 and end angle as 180. because stranded angle system is : see following picture
run this code
var border = ['border-top-color', 'border-right-color', 'border-bottom-color', 'border-left-color'];
var circle;
var standeredRotation = 135;
function getinput() {
circle = document.getElementById("circle");
var startAngle = document.getElementById("startangle").value;
var endAngle = document.getElementById("endtangle").value;
var angle = endAngle - startAngle;
if (angle % 90 != 0) {
alert("plz enter 90's multiples");
} else {
var parts = angle / 90;
draw(parts, startAngle);
}
}
function draw(parts, startAngle) {
var style = "";
for (var i = 0; i < parts; i++) {
style += border[i] + ": #FF4E4E;";
}
circle.setAttribute("style", style);
totalAngle = standeredRotation + parseInt(startAngle);
circle.style.transform = 'rotate(' + totalAngle + 'deg)';
}
#circle {
border-radius: 50%;
border: 10px solid transparent;
height: 100px;
width: 100px;
margin: 10px auto;
}
<body>
<div class="user-input">
<label>start angle</label>
<input type="text" id="startangle" value="0" />
<label>end angle</label>
<input type="text" id="endtangle" value="180" />
<button onclick="getinput()">draw</button>
</div>
<div id="circle">
</div>
</body>
for your last circle[2 overlap circles] angles are 0 and 270.to close circles you can position 2 divs and rotate them.

Related

Center Object based on rotation

I need to center an object in a canvas based on its rotation. I can't figure out the maths.
What information do I have?
x, and y coordinates of the top left corner (see red circle of image)
width and height of the object
the rotation value in degrees
What have i tried so far?
// center horizontally
if (curretElement === null) return;
curretElement.x((canvas.width() / 2) - ((curretElement.width() * curretElement.scaleX()) / 2));
canvas.draw();
// center vertically
curretElement.y((canvas.height() / 2) - ((curretElement.height() * curretElement.scaleY()) / 2));
canvas.draw();
This centers the image when it's not rotated.
currentElement is the selected object.
canvas is the room where the object should be centered in.
You can calculate the coordinates this way:
imagine that you have your object centered on the canvas
calculate the coordinates of the top left corner relative to the center of the canvas
rotate the object around the center of the canvas and calculate where the top left corner ends up relative to the center of the canvas
translate the relative coordinates of the top left corner back to absolute coordinates
Here is a function that does the calculation:
function calculateXY(canvasWidth, canvasHeight, width, height, angle) {
//calculate where the top left corner of the object would be relative to center of the canvas
//if the object had no rotation and was centered
const x = -width / 2;
const y = -height / 2;
//rotate relative x and y coordinates by angle degrees
const sinA = Math.sin(angle * Math.PI / 180);
const cosA = Math.cos(angle * Math.PI / 180);
const xRotated = x * cosA - y * sinA;
const yRotated = x * sinA + y * cosA;
//translate relative coordinates back to absolute
const canvasCenterX = canvasWidth / 2;
const canvasCenterY = canvasHeight / 2;
const finalX = xRotated + canvasCenterX;
const finalY = yRotated + canvasCenterY;
return { x: finalX, y: finalY };
}
UPDATE :first try is really bad so i update code. which actually work and keep your left corner in center of container, just fill angle input
i want to comment and ask more but i can't and this thing(bounty) is tempting
Not heavy depend on java script. may be it what you need second attempt.
Corner is container and content in before. Rotate but it remains there. does it help? comment it.
<!DOCTYPE html>
<html lang="en">
<body>
<style>
body{
margin:0;
}
#container{
display :flex;
position: absolute;
width:100%;
height:100%;
}
#ram{
display:flex;
background-color:black;
position:absolute;
margin:auto;
top:50%;
right:50%;
}
#ram::before{
content: "";
position:absolute;
height:40px;
width:400px;
background-color: #000;
}
</style>
<input type="number" id="a" onchange = "forf()">
<div id = "container">
<div id = "ram">
</div>
</div>
<script>
function forf(){
var a = document.getElementById("a").value;
document.getElementById("ram").style.transform = "rotate(" + a + "deg)";
}
</script>
</body>
</html>

How do I get the correct degress from style.transform rotate after I converted the matrix values?

I am trying to get the rotation degree from div's I rotate to create a line pattern.
Only now I am running into a problem. I need the rotation(deg) from the div's to calculate where the next line needs to appear. But when I try to get the value from a div with style.transform and convert the matrix values I still get the wrong degrees.
In my testing case I have a div that is rotated 150deg, but I get 30 deg back and this will not work for me unfortunatly. Please help, how do I get the 150deg value back?
Here is the code:
HTML:
<div class="linesBox" id="linesBox">
<div class="line1 lines" id="line1" style="float: left;
margin: 200px 0 0 100px;
position: fixed;
border-top:0.5px solid black;
width: 100px;
transform: rotate(150deg);"></div>
<!-- <div class="line2 lines" id="line1" style="float: left;
margin: 174px 0 0 193.3px;
position: fixed;
border-top:0.5px solid black;
width:100px;
transform: rotate(0deg);"></div> -->
</div>
JavaScript:
const linesBox = document.getElementById('linesBox');
let lastLineWidth;
let angle;
let lineWidthCount;
let lineHeightCount;
function createLines(){
//Last line div in a var and a var to get the computated value
let lastLine = linesBox.lastElementChild;
var st = window.getComputedStyle(lastLine, null);
//Get the width and angle of the last line and place them in a var
lastLineWidth = parseFloat(lastLine.style.width);
lastLineXPos = parseFloat(lastLine.style.marginLeft);
lastLineYPos = parseFloat(lastLine.style.marginTop);
let lastLineAngle = st.getPropertyValue("transform");
console.log(lastLineWidth, lastLineXPos, lastLineYPos);
//Get and map the Matrix value from transform rotate() and set it to lastLineAngle
var values = lastLineAngle.split('(')[1],
values = values.split(')')[0],
values = values.split(',');
//Set each value of the matrix values to a var
let a = values[0];
let b = values[1];
let c = values[2];
let d = values[3];
//Take the correc value from the matrix values and place it in the formula and save the outcome in a var
angle = Math.round(Math.asin(b) * (180/Math.PI));
console.log(angle);
//Calculate margin left starting position for the next line
//Get sin en cos values by angle
let yChangeOne = lastLineWidth * Math.sin(angle / 180 * Math.PI) / 2;
let xChangeOne = parseFloat(lastLineWidth - lastLineWidth * Math.cos(angle / 180 * Math.PI)) / 2;
// let yChangeOne = lastLineWidth * sinOutcome / 2;
// let xChangeOne = lastLineWidth - lastLineWidth * cosOutcome;
console.log(yChangeOne, xChangeOne);
let newYPos;
let newXPos;
if( angle <= 89 && angle >= 1 ){
newYPos = lastLineYPos + yChangeOne;
} else if ( angle >= 91 && angle <= 179 ){
newYPos = lastLineYPos - yChangeOne;
}
console.log(newYPos);}
//Get the start position for the next line
createLines();
The angle should return 150deg not 30deg otherwise my if statement will not work. Please help :)
Both 30° and 150° have the same sine. You also need to take the cosine into account. Instead of Math.asin(b), use
Math.atan2(b, a)
Btw, if you are just calculating the angle to calculate its sine and cosine again, then spare this step (Math.sin(angle...)). You have sine and cosine right there, so just use them.

Need help understanding mathematical formula for ellipse in JavaScript

Need help understanding this code, which is used to make an image move in an elliptical shape. What I don't understand, is the formula for e, px and py variable. What exactly is the e variable defined the complex way it is? I know it uses some mathematical formulas but i don't know which ones.
var b = 125;
var h = 115;
var rx = 7;
var ry = 4;
var e = 0;
function update() {
setInterval(function() {
e = (e + Math.PI / 360) % (Math.PI * 2);
rotate(e);
}, 10);
var lyd = new Audio("Vedlegg/skoytelyd.mp3");
lyd.play();
}
function rotate(e) {
var px = b + rx * Math.cos(e)*b/2;
var py = h + ry * Math.sin(e)*h/2;
document.getElementById("punkt").style.left = px + "px";
document.getElementById("punkt").style.top = py + "px";
}
</script>
<style>
div {
position: fixed;
}
#sentrum {
background: black;
left: 100px;
top: 50px;
}
#skoyteloper {
position: absolute;
top: 190px;
left: 450px;
width: 60px;
height: 60px;
}
</style>
</head>
<body>
<div id="sentrum"></div>
<img src="Vedlegg/bane.jpg" id="imgBane"></img>
</div>
<div id="punkt">
<img src="Vedlegg/skoyteloper.png" id="skoyteloper"></img>
</div>
TILBAKE
</body>
Sinus and cosinus:
Think of a triangle with one 90° angle. 1 line is horizontal, another line is at the right side and is vertical, the third line goes from bottom-left to top-right.
The angle on the left we call e (yes,it is the e in your function)
sinus of e is defined as the vertical line on the right divided by the diagonal line; cosinus e = horizontal line (which is touching the angle e) / diagonal.
--
Now draw a circle with middle at angle e and radius = the length of the diagonal.
If you raise the angle e you will see the vertical line get bigger and the horizontal line get smaller (keep the length of the diagonal constant), until you reach 90°. Then of course you can go beyond 90°, then the vertical line can be on the left. Further than 180° the vertical line will point down (negative coordinate), ...
So that's one of the uses of sin and cos: if you set an angle they give you an y-value and a x-value, showing you 1 point on a circle. It's always a number between -1 and +1. example: sin(0) = 0 (no vertical component), cos(0) = 1
This code here below gives you a circle around center (0,0) and radius 100. Feed this function a bunch of values for e and you get as many points on a circle
function rotate(e) {
var px = 100 * Math.cos(e);
var py = 100 * Math.sin(e);
}
Now, if instead of 100 * cos(e) you put 200 * cos(e), then it's not a circle anymore. Every x coordinate will be twice as far (compared to the circle). A different rx and ry will result in an ellipse.
your variables b & h are for pushing the center of the ellipse to somewhere inside the image/div/canvas/... rather than in a corner (then you clip most of the ellipse).
Does this help?

Rotating a square towards a certain point

I'm trying to make the shooter0 rotate towards the character (which will be moving around constantly). I tried to using the atan() and then converting that to an angle but the shooter0 won't rotate.
var shooter0 = document.getElementById('shooter0');
var character = document.getElementById('character');
var tracker0 = shooter0.getContext('2d');
// The cordinates for the character and shooter0
var characterLeft = 530;
var characterTop = 180;
var shooter0Left = 960;
var shooter0Top = 470;
while (characterLeft >= 700){
setInterval(startShooter, 1000);
}
function startShooter(){
//Getting all the variable to be able to calculate the angle of the hypotenuse
var dX = characterLeft - tracker0Left;
var dY = characterTop - tracker0Top;
var arcTan = Math.atan(dX/dY)* 180/Math.PI;
var cx = shooter0.width/2;
var cy = shooter0.height/2;
tracker0.save();
tracker0.translate(cx, cy); // pivot point
//rotating the square towards the character
tracker0.rotate(arcTan * Math.PI/180);
//Drawing the square
tracker0.fillRect(400, 300, 100, 100);
tracker0.restore();
}
HTML:
<canvas id="character" height="50px;" width="50px;"></canvas>
<canvas id="shooter0" height="100px;" width="100px;"></canvas>
And CSS:
#character{
position: absolute;
top: 180px;
left: 530px;
border: 3px solid black;
background-color: orange;
}
#shooter0{
position: absolute;
left: 960px;
top: 470px;
border: 2px solid black;
background-color: #B40404;
}
Sorry if you find the code rather messy. Here's a fiddle with all of my code if you find that useful. https://jsfiddle.net/Snubben/tc0j4psz/3/
Please don't use any JQuery.
I couldn't get your fiddle to work for some reason, so I created a little example.
The thing I notice in your code:
var arcTan = Math.atan(dX/dY)* 180/Math.PI; : Math.atan returns an angle in radians. And you convert it to degrees by 180/Math.PI
Only to convert it back to radians here again:
tracker0.rotate(arcTan * Math.PI/180);
Then, for calculating angles (in radians), I think Math.atan2 is the most easy to use: Math.atan2 - MDN
The usage of Math.atan2 to calculate an angle between two points is:
Math.atan2(point2.y - point1.y, point2.x - point1.x)
With that information, I think you can get very far.
demo fiddle

HTML 5 Canvas rotate mulitple text items around circular point

I'm trying to display numbers around the spokes of a bicycle wheel. In the process of creating the 'spokes' for the wheel I can't seem to get the text to rotate without messing up the rotation of the wheel.
var arr = ['1','2','3','4','5','1','2','3','4','5','1','2','3','4','5','1','2','3','4','5'];
function drawNumber() {
var cID = document.getElementById('cogs');
var canW = cID.width,
canH = cID.height;
if (cID && cID.getContext){
var ctx = cID.getContext('2d');
if(ctx) {
ctx.translate(ctx.canvas.width/2, ctx.canvas.height/2);
var radian = (Math.PI / 180) * 18;
var i = 0
for (var degrees = 0; degrees < 360; degrees += 18) {
var fillNum = arr[i];
ctx.font = "12pt Arial"
ctx.fillStyle = 'white';
ctx.rotate(radian);
rotateText(fillNum);
i++;
}
ctx.translate(-canW/2, -canH/2);
}
}
}
function rotateText(i){
var cID = document.getElementById('cogs');
ctx = cID.getContext('2d');
ctx.fillText(i, -5, 150);
}
drawNumber();
http://jsfiddle.net/rdo64wv1/8/
If I add a rotate to the rotate text function it doesn't rotate the text, it just moves around the spokes further. Any ideas?
If I understand you correctly, you want to numbers to continue along the spoke direction at 90°. What you mean exactly is a bit unclear as what direction is text continuing at in the first place. Considering that the fiddle shows the text continuing at the y-axis, here is how to draw text with the text result continuing at the x-axis instead (if this is not what you're after, please include a mock-up of what result you expect - just adjust the angle at the commented-out line as needed).
Think of the process as an arm: shoulder is rotated first, then the elbow, both at their pivot points, but elbow is always relative to shoulder angle.
So, first rotate at center of wheel to get the spoke angle. Then translate to the origin of the text along that spoke (x-axis in canvas as 0° points right) to get to the "elbow" pivot point, or origin. Rotate (if needed) and draw text, finally reset transformation and repeat for next number.
Here's an updated example with some additional adjustments:
var arr = ['1','2','3','4','5','1','2','3','4','5','1','2','3','4','5','1','2','3','4','5'];
function drawNumber() {
var cID = document.getElementById('cogs'),
cx = cID.width * 0.5, // we'll only use the center value
cy = cID.height * 0.5;
if (cID && cID.getContext){
var ctx = cID.getContext('2d');
if(ctx) {
ctx.font = "12pt Arial" // set font only once..
ctx.textAlign = "center"; // align to center so we don't
ctx.textBaseline = "middle"; // need to calculate center..
var step = Math.PI * 2 / arr.length; // step based on array length (2xPI=360°)
for (var angle = 0, i = 0; angle < Math.PI * 2; angle += step) {
ctx.setTransform(1,0,0,1,cx, cy); // hard reset transforms + translate
ctx.rotate(angle); // absolute rotate wheel center
ctx.translate(cx - 10, 0); // translate along x axis
//ctx.rotate(-Math.PI*0.5); // 90°, if needed...
ctx.fillText(arr[i++], 0, 0); // draw at new origin
}
}
}
ctx.setTransform(1,0,0,1,0,0); // reset all transforms
}
drawNumber();
<canvas id='cogs' width='300' height='300'></canvas>

Categories