diff --git a/demos/geo2/index.html b/demos/geo2/index.html new file mode 100644 index 00000000..fb452dfa --- /dev/null +++ b/demos/geo2/index.html @@ -0,0 +1,11 @@ + + + + OxJS Geo Demo + + + + + + \ No newline at end of file diff --git a/demos/geo2/js/geo.js b/demos/geo2/js/geo.js new file mode 100644 index 00000000..72ec4b4b --- /dev/null +++ b/demos/geo2/js/geo.js @@ -0,0 +1,51 @@ +Ox.documentReady(function() { + var image = new Image(); + image.onload = function() { + var c = Ox.canvas(image), + point = {lat: 40.725342, lng: -73.996824}, // Broadway & Houston, NY + circles = Ox.range(1, 16).map(function(i) { + return Ox.getCircle( + point, + i * Ox.EARTH_CIRCUMFERENCE / 2 / 16, + 8 + ); + }), + lines = Ox.range(16).map(function(i) { + return Ox.getLine( + point, + Ox.getPoint(point, Ox.EARTH_CIRCUMFERENCE / 2 - 1000, i * 360 / 16), + 8 + ); + }); + function drawLine(pointA, pointB) { + var xyA, xyB; + if (Math.abs(pointA.lng - pointB.lng) < 180) { + xyA = getXY(pointA); + xyB = getXY(pointB); + c.context.moveTo(xyA.x, xyA.y); + c.context.lineTo(xyB.x, xyB.y); + c.context.stroke(); + } + } + function drawPath(points, close) { + points.forEach(function(point, i) { + i && drawLine(points[i - 1], point); + }); + close && drawLine(points[points.length - 1], points[0]) + } + function getXY(point) { + return Ox.map(Ox.getXYByLatLng(point), function(v) { + return v * 1024; + }); + } + document.body.appendChild(c.canvas); + c.context.strokeStyle = 'rgb(255, 0, 0)'; + circles.forEach(function(points) { + drawPath(points, true); + }); + lines.forEach(function(points) { + drawPath(points); + }); + } + image.src = 'png/earth1024.png'; +}); \ No newline at end of file diff --git a/demos/geo2/png/earth1024.png b/demos/geo2/png/earth1024.png new file mode 100644 index 00000000..04ccb6dd Binary files /dev/null and b/demos/geo2/png/earth1024.png differ diff --git a/source/Ox.UI/js/Video/Ox.VideoPlayer.js b/source/Ox.UI/js/Video/Ox.VideoPlayer.js index bcbebec3..181ed1dc 100644 --- a/source/Ox.UI/js/Video/Ox.VideoPlayer.js +++ b/source/Ox.UI/js/Video/Ox.VideoPlayer.js @@ -1664,16 +1664,6 @@ Ox.VideoPlayer = function(options, self) { } } - function parsePositionInput(str) { - var split = str.split(':').reverse(); - while (split.length > 3) { - split.pop(); - } - return split.reduce(function(prev, curr, i) { - return prev + (parseFloat(curr) || 0) * Math.pow(60, i); - }, 0); - } - function playing() { var minute, previousMinute = parseInt(self.options.position / 60); @@ -2141,8 +2131,7 @@ Ox.VideoPlayer = function(options, self) { function submitPositionInput() { self.$positionInput.hide(); self.$position.html('').show(); - //Ox.Log('Video', '###', parsePositionInput(self.$positionInput.value())) - setPosition(parsePositionInput(self.$positionInput.value())); + setPosition(Ox.parseDuration(self.$positionInput.value())); if (self.playOnSubmit) { togglePaused(); self.$video.play(); diff --git a/source/Ox/js/DOM.js b/source/Ox/js/DOM.js index 893356ba..91380a7c 100644 --- a/source/Ox/js/DOM.js +++ b/source/Ox/js/DOM.js @@ -41,7 +41,6 @@ Ox.documentReady = (function() { callbacks.forEach(function(callback) { callback(); }); - //delete callbacks; } }; return function(callback) { diff --git a/source/Ox/js/Date.js b/source/Ox/js/Date.js index d3b679ef..a56fd337 100644 --- a/source/Ox/js/Date.js +++ b/source/Ox/js/Date.js @@ -6,8 +6,8 @@ /*@ Ox.getDateInWeek Get the date that falls on a given weekday in the same week # Usage - (date, weekday) -> Date - (date, weekday, utc) -> Date + (date, weekday) -> Date + (date, weekday, utc) -> Date # Arguments date Date weekday 1-7 (Monday-Sunday) or name, full ("Monday") or short ("Sun") @@ -23,10 +23,9 @@ Ox.getDateInWeek Get the date that falls on a given weekday in the same week // fixme: why is this Monday first? shouldn't it then be "getDateInISOWeek"?? Ox.getDateInWeek = function(date, weekday, utc) { date = Ox.makeDate(date); - //Ox.print(date, Ox.getDate(date, utc), Ox.formatDate(date, '%u', utc), date) var sourceWeekday = Ox.getISODay(date, utc), - targetWeekday = Ox.isNumber(weekday) ? weekday : - Ox.map(Ox.WEEKDAYS, function(v, i) { + targetWeekday = Ox.isNumber(weekday) ? weekday + : Ox.map(Ox.WEEKDAYS, function(v, i) { return v.substr(0, 3) == weekday.substr(0, 3) ? i + 1 : null; })[0]; return Ox.setDate(date, Ox.getDate(date, utc) - sourceWeekday + targetWeekday, utc); @@ -72,8 +71,8 @@ Ox.getDaysInMonth Get the number of days in a given month @*/ Ox.getDaysInMonth = function(year, month, utc) { year = Ox.makeYear(year); - month = Ox.isNumber(month) ? month : - Ox.map(Ox.MONTHS, function(v, i) { + month = Ox.isNumber(month) ? month + : Ox.map(Ox.MONTHS, function(v, i) { return v.substr(0, 3) == month.substr(0, 3) ? i + 1 : null; })[0]; return new Date(year, month, 0).getDate(); @@ -201,9 +200,9 @@ Ox.getTimezoneOffsetString Get the local time zone offset as a string @*/ Ox.getTimezoneOffsetString = function(date) { var offset = (Ox.makeDate(date)).getTimezoneOffset(); - return (offset < 0 ? '+' : '-') + - Ox.pad(Math.floor(Math.abs(offset) / 60), 2) + - Ox.pad(Math.abs(offset) % 60, 2); + return (offset < 0 ? '+' : '-') + + Ox.pad(Math.floor(Math.abs(offset) / 60), 2) + + Ox.pad(Math.abs(offset) % 60, 2); }; /*@ @@ -218,8 +217,8 @@ Ox.getWeek Get the week of a given day @*/ Ox.getWeek = function(date, utc) { date = Ox.makeDate(date); - return Math.floor((Ox.getDayOfTheYear(date, utc) + - Ox.getFirstDayOfTheYear(date, utc) - 1) / 7); + return Math.floor((Ox.getDayOfTheYear(date, utc) + + Ox.getFirstDayOfTheYear(date, utc) - 1) / 7); }; /*@ diff --git a/source/Ox/js/Format.js b/source/Ox/js/Format.js index fe605b6e..ea1e8fe8 100644 --- a/source/Ox/js/Format.js +++ b/source/Ox/js/Format.js @@ -274,7 +274,8 @@ Ox.formatDateRange = function(start, end, utc) { Ox.formatDate(dates[0], formats[precision[0] - 1], utc), Ox.formatDate(dates[1], formats[precision[1] - 1], utc) ]; - // if same year, and neither date is more precise than day, then omit first year + // if same year, and neither date is more precise than day, + // then omit first year if ( parts[0][0] == parts[1][0] && precision[0] <= 3 @@ -553,3 +554,24 @@ Ox.formatUnit = function(num, str, dec, factor) { factor = Ox.isUndefined(factor) ? 1 : factor; return Ox.formatNumber(num * factor, dec) + (str == '%' ? '' : ' ') + str; }; + +/*@ +Ox.parseDuration Takes a formatted duration, returns seconds + > Ox.parseDuration('01:02:03') + 3723 + > Ox.parseDuration('3') + 3 + > Ox.parseDuration('2:') + 120 + > Ox.parseDuration('1::') + 3600 +@*/ +Ox.parseDuration = function(str) { + var split = str.split(':').reverse(); + while (split.length > 3) { + split.pop(); + } + return split.reduce(function(prev, curr, i) { + return prev + (parseFloat(curr) || 0) * Math.pow(60, i); + }, 0); +} \ No newline at end of file diff --git a/source/Ox/js/Geo.js b/source/Ox/js/Geo.js index 5e931b62..1ae36f8d 100644 --- a/source/Ox/js/Geo.js +++ b/source/Ox/js/Geo.js @@ -5,24 +5,29 @@ // fixme: make all this work with different types of "points" // i.e. {lat, lng}, [lat, lng] + function deg(point) { + return Ox.map(point, function(val) { + return Ox.mod(Ox.deg(val) + 180, 360) - 180; + }); + } + function rad(point) { - return { - lat: Ox.rad(point.lat), - lng: Ox.rad(point.lng) - }; + return Ox.map(point, function(val) { + return Ox.rad(val); + }); } /*@ - Ox.crossesDateline Returns true if a given rectangle crosses the dateline + Ox.crossesDateline Returns true if a given line crosses the dateline @*/ - Ox.crossesDateline = function(point0, point1) { - return point0.lng > point1.lng; - } + Ox.crossesDateline = function(pointA, pointB) { + return pointA.lng > pointB.lng; + }; /*@ Ox.getArea Returns the area in square meters of a given rectancle @*/ - Ox.getArea = function(point0, point1) { + Ox.getArea = function(pointA, pointB) { /* area of a ring between two latitudes: 2 * PI * r^2 * abs(sin(lat0) - sin(lat1)) @@ -35,14 +40,14 @@ Math.abs(Ox.rad(0) - Ox.rad(1)) / (2 * Math.PI) */ - if (Ox.crossesDateline(point0, point1)) { - point1.lng += 360; + if (Ox.crossesDateline(pointA, pointB)) { + pointB.lng += 360; } - var point0 = rad(point0), - point1 = rad(point1); - return Math.pow(Ox.EARTH_RADIUS, 2) * - Math.abs(Math.sin(point0.lat) - Math.sin(point1.lat)) * - Math.abs(point0.lng - point1.lng); + pointA = rad(pointA); + pointB = rad(pointB); + return Math.pow(Ox.EARTH_RADIUS, 2) + * Math.abs(Math.sin(pointA.lat) - Math.sin(pointB.lat)) + * Math.abs(pointA.lng - pointB.lng); }; /*@ @@ -50,14 +55,14 @@ > Ox.getBearing({lat: -45, lng: 0}, {lat: 45, lng: 0}) 0 @*/ - Ox.getBearing = function(point0, point1) { - var point0 = rad(point0), - point1 = rad(point1), - x = Math.cos(point0.lat) * Math.sin(point1.lat) - - Math.sin(point0.lat) * Math.cos(point1.lat) * - Math.cos(point1.lng - point0.lng), - y = Math.sin(point1.lng - point0.lng) * - Math.cos(point1.lat); + Ox.getBearing = function(pointA, pointB) { + var pointA = rad(pointA), + pointB = rad(pointB), + x = Math.cos(pointA.lat) * Math.sin(pointB.lat) + - Math.sin(pointA.lat) * Math.cos(pointB.lat) + * Math.cos(pointB.lng - pointA.lng), + y = Math.sin(pointB.lng - pointA.lng) + * Math.cos(pointB.lat); return (Ox.deg(Math.atan2(y, x)) + 360) % 360; }; @@ -66,23 +71,34 @@ > Ox.getCenter({lat: -45, lng: -90}, {lat: 45, lng: 90}) {lat: 0, lng: 0} @*/ - Ox.getCenter = function(point0, point1) { - var point0 = rad(point0), - point1 = rad(point1), - x = Math.cos(point1.lat) * - Math.cos(point1.lng - point0.lng), - y = Math.cos(point1.lat) * - Math.sin(point1.lng - point0.lng), + Ox.getCenter = function(pointA, pointB) { + var pointA = rad(pointA), + pointB = rad(pointB), + x = Math.cos(pointB.lat) + * Math.cos(pointB.lng - pointA.lng), + y = Math.cos(pointB.lat) + * Math.sin(pointB.lng - pointA.lng), d = Math.sqrt( - Math.pow(Math.cos(point0.lat) + x, 2) + Math.pow(y, 2) + Math.pow(Math.cos(pointA.lat) + x, 2) + Math.pow(y, 2) ), - lat = Ox.deg( - Math.atan2(Math.sin(point0.lat) + Math.sin(point1.lat), d) - ), - lng = Ox.deg( - point0.lng + Math.atan2(y, Math.cos(point0.lat) + x) - ); - return {lat: lat, lng: lng}; + lat = Math.atan2(Math.sin(pointA.lat) + Math.sin(pointB.lat), d), + lng = pointA.lng + Math.atan2(y, Math.cos(pointA.lat) + x); + return deg({lat: lat, lng: lng}); + }; + + /*@ + Ox.getCircle Returns points on a circle around a given point + (center, radius, precision) -> Points + center Center point ({lat, lng}) + radius Radius in meters + precision Precision (the circle will have 2^precision segments) + @*/ + Ox.getCircle = function(center, radius, precision) { + return Ox.range( + 0, 360, 360 / Math.pow(2, precision) + ).map(function(bearing) { + return Ox.getPoint(center, radius, bearing); + }); }; /*@ @@ -99,13 +115,13 @@ > Ox.getDistance({lat: -45, lng: -90}, {lat: 45, lng: 90}) * 2 Ox.EARTH_CIRCUMFERENCE @*/ - Ox.getDistance = function(point0, point1) { - var point0 = rad(point0), - point1 = rad(point1); + Ox.getDistance = function(pointA, pointB) { + var pointA = rad(pointA), + pointB = rad(pointB); return Math.acos( - Math.sin(point0.lat) * Math.sin(point1.lat) + - Math.cos(point0.lat) * Math.cos(point1.lat) * - Math.cos(point1.lng - point0.lng) + Math.sin(pointA.lat) * Math.sin(pointB.lat) + + Math.cos(pointA.lat) * Math.cos(pointB.lat) + * Math.cos(pointB.lng - pointA.lng) ) * Ox.EARTH_RADIUS; }; @@ -121,7 +137,30 @@ return { lat: -Ox.deg(Math.atan(Ox.sinh(getVal(xy.y)))), lng: Ox.deg(getVal(xy.x)) + }; + }; + + /*@ + Ox.getLine Returns points on a line between two points + (pointA, pointB, precision) -> Points + pointA Start point ({lat, lng}) + pointB End point ({lat, lng}) + precision Precision (the line will have 2^precision segments) + @*/ + Ox.getLine = function(pointA, pointB, precision) { + var line = [pointA, pointB], points; + while (precision > 0) { + points = [line[0]]; + Ox.loop(line.length - 1, function(i) { + points.push( + Ox.getCenter(line[i], line[i + 1]), + line[i + 1] + ); + }); + line = points; + precision--; } + return line; }; /*@ @@ -133,6 +172,27 @@ return Math.cos(lat * Math.PI / 180) * Ox.EARTH_CIRCUMFERENCE / 360; }; + /*@ + Ox.getPoint Returns a point at a given distance/bearing from a given point + > Ox.getPoint({lat: -45, lng: 0}, Ox.EARTH_CIRCUMFERENCE / 4, 0) + {lat: 45, lng: 0} + @*/ + Ox.getPoint = function(point, distance, bearing) { + var pointB = {}; + point = rad(point); + distance /= Ox.EARTH_RADIUS; + bearing = Ox.rad(bearing); + pointB.lat = Math.asin( + Math.sin(point.lat) * Math.cos(distance) + + Math.cos(point.lat) * Math.sin(distance) * Math.cos(bearing) + ); + pointB.lng = point.lng + Math.atan2( + Math.sin(bearing) * Math.sin(distance) * Math.cos(point.lat), + Math.cos(distance) - Math.sin(point.lat) * Math.sin(pointB.lat) + ); + return deg(pointB); + }; + /*@ Ox.getXYByLatLng Returns x/y on a 1x1 mercator projection for a given lat/lng > Ox.getXYByLatLng({lat: 0, lng: 0}) @@ -148,13 +208,20 @@ }; }; + /*@ + Ox.isPolar Returns true if a given point is outside the bounds of a mercator projection + @*/ + Ox.isPolar = function(point) { + return point.lat < Ox.MIN_LATITUDE || point.lat > Ox.MAX_LATITUDE; + }; + }()); //@ Ox.Line (undocumented) -Ox.Line = function(point0, point1) { +Ox.Line = function(pointA, pointB) { var self = { - points: [point0, point1] + points: [pointA, pointB] }, that = this; @@ -244,17 +311,17 @@ Ox.Point = function(lat, lng) { }; //@ Ox.Rectangle (undocumented) -Ox.Rectangle = function(point0, point1) { +Ox.Rectangle = function(pointA, pointB) { var self = { points: [ new Point( - Math.min(point0.lat(), point1.lat()), - point0.lng() + Math.min(pointA.lat(), pointB.lat()), + pointA.lng() ), new Point( - Math.max(point0.lat(), point1.lat()), - point1.lng() + Math.max(pointA.lat(), pointB.lat()), + pointB.lng() ) ] }, @@ -262,7 +329,7 @@ Ox.Rectangle = function(point0, point1) { that.contains = function(rectangle) { - } + }; that.crossesDateline = function() { return self.points[0].lng > self.points[1].lng; diff --git a/source/Ox/js/HTML.js b/source/Ox/js/HTML.js index 6ef08898..b5f4a755 100644 --- a/source/Ox/js/HTML.js +++ b/source/Ox/js/HTML.js @@ -40,8 +40,8 @@ Ox.parseHTML Takes HTML from an untrusted source and returns something sane Ox.parseHTML = (function() { var defaultTags = [ // inline formatting - 'b', 'code', 'i', 'q', 's', 'sub', 'sup', 'u', - // block + 'b', 'code', 'i', 's', 'sub', 'sup', 'u', + // block formatting 'blockquote', 'h1', 'p', 'pre', // lists 'li', 'ol', 'ul',