cordova.define("cordova-plugin-googlemaps.Map", function(require, exports, module) { var utils = require('cordova/utils'), cordova_exec = require('cordova/exec'), common = require('./Common'), Overlay = require('./Overlay'), BaseClass = require('./BaseClass'), BaseArrayClass = require('./BaseArrayClass'), LatLng = require('./LatLng'), MapTypeId = require('./MapTypeId'), event = require('./event'), VisibleRegion = require('./VisibleRegion'), Marker = require('./Marker'), Circle = require('./Circle'), Polyline = require('./Polyline'), Polygon = require('./Polygon'), TileOverlay = require('./TileOverlay'), GroundOverlay = require('./GroundOverlay'), KmlOverlay = require('./KmlOverlay'), KmlLoader = require('./KmlLoader'), MarkerCluster = require('./MarkerCluster'); /** * Google Maps model. */ var exec; var Map = function(__pgmId, _exec) { var self = this; exec = _exec; Overlay.call(self, self, {}, 'Map', _exec, { __pgmId: __pgmId }); delete self.map; self.set('myLocation', false); self.set('myLocationButton', false); self.MARKERS = {}; self.OVERLAYS = {}; var infoWindowLayer = document.createElement('div'); infoWindowLayer.style.position = 'absolute'; infoWindowLayer.style.left = 0; infoWindowLayer.style.top = 0; infoWindowLayer.style.width = 0; infoWindowLayer.style.height = 0; infoWindowLayer.style.overflow = 'visible'; infoWindowLayer.style['z-index'] = 1; Object.defineProperty(self, '_layers', { value: { info: infoWindowLayer }, enumerable: false, writable: false }); self.on(event.MAP_CLICK, function() { self.set('active_marker', undefined); }); self.on('active_marker_changed', function(prevMarker, newMarker) { var newMarkerId = newMarker ? newMarker.getId() : null; if (prevMarker) { prevMarker.hideInfoWindow.call(prevMarker); } self.exec.call(self, null, null, self.__pgmId, 'setActiveMarkerId', [newMarkerId]); }); }; utils.extend(Map, Overlay); /** * @desc Recalculate the position of HTML elements */ Map.prototype.refreshLayout = function() { // Webkit redraw mandatory // http://stackoverflow.com/a/3485654/697856 document.body.style.display = 'none'; document.body.offsetHeight; document.body.style.display = ''; this.exec.call(this, null, null, this.__pgmId, 'resizeMap', []); }; Map.prototype.getMap = function(meta, 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); if (options.controls) { this.set('myLocation', options.controls.myLocation === true); this.set('myLocationButton', options.controls.myLocationButton === true); } if (options.preferences && options.preferences.gestureBounds) { if (utils.isArray(options.preferences.gestureBounds) || options.preferences.gestureBounds.type === 'LatLngBounds') { options.preferences.gestureBounds = common.convertToPositionArray(options.preferences.gestureBounds); } } if (!common.isDom(div)) { self.set('visible', false); options = div; options = options || {}; if (options.camera) { if (options.camera.latLng) { options.camera.target = options.camera.latLng; delete options.camera.latLng; } this.set('camera', options.camera); if (options.camera.target) { this.set('camera_target', options.camera.target); } if (options.camera.bearing) { this.set('camera_bearing', options.camera.bearing); } if (options.camera.zoom) { this.set('camera_zoom', options.camera.zoom); } if (options.camera.tilt) { this.set('camera_tilt', options.camera.tilt); } } args.push(options); } else { var positionCSS = common.getStyle(div, 'position'); if (!positionCSS || positionCSS === 'static') { // important for HtmlInfoWindow div.style.position = 'relative'; } options = options || {}; if (options.camera) { if (options.camera.latLng) { options.camera.target = options.camera.latLng; delete options.camera.latLng; } this.set('camera', options.camera); if (options.camera.target) { this.set('camera_target', options.camera.target); } if (options.camera.bearing) { this.set('camera_bearing', options.camera.bearing); } if (options.camera.zoom) { this.set('camera_zoom', options.camera.zoom); } if (options.camera.tilt) { this.set('camera_tilt', options.camera.tilt); } } if (utils.isArray(options.styles)) { options.styles = JSON.stringify(options.styles); } args.push(options); div.style.overflow = 'hidden'; self.set('div', div); if (div.offsetWidth < 100 || div.offsetHeight < 100) { // If the map Div is too small, wait a little. var callee = arguments.callee; setTimeout(function() { callee.call(self, meta, div, options); }, 250 + Math.random() * 100); return; } // Gets the map div size. // The plugin needs to consider the viewport zoom ratio // for the case window.innerHTML > body.offsetWidth. 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 div = self.get('div'); if (common.isDom(div)) { // Insert the infoWindow layer if (self._layers.info.parentNode) { try { self._layers.info.parentNode.removeChild(self._layers.info.parentNode); } catch (e) { // ignore } } 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'; // Add _gmaps_cdv_ class common.attachTransparentClass(div); div = div.parentNode; } } cordova.fireDocumentEvent('plugin_touch', { force: true }); //------------------------------------------------------------------------ // In order to work map.getVisibleRegion() correctly, wait a little. //------------------------------------------------------------------------ var waitCnt = 0; var waitCameraSync = function() { if (!self.getVisibleRegion() && (waitCnt++ < 10)) { setTimeout(function() { common.nextTick(waitCameraSync); }, 100); return; } self._privateInitialize(); delete self._privateInitialize; self.refreshLayout(); self.trigger(event.MAP_READY, self); }; setTimeout(function() { common.nextTick(waitCameraSync); }, 100); }, self.errorHandler, 'CordovaGoogleMaps', 'getMap', args, { sync: true }); }; Map.prototype.setOptions = function(options) { options = options || {}; if (options.controls) { var myLocation = this.get('myLocation'); if ('myLocation' in options.controls) { myLocation = options.controls.myLocation === true; } var myLocationButton = this.get('myLocationButton'); if ('myLocationButton' in options.controls) { myLocationButton = options.controls.myLocationButton === true; } this.set('myLocation', myLocation); this.set('myLocationButton', myLocationButton); if (myLocation === true || myLocation === false) { options.controls.myLocation = myLocation; } if (myLocationButton === true || myLocationButton === false) { options.controls.myLocationButton = myLocationButton; } } if (options.camera) { if (options.camera.latLng) { options.camera.target = options.camera.latLng; delete options.camera.latLng; } this.set('camera', options.camera); if (options.camera.target) { this.set('camera_target', options.camera.target); } if (options.camera.bearing) { this.set('camera_bearing', options.camera.bearing); } if (options.camera.zoom) { this.set('camera_zoom', options.camera.zoom); } if (options.camera.tilt) { this.set('camera_tilt', options.camera.tilt); } } if (options.preferences && options.preferences.gestureBounds) { if (utils.isArray(options.preferences.gestureBounds) || options.preferences.gestureBounds.type === 'LatLngBounds') { options.preferences.gestureBounds = common.convertToPositionArray(options.preferences.gestureBounds); } } if (utils.isArray(options.styles)) { options.styles = JSON.stringify(options.styles); } this.exec.call(this, null, this.errorHandler, this.__pgmId, 'setOptions', [options]); return this; }; Map.prototype.getMyLocation = function(params, success_callback, error_callback) { return window.plugin.google.maps.LocationService.getMyLocation.call(this, params, success_callback, error_callback); }; Map.prototype.setCameraTarget = function(latLng) { this.set('camera_target', latLng); this.exec.call(this, null, this.errorHandler, this.__pgmId, 'setCameraTarget', [latLng.lat, latLng.lng]); return this; }; Map.prototype.setCameraZoom = function(zoom) { this.set('camera_zoom', zoom); this.exec.call(this, null, this.errorHandler, this.__pgmId, 'setCameraZoom', [zoom], { sync: true }); return this; }; Map.prototype.panBy = function(x, y) { x = parseInt(x, 10); y = parseInt(y, 10); this.exec.call(this, null, this.errorHandler, this.__pgmId, 'panBy', [x, y], { sync: true }); return this; }; /** * Clears all markup that has been added to the map, * including markers, polylines and ground overlays. */ Map.prototype.clear = function(callback) { var self = this; if (self._isRemoved) { // Simply ignore because this map is already removed. return Promise.resolve(); } // Close the active infoWindow var active_marker = self.get('active_marker'); if (active_marker) { active_marker.trigger(event.INFO_CLOSE); } var clearObj = function(obj) { var ids = Object.keys(obj); var id, instance; for (var i = 0; i < ids.length; i++) { id = ids[i]; instance = obj[id]; if (instance) { if (typeof instance.remove === 'function') { instance.remove(); } instance.off(); delete obj[id]; } } obj = {}; }; clearObj(self.OVERLAYS); clearObj(self.MARKERS); self.trigger('map_clear'); var resolver = function(resolve, reject) { self.exec.call(self, resolve.bind(self), reject.bind(self), self.__pgmId, 'clear', [], { sync: true }); }; if (typeof callback === 'function') { resolver(callback, self.errorHandler); } else { return new Promise(resolver); } }; /** * @desc Change the map type * @param {String} mapTypeId Specifies the one of the follow strings: * MAP_TYPE_HYBRID * MAP_TYPE_SATELLITE * MAP_TYPE_TERRAIN * MAP_TYPE_NORMAL * MAP_TYPE_NONE */ Map.prototype.setMapTypeId = function(mapTypeId) { if (mapTypeId !== MapTypeId[mapTypeId.replace('MAP_TYPE_', '')]) { return this.errorHandler('Invalid MapTypeId was specified.'); } this.set('mapTypeId', mapTypeId); this.exec.call(this, null, this.errorHandler, this.__pgmId, 'setMapTypeId', [mapTypeId]); return this; }; /** * @desc Change the map view angle * @param {Number} tilt The angle */ Map.prototype.setCameraTilt = function(tilt) { this.set('camera_tilt', tilt); this.exec.call(this, null, this.errorHandler, this.__pgmId, 'setCameraTilt', [tilt], { sync: true }); return this; }; /** * @desc Change the map view bearing * @param {Number} bearing The bearing */ Map.prototype.setCameraBearing = function(bearing) { this.set('camera_bearing', bearing); this.exec.call(this, null, this.errorHandler, this.__pgmId, 'setCameraBearing', [bearing], { sync: true }); return this; }; Map.prototype.moveCameraZoomIn = function(callback) { var self = this; var cameraPosition = self.get('camera'); cameraPosition.zoom++; cameraPosition.zoom = cameraPosition.zoom < 0 ? 0 : cameraPosition.zoom; return self.moveCamera(cameraPosition, callback); }; Map.prototype.moveCameraZoomOut = function(callback) { var self = this; var cameraPosition = self.get('camera'); cameraPosition.zoom--; cameraPosition.zoom = cameraPosition.zoom < 0 ? 0 : cameraPosition.zoom; return self.moveCamera(cameraPosition, callback); }; Map.prototype.animateCameraZoomIn = function(callback) { var self = this; var cameraPosition = self.get('camera'); cameraPosition.zoom++; cameraPosition.zoom = cameraPosition.zoom < 0 ? 0 : cameraPosition.zoom; cameraPosition.duration = 500; return self.animateCamera(cameraPosition, callback); }; Map.prototype.animateCameraZoomOut = function(callback) { var self = this; var cameraPosition = self.get('camera'); cameraPosition.zoom--; cameraPosition.zoom = cameraPosition.zoom < 0 ? 0 : cameraPosition.zoom; cameraPosition.duration = 500; return self.animateCamera(cameraPosition, callback); }; /** * Move the map camera with animation * @name animateCamera * @param {CameraPosition} cameraPosition - New camera position * @param {Function} [callback] - This callback is involved when the animation is completed. * @return {Promise} if you omit `callback`. */ Map.prototype.animateCamera = function(cameraPosition, callback) { var self = this, error; var target = cameraPosition.target; if (!target && 'position' in cameraPosition) { target = cameraPosition.position; } if (!target) { error = new Error('No target field is specified.'); if (typeof callback === 'function') { throw error; } else { return Promise.reject(error); } } // if (!('padding' in cameraPosition)) { // cameraPosition.padding = 10; // } if (utils.isArray(target) || target.type === 'LatLngBounds') { target = common.convertToPositionArray(target); if (target.length === 0) { // skip if no point is specified error = new Error('No point is specified.'); if (typeof callback === 'function') { throw error; } else { return Promise.reject(error); } } } cameraPosition.target = target; var resolver = function(resolve, reject) { self.exec.call(self, resolve.bind(self), reject.bind(self), self.__pgmId, 'animateCamera', [cameraPosition], { sync: true }); }; if (typeof callback === 'function') { resolver(callback, self.errorHandler); } else { return new Promise(resolver); } }; /** * Move the map camera without animation * * @name moveCamera * @param {CameraPosition} - cameraPosition New camera position * @param {Function} [callback] - This callback is involved when the animation is completed. * @return {Promise} if you omit `callback`. */ Map.prototype.moveCamera = function(cameraPosition, callback) { var self = this; var target = cameraPosition.target; if (!target && 'position' in cameraPosition) { target = cameraPosition.position; } if (!target) { return Promise.reject('No target field is specified.'); } // if (!('padding' in cameraPosition)) { // cameraPosition.padding = 10; // } if (utils.isArray(target) || target.type === 'LatLngBounds') { target = common.convertToPositionArray(target); if (target.length === 0) { // skip if no point is specified if (typeof callback === 'function') { callback.call(self); return; } else { return Promise.reject('No point is specified.'); } } } cameraPosition.target = target; var resolver = function(resolve, reject) { self.exec.call(self, resolve.bind(self), reject.bind(self), self.__pgmId, 'moveCamera', [cameraPosition], { sync: true }); }; if (typeof callback === 'function') { resolver(callback, self.errorHandler); } else { return new Promise(resolver); } }; Map.prototype.setMyLocationButtonEnabled = function(enabled) { var self = this; enabled = common.parseBoolean(enabled); this.set('myLocationButton', enabled); self.exec.call(self, null, this.errorHandler, this.__pgmId, 'setMyLocationEnabled', [{ myLocationButton: enabled, myLocation: self.get('myLocation') === true }], { sync: true }); return this; }; Map.prototype.setMyLocationEnabled = function(enabled) { var self = this; enabled = common.parseBoolean(enabled); this.set('myLocation', enabled); self.exec.call(self, null, this.errorHandler, this.__pgmId, 'setMyLocationEnabled', [{ myLocationButton: self.get('myLocationButton') === true, myLocation: enabled }], { sync: true }); return this; }; Map.prototype.setIndoorEnabled = function(enabled) { enabled = common.parseBoolean(enabled); this.exec.call(this, null, this.errorHandler, this.__pgmId, 'setIndoorEnabled', [enabled]); return this; }; Map.prototype.setTrafficEnabled = function(enabled) { enabled = common.parseBoolean(enabled); this.exec.call(this, null, this.errorHandler, this.__pgmId, 'setTrafficEnabled', [enabled]); return this; }; Map.prototype.setCompassEnabled = function(enabled) { var self = this; enabled = common.parseBoolean(enabled); self.exec.call(self, null, self.errorHandler, this.__pgmId, 'setCompassEnabled', [enabled]); return this; }; Map.prototype.getFocusedBuilding = function(callback) { var self = this; var resolver = function(resolve, reject) { self.exec.call(self, resolve.bind(self), reject.bind(self), self.__pgmId, 'getFocusedBuilding', []); }; if (typeof callback === 'function') { resolver(callback, self.errorHandler); } else { return new Promise(resolver); } }; Map.prototype.getVisible = function() { return this.get('visible'); }; Map.prototype.setVisible = function(isVisible) { cordova.fireDocumentEvent('plugin_touch'); var self = this; isVisible = common.parseBoolean(isVisible); self.set('visible', isVisible); self.exec.call(self, null, self.errorHandler, this.__pgmId, 'setVisible', [isVisible]); return this; }; Map.prototype.setClickable = function(isClickable) { cordova.fireDocumentEvent('plugin_touch'); var self = this; isClickable = common.parseBoolean(isClickable); self.set('clickable', isClickable); self.exec.call(self, null, self.errorHandler, this.__pgmId, 'setClickable', [isClickable]); return this; }; Map.prototype.getClickable = function() { return this.get('clickable'); }; /** * Sets the preference for whether all gestures should be enabled or disabled. */ Map.prototype.setAllGesturesEnabled = function(enabled) { var self = this; enabled = common.parseBoolean(enabled); self.exec.call(self, null, self.errorHandler, this.__pgmId, 'setAllGesturesEnabled', [enabled]); return this; }; /** * Return the current position of the camera * @return {CameraPosition} */ Map.prototype.getCameraPosition = function() { return this.get('camera'); }; /** * Remove the map completely. */ Map.prototype.remove = function(callback) { var self = this; if (self._isRemoved) { return; } Object.defineProperty(self, '_isRemoved', { value: true, writable: false }); self.trigger('remove'); // var div = self.get('div'); // if (div) { // while (div) { // if (div.style) { // div.style.backgroundColor = ''; // } // if (div.classList) { // div.classList.remove('_gmaps_cdv_'); // } else if (div.className) { // div.className = div.className.replace(/_gmaps_cdv_/g, ''); // div.className = div.className.replace(/\s+/g, ' '); // } // div = div.parentNode; // } // } // self.set('div', undefined); // Close the active infoWindow var active_marker = self.get('active_marker'); if (active_marker) { active_marker.trigger(event.INFO_CLOSE); } var clearObj = function(obj) { var ids = Object.keys(obj); var id, instance; for (var i = 0; i < ids.length; i++) { id = ids[i]; instance = obj[id]; if (instance) { if (typeof instance.remove === 'function') { instance.remove(); } instance.off(); delete obj[id]; } } obj = {}; }; clearObj(self.OVERLAYS); clearObj(self.MARKERS); var resolver = function(resolve, reject) { self.exec.call(self, resolve.bind(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); } }; Map.prototype.toDataURL = function(params, callback) { var args = [params || {}, callback]; if (typeof args[0] === 'function') { args.unshift({}); } params = args[0]; callback = args[1]; params.uncompress = params.uncompress === true; var self = this; var resolver = function(resolve, reject) { self.exec.call(self, resolve.bind(self), reject.bind(self), self.__pgmId, 'toDataURL', [params]); }; if (typeof callback === 'function') { resolver(callback, self.errorHandler); } else { return new Promise(resolver); } }; /** * Show the map into the specified div. */ Map.prototype.getDiv = function() { return this.get('div'); }; /** * Show the map into the specified div. */ Map.prototype.setDiv = function(div) { var self = this, args = []; if (!common.isDom(div)) { div = self.get('div'); if (common.isDom(div)) { div.removeAttribute('__pluginMapId'); } self.set('div', null); } else { div.setAttribute('__pluginMapId', self.__pgmId); // Insert the infoWindow layer if (self._layers.info.parentNode) { try { self._layers.info.parentNode.removeChild(self._layers.info.parentNode); } catch(e) { //ignore } } 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); // Webkit redraw mandatory // http://stackoverflow.com/a/3485654/697856 div.style.display = 'none'; div.offsetHeight; div.style.display = ''; self.set('div', div); if (cordova.platform === 'browser') { return; } positionCSS = common.getStyle(div, 'position'); if (!positionCSS || positionCSS === 'static') { div.style.position = 'relative'; } var elemId = common.getPluginDomId(div); args.push(elemId); while (div.parentNode) { div.style.backgroundColor = 'rgba(0,0,0,0)'; // Add _gmaps_cdv_ class common.attachTransparentClass(div); div = div.parentNode; } } self.exec.call(self, function() { cordova.fireDocumentEvent('plugin_touch', { force: true, action: 'setDiv' }); self.refreshLayout(); }, self.errorHandler, self.__pgmId, 'setDiv', args, { sync: true }); return self; }; /** * Return the visible region of the map. */ Map.prototype.getVisibleRegion = function(callback) { var self = this; var cameraPosition = self.get('camera'); if (!cameraPosition || !cameraPosition.southwest || !cameraPosition.northeast) { return null; } var latLngBounds = new VisibleRegion( cameraPosition.southwest, cameraPosition.northeast, cameraPosition.farLeft, cameraPosition.farRight, cameraPosition.nearLeft, cameraPosition.nearRight ); if (typeof callback === 'function') { console.log('[deprecated] getVisibleRegion() is changed. Please check out the https://goo.gl/yHstHQ'); callback.call(self, latLngBounds); } return latLngBounds; }; /** * Maps an Earth coordinate to a point coordinate in the map's view. */ Map.prototype.fromLatLngToPoint = function(latLng, callback) { var self = this; if ('lat' in latLng && 'lng' in latLng) { var resolver = function(resolve, reject) { self.exec.call(self, resolve.bind(self), reject.bind(self), self.__pgmId, 'fromLatLngToPoint', [latLng.lat, latLng.lng]); }; if (typeof callback === 'function') { resolver(callback, self.errorHandler); } else { return new Promise(resolver); } } else { var rejector = function(resolve, reject) { reject('The latLng is invalid'); }; if (typeof callback === 'function') { rejector(callback, self.errorHandler); } else { return new Promise(rejector); } } }; /** * Maps a point coordinate in the map's view to an Earth coordinate. */ Map.prototype.fromPointToLatLng = function(pixel, callback) { var self = this; if (typeof pixel === 'object' && 'x' in pixel && 'y' in pixel) { pixel = [pixel.x, pixel.y]; } if (pixel.length == 2 && utils.isArray(pixel)) { var resolver = function(resolve, reject) { self.exec.call(self, function(result) { var latLng = new LatLng(result[0] || 0, result[1] || 0); resolve.call(self, latLng); }, reject.bind(self), self.__pgmId, 'fromPointToLatLng', [pixel[0], pixel[1]]); }; if (typeof callback === 'function') { resolver(callback, self.errorHandler); } else { return new Promise(resolver); } } else { var rejector = function(resolve, reject) { reject('The pixel[] argument is invalid'); }; if (typeof callback === 'function') { rejector(callback, self.errorHandler); } else { return new Promise(rejector); } } }; Map.prototype.setPadding = function(p1, p2, p3, p4) { if (arguments.length === 0 || arguments.length > 4) { return this; } var padding = {}; padding.top = parseInt(p1, 10); switch (arguments.length) { case 4: // top right bottom left padding.right = parseInt(p2, 10); padding.bottom = parseInt(p3, 10); padding.left = parseInt(p4, 10); break; case 3: // top right&left bottom padding.right = parseInt(p2, 10); padding.left = padding.right; padding.bottom = parseInt(p3, 10); break; case 2: // top & bottom right&left padding.bottom = parseInt(p1, 10); padding.right = parseInt(p2, 10); padding.left = padding.right; break; case 1: // top & bottom right & left padding.bottom = padding.top; padding.right = padding.top; padding.left = padding.top; break; } this.exec.call(this, null, self.errorHandler, this.__pgmId, 'setPadding', [padding]); return this; }; Map.prototype.addKmlOverlay = function(kmlOverlayOptions, callback) { var self = this; kmlOverlayOptions = kmlOverlayOptions || {}; kmlOverlayOptions.url = kmlOverlayOptions.url || null; kmlOverlayOptions.clickable = common.defaultTrueOption(kmlOverlayOptions.clickable); kmlOverlayOptions.suppressInfoWindows = kmlOverlayOptions.suppressInfoWindows === true; if (kmlOverlayOptions.url) { var link = document.createElement('a'); link.href = kmlOverlayOptions.url; kmlOverlayOptions.url = link.protocol+'//'+link.host+link.pathname + link.search; var invisible_dot = self.get('invisible_dot'); if (!invisible_dot || invisible_dot._isRemoved) { // Create an invisible marker for kmlOverlay self.set('invisible_dot', self.addMarker({ position: { lat: 0, lng: 0 }, icon: 'skyblue', visible: false })); } if ('icon' in kmlOverlayOptions) { self.get('invisible_dot').setIcon(kmlOverlayOptions.icon); } var resolver = function(resolve, reject) { var loader = new KmlLoader(self, self.exec, kmlOverlayOptions); loader.parseKmlFile(function(camera, kmlData) { if (kmlData instanceof BaseClass) { kmlData = new BaseArrayClass([kmlData]); } var kmlId = 'kmloverlay_' + Math.floor(Math.random() * Date.now()); var kmlOverlay = new KmlOverlay(self, kmlId, camera, kmlData, kmlOverlayOptions); self.OVERLAYS[kmlId] = kmlOverlay; resolve.call(self, kmlOverlay); }, reject); }; if (typeof callback === 'function') { resolver(callback, self.errorHandler); } else { return new Promise(resolver); } } else { if (typeof callback === 'function') { throw new Error('KML file url is required.'); } else { return Promise.reject('KML file url is required.'); } } }; //------------- // Ground overlay //------------- Map.prototype.addGroundOverlay = function(groundOverlayOptions, callback) { var self = this; groundOverlayOptions = groundOverlayOptions || {}; groundOverlayOptions.anchor = groundOverlayOptions.anchor || [0.5, 0.5]; groundOverlayOptions.bearing = 'bearing' in groundOverlayOptions ? groundOverlayOptions.bearing : 0; groundOverlayOptions.url = groundOverlayOptions.url || null; groundOverlayOptions.clickable = groundOverlayOptions.clickable === true; groundOverlayOptions.visible = common.defaultTrueOption(groundOverlayOptions.visible); groundOverlayOptions.zIndex = groundOverlayOptions.zIndex || 0; groundOverlayOptions.bounds = common.convertToPositionArray(groundOverlayOptions.bounds); groundOverlayOptions.noCaching = true; var groundOverlay = new GroundOverlay(self, groundOverlayOptions, exec); var groundOverlayId = groundOverlay.getId(); self.OVERLAYS[groundOverlayId] = groundOverlay; groundOverlay.one(groundOverlayId + '_remove', function() { groundOverlay.off(); delete self.OVERLAYS[groundOverlayId]; groundOverlay = undefined; }); self.exec.call(self, function() { groundOverlay._privateInitialize(); delete groundOverlay._privateInitialize; if (typeof callback === 'function') { callback.call(self, groundOverlay); } }, self.errorHandler, self.__pgmId, 'loadPlugin', ['GroundOverlay', groundOverlayOptions, groundOverlay.hashCode]); return groundOverlay; }; //------------- // Tile overlay //------------- Map.prototype.addTileOverlay = function(tilelayerOptions, callback) { var self = this; tilelayerOptions = tilelayerOptions || {}; tilelayerOptions.tileUrlFormat = tilelayerOptions.tileUrlFormat || null; if (typeof tilelayerOptions.tileUrlFormat === 'string') { console.log('[deprecated] the tileUrlFormat property is now deprecated. Use the getTile property.'); tilelayerOptions.getTile = function(x, y, zoom) { return tilelayerOptions.tileUrlFormat.replace(//gi, x) .replace(//gi, y) .replace(//gi, zoom); }; } if (typeof tilelayerOptions.getTile !== 'function') { throw new Error('[error] the getTile property is required.'); } tilelayerOptions.visible = common.defaultTrueOption(tilelayerOptions.visible); tilelayerOptions.zIndex = tilelayerOptions.zIndex || 0; tilelayerOptions.tileSize = tilelayerOptions.tileSize || 512; tilelayerOptions.opacity = (tilelayerOptions.opacity === null || tilelayerOptions.opacity === undefined) ? 1 : tilelayerOptions.opacity; tilelayerOptions.debug = tilelayerOptions.debug === true; tilelayerOptions.userAgent = tilelayerOptions.userAgent || navigator.userAgent; var tileOverlay = new TileOverlay(self, tilelayerOptions, exec); var tileOverlayId = tileOverlay.getId(); self.OVERLAYS[tileOverlayId] = tileOverlay; var hashCode = tileOverlay.hashCode; tileOverlay.one(tileOverlayId + '_remove', function() { document.removeEventListener(tileOverlayId + '-' + hashCode + '-tileoverlay', onNativeCallback); tileOverlay.off(); delete self.OVERLAYS[tileOverlayId]; tileOverlay = undefined; }); var options = { visible: tilelayerOptions.visible, zIndex: tilelayerOptions.zIndex, tileSize: tilelayerOptions.tileSize, opacity: tilelayerOptions.opacity, userAgent: tilelayerOptions.userAgent, debug: tilelayerOptions.debug }; var onNativeCallback = function(params) { var url = tilelayerOptions.getTile(params.x, params.y, params.zoom); if (!url || url === '(null)' || url === 'undefined' || url === 'null') { url = '(null)'; } if (url instanceof Promise) { common.promiseTimeout(5000, url) .then(function(finalUrl) { cordova_exec(null, self.errorHandler, self.__pgmId + '-tileoverlay', 'onGetTileUrlFromJS', [hashCode, params.key, finalUrl]); }) .catch(function() { cordova_exec(null, self.errorHandler, self.__pgmId + '-tileoverlay', 'onGetTileUrlFromJS', [hashCode, params.key, '(null)']); }); } else { cordova_exec(null, self.errorHandler, self.__pgmId + '-tileoverlay', 'onGetTileUrlFromJS', [hashCode, params.key, url]); } }; document.addEventListener(self.__pgmId + '-' + hashCode + '-tileoverlay', onNativeCallback); self.exec.call(self, function() { tileOverlay._privateInitialize(); delete tileOverlay._privateInitialize; if (typeof callback === 'function') { callback.call(self, tileOverlay); } }, self.errorHandler, self.__pgmId, 'loadPlugin', ['TileOverlay', options, hashCode]); return tileOverlay; }; //------------- // Polygon //------------- Map.prototype.addPolygon = function(polygonOptions, callback) { var self = this; polygonOptions.points = polygonOptions.points || []; var _orgs = polygonOptions.points; polygonOptions.points = common.convertToPositionArray(polygonOptions.points); polygonOptions.holes = polygonOptions.holes || []; if (polygonOptions.holes.length > 0 && !Array.isArray(polygonOptions.holes[0])) { polygonOptions.holes = [polygonOptions.holes]; } polygonOptions.holes = polygonOptions.holes.map(function(hole) { if (!utils.isArray(hole)) { return []; } return hole.map(function(position) { return { 'lat': position.lat, 'lng': position.lng }; }); }); polygonOptions.strokeColor = common.HTMLColor2RGBA(polygonOptions.strokeColor || '#FF000080', 0.75); if (polygonOptions.fillColor) { polygonOptions.fillColor = common.HTMLColor2RGBA(polygonOptions.fillColor || '#FF000080', 0.75); } else { polygonOptions.fillColor = common.HTMLColor2RGBA('#FF000080', 0.75); } polygonOptions.strokeWidth = 'strokeWidth' in polygonOptions ? polygonOptions.strokeWidth : 10; polygonOptions.visible = common.defaultTrueOption(polygonOptions.visible); polygonOptions.clickable = polygonOptions.clickable === true; polygonOptions.zIndex = polygonOptions.zIndex || 0; polygonOptions.geodesic = polygonOptions.geodesic === true; var opts = JSON.parse(JSON.stringify(polygonOptions)); polygonOptions.points = _orgs; var polygon = new Polygon(self, polygonOptions, exec); var polygonId = polygon.getId(); self.OVERLAYS[polygonId] = polygon; polygon.one(polygonId + '_remove', function() { polygon.off(); delete self.OVERLAYS[polygonId]; polygon = undefined; }); self.exec.call(self, function() { polygon._privateInitialize(); delete polygon._privateInitialize; if (typeof callback === 'function') { callback.call(self, polygon); } }, self.errorHandler, self.__pgmId, 'loadPlugin', ['Polygon', opts, polygon.hashCode]); return polygon; }; //------------- // Polyline //------------- Map.prototype.addPolyline = function(polylineOptions, callback) { var self = this; polylineOptions.points = polylineOptions.points || []; var _orgs = polylineOptions.points; polylineOptions.points = common.convertToPositionArray(polylineOptions.points); polylineOptions.color = common.HTMLColor2RGBA(polylineOptions.color || '#FF000080', 0.75); polylineOptions.width = 'width' in polylineOptions ? polylineOptions.width : 10; polylineOptions.visible = common.defaultTrueOption(polylineOptions.visible); polylineOptions.clickable = polylineOptions.clickable === true; polylineOptions.zIndex = polylineOptions.zIndex || 0; polylineOptions.geodesic = polylineOptions.geodesic === true; var opts = JSON.parse(JSON.stringify(polylineOptions)); polylineOptions.points = _orgs; var polyline = new Polyline(self, polylineOptions, exec); var polylineId = polyline.getId(); self.OVERLAYS[polylineId] = polyline; polyline.one(polylineId + '_remove', function() { polyline.off(); delete self.OVERLAYS[polylineId]; polyline = undefined; }); self.exec.call(self, function() { polyline._privateInitialize(); delete polyline._privateInitialize; if (typeof callback === 'function') { callback.call(self, polyline); } }, self.errorHandler, self.__pgmId, 'loadPlugin', ['Polyline', opts, polyline.hashCode]); return polyline; }; //------------- // Circle //------------- Map.prototype.addCircle = function(circleOptions, callback) { var self = this; circleOptions.center = circleOptions.center || {}; circleOptions.center.lat = circleOptions.center.lat || 0.0; circleOptions.center.lng = circleOptions.center.lng || 0.0; circleOptions.strokeColor = common.HTMLColor2RGBA(circleOptions.strokeColor || '#FF0000', 0.75); circleOptions.fillColor = common.HTMLColor2RGBA(circleOptions.fillColor || '#000000', 0.75); circleOptions.strokeWidth = 'strokeWidth' in circleOptions ? circleOptions.strokeWidth : 10; circleOptions.visible = common.defaultTrueOption(circleOptions.visible); circleOptions.zIndex = circleOptions.zIndex || 0; circleOptions.radius = 'radius' in circleOptions ? circleOptions.radius : 1; var circle = new Circle(self, circleOptions, exec); var circleId = circle.getId(); self.OVERLAYS[circleId] = circle; circle.one(circleId + '_remove', function() { circle.off(); delete self.OVERLAYS[circleId]; circle = undefined; }); self.exec.call(self, function() { circle._privateInitialize(); delete circle._privateInitialize; if (typeof callback === 'function') { callback.call(self, circle); } }, self.errorHandler, self.__pgmId, 'loadPlugin', ['Circle', circleOptions, circle.hashCode]); return circle; }; //------------- // Marker //------------- Map.prototype.addMarker = function(markerOptions, callback) { var self = this; markerOptions = common.markerOptionsFilter(markerOptions); //------------------------------------ // Generate a makrer instance at once. //------------------------------------ markerOptions.icon = markerOptions.icon || {}; if (typeof markerOptions.icon === 'string' || Array.isArray(markerOptions.icon)) { markerOptions.icon = { url: markerOptions.icon }; } var marker = new Marker(self, markerOptions, exec); var markerId = marker.getId(); self.MARKERS[markerId] = marker; self.OVERLAYS[markerId] = marker; marker.one(markerId + '_remove', function() { delete self.MARKERS[markerId]; delete self.OVERLAYS[markerId]; marker.destroy(); marker = undefined; }); self.exec.call(self, function(result) { markerOptions.icon.size = markerOptions.icon.size || {}; markerOptions.icon.size.width = markerOptions.icon.size.width || result.width; markerOptions.icon.size.height = markerOptions.icon.size.height || result.height; markerOptions.icon.anchor = markerOptions.icon.anchor || [markerOptions.icon.size.width / 2, markerOptions.icon.size.height]; if (!markerOptions.infoWindowAnchor) { markerOptions.infoWindowAnchor = [markerOptions.icon.size.width / 2, 0]; } marker._privateInitialize(markerOptions); delete marker._privateInitialize; if (typeof callback === 'function') { callback.call(self, marker); } }, self.errorHandler, self.__pgmId, 'loadPlugin', ['Marker', markerOptions, marker.hashCode]); return marker; }; //------------------ // Marker cluster //------------------ Map.prototype.addMarkerCluster = function(markerClusterOptions, callback) { var self = this; if (typeof markerClusterOptions === 'function') { callback = markerClusterOptions; markerClusterOptions = null; } markerClusterOptions = markerClusterOptions || {}; var positionList = markerClusterOptions.markers.map(function(marker) { return marker.position; }); var markerCluster = new MarkerCluster(self, { 'icons': markerClusterOptions.icons, //'markerMap': markerMap, 'idxCount': positionList.length + 1, 'maxZoomLevel': Math.min(markerClusterOptions.maxZoomLevel || 15, 18), 'debug': markerClusterOptions.debug === true, 'boundsDraw': common.defaultTrueOption(markerClusterOptions.boundsDraw) }, exec); var markerClusterId = markerCluster.getId(); self.OVERLAYS[markerClusterId] = markerCluster; self.exec.call(self, function(result) { result.geocellList.forEach(function(geocell, idx) { var markerOptions = markerClusterOptions.markers[idx]; markerOptions = common.markerOptionsFilter(markerOptions); markerOptions._cluster = { isRemoved: false, isAdded: false, geocell: geocell }; markerCluster.addMarker(markerOptions); //self.MARKERS[marker.getId()] = marker; //self.OVERLAYS[marker.getId()] = marker; }); markerCluster.one('remove', function() { delete self.OVERLAYS[result.__pgmId]; /* result.geocellList.forEach(function(geocell, idx) { var markerOptions = markerClusterOptions.markers[idx]; var markerId = result.__pgmId + '-' + (markerOptions.__pgmId || 'marker_' + idx); var marker = self.MARKERS[markerId]; if (marker) { marker.off(); } //delete self.MARKERS[markerId]; delete self.OVERLAYS[markerId]; }); */ markerCluster.destroy(); }); markerCluster._privateInitialize(); delete markerCluster._privateInitialize; markerCluster._triggerRedraw.call(markerCluster, { force: true }); if (typeof callback === 'function') { callback.call(self, markerCluster); } }, self.errorHandler, self.__pgmId, 'loadPlugin', ['MarkerCluster', { 'positionList': positionList, 'debug': markerClusterOptions.debug === true }, markerCluster.hashCode]); return markerCluster; }; /***************************************************************************** * Callbacks from the native side *****************************************************************************/ Map.prototype._onSyncInfoWndPosition = function(eventName, points) { this.set('infoPosition', points); }; Map.prototype._onMapEvent = function(eventName) { if (!this._isReady) { return; } var args = [eventName]; for (var i = 1; i < arguments.length; i++) { args.push(arguments[i]); } this.trigger.apply(this, args); }; Map.prototype._onMarkerEvent = function(eventName, markerId, position) { var self = this; var marker = self.MARKERS[markerId] || null; if (marker) { marker.set('position', position); if (eventName === event.INFO_OPEN) { marker.set('isInfoWindowVisible', true); } if (eventName === event.INFO_CLOSE) { marker.set('isInfoWindowVisible', false); } marker.trigger(eventName, position, marker); } }; Map.prototype._onClusterEvent = function(eventName, markerClusterId, clusterId, position) { var self = this; var markerCluster = self.OVERLAYS[markerClusterId] || null; if (markerCluster) { if (/^marker_/i.test(clusterId)) { // regular marker var marker = markerCluster.getMarkerById(clusterId); if (eventName === event.MARKER_CLICK) { markerCluster.trigger(eventName, position, marker); } else { if (eventName === event.INFO_OPEN) { marker.set('isInfoWindowVisible', true); } if (eventName === event.INFO_CLOSE) { marker.set('isInfoWindowVisible', false); } } marker.trigger(eventName, position, marker); } else { // cluster marker var cluster = markerCluster._getClusterByClusterId(clusterId); if (cluster) { markerCluster.trigger(eventName, cluster); } else { console.log('-----> This is remained cluster icon : ' + clusterId); } } } }; Map.prototype._onOverlayEvent = function(eventName, overlayId) { var self = this; var overlay = self.OVERLAYS[overlayId] || null; if (overlay) { var args = [eventName]; for (var i = 2; i < arguments.length; i++) { args.push(arguments[i]); } args.push(overlay); // for ionic overlay.trigger.apply(overlay, args); } }; Map.prototype.getCameraTarget = function() { return this.get('camera_target'); }; Map.prototype.getCameraZoom = function() { return this.get('camera_zoom'); }; Map.prototype.getCameraTilt = function() { return this.get('camera_tilt'); }; Map.prototype.getCameraBearing = function() { return this.get('camera_bearing'); }; Map.prototype._onCameraEvent = function(eventName, cameraPosition) { this.set('camera', cameraPosition); this.set('camera_target', cameraPosition.target); this.set('camera_zoom', cameraPosition.zoom); this.set('camera_bearing', cameraPosition.bearing); this.set('camera_tilt', cameraPosition.viewAngle || cameraPosition.tilt); this.set('camera_northeast', cameraPosition.northeast); this.set('camera_southwest', cameraPosition.southwest); this.set('camera_nearLeft', cameraPosition.nearLeft); this.set('camera_nearRight', cameraPosition.nearRight); this.set('camera_farLeft', cameraPosition.farLeft); this.set('camera_farRight', cameraPosition.farRight); if (this._isReady) { this.trigger(eventName, cameraPosition, this); } }; module.exports = Map; });