diff --git a/examples/flight_paths/css/example.css b/examples/flight_paths/css/example.css new file mode 100644 index 00000000..21da6af0 --- /dev/null +++ b/examples/flight_paths/css/example.css @@ -0,0 +1,16 @@ +body { + margin: 0; +} +.label { + position: absolute; + width: 126px; + height: 14px; + border: 1px solid rgba(255, 255, 255, 0.75); + border-radius: 4px; + background: rgba(0, 0, 0, 0.5); + font-family: Lucida Grande; sans-serif; + font-size: 11px; + text-align: center; + color: rgb(255, 255, 255); + box-shadow: 0 0 1px rgb(0, 0, 0); +} diff --git a/examples/flight_paths/index.html b/examples/flight_paths/index.html new file mode 100644 index 00000000..6ce04245 --- /dev/null +++ b/examples/flight_paths/index.html @@ -0,0 +1,13 @@ + + + + Flight Paths + + + + + + + + + \ No newline at end of file diff --git a/examples/flight_paths/jpg/earth720.jpg b/examples/flight_paths/jpg/earth720.jpg new file mode 100644 index 00000000..25ebf3ee Binary files /dev/null and b/examples/flight_paths/jpg/earth720.jpg differ diff --git a/examples/flight_paths/js/example.js b/examples/flight_paths/js/example.js new file mode 100644 index 00000000..f41f7dcd --- /dev/null +++ b/examples/flight_paths/js/example.js @@ -0,0 +1,169 @@ +/* +In this example, we will draw flight paths on a world map. We'll use the Image +module and some of the built-in Ox.js functions for dealing with geographic +coordinates. +*/ +'use strict'; + +/* +Include the image module. +*/ +Ox.load('Image', function() { + + /* + This creates an image object from the specified source. + */ + Ox.Image('jpg/earth720.jpg', function(image) { + + /* + We want to map the route New York - London - Tokyo - Johannesburg - + Sydney - Sao Paulo - New York. + */ + var airports = [ + {name: 'JFK', lat: 40.643841, lng: -73.782304}, + {name: 'LHR', lat: 51.480902, lng: -0.464773}, + {name: 'NRT', lat: 35.553457, lng: 139.76532}, + {name: 'JNB', lat: -26.140009, lng: 28.242781}, + {name: 'SYD', lat: -33.93567, lng: 151.164322}, + {name: 'GRU', lat: -23.62754, lng: -46.700821}, + ], + /* + To get the width (and height) of the image, we call its + getSize method. + */ + mapSize = image.getSize().width, + /* + Ox.getLine returns a line from one lat/lng pair to another, as an + array of Math.pow(2, precision) + 1 points. + */ + precision = 8, + paths = airports.map(function(airport, i) { + return Ox.getLine( + airport, + /* + We make sure the last airport gets connected with the first + one. + */ + airports[(i + 1) % airports.length], + precision + ); + }); + + /* + Ox.getXYByLatLng takes a lat/lng pair and returns its x/y position on a + 1x1 Mercator position, {x: 0, y: 0} being the bottom left, + {x: 1, y: 1} being the top right. + */ + function getXY(point) { + var xy = Ox.getXYByLatLng(point); + return [xy.x * mapSize, xy.y * mapSize]; + } + + /* + For each path, we have to check if it crosses the edge of the map that + runs through the Pacific. Note that our test (a line crosses the edge + if it spans more than 180 degrees longitude) is obviously incorrect, + but works in our case, since all lines are sufficiently short. + */ + paths.forEach(function(path) { + var parts = [path]; + Ox.loop(path.length - 1, function(i) { + var lat, lng; + if (Math.abs(path[i].lng - path[i + 1].lng) > 180) { + /* + We split the path in two parts. + */ + parts = [Ox.sub(path, 0, i + 1), Ox.sub(path, i + 1)]; + /* + We get the lat/lng of the points where the line leaves + and enters the map... + */ + lat = Ox.getCenter(path[i], path[i + 1]).lat; + lng = path[i].lng < 0 ? [-180, 180] : [180, -180]; + /* + ... and append them to the end of the first part and the + beginning of the second part. + */ + parts[0].push({lat: lat, lng: lng[0]}); + parts[1].unshift({lat: lat, lng: lng[1]}); + /* + Returning false from Ox.loop is the equivalent of + break in a for loop. Again, note + that this assumes no path will cross the edge more than + once. + */ + return false; + } + }); + /* + We draw each part. + */ + parts.forEach(function(part) { + image.drawPath(part.map(getXY), {color: 'white'}); + }); + }); + + /* + Now lets add some markers. + */ + airports.forEach(function(airport, i) { + /* + j is the index of the next airport. + */ + var j = (i + 1) % airports.length, + /* + These are the options for the draw functions of the image. Some + of the properties only apply to drawPath, some + only to drawText, but we can pass all of them to + both. + */ + options = { + close: true, + color: 'rgba(255, 255, 255, 0.75)', + fill: 'rgba(0, 0, 0, 0.5)', + font: 'bold 11px Lucida Grande, sans-serif', + textAlign: 'center' + }, + /* + Ox.getDistance returns the distance, in meters, between two + lat/lng pairs, and Ox.formatNumber adds thousands separators. + */ + text = airports[i].name + '-' + airports[j].name + ' ' + + Ox.formatNumber(Math.round( + Ox.getDistance(airports[i], airports[j]) / 1000 + )) + ' km', + /* + Ox.getCenter returns the midpoint between two lat/lng pairs. + In our case, this is where we want to attach markers. + */ + xy = getXY(Ox.getCenter(airports[i], airports[j])), + x = Math.round(xy[0]), + y = Math.round(xy[1]); + /* + This is the marker... + */ + image.drawPath([ + [x, y], + [x + 4, y - 16], + [x + 64, y - 16], + [x + 64, y - 32], + [x - 64, y - 32], + [x - 64, y - 16], + [x - 4, y - 16] + ], options); + /* + ... and this is the text. + */ + image.drawText(text, [x, y - 20], options); + }); + + /* + To get the dataURL for our image, we call its src() + method, and to put it in the DOM, we use Ox.$, which is similar to + jQuery's $. + */ + Ox.$('').attr({src: image.src()}).appendTo(Ox.$('body')); + + }); + +}); \ No newline at end of file