cordova.define("cordova-plugin-googlemaps.HtmlInfoWindow", function(require, exports, module) { 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; });