53

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.

Matt Stow
  • 6,053
  • 6
  • 24
  • 26

6 Answers6

101

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)

enter image description here

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.

Mohsen
  • 64,437
  • 34
  • 159
  • 186
  • Sorry, that means nothing to me :( Delta is the difference between two values? The grdient generator provides values like this: x1="0%" y1="0%" x2="56.262833675564686%" y2="68.29999651227678%" I'm assuming it's not as simple as Math.tan((56.262833675564686-0)/(68.29999651227678-0)) as that results in 1.0798259764224096 :-\ – Matt Stow Apr 14 '13 at 00:19
  • 2
    deltaX would be x2-x1 and deltaY would be y2-y1. Your answer is correct however it is in radian units, you forgot to multiply by (180 / Math.PI) to get your answer in degrees – Waleed Amjad Apr 14 '13 at 00:48
  • Thank you very much to all of you :) – Matt Stow Apr 14 '13 at 01:20
  • 8
    You should use [`Math.atan2`](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math/atan2) instead. – Phrogz Apr 14 '13 at 14:35
  • Using atan2 you should take into account the function discontinuity, see my answer below – pasx Sep 10 '13 at 23:04
  • It isn't correct answer, You should use atan2 instead of tan. – MNie Jan 24 '15 at 16:25
  • 4
    I see this answer has been edited (it used to say `Math.tan` instead of `Math.atan2`), but it still isn't *quite* right. The coordinates should be in the order `(y,x)` instead of `(x,y)`... seems silly to me too, but that's JavaScript for you. See [here](http://www.w3schools.com/jsref/jsref_atan2.asp) for documentation on `Math.atan2` or my own answer for a bit more detail. – Matt Jan 27 '15 at 01:55
  • 1
    What if I know the angle but want to find out the deltaX & deltaY? – Imran Bughio Jan 24 '17 at 12:07
27

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.

Matt
  • 1,101
  • 11
  • 11
4

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>.

MNie
  • 1,347
  • 1
  • 15
  • 35
-1

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

楊宇恩
  • 99
  • 2
  • 11
-1

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;

}
-2

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>
Black Side
  • 17
  • 1
  • while this is a nice widget, this doesn't add anything to any of the answers... nor does it answer the question... – Chris Maes Jan 11 '16 at 10:34
  • 1
    "The amount of code per answer increases with the amount of answers a stackoverflow question has" ("so-ed-1"-theorem). "The code quality decreases with the amount of answers a stackoverflow question has" ("so-ed-2"-theorem) - sorry for my sarcasm – Erhard Dinhobl Jan 28 '16 at 07:36