I think the title is a little bit confusing so I will try to say it better.
Image you have this code:
#NadrzFrontView:before {
--beginHeight: var(--startHeight);
--endHeight: var(--finishHeight);
animation: 2s fillin ease forwards;
content: "";
position: absolute;
bottom: 0;
width: 300px;
height: 0;
background-color: #00FFF5;
display: inline-block;
}
#NadrzFrontView {
width: 300px;
height: 300px;
border-radius: 50%;
border: 3px solid black;
position: relative;
overflow: hidden;
}
<div id="NadrzFrontView" style="--startHeight: 0%; --finishHeight: 50%;"> </div>
It looks like this:
Now, you can determent left, top position and height of an element using this script:
function getOffset(el) {
var rect = el.getBoundingClientRect();
return {
left: rect.left + window.pageXOffset,
top: rect.top + window.pageYOffset,
width: rect.width || el.offsetWidth,
height: rect.height || el.offsetHeight
};
}
Ok, when we are able to find these then we go to our problem:
function SomeFunction() {
var thickness = 1;
var color = '#000000';
var off_nadrz = getOffset(document.getElementById('NadrzFrontView'));
var elem = document.getElementById('NadrzFrontView');
var pseudoStyle = window.getComputedStyle(elem, ':before');
var off_pseudo_elem = getOffset(elem);
off_pseudo_elem.top += parseInt(pseudoStyle.top, 10);
off_pseudo_elem.left += parseInt(pseudoStyle.left, 10);
off_pseudo_elem.height = parseInt(pseudoStyle.height, 10);
//finding middle of the circle
var x1 = off_nadrz.left + (off_nadrz.width / 2);
var y1 = off_nadrz.top + (off_nadrz.height / 2);
//draw point in the middle of circle
document.getElementById("AllLines").innerHTML += CreateHtmlPoint(color, x1, y1);
//fincding point on the side of an element
var x2; //I need to find this -- see more in examples
var y2; //I need to find this -- see more in examples
document.getElementById("AllLines").innerHTML += CreateHtmlPoint(color, x2, y2); //This does not work
}
function CreateHtmlPoint(color, cx, cy) {
cx -= 5; // - 5, because width of point is 10
cy -= 5; // - 5, because height of point is 10
return "<div style='padding:0px; z-index: 2; margin:0px; height: 10px; width: 10px; background-color:" + color + "; line-height:1px; position:absolute; left:" + cx + "px; top:" + cy + "px; border-radius: 50%;' />";
}
So, now example of an x2 and y2 would look like this:
Basically, we know on what coordinades is top of circle (off_nadrz.top), bottom of circle (off_nadrz.top + (off_nadrz.height / 2)) and height of an circle (off_nadrz.height). We also know same things of an psuedo_element (blue thing in the circle). From this we need to calculate x2 and y2.
Thanks for every suggestion because I am fighting with this problem for 2 days now...
you have only to apply the circumference formula:
var y2 = y1 - ( off_pseudo_elem.height - off_nadrz.height / 2 );
once you have y2, calculate x2:
var r = off_nadrz.height / 2; // if the figure is a circle, not an ellipse
var x2 = x1 + Math.sqrt( r * r - ( y2 - y1 ) * ( y2 - y1 ) );
Related
I am trying to draw a path between points wihtout using canvas or any other librares.
Everything works fine for positive degrees, but it doesn't for negative..
My "points" are 150x150 [px], that's why there is that +75px in left position.
This is my code:
useEffect(() => {
let x1 = spider1.x;
let y1 = spider1.y;
let x2 = spider2.x;
let y2 = spider2.y;
if (x1 > x2) {
let xTmp = x1;
let yTmp = y1;
x1 = x2;
y1 = y2;
x2 = xTmp;
y2 = yTmp;
}
if (x1 === x2) {
const height = Math.abs(y2 - y1).toString();
setStyle({
width: '5px',
left: (x1 + 75).toString() + 'px',
top: `${Math.min(y1, y2) + 75}px`,
height: `${height}px`,
transform: 'rotate(0deg)'
});
} else {
const a = (y2 - y1) / (x2 - x1);
const radians = Math.atan(a);
const degrees = radians * (180 / Math.PI);
setStyle({
width: `${Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1))}px`,
left: (x1 + 75).toString() + 'px',
top: `${Math.min(y1, y2) + 75}px`,
height: `5px`,
transform: `rotate(${degrees}deg)`,
transformOrigin: `${degrees > 0 ? '0% 0%' : '100% 100%'}`
});
}
}, [spider1, spider2]);
return <div className='net' style={style} ref={myRef}></div>;
And the net class:
.net {
position: absolute;
background-color: red;
z-index: 90;
}
On the screens we have the same objects, but the degrees on the second one are "-" and the line doesn't connect that two squares because of that
This example works. You will have to compare yours with mine as to what the differences are.
Note: I just wrote it from scratch rather using your example.
Just click "Random position"
var button = document.getElementById("new-points");
button.onclick = function() {
var xy1 = {
m_x : Math.floor((Math.random() * 200) + 1),
m_y : Math.floor((Math.random() * 200) + 1),
};
var xy2 = {
m_x : Math.floor((Math.random() * 200) + 1),
m_y : Math.floor((Math.random() * 200) + 1),
};
var dotA = document.getElementById("dotA");
dotA.style.left = (xy1.m_x - 5) + "px";
dotA.style.top = (xy1.m_y - 5) + "px";
var dotB = document.getElementById("dotB");
dotB.style.left = (xy2.m_x - 5) + "px";
dotB.style.top = (xy2.m_y - 5) + "px";
var line = document.getElementById("line");
var distance = Math.hypot(xy2.m_x - xy1.m_x, xy2.m_y - xy1.m_y);
line.style.width = distance + "px";
line.style.left = xy1.m_x + "px";
line.style.top = xy1.m_y + "px";
var angle = ((Math.atan2(xy1.m_x - xy2.m_x, xy2.m_y - xy1.m_y) + (Math.PI / 2.0)) * 180 / Math.PI);
line.style.transform = "rotate(" + angle + "deg)";
line.style.display = "block";
}
#new-points {
border: 1px solid black;
padding: 5px;
width: 200px;
text-align: center;
}
.dot {
position: absolute;
width: 10px;
height: 10px;
background: blue;
}
#line {
position: absolute;
border-top: solid 1px red;
height: 1px;
max-height: 1px;
transform-origin: 0% 0%;
}
<div id="dotA" class="dot"></div>
<div id="dotB" class="dot"></div>
<div id="line"></div>
<div id="new-points" style="">
Random position
</div>
I've also tried the atan method for the above and it doesn't work. You can try it yourself and see what happens.
I have arcs connecting nodes in a d3 force directed graph, the whole SVG is transformed with CSS. Now the arcs doesn't feel nice as its like lying in the ground, so I want to get them "stand up", or rotate X,Y,Z to get the effect.
I have set the transform origin to the center of the line connecting the nodes, but now I am stuck with finding the angles at which I have to rotate the arcs to make them stand up. Any idea/formula on finding the angles is much appreciated.
The code I am having right now inside the tick function looks like:
force.on("tick", function() {
path.attr("d", function (d) {
var dx = d.target.x - d.source.x,
dy = d.target.y - d.source.y,
dr = Math.sqrt(dx * dx + dy * dy) -200;
return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + d.target.x + "," + d.target.y;
})
.attr('style', function(d){
var rotateX = 0, rotateY = 0, rotateZ = 0;
return "transform-origin:" + (d.source.x + d.target.x)/2 + "px " + (d.source.y + d.target.y)/2 + "px" +
";transform:rotateX("+rotateX+"deg) rotateY("+rotateY+"deg) rotateZ("+rotateZ+"deg)";
});
rotateX, rotateY and rotateZ angles are what I am looking for!
I have no practical knowledge of d3, so I have solved the problem for a standard javascript layout.
Hopefully the procedure should work the same.
On the demo, click 2 times to set the begin and end of the arc. Then click again to see it rotating in 3d.
You can repeat the cycle how many times you want.
In the transform calculus we just calculate the angle in the plane with atan2 and the horizontal and vertical differences. The real trick is to set the 90 degrees that will get the element vertical after (in notation) the plane rotation.
Note that in the snippet I am not applying 90 degress, but 80, so that the arc is still visible when viewed from above.
var sequence = 0;
var x1, y1, x2, y2;
function getCursorPosition(event) {
var x = event.clientX;
var y = event.clientY;
var ele = document.getElementById('container');
if (sequence == 0) {
x1 = x;
y1 = y;
sequence = 1;
ele.classList.remove("animate");
} else if (sequence == 1) {
x2 = x;
y2 = y;
sequence = 2;
Compute();
} else {
ele.classList.add("animate");
sequence = 0;
}
}
function Compute() {
var ele = document.getElementById('inner');
var width = Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
ele.style.width = width + "px ";
ele.style.height = width / 2 + "px ";
ele.style.left = x1 + "px ";
ele.style.top = y1 + "px ";
var angle = Math.atan2(y2 - y1, x2 - x1);
var deg = angle * 180.0 / Math.PI;
ele.style.transform = "rotate(" + deg + "deg) rotateX(80deg) "
/*
var style = "width:" + width + "px ";
style += "left: " + x1 + "px ";
style += "top: " + y1 + "px ";
ele.setAttribute("style",style);
*/
}
.container {
width: 600px;
height: 400px;
border: solid 1px green;
perspective: 1000px;
transform-style: preserve-3d;
position: absolute;
background-image: repeating-linear-gradient(white 0px, wheat 50px, white 100px);
}
#inner {
width: 100px;
height: 50px;
border-radius: 0px 0px 100px 100px;
background-color: green;
position: absolute;
transform-origin: left top;
transform-style: preserve-3d;
}
.animate {
animation: rota 15s 1;
}
#keyframes rota {
from {
transform: perspective(1000px) rotateX(0deg);
}
to {
transform: perspective(1000px) rotateX(360deg);
}
}
<div class="container" id="container" onclick="getCursorPosition(event)">
<div id="inner">
</div>
</div>
Please run the code snippet below - you will see an angled line derived from the corners of a box. Given mouse movement, I would like to move the marker along this line - where either:
movement in x will move along the line, and additional movement in y will accelerate
movement in x will move along the line and you can get from start to finish with it (whatever is simplest)
So far I haven't got anywhere but I'll update if I do and many thanks for any help.
PS doesn't really matter if it doesn't move exactly along the line - it's the algorithm to move along an angle I'm interested in.
Fiddle: http://jsfiddle.net/ngr3dbhx/3/
var boxEl = document.getElementById('box');
var lineEl = document.getElementById('line');
var markerEl = document.getElementById('marker');
var rad, deg;
// Draw an angled line for demonstration purposes.
function getElementOffset (el) {
var rect = el.getBoundingClientRect();
var docEl = document.documentElement;
var rectTop = rect.top + window.pageYOffset - docEl.clientTop;
var rectLeft = rect.left + window.pageXOffset - docEl.clientLeft;
return {
top: rectTop,
left: rectLeft
};
}
function calcAndDrawAngle () {
var boxOffset = getElementOffset(boxEl);
var x1 = boxOffset.left;
var y1 = boxOffset.top;
var x2 = boxOffset.left + boxEl.offsetWidth;
var y2 = boxOffset.top + boxEl.offsetHeight;
var deltaX = x2 - x1;
var deltaY = y2 - y1;
rad = Math.atan2(deltaY, deltaX);
deg = rad * (180 / Math.PI);
lineEl.style.transform = 'rotate(' + deg + 'deg) translate(-50%, 0)';
}
// On mouse move I want to move the marker along the anged line..
// Do something with rad or deg?
document.addEventListener('mousemove', function (e) {
markerEl.style.top = e.clientY + 'px';
markerEl.style.left = e.clientX + 'px';
});
calcAndDrawAngle();
window.addEventListener('resize', calcAndDrawAngle);
html,
body {
margin: 0;
width: 100%;
height: 100%;
overflow: hidden;
}
#box {
position: absolute;
top: 20%;
left: 30%;
width: 35%;
height: 30%;
border: 1px solid #999;
}
#line {
position: absolute;
top: 0;
left: 0;
transform-origin: top left;
height: 1px;
width: 9999em;
background-color: black;
}
#marker {
position: absolute;
width: 8px;
height: 8px;
background-color: red;
}
<div id="box">
<div id="line"></div>
</div>
<div id="marker"></div>
you mean this?
https://jsfiddle.net/2q1nLh3q/1/
The formula is basic mathematics:
y = k * x + d
Where k is deltaY / deltaX and d is the point where the line crosses the y axis.
So your function could look like this:
document.addEventListener('mousemove', function (e) {
window.requestAnimationFrame(function() {
var boxOffset = getElementOffset(boxEl);
var k = boxEl.offsetHeight / boxEl.offsetWidth;
var d = boxOffset.top - boxOffset.left * k;
var mouseY = k * e.clientX + d;
markerEl.style.top = mouseY + 'px';
markerEl.style.left = e.clientX + 'px';
});
});
Using fairly simple math, calculate y for any x within limited range (subtracted 4 to place rectangle at center):
//var canvas = document.getElementById('canvas');
var boxEl = document.getElementById('box');
var lineEl = document.getElementById('line');
var markerEl = document.getElementById('marker');
var rad, deg;
var coords;
// Draw an angled line for demonstration purposes.
function getElementOffset (el) {
var rect = el.getBoundingClientRect();
var docEl = document.documentElement;
var rectTop = rect.top + window.pageYOffset - docEl.clientTop;
var rectLeft = rect.left + window.pageXOffset - docEl.clientLeft;
return {
top: rectTop,
left: rectLeft
};
}
function calcAndDrawAngle () {
var boxOffset = getElementOffset(boxEl);
var x1 = boxOffset.left;
var y1 = boxOffset.top;
var x2 = boxOffset.left + boxEl.offsetWidth;
var y2 = boxOffset.top + boxEl.offsetHeight;
coords = [{x:x1,y:y2},{x:x2,y:y1}];
var deltaX = x2 - x1;
var deltaY = y2 - y1;
rad = Math.atan2(deltaY, deltaX);
deg = rad * (180 / Math.PI);
lineEl.style.transform = 'rotate(' + deg + 'deg) translate(-50%, 0)';
}
// On mouse move I want to move the marker along the anged line..
// Do something with rad or deg?
document.addEventListener('mousemove', function (e) {
var x = Math.min(Math.max(e.clientX, coords[0].x), coords[1].x) - 4;
var y = coords[0].y + ((coords[1].y - coords[0].y) * (coords[1].x - x) / (coords[1].x - coords[0].x));
markerEl.style.top = y + 'px';
markerEl.style.left = x + 'px';
});
calcAndDrawAngle();
window.addEventListener('resize', calcAndDrawAngle);
html,
body {
margin: 0;
width: 100%;
height: 100%;
overflow: hidden;
}
#box {
position: absolute;
top: 20%;
left: 30%;
width: 35%;
height: 30%;
border: 1px solid #999;
}
#line {
position: absolute;
top: 0;
left: 0;
transform-origin: top left;
height: 1px;
width: 9999em;
background-color: black;
}
#marker {
position: absolute;
width: 8px;
height: 8px;
background-color: red;
}
<div id="box">
<div id="line"></div>
</div>
<div id="marker"></div>
I used below code to draw a line in circle,Now I want to draw 12 lines in different angles with same space & lines should be touched to the circle.
<!DOCTYPE html>
<html>
<head>
<style>
#straight{
height: 30px;
border-right: 1px solid blue;
-webkit-transform: rotate(**" for loop value must be displayed"** deg);
transform: rotate(**" for loop value must be displayed"** deg);
position: absolute;
top:40px;
left:400px;
}
#circle {
height: 30px;
width: 31px;
margin-left: 81px;
margin-top: 0px;
background-color: #fff;
border: 2px solid blue;
border-radius: 65px;
position:absolute;
}
</style>
</head>
<body>
<div>
<div id="circle">
<div style="position:relative; top:-40px; left:-385px;">
<div id="straight"></div>
</div>
</div>
</body>
</html>
Please help me & thanks in advance
Check this fiddle.
It uses a function DrawLine(x1,y1,x2,y2) to draw a line between the given co-ordinates.
Basically, it creates divs with thin width and rotate them according the slope.
Looks like a wheel with spokes.
Here is a wheel in action if you need.
Here is the snippet.
drawNLines(12, 40, 40, 40);
function drawNLines(N, centreX, centreY, radius) {
for (i = 0; i < N; i++) {
angle = 360 / N;
x2 = centreX + radius * Math.cos(Math.PI * angle * i / 180);
y2 = centreY + radius * Math.sin(Math.PI * angle * i / 180);
DrawLine(centreX, centreY, x2, y2);
}
}
function DrawLine(x1, y1, x2, y2) {
if (y1 < y2) {
var pom = y1;
y1 = y2;
y2 = pom;
pom = x1;
x1 = x2;
x2 = pom;
}
var a = Math.abs(x1 - x2);
var b = Math.abs(y1 - y2);
var c;
var sx = (x1 + x2) / 2;
var sy = (y1 + y2) / 2;
var width = Math.sqrt(a * a + b * b);
var x = sx - width / 2;
var y = sy;
a = width / 2;
c = Math.abs(sx - x);
b = Math.sqrt(Math.abs(x1 - x) * Math.abs(x1 - x) + Math.abs(y1 - y) * Math.abs(y1 - y));
var cosb = (b * b - a * a - c * c) / (2 * a * c);
var rad = Math.acos(cosb);
var deg = (rad * 180) / Math.PI
htmlns = "http://www.w3.org/1999/xhtml";
div = document.createElementNS(htmlns, "div");
div.setAttribute('style', 'border:1px solid black;width:' + width + 'px;height:0px;-moz-transform:rotate(' + deg + 'deg);-webkit-transform:rotate(' + deg + 'deg);position:absolute;top:' + y + 'px;left:' + x + 'px;');
document.getElementById("circle").appendChild(div);
}
#circle {
height: 80px;
width: 80px;
margin-left: 30px;
margin-top: 30px;
background-color: #fff;
border: 2px solid blue;
border-radius: 80px;
position: absolute;
}
<div id="circle"></div>
Hope this helps. :)
Microsoft provide an excellent SVG gradient maker so IE9 can also have "CSS3" gradients (click Custom).
I currently utilise their logic for my Fireworks and Dreamweaver extensions to convert gradients to SVG, but I only know how to do it for standard top, bottom, left, right directions. If you enter an angle, I don't do the conversion, because I'm not sure how I would convert x1, x2, y1, y2 to CSS3 angle degrees.
The gradient generator provides values like this: x1="0%" y1="0%" x2="56.262833675564686%" y2="68.29999651227678%"
I'm not great with mathematics or trigonometry, so could somebody help me out? I'd also like to use the same math in a Sass mixin to do a similar thing, if possible.
If you get deltaX and deltaY from your coordinates then Math.atan2 returns the arctangent of the quotient of its arguments. The return value is in radians.
var deltaX = x2 - x1;
var deltaY = y2 - y1;
var rad = Math.atan2(deltaY, deltaX); // In radians
Then you can convert it to degrees as easy as:
var deg = rad * (180 / Math.PI)
Edit
There was some bugs in my initial answer. I believe in the updated answer all bugs are addressed. Please comment here if you think there is a problem here.
The currently accepted answer is incorrect. First of all, Math.tan is totally wrong -- I suspect Mohsen meant Math.atan and this is just a typo.
However, as other responses to that answer state, you should really use Math.atan2(y,x) instead. The regular inverse tangent will only return values between -pi/2 and pi/2 (quadrants 1 and 4) because the input is ambiguous -- the inverse tangent has no way of knowing if the input value belongs in quadrant 1 vs 3, or 2 vs 4.
Math.atan2, on the other hand, can use the xy values given to figure out what quadrant you're in and return the appropriate angle for any coordinates in all 4 quadrants. Then, as others have noted, you can just multiply by (180/Math.pi) to convert radians to degrees, if you need to.
Instead of using Math.tan function You should use Math.atan2:
Here is an example of use:
deltaX = x2 - x1;
deltaY = y2 - y1;
deg = Math.atan2(deltaY, deltaX)*180.0/Math.PI;
and this will return a degree from <-180;180>.
If you in a Quadrant
P1=(X0,Y0)
P2=(X1,Y1)
a=(X0-X1)
b=(Y0-Y2)
deltaX=((a)**2)**0.5
deltaY=((b)**2)**0.5
rad=math.atan2(deltaY, deltaX)
deg = rad * (360 / math.pi)
print deg
the deg will between 0 ~ 180
This function takes 2 elements and returns the degree between the middle of the elements.
For example, I used it on a world map, to make the image of plane rotate in the direction of a city.
function degFromTwoElements(el1,el2){
var x1,x2,y1,y2,cx1,xy1,cx2,cy2,deltaX,deltaY,dx,dy,rad,deg,shortest,number;
x1 = el1.position().left;
y1 = el1.position().top;
x2 = el2.position().left;
y2 = el2.position().top;
cx1 = x1 - (el1.width() / 2);
cy1 = y1 - (el1.height() / 2);
cx2 = x2 - (el2.width() / 2);
cy2 = y2 - (el2.height() / 2);
deltaX = cx2 - cx1;
deltaY = cy2 - cy1;
y1 = Math.sqrt((Math.abs(deltaY)*Math.abs(deltaY))+(Math.abs(deltaX)*(Math.abs(deltaX))));
x1 = 0;
dy = deltaY-y1;
dx = deltaX-x1;
rad = Math.atan2(dy, dx);
deg = rad * (360 / Math.PI);
shortest;
number = Math.abs(deg);
if ((360 - number ) < number){
shortest = 360 - number;
console.log('shorter degree: ' + shortest);
return shortest;
}
else console.log('Angle is: ' + deg);
return deg;
}
var x,x1,x2,y,y1,y2;
var cells = 'cell0';
var h,w;
var cx,cy;
var dx,dy;
var derajat;
var deg;
var ang;
var light;
var control;
function mouse_watch(event){
x = event.clientX;
y = event.clientY;
cell_data(cells);
koordinat(x2,y2);
busur(derajat);
}
function koordinat(x2,y2){
x2 = x-cx;
y2 = y-cy;
yk = y2;
xk = x2;
}
function busur(derajat){
y1 = Math.sqrt((Math.abs(yk)*Math.abs(yk))+(Math.abs(xk)*(Math.abs(xk))));
x1 = 0;
dy = yk-y1;
dx = xk-x1;
rad = Math.atan2(dy, dx);
derajat = rad * (360 / Math.PI);
cell = document.getElementById(cells);
ang = cell.getElementsByClassName('angle0')[0];
ang.style.transform = 'rotate('+derajat+'deg)';
light = ang.getElementsByClassName('points')[0];
light.style.height = y1+'px';
}
function cell_data(cells){
cell = document.getElementById(cells);
h = Number(cell.style.height.replace('px',''));
w = Number(cell.style.width.replace('px',''));
cy = Number(cell.style.top.replace('px',''))+h/2;
cx = Number(cell.style.left.replace('px',''))+w/2;
}
.preview_engine{
position: absolute;
top: 0;
left: 0;
padding: 10px;
background-color: #2E8AE6;
color: white;
}
body{
cursor: default;
width: 100%;
height: 100%;
font-family: Arial;
font-size: 12px;
}
.fieldwork{
width: 100%;
height: 100%;
position: absolute;
top: 0px;
left: 0px;
}
.cell{
position: relative;
transition : width 2s, height 2s, top 2s, left 2s;
background-color: red;
}
.angle0{
width: 200px;
height: 200px;
position: absolute;
top: -75px;
left: -75px;
background-color: green;
border-radius: 50%;
opacity: 0.5;
transition : width 2s, height 2s, top 2s, left 2s;
}
.points{
width: 10px;
height: 10px;
position: absolute;
left: 95px;
top: 95px;
background-color: red;
border-radius: 1em;
opacity: none;
}
<div class="fieldwork" onmousemove="mouse_watch(event)">
<div class='cell' id="cell0" style="width:50px;height:50px;top:200px;left:400px;">
<div class="angle0">
<div class="points"></div>
</div>
</div>
</div>