├── .all-contributorsrc ├── .github ├── ISSUE_TEMPLATE │ ├── bug-report.md │ └── feature_request.md └── workflows │ ├── build.yml │ └── publish.yml ├── .gitignore ├── .npmignore ├── CapacitorCommunityGoogleMaps.podspec ├── LICENSE ├── README.md ├── android ├── .npmignore ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── proguard-rules.pro ├── settings.gradle └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── getcapacitor │ │ └── android │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── hemangkumar │ │ │ └── capacitorgooglemaps │ │ │ ├── AsyncIconLoader.java │ │ │ ├── BoundingRect.java │ │ │ ├── CapacitorGoogleMaps.java │ │ │ ├── CustomMapView.java │ │ │ ├── CustomMapViewEvents.java │ │ │ ├── CustomMarker.java │ │ │ ├── CustomPolygon.java │ │ │ ├── IconDescriptor.java │ │ │ ├── JSObjectDefaults.java │ │ │ ├── MapCameraPosition.java │ │ │ ├── MapPreferences.java │ │ │ ├── MapPreferencesAppearance.java │ │ │ ├── MapPreferencesControls.java │ │ │ ├── MapPreferencesGestures.java │ │ │ └── MarkersAppender.java │ └── res │ │ ├── layout │ │ └── bridge_layout_main.xml │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── getcapacitor │ └── ExampleUnitTest.java ├── docs ├── .nojekyll ├── README.md ├── _sidebar.md ├── about │ ├── out-of-scope-features.md │ └── should-you-use-this-plugin.md ├── advanced-concepts │ ├── README.md │ ├── touch-delegation.md │ └── transparent-webview.md ├── api.md ├── assets │ ├── xcode-subclass-1.png │ └── xcode-subclass-2.png ├── coverpage.md ├── getting-started │ ├── installation.md │ └── quickstart.md ├── guide │ ├── setup-webview.md │ └── troubleshooting.md └── index.html ├── ios ├── .npmignore ├── Plugin.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── Plugin.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── Plugin │ ├── BoundingRect.swift │ ├── CustomMapView.swift │ ├── CustomMapViewController.swift │ ├── CustomMapViewEvents.swift │ ├── CustomMarker.swift │ ├── CustomPolygon.swift │ ├── ImageCache │ │ ├── ImageURLLoadable.swift │ │ ├── NativeImageCache.swift │ │ ├── SDWebImageCache.swift │ │ └── TypeAliases.swift │ ├── Info.plist │ ├── MapCameraPosition.swift │ ├── MapPreferences.swift │ ├── MapPreferencesAppearance.swift │ ├── MapPreferencesControls.swift │ ├── MapPreferencesGestures.swift │ ├── Plugin.h │ ├── Plugin.m │ ├── Plugin.swift │ └── Utilities │ │ ├── CALayer+pixelColorAtPoint.swift │ │ ├── LinkedList.swift │ │ └── UIImage+resize.swift ├── PluginTests │ ├── Info.plist │ └── PluginTests.swift └── Podfile ├── package-lock.json ├── package.json ├── rollup.config.js ├── src ├── definitions.ts ├── index.ts ├── interfaces │ ├── events │ │ ├── DidBeginDraggingMarker.ts │ │ ├── DidBeginMovingCamera.ts │ │ ├── DidCloseInfoWindow.ts │ │ ├── DidDragMarker.ts │ │ ├── DidEndDraggingMarker.ts │ │ ├── DidEndMovingCamera.ts │ │ ├── DidLongPressMap.ts │ │ ├── DidMoveCamera.ts │ │ ├── DidTapInfoWindow.ts │ │ ├── DidTapMap.ts │ │ ├── DidTapMarker.ts │ │ ├── DidTapMyLocationButton.ts │ │ ├── DidTapMyLocationDot.ts │ │ └── DidTapPoi.ts │ ├── index.ts │ ├── methods │ │ ├── AddMarker.ts │ │ ├── AddMarkers.ts │ │ ├── AddPolygon.ts │ │ ├── ClearMap.ts │ │ ├── CreateMap.ts │ │ ├── ElementFromPointResult.ts │ │ ├── Initialize.ts │ │ ├── MoveCamera.ts │ │ ├── RemoveMap.ts │ │ ├── RemoveMarker.ts │ │ ├── RemovePolygon.ts │ │ └── UpdateMap.ts │ └── models │ │ ├── BoundingRect.ts │ │ ├── GoogleMap │ │ ├── Appearance.ts │ │ ├── Camera │ │ │ ├── MovementReason.ts │ │ │ └── Position.ts │ │ ├── Controls.ts │ │ ├── Gestures.ts │ │ ├── GoogleMap.ts │ │ ├── Marker │ │ │ ├── Marker.ts │ │ │ ├── MarkerIcon.ts │ │ │ ├── MarkerIconSize.ts │ │ │ └── MarkerPreferences.ts │ │ ├── PointOfInterest.ts │ │ ├── Polygon │ │ │ ├── Polygon.ts │ │ │ └── PolygonPreferences.ts │ │ └── Preferences.ts │ │ └── LatLng.ts └── web.ts └── tsconfig.json /.all-contributorsrc: -------------------------------------------------------------------------------- 1 | { 2 | "projectName": "google-maps", 3 | "projectOwner": "capacitor-community", 4 | "repoType": "github", 5 | "repoHost": "https://github.com", 6 | "files": [ 7 | "README.md" 8 | ], 9 | "imageSize": 100, 10 | "commit": true, 11 | "commitConvention": "none", 12 | "contributors": [ 13 | { 14 | "login": "gbrits", 15 | "name": "Grant Brits", 16 | "avatar_url": "https://avatars.githubusercontent.com/u/14840021?v=4", 17 | "profile": "https://maximus.agency/", 18 | "contributions": [ 19 | "code", 20 | "bug", 21 | "ideas" 22 | ] 23 | }, 24 | { 25 | "login": "tafelnl", 26 | "name": "Tafel", 27 | "avatar_url": "https://avatars.githubusercontent.com/u/35837839?v=4", 28 | "profile": "https://github.com/tafelnl", 29 | "contributions": [ 30 | "code", 31 | "bug", 32 | "ideas" 33 | ] 34 | }, 35 | { 36 | "login": "abcoskn", 37 | "name": "abcoskn", 38 | "avatar_url": "https://avatars.githubusercontent.com/u/6419471?v=4", 39 | "profile": "https://github.com/abcoskn", 40 | "contributions": [ 41 | "code", 42 | "bug" 43 | ] 44 | }, 45 | { 46 | "login": "hyun-yang", 47 | "name": "Hyun Yang", 48 | "avatar_url": "https://avatars.githubusercontent.com/u/2142419?v=4", 49 | "profile": "https://github.com/hyun-yang", 50 | "contributions": [ 51 | "bug", 52 | "example" 53 | ] 54 | }, 55 | { 56 | "login": "MelanieMarval", 57 | "name": "Melanie Marval", 58 | "avatar_url": "https://avatars.githubusercontent.com/u/43726363?v=4", 59 | "profile": "https://github.com/MelanieMarval", 60 | "contributions": [ 61 | "bug" 62 | ] 63 | }, 64 | { 65 | "login": "tototares", 66 | "name": "l4ke", 67 | "avatar_url": "https://avatars.githubusercontent.com/u/1064024?v=4", 68 | "profile": "https://github.com/tototares", 69 | "contributions": [ 70 | "bug" 71 | ] 72 | }, 73 | { 74 | "login": "quaz579", 75 | "name": "Ben Grossman", 76 | "avatar_url": "https://avatars.githubusercontent.com/u/13681950?v=4", 77 | "profile": "https://github.com/quaz579", 78 | "contributions": [ 79 | "bug" 80 | ] 81 | }, 82 | { 83 | "login": "gerciljunio", 84 | "name": "Gercil Junio", 85 | "avatar_url": "https://avatars.githubusercontent.com/u/4561073?v=4", 86 | "profile": "https://github.com/gerciljunio", 87 | "contributions": [ 88 | "userTesting" 89 | ] 90 | }, 91 | { 92 | "login": "aacassandra", 93 | "name": "Alauddin Afif Cassandra", 94 | "avatar_url": "https://avatars.githubusercontent.com/u/29236058?v=4", 95 | "profile": "https://github.com/aacassandra", 96 | "contributions": [ 97 | "userTesting" 98 | ] 99 | }, 100 | { 101 | "login": "togro", 102 | "name": "togro", 103 | "avatar_url": "https://avatars.githubusercontent.com/u/7252575?v=4", 104 | "profile": "https://github.com/togro", 105 | "contributions": [ 106 | "bug", 107 | "userTesting" 108 | ] 109 | }, 110 | { 111 | "login": "selected-pixel-jameson", 112 | "name": "selected-pixel-jameson", 113 | "avatar_url": "https://avatars.githubusercontent.com/u/28204537?v=4", 114 | "profile": "https://www.selectedpixel.com/", 115 | "contributions": [ 116 | "bug" 117 | ] 118 | }, 119 | { 120 | "login": "ChiKaLiO", 121 | "name": "chikalio", 122 | "avatar_url": "https://avatars.githubusercontent.com/u/12167528?v=4", 123 | "profile": "https://github.com/ChiKaLiO", 124 | "contributions": [ 125 | "bug" 126 | ] 127 | }, 128 | { 129 | "login": "J-Gonzalez", 130 | "name": "Javier Gonzalez", 131 | "avatar_url": "https://avatars.githubusercontent.com/u/1047598?v=4", 132 | "profile": "https://www.tickeri.com/", 133 | "contributions": [ 134 | "code" 135 | ] 136 | } 137 | ], 138 | "contributorsPerLine": 7 139 | } 140 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Additional context** 27 | Add any other context about the problem here. 28 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest / Enquire about a feature for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Does this feature exist in the Google Maps SDK for android and iOS? Please link the documentation for this feature.** 14 | Link to the feature in SDK docs 15 | 16 | **Describe the solution you'd like** 17 | A clear and concise description of what you want to happen. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | Also give a description of any alternative solutions or features you've considered. 22 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | test: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v1 13 | - uses: actions/setup-node@v1 14 | with: 15 | node-version: 12 16 | registry-url: https://registry.npmjs.org/ 17 | - run: npm test 18 | build: 19 | runs-on: ubuntu-latest 20 | steps: 21 | - uses: actions/checkout@v1 22 | - uses: actions/setup-node@v1 23 | with: 24 | node-version: 12 25 | registry-url: https://registry.npmjs.org/ 26 | - run: npm install 27 | - run: npm run build 28 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish 2 | 3 | on: 4 | release: 5 | types: [created] 6 | 7 | jobs: 8 | publish: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v1 12 | - uses: actions/setup-node@v1 13 | with: 14 | node-version: 12 15 | registry-url: https://registry.npmjs.org/ 16 | - run: npm install 17 | - run: npm publish --access public 18 | env: 19 | NODE_AUTH_TOKEN: ${{secrets.NPM_AUTH_TOKEN}} 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # node files 2 | dist 3 | node_modules 4 | 5 | # iOS files 6 | Pods 7 | Podfile.lock 8 | Build 9 | xcuserdata 10 | 11 | # macOS files 12 | .DS_Store 13 | 14 | 15 | 16 | # Based on Android gitignore template: https://github.com/github/gitignore/blob/HEAD/Android.gitignore 17 | 18 | # Built application files 19 | *.apk 20 | *.ap_ 21 | 22 | # Files for the ART/Dalvik VM 23 | *.dex 24 | 25 | # Java class files 26 | *.class 27 | 28 | # Generated files 29 | bin 30 | gen 31 | out 32 | 33 | # Gradle files 34 | .gradle 35 | build 36 | 37 | # Local configuration file (sdk path, etc) 38 | local.properties 39 | 40 | # Proguard folder generated by Eclipse 41 | proguard 42 | 43 | # Log Files 44 | *.log 45 | 46 | # Android Studio Navigation editor temp files 47 | .navigation 48 | 49 | # Android Studio captures folder 50 | captures 51 | 52 | # IntelliJ 53 | *.iml 54 | .idea 55 | 56 | # Keystore files 57 | # Uncomment the following line if you do not want to check your keystore files in. 58 | #*.jks 59 | 60 | # External native build folder generated in Android Studio 2.2 and later 61 | .externalNativeBuild 62 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # node files 2 | dist/ 3 | node_modules/ 4 | 5 | # iOS files 6 | Pods 7 | Build 8 | xcuserdata 9 | 10 | # macOS files 11 | .DS_Store 12 | 13 | 14 | 15 | # Based on Android gitignore template: https://github.com/github/gitignore/blob/master/Android.gitignore 16 | 17 | # Built application files 18 | *.apk 19 | *.ap_ 20 | 21 | # Files for the ART/Dalvik VM 22 | *.dex 23 | 24 | # Java class files 25 | *.class 26 | 27 | # Generated files 28 | bin/ 29 | gen/ 30 | out/ 31 | 32 | # Gradle files 33 | .gradle/ 34 | build/ 35 | 36 | # Local configuration file (sdk path, etc) 37 | local.properties 38 | 39 | # Proguard folder generated by Eclipse 40 | proguard/ 41 | 42 | # Log Files 43 | *.log 44 | 45 | # Android Studio Navigation editor temp files 46 | .navigation/ 47 | 48 | # Android Studio captures folder 49 | captures/ 50 | 51 | # IntelliJ 52 | *.iml 53 | .idea 54 | 55 | # Keystore files 56 | # Uncomment the following line if you do not want to check your keystore files in. 57 | #*.jks 58 | 59 | # External native build folder generated in Android Studio 2.2 and later 60 | .externalNativeBuild 61 | -------------------------------------------------------------------------------- /CapacitorCommunityGoogleMaps.podspec: -------------------------------------------------------------------------------- 1 | require 'json' 2 | 3 | package = JSON.parse(File.read(File.join(__dir__, 'package.json'))) 4 | 5 | Pod::Spec.new do |s| 6 | s.name = 'CapacitorCommunityGoogleMaps' 7 | s.version = package['version'] 8 | s.summary = package['description'] 9 | s.license = package['license'] 10 | s.homepage = package['repository']['url'] 11 | s.author = package['author'] 12 | s.source = { :git => package['repository']['url'], :tag => s.version.to_s } 13 | s.source_files = 'ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}' 14 | s.ios.deployment_target = '13.0' 15 | s.dependency 'Capacitor' 16 | s.dependency 'GoogleMaps' 17 | s.dependency 'SDWebImage' 18 | s.static_framework = true 19 | end 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Hemang Kumar 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |


2 | 3 |

Google Maps

4 |

@capacitor-community/google-maps

5 |

Capacitor Plugin using native Google Maps SDK for Android and iOS.

6 |

7 |

8 | 9 |

10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 |

21 | 22 | ## Purpose 23 | 24 | Under the hood this package makes use of the Native SDKs for Google Maps, written in Java and Swift for both Android and iOS respectively. In comparison to the JavaScript SDK the Native SDKs have much better performance and are more cost effective1. It also adds support for offline caching. 25 | 26 | [1] The "Dynamic Maps" SKU for the Native SDKs is offered free of charge by Google ([Native Dynamic Maps pricing](https://developers.google.com/maps/billing-and-pricing/pricing#mobile-dynamic)), as opposed to the on-demand pricing model for the JavaScript SDK ([JavaScript Dynamic Maps pricing](https://developers.google.com/maps/billing-and-pricing/pricing#dynamic-maps)). 27 | 28 | ## Documentation 29 | 30 | Extensive documentation is available [here](https://capacitor-community.github.io/google-maps/). 31 | 32 | ## Shortcuts 33 | 34 | - [Documentation homepage](https://capacitor-community.github.io/google-maps/) 35 | 36 | - [Installation](https://capacitor-community.github.io/google-maps/#/getting-started/installation) 37 | 38 | - [Should you use this plugin](https://capacitor-community.github.io/google-maps/#/about/should-you-use-this-plugin) 39 | 40 | - [API reference](https://capacitor-community.github.io/google-maps/#/api) 41 | 42 | - [Examples](https://github.com/capacitor-community/google-maps-examples) 43 | -------------------------------------------------------------------------------- /android/.npmignore: -------------------------------------------------------------------------------- 1 | /build 2 | /.idea -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | ext { 2 | junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2' 3 | androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.6.1' 4 | androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.5' 5 | androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.5.1' 6 | } 7 | 8 | buildscript { 9 | repositories { 10 | google() 11 | mavenCentral() 12 | } 13 | dependencies { 14 | classpath 'com.android.tools.build:gradle:8.2.1' 15 | } 16 | } 17 | 18 | apply plugin: 'com.android.library' 19 | 20 | android { 21 | namespace "com.hemangkumar.capacitorgooglemaps.capacitorgooglemaps" 22 | compileSdk project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 34 23 | defaultConfig { 24 | minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 22 25 | targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 34 26 | versionCode 1 27 | versionName "1.0" 28 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 29 | } 30 | buildTypes { 31 | release { 32 | minifyEnabled false 33 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 34 | } 35 | } 36 | lintOptions { 37 | abortOnError false 38 | } 39 | } 40 | 41 | repositories { 42 | google() 43 | mavenCentral() 44 | } 45 | 46 | 47 | dependencies { 48 | implementation fileTree(dir: 'libs', include: ['*.jar']) 49 | implementation project(':capacitor-android') 50 | implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion" 51 | testImplementation "junit:junit:$junitVersion" 52 | androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion" 53 | androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion" 54 | implementation 'com.google.android.gms:play-services-maps:18.1.0' 55 | implementation 'com.github.bumptech.glide:glide:4.13.0' 56 | implementation 'com.caverock:androidsvg-aar:1.4' 57 | } 58 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | org.gradle.jvmargs=-Xmx1536m 13 | 14 | # When configured, Gradle will run in incubating parallel mode. 15 | # This option should only be used with decoupled projects. More details, visit 16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 17 | # org.gradle.parallel=true 18 | 19 | # Supports AndroidX 20 | android.useAndroidX=true 21 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capacitor-community/google-maps/d82f24298c06bc95fd64eb202b1ceb3fff716582/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-all.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /android/gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | # 21 | # Gradle start up script for POSIX generated by Gradle. 22 | # 23 | # Important for running: 24 | # 25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 26 | # noncompliant, but you have some other compliant shell such as ksh or 27 | # bash, then to run this script, type that shell name before the whole 28 | # command line, like: 29 | # 30 | # ksh Gradle 31 | # 32 | # Busybox and similar reduced shells will NOT work, because this script 33 | # requires all of these POSIX shell features: 34 | # * functions; 35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 37 | # * compound commands having a testable exit status, especially «case»; 38 | # * various built-in commands including «command», «set», and «ulimit». 39 | # 40 | # Important for patching: 41 | # 42 | # (2) This script targets any POSIX shell, so it avoids extensions provided 43 | # by Bash, Ksh, etc; in particular arrays are avoided. 44 | # 45 | # The "traditional" practice of packing multiple parameters into a 46 | # space-separated string is a well documented source of bugs and security 47 | # problems, so this is (mostly) avoided, by progressively accumulating 48 | # options in "$@", and eventually passing that to Java. 49 | # 50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 52 | # see the in-line comments for details. 53 | # 54 | # There are tweaks for specific operating systems such as AIX, CygWin, 55 | # Darwin, MinGW, and NonStop. 56 | # 57 | # (3) This script is generated from the Groovy template 58 | # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 59 | # within the Gradle project. 60 | # 61 | # You can find Gradle at https://github.com/gradle/gradle/. 62 | # 63 | ############################################################################## 64 | 65 | # Attempt to set APP_HOME 66 | 67 | # Resolve links: $0 may be a link 68 | app_path=$0 69 | 70 | # Need this for daisy-chained symlinks. 71 | while 72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 73 | [ -h "$app_path" ] 74 | do 75 | ls=$( ls -ld "$app_path" ) 76 | link=${ls#*' -> '} 77 | case $link in #( 78 | /*) app_path=$link ;; #( 79 | *) app_path=$APP_HOME$link ;; 80 | esac 81 | done 82 | 83 | # This is normally unused 84 | # shellcheck disable=SC2034 85 | APP_BASE_NAME=${0##*/} 86 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit 87 | 88 | # Use the maximum available, or set MAX_FD != -1 to use that value. 89 | MAX_FD=maximum 90 | 91 | warn () { 92 | echo "$*" 93 | } >&2 94 | 95 | die () { 96 | echo 97 | echo "$*" 98 | echo 99 | exit 1 100 | } >&2 101 | 102 | # OS specific support (must be 'true' or 'false'). 103 | cygwin=false 104 | msys=false 105 | darwin=false 106 | nonstop=false 107 | case "$( uname )" in #( 108 | CYGWIN* ) cygwin=true ;; #( 109 | Darwin* ) darwin=true ;; #( 110 | MSYS* | MINGW* ) msys=true ;; #( 111 | NONSTOP* ) nonstop=true ;; 112 | esac 113 | 114 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 115 | 116 | 117 | # Determine the Java command to use to start the JVM. 118 | if [ -n "$JAVA_HOME" ] ; then 119 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 120 | # IBM's JDK on AIX uses strange locations for the executables 121 | JAVACMD=$JAVA_HOME/jre/sh/java 122 | else 123 | JAVACMD=$JAVA_HOME/bin/java 124 | fi 125 | if [ ! -x "$JAVACMD" ] ; then 126 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 127 | 128 | Please set the JAVA_HOME variable in your environment to match the 129 | location of your Java installation." 130 | fi 131 | else 132 | JAVACMD=java 133 | if ! command -v java >/dev/null 2>&1 134 | then 135 | die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 136 | 137 | Please set the JAVA_HOME variable in your environment to match the 138 | location of your Java installation." 139 | fi 140 | fi 141 | 142 | # Increase the maximum file descriptors if we can. 143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 144 | case $MAX_FD in #( 145 | max*) 146 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 147 | # shellcheck disable=SC3045 148 | MAX_FD=$( ulimit -H -n ) || 149 | warn "Could not query maximum file descriptor limit" 150 | esac 151 | case $MAX_FD in #( 152 | '' | soft) :;; #( 153 | *) 154 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 155 | # shellcheck disable=SC3045 156 | ulimit -n "$MAX_FD" || 157 | warn "Could not set maximum file descriptor limit to $MAX_FD" 158 | esac 159 | fi 160 | 161 | # Collect all arguments for the java command, stacking in reverse order: 162 | # * args from the command line 163 | # * the main class name 164 | # * -classpath 165 | # * -D...appname settings 166 | # * --module-path (only if needed) 167 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 168 | 169 | # For Cygwin or MSYS, switch paths to Windows format before running java 170 | if "$cygwin" || "$msys" ; then 171 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 172 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 173 | 174 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 175 | 176 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 177 | for arg do 178 | if 179 | case $arg in #( 180 | -*) false ;; # don't mess with options #( 181 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 182 | [ -e "$t" ] ;; #( 183 | *) false ;; 184 | esac 185 | then 186 | arg=$( cygpath --path --ignore --mixed "$arg" ) 187 | fi 188 | # Roll the args list around exactly as many times as the number of 189 | # args, so each arg winds up back in the position where it started, but 190 | # possibly modified. 191 | # 192 | # NB: a `for` loop captures its iteration list before it begins, so 193 | # changing the positional parameters here affects neither the number of 194 | # iterations, nor the values presented in `arg`. 195 | shift # remove old arg 196 | set -- "$@" "$arg" # push replacement arg 197 | done 198 | fi 199 | 200 | 201 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 202 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 203 | 204 | # Collect all arguments for the java command; 205 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of 206 | # shell script including quotes and variable substitutions, so put them in 207 | # double quotes to make sure that they get re-expanded; and 208 | # * put everything else in single quotes, so that it's not re-expanded. 209 | 210 | set -- \ 211 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 212 | -classpath "$CLASSPATH" \ 213 | org.gradle.wrapper.GradleWrapperMain \ 214 | "$@" 215 | 216 | # Stop when "xargs" is not available. 217 | if ! command -v xargs >/dev/null 2>&1 218 | then 219 | die "xargs is not available" 220 | fi 221 | 222 | # Use "xargs" to parse quoted args. 223 | # 224 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 225 | # 226 | # In Bash we could simply go: 227 | # 228 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 229 | # set -- "${ARGS[@]}" "$@" 230 | # 231 | # but POSIX shell has neither arrays nor command substitution, so instead we 232 | # post-process each arg (as a line of input to sed) to backslash-escape any 233 | # character that might be a shell metacharacter, then use eval to reverse 234 | # that process (while maintaining the separation between arguments), and wrap 235 | # the whole thing up as a single "set" statement. 236 | # 237 | # This will of course break if any of these variables contains a newline or 238 | # an unmatched quote. 239 | # 240 | 241 | eval "set -- $( 242 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 243 | xargs -n1 | 244 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 245 | tr '\n' ' ' 246 | )" '"$@"' 247 | 248 | exec "$JAVACMD" "$@" 249 | -------------------------------------------------------------------------------- /android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 48 | echo. 49 | echo Please set the JAVA_HOME variable in your environment to match the 50 | echo location of your Java installation. 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 62 | echo. 63 | echo Please set the JAVA_HOME variable in your environment to match the 64 | echo location of your Java installation. 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /android/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -keep public class * implements com.bumptech.glide.module.GlideModule 23 | -keep public class * extends com.bumptech.glide.module.AppGlideModule 24 | -keep public enum com.bumptech.glide.load.ImageHeaderParser$** { 25 | **[] $VALUES; 26 | public *; 27 | } 28 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':capacitor-android' 2 | project(':capacitor-android').projectDir = new File('../node_modules/@capacitor/android/capacitor') -------------------------------------------------------------------------------- /android/src/androidTest/java/com/getcapacitor/android/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.getcapacitor.android; 2 | 3 | import android.content.Context; 4 | 5 | import androidx.test.platform.app.InstrumentationRegistry; 6 | import androidx.test.ext.junit.runners.AndroidJUnit4; 7 | 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | 11 | import static org.junit.Assert.*; 12 | 13 | /** 14 | * Instrumented test, which will execute on an Android device. 15 | * 16 | * @see Testing documentation 17 | */ 18 | @RunWith(AndroidJUnit4.class) 19 | public class ExampleInstrumentedTest { 20 | @Test 21 | public void useAppContext() throws Exception { 22 | // Context of the app under test. 23 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); 24 | 25 | assertEquals("com.getcapacitor.android", appContext.getPackageName()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /android/src/main/java/com/hemangkumar/capacitorgooglemaps/AsyncIconLoader.java: -------------------------------------------------------------------------------- 1 | package com.hemangkumar.capacitorgooglemaps; 2 | 3 | import android.graphics.Bitmap; 4 | import android.graphics.Canvas; 5 | import android.graphics.Picture; 6 | import android.graphics.drawable.Drawable; 7 | import android.graphics.drawable.PictureDrawable; 8 | import android.text.TextUtils; 9 | import android.util.LruCache; 10 | 11 | import androidx.annotation.NonNull; 12 | import androidx.annotation.Nullable; 13 | import androidx.fragment.app.FragmentActivity; 14 | 15 | import com.bumptech.glide.Glide; 16 | import com.bumptech.glide.RequestBuilder; 17 | import com.bumptech.glide.request.target.CustomTarget; 18 | import com.bumptech.glide.request.transition.Transition; 19 | import com.caverock.androidsvg.SVG; 20 | import com.caverock.androidsvg.SVGParseException; 21 | import com.getcapacitor.JSObject; 22 | 23 | import java.io.File; 24 | import java.io.FileInputStream; 25 | import java.io.IOException; 26 | import java.io.InputStream; 27 | import java.util.Locale; 28 | 29 | class AsyncIconLoader { 30 | 31 | private static final int PICTURE_DOWNLOAD_TIMEOUT = 3000; 32 | private static final int FAST_CACHE_SIZE_ENTRIES = 32; 33 | 34 | private static final LruCache bitmapCache = new LruCache<>(FAST_CACHE_SIZE_ENTRIES); 35 | 36 | public interface OnIconReady { 37 | void onReady(@Nullable Bitmap bitmap); 38 | } 39 | 40 | private final IconDescriptor iconDescriptor; 41 | private final FragmentActivity activity; 42 | 43 | public AsyncIconLoader(JSObject jsIconDescriptor, FragmentActivity activity) { 44 | this.iconDescriptor = new IconDescriptor(jsIconDescriptor); 45 | this.activity = activity; 46 | } 47 | 48 | public void load(OnIconReady onIconReady) { 49 | 50 | if (iconDescriptor == null || TextUtils.isEmpty(iconDescriptor.url)) { 51 | onIconReady.onReady(null); 52 | return; 53 | } 54 | String url = iconDescriptor.url.toLowerCase(Locale.ROOT); 55 | Bitmap cachedBitmap = bitmapCache.get(url); 56 | if (cachedBitmap != null) { 57 | onIconReady.onReady(cachedBitmap); 58 | return; 59 | } 60 | if (url.endsWith(".svg")) { 61 | loadSvg(onIconReady); 62 | } else { 63 | loadBitmap(onIconReady); 64 | } 65 | } 66 | 67 | private void loadBitmap(final OnIconReady onIconReady) { 68 | RequestBuilder builder = Glide.with(activity) 69 | .asBitmap() 70 | .load(iconDescriptor.url) 71 | .timeout(PICTURE_DOWNLOAD_TIMEOUT); 72 | scaleImageOptional(builder).into( 73 | new CustomTarget() { 74 | // It will be called when the resource load has finished. 75 | @Override 76 | public void onResourceReady( 77 | @NonNull Bitmap bitmap, 78 | @Nullable Transition transition) { 79 | bitmapCache.put(iconDescriptor.url, bitmap); 80 | onIconReady.onReady(bitmap); 81 | } 82 | 83 | // It is called when a loadAll is cancelled and its resources are freed. 84 | @Override 85 | public void onLoadCleared(@Nullable Drawable placeholder) { 86 | // Use default marker 87 | onIconReady.onReady(null); 88 | } 89 | 90 | // It is called when can't get image from network AND from a local cache. 91 | @Override 92 | public void onLoadFailed(@Nullable Drawable errorDrawable) { 93 | // Use default marker 94 | onIconReady.onReady(null); 95 | } 96 | } 97 | ); 98 | } 99 | 100 | private void loadSvg(final OnIconReady onIconReady) { 101 | Glide.with(activity).downloadOnly().load(iconDescriptor.url).into(new CustomTarget() { 102 | @Override 103 | public void onResourceReady(@NonNull File resource, @Nullable Transition transition) { 104 | try { 105 | try (InputStream inputStream = new FileInputStream(resource)) { 106 | SVG svg = SVG.getFromInputStream(inputStream); 107 | svg.setDocumentWidth(iconDescriptor.size.getWidth()); 108 | svg.setDocumentHeight(iconDescriptor.size.getHeight()); 109 | Picture picture = svg.renderToPicture(); 110 | Bitmap bitmap = pictureToBitmap(picture); 111 | bitmapCache.put(iconDescriptor.url, bitmap); 112 | onIconReady.onReady(bitmap); 113 | } 114 | } catch (IOException | SVGParseException exception) { 115 | onIconReady.onReady(null); 116 | } 117 | } 118 | 119 | @Override 120 | public void onLoadCleared(@Nullable Drawable placeholder) { 121 | onIconReady.onReady(null); 122 | } 123 | 124 | @Override 125 | public void onLoadFailed(@Nullable Drawable errorDrawable) { 126 | onIconReady.onReady(null); 127 | } 128 | }); 129 | } 130 | 131 | private RequestBuilder scaleImageOptional( 132 | RequestBuilder builder) { 133 | return builder.override(iconDescriptor.size.getWidth(), iconDescriptor.size.getHeight()); 134 | } 135 | 136 | private static Bitmap pictureToBitmap(Picture picture) { 137 | PictureDrawable pictureDrawable = new PictureDrawable(picture); 138 | return pictureDrawableToBitmap(pictureDrawable); 139 | } 140 | 141 | private static Bitmap pictureDrawableToBitmap(PictureDrawable pictureDrawable) { 142 | Bitmap bmp = Bitmap.createBitmap( 143 | pictureDrawable.getIntrinsicWidth(), 144 | pictureDrawable.getIntrinsicHeight(), 145 | Bitmap.Config.ARGB_8888); 146 | Canvas canvas = new Canvas(bmp); 147 | canvas.drawPicture(pictureDrawable.getPicture()); 148 | return bmp; 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /android/src/main/java/com/hemangkumar/capacitorgooglemaps/BoundingRect.java: -------------------------------------------------------------------------------- 1 | package com.hemangkumar.capacitorgooglemaps; 2 | 3 | import androidx.annotation.Nullable; 4 | 5 | import com.getcapacitor.JSObject; 6 | 7 | public class BoundingRect { 8 | public Integer width; 9 | public Integer height; 10 | public Integer x; 11 | public Integer y; 12 | 13 | public BoundingRect() { 14 | this.width = 500; 15 | this.height = 500; 16 | this.x = 0; 17 | this.y = 0; 18 | } 19 | 20 | public void updateFromJSObject(@Nullable JSObject jsObject) { 21 | if (jsObject != null) { 22 | if (jsObject.has("width")) { 23 | this.width = jsObject.getInteger("width"); 24 | } 25 | if (jsObject.has("height")) { 26 | this.height = jsObject.getInteger("height"); 27 | } 28 | if (jsObject.has("x")) { 29 | this.x = jsObject.getInteger("x"); 30 | } 31 | if (jsObject.has("y")) { 32 | this.y = jsObject.getInteger("y"); 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /android/src/main/java/com/hemangkumar/capacitorgooglemaps/CustomMapViewEvents.java: -------------------------------------------------------------------------------- 1 | package com.hemangkumar.capacitorgooglemaps; 2 | 3 | import com.getcapacitor.JSObject; 4 | 5 | public interface CustomMapViewEvents { 6 | void onMapReady(String callbackId, JSObject result); 7 | 8 | void resultForCallbackId(String callbackId, JSObject result); 9 | } 10 | -------------------------------------------------------------------------------- /android/src/main/java/com/hemangkumar/capacitorgooglemaps/CustomMarker.java: -------------------------------------------------------------------------------- 1 | package com.hemangkumar.capacitorgooglemaps; 2 | 3 | import androidx.annotation.NonNull; 4 | import androidx.annotation.Nullable; 5 | import androidx.core.util.Consumer; 6 | import androidx.fragment.app.FragmentActivity; 7 | 8 | import com.getcapacitor.JSObject; 9 | import com.google.android.gms.maps.GoogleMap; 10 | import com.google.android.gms.maps.model.BitmapDescriptor; 11 | import com.google.android.gms.maps.model.BitmapDescriptorFactory; 12 | import com.google.android.gms.maps.model.LatLng; 13 | import com.google.android.gms.maps.model.Marker; 14 | import com.google.android.gms.maps.model.MarkerOptions; 15 | 16 | import java.util.UUID; 17 | 18 | public class CustomMarker { 19 | // generate id for the just added marker, 20 | // put this marker into a hashmap with the corresponding id, 21 | // so we can retrieve the marker by id later on 22 | public String markerId = UUID.randomUUID().toString(); 23 | 24 | private final MarkerOptions markerOptions = new MarkerOptions(); 25 | private JSObject tag = new JSObject(); 26 | private JSObject iconDescriptor; 27 | 28 | public void asyncLoadIcon( 29 | @NonNull FragmentActivity activity, 30 | @Nullable Consumer consumer) { 31 | new AsyncIconLoader(iconDescriptor, activity) 32 | .load((bitmap) -> { 33 | BitmapDescriptor bitmapDescriptor; 34 | if (bitmap != null) { 35 | bitmapDescriptor = BitmapDescriptorFactory.fromBitmap(bitmap); 36 | } else { 37 | bitmapDescriptor = null; 38 | } 39 | 40 | if (consumer != null) { 41 | consumer.accept(bitmapDescriptor); 42 | } 43 | }); 44 | } 45 | 46 | public void updateFromJSObject(JSObject marker) { 47 | final JSObject position = JSObjectDefaults.getJSObjectSafe(marker, "position", new JSObject()); 48 | final Double latitude = JSObjectDefaults.getDoubleSafe(position, "latitude", 0d); 49 | final Double longitude = JSObjectDefaults.getDoubleSafe(position, "longitude", 0d); 50 | LatLng latLng = new LatLng(latitude, longitude); 51 | 52 | final JSObject preferences = JSObjectDefaults.getJSObjectSafe(marker, "preferences", new JSObject()); 53 | final String title = preferences.getString("title", ""); 54 | final String snippet = preferences.getString("snippet", ""); 55 | final Float opacity = JSObjectDefaults.getFloatSafe(preferences, "opacity", 1f); 56 | final Boolean isFlat = JSObjectDefaults.getBooleanSafe(preferences,"isFlat", false); 57 | final Boolean isDraggable = JSObjectDefaults.getBooleanSafe(preferences,"isDraggable", false); 58 | final Integer zIndex = JSObjectDefaults.getIntegerSafe(preferences,"zIndex", 0); 59 | 60 | final JSObject anchor = JSObjectDefaults.getJSObjectSafe(preferences, "anchor", new JSObject()); 61 | final Float anchorX = JSObjectDefaults.getFloatSafe(anchor, "x", 0.5f); 62 | final Float anchorY = JSObjectDefaults.getFloatSafe(anchor, "y", 1f); 63 | 64 | this.markerOptions.position(latLng); 65 | this.markerOptions.title(title); 66 | this.markerOptions.snippet(snippet); 67 | this.markerOptions.alpha(opacity); 68 | this.markerOptions.flat(isFlat); 69 | this.markerOptions.draggable(isDraggable); 70 | this.markerOptions.zIndex(zIndex); 71 | this.markerOptions.anchor(anchorX, anchorY); 72 | 73 | this.setMetadata(JSObjectDefaults.getJSObjectSafe(preferences, "metadata", new JSObject())); 74 | 75 | iconDescriptor = JSObjectDefaults.getJSObjectSafe(preferences, "icon", new JSObject()); 76 | } 77 | 78 | public void addToMap(FragmentActivity activity, GoogleMap googleMap, @Nullable Consumer consumer) { 79 | asyncLoadIcon( 80 | activity, 81 | (BitmapDescriptor bitmapDescriptor) -> { 82 | markerOptions.icon(bitmapDescriptor); 83 | Marker marker = googleMap.addMarker(markerOptions); 84 | marker.setTag(tag); 85 | 86 | if (consumer != null) { 87 | consumer.accept(marker); 88 | } 89 | }); 90 | } 91 | 92 | private void setMetadata(@NonNull JSObject jsObject) { 93 | JSObject tag = new JSObject(); 94 | // set id to tag 95 | tag.put("markerId", this.markerId); 96 | // set anchor to tag (because it cannot be retrieved from a marker instance) 97 | JSObject anchorResult = new JSObject(); 98 | anchorResult.put("x", this.markerOptions.getAnchorU()); 99 | anchorResult.put("y", this.markerOptions.getAnchorV()); 100 | tag.put("anchor", anchorResult); 101 | // then set metadata to tag 102 | tag.put("metadata", jsObject); 103 | // save in tag variable 104 | this.tag = tag; 105 | } 106 | 107 | public static JSObject getResultForMarker(Marker marker, String mapId) { 108 | JSObject tag = null; 109 | 110 | try { 111 | tag = (JSObject) marker.getTag(); 112 | } catch (Exception e) { 113 | e.printStackTrace(); 114 | } finally { 115 | tag = tag != null ? tag : new JSObject(); 116 | } 117 | 118 | // initialize JSObjects to return 119 | JSObject result = new JSObject(); 120 | JSObject markerResult = new JSObject(); 121 | JSObject positionResult = new JSObject(); 122 | JSObject preferencesResult = new JSObject(); 123 | 124 | result.put("marker", markerResult); 125 | markerResult.put("position", positionResult); 126 | markerResult.put("preferences", preferencesResult); 127 | 128 | // get map id 129 | markerResult.put("mapId", mapId); 130 | 131 | // get id 132 | String markerId = tag.optString("markerId", marker.getId()); 133 | markerResult.put("markerId", markerId); 134 | 135 | // get position values 136 | positionResult.put("latitude", marker.getPosition().latitude); 137 | positionResult.put("longitude", marker.getPosition().longitude); 138 | 139 | // get preferences 140 | preferencesResult.put("title", marker.getTitle()); 141 | preferencesResult.put("snippet", marker.getSnippet()); 142 | preferencesResult.put("opacity", marker.getAlpha()); 143 | preferencesResult.put("isFlat", marker.isFlat()); 144 | preferencesResult.put("isDraggable", marker.isDraggable()); 145 | preferencesResult.put("zIndex", marker.getZIndex()); 146 | // anchor values 147 | JSObject anchorResult = JSObjectDefaults.getJSObjectSafe(tag, "anchor", new JSObject()); 148 | preferencesResult.put("anchor", anchorResult); 149 | // metadata 150 | JSObject metadata = JSObjectDefaults.getJSObjectSafe(tag, "metadata", new JSObject()); 151 | preferencesResult.put("metadata", metadata); 152 | 153 | return result; 154 | } 155 | 156 | } 157 | -------------------------------------------------------------------------------- /android/src/main/java/com/hemangkumar/capacitorgooglemaps/CustomPolygon.java: -------------------------------------------------------------------------------- 1 | package com.hemangkumar.capacitorgooglemaps; 2 | 3 | import androidx.annotation.NonNull; 4 | import androidx.annotation.Nullable; 5 | import androidx.core.util.Consumer; 6 | 7 | import com.getcapacitor.JSArray; 8 | import com.getcapacitor.JSObject; 9 | import com.getcapacitor.util.WebColor; 10 | import com.google.android.gms.maps.GoogleMap; 11 | import com.google.android.gms.maps.model.LatLng; 12 | import com.google.android.gms.maps.model.Polygon; 13 | import com.google.android.gms.maps.model.PolygonOptions; 14 | 15 | import org.json.JSONArray; 16 | import org.json.JSONObject; 17 | 18 | import java.util.ArrayList; 19 | import java.util.Collection; 20 | import java.util.List; 21 | import java.util.UUID; 22 | 23 | public class CustomPolygon { 24 | // generate id for the just added polygon, 25 | // put this polygon into a hashmap with the corresponding id, 26 | // so we can retrieve the polygon by id later on 27 | public final String polygonId = UUID.randomUUID().toString(); 28 | 29 | private final PolygonOptions polygonOptions = new PolygonOptions(); 30 | protected JSObject tag = new JSObject(); 31 | 32 | public void updateFromJSObject(JSObject polygon) { 33 | this.setPath(polygon.optJSONArray("path")); 34 | 35 | final JSObject preferences = JSObjectDefaults.getJSObjectSafe(polygon, "preferences", new JSObject()); 36 | 37 | this.setBasicFields(preferences); 38 | this.setHoles(preferences.optJSONArray("holes")); 39 | this.setMetadata(JSObjectDefaults.getJSObjectSafe(preferences, "metadata", new JSObject())); 40 | } 41 | 42 | public void addToMap(GoogleMap googleMap, @Nullable Consumer consumer) { 43 | final Polygon polygon = googleMap.addPolygon(polygonOptions); 44 | polygon.setTag(tag); 45 | 46 | if (consumer != null) { 47 | consumer.accept(polygon); 48 | } 49 | } 50 | 51 | private void setPath(@Nullable JSONArray path) { 52 | if (path != null) { 53 | List latLngList = getLatLngList(path); 54 | this.polygonOptions.addAll(latLngList); 55 | } 56 | } 57 | 58 | private void setHoles(@Nullable JSONArray holes) { 59 | if (holes != null) { 60 | for (int i = 0; i < holes.length(); i++) { 61 | // For each hole, get the path. 62 | JSONArray path = holes.optJSONArray(i); 63 | if (path != null) { 64 | List latLngList = getLatLngList(path); 65 | this.polygonOptions.addHole(latLngList); 66 | } 67 | } 68 | } 69 | } 70 | 71 | private static List getLatLngList(@NonNull JSONArray latLngArray) { 72 | List latLngList = new ArrayList<>(); 73 | 74 | for (int n = 0; n < latLngArray.length(); n++) { 75 | JSONObject latLngObject = latLngArray.optJSONObject(n); 76 | if (latLngObject != null) { 77 | LatLng latLng = getLatLng(latLngObject); 78 | latLngList.add(latLng); 79 | } 80 | } 81 | 82 | return latLngList; 83 | } 84 | 85 | private static LatLng getLatLng(@NonNull JSONObject latLngObject) { 86 | double latitude = latLngObject.optDouble("latitude", 0d); 87 | double longitude = latLngObject.optDouble("longitude", 0d); 88 | return new LatLng(latitude, longitude); 89 | } 90 | 91 | private void setBasicFields(@NonNull JSObject preferences) { 92 | final float strokeWidth = (float) preferences.optDouble("strokeWidth", 10); 93 | final int strokeColor = WebColor.parseColor(preferences.optString("strokeColor", "#000000")); 94 | final int fillColor = WebColor.parseColor(preferences.optString("fillColor", "#00000000")); 95 | final float zIndex = (float) preferences.optDouble("zIndex", 0); 96 | final boolean isVisible = preferences.optBoolean("isVisible", true); 97 | final boolean isGeodesic = preferences.optBoolean("isGeodesic", false); 98 | final boolean isClickable = preferences.optBoolean("isClickable", false); 99 | 100 | polygonOptions.strokeWidth(strokeWidth); 101 | polygonOptions.strokeColor(strokeColor); 102 | polygonOptions.fillColor(fillColor); 103 | polygonOptions.zIndex(zIndex); 104 | polygonOptions.visible(isVisible); 105 | polygonOptions.geodesic(isGeodesic); 106 | polygonOptions.clickable(isClickable); 107 | } 108 | 109 | private void setMetadata(@NonNull JSObject jsObject) { 110 | JSObject tag = new JSObject(); 111 | tag.put("id", this.polygonId); 112 | tag.put("metadata", jsObject); 113 | this.tag = tag; 114 | } 115 | 116 | public JSObject getResultForPolygon(Polygon polygon, String mapId) { 117 | JSObject tag = null; 118 | 119 | try { 120 | tag = (JSObject) polygon.getTag(); 121 | } catch (Exception e) { 122 | e.printStackTrace(); 123 | } finally { 124 | tag = tag != null ? tag : new JSObject(); 125 | } 126 | 127 | // initialize JSObjects to return 128 | JSObject result = new JSObject(); 129 | JSObject polygonResult = new JSObject(); 130 | JSObject preferencesResult = new JSObject(); 131 | 132 | result.put("polygon", polygonResult); 133 | polygonResult.put("preferences", preferencesResult); 134 | 135 | // get map id 136 | polygonResult.put("mapId", mapId); 137 | 138 | // get id 139 | String polygonId = tag.optString("polygonId", polygon.getId()); 140 | polygonResult.put("polygonId", polygonId); 141 | 142 | // get path values 143 | JSArray path = latLngsToJSArray(polygon.getPoints()); 144 | polygonResult.put("path", path); 145 | 146 | // get preferences 147 | preferencesResult.put("strokeWidth", polygon.getStrokeWidth()); 148 | preferencesResult.put("strokeColor", colorToString(polygon.getStrokeColor())); 149 | preferencesResult.put("fillColor", colorToString(polygon.getFillColor())); 150 | preferencesResult.put("zIndex", polygon.getZIndex()); 151 | preferencesResult.put("isVisible", polygon.isVisible()); 152 | preferencesResult.put("isGeodesic", polygon.isGeodesic()); 153 | preferencesResult.put("isClickable", polygon.isClickable()); 154 | // holes 155 | JSArray holesResult = new JSArray(); 156 | for (List hole : polygon.getHoles()) { 157 | JSArray holeArray = latLngsToJSArray(hole); 158 | holesResult.put(holeArray); 159 | } 160 | if (holesResult.length() > 0) { 161 | preferencesResult.put("holes", holesResult); 162 | } 163 | // metadata 164 | JSObject metadata = JSObjectDefaults.getJSObjectSafe(tag, "metadata", new JSObject()); 165 | preferencesResult.put("metadata", metadata); 166 | 167 | return result; 168 | } 169 | 170 | private static JSArray latLngsToJSArray(Collection positions) { 171 | JSArray jsPositions = new JSArray(); 172 | for (LatLng pos : positions) { 173 | JSObject jsPos = latLngToJSObject(pos); 174 | jsPositions.put(jsPos); 175 | } 176 | return jsPositions; 177 | } 178 | 179 | private static JSObject latLngToJSObject(LatLng latLng) { 180 | JSObject jsPos = new JSObject(); 181 | jsPos.put("latitude", latLng.latitude); 182 | jsPos.put("longitude", latLng.longitude); 183 | return jsPos; 184 | } 185 | 186 | private static String colorToString(int color) { 187 | int r = ((color >> 16) & 0xff); 188 | int g = ((color >> 8) & 0xff); 189 | int b = ((color) & 0xff); 190 | int a = ((color >> 24) & 0xff); 191 | if (a != 255) { 192 | return String.format("#%02X%02X%02X%02X", a, r, g, b); 193 | } else { 194 | return String.format("#%02X%02X%02X", r, g, b); 195 | } 196 | } 197 | 198 | } 199 | -------------------------------------------------------------------------------- /android/src/main/java/com/hemangkumar/capacitorgooglemaps/IconDescriptor.java: -------------------------------------------------------------------------------- 1 | package com.hemangkumar.capacitorgooglemaps; 2 | 3 | import android.content.res.Resources; 4 | import android.util.Size; 5 | 6 | import androidx.annotation.NonNull; 7 | 8 | import com.getcapacitor.JSObject; 9 | 10 | class IconDescriptor { 11 | @NonNull 12 | public final String url; 13 | @NonNull 14 | public final Size size; 15 | 16 | private float density = Resources.getSystem().getDisplayMetrics().density; 17 | 18 | /** 19 | * Example source of JSObject: 20 | * { 21 | * url: 'https://www.google.com/favicon.ico', 22 | * size: { 23 | * width: 64, 24 | * height: 64 25 | * } 26 | * } 27 | * @param jsIcon is a JSObject icon representation 28 | * @return IconDescriptor 29 | */ 30 | public IconDescriptor(@NonNull final JSObject jsIcon) { 31 | url = jsIcon.optString("url", ""); 32 | 33 | final JSObject jsSize = JSObjectDefaults.getJSObjectSafe( 34 | jsIcon, 35 | "size", 36 | new JSObject()); 37 | 38 | size = new Size( 39 | (int) Math.round(jsSize.optDouble("width", 30) * density), 40 | (int) Math.round(jsSize.optDouble("height", 30) * density)); 41 | } 42 | } -------------------------------------------------------------------------------- /android/src/main/java/com/hemangkumar/capacitorgooglemaps/JSObjectDefaults.java: -------------------------------------------------------------------------------- 1 | package com.hemangkumar.capacitorgooglemaps; 2 | 3 | import androidx.annotation.NonNull; 4 | import androidx.annotation.Nullable; 5 | 6 | import com.getcapacitor.JSObject; 7 | import com.getcapacitor.PluginCall; 8 | 9 | import org.json.JSONException; 10 | 11 | import java.util.HashMap; 12 | 13 | public abstract class JSObjectDefaults { 14 | private final HashMap defaults; 15 | 16 | private final HashMap actualValues = new HashMap(){}; 17 | 18 | public JSObjectDefaults(HashMap defaults) { 19 | this.defaults = defaults; 20 | } 21 | 22 | private Object getObject(String key) { 23 | // get default value 24 | Object defaultObject = this.defaults.get(key); 25 | 26 | // then get actual value 27 | if (this.actualValues.containsKey(key)) { 28 | Object object = this.actualValues.get(key); 29 | if (object != null) { 30 | return object; 31 | } 32 | } 33 | 34 | if (defaultObject != null) { 35 | return defaultObject; 36 | } 37 | 38 | return null; 39 | } 40 | 41 | public boolean getBoolean(String key) { 42 | Object object = getObject(key); 43 | 44 | if (object != null) { 45 | return (boolean) object; 46 | } 47 | 48 | return false; 49 | } 50 | 51 | public void updateFromJSObject(@Nullable JSObject jsObject) { 52 | if (jsObject != null) { 53 | for (HashMap.Entry entry : defaults.entrySet()) { 54 | String key = entry.getKey(); 55 | Object defaultValue = entry.getValue(); 56 | 57 | if (defaultValue instanceof Boolean) { 58 | if (jsObject.has(key)) { 59 | Boolean newValue = jsObject.getBoolean(key, (Boolean) defaultValue); 60 | if (newValue == null) { 61 | newValue = (Boolean) defaultValue; 62 | } 63 | actualValues.put(key, (boolean) newValue); 64 | } 65 | } 66 | } 67 | } 68 | } 69 | 70 | @NonNull 71 | public static JSObject getJSObjectSafe(JSObject jsObject, @NonNull String name, @NonNull JSObject defaultValue) { 72 | JSObject returnedJsObject = jsObject.getJSObject(name); 73 | if (returnedJsObject != null) { 74 | return returnedJsObject; 75 | } 76 | return defaultValue; 77 | } 78 | 79 | @NonNull 80 | public static JSObject getJSObjectSafe(PluginCall call, @NonNull String name, @NonNull JSObject defaultValue) { 81 | if (call != null) { 82 | JSObject jsObject = call.getObject(name, defaultValue); 83 | if (jsObject != null) { 84 | return jsObject; 85 | } 86 | } 87 | return new JSObject(); 88 | } 89 | 90 | @NonNull 91 | public static Double getDoubleSafe(JSObject jsObject, @NonNull String name, @NonNull Double defaultValue) { 92 | try { 93 | return jsObject.getDouble(name); 94 | } catch (JSONException ignored) {} 95 | return defaultValue; 96 | } 97 | 98 | @NonNull 99 | public static Float getFloatSafe(JSObject jsObject, @NonNull String name, @NonNull Float defaultValue) { 100 | Double returnedDouble = JSObjectDefaults.getDoubleSafe(jsObject, name, (double) defaultValue); 101 | return returnedDouble.floatValue(); 102 | } 103 | 104 | @NonNull 105 | public static Integer getIntegerSafe(JSObject jsObject, @NonNull String name, @NonNull Integer defaultValue) { 106 | Integer returnedInteger = jsObject.getInteger(name); 107 | if (returnedInteger != null) { 108 | return returnedInteger; 109 | } 110 | return defaultValue; 111 | } 112 | 113 | @NonNull 114 | public static Boolean getBooleanSafe(JSObject jsObject, @NonNull String name, @NonNull Boolean defaultValue) { 115 | Boolean returnedBoolean = jsObject.getBoolean(name, false); 116 | if (returnedBoolean != null) { 117 | return returnedBoolean; 118 | } 119 | return defaultValue; 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /android/src/main/java/com/hemangkumar/capacitorgooglemaps/MapCameraPosition.java: -------------------------------------------------------------------------------- 1 | package com.hemangkumar.capacitorgooglemaps; 2 | 3 | import android.util.Log; 4 | 5 | import androidx.annotation.Nullable; 6 | 7 | import com.getcapacitor.JSObject; 8 | import com.google.android.gms.maps.model.CameraPosition; 9 | import com.google.android.gms.maps.model.LatLng; 10 | 11 | import org.json.JSONException; 12 | 13 | public class MapCameraPosition { 14 | public CameraPosition cameraPosition; 15 | 16 | public MapCameraPosition() { 17 | this.cameraPosition = CameraPosition.builder().target(new LatLng(0, 0)).build(); 18 | } 19 | 20 | public void updateFromJSObject(@Nullable JSObject cameraPosition, CameraPosition baseCameraPosition) { 21 | CameraPosition.Builder cameraPositionBuilder; 22 | if (baseCameraPosition != null) { 23 | // use given cameraPosition as the base 24 | cameraPositionBuilder = new CameraPosition.Builder(baseCameraPosition); 25 | } else { 26 | // use default cameraPosition as the base 27 | cameraPositionBuilder = new CameraPosition.Builder(); 28 | } 29 | 30 | LatLng latLng = null; 31 | if (cameraPosition != null) { 32 | JSObject target = cameraPosition.getJSObject("target"); 33 | 34 | if (target != null) { 35 | try { 36 | if (target.has("latitude") && target.has("longitude")) { 37 | double latitude = target.getDouble("latitude"); 38 | double longitude = target.getDouble("longitude"); 39 | 40 | latLng = new LatLng(latitude, longitude); 41 | cameraPositionBuilder.target(latLng); 42 | } 43 | } catch (JSONException e) { 44 | e.printStackTrace(); 45 | } 46 | } 47 | 48 | if (cameraPosition.has("bearing")) { 49 | try { 50 | float bearing = (float) cameraPosition.getDouble("bearing"); 51 | cameraPositionBuilder.bearing(bearing); 52 | } catch (JSONException e) { 53 | e.printStackTrace(); 54 | } 55 | } 56 | 57 | if (cameraPosition.has("tilt")) { 58 | try { 59 | float tilt = (float) cameraPosition.getDouble("tilt"); 60 | if (tilt < 0.0F || tilt > 90.0F) { 61 | Log.d("GoogleMap", "Tilt needs to be between 0 and 90 inclusive: " + tilt); 62 | } else { 63 | cameraPositionBuilder.tilt(tilt); 64 | } 65 | } catch (JSONException e) { 66 | e.printStackTrace(); 67 | } 68 | } 69 | 70 | if (cameraPosition.has("zoom")) { 71 | try { 72 | float zoom = (float) cameraPosition.getDouble("zoom"); 73 | cameraPositionBuilder.zoom(zoom); 74 | } catch (JSONException e) { 75 | e.printStackTrace(); 76 | } 77 | } 78 | } 79 | 80 | if (this.cameraPosition == null && latLng == null) { 81 | // at the very least a camera target should be set 82 | Log.d("GoogleMap", "Target of camera has been set to (0,0) automatically."); 83 | latLng = new LatLng(0, 0); 84 | cameraPositionBuilder.target(latLng); 85 | } 86 | 87 | try { 88 | this.cameraPosition = cameraPositionBuilder.build(); 89 | } catch (Exception e) { 90 | e.printStackTrace(); 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /android/src/main/java/com/hemangkumar/capacitorgooglemaps/MapPreferences.java: -------------------------------------------------------------------------------- 1 | package com.hemangkumar.capacitorgooglemaps; 2 | 3 | import androidx.annotation.Nullable; 4 | 5 | import com.getcapacitor.JSObject; 6 | import com.google.android.gms.maps.GoogleMapOptions; 7 | 8 | public class MapPreferences { 9 | public MapPreferencesGestures gestures; 10 | public MapPreferencesControls controls; 11 | public MapPreferencesAppearance appearance; 12 | 13 | public MapPreferences() { 14 | this.gestures = new MapPreferencesGestures(); 15 | this.controls = new MapPreferencesControls(); 16 | this.appearance = new MapPreferencesAppearance(); 17 | } 18 | 19 | public void updateFromJSObject(@Nullable JSObject preferences) { 20 | if (preferences != null) { 21 | // update gestures 22 | JSObject gesturesObject = preferences.getJSObject("gestures"); 23 | this.gestures.updateFromJSObject(gesturesObject); 24 | // update controls 25 | JSObject controlsObject = preferences.getJSObject("controls"); 26 | this.controls.updateFromJSObject(controlsObject); 27 | // update appearance 28 | JSObject appearanceObject = preferences.getJSObject("appearance"); 29 | this.appearance.updateFromJSObject(appearanceObject); 30 | } 31 | } 32 | 33 | public GoogleMapOptions generateGoogleMapOptions() { 34 | GoogleMapOptions googleMapOptions = new GoogleMapOptions(); 35 | 36 | // set gestures 37 | if (this.gestures != null) { 38 | googleMapOptions.rotateGesturesEnabled(gestures.getBoolean(MapPreferencesGestures.ROTATE_ALLOWED_KEY)); 39 | googleMapOptions.scrollGesturesEnabled(gestures.getBoolean(MapPreferencesGestures.SCROLL_ALLOWED_KEY)); 40 | googleMapOptions.scrollGesturesEnabledDuringRotateOrZoom(gestures.getBoolean(MapPreferencesGestures.SCROLL_ALLOWED_DURING_ROTATE_OR_ZOOM_KEY)); 41 | googleMapOptions.tiltGesturesEnabled(gestures.getBoolean(MapPreferencesGestures.TILT_ALLOWED_KEY)); 42 | googleMapOptions.zoomGesturesEnabled(gestures.getBoolean(MapPreferencesGestures.ZOOM_ALLOWED_KEY)); 43 | } 44 | 45 | // set controls 46 | if (this.controls != null) { 47 | googleMapOptions.compassEnabled(controls.getBoolean(MapPreferencesControls.COMPASS_BUTTON_KEY)); 48 | googleMapOptions.mapToolbarEnabled(controls.getBoolean(MapPreferencesControls.MAP_TOOLBAR_KEY)); 49 | googleMapOptions.zoomControlsEnabled(controls.getBoolean(MapPreferencesControls.ZOOM_BUTTONS_KEY)); 50 | 51 | // controls.isIndoorLevelPickerEnabled can only be set through `UiSettings` 52 | // controls.isMyLocationButtonEnabled can only be set through `UiSettings` 53 | } 54 | 55 | // set appearance 56 | if (this.appearance != null) { 57 | // set mapType 58 | googleMapOptions.mapType(this.appearance.type); 59 | 60 | // appearance.style can only be set through `GoogleMap` 61 | // appearance.isIndoorShown can only be set through `GoogleMap` 62 | // appearance.isBuildingsShown can only be set through `GoogleMap` 63 | // appearance.isMyLocationDotShown can only be set through `GoogleMap` 64 | // appearance.isTrafficShown can only be set through `GoogleMap` 65 | } 66 | 67 | return googleMapOptions; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /android/src/main/java/com/hemangkumar/capacitorgooglemaps/MapPreferencesAppearance.java: -------------------------------------------------------------------------------- 1 | package com.hemangkumar.capacitorgooglemaps; 2 | 3 | import androidx.annotation.Nullable; 4 | 5 | import com.getcapacitor.JSObject; 6 | import com.google.android.gms.maps.model.MapStyleOptions; 7 | 8 | public class MapPreferencesAppearance { 9 | public Integer type; 10 | public MapStyleOptions style; 11 | public Boolean isBuildingsShown; 12 | public Boolean isIndoorShown; 13 | public Boolean isMyLocationDotShown; 14 | public Boolean isTrafficShown; 15 | 16 | public static final String TYPE_KEY = "type"; 17 | public static final String STYLE_KEY = "style"; 18 | public static final String BUILDINGS_SHOWN_KEY = "isBuildingsShown"; 19 | public static final String INDOOR_SHOWN_KEY = "isIndoorShown"; 20 | public static final String MY_LOCATION_DOT_SHOWN_KEY = "isMyLocationDotShown"; 21 | public static final String TRAFFIC_SHOWN_KEY = "isTrafficShown"; 22 | 23 | public MapPreferencesAppearance() { 24 | this.type = 1; 25 | this.style = null; 26 | this.isBuildingsShown = true; 27 | this.isIndoorShown = true; 28 | this.isMyLocationDotShown = false; 29 | this.isTrafficShown = false; 30 | } 31 | 32 | public void updateFromJSObject(@Nullable JSObject jsObject) { 33 | if (jsObject != null) { 34 | // update mapType 35 | if (jsObject.has(TYPE_KEY)) { 36 | Integer mapType = jsObject.getInteger(TYPE_KEY, 1); 37 | if (mapType != null) { 38 | if (mapType < 0 || mapType > 4) { 39 | mapType = 1; 40 | } 41 | this.type = mapType; 42 | } 43 | } 44 | if (jsObject.has(STYLE_KEY)) { 45 | String mapStyle = jsObject.getString(STYLE_KEY, null); 46 | if (mapStyle == null) { 47 | this.style = null; 48 | } else { 49 | this.style = new MapStyleOptions(mapStyle); 50 | } 51 | } 52 | if (jsObject.has(BUILDINGS_SHOWN_KEY)) { 53 | this.isBuildingsShown = jsObject.getBool(BUILDINGS_SHOWN_KEY); 54 | } 55 | if (jsObject.has(INDOOR_SHOWN_KEY)) { 56 | this.isIndoorShown = jsObject.getBool(INDOOR_SHOWN_KEY); 57 | } 58 | if (jsObject.has(MY_LOCATION_DOT_SHOWN_KEY)) { 59 | this.isMyLocationDotShown = jsObject.getBool(MY_LOCATION_DOT_SHOWN_KEY); 60 | } 61 | if (jsObject.has(TRAFFIC_SHOWN_KEY)) { 62 | this.isTrafficShown = jsObject.getBool(TRAFFIC_SHOWN_KEY); 63 | } 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /android/src/main/java/com/hemangkumar/capacitorgooglemaps/MapPreferencesControls.java: -------------------------------------------------------------------------------- 1 | package com.hemangkumar.capacitorgooglemaps; 2 | 3 | import java.util.HashMap; 4 | 5 | public class MapPreferencesControls extends JSObjectDefaults { 6 | public static final String COMPASS_BUTTON_KEY = "isCompassButtonEnabled"; 7 | public static final String INDOOR_LEVEL_PICKER_KEY = "isIndoorLevelPickerEnabled"; 8 | public static final String MAP_TOOLBAR_KEY = "isMapToolbarEnabled"; 9 | public static final String MY_LOCATION_BUTTON_KEY = "isMyLocationButtonEnabled"; 10 | public static final String ZOOM_BUTTONS_KEY = "isZoomButtonsEnabled"; 11 | 12 | public MapPreferencesControls() { 13 | super(new HashMap(){{ 14 | put(COMPASS_BUTTON_KEY, Boolean.TRUE); 15 | put(INDOOR_LEVEL_PICKER_KEY, Boolean.FALSE); 16 | put(MAP_TOOLBAR_KEY, Boolean.FALSE); 17 | put(MY_LOCATION_BUTTON_KEY, Boolean.TRUE); 18 | put(ZOOM_BUTTONS_KEY, Boolean.FALSE); 19 | }}); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /android/src/main/java/com/hemangkumar/capacitorgooglemaps/MapPreferencesGestures.java: -------------------------------------------------------------------------------- 1 | package com.hemangkumar.capacitorgooglemaps; 2 | 3 | import java.util.HashMap; 4 | 5 | public class MapPreferencesGestures extends JSObjectDefaults { 6 | public static final String ROTATE_ALLOWED_KEY = "isRotateAllowed"; 7 | public static final String SCROLL_ALLOWED_KEY = "isScrollAllowed"; 8 | public static final String SCROLL_ALLOWED_DURING_ROTATE_OR_ZOOM_KEY = "isScrollAllowedDuringRotateOrZoom"; 9 | public static final String TILT_ALLOWED_KEY = "isTiltAllowed"; 10 | public static final String ZOOM_ALLOWED_KEY = "isZoomAllowed"; 11 | 12 | public MapPreferencesGestures() { 13 | super(new HashMap(){{ 14 | put(ROTATE_ALLOWED_KEY, Boolean.TRUE); 15 | put(SCROLL_ALLOWED_KEY, Boolean.TRUE); 16 | put(SCROLL_ALLOWED_DURING_ROTATE_OR_ZOOM_KEY, Boolean.TRUE); 17 | put(TILT_ALLOWED_KEY, Boolean.TRUE); 18 | put(ZOOM_ALLOWED_KEY, Boolean.TRUE); 19 | }}); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /android/src/main/java/com/hemangkumar/capacitorgooglemaps/MarkersAppender.java: -------------------------------------------------------------------------------- 1 | package com.hemangkumar.capacitorgooglemaps; 2 | 3 | import android.app.Activity; 4 | 5 | import androidx.core.util.Consumer; 6 | 7 | import com.getcapacitor.JSArray; 8 | import com.getcapacitor.JSObject; 9 | import com.getcapacitor.PluginCall; 10 | import com.google.android.gms.maps.model.Marker; 11 | 12 | import org.json.JSONException; 13 | import org.json.JSONObject; 14 | 15 | import java.util.ArrayList; 16 | import java.util.List; 17 | import java.util.concurrent.ExecutorService; 18 | import java.util.concurrent.Executors; 19 | import java.util.concurrent.atomic.AtomicBoolean; 20 | import java.util.concurrent.atomic.AtomicInteger; 21 | 22 | public class MarkersAppender { 23 | 24 | public static class AppenderException extends Exception { 25 | public AppenderException(String message, Throwable cause) { 26 | super(message, cause); 27 | } 28 | } 29 | 30 | private final Object syncRoot = new Object(); 31 | private final ExecutorService executorService = Executors.newFixedThreadPool(4); 32 | private Throwable currentException = null; 33 | private final AtomicBoolean isException = new AtomicBoolean(false); 34 | 35 | public void addMarkers(final CustomMapView customMapView, 36 | final JSArray jsMarkers, 37 | final Activity activity, 38 | Consumer resultConsumer) throws AppenderException { 39 | final List customMarkers = createCustomMarkers(jsMarkers); 40 | addCustomMarkers(customMarkers, customMapView, activity, resultConsumer); 41 | } 42 | 43 | private List createCustomMarkers(final JSArray jsMarkers) throws AppenderException { 44 | final int n = jsMarkers.length(); 45 | final List customMarkers = new ArrayList<>(n); 46 | final Object syncRoot = new Object(); 47 | final AtomicInteger nMarkersCounter = new AtomicInteger(0); 48 | isException.set(false); 49 | currentException = null; 50 | // prepare customMarkers as fast as possible. Really it doesn't increase the total 51 | // speed of this method :( noticeably. 52 | for (int i = 0; i < n; i++) { 53 | final int fi = i; 54 | if (isException.get()) { 55 | break; 56 | } 57 | executorService.execute(() -> { 58 | try { 59 | JSONObject jsonObject = (JSONObject) jsMarkers.get(fi); 60 | JSObject jsObject = JSObject.fromJSONObject(jsonObject); 61 | CustomMarker customMarker = new CustomMarker(); 62 | customMarker.updateFromJSObject(jsObject); 63 | synchronized (customMarkers) { 64 | customMarkers.add(customMarker); 65 | } 66 | if (nMarkersCounter.addAndGet(1) == n) { 67 | synchronized (syncRoot) { 68 | syncRoot.notify(); 69 | } 70 | } 71 | } catch (JSONException exception) { 72 | currentException = exception; 73 | isException.set(true); 74 | synchronized (syncRoot) { 75 | syncRoot.notify(); 76 | } 77 | } 78 | }); 79 | } 80 | 81 | synchronized (syncRoot) { 82 | try { 83 | // Wait for customMarkers are populated 84 | // I follow https://www.baeldung.com/java-wait-notify#1-why-enclose-wait-in-a-while-loop 85 | while (nMarkersCounter.get() < n && !isException.get()) { 86 | syncRoot.wait(); 87 | } 88 | } catch (InterruptedException ignored) { 89 | } 90 | } 91 | 92 | if (isException.get()) { 93 | throw new AppenderException("exception in createCustomMarkers", currentException); 94 | } 95 | return customMarkers; 96 | } 97 | 98 | private void addCustomMarkers(final List customMarkers, 99 | final CustomMapView customMapView, 100 | final Activity activity, 101 | Consumer resultConsumer) { 102 | final int n = customMarkers.size(); 103 | final List result = new ArrayList<>(n); 104 | final AtomicInteger nMarkersAdded = new AtomicInteger(0); 105 | final AtomicBoolean isMarkerAdded = new AtomicBoolean(false); 106 | 107 | executorService.execute(() -> { 108 | for (CustomMarker customMarker : customMarkers) { 109 | activity.runOnUiThread(() -> { 110 | customMapView.addMarker( 111 | customMarker, 112 | (marker) -> { 113 | result.add( 114 | (JSObject) CustomMarker.getResultForMarker( 115 | marker, 116 | customMapView.getId()) 117 | .opt("marker") 118 | ); 119 | synchronized (syncRoot) { 120 | isMarkerAdded.set(true); 121 | syncRoot.notify(); 122 | } 123 | if (nMarkersAdded.addAndGet(1) == n) { 124 | JSObject jsResult = new JSObject(); 125 | jsResult.put("mapId", customMapView.getId()); 126 | JSArray jsMarkerOutputEntries = JSArray.from(result.toArray()); 127 | jsResult.put("markers", jsMarkerOutputEntries); 128 | resultConsumer.accept(jsResult); 129 | } 130 | } 131 | ); 132 | }); // end of runOnUiThread 133 | synchronized (syncRoot) { 134 | try { 135 | // wait for Marker is rendered before the next iteration 136 | // here is a background thread -> No UI freeze 137 | while (!isMarkerAdded.get()) { 138 | syncRoot.wait(); 139 | if (!isMarkerAdded.get()) { 140 | continue; 141 | } 142 | isMarkerAdded.set(false); 143 | break; 144 | } 145 | } catch (InterruptedException ignored) { 146 | break; 147 | } 148 | } 149 | } // end for 150 | }); // end of execute 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /android/src/main/res/layout/bridge_layout_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /android/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /android/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Just a simple string 3 | 4 | -------------------------------------------------------------------------------- /android/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /android/src/test/java/com/getcapacitor/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.getcapacitor; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() throws Exception { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /docs/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capacitor-community/google-maps/d82f24298c06bc95fd64eb202b1ceb3fff716582/docs/.nojekyll -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 |


2 | 3 |

Google Maps

4 |

@capacitor-community/google-maps

5 |

Capacitor Plugin using native Google Maps SDK for Android and iOS.

6 |

7 |

8 | 9 |

10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 |

21 | 22 | ## Purpose 23 | 24 | Under the hood this package makes use of the native Maps SDK for Android and iOS. The native Maps SDK has much better performance than the JS equivalent. It also adds support for offline caching. On top of that it ("Dynamic Maps") is completely free to use (as of February 2022) ([native pricing](https://developers.google.com/maps/billing-and-pricing/pricing)), in contrary to the JS SDK ([JS pricing](https://developers.google.com/maps/documentation/javascript/usage-and-billing#new-payg)). 25 | 26 | See if this plugin is a good fit for your use case in [this section](about/should-you-use-this-plugin.md). 27 | 28 | ## Maintainers 29 | 30 | | Maintainer | GitHub | Mail | 31 | | ------------ | --------------------------------------- | ---------------------------------------------------------- | 32 | | Hemang Kumar | [hemangsk](https://github.com/hemangsk) | hemangsk@gmail.com | 33 | 34 | ## Limitations 35 | 36 | - Right now, its not possible to allow the rendered Map view to scroll along with the page, it remains at its fixed position. 37 | - This plugins only adds support for using the native iOS and Android SDK. If you want to make use of the JavaScript SDK as well (for a possible webapp) you should implement that separately. Of course it should possible to integrate this into the plugin in the future. If you want to help out with this, please start a PR. 38 | 39 | ## Contributors ✨ 40 | 41 | Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 |

Grant Brits

💻 🐛 🤔

Tafel

💻 🐛 🤔

abcoskn

💻 🐛

Hyun Yang

🐛 💡

Melanie Marval

🐛

l4ke

🐛

Ben Grossman

🐛

Gercil Junio

📓

Alauddin Afif Cassandra

📓

togro

🐛 📓

selected-pixel-jameson

🐛

chikalio

🐛

Javier Gonzalez

💻
65 | 66 | 67 | 68 | 69 | 70 | 71 | This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! 72 | -------------------------------------------------------------------------------- /docs/_sidebar.md: -------------------------------------------------------------------------------- 1 | - About 2 | 3 | - [Should you use this plugin?](about/should-you-use-this-plugin.md) 4 | - [Out of scope features](about/out-of-scope-features.md) 5 | 6 | - Getting started 7 | 8 | - [Installation](getting-started/installation.md) 9 | - [Quick start](getting-started/quickstart.md) 10 | 11 | - Guide 12 | 13 | - [Setting up the WebView](guide/setup-webview.md) 14 | - [Troubleshooting](guide/troubleshooting.md) 15 | 16 | - [Advanced concepts](advanced-concepts/) 17 | 18 | - [Transparent WebView](advanced-concepts/transparent-webview.md) 19 | - [Touch delegation](advanced-concepts/touch-delegation.md) 20 | 21 | - [API Reference](api.md) 22 | -------------------------------------------------------------------------------- /docs/about/out-of-scope-features.md: -------------------------------------------------------------------------------- 1 | # Features that are out of scope for this plugin 2 | 3 | There are certain features that are not baked in to this plugin. Examples are Launch Urls and (reverse) Geocoding. Several good reasons exist to not implement this in the plugin. The official Google APIs are already fairly simple and easily accessible from JavaScript. Also it would add overhead supporting this for the maintainers of the plugin. It would also require you, the user of the plugin, to learn non-standard APIs to be able to implement it. 4 | 5 | Nonetheless we have written a few quick guides on these features to get you started 6 | 7 | ## Launch URLs 8 | 9 | > Using Maps URLs, you can build a universal, cross-platform URL to launch Google Maps and perform searches, get directions and navigation, and display map views and panoramic images. The URL syntax is the same regardless of the platform in use. 10 | > 11 | > You don't need a Google API key to use Maps URLs. 12 | 13 | Location search 14 | 15 | In a location search, you search for a specific location using a place name, address, or comma-separated latitude/longitude coordinates, and the resulting map displays a pin at that location. These three examples illustrate searches for the same location, CenturyLink Field (a sports stadium in Seattle, WA), using different location values. 16 | 17 | Example 1: Searching for the place name "CenturyLink Field" results in the following map: 18 | 19 | `https://www.google.com/maps/search/?api=1&query=centurylink+field` 20 | 21 | Example 2: Searching for CenturyLink Field using latitude/longitude coordinates as well as the place ID results in the following map: 22 | 23 | `https://www.google.com/maps/search/?api=1&query=47.5951518%2C-122.3316393&query_place_id=ChIJKxjxuaNqkFQR3CK6O1HNNqY` 24 | 25 | Read more about Launch URLs in the official [Google documentation](https://developers.google.com/maps/documentation/urls/get-started). 26 | 27 | ## Geocoding 28 | 29 |

Geocoding

30 | 31 | > Geocoding is the process of converting addresses (like "1600 Amphitheatre Parkway, Mountain View, CA") into geographic coordinates (like latitude 37.423021 and longitude -122.083739), which you can use to place markers on a map, or position the map 32 | 33 | You can start using the Geocoding API by using the API url directly. An example: 34 | 35 | `https://maps.googleapis.com/maps/api/geocode/json?address=Washington&key=YOUR_API_KEY` 36 | 37 | You could also use the offical JavaScript SDK like so: 38 | 39 | ```js 40 | geocoder 41 | .geocode({ address: "Some address" }) 42 | .then((response) => { 43 | if (response.results[0]) { 44 | console.log(response.results); 45 | } else { 46 | console.log("No results found"); 47 | } 48 | }) 49 | .catch((e) => console.error(e)); 50 | ``` 51 | 52 |

Reverse geocoding

53 | 54 | > Reverse geocoding is the process of converting geographic coordinates into a human-readable address. 55 | 56 | You can start using the reverse Geocoding API by using the API url directly. An example: 57 | 58 | `https://maps.googleapis.com/maps/api/geocode/json?latlng=40.714224,-73.961452&key=YOUR_API_KEY` 59 | 60 | You could also use the offical JavaScript SDK like so: 61 | 62 | ```js 63 | geocoder 64 | .geocode({ location: { lat: 40.731, lng: -73.997 } }) 65 | .then((response) => { 66 | if (response.results[0]) { 67 | console.log(response.results); 68 | } else { 69 | console.log("No results found"); 70 | } 71 | }) 72 | .catch((e) => console.error(e)); 73 | ``` 74 | 75 | Read more about geocoding in the official [Google documentation](https://developers.google.com/maps/documentation/geocoding/overview). 76 | -------------------------------------------------------------------------------- /docs/about/should-you-use-this-plugin.md: -------------------------------------------------------------------------------- 1 | # Should you use this plugin? 2 | 3 |

Purpose

4 | 5 | Under the hood this package makes use of the native Maps SDK for Android and iOS. The native Maps SDK has much better performance than the JS equivalent. It also adds support for offline caching. On top of that it ("Dynamic Maps") is completely free to use (as of February 2022) ([native pricing](https://developers.google.com/maps/billing-and-pricing/pricing)), in contrary to the JS SDK ([JS pricing](https://developers.google.com/maps/documentation/javascript/usage-and-billing#new-payg)). 6 | 7 |

This plugin likely is a good fit for you if ...

8 | 9 |

... you are building an app which main focus is the Map

10 | 11 | If your app revolves mainly around a Map, like for example Uber or Lime, this plugin is probably a good fit for your concept. 12 | 13 |

... you have one or a few Maps in your app that need a performance boost

14 | 15 | If your app utilizes a one or a few Map instances that can remain at its fixed position on the page (see [Limitations](/#limitations)) that need a performance boost (because for example a lot of markers are being rendered) than this plugin is probably a good fit. 16 | 17 |

This plugin likely is not a good fit for you if ...

18 | 19 |

... you are only using the Map to show a single static place

20 | 21 | If your app only uses Google Maps to show a single static place (e.g. to show the location of a restaurant), you should probably use an iframe instead (which should be free to use as well). You can do a Google search on "embed Google Maps free". Or take a look a [this site](https://www.embedgooglemap.net/) for example. 22 | 23 |

... you are already using the JavaScript SDK with success

24 | 25 | If your app already successfully uses the JavaScript SDK, and does not suffer of performance issues, it might not be worth the extra work/overhead to implement this plugin. Especially when your current/planned usage falls under the free tier the JavaScript SDK offers. 26 | -------------------------------------------------------------------------------- /docs/advanced-concepts/README.md: -------------------------------------------------------------------------------- 1 | # Advanced concepts 2 | 3 | In this section you can learn more about the advanced concepts that power this plugin. It should not be necessary to read through this to make use of the plugin. But it could help answer questions you might have. It could also help you understand certain concepts better. Also, it's just cool to know these things and brag about to your colleagues 😏. 4 | -------------------------------------------------------------------------------- /docs/advanced-concepts/touch-delegation.md: -------------------------------------------------------------------------------- 1 | # Touch delegation 2 | 3 | > WIP 4 | 5 | This plugin generates native map views, and puts them behind the `WebView`. You can read more about that [here](advanced-concepts/transparent-webview.md). Because of that, advanced mechanisms are put into place, to make sure the Map is still interactable. This section explains the (advanced) techniques behind the "touch delegation" that make that possible. 6 | 7 | Normally when a view overlaps another view in Java or Swift, the lower view is not touchable. You can compare this to the way `z-index` works in HTML. 8 | 9 | This plugin, however, works around that by detecting the point a user touches the screen and consequently detecting whether that touch is meant for either the `WebView` or one of the Map instances. 10 | -------------------------------------------------------------------------------- /docs/advanced-concepts/transparent-webview.md: -------------------------------------------------------------------------------- 1 | # Transparent WebView 2 | 3 | Whenever [`createMap`](api.md#createmap) is being called, a native Google Maps instance ([Android](https://developers.google.com/android/reference/com/google/android/gms/maps/MapView), [iOS](https://developers.google.com/maps/documentation/ios-sdk/reference/interface_g_m_s_map_view)) is added to the app. Such an instance is a native view which thus lives in the native side of the code base (Java and Swift). This means that they are **not** HTMLElements, **not** a `
` or anything HTML related. 4 | 5 | These view instances are being rendered **behind** the `WebView` ([Android](https://developer.android.com/reference/android/webkit/WebView), [iOS](https://developer.apple.com/documentation/webkit/wkwebview)). The `WebView` itself is made transparent. This has the major benefit that you can render any kind of HTMLElement on top of the native Map. 6 | 7 | > Read more about how we managed to make both the Map instances and `WebView` interactable in [this section](advanced-concepts/touch-delegation.md). 8 | 9 |

Android

10 | 11 | On Android this plugin makes sure that the `WebView` overlays the Map by this piece of code: 12 | 13 | ```Java 14 | bridge.getWebView().bringToFront(); 15 | ``` 16 | 17 | Simple yet effective. 18 | 19 | Since the `WebView` has a background color by default, the plugin also makes sure the background is transparent by the following code snippet: 20 | 21 | ```Java 22 | bridge.getWebView().setBackgroundColor(Color.TRANSPARENT); 23 | ``` 24 | 25 | Of course the webapp itself also may have elements that are not transparent by default. An example of this is the `` element. The plugin automatically tries to make the `` element transparent by adding `background: 'transparent';` to the `style=""` attribute\*. 26 | 27 | This is done by this piece of code: 28 | 29 | ```Java 30 | bridge.getWebView().loadUrl("javascript:document.documentElement.style.backgroundColor = 'transparent';void(0);"); 31 | ``` 32 | 33 | !> \* This means in theory it is possible that this is overwritten by some CSS property in your setup. Learn how to make sure the Map is viewable in [this guide](guide/setup-webview.md). 34 | 35 |

iOS

36 | 37 | On iOS this plugin makes sure that the `WebView` overlays the Map by "sending" the Map view to the back: 38 | 39 | ```swift 40 | self.bridge?.viewController?.view.sendSubviewToBack(customMapView.view) 41 | ``` 42 | 43 | Simple yet effective. 44 | 45 | Since the `WebView` has a background color by default, the plugin also makes sure the background is transparent by the following code snippet: 46 | 47 | ```Swift 48 | self.customWebView?.isOpaque = false 49 | self.customWebView?.backgroundColor = .clear 50 | ``` 51 | 52 | Of course the webapp itself also may have elements that are not transparent by default. An example of this is the `` element. The plugin automatically tries to make the `` element transparent by adding `background: 'transparent';` to the `style=""` attribute\*. 53 | 54 | This is done by this piece of code: 55 | 56 | ```Swift 57 | let javascript = "document.documentElement.style.backgroundColor = 'transparent'" 58 | self.customWebView?.evaluateJavaScript(javascript) 59 | ``` 60 | 61 | !> \* This means in theory it is possible that this is overwritten by some CSS property in your setup. Learn how to make sure the Map is viewable in [this guide](guide/setup-webview.md). 62 | -------------------------------------------------------------------------------- /docs/assets/xcode-subclass-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capacitor-community/google-maps/d82f24298c06bc95fd64eb202b1ceb3fff716582/docs/assets/xcode-subclass-1.png -------------------------------------------------------------------------------- /docs/assets/xcode-subclass-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capacitor-community/google-maps/d82f24298c06bc95fd64eb202b1ceb3fff716582/docs/assets/xcode-subclass-2.png -------------------------------------------------------------------------------- /docs/coverpage.md: -------------------------------------------------------------------------------- 1 | # @capacitor-community/google-maps 2 | 3 | > Capacitor Plugin using native Google Maps SDK for Android and iOS. 4 | 5 | - ⚡️ Native performance 6 | - 💸 Free to use\* 7 | - 🔌 Same API for both iOS and Android 8 | - ✨ Most features from JS SDK 9 | 10 | [GitHub](https://github.com/capacitor-community/google-maps) 11 | [Get Started](#home) 12 | -------------------------------------------------------------------------------- /docs/getting-started/installation.md: -------------------------------------------------------------------------------- 1 | # Installation 2 | 3 | ## Install package from npm 4 | 5 | ```bash 6 | npm i --save @capacitor-community/google-maps 7 | npx cap sync 8 | ``` 9 | 10 | ## Setup 11 | 12 | ### Obtain API Keys 13 | 14 | You must add an API key for the Maps SDK to any app that uses the SDK. 15 | 16 | Before you start using the Maps SDK, you need a project with a billing account and the Maps SDK (both for Android and iOS) enabled. Google requires you to have a valid billing account setup, although likely you will not be charged anything. See the [Should you use this plugin?](about/should-you-use-this-plugin.md) section for more information on pricing. 17 | 18 | Extensive and detailed steps can be found here: 19 | 20 | - [Android](https://developers.google.com/maps/documentation/android-sdk/get-api-key) 21 | - [iOS](https://developers.google.com/maps/documentation/ios-sdk/get-api-key) 22 | 23 | You should have two API keys by the end of this step. Let's proceed. 24 | 25 | ### Adding API keys to your App 26 | 27 | #### Android 28 | 29 | Please follow the [official Google guide](https://developers.google.com/maps/documentation/android-sdk/config#step_2_add_your_api_key_to_the_project). See "Step 2: Add your API key to the project". You can skip Step 1, since this plugin already takes care of that. 30 | 31 | Alternatively, you can (**but really should not**) use the following quick and dirty way: 32 | 33 | In your `AndroidManifest.xml` add the following lines: 34 | 35 | ```diff 36 | 37 | ... 38 | + 41 | ... 42 | 43 | ``` 44 | 45 | where `YOUR_ANDROID_MAPS_API_KEY` is the API key you aqcuired in the previous step. 46 | 47 | Again: please **do not** use this alternative method for anything other than testing purposes, since you **will** leak your API Key. 48 | 49 | #### iOS 50 | 51 | On iOS, the API key needs to be set programmatically. This is done using the [`initialize`](./api.md#initialize) method. 52 | 53 | ### Edit Main.storyboard (iOS only) 54 | 55 | On iOS a little extra step should be done. This is needed for touch delegation, which you can read more about in the [advanced concepts section](advanced-concepts/touch-delegation.md). 56 | 57 | In this step you will subclass the default ViewController (called `CAPBridgeViewController`). This is fairly straight forward, as this library already includes the required custom ViewController. The following two images explain in detail how to do that. 58 | 59 | Select the `Main.storyboard` file in the Project Navigator, select the **Bridge View Controller** in the **Bridge View Controller Scene**, select the **Identity Inspector** on the right. 60 | 61 | Screenshot of Xcode, explaining how to subclass CAPBridgeViewController. 62 | 63 | Finally, select `CustomMapViewController` from the dropdown under **Custom Class**. 64 | 65 | Screenshot of Xcode, explaining how to subclass CAPBridgeViewController. 66 | 67 | > If you want to know more about subclassing `CAPBridgeViewController`, you can read about it in the [official Capacitor documentation](https://capacitorjs.com/docs/ios/viewcontroller). 68 | -------------------------------------------------------------------------------- /docs/getting-started/quickstart.md: -------------------------------------------------------------------------------- 1 | # Quick start 2 | 3 | Before you continue, make sure you have followed all the steps from the [Installation section](installation). 4 | 5 | ## Initializing a Map instance 6 | 7 | After following all installation steps, you can follow this small guide to quickly setup a simple Map instance. 8 | 9 | ### Setting up your HTML 10 | 11 | The Maps SDK renders a native element (`MapView`) behind your webapp (`WebView`). You need to specify the boundaries (which is explained later) that is rendered in. So it is NOT an HTMLElement, but rather a native element. It can therefore not be styled, mutated or listened to like you would with a 'normal' HTMLElement. 12 | 13 | > Read more about this concept in the "Advanced concepts" section. 14 | 15 | At the moment, the only drawback of this is, that the map instance does not size and move along with the div that it is attached to. This is a known limitation and it may be solved in the future as there are some known solutions as well. However, most use cases would use a Map instance that stays at a fixed position anyway. 16 | 17 | Therefore the only requirement right now is to make sure the 'foster element' (the element which you are going to attach the Map instance to) remains at the same position. This can be achieved by preventing it to be able to scroll and to make the current view portrait (or landscape) only. 18 | 19 | So let's get to it. Let's assume you have the following layout: 20 | 21 | ```html 22 | 23 | 24 | 25 | 26 | 27 | Maps SDK for Capacitor - Basic Example 28 | 38 | 39 | 40 |
41 | 42 | 43 | ``` 44 | 45 | Note that it can be anything really. Like with Capacitor itself, it does not matter what framework you are using. Angular, Vue, React, Svelte... they are all supported. 46 | 47 | ### Setting up your JavaScript 48 | 49 | The Plugin can be imported as follows: 50 | 51 | ```javascript 52 | import { CapacitorGoogleMaps } from "@capacitor-community/google-maps"; 53 | ``` 54 | 55 | Let's assume you have imported the Plugin correctly. A simple Maps instance can then be initialized as follows: 56 | 57 | ```javascript 58 | const initializeMap = async () => { 59 | // first of all, you should initialize the Maps SDK: 60 | await CapacitorGoogleMaps.initialize({ 61 | key: "YOUR_IOS_MAPS_API_KEY", 62 | devicePixelRatio: window.devicePixelRatio, // this line is very important 63 | }); 64 | 65 | // then get the element you want to attach the Maps instance to: 66 | const element = document.getElementById("container"); 67 | 68 | // afterwards get its boundaries like so: 69 | const boundingRect = element.getBoundingClientRect(); 70 | 71 | // we can now create the map using the boundaries of #container 72 | try { 73 | const result = await CapacitorGoogleMaps.createMap({ 74 | boundingRect: { 75 | width: Math.round(boundingRect.width), 76 | height: Math.round(boundingRect.height), 77 | x: Math.round(boundingRect.x), 78 | y: Math.round(boundingRect.y), 79 | }, 80 | }); 81 | 82 | // remove background, so map can be seen 83 | // (you can read more about this in the "Setting up the WebView" guide) 84 | element.style.background = ""; 85 | 86 | // finally set `data-maps-id` attribute for delegating touch events 87 | element.setAttribute("data-maps-id", result.googleMap.mapId); 88 | 89 | alert("Map loaded successfully"); 90 | } catch (e) { 91 | alert("Map failed to load"); 92 | } 93 | }; 94 | 95 | (function () { 96 | // on page load, execute the above method 97 | initializeMap(); 98 | 99 | // Some frameworks and a recommended lifecycle hook you could use to initialize the Map: 100 | // Ionic: `ionViewDidEnter` 101 | // Angular: `mounted` 102 | // Vue: `mounted` 103 | // React: `componentDidMount` 104 | 105 | // Of course you can also initialize the Map on different events, like clicking on a button. 106 | // Just make sure you do not unnecessarily initialize it multiple times. 107 | })(); 108 | ``` 109 | 110 | ## What's next? 111 | 112 | As the previous example shows, it is really easy to integrate the Maps SDK into your app. But, of course, there are many more possibilities. 113 | 114 | - Read the Guides to learn more about the plugin. 115 | - Refer to the [API Reference](api.md#api-reference-🔌) to see all available methods the plugin offers. 116 | - Take a look at some examples [here](https://github.com/capacitor-community/google-maps-examples). 117 | -------------------------------------------------------------------------------- /docs/guide/setup-webview.md: -------------------------------------------------------------------------------- 1 | # Setting up the WebView 2 | 3 | The Map instances are rendered behind the WebView. Because of this, it should be made sure the native WebView and the concerned HTMLElements inside it, are transparent. 4 | 5 | > If you want to learn more about this concept you can refer to the [advanced concepts section](advanced-concepts/transparent-webview.md) 6 | 7 | This plugin takes care of making the native WebView and the `` transparent\*. You will have to take care of the rest (the `div`'s and other HTMLElements overlaying the Map). This is a deliberate choice, because this plugin could impossibly take care of all the different project setups and an infinite number of different CSS possibilities. 8 | 9 | !> \* The `` element is made transparent by adding `background: 'transparent';` to the `style=""` attribute. So in theory it is possible that this is overwritten by some CSS property in your setup. 10 | 11 | ## Debugging 12 | 13 | So how to go about debugging which HTMLElements are not transparent and thus blocking the Map from being viewable? 14 | 15 | What you could do to discover what divs are responsible for it, is the following: 16 | 17 | 1. Inspect your webapp in your browser. 18 | 1. Add some very noticeable and distinguishable background color to ``. 19 | 1. Then delete the most upper root `div` and see if you can see the background color of ``. 20 | 1. You do? Nice. Undo the deletion and remove the child of that `div` and see if you can see the background color of ``. 21 | 1. Repeat the previous step until you figured out what `div`'s are responsible for overlaying the Map. 22 | -------------------------------------------------------------------------------- /docs/guide/troubleshooting.md: -------------------------------------------------------------------------------- 1 | # Troubleshooting 2 | 3 | ##### I have a `Error: Plugin GoogleMaps does not respond to method call` error message on iOS 4 | 5 | In Xcode click on `Product` > `Clean Build Folder` and try to build again. 6 | 7 | ##### I have a `Cannot resolve symbol GoogleMaps` error message in Android Studio 8 | 9 | In Android Studio click `File` > `Sync Project with Gradle Files` and try to build again. 10 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Document 6 | 7 | 8 | 12 | 16 | 17 | 18 |
19 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /ios/.npmignore: -------------------------------------------------------------------------------- 1 | Pods 2 | Build 3 | xcuserdata -------------------------------------------------------------------------------- /ios/Plugin.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Plugin.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Plugin.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ios/Plugin.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Plugin/BoundingRect.swift: -------------------------------------------------------------------------------- 1 | import Capacitor 2 | 3 | class BoundingRect { 4 | public static let WIDTH_KEY: String! = "width"; 5 | public static let HEIGHT_KEY: String! = "height"; 6 | public static let X_KEY: String! = "x"; 7 | public static let Y_KEY: String! = "y"; 8 | 9 | private static let WIDTH_DEFAULT: Double! = 500.0; 10 | private static let HEIGHT_DEFAULT: Double! = 500.0; 11 | private static let X_DEFAULT: Double! = 0.0; 12 | private static let Y_DEFAULT: Double! = 0.0; 13 | 14 | public var width: Double!; 15 | public var height: Double!; 16 | public var x: Double!; 17 | public var y: Double!; 18 | 19 | public init () { 20 | self.width = BoundingRect.WIDTH_DEFAULT; 21 | self.height = BoundingRect.HEIGHT_DEFAULT; 22 | self.x = BoundingRect.X_DEFAULT; 23 | self.y = BoundingRect.Y_DEFAULT; 24 | } 25 | 26 | func updateFromJSObject(_ object: JSObject) { 27 | self.width = object[BoundingRect.WIDTH_KEY] as? Double ?? BoundingRect.WIDTH_DEFAULT; 28 | self.height = object[BoundingRect.HEIGHT_KEY] as? Double ?? BoundingRect.HEIGHT_DEFAULT; 29 | self.x = object[BoundingRect.X_KEY] as? Double ?? BoundingRect.X_DEFAULT; 30 | self.y = object[BoundingRect.Y_KEY] as? Double ?? BoundingRect.Y_DEFAULT; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /ios/Plugin/CustomMapViewController.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Capacitor 3 | import GoogleMaps 4 | 5 | class CustomWKWebView: WKWebView { 6 | var customMapViews = [String : CustomMapView](); 7 | 8 | open override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { 9 | let view = super.hitTest(point, with: event) 10 | let values = self.customMapViews.map({ $0.value }) 11 | for customMapView in values { 12 | let convertedPoint = self.convert(point, to: customMapView.GMapView) 13 | let mapView = customMapView.GMapView.hitTest(convertedPoint, with: event) 14 | let contentView = scrollView.subviews[self.customMapViews.count] 15 | 16 | if (mapView != nil), contentView.layer.pixelColorAtPoint(point: point) == true{ 17 | return mapView 18 | } 19 | } 20 | return view 21 | } 22 | } 23 | 24 | class CustomMapViewController: CAPBridgeViewController, UIScrollViewDelegate { 25 | open override func webView(with frame: CGRect, configuration: WKWebViewConfiguration) -> WKWebView { 26 | return CustomWKWebView(frame: frame, configuration: configuration) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /ios/Plugin/CustomMapViewEvents.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import Capacitor 3 | 4 | public class CustomMapViewEvents: CAPPlugin { 5 | func lastResultForCallbackId(callbackId: String, result: PluginCallResultData) {} 6 | func resultForCallbackId(callbackId: String, result: PluginCallResultData?) {} 7 | } 8 | -------------------------------------------------------------------------------- /ios/Plugin/CustomMarker.swift: -------------------------------------------------------------------------------- 1 | import Capacitor 2 | import GoogleMaps 3 | 4 | class CustomMarker: GMSMarker { 5 | var id: String! = NSUUID().uuidString.lowercased(); 6 | 7 | public func updateFromJSObject(_ markerData: JSObject) { 8 | let position = markerData["position"] as? JSObject ?? JSObject(); 9 | 10 | let latitude = position["latitude"] as? Double ?? 0.0; 11 | let longitude = position["longitude"] as? Double ?? 0.0; 12 | 13 | let preferences = markerData["preferences"] as? JSObject ?? JSObject(); 14 | 15 | self.position = CLLocationCoordinate2D(latitude: latitude, longitude: longitude); 16 | 17 | self.title = preferences["title"] as? String ?? nil; 18 | 19 | self.snippet = preferences["snippet"] as? String ?? nil; 20 | 21 | self.opacity = preferences["opacity"] as? Float ?? 1.0; 22 | 23 | self.isFlat = preferences["isFlat"] as? Bool ?? false; 24 | 25 | self.isDraggable = preferences["isDraggable"] as? Bool ?? false; 26 | 27 | self.zIndex = Int32.init(preferences["zIndex"] as? Int ?? 0); 28 | 29 | let anchor = preferences["anchor"] as? JSObject ?? JSObject(); 30 | let anchorX = anchor["x"] as? Double ?? 0.5; 31 | let anchorY = anchor["y"] as? Double ?? 1.0; 32 | self.groundAnchor = CGPoint.init(x: anchorX, y: anchorY); 33 | 34 | let metadata: JSObject = preferences["metadata"] as? JSObject ?? JSObject(); 35 | self.userData = [ 36 | "markerId": self.id!, 37 | "metadata": metadata 38 | ] as? JSObject ?? JSObject(); 39 | } 40 | 41 | public static func getResultForMarker(_ marker: GMSMarker, mapId: String) -> PluginCallResultData { 42 | let tag: JSObject = marker.userData as! JSObject; 43 | 44 | return [ 45 | "marker": [ 46 | "mapId": mapId, 47 | "markerId": tag["markerId"] ?? nil, 48 | "position": [ 49 | "latitude": marker.position.latitude, 50 | "longitude": marker.position.longitude 51 | ], 52 | "preferences": [ 53 | "title": marker.title, 54 | "snippet": marker.snippet, 55 | "opacity": marker.opacity, 56 | "isFlat": marker.isFlat, 57 | "isDraggable": marker.isDraggable, 58 | "zIndex": marker.zIndex, 59 | "anchor": [ 60 | "x": marker.groundAnchor.x, 61 | "y": marker.groundAnchor.y 62 | ], 63 | "metadata": tag["metadata"] ?? JSObject() 64 | ] 65 | ] 66 | ]; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /ios/Plugin/CustomPolygon.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import GoogleMaps 3 | import Capacitor 4 | 5 | class CustomPolygon : GMSPolygon { 6 | var id: String! = NSUUID().uuidString.lowercased(); 7 | 8 | public func updateFromJSObject(_ polygonData: JSObject) { 9 | let pathArray = polygonData["path"] as? [JSObject] ?? [JSObject]() 10 | let path = CustomPolygon.pathFromJson(pathArray) 11 | self.path = path 12 | 13 | let preferences = polygonData["preferences"] as? JSObject ?? JSObject() 14 | 15 | let holesArray = preferences["holes"] as? [[JSObject]] ?? [[JSObject]]() 16 | let holes = holesArray.map { holePathArray in 17 | return CustomPolygon.pathFromJson(holePathArray) 18 | } 19 | self.holes = holes 20 | 21 | self.strokeWidth = preferences["strokeWidth"] as? Double ?? 10.0 22 | 23 | if let strokeColor = preferences["strokeColor"] as? String { 24 | self.strokeColor = UIColor.capacitor.color(fromHex: strokeColor) ?? nil 25 | } 26 | 27 | if let fillColor = preferences["fillColor"] as? String { 28 | self.fillColor = UIColor.capacitor.color(fromHex: fillColor) ?? nil 29 | } 30 | 31 | self.title = preferences["title"] as? String ?? "" 32 | self.zIndex = Int32.init(preferences["zIndex"] as? Int ?? 1) 33 | self.geodesic = preferences["isGeodesic"] as? Bool ?? false 34 | self.isTappable = preferences["isClickable"] as? Bool ?? false 35 | 36 | let metadata: JSObject = preferences["metadata"] as? JSObject ?? JSObject() 37 | self.userData = [ 38 | "polygonId": self.id!, 39 | "metadata": metadata 40 | ] as? JSObject ?? JSObject() 41 | } 42 | 43 | public static func getResultForPolygon(_ polygon: GMSPolygon, mapId: String) -> PluginCallResultData { 44 | let tag: JSObject = polygon.userData as! JSObject 45 | let holes: [GMSPath] = polygon.holes ?? [GMSPath]() 46 | 47 | return [ 48 | "polygon": [ 49 | "mapId": mapId, 50 | "polygonId": tag["polygonId"] ?? "", 51 | "path": CustomPolygon.jsonFromPath(polygon.path), 52 | "preferences": [ 53 | "title": polygon.title ?? "", 54 | "holes": holes.map { path in 55 | return CustomPolygon.jsonFromPath(path) 56 | }, 57 | "strokeWidth": polygon.strokeWidth, 58 | "strokeColor": polygon.strokeColor ?? "", 59 | "fillColor": polygon.fillColor ?? "", 60 | "zIndex": polygon.zIndex, 61 | "isGeodesic": polygon.geodesic, 62 | "isClickable": polygon.isTappable, 63 | "metadata": tag["metadata"] ?? JSObject() 64 | ] 65 | ] 66 | ]; 67 | } 68 | 69 | 70 | private static func jsonFromPath(_ path: GMSPath?) -> [JSObject] { 71 | guard let path = path else { 72 | return [JSObject]() 73 | } 74 | let size = path.count() 75 | var result: [JSObject] = [] 76 | for i in stride(from: 0, to: size, by: 1) { 77 | let coord = path.coordinate(at: i) 78 | result.append(CustomPolygon.jsonFromCoord(coord)) 79 | } 80 | return result 81 | } 82 | 83 | private static func jsonFromCoord(_ coord: CLLocationCoordinate2D) -> JSObject { 84 | return ["latitude" : coord.latitude, "longitude": coord.longitude] 85 | } 86 | 87 | private static func pathFromJson(_ latLngArray: [JSObject]) -> GMSPath { 88 | let path = GMSMutablePath() 89 | latLngArray.forEach { point in 90 | if let lat = point["latitude"] as? Double, let long = point["longitude"] as? Double { 91 | let coord = CLLocationCoordinate2D(latitude: lat, longitude: long) 92 | path.add(coord) 93 | } 94 | } 95 | 96 | return path as GMSPath 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /ios/Plugin/ImageCache/ImageURLLoadable.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | protocol ImageURLLoadable { 4 | static var shared: ImageURLLoadable { get } 5 | func image(at urlString: String, resizeWidth: Int, resizeHeight: Int, completion: @escaping VoidReturnClosure) 6 | func clear(completion: @escaping NoArgsClosure) 7 | } 8 | 9 | protocol ImageCachable { 10 | var imageCache: ImageURLLoadable { get } 11 | } 12 | -------------------------------------------------------------------------------- /ios/Plugin/ImageCache/NativeImageCache.swift: -------------------------------------------------------------------------------- 1 | import SDWebImage 2 | 3 | final class NativeImageCache: ImageURLLoadable { 4 | static let shared: ImageURLLoadable = NativeImageCache() 5 | 6 | private lazy var cache: NSCache = { 7 | NSCache() 8 | }() 9 | 10 | private init(){} 11 | 12 | func image(at urlString: String, resizeWidth: Int, resizeHeight: Int, completion: @escaping VoidReturnClosure) { 13 | guard let url = URL(string: urlString) else { 14 | completion(nil) 15 | return 16 | } 17 | 18 | // Generate custom key based on the size, 19 | // so we can cache the resized variant of the image as well. 20 | let key = "\(urlString)\(resizeWidth)\(resizeHeight)" 21 | 22 | if let image = cache.object(forKey: key as AnyObject) as? UIImage { 23 | // If the resized image is found in the cache, 24 | // return it. 25 | completion(image) 26 | } else { 27 | // Otherwise, we should download the original image, 28 | SDWebImageDownloader.shared.downloadImage(with: url, options: [], context: nil, progress: nil) { image, _, _, _ in 29 | // then resize it to the preferred size, 30 | guard let resizedImage = image?.resize(targetSize: CGSize(width: resizeWidth, height: resizeHeight)) else { 31 | completion(nil) 32 | return 33 | } 34 | // save it in the cache, 35 | self.cache.setObject(resizedImage, forKey: key as AnyObject) 36 | // and return it. 37 | completion(resizedImage) 38 | } 39 | } 40 | } 41 | 42 | func clear(completion: @escaping NoArgsClosure) { 43 | cache.removeAllObjects() 44 | completion() 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /ios/Plugin/ImageCache/SDWebImageCache.swift: -------------------------------------------------------------------------------- 1 | import SDWebImage 2 | 3 | final class SDWebImageCache: ImageURLLoadable { 4 | static let shared: ImageURLLoadable = SDWebImageCache() 5 | 6 | private let cache = SDImageCache.shared 7 | private let downloadManager = SDWebImageManager.shared 8 | 9 | private init() { 10 | cache.config.maxDiskAge = 7 * 24 * 60 * 60 11 | } 12 | 13 | func image(at urlString: String, resizeWidth: Int, resizeHeight: Int, completion: @escaping VoidReturnClosure) { 14 | guard let url = URL(string: urlString) else { 15 | completion(nil) 16 | return 17 | } 18 | 19 | // Generate custom key based on the size, 20 | // so we can cache the resized variant of the image as well. 21 | let key = "\(urlString)\(resizeWidth)\(resizeHeight)" 22 | 23 | SDImageCache.shared.queryCacheOperation(forKey: key, done: { (image, data, type) in 24 | if let image = image { 25 | // If the resized image is found in the cache, 26 | // return it. 27 | completion(image) 28 | } else { 29 | // Otherwise, we should download the original image, 30 | self.downloadManager.loadImage(with: url, options: [], context: nil, progress: nil) { image, _, _, _, _, _ in 31 | // then resize it to the preferred size, 32 | guard let resizedImage = image?.resize(targetSize: CGSize(width: resizeWidth, height: resizeHeight)) else { 33 | completion(nil) 34 | return 35 | } 36 | // save it in the cache, 37 | SDImageCache.shared.store(resizedImage, forKey: key, completion: { 38 | // and return it. 39 | completion(resizedImage) 40 | }) 41 | } 42 | } 43 | }) 44 | } 45 | 46 | func clear(completion: @escaping NoArgsClosure) { 47 | cache.clearDisk(onCompletion: completion) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /ios/Plugin/ImageCache/TypeAliases.swift: -------------------------------------------------------------------------------- 1 | typealias NoArgsClosure = () -> Void 2 | typealias VoidReturnClosure = (T) -> Void 3 | -------------------------------------------------------------------------------- /ios/Plugin/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSPrincipalClass 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /ios/Plugin/MapCameraPosition.swift: -------------------------------------------------------------------------------- 1 | import Capacitor 2 | import GoogleMaps 3 | 4 | class MapCameraPosition { 5 | public static let TARGET_KEY: String! = "target"; 6 | public static let LATITUDE_KEY: String! = "latitude"; 7 | public static let LONGITUDE_KEY: String! = "longitude"; 8 | public static let BEARING_KEY: String! = "bearing"; 9 | public static let TILT_KEY: String! = "tilt"; 10 | public static let ZOOM_KEY: String! = "zoom"; 11 | 12 | private static let TARGET_DEFAULT: JSObject! = JSObject(); 13 | private static let LATITUDE_DEFAULT: Double! = 0.0; 14 | private static let LONGITUDE_DEFAULT: Double! = 0.0; 15 | private static let BEARING_DEFAULT: Double! = 0.0; 16 | private static let TILT_DEFAULT: Double! = 0.0; 17 | private static let ZOOM_DEFAULT: Float! = 12.0; 18 | 19 | public var latitude: Double!; 20 | public var longitude: Double!; 21 | public var bearing: Double!; 22 | public var tilt: Double!; 23 | public var zoom: Float!; 24 | 25 | public init () { 26 | self.latitude = MapCameraPosition.LATITUDE_DEFAULT; 27 | self.longitude = MapCameraPosition.LONGITUDE_DEFAULT; 28 | self.bearing = MapCameraPosition.BEARING_DEFAULT; 29 | self.tilt = MapCameraPosition.TILT_DEFAULT; 30 | self.zoom = MapCameraPosition.ZOOM_DEFAULT; 31 | } 32 | 33 | func getCameraPosition() -> GMSCameraPosition { 34 | return GMSCameraPosition.camera( 35 | withLatitude: self.latitude, 36 | longitude: self.longitude, 37 | zoom: self.zoom, 38 | bearing: self.bearing, 39 | viewingAngle: self.tilt 40 | ) 41 | } 42 | 43 | func updateFromJSObject(_ object: JSObject, baseCameraPosition: GMSCameraPosition?) { 44 | let target: JSObject = object[MapCameraPosition.TARGET_KEY] as? JSObject ?? MapCameraPosition.TARGET_DEFAULT; 45 | 46 | var latitude = baseCameraPosition?.target.latitude ?? MapCameraPosition.LATITUDE_DEFAULT 47 | if (target[MapCameraPosition.LATITUDE_KEY] != nil) { 48 | // TODO: validate latitude 49 | latitude = target[MapCameraPosition.LATITUDE_KEY] as? Double ?? latitude 50 | } 51 | self.latitude = latitude; 52 | 53 | var longitude = baseCameraPosition?.target.longitude ?? MapCameraPosition.LONGITUDE_DEFAULT 54 | if (target[MapCameraPosition.LONGITUDE_KEY] != nil) { 55 | // TODO: validate longitude 56 | longitude = target[MapCameraPosition.LONGITUDE_KEY] as? Double ?? longitude 57 | } 58 | self.longitude = longitude; 59 | 60 | var bearing = baseCameraPosition?.bearing ?? MapCameraPosition.BEARING_DEFAULT 61 | if (object[MapCameraPosition.BEARING_KEY] != nil) { 62 | // TODO: validate bearing 63 | bearing = object[MapCameraPosition.BEARING_KEY] as? Double ?? bearing 64 | } 65 | self.bearing = bearing; 66 | 67 | var tilt = baseCameraPosition?.viewingAngle ?? MapCameraPosition.TILT_DEFAULT 68 | if (object[MapCameraPosition.TILT_KEY] != nil) { 69 | // TODO: validate tilt 70 | tilt = object[MapCameraPosition.TILT_KEY] as? Double ?? tilt 71 | } 72 | self.tilt = tilt; 73 | 74 | var zoom = baseCameraPosition?.zoom ?? MapCameraPosition.ZOOM_DEFAULT 75 | if (object[MapCameraPosition.ZOOM_KEY] != nil) { 76 | // TODO: validate zoom 77 | zoom = object[MapCameraPosition.ZOOM_KEY] as? Float ?? zoom 78 | } 79 | self.zoom = zoom; 80 | } 81 | 82 | func getJSObject(_ cameraPosition: GMSCameraPosition) -> JSObject { 83 | return [ 84 | MapCameraPosition.TARGET_KEY: [ 85 | MapCameraPosition.LATITUDE_KEY: cameraPosition.target.latitude, 86 | MapCameraPosition.LONGITUDE_KEY: cameraPosition.target.longitude 87 | ], 88 | MapCameraPosition.BEARING_KEY: cameraPosition.bearing, 89 | MapCameraPosition.TILT_KEY: cameraPosition.viewingAngle, 90 | MapCameraPosition.ZOOM_KEY: cameraPosition.zoom 91 | ] 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /ios/Plugin/MapPreferences.swift: -------------------------------------------------------------------------------- 1 | import Capacitor 2 | 3 | class MapPreferences { 4 | public var gestures: MapPreferencesGestures! 5 | public var controls: MapPreferencesControls! 6 | public var appearance: MapPreferencesAppearance! 7 | 8 | public init() { 9 | self.gestures = MapPreferencesGestures(); 10 | self.controls = MapPreferencesControls(); 11 | self.appearance = MapPreferencesAppearance(); 12 | } 13 | 14 | open func updateFromJSObject(_ preferences: JSObject!) { 15 | if preferences != nil { 16 | // update gestures 17 | let gesturesObject: JSObject! = preferences["gestures"] as? JSObject ?? JSObject(); 18 | self.gestures.updateFromJSObject(object: gesturesObject); 19 | // update controls 20 | let controlsObject: JSObject! = preferences["controls"] as? JSObject ?? JSObject(); 21 | self.controls.updateFromJSObject(object: controlsObject); 22 | // update appearance 23 | let appearanceObject: JSObject! = preferences["appearance"] as? JSObject ?? JSObject(); 24 | self.appearance.updateFromJSObject(object: appearanceObject); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /ios/Plugin/MapPreferencesAppearance.swift: -------------------------------------------------------------------------------- 1 | import Capacitor 2 | import GoogleMaps 3 | 4 | class MapPreferencesAppearance { 5 | public static let TYPE_KEY: String! = "type" 6 | public static let STYLE_KEY: String! = "style" 7 | public static let BUILDINGS_SHOWN_KEY: String! = "isBuildingsShown" 8 | public static let INDOOR_SHOWN_KEY: String! = "isIndoorShown" 9 | public static let MY_LOCATION_DOT_SHOWN_KEY: String! = "isMyLocationDotShown" 10 | public static let TRAFFIC_SHOWN_KEY: String! = "isTrafficShown" 11 | 12 | var type: GMSMapViewType = GMSMapViewType.normal; 13 | 14 | var style: GMSMapStyle? = nil; 15 | 16 | var _isBuildingsShown: Bool = true 17 | var isBuildingsShown: Bool! { 18 | get { 19 | return _isBuildingsShown 20 | } 21 | set (newVal) { 22 | _isBuildingsShown = newVal ?? true 23 | } 24 | } 25 | 26 | var _isIndoorShown: Bool = true 27 | var isIndoorShown: Bool! { 28 | get { 29 | return _isIndoorShown 30 | } 31 | set (newVal) { 32 | _isIndoorShown = newVal ?? true 33 | } 34 | } 35 | 36 | var _isMyLocationDotShown: Bool = false 37 | var isMyLocationDotShown: Bool! { 38 | get { 39 | return _isMyLocationDotShown 40 | } 41 | set (newVal) { 42 | _isMyLocationDotShown = newVal ?? false 43 | } 44 | } 45 | 46 | var _isTrafficShown: Bool = false 47 | var isTrafficShown: Bool! { 48 | get { 49 | return _isTrafficShown 50 | } 51 | set (newVal) { 52 | _isTrafficShown = newVal ?? false 53 | } 54 | } 55 | 56 | func updateFromJSObject(object: JSObject) { 57 | if (object[MapPreferencesAppearance.TYPE_KEY] != nil) { 58 | let type = object[MapPreferencesAppearance.TYPE_KEY] as? Int; 59 | if (type != nil) { 60 | if (type == 0) { 61 | self.type = GMSMapViewType.none; 62 | } else if (type == 1) { 63 | self.type = GMSMapViewType.normal; 64 | } else if (type == 2) { 65 | self.type = GMSMapViewType.satellite; 66 | } else if (type == 3) { 67 | self.type = GMSMapViewType.terrain; 68 | } else if (type == 4) { 69 | self.type = GMSMapViewType.hybrid; 70 | } else { 71 | self.type = GMSMapViewType.normal; 72 | } 73 | } 74 | } 75 | 76 | if (object[MapPreferencesAppearance.STYLE_KEY] != nil) { 77 | let style = object[MapPreferencesAppearance.STYLE_KEY] as? String; 78 | if (style == nil) { 79 | self.style = nil; 80 | } else { 81 | do { 82 | try self.style = GMSMapStyle(jsonString: style ?? "{}"); 83 | } catch { 84 | print("error parsing style json string"); 85 | } 86 | } 87 | } 88 | 89 | self.isBuildingsShown = object[MapPreferencesAppearance.BUILDINGS_SHOWN_KEY] as? Bool; 90 | self.isIndoorShown = object[MapPreferencesAppearance.INDOOR_SHOWN_KEY] as? Bool; 91 | self.isMyLocationDotShown = object[MapPreferencesAppearance.MY_LOCATION_DOT_SHOWN_KEY] as? Bool; 92 | self.isTrafficShown = object[MapPreferencesAppearance.TRAFFIC_SHOWN_KEY] as? Bool; 93 | } 94 | 95 | func getJSObject(_ mapView: GMSMapView) -> JSObject { 96 | var type = 1; 97 | if (mapView.mapType == GMSMapViewType.none) { 98 | type = 0; 99 | } else if (mapView.mapType == GMSMapViewType.normal) { 100 | type = 1; 101 | } else if (mapView.mapType == GMSMapViewType.satellite) { 102 | type = 2; 103 | } else if (mapView.mapType == GMSMapViewType.terrain) { 104 | type = 3; 105 | } else if (mapView.mapType == GMSMapViewType.hybrid) { 106 | type = 4; 107 | } 108 | 109 | return [ 110 | MapPreferencesAppearance.TYPE_KEY: type, 111 | MapPreferencesAppearance.BUILDINGS_SHOWN_KEY: mapView.isBuildingsEnabled, 112 | MapPreferencesAppearance.INDOOR_SHOWN_KEY: mapView.isIndoorEnabled, 113 | MapPreferencesAppearance.MY_LOCATION_DOT_SHOWN_KEY: mapView.isMyLocationEnabled, 114 | MapPreferencesAppearance.TRAFFIC_SHOWN_KEY: mapView.isTrafficEnabled 115 | ] 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /ios/Plugin/MapPreferencesControls.swift: -------------------------------------------------------------------------------- 1 | import Capacitor 2 | import GoogleMaps 3 | 4 | class MapPreferencesControls { 5 | public static let COMPASS_BUTTON_KEY: String! = "isCompassButtonEnabled" 6 | public static let INDOOR_LEVEL_PICKER_KEY: String! = "isIndoorLevelPickerEnabled" 7 | public static let MAP_TOOLBAR_KEY: String! = "isMapToolbarEnabled" // (android only) 8 | public static let MY_LOCATION_BUTTON_KEY: String! = "isMyLocationButtonEnabled" 9 | public static let ZOOM_BUTTONS_KEY: String! = "isZoomButtonsEnabled" // (android only) 10 | 11 | var _isCompassButtonEnabled: Bool = true 12 | var isCompassButtonEnabled: Bool! { 13 | get { 14 | return _isCompassButtonEnabled 15 | } 16 | set (newVal) { 17 | _isCompassButtonEnabled = newVal ?? true 18 | } 19 | } 20 | 21 | var _isIndoorLevelPickerEnabled: Bool = false 22 | var isIndoorLevelPickerEnabled: Bool! { 23 | get { 24 | return _isIndoorLevelPickerEnabled 25 | } 26 | set (newVal) { 27 | _isIndoorLevelPickerEnabled = newVal ?? false 28 | } 29 | } 30 | 31 | var _isMyLocationButtonEnabled: Bool = true 32 | var isMyLocationButtonEnabled: Bool! { 33 | get { 34 | return _isMyLocationButtonEnabled 35 | } 36 | set (newVal) { 37 | _isMyLocationButtonEnabled = newVal ?? true 38 | } 39 | } 40 | 41 | func updateFromJSObject(object: JSObject) { 42 | self.isCompassButtonEnabled = object[MapPreferencesControls.COMPASS_BUTTON_KEY] as? Bool; 43 | self.isIndoorLevelPickerEnabled = object[MapPreferencesControls.INDOOR_LEVEL_PICKER_KEY] as? Bool; 44 | self.isMyLocationButtonEnabled = object[MapPreferencesControls.MY_LOCATION_BUTTON_KEY] as? Bool; 45 | } 46 | 47 | func getJSObject(_ mapView: GMSMapView) -> JSObject { 48 | return [ 49 | MapPreferencesControls.COMPASS_BUTTON_KEY: mapView.settings.compassButton, 50 | MapPreferencesControls.INDOOR_LEVEL_PICKER_KEY: mapView.settings.indoorPicker, 51 | MapPreferencesControls.MAP_TOOLBAR_KEY: false, // (android only) 52 | MapPreferencesControls.MY_LOCATION_BUTTON_KEY: mapView.settings.myLocationButton, 53 | MapPreferencesControls.ZOOM_BUTTONS_KEY: false, // (android only) 54 | ] 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /ios/Plugin/MapPreferencesGestures.swift: -------------------------------------------------------------------------------- 1 | import Capacitor 2 | import GoogleMaps 3 | 4 | class MapPreferencesGestures { 5 | public static let ROTATE_ALLOWED_KEY: String! = "isRotateAllowed" 6 | public static let SCROLL_ALLOWED_KEY: String! = "isScrollAllowed" 7 | public static let SCROLL_ALLOWED_DURING_ROTATE_OR_ZOOM_KEY: String! = "isScrollAllowedDuringRotateOrZoom" 8 | public static let TILT_ALLOWED_KEY: String! = "isTiltAllowed" 9 | public static let ZOOM_ALLOWED_KEY: String! = "isZoomAllowed" 10 | 11 | var _isRotateAllowed: Bool = true 12 | var isRotateAllowed: Bool! { 13 | get { 14 | return _isRotateAllowed 15 | } 16 | set (newVal) { 17 | _isRotateAllowed = newVal ?? true 18 | } 19 | } 20 | 21 | var _isScrollAllowed: Bool = true 22 | var isScrollAllowed: Bool! { 23 | get { 24 | return _isScrollAllowed 25 | } 26 | set (newVal) { 27 | _isScrollAllowed = newVal ?? true 28 | } 29 | } 30 | 31 | var _isScrollAllowedDuringRotateOrZoom: Bool = true 32 | var isScrollAllowedDuringRotateOrZoom: Bool! { 33 | get { 34 | return _isScrollAllowedDuringRotateOrZoom 35 | } 36 | set (newVal) { 37 | _isScrollAllowedDuringRotateOrZoom = newVal ?? true 38 | } 39 | } 40 | 41 | var _isTiltAllowed: Bool = true 42 | var isTiltAllowed: Bool! { 43 | get { 44 | return _isTiltAllowed 45 | } 46 | set (newVal) { 47 | _isTiltAllowed = newVal ?? true 48 | } 49 | } 50 | 51 | var _isZoomAllowed: Bool = true 52 | var isZoomAllowed: Bool! { 53 | get { 54 | return _isZoomAllowed 55 | } 56 | set (newVal) { 57 | _isZoomAllowed = newVal ?? true 58 | } 59 | } 60 | 61 | func updateFromJSObject(object: JSObject) { 62 | self.isRotateAllowed = object[MapPreferencesGestures.ROTATE_ALLOWED_KEY] as? Bool; 63 | self.isScrollAllowed = object[MapPreferencesGestures.SCROLL_ALLOWED_KEY] as? Bool; 64 | self.isScrollAllowedDuringRotateOrZoom = object[MapPreferencesGestures.SCROLL_ALLOWED_DURING_ROTATE_OR_ZOOM_KEY] as? Bool; 65 | self.isScrollAllowed = object[MapPreferencesGestures.TILT_ALLOWED_KEY] as? Bool; 66 | self.isScrollAllowed = object[MapPreferencesGestures.ZOOM_ALLOWED_KEY] as? Bool; 67 | } 68 | 69 | func getJSObject(_ mapView: GMSMapView) -> JSObject { 70 | return [ 71 | MapPreferencesGestures.ROTATE_ALLOWED_KEY: mapView.settings.rotateGestures, 72 | MapPreferencesGestures.SCROLL_ALLOWED_KEY: mapView.settings.scrollGestures, 73 | MapPreferencesGestures.SCROLL_ALLOWED_DURING_ROTATE_OR_ZOOM_KEY: mapView.settings.allowScrollGesturesDuringRotateOrZoom, 74 | MapPreferencesGestures.TILT_ALLOWED_KEY: mapView.settings.tiltGestures, 75 | MapPreferencesGestures.ZOOM_ALLOWED_KEY: mapView.settings.zoomGestures 76 | ] 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /ios/Plugin/Plugin.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | //! Project version number for Plugin. 4 | FOUNDATION_EXPORT double PluginVersionNumber; 5 | 6 | //! Project version string for Plugin. 7 | FOUNDATION_EXPORT const unsigned char PluginVersionString[]; 8 | 9 | // In this header, you should import all the public headers of your framework using statements like #import 10 | 11 | -------------------------------------------------------------------------------- /ios/Plugin/Plugin.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | // Define the plugin using the CAP_PLUGIN Macro, and 5 | // each method the plugin supports using the CAP_PLUGIN_METHOD macro. 6 | CAP_PLUGIN(CapacitorGoogleMaps, "CapacitorGoogleMaps", 7 | CAP_PLUGIN_METHOD(initialize, CAPPluginReturnPromise); 8 | CAP_PLUGIN_METHOD(createMap, CAPPluginReturnPromise); 9 | CAP_PLUGIN_METHOD(updateMap, CAPPluginReturnPromise); 10 | CAP_PLUGIN_METHOD(clearMap, CAPPluginReturnNone); 11 | CAP_PLUGIN_METHOD(removeMap, CAPPluginReturnPromise); 12 | CAP_PLUGIN_METHOD(moveCamera, CAPPluginReturnPromise); 13 | CAP_PLUGIN_METHOD(addMarker, CAPPluginReturnPromise); 14 | CAP_PLUGIN_METHOD(addMarkers, CAPPluginReturnPromise); 15 | CAP_PLUGIN_METHOD(removeMarker, CAPPluginReturnPromise); 16 | CAP_PLUGIN_METHOD(addPolygon, CAPPluginReturnPromise); 17 | CAP_PLUGIN_METHOD(removePolygon, CAPPluginReturnPromise); 18 | CAP_PLUGIN_METHOD(didTapInfoWindow, CAPPluginReturnCallback); 19 | CAP_PLUGIN_METHOD(didCloseInfoWindow, CAPPluginReturnCallback); 20 | CAP_PLUGIN_METHOD(didTapMap, CAPPluginReturnCallback); 21 | CAP_PLUGIN_METHOD(didLongPressMap, CAPPluginReturnCallback); 22 | CAP_PLUGIN_METHOD(didTapMarker, CAPPluginReturnCallback); 23 | CAP_PLUGIN_METHOD(didBeginDraggingMarker, CAPPluginReturnCallback); 24 | CAP_PLUGIN_METHOD(didDragMarker, CAPPluginReturnCallback); 25 | CAP_PLUGIN_METHOD(didEndDraggingMarker, CAPPluginReturnCallback); 26 | CAP_PLUGIN_METHOD(didTapMyLocationButton, CAPPluginReturnCallback); 27 | CAP_PLUGIN_METHOD(didTapMyLocationDot, CAPPluginReturnCallback); 28 | CAP_PLUGIN_METHOD(didTapPoi, CAPPluginReturnCallback); 29 | CAP_PLUGIN_METHOD(didBeginMovingCamera, CAPPluginReturnCallback); 30 | CAP_PLUGIN_METHOD(didMoveCamera, CAPPluginReturnCallback); 31 | CAP_PLUGIN_METHOD(didEndMovingCamera, CAPPluginReturnCallback); 32 | ) 33 | -------------------------------------------------------------------------------- /ios/Plugin/Utilities/CALayer+pixelColorAtPoint.swift: -------------------------------------------------------------------------------- 1 | extension CALayer { 2 | func pixelColorAtPoint(point:CGPoint) -> Bool { 3 | var pixel: [UInt8] = [0, 0, 0, 0] 4 | let colourSpace = CGColorSpaceCreateDeviceRGB() 5 | let alphaInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue) 6 | let context = CGContext(data: &pixel, width: 1, height: 1, bitsPerComponent: 8, bytesPerRow: 4, space: colourSpace, bitmapInfo: alphaInfo.rawValue) 7 | 8 | context?.translateBy(x: -point.x, y: -point.y) 9 | 10 | self.render(in: context!) 11 | 12 | return CGFloat(pixel[0]) == 0 13 | && CGFloat(pixel[1]) == 0 14 | && CGFloat(pixel[2]) == 0 15 | && CGFloat(pixel[3]) == 0 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /ios/Plugin/Utilities/LinkedList.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public class Node { 4 | var value: T 5 | var next: Node? 6 | 7 | init(value: T) { 8 | self.value = value 9 | } 10 | } 11 | 12 | public class List { 13 | fileprivate var head: Node? 14 | private var tail: Node? 15 | 16 | public var isEmpty: Bool { 17 | return head == nil 18 | } 19 | public var first: Node? { 20 | return head 21 | } 22 | public var last: Node? { 23 | return tail 24 | } 25 | 26 | init(elements: [T]) { 27 | elements.forEach { 28 | self.append(value: $0) 29 | } 30 | } 31 | 32 | public func append(value: T) { 33 | let newNode = Node(value: value) 34 | 35 | if let tailNode = tail { 36 | tailNode.next = newNode 37 | } else { 38 | head = newNode 39 | } 40 | 41 | tail = newNode 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /ios/Plugin/Utilities/UIImage+resize.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | extension UIImage { 4 | func resize(targetSize: CGSize) -> UIImage? { 5 | let widthRatio = targetSize.width / size.width 6 | let heightRatio = targetSize.height / size.height 7 | 8 | var newSize: CGSize 9 | if(widthRatio > heightRatio) { 10 | newSize = CGSize(width: size.width * heightRatio, height: size.height * heightRatio) 11 | } else { 12 | newSize = CGSize(width: size.width * widthRatio, height: size.height * widthRatio) 13 | } 14 | 15 | let rect = CGRect(origin: .zero, size: newSize) 16 | 17 | UIGraphicsBeginImageContextWithOptions(newSize, false, UIScreen.main.scale) 18 | self.draw(in: rect) 19 | let newImage = UIGraphicsGetImageFromCurrentImageContext() 20 | UIGraphicsEndImageContext() 21 | 22 | return newImage 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /ios/PluginTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /ios/PluginTests/PluginTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | import Capacitor 3 | @testable import Plugin 4 | 5 | class PluginTests: XCTestCase { 6 | 7 | override func setUp() { 8 | super.setUp() 9 | // Put setup code here. This method is called before the invocation of each test method in the class. 10 | } 11 | 12 | override func tearDown() { 13 | // Put teardown code here. This method is called after the invocation of each test method in the class. 14 | super.tearDown() 15 | } 16 | 17 | func testEcho() { 18 | // This is an example of a functional test case for a plugin. 19 | // Use XCTAssert and related functions to verify your tests produce the correct results. 20 | 21 | let value = "Hello, World!" 22 | let plugin = MyPlugin() 23 | 24 | let call = CAPPluginCall(callbackId: "test", options: [ 25 | "value": value 26 | ], success: { (result, call) in 27 | let resultValue = result!.data["value"] as? String 28 | XCTAssertEqual(value, resultValue) 29 | }, error: { (err) in 30 | XCTFail("Error shouldn't have been called") 31 | }) 32 | 33 | plugin.echo(call!) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /ios/Podfile: -------------------------------------------------------------------------------- 1 | platform :ios, '13.0' 2 | 3 | def capacitor_pods 4 | # Comment the next line if you're not using Swift and don't want to use dynamic frameworks 5 | pod 'Capacitor', :path => '../node_modules/@capacitor/ios' 6 | pod 'CapacitorCordova', :path => '../node_modules/@capacitor/ios' 7 | end 8 | 9 | target 'Plugin' do 10 | use_frameworks! 11 | pod 'GoogleMaps' 12 | capacitor_pods 13 | end 14 | 15 | target 'PluginTests' do 16 | use_frameworks! 17 | pod 'GoogleMaps' 18 | capacitor_pods 19 | end 20 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@capacitor-community/google-maps", 3 | "version": "2.0.0-beta.10", 4 | "description": "Plugin using native Maps API for Android and iOS.", 5 | "main": "dist/esm/index.js", 6 | "module": "dist/esm/index.js", 7 | "types": "dist/esm/index.d.ts", 8 | "scripts": { 9 | "docgen": "docgen --api CapacitorGoogleMapsPlugin --output-readme ./docs/api.md", 10 | "build": "npm run clean && tsc", 11 | "clean": "rimraf ./dist", 12 | "watch": "tsc --watch", 13 | "prepublishOnly": "npm run build", 14 | "prepare": "npm run build" 15 | }, 16 | "author": "@capacitor-community", 17 | "license": "MIT", 18 | "devDependencies": { 19 | "@capacitor/android": "^6.0.0", 20 | "@capacitor/core": "^6.0.0", 21 | "@capacitor/docgen": "git+https://github.com/DutchConcepts/capacitor-docgen.git", 22 | "@capacitor/ios": "^6.0.0", 23 | "all-contributors-cli": "^6.20.0", 24 | "rimraf": "^3.0.0", 25 | "typescript": "~4.1.5" 26 | }, 27 | "peerDependencies": { 28 | "@capacitor/core": "^6.0.0" 29 | }, 30 | "files": [ 31 | "dist/", 32 | "ios/", 33 | "android/", 34 | "CapacitorCommunityGoogleMaps.podspec" 35 | ], 36 | "keywords": [ 37 | "capacitor", 38 | "plugin", 39 | "native" 40 | ], 41 | "capacitor": { 42 | "ios": { 43 | "src": "ios" 44 | }, 45 | "android": { 46 | "src": "android" 47 | } 48 | }, 49 | "repository": { 50 | "type": "git", 51 | "url": "git+https://github.com/capacitor-community/google-maps.git" 52 | }, 53 | "bugs": { 54 | "url": "https://github.com/capacitor-community/google-maps/issues" 55 | }, 56 | "homepage": "https://github.com/capacitor-community/google-maps#readme", 57 | "directories": { 58 | "doc": "docs" 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import nodeResolve from 'rollup-plugin-node-resolve'; 2 | 3 | export default { 4 | input: 'dist/esm/index.js', 5 | output: { 6 | file: 'dist/plugin.js', 7 | format: 'iife', 8 | name: 'capacitorPlugin', 9 | sourcemap: true 10 | }, 11 | plugins: [ 12 | nodeResolve() 13 | ] 14 | }; -------------------------------------------------------------------------------- /src/definitions.ts: -------------------------------------------------------------------------------- 1 | import { PluginListenerHandle } from "@capacitor/core"; 2 | 3 | import { 4 | // methods 5 | InitializeOptions, 6 | CreateMapOptions, 7 | CreateMapResult, 8 | UpdateMapOptions, 9 | UpdateMapResult, 10 | RemoveMapOptions, 11 | ClearMapOptions, 12 | MoveCameraOptions, 13 | ElementFromPointResultOptions, 14 | AddMarkerOptions, 15 | AddMarkerResult, 16 | AddMarkersOptions, 17 | AddMarkersResult, 18 | RemoveMarkerOptions, 19 | AddPolygonOptions, 20 | AddPolygonResult, 21 | RemovePolygonOptions, 22 | // events 23 | DidTapInfoWindowCallback, 24 | DidCloseInfoWindowCallback, 25 | DidTapMapCallback, 26 | DidLongPressMapCallback, 27 | DidTapMarkerCallback, 28 | DidBeginDraggingMarkerCallback, 29 | DidDragMarkerCallback, 30 | DidEndDraggingMarkerCallback, 31 | DidTapMyLocationButtonCallback, 32 | DidTapMyLocationDotCallback, 33 | DidTapPoiCallback, 34 | DidBeginMovingCameraCallback, 35 | DidMoveCameraCallback, 36 | DidEndMovingCameraCallback, 37 | } from "./interfaces"; 38 | 39 | export type CallbackID = string; 40 | 41 | export interface DefaultEventOptions { 42 | mapId: string; 43 | } 44 | 45 | export interface DefaultEventWithPreventDefaultOptions { 46 | mapId: string; 47 | preventDefault?: boolean; 48 | } 49 | 50 | export interface DidRequestElementFromPointResult { 51 | eventChainId: string; 52 | point?: { 53 | x: number; 54 | y: number; 55 | }; 56 | } 57 | 58 | export interface CapacitorGoogleMapsPlugin { 59 | initialize(options: InitializeOptions): Promise; 60 | 61 | createMap(options: CreateMapOptions): Promise; 62 | 63 | updateMap(options: UpdateMapOptions): Promise; 64 | 65 | removeMap(options: RemoveMapOptions): Promise; 66 | 67 | clearMap(options: ClearMapOptions): Promise; 68 | 69 | moveCamera(options: MoveCameraOptions): Promise; 70 | 71 | addMarker(options: AddMarkerOptions): Promise; 72 | 73 | addMarkers(options: AddMarkersOptions): Promise; 74 | 75 | removeMarker(options: RemoveMarkerOptions): Promise; 76 | 77 | addPolygon(options: AddPolygonOptions): Promise; 78 | 79 | removePolygon(options: RemovePolygonOptions): Promise; 80 | 81 | didTapInfoWindow( 82 | options: DefaultEventOptions, 83 | callback: DidTapInfoWindowCallback 84 | ): Promise; 85 | 86 | didCloseInfoWindow( 87 | options: DefaultEventOptions, 88 | callback: DidCloseInfoWindowCallback 89 | ): Promise; 90 | 91 | didTapMap( 92 | options: DefaultEventOptions, 93 | callback: DidTapMapCallback 94 | ): Promise; 95 | 96 | didLongPressMap( 97 | options: DefaultEventOptions, 98 | callback: DidLongPressMapCallback 99 | ): Promise; 100 | 101 | didTapMarker( 102 | options: DefaultEventWithPreventDefaultOptions, 103 | callback: DidTapMarkerCallback 104 | ): Promise; 105 | 106 | didBeginDraggingMarker( 107 | options: DefaultEventOptions, 108 | callback: DidBeginDraggingMarkerCallback 109 | ): Promise; 110 | 111 | didDragMarker( 112 | options: DefaultEventOptions, 113 | callback: DidDragMarkerCallback 114 | ): Promise; 115 | 116 | didEndDraggingMarker( 117 | options: DefaultEventOptions, 118 | callback: DidEndDraggingMarkerCallback 119 | ): Promise; 120 | 121 | didTapMyLocationButton( 122 | options: DefaultEventWithPreventDefaultOptions, 123 | callback: DidTapMyLocationButtonCallback 124 | ): Promise; 125 | 126 | didTapMyLocationDot( 127 | options: DefaultEventOptions, 128 | callback: DidTapMyLocationDotCallback 129 | ): Promise; 130 | 131 | didTapPoi( 132 | options: DefaultEventOptions, 133 | callback: DidTapPoiCallback 134 | ): Promise; 135 | 136 | didBeginMovingCamera( 137 | options: DefaultEventOptions, 138 | callback: DidBeginMovingCameraCallback 139 | ): Promise; 140 | 141 | didMoveCamera( 142 | options: DefaultEventOptions, 143 | callback: DidMoveCameraCallback 144 | ): Promise; 145 | 146 | didEndMovingCamera( 147 | options: DefaultEventOptions, 148 | callback: DidEndMovingCameraCallback 149 | ): Promise; 150 | 151 | /** 152 | * After `didRequestElementFromPoint` fires, this method is used to let the WebView know whether or not to delegate the touch event to a certain MapView. 153 | * It is handled automatically and you should probably not use it. 154 | */ 155 | elementFromPointResult(options: ElementFromPointResultOptions): Promise; 156 | 157 | /** 158 | * This listens for touch events on the WebView. 159 | * It is handled automatically and you should probably not use it. 160 | */ 161 | addListener( 162 | eventName: "didRequestElementFromPoint", 163 | listenerFunc: (result: DidRequestElementFromPointResult) => void 164 | ): Promise; 165 | } 166 | 167 | export * from "./interfaces"; 168 | 169 | // methods to implement: 170 | // - GoogleMap.animateCamera 171 | // - GoogleMap.snapshot 172 | // - GoogleMap.setInfoWindowAdapter (HTMLElement) 173 | 174 | // listeners to implement: 175 | // - a lot 176 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { registerPlugin } from "@capacitor/core"; 2 | import { 3 | CapacitorGoogleMapsPlugin, 4 | ElementFromPointResultOptions, 5 | } from "./definitions"; 6 | 7 | const CapacitorGoogleMaps = registerPlugin( 8 | "CapacitorGoogleMaps", 9 | { 10 | web: () => import("./web").then((m) => new m.CapacitorGoogleMapsWeb()), 11 | } 12 | ); 13 | 14 | CapacitorGoogleMaps.addListener("didRequestElementFromPoint", (data) => { 15 | const object: ElementFromPointResultOptions = { 16 | eventChainId: data?.eventChainId, 17 | mapId: null, 18 | isSameNode: false, 19 | }; 20 | 21 | const { x, y } = data?.point || {}; 22 | 23 | if (x && y) { 24 | const element = document.elementFromPoint(x, y); 25 | 26 | const mapId = element?.getAttribute?.("data-maps-id"); 27 | if (mapId) { 28 | // if (ref.isSameNode(element)) { 29 | // object.isSameNode = true; 30 | // } 31 | object.mapId = mapId; 32 | object.isSameNode = true; 33 | } 34 | } 35 | 36 | CapacitorGoogleMaps.elementFromPointResult(object); 37 | }); 38 | 39 | export * from "./definitions"; 40 | export { CapacitorGoogleMaps }; 41 | -------------------------------------------------------------------------------- /src/interfaces/events/DidBeginDraggingMarker.ts: -------------------------------------------------------------------------------- 1 | import { Marker } from "./../../definitions"; 2 | 3 | export interface DidBeginDraggingMarkerResult { 4 | marker: Marker; 5 | } 6 | 7 | export type DidBeginDraggingMarkerCallback = ( 8 | result: DidBeginDraggingMarkerResult | null, 9 | err?: any 10 | ) => void; 11 | -------------------------------------------------------------------------------- /src/interfaces/events/DidBeginMovingCamera.ts: -------------------------------------------------------------------------------- 1 | import { CameraMovementReason } from "./../../definitions"; 2 | 3 | export interface DidBeginMovingCameraResult { 4 | reason: CameraMovementReason; 5 | } 6 | 7 | export type DidBeginMovingCameraCallback = ( 8 | result: DidBeginMovingCameraResult, 9 | err?: any 10 | ) => void; 11 | -------------------------------------------------------------------------------- /src/interfaces/events/DidCloseInfoWindow.ts: -------------------------------------------------------------------------------- 1 | import { Marker } from "./../../definitions"; 2 | 3 | export interface DidCloseInfoWindowResult { 4 | marker: Marker; 5 | } 6 | 7 | export type DidCloseInfoWindowCallback = ( 8 | result: DidCloseInfoWindowResult | null, 9 | err?: any 10 | ) => void; 11 | -------------------------------------------------------------------------------- /src/interfaces/events/DidDragMarker.ts: -------------------------------------------------------------------------------- 1 | import { Marker } from "./../../definitions"; 2 | 3 | export interface DidDragMarkerResult { 4 | marker: Marker; 5 | } 6 | 7 | export type DidDragMarkerCallback = ( 8 | result: DidDragMarkerResult | null, 9 | err?: any 10 | ) => void; 11 | -------------------------------------------------------------------------------- /src/interfaces/events/DidEndDraggingMarker.ts: -------------------------------------------------------------------------------- 1 | import { Marker } from "./../../definitions"; 2 | 3 | export interface DidEndDraggingMarkerResult { 4 | marker: Marker; 5 | } 6 | 7 | export type DidEndDraggingMarkerCallback = ( 8 | result: DidEndDraggingMarkerResult | null, 9 | err?: any 10 | ) => void; 11 | -------------------------------------------------------------------------------- /src/interfaces/events/DidEndMovingCamera.ts: -------------------------------------------------------------------------------- 1 | import { CameraPosition } from "./../../definitions"; 2 | 3 | export interface DidEndMovingCameraResult { 4 | cameraPosition: CameraPosition; 5 | } 6 | 7 | export type DidEndMovingCameraCallback = ( 8 | result: DidEndMovingCameraResult, 9 | err?: any 10 | ) => void; 11 | -------------------------------------------------------------------------------- /src/interfaces/events/DidLongPressMap.ts: -------------------------------------------------------------------------------- 1 | import { LatLng } from "./../../definitions"; 2 | 3 | export interface DidLongPressMapResult { 4 | position: LatLng; 5 | } 6 | 7 | export type DidLongPressMapCallback = ( 8 | result: DidLongPressMapResult | null, 9 | err?: any 10 | ) => void; 11 | -------------------------------------------------------------------------------- /src/interfaces/events/DidMoveCamera.ts: -------------------------------------------------------------------------------- 1 | export type DidMoveCameraCallback = ( 2 | result: undefined | null, 3 | err?: any 4 | ) => void; 5 | -------------------------------------------------------------------------------- /src/interfaces/events/DidTapInfoWindow.ts: -------------------------------------------------------------------------------- 1 | import { Marker } from "./../../definitions"; 2 | 3 | export interface DidTapInfoWindowResult { 4 | marker: Marker; 5 | } 6 | 7 | export type DidTapInfoWindowCallback = ( 8 | result: DidTapInfoWindowResult | null, 9 | err?: any 10 | ) => void; 11 | -------------------------------------------------------------------------------- /src/interfaces/events/DidTapMap.ts: -------------------------------------------------------------------------------- 1 | import { LatLng } from "./../../definitions"; 2 | 3 | export interface DidTapMapResult { 4 | position: LatLng; 5 | } 6 | 7 | export type DidTapMapCallback = ( 8 | result: DidTapMapResult | null, 9 | err?: any 10 | ) => void; 11 | -------------------------------------------------------------------------------- /src/interfaces/events/DidTapMarker.ts: -------------------------------------------------------------------------------- 1 | import { Marker } from "./../../definitions"; 2 | 3 | export interface DidTapMarkerResult { 4 | marker: Marker; 5 | } 6 | 7 | export type DidTapMarkerCallback = ( 8 | result: DidTapMarkerResult | null, 9 | err?: any 10 | ) => void; 11 | -------------------------------------------------------------------------------- /src/interfaces/events/DidTapMyLocationButton.ts: -------------------------------------------------------------------------------- 1 | export type DidTapMyLocationButtonCallback = ( 2 | result: undefined | null, 3 | err?: any 4 | ) => void; 5 | -------------------------------------------------------------------------------- /src/interfaces/events/DidTapMyLocationDot.ts: -------------------------------------------------------------------------------- 1 | import { LatLng } from "./../../definitions"; 2 | 3 | export interface DidTapMyLocationDotResult { 4 | position: LatLng; 5 | } 6 | 7 | export type DidTapMyLocationDotCallback = ( 8 | result: DidTapMyLocationDotResult | null, 9 | err?: any 10 | ) => void; 11 | -------------------------------------------------------------------------------- /src/interfaces/events/DidTapPoi.ts: -------------------------------------------------------------------------------- 1 | import { PointOfInterest } from "./../../definitions"; 2 | 3 | export interface DidTapPoiResult { 4 | poi: PointOfInterest; 5 | } 6 | 7 | export type DidTapPoiCallback = ( 8 | result: DidTapPoiResult | null, 9 | err?: any 10 | ) => void; 11 | -------------------------------------------------------------------------------- /src/interfaces/index.ts: -------------------------------------------------------------------------------- 1 | // methods 2 | export { InitializeOptions } from "./methods/Initialize"; 3 | export { CreateMapOptions, CreateMapResult } from "./methods/CreateMap"; 4 | export { UpdateMapOptions, UpdateMapResult } from "./methods/UpdateMap"; 5 | export { RemoveMapOptions } from "./methods/RemoveMap"; 6 | export { ClearMapOptions } from "./methods/ClearMap"; 7 | export { MoveCameraOptions } from "./methods/MoveCamera"; 8 | export { ElementFromPointResultOptions } from "./methods/ElementFromPointResult"; 9 | export { AddMarkerOptions, AddMarkerResult } from "./methods/AddMarker"; 10 | export { 11 | AddMarkersOptions, 12 | MarkerInputEntry, 13 | AddMarkersResult, 14 | } from "./methods/AddMarkers"; 15 | export { RemoveMarkerOptions } from "./methods/RemoveMarker"; 16 | export { AddPolygonOptions, AddPolygonResult } from "./methods/AddPolygon"; 17 | export { RemovePolygonOptions } from "./methods/RemovePolygon"; 18 | 19 | // events 20 | export * from "./events/DidTapInfoWindow"; 21 | export * from "./events/DidCloseInfoWindow"; 22 | export * from "./events/DidTapMap"; 23 | export * from "./events/DidLongPressMap"; 24 | export * from "./events/DidTapMarker"; 25 | export * from "./events/DidBeginDraggingMarker"; 26 | export * from "./events/DidDragMarker"; 27 | export * from "./events/DidEndDraggingMarker"; 28 | export * from "./events/DidTapMyLocationButton"; 29 | export * from "./events/DidTapMyLocationDot"; 30 | export * from "./events/DidTapPoi"; 31 | export * from "./events/DidBeginMovingCamera"; 32 | export * from "./events/DidMoveCamera"; 33 | export * from "./events/DidEndMovingCamera"; 34 | 35 | // models 36 | export { CameraMovementReason } from "./models/GoogleMap/Camera/MovementReason"; 37 | export { CameraPosition } from "./models/GoogleMap/Camera/Position"; 38 | export { Marker } from "./models/GoogleMap/Marker/Marker"; 39 | export { MarkerPreferences } from "./models/GoogleMap/Marker/MarkerPreferences"; 40 | export { MarkerIcon } from "./models/GoogleMap/Marker/MarkerIcon"; 41 | export { MarkerIconSize } from "./models/GoogleMap/Marker/MarkerIconSize"; 42 | export { MapAppearance } from "./models/GoogleMap/Appearance"; 43 | export { MapControls } from "./models/GoogleMap/Controls"; 44 | export { MapGestures } from "./models/GoogleMap/Gestures"; 45 | export { GoogleMap } from "./models/GoogleMap/GoogleMap"; 46 | export { MapPreferences } from "./models/GoogleMap/Preferences"; 47 | export { PointOfInterest } from "./models/GoogleMap/PointOfInterest"; 48 | export { Polygon } from "./models/GoogleMap/Polygon/Polygon"; 49 | export { PolygonPreferences } from "./models/GoogleMap/Polygon/PolygonPreferences"; 50 | export { BoundingRect } from "./models/BoundingRect"; 51 | export { LatLng } from "./models/LatLng"; 52 | -------------------------------------------------------------------------------- /src/interfaces/methods/AddMarker.ts: -------------------------------------------------------------------------------- 1 | import { LatLng, Marker, MarkerPreferences } from "./../../definitions"; 2 | 3 | export interface AddMarkerOptions { 4 | /** 5 | * @since 2.0.0 6 | */ 7 | mapId: string; 8 | /** 9 | * @since 2.0.0 10 | */ 11 | position: LatLng; 12 | /** 13 | * @since 2.0.0 14 | */ 15 | preferences?: MarkerPreferences; 16 | } 17 | 18 | export interface AddMarkerResult { 19 | /** 20 | * @since 2.0.0 21 | */ 22 | marker: Marker; 23 | } 24 | -------------------------------------------------------------------------------- /src/interfaces/methods/AddMarkers.ts: -------------------------------------------------------------------------------- 1 | import { LatLng, MarkerPreferences } from "./../../definitions"; 2 | 3 | export interface MarkerInputEntry { 4 | /** 5 | * @since 2.0.0 6 | */ 7 | position: LatLng; 8 | /** 9 | * @since 2.0.0 10 | */ 11 | preferences?: MarkerPreferences; 12 | } 13 | 14 | export interface AddMarkersOptions { 15 | /** 16 | * @since 2.0.0 17 | */ 18 | mapId: string; 19 | /** 20 | * @since 2.0.0 21 | */ 22 | markers: MarkerInputEntry[]; 23 | } 24 | 25 | export interface MarkerOutputEntry { 26 | /** 27 | * GUID representing the unique id of this marker 28 | * 29 | * @since 2.0.0 30 | */ 31 | markerId: string; 32 | /** 33 | * @since 2.0.0 34 | */ 35 | position: LatLng; 36 | /** 37 | * @since 2.0.0 38 | */ 39 | preferences: MarkerPreferences; 40 | } 41 | 42 | export interface AddMarkersResult { 43 | /** 44 | * @since 2.0.0 45 | */ 46 | mapId: string; 47 | /** 48 | * @since 2.0.0 49 | */ 50 | markers: MarkerOutputEntry[]; 51 | } 52 | -------------------------------------------------------------------------------- /src/interfaces/methods/AddPolygon.ts: -------------------------------------------------------------------------------- 1 | import { Polygon, PolygonPreferences, LatLng } from "../../definitions"; 2 | 3 | export interface AddPolygonOptions { 4 | /** 5 | * GUID representing the map this polygon is a part of 6 | * 7 | * @since 2.0.0 8 | */ 9 | mapId: string; 10 | /** 11 | * The path (outline) is specified by a list of vertices in clockwise or counterclockwise order. 12 | * It is not necessary for the start and end points to coincide; 13 | * if they do not, the polygon will be automatically closed. 14 | * Line segments are drawn between consecutive points in the shorter of the two directions (east or west). 15 | * 16 | * @since 2.0.0 17 | */ 18 | path: LatLng[]; 19 | /** 20 | * @since 2.0.0 21 | */ 22 | preferences?: PolygonPreferences; 23 | } 24 | 25 | export interface AddPolygonResult { 26 | /** 27 | * @since 2.0.0 28 | */ 29 | polygon: Polygon; 30 | } 31 | -------------------------------------------------------------------------------- /src/interfaces/methods/ClearMap.ts: -------------------------------------------------------------------------------- 1 | export interface ClearMapOptions { 2 | /** 3 | * @since 2.0.0 4 | */ 5 | mapId: string; 6 | } 7 | -------------------------------------------------------------------------------- /src/interfaces/methods/CreateMap.ts: -------------------------------------------------------------------------------- 1 | import { 2 | GoogleMap, 3 | BoundingRect, 4 | MapPreferences, 5 | CameraPosition, 6 | } from "./../../definitions"; 7 | 8 | export interface CreateMapOptions { 9 | /** 10 | * @since 2.0.0 11 | */ 12 | element?: HTMLElement; 13 | /** 14 | * @since 2.0.0 15 | */ 16 | boundingRect?: BoundingRect; 17 | /** 18 | * @since 2.0.0 19 | */ 20 | cameraPosition: CameraPosition; 21 | /** 22 | * @since 2.0.0 23 | */ 24 | preferences?: MapPreferences; 25 | } 26 | 27 | export interface CreateMapResult { 28 | /** 29 | * @since 2.0.0 30 | */ 31 | googleMap: GoogleMap; 32 | } 33 | -------------------------------------------------------------------------------- /src/interfaces/methods/ElementFromPointResult.ts: -------------------------------------------------------------------------------- 1 | export interface ElementFromPointResultOptions { 2 | eventChainId: string; 3 | mapId: string | null; 4 | isSameNode: boolean; 5 | } 6 | -------------------------------------------------------------------------------- /src/interfaces/methods/Initialize.ts: -------------------------------------------------------------------------------- 1 | export interface InitializeOptions { 2 | /** 3 | * Defines the pixel ratio of the current device in the current state. 4 | * Recommended to be set by using `window.devicePixelRatio`. 5 | * This is needed because real pixels on a device do not necessarily correspond with how pixels are calculated in a WebView. 6 | * 7 | * @since 2.0.0 8 | */ 9 | devicePixelRatio: number; 10 | /** 11 | * (iOS only) 12 | * API Key for Google Maps SDK for iOS. 13 | * Hence it is only required on iOS. 14 | * 15 | * @since 1.0.0 16 | */ 17 | key?: string; 18 | } 19 | -------------------------------------------------------------------------------- /src/interfaces/methods/MoveCamera.ts: -------------------------------------------------------------------------------- 1 | import { CameraPosition } from "./../../definitions"; 2 | 3 | export interface MoveCameraOptions { 4 | /** 5 | * The identifier of the map to which this method should be applied. 6 | * 7 | * @since 2.0.0 8 | */ 9 | mapId: string; 10 | /** 11 | * @since 2.0.0 12 | */ 13 | cameraPosition: CameraPosition; 14 | /** 15 | * The duration of the animation in milliseconds. 16 | * If not specified, or equals or smaller than 0, the camera movement will be immediate 17 | * 18 | * @default 0 19 | * @since 2.0.0 20 | */ 21 | duration?: number; 22 | /** 23 | * By default the moveCamera method uses the current CameraPosition as the base. 24 | * That means that if, for example, the CameraPosition.target is not specified, 25 | * the current CameraPosition.target will be used. 26 | * Among other things, this default behaviour allows you to set the zoom without moving the map. 27 | * Or move the map without changing the current zoom. 28 | * If instead of this default behaviour, the previous CameraPosition (the one you gave the previous 29 | * time you called `moveCamera` or `createMap`) should be used as the base, this parameter should be set to `false`. 30 | * But be cautious when using this. 31 | * If the user made changes to the CameraPosition (e.g. by scrolling or zooming the map), 32 | * those changes will be undone because it will be overwritten by the last explicitly set CameraPosition. 33 | * The CameraPosition is only "explicitly set" with these methods: `createMap` and `moveCamera`. 34 | * 35 | * @default true 36 | * @since 2.0.0 37 | */ 38 | useCurrentCameraPositionAsBase?: boolean; 39 | } 40 | -------------------------------------------------------------------------------- /src/interfaces/methods/RemoveMap.ts: -------------------------------------------------------------------------------- 1 | export interface RemoveMapOptions { 2 | /** 3 | * @since 2.0.0 4 | */ 5 | mapId: string; 6 | } 7 | -------------------------------------------------------------------------------- /src/interfaces/methods/RemoveMarker.ts: -------------------------------------------------------------------------------- 1 | export interface RemoveMarkerOptions { 2 | /** 3 | * @since 2.0.0 4 | */ 5 | mapId: string; 6 | /** 7 | * @since 2.0.0 8 | */ 9 | markerId: string; 10 | } 11 | -------------------------------------------------------------------------------- /src/interfaces/methods/RemovePolygon.ts: -------------------------------------------------------------------------------- 1 | export interface RemovePolygonOptions { 2 | /** 3 | * @since 2.0.0 4 | */ 5 | mapId: string; 6 | /** 7 | * @since 2.0.0 8 | */ 9 | polygonId: string; 10 | } 11 | -------------------------------------------------------------------------------- /src/interfaces/methods/UpdateMap.ts: -------------------------------------------------------------------------------- 1 | import { GoogleMap, BoundingRect, MapPreferences } from "./../../definitions"; 2 | 3 | export interface UpdateMapOptions { 4 | /** 5 | * @since 2.0.0 6 | */ 7 | mapId: string; 8 | /** 9 | * @since 2.0.0 10 | */ 11 | element?: HTMLElement; 12 | /** 13 | * @since 2.0.0 14 | */ 15 | boundingRect?: BoundingRect; 16 | /** 17 | * @since 2.0.0 18 | */ 19 | preferences?: MapPreferences; 20 | } 21 | 22 | export interface UpdateMapResult { 23 | /** 24 | * @since 2.0.0 25 | */ 26 | googleMap: GoogleMap; 27 | } 28 | -------------------------------------------------------------------------------- /src/interfaces/models/BoundingRect.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @todo: documentation 3 | */ 4 | export interface BoundingRect { 5 | width: number; 6 | height: number; 7 | x: number; 8 | y: number; 9 | } 10 | -------------------------------------------------------------------------------- /src/interfaces/models/GoogleMap/Appearance.ts: -------------------------------------------------------------------------------- 1 | enum MapType { 2 | /** 3 | * No base map tiles. 4 | * 5 | * @since 2.0.0 6 | */ 7 | None = 0, 8 | /** 9 | * Basic map. 10 | * 11 | * @since 2.0.0 12 | */ 13 | Normal = 1, 14 | /** 15 | * Satellite imagery with no labels. 16 | * 17 | * @since 2.0.0 18 | */ 19 | Satellite = 2, 20 | /** 21 | * Topographic data. 22 | * 23 | * @since 2.0.0 24 | */ 25 | Terrain = 3, 26 | /** 27 | * Satellite imagery with roads and labels. 28 | * 29 | * @since 2.0.0 30 | */ 31 | Hybrid = 4, 32 | } 33 | 34 | /** 35 | * Aggregates all appearance parameters such as showing 3d building, indoor maps, the my-location (blue) dot and traffic. 36 | * Additionally, it also holds parameters such as the type of map tiles and the overall styling of the base map. 37 | */ 38 | export interface MapAppearance { 39 | /** 40 | * Controls the type of map tiles that should be displayed. 41 | * 42 | * @default MapType.Normal 43 | * @since 2.0.0 44 | */ 45 | type?: MapType; 46 | /** 47 | * Holds details about a style which can be applied to a map. 48 | * When set to `null` the default styling will be used. 49 | * With style options you can customize the presentation of the standard Google map styles, changing the visual display of features like roads, parks, and other points of interest. 50 | * As well as changing the style of these features, you can also hide features entirely. 51 | * This means that you can emphasize particular components of the map or make the map complement the content of your app. 52 | * For more information check: https://developers.google.com/maps/documentation/ios-sdk/style-reference 53 | * Or use the wizard for generating JSON: https://mapstyle.withgoogle.com/ 54 | * 55 | * @default null 56 | * @since 2.0.0 57 | */ 58 | style?: string | null; 59 | /** 60 | * If `true`, 3D buildings will be shown where available. 61 | * 62 | * @default true 63 | * @since 2.0.0 64 | */ 65 | isBuildingsShown?: boolean; 66 | /** 67 | * If `true`, indoor maps are shown, where available. 68 | * If this is set to false, caches for indoor data may be purged and any floor currently selected by the end-user may be reset. 69 | * 70 | * @default true 71 | * @since 2.0.0 72 | */ 73 | isIndoorShown?: boolean; 74 | /** 75 | * If `true`, the my-location (blue) dot and accuracy circle are shown. 76 | * 77 | * @default false 78 | * @since 2.0.0 79 | */ 80 | isMyLocationDotShown?: boolean; 81 | /** 82 | * If `true`, the map draws traffic data, if available. 83 | * This is subject to the availability of traffic data. 84 | * 85 | * @default false 86 | * @since 2.0.0 87 | */ 88 | isTrafficShown?: boolean; 89 | } 90 | -------------------------------------------------------------------------------- /src/interfaces/models/GoogleMap/Camera/MovementReason.ts: -------------------------------------------------------------------------------- 1 | export enum CameraMovementReason { 2 | /** 3 | * Camera motion initiated in response to user gestures on the map. 4 | * For example: pan, tilt, pinch to zoom, or rotate. 5 | * 6 | * @since 2.0.0 7 | */ 8 | Gesture = 1, 9 | /** 10 | * Indicates that this is part of a programmatic change - for example, via methods such as `moveCamera`. 11 | * This may also be the case if a user has tapped on the My Location or compass buttons, which generate animations that change the camera. 12 | * 13 | * @since 2.0.0 14 | */ 15 | Other = 2, 16 | } 17 | -------------------------------------------------------------------------------- /src/interfaces/models/GoogleMap/Camera/Position.ts: -------------------------------------------------------------------------------- 1 | import { LatLng } from "./../../../../definitions"; 2 | 3 | /** 4 | * The map view is modeled as a camera looking down on a flat plane. 5 | * The position of the camera (and hence the rendering of the map) is specified by the following properties: target (latitude/longitude location), bearing, tilt, and zoom. 6 | * More information can be found here: https://developers.google.com/maps/documentation/android-sdk/views#the_camera_position 7 | */ 8 | export interface CameraPosition { 9 | /** 10 | * The camera target is the location of the center of the map, specified as latitude and longitude co-ordinates. 11 | * 12 | * @since 2.0.0 13 | */ 14 | target?: LatLng; 15 | /** 16 | * The camera bearing is the direction in which a vertical line on the map points, measured in degrees clockwise from north. 17 | * Someone driving a car often turns a road map to align it with their direction of travel, while hikers using a map and compass usually orient the map so that a vertical line is pointing north. 18 | * The Maps API lets you change a map's alignment or bearing. 19 | * For example, a bearing of 90 degrees results in a map where the upwards direction points due east. 20 | * 21 | * @since 2.0.0 22 | */ 23 | bearing?: number; 24 | /** 25 | * The tilt defines the camera's position on an arc between directly over the map's center position and the surface of the Earth, measured in degrees from the nadir (the direction pointing directly below the camera). 26 | * When you change the viewing angle, the map appears in perspective, with far-away features appearing smaller, and nearby features appearing larger. 27 | * 28 | * @since 2.0.0 29 | */ 30 | tilt?: number; 31 | /** 32 | * The zoom level of the camera determines the scale of the map. 33 | * At larger zoom levels more detail can be seen on the screen, 34 | * while at smaller zoom levels more of the world can be seen on the screen. 35 | * 36 | * @since 2.0.0 37 | */ 38 | zoom?: number; 39 | } 40 | -------------------------------------------------------------------------------- /src/interfaces/models/GoogleMap/Controls.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Aggregates all control parameters such as enabling the compass, my-location and zoom buttons as well as the toolbar. 3 | */ 4 | export interface MapControls { 5 | /** 6 | * If `true`, the compass button is enabled. 7 | * The compass is an icon on the map that indicates the direction of north on the map. 8 | * If enabled, it is only shown when the camera is rotated away from its default orientation (bearing of 0). 9 | * When a user taps the compass, the camera orients itself to its default orientation and fades away shortly after. 10 | * If disabled, the compass will never be displayed. 11 | * 12 | * @default true 13 | * @since 2.0.0 14 | */ 15 | isCompassButtonEnabled?: boolean; 16 | // TODO: 17 | // /** 18 | // * If `true`, the indoor level picker is enabled. 19 | // * If the button is enabled, it is only shown when `MapAppearance.isIndoorShown === true`. 20 | // * Additionally, it is only visible when the view is focused on a building with indoor floor data. 21 | // * 22 | // */ 23 | // isIndoorLevelPickerEnabled: boolean; 24 | /** 25 | * (Android only) 26 | * 27 | * If `true`, the Map Toolbar is enabled. 28 | * If enabled, and the Map Toolbar can be shown in the current context, users will see a bar with various context-dependent actions, including 'open this map in the Google Maps app' and 'find directions to the highlighted marker in the Google Maps app'. 29 | * 30 | * @default false 31 | * @since 2.0.0 32 | */ 33 | isMapToolbarEnabled?: boolean; 34 | /** 35 | * If `true`, the my-location button is enabled. 36 | * This is a button visible on the map that, when tapped by users, will center the map on the current user location. 37 | * If the button is enabled, it is only shown when `MapAppearance.isMyLocationDotShown === true`. 38 | * 39 | * @default true 40 | * @since 2.0.0 41 | */ 42 | isMyLocationButtonEnabled?: boolean; 43 | /** 44 | * (Android only) 45 | * If `true`, the zoom controls are enabled. 46 | * The zoom controls are a pair of buttons (one for zooming in, one for zooming out) that appear on the screen when enabled. 47 | * When pressed, they cause the camera to zoom in (or out) by one zoom level. 48 | * If disabled, the zoom controls are not shown. 49 | * 50 | * @default false 51 | * @since 2.0.0 52 | */ 53 | isZoomButtonsEnabled?: boolean; 54 | } 55 | -------------------------------------------------------------------------------- /src/interfaces/models/GoogleMap/Gestures.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Aggregates all gesture parameters such as allowing for rotating, scrolling, tilting and zooming the map. 3 | */ 4 | export interface MapGestures { 5 | /** 6 | * If `true`, rotate gestures are allowed. 7 | * If enabled, users can use a two-finger rotate gesture to rotate the camera. 8 | * If disabled, users cannot rotate the camera via gestures. 9 | * This setting doesn't restrict the user from tapping the compass button to reset the camera orientation, 10 | * nor does it restrict programmatic movements and animation of the camera. 11 | * 12 | * @default true 13 | * @since 2.0.0 14 | */ 15 | isRotateAllowed?: boolean; 16 | /** 17 | * If `true`, scroll gestures are allowed. 18 | * If enabled, users can swipe to pan the camera. 19 | * If disabled, swiping has no effect. 20 | * This setting doesn't restrict programmatic movement and animation of the camera. 21 | * 22 | * @default true 23 | * @since 2.0.0 24 | */ 25 | isScrollAllowed?: boolean; 26 | /** 27 | * If `true`, scroll gestures can take place at the same time as a zoom or rotate gesture. 28 | * If enabled, users can scroll the map while rotating or zooming the map. 29 | * If disabled, the map cannot be scrolled while the user rotates or zooms the map using gestures. 30 | * This setting doesn't disable scroll gestures entirely, only during rotation and zoom gestures, 31 | * nor does it restrict programmatic movements and animation of the camera. 32 | * 33 | * @default true 34 | * @since 2.0.0 35 | */ 36 | isScrollAllowedDuringRotateOrZoom?: boolean; 37 | /** 38 | * If `true`, tilt gestures are allowed. 39 | * If enabled, users can use a two-finger vertical down swipe to tilt the camera. 40 | * If disabled, users cannot tilt the camera via gestures. 41 | * This setting doesn't restrict users from tapping the compass button to reset the camera orientation, 42 | * nor does it restrict programmatic movement and animation of the camera. 43 | * 44 | * @default true 45 | * @since 2.0.0 46 | */ 47 | isTiltAllowed?: boolean; 48 | /** 49 | * If `true`, zoom gestures are allowed. 50 | * If enabled, users can either double tap/two-finger tap or pinch to zoom the camera. 51 | * If disabled, these gestures have no effect. 52 | * This setting doesn't affect the zoom buttons, 53 | * nor does it restrict programmatic movement and animation of the camera. 54 | * 55 | * @default true 56 | * @since 2.0.0 57 | */ 58 | isZoomAllowed?: boolean; 59 | } 60 | -------------------------------------------------------------------------------- /src/interfaces/models/GoogleMap/GoogleMap.ts: -------------------------------------------------------------------------------- 1 | import { MapPreferences, CameraPosition } from "./../../../definitions"; 2 | 3 | export interface GoogleMap { 4 | /** 5 | * GUID representing the unique id of this map 6 | * 7 | * @since 2.0.0 8 | */ 9 | mapId: string; 10 | /** 11 | * @since 2.0.0 12 | */ 13 | cameraPosition: CameraPosition; 14 | /** 15 | * @since 2.0.0 16 | */ 17 | preferences: MapPreferences; 18 | } 19 | -------------------------------------------------------------------------------- /src/interfaces/models/GoogleMap/Marker/Marker.ts: -------------------------------------------------------------------------------- 1 | import { MarkerPreferences, LatLng } from "./../../../../definitions"; 2 | 3 | export interface Marker { 4 | /** 5 | * GUID representing the map this marker is part of 6 | * 7 | * @since 2.0.0 8 | */ 9 | mapId: string; 10 | /** 11 | * GUID representing the unique id of this marker 12 | * 13 | * @since 2.0.0 14 | */ 15 | markerId: string; 16 | /** 17 | * @since 2.0.0 18 | */ 19 | position: LatLng; 20 | /** 21 | * @since 2.0.0 22 | */ 23 | preferences: MarkerPreferences; 24 | } 25 | -------------------------------------------------------------------------------- /src/interfaces/models/GoogleMap/Marker/MarkerIcon.ts: -------------------------------------------------------------------------------- 1 | import { MarkerIconSize } from "./../../../../definitions"; 2 | 3 | /** 4 | * A data class representing icon/marker. 5 | */ 6 | export interface MarkerIcon { 7 | /** 8 | * URL path to icon 9 | * 10 | * @since 2.0.0 11 | */ 12 | url: string; 13 | /** 14 | * Target icon size in pixels. Defaults to 30x30 if not specified. 15 | * 16 | * @since 2.0.0 17 | */ 18 | size?: MarkerIconSize; 19 | } 20 | -------------------------------------------------------------------------------- /src/interfaces/models/GoogleMap/Marker/MarkerIconSize.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * A data class representing a pair of "width" and "height" in pixels. 3 | */ 4 | export interface MarkerIconSize { 5 | /** 6 | * Width in pixels 7 | * 8 | * @default 30 9 | * @since 2.0.0 10 | */ 11 | width: number; 12 | /** 13 | * Height in pixels 14 | * 15 | * @default 30 16 | * @since 2.0.0 17 | */ 18 | height: number; 19 | } 20 | -------------------------------------------------------------------------------- /src/interfaces/models/GoogleMap/Marker/MarkerPreferences.ts: -------------------------------------------------------------------------------- 1 | import { MarkerIcon } from "./../../../../definitions"; 2 | 3 | export interface MarkerPreferences { 4 | /** 5 | * A text string that's displayed in an info window when the user taps the marker. 6 | * You can change this value at any time. 7 | * 8 | * @default null 9 | * @since 2.0.0 10 | */ 11 | title?: string; 12 | /** 13 | * Additional text that's displayed below the title. You can change this value at any time. 14 | * 15 | * @default null 16 | * @since 2.0.0 17 | */ 18 | snippet?: string; 19 | /** 20 | * This is a value from 0 to 1, where 0 means the marker is completely transparent and 1 means the marker is completely opaque. 21 | * 22 | * @default 1 23 | * @since 2.0.0 24 | */ 25 | opacity?: number; 26 | /** 27 | * Controls whether this marker should be flat against the Earth's surface (`true`) or a billboard facing the camera (`false`). 28 | * 29 | * @default false 30 | * @since 2.0.0 31 | */ 32 | isFlat?: boolean; 33 | /** 34 | * Controls whether this marker can be dragged interactively. 35 | * When a marker is draggable, it can be moved by the user by long pressing on the marker. 36 | * 37 | * @default false 38 | * @since 2.0.0 39 | */ 40 | isDraggable?: boolean; 41 | /** 42 | * The z-index specifies the stack order of this marker, relative to other markers on the map. 43 | * A marker with a high z-index is drawn on top of markers with lower z-indexes. 44 | * Markers are always drawn above tile layers and other non-marker overlays (ground overlays, 45 | * polylines, polygons, and other shapes) regardless of the z-index of the other overlays. 46 | * Markers are effectively considered to be in a separate z-index group compared to other overlays. 47 | * 48 | * @default 0 49 | * @since 2.0.0 50 | */ 51 | zIndex?: number; 52 | /** 53 | * Specifies the anchor to be at a particular point in the marker image. 54 | * 55 | * The anchor specifies the point in the icon image that is anchored to the marker's position on the Earth's surface. 56 | * 57 | * The anchor point is specified in the continuous space [0.0, 1.0] x [0.0, 1.0], where (0, 0) is the top-left corner of the image, and (1, 1) is the bottom-right corner. 58 | * 59 | * Read more about it here: https://developers.google.com/android/reference/com/google/android/gms/maps/model/MarkerOptions#anchor(float,%20float) 60 | * 61 | * @default { x: 0.5, y: 1 } 62 | * @since 2.0.0 63 | */ 64 | anchor?: { x: number; y: number }; 65 | /** 66 | * @default undefined 67 | * @since 2.0.0 68 | */ 69 | icon?: MarkerIcon; 70 | /** 71 | * You can use this property to associate an arbitrary object with this overlay. 72 | * The Google Maps SDK neither reads nor writes this property. 73 | * Note that metadata should not hold any strong references to any Maps objects, 74 | * otherwise a retain cycle may be created (preventing objects from being released). 75 | * 76 | * @default {} 77 | * @since 2.0.0 78 | */ 79 | metadata?: { [key: string]: any }; 80 | } 81 | -------------------------------------------------------------------------------- /src/interfaces/models/GoogleMap/PointOfInterest.ts: -------------------------------------------------------------------------------- 1 | import { LatLng } from "./../../../definitions"; 2 | 3 | export interface PointOfInterest { 4 | /** 5 | * The name of the POI. 6 | * 7 | * @since 2.0.0 8 | */ 9 | name: String; 10 | /** 11 | * The placeId of the POI. 12 | * Read more about what you can use a placeId for here: https://developers.google.com/maps/documentation/places/web-service/place-id 13 | * 14 | * @since 2.0.0 15 | */ 16 | placeId: String; 17 | /** 18 | * @since 2.0.0 19 | */ 20 | position: LatLng; 21 | } 22 | -------------------------------------------------------------------------------- /src/interfaces/models/GoogleMap/Polygon/Polygon.ts: -------------------------------------------------------------------------------- 1 | import { LatLng, PolygonPreferences } from "../../../../definitions"; 2 | 3 | export interface Polygon { 4 | /** 5 | * GUID representing the map this polygon is a part of 6 | * 7 | * @since 2.0.0 8 | */ 9 | mapId: string; 10 | /** 11 | * GUID representing the unique id of this polygon 12 | * 13 | * @since 2.0.0 14 | */ 15 | polygonId: string; 16 | /** 17 | * The path (outline) is specified by a list of vertices in clockwise or counterclockwise order. 18 | * It is not necessary for the start and end points to coincide; 19 | * if they do not, the polygon will be automatically closed. 20 | * Line segments are drawn between consecutive points in the shorter of the two directions (east or west). 21 | * 22 | * @since 2.0.0 23 | */ 24 | path: LatLng[]; 25 | /** 26 | * @since 2.0.0 27 | */ 28 | preferences?: PolygonPreferences; 29 | } 30 | -------------------------------------------------------------------------------- /src/interfaces/models/GoogleMap/Polygon/PolygonPreferences.ts: -------------------------------------------------------------------------------- 1 | import { LatLng } from "../../../../definitions"; 2 | 3 | export interface PolygonPreferences { 4 | /** 5 | * A hole is a region inside the polygon that is not filled. 6 | * A hole is specified in exactly the same way as the path of the polygon itself. 7 | * A hole must be fully contained within the outline. 8 | * Multiple holes can be specified, however overlapping holes are not supported. 9 | * 10 | * @since 2.0.0 11 | */ 12 | holes?: LatLng[][]; 13 | /** 14 | * Line segment width in screen pixels. 15 | * The width is constant and independent of the camera's zoom level. 16 | * 17 | * @default 10 18 | * @since 2.0.0 19 | */ 20 | strokeWidth?: number; 21 | /** 22 | * Line segment color in HEX format (with transparency). 23 | * 24 | * @default #000000 (black) 25 | * @since 2.0.0 26 | */ 27 | strokeColor?: string; 28 | /** 29 | * Fill color in HEX format (with transparency). 30 | * 31 | * @default #00000000 (transparent) 32 | * @since 2.0.0 33 | */ 34 | fillColor?: string; 35 | /** 36 | * The z-index specifies the stack order of this polygon, relative to other polygons on the map. 37 | * A polygon with a higher z-index is drawn on top of those with lower indices. 38 | * Markers are always drawn above tile layers and other non-marker overlays (ground overlays, 39 | * polylines, polygons, and other shapes) regardless of the z-index of the other overlays. 40 | * Markers are effectively considered to be in a separate z-index group compared to other overlays. 41 | * 42 | * @default 0 43 | * @since 2.0.0 44 | */ 45 | zIndex?: number; 46 | /** 47 | * Sets the visibility of this polygon. 48 | * When not visible, a polygon is not drawn, but it keeps all its other properties. 49 | * 50 | * @default true 51 | * @since 2.0.0 52 | */ 53 | isVisible?: boolean; 54 | /** 55 | * If `true`, then each segment is drawn as a geodesic. 56 | * If `false`, each segment is drawn as a straight line on the Mercator projection. 57 | * 58 | * @default false 59 | * @since 2.0.0 60 | */ 61 | isGeodesic?: boolean; 62 | /** 63 | * If you want to handle events fired when the user clicks the polygon, set this property to `true`. 64 | * You can change this value at any time. 65 | * 66 | * @default false 67 | * @since 2.0.0 68 | */ 69 | isClickable?: boolean; 70 | /** 71 | * You can use this property to associate an arbitrary object with this overlay. 72 | * The Google Maps SDK neither reads nor writes this property. 73 | * Note that metadata should not hold any strong references to any Maps objects, 74 | * otherwise a retain cycle may be created (preventing objects from being released). 75 | * 76 | * @default {} 77 | * @since 2.0.0 78 | */ 79 | metadata?: { [key: string]: any }; 80 | } 81 | -------------------------------------------------------------------------------- /src/interfaces/models/GoogleMap/Preferences.ts: -------------------------------------------------------------------------------- 1 | import { 2 | MapAppearance, 3 | MapControls, 4 | MapGestures, 5 | } from "./../../../definitions"; 6 | 7 | export interface MapPreferences { 8 | /** 9 | * @since 2.0.0 10 | */ 11 | gestures?: MapGestures; 12 | /** 13 | * @since 2.0.0 14 | */ 15 | controls?: MapControls; 16 | /** 17 | * @since 2.0.0 18 | */ 19 | appearance?: MapAppearance; 20 | 21 | maxZoom?: number; // @todo: Sets a preferred upper bound for the camera zoom. 22 | 23 | minZoom?: number; // @todo: Sets a preferred lower bound for the camera zoom. 24 | 25 | padding?: any; // @todo: Sets padding on the map. 26 | 27 | liteMode?: boolean; // @todo 28 | } 29 | -------------------------------------------------------------------------------- /src/interfaces/models/LatLng.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * A data class representing a pair of latitude and longitude coordinates, stored as degrees. 3 | */ 4 | export interface LatLng { 5 | /** 6 | * Latitude, in degrees. This value is in the range [-90, 90]. 7 | * 8 | * @since 2.0.0 9 | */ 10 | latitude: number; 11 | /** 12 | * Longitude, in degrees. This value is in the range [-180, 180]. 13 | * 14 | * @since 2.0.0 15 | */ 16 | longitude: number; 17 | } 18 | -------------------------------------------------------------------------------- /src/web.ts: -------------------------------------------------------------------------------- 1 | import { WebPlugin } from "@capacitor/core"; 2 | 3 | import { 4 | CapacitorGoogleMapsPlugin, 5 | CallbackID, 6 | InitializeOptions, 7 | CreateMapOptions, 8 | CreateMapResult, 9 | UpdateMapOptions, 10 | UpdateMapResult, 11 | RemoveMapOptions, 12 | ClearMapOptions, 13 | MoveCameraOptions, 14 | ElementFromPointResultOptions, 15 | AddMarkerOptions, 16 | AddMarkerResult, 17 | AddMarkersOptions, 18 | AddMarkersResult, 19 | RemoveMarkerOptions, 20 | AddPolygonOptions, 21 | AddPolygonResult, 22 | RemovePolygonOptions, 23 | DidTapInfoWindowCallback, 24 | DidCloseInfoWindowCallback, 25 | DidTapMapCallback, 26 | DidLongPressMapCallback, 27 | DidTapMarkerCallback, 28 | DidBeginDraggingMarkerCallback, 29 | DidDragMarkerCallback, 30 | DidEndDraggingMarkerCallback, 31 | DidTapMyLocationButtonCallback, 32 | DidTapMyLocationDotCallback, 33 | DidTapPoiCallback, 34 | DidBeginMovingCameraCallback, 35 | DidMoveCameraCallback, 36 | DidEndMovingCameraCallback, 37 | DefaultEventOptions, 38 | DefaultEventWithPreventDefaultOptions, 39 | } from "./definitions"; 40 | 41 | export class CapacitorGoogleMapsWeb 42 | extends WebPlugin 43 | implements CapacitorGoogleMapsPlugin 44 | { 45 | constructor() { 46 | super({ 47 | name: "CapacitorGoogleMaps", 48 | platforms: ["web"], 49 | }); 50 | } 51 | 52 | async initialize(_options: InitializeOptions): Promise { 53 | throw this.unimplemented("Not implemented on web."); 54 | } 55 | 56 | async createMap(_options: CreateMapOptions): Promise { 57 | throw this.unimplemented("Not implemented on web."); 58 | } 59 | 60 | async removeMap(_options: RemoveMapOptions): Promise { 61 | throw this.unimplemented("Not implemented on web."); 62 | } 63 | 64 | async clearMap(_options: ClearMapOptions): Promise { 65 | throw this.unimplemented("Not implemented on web."); 66 | } 67 | 68 | async updateMap(_options: UpdateMapOptions): Promise { 69 | throw this.unimplemented("Not implemented on web."); 70 | } 71 | 72 | async moveCamera(_options: MoveCameraOptions): Promise { 73 | throw this.unimplemented("Not implemented on web."); 74 | } 75 | 76 | async addMarker(_options: AddMarkerOptions): Promise { 77 | throw this.unimplemented("Not implemented on web."); 78 | } 79 | 80 | async addMarkers(_options: AddMarkersOptions): Promise { 81 | throw this.unimplemented("Not implemented on web."); 82 | } 83 | 84 | async removeMarker(_options: RemoveMarkerOptions): Promise { 85 | throw this.unimplemented("Not implemented on web."); 86 | } 87 | 88 | async addPolygon(_options: AddPolygonOptions): Promise { 89 | throw this.unimplemented("Not implemented on web."); 90 | } 91 | 92 | async removePolygon(_options: RemovePolygonOptions): Promise { 93 | throw this.unimplemented("Not implemented on web."); 94 | } 95 | 96 | async didTapInfoWindow( 97 | _options: DefaultEventOptions, 98 | _callback: DidTapInfoWindowCallback 99 | ): Promise { 100 | throw this.unimplemented("Not implemented on web."); 101 | } 102 | 103 | async didCloseInfoWindow( 104 | _options: DefaultEventOptions, 105 | _callback: DidCloseInfoWindowCallback 106 | ): Promise { 107 | throw this.unimplemented("Not implemented on web."); 108 | } 109 | 110 | async didTapMap( 111 | _options: DefaultEventOptions, 112 | _callback: DidTapMapCallback 113 | ): Promise { 114 | throw this.unimplemented("Not implemented on web."); 115 | } 116 | 117 | async didLongPressMap( 118 | _options: DefaultEventOptions, 119 | _callback: DidLongPressMapCallback 120 | ): Promise { 121 | throw this.unimplemented("Not implemented on web."); 122 | } 123 | 124 | async didTapMarker( 125 | _options: DefaultEventWithPreventDefaultOptions, 126 | _callback: DidTapMarkerCallback 127 | ): Promise { 128 | throw this.unimplemented("Not implemented on web."); 129 | } 130 | 131 | async didBeginDraggingMarker( 132 | _options: DefaultEventOptions, 133 | _callback: DidBeginDraggingMarkerCallback 134 | ): Promise { 135 | throw this.unimplemented("Not implemented on web."); 136 | } 137 | 138 | async didDragMarker( 139 | _options: DefaultEventOptions, 140 | _callback: DidDragMarkerCallback 141 | ): Promise { 142 | throw this.unimplemented("Not implemented on web."); 143 | } 144 | 145 | async didEndDraggingMarker( 146 | _options: DefaultEventOptions, 147 | _callback: DidEndDraggingMarkerCallback 148 | ): Promise { 149 | throw this.unimplemented("Not implemented on web."); 150 | } 151 | 152 | async didTapMyLocationButton( 153 | _options: DefaultEventWithPreventDefaultOptions, 154 | _callback: DidTapMyLocationButtonCallback 155 | ): Promise { 156 | throw this.unimplemented("Not implemented on web."); 157 | } 158 | 159 | async didTapMyLocationDot( 160 | _options: DefaultEventWithPreventDefaultOptions, 161 | _callback: DidTapMyLocationDotCallback 162 | ): Promise { 163 | throw this.unimplemented("Not implemented on web."); 164 | } 165 | 166 | async didTapPoi( 167 | _options: DefaultEventOptions, 168 | _callback: DidTapPoiCallback 169 | ): Promise { 170 | throw this.unimplemented("Not implemented on web."); 171 | } 172 | 173 | async didBeginMovingCamera( 174 | _options: DefaultEventOptions, 175 | _callback: DidBeginMovingCameraCallback 176 | ): Promise { 177 | throw this.unimplemented("Not implemented on web."); 178 | } 179 | 180 | async didMoveCamera( 181 | _options: DefaultEventOptions, 182 | _callback: DidMoveCameraCallback 183 | ): Promise { 184 | throw this.unimplemented("Not implemented on web."); 185 | } 186 | 187 | async didEndMovingCamera( 188 | _options: DefaultEventOptions, 189 | _callback: DidEndMovingCameraCallback 190 | ): Promise { 191 | throw this.unimplemented("Not implemented on web."); 192 | } 193 | 194 | async elementFromPointResult( 195 | _options: ElementFromPointResultOptions 196 | ): Promise { 197 | throw this.unimplemented("Not implemented on web."); 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowSyntheticDefaultImports": true, 4 | "declaration": true, 5 | "experimentalDecorators": true, 6 | "lib": [ 7 | "dom", 8 | "es2017" 9 | ], 10 | "module": "esnext", 11 | "moduleResolution": "node", 12 | "noImplicitAny": true, 13 | "noUnusedLocals": true, 14 | "noUnusedParameters": true, 15 | "outDir": "dist/esm", 16 | "sourceMap": true, 17 | "target": "es2017" 18 | }, 19 | "files": [ 20 | "src/index.ts" 21 | ] 22 | } 23 | --------------------------------------------------------------------------------