├── .vscode └── launch.json ├── LICENSE ├── README.md ├── example ├── .gitignore ├── .metadata ├── android │ ├── .gitignore │ ├── app │ │ ├── build.gradle │ │ └── src │ │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ │ ├── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── kotlin │ │ │ │ └── com │ │ │ │ │ └── example │ │ │ │ │ └── flutter_floating_map_marker_titles_demo │ │ │ │ │ └── MainActivity.kt │ │ │ └── res │ │ │ │ ├── drawable-v21 │ │ │ │ └── launch_background.xml │ │ │ │ ├── drawable │ │ │ │ └── launch_background.xml │ │ │ │ ├── mipmap-hdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── values-night │ │ │ │ └── styles.xml │ │ │ │ └── values │ │ │ │ └── styles.xml │ │ │ └── profile │ │ │ └── AndroidManifest.xml │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ └── gradle-wrapper.properties │ └── settings.gradle ├── ios │ ├── .gitignore │ ├── Flutter │ │ ├── AppFrameworkInfo.plist │ │ ├── Debug.xcconfig │ │ └── Release.xcconfig │ ├── Runner.xcodeproj │ │ ├── project.pbxproj │ │ ├── project.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ │ └── WorkspaceSettings.xcsettings │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── Runner.xcscheme │ ├── Runner.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ └── WorkspaceSettings.xcsettings │ ├── Runner │ │ ├── AppDelegate.swift │ │ ├── Assets.xcassets │ │ │ ├── AppIcon.appiconset │ │ │ │ ├── Contents.json │ │ │ │ ├── Icon-App-1024x1024@1x.png │ │ │ │ ├── Icon-App-20x20@1x.png │ │ │ │ ├── Icon-App-20x20@2x.png │ │ │ │ ├── Icon-App-20x20@3x.png │ │ │ │ ├── Icon-App-29x29@1x.png │ │ │ │ ├── Icon-App-29x29@2x.png │ │ │ │ ├── Icon-App-29x29@3x.png │ │ │ │ ├── Icon-App-40x40@1x.png │ │ │ │ ├── Icon-App-40x40@2x.png │ │ │ │ ├── Icon-App-40x40@3x.png │ │ │ │ ├── Icon-App-60x60@2x.png │ │ │ │ ├── Icon-App-60x60@3x.png │ │ │ │ ├── Icon-App-76x76@1x.png │ │ │ │ ├── Icon-App-76x76@2x.png │ │ │ │ └── Icon-App-83.5x83.5@2x.png │ │ │ └── LaunchImage.imageset │ │ │ │ ├── Contents.json │ │ │ │ ├── LaunchImage.png │ │ │ │ ├── LaunchImage@2x.png │ │ │ │ ├── LaunchImage@3x.png │ │ │ │ └── README.md │ │ ├── Base.lproj │ │ │ ├── LaunchScreen.storyboard │ │ │ └── Main.storyboard │ │ ├── Info.plist │ │ └── Runner-Bridging-Header.h │ └── RunnerTests │ │ └── RunnerTests.swift ├── lib │ ├── assets │ │ ├── demo_data.dart │ │ └── images │ │ │ └── marker.png │ ├── drawer │ │ └── drawer.dart │ ├── main.dart │ └── pages │ │ ├── abstract_demo_page.dart │ │ ├── flutter_map │ │ ├── abstract_flutter_map_demo_page.dart │ │ ├── flutter_map_with_layer.dart │ │ ├── flutter_map_wrapped_data.dart │ │ └── flutter_map_wrapped_streams.dart │ │ └── google_maps │ │ └── google_maps.dart ├── pubspec.lock ├── pubspec.yaml ├── test │ └── widget_test.dart └── web │ ├── favicon.png │ ├── icons │ ├── Icon-192.png │ ├── Icon-512.png │ ├── Icon-maskable-192.png │ └── Icon-maskable-512.png │ ├── index.html │ └── manifest.json ├── flutter_floating_map_marker_titles_core ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── analysis_options.yaml ├── lib │ ├── controller │ │ ├── cache │ │ │ ├── epsg_3857_proj_cache.dart │ │ │ └── text_painting_cache.dart │ │ ├── display │ │ │ ├── floating_title_painter.dart │ │ │ ├── layer │ │ │ │ ├── title_layer_background_painter.dart │ │ │ │ ├── title_layer_foreground_painter.dart │ │ │ │ └── title_layer_painter.dart │ │ │ └── titles_display_state.dart │ │ ├── fmto_controller.dart │ │ └── map_view_interface │ │ │ ├── abstract_czr_map_view_interface.dart │ │ │ └── abstract_map_view_interface.dart │ ├── model │ │ └── floating_marker_title_info.dart │ ├── utils │ │ ├── cached_calculator.dart │ │ ├── geo │ │ │ ├── bounds.dart │ │ │ ├── crs.dart │ │ │ └── point.dart │ │ ├── rotating_cache.dart │ │ └── utils.dart │ └── view │ │ ├── abstract_map_view_wrapper.dart │ │ ├── floating_marker_titles_overlay.dart │ │ └── floating_marker_titles_overlay_layer.dart ├── pubspec.lock └── pubspec.yaml ├── flutter_map_floating_marker_titles ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── lib │ └── flutter_map_floating_marker_titles.dart ├── pubspec.lock └── pubspec.yaml ├── google_maps_flutter_floating_marker_titles ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── lib │ └── google_maps_flutter_floating_marker_titles.dart ├── pubspec.lock └── pubspec.yaml ├── publish_checklist.md └── visual_demo.gif /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "FMFMT", 9 | "cwd": "example", 10 | "request": "launch", 11 | "type": "dart" 12 | }, 13 | { 14 | "name": "FMFMT Profiling", 15 | "cwd": "example", 16 | "request": "launch", 17 | "type": "dart", 18 | "flutterMode": "profile" 19 | } 20 | ] 21 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2021, androidseb 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Flutter Floating Map Marker Titles 2 | 3 | This library is inspired from [android-google-maps-floating-marker-titles](https://github.com/androidseb/android-google-maps-floating-marker-titles) and aims to achieve the same thing on Flutter apps. 4 | 5 | I had initially built this library as an experiment to gauge how well native-like things can be achieved with Flutter (e.g. real-time drawing on a Canvas), and I've been very happy with the results, this library is now used in my production app [Map Marker](https://mapmarker.app) running on [Android](https://play.google.com/store/apps/details?id=com.exlyo.mapmarker), [iOS](https://itunes.apple.com/us/app/map-marker-places-organizer/id1287281807) and [Web](https://www.mapmarker.app/webapp/). 6 | 7 | This library is useful if you want to see the titles of the markers on the map floating next to the marker. It attempts to reproduce the behavior for labels of points of interest shown in map applications. It works as a wrapper of existing map view widgets for the following libraries: 8 | * [Flutter Map](https://github.com/fleaflet/flutter_map) 9 | * [Google Maps Flutter](https://github.com/flutter/plugins/tree/master/packages/google_maps_flutter/google_maps_flutter) 10 | 11 | ## Visual Preview 12 | 13 | This is how it looks like, from the example sample app of this library: 14 | 15 | 16 | 17 | ## Project structure 18 | 19 | This project is divided into the following main folders: 20 | * `flutter_floating_map_marker_titles_core`: the core code of the floating map marker titles library, meant to be agnostic of any map view implementation, this is the source code of the [flutter_floating_map_marker_titles_core](https://pub.dev/packages/flutter_floating_map_marker_titles_core) library 21 | * `flutter_map_floating_marker_titles`: the code of the floating map marker titles library for [Flutter Map](https://github.com/fleaflet/flutter_map), this is the source code of the [flutter_map_floating_marker_titles](https://pub.dev/packages/flutter_map_floating_marker_titles) library 22 | * `google_maps_flutter_floating_marker_titles`: the code of the floating map marker titles library for [Google Maps Flutter](https://github.com/flutter/plugins/tree/master/packages/google_maps_flutter/google_maps_flutter), this is the source code of the [google_maps_flutter_floating_marker_titles](https://pub.dev/packages/google_maps_flutter_floating_marker_titles) library 23 | * `example`: a simple example of a flutter application show-casing the use of the libraries 24 | 25 | ## Sample app setup 26 | 27 | In the sample app, the [Flutter Map](https://github.com/fleaflet/flutter_map) example will work out of the box, but for the [Google Maps Flutter](https://github.com/flutter/plugins/tree/master/packages/google_maps_flutter/google_maps_flutter) example to work, you will need to update the following file, based on the [Google Maps Flutter library getting started instructions](https://github.com/flutter/plugins/tree/master/packages/google_maps_flutter/google_maps_flutter#getting-started): 28 | * `example/android/app/src/main/AndroidManifest.xml` 29 | * `example/ios/Runner/AppDelegate.swift` 30 | 31 | ## How to use this library in your code 32 | 33 | For a working example, see the flutter app project in the `example` folder of this repo. 34 | 35 | ### Step 1: depend on the library 36 | 37 | Add `flutter_map_floating_marker_titles` and/or `google_maps_flutter_floating_marker_titles` to your pubspec: 38 | 39 | ```yaml 40 | dependencies: 41 | flutter_map_floating_marker_titles: any # or the latest version on Pub 42 | google_maps_flutter_floating_marker_titles: any # or the latest version on Pub 43 | ``` 44 | 45 | ### Step 2: create the FMTOOptions object 46 | 47 | ```dart 48 | final FMTOOptions fmtoOptions = FMTOOptions(); 49 | ``` 50 | 51 | ### Step 3: create the list of FloatingMarkerTitleInfo items 52 | 53 | ```dart 54 | final List floatingTitles = []; 55 | floatingTitles.add(FloatingMarkerTitleInfo( 56 | id: 0, 57 | latLng: LatLng(0, 0), 58 | title: 'A floating title', 59 | color: Colors.green, 60 | )); 61 | ``` 62 | 63 | ### Step 4a: Create the Flutter Map View 64 | 65 | ```dart 66 | // With the FlutterMapWithFMTO widget as a FlutterMap wrapper 67 | FlutterMapWithFMTO( 68 | floatingTitles: floatingTitles, 69 | fmtoOptions: fmtoOptions, 70 | // ... other than the 2 above option, this widget takes 71 | // exactly the same props as the FlutterMap widget. 72 | options: MapOptions( 73 | center: LatLng(0, 0), 74 | zoom: 13, 75 | ), 76 | children: [ 77 | TileLayer( 78 | urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', 79 | ), 80 | ], 81 | ) 82 | 83 | // Or with the FloatingMarkerTitlesLayer widget as a FlutterMap layer 84 | FlutterMap( 85 | options: MapOptions( 86 | center: LatLng(0, 0), 87 | zoom: 13, 88 | ), 89 | children: [ 90 | TileLayer( 91 | urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', 92 | ), 93 | FloatingMarkerTitlesLayer( 94 | floatingTitles: floatingTitles, 95 | fmtoOptions: fmtoOptions, 96 | ), 97 | ], 98 | ) 99 | ``` 100 | 101 | ### Step 4b: Create the Google Maps View 102 | 103 | ```dart 104 | GoogleMapWithFMTO( 105 | floatingTitles: floatingTitles, 106 | fmtoOptions: fmtoOptions, 107 | // ... other than the 2 above option, this widget takes 108 | // exactly the same props as the GoogleMap widget. 109 | initialCameraPosition: CameraPosition( 110 | target: LatLng(0, 0), 111 | zoom: 13, 112 | ), 113 | ) 114 | ``` 115 | 116 | ## Library features 117 | 118 | ### Overall features 119 | 120 | * Display floating markers titles on top of the map 121 | * Automatically avoids overlap between floating marker titles, will not display a title if overlapping with others 122 | * Marker title text transparent outline for better visuals: the text will be readable no matter the map background and the outline color will adapt to white or black depending on the text color's luminance (perceived brightness) 123 | * Marker title fade-in animation for better visuals 124 | 125 | ### View-wide customization options 126 | 127 | ```dart 128 | FMTOOptions( 129 | // The number of milliseconds between two repaints of the titles layer. 60 frames per seconds = 16 milliseconds between each frame. 130 | repaintIntervalMillis: 16, 131 | // Titles text size 132 | textSize: 14.0, 133 | // Maximum number of floating titles 134 | maxTitlesCount: 30, 135 | // Maximum width of floating titles 136 | maxTitlesWidth: 150, 137 | // Maximum lines count of floating titles 138 | maxTitleLines: 2, 139 | // Maximum number of cached, pre-laid out, ready to draw floating titles info, since computing the layout of text is an expensive operation 140 | textPaintingCacheSize: 2000, 141 | // Maximum number of cached coordinates by the map coordinates projections calculator 142 | mapProjectionsCacheSize: 10000, 143 | // No performance drop with more markers once the maximum number of floating titles has been reached, since the library only scans for a limited number of markers per frame, which can be set with titlesToCheckPerFrame 144 | titlesToCheckPerFrame: 30, 145 | // Time in milliseconds of the title fade-in animation 146 | fadeInAnimationTimeMillis: 300, 147 | // Titles placement option with anchor and margin 148 | titlePlacementPolicy: const FloatingMarkerPlacementPolicy(FloatingMarkerGravity.right, 12), 149 | ); 150 | ``` 151 | 152 | ### Per-title customization options 153 | 154 | ```dart 155 | FloatingMarkerTitleInfo( 156 | // ID of the floating title, used by the system to track what was added/removed between two paints 157 | id: 0, 158 | // Base coordinates the title is attached to 159 | latLng: LatLng(0, 0), 160 | // The title text as a String 161 | title: 'The title', 162 | // The title base color 163 | color: Colors.green, 164 | // Whether the title text should be written in bold 165 | isBold: false, 166 | // z-index of the title to specify which title has the most priority for display in case of titles collisions 167 | zIndex: 1, 168 | ); 169 | ``` 170 | 171 | ## Known limitations 172 | 173 | * Does not work in web for [Google Maps Flutter](https://github.com/flutter/plugins/tree/master/packages/google_maps_flutter/google_maps_flutter) 174 | * Works poorly with Google Maps on Android - when moving the map around, the titles visually lag behind: this is due to a bug in the [google_maps_flutter_android](https://pub.dev/packages/google_maps_flutter_android) library reported [here](https://github.com/flutter/flutter/issues/169152) 175 | 176 | ## About issues and/or feature requests 177 | 178 | I am not willing to invest time to take feature requests at the moment, but if you find a bug, I'll probably want to fix it, so feel free to report any bugs you may find. 179 | 180 | If you need a feature and want to build it and then submit it as a pull request, I'm willing to work with you to merge your work into the current code. 181 | -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .build/ 9 | .buildlog/ 10 | .history 11 | .svn/ 12 | .swiftpm/ 13 | migrate_working_dir/ 14 | 15 | # IntelliJ related 16 | *.iml 17 | *.ipr 18 | *.iws 19 | .idea/ 20 | 21 | # The .vscode folder contains launch configuration and tasks you configure in 22 | # VS Code which you may wish to be included in version control, so this line 23 | # is commented out by default. 24 | #.vscode/ 25 | 26 | # Flutter/Dart/Pub related 27 | **/doc/api/ 28 | **/ios/Flutter/.last_build_id 29 | .dart_tool/ 30 | .flutter-plugins 31 | .flutter-plugins-dependencies 32 | .pub-cache/ 33 | .pub/ 34 | /build/ 35 | 36 | # Symbolication related 37 | app.*.symbols 38 | 39 | # Obfuscation related 40 | app.*.map.json 41 | 42 | # Android Studio will place build artifacts here 43 | /android/app/debug 44 | /android/app/profile 45 | /android/app/release 46 | -------------------------------------------------------------------------------- /example/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: "68415ad1d920f6fe5ec284f5c2febf7c4dd5b0b3" 8 | channel: "stable" 9 | 10 | project_type: app 11 | 12 | # Tracks metadata for the flutter migrate command 13 | migration: 14 | platforms: 15 | - platform: root 16 | create_revision: 68415ad1d920f6fe5ec284f5c2febf7c4dd5b0b3 17 | base_revision: 68415ad1d920f6fe5ec284f5c2febf7c4dd5b0b3 18 | - platform: android 19 | create_revision: 68415ad1d920f6fe5ec284f5c2febf7c4dd5b0b3 20 | base_revision: 68415ad1d920f6fe5ec284f5c2febf7c4dd5b0b3 21 | - platform: ios 22 | create_revision: 68415ad1d920f6fe5ec284f5c2febf7c4dd5b0b3 23 | base_revision: 68415ad1d920f6fe5ec284f5c2febf7c4dd5b0b3 24 | 25 | # User provided section 26 | 27 | # List of Local paths (relative to this file) that should be 28 | # ignored by the migrate tool. 29 | # 30 | # Files that are not part of the templates will be ignored by default. 31 | unmanaged_files: 32 | - 'lib/main.dart' 33 | - 'ios/Runner.xcodeproj/project.pbxproj' 34 | -------------------------------------------------------------------------------- /example/android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/to/reference-keystore 11 | key.properties 12 | **/*.keystore 13 | **/*.jks 14 | -------------------------------------------------------------------------------- /example/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id "com.android.application" 3 | id "kotlin-android" 4 | // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. 5 | id "dev.flutter.flutter-gradle-plugin" 6 | } 7 | 8 | android { 9 | namespace = "com.example.flutter_floating_map_marker_titles_demo" 10 | compileSdk = flutter.compileSdkVersion 11 | ndkVersion = flutter.ndkVersion 12 | 13 | compileOptions { 14 | sourceCompatibility = JavaVersion.VERSION_1_8 15 | targetCompatibility = JavaVersion.VERSION_1_8 16 | } 17 | 18 | kotlinOptions { 19 | jvmTarget = JavaVersion.VERSION_1_8 20 | } 21 | 22 | defaultConfig { 23 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 24 | applicationId = "com.example.flutter_floating_map_marker_titles_demo" 25 | // You can update the following values to match your application needs. 26 | // For more information, see: https://flutter.dev/to/review-gradle-config. 27 | minSdk = flutter.minSdkVersion 28 | targetSdk = flutter.targetSdkVersion 29 | versionCode = flutter.versionCode 30 | versionName = flutter.versionName 31 | } 32 | 33 | buildTypes { 34 | release { 35 | // TODO: Add your own signing config for the release build. 36 | // Signing with the debug keys for now, so `flutter run --release` works. 37 | signingConfig = signingConfigs.debug 38 | } 39 | } 40 | } 41 | 42 | flutter { 43 | source = "../.." 44 | } 45 | -------------------------------------------------------------------------------- /example/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 9 | 18 | 22 | 26 | 27 | 28 | 29 | 30 | 31 | 33 | 36 | 38 | 39 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /example/android/app/src/main/kotlin/com/example/flutter_floating_map_marker_titles_demo/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.flutter_floating_map_marker_titles_demo 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() 6 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androidseb/flutter_map_floating_marker_titles/9834a35c0f0292e1c24dc91acb340e80f71bc388/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androidseb/flutter_map_floating_marker_titles/9834a35c0f0292e1c24dc91acb340e80f71bc388/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androidseb/flutter_map_floating_marker_titles/9834a35c0f0292e1c24dc91acb340e80f71bc388/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androidseb/flutter_map_floating_marker_titles/9834a35c0f0292e1c24dc91acb340e80f71bc388/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androidseb/flutter_map_floating_marker_titles/9834a35c0f0292e1c24dc91acb340e80f71bc388/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /example/android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/android/build.gradle: -------------------------------------------------------------------------------- 1 | allprojects { 2 | repositories { 3 | google() 4 | mavenCentral() 5 | } 6 | } 7 | 8 | rootProject.buildDir = "../build" 9 | subprojects { 10 | project.buildDir = "${rootProject.buildDir}/${project.name}" 11 | } 12 | subprojects { 13 | project.evaluationDependsOn(":app") 14 | } 15 | 16 | tasks.register("clean", Delete) { 17 | delete rootProject.buildDir 18 | } 19 | -------------------------------------------------------------------------------- /example/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx4G -XX:MaxMetaspaceSize=2G -XX:+HeapDumpOnOutOfMemoryError 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /example/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-all.zip 6 | -------------------------------------------------------------------------------- /example/android/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | def flutterSdkPath = { 3 | def properties = new Properties() 4 | file("local.properties").withInputStream { properties.load(it) } 5 | def flutterSdkPath = properties.getProperty("flutter.sdk") 6 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 7 | return flutterSdkPath 8 | }() 9 | 10 | includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") 11 | 12 | repositories { 13 | google() 14 | mavenCentral() 15 | gradlePluginPortal() 16 | } 17 | } 18 | 19 | plugins { 20 | id "dev.flutter.flutter-plugin-loader" version "1.0.0" 21 | id "com.android.application" version "8.1.0" apply false 22 | id "org.jetbrains.kotlin.android" version "1.8.22" apply false 23 | } 24 | 25 | include ":app" 26 | -------------------------------------------------------------------------------- /example/ios/.gitignore: -------------------------------------------------------------------------------- 1 | **/dgph 2 | *.mode1v3 3 | *.mode2v3 4 | *.moved-aside 5 | *.pbxuser 6 | *.perspectivev3 7 | **/*sync/ 8 | .sconsign.dblite 9 | .tags* 10 | **/.vagrant/ 11 | **/DerivedData/ 12 | Icon? 13 | **/Pods/ 14 | **/.symlinks/ 15 | profile 16 | xcuserdata 17 | **/.generated/ 18 | Flutter/App.framework 19 | Flutter/Flutter.framework 20 | Flutter/Flutter.podspec 21 | Flutter/Generated.xcconfig 22 | Flutter/ephemeral/ 23 | Flutter/app.flx 24 | Flutter/app.zip 25 | Flutter/flutter_assets/ 26 | Flutter/flutter_export_environment.sh 27 | ServiceDefinitions.json 28 | Runner/GeneratedPluginRegistrant.* 29 | 30 | # Exceptions to above rules. 31 | !default.mode1v3 32 | !default.mode2v3 33 | !default.pbxuser 34 | !default.perspectivev3 35 | -------------------------------------------------------------------------------- /example/ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 12.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /example/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /example/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 43 | 49 | 50 | 51 | 52 | 53 | 63 | 65 | 71 | 72 | 73 | 74 | 80 | 82 | 88 | 89 | 90 | 91 | 93 | 94 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import Flutter 2 | import UIKit 3 | import GoogleMaps 4 | 5 | @main 6 | @objc class AppDelegate: FlutterAppDelegate { 7 | override func application( 8 | _ application: UIApplication, 9 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 10 | ) -> Bool { 11 | GMSServices.provideAPIKey("YOUR KEY HERE") 12 | GeneratedPluginRegistrant.register(with: self) 13 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androidseb/flutter_map_floating_marker_titles/9834a35c0f0292e1c24dc91acb340e80f71bc388/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androidseb/flutter_map_floating_marker_titles/9834a35c0f0292e1c24dc91acb340e80f71bc388/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androidseb/flutter_map_floating_marker_titles/9834a35c0f0292e1c24dc91acb340e80f71bc388/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androidseb/flutter_map_floating_marker_titles/9834a35c0f0292e1c24dc91acb340e80f71bc388/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androidseb/flutter_map_floating_marker_titles/9834a35c0f0292e1c24dc91acb340e80f71bc388/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androidseb/flutter_map_floating_marker_titles/9834a35c0f0292e1c24dc91acb340e80f71bc388/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androidseb/flutter_map_floating_marker_titles/9834a35c0f0292e1c24dc91acb340e80f71bc388/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androidseb/flutter_map_floating_marker_titles/9834a35c0f0292e1c24dc91acb340e80f71bc388/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androidseb/flutter_map_floating_marker_titles/9834a35c0f0292e1c24dc91acb340e80f71bc388/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androidseb/flutter_map_floating_marker_titles/9834a35c0f0292e1c24dc91acb340e80f71bc388/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androidseb/flutter_map_floating_marker_titles/9834a35c0f0292e1c24dc91acb340e80f71bc388/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androidseb/flutter_map_floating_marker_titles/9834a35c0f0292e1c24dc91acb340e80f71bc388/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androidseb/flutter_map_floating_marker_titles/9834a35c0f0292e1c24dc91acb340e80f71bc388/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androidseb/flutter_map_floating_marker_titles/9834a35c0f0292e1c24dc91acb340e80f71bc388/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androidseb/flutter_map_floating_marker_titles/9834a35c0f0292e1c24dc91acb340e80f71bc388/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androidseb/flutter_map_floating_marker_titles/9834a35c0f0292e1c24dc91acb340e80f71bc388/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androidseb/flutter_map_floating_marker_titles/9834a35c0f0292e1c24dc91acb340e80f71bc388/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androidseb/flutter_map_floating_marker_titles/9834a35c0f0292e1c24dc91acb340e80f71bc388/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /example/ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /example/ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /example/ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | Flutter Floating Map Marker Titles Demo 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | flutter_floating_map_marker_titles_demo 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(FLUTTER_BUILD_NAME) 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | $(FLUTTER_BUILD_NUMBER) 25 | LSRequiresIPhoneOS 26 | 27 | UILaunchStoryboardName 28 | LaunchScreen 29 | UIMainStoryboardFile 30 | Main 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | CADisableMinimumFrameDurationOnPhone 45 | 46 | UIApplicationSupportsIndirectInputEvents 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /example/ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /example/ios/RunnerTests/RunnerTests.swift: -------------------------------------------------------------------------------- 1 | import Flutter 2 | import UIKit 3 | import XCTest 4 | 5 | class RunnerTests: XCTestCase { 6 | 7 | func testExample() { 8 | // If you add code to the Runner application, consider adding tests here. 9 | // See https://developer.apple.com/documentation/xctest for more information about using XCTest. 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /example/lib/assets/demo_data.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:latlong2/latlong.dart'; 3 | 4 | const String APP_TITLE = 'Floating markers demo'; 5 | const String FLUTTER_MAP_HELP_DIALOG_MESSAGE = ''' 6 | You can tap on the map to add markers with floating titles. 7 | You can use the slider at the top to rotate the map too. 8 | This example uses the 'fleaflet' flutter library to display the map. 9 | '''; 10 | const String GOOGLE_MAPS_HELP_DIALOG_MESSAGE = ''' 11 | You can tap on the map to add markers with floating titles. 12 | You can use the pinch gesture to rotate the map too. 13 | This example uses the 'google_maps_flutter' flutter library to display the map. 14 | '''; 15 | const String OK_BUTTON_TEXT = 'OK'; 16 | const String ROTATION_LABEL_TEXT = 'Rotation'; 17 | // ignore: non_constant_identifier_names 18 | LatLng INITIAL_MAP_LOCATION = LatLng(47.2378, 6.0241); 19 | const double INITIAL_MAP_ZOOM = 13.0; 20 | const String MARKER_ICON_ASSET_PATH = 'lib/assets/images/marker.png'; 21 | const List COLORS = [ 22 | Colors.amber, 23 | Colors.blue, 24 | Colors.blueGrey, 25 | Colors.brown, 26 | Colors.cyan, 27 | Colors.deepOrange, 28 | Colors.deepPurple, 29 | Colors.green, 30 | Colors.grey, 31 | Colors.indigo, 32 | Colors.lightBlue, 33 | Colors.lightGreen, 34 | Colors.lime, 35 | Colors.orange, 36 | Colors.pink, 37 | Colors.purple, 38 | Colors.red, 39 | Colors.teal, 40 | Colors.yellow, 41 | Colors.black, 42 | Colors.white, 43 | ]; 44 | const List MARKER_NAMES = [ 45 | 'Marker', 46 | 'A marker with a moderately long name', 47 | 'A marker with a somewhat long long long long long long long long name', 48 | 'A marker with a very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very long name', 49 | 'Some marker', 50 | 'Some other marker', 51 | 'Bakery', 52 | 'A', 53 | 'B', 54 | 'Restaurant', 55 | 'Some lake', 56 | ]; 57 | -------------------------------------------------------------------------------- /example/lib/assets/images/marker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androidseb/flutter_map_floating_marker_titles/9834a35c0f0292e1c24dc91acb340e80f71bc388/example/lib/assets/images/marker.png -------------------------------------------------------------------------------- /example/lib/drawer/drawer.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_floating_map_marker_titles_demo/pages/flutter_map/flutter_map_with_layer.dart'; 3 | import 'package:flutter_floating_map_marker_titles_demo/pages/flutter_map/flutter_map_wrapped_data.dart'; 4 | import 'package:flutter_floating_map_marker_titles_demo/pages/flutter_map/flutter_map_wrapped_streams.dart'; 5 | import 'package:flutter_floating_map_marker_titles_demo/pages/google_maps/google_maps.dart'; 6 | import 'package:flutter_floating_map_marker_titles_demo/assets/demo_data.dart' as demo_data; 7 | 8 | Widget _buildMenuItem(final BuildContext context, final String routeName, final String currentRoute) { 9 | bool isSelected = routeName == currentRoute; 10 | 11 | return ListTile( 12 | title: Text(routeName), 13 | selected: isSelected, 14 | onTap: () { 15 | if (isSelected) { 16 | Navigator.pop(context); 17 | } else { 18 | Navigator.pushReplacementNamed(context, routeName); 19 | } 20 | }, 21 | ); 22 | } 23 | 24 | Drawer buildDrawer(final BuildContext context, final String currentRoute) { 25 | return Drawer( 26 | child: ListView( 27 | children: [ 28 | const DrawerHeader( 29 | child: Center( 30 | child: Text(demo_data.APP_TITLE), 31 | ), 32 | ), 33 | _buildMenuItem( 34 | context, 35 | FlutterMapLayerDemoPage.route, 36 | currentRoute, 37 | ), 38 | _buildMenuItem( 39 | context, 40 | FlutterMapDWrapperDemoPage.route, 41 | currentRoute, 42 | ), 43 | _buildMenuItem( 44 | context, 45 | FlutterMapSWrapperDemoPage.route, 46 | currentRoute, 47 | ), 48 | _buildMenuItem( 49 | context, 50 | GoogleMapsDemoPage.route, 51 | currentRoute, 52 | ), 53 | ], 54 | ), 55 | ); 56 | } 57 | -------------------------------------------------------------------------------- /example/lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import 'package:flutter_floating_map_marker_titles_demo/assets/demo_data.dart' as demo_data; 4 | import 'package:flutter_floating_map_marker_titles_demo/pages/flutter_map/flutter_map_with_layer.dart'; 5 | import 'package:flutter_floating_map_marker_titles_demo/pages/flutter_map/flutter_map_wrapped_data.dart'; 6 | import 'package:flutter_floating_map_marker_titles_demo/pages/flutter_map/flutter_map_wrapped_streams.dart'; 7 | import 'package:flutter_floating_map_marker_titles_demo/pages/google_maps/google_maps.dart'; 8 | 9 | void main() { 10 | runApp(DemoApp()); 11 | } 12 | 13 | class DemoApp extends StatelessWidget { 14 | @override 15 | Widget build(final BuildContext context) { 16 | return MaterialApp( 17 | debugShowCheckedModeBanner: false, 18 | title: demo_data.APP_TITLE, 19 | theme: ThemeData( 20 | primarySwatch: Colors.blue, 21 | ), 22 | home: FlutterMapLayerDemoPage(), 23 | routes: { 24 | FlutterMapLayerDemoPage.route: (context) => FlutterMapLayerDemoPage(), 25 | FlutterMapDWrapperDemoPage.route: (context) => FlutterMapDWrapperDemoPage(), 26 | FlutterMapSWrapperDemoPage.route: ((context) => FlutterMapSWrapperDemoPage()), 27 | GoogleMapsDemoPage.route: (context) => GoogleMapsDemoPage(), 28 | }, 29 | ); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /example/lib/pages/abstract_demo_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_floating_map_marker_titles_core/controller/fmto_controller.dart'; 4 | import 'package:flutter_floating_map_marker_titles_core/model/floating_marker_title_info.dart'; 5 | import 'package:flutter_floating_map_marker_titles_demo/drawer/drawer.dart'; 6 | import 'package:latlong2/latlong.dart'; 7 | import 'package:flutter_floating_map_marker_titles_demo/assets/demo_data.dart' as demo_data; 8 | 9 | abstract class AbstractDemoPage extends StatefulWidget { 10 | AbstractDemoPage({final Key? key}) : super(key: key); 11 | @override 12 | AbstractDemoPageState createState(); 13 | } 14 | 15 | abstract class AbstractDemoPageState extends State> { 16 | final List markers = []; 17 | final List floatingTitles = []; 18 | 19 | M createMarker(final LatLng latLng); 20 | 21 | String getTitleText(); 22 | 23 | String getHelpMessageText(); 24 | 25 | String getPageRouteString(); 26 | 27 | Widget buildMapWidget(final BuildContext context, final Function(LatLng) createNewMarkerCallback); 28 | 29 | FMTOOptions createFMTOOptions() { 30 | // You can specify the Floating Marker Titles Overlay options here 31 | return FMTOOptions(); 32 | } 33 | 34 | @protected 35 | void addMarker(final LatLng latLng) { 36 | setState(() { 37 | addMarkerToData(latLng); 38 | }); 39 | } 40 | 41 | @nonVirtual 42 | @protected 43 | void addMarkerToData(final LatLng latLng) { 44 | markers.add(createMarker(latLng)); 45 | floatingTitles.add(FloatingMarkerTitleInfo( 46 | id: floatingTitles.length + 1, 47 | latLng: latLng, 48 | title: demo_data.MARKER_NAMES[floatingTitles.length % demo_data.MARKER_NAMES.length] + 49 | ' ${floatingTitles.length + 1}', 50 | color: demo_data.COLORS[floatingTitles.length % demo_data.COLORS.length], 51 | zIndex: floatingTitles.length + 1, 52 | )); 53 | } 54 | 55 | Future _showHelpMessageDialog(final BuildContext context) async { 56 | return showDialog( 57 | context: context, 58 | builder: (BuildContext context) { 59 | return AlertDialog( 60 | title: Text(getTitleText()), 61 | content: SingleChildScrollView( 62 | child: ListBody( 63 | children: [ 64 | Text(getHelpMessageText()), 65 | ], 66 | ), 67 | ), 68 | actions: [ 69 | TextButton( 70 | child: Text(demo_data.OK_BUTTON_TEXT), 71 | onPressed: () { 72 | Navigator.of(context).pop(); 73 | }, 74 | ), 75 | ], 76 | ); 77 | }, 78 | ); 79 | } 80 | 81 | @override 82 | Widget build(final BuildContext context) { 83 | return Scaffold( 84 | appBar: AppBar( 85 | title: Text(getTitleText()), 86 | actions: [ 87 | IconButton( 88 | icon: Icon(Icons.help), 89 | onPressed: () { 90 | _showHelpMessageDialog(context); 91 | }, 92 | ) 93 | ], 94 | ), 95 | drawer: buildDrawer(context, getPageRouteString()), 96 | body: buildMapWidget(context, (final LatLng newMarkerLatLng) { 97 | addMarker(newMarkerLatLng); 98 | }), 99 | ); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /example/lib/pages/flutter_map/abstract_flutter_map_demo_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_floating_map_marker_titles_demo/pages/abstract_demo_page.dart'; 4 | import 'package:flutter_map/flutter_map.dart'; 5 | import 'package:latlong2/latlong.dart'; 6 | import 'package:flutter_floating_map_marker_titles_demo/assets/demo_data.dart' as demo_data; 7 | 8 | abstract class AbstractFlutterMapDemoPage extends AbstractDemoPage { 9 | AbstractFlutterMapDemoPage({final Key? key}) : super(key: key); 10 | } 11 | 12 | abstract class AbstractFlutterMapDemoPageState extends AbstractDemoPageState { 13 | final MapController mapController = MapController(); 14 | double currentRotation = 0; 15 | 16 | @override 17 | String getHelpMessageText() { 18 | return demo_data.FLUTTER_MAP_HELP_DIALOG_MESSAGE; 19 | } 20 | 21 | @override 22 | Marker createMarker(final LatLng latLng) { 23 | return Marker( 24 | point: latLng, 25 | width: 14, 26 | height: 20, 27 | alignment: Alignment.topCenter, 28 | rotate: true, 29 | child: Container( 30 | child: Image.asset( 31 | demo_data.MARKER_ICON_ASSET_PATH, 32 | fit: BoxFit.fitHeight, 33 | width: 28, 34 | height: 40, 35 | ), 36 | ), 37 | ); 38 | } 39 | 40 | @nonVirtual 41 | @override 42 | Widget buildMapWidget(final BuildContext context, final Function(LatLng) createNewMarkerCallback) { 43 | return Column( 44 | children: [ 45 | Padding( 46 | padding: EdgeInsets.fromLTRB(16, 4, 16, 4), 47 | child: Row( 48 | children: [ 49 | Text(demo_data.ROTATION_LABEL_TEXT), 50 | Flexible( 51 | child: Slider( 52 | value: currentRotation, 53 | min: 0, 54 | max: 360, 55 | onChanged: (final double newRotationValue) { 56 | mapController.rotate(newRotationValue); 57 | setState(() { 58 | currentRotation = newRotationValue; 59 | }); 60 | }, 61 | ), 62 | ), 63 | ], 64 | ), 65 | ), 66 | Flexible( 67 | child: buildMapWidgetImpl( 68 | context, 69 | MapOptions( 70 | initialCenter: demo_data.INITIAL_MAP_LOCATION, 71 | initialZoom: demo_data.INITIAL_MAP_ZOOM, 72 | onTap: (final TapPosition tapPosition, final LatLng latLng) { 73 | createNewMarkerCallback(latLng); 74 | }, 75 | ), 76 | TileLayer( 77 | urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', 78 | userAgentPackageName: 'com.flutter_map_floating_marker_titles.example', 79 | ), 80 | createNewMarkerCallback, 81 | ), 82 | ), 83 | ], 84 | ); 85 | } 86 | 87 | @protected 88 | Widget buildMapWidgetImpl( 89 | final BuildContext context, 90 | final MapOptions mapOptions, 91 | final Widget backgroundLayer, 92 | final Function(LatLng) createNewMarkerCallback, 93 | ); 94 | } 95 | -------------------------------------------------------------------------------- /example/lib/pages/flutter_map/flutter_map_with_layer.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_floating_map_marker_titles_demo/pages/flutter_map/abstract_flutter_map_demo_page.dart'; 3 | import 'package:flutter_map/flutter_map.dart'; 4 | import 'package:flutter_map_floating_marker_titles/flutter_map_floating_marker_titles.dart'; 5 | import 'package:latlong2/latlong.dart'; 6 | 7 | class FlutterMapLayerDemoPage extends AbstractFlutterMapDemoPage { 8 | static const String route = 'Flutter Map - Layer'; 9 | 10 | FlutterMapLayerDemoPage({final Key? key}) : super(key: key); 11 | @override 12 | _FlutterMapLayerLayerDemoPageState createState() => _FlutterMapLayerLayerDemoPageState(); 13 | } 14 | 15 | class _FlutterMapLayerLayerDemoPageState extends AbstractFlutterMapDemoPageState { 16 | @override 17 | String getTitleText() { 18 | return FlutterMapLayerDemoPage.route; 19 | } 20 | 21 | @override 22 | String getPageRouteString() { 23 | return FlutterMapLayerDemoPage.route; 24 | } 25 | 26 | @override 27 | Widget buildMapWidgetImpl( 28 | final BuildContext context, 29 | final MapOptions mapOptions, 30 | final Widget backgroundLayer, 31 | final Function(LatLng) createNewMarkerCallback, 32 | ) { 33 | return FlutterMap( 34 | mapController: mapController, 35 | options: mapOptions, 36 | children: [ 37 | backgroundLayer, 38 | MarkerLayer( 39 | markers: markers, 40 | ), 41 | FloatingMarkerTitlesLayer( 42 | floatingTitles: floatingTitles, 43 | fmtoOptions: createFMTOOptions(), 44 | ), 45 | ], 46 | ); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /example/lib/pages/flutter_map/flutter_map_wrapped_data.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_floating_map_marker_titles_demo/pages/flutter_map/abstract_flutter_map_demo_page.dart'; 3 | import 'package:flutter_map/flutter_map.dart'; 4 | import 'package:flutter_map_floating_marker_titles/flutter_map_floating_marker_titles.dart'; 5 | import 'package:latlong2/latlong.dart'; 6 | 7 | class FlutterMapDWrapperDemoPage extends AbstractFlutterMapDemoPage { 8 | static const String route = 'Flutter Map - Wrapper + Data'; 9 | 10 | FlutterMapDWrapperDemoPage({final Key? key}) : super(key: key); 11 | @override 12 | _FlutterMapDWrapperDemoPageState createState() => _FlutterMapDWrapperDemoPageState(); 13 | } 14 | 15 | class _FlutterMapDWrapperDemoPageState extends AbstractFlutterMapDemoPageState { 16 | @override 17 | String getTitleText() { 18 | return FlutterMapDWrapperDemoPage.route; 19 | } 20 | 21 | @override 22 | String getPageRouteString() { 23 | return FlutterMapDWrapperDemoPage.route; 24 | } 25 | 26 | @override 27 | Widget buildMapWidgetImpl( 28 | final BuildContext context, 29 | final MapOptions mapOptions, 30 | final Widget backgroundLayer, 31 | final Function(LatLng) createNewMarkerCallback, 32 | ) { 33 | return FlutterMapWithFMTO( 34 | floatingTitles: floatingTitles, 35 | fmtoOptions: createFMTOOptions(), 36 | mapController: mapController, 37 | options: mapOptions, 38 | children: [ 39 | backgroundLayer, 40 | MarkerLayer( 41 | markers: markers, 42 | ), 43 | ], 44 | ); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /example/lib/pages/flutter_map/flutter_map_wrapped_streams.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_floating_map_marker_titles_demo/pages/flutter_map/abstract_flutter_map_demo_page.dart'; 5 | import 'package:flutter_map/flutter_map.dart'; 6 | import 'package:flutter_map_floating_marker_titles/flutter_map_floating_marker_titles.dart'; 7 | import 'package:latlong2/latlong.dart'; 8 | import 'package:flutter_floating_map_marker_titles_core/model/floating_marker_title_info.dart'; 9 | 10 | class FlutterMapSWrapperDemoPage extends AbstractFlutterMapDemoPage { 11 | static const String route = 'Flutter Map - Wrapper + Stream'; 12 | 13 | FlutterMapSWrapperDemoPage({final Key? key}) : super(key: key); 14 | @override 15 | _FlutterMapSWrapperDemoPageState createState() => _FlutterMapSWrapperDemoPageState(); 16 | } 17 | 18 | class _FlutterMapSWrapperDemoPageState extends AbstractFlutterMapDemoPageState { 19 | final StreamController> _floatingTitlesSC = StreamController(); 20 | final StreamController> _markersSC = StreamController(); 21 | 22 | @override 23 | void addMarker(LatLng latLng) { 24 | addMarkerToData(latLng); 25 | _markersSC.add(markers); 26 | _floatingTitlesSC.add(floatingTitles); 27 | } 28 | 29 | @override 30 | String getTitleText() { 31 | return FlutterMapSWrapperDemoPage.route; 32 | } 33 | 34 | @override 35 | String getPageRouteString() { 36 | return FlutterMapSWrapperDemoPage.route; 37 | } 38 | 39 | @override 40 | Widget buildMapWidgetImpl( 41 | final BuildContext context, 42 | final MapOptions mapOptions, 43 | final Widget backgroundLayer, 44 | final Function(LatLng) createNewMarkerCallback, 45 | ) { 46 | return FlutterMapWithFMTO( 47 | floatingTitlesStream: _floatingTitlesSC.stream, 48 | floatingTitles: floatingTitles, 49 | fmtoOptions: createFMTOOptions(), 50 | mapController: mapController, 51 | options: mapOptions, 52 | children: [ 53 | backgroundLayer, 54 | StreamBuilder( 55 | stream: _markersSC.stream, 56 | builder: (context, snapshot) { 57 | return MarkerLayer( 58 | markers: markers, 59 | ); 60 | }, 61 | ), 62 | ], 63 | ); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /example/lib/pages/google_maps/google_maps.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter/services.dart'; 3 | import 'package:flutter_floating_map_marker_titles_demo/assets/demo_data.dart' as demo_data; 4 | import 'package:flutter_floating_map_marker_titles_demo/pages/abstract_demo_page.dart'; 5 | import 'package:google_maps_flutter/google_maps_flutter.dart'; 6 | import 'package:google_maps_flutter_floating_marker_titles/google_maps_flutter_floating_marker_titles.dart'; 7 | import 'package:latlong2/latlong.dart' as latlong; 8 | 9 | class GoogleMapsDemoPage extends AbstractDemoPage { 10 | static const String route = 'Google Maps'; 11 | 12 | GoogleMapsDemoPage({final Key? key}) : super(key: key); 13 | @override 14 | _GoogleMapsDemoPageState createState() => _GoogleMapsDemoPageState(); 15 | } 16 | 17 | int markerId = 0; 18 | 19 | class _GoogleMapsDemoPageState extends AbstractDemoPageState { 20 | BitmapDescriptor? _markerIcon; 21 | 22 | BitmapDescriptor createBitmapDescriptorFromBytes(Uint8List bytes) { 23 | // Note that the correct non-deprecated code should be: 24 | // return BitmapDescriptor.bytes( 25 | // bytes, 26 | // bitmapScaling: MapBitmapScaling.none, 27 | // ); 28 | // However at the current time, bitmapScaling is not working on iOS: 29 | // https://github.com/flutter/flutter/issues/165212 30 | // Using the deprecated method instead which works for both Android and iOS. 31 | // ignore: deprecated_member_use 32 | return BitmapDescriptor.fromBytes(bytes); 33 | } 34 | 35 | Future _createMarkerImageFromAsset(final BuildContext context) async { 36 | if (_markerIcon == null) { 37 | final bytes = Uint8List.sublistView(await rootBundle.load(demo_data.MARKER_ICON_ASSET_PATH)); 38 | final BitmapDescriptor bitmapDescriptor = createBitmapDescriptorFromBytes(bytes); 39 | _updateBitmap(bitmapDescriptor); 40 | } 41 | } 42 | 43 | void _updateBitmap(final BitmapDescriptor bitmap) { 44 | setState(() { 45 | _markerIcon = bitmap; 46 | }); 47 | } 48 | 49 | @override 50 | Widget buildMapWidget(final BuildContext context, final Function(latlong.LatLng) createNewMarkerCallback) { 51 | _createMarkerImageFromAsset(context); 52 | return Column( 53 | children: [ 54 | Flexible( 55 | child: GoogleMapWithFMTO( 56 | floatingTitles: floatingTitles, 57 | fmtoOptions: createFMTOOptions(), 58 | initialCameraPosition: CameraPosition( 59 | target: LatLng( 60 | demo_data.INITIAL_MAP_LOCATION.latitude, 61 | demo_data.INITIAL_MAP_LOCATION.longitude, 62 | ), 63 | zoom: demo_data.INITIAL_MAP_ZOOM, 64 | ), 65 | onTap: (final LatLng latLng) { 66 | createNewMarkerCallback(latlong.LatLng(latLng.latitude, latLng.longitude)); 67 | }, 68 | markers: _buildMarkersSet(), 69 | ), 70 | ), 71 | ], 72 | ); 73 | } 74 | 75 | Set _buildMarkersSet() { 76 | final Set res = {}; 77 | res.addAll(markers); 78 | return res; 79 | } 80 | 81 | @override 82 | Marker createMarker(final latlong.LatLng latLng) { 83 | return Marker( 84 | markerId: MarkerId('${markerId++}'), 85 | position: LatLng(latLng.latitude, latLng.longitude), 86 | icon: _markerIcon!, 87 | ); 88 | } 89 | 90 | @override 91 | String getTitleText() { 92 | return GoogleMapsDemoPage.route; 93 | } 94 | 95 | @override 96 | String getHelpMessageText() { 97 | return demo_data.GOOGLE_MAPS_HELP_DIALOG_MESSAGE; 98 | } 99 | 100 | @override 101 | String getPageRouteString() { 102 | return GoogleMapsDemoPage.route; 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /example/pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | async: 5 | dependency: transitive 6 | description: 7 | name: async 8 | sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" 9 | url: "https://pub.dev" 10 | source: hosted 11 | version: "2.11.0" 12 | boolean_selector: 13 | dependency: transitive 14 | description: 15 | name: boolean_selector 16 | sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" 17 | url: "https://pub.dev" 18 | source: hosted 19 | version: "2.1.1" 20 | characters: 21 | dependency: transitive 22 | description: 23 | name: characters 24 | sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" 25 | url: "https://pub.dev" 26 | source: hosted 27 | version: "1.3.0" 28 | clock: 29 | dependency: transitive 30 | description: 31 | name: clock 32 | sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf 33 | url: "https://pub.dev" 34 | source: hosted 35 | version: "1.1.1" 36 | collection: 37 | dependency: transitive 38 | description: 39 | name: collection 40 | sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf 41 | url: "https://pub.dev" 42 | source: hosted 43 | version: "1.19.0" 44 | csslib: 45 | dependency: transitive 46 | description: 47 | name: csslib 48 | sha256: "09bad715f418841f976c77db72d5398dc1253c21fb9c0c7f0b0b985860b2d58e" 49 | url: "https://pub.dev" 50 | source: hosted 51 | version: "1.0.2" 52 | dart_earcut: 53 | dependency: transitive 54 | description: 55 | name: dart_earcut 56 | sha256: e485001bfc05dcbc437d7bfb666316182e3522d4c3f9668048e004d0eb2ce43b 57 | url: "https://pub.dev" 58 | source: hosted 59 | version: "1.2.0" 60 | fake_async: 61 | dependency: transitive 62 | description: 63 | name: fake_async 64 | sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" 65 | url: "https://pub.dev" 66 | source: hosted 67 | version: "1.3.1" 68 | flutter: 69 | dependency: "direct main" 70 | description: flutter 71 | source: sdk 72 | version: "0.0.0" 73 | flutter_floating_map_marker_titles_core: 74 | dependency: "direct overridden" 75 | description: 76 | path: "../flutter_floating_map_marker_titles_core" 77 | relative: true 78 | source: path 79 | version: "1.1.1" 80 | flutter_map: 81 | dependency: "direct main" 82 | description: 83 | name: flutter_map 84 | sha256: bbf145e8220531f2f727608c431871c7457f3b134e513543913afd00fdc1cd47 85 | url: "https://pub.dev" 86 | source: hosted 87 | version: "8.1.0" 88 | flutter_map_floating_marker_titles: 89 | dependency: "direct overridden" 90 | description: 91 | path: "../flutter_map_floating_marker_titles" 92 | relative: true 93 | source: path 94 | version: "1.3.0" 95 | flutter_plugin_android_lifecycle: 96 | dependency: transitive 97 | description: 98 | name: flutter_plugin_android_lifecycle 99 | sha256: "5a1e6fb2c0561958d7e4c33574674bda7b77caaca7a33b758876956f2902eea3" 100 | url: "https://pub.dev" 101 | source: hosted 102 | version: "2.0.27" 103 | flutter_test: 104 | dependency: "direct dev" 105 | description: flutter 106 | source: sdk 107 | version: "0.0.0" 108 | flutter_web_plugins: 109 | dependency: transitive 110 | description: flutter 111 | source: sdk 112 | version: "0.0.0" 113 | google_maps: 114 | dependency: transitive 115 | description: 116 | name: google_maps 117 | sha256: "4d6e199c561ca06792c964fa24b2bac7197bf4b401c2e1d23e345e5f9939f531" 118 | url: "https://pub.dev" 119 | source: hosted 120 | version: "8.1.1" 121 | google_maps_flutter: 122 | dependency: "direct main" 123 | description: 124 | name: google_maps_flutter 125 | sha256: "621125e35e81ca39ef600e45243d2be93167e61def72bc7207b0c4a635c58506" 126 | url: "https://pub.dev" 127 | source: hosted 128 | version: "2.10.1" 129 | google_maps_flutter_android: 130 | dependency: transitive 131 | description: 132 | name: google_maps_flutter_android 133 | sha256: "721ffae2240e957c04b0de19ffd4b68580adb57a8224496b7fb55fad23aec98a" 134 | url: "https://pub.dev" 135 | source: hosted 136 | version: "2.14.13" 137 | google_maps_flutter_floating_marker_titles: 138 | dependency: "direct overridden" 139 | description: 140 | path: "../google_maps_flutter_floating_marker_titles" 141 | relative: true 142 | source: path 143 | version: "1.1.0" 144 | google_maps_flutter_ios: 145 | dependency: transitive 146 | description: 147 | name: google_maps_flutter_ios 148 | sha256: "6f798adb0aa1db5adf551f2e39e24bd06c8c0fbe4de912fb2d9b5b3f48147b02" 149 | url: "https://pub.dev" 150 | source: hosted 151 | version: "2.13.2" 152 | google_maps_flutter_platform_interface: 153 | dependency: transitive 154 | description: 155 | name: google_maps_flutter_platform_interface 156 | sha256: "970c8f766c02909c7be282dea923c971f83a88adaf07f8871d0aacebc3b07bb2" 157 | url: "https://pub.dev" 158 | source: hosted 159 | version: "2.11.1" 160 | google_maps_flutter_web: 161 | dependency: transitive 162 | description: 163 | name: google_maps_flutter_web 164 | sha256: a9fd5356d46f54744ced1ebedbbf212f3d2cb71e95d79b1d08690c1ec33dc584 165 | url: "https://pub.dev" 166 | source: hosted 167 | version: "0.5.10+1" 168 | html: 169 | dependency: transitive 170 | description: 171 | name: html 172 | sha256: "1fc58edeaec4307368c60d59b7e15b9d658b57d7f3125098b6294153c75337ec" 173 | url: "https://pub.dev" 174 | source: hosted 175 | version: "0.15.5" 176 | http: 177 | dependency: transitive 178 | description: 179 | name: http 180 | sha256: fe7ab022b76f3034adc518fb6ea04a82387620e19977665ea18d30a1cf43442f 181 | url: "https://pub.dev" 182 | source: hosted 183 | version: "1.3.0" 184 | http_parser: 185 | dependency: transitive 186 | description: 187 | name: http_parser 188 | sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" 189 | url: "https://pub.dev" 190 | source: hosted 191 | version: "4.1.2" 192 | intl: 193 | dependency: transitive 194 | description: 195 | name: intl 196 | sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5" 197 | url: "https://pub.dev" 198 | source: hosted 199 | version: "0.20.2" 200 | latlong2: 201 | dependency: transitive 202 | description: 203 | name: latlong2 204 | sha256: "98227922caf49e6056f91b6c56945ea1c7b166f28ffcd5fb8e72fc0b453cc8fe" 205 | url: "https://pub.dev" 206 | source: hosted 207 | version: "0.9.1" 208 | leak_tracker: 209 | dependency: transitive 210 | description: 211 | name: leak_tracker 212 | sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06" 213 | url: "https://pub.dev" 214 | source: hosted 215 | version: "10.0.7" 216 | leak_tracker_flutter_testing: 217 | dependency: transitive 218 | description: 219 | name: leak_tracker_flutter_testing 220 | sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379" 221 | url: "https://pub.dev" 222 | source: hosted 223 | version: "3.0.8" 224 | leak_tracker_testing: 225 | dependency: transitive 226 | description: 227 | name: leak_tracker_testing 228 | sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" 229 | url: "https://pub.dev" 230 | source: hosted 231 | version: "3.0.1" 232 | lint: 233 | dependency: "direct dev" 234 | description: 235 | name: lint 236 | sha256: f4bd4dbaa39f4ae8836f2d1275f2f32bc68b3a8cce0a0735dd1f7a601f06682a 237 | url: "https://pub.dev" 238 | source: hosted 239 | version: "2.1.2" 240 | lists: 241 | dependency: transitive 242 | description: 243 | name: lists 244 | sha256: "4ca5c19ae4350de036a7e996cdd1ee39c93ac0a2b840f4915459b7d0a7d4ab27" 245 | url: "https://pub.dev" 246 | source: hosted 247 | version: "1.0.1" 248 | logger: 249 | dependency: transitive 250 | description: 251 | name: logger 252 | sha256: be4b23575aac7ebf01f225a241eb7f6b5641eeaf43c6a8613510fc2f8cf187d1 253 | url: "https://pub.dev" 254 | source: hosted 255 | version: "2.5.0" 256 | matcher: 257 | dependency: transitive 258 | description: 259 | name: matcher 260 | sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb 261 | url: "https://pub.dev" 262 | source: hosted 263 | version: "0.12.16+1" 264 | material_color_utilities: 265 | dependency: transitive 266 | description: 267 | name: material_color_utilities 268 | sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec 269 | url: "https://pub.dev" 270 | source: hosted 271 | version: "0.11.1" 272 | meta: 273 | dependency: transitive 274 | description: 275 | name: meta 276 | sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 277 | url: "https://pub.dev" 278 | source: hosted 279 | version: "1.15.0" 280 | mgrs_dart: 281 | dependency: transitive 282 | description: 283 | name: mgrs_dart 284 | sha256: fb89ae62f05fa0bb90f70c31fc870bcbcfd516c843fb554452ab3396f78586f7 285 | url: "https://pub.dev" 286 | source: hosted 287 | version: "2.0.0" 288 | path: 289 | dependency: transitive 290 | description: 291 | name: path 292 | sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" 293 | url: "https://pub.dev" 294 | source: hosted 295 | version: "1.9.0" 296 | plugin_platform_interface: 297 | dependency: transitive 298 | description: 299 | name: plugin_platform_interface 300 | sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" 301 | url: "https://pub.dev" 302 | source: hosted 303 | version: "2.1.8" 304 | polylabel: 305 | dependency: transitive 306 | description: 307 | name: polylabel 308 | sha256: "41b9099afb2aa6c1730bdd8a0fab1400d287694ec7615dd8516935fa3144214b" 309 | url: "https://pub.dev" 310 | source: hosted 311 | version: "1.0.1" 312 | proj4dart: 313 | dependency: transitive 314 | description: 315 | name: proj4dart 316 | sha256: c8a659ac9b6864aa47c171e78d41bbe6f5e1d7bd790a5814249e6b68bc44324e 317 | url: "https://pub.dev" 318 | source: hosted 319 | version: "2.1.0" 320 | sanitize_html: 321 | dependency: transitive 322 | description: 323 | name: sanitize_html 324 | sha256: "12669c4a913688a26555323fb9cec373d8f9fbe091f2d01c40c723b33caa8989" 325 | url: "https://pub.dev" 326 | source: hosted 327 | version: "2.1.0" 328 | sky_engine: 329 | dependency: transitive 330 | description: flutter 331 | source: sdk 332 | version: "0.0.0" 333 | source_span: 334 | dependency: transitive 335 | description: 336 | name: source_span 337 | sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" 338 | url: "https://pub.dev" 339 | source: hosted 340 | version: "1.10.0" 341 | stack_trace: 342 | dependency: transitive 343 | description: 344 | name: stack_trace 345 | sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377" 346 | url: "https://pub.dev" 347 | source: hosted 348 | version: "1.12.0" 349 | stream_channel: 350 | dependency: transitive 351 | description: 352 | name: stream_channel 353 | sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 354 | url: "https://pub.dev" 355 | source: hosted 356 | version: "2.1.2" 357 | stream_transform: 358 | dependency: transitive 359 | description: 360 | name: stream_transform 361 | sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871 362 | url: "https://pub.dev" 363 | source: hosted 364 | version: "2.1.1" 365 | string_scanner: 366 | dependency: transitive 367 | description: 368 | name: string_scanner 369 | sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3" 370 | url: "https://pub.dev" 371 | source: hosted 372 | version: "1.3.0" 373 | term_glyph: 374 | dependency: transitive 375 | description: 376 | name: term_glyph 377 | sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 378 | url: "https://pub.dev" 379 | source: hosted 380 | version: "1.2.1" 381 | test_api: 382 | dependency: transitive 383 | description: 384 | name: test_api 385 | sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c" 386 | url: "https://pub.dev" 387 | source: hosted 388 | version: "0.7.3" 389 | tuple: 390 | dependency: transitive 391 | description: 392 | name: tuple 393 | sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151 394 | url: "https://pub.dev" 395 | source: hosted 396 | version: "2.0.2" 397 | typed_data: 398 | dependency: transitive 399 | description: 400 | name: typed_data 401 | sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 402 | url: "https://pub.dev" 403 | source: hosted 404 | version: "1.4.0" 405 | unicode: 406 | dependency: transitive 407 | description: 408 | name: unicode 409 | sha256: "0f69e46593d65245774d4f17125c6084d2c20b4e473a983f6e21b7d7762218f1" 410 | url: "https://pub.dev" 411 | source: hosted 412 | version: "0.3.1" 413 | vector_math: 414 | dependency: transitive 415 | description: 416 | name: vector_math 417 | sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" 418 | url: "https://pub.dev" 419 | source: hosted 420 | version: "2.1.4" 421 | vm_service: 422 | dependency: transitive 423 | description: 424 | name: vm_service 425 | sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b 426 | url: "https://pub.dev" 427 | source: hosted 428 | version: "14.3.0" 429 | web: 430 | dependency: transitive 431 | description: 432 | name: web 433 | sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" 434 | url: "https://pub.dev" 435 | source: hosted 436 | version: "1.1.1" 437 | wkt_parser: 438 | dependency: transitive 439 | description: 440 | name: wkt_parser 441 | sha256: "8a555fc60de3116c00aad67891bcab20f81a958e4219cc106e3c037aa3937f13" 442 | url: "https://pub.dev" 443 | source: hosted 444 | version: "2.0.0" 445 | sdks: 446 | dart: ">=3.6.0 <4.0.0" 447 | flutter: ">=3.27.0" 448 | -------------------------------------------------------------------------------- /example/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: flutter_floating_map_marker_titles_demo 2 | description: A new Flutter project. 3 | 4 | # The following line prevents the package from being accidentally published to 5 | # pub.dev using `flutter pub publish`. This is preferred for private packages. 6 | publish_to: 'none' # Remove this line if you wish to publish to pub.dev 7 | 8 | version: 1.0.0+1 9 | 10 | environment: 11 | sdk: '>=2.17.1 <4.0.0' 12 | 13 | dependencies: 14 | flutter: 15 | sdk: flutter 16 | google_maps_flutter: ^2.2.0 17 | flutter_map: ^8.1.0 18 | 19 | # Dependency overrides for the demo app, you would normally use this in dependencies: 20 | # flutter_floating_map_marker_titles_core: ^X.Y.Z+1 21 | # flutter_map_floating_marker_titles: ^X.Y.Z+1 22 | # google_maps_flutter_floating_marker_titles: ^X.Y.Z+1 23 | dependency_overrides: 24 | flutter_floating_map_marker_titles_core: 25 | path: ../flutter_floating_map_marker_titles_core 26 | flutter_map_floating_marker_titles: 27 | path: ../flutter_map_floating_marker_titles 28 | google_maps_flutter_floating_marker_titles: 29 | path: ../google_maps_flutter_floating_marker_titles 30 | 31 | dev_dependencies: 32 | flutter_test: 33 | sdk: flutter 34 | lint: 2.1.2 35 | 36 | flutter: 37 | uses-material-design: true 38 | assets: 39 | - lib/assets/images/marker.png 40 | -------------------------------------------------------------------------------- /example/test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // 3 | // To perform an interaction with a widget in your test, use the WidgetTester 4 | // utility in the flutter_test package. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter_test/flutter_test.dart'; 10 | 11 | import 'package:flutter_floating_map_marker_titles_demo/main.dart'; 12 | 13 | void main() { 14 | testWidgets('Counter increments smoke test', (WidgetTester tester) async { 15 | // Build our app and trigger a frame. 16 | await tester.pumpWidget(DemoApp()); 17 | 18 | // Verify that our counter starts at 0. 19 | expect(find.text('0'), findsOneWidget); 20 | expect(find.text('1'), findsNothing); 21 | 22 | // Tap the '+' icon and trigger a frame. 23 | await tester.tap(find.byIcon(Icons.add)); 24 | await tester.pump(); 25 | 26 | // Verify that our counter has incremented. 27 | expect(find.text('0'), findsNothing); 28 | expect(find.text('1'), findsOneWidget); 29 | }); 30 | } 31 | -------------------------------------------------------------------------------- /example/web/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androidseb/flutter_map_floating_marker_titles/9834a35c0f0292e1c24dc91acb340e80f71bc388/example/web/favicon.png -------------------------------------------------------------------------------- /example/web/icons/Icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androidseb/flutter_map_floating_marker_titles/9834a35c0f0292e1c24dc91acb340e80f71bc388/example/web/icons/Icon-192.png -------------------------------------------------------------------------------- /example/web/icons/Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androidseb/flutter_map_floating_marker_titles/9834a35c0f0292e1c24dc91acb340e80f71bc388/example/web/icons/Icon-512.png -------------------------------------------------------------------------------- /example/web/icons/Icon-maskable-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androidseb/flutter_map_floating_marker_titles/9834a35c0f0292e1c24dc91acb340e80f71bc388/example/web/icons/Icon-maskable-192.png -------------------------------------------------------------------------------- /example/web/icons/Icon-maskable-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androidseb/flutter_map_floating_marker_titles/9834a35c0f0292e1c24dc91acb340e80f71bc388/example/web/icons/Icon-maskable-512.png -------------------------------------------------------------------------------- /example/web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | flutter_floating_map_marker_titles_demo 33 | 34 | 35 | 39 | 40 | 41 | 42 | 43 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /example/web/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "flutter_floating_map_marker_titles_demo", 3 | "short_name": "flutter_floating_map_marker_titles_demo", 4 | "start_url": ".", 5 | "display": "standalone", 6 | "background_color": "#0175C2", 7 | "theme_color": "#0175C2", 8 | "description": "A new Flutter project.", 9 | "orientation": "portrait-primary", 10 | "prefer_related_applications": false, 11 | "icons": [ 12 | { 13 | "src": "icons/Icon-192.png", 14 | "sizes": "192x192", 15 | "type": "image/png" 16 | }, 17 | { 18 | "src": "icons/Icon-512.png", 19 | "sizes": "512x512", 20 | "type": "image/png" 21 | }, 22 | { 23 | "src": "icons/Icon-maskable-192.png", 24 | "sizes": "192x192", 25 | "type": "image/png", 26 | "purpose": "maskable" 27 | }, 28 | { 29 | "src": "icons/Icon-maskable-512.png", 30 | "sizes": "512x512", 31 | "type": "image/png", 32 | "purpose": "maskable" 33 | } 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /flutter_floating_map_marker_titles_core/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | **/ios/Flutter/.last_build_id 26 | .dart_tool/ 27 | .flutter-plugins 28 | .flutter-plugins-dependencies 29 | .packages 30 | .pub-cache/ 31 | .pub/ 32 | /build/ 33 | 34 | # Web related 35 | lib/generated_plugin_registrant.dart 36 | 37 | # Symbolication related 38 | app.*.symbols 39 | 40 | # Obfuscation related 41 | app.*.map.json 42 | 43 | # Android Studio will place build artifacts here 44 | /android/app/debug 45 | /android/app/profile 46 | /android/app/release 47 | -------------------------------------------------------------------------------- /flutter_floating_map_marker_titles_core/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [1.1.1] - 2025/03/04 2 | 3 | * Fixed some warnings related to color class getters 4 | 5 | ## [1.1.0] - 2024/08/10 6 | 7 | * Fixed a bug with floating marker titles still appearing with maxTitlesCount=0 in some specific cases (e.g. using more than one z-index) 8 | 9 | ## [1.0.0] - 2023/06/22 10 | 11 | * Updated the semantic version prefix to "officially stable" 1.X.X, because this library has been successful in a production app (see https://mapmarker.app) used by thousands of daily users for several months 12 | * Updated latlong2 dependency to latlong2: ^0.9.0 13 | 14 | ## [0.3.0] - 2022/10/23 15 | 16 | * Improved the logic handling the appearance for higher z-index titles 17 | 18 | ## [0.2.0] - 2022/09/15 19 | 20 | * Added the ability to set floating marker titles with a stream with the `floatingTitlesStream` parameter 21 | 22 | ## [0.1.0] - 2022/09/02 23 | 24 | * Changed the versioning pattern to leave the last digit for minor non-feature-related changes (e.g. library upgrades) 25 | 26 | ## [0.0.6] - 2022/06/11 27 | 28 | Added linter rules from the [lint](https://pub.dev/packages/lint) package. 29 | 30 | ## [0.0.5+5] - 2022/01/09 31 | 32 | Removed web-specific code working around [a bug](https://github.com/flutter/flutter/issues/46683) that has since then been fixed. 33 | 34 | ## [0.0.4+4] - 2021/11/29 35 | 36 | Migrated to null safety. 37 | 38 | ## [0.0.3+3] - 2021/06/01 39 | 40 | Updated dependencies to support dependent libraries. 41 | 42 | ## [0.0.2+2] - 2021/04/01 43 | 44 | Fixed some issues with floating titles data not being updated in some cases, due to a wrong widget state setup. 45 | 46 | ## [0.0.1+1] - 2021/01/30 47 | 48 | This is the initial release of the library. 49 | 50 | * Floating Map Marker Titles 51 | * Titles overlap detection 52 | * Titles automatic outline based on color 53 | * Titles fade-in animation 54 | * Overlay customization options 55 | * Paint time interval 56 | * Text size 57 | * Text width 58 | * Text max lines 59 | * Text painting cache size 60 | * Coordinates cache size 61 | * Number of titles to check per frame 62 | * Fade-in animation time 63 | * Title placement policy 64 | * Title customization options 65 | * Color 66 | * Bold 67 | * Z-index 68 | -------------------------------------------------------------------------------- /flutter_floating_map_marker_titles_core/LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2021, androidseb 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /flutter_floating_map_marker_titles_core/README.md: -------------------------------------------------------------------------------- 1 | # Flutter Floating Map Marker Titles Core 2 | 3 | This is the core library for the [Flutter Floating Map Marker Titles](https://github.com/androidseb/flutter_map_floating_marker_titles) project. 4 | 5 | This core library is meant to be agnostic of any specific map view implementation details, so that it can be re-used with various map providers. 6 | -------------------------------------------------------------------------------- /flutter_floating_map_marker_titles_core/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:lint/analysis_options.yaml 2 | 3 | analyzer: 4 | exclude: 5 | - 'lib/utils/geo/bounds.dart' 6 | - 'lib/utils/geo/crs.dart' 7 | - 'lib/utils/geo/point.dart' 8 | # can be found at https://dart-lang.github.io/linter/lints/options/options.html 9 | linter: 10 | rules: 11 | avoid_positional_boolean_parameters: false 12 | avoid_classes_with_only_static_members: false 13 | use_setters_to_change_properties: false 14 | avoid_final_parameters: false 15 | -------------------------------------------------------------------------------- /flutter_floating_map_marker_titles_core/lib/controller/cache/epsg_3857_proj_cache.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math' as math; 2 | import 'package:flutter_floating_map_marker_titles_core/utils/cached_calculator.dart'; 3 | import 'package:flutter_floating_map_marker_titles_core/utils/geo/crs.dart'; 4 | import 'package:latlong2/latlong.dart'; 5 | 6 | class _Epsg3857ProjCacheKey { 7 | final LatLng latLng; 8 | final double zoom; 9 | 10 | _Epsg3857ProjCacheKey( 11 | this.latLng, 12 | this.zoom, 13 | ); 14 | 15 | @override 16 | int get hashCode { 17 | return latLng.hashCode + zoom.hashCode; 18 | } 19 | 20 | @override 21 | bool operator ==(Object other) { 22 | if (other is! _Epsg3857ProjCacheKey) { 23 | return false; 24 | } 25 | final _Epsg3857ProjCacheKey o = other; 26 | return latLng == o.latLng && zoom == o.zoom; 27 | } 28 | } 29 | 30 | class _Epsg3857ProjCacheImpl extends CachedCalculator<_Epsg3857ProjCacheKey, math.Point> { 31 | static const Epsg3857 mapProjection = Epsg3857(); 32 | 33 | _Epsg3857ProjCacheImpl(super.cacheMaxSize); 34 | 35 | @override 36 | math.Point calculateValue(final _Epsg3857ProjCacheKey key) { 37 | return mapProjection.latLngToPoint(key.latLng, key.zoom); 38 | } 39 | } 40 | 41 | class Epsg3857ProjCache { 42 | late _Epsg3857ProjCacheImpl _projectionsCache; 43 | 44 | Epsg3857ProjCache(final int cacheMaxSize) { 45 | _projectionsCache = _Epsg3857ProjCacheImpl(cacheMaxSize); 46 | } 47 | 48 | void updateFrom(final Epsg3857ProjCache projCache) { 49 | _projectionsCache = projCache._projectionsCache; 50 | } 51 | 52 | math.Point getProjectedLatLng(final LatLng latLng, final double zoom) { 53 | return _projectionsCache.getValue(_Epsg3857ProjCacheKey(latLng, zoom)); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /flutter_floating_map_marker_titles_core/lib/controller/cache/text_painting_cache.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_floating_map_marker_titles_core/controller/display/floating_title_painter.dart'; 3 | import 'package:flutter_floating_map_marker_titles_core/controller/fmto_controller.dart'; 4 | import 'package:flutter_floating_map_marker_titles_core/utils/cached_calculator.dart'; 5 | 6 | class _TextPaintingCacheKey { 7 | final String textString; 8 | final Color textColor; 9 | final bool isBoldText; 10 | final FMTOOptions options; 11 | 12 | _TextPaintingCacheKey( 13 | this.textString, 14 | this.textColor, 15 | this.isBoldText, 16 | this.options, 17 | ); 18 | 19 | @override 20 | int get hashCode { 21 | return textString.hashCode + 22 | textColor.hashCode + 23 | isBoldText.hashCode + 24 | options.maxTitleLines.hashCode + 25 | options.maxTitlesWidth.hashCode + 26 | options.textSize.hashCode; 27 | } 28 | 29 | @override 30 | bool operator ==(Object other) { 31 | if (other is! _TextPaintingCacheKey) { 32 | return false; 33 | } 34 | final _TextPaintingCacheKey o = other; 35 | return textString == o.textString && 36 | textColor == o.textColor && 37 | isBoldText == o.isBoldText && 38 | options.maxTitleLines == o.options.maxTitleLines && 39 | options.maxTitlesWidth == o.options.maxTitlesWidth && 40 | options.textSize == o.options.textSize; 41 | } 42 | } 43 | 44 | class _TextPaintingCacheImpl extends CachedCalculator<_TextPaintingCacheKey, FloatingTitlePainter> { 45 | _TextPaintingCacheImpl(super.cacheMaxSize); 46 | 47 | @override 48 | FloatingTitlePainter calculateValue(final _TextPaintingCacheKey key) { 49 | return FloatingTitlePainter( 50 | key.textString, 51 | key.textColor, 52 | key.isBoldText, 53 | key.options, 54 | ); 55 | } 56 | } 57 | 58 | class TextPaintingCache { 59 | late _TextPaintingCacheImpl _paintersCache; 60 | 61 | TextPaintingCache(final int cacheMaxSize) { 62 | _paintersCache = _TextPaintingCacheImpl(cacheMaxSize); 63 | } 64 | 65 | void updateFrom(final TextPaintingCache textPaintingCache) { 66 | _paintersCache = textPaintingCache._paintersCache; 67 | } 68 | 69 | FloatingTitlePainter getTitlePainter( 70 | final String textString, 71 | final Color textColor, 72 | final bool isBoldText, 73 | final FMTOOptions options, 74 | ) { 75 | return _paintersCache.getValue( 76 | _TextPaintingCacheKey( 77 | textString, 78 | textColor, 79 | isBoldText, 80 | options, 81 | ), 82 | ); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /flutter_floating_map_marker_titles_core/lib/controller/display/floating_title_painter.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_floating_map_marker_titles_core/controller/display/layer/title_layer_background_painter.dart'; 3 | import 'package:flutter_floating_map_marker_titles_core/controller/display/layer/title_layer_foreground_painter.dart'; 4 | import 'package:flutter_floating_map_marker_titles_core/controller/display/layer/title_layer_painter.dart'; 5 | import 'package:flutter_floating_map_marker_titles_core/controller/fmto_controller.dart'; 6 | 7 | class FloatingTitlePainter { 8 | final TitleLayerPainter? _bgLayerPainter; 9 | final TitleLayerPainter _fgLayerPainter; 10 | 11 | factory FloatingTitlePainter( 12 | final String textString, 13 | final Color textColor, 14 | final bool isBoldText, 15 | final FMTOOptions fmtoOptions, 16 | ) { 17 | return FloatingTitlePainter._internal( 18 | _createBGPainter(textString, textColor, isBoldText, fmtoOptions), 19 | _createFGPainter(textString, textColor, isBoldText, fmtoOptions), 20 | ); 21 | } 22 | 23 | FloatingTitlePainter._internal( 24 | this._bgLayerPainter, 25 | this._fgLayerPainter, 26 | ); 27 | 28 | static TitleLayerPainter? _createBGPainter( 29 | final String textString, 30 | final Color textColor, 31 | final bool isBoldText, 32 | final FMTOOptions fmtoOptions, 33 | ) { 34 | return TitleLayerBackgroundPainter( 35 | textString, 36 | textColor, 37 | isBoldText, 38 | fmtoOptions, 39 | ); 40 | } 41 | 42 | static TitleLayerPainter _createFGPainter( 43 | final String textString, 44 | final Color textColor, 45 | final bool isBoldText, 46 | final FMTOOptions fmtoOptions, 47 | ) { 48 | return TitleLayerForegroundPainter( 49 | textString, 50 | textColor, 51 | isBoldText, 52 | fmtoOptions, 53 | ); 54 | } 55 | 56 | void paintTitle(final Canvas canvas, final Offset offset) { 57 | _bgLayerPainter?.paintLayer(canvas, offset); 58 | _fgLayerPainter.paintLayer(canvas, offset); 59 | } 60 | 61 | double get width { 62 | return _fgLayerPainter.width; 63 | } 64 | 65 | double get height { 66 | return _fgLayerPainter.height; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /flutter_floating_map_marker_titles_core/lib/controller/display/layer/title_layer_background_painter.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_floating_map_marker_titles_core/controller/display/layer/title_layer_painter.dart'; 3 | import 'package:flutter_floating_map_marker_titles_core/controller/fmto_controller.dart'; 4 | 5 | class TitleLayerBackgroundPainter extends TitleLayerPainter { 6 | TitleLayerBackgroundPainter( 7 | super.textString, 8 | super.textColor, 9 | super.isBoldText, 10 | super.fmtoOptions, 11 | ); 12 | 13 | @override 14 | TextSpan buildText( 15 | final String textString, 16 | final Color textColor, 17 | final bool isBoldText, 18 | final FMTOOptions fmtoOptions, 19 | ) { 20 | return TextSpan( 21 | style: TextStyle( 22 | fontSize: fmtoOptions.textSize, 23 | fontWeight: isBoldText ? FontWeight.bold : FontWeight.normal, 24 | foreground: Paint() 25 | ..style = PaintingStyle.stroke 26 | ..strokeWidth = 3 27 | ..color = TitleLayerPainter.computeBgColorForTextColor(textColor), 28 | ), 29 | text: textString, 30 | ); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /flutter_floating_map_marker_titles_core/lib/controller/display/layer/title_layer_foreground_painter.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_floating_map_marker_titles_core/controller/display/layer/title_layer_painter.dart'; 3 | import 'package:flutter_floating_map_marker_titles_core/controller/fmto_controller.dart'; 4 | 5 | class TitleLayerForegroundPainter extends TitleLayerPainter { 6 | TitleLayerForegroundPainter( 7 | super.textString, 8 | super.textColor, 9 | super.isBoldText, 10 | super.fmtoOptions, 11 | ); 12 | 13 | @override 14 | TextSpan buildText( 15 | final String textString, 16 | final Color textColor, 17 | final bool isBoldText, 18 | final FMTOOptions fmtoOptions, 19 | ) { 20 | return TextSpan( 21 | style: TextStyle( 22 | fontSize: fmtoOptions.textSize, 23 | color: textColor, 24 | fontWeight: isBoldText ? FontWeight.bold : FontWeight.normal, 25 | ), 26 | text: textString, 27 | ); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /flutter_floating_map_marker_titles_core/lib/controller/display/layer/title_layer_painter.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_floating_map_marker_titles_core/controller/fmto_controller.dart'; 3 | import 'package:flutter_floating_map_marker_titles_core/utils/utils.dart'; 4 | 5 | abstract class TitleLayerPainter { 6 | static Color computeBgColorForTextColor(final Color textColor) { 7 | if (Utils.isDarkColor(textColor)) { 8 | return Colors.white; 9 | } else { 10 | return Colors.black; 11 | } 12 | } 13 | 14 | final String _textString; 15 | final Color _textColor; 16 | final bool _isBoldText; 17 | final FMTOOptions _fmtoOptions; 18 | 19 | late TextPainter _textPainter; 20 | 21 | TitleLayerPainter( 22 | this._textString, 23 | this._textColor, 24 | this._isBoldText, 25 | this._fmtoOptions, 26 | ) { 27 | _textPainter = _buildTextPainter(); 28 | } 29 | 30 | TextSpan buildText( 31 | final String textString, 32 | final Color textColor, 33 | final bool isBoldText, 34 | final FMTOOptions fmtoOptions, 35 | ); 36 | 37 | TextPainter _buildTextPainter() { 38 | final TextPainter textPainter = TextPainter( 39 | text: buildText( 40 | _textString, 41 | _textColor, 42 | _isBoldText, 43 | _fmtoOptions, 44 | ), 45 | textAlign: TextAlign.left, 46 | textDirection: TextDirection.ltr, 47 | maxLines: _fmtoOptions.maxTitleLines, 48 | ellipsis: '...', 49 | ); 50 | textPainter.layout(maxWidth: _fmtoOptions.maxTitlesWidth); 51 | return textPainter; 52 | } 53 | 54 | double get width => _textPainter.width; 55 | 56 | double get height => _textPainter.height; 57 | 58 | void paintLayer( 59 | final Canvas canvas, 60 | final Offset offset, 61 | ) { 62 | _textPainter.paint(canvas, offset); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /flutter_floating_map_marker_titles_core/lib/controller/display/titles_display_state.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | import 'package:flutter_floating_map_marker_titles_core/controller/display/floating_title_painter.dart'; 3 | import 'package:flutter_floating_map_marker_titles_core/model/floating_marker_title_info.dart'; 4 | import 'package:flutter_floating_map_marker_titles_core/utils/geo/bounds.dart'; 5 | import 'package:flutter_floating_map_marker_titles_core/utils/geo/point.dart'; 6 | import 'package:flutter_floating_map_marker_titles_core/utils/utils.dart'; 7 | 8 | class TitleDisplayInfo { 9 | int creationTime; 10 | final FloatingMarkerTitleInfo floatingMarkerTitleInfo; 11 | final FloatingTitlePainter titlePainter; 12 | final Offset viewCoordinates; 13 | final Bounds _displayBounds; 14 | 15 | TitleDisplayInfo( 16 | this.floatingMarkerTitleInfo, 17 | this.titlePainter, 18 | this.viewCoordinates, 19 | ) : creationTime = Utils.currentTimeEpochMillis(), 20 | _displayBounds = Bounds( 21 | CustomPoint( 22 | viewCoordinates.dx, 23 | viewCoordinates.dy, 24 | ), 25 | CustomPoint( 26 | viewCoordinates.dx + titlePainter.width, 27 | viewCoordinates.dy + titlePainter.height, 28 | ), 29 | ); 30 | 31 | bool intersectsWith(final TitleDisplayInfo titleDisplayInfo) { 32 | return _displayBounds.containsPartialBounds(titleDisplayInfo._displayBounds); 33 | } 34 | } 35 | 36 | class TitlesDisplayState { 37 | final Map _titleDisplayInfoMap = {}; 38 | final Set fullyVisibleTitleIds = {}; 39 | final Set fadingInTitleIds = {}; 40 | final Set pendingFadeInTitleIds = {}; 41 | int currentTitleIndex = 0; 42 | int lastFadeInStartTimeEpochMillis = 0; 43 | 44 | TitleDisplayInfo? getTitleDisplayInfo(final int floatingMarkerTitleInfoId) { 45 | return _titleDisplayInfoMap[floatingMarkerTitleInfoId]; 46 | } 47 | 48 | void updateFrom(final TitlesDisplayState oldState) { 49 | _titleDisplayInfoMap.addAll(oldState._titleDisplayInfoMap); 50 | fullyVisibleTitleIds.addAll(oldState.fullyVisibleTitleIds); 51 | fadingInTitleIds.addAll(oldState.fadingInTitleIds); 52 | pendingFadeInTitleIds.addAll(oldState.pendingFadeInTitleIds); 53 | currentTitleIndex = oldState.currentTitleIndex; 54 | lastFadeInStartTimeEpochMillis = oldState.lastFadeInStartTimeEpochMillis; 55 | } 56 | 57 | void removeObsoleteTitles(final Iterable availableIds) { 58 | final Iterable currentIds = List.from(_titleDisplayInfoMap.keys); 59 | for (final currentId in currentIds) { 60 | if (!availableIds.contains(currentId)) { 61 | removeTitleInfo(currentId); 62 | } 63 | } 64 | } 65 | 66 | void removeAllTitles() { 67 | final Iterable currentIds = List.from(_titleDisplayInfoMap.keys); 68 | for (final currentId in currentIds) { 69 | removeTitleInfo(currentId); 70 | } 71 | } 72 | 73 | void removeTitleInfo(final int floatingMarkerTitleInfoId) { 74 | _titleDisplayInfoMap.remove(floatingMarkerTitleInfoId); 75 | fullyVisibleTitleIds.remove(floatingMarkerTitleInfoId); 76 | fadingInTitleIds.remove(floatingMarkerTitleInfoId); 77 | pendingFadeInTitleIds.remove(floatingMarkerTitleInfoId); 78 | } 79 | 80 | void updateWithTitleInfo(final TitleDisplayInfo titleDisplayInfo) { 81 | final TitleDisplayInfo? existingTDI = _titleDisplayInfoMap[titleDisplayInfo.floatingMarkerTitleInfo.id]; 82 | if (existingTDI == null) { 83 | pendingFadeInTitleIds.add(titleDisplayInfo.floatingMarkerTitleInfo.id); 84 | } else { 85 | titleDisplayInfo.creationTime = existingTDI.creationTime; 86 | } 87 | _titleDisplayInfoMap[titleDisplayInfo.floatingMarkerTitleInfo.id] = titleDisplayInfo; 88 | } 89 | 90 | Iterable get titleDisplayInfos { 91 | return _titleDisplayInfoMap.values; 92 | } 93 | 94 | int get titlesCount { 95 | return _titleDisplayInfoMap.length; 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /flutter_floating_map_marker_titles_core/lib/controller/map_view_interface/abstract_czr_map_view_interface.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math' as math; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_floating_map_marker_titles_core/controller/cache/epsg_3857_proj_cache.dart'; 4 | import 'package:flutter_floating_map_marker_titles_core/controller/map_view_interface/abstract_map_view_interface.dart'; 5 | import 'package:latlong2/latlong.dart'; 6 | import 'package:vector_math/vector_math.dart' as vector_math; 7 | 8 | abstract class AbstractCZRMapViewInterface extends AbstractMapViewInterface { 9 | final Epsg3857ProjCache _projCache; 10 | 11 | AbstractCZRMapViewInterface(final int projCacheSize) : _projCache = Epsg3857ProjCache(projCacheSize); 12 | 13 | @override 14 | void updateFrom(AbstractMapViewInterface oldMapInterface) { 15 | final AbstractCZRMapViewInterface oldMapInterfaceCast = oldMapInterface as AbstractCZRMapViewInterface; 16 | _projCache.updateFrom(oldMapInterfaceCast._projCache); 17 | } 18 | 19 | LatLng getMapViewCenter(); 20 | double getMapViewZoom(); 21 | double getMapViewRotationDegrees(); 22 | 23 | @override 24 | Offset latLngToViewCoordinates(final LatLng latLng, final Size viewSize) { 25 | final LatLng centerLatLng = getMapViewCenter(); 26 | final double mapViewZoom = getMapViewZoom(); 27 | final double mapViewRotationDegrees = getMapViewRotationDegrees(); 28 | final math.Point targetPoint = _projCache.getProjectedLatLng(latLng, mapViewZoom); 29 | final math.Point centerPoint = _projCache.getProjectedLatLng(centerLatLng, mapViewZoom); 30 | final double xDiff = targetPoint.x - (centerPoint.x as double); 31 | final double yDiff = targetPoint.y - (centerPoint.y as double); 32 | final double viewCenterX = viewSize.width / 2; 33 | final double viewCenterY = viewSize.height / 2; 34 | if (mapViewRotationDegrees == 0) { 35 | return Offset(viewCenterX + xDiff, viewCenterY + yDiff); 36 | } else { 37 | final double radius = math.sqrt(math.pow(xDiff, 2) + math.pow(yDiff, 2)); 38 | final double baseAngleRad = math.acos(xDiff / radius); 39 | final double angleDeltaRad = vector_math.radians(mapViewRotationDegrees); 40 | double resultingAngleRad; 41 | if (yDiff >= 0) { 42 | resultingAngleRad = baseAngleRad + angleDeltaRad; 43 | } else { 44 | resultingAngleRad = angleDeltaRad - baseAngleRad; 45 | } 46 | final double translatedXDiff = radius * math.cos(resultingAngleRad); 47 | final double translatedYDiff = radius * math.sin(resultingAngleRad); 48 | return Offset( 49 | viewCenterX + translatedXDiff, 50 | viewCenterY + translatedYDiff, 51 | ); 52 | } 53 | } 54 | 55 | @override 56 | String getMapViewTitlesPerspectiveValue() { 57 | return '${getMapViewRotationDegrees()}-${getMapViewZoom()}'; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /flutter_floating_map_marker_titles_core/lib/controller/map_view_interface/abstract_map_view_interface.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:latlong2/latlong.dart'; 3 | 4 | abstract class AbstractMapViewInterface { 5 | /// Update the Map Interface from a previous instance. 6 | /// This method is the ideal moment to transfer any cache data from the old instance 7 | void updateFrom(final AbstractMapViewInterface oldMapInterface); 8 | 9 | /// Convert LatLng coordinates to screen coordinates 10 | Offset latLngToViewCoordinates(final LatLng latLng, final Size viewSize); 11 | 12 | /// Return the current Map View Titles Perspective Value: 13 | /// This value is a way to identify when the map view perspective has changed in a way 14 | /// floating titles might collide with each other (e.g. zoom, rotation, tilt, etc.) 15 | /// This allows the floating titles controller to know when to ignore existing titles collisions, 16 | /// to avoid making titles blink when they are too close together with coordinates calculations 17 | /// rounding makes them look like they are colliding/not colliding every other frame. 18 | String getMapViewTitlesPerspectiveValue() ; 19 | } 20 | -------------------------------------------------------------------------------- /flutter_floating_map_marker_titles_core/lib/model/floating_marker_title_info.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:latlong2/latlong.dart'; 3 | 4 | class FloatingMarkerTitleInfo { 5 | /// ID of the floating title, used by the system to track what was added/removed between two paints 6 | final int id; 7 | 8 | /// Base coordinates the title is attached to 9 | final LatLng latLng; 10 | 11 | /// The title text as a String 12 | final String title; 13 | 14 | /// The title base color 15 | final Color color; 16 | 17 | /// Whether the title text should be written in bold 18 | final bool isBold; 19 | 20 | /// z-index of the title to specify which title has the most priority for display in case of titles collisions 21 | final int zIndex; 22 | 23 | FloatingMarkerTitleInfo({ 24 | required this.id, 25 | required this.latLng, 26 | required this.title, 27 | required this.color, 28 | this.isBold = false, 29 | this.zIndex = 1, 30 | }); 31 | } 32 | -------------------------------------------------------------------------------- /flutter_floating_map_marker_titles_core/lib/utils/cached_calculator.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_floating_map_marker_titles_core/utils/rotating_cache.dart'; 2 | 3 | abstract class CachedCalculator { 4 | final RotatingCache _cache; 5 | 6 | static int _computeSaneHalfCacheSize(final int cacheMaxSize) { 7 | if (cacheMaxSize < 2) { 8 | return 1; 9 | } else { 10 | return (cacheMaxSize / 2).floor(); 11 | } 12 | } 13 | 14 | CachedCalculator(final int cacheMaxSize) : _cache = RotatingCache(_computeSaneHalfCacheSize(cacheMaxSize)); 15 | 16 | V getValue(final K key) { 17 | final V? existingCacheEntry = _cache.getValue(key); 18 | if (existingCacheEntry != null) { 19 | return existingCacheEntry; 20 | } 21 | final V createdCacheEntry = calculateValue(key); 22 | _cache.putValue(key, createdCacheEntry); 23 | return createdCacheEntry; 24 | } 25 | 26 | V calculateValue(final K key); 27 | } 28 | -------------------------------------------------------------------------------- /flutter_floating_map_marker_titles_core/lib/utils/geo/bounds.dart: -------------------------------------------------------------------------------- 1 | // File copied from the flutter_map project to re-use projection utils classes 2 | // Source project file: https://raw.githubusercontent.com/fleaflet/flutter_map/master/lib/src/core/bounds.dart 3 | 4 | import 'dart:math' as math; 5 | 6 | import 'package:flutter_floating_map_marker_titles_core/utils/geo/point.dart'; 7 | 8 | /// Rectangular bound delimited by orthogonal lines passing through two 9 | /// points. 10 | class Bounds { 11 | final CustomPoint min; 12 | final CustomPoint max; 13 | 14 | factory Bounds(CustomPoint a, CustomPoint b) { 15 | var bounds1 = Bounds._(a, b); 16 | var bounds2 = bounds1.extend(a); 17 | return bounds2.extend(b); 18 | } 19 | 20 | const Bounds._(this.min, this.max); 21 | 22 | /// Creates a new [Bounds] obtained by expanding the current ones with a new 23 | /// point. 24 | Bounds extend(CustomPoint point) { 25 | return Bounds._( 26 | CustomPoint( 27 | math.min(point.x, min.x), 28 | math.min(point.y, min.y), 29 | ), 30 | CustomPoint( 31 | math.max(point.x, max.x), 32 | math.max(point.y, max.y), 33 | ), 34 | ); 35 | } 36 | 37 | /// This [Bounds] central point. 38 | CustomPoint get center => CustomPoint( 39 | (min.x + max.x) / 2, 40 | (min.y + max.y) / 2, 41 | ); 42 | 43 | /// Bottom-Left corner's point. 44 | CustomPoint get bottomLeft => CustomPoint(min.x, max.y); 45 | 46 | /// Top-Right corner's point. 47 | CustomPoint get topRight => CustomPoint(max.x, min.y); 48 | 49 | /// Top-Left corner's point. 50 | CustomPoint get topLeft => min; 51 | 52 | /// Bottom-Right corner's point. 53 | CustomPoint get bottomRight => max; 54 | 55 | /// A point that contains the difference between the point's axis projections. 56 | CustomPoint get size { 57 | return max - min; 58 | } 59 | 60 | bool contains(CustomPoint point) { 61 | var min = point; 62 | var max = point; 63 | return containsBounds(Bounds(min, max)); 64 | } 65 | 66 | bool containsBounds(Bounds b) { 67 | return (b.min.x >= min.x) && 68 | (b.max.x <= max.x) && 69 | (b.min.y >= min.y) && 70 | (b.max.y <= max.y); 71 | } 72 | 73 | bool containsPartialBounds(Bounds b) { 74 | return (b.min.x <= max.x) && 75 | (b.max.x >= min.x) && 76 | (b.min.y <= max.y) && 77 | (b.max.y >= min.y); 78 | } 79 | 80 | @override 81 | String toString() => 'Bounds($min, $max)'; 82 | } 83 | -------------------------------------------------------------------------------- /flutter_floating_map_marker_titles_core/lib/utils/geo/crs.dart: -------------------------------------------------------------------------------- 1 | // File copied from the flutter_map project to re-use projection utils classes 2 | // Source project file: https://raw.githubusercontent.com/fleaflet/flutter_map/master/lib/src/geo/crs/crs.dart 3 | 4 | import 'dart:math' as math; 5 | 6 | import 'package:flutter_floating_map_marker_titles_core/utils/geo/bounds.dart'; 7 | import 'package:flutter_floating_map_marker_titles_core/utils/geo/point.dart'; 8 | import 'package:latlong2/latlong.dart'; 9 | import 'package:meta/meta.dart'; 10 | import 'package:proj4dart/proj4dart.dart' as proj4; 11 | import 'package:tuple/tuple.dart'; 12 | 13 | /// An abstract representation of a 14 | /// [Coordinate Reference System](https://bit.ly/3iVKpja). 15 | /// 16 | /// The main objective of a CRS is to handle the conversion between surface 17 | /// points of objects of different dimensions. In our case 3D and 2D objects. 18 | abstract class Crs { 19 | String get code; 20 | 21 | Projection get projection; 22 | 23 | Transformation get transformation; 24 | 25 | const Crs(); 26 | 27 | /// Converts a point on the sphere surface (with a certain zoom) in a 28 | /// map point. 29 | CustomPoint latLngToPoint(LatLng latlng, double zoom) { 30 | try { 31 | var projectedPoint = projection.project(latlng); 32 | var scale = this.scale(zoom); 33 | return transformation.transform(projectedPoint, scale.toDouble()); 34 | } catch (e) { 35 | return CustomPoint(0.0, 0.0); 36 | } 37 | } 38 | 39 | /// Converts a map point to the sphere coordinate (at a certain zoom). 40 | LatLng? pointToLatLng(CustomPoint point, double zoom) { 41 | var scale = this.scale(zoom); 42 | var untransformedPoint = 43 | transformation.untransform(point, scale.toDouble()); 44 | try { 45 | return projection.unproject(untransformedPoint); 46 | } catch (e) { 47 | return null; 48 | } 49 | } 50 | 51 | /// Zoom to Scale function. 52 | num scale(double zoom) { 53 | return 256 * math.pow(2, zoom); 54 | } 55 | 56 | /// Scale to Zoom function. 57 | num zoom(double scale) { 58 | return math.log(scale / 256) / math.ln2; 59 | } 60 | 61 | /// Rescales the bounds to a given zoom value. 62 | Bounds? getProjectedBounds(double zoom) { 63 | if (infinite) return null; 64 | 65 | var b = projection.bounds!; 66 | var s = scale(zoom); 67 | var min = transformation.transform(b.min, s.toDouble()); 68 | var max = transformation.transform(b.max, s.toDouble()); 69 | return Bounds(min, max); 70 | } 71 | 72 | bool get infinite; 73 | 74 | Tuple2? get wrapLng; 75 | 76 | Tuple2? get wrapLat; 77 | } 78 | 79 | // Custom CRS for non geographical maps 80 | class CrsSimple extends Crs { 81 | @override 82 | final String code = 'CRS.SIMPLE'; 83 | 84 | @override 85 | final Projection projection; 86 | 87 | @override 88 | final Transformation transformation; 89 | 90 | CrsSimple() 91 | : projection = const _LonLat(), 92 | transformation = Transformation(1, 0, -1, 0), 93 | super(); 94 | 95 | @override 96 | bool get infinite => false; 97 | 98 | @override 99 | Tuple2? get wrapLat => null; 100 | 101 | @override 102 | Tuple2? get wrapLng => null; 103 | } 104 | 105 | abstract class Earth extends Crs { 106 | @override 107 | bool get infinite => false; 108 | 109 | @override 110 | final Tuple2 wrapLng = const Tuple2(-180.0, 180.0); 111 | 112 | @override 113 | final Tuple2? wrapLat = null; 114 | 115 | const Earth() : super(); 116 | } 117 | 118 | /// The most common CRS used for rendering maps. 119 | class Epsg3857 extends Earth { 120 | @override 121 | final String code = 'EPSG:3857'; 122 | 123 | @override 124 | final Projection projection; 125 | 126 | @override 127 | final Transformation transformation; 128 | 129 | static const num _scale = 0.5 / (math.pi * SphericalMercator.r); 130 | 131 | const Epsg3857() 132 | : projection = const SphericalMercator(), 133 | transformation = const Transformation(_scale, 0.5, -_scale, 0.5), 134 | super(); 135 | 136 | //@override 137 | //Tuple2 get wrapLat => const Tuple2(-85.06, 85.06); 138 | } 139 | 140 | /// A common CRS among GIS enthusiasts. Uses simple Equirectangular projection. 141 | class Epsg4326 extends Earth { 142 | @override 143 | final String code = 'EPSG:4326'; 144 | 145 | @override 146 | final Projection projection; 147 | 148 | @override 149 | final Transformation transformation; 150 | 151 | const Epsg4326() 152 | : projection = const _LonLat(), 153 | transformation = const Transformation(1 / 180, 0.5, -1 / 180, 0.5), 154 | super(); 155 | } 156 | 157 | /// Custom CRS 158 | class Proj4Crs extends Crs { 159 | @override 160 | final String code; 161 | 162 | @override 163 | final Projection projection; 164 | 165 | @override 166 | final Transformation transformation; 167 | 168 | @override 169 | final bool infinite; 170 | 171 | @override 172 | final Tuple2? wrapLat = null; 173 | 174 | @override 175 | final Tuple2? wrapLng = null; 176 | 177 | final List? _transformations; 178 | 179 | final List _scales; 180 | 181 | Proj4Crs._({ 182 | required this.code, 183 | required this.projection, 184 | required this.transformation, 185 | required this.infinite, 186 | List? transformations, 187 | required List scales, 188 | }) : _transformations = transformations, 189 | _scales = scales; 190 | 191 | factory Proj4Crs.fromFactory({ 192 | required String code, 193 | required proj4.Projection proj4Projection, 194 | Transformation? transformation, 195 | List? origins, 196 | Bounds? bounds, 197 | List? scales, 198 | List? resolutions, 199 | }) { 200 | final projection = 201 | _Proj4Projection(proj4Projection: proj4Projection, bounds: bounds); 202 | List? transformations; 203 | var infinite = null == bounds; 204 | List finalScales; 205 | 206 | if (null != scales && scales.isNotEmpty) { 207 | finalScales = scales; 208 | } else if (null != resolutions && resolutions.isNotEmpty) { 209 | finalScales = resolutions.map((r) => 1 / r).toList(growable: false); 210 | } else { 211 | throw Exception( 212 | 'Please provide scales or resolutions to determine scales'); 213 | } 214 | 215 | if (null == origins || origins.isEmpty) { 216 | transformation ??= Transformation(1, 0, -1, 0); 217 | } else { 218 | if (origins.length == 1) { 219 | var origin = origins[0]; 220 | transformation = Transformation(1, -origin.x, -1, origin.y); 221 | } else { 222 | transformations = 223 | origins.map((p) => Transformation(1, -p.x, -1, p.y)).toList(); 224 | transformation = null; 225 | } 226 | } 227 | 228 | return Proj4Crs._( 229 | code: code, 230 | projection: projection, 231 | transformation: transformation!, 232 | infinite: infinite, 233 | transformations: transformations, 234 | scales: finalScales, 235 | ); 236 | } 237 | 238 | /// Converts a point on the sphere surface (with a certain zoom) in a 239 | /// map point. 240 | @override 241 | CustomPoint latLngToPoint(LatLng latlng, double zoom) { 242 | try { 243 | var projectedPoint = projection.project(latlng); 244 | var scale = this.scale(zoom); 245 | var transformation = _getTransformationByZoom(zoom); 246 | 247 | return transformation.transform(projectedPoint, scale.toDouble()); 248 | } catch (e) { 249 | return CustomPoint(0.0, 0.0); 250 | } 251 | } 252 | 253 | /// Converts a map point to the sphere coordinate (at a certain zoom). 254 | @override 255 | LatLng? pointToLatLng(CustomPoint point, double zoom) { 256 | var scale = this.scale(zoom); 257 | var transformation = _getTransformationByZoom(zoom); 258 | 259 | var untransformedPoint = 260 | transformation.untransform(point, scale.toDouble()); 261 | try { 262 | return projection.unproject(untransformedPoint); 263 | } catch (e) { 264 | return null; 265 | } 266 | } 267 | 268 | /// Rescales the bounds to a given zoom value. 269 | @override 270 | Bounds? getProjectedBounds(double zoom) { 271 | if (infinite) return null; 272 | 273 | var b = projection.bounds!; 274 | var s = scale(zoom); 275 | 276 | var transformation = _getTransformationByZoom(zoom); 277 | 278 | var min = transformation.transform(b.min, s.toDouble()); 279 | var max = transformation.transform(b.max, s.toDouble()); 280 | return Bounds(min, max); 281 | } 282 | 283 | /// Zoom to Scale function. 284 | @override 285 | num scale(double zoom) { 286 | var iZoom = zoom.floor(); 287 | if (zoom == iZoom) { 288 | return _scales[iZoom]; 289 | } else { 290 | // Non-integer zoom, interpolate 291 | var baseScale = _scales[iZoom]; 292 | var nextScale = _scales[iZoom + 1]; 293 | var scaleDiff = nextScale - baseScale; 294 | var zDiff = (zoom - iZoom); 295 | return baseScale + scaleDiff * zDiff; 296 | } 297 | } 298 | 299 | /// Scale to Zoom function. 300 | @override 301 | num zoom(double scale) { 302 | // Find closest number in _scales, down 303 | var downScale = _closestElement(_scales, scale); 304 | if (downScale == null) { 305 | return double.negativeInfinity; 306 | } 307 | var downZoom = _scales.indexOf(downScale); 308 | // Check if scale is downScale => return array index 309 | if (scale == downScale) { 310 | return downZoom; 311 | } 312 | // Interpolate 313 | var nextZoom = downZoom + 1; 314 | var nextScale = _scales[nextZoom]; 315 | 316 | var scaleDiff = nextScale - downScale; 317 | return (scale - downScale) / scaleDiff + downZoom; 318 | } 319 | 320 | /// Get the closest lowest element in an array 321 | double? _closestElement(List array, double element) { 322 | double? low; 323 | for (var i = array.length - 1; i >= 0; i--) { 324 | var curr = array[i]; 325 | 326 | if (curr <= element && (null == low || low < curr)) { 327 | low = curr; 328 | } 329 | } 330 | return low; 331 | } 332 | 333 | /// returns Transformation object based on zoom 334 | Transformation _getTransformationByZoom(double zoom) { 335 | if (null == _transformations) { 336 | return transformation; 337 | } 338 | 339 | var iZoom = zoom.round(); 340 | var lastIdx = _transformations!.length - 1; 341 | 342 | return _transformations![iZoom > lastIdx ? lastIdx : iZoom]; 343 | } 344 | } 345 | 346 | abstract class Projection { 347 | const Projection(); 348 | 349 | Bounds? get bounds; 350 | 351 | CustomPoint project(LatLng latlng); 352 | 353 | LatLng unproject(CustomPoint point); 354 | 355 | double _inclusive(Comparable start, Comparable end, double value) { 356 | if (value.compareTo(start as num) < 0) return start as double; 357 | if (value.compareTo(end as num) > 0) return end as double; 358 | 359 | return value; 360 | } 361 | 362 | @protected 363 | double inclusiveLat(double value) { 364 | return _inclusive(-90.0, 90.0, value); 365 | } 366 | 367 | @protected 368 | double inclusiveLng(double value) { 369 | return _inclusive(-180.0, 180.0, value); 370 | } 371 | } 372 | 373 | class _LonLat extends Projection { 374 | static final Bounds _bounds = Bounds( 375 | CustomPoint(-180.0, -90.0), CustomPoint(180.0, 90.0)); 376 | 377 | const _LonLat() : super(); 378 | 379 | @override 380 | Bounds get bounds => _bounds; 381 | 382 | @override 383 | CustomPoint project(LatLng latlng) { 384 | return CustomPoint(latlng.longitude, latlng.latitude); 385 | } 386 | 387 | @override 388 | LatLng unproject(CustomPoint point) { 389 | return LatLng( 390 | inclusiveLat(point.y as double), inclusiveLng(point.x as double)); 391 | } 392 | } 393 | 394 | class SphericalMercator extends Projection { 395 | static const int r = 6378137; 396 | static const double maxLatitude = 85.0511287798; 397 | static const double _boundsD = r * math.pi; 398 | static final Bounds _bounds = Bounds( 399 | CustomPoint(-_boundsD, -_boundsD), 400 | CustomPoint(_boundsD, _boundsD), 401 | ); 402 | 403 | const SphericalMercator() : super(); 404 | 405 | @override 406 | Bounds get bounds => _bounds; 407 | 408 | @override 409 | CustomPoint project(LatLng latlng) { 410 | var d = math.pi / 180; 411 | var max = maxLatitude; 412 | var lat = math.max(math.min(max, latlng.latitude), -max); 413 | var sin = math.sin(lat * d); 414 | 415 | return CustomPoint( 416 | r * latlng.longitude * d, r * math.log((1 + sin) / (1 - sin)) / 2); 417 | } 418 | 419 | @override 420 | LatLng unproject(CustomPoint point) { 421 | var d = 180 / math.pi; 422 | return LatLng( 423 | inclusiveLat( 424 | (2 * math.atan(math.exp(point.y / r)) - (math.pi / 2)) * d), 425 | inclusiveLng(point.x * d / r)); 426 | } 427 | } 428 | 429 | class _Proj4Projection extends Projection { 430 | final proj4.Projection epsg4326; 431 | 432 | final proj4.Projection proj4Projection; 433 | 434 | @override 435 | final Bounds? bounds; 436 | 437 | _Proj4Projection({ 438 | required this.proj4Projection, 439 | this.bounds, 440 | }) : epsg4326 = proj4.Projection.WGS84; 441 | 442 | @override 443 | CustomPoint project(LatLng latlng) { 444 | var point = epsg4326.transform( 445 | proj4Projection, proj4.Point(x: latlng.longitude, y: latlng.latitude)); 446 | 447 | return CustomPoint(point.x, point.y); 448 | } 449 | 450 | @override 451 | LatLng unproject(CustomPoint point) { 452 | var point2 = proj4Projection.transform( 453 | epsg4326, proj4.Point(x: point.x as double, y: point.y as double)); 454 | 455 | return LatLng(inclusiveLat(point2.y), inclusiveLng(point2.x)); 456 | } 457 | } 458 | 459 | class Transformation { 460 | final num a; 461 | final num b; 462 | final num c; 463 | final num d; 464 | 465 | const Transformation(this.a, this.b, this.c, this.d); 466 | 467 | CustomPoint transform(CustomPoint point, double? scale) { 468 | scale ??= 1.0; 469 | var x = scale * (a * point.x + b); 470 | var y = scale * (c * point.y + d); 471 | return CustomPoint(x, y); 472 | } 473 | 474 | CustomPoint untransform(CustomPoint point, double? scale) { 475 | scale ??= 1.0; 476 | var x = (point.x / scale - b) / a; 477 | var y = (point.y / scale - d) / c; 478 | return CustomPoint(x, y); 479 | } 480 | } 481 | -------------------------------------------------------------------------------- /flutter_floating_map_marker_titles_core/lib/utils/geo/point.dart: -------------------------------------------------------------------------------- 1 | // File copied from the flutter_map project to re-use projection utils classes 2 | // Source project file: https://github.com/fleaflet/flutter_map/blob/master/lib/src/core/point.dart 3 | 4 | import 'dart:math' as math; 5 | 6 | class CustomPoint extends math.Point { 7 | const CustomPoint(num x, num y) : super(x as T, y as T); 8 | 9 | CustomPoint operator /(num /*T|int*/ factor) { 10 | return CustomPoint(x / factor, y / factor); 11 | } 12 | 13 | CustomPoint ceil() { 14 | return CustomPoint(x.ceil(), y.ceil()); 15 | } 16 | 17 | CustomPoint floor() { 18 | return CustomPoint(x.floor(), y.floor()); 19 | } 20 | 21 | CustomPoint unscaleBy(CustomPoint point) { 22 | return CustomPoint(x / point.x, y / point.y); 23 | } 24 | 25 | @override 26 | CustomPoint operator +(math.Point other) { 27 | return CustomPoint(x + other.x, y + other.y); 28 | } 29 | 30 | @override 31 | CustomPoint operator -(math.Point other) { 32 | return CustomPoint(x - other.x, y - other.y); 33 | } 34 | 35 | @override 36 | CustomPoint operator *(num /*T|int*/ factor) { 37 | return CustomPoint((x * factor), (y * factor)); 38 | } 39 | 40 | CustomPoint scaleBy(CustomPoint point) { 41 | return CustomPoint(x * point.x, y * point.y); 42 | } 43 | 44 | CustomPoint round() { 45 | final x = this.x is double ? this.x.round() : this.x; 46 | final y = this.y is double ? this.y.round() : this.y; 47 | return CustomPoint(x, y); 48 | } 49 | 50 | CustomPoint multiplyBy(num n) { 51 | return CustomPoint(x * n, y * n); 52 | } 53 | 54 | // Clockwise rotation 55 | CustomPoint rotate(num radians) { 56 | if (radians != 0.0) { 57 | final cos = math.cos(radians); 58 | final sin = math.sin(radians); 59 | final nx = (cos * x) + (sin * y); 60 | final ny = (cos * y) - (sin * x); 61 | 62 | return CustomPoint(nx, ny); 63 | } 64 | 65 | return this; 66 | } 67 | 68 | @override 69 | String toString() => 'CustomPoint ($x, $y)'; 70 | } 71 | -------------------------------------------------------------------------------- /flutter_floating_map_marker_titles_core/lib/utils/rotating_cache.dart: -------------------------------------------------------------------------------- 1 | class RotatingCache { 2 | final int halfCacheMaxSize; 3 | 4 | Map _primaryCache = {}; 5 | Map _secondaryCache = {}; 6 | 7 | RotatingCache(this.halfCacheMaxSize); 8 | 9 | void _swapCaches() { 10 | final Map tmp = _primaryCache; 11 | _primaryCache = _secondaryCache; 12 | _secondaryCache = tmp; 13 | } 14 | 15 | V? getValue(final K key) { 16 | V? cachedValue = _primaryCache[key]; 17 | if (cachedValue != null) { 18 | return cachedValue; 19 | } 20 | cachedValue = _secondaryCache[key]; 21 | if (cachedValue == null) { 22 | return null; 23 | } 24 | 25 | putValue(key, cachedValue); 26 | return cachedValue; 27 | } 28 | 29 | void putValue(final K key, final V value) { 30 | if (_primaryCache.length >= halfCacheMaxSize) { 31 | _secondaryCache.clear(); 32 | _swapCaches(); 33 | } 34 | _primaryCache[key] = value; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /flutter_floating_map_marker_titles_core/lib/utils/utils.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class Utils { 4 | static const double minLuminanceToLightTinting = 0.75; 5 | 6 | static double colorLuminance(final Color color) { 7 | final double red = color.r; 8 | final double green = color.g; 9 | final double blue = color.b; 10 | 11 | return 0.2126 * red + 0.7152 * green + 0.0722 * blue; 12 | } 13 | 14 | static bool isDarkColor(final Color color) { 15 | return colorLuminance(color) < minLuminanceToLightTinting; 16 | } 17 | 18 | static int currentTimeEpochMillis() { 19 | return DateTime.now().millisecondsSinceEpoch; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /flutter_floating_map_marker_titles_core/lib/view/abstract_map_view_wrapper.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/widgets.dart'; 2 | import 'package:flutter_floating_map_marker_titles_core/controller/fmto_controller.dart'; 3 | import 'package:flutter_floating_map_marker_titles_core/controller/map_view_interface/abstract_map_view_interface.dart'; 4 | import 'package:flutter_floating_map_marker_titles_core/model/floating_marker_title_info.dart'; 5 | import 'package:flutter_floating_map_marker_titles_core/view/floating_marker_titles_overlay.dart'; 6 | 7 | abstract class AbstractMapViewWrapper extends StatelessWidget { 8 | final T _mapViewInterface; 9 | final FMTOOptions _fmtoOptions; 10 | final List? floatingTitles; 11 | final Stream>? floatingTitlesStream; 12 | 13 | const AbstractMapViewWrapper( 14 | this._mapViewInterface, 15 | this._fmtoOptions, { 16 | super.key, 17 | this.floatingTitles, 18 | this.floatingTitlesStream, 19 | }); 20 | 21 | Widget buildMapView(final BuildContext context, final T mapViewInterface); 22 | 23 | @override 24 | Widget build(final BuildContext context) { 25 | return Stack( 26 | children: [ 27 | buildMapView(context, _mapViewInterface), 28 | FlutterMapFloatingMarkerTitlesOverlay( 29 | _mapViewInterface, 30 | _fmtoOptions, 31 | floatingTitles: floatingTitles, 32 | floatingTitlesStream: floatingTitlesStream, 33 | ), 34 | ], 35 | ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /flutter_floating_map_marker_titles_core/lib/view/floating_marker_titles_overlay.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/widgets.dart'; 2 | import 'package:flutter_floating_map_marker_titles_core/controller/fmto_controller.dart'; 3 | import 'package:flutter_floating_map_marker_titles_core/controller/map_view_interface/abstract_map_view_interface.dart'; 4 | import 'package:flutter_floating_map_marker_titles_core/model/floating_marker_title_info.dart'; 5 | import 'package:flutter_floating_map_marker_titles_core/view/floating_marker_titles_overlay_layer.dart'; 6 | 7 | class FlutterMapFloatingMarkerTitlesOverlay extends StatefulWidget { 8 | final FMTOController _fmtoController; 9 | 10 | FlutterMapFloatingMarkerTitlesOverlay( 11 | final AbstractMapViewInterface mapViewInterface, 12 | final FMTOOptions fmtoOptions, { 13 | super.key, 14 | final List? floatingTitles, 15 | final Stream>? floatingTitlesStream, 16 | }) : _fmtoController = FMTOController( 17 | mapViewInterface, 18 | fmtoOptions, 19 | floatingTitles: floatingTitles, 20 | floatingTitlesStream: floatingTitlesStream, 21 | ); 22 | 23 | @override 24 | _FlutterMapFloatingMarkerTitlesOverlayState createState() => _FlutterMapFloatingMarkerTitlesOverlayState(); 25 | } 26 | 27 | class _FlutterMapFloatingMarkerTitlesOverlayState extends State { 28 | @override 29 | void didUpdateWidget(covariant FlutterMapFloatingMarkerTitlesOverlay oldWidget) { 30 | widget._fmtoController.updateFrom(oldWidget._fmtoController); 31 | super.didUpdateWidget(oldWidget); 32 | } 33 | 34 | @override 35 | Widget build(final BuildContext context) { 36 | return Stack( 37 | children: [ 38 | FlutterMapFloatingMarkerTitlesOverlayLayer( 39 | widget._fmtoController, 40 | ), 41 | _FMTOTransparentTitlesLayerWrapper(widget._fmtoController), 42 | ], 43 | ); 44 | } 45 | } 46 | 47 | class _FMTOTransparentTitlesLayerWrapper extends StatefulWidget { 48 | final FMTOController _fmtoController; 49 | 50 | const _FMTOTransparentTitlesLayerWrapper( 51 | this._fmtoController, 52 | ); 53 | 54 | @override 55 | _FMTOTransparentTitlesLayerWrapperState createState() => _FMTOTransparentTitlesLayerWrapperState(); 56 | } 57 | 58 | class _FMTOTransparentTitlesLayerWrapperState extends State<_FMTOTransparentTitlesLayerWrapper> { 59 | double _transparentTitlesOpacity = 0; 60 | 61 | @override 62 | Widget build(final BuildContext context) { 63 | widget._fmtoController.setOnTransparentTitlesOpacityChanged((final double transparentTitlesOpacity) { 64 | Future.delayed(Duration.zero, () { 65 | setState(() { 66 | _transparentTitlesOpacity = transparentTitlesOpacity; 67 | }); 68 | }); 69 | }); 70 | return Opacity( 71 | opacity: _transparentTitlesOpacity, 72 | child: FlutterMapFloatingMarkerTitlesOverlayLayer( 73 | widget._fmtoController, 74 | transparentTitles: true, 75 | ), 76 | ); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /flutter_floating_map_marker_titles_core/lib/view/floating_marker_titles_overlay_layer.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/widgets.dart'; 2 | import 'package:flutter_floating_map_marker_titles_core/controller/fmto_controller.dart'; 3 | 4 | class FlutterMapFloatingMarkerTitlesOverlayLayer extends StatelessWidget { 5 | final FMTOController _fmtoController; 6 | final bool transparentTitles; 7 | const FlutterMapFloatingMarkerTitlesOverlayLayer( 8 | this._fmtoController, { 9 | this.transparentTitles = false, 10 | }); 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | return Container( 15 | constraints: const BoxConstraints.expand(), 16 | child: CustomPaint( 17 | foregroundPainter: _FloatingMarkersTitlesPainter( 18 | _fmtoController, 19 | _FMTPainterNotifier(), 20 | transparentTitles, 21 | ), 22 | ), 23 | ); 24 | } 25 | } 26 | 27 | class _FMTPainterNotifier extends ChangeNotifier { 28 | void triggerRepaint() { 29 | notifyListeners(); 30 | } 31 | } 32 | 33 | class _FloatingMarkersTitlesPainter extends CustomPainter { 34 | final _FMTPainterNotifier _changeNotifier; 35 | final FMTOController _fmtoController; 36 | final bool _transparentTitles; 37 | 38 | _FloatingMarkersTitlesPainter( 39 | this._fmtoController, 40 | final _FMTPainterNotifier changeNotifier, 41 | final bool transparentTitles, 42 | ) : _changeNotifier = changeNotifier, 43 | _transparentTitles = transparentTitles, 44 | super(repaint: changeNotifier) { 45 | if (!_transparentTitles) { 46 | _repaintForever(); 47 | } 48 | } 49 | 50 | Future _repaintForever() async { 51 | while (true) { 52 | await Future.delayed( 53 | Duration( 54 | milliseconds: _fmtoController.fmtoOptions.repaintIntervalMillis, 55 | ), 56 | ); 57 | _changeNotifier.triggerRepaint(); 58 | } 59 | } 60 | 61 | @override 62 | void paint(final Canvas canvas, final Size size) { 63 | if (size.width > 0 && size.height > 0) { 64 | // This call to clipRect is necessary to make sure the drawing doesn't happen over other views 65 | canvas.clipRect( 66 | Rect.fromLTRB( 67 | 0, 68 | 0, 69 | size.width, 70 | size.height, 71 | ), 72 | ); 73 | } 74 | _fmtoController.paintFloatingMarkerTitles( 75 | canvas, 76 | size, 77 | _transparentTitles, 78 | ); 79 | } 80 | 81 | @override 82 | bool shouldRepaint(final CustomPainter oldDelegate) { 83 | return true; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /flutter_floating_map_marker_titles_core/pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | async: 5 | dependency: transitive 6 | description: 7 | name: async 8 | sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" 9 | url: "https://pub.dev" 10 | source: hosted 11 | version: "2.11.0" 12 | boolean_selector: 13 | dependency: transitive 14 | description: 15 | name: boolean_selector 16 | sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" 17 | url: "https://pub.dev" 18 | source: hosted 19 | version: "2.1.1" 20 | characters: 21 | dependency: transitive 22 | description: 23 | name: characters 24 | sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" 25 | url: "https://pub.dev" 26 | source: hosted 27 | version: "1.3.0" 28 | clock: 29 | dependency: transitive 30 | description: 31 | name: clock 32 | sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf 33 | url: "https://pub.dev" 34 | source: hosted 35 | version: "1.1.1" 36 | collection: 37 | dependency: transitive 38 | description: 39 | name: collection 40 | sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf 41 | url: "https://pub.dev" 42 | source: hosted 43 | version: "1.19.0" 44 | fake_async: 45 | dependency: transitive 46 | description: 47 | name: fake_async 48 | sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" 49 | url: "https://pub.dev" 50 | source: hosted 51 | version: "1.3.1" 52 | flutter: 53 | dependency: "direct main" 54 | description: flutter 55 | source: sdk 56 | version: "0.0.0" 57 | flutter_test: 58 | dependency: "direct dev" 59 | description: flutter 60 | source: sdk 61 | version: "0.0.0" 62 | intl: 63 | dependency: transitive 64 | description: 65 | name: intl 66 | sha256: "910f85bce16fb5c6f614e117efa303e85a1731bb0081edf3604a2ae6e9a3cc91" 67 | url: "https://pub.dev" 68 | source: hosted 69 | version: "0.17.0" 70 | latlong2: 71 | dependency: "direct main" 72 | description: 73 | name: latlong2 74 | sha256: "18712164760cee655bc790122b0fd8f3d5b3c36da2cb7bf94b68a197fbb0811b" 75 | url: "https://pub.dev" 76 | source: hosted 77 | version: "0.9.0" 78 | leak_tracker: 79 | dependency: transitive 80 | description: 81 | name: leak_tracker 82 | sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06" 83 | url: "https://pub.dev" 84 | source: hosted 85 | version: "10.0.7" 86 | leak_tracker_flutter_testing: 87 | dependency: transitive 88 | description: 89 | name: leak_tracker_flutter_testing 90 | sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379" 91 | url: "https://pub.dev" 92 | source: hosted 93 | version: "3.0.8" 94 | leak_tracker_testing: 95 | dependency: transitive 96 | description: 97 | name: leak_tracker_testing 98 | sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" 99 | url: "https://pub.dev" 100 | source: hosted 101 | version: "3.0.1" 102 | lint: 103 | dependency: "direct dev" 104 | description: 105 | name: lint 106 | sha256: f4bd4dbaa39f4ae8836f2d1275f2f32bc68b3a8cce0a0735dd1f7a601f06682a 107 | url: "https://pub.dev" 108 | source: hosted 109 | version: "2.1.2" 110 | lists: 111 | dependency: transitive 112 | description: 113 | name: lists 114 | sha256: "4ca5c19ae4350de036a7e996cdd1ee39c93ac0a2b840f4915459b7d0a7d4ab27" 115 | url: "https://pub.dev" 116 | source: hosted 117 | version: "1.0.1" 118 | matcher: 119 | dependency: transitive 120 | description: 121 | name: matcher 122 | sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb 123 | url: "https://pub.dev" 124 | source: hosted 125 | version: "0.12.16+1" 126 | material_color_utilities: 127 | dependency: transitive 128 | description: 129 | name: material_color_utilities 130 | sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec 131 | url: "https://pub.dev" 132 | source: hosted 133 | version: "0.11.1" 134 | meta: 135 | dependency: "direct main" 136 | description: 137 | name: meta 138 | sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 139 | url: "https://pub.dev" 140 | source: hosted 141 | version: "1.15.0" 142 | mgrs_dart: 143 | dependency: transitive 144 | description: 145 | name: mgrs_dart 146 | sha256: fb89ae62f05fa0bb90f70c31fc870bcbcfd516c843fb554452ab3396f78586f7 147 | url: "https://pub.dev" 148 | source: hosted 149 | version: "2.0.0" 150 | path: 151 | dependency: transitive 152 | description: 153 | name: path 154 | sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" 155 | url: "https://pub.dev" 156 | source: hosted 157 | version: "1.9.0" 158 | proj4dart: 159 | dependency: "direct main" 160 | description: 161 | name: proj4dart 162 | sha256: ecece8694cb026917f9e90c0e0593043c65051e516aa9e6cd0f6f8c48485262e 163 | url: "https://pub.dev" 164 | source: hosted 165 | version: "2.0.0" 166 | quiver: 167 | dependency: transitive 168 | description: 169 | name: quiver 170 | sha256: "616b691d1c8f5c53b7b39ce3542f6a25308d7900bf689d0210e72a644a10387e" 171 | url: "https://pub.dev" 172 | source: hosted 173 | version: "3.0.1+1" 174 | sky_engine: 175 | dependency: transitive 176 | description: flutter 177 | source: sdk 178 | version: "0.0.0" 179 | source_span: 180 | dependency: transitive 181 | description: 182 | name: source_span 183 | sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" 184 | url: "https://pub.dev" 185 | source: hosted 186 | version: "1.10.0" 187 | stack_trace: 188 | dependency: transitive 189 | description: 190 | name: stack_trace 191 | sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377" 192 | url: "https://pub.dev" 193 | source: hosted 194 | version: "1.12.0" 195 | stream_channel: 196 | dependency: transitive 197 | description: 198 | name: stream_channel 199 | sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 200 | url: "https://pub.dev" 201 | source: hosted 202 | version: "2.1.2" 203 | string_scanner: 204 | dependency: transitive 205 | description: 206 | name: string_scanner 207 | sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3" 208 | url: "https://pub.dev" 209 | source: hosted 210 | version: "1.3.0" 211 | term_glyph: 212 | dependency: transitive 213 | description: 214 | name: term_glyph 215 | sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 216 | url: "https://pub.dev" 217 | source: hosted 218 | version: "1.2.1" 219 | test_api: 220 | dependency: transitive 221 | description: 222 | name: test_api 223 | sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c" 224 | url: "https://pub.dev" 225 | source: hosted 226 | version: "0.7.3" 227 | tuple: 228 | dependency: "direct main" 229 | description: 230 | name: tuple 231 | sha256: fe3ae4f0dca3f9aac0888e2e0d117b642ce283a82d7017b54136290c0a3b0dd3 232 | url: "https://pub.dev" 233 | source: hosted 234 | version: "2.0.0" 235 | unicode: 236 | dependency: transitive 237 | description: 238 | name: unicode 239 | sha256: "0f69e46593d65245774d4f17125c6084d2c20b4e473a983f6e21b7d7762218f1" 240 | url: "https://pub.dev" 241 | source: hosted 242 | version: "0.3.1" 243 | vector_math: 244 | dependency: "direct main" 245 | description: 246 | name: vector_math 247 | sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" 248 | url: "https://pub.dev" 249 | source: hosted 250 | version: "2.1.4" 251 | vm_service: 252 | dependency: transitive 253 | description: 254 | name: vm_service 255 | sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b 256 | url: "https://pub.dev" 257 | source: hosted 258 | version: "14.3.0" 259 | wkt_parser: 260 | dependency: transitive 261 | description: 262 | name: wkt_parser 263 | sha256: "8a555fc60de3116c00aad67891bcab20f81a958e4219cc106e3c037aa3937f13" 264 | url: "https://pub.dev" 265 | source: hosted 266 | version: "2.0.0" 267 | sdks: 268 | dart: ">=3.4.0 <4.0.0" 269 | flutter: ">=3.18.0-18.0.pre.54" 270 | -------------------------------------------------------------------------------- /flutter_floating_map_marker_titles_core/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: flutter_floating_map_marker_titles_core 2 | description: Flutter Floating Map Marker Titles Core library 3 | version: 1.1.1 4 | repository: https://github.com/androidseb/flutter_map_floating_marker_titles 5 | 6 | environment: 7 | sdk: '>=2.17.1 <4.0.0' 8 | # This flutter >= 2.8.0 requirement is necessary for the web implementation to work: 9 | # https://github.com/flutter/flutter/issues/46683 10 | flutter: '>=2.8.0' 11 | 12 | dependencies: 13 | flutter: 14 | sdk: flutter 15 | latlong2: ^0.9.0 16 | meta: ^1.7.0 17 | proj4dart: ^2.0.0 18 | tuple: ^2.0.0 19 | vector_math: ^2.1.0 20 | 21 | dev_dependencies: 22 | flutter_test: 23 | sdk: flutter 24 | lint: 2.1.2 25 | -------------------------------------------------------------------------------- /flutter_map_floating_marker_titles/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | **/ios/Flutter/.last_build_id 26 | .dart_tool/ 27 | .flutter-plugins 28 | .flutter-plugins-dependencies 29 | .packages 30 | .pub-cache/ 31 | .pub/ 32 | /build/ 33 | 34 | # Web related 35 | lib/generated_plugin_registrant.dart 36 | 37 | # Symbolication related 38 | app.*.symbols 39 | 40 | # Obfuscation related 41 | app.*.map.json 42 | 43 | # Android Studio will place build artifacts here 44 | /android/app/debug 45 | /android/app/profile 46 | /android/app/release 47 | -------------------------------------------------------------------------------- /flutter_map_floating_marker_titles/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [1.3.0] - 2025/03/04 2 | 3 | * Updated flutter_map dependency to flutter_map: ^8.0.0 4 | 5 | ## [1.2.0] - 2024/08/10 6 | 7 | * Updated flutter_map dependency to flutter_map: ^7.0.2 8 | * Updated flutter_floating_map_marker_titles_core dependency to flutter_floating_map_marker_titles_core: ^1.1.0 9 | 10 | ## [1.1.0] - 2023/10/09 11 | 12 | * Updated flutter_map dependency to flutter_map: ^6.0.0 13 | * Added the `FloatingMarkerTitlesLayer` widget to use in flutter_map as a layer 14 | 15 | ## [1.0.0] - 2023/06/22 16 | 17 | * Updated the semantic version prefix to "officially stable" 1.X.X, because this library has been successful in a production app (see https://mapmarker.app) used by thousands of daily users for several months 18 | * Updated flutter_map dependency to flutter_map: ^5.0.0 19 | * Updated latlong2 dependency to latlong2: ^0.9.0 20 | 21 | ## [0.4.1] - 2023/05/07 22 | 23 | * Updated flutter_map dependency to flutter_map: ^4.0.0 24 | 25 | ## [0.4.0] - 2022/11/11 26 | 27 | * Updated flutter_map dependency to flutter_map: ^3.0.0 28 | 29 | ## [0.3.0] - 2022/10/23 30 | 31 | * Improved the logic handling the appearance for higher z-index titles 32 | 33 | ## [0.2.0] - 2022/09/15 34 | 35 | * Added the ability to set floating marker titles with a stream with the `floatingTitlesStream` parameter 36 | 37 | ## [0.1.0] - 2022/09/02 38 | 39 | * Changed the versioning pattern to leave the last digit for minor non-feature-related changes (e.g. library upgrades) 40 | * Updated dependencies to use flutter_map: ^2.2.0 41 | 42 | ## [0.0.6] - 2022/06/11 43 | 44 | Updated dependencies to use flutter_map: ^1.0.0 45 | 46 | ## [0.0.5+5] - 2022/01/09 47 | 48 | Removed web-specific code working around [a bug](https://github.com/flutter/flutter/issues/46683) that has since then been fixed. 49 | 50 | ## [0.0.4+4] - 2021/11/29 51 | 52 | Migrated to null safety. 53 | 54 | ## [0.0.3+3] - 2021/06/01 55 | 56 | Updated dependencies to use flutter_map: ^0.12.0 57 | 58 | ## [0.0.2+2] - 2021/04/01 59 | 60 | Fixed some issues with floating titles data not being updated in some cases, due to a wrong widget state setup. 61 | 62 | ## [0.0.1+1] - 2021/01/30 63 | 64 | This is the initial release of the library. 65 | 66 | * Support for floating map marker titles on flutter_map 67 | -------------------------------------------------------------------------------- /flutter_map_floating_marker_titles/LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2021, androidseb 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /flutter_map_floating_marker_titles/README.md: -------------------------------------------------------------------------------- 1 | # Flutter Map Floating Map Marker Titles 2 | 3 | Floating Map Marker Titles for [flutter_map](https://github.com/fleaflet/flutter_map), using the core library of the [Flutter Floating Map Marker Titles](https://github.com/androidseb/flutter_map_floating_marker_titles) project. 4 | 5 | ## Code example 6 | 7 | ```dart 8 | // With the FlutterMapWithFMTO widget as a FlutterMap wrapper 9 | FlutterMapWithFMTO( 10 | floatingTitles: floatingTitles, 11 | fmtoOptions: fmtoOptions, 12 | // ... other than the 2 above option, this widget takes 13 | // exactly the same props as the FlutterMap widget. 14 | options: MapOptions( 15 | center: LatLng(0, 0), 16 | zoom: 13, 17 | ), 18 | children: [ 19 | TileLayer( 20 | urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', 21 | ), 22 | ], 23 | ) 24 | 25 | // Or with the FloatingMarkerTitlesLayer widget as a FlutterMap layer 26 | FlutterMap( 27 | options: MapOptions( 28 | center: LatLng(0, 0), 29 | zoom: 13, 30 | ), 31 | children: [ 32 | TileLayer( 33 | urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', 34 | ), 35 | FloatingMarkerTitlesLayer( 36 | floatingTitles: floatingTitles, 37 | fmtoOptions: fmtoOptions, 38 | ), 39 | ], 40 | ) 41 | ``` 42 | 43 | See the [how-to](https://github.com/androidseb/flutter_map_floating_marker_titles#how-to-use-this-library-in-your-code) section of the main project for more details. 44 | -------------------------------------------------------------------------------- /flutter_map_floating_marker_titles/lib/flutter_map_floating_marker_titles.dart: -------------------------------------------------------------------------------- 1 | library flutter_map_floating_marker_titles; 2 | 3 | import 'package:flutter/widgets.dart'; 4 | import 'package:flutter_floating_map_marker_titles_core/controller/fmto_controller.dart'; 5 | import 'package:flutter_floating_map_marker_titles_core/controller/map_view_interface/abstract_map_view_interface.dart'; 6 | import 'package:flutter_floating_map_marker_titles_core/model/floating_marker_title_info.dart'; 7 | import 'package:flutter_floating_map_marker_titles_core/view/floating_marker_titles_overlay.dart'; 8 | import 'package:flutter_floating_map_marker_titles_core/controller/map_view_interface/abstract_czr_map_view_interface.dart'; 9 | import 'package:flutter_floating_map_marker_titles_core/view/abstract_map_view_wrapper.dart'; 10 | import 'package:flutter/material.dart'; 11 | import 'package:flutter_map/flutter_map.dart'; 12 | import 'package:latlong2/latlong.dart'; 13 | import 'dart:async'; 14 | 15 | class FlutterMapWithFMTO extends AbstractMapViewWrapper<_FlutterMapMVI> { 16 | final MapOptions _mapOptions; 17 | final List _children; 18 | 19 | factory FlutterMapWithFMTO({ 20 | required final FMTOOptions fmtoOptions, 21 | required final MapOptions options, 22 | final Key? key, 23 | final List? floatingTitles, 24 | final Stream>? floatingTitlesStream, 25 | final List children = const [], 26 | final MapController? mapController, 27 | }) { 28 | return FlutterMapWithFMTO._internal( 29 | _FlutterMapMVI(mapController ?? MapController(), fmtoOptions.mapProjectionsCacheSize), 30 | fmtoOptions, 31 | key, 32 | options, 33 | children, 34 | floatingTitles: floatingTitles, 35 | floatingTitlesStream: floatingTitlesStream, 36 | ); 37 | } 38 | 39 | FlutterMapWithFMTO._internal( 40 | final _FlutterMapMVI mapViewInterface, 41 | final FMTOOptions fmtoOptions, 42 | final Key? key, 43 | this._mapOptions, 44 | this._children, { 45 | final List? floatingTitles, 46 | final Stream>? floatingTitlesStream, 47 | }) : super( 48 | mapViewInterface, 49 | fmtoOptions, 50 | key: key, 51 | floatingTitles: floatingTitles, 52 | floatingTitlesStream: floatingTitlesStream, 53 | ); 54 | 55 | @override 56 | Widget buildMapView(final BuildContext context, final _FlutterMapMVI mapViewInterface) { 57 | return FlutterMap( 58 | options: _mapOptions, 59 | children: _children, 60 | mapController: mapViewInterface.mapController, 61 | ); 62 | } 63 | } 64 | 65 | class FloatingMarkerTitlesLayer extends StatelessWidget { 66 | final FMTOOptions fmtoOptions; 67 | final List? floatingTitles; 68 | final Stream>? floatingTitlesStream; 69 | 70 | const FloatingMarkerTitlesLayer({ 71 | required this.fmtoOptions, 72 | super.key, 73 | this.floatingTitles, 74 | this.floatingTitlesStream, 75 | }); 76 | 77 | @override 78 | Widget build(BuildContext context) { 79 | final MapController mapController = MapController.of(context); 80 | final _FlutterMapMVI _mapViewInterface = _FlutterMapMVI(mapController, fmtoOptions.mapProjectionsCacheSize); 81 | return FlutterMapFloatingMarkerTitlesOverlay( 82 | _mapViewInterface, 83 | fmtoOptions, 84 | floatingTitles: floatingTitles, 85 | floatingTitlesStream: floatingTitlesStream, 86 | ); 87 | } 88 | } 89 | 90 | class _FlutterMapMVI extends AbstractCZRMapViewInterface { 91 | MapController mapController; 92 | 93 | _FlutterMapMVI( 94 | this.mapController, 95 | final int projCacheSize, 96 | ) : super(projCacheSize); 97 | 98 | @override 99 | void updateFrom(final AbstractMapViewInterface oldMapInterface) { 100 | super.updateFrom(oldMapInterface); 101 | if (oldMapInterface is _FlutterMapMVI) { 102 | mapController = oldMapInterface.mapController; 103 | } 104 | } 105 | 106 | @override 107 | LatLng getMapViewCenter() { 108 | return mapController.camera.center; 109 | } 110 | 111 | @override 112 | double getMapViewZoom() { 113 | return mapController.camera.zoom; 114 | } 115 | 116 | @override 117 | double getMapViewRotationDegrees() { 118 | return mapController.camera.rotation; 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /flutter_map_floating_marker_titles/pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | async: 5 | dependency: transitive 6 | description: 7 | name: async 8 | sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" 9 | url: "https://pub.dev" 10 | source: hosted 11 | version: "2.11.0" 12 | boolean_selector: 13 | dependency: transitive 14 | description: 15 | name: boolean_selector 16 | sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" 17 | url: "https://pub.dev" 18 | source: hosted 19 | version: "2.1.1" 20 | characters: 21 | dependency: transitive 22 | description: 23 | name: characters 24 | sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" 25 | url: "https://pub.dev" 26 | source: hosted 27 | version: "1.3.0" 28 | charcode: 29 | dependency: transitive 30 | description: 31 | name: charcode 32 | sha256: fb98c0f6d12c920a02ee2d998da788bca066ca5f148492b7085ee23372b12306 33 | url: "https://pub.dev" 34 | source: hosted 35 | version: "1.3.1" 36 | clock: 37 | dependency: transitive 38 | description: 39 | name: clock 40 | sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf 41 | url: "https://pub.dev" 42 | source: hosted 43 | version: "1.1.1" 44 | collection: 45 | dependency: transitive 46 | description: 47 | name: collection 48 | sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf 49 | url: "https://pub.dev" 50 | source: hosted 51 | version: "1.19.0" 52 | dart_earcut: 53 | dependency: transitive 54 | description: 55 | name: dart_earcut 56 | sha256: "41b493147e30a051efb2da1e3acb7f38fe0db60afba24ac1ea5684cee272721e" 57 | url: "https://pub.dev" 58 | source: hosted 59 | version: "1.1.0" 60 | fake_async: 61 | dependency: transitive 62 | description: 63 | name: fake_async 64 | sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" 65 | url: "https://pub.dev" 66 | source: hosted 67 | version: "1.3.1" 68 | flutter: 69 | dependency: "direct main" 70 | description: flutter 71 | source: sdk 72 | version: "0.0.0" 73 | flutter_floating_map_marker_titles_core: 74 | dependency: "direct main" 75 | description: 76 | name: flutter_floating_map_marker_titles_core 77 | sha256: "4ec34fbb4c4ab99c43c1a3a29fd5e3954354e979005dfea2af1da61887d74054" 78 | url: "https://pub.dev" 79 | source: hosted 80 | version: "1.1.0" 81 | flutter_map: 82 | dependency: "direct main" 83 | description: 84 | name: flutter_map 85 | sha256: bbf145e8220531f2f727608c431871c7457f3b134e513543913afd00fdc1cd47 86 | url: "https://pub.dev" 87 | source: hosted 88 | version: "8.1.0" 89 | flutter_test: 90 | dependency: "direct dev" 91 | description: flutter 92 | source: sdk 93 | version: "0.0.0" 94 | http: 95 | dependency: transitive 96 | description: 97 | name: http 98 | sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010 99 | url: "https://pub.dev" 100 | source: hosted 101 | version: "1.2.2" 102 | http_parser: 103 | dependency: transitive 104 | description: 105 | name: http_parser 106 | sha256: e362d639ba3bc07d5a71faebb98cde68c05bfbcfbbb444b60b6f60bb67719185 107 | url: "https://pub.dev" 108 | source: hosted 109 | version: "4.0.0" 110 | intl: 111 | dependency: transitive 112 | description: 113 | name: intl 114 | sha256: "910f85bce16fb5c6f614e117efa303e85a1731bb0081edf3604a2ae6e9a3cc91" 115 | url: "https://pub.dev" 116 | source: hosted 117 | version: "0.17.0" 118 | latlong2: 119 | dependency: "direct main" 120 | description: 121 | name: latlong2 122 | sha256: "98227922caf49e6056f91b6c56945ea1c7b166f28ffcd5fb8e72fc0b453cc8fe" 123 | url: "https://pub.dev" 124 | source: hosted 125 | version: "0.9.1" 126 | leak_tracker: 127 | dependency: transitive 128 | description: 129 | name: leak_tracker 130 | sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06" 131 | url: "https://pub.dev" 132 | source: hosted 133 | version: "10.0.7" 134 | leak_tracker_flutter_testing: 135 | dependency: transitive 136 | description: 137 | name: leak_tracker_flutter_testing 138 | sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379" 139 | url: "https://pub.dev" 140 | source: hosted 141 | version: "3.0.8" 142 | leak_tracker_testing: 143 | dependency: transitive 144 | description: 145 | name: leak_tracker_testing 146 | sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" 147 | url: "https://pub.dev" 148 | source: hosted 149 | version: "3.0.1" 150 | lint: 151 | dependency: "direct dev" 152 | description: 153 | name: lint 154 | sha256: f4bd4dbaa39f4ae8836f2d1275f2f32bc68b3a8cce0a0735dd1f7a601f06682a 155 | url: "https://pub.dev" 156 | source: hosted 157 | version: "2.1.2" 158 | lists: 159 | dependency: transitive 160 | description: 161 | name: lists 162 | sha256: "4ca5c19ae4350de036a7e996cdd1ee39c93ac0a2b840f4915459b7d0a7d4ab27" 163 | url: "https://pub.dev" 164 | source: hosted 165 | version: "1.0.1" 166 | logger: 167 | dependency: transitive 168 | description: 169 | name: logger 170 | sha256: "6bbb9d6f7056729537a4309bda2e74e18e5d9f14302489cc1e93f33b3fe32cac" 171 | url: "https://pub.dev" 172 | source: hosted 173 | version: "2.0.2+1" 174 | matcher: 175 | dependency: transitive 176 | description: 177 | name: matcher 178 | sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb 179 | url: "https://pub.dev" 180 | source: hosted 181 | version: "0.12.16+1" 182 | material_color_utilities: 183 | dependency: transitive 184 | description: 185 | name: material_color_utilities 186 | sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec 187 | url: "https://pub.dev" 188 | source: hosted 189 | version: "0.11.1" 190 | meta: 191 | dependency: transitive 192 | description: 193 | name: meta 194 | sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 195 | url: "https://pub.dev" 196 | source: hosted 197 | version: "1.15.0" 198 | mgrs_dart: 199 | dependency: transitive 200 | description: 201 | name: mgrs_dart 202 | sha256: fb89ae62f05fa0bb90f70c31fc870bcbcfd516c843fb554452ab3396f78586f7 203 | url: "https://pub.dev" 204 | source: hosted 205 | version: "2.0.0" 206 | path: 207 | dependency: transitive 208 | description: 209 | name: path 210 | sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" 211 | url: "https://pub.dev" 212 | source: hosted 213 | version: "1.9.0" 214 | polylabel: 215 | dependency: transitive 216 | description: 217 | name: polylabel 218 | sha256: "41b9099afb2aa6c1730bdd8a0fab1400d287694ec7615dd8516935fa3144214b" 219 | url: "https://pub.dev" 220 | source: hosted 221 | version: "1.0.1" 222 | proj4dart: 223 | dependency: transitive 224 | description: 225 | name: proj4dart 226 | sha256: c8a659ac9b6864aa47c171e78d41bbe6f5e1d7bd790a5814249e6b68bc44324e 227 | url: "https://pub.dev" 228 | source: hosted 229 | version: "2.1.0" 230 | quiver: 231 | dependency: transitive 232 | description: 233 | name: quiver 234 | sha256: "616b691d1c8f5c53b7b39ce3542f6a25308d7900bf689d0210e72a644a10387e" 235 | url: "https://pub.dev" 236 | source: hosted 237 | version: "3.0.1+1" 238 | sky_engine: 239 | dependency: transitive 240 | description: flutter 241 | source: sdk 242 | version: "0.0.0" 243 | source_span: 244 | dependency: transitive 245 | description: 246 | name: source_span 247 | sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" 248 | url: "https://pub.dev" 249 | source: hosted 250 | version: "1.10.0" 251 | stack_trace: 252 | dependency: transitive 253 | description: 254 | name: stack_trace 255 | sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377" 256 | url: "https://pub.dev" 257 | source: hosted 258 | version: "1.12.0" 259 | stream_channel: 260 | dependency: transitive 261 | description: 262 | name: stream_channel 263 | sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 264 | url: "https://pub.dev" 265 | source: hosted 266 | version: "2.1.2" 267 | string_scanner: 268 | dependency: transitive 269 | description: 270 | name: string_scanner 271 | sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3" 272 | url: "https://pub.dev" 273 | source: hosted 274 | version: "1.3.0" 275 | term_glyph: 276 | dependency: transitive 277 | description: 278 | name: term_glyph 279 | sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 280 | url: "https://pub.dev" 281 | source: hosted 282 | version: "1.2.1" 283 | test_api: 284 | dependency: transitive 285 | description: 286 | name: test_api 287 | sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c" 288 | url: "https://pub.dev" 289 | source: hosted 290 | version: "0.7.3" 291 | tuple: 292 | dependency: transitive 293 | description: 294 | name: tuple 295 | sha256: fe3ae4f0dca3f9aac0888e2e0d117b642ce283a82d7017b54136290c0a3b0dd3 296 | url: "https://pub.dev" 297 | source: hosted 298 | version: "2.0.0" 299 | typed_data: 300 | dependency: transitive 301 | description: 302 | name: typed_data 303 | sha256: "53bdf7e979cfbf3e28987552fd72f637e63f3c8724c9e56d9246942dc2fa36ee" 304 | url: "https://pub.dev" 305 | source: hosted 306 | version: "1.3.0" 307 | unicode: 308 | dependency: transitive 309 | description: 310 | name: unicode 311 | sha256: "0f69e46593d65245774d4f17125c6084d2c20b4e473a983f6e21b7d7762218f1" 312 | url: "https://pub.dev" 313 | source: hosted 314 | version: "0.3.1" 315 | vector_math: 316 | dependency: transitive 317 | description: 318 | name: vector_math 319 | sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" 320 | url: "https://pub.dev" 321 | source: hosted 322 | version: "2.1.4" 323 | vm_service: 324 | dependency: transitive 325 | description: 326 | name: vm_service 327 | sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b 328 | url: "https://pub.dev" 329 | source: hosted 330 | version: "14.3.0" 331 | web: 332 | dependency: transitive 333 | description: 334 | name: web 335 | sha256: d43c1d6b787bf0afad444700ae7f4db8827f701bc61c255ac8d328c6f4d52062 336 | url: "https://pub.dev" 337 | source: hosted 338 | version: "1.0.0" 339 | wkt_parser: 340 | dependency: transitive 341 | description: 342 | name: wkt_parser 343 | sha256: "8a555fc60de3116c00aad67891bcab20f81a958e4219cc106e3c037aa3937f13" 344 | url: "https://pub.dev" 345 | source: hosted 346 | version: "2.0.0" 347 | sdks: 348 | dart: ">=3.6.0 <4.0.0" 349 | flutter: ">=3.27.0" 350 | -------------------------------------------------------------------------------- /flutter_map_floating_marker_titles/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: flutter_map_floating_marker_titles 2 | description: Floating Map Marker Titles for flutter_map 3 | version: 1.3.0 4 | repository: https://github.com/androidseb/flutter_map_floating_marker_titles 5 | 6 | environment: 7 | sdk: '>=2.17.1 <4.0.0' 8 | 9 | dependencies: 10 | flutter: 11 | sdk: flutter 12 | 13 | latlong2: ^0.9.0 14 | 15 | flutter_floating_map_marker_titles_core: ^1.1.0 16 | # Uncomment and use this a dependency when working locally 17 | #flutter_floating_map_marker_titles_core: 18 | # path: ../flutter_floating_map_marker_titles_core 19 | flutter_map: ^8.0.0 20 | 21 | dev_dependencies: 22 | flutter_test: 23 | sdk: flutter 24 | lint: 2.1.2 25 | -------------------------------------------------------------------------------- /google_maps_flutter_floating_marker_titles/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | **/ios/Flutter/.last_build_id 26 | .dart_tool/ 27 | .flutter-plugins 28 | .flutter-plugins-dependencies 29 | .packages 30 | .pub-cache/ 31 | .pub/ 32 | /build/ 33 | 34 | # Web related 35 | lib/generated_plugin_registrant.dart 36 | 37 | # Symbolication related 38 | app.*.symbols 39 | 40 | # Obfuscation related 41 | app.*.map.json 42 | 43 | # Android Studio will place build artifacts here 44 | /android/app/debug 45 | /android/app/profile 46 | /android/app/release 47 | -------------------------------------------------------------------------------- /google_maps_flutter_floating_marker_titles/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [1.1.0] - 2024/08/10 2 | 3 | * Updated flutter_floating_map_marker_titles_core dependency to flutter_floating_map_marker_titles_core: ^1.1.0 4 | 5 | ## [1.0.0] - 2023/06/22 6 | 7 | * Updated the semantic version prefix to "officially stable" 1.X.X, because this library has been successful in a production app (see https://mapmarker.app) used by thousands of daily users for several months 8 | * Updated latlong2 dependency to latlong2: ^0.9.0 9 | 10 | ## [0.3.0] - 2022/10/23 11 | 12 | * Improved the logic handling the appearance for higher z-index titles 13 | 14 | ## [0.2.0] - 2022/09/15 15 | 16 | * Added the ability to set floating marker titles with a stream with the `floatingTitlesStream` parameter 17 | * Updated dependencies to use google_maps_flutter: ^2.2.0 18 | 19 | ## [0.1.0] - 2022/09/02 20 | 21 | * Changed the versioning pattern to leave the last digit for minor non-feature-related changes (e.g. library upgrades) 22 | 23 | ## [0.0.6] - 2022/06/11 24 | 25 | Fixed titles being placed incorrectly when the map is rotated. 26 | 27 | ## [0.0.5+5] - 2022/01/09 28 | 29 | Removed web-specific code working around [a bug](https://github.com/flutter/flutter/issues/46683) that has since then been fixed. 30 | 31 | ## [0.0.4+4] - 2021/11/29 32 | 33 | Migrated to null safety. 34 | 35 | ## [0.0.3+3] - 2021/06/01 36 | 37 | Updated dependencies to use google_maps_flutter: ^2.0.4 38 | 39 | ## [0.0.2+2] - 2021/04/01 40 | 41 | Fixed some issues with floating titles data not being updated in some cases, due to a wrong widget state setup. 42 | 43 | ## [0.0.1+1] - 2021/01/30 44 | 45 | This is the initial release of the library. 46 | 47 | * Support for floating map marker titles on google_maps_flutter 48 | -------------------------------------------------------------------------------- /google_maps_flutter_floating_marker_titles/LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2021, androidseb 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /google_maps_flutter_floating_marker_titles/README.md: -------------------------------------------------------------------------------- 1 | # Flutter Map Floating Map Marker Titles 2 | 3 | Floating Map Marker Titles for [google_maps_flutter](https://github.com/flutter/plugins/tree/master/packages/google_maps_flutter/google_maps_flutter), using the core library of the [Flutter Floating Map Marker Titles](https://github.com/androidseb/flutter_map_floating_marker_titles) project. 4 | 5 | ## Code example 6 | 7 | ```dart 8 | GoogleMapWithFMTO( 9 | floatingTitles, 10 | fmtoOptions: fmtoOptions, 11 | // ... other than the 2 above option, this widget takes 12 | // exactly the same props as the GoogleMap widget. 13 | initialCameraPosition: CameraPosition( 14 | target: LatLng(0, 0), 15 | zoom: 13, 16 | ), 17 | ) 18 | ``` 19 | 20 | See the [how-to](https://github.com/androidseb/flutter_map_floating_marker_titles#how-to-use-this-library-in-your-code) section of the main project for more details. 21 | -------------------------------------------------------------------------------- /google_maps_flutter_floating_marker_titles/lib/google_maps_flutter_floating_marker_titles.dart: -------------------------------------------------------------------------------- 1 | library google_maps_flutter_floating_marker_titles; 2 | 3 | import 'package:flutter/foundation.dart'; 4 | import 'package:flutter/gestures.dart'; 5 | import 'package:flutter/widgets.dart'; 6 | import 'package:flutter_floating_map_marker_titles_core/controller/fmto_controller.dart'; 7 | import 'package:flutter_floating_map_marker_titles_core/controller/map_view_interface/abstract_czr_map_view_interface.dart'; 8 | import 'package:flutter_floating_map_marker_titles_core/controller/map_view_interface/abstract_map_view_interface.dart'; 9 | import 'package:flutter_floating_map_marker_titles_core/model/floating_marker_title_info.dart'; 10 | import 'package:flutter_floating_map_marker_titles_core/view/abstract_map_view_wrapper.dart'; 11 | import 'package:flutter/material.dart'; 12 | import 'package:google_maps_flutter/google_maps_flutter.dart'; 13 | import 'package:latlong2/latlong.dart' as latlong; 14 | 15 | class GoogleMapWithFMTO extends AbstractMapViewWrapper<_GoogleMapMVI> { 16 | final CameraPosition _initialCameraPosition; 17 | final MapCreatedCallback? _onMapCreated; 18 | final Set>? _gestureRecognizers; 19 | final bool _compassEnabled; 20 | final bool _mapToolbarEnabled; 21 | final CameraTargetBounds _cameraTargetBounds; 22 | final MapType _mapType; 23 | final MinMaxZoomPreference _minMaxZoomPreference; 24 | final bool _rotateGesturesEnabled; 25 | final bool _scrollGesturesEnabled; 26 | final bool _zoomControlsEnabled; 27 | final bool _zoomGesturesEnabled; 28 | final bool _liteModeEnabled; 29 | final bool _tiltGesturesEnabled; 30 | final EdgeInsets _padding; 31 | final Set? _markers; 32 | final Set? _polygons; 33 | final Set? _polylines; 34 | final Set? _circles; 35 | final VoidCallback? _onCameraMoveStarted; 36 | final CameraPositionCallback? _onCameraMove; 37 | final VoidCallback? _onCameraIdle; 38 | final ArgumentCallback? _onTap; 39 | final ArgumentCallback? _onLongPress; 40 | final bool? _myLocationEnabled; 41 | final bool? _myLocationButtonEnabled; 42 | final bool? _indoorViewEnabled; 43 | final bool? _trafficEnabled; 44 | final bool? _buildingsEnabled; 45 | 46 | factory GoogleMapWithFMTO({ 47 | required final FMTOOptions fmtoOptions, 48 | required final CameraPosition initialCameraPosition, 49 | final Key? key, 50 | final List? floatingTitles, 51 | final Stream>? floatingTitlesStream, 52 | final MapCreatedCallback? onMapCreated, 53 | final Set>? gestureRecognizers, 54 | final bool compassEnabled = true, 55 | final bool mapToolbarEnabled = true, 56 | final CameraTargetBounds cameraTargetBounds = CameraTargetBounds.unbounded, 57 | final MapType mapType = MapType.normal, 58 | final MinMaxZoomPreference minMaxZoomPreference = MinMaxZoomPreference.unbounded, 59 | final bool rotateGesturesEnabled = true, 60 | final bool scrollGesturesEnabled = true, 61 | final bool zoomControlsEnabled = true, 62 | final bool zoomGesturesEnabled = true, 63 | final bool liteModeEnabled = false, 64 | final bool tiltGesturesEnabled = true, 65 | final EdgeInsets padding = const EdgeInsets.all(0), 66 | final Set? markers, 67 | final Set? polygons, 68 | final Set? polylines, 69 | final Set? circles, 70 | final VoidCallback? onCameraMoveStarted, 71 | final CameraPositionCallback? onCameraMove, 72 | final VoidCallback? onCameraIdle, 73 | final ArgumentCallback? onTap, 74 | final ArgumentCallback? onLongPress, 75 | final bool? myLocationEnabled, 76 | final bool? myLocationButtonEnabled, 77 | final bool? indoorViewEnabled, 78 | final bool? trafficEnabled, 79 | final bool? buildingsEnabled, 80 | }) { 81 | return GoogleMapWithFMTO._internal( 82 | _GoogleMapMVI(fmtoOptions.mapProjectionsCacheSize), 83 | fmtoOptions, 84 | key, 85 | initialCameraPosition, 86 | onMapCreated, 87 | gestureRecognizers, 88 | compassEnabled, 89 | mapToolbarEnabled, 90 | cameraTargetBounds, 91 | mapType, 92 | minMaxZoomPreference, 93 | rotateGesturesEnabled, 94 | scrollGesturesEnabled, 95 | zoomControlsEnabled, 96 | zoomGesturesEnabled, 97 | liteModeEnabled, 98 | tiltGesturesEnabled, 99 | padding, 100 | markers, 101 | polygons, 102 | polylines, 103 | circles, 104 | onCameraMoveStarted, 105 | onCameraMove, 106 | onCameraIdle, 107 | onTap, 108 | onLongPress, 109 | myLocationEnabled, 110 | myLocationButtonEnabled, 111 | indoorViewEnabled, 112 | trafficEnabled, 113 | buildingsEnabled, 114 | floatingTitles: floatingTitles, 115 | floatingTitlesStream: floatingTitlesStream, 116 | ); 117 | } 118 | 119 | GoogleMapWithFMTO._internal( 120 | final _GoogleMapMVI mapViewInterface, 121 | final FMTOOptions fmtoOptions, 122 | final Key? key, 123 | this._initialCameraPosition, 124 | this._onMapCreated, 125 | this._gestureRecognizers, 126 | this._compassEnabled, 127 | this._mapToolbarEnabled, 128 | this._cameraTargetBounds, 129 | this._mapType, 130 | this._minMaxZoomPreference, 131 | this._rotateGesturesEnabled, 132 | this._scrollGesturesEnabled, 133 | this._zoomControlsEnabled, 134 | this._zoomGesturesEnabled, 135 | this._liteModeEnabled, 136 | this._tiltGesturesEnabled, 137 | this._padding, 138 | this._markers, 139 | this._polygons, 140 | this._polylines, 141 | this._circles, 142 | this._onCameraMoveStarted, 143 | this._onCameraMove, 144 | this._onCameraIdle, 145 | this._onTap, 146 | this._onLongPress, 147 | this._myLocationEnabled, 148 | this._myLocationButtonEnabled, 149 | this._indoorViewEnabled, 150 | this._trafficEnabled, 151 | this._buildingsEnabled, { 152 | final List? floatingTitles, 153 | final Stream>? floatingTitlesStream, 154 | }) : super( 155 | mapViewInterface, 156 | fmtoOptions, 157 | key: key, 158 | floatingTitles: floatingTitles, 159 | floatingTitlesStream: floatingTitlesStream, 160 | ) { 161 | mapViewInterface.cameraPosition = this._initialCameraPosition; 162 | } 163 | 164 | @override 165 | Widget buildMapView(final BuildContext context, final _GoogleMapMVI mapViewInterface) { 166 | return GoogleMap( 167 | initialCameraPosition: _initialCameraPosition, 168 | onMapCreated: _onMapCreated, 169 | gestureRecognizers: _gestureRecognizers ?? const >{}, 170 | compassEnabled: _compassEnabled, 171 | mapToolbarEnabled: _mapToolbarEnabled, 172 | cameraTargetBounds: _cameraTargetBounds, 173 | mapType: _mapType, 174 | minMaxZoomPreference: _minMaxZoomPreference, 175 | rotateGesturesEnabled: _rotateGesturesEnabled, 176 | scrollGesturesEnabled: _scrollGesturesEnabled, 177 | zoomControlsEnabled: _zoomControlsEnabled, 178 | zoomGesturesEnabled: _zoomGesturesEnabled, 179 | liteModeEnabled: _liteModeEnabled, 180 | tiltGesturesEnabled: _tiltGesturesEnabled, 181 | myLocationEnabled: _myLocationEnabled ?? false, 182 | myLocationButtonEnabled: _myLocationButtonEnabled ?? true, 183 | padding: _padding, 184 | indoorViewEnabled: _indoorViewEnabled ?? false, 185 | trafficEnabled: _trafficEnabled ?? false, 186 | buildingsEnabled: _buildingsEnabled ?? true, 187 | markers: _markers ?? const {}, 188 | polygons: _polygons ?? const {}, 189 | polylines: _polylines ?? const {}, 190 | circles: _circles ?? const {}, 191 | onCameraMoveStarted: _onCameraMoveStarted, 192 | onCameraMove: (final CameraPosition newPosition) { 193 | _onCameraMove?.call(newPosition); 194 | mapViewInterface.cameraPosition = newPosition; 195 | }, 196 | onCameraIdle: _onCameraIdle, 197 | onTap: _onTap, 198 | onLongPress: _onLongPress, 199 | ); 200 | } 201 | } 202 | 203 | class _GoogleMapMVI extends AbstractCZRMapViewInterface { 204 | CameraPosition? cameraPosition; 205 | 206 | _GoogleMapMVI(final int projCacheSize) : super(projCacheSize); 207 | 208 | @override 209 | void updateFrom(final AbstractMapViewInterface oldMapInterface) { 210 | super.updateFrom(oldMapInterface); 211 | if (oldMapInterface is _GoogleMapMVI) { 212 | cameraPosition = oldMapInterface.cameraPosition; 213 | } 214 | } 215 | 216 | @override 217 | latlong.LatLng getMapViewCenter() { 218 | final double? latitude = cameraPosition?.target.latitude; 219 | final double? longitude = cameraPosition?.target.longitude; 220 | if (latitude == null || longitude == null || latitude.isNaN || longitude.isNaN) { 221 | return latlong.LatLng(0, 0); 222 | } 223 | return latlong.LatLng( 224 | latitude, 225 | longitude, 226 | ); 227 | } 228 | 229 | @override 230 | double getMapViewZoom() { 231 | final double? zoom = cameraPosition?.zoom; 232 | if (zoom == null || zoom.isNaN) { 233 | return 1; 234 | } 235 | return zoom; 236 | } 237 | 238 | @override 239 | double getMapViewRotationDegrees() { 240 | final double? bearing = cameraPosition?.bearing; 241 | if (bearing == null || bearing.isNaN) { 242 | return 1; 243 | } 244 | return -bearing; 245 | } 246 | } 247 | -------------------------------------------------------------------------------- /google_maps_flutter_floating_marker_titles/pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | async: 5 | dependency: transitive 6 | description: 7 | name: async 8 | sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" 9 | url: "https://pub.dev" 10 | source: hosted 11 | version: "2.11.0" 12 | boolean_selector: 13 | dependency: transitive 14 | description: 15 | name: boolean_selector 16 | sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" 17 | url: "https://pub.dev" 18 | source: hosted 19 | version: "2.1.1" 20 | characters: 21 | dependency: transitive 22 | description: 23 | name: characters 24 | sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" 25 | url: "https://pub.dev" 26 | source: hosted 27 | version: "1.3.0" 28 | clock: 29 | dependency: transitive 30 | description: 31 | name: clock 32 | sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf 33 | url: "https://pub.dev" 34 | source: hosted 35 | version: "1.1.1" 36 | collection: 37 | dependency: transitive 38 | description: 39 | name: collection 40 | sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf 41 | url: "https://pub.dev" 42 | source: hosted 43 | version: "1.19.0" 44 | fake_async: 45 | dependency: transitive 46 | description: 47 | name: fake_async 48 | sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" 49 | url: "https://pub.dev" 50 | source: hosted 51 | version: "1.3.1" 52 | flutter: 53 | dependency: "direct main" 54 | description: flutter 55 | source: sdk 56 | version: "0.0.0" 57 | flutter_floating_map_marker_titles_core: 58 | dependency: "direct main" 59 | description: 60 | name: flutter_floating_map_marker_titles_core 61 | sha256: "4ec34fbb4c4ab99c43c1a3a29fd5e3954354e979005dfea2af1da61887d74054" 62 | url: "https://pub.dev" 63 | source: hosted 64 | version: "1.1.0" 65 | flutter_plugin_android_lifecycle: 66 | dependency: transitive 67 | description: 68 | name: flutter_plugin_android_lifecycle 69 | sha256: aa36b33c721ac6e889adad07e3c87e6a07b33c28d1f2bc22f2561762cd7d2162 70 | url: "https://pub.dev" 71 | source: hosted 72 | version: "2.0.2" 73 | flutter_test: 74 | dependency: "direct dev" 75 | description: flutter 76 | source: sdk 77 | version: "0.0.0" 78 | google_maps_flutter: 79 | dependency: "direct main" 80 | description: 81 | name: google_maps_flutter 82 | sha256: "07f81e2d26a4dd2664e3beed547c75eb24b780c5c8519cd42bc0137308a1e7f6" 83 | url: "https://pub.dev" 84 | source: hosted 85 | version: "2.2.0" 86 | google_maps_flutter_android: 87 | dependency: transitive 88 | description: 89 | name: google_maps_flutter_android 90 | sha256: "7e0234029f1e2531203ea735e0bf69a0a25a6c6d62a19b7cac756f87062c8f5a" 91 | url: "https://pub.dev" 92 | source: hosted 93 | version: "2.3.0" 94 | google_maps_flutter_ios: 95 | dependency: transitive 96 | description: 97 | name: google_maps_flutter_ios 98 | sha256: "71213e497600e0c67cf7a096f643e58a72ed36334456c32c7ae0a6b4698018df" 99 | url: "https://pub.dev" 100 | source: hosted 101 | version: "2.1.11" 102 | google_maps_flutter_platform_interface: 103 | dependency: transitive 104 | description: 105 | name: google_maps_flutter_platform_interface 106 | sha256: "0a91acaa7ab6a438f428efe49f145a2b48f18ff039301ee2232696e18bf78784" 107 | url: "https://pub.dev" 108 | source: hosted 109 | version: "2.2.2" 110 | intl: 111 | dependency: transitive 112 | description: 113 | name: intl 114 | sha256: "910f85bce16fb5c6f614e117efa303e85a1731bb0081edf3604a2ae6e9a3cc91" 115 | url: "https://pub.dev" 116 | source: hosted 117 | version: "0.17.0" 118 | latlong2: 119 | dependency: "direct main" 120 | description: 121 | name: latlong2 122 | sha256: "18712164760cee655bc790122b0fd8f3d5b3c36da2cb7bf94b68a197fbb0811b" 123 | url: "https://pub.dev" 124 | source: hosted 125 | version: "0.9.0" 126 | leak_tracker: 127 | dependency: transitive 128 | description: 129 | name: leak_tracker 130 | sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06" 131 | url: "https://pub.dev" 132 | source: hosted 133 | version: "10.0.7" 134 | leak_tracker_flutter_testing: 135 | dependency: transitive 136 | description: 137 | name: leak_tracker_flutter_testing 138 | sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379" 139 | url: "https://pub.dev" 140 | source: hosted 141 | version: "3.0.8" 142 | leak_tracker_testing: 143 | dependency: transitive 144 | description: 145 | name: leak_tracker_testing 146 | sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" 147 | url: "https://pub.dev" 148 | source: hosted 149 | version: "3.0.1" 150 | lint: 151 | dependency: "direct dev" 152 | description: 153 | name: lint 154 | sha256: f4bd4dbaa39f4ae8836f2d1275f2f32bc68b3a8cce0a0735dd1f7a601f06682a 155 | url: "https://pub.dev" 156 | source: hosted 157 | version: "2.1.2" 158 | lists: 159 | dependency: transitive 160 | description: 161 | name: lists 162 | sha256: "4ca5c19ae4350de036a7e996cdd1ee39c93ac0a2b840f4915459b7d0a7d4ab27" 163 | url: "https://pub.dev" 164 | source: hosted 165 | version: "1.0.1" 166 | matcher: 167 | dependency: transitive 168 | description: 169 | name: matcher 170 | sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb 171 | url: "https://pub.dev" 172 | source: hosted 173 | version: "0.12.16+1" 174 | material_color_utilities: 175 | dependency: transitive 176 | description: 177 | name: material_color_utilities 178 | sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec 179 | url: "https://pub.dev" 180 | source: hosted 181 | version: "0.11.1" 182 | meta: 183 | dependency: transitive 184 | description: 185 | name: meta 186 | sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 187 | url: "https://pub.dev" 188 | source: hosted 189 | version: "1.15.0" 190 | mgrs_dart: 191 | dependency: transitive 192 | description: 193 | name: mgrs_dart 194 | sha256: fb89ae62f05fa0bb90f70c31fc870bcbcfd516c843fb554452ab3396f78586f7 195 | url: "https://pub.dev" 196 | source: hosted 197 | version: "2.0.0" 198 | path: 199 | dependency: transitive 200 | description: 201 | name: path 202 | sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" 203 | url: "https://pub.dev" 204 | source: hosted 205 | version: "1.9.0" 206 | plugin_platform_interface: 207 | dependency: transitive 208 | description: 209 | name: plugin_platform_interface 210 | sha256: dbf0f707c78beedc9200146ad3cb0ab4d5da13c246336987be6940f026500d3a 211 | url: "https://pub.dev" 212 | source: hosted 213 | version: "2.1.3" 214 | proj4dart: 215 | dependency: transitive 216 | description: 217 | name: proj4dart 218 | sha256: c8a659ac9b6864aa47c171e78d41bbe6f5e1d7bd790a5814249e6b68bc44324e 219 | url: "https://pub.dev" 220 | source: hosted 221 | version: "2.1.0" 222 | sky_engine: 223 | dependency: transitive 224 | description: flutter 225 | source: sdk 226 | version: "0.0.0" 227 | source_span: 228 | dependency: transitive 229 | description: 230 | name: source_span 231 | sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" 232 | url: "https://pub.dev" 233 | source: hosted 234 | version: "1.10.0" 235 | stack_trace: 236 | dependency: transitive 237 | description: 238 | name: stack_trace 239 | sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377" 240 | url: "https://pub.dev" 241 | source: hosted 242 | version: "1.12.0" 243 | stream_channel: 244 | dependency: transitive 245 | description: 246 | name: stream_channel 247 | sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 248 | url: "https://pub.dev" 249 | source: hosted 250 | version: "2.1.2" 251 | stream_transform: 252 | dependency: transitive 253 | description: 254 | name: stream_transform 255 | sha256: ed464977cb26a1f41537e177e190c67223dbd9f4f683489b6ab2e5d211ec564e 256 | url: "https://pub.dev" 257 | source: hosted 258 | version: "2.0.0" 259 | string_scanner: 260 | dependency: transitive 261 | description: 262 | name: string_scanner 263 | sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3" 264 | url: "https://pub.dev" 265 | source: hosted 266 | version: "1.3.0" 267 | term_glyph: 268 | dependency: transitive 269 | description: 270 | name: term_glyph 271 | sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 272 | url: "https://pub.dev" 273 | source: hosted 274 | version: "1.2.1" 275 | test_api: 276 | dependency: transitive 277 | description: 278 | name: test_api 279 | sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c" 280 | url: "https://pub.dev" 281 | source: hosted 282 | version: "0.7.3" 283 | tuple: 284 | dependency: transitive 285 | description: 286 | name: tuple 287 | sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151 288 | url: "https://pub.dev" 289 | source: hosted 290 | version: "2.0.2" 291 | unicode: 292 | dependency: transitive 293 | description: 294 | name: unicode 295 | sha256: "0f69e46593d65245774d4f17125c6084d2c20b4e473a983f6e21b7d7762218f1" 296 | url: "https://pub.dev" 297 | source: hosted 298 | version: "0.3.1" 299 | vector_math: 300 | dependency: transitive 301 | description: 302 | name: vector_math 303 | sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" 304 | url: "https://pub.dev" 305 | source: hosted 306 | version: "2.1.4" 307 | vm_service: 308 | dependency: transitive 309 | description: 310 | name: vm_service 311 | sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b 312 | url: "https://pub.dev" 313 | source: hosted 314 | version: "14.3.0" 315 | wkt_parser: 316 | dependency: transitive 317 | description: 318 | name: wkt_parser 319 | sha256: "8a555fc60de3116c00aad67891bcab20f81a958e4219cc106e3c037aa3937f13" 320 | url: "https://pub.dev" 321 | source: hosted 322 | version: "2.0.0" 323 | sdks: 324 | dart: ">=3.4.0 <4.0.0" 325 | flutter: ">=3.18.0-18.0.pre.54" 326 | -------------------------------------------------------------------------------- /google_maps_flutter_floating_marker_titles/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: google_maps_flutter_floating_marker_titles 2 | description: Floating Map Marker Titles for google_maps_flutter 3 | version: 1.1.0 4 | repository: https://github.com/androidseb/flutter_map_floating_marker_titles 5 | 6 | environment: 7 | sdk: '>=2.17.1 <4.0.0' 8 | 9 | dependencies: 10 | flutter: 11 | sdk: flutter 12 | 13 | latlong2: ^0.9.0 14 | 15 | flutter_floating_map_marker_titles_core: ^1.1.0 16 | # Uncomment and use this a dependency when working locally 17 | #flutter_floating_map_marker_titles_core: 18 | # path: ../flutter_floating_map_marker_titles_core 19 | google_maps_flutter: ^2.2.0 20 | 21 | dev_dependencies: 22 | flutter_test: 23 | sdk: flutter 24 | lint: 2.1.2 25 | -------------------------------------------------------------------------------- /publish_checklist.md: -------------------------------------------------------------------------------- 1 | # Publish checklist 2 | 3 | This is just a cheat sheet for me when I publish a new library version for the following library folders: 4 | * `flutter_floating_map_marker_titles_core` 5 | * `flutter_map_floating_marker_titles` 6 | * `google_maps_flutter_floating_marker_titles` 7 | 8 | These steps are based on the [official documentation](https://flutter.dev/docs/development/packages-and-plugins/developing-packages). 9 | 10 | **Publishing steps:** 11 | 12 | * Branch off main with a temporary branch (e.g. "version/2025.03.04") 13 | * Update the version in `pubspec.yaml` 14 | * Update the changelog file `CHANGELOG.md` documenting the changes of that new version 15 | * Test the publishing with this command: `flutter pub publish --dry-run` 16 | * Actually publish with this command: `flutter pub publish` 17 | * Tag the version with git: 18 | * core library: `git tag -a "core_v1.1.0" -m "core_v1.1.0"` 19 | * flutter_map plugin: `git tag -a "fm_v1.2.0" -m "fm_v1.2.0"` 20 | * google_maps_flutter plugin: `git tag -a "gm_v1.1.0" -m "gm_v1.1.0"` 21 | * Push the tags with: `git push origin --tags` 22 | * Merge the temporary branch back into main 23 | * Delete the temporary branch 24 | -------------------------------------------------------------------------------- /visual_demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androidseb/flutter_map_floating_marker_titles/9834a35c0f0292e1c24dc91acb340e80f71bc388/visual_demo.gif --------------------------------------------------------------------------------