/* 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 1×1 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]}); /* Ox.Break() breaks the loop. Again, note that this assumes no path will cross the edge more than once. */ Ox.Break(); } }); /* 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')); }); });