Archive
Calculating the angle between two points on a circle
I needed to calculate the angle between two points on the same circle. Don’t ask why, totally a new more complicated discussion.
So I had to remember a little trigonometry from the old days. Actually, this is done surprisingly easy, by simply using the atan2
method. Fortunately, this is available in JavaScript
in the Math
library.
In my problem, I had the center of the circle, one of the coordinates point(p1) and I had to find out the angle between the point (p0) at the 12-hour (imagine the circle as a clock) and the given one.

Angle between two points on a circle
First of all the coordinates of the point at 12-hour is
p0(x,y) = (center.x, center.y - radius)
where radius is the circle radius and is calculated (according to Pythagorean theorem) as
radius = sqrt(|center.x - p1.x|<sup>2</sup> * |center.y - p1.y|<sup>2</sup>)
Now let’s calculate the angle:
angle = atan2(p1.y - p0.y, p1.x - p0.x)
This will return the angle in radians. If you want to translate it into the interval [0,2 π] then simply multiply by two. If you want to transform it to degrees use angle * 180 / π
.
Below you have a JavaScript function that receives as arguments the coordinates of the center and second point and returns the angle in degrees in the interval (0°, 360°) between the 12-hour point and the second point
function angle(center, p1) { var p0 = {x: center.x, y: center.y - Math.sqrt(Math.abs(p1.x - center.x) * Math.abs(p1.x - center.x) + Math.abs(p1.y - center.y) * Math.abs(p1.y - center.y))}; return (2 * Math.atan2(p1.y - p0.y, p1.x - p0.x)) * 180 / Math.PI; }
I also wrote a small demo.
Later update:
As I had this question in the comments, in case you have the center coordinates, radius, angle and you want to calculate the second point coordinates, below is the JavaScript function. The first point is considered to be at 12’o clock.
function getPointAt(center, radius, angle) { // Please note that the angle is given in radians; // if given in degrees uncomment the line below //angle *= Math.PI / 180; return {x: center.x + Math.sin(Math.PI - angle) * radius, y: center.y + Math.cos(Math.PI - angle) * radius}; }
All the coordinates are relative to the top left corner.
Behavior helping cross browser transparency
One of the things that I hate the most when developing DHTML applications is that I have to write code for at least 3 browsers. And nowadays the differences between them are not so big, but 5 years ago …
If you write some DHTML code you have to consider at least Firefox (>=2), Internet Explorer (>=6) and Safari. These are the most common web browsers. Google Chrome is gaining lately some popularity, but you can assimilate it with Firefox. Opera and other browsers have such a low percentage usage that you can safely ignore them.
Every time you will see some JavaScript code that shows you how to do some tricks, you will probably see a notice that is cross-browser. And if you dig deep inside the code, you will probably see lots of code that does nothing else but testing for the browser and then applying specific code for it.
It would be so nice if all the browsers will implement the standard(W3C) and only the standard. Then you will have an environment by default cross-browser.
A compromise are the existing cross-browser frameworks. But … you have to learn a new framework and you’re stuck with that framework, as your code will not work without it. And, if in the future browsers will become more and more compliant (it’s not a joke, IE8 seems to make small steps in that direction), you are still stuck with that framework.
Nice will be a framework that will ensure the cross-browser thingy in a transparent way.
Let’s be more practical. Some time ago I wrote an article about how you can make HTML elements transparent in a cross-browser way. But you actually had to write code for three browsers. Safari follows the standards here, Firefox >= 1.x as well (we can ignore FF 0.x – nobody is probably using it anymore). So I will focus on a workaround to help you write
element.style.opacity = 0.7;
and to have the desired result even in IE. Let’s admit, IE has always been the “rebel kid”, but also the most used.
The idea is simple. Every time I modify the “opacity” property of an element style in IE, I will run some code to do the necessary translation and ensure the cross-browser in a transparent way.
Now, for this we will use behaviors, an IE specific feature. Which in this case is good, as the code will be ignored by other browsers.
First of all attach a behavior, described in cb-opacity.htc
, to all the elements, through CSS code (put it in a STYLE
tag or a separate .css file):
* { behavior: url(cb-opacity.htc);}
.
And now the most interesting part – cb-opacity.htc
<PUBLIC:COMPONENT lightWeight="true"> <PUBLIC:ATTACH event="onpropertychange" handler="doOnPropertyChange"/> <PUBLIC:ATTACH event="oncontentready" handler="doOnContentReady"/> <SCRIPT> function doOnContentReady() { // when this behavior is attached to an element, then check if the opacity was not already set // most likely through CSS code if (element.currentStyle.opacity != null) { element.style.filter = 'alpha(opacity=' + (element.currentStyle.opacity * 100) + ')'; } else if (element.style.opacity != null) { element.style.filter = 'alpha(opacity=' + (element.style.opacity * 100) + ')'; } } function doOnPropertyChange() { // every time the style opacity is changed through JavaScript, then modify the CSS filter too if (window.event.propertyName == "style.opacity") { element.style.filter = 'alpha(opacity=' + (element.style.opacity * 100) + ')'; } } </SCRIPT> </PUBLIC:COMPONENT>
And now IE has support for style.opacity
. Pretty nice, isn’t it?
Later edit: The same can be applied to cssFloat and styleFloat.
!u@#!^$ “Invalid character” IE error
Internet Explorer is probably the worst browser for web development. Or maybe I’m too used to Firefox.
Let me give you just a simple example, that can drive you mad.
Have you ever encountered the below error?
Line: 2 Char: 1 Error: Invalid character Code: 0 URL: ...
I did. So I googled a little bit to see what could be the problem and I come over this article. Of course, that wasn’t the problem. Finally, I realized myself: one of the referenced JavaScript files was missing.
I know that this is my mistake, but I’m totally amazed about the usefulness of the IE error messages. It is a missing file, not an invalid character.
Not to mention, that the URL is always the main one, even though the error occurred in one of the referenced JavaScript files and the line reported is not the actual line where the error occurred, but increased by 1. But this is already common knowledge.
That’s one of the reasons I always use Firefox for web development, try to stick to the standards and only in the end, test the solution on Internet Explorer too. And there is no decent JavaScript debugger for IE. And …
I also wrote a small HTML, for you to see what I’m talking about.
Later update: This was tested on IE6. In IE8 works as expected.
Fixing IE: CSS fixed position
I will start a series of articles about how you can fix some IE bugs. We all agree that IE is very buggy, but instead of whining, let’s see what we can do about it. So I will present you the problem, the fix, explain the fix and how you can EASILY INTEGRATE it.
Before, I will explain you a few things that I will use in these fixes. There are few different things in IE when it comes to CSS.
If you prefix a CSS property with _, IE will still recognize it. If you think this can be very useful. You can specify values for CSS properties only for IE. Let’s take an example.
color: green;
_color: red;
The font color will be green in all the browsers, except IE, where it will be red.
Instead of _, you can also use *, + and some other special signs.
The CSS value supports in IE a special value: expression([expr]). The [expr]
is a JavaScript expression, which is evaluated and the CSS value is assigned to it. Again an example:
_height: expression((1 + 1) + 'px');
The CSS height in the above example is actually 2 pixels in IE. In the expression we can even use this
to refer to the element for which the CSS value is applied.
Now let’s get back to the current issue. If you specify the fixed
value for the position
property, the element should be absolutely positioned, but relatively to the viewport, instead of the document. For more detailed info, please see the CSS specification. Not surprisingly, this works in most of the browsers, except IE.
And now, the fix. Which is actually very simple. We will use absolute positioning but we will calculate the coordinates dynamically relative to the viewport.
So the CSS code
position: fixed;
top: 10px;
left: 20px;
will have the following IE equivalent
_position: absolute;
_top: expression(((ignoreMe
= document.documentElement.scrollTop
? document.documentElement.scrollTop
: document.body.scrollTop ) + 10) + 'px' );
_left: expression(((ignoreMe
= document.documentElement.scrollLeft
? document.documentElement.scrollLeft
: document.body.scrollLeft ) + 20) + 'px' );
.
Don’t remove the ignoreMe
variable as this will force the expression to be evaluated not only the first time the page is loaded, but always.
In the end, a live example. And if you complain that in Mozilla the things are smoother, then simply switch to Mozilla :).
Cross browser XMLHttpRequest
AJAX has become more and more widely used. It is a cool thing, you can do a lot with it, but basically (and here is the best part) it is only a new JavaScript object: XMLHttpRequest. There is no need to learn new technologies or languages.
Unfortunately, not all the browsers (please read especially IE) support this in a native and smooth way. If in FF2+ and even IE7, this comes in a native way, in IE6 this comes only as an ActiveX object.
The good news is that, except how the objects are instantiated, everything else is the same.
As I said in FF/Mozilla this comes in a native smooth way
var xmlHttp = new XMLHttpRequest();
but in IE5 and 6, to create it, you actually create an ActiveX object
var xmlHttp = new ActiveXObject("MSXML2.XMLHTTP");
And that’s not all, even the ActiveX object class can be different from Windows version to another, so you might also have:
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
So every time you want AJAX you might end up with something like this:
var xmlHttp; // use the ActiveX control for IE5.x and IE6 try { xmlHttp = new ActiveXObject("MSXML2.XMLHTTP"); } catch (othermicrosoft){ try { xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); } catch (native) { // If IE7, Mozilla, Safari, etc: Use native object xmlHttp = new XMLHttpRequest(); } }
As I’m lazy and I don’t want to write this code every time, I decided to wrap it up in a nice cross browser way.
How? Look at the code below.
try { // test to see if XMLHttpRequest is defined XMLHttpRequest.DONE; } catch (e) { XMLHttpRequest = new Object(); // define also all the constants XMLHttpRequest.UNSENT = 0; XMLHttpRequest.OPENED = 1; XMLHttpRequest.HEADERS_RECEIVED = 2; XMLHttpRequest.LOADING = 3; XMLHttpRequest.DONE = 4; } /** Creates new instance of the XMLHttpRequest object */ XMLHttpRequest.newInstance = function() { var xmlHttp = null; // use the ActiveX control for IE5.x and IE6 try { xmlHttp = new ActiveXObject("MSXML2.XMLHTTP"); } catch (othermicrosoft){ try { xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); } catch (native) { // If IE7, Mozilla, Safari, etc: Use native object xmlHttp = new XMLHttpRequest(); } } return xmlHttp; };
Just to explain a little bit what happens. First we test if the XMLHttpRequest exists, by calling a property on it. If it doesn’t exist, then this will raise an exception and then we will create it. After this, the next step will be to define a method (similar to a static one) to create a new instance and enclose the entire cross browser code. So now we will create a new XMLHttpRequest like this:
var xmlHttp = XMLHttpRequest.newInstance();
Lazy enough for you !? 😉
Cross-browser custom CSS cursors
I saw sometime ago the funny drawing below.
You can see that big portion is for making the design work in Internet Explorer.
First you laugh, but if you developed rich web sites/user interfaces you actually realize that this is only underevaluated. I would also extend it and say “make the design cross-browser”.
The tip that I’ll present you next it’s actually a small workaround and it will help you reduce that big pie slice.
Let’s say that you want to change the cursor for a page, for links or for some other specific elements. How? Using CSS. Then we should first go at W3C and read how to do it.
So the cursor
property is the answer.
As good web developers we will separate the CSS from HTML and create the following structure
/ +-- cursor.html |-- cursor +-- cursor.css |-- cursor.cur
cursor.html
<html> <head> <link rel="stylesheet" type="text/css" href="cursor/cursor.css"> </head> <body> Hello world! Look at me, I have a new cool cursor! </body> </html>
cursor.css
BODY { cursor: url(cursor.cur); }
Now everything should be set, so let’s give it a spin. Of course, we want everything to be cross-browser. For the sake of testing open cursor.html
in Internet Explorer, Firefox and (for those Mac lovers) Safari. Surprise, the cursor is the default one in IE and Mozilla, but it’s the desired one in Safari. Frustrating isn’t it? You write W3C compliant code and it doesn’t work in the first two major browsers. The “best” part is that this is happening for different reasons.
Let’s first take care of Mozilla. Remember from CSS2 specification that cursor
property holds a list of possible cursors and the browser should use the first found one or the default one if none is found.
Add to this list default
and modify the cursor
property from
cursor: url(cursor.cur);
to
cursor: url(cursor.cur),default;
And now refresh the page in Firefox. Even tough it doesn’t make sense at all, it will work and you will see your nice cursor.
And now IE comes next (as it still doesn’t work). As you noticed in cursor.css
, we used for the cursor
property relative URIs. To quote from there: For CSS style sheets, the base URI is that of the style sheet, not that of the source document. But if you modify the cursor
property to
cursor: url(cursor/cursor.cur),default;
this will actually work. This is because in IE, for style sheets, the base URI is that of the source element, not that of the style sheet. Totally opposite to W3C specifications, but, yeah … that’s MSIE.
And if we want to still work in Firefox and Safari we have to keep the property value as below:
cursor: url(cursor.cur),url(cursor/cursor.cur),default;
. So everytime you want to define a crossbrowser CSS cursor you should define it as a list containing the url relative to the source element, the url relative to the style sheet and the default
value.
The above examples were tested on IE 6.0.2900.2180, IE 7.0.5730, Firefox 2.0.0.11, Firefox 3.0.1, Safari 3.0.4, all under Windows XP SP2. I also tested in Opera 9.25, but it seems that it doesn’t support custom cursors.
Later edit – Jan 28, 2009:
The above examples were also tested under Firefox 3.0.5, Internet Explorer 8 beta 2 (inside IETester), Internet Explorer 8 RC1 (version 8.0.6001.18372CO), Safari 3.2.1 (525.27.1), Google Chrome 1.0.154.43 under Windows Vista.
I also tested with IE 5.5 (inside IETester), but it doesn’t support custom cursors.
There is also an example.
Later edit – Feb 10th, 2010:
If you want a custom cursor for an image (IMG) or link (A), then you need to attach the CSS to that tag, not to an enclosing container (e.g. DIV).
Web transparency
If a few years back, transparency was the cool kid in user interfaces, nowadays it’s a must if you want to have a user interface that is not dull and lives in the present.
And I’m talking here not only about desktop graphical interfaces, but also about web interfaces. With all the comotion about Web2.0 and web applications, transparency is something that you should definately see 😉 in your web site.
But how to do it? The browsers wars will definately be a battle to take and win here. But to keep it simple, I’ll tell that there are three ways to do it: W3C, Internet Explorer and Mozilla.
- W3C. If we will go to their site http://www.w3.org/TR/css3-color/#opacity we will see that the CSS property handling this is called
opacity
. The possible values are floats between 0 and 1, with 0 totally transparent and 1 totally opaque. The intermediate values represent different levels of transparency.
But you probably noticed that this is a CSS version 3 property and unfortunately very few browsers supports it currently. Latest versions of Firefox do support this (I tested it with version 2.0.0.8). - Mozilla. In Mozilla the things are the same, but the name of the CSS property is different:
-moz-opacity
. As this is an obsolete way, you should prefer the CSS3 property and use this only for backward compatibility. - Internet Explorer. Here things are a little bit more complicated. You should use the
filter
property and the Alpha. As I said, a little bit more complicated, that’s why here’s below a code sample:
filter: progid:DXImageTransform.Microsoft.Alpha(opacity=50);
The
opacity
argument can have integer values between 0 and 100, with 0 totally transparent and 100 totally opaque.
And this is for CSS. But what if you want, e. g. to create a fade in/fade out effect and to dinamically modify the transparency? Then you should simply use JavaScript and I think the best way to explain how it is through code samples.
- W3C method:
element.style.opacity = opacity;
- Mozilla method:
element.style.MozOpacity = opacity;
- Internet Explorer method:
element.style.filter = 'alpha(opacity=' + (opacity * 100) + ')';
In these samples, the opacity
parameter value has the same semantic as in the CSS3 case. Please note that in the IE code sample this value is multiplied by 100.
And now if we put all these together we have cross browser methods for getting and setting the transparency of an HTML element:
function getOpacity(element) { var v = element.style.opacity; return ((v == null || isNaN(v)) ? 1 : element.style.opacity); } function setOpacity(element, opacity) { if (opacity < 0) opacity = 0; if (opacity > 1) opacity = 1; element.style.opacity = opacity; if (document.getElementById("ie").checked && (element.style.filter != undefined)) element.style.filter = 'alpha(opacity=' + (opacity * 100) + ')'; if (document.getElementById("moz").checked && (element.style.filter == undefined)) element.style.MozOpacity = opacity; }
You can see these samples working here.