依赖文件

This commit is contained in:
浅念
2025-03-20 17:35:53 +08:00
parent 634fe57349
commit 021ffc6052
1134 changed files with 137518 additions and 132 deletions
+613
View File
@@ -0,0 +1,613 @@
var utils = require('cordova/utils'),
BaseClass = require('./BaseClass');
var ARRAY_FIELD = typeof Symbol === 'undefined' ? '__array' + Date.now() : Symbol('array');
var nextTick = function(fn) { Promise.resolve().then(fn); };
/**
* Create a BaseArrayClass.
* @class
*/
function BaseArrayClass(array) {
BaseClass.apply(this);
var self = this;
self[ARRAY_FIELD] = [];
if (array && (array instanceof Array || Array.isArray(array))) {
for (var i = 0; i < array.length; i++) {
self[ARRAY_FIELD].push(array[i]);
}
}
}
utils.extend(BaseArrayClass, BaseClass);
/**
* The same as `Array.map` but runs a single async operation at a time.
*
* @name mapSeries
* @param {Function} iteratee - An async function to apply to each item in array.
* @param {Function} [callback] - A callback which is called when all `iteratee` functions
* have finished. Results is an array of the transformed items from holding array.
* Invoked with (results);
* @return {Promise} a promise, if no calback if passed.
*/
BaseArrayClass.prototype.mapSeries = function(iteratee, callback) {
if (typeof iteratee !== 'function') {
var error = new Error('iteratee must be a function');
if (typeof callback === 'function') {
throw error;
} else {
return Promise.reject(error);
}
}
var self = this;
var results = [];
var _arrayLength = self[ARRAY_FIELD].length;
var currentCnt = 0;
if (_arrayLength === 0) {
if (typeof callback === 'function') {
callback.call(self, []);
return;
} else {
return Promise.resolve([]);
}
}
var _looper = function(currentIdx, resolve) {
iteratee.call(self, self[ARRAY_FIELD][currentIdx], function(value) {
results[currentIdx] = value;
currentCnt++;
if (_arrayLength === currentCnt) {
resolve(results);
} else {
nextTick(function() {
_looper(currentIdx + 1, resolve);
});
}
});
};
return new Promise(function(resolve) {
nextTick(function() {
_looper(0, resolve);
});
}).then(function(results) {
if (typeof callback === 'function') {
return callback.call(self, results);
} else {
return Promise.resolve(results);
}
});
};
/**
* The same as `Array.map` but runs async all `iteratee` function at the same time.
*
* ```
* baseArray.mapAsync(function(item, idx, callback) {
* ...
* callback(value);
* }).then(function(values) {
*
* });
* ```
*
* @name mapAsync
* @param {Function} iteratee - An async function to apply to each item in array.
* @param {Function} [callback] - A callback which is called when all `iteratee` functions
* have finished. Results is an array of the transformed items from holding array.
* Invoked with (results);
* @return {Promise} a promise, if no calback if passed.
*/
BaseArrayClass.prototype.mapAsync = function(iteratee, callback) {
if (typeof iteratee !== 'function') {
var error = new Error('iteratee must be a function');
if (typeof callback === 'function') {
throw error;
} else {
return Promise.reject(error);
}
}
var self = this;
var results = [];
for (var i = 0; i < self[ARRAY_FIELD].length; i++) {
results.push(null);
}
var _arrayLength = self[ARRAY_FIELD].length;
var finishCnt = 0;
if (_arrayLength === 0) {
if (typeof callback === 'function') {
callback.call(self, []);
return;
} else {
return Promise.resolve([]);
}
}
return new Promise(function(resolve) {
for (i = 0; i < self[ARRAY_FIELD].length; i++) {
(function(item, idx) {
nextTick(function() {
iteratee.call(self, item, function(value) {
results[idx] = value;
finishCnt++;
if (finishCnt === _arrayLength) {
resolve(results);
}
});
});
})(self[ARRAY_FIELD][i], i);
}
}).then(function(results) {
if (typeof callback === 'function') {
return callback.call(self, results);
} else {
return Promise.resolve(results);
}
});
};
/**
* If you provide `iteratee` and `callback`, work as `mapAsync()`.
* If you provide `iteratee`, but omit `callback`, work as `Array.map()`.
*
* @deprecated
* @name map
* @param {Function} iteratee - An async function to apply to each item in array.
* @param {Function} [callback] - A callback which is called when all `iteratee` functions
* have finished. Results is an array of the transformed items from holding array.
* Invoked with (results);
* @return {Promise|any[]} a promise, if no calback if passed. If you omit `callback`, return transformed items.
*/
BaseArrayClass.prototype.map = function(iteratee, callback) {
var self = this;
if (typeof iteratee !== 'function') {
var error = new Error('iteratee must be a function');
if (typeof callback === 'function') {
throw error;
} else {
return Promise.reject(error);
}
}
if (typeof callback !== 'function') {
//------------------------
// example:
// var values = baseArray.map(function(item, idx) {
// ...
// return someValue;
// });
//------------------------
return self[ARRAY_FIELD].map(iteratee.bind(self));
}
return self.mapAsync(iteratee, callback);
};
/**
* The same as `Array.forEach` but runs async all `iteratee` function at the same time.
*
* @name forEachAsync
* @param {Function} iteratee - An async function to apply to each item in array.
* @param {Function} [callback] - A callback which is called when all `iteratee` functions
* have finished.
* @return {Promise} a promise, if no calback if passed.
*/
BaseArrayClass.prototype.forEachAsync = function(iteratee, callback) {
if (typeof iteratee !== 'function') {
var error = new Error('iteratee must be a function');
if (typeof callback === 'function') {
throw error;
} else {
return Promise.reject(error);
}
}
var self = this;
//------------------------
// example:
// baseArray.forEach(function(item, callback) {
// ...
// callback();
// }, function() {
//
// });
//------------------------
var finishCnt = 0;
var _arrayLength = self[ARRAY_FIELD].length;
if (_arrayLength === 0) {
if (typeof callback === 'function') {
callback.call(self);
return;
} else {
return Promise.resolve();
}
}
return new Promise(function(resolve) {
self[ARRAY_FIELD].forEach(function(item) {
iteratee.call(self, item, function() {
finishCnt++;
if (finishCnt === _arrayLength) {
resolve(self);
}
});
});
})
.then(function() {
if (typeof callback === 'function') {
callback.call(self);
return;
} else {
return Promise.resolve();
}
});
};
/**
* If you provide `iteratee` and `callback`, work as `forEachAsync()`.
* If you provide `iteratee`, but you omit `callback`, work as `Array.forEach()`
*
* @deprecated
* @name forEach
* @param {Function} iteratee - An async function to apply to each item in array.
* @param {Function} [callback] - A callback which is called when all `iteratee` functions
* have finished.
* Invoked with (results);
* @return {Promise} a promise, if no calback if passed.
*/
BaseArrayClass.prototype.forEach = function(iteratee, callback) {
var self = this;
if (typeof iteratee !== 'function') {
var error = new Error('iteratee must be a function');
if (typeof callback === 'function') {
throw error;
} else {
return Promise.reject(error);
}
}
if (typeof callback !== 'function') {
//------------------------
// example:
// baseArray.forEach(function(item, idx) {
// ...
// });
//------------------------
self[ARRAY_FIELD].forEach(iteratee.bind(self));
return Promise.resolve();
}
return self.forEachAsync(iteratee, callback);
};
/**
* The same as `Array.filter` but runs async all `iteratee` function at the same time.
*
* @name filterAsync
* @param {Function} iteratee - An async function to apply to each item in array.
* @param {Function} [callback] - A callback which is called when all `iteratee` functions
* have finished. Results is an array of the filtered items from holding array.
* Invoked with (results);
* @return {Promise} a promise, if no calback if passed.
*/
BaseArrayClass.prototype.filterAsync = function(iteratee, callback) {
var self = this;
if (typeof iteratee !== 'function') {
var error = new Error('iteratee must be a function');
if (typeof callback === 'function') {
throw error;
} else {
return Promise.reject(error);
}
}
//------------------------
// example:
// baseArray.filter(function(item, callback) {
// ...
// callback(true or false);
// }, function(filteredItems) {
//
// });
//------------------------
var finishCnt = 0;
var _arrayLength = self[ARRAY_FIELD].length;
if (_arrayLength === 0) {
if (typeof callback === 'function') {
callback.call(self, []);
return;
} else {
return Promise.resolve([]);
}
}
return (new Promise(function(resolve) {
var results = [];
self[ARRAY_FIELD].forEach(function(item, idx) {
iteratee.call(self, item, function(isOk) {
results[idx] = isOk;
finishCnt++;
if (finishCnt === _arrayLength) {
resolve(self[ARRAY_FIELD].filter(function(item, j) {
return results[j];
}));
}
});
});
}))
.then(function(results) {
if (typeof callback === 'function') {
callback.call(self, results);
return;
} else {
return Promise.resolve(results);
}
});
};
/**
* If you provide `iteratee` and `callback`, work as `filterAsync()`.
* If you provide `iteratee`, but you omit `callback`, work as `Array.filter()`
*
* @deprecated
* @name filter
* @param {Function} iteratee - An async function to apply to each item in array.
* @param {Function} [callback] - A callback which is called when all `iteratee` functions
* have finished.
* @return {Promise} a promise, if no calback if passed.
*/
BaseArrayClass.prototype.filter = function(iteratee, callback) {
var self = this;
if (typeof iteratee !== 'function') {
var error = new Error('iteratee must be a function');
if (typeof callback === 'function') {
throw error;
} else {
return Promise.reject(error);
}
}
if (typeof callback !== 'function') {
//------------------------
// example:
// baseArray.filter(function(item, idx) {
// ...
// return true or false
// });
//------------------------
return self[ARRAY_FIELD].filter(iteratee);
}
return self.filterAsync(iteratee, callback);
};
/**
* Returns the first index at which a given element can be found in the array, or -1 if it is not present.
*
* @name indexOf
* @param {any} searchElement - Element to locate in the array.
* @param {number} [searchElement] - The index to start the search at.
* If the index is greater than or equal to the array's length, -1 is returned,
* which means the array will not be searched.
* If the provided index value is a negative number,
* it is taken as the offset from the end of the array.
* Note: if the provided index is negative, the array is still searched from front to back.
* If the provided index is 0, then the whole array will be searched. Default: 0 (entire array is searched).
* @return The first index of the element in the array; -1 if not found.
*/
BaseArrayClass.prototype.indexOf = function(item, searchElement) {
searchElement = searchElement === undefined || searchElement === null ? 0 : searchElement;
if (typeof searchElement !== 'number') {
throw new Error('searchElement must be a number');
}
if (searchElement < 0) {
throw new Error('searchElement must be over number than 0');
}
return this[ARRAY_FIELD].indexOf(item, searchElement);
};
/**
* Removes all elements. Fire `remove_at` event for each element.
*
* @name empty
* @param {boolean} [noNotify] - Sets `true` if you don't want to fire `remove_at` event.
*/
BaseArrayClass.prototype.empty = function(noNotify) {
var self = this;
var cnt = self[ARRAY_FIELD].length;
for (var i = cnt - 1; i >= 0; i--) {
self.removeAt(i, noNotify);
}
};
/**
* Adds one element to the end of an array and returns the new length of the array.
* Fire `insert_at` event if `noNotify` is `false`.
*
* @name push
* @param {any} value - The element to add to the end of the array.
* @param {boolean} [noNotify] - Sets `true` if you don't want to fire `insert_at` event.
* @return {number} The new length property of the object upon which the method was called.
*/
BaseArrayClass.prototype.push = function(value, noNotify) {
var self = this;
self[ARRAY_FIELD].push(value);
if (noNotify !== true) {
self.trigger('insert_at', self[ARRAY_FIELD].length - 1);
}
return self[ARRAY_FIELD].length;
};
/**
* Adds one element to the end of an array and returns the new length of the array.
* Fire `insert_at` event if `noNotify` is `false`.
*
* @name insertAt
* @param {number} index - The position of the array you want to insert new element.
* @param {any} value - The element to add to the end of the array.
* @param {boolean} [noNotify] - Sets `true` if you don't want to fire `insert_at` event.
* @return {number} The new length property of the object upon which the method was called.
*/
BaseArrayClass.prototype.insertAt = function(index, value, noNotify) {
var self = this;
if (typeof index !== 'number') {
throw new Error('index must be a number');
}
if (index < 0) {
throw new Error('index must be over number than 0');
}
self[ARRAY_FIELD].splice(index, 0, value);
if (noNotify !== true) {
self.trigger('insert_at', index);
}
return self[ARRAY_FIELD].length;
};
/**
* Returns a new array that is the clone of internal array.
*
* @name getArray
* @return {Array<any>} New array
*/
BaseArrayClass.prototype.getArray = function() {
//return _array.slice(0); <-- Android browser keeps the same instance of original array
return JSON.parse(JSON.stringify(this[ARRAY_FIELD]));
};
/**
* Returns item of specified position.
*
* @name getAt
* @param {number} index - The position of the array you want to get.
* @return {any} item
*/
BaseArrayClass.prototype.getAt = function(index) {
var self = this;
if (typeof index !== 'number') {
throw new Error('index must be a number');
}
if (index < 0) {
throw new Error('index must be over number than 0');
}
if (index >= self[ARRAY_FIELD].length) {
throw new Error('index must be lower number than ' + self[ARRAY_FIELD].length);
}
return this[ARRAY_FIELD][index];
};
/**
* Replaces item of specified position.
*
* @name setAt
* @param {number} index - The position of the array you want to get.
* @param {any} value - New element
* @param {boolean} [noNotify] - Sets `true` if you don't want to fire `set_at` event.
* @return {any} previous item
*/
BaseArrayClass.prototype.setAt = function(index, value, noNotify) {
var self = this;
if (typeof index !== 'number') {
throw new Error('index must be a number');
}
if (index < 0) {
throw new Error('index must be over number than 0');
}
if (index > self[ARRAY_FIELD].length) {
for (var i = self[ARRAY_FIELD].length; i <= index; i++) {
self[ARRAY_FIELD][i] = undefined;
}
}
var prev = self[ARRAY_FIELD][index];
self[ARRAY_FIELD][index] = value;
if (noNotify !== true) {
self.trigger('set_at', index, prev);
}
return prev;
};
/**
* Removes item of specified position.
*
* @name removeAt
* @param {number} index - The position of the array you want to get.
* @param {boolean} [noNotify] - Sets `true` if you don't want to fire `remove_at` event.
* @return {any} removed item
*/
BaseArrayClass.prototype.removeAt = function(index, noNotify) {
var self = this;
if (typeof index !== 'number') {
throw new Error('index must be a number');
}
if (index < 0) {
throw new Error('index must be over number than 0');
}
if (index >= self[ARRAY_FIELD].length) {
throw new Error('index must be lower number than ' + self[ARRAY_FIELD].length);
}
var value = self[ARRAY_FIELD][index];
self[ARRAY_FIELD].splice(index, 1);
if (noNotify !== true) {
self.trigger('remove_at', index, value);
}
return value;
};
/**
* Removes item of the last array item.
*
* @name pop
* @param {boolean} [noNotify] - Sets `true` if you don't want to fire `remove_at` event.
* @return {any} removed item
*/
BaseArrayClass.prototype.pop = function(noNotify) {
var self = this;
var index = self[ARRAY_FIELD].length - 1;
var value = self[ARRAY_FIELD].pop();
if (noNotify !== true) {
self.trigger('remove_at', index, value);
}
return value;
};
/**
* Returns the length of array.
*
* @name getLength
* @return {any} Number of items
*/
BaseArrayClass.prototype.getLength = function() {
return parseInt(this[ARRAY_FIELD].length, 10); // In order to prevent manupulating through `length` property, conver to number mandatory using `parseInt`.
};
/**
* Reverses an array in place. The first array element becomes the last, and the last array element becomes the first.
*
* @name reverse
*/
BaseArrayClass.prototype.reverse = function() {
this[ARRAY_FIELD].reverse();
};
/**
* The `sort()` method sorts the elements of an array in place and returns the array.
* The same as `array.sort()`.
*
* @name sort
* @param {Function} [compareFunction] - Specifies a function that defines the sort order.
* If omitted, the array is sorted according to each character's Unicode code point value,
* according to the string conversion of each element.
*/
BaseArrayClass.prototype.sort = function(compareFunction) {
if (typeof compareFunction === 'function') {
this[ARRAY_FIELD].sort(compareFunction);
} else {
this[ARRAY_FIELD].sort();
}
};
module.exports = BaseArrayClass;
+225
View File
@@ -0,0 +1,225 @@
var VARS_FIELD = typeof Symbol === 'undefined' ? '__vars' + Date.now() : Symbol('vars');
var SUBSCRIPTIONS_FIELD = typeof Symbol === 'undefined' ? '__subs' + Date.now() : Symbol('subscriptions');
function BaseClass() {
this[VARS_FIELD] = {};
this[SUBSCRIPTIONS_FIELD] = {};
this.errorHandler = this.errorHandler.bind(this);
Object.defineProperty(this, 'hashCode', {
value: Math.floor(Date.now() * Math.random())
});
}
BaseClass.prototype = {
empty: function () {
var vars = this[VARS_FIELD];
Object.keys(vars).forEach(function (name) {
vars[name] = null;
delete vars[name];
});
},
get: function (key) {
return this[VARS_FIELD].hasOwnProperty(key) ? this[VARS_FIELD][key] : undefined;
},
set: function (key, value, noNotify) {
if (key === '__pgmId') return;
var prev = this.get(key);
this[VARS_FIELD][key] = value;
if (!noNotify && prev !== value) {
this.trigger(key + '_changed', prev, value, key);
}
return this;
},
bindTo: function (key, target, targetKey, noNotify) {
if (key === '__pgmId') return;
targetKey = targetKey || key;
// If `noNotify` is true, prevent `(targetKey)_changed` event occurrs,
// when bind the value for the first time only.
// (Same behaviour as Google Maps JavaScript v3)
target.set(targetKey, this[VARS_FIELD][key], noNotify);
this.on(key + '_changed', function (oldValue, value) {
target.set(targetKey, value);
});
},
trigger: function (eventName) {
if (!eventName) {
return this;
}
if (!this[SUBSCRIPTIONS_FIELD][eventName]) {
return this;
}
var listenerHashMap = this[SUBSCRIPTIONS_FIELD][eventName];
var keys = Object.keys(listenerHashMap);
var args = Array.prototype.slice.call(arguments, 1);
var self = this;
keys.forEach(function (_hashCode) {
if (self[SUBSCRIPTIONS_FIELD] &&
self[SUBSCRIPTIONS_FIELD][eventName] &&
_hashCode in self[SUBSCRIPTIONS_FIELD][eventName]) {
var info = self[SUBSCRIPTIONS_FIELD][eventName][_hashCode];
switch (info.kind) {
case 'on':
info.listener.apply(self, args);
break;
case 'onThrottled':
info.args = args;
if (!info.timer) {
info.timer = setTimeout(function () {
info.listener.apply(this, info.args);
info.timer = null;
}.bind(self), info.interval);
}
break;
}
}
});
return this;
},
on: function (eventName, listener) {
if (!listener || typeof listener !== 'function') {
throw Error('Listener for on()/addEventListener() method is not a function');
}
if (!listener._hashCode) {
Object.defineProperty(listener, '_hashCode', {
value: Math.floor(Date.now() * Math.random()),
writable: false,
enumerable: false
});
}
this[SUBSCRIPTIONS_FIELD][eventName] = this[SUBSCRIPTIONS_FIELD][eventName] || {};
this[SUBSCRIPTIONS_FIELD][eventName][listener._hashCode] = {
'kind': 'on',
'listener': listener
};
return this;
},
onThrottled: function (eventName, listener, interval) {
if (!listener || typeof listener !== 'function') {
throw Error('Listener for on()/addEventListener() method is not a function');
}
if (typeof interval !== 'number' || interval < 1) {
throw Error('interval argument must be bigger number than 0');
}
if (!listener._hashCode) {
Object.defineProperty(listener, '_hashCode', {
value: Math.floor(Date.now() * Math.random()),
writable: false,
enumerable: false
});
}
this[SUBSCRIPTIONS_FIELD][eventName] = this[SUBSCRIPTIONS_FIELD][eventName] || {};
this[SUBSCRIPTIONS_FIELD][eventName][listener._hashCode] = {
'kind': 'onThrottled',
'interval': interval,
'timer': null,
'listener': listener
};
return this;
},
off: function (eventName, listener) {
if (!eventName && !listener) {
this[SUBSCRIPTIONS_FIELD] = {};
return this;
}
if (eventName && !listener) {
this[SUBSCRIPTIONS_FIELD][eventName] = null;
delete this[SUBSCRIPTIONS_FIELD][eventName];
} else if (this[SUBSCRIPTIONS_FIELD][eventName] && listener._hashCode) {
delete this[SUBSCRIPTIONS_FIELD][eventName][listener._hashCode];
}
return this;
},
one: function (eventName, listener) {
if (!listener || typeof listener !== 'function') {
throw Error('Listener for one()/addEventListenerOnce() method is not a function');
}
var self = this;
var callback = function () {
self.off(eventName, arguments.callee);
listener.apply(self, arguments);
callback = undefined;
};
this.on(eventName, callback);
return this;
},
hasEventListener: function (eventName) {
return (eventName in this[SUBSCRIPTIONS_FIELD] && Object.keys(this[SUBSCRIPTIONS_FIELD][eventName]).length > 0);
},
destroy: function () {
this.off();
this.empty();
},
errorHandler: function (error) {
if (error) {
if (typeof console.error === 'function') {
if (this.__pgmId) {
console.error(this.__pgmId, error);
} else {
console.error(error);
}
} else {
if (this.__pgmId) {
console.log(this.__pgmId, error);
} else {
console.log(error);
}
}
this.trigger('error', error instanceof Error ? error : createError(error));
}
return false;
}
};
BaseClass.prototype.addEventListener = BaseClass.prototype.on;
BaseClass.prototype.addThrottledEventListener = BaseClass.prototype.onThrottled;
BaseClass.prototype.addEventListenerOnce = BaseClass.prototype.one;
BaseClass.prototype.removeEventListener = BaseClass.prototype.off;
function createError(message, methodName, args) {
var error = new Error(methodName ? [
'Got error with message: "', message, '" ',
'after calling "', methodName, '"'
].join('') : message);
Object.defineProperties(error, {
methodName: {
value: methodName
},
args: {
value: args
}
});
return error;
}
module.exports = BaseClass;
+20
View File
@@ -0,0 +1,20 @@
/********************************************************************************
* @name CameraPosition
* @class This class represents new camera position
* @property {LatLng} target The location where you want to show
* @property {Number} [tilt] View angle
* @property {Number} [zoom] Zoom level
* @property {Number} [bearing] Map orientation
* @property {Number} [duration] The duration of animation
*******************************************************************************/
var CameraPosition = function(params) {
var self = this;
self.zoom = params.zoom;
self.tilt = params.tilt;
self.target = params.target;
self.bearing = params.bearing;
self.hashCode = params.hashCode;
self.duration = params.duration;
};
module.exports = CameraPosition;
+174
View File
@@ -0,0 +1,174 @@
var utils = require('cordova/utils'),
common = require('./Common'),
LatLngBounds = require('./LatLngBounds'),
Overlay = require('./Overlay');
/*****************************************************************************
* Circle Class
*****************************************************************************/
var Circle = function (map, circleOptions, _exec) {
Overlay.call(this, map, circleOptions, 'Circle', _exec);
var self = this;
//-----------------------------------------------
// Sets event listeners
//-----------------------------------------------
self.on('center_changed', function () {
var center = self.get('center');
center.lat = parseFloat(center.lat, 10);
center.lng = parseFloat(center.lng, 10);
self.exec.call(self, null, self.errorHandler, self.getPluginName(), 'setCenter', [self.getId(), center.lat, center.lng]);
});
self.on('fillColor_changed', function () {
var color = self.get('fillColor');
self.exec.call(self, null, self.errorHandler, self.getPluginName(), 'setFillColor', [self.getId(), common.HTMLColor2RGBA(color, 0.75)]);
});
self.on('strokeColor_changed', function () {
var color = self.get('strokeColor');
self.exec.call(self, null, self.errorHandler, self.getPluginName(), 'setStrokeColor', [self.getId(), common.HTMLColor2RGBA(color, 0.75)]);
});
self.on('strokeWidth_changed', function () {
var width = self.get('strokeWidth');
self.exec.call(self, null, self.errorHandler, self.getPluginName(), 'setStrokeWidth', [self.getId(), width]);
});
self.on('clickable_changed', function () {
var clickable = self.get('clickable');
self.exec.call(self, null, self.errorHandler, self.getPluginName(), 'setClickable', [self.getId(), clickable]);
});
self.on('radius_changed', function () {
var radius = self.get('radius');
self.exec.call(self, null, self.errorHandler, self.getPluginName(), 'setRadius', [self.getId(), radius]);
});
self.on('zIndex_changed', function () {
var zIndex = self.get('zIndex');
self.exec.call(self, null, self.errorHandler, self.getPluginName(), 'setZIndex', [self.getId(), zIndex]);
});
self.on('visible_changed', function () {
var visible = self.get('visible');
self.exec.call(self, null, self.errorHandler, self.getPluginName(), 'setVisible', [self.getId(), visible]);
});
};
utils.extend(Circle, Overlay);
Circle.prototype.getCenter = function () {
return this.get('center');
};
Circle.prototype.getRadius = function () {
return this.get('radius');
};
Circle.prototype.getStrokeColor = function () {
return this.get('strokeColor');
};
Circle.prototype.getStrokeWidth = function () {
return this.get('strokeWidth');
};
Circle.prototype.getZIndex = function () {
return this.get('zIndex');
};
Circle.prototype.getVisible = function () {
return this.get('visible');
};
Circle.prototype.getClickable = function () {
return this.get('clickable');
};
Circle.prototype.setCenter = function (center) {
center.lat = parseFloat(center.lat, 10);
center.lng = parseFloat(center.lng, 10);
this.set('center', center);
return this;
};
Circle.prototype.setFillColor = function (color) {
this.set('fillColor', color);
return this;
};
Circle.prototype.setStrokeColor = function (color) {
this.set('strokeColor', color);
return this;
};
Circle.prototype.setStrokeWidth = function (width) {
this.set('strokeWidth', width);
return this;
};
Circle.prototype.setVisible = function (visible) {
visible = common.parseBoolean(visible);
this.set('visible', visible);
return this;
};
Circle.prototype.setClickable = function (clickable) {
clickable = common.parseBoolean(clickable);
this.set('clickable', clickable);
return this;
};
Circle.prototype.setZIndex = function (zIndex) {
this.set('zIndex', zIndex);
return this;
};
Circle.prototype.setRadius = function (radius) {
this.set('radius', radius);
return this;
};
Circle.prototype.remove = function (callback) {
var self = this;
if (self._isRemoved) {
if (typeof callback === 'function') {
return;
} else {
return Promise.resolve();
}
}
Object.defineProperty(self, '_isRemoved', {
value: true,
writable: false
});
self.trigger(self.__pgmId + '_remove');
var resolver = function(resolve, reject) {
self.exec.call(self,
function() {
self.destroy();
resolve.call(self);
},
reject.bind(self),
self.getPluginName(), 'remove', [self.getId()], {
remove: true
});
};
if (typeof callback === 'function') {
resolver(callback, self.errorHandler);
} else {
return new Promise(resolver);
}
};
Circle.prototype.getBounds = function () {
var d2r = Math.PI / 180; // degrees to radians
var r2d = 180 / Math.PI; // radians to degrees
var earthsradius = 3963.189; // 3963 is the radius of the earth in miles
var radius = this.get('radius');
var center = this.get('center');
radius *= 0.000621371192;
// find the raidus in lat/lon
var rlat = (radius / earthsradius) * r2d;
var rlng = rlat / Math.cos(center.lat * d2r);
var bounds = new LatLngBounds();
var ex, ey;
for (var i = 0; i < 360; i += 90) {
ey = center.lng + (rlng * Math.cos(i * d2r)); // center a + radius x * cos(theta)
ex = center.lat + (rlat * Math.sin(i * d2r)); // center b + radius y * sin(theta)
bounds.extend({
lat: ex,
lng: ey
});
}
return bounds;
};
module.exports = Circle;
+112
View File
@@ -0,0 +1,112 @@
var LatLngBounds = require('./LatLngBounds');
/*****************************************************************************
* Cluster Class
*****************************************************************************/
var Cluster = function(__pgmId, geocell) {
var obj = {};
var self = this;
Object.defineProperty(self, '__pgmId', {
value: __pgmId,
writable: false
});
Object.defineProperty(self, 'geocell', {
value: geocell,
writable: false
});
Object.defineProperty(self, 'type', {
value: 'Cluster',
writable: false
});
Object.defineProperty(self, '_markerArray', {
value: [],
writable: false
});
Object.defineProperty(self, 'set', {
value: function(key, value) {
obj[key] = value;
},
writable: false
});
Object.defineProperty(self, 'get', {
value: function(key) {
return obj[key];
},
writable: false
});
};
Cluster.prototype.NO_CLUSTER_MODE = 1;
Cluster.prototype.CLUSTER_MODE = 2;
Cluster.prototype.getPluginName = function() {
return this.map.getId() + '-cluster';
};
Cluster.prototype.getBounds = function() {
return this.get('bounds');
};
/*
Cluster.prototype.getBounds = function() {
var bounds = this.get('bounds');
if (!bounds) {
bounds = geomodel.computeBox(this.geocell);
this.set('bounds', bounds);
}
return bounds;
};
*/
Cluster.prototype.getCenter = function() {
return this.getBounds().getCenter();
};
Cluster.prototype.getMarkers = function() {
return this._markerArray;
};
Cluster.prototype.addMarkers = function(markerRefs) {
var self = this;
var bounds = this.get('bounds') || new LatLngBounds(markerRefs[0].get('position'), markerRefs[0].get('position'));
markerRefs.forEach(function(marker) {
if (self._markerArray.indexOf(marker) === -1) {
marker.get('_cluster').isAdded = true;
self._markerArray.push(marker);
bounds.extend(marker.get('position'));
}
});
this.set('bounds', bounds);
};
Cluster.prototype.getId = function() {
return this.__pgmId;
};
Cluster.prototype.setMode = function(mode) {
this.set('mode', mode);
};
Cluster.prototype.getMode = function() {
return this.get('mode');
};
Cluster.prototype.removeMarker = function(marker) {
var idx = this._markerArray.indexOf(marker);
if (idx !== -1) {
this._markerArray.splice(idx, 1);
}
};
Cluster.prototype.remove = function() {
this.set('isRemoved', true);
this._markerArray.forEach(function(marker) {
marker.get('_cluster').isAdded = false;
});
};
Cluster.prototype.getItemLength = function() {
return this._markerArray.length;
};
module.exports = Cluster;
+796
View File
@@ -0,0 +1,796 @@
var BaseArrayClass = require('./BaseArrayClass');
var utils = require('cordova/utils');
var resolvedPromise = typeof Promise == 'undefined' ? null : Promise.resolve();
var nextTick = resolvedPromise ? function (fn) {
resolvedPromise.then(fn);
} : function (fn) {
setTimeout(fn);
};
//---------------------------
// Convert HTML color to RGB
//---------------------------
function isHTMLColorString(inputValue) {
if (!inputValue || typeof inputValue !== 'string') {
return false;
}
if (inputValue.match(/^#[0-9A-F]{3}$/i) ||
inputValue.match(/^#[0-9A-F]{4}$/i) ||
inputValue.match(/^#[0-9A-F]{6}$/i) ||
inputValue.match(/^#[0-9A-F]{8}$/i) ||
inputValue.match(/^rgba?\([\d,.\s]+\)$/) ||
inputValue.match(/^hsla?\([\d%,.\s]+\)$/)) {
return true;
}
inputValue = inputValue.toLowerCase();
return inputValue in HTML_COLORS;
}
function HTMLColor2RGBA(colorValue, defaultOpacity) {
defaultOpacity = !defaultOpacity ? 1.0 : defaultOpacity;
if (colorValue instanceof Array) {
return colorValue;
}
if (colorValue === 'transparent' || !colorValue) {
return [0, 0, 0, 0];
}
var alpha = Math.floor(255 * defaultOpacity),
matches;
var colorStr = colorValue.toLowerCase();
if (colorStr in HTML_COLORS) {
colorStr = HTML_COLORS[colorStr];
}
if (colorStr.match(/^#([0-9A-F]){3}$/i)) {
matches = colorStr.match(/([0-9A-F])/ig);
return [
parseInt(matches[0], 16),
parseInt(matches[1], 16),
parseInt(matches[2], 16),
alpha
];
}
if (colorStr.match(/^#[0-9A-F]{4}$/i)) {
alpha = colorStr.substr(4, 1);
alpha = parseInt(alpha + alpha, 16);
matches = colorStr.match(/([0-9A-F])/ig);
return [
parseInt(matches[0], 16),
parseInt(matches[1], 16),
parseInt(matches[2], 16),
alpha
];
}
if (colorStr.match(/^#[0-9A-F]{6}$/i)) {
matches = colorStr.match(/([0-9A-F]{2})/ig);
return [
parseInt(matches[0], 16),
parseInt(matches[1], 16),
parseInt(matches[2], 16),
alpha
];
}
if (colorStr.match(/^#[0-9A-F]{8}$/i)) {
matches = colorStr.match(/([0-9A-F]{2})/ig);
return [
parseInt(matches[0], 16),
parseInt(matches[1], 16),
parseInt(matches[2], 16),
parseInt(matches[3], 16)
];
}
// convert rgb(), rgba()
if (colorStr.match(/^rgba?\([\d,.\s]+\)$/)) {
matches = colorStr.match(/([\d.]+)/g);
alpha = matches.length == 4 ? Math.floor(parseFloat(matches[3]) * 255) : alpha;
return [
parseInt(matches[0], 10),
parseInt(matches[1], 10),
parseInt(matches[2], 10),
alpha
];
}
// convert hsl(), hsla()
if (colorStr.match(/^hsla?\([\d%,.\s]+\)$/)) {
matches = colorStr.match(/([\d%.]+)/g);
alpha = matches.length == 4 ? Math.floor(parseFloat(matches[3]) * 255) : alpha;
var rgb = HLStoRGB(matches[0], matches[1], matches[2]);
rgb.push(alpha);
return rgb;
}
console.warn('Warning: "' + colorValue + '" is not available. The overlay is drew by black.');
return [0, 0, 0, alpha];
}
/**
* http://d.hatena.ne.jp/ja9/20100907/1283840213
*/
function HLStoRGB(h, l, s) {
var r, g, b; // 0..255
while (h < 0) {
h += 360;
}
h = h % 360;
// In case of saturation = 0
if (s === 0) {
// RGB are the same as V
l = Math.round(l * 255);
return [l, l, l];
}
var m2 = (l < 0.5) ? l * (1 + s) : l + s - l * s,
m1 = l * 2 - m2,
tmp;
tmp = h + 120;
if (tmp > 360) {
tmp = tmp - 360;
}
if (tmp < 60) {
r = (m1 + (m2 - m1) * tmp / 60);
} else if (tmp < 180) {
r = m2;
} else if (tmp < 240) {
r = m1 + (m2 - m1) * (240 - tmp) / 60;
} else {
r = m1;
}
tmp = h;
if (tmp < 60) {
g = m1 + (m2 - m1) * tmp / 60;
} else if (tmp < 180) {
g = m2;
} else if (tmp < 240) {
g = m1 + (m2 - m1) * (240 - tmp) / 60;
} else {
g = m1;
}
tmp = h - 120;
if (tmp < 0) {
tmp = tmp + 360;
}
if (tmp < 60) {
b = m1 + (m2 - m1) * tmp / 60;
} else if (tmp < 180) {
b = m2;
} else if (tmp < 240) {
b = m1 + (m2 - m1) * (240 - tmp) / 60;
} else {
b = m1;
}
return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
}
function parseBoolean(boolValue) {
return typeof (boolValue) === 'string' && boolValue.toLowerCase() === 'true' ||
boolValue === true ||
boolValue === 1;
}
function isDom(element) {
return element &&
element.nodeType === Node.ELEMENT_NODE &&
element instanceof SVGElement === false &&
typeof element.getBoundingClientRect === 'function';
}
function getDivRect(div) {
if (!div) {
return;
}
var rect;
if (div === document.body) {
rect = div.getBoundingClientRect();
rect.left = Math.max(rect.left, window.pageOffsetX);
rect.top = Math.max(rect.top, window.pageOffsetY);
rect.width = Math.max(rect.width, window.innerWidth);
rect.height = Math.max(rect.height, window.innerHeight);
rect.right = rect.left + rect.width;
rect.bottom = rect.top + rect.height;
} else {
rect = div.getBoundingClientRect();
if ('right' in rect === false) {
rect.right = rect.left + rect.width;
}
if ('bottom' in rect === false) {
rect.bottom = rect.top + rect.height;
}
}
return {
left: rect.left,
top: rect.top,
width: rect.width,
height: rect.height,
right: rect.right,
bottom: rect.bottom
};
}
var ignoreTags = [
'pre', 'textarea', 'p', 'input', 'caption', 'canvas', 'svg'
];
function shouldWatchByNative(node) {
if (!node || node.nodeType !== Node.ELEMENT_NODE || !node.parentNode || node instanceof SVGElement) {
if (node === document.body) {
return true;
}
return false;
}
var tagName = node.tagName.toLowerCase();
if (ignoreTags.indexOf(tagName) > -1) {
return false;
}
var classNames = (node.className || '').split(' ');
if (classNames.indexOf('_gmaps_cdv_') > -1) {
return true;
}
var visibilityCSS = getStyle(node, 'visibility');
var displayCSS = getStyle(node, 'display');
// Do not check this at here.
//var pointerEventsCSS = getStyle(node, 'pointer-events');
//-----------------------------------------
// no longer check the opacity property,
// because the app might start changing the opacity later.
//-----------------------------------------
//var opacityCSS = getStyle(node, 'opacity');
//opacityCSS = /^[\d.]+$/.test(opacityCSS + '') ? opacityCSS : 1;
//-----------------------------------------
// no longer check the clickable size,
// because HTML still can display larger element inside one small element.
//-----------------------------------------
// var clickableSize = (
// node.offsetHeight > 0 && node.offsetWidth > 0 ||
// node.clientHeight > 0 && node.clientWidth > 0);
return displayCSS !== 'none' &&
visibilityCSS !== 'hidden';
}
// Get z-index order
// http://stackoverflow.com/a/24136505
var internalCache = {};
function _clearInternalCache() {
internalCache = undefined;
internalCache = {};
}
function _removeCacheById(elemId) {
delete internalCache[elemId];
}
function getZIndex(dom) {
if (dom === document.body) {
internalCache = undefined;
internalCache = {};
}
if (!dom) {
return 0;
}
var z = 0;
if (window.getComputedStyle) {
z = document.defaultView.getComputedStyle(dom, null).getPropertyValue('z-index');
}
if (dom.currentStyle) {
z = dom.currentStyle['z-index'];
}
var elemId = dom.getAttribute('__pluginDomId');
var parentNode = dom.parentNode;
var parentZIndex = 0;
if (parentNode && parentNode.nodeType === Node.ELEMENT_NODE) {
var parentElemId = parentNode.getAttribute('__pluginDomId');
if (parentElemId in internalCache) {
parentZIndex = internalCache[parentElemId];
} else {
parentZIndex = getZIndex(dom.parentNode);
internalCache[parentElemId] = parentZIndex;
}
}
var isInherit = false;
if (z === 'unset' || z === 'initial') {
z = 0;
} else if (z === 'auto' || z === 'inherit') {
z = 0;
isInherit = true;
} else {
z = parseInt(z);
}
//dom.setAttribute('__ZIndex', z);
internalCache[elemId] = z + parentZIndex;
return {
isInherit: isInherit,
z: z
};
}
// Get CSS value of an element
// http://stackoverflow.com/a/1388022
function getStyle(element, styleProperty) {
if (window.getComputedStyle) {
return document.defaultView.getComputedStyle(element, null).getPropertyValue(styleProperty);
} else if (element.currentStyle) {
return element.currentStyle[styleProperty];
}
return;
}
var HTML_COLORS = {
'aliceblue': '#f0f8ff',
'antiquewhite': '#faebd7',
'aqua': '#00ffff',
'aquamarine': '#7fffd4',
'azure': '#f0ffff',
'beige': '#f5f5dc',
'bisque': '#ffe4c4',
'black': '#000000',
'blanchedalmond': '#ffebcd',
'blue': '#0000ff',
'blueviolet': '#8a2be2',
'brown': '#a52a2a',
'burlywood': '#deb887',
'cadetblue': '#5f9ea0',
'chartreuse': '#7fff00',
'chocolate': '#d2691e',
'coral': '#ff7f50',
'cornflowerblue': '#6495ed',
'cornsilk': '#fff8dc',
'crimson': '#dc143c',
'cyan': '#00ffff',
'darkblue': '#00008b',
'darkcyan': '#008b8b',
'darkgoldenrod': '#b8860b',
'darkgray': '#a9a9a9',
'darkgrey': '#a9a9a9',
'darkgreen': '#006400',
'darkkhaki': '#bdb76b',
'darkmagenta': '#8b008b',
'darkolivegreen': '#556b2f',
'darkorange': '#ff8c00',
'darkorchid': '#9932cc',
'darkred': '#8b0000',
'darksalmon': '#e9967a',
'darkseagreen': '#8fbc8f',
'darkslateblue': '#483d8b',
'darkslategray': '#2f4f4f',
'darkslategrey': '#2f4f4f',
'darkturquoise': '#00ced1',
'darkviolet': '#9400d3',
'deeppink': '#ff1493',
'deepskyblue': '#00bfff',
'dimgray': '#696969',
'dimgrey': '#696969',
'dodgerblue': '#1e90ff',
'firebrick': '#b22222',
'floralwhite': '#fffaf0',
'forestgreen': '#228b22',
'fuchsia': '#ff00ff',
'gainsboro': '#dcdcdc',
'ghostwhite': '#f8f8ff',
'gold': '#ffd700',
'goldenrod': '#daa520',
'gray': '#808080',
'grey': '#808080',
'green': '#008000',
'greenyellow': '#adff2f',
'honeydew': '#f0fff0',
'hotpink': '#ff69b4',
'indianred ': '#cd5c5c',
'indigo ': '#4b0082',
'ivory': '#fffff0',
'khaki': '#f0e68c',
'lavender': '#e6e6fa',
'lavenderblush': '#fff0f5',
'lawngreen': '#7cfc00',
'lemonchiffon': '#fffacd',
'lightblue': '#add8e6',
'lightcoral': '#f08080',
'lightcyan': '#e0ffff',
'lightgoldenrodyellow': '#fafad2',
'lightgray': '#d3d3d3',
'lightgrey': '#d3d3d3',
'lightgreen': '#90ee90',
'lightpink': '#ffb6c1',
'lightsalmon': '#ffa07a',
'lightseagreen': '#20b2aa',
'lightskyblue': '#87cefa',
'lightslategray': '#778899',
'lightslategrey': '#778899',
'lightsteelblue': '#b0c4de',
'lightyellow': '#ffffe0',
'lime': '#00ff00',
'limegreen': '#32cd32',
'linen': '#faf0e6',
'magenta': '#ff00ff',
'maroon': '#800000',
'mediumaquamarine': '#66cdaa',
'mediumblue': '#0000cd',
'mediumorchid': '#ba55d3',
'mediumpurple': '#9370db',
'mediumseagreen': '#3cb371',
'mediumslateblue': '#7b68ee',
'mediumspringgreen': '#00fa9a',
'mediumturquoise': '#48d1cc',
'mediumvioletred': '#c71585',
'midnightblue': '#191970',
'mintcream': '#f5fffa',
'mistyrose': '#ffe4e1',
'moccasin': '#ffe4b5',
'navajowhite': '#ffdead',
'navy': '#000080',
'oldlace': '#fdf5e6',
'olive': '#808000',
'olivedrab': '#6b8e23',
'orange': '#ffa500',
'orangered': '#ff4500',
'orchid': '#da70d6',
'palegoldenrod': '#eee8aa',
'palegreen': '#98fb98',
'paleturquoise': '#afeeee',
'palevioletred': '#db7093',
'papayawhip': '#ffefd5',
'peachpuff': '#ffdab9',
'peru': '#cd853f',
'pink': '#ffc0cb',
'plum': '#dda0dd',
'powderblue': '#b0e0e6',
'purple': '#800080',
'rebeccapurple': '#663399',
'red': '#ff0000',
'rosybrown': '#bc8f8f',
'royalblue': '#4169e1',
'saddlebrown': '#8b4513',
'salmon': '#fa8072',
'sandybrown': '#f4a460',
'seagreen': '#2e8b57',
'seashell': '#fff5ee',
'sienna': '#a0522d',
'silver': '#c0c0c0',
'skyblue': '#87ceeb',
'slateblue': '#6a5acd',
'slategray': '#708090',
'slategrey': '#708090',
'snow': '#fffafa',
'springgreen': '#00ff7f',
'steelblue': '#4682b4',
'tan': '#d2b48c',
'teal': '#008080',
'thistle': '#d8bfd8',
'tomato': '#ff6347',
'turquoise': '#40e0d0',
'violet': '#ee82ee',
'wheat': '#f5deb3',
'white': '#ffffff',
'whitesmoke': '#f5f5f5',
'yellow': '#ffff00',
'yellowgreen': '#9acd32'
};
function defaultTrueOption(value) {
return value === undefined ? true : value === true;
}
function createMvcArray(array) {
if (!array) {
return new BaseArrayClass();
}
if (array.type === 'BaseArrayClass') {
return array;
}
var mvcArray;
if (array.type === 'LatLngBounds') {
array = [
array.southwest,
{
lat: array.northeast.lat,
lng: array.southwest.lng
},
array.northeast,
{
lat: array.southwest.lat,
lng: array.northeast.lng
},
array.southwest
];
array = array.map(getLatLng);
}
if (array && typeof array.getArray === 'function') {
mvcArray = new BaseArrayClass(array.getArray());
array.on('set_at', function (index) {
var value = array.getAt(index);
value = 'position' in value ? value.getPosition() : value;
mvcArray.setAt(index, value);
});
array.on('insert_at', function (index) {
var value = array.getAt(index);
value = 'position' in value ? value.getPosition() : value;
mvcArray.insertAt(index, value);
});
array.on('remove_at', function (index) {
mvcArray.removeAt(index);
});
} else {
mvcArray = new BaseArrayClass(array ? array.slice(0) : undefined);
}
return mvcArray;
}
function getLatLng(target) {
return 'getPosition' in target ? target.getPosition() : {
'lat': parseFloat(target.lat, 10),
'lng': parseFloat(target.lng, 10)
};
}
function convertToPositionArray(array) {
array = array || [];
if (!utils.isArray(array)) {
if (array.type === 'LatLngBounds') {
array = [
array.southwest,
{
lat: array.northeast.lat,
lng: array.southwest.lng
},
array.northeast,
{
lat: array.southwest.lat,
lng: array.northeast.lng
},
array.southwest
];
} else if (array && typeof array.getArray === 'function') {
array = array.getArray();
} else {
array = [array];
}
}
array = array.map(getLatLng);
return array;
}
function markerOptionsFilter(markerOptions) {
markerOptions = markerOptions || {};
markerOptions.animation = markerOptions.animation || undefined;
markerOptions.position = markerOptions.position || {};
markerOptions.position.lat = markerOptions.position.lat || 0.0;
markerOptions.position.lng = markerOptions.position.lng || 0.0;
markerOptions.draggable = markerOptions.draggable === true;
markerOptions.icon = markerOptions.icon || undefined;
markerOptions.zIndex = markerOptions.zIndex || 0;
markerOptions.snippet = typeof (markerOptions.snippet) === 'string' ? markerOptions.snippet : undefined;
markerOptions.title = typeof (markerOptions.title) === 'string' ? markerOptions.title : undefined;
markerOptions.visible = defaultTrueOption(markerOptions.visible);
markerOptions.flat = markerOptions.flat === true;
markerOptions.rotation = markerOptions.rotation || 0;
markerOptions.opacity = markerOptions.opacity === 0 ? 0 : (parseFloat('' + markerOptions.opacity, 10) || 1);
markerOptions.disableAutoPan = markerOptions.disableAutoPan === true;
markerOptions.noCache = markerOptions.noCache === true; //experimental
if (typeof markerOptions.icon === 'object') {
if ('anchor' in markerOptions.icon &&
!Array.isArray(markerOptions.icon.anchor) &&
'x' in markerOptions.icon.anchor &&
'y' in markerOptions.icon.anchor) {
markerOptions.icon.anchor = [markerOptions.icon.anchor.x, markerOptions.icon.anchor.y];
}
}
if ('infoWindowAnchor' in markerOptions &&
!Array.isArray(markerOptions.infoWindowAnchor) &&
'x' in markerOptions.infoWindowAnchor &&
'y' in markerOptions.infoWindowAnchor) {
markerOptions.infoWindowAnchor = [markerOptions.infoWindowAnchor.x, markerOptions.infoWindowAnchor.anchor.y];
}
if ('style' in markerOptions && !('styles' in markerOptions)) {
markerOptions.styles = markerOptions.style;
delete markerOptions.style;
}
if ('styles' in markerOptions) {
markerOptions.styles = typeof markerOptions.styles === 'object' ? markerOptions.styles : {};
if ('color' in markerOptions.styles) {
markerOptions.styles.color = HTMLColor2RGBA(markerOptions.styles.color || '#000000');
}
}
if (markerOptions.icon && isHTMLColorString(markerOptions.icon)) {
markerOptions.icon = HTMLColor2RGBA(markerOptions.icon);
}
if (markerOptions.icon && markerOptions.icon.label &&
isHTMLColorString(markerOptions.icon.label.color)) {
markerOptions.icon.label.color = HTMLColor2RGBA(markerOptions.icon.label.color);
}
return markerOptions;
}
function quickfilter(domPositions, mapElemIDs) {
//console.log('before', JSON.parse(JSON.stringify(domPositions)));
var keys = Object.keys(domPositions);
var tree = {};
mapElemIDs.forEach(function (mapElemId) {
var size = domPositions[mapElemId].size;
var mapRect = {
left: size.left,
top: size.top,
right: size.left + size.width,
bottom: size.top + size.height
};
tree[mapElemId] = domPositions[mapElemId];
keys.forEach(function (elemId) {
if (domPositions[elemId].ignore) {
return;
}
var domSize = {
left: domPositions[elemId].size.left,
top: domPositions[elemId].size.top,
right: domPositions[elemId].size.left + domPositions[elemId].size.width,
bottom: domPositions[elemId].size.bottom + domPositions[elemId].size.height
};
if (
(domSize.left >= mapRect.left && domSize.left <= mapRect.right) ||
(domSize.right >= mapRect.left && domSize.right <= mapRect.right) ||
(domSize.top >= mapRect.top && domSize.top <= mapRect.bottom) ||
(domSize.bottom >= mapRect.top && domSize.bottom <= mapRect.bottom)
) {
tree[elemId] = domPositions[elemId];
}
});
});
//console.log('after', JSON.parse(JSON.stringify(tree)));
return tree;
}
function getPluginDomId(element) {
// Generates a __pluginDomId
if (!element || !shouldWatchByNative(element)) {
return;
}
var elemId = element.getAttribute('__pluginDomId');
if (!elemId) {
if (element === document.body) {
elemId = 'root';
} else {
elemId = 'pgm' + Math.floor(Math.random() * Date.now());
}
element.setAttribute('__pluginDomId', elemId);
}
return elemId;
}
// Add hashCode() method
// https://stackoverflow.com/a/7616484/697856
function hashCode(text) {
var hash = 0,
i, chr;
if (text.length === 0) return hash;
for (i = 0; i < text.length; i++) {
chr = text.charCodeAt(i);
hash = ((hash << 5) - hash) + chr;
hash |= 0; // Convert to 32bit integer
}
return hash;
}
function createEvent(eventName, properties) {
var evt;
if (typeof CustomEvent === 'function') {
evt = new CustomEvent(eventName, {
bubbles: true,
detail: properties || null
});
} else {
evt = document.createEvent('Event');
evt.initEvent(eventName, true, false);
if (properties) {
Object.keys(properties).forEach(function (key) {
if (!(key in properties)) {
evt[key] = properties[key];
}
});
}
}
return evt;
}
function attachTransparentClass(div) {
if (div.classList && !div.classList.contains('_gmaps_cdv_')) {
div.classList.add('_gmaps_cdv_');
} else if (div.className && div.className.indexOf('_gmaps_cdv_') === -1) {
div.className = div.className + ' _gmaps_cdv_';
}
if (div.shadowRoot) {
var styleAttr = div.getAttribute('style') || '';
if (styleAttr && styleAttr.indexOf('--ion-background-color') === -1) {
styleAttr = styleAttr + ' --ion-background-color: transparent;';
}
div.setAttribute('style', styleAttr);
}
}
// function dettachTransparentClass(root) {
//
// if (div.classList && div.classList.contains('_gmaps_cdv_')) {
// div.classList.remove('_gmaps_cdv_');
// } else if (div.className && div.className.indexOf('_gmaps_cdv_') === -1) {
// div.className = div.className.replace('_gmaps_cdv_', '');
// }
//
// var visibilityCSS = getStyle(node, 'visibility');
// if (getStyle(div, 'background-color') === 'transparent !important') {
// div.style.backgroundColor = undefined;
// }
// if (getStyle(div, 'background') === 'transparent !important') {
// div.style.backgroundColor = undefined;
// }
// if (getStyle(div, 'background-image') === 'transparent !important') {
// div.style.backgroundImage = undefined;
// }
// if (div.shadowRoot) {
// var hiddenChildren = div.querySelectorAll('*');
// hiddenChildren = Array.prototype.splice(hiddenChildren, 0);
// hiddenChildren.forEach(dettachTransparentClass);
// }
// }
module.exports = {
_clearInternalCache: _clearInternalCache,
_removeCacheById: _removeCacheById,
getZIndex: getZIndex,
getDivRect: getDivRect,
isDom: isDom,
parseBoolean: parseBoolean,
HLStoRGB: HLStoRGB,
HTMLColor2RGBA: HTMLColor2RGBA,
isHTMLColorString: isHTMLColorString,
defaultTrueOption: defaultTrueOption,
createMvcArray: createMvcArray,
getStyle: getStyle,
convertToPositionArray: convertToPositionArray,
getLatLng: getLatLng,
shouldWatchByNative: shouldWatchByNative,
markerOptionsFilter: markerOptionsFilter,
quickfilter: quickfilter,
nextTick: nextTick,
getPluginDomId: getPluginDomId,
hashCode: hashCode,
createEvent: createEvent,
//dettachTransparentClass: dettachTransparentClass,
attachTransparentClass: attachTransparentClass
};
if (cordova && cordova.platformId === 'browser') {
require('cordova/exec/proxy').add('common', module.exports);
}
+36
View File
@@ -0,0 +1,36 @@
var common = require('./Common');
/*****************************************************************************
* Config Class
*****************************************************************************/
var Environment = {};
Environment.setBackgroundColor = function (color) {
cordova.exec(null, null, 'PluginEnvironment', 'setBackGroundColor', [common.HTMLColor2RGBA(color)]);
};
Environment.isAvailable = function (callback) {
cordova.exec(function () {
if (typeof callback === 'function') {
callback(true);
}
}, function (message) {
if (typeof callback === 'function') {
callback(false, message);
}
}, 'PluginEnvironment', 'isAvailable', ['']);
};
Environment.getLicenseInfo = function (callback) {
cordova.exec(function (txt) {
callback(txt);
}, null, 'PluginEnvironment', 'getLicenseInfo', []);
};
Environment.setEnv = function (options) {
if (options) {
cordova.exec(null, null, 'PluginEnvironment', 'setEnv', [options]);
}
};
module.exports = Environment;
+124
View File
@@ -0,0 +1,124 @@
/*****************************************************************************
* Geocoder class
*****************************************************************************/
var common = require('./Common'),
utils = require('cordova/utils');
var Geocoder = function (exec) {
return {
geocode: function (geocoderRequest, callback) {
geocoderRequest = geocoderRequest || {};
var requestProperty = null;
if ('position' in geocoderRequest && !('address' in geocoderRequest)) {
requestProperty = 'position';
} else if ('address' in geocoderRequest && !('position' in geocoderRequest)) {
requestProperty = 'address';
}
if (!requestProperty) {
var error = new Error('Invalid request');
if (typeof callback === 'function') {
callback([], error);
} else {
return Promise.reject(error);
}
}
if (geocoderRequest[requestProperty] instanceof Array || Array.isArray(geocoderRequest[requestProperty])) {
//-------------------------
// Geocoder.geocode({
// address: [
// 'Kyoto, Japan',
// 'Tokyo, Japan'
// ]
// })
//-------------------------
var mvcResults = common.createMvcArray();
for (var i = 0; i < requestCnt; i++) {
mvcResults.push(-1, true);
}
// Execute geocoder.geocode() when a new request is instearted.
var requestCnt = geocoderRequest[requestProperty].length;
var requests = common.createMvcArray();
requests.on('insert_at', function (idx) {
var request = requests.getAt(idx);
request.idx = idx;
exec.call({
_isReady: true
}, function (result) {
mvcResults.insertAt(result.idx, result.results);
if (mvcResults.getLength() === requestCnt) {
var tmp = mvcResults.getArray();
var tmp2 = tmp.filter(function (ele) {
return ele === -1;
});
if (tmp2.length === 0) {
// Notifies `finish` event when all results are received.
mvcResults.trigger('finish');
}
}
}, function (error) {
mvcResults.trigger('error', error);
}, 'PluginGeocoder', 'geocode', [request]);
});
var request;
var baseRequest = utils.clone(geocoderRequest);
delete baseRequest[requestProperty];
for (i = 0; i < requestCnt; i++) {
request = utils.clone(baseRequest);
request[requestProperty] = geocoderRequest[requestProperty][i];
request.idx = i;
if (requestProperty === 'position') {
request.position.lat = request.position.lat || 0.0;
request.position.lng = request.position.lng || 0.0;
}
requests.push(request);
}
if (typeof callback === 'function') {
callback(mvcResults);
} else {
return Promise.resolve(mvcResults);
}
} else {
//-------------------------
// Geocoder.geocode({
// address: 'Kyoto, Japan'
// })
//-------------------------
if (requestProperty === 'position') {
geocoderRequest.position.lat = geocoderRequest.position.lat || 0.0;
geocoderRequest.position.lng = geocoderRequest.position.lng || 0.0;
}
geocoderRequest.idx = -1;
var resolver1 = function (resolve, reject) {
exec.call({
_isReady: true
}, function (_results) {
resolve(_results.results);
}, reject, 'PluginGeocoder', 'geocode', [geocoderRequest]);
};
if (typeof callback === 'function') {
resolver1(callback, function (error) {
callback([], error);
});
} else {
return new Promise(resolver1);
}
}
}
};
};
module.exports = Geocoder;
+152
View File
@@ -0,0 +1,152 @@
var utils = require('cordova/utils'),
common = require('./Common'),
Overlay = require('./Overlay');
/*****************************************************************************
* GroundOverlay Class
*****************************************************************************/
var GroundOverlay = function (map, groundOverlayOptions, _exec) {
Overlay.call(this, map, groundOverlayOptions, 'GroundOverlay', _exec);
var self = this;
groundOverlayOptions.visible = groundOverlayOptions.visible === undefined ? true : groundOverlayOptions.visible;
groundOverlayOptions.zIndex = groundOverlayOptions.zIndex || 1;
groundOverlayOptions.opacity = groundOverlayOptions.opacity || 1;
groundOverlayOptions.bounds = groundOverlayOptions.bounds || [];
groundOverlayOptions.anchor = groundOverlayOptions.anchor || [0, 0];
groundOverlayOptions.bearing = groundOverlayOptions.bearing || 0;
//-----------------------------------------------
// Sets event listeners
//-----------------------------------------------
self.on('visible_changed', function () {
var visible = self.get('visible');
self.exec.call(self, null, self.errorHandler, self.getPluginName(), 'setVisible', [self.getId(), visible]);
});
self.on('image_changed', function () {
var image = self.get('image');
self.exec.call(self, null, self.errorHandler, self.getPluginName(), 'setImage', [self.getId(), image]);
});
self.on('bounds_changed', function () {
var bounds = self.get('bounds');
self.exec.call(self, null, self.errorHandler, self.getPluginName(), 'setBounds', [self.getId(), bounds]);
});
self.on('opacity_changed', function () {
var opacity = self.get('opacity');
self.exec.call(self, null, self.errorHandler, self.getPluginName(), 'setOpacity', [self.getId(), opacity]);
});
self.on('clickable_changed', function () {
var clickable = self.get('clickable');
self.exec.call(self, null, self.errorHandler, self.getPluginName(), 'setClickable', [self.getId(), clickable]);
});
self.on('bearing_changed', function () {
var bearing = self.get('bearing');
self.exec.call(self, null, self.errorHandler, self.getPluginName(), 'setBearing', [self.getId(), bearing]);
});
self.on('zIndex_changed', function () {
var zIndex = self.get('zIndex');
self.exec.call(self, null, self.errorHandler, self.getPluginName(), 'setZIndex', [self.getId(), zIndex]);
});
};
utils.extend(GroundOverlay, Overlay);
GroundOverlay.prototype.setVisible = function (visible) {
this.set('visible', visible);
};
GroundOverlay.prototype.getVisible = function () {
return this.get('visible');
};
GroundOverlay.prototype.setImage = function (url) {
this.set('image', url);
};
GroundOverlay.prototype.setBounds = function (points) {
var i,
bounds = [];
for (i = 0; i < points.length; i++) {
bounds.push({
'lat': parseFloat(points[i].lat, 10),
'lng': parseFloat(points[i].lng, 10)
});
}
this.set('bounds', bounds);
};
GroundOverlay.prototype.getOpacity = function () {
return this.get('opacity');
};
GroundOverlay.prototype.getBearing = function () {
return this.get('bearing');
};
GroundOverlay.prototype.setOpacity = function (opacity) {
if (!opacity && opacity !== 0) {
console.log('opacity value must be int or double');
return false;
}
this.set('opacity', opacity);
};
GroundOverlay.prototype.setBearing = function (bearing) {
if (bearing > 360) {
bearing = bearing - Math.floor(bearing / 360) * 360;
}
this.set('bearing', bearing);
};
GroundOverlay.prototype.getZIndex = function () {
return this.get('zIndex');
};
GroundOverlay.prototype.setZIndex = function (zIndex) {
this.set('zIndex', zIndex);
};
GroundOverlay.prototype.setClickable = function (clickable) {
clickable = common.parseBoolean(clickable);
this.set('clickable', clickable);
return this;
};
GroundOverlay.prototype.getClickable = function () {
return this.get('clickable');
};
GroundOverlay.prototype.remove = function (callback) {
var self = this;
if (self._isRemoved) {
if (typeof callback === 'function') {
return;
} else {
return Promise.resolve();
}
}
Object.defineProperty(self, '_isRemoved', {
value: true,
writable: false
});
self.trigger(self.__pgmId + '_remove');
var resolver = function(resolve, reject) {
self.exec.call(self,
function() {
self.destroy();
resolve.call(self);
},
reject.bind(self),
self.getPluginName(), 'remove', [self.getId()], {
remove: true
});
};
if (typeof callback === 'function') {
resolver(callback, self.errorHandler);
} else {
return new Promise(resolver);
}
};
module.exports = GroundOverlay;
+473
View File
@@ -0,0 +1,473 @@
var utils = require('cordova/utils'),
event = require('./event'),
BaseClass = require('./BaseClass');
/*****************************************************************************
* HTMLInfoWindow Class
*****************************************************************************/
var HTMLInfoWindow = function () {
var self = this;
BaseClass.apply(self);
var callbackTable = {};
var listenerMgr = {
one: function (target, eventName, callback) {
callbackTable[target.hashCode] = callbackTable[target.hashCode] || {};
callbackTable[target.hashCode][eventName] = callbackTable[target.hashCode][eventName] || [];
callbackTable[target.hashCode][eventName].push(callback);
target.one.call(target, eventName, callback);
},
on: function (target, eventName, callback) {
callbackTable[target.hashCode] = callbackTable[target.hashCode] || {};
callbackTable[target.hashCode][eventName] = callbackTable[target.hashCode][eventName] || [];
callbackTable[target.hashCode][eventName].push(callback);
target.on.call(target, eventName, callback);
},
bindTo: function (srcObj, srcField, dstObj, dstField, noNotify) {
var eventName = srcField + '_changed';
dstField = dstField || srcField;
var callback = function (oldValue, newValue) {
dstObj.set(dstField, newValue, noNotify);
};
callbackTable[dstObj.hashCode] = callbackTable[dstObj.hashCode] || {};
callbackTable[dstObj.hashCode][eventName] = callbackTable[dstObj.hashCode][eventName] || [];
callbackTable[dstObj.hashCode][eventName].push(callback);
srcObj.on.call(srcObj, eventName, callback);
},
off: function (target, eventName) {
if (!target || !eventName ||
!(target.hashCode in callbackTable) ||
!(eventName in callbackTable[target.hashCode])) {
return;
}
callbackTable[target.hashCode][eventName].forEach(function (listener) {
target.off.call(target, eventName, listener);
});
delete callbackTable[target.hashCode][eventName];
}
};
Object.defineProperty(self, '_hook', {
value: listenerMgr,
writable: false
});
var frame = document.createElement('div');
frame.style.overflow = 'visible';
frame.style.position = 'absolute';
frame.style.display = 'inline-block';
frame.classList.add('pgm-html-info-frame');
self.set('frame', frame);
var anchorDiv = document.createElement('div');
anchorDiv.setAttribute('class', 'pgm-anchor');
anchorDiv.style.overflow = 'visible';
anchorDiv.style.position = 'absolute';
anchorDiv.style['z-index'] = 0;
anchorDiv.style.width = '0 !important';
anchorDiv.style.height = '0 !important';
//anchorDiv.style.border = '1px solid green';
//anchorDiv.style.backgroundColor = 'rgba(125, 125, 255, 0.5)';
anchorDiv.style.transition = 'transform 0s ease';
anchorDiv.style['will-change'] = 'transform';
anchorDiv.style['-webkit-backface-visibility'] = 'hidden';
anchorDiv.style['-webkit-perspective'] = 1000;
anchorDiv.style['-webkit-transition'] = '-webkit-transform 0s ease';
anchorDiv.appendChild(frame);
self.set('anchor', anchorDiv);
var contentBox = document.createElement('div');
contentBox.style.display = 'inline-block';
contentBox.style.padding = '5px';
contentBox.style.boxSizing = 'content-box';
contentBox.classList.add('pgm-html-info-content-box');
var contentFrame = document.createElement('div');
contentFrame.style.display = 'block';
contentFrame.style.position = 'relative';
contentFrame.style.backgroundColor = 'white';
contentFrame.style.border = '1px solid rgb(204, 204, 204)';
contentFrame.style.left = '0px';
contentFrame.style.right = '0px';
contentFrame.style.zIndex = '1'; // In order to set higher depth than the map div certainly
contentFrame.style.overflow = 'hidden';
contentFrame.classList.add('pgm-html-info-content-frame');
frame.appendChild(contentFrame);
contentFrame.appendChild(contentBox);
var tailFrame = document.createElement('div');
tailFrame.style.position = 'relative';
tailFrame.style.top = '-1px';
tailFrame.style.zIndex = 100;
tailFrame.classList.add('pgm-html-info-tail-frame');
frame.appendChild(tailFrame);
var tailLeft = document.createElement('div');
/*
tailLeft.style.position = 'absolute';
tailLeft.style.marginLeft = '-15px';
tailLeft.style.left = '50%';
tailLeft.style.top = '0px';
tailLeft.style.height = '15px';
tailLeft.style.width = '16px';
tailLeft.style.overflow = 'hidden';
tailLeft.style.borderWidth = '0px';
*/
tailLeft.classList.add('pgm-html-info-tail-left');
tailLeft.style.position = 'absolute';
tailLeft.style.left = '50%';
tailLeft.style.height = '0px';
tailLeft.style.width = '0px';
tailLeft.style.marginLeft = '-15px';
tailLeft.style.borderWidth = '15px 15px 0px';
tailLeft.style.borderColor = 'rgb(204, 204, 204) transparent transparent';
tailLeft.style.borderStyle = 'solid';
tailFrame.appendChild(tailLeft);
/*
var tailLeftCover = document.createElement('div');
tailLeftCover.style.position = 'absolute';
tailLeftCover.style.backgroundColor = 'white';
tailLeftCover.style.transform = 'skewX(45deg)';
tailLeftCover.style.transformOrigin = '0px 0px 0px';
tailLeftCover.style.left = '0px';
tailLeftCover.style.height = '15px';
tailLeftCover.style.width = '15px';
tailLeftCover.style.top = '0px';
tailLeftCover.style.zIndex = 1;
tailLeftCover.style.borderLeft = '1px solid rgb(204, 204, 204)';
tailLeft.classList.add('pgm-html-info-tail-left-cover');
tailLeft.appendChild(tailLeftCover);
*/
var tailRight = document.createElement('div');
/*
tailRight.style.position = 'absolute';
tailRight.style.left = '50%';
tailRight.style.top = '0px';
tailRight.style.height = '15px';
tailRight.style.width = '16px';
tailRight.style.overflow = 'hidden';
tailRight.style.borderWidth = '0px';
*/
tailRight.style.position = 'absolute';
tailRight.style.left = '50%';
tailRight.style.height = '0px';
tailRight.style.width = '0px';
tailRight.style.marginLeft = '-14px';
tailRight.style.borderTopWidth = '14px';
tailRight.style.borderLeftWidth = '14px';
tailRight.style.borderRightWidth = '14px';
tailRight.style.borderColor = 'rgb(255, 255, 255) transparent transparent';
tailRight.style.borderStyle = 'solid';
tailRight.classList.add('pgm-html-info-tail-right');
tailFrame.appendChild(tailRight);
/*
var tailRightCover = document.createElement('div');
tailRightCover.style.position = 'absolute';
tailRightCover.style.backgroundColor = 'white';
tailRightCover.style.transform = 'skewX(-45deg)';
tailRightCover.style.transformOrigin = '0px 0px 0px';
tailRightCover.style.left = '0px';
tailRightCover.style.height = '15px';
tailRightCover.style.width = '15px';
tailRightCover.style.top = '0px';
tailRightCover.style.zIndex = 2;
tailRightCover.style.borderRight = '1px solid rgb(204, 204, 204)';
tailRightCover.classList.add('pgm-html-info-tail-right-cover');
tailRight.appendChild(tailRightCover);
*/
var eraseBorder = document.createElement('div');
eraseBorder.style.position = 'absolute';
eraseBorder.style.zIndex = 3;
eraseBorder.style.backgroundColor = 'white';
eraseBorder.style.width = '27px';
eraseBorder.style.height = '2px';
eraseBorder.style.top = '-1px';
eraseBorder.style.left = '50%';
eraseBorder.style.marginLeft = '-13px';
eraseBorder.classList.add('pgm-html-info-tail-erase-border');
tailFrame.appendChild(eraseBorder);
var calculate = function (marker) {
//var marker = self.get('marker');
var map = marker.getMap();
var div = map.getDiv();
var frame = self.get('frame');
var contentFrame = frame.firstChild;
var contentBox = contentFrame.firstChild;
contentBox.style.minHeight = '50px';
contentBox.style.width = 'auto';
contentBox.style.height = 'auto';
contentBox.style.padding = '5px';
var content = self.get('content');
if (typeof content === 'string') {
contentBox.style.whiteSpace = 'pre-wrap';
contentBox.innerHTML = content;
} else {
if (!content) {
contentBox.innerText = '';
} else if (content.nodeType === 1) {
contentBox.innerHTML = '';
contentBox.appendChild(content);
} else {
contentBox.innerText = content;
}
}
var cssOptions = self.get('cssOptions');
if (cssOptions && typeof cssOptions === 'object') {
var keys = Object.keys(cssOptions);
keys.forEach(function (key) {
contentBox.style.setProperty(key, cssOptions[key]);
});
}
// Insert the contents to this HTMLInfoWindow
if (!anchorDiv.parentNode) {
map._layers.info.appendChild(anchorDiv);
}
// Adjust the HTMLInfoWindow size
var contentsWidth = contentBox.offsetWidth + 10; // padding 5px x 2
var contentsHeight = contentBox.offsetHeight;
self.set('contentsHeight', contentsHeight);
contentFrame.style.width = contentsWidth + 'px';
contentFrame.style.height = contentsHeight + 'px';
frame.style.width = contentsWidth + 'px';
frame.style.height = (contentsHeight + 15) + 'px';
if (contentBox.offsetWidth > div.offsetWidth * 0.9) {
contentBox.style.width = (div.offsetWidth * 0.9) + 'px';
}
contentBox.style.width = '100%';
contentBox.style.height = '100%';
contentBox.style.padding = '5px 17px 17px 5px';
self.set('contentsWidth', contentsWidth);
var infoOffset = {
x: 31,
y: 31
};
var iconSize = {
width: 62,
height: 110
};
// If there is no specification with `anchor` property,
// the values {x: 0.5, y: 1} are specified by native APIs.
// For the case, anchor values are {x: 0} in JS.
var anchor = {
x: 15,
y: 15
};
var icon = marker.get('icon');
if (typeof icon === 'object') {
if (typeof icon.url === 'string' && icon.url.indexOf('data:image/') === 0) {
var img = document.createElement('img');
img.src = icon.url;
iconSize.width = img.width;
iconSize.height = img.height;
}
if (typeof icon.size === 'object') {
iconSize.width = icon.size.width;
iconSize.height = icon.size.height;
}
if (Array.isArray(icon.anchor)) {
anchor.x = icon.anchor[0];
anchor.y = icon.anchor[1];
}
}
var infoWindowAnchor = marker.get('infoWindowAnchor');
if (utils.isArray(infoWindowAnchor)) {
infoOffset.x = infoWindowAnchor[0];
infoOffset.y = infoWindowAnchor[1];
}
infoOffset.x = infoOffset.x / iconSize.width;
infoOffset.x = infoOffset.x > 1 ? 1 : infoOffset.x;
infoOffset.x = infoOffset.x < 0 ? 0 : infoOffset.x;
infoOffset.y = infoOffset.y / iconSize.height;
infoOffset.y = infoOffset.y > 1 ? 1 : infoOffset.y;
infoOffset.y = infoOffset.y < 0 ? 0 : infoOffset.y;
infoOffset.y *= iconSize.height;
infoOffset.x *= iconSize.width;
anchor.x = anchor.x / iconSize.width;
anchor.x = anchor.x > 1 ? 1 : anchor.x;
anchor.x = anchor.x < 0 ? 0 : anchor.x;
anchor.y = anchor.y / iconSize.height;
anchor.y = anchor.y > 1 ? 1 : anchor.y;
anchor.y = anchor.y < 0 ? 0 : anchor.y;
anchor.y *= iconSize.height;
anchor.x *= iconSize.width;
//console.log('contentsSize = ' + contentsWidth + ', ' + contentsHeight);
//console.log('iconSize = ' + iconSize.width + ', ' + iconSize.height);
//console.log('infoOffset = ' + infoOffset.x + ', ' + infoOffset.y);
//var frameBorder = parseInt(common.getStyle(contentFrame, 'border-left-width').replace(/[^\d]/g, ''), 10);
//var offsetX = (contentsWidth + frameBorder + anchor.x ) * 0.5 + (iconSize.width / 2 - infoOffset.x);
//var offsetY = contentsHeight + anchor.y - (frameBorder * 2) - infoOffset.y + 15;
var offsetX = -(iconSize.width / 2) - (cordova.platformId === 'android' ? 1 : 0);
var offsetY = -iconSize.height - (cordova.platformId === 'android' ? 1 : 0);
anchorDiv.style.width = iconSize.width + 'px';
anchorDiv.style.height = iconSize.height + 'px';
self.set('offsetX', offsetX);
self.set('offsetY', offsetY);
frame.style.bottom = (iconSize.height - infoOffset.y) + 'px';
frame.style.left = ((-contentsWidth) / 2 + infoOffset.x) + 'px';
//console.log('frameLeft = ' + frame.style.left );
var point = map.get('infoPosition');
anchorDiv.style.visibility = 'hidden';
var x = point.x + self.get('offsetX');
var y = point.y + self.get('offsetY');
anchorDiv.style['-webkit-transform'] = 'translate3d(' + x + 'px, ' + y + 'px, 0px)';
anchorDiv.style.transform = 'translate3d(' + x + 'px, ' + y + 'px, 0px)';
anchorDiv.style.visibility = 'visible';
self.trigger('infoPosition_changed', '', point);
self.trigger(event.INFO_OPEN);
};
self._hook.on(self, 'infoPosition_changed', function (ignore, point) {
if (!point) return;
var x = point.x + self.get('offsetX');
var y = point.y + self.get('offsetY');
anchorDiv.style['-webkit-transform'] = 'translate3d(' + x + 'px, ' + y + 'px, 0px)';
anchorDiv.style.transform = 'translate3d(' + x + 'px, ' + y + 'px, 0px)';
});
self._hook.on(self, 'infoWindowAnchor_changed', calculate);
self.set('isInfoWindowVisible', false);
};
utils.extend(HTMLInfoWindow, BaseClass);
HTMLInfoWindow.prototype.isInfoWindowShown = function () {
return this.get('isInfoWindowVisible') === true;
};
HTMLInfoWindow.prototype.close = function () {
var self = this;
var marker = self.get('marker');
if (marker) {
self._hook.off(marker, 'isInfoWindowVisible_changed');
}
if (!self.isInfoWindowShown() || !marker) {
return;
}
self.set('isInfoWindowVisible', false);
marker.set('isInfoWindowVisible', false);
marker.set('infoWindow', undefined);
this.set('marker', undefined);
var map = marker.getMap();
self._hook.off(marker.getMap(), 'map_clear');
self._hook.off(marker, 'infoPosition_changed');
self._hook.off(marker, 'icon_changed');
//self._hook.off(self, 'infoWindowAnchor_changed');
self._hook.off(marker, event.INFO_CLOSE); //This event listener is assigned in the open method. So detach it.
self.trigger(event.INFO_CLOSE);
map.set('active_marker', null);
//var div = map.getDiv();
var anchorDiv = self.get('anchor');
if (anchorDiv && anchorDiv.parentNode) {
anchorDiv.parentNode.removeChild(anchorDiv);
// Remove the contents from this HTMLInfoWindow
var contentFrame = anchorDiv.firstChild.firstChild;
var contentBox = contentFrame.firstChild;
contentBox.innerHTML = '';
}
};
HTMLInfoWindow.prototype.setContent = function (content, cssOptions) {
var self = this;
var prevContent = self.get('content');
self.set('content', content);
self.set('cssOptions', cssOptions);
var marker = self.get('marker');
if (content !== prevContent && marker && marker.isInfoWindowShown()) {
var anchorDiv = self.get('anchor');
if (anchorDiv) {
anchorDiv.style.width = '0 !important';
anchorDiv.style.height = '0 !important';
if (anchorDiv.parentNode) {
anchorDiv.parentNode.removeChild(anchorDiv);
// Remove the contents from this HTMLInfoWindow
var contentFrame = anchorDiv.firstChild.firstChild;
var contentBox = contentFrame.firstChild;
contentBox.innerHTML = '';
}
}
self.trigger('infoWindowAnchor_changed', marker);
}
};
HTMLInfoWindow.prototype.open = function (marker) {
if (!marker) {
return;
}
if (marker._objectInstance) {
// marker is an instance of the ionic-native wrapper plugin.
marker = marker._objectInstance;
}
var self = this,
map = marker.getMap();
marker.set('infoWindow', self);
marker.set('isInfoWindowVisible', true);
self._hook.on(marker, 'icon_changed', function () {
self.trigger.call(self, 'infoWindowAnchor_changed', marker);
});
self.set('isInfoWindowVisible', true);
self._hook.on(marker, 'isInfoWindowVisible_changed', function (prevValue, newValue) {
if (newValue === false) {
self.close.call(self);
}
});
map.fromLatLngToPoint(marker.getPosition(), function (point) {
map.set('infoPosition', {
x: point[0],
y: point[1]
});
self._hook.bindTo(map, 'infoPosition', self);
self._hook.bindTo(marker, 'infoWindowAnchor', self);
self._hook.bindTo(marker, 'icon', self);
self._hook.one(marker.getMap(), 'map_clear', self.close.bind(self));
self._hook.one(marker, event.INFO_CLOSE, self.close.bind(self));
self.set('marker', marker);
map.set('active_marker', marker);
self.trigger.call(self, 'infoWindowAnchor_changed', marker);
});
};
HTMLInfoWindow.prototype.setBackgroundColor = function (backgroundColor) {
this.get('frame').children[0].style.backgroundColor = backgroundColor;
this.get('frame').children[1].children[0].style.borderColor = backgroundColor + ' rgba(0,0,0,0) rgba(0,0,0,0)';
this.get('frame').children[1].children[1].style.borderColor = backgroundColor + ' rgba(0,0,0,0) rgba(0,0,0,0)';
this.get('frame').children[1].children[2].style.backgroundColor = backgroundColor;
};
module.exports = HTMLInfoWindow;
+53
View File
@@ -0,0 +1,53 @@
// InlineWorker
// https://github.com/mohayonao/inline-worker
//
// The MIT License (MIT)
// Copyright © 2018 Nao Yonamine
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
var WORKER_ENABLED = !!window.Worker;
var global = window;
function InlineWorker(func, self) {
var _this = this;
var functionBody;
self = self || {};
if (WORKER_ENABLED) {
functionBody = func.toString().trim().match(
/^function\s*\w*\s*\([\w\s,]*\)\s*{([\w\W]*?)}$/
)[1];
return new global.Worker(global.URL.createObjectURL(
new global.Blob([ functionBody ], { type: 'text/javascript' })
));
}
function postMessage(data) {
setTimeout(function() {
_this.onmessage({ data: data });
}, 0);
}
this.self = self;
this.self.postMessage = postMessage;
setTimeout(func.bind(self, self), 0);
}
InlineWorker.prototype.postMessage = function postMessage(data) {
var _this = this;
setTimeout(function() {
_this.self.onmessage({ data: data });
}, 0);
};
module.exports = InlineWorker;
File diff suppressed because it is too large Load Diff
+368
View File
@@ -0,0 +1,368 @@
var utils = require('cordova/utils'),
common = require('./Common'),
BaseClass = require('./BaseClass'),
event = require('./event'),
BaseArrayClass = require('./BaseArrayClass'),
HtmlInfoWindow = require('./HtmlInfoWindow');
var XElement = null;
window.addEventListener('WebComponentsReady', function () {
var XElementPrototype = Object.create(HTMLElement.prototype);
XElement = document.registerElement('pgm-sandbox', {
prototype: XElementPrototype
});
});
/*****************************************************************************
* KmlOverlay Class
*****************************************************************************/
var KmlOverlay = function (map, kmlId, camera, kmlData, kmlOverlayOptions) {
BaseClass.apply(this);
var self = this;
//self.set('visible', kmlOverlayOptions.visible === undefined ? true : kmlOverlayOptions.visible);
//self.set('zIndex', kmlOverlayOptions.zIndex || 0);
Object.defineProperty(self, '_isReady', {
value: true,
writable: false
});
Object.defineProperty(self, 'type', {
value: 'KmlOverlay',
writable: false
});
Object.defineProperty(self, '__pgmId', {
value: kmlId,
writable: false
});
Object.defineProperty(self, 'map', {
value: map,
writable: false
});
Object.defineProperty(self, 'camera', {
value: camera,
writable: false
});
Object.defineProperty(self, 'kmlData', {
value: kmlData,
writable: false
});
function templateRenderer(html, marker) {
var extendedData = marker.get('extendeddata');
return html.replace(/\$[{\\[](.+?)[}\]]/gi, function(match, name) {
var text = '';
if (marker.get(name)) {
text = marker.get(name).value || '';
}
if (extendedData && text) {
text = text.replace(/\$[{\\[](.+?)[}\]]/gi, function(match1, name1) {
return extendedData[name1.toLowerCase()] || '';
});
}
return text;
});
}
function parseBalloonStyle(balloonStyle) {
var css = {};
var hasBgColor = false;
var keys = Object.keys(balloonStyle);
keys.forEach(function (key) {
switch (key.toLowerCase()) {
case 'bgcolor':
hasBgColor = true;
ballon.setBackgroundColor(common.kmlColorToCSS(balloonStyle[key]));
break;
case 'textcolor':
css.color = common.kmlColorToCSS(balloonStyle[key]);
break;
}
});
if (!hasBgColor) {
ballon.setBackgroundColor('white');
}
return css;
}
self.set('clickable', kmlOverlayOptions.clickable);
var ballon = new HtmlInfoWindow();
var onOverlayClick = function (position, overlay) {
if (!self.get('clickable')) {
return;
}
self.trigger(event.KML_CLICK, overlay, position);
if (kmlOverlayOptions.suppressInfoWindows) {
return;
}
var description = overlay.get('description');
if (!description && overlay.get('extendeddata')) {
var extendeddata = overlay.get('extendeddata');
var keys = Object.keys(extendeddata);
var table = [];
keys.forEach(function (key) {
if (extendeddata[key] !== '' && extendeddata[key] !== null && extendeddata[key] !== undefined) {
table.push('<tr><th>' + key + '</th><td>' + extendeddata[key] + '</td></tr>');
}
});
if (table.length > 0) {
table.unshift('<table border="1">');
table.push('</table>');
description = {
value: table.join('')
};
overlay.set('description', description);
}
}
var html = [];
var result;
var descriptionTxt = '';
if (description && description.value) {
descriptionTxt = description.value;
}
if (description && (descriptionTxt.indexOf('<html>') > -1 || descriptionTxt.indexOf('script') > -1)) {
var text = templateRenderer(descriptionTxt, overlay);
// create a sandbox
// if (text.indexOf('<html') === -1) {
// text = '<html><body>' + text + '</body></html>';
// }
result = document.createElement('div');
if (overlay.get('name') && overlay.get('name').value) {
var name = document.createElement('div');
name.style.fontWeight = 500;
name.style.fontSize = 'medium';
name.style.marginBottom = 0;
name.style.whiteSpace = 'pre';
name.innerText = overlay.get('name').value || '';
result.appendChild(name);
}
if (overlay.get('snippet') && overlay.get('snippet').value.length > 0) {
var snippet = document.createElement('div');
snippet.style.fontWeight = 300;
snippet.style.fontSize = 'small';
snippet.style.whiteSpace = 'normal';
snippet.style.whiteSpace = 'pre';
snippet.style.fontFamily = 'Roboto,Arial,sans-serif';
snippet.innerText = overlay.get('snippet').value || '';
result.appendChild(snippet);
}
if (text && text.length > 0) {
if (XElement) {
var xElement = new XElement();
xElement.innerHTML = text;
result.appendChild(xElement);
} else {
var iframe = document.createElement('iframe');
iframe.sandbox = 'allow-scripts allow-same-origin';
iframe.frameBorder = 'no';
iframe.scrolling = 'yes';
iframe.style.overflow = 'hidden';
iframe.addEventListener('load', function () {
iframe.contentWindow.document.open();
iframe.contentWindow.document.write(text);
iframe.contentWindow.document.close();
}, {
once: true
});
result.appendChild(iframe);
}
}
} else {
if (overlay.get('description')) {
html.push('<div style="font-weight: 300; font-size: small; font-family: Roboto,Arial,sans-serif;white-space:pre;min-width:100px;padding: auto 0.5em;">${description}</div>');
} else {
if (overlay.get('name')) {
html.push('<div style="font-weight: 500; font-size: medium; margin-bottom: 0em">${name}</div>');
}
if (overlay.get('_snippet')) {
html.push('<div style="font-weight: 300; font-size: small; font-family: Roboto,Arial,sans-serif;">${_snippet}</div>');
}
}
var prevMatchedCnt = 0;
result = html.join('');
var matches = result.match(/\$[{\\[].+?[}\]]/gi);
while(matches && matches.length !== prevMatchedCnt) {
prevMatchedCnt = matches.length;
result = templateRenderer(result, overlay);
matches = result.match(/\$[{\\[].+?[}\]]/gi);
}
}
var styles = null;
if (overlay.get('balloonstyle')) {
styles = parseBalloonStyle(overlay.get('balloonstyle'));
}
styles = styles || {};
styles.overflow = 'scroll';
styles['max-width'] = (map.getDiv().offsetWidth * 0.8) + 'px';
styles['max-height'] = (map.getDiv().offsetHeight * 0.6) + 'px';
ballon.setContent(result, styles);
var marker = map.get('invisible_dot');
if (overlay.type === 'Marker') {
marker.setVisible(false);
ballon.open(overlay);
} else {
marker.setPosition(position);
marker.setVisible(true);
marker.off(event.MARKER_CLICK);
map.animateCamera({
target: position,
duration: 300
}, function () {
marker.setAnimation(window.plugin.google.maps.Animation.DROP, function () {
marker.on(event.MARKER_CLICK, function () {
ballon.open(marker);
});
marker.trigger(event.MARKER_CLICK);
});
});
}
};
var eventNames = {
'Marker': event.MARKER_CLICK,
'Polyline': event.POLYLINE_CLICK,
'Polygon': event.POLYGON_CLICK,
'GroundOverlay': event.GROUND_OVERLAY_CLICK
};
var seekOverlays = function (overlay) {
if (overlay instanceof BaseArrayClass) {
overlay.forEach(seekOverlays);
} else if (Array.isArray(overlay)) {
(new BaseArrayClass(overlay)).forEach(seekOverlays);
} else if (overlay instanceof BaseClass && overlay.type in eventNames) {
overlay.on(eventNames[overlay.type], onOverlayClick);
}
};
kmlData.forEach(seekOverlays);
/*
var ignores = ['map', '__pgmId', 'hashCode', 'type'];
for (var key in kmlOverlayOptions) {
if (ignores.indexOf(key) === -1) {
self.set(key, kmlOverlayOptions[key]);
}
}
*/
};
utils.extend(KmlOverlay, BaseClass);
KmlOverlay.prototype.getPluginName = function () {
return this.map.getId() + '-kmloverlay';
};
KmlOverlay.prototype.getHashCode = function () {
return this.hashCode;
};
KmlOverlay.prototype.getDefaultViewport = function () {
return this.camera;
};
KmlOverlay.prototype.getKmlData = function () {
return this.kmlData;
};
KmlOverlay.prototype.getMap = function () {
return this.map;
};
KmlOverlay.prototype.getId = function () {
return this.__pgmId;
};
KmlOverlay.prototype.setClickable = function (clickable) {
clickable = common.parseBoolean(clickable);
this.set('clickable', clickable);
return this;
};
KmlOverlay.prototype.getClickable = function () {
return this.get('clickable');
};
KmlOverlay.prototype.getVisible = function () {
return this.get('visible');
};
KmlOverlay.prototype.setVisible = function (visible) {
var self = this;
if (self._isRemoved) {
return;
}
visible = common.parseBoolean(visible);
this.set('visible', visible);
var applyChildren = function (children) {
children.forEach(function (child) {
if ('setVisible' in child &&
typeof child.setVisible === 'function') {
child.setVisible(visible);
return;
}
if (child instanceof BaseArrayClass) {
applyChildren(child);
return;
}
});
};
applyChildren(self.kmlData);
};
KmlOverlay.prototype.remove = function (callback) {
var self = this;
if (self._isRemoved) {
if (typeof callback === 'function') {
return;
} else {
return Promise.resolve();
}
}
Object.defineProperty(self, '_isRemoved', {
value: true,
writable: false
});
var removeChildren = function (children, cb) {
children.forEach(function (child, next) {
if ('remove' in child &&
typeof child.remove === 'function') {
child.remove(next);
return;
}
if (child instanceof BaseArrayClass) {
removeChildren(child, next);
return;
}
next();
}, cb);
};
var resolver = function (resolve) {
removeChildren(self.kmlData, function () {
self.destroy();
resolve.call(self);
});
};
if (typeof callback === 'function') {
resolver.call(self, callback, null);
return;
} else {
return Promise.resolve();
}
};
module.exports = KmlOverlay;
+51
View File
@@ -0,0 +1,51 @@
/*******************************************************************************
* @name LatLng
* @class This class represents new camera position
* @param {Number} latitude
* @param {Number} longitude
******************************************************************************/
function LatLng(latitude, longitude) {
var self = this;
/**
* @property {Number} latitude
*/
self.lat = parseFloat(latitude || 0, 10);
/**
* @property {Number} longitude
*/
self.lng = parseFloat(longitude || 0, 10);
}
LatLng.prototype = {
/**
* Comparison function.
* @method
* @return {Boolean}
*/
equals: function(other) {
other = other || {};
return other.lat === this.lat &&
other.lng === this.lng;
},
/**
* @method
* @return {String} latitude,lontitude
*/
toString: function() {
return '{"lat": ' + this.lat + ', "lng": ' + this.lng + '}';
},
/**
* @method
* @param {Number}
* @return {String} latitude,lontitude
*/
toUrlValue: function(precision) {
precision = precision || 6;
return '{"lat": ' + this.lat.toFixed(precision) + ', "lng": ' + this.lng.toFixed(precision) + '}';
}
};
module.exports = LatLng;
+130
View File
@@ -0,0 +1,130 @@
var LatLng = require('./LatLng');
/*****************************************************************************
* LatLngBounds Class
*****************************************************************************/
var LatLngBounds = function () {
Object.defineProperty(this, 'type', {
value: 'LatLngBounds',
writable: false
});
var args = [];
if (arguments.length === 1 &&
typeof arguments[0] === 'object' &&
'push' in arguments[0]) {
args = arguments[0];
} else {
args = Array.prototype.slice.call(arguments, 0);
}
for (var i = 0; i < args.length; i++) {
if (args[i] && 'lat' in args[i] && 'lng' in args[i]) {
this.extend(args[i]);
}
}
};
LatLngBounds.prototype.northeast = null;
LatLngBounds.prototype.southwest = null;
LatLngBounds.prototype.toString = function () {
return '{"southwest":' + this.southwest.toString() + ', "northeast":' + this.northeast.toString() + '}';
};
LatLngBounds.prototype.toUrlValue = function (precision) {
precision = precision || 6;
return '[' + this.southwest.toUrlValue(precision) + ',' + this.northeast.toUrlValue(precision) + ']';
};
LatLngBounds.prototype.extend = function (latLng) {
if (latLng && 'lat' in latLng && 'lng' in latLng) {
if (!this.southwest && !this.northeast) {
this.southwest = latLng;
this.northeast = latLng;
} else {
var south = Math.min(latLng.lat, this.southwest.lat);
var north = Math.max(latLng.lat, this.northeast.lat);
var west = this.southwest.lng,
east = this.northeast.lng;
if (west > 0 && east < 0) {
if (latLng.lng > 0) {
west = Math.min(latLng.lng, west);
} else {
east = Math.max(latLng.lng, east);
}
} else {
west = Math.min(latLng.lng, this.southwest.lng);
east = Math.max(latLng.lng, this.northeast.lng);
}
delete this.southwest;
delete this.northeast;
this.southwest = new LatLng(south, west);
this.northeast = new LatLng(north, east);
}
}
};
LatLngBounds.prototype.getCenter = function () {
var centerLat = (this.southwest.lat + this.northeast.lat) / 2;
var swLng = this.southwest.lng;
var neLng = this.northeast.lng;
var sumLng = swLng + neLng;
var centerLng = sumLng / 2;
if ((swLng > 0 && neLng < 0 && sumLng < 180)) {
centerLng += sumLng > 0 ? -180 : 180;
}
return new LatLng(centerLat, centerLng);
};
LatLngBounds.prototype.contains = function (latLng) {
if (!latLng || !('lat' in latLng) || !('lng' in latLng)) {
return false;
}
var y = latLng.lat,
x = latLng.lng;
var y90 = y + 90;
var south = this.southwest.lat,
north = this.northeast.lat,
west = this.southwest.lng,
east = this.northeast.lng;
var south90 = south + 90,
north90 = north + 90;
var containX = false,
containY = false;
if (west <= 0 && east <= 0 && west <= east) {
if (x > 0) {
containX = false;
} else {
containX = (west <= x && x <= east);
}
} else if (east <= 0 && west > 0 && east <= west) {
if (x > 0) {
containX = (x >= west && x <= 180);
} else {
containX = (-180 <= x && x <= west);
}
} else if (west <= 0 && east > 0 && west <= east) {
if (x < 0) {
containX = (west <= x && x <= 0);
} else {
containX = (x >= 0 && x <= east);
}
} else {
containX = (west <= x && x <= east);
}
containY = (south90 <= y90 && y90 <= north90) || //#a
(south >= 0 && north <= 0 && ((south <= y && y <= 90) || (y >= -90 && y <= north))); // #d
return containX && containY;
};
module.exports = LatLngBounds;
+18
View File
@@ -0,0 +1,18 @@
/*****************************************************************************
* Location Class
*****************************************************************************/
var LatLng = require('./LatLng');
var Location = function(params) {
var self = this;
self.latLng = params.latLng || new LatLng(params.lat || 0, params.lng || 0);
self.elapsedRealtimeNanos = params.elapsedRealtimeNanos;
self.time = params.time;
self.accuracy = params.accuracy || null;
self.bearing = params.bearing || null;
self.altitude = params.altitude || null;
self.speed = params.speed || null;
self.provider = params.provider;
self.hashCode = params.hashCode;
};
module.exports = Location;
+114
View File
@@ -0,0 +1,114 @@
/*****************************************************************************
* LocationService class
*****************************************************************************/
var LatLng = require('./LatLng');
var LocationService = function(exec) {
function _errorHandler(err) {
console.error(err);
}
return {
hasPermission: function(callback, errorCallback) {
var self = this;
var resolver = function(resolve, reject) {
exec.call({
_isReady: true
},
function(hasPermission) {
resolve.call(self, hasPermission === 1);
},
reject.bind(self), 'PluginLocationService', 'hasPermission', [], {sync: true});
};
var errorHandler = function(result) {
if (typeof errorCallback === 'function') {
errorCallback.call(self, result);
} else {
(self.errorHandler || _errorHandler).call(self, result);
}
};
if (typeof callback === 'function') {
resolver(callback, errorHandler);
return self;
} else {
return new Promise(resolver);
}
},
getMyLocation: function(params, success_callback, errorCallback) {
var self = this;
var args = [params || {}, success_callback || null, errorCallback];
if (typeof args[0] === 'function') {
args.unshift({});
}
params = args[0];
success_callback = args[1];
errorCallback = args[2];
var resolver = function(resolve, reject) {
exec.call({
_isReady: true
},
function(location) {
location.latLng = new LatLng(location.latLng.lat, location.latLng.lng);
resolve.call(self, location);
},
reject.bind(self), 'PluginLocationService', 'getMyLocation', [params], {sync: true});
};
params.enableHighAccuracy = params.enableHighAccuracy === true;
var errorHandler = function(result) {
if (typeof errorCallback === 'function') {
errorCallback.call(self, result);
} else {
(self.errorHandler || _errorHandler).call(self, result);
}
};
if (typeof success_callback === 'function') {
resolver(success_callback, errorHandler);
return self;
} else {
return new Promise(resolver);
}
}
};
};
/**
// TODO:
LocationService.prototype.followMyPosition = function(params, success_callback, errorCallback) {
var self = this;
var args = [params || {}, success_callback || null, errorCallback];
if (typeof args[0] === 'function') {
args.unshift({});
}
self.on('currentPosition_changed', success_callback);
var successHandler = function(location) {
location.latLng = new LatLng(location.latLng.lat, location.latLng.lng);
if (typeof success_callback === 'function') {
success_callback.call(self, location);
}
self.set('currentPosition', location);
};
var errorHandler = function(result) {
if (typeof errorCallback === 'function') {
errorCallback.call(self, result);
}
};
exec.call({
_isReady: true
}, successHandler, errorHandler, 'CordovaGoogleMaps', 'followMyPosition', [params], {sync: true});
};
LocationService.prototype.clearFollowing = function() {
var self = this;
self.off('currentPosition_changed');
exec.call({
_isReady: true
}, successHandler, errorHandler, 'CordovaGoogleMaps', 'clearFollowing', [params], {sync: true});
};
**/
module.exports = LocationService;
+1589
View File
File diff suppressed because it is too large Load Diff
+8
View File
@@ -0,0 +1,8 @@
module.exports = {
'NORMAL': 'MAP_TYPE_NORMAL',
'ROADMAP': 'MAP_TYPE_NORMAL',
'SATELLITE': 'MAP_TYPE_SATELLITE',
'HYBRID': 'MAP_TYPE_HYBRID',
'TERRAIN': 'MAP_TYPE_TERRAIN',
'NONE': 'MAP_TYPE_NONE'
};
+362
View File
@@ -0,0 +1,362 @@
var utils = require('cordova/utils'),
common = require('./Common'),
LatLng = require('./LatLng'),
event = require('./event'),
Overlay = require('./Overlay');
/*****************************************************************************
* Marker Class
*****************************************************************************/
var Marker = function(map, markerOptions, _exec, extras) {
extras = extras || {};
Overlay.call(this, map, markerOptions, extras.className || 'Marker', _exec, extras);
var self = this;
if (markerOptions && markerOptions.position) {
markerOptions.position.lat = parseFloat(markerOptions.position.lat);
markerOptions.position.lng = parseFloat(markerOptions.position.lng);
self.set('position', markerOptions.position);
}
//-----------------------------------------------
// Sets event listeners
//-----------------------------------------------
self.on(event.MARKER_CLICK, function() {
self.showInfoWindow.apply(self);
});
self.on('position_changed', function() {
var position = self.get('position');
try {
position.lat = parseFloat(position.lat, 10);
position.lng = parseFloat(position.lng, 10);
self.exec.call(self, null, self.errorHandler, self.getPluginName(), 'setPosition', [self.getId(), position.lat, position.lng]);
} catch (e) {
return;
}
});
self.on('rotation_changed', function() {
var rotation = self.get('rotation');
self.exec.call(self, null, self.errorHandler, self.getPluginName(), 'setRotation', [self.getId(), rotation]);
});
self.on('snippet_changed', function() {
var snippet = self.get('snippet');
self.exec.call(self, null, self.errorHandler, self.getPluginName(), 'setSnippet', [self.getId(), snippet]);
});
self.on('visible_changed', function() {
var visible = self.get('visible');
self.exec.call(self, null, self.errorHandler, self.getPluginName(), 'setVisible', [self.getId(), visible]);
});
self.on('title_changed', function() {
var title = self.get('title');
self.exec.call(self, null, self.errorHandler, self.getPluginName(), 'setTitle', [self.getId(), title]);
});
self.on('icon_changed', function() {
var icon = self.get('icon');
var link;
if (typeof icon === 'string') {
if (icon.indexOf('://') === -1 &&
icon.indexOf('.') === 0) {
link = document.createElement('a');
link.href = icon;
icon = link.protocol+'//'+link.host+link.pathname + link.search;
link = undefined;
}
} else if (typeof icon === 'object' && typeof icon.url === 'string') {
if (icon.url.indexOf('://') === -1 &&
icon.url.indexOf('.') === 0) {
link = document.createElement('a');
link.href = icon.url;
icon.url = link.protocol+'//'+link.host+link.pathname + link.search;
link = undefined;
}
}
if (typeof icon === 'object' &&
typeof icon.anchor === 'object' &&
'x' in icon.anchor &&
'y' in icon.anchor) {
icon.anchor = [icon.anchor.x, icon.anchor.y];
}
self.exec.call(self, null, self.errorHandler, self.getPluginName(), 'setIcon', [self.getId(), icon]);
});
self.on('flat_changed', function() {
var flat = self.get('flat');
flat = flat === true;
self.exec.call(self, null, self.errorHandler, self.getPluginName(), 'setFlat', [self.getId(), flat]);
});
self.on('draggable_changed', function() {
var draggable = self.get('draggable');
draggable = draggable === true;
self.exec.call(self, null, self.errorHandler, self.getPluginName(), 'setDraggable', [self.getId(), draggable]);
});
self.on('anchor_changed', function() {
var anchor = self.get('anchor');
if (!anchor) {
return;
}
self.exec.call(self, null, self.errorHandler, self.getPluginName(), 'setIconAnchor', [self.getId(), anchor[0], anchor[1]]);
});
self.on('infoWindowAnchor_changed', function() {
var anchor = self.get('infoWindowAnchor');
if (!anchor) {
return;
}
self.exec.call(self, null, self.errorHandler, self.getPluginName(), 'setInfoWindowAnchor', [self.getId(), anchor[0], anchor[1]]);
});
self.on('zIndex_changed', function() {
var zIndex = self.get('zIndex');
if (zIndex === null || zIndex === undefined) {
return;
}
self.exec.call(self, null, self.errorHandler, self.getPluginName(), 'setZIndex', [self.getId(), zIndex]);
});
self.on('opacity_changed', function() {
var opacity = self.get('opacity');
self.exec.call(self, null, self.errorHandler, self.getPluginName(), 'setOpacity', [self.getId(), opacity]);
});
self.on('disableAutoPan_changed', function() {
var disableAutoPan = self.get('disableAutoPan');
self.exec.call(self, null, self.errorHandler, self.getPluginName(), 'setDisableAutoPan', [self.getId(), disableAutoPan]);
});
};
utils.extend(Marker, Overlay);
Marker.prototype.remove = function(callback) {
var self = this;
if (self._isRemoved) {
if (typeof callback === 'function') {
return;
} else {
return Promise.resolve();
}
}
Object.defineProperty(self, '_isRemoved', {
value: true,
writable: false
});
self.trigger(event.INFO_CLOSE); // close open infowindow, otherwise it will stay
self.trigger(self.__pgmId + '_remove');
var resolver = function(resolve, reject) {
self.exec.call(self,
function() {
self.destroy();
resolve.call(self);
},
reject.bind(self),
self.getPluginName(), 'remove', [self.getId()], {
remove: true
});
};
if (typeof callback === 'function') {
resolver(callback, self.errorHandler);
} else {
return new Promise(resolver);
}
};
Marker.prototype.getOptions = function() {
var self = this;
return {
'__pgmId': self.getId(),
'position': self.getPosition(),
'disableAutoPan': self.get('disableAutoPan'),
'opacity': self.get('opacity'),
'icon': self.get('icon'),
'zIndex': self.get('zIndex'),
'anchor': self.get('anchor'),
'infoWindowAnchor': self.get('infoWindowAnchor'),
'draggable': self.get('draggable'),
'title': self.getTitle(),
'snippet': self.getSnippet(),
'visible': self.get('visible'),
'rotation': self.getRotation()
};
};
Marker.prototype.getPosition = function() {
var position = this.get('position');
if (!(position instanceof LatLng)) {
return new LatLng(position.lat, position.lng);
}
return position;
};
Marker.prototype.setAnimation = function(animation, callback) {
var self = this;
animation = animation || null;
if (!animation) {
// just ignore
if (typeof callback === 'function') {
return self;
} else {
return Promise.resolve();
}
}
self.set('animation', animation);
var resolver = function(resolve, reject) {
self.exec.call(self,
resolve.bind(self),
reject.bind(self),
self.getPluginName(), 'setAnimation', [self.getId(), animation]);
};
if (typeof callback === 'function') {
resolver(callback, self.errorHandler);
return self;
} else {
return new Promise(resolver);
}
};
Marker.prototype.setDisableAutoPan = function(disableAutoPan) {
disableAutoPan = common.parseBoolean(disableAutoPan);
this.set('disableAutoPan', disableAutoPan);
return this;
};
Marker.prototype.setOpacity = function(opacity) {
if (!opacity && opacity !== 0) {
console.log('opacity value must be int or double');
return false;
}
this.set('opacity', opacity);
return this;
};
Marker.prototype.setZIndex = function(zIndex) {
if (typeof zIndex === 'undefined') {
return false;
}
this.set('zIndex', zIndex);
return this;
};
Marker.prototype.getOpacity = function() {
return this.get('opacity');
};
Marker.prototype.setIconAnchor = function(anchorX, anchorY) {
this.set('anchor', [anchorX, anchorY]);
return this;
};
Marker.prototype.setInfoWindowAnchor = function(anchorX, anchorY) {
this.set('infoWindowAnchor', [anchorX, anchorY]);
return this;
};
Marker.prototype.setDraggable = function(draggable) {
draggable = common.parseBoolean(draggable);
this.set('draggable', draggable);
return this;
};
Marker.prototype.isDraggable = function() {
return this.get('draggable');
};
Marker.prototype.setFlat = function(flat) {
flat = common.parseBoolean(flat);
this.set('flat', flat);
return this;
};
Marker.prototype.setIcon = function(url) {
if (url && common.isHTMLColorString(url)) {
url = common.HTMLColor2RGBA(url);
}
this.set('icon', url);
return this;
};
Marker.prototype.setTitle = function(title) {
if (!title) {
console.log('missing value for title');
return this;
}
title = '' + title; // Convert to strings mandatory
this.set('title', title);
return this;
};
Marker.prototype.setVisible = function(visible) {
visible = common.parseBoolean(visible);
this.set('visible', visible);
if (!visible && this.map.get('active_marker_id') === this.__pgmId) {
this.map.set('active_marker_id', undefined);
}
return this;
};
Marker.prototype.getTitle = function() {
return this.get('title');
};
Marker.prototype.setSnippet = function(snippet) {
this.set('snippet', snippet);
return this;
};
Marker.prototype.getSnippet = function() {
return this.get('snippet');
};
Marker.prototype.setRotation = function(rotation) {
if (typeof rotation !== 'number') {
console.log('missing value for rotation');
return false;
}
this.set('rotation', rotation);
return this;
};
Marker.prototype.getRotation = function() {
return this.get('rotation');
};
Marker.prototype.showInfoWindow = function() {
var self = this;
//if (!self.get('title') && !self.get('snippet') ||
// self.get('isInfoWindowVisible')) {
if (!self.get('title') && !self.get('snippet')) {
return;
}
self.set('isInfoWindowVisible', true);
self.map.set('active_marker_id', self.__pgmId);
self.exec.call(self, null, self.errorHandler, self.getPluginName(), 'showInfoWindow', [self.getId()], {
sync: true
});
return self;
};
Marker.prototype.hideInfoWindow = function() {
var self = this;
if (self.map.get('active_marker_id') === self.__pgmId) {
self.map.set('active_marker_id', null);
}
if (self.get('isInfoWindowVisible')) {
self.set('isInfoWindowVisible', false);
self.exec.call(self, null, self.errorHandler, self.getPluginName(), 'hideInfoWindow', [self.getId()], {
sync: true
});
}
return self;
};
Marker.prototype.isInfoWindowShown = function() {
return this.get('isInfoWindowVisible') === true;
};
Marker.prototype.isVisible = function() {
return this.get('visible') === true;
};
Marker.prototype.setPosition = function(position) {
if (!position) {
console.log('missing value for position');
return false;
}
this.set('position', {
'lat': position.lat,
'lng': position.lng
});
return this;
};
module.exports = Marker;
File diff suppressed because it is too large Load Diff
+120
View File
@@ -0,0 +1,120 @@
var BaseClass = require('./BaseClass'),
utils = require('cordova/utils'),
BaseArrayClass = require('./BaseArrayClass');
/*****************************************************************************
* Overlay Class
*****************************************************************************/
var Overlay = function (map, options, className, _exec, extras) {
extras = extras || {};
BaseClass.apply(this);
var self = this;
//-----------------------------------------------
// Sets the initialize option to each property
//-----------------------------------------------
var ignores = ['map', '__pgmId', 'hashCode', 'type'];
if (extras.ignores) {
ignores = ignores.concat(extras.ignores);
}
for (var key in options) {
if (ignores.indexOf(key) === -1) {
self.set(key, options[key]);
}
}
//-------------------------------------------------------------------------------
// If app code wants to execute some method before `_isReady = true`,
// just stack in to the internal queue.
// If this overlay is ready, execute it.
//-------------------------------------------------------------------------------
var cmdQueue = new BaseArrayClass();
cmdQueue.on('insert_at', function () {
if (!self._isReady) {
return;
}
var cmd;
while (cmdQueue.getLength() > 0) {
cmd = cmdQueue.removeAt(0, true);
if (cmd && cmd.target && cmd.args && cmd.args[0] !== 'nop') {
_exec.apply(cmd.target, cmd.args);
}
}
});
Object.defineProperty(self, '_cmdQueue', {
enumerable: false,
value: cmdQueue,
writable: false
});
Object.defineProperty(self, '_isReady', {
value: false,
writable: true
});
Object.defineProperty(self, 'map', {
value: map,
writable: false
});
Object.defineProperty(self, '__pgmId', {
value: extras.__pgmId || (className.toLowerCase()) + '_' + this.hashCode,
writable: false
});
Object.defineProperty(self, 'type', {
value: className,
writable: false
});
Object.defineProperty(self, 'getPluginName', {
writable: false,
value: function () {
return this.map.getId() + '-' + className.toLowerCase();
}
});
};
utils.extend(Overlay, BaseClass);
Overlay.prototype._privateInitialize = function (options) {
var self = this;
//-----------------------------------------------
// Sets the initialize option to each property
//-----------------------------------------------
if (options) {
var ignores = ['map', '__pgmId', 'hashCode', 'type'];
for (var key in options) {
if (ignores.indexOf(key) === -1) {
self.set(key, options[key], true);
}
}
}
//-----------------------------------------------
// Trigger internal command queue
//-----------------------------------------------
Object.defineProperty(self, '_isReady', {
value: true,
writable: false
});
self.exec('nop');
};
Overlay.prototype.exec = function () {
this._cmdQueue.push.call(this._cmdQueue, {
target: this,
args: Array.prototype.slice.call(arguments, 0)
});
};
Overlay.prototype.getId = function () {
return this.__pgmId;
};
Overlay.prototype.getMap = function () {
return this.map;
};
Overlay.prototype.getHashCode = function () {
return this.hashCode;
};
module.exports = Overlay;
+248
View File
@@ -0,0 +1,248 @@
var utils = require('cordova/utils'),
common = require('./Common'),
Overlay = require('./Overlay');
/*****************************************************************************
* Polygon Class
*****************************************************************************/
var Polygon = function (map, polygonOptions, _exec) {
Overlay.call(this, map, polygonOptions, 'Polygon', _exec);
var self = this;
var polygonId = this.getId();
//--------------------------
// points property
//--------------------------
var pointsProperty = common.createMvcArray(polygonOptions.points);
pointsProperty.on('set_at', function (index) {
var value = common.getLatLng(pointsProperty.getAt(index));
self.exec.call(self, null, self.errorHandler, self.getPluginName(), 'setPointAt', [polygonId, index, value]);
});
pointsProperty.on('insert_at', function (index) {
var value = common.getLatLng(pointsProperty.getAt(index));
self.exec.call(self, null, self.errorHandler, self.getPluginName(), 'insertPointAt', [polygonId, index, value]);
});
pointsProperty.on('remove_at', function (index) {
self.exec.call(self, null, self.errorHandler, self.getPluginName(), 'removePointAt', [polygonId, index]);
});
Object.defineProperty(self, 'points', {
value: pointsProperty,
writable: false
});
//--------------------------
// holes property
//--------------------------
var holesProperty = common.createMvcArray(polygonOptions.holes);
var _holes = common.createMvcArray(holesProperty.getArray());
holesProperty.on('set_at', function (index) {
var value = common.getLatLng(holesProperty.getAt(index));
_holes.setAt(index, value);
});
holesProperty.on('remove_at', function (index) {
_holes.removeAt(index);
});
holesProperty.on('insert_at', function (index) {
var array = holesProperty.getAt(index);
if (array && (array instanceof Array || Array.isArray(array))) {
array = common.createMvcArray(array);
}
array.on('insert_at', function (idx) {
var value = common.getLatLng(array.getAt(idx));
self.exec.call(self, null, self.errorHandler, self.getPluginName(), 'insertPointOfHoleAt', [polygonId, index, idx, value]);
});
array.on('set_at', function (idx) {
var value = common.getLatLng(array.getAt(idx));
self.exec.call(self, null, self.errorHandler, self.getPluginName(), 'setPointOfHoleAt', [polygonId, index, idx, value]);
});
array.on('remove_at', function (idx) {
self.exec.call(self, null, self.errorHandler, self.getPluginName(), 'removePointOfHoleAt', [polygonId, index, idx]);
});
self.exec.call(self, null, self.errorHandler, self.getPluginName(), 'insertHoleAt', [polygonId, index, array.getArray()]);
});
Object.defineProperty(self, 'holes', {
value: holesProperty,
writable: false
});
//--------------------------
// other properties
//--------------------------.
// var ignores = ['map', '__pgmId', 'hashCode', 'type', 'points', 'holes'];
// for (var key in polygonOptions) {
// if (ignores.indexOf(key) === -1) {
// self.set(key, polygonOptions[key]);
// }
// }
//-----------------------------------------------
// Sets event listeners
//-----------------------------------------------
self.on('clickable_changed', function () {
var clickable = self.get('clickable');
self.exec.call(self, null, self.errorHandler, self.getPluginName(), 'setClickable', [self.getId(), clickable]);
});
self.on('geodesic_changed', function () {
var geodesic = self.get('geodesic');
self.exec.call(self, null, self.errorHandler, self.getPluginName(), 'setGeodesic', [self.getId(), geodesic]);
});
self.on('zIndex_changed', function () {
var zIndex = self.get('zIndex');
self.exec.call(self, null, self.errorHandler, self.getPluginName(), 'setZIndex', [self.getId(), zIndex]);
});
self.on('visible_changed', function () {
var visible = self.get('visible');
self.exec.call(self, null, self.errorHandler, self.getPluginName(), 'setVisible', [self.getId(), visible]);
});
self.on('strokeWidth_changed', function () {
var width = self.get('strokeWidth');
self.exec.call(self, null, self.errorHandler, self.getPluginName(), 'setStrokeWidth', [self.getId(), width]);
});
self.on('strokeColor_changed', function () {
var color = self.get('strokeColor');
self.exec.call(self, null, self.errorHandler, self.getPluginName(), 'setStrokeColor', [self.getId(), common.HTMLColor2RGBA(color, 0.75)]);
});
self.on('fillColor_changed', function () {
var color = self.get('fillColor');
self.exec.call(self, null, self.errorHandler, self.getPluginName(), 'setFillColor', [self.getId(), common.HTMLColor2RGBA(color, 0.75)]);
});
};
utils.extend(Polygon, Overlay);
Polygon.prototype.remove = function (callback) {
var self = this;
if (self._isRemoved) {
if (typeof callback === 'function') {
return;
} else {
return Promise.resolve();
}
}
Object.defineProperty(self, '_isRemoved', {
value: true,
writable: false
});
self.trigger(this.__pgmId + '_remove');
var resolver = function(resolve, reject) {
self.exec.call(self,
function() {
self.destroy();
resolve.call(self);
},
reject.bind(self),
self.getPluginName(), 'remove', [self.getId()], {
remove: true
});
};
if (typeof callback === 'function') {
resolver(callback, self.errorHandler);
} else {
return new Promise(resolver);
}
};
Polygon.prototype.setPoints = function (points) {
var self = this;
var mvcArray = self.points;
mvcArray.empty(true);
var i;
for (i = 0; i < points.length; i++) {
mvcArray.push(common.getLatLng(points[i]), true);
}
self.exec.call(self, null, self.errorHandler, self.getPluginName(), 'setPoints', [self.__pgmId, mvcArray.getArray()]);
return self;
};
Polygon.prototype.getPoints = function () {
return this.points;
};
Polygon.prototype.setHoles = function (holes) {
var self = this;
var mvcArray = this.holes;
mvcArray.empty(true);
holes = holes || [];
if (holes.length > 0 && !utils.isArray(holes[0])) {
holes = [holes];
}
holes.forEach(function (hole) {
if (!utils.isArray(hole)) {
hole = [hole];
mvcArray.push(hole, true);
} else {
var newHole = [];
for (var i = 0; i < hole.length; i++) {
newHole.push(common.getLatLng(hole[i]));
}
mvcArray.push(newHole, true);
}
});
self.exec.call(self, null, self.errorHandler, self.getPluginName(), 'setHoles', [self.__pgmId, mvcArray.getArray()]);
return this;
};
Polygon.prototype.getHoles = function () {
return this.holes;
};
Polygon.prototype.setFillColor = function (color) {
this.set('fillColor', color);
return this;
};
Polygon.prototype.getFillColor = function () {
return this.get('fillColor');
};
Polygon.prototype.setStrokeColor = function (color) {
this.set('strokeColor', color);
return this;
};
Polygon.prototype.getStrokeColor = function () {
return this.get('strokeColor');
};
Polygon.prototype.setStrokeWidth = function (width) {
this.set('strokeWidth', width);
return this;
};
Polygon.prototype.getStrokeWidth = function () {
return this.get('strokeWidth');
};
Polygon.prototype.setVisible = function (visible) {
visible = common.parseBoolean(visible);
this.set('visible', visible);
return this;
};
Polygon.prototype.getVisible = function () {
return this.get('visible');
};
Polygon.prototype.setClickable = function (clickable) {
clickable = common.parseBoolean(clickable);
this.set('clickable', clickable);
return this;
};
Polygon.prototype.getClickable = function () {
return this.get('clickable');
};
Polygon.prototype.setGeodesic = function (geodesic) {
geodesic = common.parseBoolean(geodesic);
this.set('geodesic', geodesic);
return this;
};
Polygon.prototype.getGeodesic = function () {
return this.get('geodesic');
};
Polygon.prototype.setZIndex = function (zIndex) {
this.set('zIndex', zIndex);
return this;
};
Polygon.prototype.getZIndex = function () {
return this.get('zIndex');
};
module.exports = Polygon;
+189
View File
@@ -0,0 +1,189 @@
var utils = require('cordova/utils'),
common = require('./Common'),
Overlay = require('./Overlay');
/*****************************************************************************
* Polyline Class
*****************************************************************************/
var Polyline = function (map, polylineOptions, _exec) {
Overlay.call(this, map, polylineOptions, 'Polyline', _exec, {
'ignores': ['points']
});
var self = this;
var polylineId = this.getId();
var pointsProperty = common.createMvcArray(polylineOptions.points);
pointsProperty.on('set_at', function (index) {
if (self._isRemoved) return;
var value = common.getLatLng(pointsProperty.getAt(index));
self.exec.call(self, null, self.errorHandler, self.getPluginName(), 'setPointAt', [polylineId, index, value]);
});
pointsProperty.on('insert_at', function (index) {
if (self._isRemoved) return;
var value = common.getLatLng(pointsProperty.getAt(index));
self.exec.call(self, null, self.errorHandler, self.getPluginName(), 'insertPointAt', [polylineId, index, value]);
});
pointsProperty.on('remove_at', function (index) {
if (self._isRemoved) return;
self.exec.call(self, null, self.errorHandler, self.getPluginName(), 'removePointAt', [polylineId, index]);
});
Object.defineProperty(self, 'points', {
value: pointsProperty,
writable: false
});
//-----------------------------------------------
// Sets the initialize option to each property
//-----------------------------------------------
// var ignores = ['map', '__pgmId', 'hashCode', 'type', 'points'];
// for (var key in polylineOptions) {
// if (ignores.indexOf(key) === -1) {
// self.set(key, polylineOptions[key]);
// }
// }
//-----------------------------------------------
// Sets event listeners
//-----------------------------------------------
self.on('geodesic_changed', function () {
if (self._isRemoved) return;
var geodesic = self.get('geodesic');
self.exec.call(self, null, self.errorHandler, self.getPluginName(), 'setGeodesic', [self.getId(), geodesic]);
});
self.on('zIndex_changed', function () {
if (self._isRemoved) return;
var zIndex = self.get('zIndex');
self.exec.call(self, null, self.errorHandler, self.getPluginName(), 'setZIndex', [self.getId(), zIndex]);
});
self.on('clickable_changed', function () {
if (self._isRemoved) return;
var clickable = self.get('clickable');
self.exec.call(self, null, self.errorHandler, self.getPluginName(), 'setClickable', [self.getId(), clickable]);
});
self.on('visible_changed', function () {
if (self._isRemoved) return;
var visible = self.get('visible');
self.exec.call(self, null, self.errorHandler, self.getPluginName(), 'setVisible', [self.getId(), visible]);
});
self.on('strokeWidth_changed', function () {
if (self._isRemoved) return;
var strokeWidth = self.get('strokeWidth');
self.exec.call(self, null, self.errorHandler, self.getPluginName(), 'setStrokeWidth', [self.getId(), strokeWidth]);
});
self.on('strokeColor_changed', function () {
if (self._isRemoved) return;
var color = self.get('strokeColor');
self.exec.call(self, null, self.errorHandler, self.getPluginName(), 'setStrokeColor', [self.getId(), common.HTMLColor2RGBA(color, 0.75)]);
});
};
utils.extend(Polyline, Overlay);
Polyline.prototype.setPoints = function (points) {
var self = this;
var mvcArray = self.points;
mvcArray.empty(true);
var i;
for (i = 0; i < points.length; i++) {
mvcArray.push({
'lat': points[i].lat,
'lng': points[i].lng
}, true);
}
self.exec.call(self, null, self.errorHandler, self.getPluginName(), 'setPoints', [self.__pgmId, mvcArray.getArray()]);
return self;
};
Polyline.prototype.getPoints = function () {
return this.points;
};
Polyline.prototype.setStrokeColor = function (color) {
this.set('strokeColor', color);
return this;
};
Polyline.prototype.getStrokeColor = function () {
return this.get('strokeColor');
};
Polyline.prototype.setStrokeWidth = function (width) {
this.set('strokeWidth', width);
return this;
};
Polyline.prototype.getStrokeWidth = function () {
return this.get('strokeWidth');
};
Polyline.prototype.setVisible = function (visible) {
visible = common.parseBoolean(visible);
this.set('visible', visible);
return this;
};
Polyline.prototype.getVisible = function () {
return this.get('visible');
};
Polyline.prototype.setClickable = function (clickable) {
clickable = common.parseBoolean(clickable);
this.set('clickable', clickable);
return this;
};
Polyline.prototype.getClickable = function () {
return this.get('clickable');
};
Polyline.prototype.setGeodesic = function (geodesic) {
geodesic = common.parseBoolean(geodesic);
this.set('geodesic', geodesic);
return this;
};
Polyline.prototype.getGeodesic = function () {
return this.get('geodesic');
};
Polyline.prototype.setZIndex = function (zIndex) {
this.set('zIndex', zIndex);
return this;
};
Polyline.prototype.getZIndex = function () {
return this.get('zIndex');
};
Polyline.prototype.remove = function (callback) {
var self = this;
if (self._isRemoved) {
if (typeof callback === 'function') {
return;
} else {
return Promise.resolve();
}
}
Object.defineProperty(self, '_isRemoved', {
value: true,
writable: false
});
var resolver = function (resolve, reject) {
self.exec.call(self,
function () {
self.destroy();
resolve.call(self);
},
reject.bind(self),
self.getPluginName(), 'remove', [self.getId()], {
remove: true
});
};
var result;
if (typeof callback === 'function') {
resolver(callback, self.errorHandler);
} else {
result = new Promise(resolver);
}
if (self.points) {
self.points.empty();
}
self.trigger(self.__pgmId + '_remove');
return result;
};
module.exports = Polyline;
+20
View File
@@ -0,0 +1,20 @@
// Copyright (c) 2013 Forbes Lindesay
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
!function n(t,e,r){function o(u,f){if(!e[u]){if(!t[u]){var c="function"==typeof require&&require;if(!f&&c)return c(u,!0);if(i)return i(u,!0);var s=new Error("Cannot find module '"+u+"'");throw s.code="MODULE_NOT_FOUND",s}var l=e[u]={exports:{}};t[u][0].call(l.exports,function(n){var e=t[u][1][n];return o(e?e:n)},l,l.exports,n,t,e,r)}return e[u].exports}for(var i="function"==typeof require&&require,u=0;u<r.length;u++)o(r[u]);return o}({1:[function(n,t,e){"use strict";function r(){}function o(n){try{return n.then}catch(t){return d=t,w}}function i(n,t){try{return n(t)}catch(e){return d=e,w}}function u(n,t,e){try{n(t,e)}catch(r){return d=r,w}}function f(n){if("object"!=typeof this)throw new TypeError("Promises must be constructed via new");if("function"!=typeof n)throw new TypeError("not a function");this._37=0,this._12=null,this._59=[],n!==r&&v(n,this)}function c(n,t,e){return new n.constructor(function(o,i){var u=new f(r);u.then(o,i),s(n,new p(t,e,u))})}function s(n,t){for(;3===n._37;)n=n._12;return 0===n._37?void n._59.push(t):void y(function(){var e=1===n._37?t.onFulfilled:t.onRejected;if(null===e)return void(1===n._37?l(t.promise,n._12):a(t.promise,n._12));var r=i(e,n._12);r===w?a(t.promise,d):l(t.promise,r)})}function l(n,t){if(t===n)return a(n,new TypeError("A promise cannot be resolved with itself."));if(t&&("object"==typeof t||"function"==typeof t)){var e=o(t);if(e===w)return a(n,d);if(e===n.then&&t instanceof f)return n._37=3,n._12=t,void h(n);if("function"==typeof e)return void v(e.bind(t),n)}n._37=1,n._12=t,h(n)}function a(n,t){n._37=2,n._12=t,h(n)}function h(n){for(var t=0;t<n._59.length;t++)s(n,n._59[t]);n._59=null}function p(n,t,e){this.onFulfilled="function"==typeof n?n:null,this.onRejected="function"==typeof t?t:null,this.promise=e}function v(n,t){var e=!1,r=u(n,function(n){e||(e=!0,l(t,n))},function(n){e||(e=!0,a(t,n))});e||r!==w||(e=!0,a(t,d))}var y=n("asap/raw"),d=null,w={};t.exports=f,f._99=r,f.prototype.then=function(n,t){if(this.constructor!==f)return c(this,n,t);var e=new f(r);return s(this,new p(n,t,e)),e}},{"asap/raw":4}],2:[function(n,t,e){"use strict";function r(n){var t=new o(o._99);return t._37=1,t._12=n,t}var o=n("./core.js");t.exports=o;var i=r(!0),u=r(!1),f=r(null),c=r(void 0),s=r(0),l=r("");o.resolve=function(n){if(n instanceof o)return n;if(null===n)return f;if(void 0===n)return c;if(n===!0)return i;if(n===!1)return u;if(0===n)return s;if(""===n)return l;if("object"==typeof n||"function"==typeof n)try{var t=n.then;if("function"==typeof t)return new o(t.bind(n))}catch(e){return new o(function(n,t){t(e)})}return r(n)},o.all=function(n){var t=Array.prototype.slice.call(n);return new o(function(n,e){function r(u,f){if(f&&("object"==typeof f||"function"==typeof f)){if(f instanceof o&&f.then===o.prototype.then){for(;3===f._37;)f=f._12;return 1===f._37?r(u,f._12):(2===f._37&&e(f._12),void f.then(function(n){r(u,n)},e))}var c=f.then;if("function"==typeof c){var s=new o(c.bind(f));return void s.then(function(n){r(u,n)},e)}}t[u]=f,0===--i&&n(t)}if(0===t.length)return n([]);for(var i=t.length,u=0;u<t.length;u++)r(u,t[u])})},o.reject=function(n){return new o(function(t,e){e(n)})},o.race=function(n){return new o(function(t,e){n.forEach(function(n){o.resolve(n).then(t,e)})})},o.prototype["catch"]=function(n){return this.then(null,n)}},{"./core.js":1}],3:[function(n,t,e){"use strict";function r(){if(c.length)throw c.shift()}function o(n){var t;t=f.length?f.pop():new i,t.task=n,u(t)}function i(){this.task=null}var u=n("./raw"),f=[],c=[],s=u.makeRequestCallFromTimer(r);t.exports=o,i.prototype.call=function(){try{this.task.call()}catch(n){o.onerror?o.onerror(n):(c.push(n),s())}finally{this.task=null,f[f.length]=this}}},{"./raw":4}],4:[function(n,t,e){(function(n){"use strict";function e(n){f.length||(u(),c=!0),f[f.length]=n}function r(){for(;s<f.length;){var n=s;if(s+=1,f[n].call(),s>l){for(var t=0,e=f.length-s;e>t;t++)f[t]=f[t+s];f.length-=s,s=0}}f.length=0,s=0,c=!1}function o(n){var t=1,e=new a(n),r=document.createTextNode("");return e.observe(r,{characterData:!0}),function(){t=-t,r.data=t}}function i(n){return function(){function t(){clearTimeout(e),clearInterval(r),n()}var e=setTimeout(t,0),r=setInterval(t,50)}}t.exports=e;var u,f=[],c=!1,s=0,l=1024,a=n.MutationObserver||n.WebKitMutationObserver;u="function"==typeof a?o(r):i(r),e.requestFlush=u,e.makeRequestCallFromTimer=i}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}],5:[function(n,t,e){"function"!=typeof Promise.prototype.done&&(Promise.prototype.done=function(n,t){var e=arguments.length?this.then.apply(this,arguments):this;e.then(null,function(n){setTimeout(function(){throw n},0)})})},{}],6:[function(n,t,e){n("asap");"undefined"==typeof Promise&&(Promise=n("./lib/core.js"),n("./lib/es6-extensions.js")),n("./polyfill-done.js")},{"./lib/core.js":1,"./lib/es6-extensions.js":2,"./polyfill-done.js":5,asap:3}]},{},[6]);
+320
View File
@@ -0,0 +1,320 @@
var utils = require('cordova/utils'),
common = require('./Common'),
event = require('./event'),
Overlay = require('./Overlay');
/*****************************************************************************
* StreetViewPanorama Class
*****************************************************************************/
var exec;
var StreetViewPanorama = function(streetViewId, _exec) {
exec = _exec;
Overlay.call(this, this, {}, 'StreetViewPanorama', _exec, {
__pgmId: streetViewId
});
var self = this;
self.set('visible', true);
self.set('gesture_panning', true);
self.set('gesture_zoom', true);
self.set('control_navigation', true);
self.set('control_streetNames', true);
self.set('camera_zoom', 0);
self.set('camera_tilt', 0);
self.set('camera_bearing', 0);
//-----------------------------------------------
// Sets event listeners
//-----------------------------------------------
self.on('gesture_panning_changed', function() {
var booleanValue = self.get('gesture_panning');
self.exec.call(self, null, self.errorHandler, self.__pgmId, 'setPanningGesturesEnabled', [booleanValue]);
});
self.on('gesture_zoom_changed', function() {
var booleanValue = self.get('gesture_zoom');
self.exec.call(self, null, self.errorHandler, self.__pgmId, 'setZoomGesturesEnabled', [booleanValue]);
});
self.on('control_navigation_changed', function() {
var booleanValue = self.get('control_navigation');
self.exec.call(self, null, self.errorHandler, self.__pgmId, 'setNavigationEnabled', [booleanValue]);
});
self.on('control_streetNames_changed', function() {
var booleanValue = self.get('control_streetNames');
self.exec.call(self, null, self.errorHandler, self.__pgmId, 'setStreetNamesEnabled', [booleanValue]);
});
self.on('visible_changed', function() {
var booleanValue = self.get('visible');
self.exec.call(self, null, self.errorHandler, self.__pgmId, 'setVisible', [booleanValue]);
});
};
utils.extend(StreetViewPanorama, Overlay);
StreetViewPanorama.prototype.getPluginName = function() {
return this.map.getId() + '-streetview';
};
StreetViewPanorama.prototype.getHashCode = function() {
return this.hashCode;
};
StreetViewPanorama.prototype.getId = function() {
return this.__pgmId;
};
StreetViewPanorama.prototype.getPanorama = function(meta, panorama, div, options) {
var self = this,
args = [meta];
options = options || {};
//self.set('clickable', options.clickable === false ? false : true);
self.set('visible', options.visible === false ? false : true, true);
args.push(options);
// Initial camera options
if ('camera' in options) {
self.set('camera', options.camera, true);
if ('zoom' in options.camera) {
self.set('camera_zoom', options.camera.zoom, true);
}
if ('bearing' in options.camera) {
self.set('camera_bearing', options.camera.bearing, true);
}
if ('tilt' in options.camera) {
self.set('camera_tilt', options.camera.tilt, true);
}
if ('target' in options.camera) {
self.set('position', options.camera.target, true);
}
}
// Gesture options
options.gestures = options.gestures || {};
options.gestures.panning = common.defaultTrueOption(options.gestures.panning);
options.gestures.zoom = common.defaultTrueOption(options.gestures.zoom);
self.set('gesture_panning', options.gestures.panning, true);
self.set('gesture_zoom', options.gestures.zoom, true);
// Controls options
options.controls = options.controls || {};
options.controls.navigation = common.defaultTrueOption(options.controls.navigation);
options.controls.streetNames = common.defaultTrueOption(options.controls.streetNames);
self.set('control_navigation', options.controls.navigation, true);
self.set('control_streetNames', options.controls.streetNames, true);
// Gets the map div size.
// The plugin needs to consider the viewport zoom ratio
// for the case window.innerHTML > body.offsetWidth.
self.set('div', div);
var elemId = common.getPluginDomId(div);
args.push(elemId);
exec.call({
_isReady: true
}, function() {
//------------------------------------------------------------------------
// Clear background colors of map div parents after the map is created
//------------------------------------------------------------------------
var positionCSS;
for (var i = 0; i < div.children.length; i++) {
positionCSS = common.getStyle(div.children[i], 'position');
if (positionCSS === 'static') {
div.children[i].style.position = 'relative';
}
}
//div.insertBefore(self._layers.info, div.firstChild);
while (div.parentNode) {
div.style.backgroundColor = 'rgba(0,0,0,0) !important';
common.attachTransparentClass(div);
div = div.parentNode;
}
cordova.fireDocumentEvent('plugin_touch', {
force: true
});
self._privateInitialize();
delete self._privateInitialize;
self.trigger(event.PANORAMA_READY, self);
}, self.errorHandler, 'CordovaGoogleMaps', 'getPanorama', args, {
sync: true
});
};
StreetViewPanorama.prototype.setVisible = function(isVisible) {
this.set('visible', common.parseBoolean(isVisible));
return this;
};
StreetViewPanorama.prototype.getVisible = function() {
return this.get('visible');
};
StreetViewPanorama.prototype.getDiv = function() {
return this.get('div');
};
StreetViewPanorama.prototype.getMap = function() {
// stub
};
StreetViewPanorama.prototype.setPanningGesturesEnabled = function (boolValue) {
boolValue = common.parseBoolean(boolValue);
this.set('gesture_panning', boolValue);
return this;
};
StreetViewPanorama.prototype.getPanningGesturesEnabled = function () {
return this.get('gesture_panning');
};
StreetViewPanorama.prototype.setZoomGesturesEnabled = function (boolValue) {
boolValue = common.parseBoolean(boolValue);
this.set('gesture_zoom', boolValue);
return this;
};
StreetViewPanorama.prototype.getZoomGesturesEnabled = function () {
return this.get('gesture_zoom');
};
StreetViewPanorama.prototype.setNavigationEnabled = function (boolValue) {
boolValue = common.parseBoolean(boolValue);
this.set('control_navigation', boolValue);
return this;
};
StreetViewPanorama.prototype.getNavigationEnabled = function () {
return this.get('control_navigation');
};
StreetViewPanorama.prototype.setStreetNamesEnabled = function (boolValue) {
boolValue = common.parseBoolean(boolValue);
this.set('control_streetNames', boolValue);
return this;
};
StreetViewPanorama.prototype.getStreetNamesEnabled = function () {
return this.get('control_streetNames');
};
StreetViewPanorama.prototype.getLinks = function () {
return this.get('links');
};
StreetViewPanorama.prototype.getLocation = function () {
return this.get('location');
};
StreetViewPanorama.prototype.getPanoId = function () {
return this.get('pano');
};
StreetViewPanorama.prototype.getPosition = function () {
return this.get('position');
};
StreetViewPanorama.prototype.setPosition = function(cameraPosition, callback) {
var self = this;
cameraPosition = cameraPosition || {};
if (typeof cameraPosition === 'string') {
// case: panorama.setPosition(panoId);
cameraPosition = {
target : cameraPosition
};
}
if (typeof cameraPosition.target === 'object') {
// case: panorama.setPosition({
// target: {lat: ..., lng: ...}
// });
self.set('position', cameraPosition.target);
}
self.exec.call(self, function() {
if (typeof callback === 'function') {
callback.call(self);
}
}, self.errorHandler, self.__pgmId, 'setPosition', [cameraPosition], {
sync: true
});
return this;
};
StreetViewPanorama.prototype.setPov = function(pov, callback) {
var self = this;
pov = pov || {};
if ('zoom' in pov) {
self.set('camera_zoom', pov.zoom);
}
if ('bearing' in pov) {
self.set('camera_bearing', pov.bearing);
}
if ('tilt' in pov) {
self.set('camera_tilt', pov.tilt);
}
self.exec.call(self, function() {
if (typeof callback === 'function') {
callback.call(self);
}
}, self.errorHandler, self.__pgmId, 'setPov', [pov], {
sync: true
});
return this;
};
StreetViewPanorama.prototype.remove = function(callback) {
var self = this;
var resolver = function(resolve, reject) {
self.exec.call(self,
function() {
self.destroy();
resolve.call(self);
},
reject.bind(self),
'CordovaGoogleMaps', 'removeMap', [self.__pgmId], {
sync: true,
remove: true
});
};
if (typeof callback === 'function') {
resolver(callback, self.errorHandler);
} else {
return new Promise(resolver);
}
self.trigger('remove');
};
StreetViewPanorama.prototype._onPanoramaCameraChange = function(eventName, cameraPosition) {
var self = this;
self.set('camera', utils.clone(self.get('camera') || {}, cameraPosition));
self.set('camera_zoom', cameraPosition.zoom);
self.set('camera_bearing', cameraPosition.bearing);
self.set('camera_tilt', cameraPosition.viewAngle || cameraPosition.tilt);
self.set('links', cameraPosition.links || []);
if (self._isReady) {
self._onPanoramaEvent(eventName, cameraPosition);
}
};
StreetViewPanorama.prototype._onPanoramaLocationChange = function(eventName, panoramaLocation) {
var self = this;
self.set('location', panoramaLocation);
self.set('pano', panoramaLocation ? panoramaLocation.panoId : null);
self.set('position', panoramaLocation ? panoramaLocation.latLng : null);
if (self._isReady) {
self._onPanoramaEvent(eventName, panoramaLocation);
}
};
StreetViewPanorama.prototype._onPanoramaEvent = function() {
var self = this;
if (self._isReady) {
var args = Array.prototype.slice.call(arguments, 0);
args.push(self);
self.trigger.apply(self, args);
}
};
module.exports = StreetViewPanorama;
+381
View File
@@ -0,0 +1,381 @@
// Thread.js
// https://threadjs.deep-rain.com
// https://github.com/deep-rain/thread
// Apache License
// Version 2.0, January 2004
// http://www.apache.org/licenses/
//
// TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
//
// 1. Definitions.
//
// 'License' shall mean the terms and conditions for use, reproduction,
// and distribution as defined by Sections 1 through 9 of this document.
//
// 'Licensor' shall mean the copyright owner or entity authorized by
// the copyright owner that is granting the License.
//
// 'Legal Entity' shall mean the union of the acting entity and all
// other entities that control, are controlled by, or are under common
// control with that entity. For the purposes of this definition,
// 'control' means (i) the power, direct or indirect, to cause the
// direction or management of such entity, whether by contract or
// otherwise, or (ii) ownership of fifty percent (50%) or more of the
// outstanding shares, or (iii) beneficial ownership of such entity.
//
// 'You' (or 'Your') shall mean an individual or Legal Entity
// exercising permissions granted by this License.
//
// 'Source' form shall mean the preferred form for making modifications,
// including but not limited to software source code, documentation
// source, and configuration files.
//
// 'Object' form shall mean any form resulting from mechanical
// transformation or translation of a Source form, including but
// not limited to compiled object code, generated documentation,
// and conversions to other media types.
//
// 'Work' shall mean the work of authorship, whether in Source or
// Object form, made available under the License, as indicated by a
// copyright notice that is included in or attached to the work
// (an example is provided in the Appendix below).
//
// 'Derivative Works' shall mean any work, whether in Source or Object
// form, that is based on (or derived from) the Work and for which the
// editorial revisions, annotations, elaborations, or other modifications
// represent, as a whole, an original work of authorship. For the purposes
// of this License, Derivative Works shall not include works that remain
// separable from, or merely link (or bind by name) to the interfaces of,
// the Work and Derivative Works thereof.
//
// 'Contribution' shall mean any work of authorship, including
// the original version of the Work and any modifications or additions
// to that Work or Derivative Works thereof, that is intentionally
// submitted to Licensor for inclusion in the Work by the copyright owner
// or by an individual or Legal Entity authorized to submit on behalf of
// the copyright owner. For the purposes of this definition, 'submitted'
// means any form of electronic, verbal, or written communication sent
// to the Licensor or its representatives, including but not limited to
// communication on electronic mailing lists, source code control systems,
// and issue tracking systems that are managed by, or on behalf of, the
// Licensor for the purpose of discussing and improving the Work, but
// excluding communication that is conspicuously marked or otherwise
// designated in writing by the copyright owner as 'Not a Contribution.'
//
// 'Contributor' shall mean Licensor and any individual or Legal Entity
// on behalf of whom a Contribution has been received by Licensor and
// subsequently incorporated within the Work.
//
// 2. Grant of Copyright License. Subject to the terms and conditions of
// this License, each Contributor hereby grants to You a perpetual,
// worldwide, non-exclusive, no-charge, royalty-free, irrevocable
// copyright license to reproduce, prepare Derivative Works of,
// publicly display, publicly perform, sublicense, and distribute the
// Work and such Derivative Works in Source or Object form.
//
// 3. Grant of Patent License. Subject to the terms and conditions of
// this License, each Contributor hereby grants to You a perpetual,
// worldwide, non-exclusive, no-charge, royalty-free, irrevocable
// (except as stated in this section) patent license to make, have made,
// use, offer to sell, sell, import, and otherwise transfer the Work,
// where such license applies only to those patent claims licensable
// by such Contributor that are necessarily infringed by their
// Contribution(s) alone or by combination of their Contribution(s)
// with the Work to which such Contribution(s) was submitted. If You
// institute patent litigation against any entity (including a
// cross-claim or counterclaim in a lawsuit) alleging that the Work
// or a Contribution incorporated within the Work constitutes direct
// or contributory patent infringement, then any patent licenses
// granted to You under this License for that Work shall terminate
// as of the date such litigation is filed.
//
// 4. Redistribution. You may reproduce and distribute copies of the
// Work or Derivative Works thereof in any medium, with or without
// modifications, and in Source or Object form, provided that You
// meet the following conditions:
//
// (a) You must give any other recipients of the Work or
// Derivative Works a copy of this License; and
//
// (b) You must cause any modified files to carry prominent notices
// stating that You changed the files; and
//
// (c) You must retain, in the Source form of any Derivative Works
// that You distribute, all copyright, patent, trademark, and
// attribution notices from the Source form of the Work,
// excluding those notices that do not pertain to any part of
// the Derivative Works; and
//
// (d) If the Work includes a 'NOTICE' text file as part of its
// distribution, then any Derivative Works that You distribute must
// include a readable copy of the attribution notices contained
// within such NOTICE file, excluding those notices that do not
// pertain to any part of the Derivative Works, in at least one
// of the following places: within a NOTICE text file distributed
// as part of the Derivative Works; within the Source form or
// documentation, if provided along with the Derivative Works; or,
// within a display generated by the Derivative Works, if and
// wherever such third-party notices normally appear. The contents
// of the NOTICE file are for informational purposes only and
// do not modify the License. You may add Your own attribution
// notices within Derivative Works that You distribute, alongside
// or as an addendum to the NOTICE text from the Work, provided
// that such additional attribution notices cannot be construed
// as modifying the License.
//
// You may add Your own copyright statement to Your modifications and
// may provide additional or different license terms and conditions
// for use, reproduction, or distribution of Your modifications, or
// for any such Derivative Works as a whole, provided Your use,
// reproduction, and distribution of the Work otherwise complies with
// the conditions stated in this License.
//
// 5. Submission of Contributions. Unless You explicitly state otherwise,
// any Contribution intentionally submitted for inclusion in the Work
// by You to the Licensor shall be under the terms and conditions of
// this License, without any additional terms or conditions.
// Notwithstanding the above, nothing herein shall supersede or modify
// the terms of any separate license agreement you may have executed
// with Licensor regarding such Contributions.
//
// 6. Trademarks. This License does not grant permission to use the trade
// names, trademarks, service marks, or product names of the Licensor,
// except as required for reasonable and customary use in describing the
// origin of the Work and reproducing the content of the NOTICE file.
//
// 7. Disclaimer of Warranty. Unless required by applicable law or
// agreed to in writing, Licensor provides the Work (and each
// Contributor provides its Contributions) on an 'AS IS' BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied, including, without limitation, any warranties or conditions
// of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
// PARTICULAR PURPOSE. You are solely responsible for determining the
// appropriateness of using or redistributing the Work and assume any
// risks associated with Your exercise of permissions under this License.
//
// 8. Limitation of Liability. In no event and under no legal theory,
// whether in tort (including negligence), contract, or otherwise,
// unless required by applicable law (such as deliberate and grossly
// negligent acts) or agreed to in writing, shall any Contributor be
// liable to You for damages, including any direct, indirect, special,
// incidental, or consequential damages of any character arising as a
// result of this License or out of the use or inability to use the
// Work (including but not limited to damages for loss of goodwill,
// work stoppage, computer failure or malfunction, or any and all
// other commercial damages or losses), even if such Contributor
// has been advised of the possibility of such damages.
//
// 9. Accepting Warranty or Additional Liability. While redistributing
// the Work or Derivative Works thereof, You may choose to offer,
// and charge a fee for, acceptance of support, warranty, indemnity,
// or other liability obligations and/or rights consistent with this
// License. However, in accepting such obligations, You may act only
// on Your own behalf and on Your sole responsibility, not on behalf
// of any other Contributor, and only if You agree to indemnify,
// defend, and hold each Contributor harmless for any liability
// incurred by, or claims asserted against, such Contributor by reason
// of your accepting any such warranty or additional liability.
//
// END OF TERMS AND CONDITIONS
//
// APPENDIX: How to apply the Apache License to your work.
//
// To apply the Apache License to your work, attach the following
// boilerplate notice, with the fields enclosed by brackets '{}'
// replaced with your own identifying information. (Don't include
// the brackets!) The text should be enclosed in the appropriate
// comment syntax for the file format. We also recommend that a
// file or class name and description of purpose be included on the
// same 'printed page' as the copyright notice for easier
// identification within third-party archives.
//
// Copyright 2017 deep-rain.com
//
// Licensed under the Apache License, Version 2.0 (the 'License');
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an 'AS IS' BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Constants
var Type = {
RESOLVE: 'resolve',
NOTIFY: 'notify'
};
var REPLACE_SEQUENCE = '{{#CODE}}';
var CODE = 'onmessage = function(e){ postMessage({type:"' + Type.RESOLVE + '",content:({{#CODE}}).call(this, (e.data ? JSON.parse(e.data) : undefined))});};function notify(c){postMessage({type:"' + Type.NOTIFY + '", content:c})}';
var getEmbeddedCode = function (s) {
return CODE.replace(REPLACE_SEQUENCE, s);
};
module.exports = (function () {
// Deferred class
var Deferred = function () {
this.resolveQueues = [];
this.rejectQueues = [];
this.progressQueues = [];
this.args = null;
this.isDone = false;
this.isFailed = false;
};
Deferred.prototype.done = function (func) {
if (this.isDone) {
func(this.args);
} else {
this.resolveQueues.push(func);
}
return this;
};
Deferred.prototype.fail = function (func) {
if (this.isFailed) {
func(this.args);
} else {
this.rejectQueues.push(func);
}
return this;
};
Deferred.prototype.always = function (func) {
if (this.isFailed || this.isDone) {
func(this.args);
} else {
this.resolveQueues.push(func);
this.rejectQueues.push(func);
}
return this;
};
Deferred.prototype.progress = function (func) {
this.progressQueues.push(func);
};
Deferred.prototype.resolve = function (obj) {
this.isDone = true;
this.args = obj;
this.resolveQueues.forEach(function (q) {
q(obj);
});
return this;
};
Deferred.prototype.notify = function (obj) {
this.progressQueues.forEach(function (q) {
q(obj);
});
};
Deferred.prototype.reject = function (obj) {
this.isFailed = true;
this.args = obj;
this.rejectQueues.forEach(function (q) {
q(obj);
});
return this;
};
// Thread class
var Thread = function (func, depends) {
// check browser
if (!window.Blob ||
!window.URL ||
!window.Worker) {
throw new Error('this browser is not supported');
}
// inject dependent libraries.
depends = depends || [];
if (!(depends instanceof window.Array)) {
depends = [depends];
}
var scripts = '';
if (depends.length > 0) {
scripts = 'importScripts("' + depends.join('','') + '");';
}
// create Blob object.
var blob = new window.Blob([scripts + getEmbeddedCode(func.toString())]);
this.blobUrl = window.URL.createObjectURL(blob);
// greate Worker object.
this.worker = new window.Worker(this.blobUrl);
this.deferred = new Deferred();
// add event listener.
var self = this;
// onmessage
this.worker.addEventListener('message', function (e) {
switch (e.data.type) {
case Type.RESOLVE:
self.deferred.resolve(e.data.content);
return;
case Type.NOTIFY:
self.deferred.notify(e.data.content);
return;
}
});
// onerror
this.worker.addEventListener('error', function (e) {
self.deferred.reject(e);
});
};
Thread.prototype.execute = function (obj) {
if (this.isClosed) {
throw new Error('thread has been closed.');
}
var json = JSON.stringify(obj);
this.worker.postMessage(json);
return this;
};
Thread.prototype.once = function (args) {
var self = this;
this.deferred.always(function () {
self.terminate();
});
this.execute(args);
this.isClosed = true;
return this;
};
Thread.prototype.terminate = function () {
window.URL.revokeObjectURL(this.blobUrl);
this.worker.terminate();
this.worker = null;
this.deferred = null;
this.blobUrl = null;
};
Thread.prototype.done = function (f) {
this.deferred.done(f);
return this;
};
Thread.prototype.fail = function (f) {
this.deferred.fail(f);
return this;
};
Thread.prototype.progress = function (f) {
this.deferred.progress(f);
return this;
};
return Thread;
})();
+119
View File
@@ -0,0 +1,119 @@
var utils = require('cordova/utils'),
common = require('./Common'),
Overlay = require('./Overlay');
/*****************************************************************************
* TileOverlay Class
*****************************************************************************/
var TileOverlay = function (map, tileOverlayOptions, _exec) {
Overlay.call(this, map, tileOverlayOptions, 'TileOverlay', _exec);
var self = this;
//-----------------------------------------------
// Sets event listeners
//-----------------------------------------------
self.on('fadeIn_changed', function () {
var fadeIn = self.get('fadeIn');
self.exec.call(self, null, self.errorHandler, self.getPluginName(), 'setFadeIn', [self.getId(), fadeIn]);
});
self.on('opacity_changed', function () {
var opacity = self.get('opacity');
self.exec.call(self, null, self.errorHandler, self.getPluginName(), 'setOpacity', [self.getId(), opacity]);
});
self.on('zIndex_changed', function () {
var zIndex = self.get('zIndex');
self.exec.call(self, null, self.errorHandler, self.getPluginName(), 'setZIndex', [self.getId(), zIndex]);
});
self.on('visible_changed', function () {
var visible = self.get('visible');
self.exec.call(self, null, self.errorHandler, self.getPluginName(), 'setVisible', [self.getId(), visible]);
});
};
utils.extend(TileOverlay, Overlay);
TileOverlay.prototype.getPluginName = function () {
return this.map.getId() + '-tileoverlay';
};
TileOverlay.prototype.getHashCode = function () {
return this.hashCode;
};
TileOverlay.prototype.getMap = function () {
return this.map;
};
TileOverlay.prototype.getId = function () {
return this.__pgmId;
};
TileOverlay.prototype.getTileSize = function () {
return this.get('tileSize');
};
TileOverlay.prototype.getZIndex = function () {
return this.get('zIndex');
};
TileOverlay.prototype.setZIndex = function (zIndex) {
this.set('zIndex', zIndex);
};
TileOverlay.prototype.setFadeIn = function (fadeIn) {
fadeIn = common.parseBoolean(fadeIn);
this.set('fadeIn', fadeIn);
};
TileOverlay.prototype.getFadeIn = function () {
return this.get('fadeIn');
};
TileOverlay.prototype.setVisible = function (visible) {
visible = common.parseBoolean(visible);
this.set('visible', visible);
};
TileOverlay.prototype.getOpacity = function () {
return this.get('opacity');
};
TileOverlay.prototype.setOpacity = function (opacity) {
if (!opacity && opacity !== 0) {
console.log('opacity value must be int or double');
return false;
}
this.set('opacity', opacity);
};
TileOverlay.prototype.getVisible = function () {
return this.get('visible');
};
TileOverlay.prototype.remove = function (callback) {
var self = this;
if (self._isRemoved) {
if (typeof callback === 'function') {
return;
} else {
return Promise.resolve();
}
}
Object.defineProperty(self, '_isRemoved', {
value: true,
writable: false
});
self.trigger(self.__pgmId + '_remove');
var resolver = function(resolve, reject) {
self.exec.call(self,
function() {
self.destroy();
resolve.call(self);
},
reject.bind(self),
self.getPluginName(), 'remove', [self.getId()], {
remove: true
});
};
if (typeof callback === 'function') {
resolver(callback, self.errorHandler);
} else {
return new Promise(resolver);
}
};
module.exports = TileOverlay;
+66
View File
@@ -0,0 +1,66 @@
var utils = require('cordova/utils'),
LatLngBounds = require('./LatLngBounds');
/*****************************************************************************
* VisibleRegion Class
*****************************************************************************/
var VisibleRegion = function(southwest, northeast, farLeft, farRight, nearLeft, nearRight) {
Object.defineProperty(this, 'type', {
value: 'VisibleRegion',
writable: false
});
this.southwest = southwest;
this.northeast = northeast;
this.farLeft = farLeft;
this.farRight = farRight;
this.nearLeft = nearLeft;
this.nearRight = nearRight;
};
utils.extend(VisibleRegion, LatLngBounds);
delete VisibleRegion.prototype.extend;
delete VisibleRegion.prototype.getCenter;
VisibleRegion.prototype.contains = function(latLng) {
if (!latLng || !('lat' in latLng) || !('lng' in latLng)) {
return false;
}
var y = latLng.lat,
x = latLng.lng;
var y90 = y + 90;
var south = this.southwest.lat,
north = this.northeast.lat,
west = this.southwest.lng,
east = this.northeast.lng;
var south90 = south + 90,
north90 = north + 90;
var containX = false,
containY = false;
if (east >= 0 && west >= east) {
if (x <= 0 && x >= -180) {
containX = true;
} else {
containX = (west <= x && x <= east);
}
} else if (west <= 0 && east <= west) {
containX = (west <= x && x <= east);
if (x >= 0 && x <= 180) {
containX = true;
} else {
containX = (x <= 0 && x <= west || x <= east && x>= -180);
}
} else {
return LatLngBounds.prototype.contains.call(this, latLng);
}
containY = (south90 <= y90 && y90 <= north90) || //#a
(south >= 0 && north <= 0 && ((south <= y && y <= 90) || (y >= -90 && y<= north))); // #d
return containX && containY;
};
module.exports = VisibleRegion;
@@ -0,0 +1,267 @@
// jshint esversion: 6
const BaseArrayClass = require('../BaseArrayClass');
describe('[BaseArrayClass]', () => {
describe('getLength()', () => {
it('should return the same size with initial array', () => {
const initArray = [0, 1, 2];
const _ = new BaseArrayClass(initArray);
expect(_.getLength()).toBe(initArray.length);
});
});
describe('mapSeries()', () => {
it('should keep item order', () => {
const initArray = ['A', 'B', 'C'];
const _ = new BaseArrayClass(initArray);
expect(_.mapSeries((item, next) => {
setTimeout(() => {
next(item);
}, 3 * Math.random());
})).resolves.toEqual(initArray);
});
});
describe('mapAsync()', () => {
it('should keep item order', () => {
const initArray = ['A', 'B', 'C'];
const _ = new BaseArrayClass(initArray);
expect(_.mapAsync((item, next) => {
setTimeout(() => {
next(item);
}, 3 * Math.random());
})).resolves.toEqual(initArray);
});
});
describe('map()', () => {
it('should work as `mapAsync()` if callback is given', (done) => {
const initArray = ['A', 'B', 'C'];
const _ = new BaseArrayClass(initArray);
_.map((item, next) => {
setTimeout(() => {
next(item);
}, 3 * Math.random());
}, (results) => {
expect(results).toEqual(initArray);
done();
});
});
it('should work as `Array.map()` if callback is omitted', () => {
const initArray = ['A', 'B', 'C'];
const _ = new BaseArrayClass(initArray);
expect(_.map((item) => {
return item;
})).toEqual(initArray);
});
});
describe('forEachAsync()', () => {
it('should execute `iteratee` 3 times', (done) => {
const initArray = ['A', 'B', 'C'];
const _ = new BaseArrayClass(initArray);
let i = 0;
_.forEachAsync((item, next) => {
setTimeout(() => {
i++;
next(item);
}, 0);
}).then(() => {
expect(i).toBe(3);
done();
});
});
});
describe('forEach()', () => {
it('should work as `forEach()` if callback is given', (done) => {
let i = 0;
const initArray = ['A', 'B', 'C'];
const _ = new BaseArrayClass(initArray);
_.forEach((item, next) => {
setTimeout(() => {
i++;
next();
}, 3 * Math.random());
}, () => {
expect(i).toBe(3);
done();
});
});
it('should work as `Array.forEach()` if callback is omitted', () => {
let i = 0;
const initArray = ['A', 'B', 'C'];
const _ = new BaseArrayClass(initArray);
_.forEach((item) => {
i++;
});
expect(i).toBe(3);
});
});
describe('filterAsync()', () => {
it('should return [0, 2, 4]', (done) => {
const initArray = [0, 1, 2, 3, 4, 5];
const _ = new BaseArrayClass(initArray);
_.filterAsync((item, next) => {
setTimeout(() => {
next(item % 2 === 0);
}, 5 * Math.random());
}).then((results) => {
expect(results).toEqual([0, 2, 4]);
done();
});
});
});
describe('filter()', () => {
it('should work as `filter()` if callback is given', (done) => {
let i = 0;
const initArray = [0, 1, 2, 3, 4, 5];
const _ = new BaseArrayClass(initArray);
_.filter((item, next) => {
setTimeout(() => {
next(item % 2 !== 0);
}, 3 * Math.random());
}, (results) => {
expect(results).toEqual([1, 3, 5]);
done();
});
});
it('should work as `Array.filter()` if callback is omitted', () => {
const initArray = [
{condition: true},
{condition: false},
{condition: true}
];
const _ = new BaseArrayClass(initArray);
expect(_.filter((item) => {
return item.condition === true;
})).toHaveLength(2);
});
});
describe('indexOf()', () => {
it('should find the first element position', () => {
const initArray = ['Hello', 'World', 'test'];
const _ = new BaseArrayClass(initArray);
expect(_.indexOf('World')).toBe(1);
});
it('should find the second element position', () => {
const initArray = ['Hello', 'World', 'test', 'World'];
const _ = new BaseArrayClass(initArray);
expect(_.indexOf('World', 2)).toBe(3);
});
});
describe('empty()', () => {
it('should delete all elements', () => {
const initArray = ['Hello', 'World', 'test'];
const _ = new BaseArrayClass(initArray);
_.empty();
expect(_.getLength()).toBe(0);
});
});
describe('push()', () => {
it('should add the item to the last', () => {
const initArray = ['Hello', 'World', 'test'];
const _ = new BaseArrayClass(initArray);
_.push('HelloWorld');
expect(_.getAt(3)).toEqual('HelloWorld');
});
});
describe('insertAt()', () => {
it('should add the item at the specified position', () => {
const initArray = ['Hello', 'World', 'test'];
const _ = new BaseArrayClass(initArray);
_.insertAt(1, 'Aloha');
expect(_.getArray()).toEqual(['Hello', 'Aloha', 'World', 'test']);
});
});
describe('getArray()', () => {
it('should return the same array', () => {
const initArray = ['Hello', 'World', 'test'];
const _ = new BaseArrayClass(initArray);
expect(_.getArray()).toEqual(['Hello', 'World', 'test']);
});
});
describe('getAt()', () => {
it('should return the same item at specified position', () => {
const initArray = ['Hello', 'World', 'test'];
const _ = new BaseArrayClass(initArray);
expect(_.getAt(1)).toEqual('World');
});
});
describe('setAt()', () => {
it('should replace the item of specified position', () => {
const initArray = ['Hello', 'World', 'test'];
const _ = new BaseArrayClass(initArray);
_.setAt(0, 'Aloha');
expect(_.getAt(0)).toEqual('Aloha');
});
});
describe('removeAt()', () => {
it('should remove the item of specified position', () => {
const initArray = ['Hello', 'World', 'test'];
const _ = new BaseArrayClass(initArray);
_.removeAt(1);
expect(_.getAt(1)).toEqual('test');
expect(_.getLength()).toBe(2);
});
});
describe('pop()', () => {
it('should return the same item of the last item', () => {
const initArray = ['Hello', 'World', 'test'];
const _ = new BaseArrayClass(initArray);
expect(_.pop()).toEqual('test');
expect(_.getLength()).toBe(2);
});
});
describe('reverse()', () => {
it('should reverse the array', () => {
const initArray = ['Hello', 'World', 'test'];
const _ = new BaseArrayClass(initArray);
_.reverse();
expect(_.getArray()).toEqual(['test', 'World', 'Hello']);
});
});
describe('sort()', () => {
it('should return ["A", "B", "C", "a", "b", "c"]', () => {
const initArray = ['c', 'C', 'A', 'B', 'b', 'a'];
const _ = new BaseArrayClass(initArray);
_.sort();
expect(_.getArray()).toEqual(['A', 'B', 'C', 'a', 'b', 'c']);
});
it('should return ["a", "A", "b", "B", "c", "C"]', () => {
const initArray = ['c', 'C', 'A', 'B', 'b', 'a'];
const _ = new BaseArrayClass(initArray);
_.sort((a, b) => {
const charCodeA = a.charCodeAt(0);
const charCodeB = b.charCodeAt(0);
const lowerA = charCodeA > 96 ? charCodeA - 32 : charCodeA;
const lowerB = charCodeB > 96 ? charCodeB - 32 : charCodeB;
return lowerA === lowerB ? charCodeB - charCodeA : lowerA - lowerB;
});
expect(_.getArray()).toEqual(['a', 'A', 'b', 'B', 'c', 'C']);
});
});
});
+186
View File
@@ -0,0 +1,186 @@
// jshint esversion: 6
const BaseClass = require('../BaseClass');
describe('[BaseClass]', () => {
it('"instanceB.hello" should be "world"', () => {
const instance = new BaseClass();
instance.set('hello', 'world');
expect(instance.get('hello')).toEqual('world');
});
it('"instanceB.anotherHello" should be the same as "instanceA.hello"', () => {
const instanceA = new BaseClass();
const instanceB = new BaseClass();
instanceA.bindTo('hello', instanceB, 'anotherHello');
instanceA.set('hello', 'world');
expect(instanceA.get('hello')).toEqual('world');
expect(instanceB.get('anotherHello')).toEqual('world');
});
it('"instance.one()" should receive "hello_changed" event.', (done) => {
const instance = new BaseClass();
instance.set('hello', 'world');
instance.one('hello_changed', (prevValue, newValue) => {
expect(prevValue).toEqual('world');
expect(newValue).toEqual('Aloha');
done();
});
instance.set('hello', 'Aloha');
});
it('"instance.hasEventListener(\'hello_changed\')"', () => {
const instance = new BaseClass();
instance.on('hello_changed', () => { });
expect(instance.hasEventListener('hello_changed')).toEqual(true);
instance.off('hello_changed');
expect(instance.hasEventListener('hello_changed')).toEqual(false);
});
it('"instance.on()" should receive "hello_changed" event twice.', (done) => {
(new Promise((resolve, reject) => {
const instance = new BaseClass();
const timer = setTimeout(reject, 50); // just in case
let count = 0;
const listener = (prevValue, newValue) => {
count++;
if (count === 2) {
instance.off('hello_changed', listener);
clearTimeout(timer);
resolve(newValue);
}
};
instance.on('hello_changed', listener);
instance.set('hello', '你好'); // should receive
instance.set('hello', 'こんにちは'); // should receive
instance.set('hello', '안녕하세요'); // should not receive
}))
.then((answer) => {
expect(answer).toBe('こんにちは');
done();
});
});
it('"instance.on() then .off()" should receive only one time "hello_changed" event.', (done) => {
(new Promise((resolve, reject) => {
const instance = new BaseClass();
let count = 0;
const listener = () => {
count++;
instance.off('hello_changed', listener);
};
instance.on('hello_changed', listener);
setTimeout(() => {
resolve(count);
}, 10);
for (let i = 0; i < 10; i++) {
instance.set('hello', i);
}
}))
.then((answer) => {
expect(answer).toBe(1);
done();
});
});
it('"instance.off()" should remove all event listeners.', (done) => {
(new Promise((resolve, reject) => {
const instance = new BaseClass();
let called = false;
const dummyListener = () => {
called = true;
};
instance.on('myEvent', dummyListener);
instance.on('myEvent', dummyListener);
instance.on('myEvent', dummyListener);
instance.on('myEvent', dummyListener);
instance.off('myEvent');
instance.trigger('myEvent');
setTimeout(() => {
resolve(called);
}, 10);
}))
.then((answer) => {
expect(answer).toBe(false);
done();
});
});
it('"instance.onThrottled()" should receive event only 3 times.', (done) => {
(new Promise((resolve) => {
let eventCount = 0;
const instance = new BaseClass();
// eventListener should be involved 3 times.
// first time: at 50ms
// second time: at 100ms
// third time: at 150ms
instance.onThrottled('myEvent', (receivedData) => {
eventCount++;
}, 50);
// Trigger event 13 times (takes 130ms)
let sendCount = 0;
const triggerTimer = setInterval(() => {
sendCount++;
instance.trigger('myEvent', sendCount);
if (sendCount > 12) {
clearInterval(triggerTimer);
}
}, 10);
// When 300ms, test should be complited.
setTimeout(() => {
resolve(eventCount);
}, 300);
}))
.then((answer) => {
expect(answer).toBe(3);
done();
});
});
it('"instance.trigger()" should fire a "myEvent" event.', (done) => {
(new Promise((resolve, reject) => {
const timer = setTimeout(reject, 10); // just in case
const instance = new BaseClass();
instance.on('myEvent', (...parameters) => {
clearTimeout(timer);
resolve(parameters);
});
instance.trigger('myEvent', 'data', 1);
}))
.then((receivedData) => {
expect(receivedData[0]).toBe('data');
expect(receivedData[1]).toBe(1);
done();
});
});
it('"instance.empty()" should delete all holded variables.', () => {
const instance = new BaseClass();
instance.set('hello1', 'world');
instance.set('hello2', 'test');
instance.empty();
expect(instance.get('hello1')).toBe(undefined);
expect(instance.get('hello2')).toBe(undefined);
});
});
+120
View File
@@ -0,0 +1,120 @@
// jshint esversion: 6
const Geocoder = require('../Geocoder');
describe('Geocode', () => {
// Initialize them here so that vscode typing
// will work without this being a TS project
let geocoder = new Geocoder();
let execSpy = jest.fn();
beforeEach(() => {
execSpy = jest.fn();
geocoder = new Geocoder(execSpy);
});
it('should exist', () => {
expect(geocoder).toBeDefined();
});
describe('geocode()', () => {
it('should exist', () => {
expect(geocoder.geocode).toBeDefined();
});
it('should return a promise if a callback is not passed', async () => {
const request = {
address: '',
};
const mockResults = [
{
foo: 'bar',
},
];
execSpy.mockImplementation(resolve => {
resolve({
results: mockResults,
});
});
const results = geocoder.geocode(request);
expect(results).toMatchSnapshot();
await expect(results).resolves.toMatchSnapshot();
});
it('should error if both position and address options are provided', async () => {
const request = {
position: [],
address: [],
};
await expect(geocoder.geocode(request)).rejects.toMatchSnapshot();
});
it('should call the if both position and address options are provided', () => {
const request = {
position: [],
address: [],
};
expect(geocoder.geocode(request)).rejects.toMatchSnapshot();
});
describe('single request', () => {
describe('position', () => {
it('should call the native plugin with the correct parameters', () => {
geocoder.geocode({
position: {
lat: 0,
lng: 0,
},
});
expect(execSpy.mock.calls).toMatchSnapshot();
});
});
describe('address', () => {
it('should call the native plugin with the correct parameters', () => {
geocoder.geocode({
address: 'Tokyo, Japan',
});
expect(execSpy.mock.calls).toMatchSnapshot();
});
});
});
describe('multiple request', () => {
describe('position', () => {
it('should call the native plugin with the correct parameters', () => {
geocoder.geocode({
position: [
{
lat: 0,
lng: 0,
},
{
lat: 1,
lng: 1,
},
]
});
expect(execSpy.mock.calls).toMatchSnapshot();
});
});
describe('address1', () => {
it('should call the native plugin with the correct parameters', () => {
geocoder.geocode({
address: [
'Tokyo, Japan',
'Kyoto, Japan',
]
});
expect(execSpy.mock.calls).toMatchSnapshot();
});
});
});
});
});
@@ -0,0 +1,116 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Geocode geocode() multiple request address1 should call the native plugin with the correct parameters 1`] = `
Array [
Array [
[Function],
[Function],
"PluginGeocoder",
"geocode",
Array [
Object {
"address": "Tokyo, Japan",
"idx": 0,
},
],
],
Array [
[Function],
[Function],
"PluginGeocoder",
"geocode",
Array [
Object {
"address": "Kyoto, Japan",
"idx": 1,
},
],
],
]
`;
exports[`Geocode geocode() multiple request position should call the native plugin with the correct parameters 1`] = `
Array [
Array [
[Function],
[Function],
"PluginGeocoder",
"geocode",
Array [
Object {
"idx": 0,
"position": Object {
"lat": 0,
"lng": 0,
},
},
],
],
Array [
[Function],
[Function],
"PluginGeocoder",
"geocode",
Array [
Object {
"idx": 1,
"position": Object {
"lat": 1,
"lng": 1,
},
},
],
],
]
`;
exports[`Geocode geocode() should call the if both position and address options are provided 1`] = `[Error: Invalid request]`;
exports[`Geocode geocode() should error if both position and address options are provided 1`] = `[Error: Invalid request]`;
exports[`Geocode geocode() should return a promise if a callback is not passed 1`] = `Promise {}`;
exports[`Geocode geocode() should return a promise if a callback is not passed 2`] = `
Array [
Object {
"foo": "bar",
},
]
`;
exports[`Geocode geocode() single request address should call the native plugin with the correct parameters 1`] = `
Array [
Array [
[Function],
[Function],
"PluginGeocoder",
"geocode",
Array [
Object {
"address": "Tokyo, Japan",
"idx": -1,
},
],
],
]
`;
exports[`Geocode geocode() single request position should call the native plugin with the correct parameters 1`] = `
Array [
Array [
[Function],
[Function],
"PluginGeocoder",
"geocode",
Array [
Object {
"idx": -1,
"position": Object {
"lat": 0,
"lng": 0,
},
},
],
],
]
`;
+185
View File
@@ -0,0 +1,185 @@
/*****************************************************************************
* Command queue mechanism
* (Save the number of method executing at the same time)
*****************************************************************************/
var cordova_exec = require('cordova/exec'),
common = require('./Common');
var commandQueue = [];
var _isWaitMethod = null;
var _isExecuting = false;
var _executingCnt = 0;
var MAX_EXECUTE_CNT = 10;
var _lastGetMapExecuted = 0;
var _isResizeMapExecuting = false;
// This flag becomes true when the page will be unloaded.
var _stopRequested = false;
function execCmd(success, error, pluginName, methodName, args, execOptions) {
execOptions = execOptions || {};
// The JavaScript special keyword 'this' indicates `who call this function`.
// This execCmd function is executed from overlay instances such as marker.
// So `this` means `overlay` instance.
var overlay = this;
// If the overlay has been already removed from map,
// do not execute any methods on it.
if (overlay._isRemoved && !execOptions.remove) {
console.error('[ignore]' + pluginName + '.' + methodName + ', because removed.');
return true;
}
// If the overlay is not ready in native side,
// do not execute any methods except remove on it.
// This code works for map class especially.
if (!this._isReady && methodName !== 'remove') {
console.error('[ignore]' + pluginName + '.' + methodName + ', because it\'s not ready.');
return true;
}
// Push the method into the commandQueue(FIFO) at once.
commandQueue.push({
'execOptions': execOptions,
'args': [
function() {
//-------------------------------
// success callback
//-------------------------------
if (methodName === 'resizeMap') {
_isResizeMapExecuting = false;
}
// Even if the method was successful,
// but the _stopRequested flag is true,
// do not execute further code.
if (!_stopRequested && success) {
var results = Array.prototype.slice.call(arguments, 0);
common.nextTick(function() {
success.apply(overlay,results);
});
}
// Insert small delays only for `map.getMap()`,
// because if you execute three or four `map.getMap()` at the same time,
// Android OS itself crashes.
// In order to prevent this error, insert small delays.
var delay = 0;
if (methodName === _isWaitMethod) {
if (_isWaitMethod === 'getMap' && Date.now() - _lastGetMapExecuted < 1500) {
delay = 1500;
}
_lastGetMapExecuted = Date.now();
_isWaitMethod = null;
}
setTimeout(function() {
_executingCnt--;
common.nextTick(_exec);
}, delay);
},
function() {
//-------------------------------
// error callback
//-------------------------------
if (methodName === 'resizeMap') {
_isResizeMapExecuting = false;
}
if (!_stopRequested && error) {
var results = Array.prototype.slice.call(arguments, 0);
common.nextTick(function() {
error.apply(overlay,results);
});
}
if (methodName === _isWaitMethod) {
_isWaitMethod = null;
}
_executingCnt--;
common.nextTick(_exec);
},
pluginName, methodName, args]
});
// In order to execute all methods in safe,
// the maps plugin limits the number of execution in a moment to 10.
//
// Note that Cordova-Android drops has also another internal queue,
// and the internal queue drops our statement if the app send too much.
//
// Also executing too much statements at the same time,
// it would cause many errors in native side, such as out-of-memory.
//
// In order to prevent these troubles, the maps plugin limits the number of execution is 10.
if (_isExecuting || _executingCnt >= MAX_EXECUTE_CNT || _isWaitMethod || commandQueue.length === 0) {
return;
}
common.nextTick(_exec);
}
function _exec() {
// You probably wonder why there is this code because it's already simular code at the end of the execCmd function.
//
// Because the commandQueue might change after the last code of the execCmd.
// (And yes, it was occurred.)
// In order to block surely, block the execution again.
if (_isExecuting || _executingCnt >= MAX_EXECUTE_CNT || _isWaitMethod || commandQueue.length === 0) {
return;
}
_isExecuting = true;
// Execute some execution requests (up to 10) from the commandQueue.
var methodName;
while (commandQueue.length > 0 && _executingCnt < MAX_EXECUTE_CNT) {
if (!_stopRequested) {
_executingCnt++;
}
// Pick up the head one.
var commandParams = commandQueue.shift();
methodName = commandParams.args[3];
// If the request is `map.refreshLayout()` and another `map.refreshLayout()` is executing,
// skip it.
// This prevents to execute multiple `map.refreshLayout()` at the same time.
if (methodName === 'resizeMap') {
if (_isResizeMapExecuting) {
_executingCnt--;
continue;
}
_isResizeMapExecuting = true;
}
// If the `_stopRequested` flag is true,
// do not execute any statements except `remove()` or `clear()` methods.
if (_stopRequested && (!commandParams.execOptions.remove || methodName !== 'clear')) {
_executingCnt--;
continue;
}
// Some methods have to block other execution requests, such as `map.clear()`
if (commandParams.execOptions.sync) {
_isWaitMethod = methodName;
cordova_exec.apply(this, commandParams.args);
break;
}
cordova_exec.apply(this, commandParams.args);
}
_isExecuting = false;
}
//----------------------------------------------------
// Stop all executions if the page will be closed.
//----------------------------------------------------
function stopExecution() {
// Request stop all tasks.
_stopRequested = true;
}
window.addEventListener('unload', stopExecution);
module.exports = execCmd;
+96
View File
@@ -0,0 +1,96 @@
var LatLng = require('./LatLng');
var common = require('./Common');
/*****************************************************************************
* geometry Encode / decode points
* http://jsfiddle.net/8nzg7tta/
*****************************************************************************/
//decode function
function decodePath(encoded, precision) {
precision = precision || 5;
precision = Math.pow(10, -precision);
var len = encoded.length,
index = 0,
lat = 0,
lng = 0,
array = [];
while (index < len) {
var b, shift = 0,
result = 0;
do {
b = encoded.charCodeAt(index++) - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
var dlat = ((result & 1) ? ~(result >> 1) : (result >> 1));
lat += dlat;
shift = 0;
result = 0;
do {
b = encoded.charCodeAt(index++) - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
var dlng = ((result & 1) ? ~(result >> 1) : (result >> 1));
lng += dlng;
array.push(new LatLng(lat * precision, lng * precision));
}
return array;
}
//encode functions
function encodePath(points) {
var plat = 0;
var plng = 0;
var encoded_points = '';
points = common.convertToPositionArray(points);
for (var i = 0; i < points.length; ++i) {
encoded_points += encodePoint(plat, plng, points[i].lat, points[i].lng);
plat = points[i].lat;
plng = points[i].lng;
}
return encoded_points;
}
function encodePoint(plat, plng, lat, lng) {
var late5 = Math.round(lat * 1e5);
var plate5 = Math.round(plat * 1e5);
var lnge5 = Math.round(lng * 1e5);
var plnge5 = Math.round(plng * 1e5);
var dlng = lnge5 - plnge5;
var dlat = late5 - plate5;
return encodeSignedNumber(dlat) + encodeSignedNumber(dlng);
}
function encodeSignedNumber(num) {
var sgn_num = num << 1;
if (num < 0) {
sgn_num = ~(sgn_num);
}
return (encodeNumber(sgn_num));
}
function encodeNumber(num) {
var encodeString = '';
while (num >= 0x20) {
encodeString += (String.fromCharCode((0x20 | (num & 0x1f)) + 63));
num >>= 5;
}
encodeString += (String.fromCharCode(num + 63));
return encodeString;
}
module.exports = {
decodePath: decodePath,
encodePath: encodePath
};
+35
View File
@@ -0,0 +1,35 @@
module.exports = {
MAP_READY: 'map_ready',
MAP_CLICK: 'map_click',
MAP_LONG_CLICK: 'map_long_click',
POI_CLICK: 'poi_click',
MY_LOCATION_CLICK: 'my_location_click',
MY_LOCATION_BUTTON_CLICK: 'my_location_button_click',
INDOOR_BUILDING_FOCUSED: 'indoor_building_focused',
INDOOR_LEVEL_ACTIVATED: 'indoor_level_activated',
CAMERA_MOVE_START: 'camera_move_start',
CAMERA_MOVE: 'camera_move',
CAMERA_MOVE_END: 'camera_move_end',
OVERLAY_CLICK: 'overlay_click',
POLYGON_CLICK: 'polygon_click',
POLYLINE_CLICK: 'polyline_click',
CIRCLE_CLICK: 'circle_click',
GROUND_OVERLAY_CLICK: 'groundoverlay_click',
INFO_CLICK: 'info_click',
INFO_LONG_CLICK: 'info_long_click',
INFO_CLOSE: 'info_close',
INFO_OPEN: 'info_open',
MARKER_CLICK: 'marker_click',
MARKER_DRAG: 'marker_drag',
MARKER_DRAG_START: 'marker_drag_start',
MARKER_DRAG_END: 'marker_drag_end',
MAP_DRAG: 'map_drag',
MAP_DRAG_START: 'map_drag_start',
MAP_DRAG_END: 'map_drag_end',
KML_CLICK: 'kml_click',
FUSION_TABLE_CLICK: 'fusion_table_click',
PANORAMA_READY: 'panorama_ready',
PANORAMA_CAMERA_CHANGE: 'panorama_camera_change',
PANORAMA_LOCATION_CHANGE: 'panorama_location_change',
PANORAMA_CLICK: 'panorama_click'
};
+139
View File
@@ -0,0 +1,139 @@
/**
#
# Copyright 2010 Alexandre Gellibert
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
*/
var LatLng = require('./LatLng'),
LatLngBounds = require('./LatLngBounds'),
GEOCELL_GRID_SIZE = 4,
GEOCELL_ALPHABET = '0123456789abcdef';
function computeBox(geocell) {
var subcell_lng_span, subcell_lat_span;
var xy, x, y;
var bbox = _createBoundingBox(90.0, 180.0, -90.0, -180.0);
while(geocell.length > 0) {
//geoChar = geocell.charAt(i);
//pos = GEOCELL_ALPHABET.indexOf(geoChar);
subcell_lng_span = (bbox.getEast() - bbox.getWest()) / GEOCELL_GRID_SIZE;
subcell_lat_span = (bbox.getNorth() - bbox.getSouth()) / GEOCELL_GRID_SIZE;
xy = _subdiv_xy(geocell.charAt(0));
x = xy[0];
y = xy[1];
bbox = _createBoundingBox(bbox.getSouth() + subcell_lat_span * (y + 1),
bbox.getWest() + subcell_lng_span * (x + 1),
bbox.getSouth() + subcell_lat_span * y,
bbox.getWest() + subcell_lng_span * x);
geocell = geocell.substring(1);
}
var sw = new LatLng(bbox.getSouth(), bbox.getWest());
var ne = new LatLng(bbox.getNorth(), bbox.getEast());
var bounds = new LatLngBounds(sw, ne);
return bounds;
}
function _createBoundingBox(north, east, south, west) {
var north_,south_;
if(south > north) {
south_ = north;
north_ = south;
} else {
south_ = south;
north_ = north;
}
return {
northEast: {lat: north_, lng: east},
southWest: {lat: south_, lng: west},
getNorth: function() {
return this.northEast.lat;
},
getSouth: function() {
return this.southWest.lat;
},
getWest: function() {
return this.southWest.lng;
},
getEast: function() {
return this.northEast.lng;
}
};
}
/**
* https://code.google.com/p/geomodel/source/browse/trunk/geo/geocell.py#370
* @param latLng
* @param resolution
* @return
*/
function getGeocell(lat, lng, resolution) {
var cell = '';
var north = 90.0;
var south = -90.0;
var east = 180.0;
var west = -180.0;
var subcell_lng_span, subcell_lat_span;
var x, y;
while(cell.length < resolution + 1) {
subcell_lng_span = (east - west) / GEOCELL_GRID_SIZE;
subcell_lat_span = (north - south) / GEOCELL_GRID_SIZE;
x = Math.min(Math.floor(GEOCELL_GRID_SIZE * (lng - west) / (east - west)), GEOCELL_GRID_SIZE - 1);
y = Math.min(Math.floor(GEOCELL_GRID_SIZE * (lat - south) / (north - south)),GEOCELL_GRID_SIZE - 1);
cell += _subdiv_char(x, y);
south += subcell_lat_span * y;
north = south + subcell_lat_span;
west += subcell_lng_span * x;
east = west + subcell_lng_span;
}
return cell;
}
/*
* Returns the (x, y) of the geocell character in the 4x4 alphabet grid.
*/
function _subdiv_xy(char) {
// NOTE: This only works for grid size 4.
var charI = GEOCELL_ALPHABET.indexOf(char);
return [(charI & 4) >> 1 | (charI & 1) >> 0,
(charI & 8) >> 2 | (charI & 2) >> 1];
}
/**
* Returns the geocell character in the 4x4 alphabet grid at pos. (x, y).
* @return
*/
function _subdiv_char(posX, posY) {
// NOTE: This only works for grid size 4.
return GEOCELL_ALPHABET.charAt(
(posY & 2) << 2 |
(posX & 2) << 1 |
(posY & 1) << 1 |
(posX & 1) << 0);
}
module.exports = {
computeBox: computeBox,
getGeocell: getGeocell
};
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,282 @@
if (!window.Promise) {
window.Promise = require('cordova-plugin-googlemaps.Promise');
}
var common = require('cordova-plugin-googlemaps.Common'),
Map = require('cordova-plugin-googlemaps.Map'),
StreetViewPanorama = require('cordova-plugin-googlemaps.StreetViewPanorama');
function nativeCallback(params) {
var args = params.args || [];
args.unshift(params.evtName);
this[params.callback].apply(this, args);
}
function CordovaGoogleMaps(execCmd) {
var self = this;
self.execCmd = execCmd;
// random unique number
self.saltHash = Math.floor(Math.random() * Date.now());
// Hold map instances.
self.MAPS = {};
self.MAP_CNT = 0;
var removeMapDiv = function(node) {
if (node.hasAttribute('__pluginmapid') && !node.parentNode) {
var mapId = node.getAttribute('__pluginmapid');
var map = self.MAPS[mapId];
if (map) {
map.remove();
delete self.MAPS[mapId];
}
} else {
var childNodes = Array.prototype.slice.call(node.childNodes);
childNodes.forEach(function(child) {
if (child.outerHTML && child.outerHTML.indexOf('__pluginmapid') > -1) {
removeMapDiv(child);
}
});
}
};
//------------------------------------------------------------------------------
// Using MutationObserver, observe only added/removed or style changed elements
//------------------------------------------------------------------------------
var observer = new MutationObserver(function(mutations) {
common.nextTick(function() {
var mutationRecords = Array.prototype.slice.call(mutations, 0);
mutationRecords.forEach(function(record) {
if (record.removedNodes.length > 0) {
record.removeNodes = Array.prototype.slice.call(record.removedNodes, 0);
record.removeNodes.forEach(function(node) {
if (node.outerHTML && node.outerHTML.indexOf('__pluginmapid') > -1) {
removeMapDiv(node);
}
});
}
});
});
});
observer.observe(document.body.parentElement, {
childList: true,
subtree: true
});
}
CordovaGoogleMaps.prototype.getMap = function(div, mapOptions) {
//----------------------------------------------------------------------------
// This procedure return a map instance.
// - usage 1
// plugin.google.maps.Map.getMap(options?) returns a map instance.
//
// - usage 2
// plugin.google.maps.Map.getMap(mapDiv, options?) returns a map instance.
// The generated map follows the mapDiv position and size automatically.
//
// - usage 3 (not good way)
// In order to keep the backward compatibility for v1,
// if the mapDiv has already a map, returns the map instance for the map div.
//----------------------------------------------------------------------------
var self = this,
mapId;
if (common.isDom(div)) {
mapId = div.getAttribute('__pluginMapId');
// Wow, the app specifies the map div that has already another map,
// but the app try to create new map.
// In this case, remove the old map instance automatically.
if (mapId && self.MAPS[mapId].getDiv() !== div) {
var oldMap = self.MAPS[mapId];
if (oldMap.infoWindowLayer) {
var oldDiv = oldMap.getDiv();
oldDiv.removeChild(oldMap.infoWindowLayer);
}
oldMap.remove();
oldMap = undefined;
mapId = undefined;
}
if (mapId && mapId in self.MAPS) {
// Usage 3
// If the map div has already a map,
// return the map instance.
return self.MAPS[mapId];
}
}
if (!mapId) {
mapId = 'map_' + self.MAP_CNT + '_' + self.saltHash;
}
// Create a map instance.
var map = new Map(mapId, self.execCmd);
window.plugin.google.maps[mapId] = nativeCallback.bind(map);
// If the map is removed, clean up the information.
map.one('remove', self._remove.bind(self, mapId));
self.MAP_CNT++;
self.isThereAnyChange = true;
if (div instanceof Promise) {
// This hack code for @ionic-native/google-maps
div.then(function(params) {
self.MAPS[mapId] = map;
params = params || [];
params.unshift(map);
postMapInit.apply(self, params);
});
} else {
// Normal code flow
self.MAPS[mapId] = map;
postMapInit.call(self, map, div, mapOptions);
}
return map;
};
CordovaGoogleMaps.prototype.getPanorama = function(div, streetViewOptions) {
var self = this;
var mapId = 'streetview_' + self.MAP_CNT + '_' + self.saltHash;
// Create a panorama instance.
var panorama = new StreetViewPanorama(mapId, self.execCmd);
// Catch all events for this map instance, then pass to the instance.
// (Don't execute this native callback from your code)
window.plugin.google.maps[mapId] = nativeCallback.bind(panorama);
self.MAP_CNT++;
panorama.one('remove', self._remove.bind(self, mapId));
if (div instanceof Promise) {
// This hack code for @ionic-native/google-maps
div.then(function(params) {
self.MAPS[mapId] = panorama;
params = params || [];
params.unshift(panorama);
postPanoramaInit.apply(self, params);
});
} else {
// Normal code flow
self.MAPS[mapId] = panorama;
postPanoramaInit.call(self, panorama, div, streetViewOptions);
}
return panorama;
};
CordovaGoogleMaps.prototype._remove = function(mapId) {
var self = this;
var map = self.MAPS[mapId];
if (map) {
var div = map.getDiv();
if (!div) {
div = document.querySelector('[__pluginMapId="' + mapId + '"]');
}
if (div) {
div.removeAttribute('__pluginMapId');
}
self.MAPS[mapId].destroy();
}
delete self.MAPS[mapId];
map = undefined;
};
function postPanoramaInit(panorama, div, options) {
var self = this;
var mapId = panorama.getId();
self.isThereAnyChange = true;
if (!common.isDom(div)) {
console.error('[GoogleMaps] You need to specify a dom element(such as <div>) for this method', div);
return;
}
// If the given div is not fully ready, wait a little
if (!common.shouldWatchByNative(div)) {
setTimeout(function() {
common.nextTick(postPanoramaInit.bind(self, panorama, div, options));
}, 50);
return;
}
if (div.offsetWidth < 100 || div.offsetHeight < 100) {
console.error('[GoogleMaps] Minimum container dimention is 100x100 in pixels.', div);
return;
}
// If the mapDiv is specified,
// the native side needs to know the map div position
// before creating the map view.
div.setAttribute('__pluginMapId', mapId);
if (div.offsetWidth < 100 || div.offsetHeight < 100) {
console.error('[GoogleMaps] Minimum container dimention is 100x100 in pixels.', div);
return;
}
var args = Array.prototype.slice.call(arguments, 0);
args.unshift({
__pgmId: mapId
});
// If the mapDiv is specified,
// the native side needs to know the map div position
// before creating the map view.
div.setAttribute('__pluginMapId', mapId);
panorama.getPanorama.apply(panorama, args);
}
function postMapInit(map, div, options) {
var self = this;
var mapId = map.getId();
var args = [];
if (common.isDom(div)) {
// If the given div is not fully ready, wait a little
if (!common.shouldWatchByNative(div)) {
setTimeout(function() {
common.nextTick(postMapInit.bind(self, map, div, options));
}, 50);
return;
}
if (div.offsetWidth < 100 || div.offsetHeight < 100) {
console.error('[GoogleMaps] Minimum container dimention is 100x100 in pixels.', div);
return;
}
// If the mapDiv is specified,
// the native side needs to know the map div position
// before creating the map view.
div.setAttribute('__pluginMapId', mapId);
args.push({
__pgmId: mapId,
depth: 0
});
args.push(div);
if (options) {
args.push(options);
}
map.getMap.apply(map, args);
} else {
args.push({
__pgmId: mapId,
depth: 0
});
args.push(null);
if (options) {
args.push(options);
}
map.getMap.apply(map, args);
}
}
module.exports = CordovaGoogleMaps;
@@ -0,0 +1,163 @@
if (!cordova) {
document.addEventListener('deviceready', function () {
require('cordova/exec')(null, null, 'CordovaGoogleMaps', 'pause', []);
}, {
once: true
});
} else {
var common = require('./Common');
cordova.addConstructor(function () {
if (!window.Cordova) {
window.Cordova = cordova;
}
window.plugin = window.plugin || {};
window.plugin.google = window.plugin.google || {};
window.plugin.google.maps = window.plugin.google.maps || module.exports;
document.addEventListener('deviceready', function () {
// workaround for issue on android-19: Cannot read property 'maps' of undefined
if (!window.plugin) {
console.warn('re-init window.plugin');
window.plugin = window.plugin || {};
}
if (!window.plugin.google) {
console.warn('re-init window.plugin.google');
window.plugin.google = window.plugin.google || {};
}
if (!window.plugin.google.maps) {
console.warn('re-init window.plugin.google.maps');
window.plugin.google.maps = window.plugin.google.maps || module.exports;
}
cordova.exec(null, function (message) {
alert(message);
}, 'PluginEnvironment', 'isAvailable', ['']);
}, {
once: true
});
});
var execCmd = require('./commandQueueExecutor');
var cordovaGoogleMaps = new(require('./js_CordovaGoogleMaps'))(execCmd);
(new Promise(function (resolve) {
var wait = function () {
if (document.body) {
wait = undefined;
cordovaGoogleMaps.trigger('start');
resolve();
} else {
setTimeout(wait, 50);
}
};
wait();
})).then(function () {
// The pluginInit.js must execute before loading HTML is completed.
require('./pluginInit')();
common.nextTick(function () {
// If the developer needs to recalculate the DOM tree graph,
// use `cordova.fireDocumentEvent('plugin_touch')`
document.addEventListener('plugin_touch', cordovaGoogleMaps.invalidate.bind(cordovaGoogleMaps));
// Repositioning 30 times when the device orientaion is changed.
window.addEventListener('orientationchange', cordovaGoogleMaps.followMaps.bind(cordovaGoogleMaps, {
target: document.body
}));
// If <body> is not ready yet, wait 25ms, then execute this function again.
// if (!document.body || !document.body.firstChild) {
// common.nextTick(arguments.callee, 25);
// return;
// }
document.addEventListener('transitionstart', cordovaGoogleMaps.followMaps.bind(cordovaGoogleMaps), {
capture: true
});
document.body.parentNode.addEventListener('transitionend', cordovaGoogleMaps.onTransitionEnd.bind(cordovaGoogleMaps), {
capture: true
});
// document.body.addEventListener('transitionend', function(e) {
// if (!e.target.hasAttribute('__pluginDomId')) {
// return;
// }
// cordovaGoogleMaps.invalidateN(5);
// }, true);
// If the `scroll` event is ocurred on the observed element,
// adjust the position and size of the map view
document.body.parentNode.addEventListener('scroll', cordovaGoogleMaps.followMaps.bind(cordovaGoogleMaps), true);
window.addEventListener('resize', function () {
cordovaGoogleMaps.transforming = true;
cordovaGoogleMaps.onTransitionFinish.call(cordovaGoogleMaps);
}, true);
});
});
/*****************************************************************************
* Name space
*****************************************************************************/
/** @namespace plugin.google.maps */
module.exports = {
event: require('./event'),
Animation: {
BOUNCE: 'BOUNCE',
DROP: 'DROP'
},
BaseClass: require('./BaseClass'),
BaseArrayClass: require('./BaseArrayClass'),
/** @namespace plugin.google.maps.Map */
Map: {
/**
* @function getMap
* @memberof plugin.google.maps.Map
* @static
*/
getMap: cordovaGoogleMaps.getMap.bind(cordovaGoogleMaps)
},
/** @namespace plugin.google.maps.StreetView */
StreetView: {
/**
* @function getPanorama
* @memberof plugin.google.maps.StreetView
* @static
*/
getPanorama: cordovaGoogleMaps.getPanorama.bind(cordovaGoogleMaps),
/**
* @readonly
* @enum {string}
* @memberof plugin.google.maps.StreetView
* @static
*/
Source: {
/**
* Search panorama inside and outdoor
*/
DEFAULT: 'DEFAULT',
/**
* Search panorama inside and outdoor
*/
OUTDOOR: 'OUTDOOR'
}
},
HtmlInfoWindow: require('./HtmlInfoWindow'),
LatLng: require('./LatLng'),
LatLngBounds: require('./LatLngBounds'),
MapTypeId: require('./MapTypeId'),
environment: require('./Environment'),
Geocoder: require('./Geocoder')(execCmd),
LocationService: require('./LocationService')(execCmd),
geometry: {
encoding: require('./encoding'),
spherical: require('./spherical'),
poly: require('./poly')
}
};
}
@@ -0,0 +1,46 @@
var event = require('cordova-plugin-googlemaps.event'),
BaseClass = require('cordova-plugin-googlemaps.BaseClass'),
BaseArrayClass = require('cordova-plugin-googlemaps.BaseArrayClass'),
execCmd = require('cordova-plugin-googlemaps.commandQueueExecutor'),
cordovaGoogleMaps = new(require('cordova-plugin-googlemaps.js_CordovaGoogleMaps'))(execCmd);
module.exports = {
event: event,
Animation: {
BOUNCE: 'BOUNCE',
DROP: 'DROP'
},
BaseClass: BaseClass,
BaseArrayClass: BaseArrayClass,
Map: {
getMap: cordovaGoogleMaps.getMap.bind(cordovaGoogleMaps)
},
StreetView: {
getPanorama: cordovaGoogleMaps.getPanorama.bind(cordovaGoogleMaps),
Source: {
DEFAULT: 'DEFAULT',
OUTDOOR: 'OUTDOOR'
}
},
HtmlInfoWindow: require('cordova-plugin-googlemaps.HtmlInfoWindow'),
LatLng: require('cordova-plugin-googlemaps.LatLng'),
LatLngBounds: require('cordova-plugin-googlemaps.LatLngBounds'),
MapTypeId: require('cordova-plugin-googlemaps.MapTypeId'),
environment: require('cordova-plugin-googlemaps.Environment'),
Geocoder: require('cordova-plugin-googlemaps.Geocoder')(execCmd),
LocationService: require('cordova-plugin-googlemaps.LocationService')(execCmd),
geometry: {
encoding: require('cordova-plugin-googlemaps.encoding'),
spherical: require('cordova-plugin-googlemaps.spherical'),
poly: require('cordova-plugin-googlemaps.poly')
}
};
cordova.addConstructor(function () {
if (!window.Cordova) {
window.Cordova = cordova;
}
window.plugin = window.plugin || {};
window.plugin.google = window.plugin.google || {};
window.plugin.google.maps = window.plugin.google.maps || module.exports;
});
+169
View File
@@ -0,0 +1,169 @@
var cordova_exec = require('cordova/exec'),
common = require('cordova-plugin-googlemaps.Common');
function pluginInit() {
//-------------------------------------------------------------
// In some older browsers do not implement these methods.
// For example, Android 4.4 does not have Array.map()
//
// But this plugin needs them.
// That's why if the browser does not have it, implement it.
//-------------------------------------------------------------
if (typeof Array.prototype.forEach !== 'function') {
(function () {
Array.prototype.forEach = function (fn, thisArg) {
thisArg = thisArg || this;
for (var i = 0; i < this.length; i++) {
fn.call(thisArg, this[i], i, this);
}
};
})();
}
if (typeof Array.prototype.filter !== 'function') {
(function () {
Array.prototype.filter = function (fn, thisArg) {
thisArg = thisArg || this;
var results = [];
for (var i = 0; i < this.length; i++) {
if (fn.call(thisArg, this[i], i, this) === true) {
results.push(this[i]);
}
}
return results;
};
})();
}
if (typeof Array.prototype.map !== 'function') {
(function () {
Array.prototype.map = function (fn, thisArg) {
thisArg = thisArg || this;
var results = [];
for (var i = 0; i < this.length; i++) {
results.push(fn.call(thisArg, this[i], i, this));
}
return results;
};
})();
}
/*****************************************************************************
* To prevent strange things happen,
* disable the changing of viewport zoom level by double clicking.
* This code has to run before the device ready event.
*****************************************************************************/
var viewportTag = null;
var metaTags = document.getElementsByTagName('meta');
for (var i = 0; i < metaTags.length; i++) {
if (metaTags[i].getAttribute('name') === 'viewport') {
viewportTag = metaTags[i];
break;
}
}
if (!viewportTag) {
viewportTag = document.createElement('meta');
viewportTag.setAttribute('name', 'viewport');
}
var viewportTagContent = 'width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no';
//
// Detect support for CSS env() variable
//
var envTestDiv = '<div id="envTest" style="margin-top:-99px;margin-top:constant(safe-area-inset-top);margin-top:env(safe-area-inset-top);position:absolute;z-index:-1;"></div>';
document.body.insertAdjacentHTML('afterbegin', envTestDiv);
var testElement = document.getElementById('envTest');
var testResult = common.getStyle(testElement, 'margin-top');
document.body.removeChild(testElement);
// if browser supports env(), returns a pixel value as string, even if 0px
if (testResult != '-99px') {
viewportTagContent += ', viewport-fit=cover';
}
// Update viewport tag attribute
viewportTag.setAttribute('content', viewportTagContent);
/*****************************************************************************
* Prevent background, background-color, background-image properties
*****************************************************************************/
var cssAdjuster = document.createElement('style');
cssAdjuster.setAttribute('type', 'text/css');
cssAdjuster.innerText = [
'html, body, ._gmaps_cdv_ {',
' background-image: none !important;',
' background: rgba(0,0,0,0) none !important;',
' background-color: rgba(0,0,0,0) !important;',
'}',
'._gmaps_cdv_ .nav-decor {',
' background-color: rgba(0,0,0,0) !important;',
' background: rgba(0,0,0,0) none !important;',
' display:none !important;',
'}',
'.framework7-root .page-previous {',
' display:none !important;',
'}'
].join('');
document.head.appendChild(cssAdjuster);
// I guess no longer necessary this code at 2018/March
// //----------------------------------------------
// // Set transparent mandatory for older browser
// // http://stackoverflow.com/a/3485654/697856
// //----------------------------------------------
// if(document.body){
// document.body.style.backgroundColor = 'rgba(0,0,0,0)';
// //document.body.style.display='none';
// document.body.offsetHeight;
// //document.body.style.display='';
// }
//--------------------------------------------
// Hook the backbutton of Android action
//--------------------------------------------
var anotherBackbuttonHandler = null;
function onBackButton(e) {
// Check DOM tree for new page
cordova.fireDocumentEvent('plugin_touch', {
force: true
});
if (anotherBackbuttonHandler) {
// anotherBackbuttonHandler must handle the page moving transaction.
// The plugin does not take care anymore if another callback is registered.
anotherBackbuttonHandler(e);
} else {
cordova_exec(null, null, 'CordovaGoogleMaps', 'backHistory', []);
}
}
document.addEventListener('backbutton', onBackButton);
var _org_addEventListener = document.addEventListener;
var _org_removeEventListener = document.removeEventListener;
document.addEventListener = function (eventName, callback) {
var args = Array.prototype.slice.call(arguments, 0);
if (eventName.toLowerCase() !== 'backbutton') {
_org_addEventListener.apply(this, args);
return;
}
if (!anotherBackbuttonHandler) {
anotherBackbuttonHandler = callback;
}
};
document.removeEventListener = function (eventName, callback) {
var args = Array.prototype.slice.call(arguments, 0);
if (eventName.toLowerCase() !== 'backbutton') {
_org_removeEventListener.apply(this, args);
return;
}
if (anotherBackbuttonHandler === callback) {
anotherBackbuttonHandler = null;
}
};
}
module.exports = pluginInit;
+106
View File
@@ -0,0 +1,106 @@
var LatLngBounds = require('./LatLngBounds'),
BaseArrayClass = require('./BaseArrayClass');
function containsLocation(latLng, path) {
if ('lat' in latLng === false ||
'lng' in latLng === false) {
return false;
}
if (path instanceof BaseArrayClass) {
path = path.getArray();
}
var points = JSON.parse(JSON.stringify(path));
var first = points[0],
last = points[points.length - 1];
if (first.lat !== last.lat || first.lng !== last.lng) {
points.push({
lat: first.lat,
lng: first.lng
});
}
var point = {
lat: latLng.lat,
lng: latLng.lng
};
var wn = 0,
bounds = new LatLngBounds(points),
sw = bounds.southwest,
ne = bounds.northeast,
offsetLng360 = sw.lng <= 0 && ne.lng >= 0 && sw.lng < ne.lng ? 360 : 0;
sw.lng += offsetLng360;
point.lng += offsetLng360;
points = points.map(function(vertex) {
vertex.lng += +offsetLng360;
return vertex;
});
var vt, a, b;
for (var i = 0; i < points.length - 1; i++) {
a = points[i];
b = points[i + 1];
if ((a.lat <= point.lat) && (b.lat > point.lat)) {
vt = (point.lat - a.lat) / (b.lat - a.lat);
if (point.lng < (a.lng + (vt * (b.lng - a.lng)))) {
wn++;
}
} else if ((a.lat > point.lat) && (b.lat <= point.lat)) {
vt = (point.lat - a.lat) / (b.lat - a.lat);
if (point.lng < (a.lng + (vt * (b.lng - a.lng)))) {
wn--;
}
}
}
return (wn !== 0);
}
function isLocationOnEdge(latLng, path) {
if ('lat' in latLng === false ||
'lng' in latLng === false) {
return false;
}
var Sx, Sy;
var p0, p1;
var point = {'lat': latLng.lat, 'lng': latLng.lng};
if (path instanceof BaseArrayClass) {
path = path.getArray();
}
var points = JSON.parse(JSON.stringify(path));
var bounds = new LatLngBounds(points),
sw = bounds.southwest,
ne = bounds.northeast,
offsetLng360 = sw.lng <= 0 && ne.lng >= 0 && sw.lng < ne.lng ? 360 : 0;
point.lng += offsetLng360;
points = points.map(function(vertex) {
vertex.lng += offsetLng360;
return vertex;
});
p0 = points[0];
for (var i = 1; i < points.length; i++) {
p1 = points[i];
Sx = (point.lng - p0.lng) / (p1.lng - p0.lng);
Sy = (point.lat - p0.lat) / (p1.lat - p0.lat);
if (Math.abs(Sx - Sy) < 0.05 && Sx < 1 && Sx > 0) {
return true;
}
p0 = p1;
}
return false;
}
module.exports = {
containsLocation: containsLocation,
isLocationOnEdge: isLocationOnEdge
};
+281
View File
@@ -0,0 +1,281 @@
var LatLng = require('./LatLng');
var common = require('./Common');
var EARTH_RADIUS = 6371009;
/**
* Port from android-maps-utils
* https://github.com/googlemaps/android-maps-utils/blob/master/library/src/com/google/maps/android/SphericalUtil.java
*/
/**
* Returns the non-negative remainder of x / m.
* @param x The operand.
* @param m The modulus.
*/
function mod(x, m) {
return ((x % m) + m) % m;
}
/**
* Wraps the given value into the inclusive-exclusive interval between min and max.
* @param n The value to wrap.
* @param min The minimum.
* @param max The maximum.
*/
function wrap(n, min, max) {
return (n >= min && n < max) ? n : (mod(n - min, max - min) + min);
}
/**
* Returns haversine(angle-in-radians).
* hav(x) == (1 - cos(x)) / 2 == sin(x / 2)^2.
*/
function hav(x) {
var sinHalf = Math.sin(x * 0.5);
return sinHalf * sinHalf;
}
/**
* Computes inverse haversine. Has good numerical stability around 0.
* arcHav(x) == acos(1 - 2 * x) == 2 * asin(sqrt(x)).
* The argument must be in [0, 1], and the result is positive.
*/
function arcHav(x) {
return 2 * Math.asin(Math.sqrt(x));
}
/**
* Returns hav() of distance from (lat1, lng1) to (lat2, lng2) on the unit sphere.
*/
function havDistance(lat1, lat2, dLng) {
return hav(lat1 - lat2) + hav(dLng) * Math.cos(lat1) * Math.cos(lat2);
}
/**
* Returns distance on the unit sphere; the arguments are in radians.
*/
function distanceRadians(lat1, lng1, lat2, lng2) {
return arcHav(havDistance(lat1, lat2, lng1 - lng2));
}
/**
* Returns the angle between two LatLngs, in radians. This is the same as the distance
* on the unit sphere.
*/
function computeAngleBetween(from, to) {
return distanceRadians(toRadians(from.lat), toRadians(from.lng),
toRadians(to.lat), toRadians(to.lng));
}
/**
* Returns the distance between two LatLngs, in meters.
*/
function computeDistanceBetween(from, to) {
return computeAngleBetween(from, to) * EARTH_RADIUS;
}
/**
* Returns the distance between two LatLngs, in meters.
*/
function computeOffset(from, distance, heading) {
distance /= EARTH_RADIUS;
heading = toRadians(heading);
// http://williams.best.vwh.net/avform.htm#LL
var fromLat = toRadians(from.lat);
var fromLng = toRadians(from.lng);
var cosDistance = Math.cos(distance);
var sinDistance = Math.sin(distance);
var sinFromLat = Math.sin(fromLat);
var cosFromLat = Math.cos(fromLat);
var sinLat = cosDistance * sinFromLat + sinDistance * cosFromLat * Math.cos(heading);
var dLng = Math.atan2(
sinDistance * cosFromLat * Math.sin(heading),
cosDistance - sinFromLat * sinLat);
return new LatLng(toDegrees(Math.asin(sinLat)), toDegrees(fromLng + dLng));
}
function toRadians(d) {
return d * Math.PI / 180;
}
function toDegrees(r) {
return r * 180 / Math.PI;
}
/*
* Returns the signed area of a closed path on a sphere of given radius.
*/
function computeSignedArea(path) {
var radius = EARTH_RADIUS;
path = common.convertToPositionArray(path);
var size = path.length;
if (size < 3) {
return 0;
}
var total = 0;
var prev = path[size - 1];
var prevTanLat = Math.tan((Math.PI / 2 - toRadians(prev.lat)) / 2);
var prevLng = toRadians(prev.lng);
// For each edge, accumulate the signed area of the triangle formed by the North Pole
// and that edge ("polar triangle").
path.forEach(function (position) {
var tanLat = Math.tan((Math.PI / 2 - toRadians(position.lat)) / 2);
var lng = toRadians(position.lng);
total += polarTriangleArea(tanLat, lng, prevTanLat, prevLng);
prevTanLat = tanLat;
prevLng = lng;
});
return total * (radius * radius);
}
/*
* Returns the signed area of a triangle which has North Pole as a vertex.
* Formula derived from "Area of a spherical triangle given two edges and the included angle"
* as per "Spherical Trigonometry" by Todhunter, page 71, section 103, point 2.
* See http://books.google.com/books?id=3uBHAAAAIAAJ&pg=PA71
* The arguments named "tan" are tan((pi/2 - latitude)/2).
*/
function polarTriangleArea(tan1, lng1, tan2, lng2) {
var deltaLng = lng1 - lng2;
var t = tan1 * tan2;
return 2 * Math.atan2(t * Math.sin(deltaLng), 1 + t * Math.cos(deltaLng));
}
function computeArea(path) {
return Math.abs(computeSignedArea(path));
}
/**
* Returns the heading from one LatLng to another LatLng. Headings are
* expressed in degrees clockwise from North within the range [-180,180).
* @return The heading in degrees clockwise from north.
*/
function computeHeading(from, to) {
// http://williams.best.vwh.net/avform.htm#Crs
var fromLat = toRadians(from.lat);
var fromLng = toRadians(from.lng);
var toLat = toRadians(to.lat);
var toLng = toRadians(to.lng);
var dLng = toLng - fromLng;
var heading = Math.atan2(
Math.sin(dLng) * Math.cos(toLat),
Math.cos(fromLat) * Math.sin(toLat) - Math.sin(fromLat) * Math.cos(toLat) * Math.cos(dLng));
return wrap(toDegrees(heading), -180, 180);
}
/**
* Returns the location of origin when provided with a LatLng destination,
* meters travelled and original heading. Headings are expressed in degrees
* clockwise from North. This function returns null when no solution is
* available.
* @param to The destination LatLng.
* @param distance The distance travelled, in meters.
* @param heading The heading in degrees clockwise from north.
*/
function computeOffsetOrigin(to, distance, heading) {
heading = toRadians(heading);
distance /= EARTH_RADIUS;
// http://lists.maptools.org/pipermail/proj/2008-October/003939.html
var n1 = Math.cos(distance);
var n2 = Math.sin(distance) * Math.cos(heading);
var n3 = Math.sin(distance) * Math.sin(heading);
var n4 = Math.sin(toRadians(to.lat));
// There are two solutions for b. b = n2 * n4 +/- sqrt(), one solution results
// in the latitude outside the [-90, 90] range. We first try one solution and
// back off to the other if we are outside that range.
var n12 = n1 * n1;
var discriminant = n2 * n2 * n12 + n12 * n12 - n12 * n4 * n4;
if (discriminant < 0) {
// No real solution which would make sense in LatLng-space.
return null;
}
var b = n2 * n4 + Math.sqrt(discriminant);
b /= n1 * n1 + n2 * n2;
var a = (n4 - n2 * b) / n1;
var fromLatRadians = Math.atan2(a, b);
if (fromLatRadians < -Math.PI / 2 || fromLatRadians > Math.PI / 2) {
b = n2 * n4 - Math.sqrt(discriminant);
b /= n1 * n1 + n2 * n2;
fromLatRadians = Math.atan2(a, b);
}
if (fromLatRadians < -Math.PI / 2 || fromLatRadians > Math.PI / 2) {
// No solution which would make sense in LatLng-space.
return null;
}
var fromLngRadians = toRadians(to.lng) -
Math.atan2(n3, n1 * Math.cos(fromLatRadians) - n2 * Math.sin(fromLatRadians));
return new LatLng(toDegrees(fromLatRadians), toDegrees(fromLngRadians));
}
/**
* Returns the LatLng which lies the given fraction of the way between the
* origin LatLng and the destination LatLng.
* @param from The LatLng from which to start.
* @param to The LatLng toward which to travel.
* @param fraction A fraction of the distance to travel.
* @return The interpolated LatLng.
*/
function interpolate(from, to, fraction) {
// http://en.wikipedia.org/wiki/Slerp
var fromLat = toRadians(from.lat);
var fromLng = toRadians(from.lng);
var toLat = toRadians(to.lat);
var toLng = toRadians(to.lng);
var cosFromLat = Math.cos(fromLat);
var cosToLat = Math.cos(toLat);
// Computes Spherical interpolation coefficients.
var angle = computeAngleBetween(from, to);
var sinAngle = Math.sin(angle);
if (sinAngle < 1E-6) {
return from;
}
var a = Math.sin((1 - fraction) * angle) / sinAngle;
var b = Math.sin(fraction * angle) / sinAngle;
// Converts from polar to vector and interpolate.
var x = a * cosFromLat * Math.cos(fromLng) + b * cosToLat * Math.cos(toLng);
var y = a * cosFromLat * Math.sin(fromLng) + b * cosToLat * Math.sin(toLng);
var z = a * Math.sin(fromLat) + b * Math.sin(toLat);
// Converts interpolated vector back to polar.
var lat = Math.atan2(z, Math.sqrt(x * x + y * y));
var lng = Math.atan2(y, x);
return new LatLng(toDegrees(lat), toDegrees(lng));
}
/**
* Returns the length of the given path, in meters, on Earth.
*/
function computeLength(path) {
path = common.convertToPositionArray(path);
if (path.length < 2) {
return 0;
}
var length = 0;
var prev = path[0];
var prevLat = toRadians(prev.lat);
var prevLng = toRadians(prev.lng);
path.forEach(function (point) {
var lat = toRadians(point.lat);
var lng = toRadians(point.lng);
length += distanceRadians(prevLat, prevLng, lat, lng);
prevLat = lat;
prevLng = lng;
});
return length * EARTH_RADIUS;
}
module.exports = {
computeDistanceBetween: computeDistanceBetween,
computeOffset: computeOffset,
computeOffsetOrigin: computeOffsetOrigin,
computeArea: computeArea,
computeSignedArea: computeSignedArea,
computeHeading: computeHeading,
interpolate: interpolate,
computeLength: computeLength
};