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',