├── .gitignore ├── .pubignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── docs └── debugger_v1.png ├── example ├── .gitignore ├── .metadata ├── README.md ├── android │ ├── .gitignore │ ├── app │ │ ├── build.gradle │ │ └── src │ │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ │ ├── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── kotlin │ │ │ │ └── com │ │ │ │ │ └── example │ │ │ │ │ └── example │ │ │ │ │ └── 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 ├── assets │ ├── brazil_counties.json │ ├── level.geojson │ ├── polygons.json │ ├── rooms.geojson │ ├── south_america.json │ └── workplaces.geojson ├── 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 ├── lib │ └── main.dart ├── pubspec.lock ├── pubspec.yaml └── web │ ├── favicon.png │ ├── icons │ ├── Icon-192.png │ └── Icon-512.png │ ├── index.html │ └── manifest.json ├── lib ├── src │ ├── addon │ │ ├── legend │ │ │ ├── gradient_legend.dart │ │ │ └── legend.dart │ │ └── map_addon.dart │ ├── data │ │ ├── geometries.dart │ │ ├── map_data_source.dart │ │ ├── map_feature.dart │ │ ├── map_layer.dart │ │ ├── property_limits.dart │ │ └── simplified_path.dart │ ├── data_reader.dart │ ├── debugger.dart │ ├── draw_utils.dart │ ├── drawable │ │ ├── circle_marker.dart │ │ ├── drawable.dart │ │ ├── drawable_builder.dart │ │ ├── drawable_feature.dart │ │ ├── drawable_layer.dart │ │ ├── drawable_layer_chunk.dart │ │ ├── drawable_line.dart │ │ ├── drawable_path.dart │ │ ├── drawable_polygon.dart │ │ └── marker.dart │ ├── error.dart │ ├── low_quality_mode.dart │ ├── map_highlight.dart │ ├── map_painter.dart │ ├── simplifier.dart │ ├── theme │ │ ├── map_gradient_theme.dart │ │ ├── map_highlight_theme.dart │ │ ├── map_rule_theme.dart │ │ ├── map_theme.dart │ │ └── map_value_theme.dart │ ├── vector_map.dart │ ├── vector_map_api.dart │ ├── vector_map_controller.dart │ └── vector_map_mode.dart └── vector_map.dart ├── pubspec.lock └── pubspec.yaml /.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 | .dart_tool/ 26 | .flutter-plugins 27 | .flutter-plugins-dependencies 28 | .packages 29 | .pub-cache/ 30 | .pub/ 31 | build/ 32 | 33 | # Android related 34 | **/android/**/gradle-wrapper.jar 35 | **/android/.gradle 36 | **/android/captures/ 37 | **/android/gradlew 38 | **/android/gradlew.bat 39 | **/android/local.properties 40 | **/android/**/GeneratedPluginRegistrant.java 41 | 42 | # iOS/XCode related 43 | **/ios/**/*.mode1v3 44 | **/ios/**/*.mode2v3 45 | **/ios/**/*.moved-aside 46 | **/ios/**/*.pbxuser 47 | **/ios/**/*.perspectivev3 48 | **/ios/**/*sync/ 49 | **/ios/**/.sconsign.dblite 50 | **/ios/**/.tags* 51 | **/ios/**/.vagrant/ 52 | **/ios/**/DerivedData/ 53 | **/ios/**/Icon? 54 | **/ios/**/Pods/ 55 | **/ios/**/.symlinks/ 56 | **/ios/**/profile 57 | **/ios/**/xcuserdata 58 | **/ios/.generated/ 59 | **/ios/Flutter/App.framework 60 | **/ios/Flutter/Flutter.framework 61 | **/ios/Flutter/Flutter.podspec 62 | **/ios/Flutter/Generated.xcconfig 63 | **/ios/Flutter/app.flx 64 | **/ios/Flutter/app.zip 65 | **/ios/Flutter/flutter_assets/ 66 | **/ios/Flutter/flutter_export_environment.sh 67 | **/ios/ServiceDefinitions.json 68 | **/ios/Runner/GeneratedPluginRegistrant.* 69 | 70 | # Exceptions to above rules. 71 | !**/ios/**/default.mode1v3 72 | !**/ios/**/default.mode2v3 73 | !**/ios/**/default.pbxuser 74 | !**/ios/**/default.perspectivev3 75 | -------------------------------------------------------------------------------- /.pubignore: -------------------------------------------------------------------------------- 1 | docs/ 2 | 3 | # Miscellaneous 4 | *.class 5 | *.log 6 | *.pyc 7 | *.swp 8 | .DS_Store 9 | .atom/ 10 | .buildlog/ 11 | .history 12 | .svn/ 13 | 14 | # IntelliJ related 15 | *.iml 16 | *.ipr 17 | *.iws 18 | .idea/ 19 | 20 | # The .vscode folder contains launch configuration and tasks you configure in 21 | # VS Code which you may wish to be included in version control, so this line 22 | # is commented out by default. 23 | #.vscode/ 24 | 25 | # Flutter/Dart/Pub related 26 | **/doc/api/ 27 | .dart_tool/ 28 | .flutter-plugins 29 | .flutter-plugins-dependencies 30 | .packages 31 | .pub-cache/ 32 | .pub/ 33 | build/ 34 | 35 | # Android related 36 | **/android/**/gradle-wrapper.jar 37 | **/android/.gradle 38 | **/android/captures/ 39 | **/android/gradlew 40 | **/android/gradlew.bat 41 | **/android/local.properties 42 | **/android/**/GeneratedPluginRegistrant.java 43 | 44 | # iOS/XCode related 45 | **/ios/**/*.mode1v3 46 | **/ios/**/*.mode2v3 47 | **/ios/**/*.moved-aside 48 | **/ios/**/*.pbxuser 49 | **/ios/**/*.perspectivev3 50 | **/ios/**/*sync/ 51 | **/ios/**/.sconsign.dblite 52 | **/ios/**/.tags* 53 | **/ios/**/.vagrant/ 54 | **/ios/**/DerivedData/ 55 | **/ios/**/Icon? 56 | **/ios/**/Pods/ 57 | **/ios/**/.symlinks/ 58 | **/ios/**/profile 59 | **/ios/**/xcuserdata 60 | **/ios/.generated/ 61 | **/ios/Flutter/App.framework 62 | **/ios/Flutter/Flutter.framework 63 | **/ios/Flutter/Flutter.podspec 64 | **/ios/Flutter/Generated.xcconfig 65 | **/ios/Flutter/app.flx 66 | **/ios/Flutter/app.zip 67 | **/ios/Flutter/flutter_assets/ 68 | **/ios/Flutter/flutter_export_environment.sh 69 | **/ios/ServiceDefinitions.json 70 | **/ios/Runner/GeneratedPluginRegistrant.* 71 | 72 | # Exceptions to above rules. 73 | !**/ios/**/default.mode1v3 74 | !**/ios/**/default.mode2v3 75 | !**/ios/**/default.pbxuser 76 | !**/ios/**/default.perspectivev3 77 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.7.0 2 | 3 | * Multiline reader 4 | 5 | ## 0.6.1+2 6 | 7 | * Updating the README 8 | 9 | ## 0.6.1+1 10 | 11 | * Removing unnecessary imports 12 | 13 | ## 0.6.1 14 | 15 | * Bugfix mobile 16 | * Wrong feature on click listener 17 | 18 | ## 0.6.0 19 | 20 | * Pan and zoom mode 21 | * Placeholder for map without layers 22 | * `MapDataSource.geoJSON` renamed to `MapDataSource.geoJson` 23 | * `contourThickness` parameter moved from `VectorMap` to `VectorMapController` 24 | * `VectorMapController.getLayer` renamed to `VectorMapController.getLayerByIndex` 25 | * New methods 26 | * `VectorMapController.getLayerById` 27 | * `VectorMapController.hasLayerId` 28 | 29 | ## 0.5.0 30 | 31 | * Gradient legend 32 | * `MapLayer.hoverTheme` refactored to `MapLayer.highlightTheme` to be used by addons as well 33 | 34 | ## 0.4.0 35 | 36 | * Debugger 37 | * GeoJSON line geometry reader 38 | * It remains to calculate buffered area to allow the hover to be detected 39 | * Experimental (the API will change) 40 | * Addons 41 | * Gradient legend 42 | 43 | ## 0.3.0 44 | 45 | * Drastic reduction in package size 46 | * Demo moved to separate repository 47 | * Marker 48 | 49 | ## 0.2.0 50 | 51 | * Multiple layers 52 | * GeoJSON point geometry reader 53 | 54 | ## 0.1.0 55 | 56 | * Initial release 57 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Carlos Eduardo Leite de Andrade 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /docs/debugger_v1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/caduandrade/vector_map_flutter/34c10c2835b111d23a85d930ae50769c98d117ff/docs/debugger_v1.png -------------------------------------------------------------------------------- /example/.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 | -------------------------------------------------------------------------------- /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: b1395592de68cc8ac4522094ae59956dd21a91db 8 | channel: stable 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # example 2 | 3 | A new Flutter project. 4 | 5 | ## Getting Started 6 | 7 | This project is a starting point for a Flutter application. 8 | 9 | A few resources to get you started if this is your first Flutter project: 10 | 11 | - [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) 12 | - [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) 13 | 14 | For help getting started with Flutter, view our 15 | [online documentation](https://flutter.dev/docs), which offers tutorials, 16 | samples, guidance on mobile development, and a full API reference. 17 | -------------------------------------------------------------------------------- /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/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | -------------------------------------------------------------------------------- /example/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withReader('UTF-8') { reader -> 5 | localProperties.load(reader) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 12 | } 13 | 14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 15 | if (flutterVersionCode == null) { 16 | flutterVersionCode = '1' 17 | } 18 | 19 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 20 | if (flutterVersionName == null) { 21 | flutterVersionName = '1.0' 22 | } 23 | 24 | apply plugin: 'com.android.application' 25 | apply plugin: 'kotlin-android' 26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 27 | 28 | android { 29 | compileSdkVersion 30 30 | 31 | sourceSets { 32 | main.java.srcDirs += 'src/main/kotlin' 33 | } 34 | 35 | defaultConfig { 36 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 37 | applicationId "com.example.example" 38 | minSdkVersion 16 39 | targetSdkVersion 30 40 | versionCode flutterVersionCode.toInteger() 41 | versionName flutterVersionName 42 | } 43 | 44 | buildTypes { 45 | release { 46 | // TODO: Add your own signing config for the release build. 47 | // Signing with the debug keys for now, so `flutter run --release` works. 48 | signingConfig signingConfigs.debug 49 | } 50 | } 51 | } 52 | 53 | flutter { 54 | source '../..' 55 | } 56 | 57 | dependencies { 58 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 59 | } 60 | -------------------------------------------------------------------------------- /example/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 13 | 17 | 21 | 26 | 30 | 31 | 32 | 33 | 34 | 35 | 37 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /example/android/app/src/main/kotlin/com/example/example/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.example 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() { 6 | } 7 | -------------------------------------------------------------------------------- /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/caduandrade/vector_map_flutter/34c10c2835b111d23a85d930ae50769c98d117ff/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/caduandrade/vector_map_flutter/34c10c2835b111d23a85d930ae50769c98d117ff/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/caduandrade/vector_map_flutter/34c10c2835b111d23a85d930ae50769c98d117ff/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/caduandrade/vector_map_flutter/34c10c2835b111d23a85d930ae50769c98d117ff/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/caduandrade/vector_map_flutter/34c10c2835b111d23a85d930ae50769c98d117ff/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 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.3.50' 3 | repositories { 4 | google() 5 | jcenter() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:4.1.0' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | } 12 | } 13 | 14 | allprojects { 15 | repositories { 16 | google() 17 | jcenter() 18 | } 19 | } 20 | 21 | rootProject.buildDir = '../build' 22 | subprojects { 23 | project.buildDir = "${rootProject.buildDir}/${project.name}" 24 | } 25 | subprojects { 26 | project.evaluationDependsOn(':app') 27 | } 28 | 29 | task clean(type: Delete) { 30 | delete rootProject.buildDir 31 | } 32 | -------------------------------------------------------------------------------- /example/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /example/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 23 08:50:38 CEST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip 7 | -------------------------------------------------------------------------------- /example/android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties") 4 | def properties = new Properties() 5 | 6 | assert localPropertiesFile.exists() 7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } 8 | 9 | def flutterSdkPath = properties.getProperty("flutter.sdk") 10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" 12 | -------------------------------------------------------------------------------- /example/assets/polygons.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "features": [ 4 | { 5 | "type": "Feature", 6 | "properties": { 7 | "Seq": 1, 8 | "Name": "Einstein", 9 | "Rnd": "73", 10 | "Gts": 15000 11 | }, 12 | "geometry": { 13 | "type": "Polygon", 14 | "coordinates": [ 15 | [ 16 | [ 17 | 1, 18 | 5 19 | ], 20 | [ 21 | 2, 22 | 4 23 | ], 24 | [ 25 | 1, 26 | 3 27 | ], 28 | [ 29 | 0, 30 | 4 31 | ], 32 | [ 33 | 1, 34 | 5 35 | ] 36 | ] 37 | ] 38 | } 39 | }, 40 | { 41 | "type": "Feature", 42 | "properties": { 43 | "Seq": 2, 44 | "Name": "Newton", 45 | "Rnd": "92", 46 | "Gts": 7500 47 | }, 48 | "geometry": { 49 | "type": "Polygon", 50 | "coordinates": [ 51 | [ 52 | [ 53 | 2, 54 | 0 55 | ], 56 | [ 57 | 0, 58 | 2 59 | ], 60 | [ 61 | 2, 62 | 4 63 | ], 64 | [ 65 | 4, 66 | 2 67 | ], 68 | [ 69 | 2, 70 | 0 71 | ] 72 | ] 73 | ] 74 | } 75 | }, 76 | { 77 | "type": "Feature", 78 | "properties": { 79 | "Seq": 3, 80 | "Name": "Galileu", 81 | "Rnd": "10", 82 | "Gts": 3000 83 | }, 84 | "geometry": { 85 | "type": "Polygon", 86 | "coordinates": [ 87 | [ 88 | [ 89 | 2, 90 | 6 91 | ], 92 | [ 93 | 3, 94 | 5 95 | ], 96 | [ 97 | 2, 98 | 4 99 | ], 100 | [ 101 | 1, 102 | 5 103 | ], 104 | [ 105 | 2, 106 | 6 107 | ] 108 | ] 109 | ] 110 | } 111 | }, 112 | { 113 | "type": "Feature", 114 | "properties": { 115 | "Seq": 4, 116 | "Name": "Darwin", 117 | "Gts": 15000 118 | }, 119 | "geometry": { 120 | "type": "Polygon", 121 | "coordinates": [ 122 | [ 123 | [ 124 | 4, 125 | 2 126 | ], 127 | [ 128 | 2, 129 | 4 130 | ], 131 | [ 132 | 4, 133 | 6 134 | ], 135 | [ 136 | 6, 137 | 4 138 | ], 139 | [ 140 | 4, 141 | 2 142 | ] 143 | ] 144 | ] 145 | } 146 | }, 147 | { 148 | "type": "Feature", 149 | "properties": { 150 | "Seq": 5, 151 | "Name": "Pasteur", 152 | "Rnd": "77", 153 | "Gts": 17000 154 | }, 155 | "geometry": { 156 | "type": "Polygon", 157 | "coordinates": [ 158 | [ 159 | [ 160 | 4, 161 | 2 162 | ], 163 | [ 164 | 5, 165 | 1 166 | ], 167 | [ 168 | 4, 169 | 0 170 | ], 171 | [ 172 | 3, 173 | 1 174 | ], 175 | [ 176 | 4, 177 | 2 178 | ] 179 | ] 180 | ] 181 | } 182 | }, 183 | { 184 | "type": "Feature", 185 | "properties": { 186 | "Seq": 6, 187 | "Name": "Faraday", 188 | "Rnd": "32", 189 | "Gts": 17500 190 | }, 191 | "geometry": { 192 | "type": "Polygon", 193 | "coordinates": [ 194 | [ 195 | [ 196 | 6, 197 | 0 198 | ], 199 | [ 200 | 4, 201 | 2 202 | ], 203 | [ 204 | 8, 205 | 6 206 | ], 207 | [ 208 | 10, 209 | 4 210 | ], 211 | [ 212 | 6, 213 | 0 214 | ] 215 | ] 216 | ] 217 | } 218 | }, 219 | { 220 | "type": "Feature", 221 | "properties": { 222 | "Seq": 7, 223 | "Name": "Arquimedes", 224 | "Rnd": "87", 225 | "Gts": 25000 226 | }, 227 | "geometry": { 228 | "type": "Polygon", 229 | "coordinates": [ 230 | [ 231 | [ 232 | 6, 233 | 6 234 | ], 235 | [ 236 | 7, 237 | 5 238 | ], 239 | [ 240 | 6, 241 | 4 242 | ], 243 | [ 244 | 5, 245 | 5 246 | ], 247 | [ 248 | 6, 249 | 6 250 | ] 251 | ] 252 | ] 253 | } 254 | }, 255 | { 256 | "type": "Feature", 257 | "properties": { 258 | "Seq": 8, 259 | "Name": "Tesla", 260 | "Rnd": "17", 261 | "Gts": 12500 262 | }, 263 | "geometry": { 264 | "type": "Polygon", 265 | "coordinates": [ 266 | [ 267 | [ 268 | 8, 269 | 2 270 | ], 271 | [ 272 | 9, 273 | 1 274 | ], 275 | [ 276 | 8, 277 | 0 278 | ], 279 | [ 280 | 7, 281 | 1 282 | ], 283 | [ 284 | 8, 285 | 2 286 | ] 287 | ] 288 | ] 289 | } 290 | }, 291 | { 292 | "type": "Feature", 293 | "properties": { 294 | "Seq": 9, 295 | "Name": "Lavoisier", 296 | "Gts": 4000 297 | }, 298 | "geometry": { 299 | "type": "Polygon", 300 | "coordinates": [ 301 | [ 302 | [ 303 | 10, 304 | 0 305 | ], 306 | [ 307 | 8, 308 | 2 309 | ], 310 | [ 311 | 10, 312 | 4 313 | ], 314 | [ 315 | 12, 316 | 2 317 | ], 318 | [ 319 | 10, 320 | 0 321 | ] 322 | ] 323 | ] 324 | } 325 | }, 326 | { 327 | "type": "Feature", 328 | "properties": { 329 | "Seq": 10, 330 | "Name": "Kepler", 331 | "Rnd": "32", 332 | "Gts": 18000 333 | }, 334 | "geometry": { 335 | "type": "Polygon", 336 | "coordinates": [ 337 | [ 338 | [ 339 | 10, 340 | 6 341 | ], 342 | [ 343 | 11, 344 | 5 345 | ], 346 | [ 347 | 10, 348 | 4 349 | ], 350 | [ 351 | 9, 352 | 5 353 | ], 354 | [ 355 | 10, 356 | 6 357 | ] 358 | ] 359 | ] 360 | } 361 | }, 362 | { 363 | "type": "Feature", 364 | "properties": { 365 | "Seq": 11, 366 | "Name": "Turing", 367 | "Rnd": "93", 368 | "Gts": 31400 369 | }, 370 | "geometry": { 371 | "type": "Polygon", 372 | "coordinates": [ 373 | [ 374 | [ 375 | 11, 376 | 5 377 | ], 378 | [ 379 | 12, 380 | 4 381 | ], 382 | [ 383 | 11, 384 | 3 385 | ], 386 | [ 387 | 10, 388 | 4 389 | ], 390 | [ 391 | 11, 392 | 5 393 | ] 394 | ] 395 | ] 396 | } 397 | } 398 | ] 399 | } -------------------------------------------------------------------------------- /example/assets/rooms.geojson: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "name": "rooms", 4 | "features": [ 5 | { 6 | "type": "Feature", 7 | "properties": { 8 | "_id": "LUUID(\"b46f97a8-6827-6e43-8957-a73d4c67641b\")", 9 | "FeatureId": "LUUID(\"a4183b99-3c7a-c746-a158-ed57556582ae\")" 10 | }, 11 | "geometry": { 12 | "type": "MultiPolygon", 13 | "coordinates": [ 14 | [ 15 | [ 16 | [ 17 | 12.9316, 18 | 9.89333 19 | ], 20 | [ 21 | 11.1673, 22 | 9.89333 23 | ], 24 | [ 25 | 11.1673, 26 | 12.7614 27 | ], 28 | [ 29 | 11.1673, 30 | 12.7614 31 | ], 32 | [ 33 | 11.1673, 34 | 14.0811 35 | ], 36 | [ 37 | 12.9315548074708, 38 | 14.0811 39 | ], 40 | [ 41 | 12.9316, 42 | 9.89333 43 | ] 44 | ] 45 | ] 46 | ] 47 | } 48 | }, 49 | { 50 | "type": "Feature", 51 | "properties": { 52 | "_id": "LUUID(\"abd9b8d9-9bae-3c48-acd4-598568126703\")", 53 | "FeatureId": "LUUID(\"245ae597-5917-ab4f-a5b7-2abf9b687b51\")" 54 | }, 55 | "geometry": { 56 | "type": "MultiPolygon", 57 | "coordinates": [ 58 | [ 59 | [ 60 | [ 61 | 12.9315, 62 | 19.1585 63 | ], 64 | [ 65 | 12.5008, 66 | 19.1585 67 | ], 68 | [ 69 | 12.5008, 70 | 19.1358 71 | ], 72 | [ 73 | 12.4685, 74 | 19.1358 75 | ], 76 | [ 77 | 12.4685, 78 | 19.1358 79 | ], 80 | [ 81 | 12.4685, 82 | 19.2038 83 | ], 84 | [ 85 | 12.4685, 86 | 19.2038 87 | ], 88 | [ 89 | 12.4685, 90 | 19.2038 91 | ], 92 | [ 93 | 11.5165, 94 | 19.2038 95 | ], 96 | [ 97 | 11.5165, 98 | 19.2038 99 | ], 100 | [ 101 | 11.5165, 102 | 19.2038 103 | ], 104 | [ 105 | 11.5165, 106 | 19.2038 107 | ], 108 | [ 109 | 11.5165, 110 | 19.2038 111 | ], 112 | [ 113 | 11.5165, 114 | 19.2038 115 | ], 116 | [ 117 | 11.5165, 118 | 19.136 119 | ], 120 | [ 121 | 11.5165, 122 | 19.136 123 | ], 124 | [ 125 | 11.485, 126 | 19.136 127 | ], 128 | [ 129 | 11.485, 130 | 19.136 131 | ], 132 | [ 133 | 11.4843, 134 | 19.1585 135 | ], 136 | [ 137 | 11.4843, 138 | 19.1585 139 | ], 140 | [ 141 | 10.213, 142 | 19.1585 143 | ], 144 | [ 145 | 10.213, 146 | 17.9874 147 | ], 148 | [ 149 | 11.1673, 150 | 17.9874 151 | ], 152 | [ 153 | 11.1673, 154 | 14.0929 155 | ], 156 | [ 157 | 12.9315, 158 | 14.0929 159 | ], 160 | [ 161 | 12.9315, 162 | 19.1585 163 | ] 164 | ] 165 | ] 166 | ] 167 | } 168 | }, 169 | { 170 | "type": "Feature", 171 | "properties": { 172 | "_id": "LUUID(\"b8ba6975-a436-e546-9251-9202ffaf4a03\")", 173 | "FeatureId": "LUUID(\"c7dd7f42-4dec-8442-a0ce-e13ac0b7021a\")" 174 | }, 175 | "geometry": { 176 | "type": "MultiPolygon", 177 | "coordinates": [ 178 | [ 179 | [ 180 | [ 181 | 16.3897, 182 | 17.9442 183 | ], 184 | [ 185 | 16.3897, 186 | 19.1599 187 | ], 188 | [ 189 | 15.2177545029263, 190 | 19.1599 191 | ], 192 | [ 193 | 15.2174, 194 | 19.136 195 | ], 196 | [ 197 | 15.185, 198 | 19.1353 199 | ], 200 | [ 201 | 15.185, 202 | 19.2033 203 | ], 204 | [ 205 | 15.185, 206 | 19.2033 207 | ], 208 | [ 209 | 14.2331, 210 | 19.2033 211 | ], 212 | [ 213 | 14.2331, 214 | 19.2033 215 | ], 216 | [ 217 | 14.2331, 218 | 19.1521887937681 219 | ], 220 | [ 221 | 14.2331, 222 | 19.1357835907336 223 | ], 224 | [ 225 | 14.2008, 226 | 19.1358 227 | ], 228 | [ 229 | 14.2008, 230 | 19.1585 231 | ], 232 | [ 233 | 12.9433, 234 | 19.1585 235 | ], 236 | [ 237 | 12.9434, 238 | 17.0236 239 | ], 240 | [ 241 | 16.4474, 242 | 17.0236 243 | ], 244 | [ 245 | 16.4474, 246 | 17.9244 247 | ], 248 | [ 249 | 16.3008, 250 | 17.9244 251 | ], 252 | [ 253 | 16.3008, 254 | 17.9442 255 | ], 256 | [ 257 | 16.3897, 258 | 17.9442 259 | ] 260 | ] 261 | ] 262 | ] 263 | } 264 | }, 265 | { 266 | "type": "Feature", 267 | "properties": { 268 | "_id": "LUUID(\"4fee597f-e995-9742-b958-739016dd69b9\")", 269 | "FeatureId": "LUUID(\"0f7d3ace-c2f3-a34e-a0ed-734f2c01681d\")" 270 | }, 271 | "geometry": { 272 | "type": "MultiPolygon", 273 | "coordinates": [ 274 | [ 275 | [ 276 | [ 277 | 16.4474, 278 | 17.0117 279 | ], 280 | [ 281 | 16.4474, 282 | 15.1843 283 | ], 284 | [ 285 | 16.3008, 286 | 15.1843 287 | ], 288 | [ 289 | 16.3008, 290 | 15.1646 291 | ], 292 | [ 293 | 16.3882, 294 | 15.1646 295 | ], 296 | [ 297 | 16.3882, 298 | 13.9491140476755 299 | ], 300 | [ 301 | 13.6975, 302 | 13.9491140476755 303 | ], 304 | [ 305 | 13.6974, 306 | 17.0117 307 | ], 308 | [ 309 | 16.4474, 310 | 17.0117 311 | ] 312 | ] 313 | ] 314 | ] 315 | } 316 | } 317 | ] 318 | } -------------------------------------------------------------------------------- /example/assets/workplaces.geojson: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "name": "workplaces", 4 | "features": [ 5 | { 6 | "type": "Feature", 7 | "properties": { 8 | "_id": "LUUID(\"21eabee1-8efb-2043-b974-9ed1f658b1f7\")", 9 | "FeatureId": "LUUID(\"fece8db1-fdab-9180-350c-695608503c3d\")" 10 | }, 11 | "geometry": { 12 | "type": "Point", 13 | "coordinates": [ 14 | 12.2337, 15 | 18.7292 16 | ] 17 | } 18 | }, 19 | { 20 | "type": "Feature", 21 | "properties": { 22 | "_id": "LUUID(\"4d40001f-dce0-bd45-9b45-8eefa83eda99\")", 23 | "FeatureId": "LUUID(\"5e510414-6776-1726-6ad7-5a532039ccd8\")" 24 | }, 25 | "geometry": { 26 | "type": "Point", 27 | "coordinates": [ 28 | 12.2337, 29 | 16.9062 30 | ] 31 | } 32 | }, 33 | { 34 | "type": "Feature", 35 | "properties": { 36 | "_id": "LUUID(\"7785d83b-e932-5148-aa3e-b6ef351d8526\")", 37 | "FeatureId": "LUUID(\"54408dc0-d796-3b19-fbcd-9edd45d6a78c\")" 38 | }, 39 | "geometry": { 40 | "type": "Point", 41 | "coordinates": [ 42 | 12.2337, 43 | 17.5599 44 | ] 45 | } 46 | }, 47 | { 48 | "type": "Feature", 49 | "properties": { 50 | "_id": "LUUID(\"7589175b-b9aa-014c-a50d-2aca849c9c1d\")", 51 | "FeatureId": "LUUID(\"dbc2461e-8e58-7c54-8683-c5aec0419bc1\")" 52 | }, 53 | "geometry": { 54 | "type": "Point", 55 | "coordinates": [ 56 | 11.7612, 57 | 16.9062 58 | ] 59 | } 60 | }, 61 | { 62 | "type": "Feature", 63 | "properties": { 64 | "_id": "LUUID(\"2232a661-ea68-7b44-a256-f43ad6f9f7aa\")", 65 | "FeatureId": "LUUID(\"9e758445-a4a1-13e8-9fa9-333ee641fb16\")" 66 | }, 67 | "geometry": { 68 | "type": "Point", 69 | "coordinates": [ 70 | 11.7612, 71 | 15.7094 72 | ] 73 | } 74 | }, 75 | { 76 | "type": "Feature", 77 | "properties": { 78 | "_id": "LUUID(\"77467e68-70b7-f54d-8dd5-a11a9563515f\")", 79 | "FeatureId": "LUUID(\"c1472bac-3f06-f598-fbaa-1175bcba8feb\")" 80 | }, 81 | "geometry": { 82 | "type": "Point", 83 | "coordinates": [ 84 | 11.7612, 85 | 15.056 86 | ] 87 | } 88 | }, 89 | { 90 | "type": "Feature", 91 | "properties": { 92 | "_id": "LUUID(\"acfd7bbe-91cc-2e42-9777-4c67d27446a7\")", 93 | "FeatureId": "LUUID(\"8c09e269-4ea7-701b-c38a-e3f81241ebfe\")" 94 | }, 95 | "geometry": { 96 | "type": "Point", 97 | "coordinates": [ 98 | 11.7612, 99 | 17.5599 100 | ] 101 | } 102 | }, 103 | { 104 | "type": "Feature", 105 | "properties": { 106 | "_id": "LUUID(\"8018c4f8-3bcc-1043-8911-4f91ebf8bc39\")", 107 | "FeatureId": "LUUID(\"29cb41ea-3ff8-13f0-815b-cb3be9c30ccf\")" 108 | }, 109 | "geometry": { 110 | "type": "Point", 111 | "coordinates": [ 112 | 11.7612, 113 | 18.7292 114 | ] 115 | } 116 | }, 117 | { 118 | "type": "Feature", 119 | "properties": { 120 | "_id": "LUUID(\"885cd8af-53e9-f744-8484-6e62a1eb8645\")", 121 | "FeatureId": "LUUID(\"5eed3d5e-a461-3ec5-e3b7-3d9a0a16f87c\")" 122 | }, 123 | "geometry": { 124 | "type": "Point", 125 | "coordinates": [ 126 | 11.7612, 127 | 12.911 128 | ] 129 | } 130 | }, 131 | { 132 | "type": "Feature", 133 | "properties": { 134 | "_id": "LUUID(\"a65cf58e-9a83-f34c-9099-a5512486879c\")", 135 | "FeatureId": "LUUID(\"a242c63f-7cd2-29fd-df33-8a6fb0c34476\")" 136 | }, 137 | "geometry": { 138 | "type": "Point", 139 | "coordinates": [ 140 | 11.7612, 141 | 12.2575 142 | ] 143 | } 144 | }, 145 | { 146 | "type": "Feature", 147 | "properties": { 148 | "_id": "LUUID(\"061ce968-416d-924d-bd56-5e167e56bd7c\")", 149 | "FeatureId": "LUUID(\"e936d1e8-43da-a9f7-00c5-a221c1a81ebc\")" 150 | }, 151 | "geometry": { 152 | "type": "Point", 153 | "coordinates": [ 154 | 11.7612, 155 | 11.0213 156 | ] 157 | } 158 | }, 159 | { 160 | "type": "Feature", 161 | "properties": { 162 | "_id": "LUUID(\"1d8eee62-6d37-2943-af64-0ba45cdda16b\")", 163 | "FeatureId": "LUUID(\"4ed889aa-6b9e-7f5e-3b86-6cbd936720b1\")" 164 | }, 165 | "geometry": { 166 | "type": "Point", 167 | "coordinates": [ 168 | 11.7612, 169 | 10.3677 170 | ] 171 | } 172 | }, 173 | { 174 | "type": "Feature", 175 | "properties": { 176 | "_id": "LUUID(\"0f458140-020c-a144-a8da-a39467586ce6\")", 177 | "FeatureId": "LUUID(\"2b34cb22-c7c2-abf2-84b2-ee2fa62ca790\")" 178 | }, 179 | "geometry": { 180 | "type": "Point", 181 | "coordinates": [ 182 | 12.2337, 183 | 15.7094 184 | ] 185 | } 186 | }, 187 | { 188 | "type": "Feature", 189 | "properties": { 190 | "_id": "LUUID(\"b5ebce8e-81bb-b84e-b066-addc3776e7c9\")", 191 | "FeatureId": "LUUID(\"f6dc093d-24a7-2ac2-8791-6821e4143803\")" 192 | }, 193 | "geometry": { 194 | "type": "Point", 195 | "coordinates": [ 196 | 12.2337, 197 | 15.056 198 | ] 199 | } 200 | }, 201 | { 202 | "type": "Feature", 203 | "properties": { 204 | "_id": "LUUID(\"c3cc2e79-e0be-ec48-b053-0b538dd01edd\")", 205 | "FeatureId": "LUUID(\"b53821a6-23e4-fce3-db2c-d6748f324c15\")" 206 | }, 207 | "geometry": { 208 | "type": "Point", 209 | "coordinates": [ 210 | 12.2337, 211 | 12.911 212 | ] 213 | } 214 | }, 215 | { 216 | "type": "Feature", 217 | "properties": { 218 | "_id": "LUUID(\"2aa69130-5c3f-5d4d-a094-59c25d0f1071\")", 219 | "FeatureId": "LUUID(\"9bb54400-42ce-478d-4f61-c5a2a749360a\")" 220 | }, 221 | "geometry": { 222 | "type": "Point", 223 | "coordinates": [ 224 | 12.2337, 225 | 12.2575 226 | ] 227 | } 228 | }, 229 | { 230 | "type": "Feature", 231 | "properties": { 232 | "_id": "LUUID(\"81c9b85d-eea6-d24f-920b-5cb0d913b71c\")", 233 | "FeatureId": "LUUID(\"cef3b84b-9854-193b-b57c-63dbf4c4a9dc\")" 234 | }, 235 | "geometry": { 236 | "type": "Point", 237 | "coordinates": [ 238 | 12.2337, 239 | 11.0213 240 | ] 241 | } 242 | }, 243 | { 244 | "type": "Feature", 245 | "properties": { 246 | "_id": "LUUID(\"6050272c-c085-fe47-8518-fb1303e3432e\")", 247 | "FeatureId": "LUUID(\"a0012879-9860-a676-858a-044fce228246\")" 248 | }, 249 | "geometry": { 250 | "type": "Point", 251 | "coordinates": [ 252 | 13.39995, 253 | 18.3654 254 | ] 255 | } 256 | }, 257 | { 258 | "type": "Feature", 259 | "properties": { 260 | "_id": "LUUID(\"a9712fe7-aae4-c343-96a1-1f4f0122b358\")", 261 | "FeatureId": "LUUID(\"eca25869-e0f1-d702-2261-13dfe73b57f4\")" 262 | }, 263 | "geometry": { 264 | "type": "Point", 265 | "coordinates": [ 266 | 13.39995, 267 | 17.7354 268 | ] 269 | } 270 | }, 271 | { 272 | "type": "Feature", 273 | "properties": { 274 | "_id": "LUUID(\"1e327b17-dee2-dc46-87a7-687e226307d5\")", 275 | "FeatureId": "LUUID(\"44037d4b-e9a8-7b2a-1b62-21b164a40aaf\")" 276 | }, 277 | "geometry": { 278 | "type": "Point", 279 | "coordinates": [ 280 | 15.87045, 281 | 18.3654 282 | ] 283 | } 284 | }, 285 | { 286 | "type": "Feature", 287 | "properties": { 288 | "_id": "LUUID(\"084a28b1-1337-9348-97bf-d8955779148a\")", 289 | "FeatureId": "LUUID(\"14b0ab06-0875-27a1-e6fd-2eb30fa6068a\")" 290 | }, 291 | "geometry": { 292 | "type": "Point", 293 | "coordinates": [ 294 | 15.87045, 295 | 17.7354 296 | ] 297 | } 298 | }, 299 | { 300 | "type": "Feature", 301 | "properties": { 302 | "_id": "LUUID(\"d7be478a-3bef-914f-8c5d-f690d2e01ab1\")", 303 | "FeatureId": "LUUID(\"b2d4f955-a472-1e8e-b0fe-aa8d01251f85\")" 304 | }, 305 | "geometry": { 306 | "type": "Point", 307 | "coordinates": [ 308 | 14.70925, 309 | 16.429 310 | ] 311 | } 312 | }, 313 | { 314 | "type": "Feature", 315 | "properties": { 316 | "_id": "LUUID(\"d18a7922-24c2-f140-8e40-986b546045d3\")", 317 | "FeatureId": "LUUID(\"5a41656e-d428-685b-8168-c16738209e31\")" 318 | }, 319 | "geometry": { 320 | "type": "Point", 321 | "coordinates": [ 322 | 14.70515, 323 | 15.9567 324 | ] 325 | } 326 | }, 327 | { 328 | "type": "Feature", 329 | "properties": { 330 | "_id": "LUUID(\"d73ebc93-e548-f44c-8f10-80db9bd9f40f\")", 331 | "FeatureId": "LUUID(\"6b600d53-4f5a-7ed2-662d-0fa5d2be3c0e\")" 332 | }, 333 | "geometry": { 334 | "type": "Point", 335 | "coordinates": [ 336 | 15.36285, 337 | 16.429 338 | ] 339 | } 340 | }, 341 | { 342 | "type": "Feature", 343 | "properties": { 344 | "_id": "LUUID(\"1cc0517a-0d36-824d-83ff-0b5dddccf9ba\")", 345 | "FeatureId": "LUUID(\"ff9ecc0b-5571-abad-5319-69debdad163c\")" 346 | }, 347 | "geometry": { 348 | "type": "Point", 349 | "coordinates": [ 350 | 15.36675, 351 | 15.9567 352 | ] 353 | } 354 | }, 355 | { 356 | "type": "Feature", 357 | "properties": { 358 | "_id": "LUUID(\"0f062f65-8a3d-7a4b-8726-077105dcb11e\")", 359 | "FeatureId": "LUUID(\"0e7ee077-8c51-8431-26f5-db87bd094a5b\")" 360 | }, 361 | "geometry": { 362 | "type": "Point", 363 | "coordinates": [ 364 | 14.70535, 365 | 15.0044 366 | ] 367 | } 368 | }, 369 | { 370 | "type": "Feature", 371 | "properties": { 372 | "_id": "LUUID(\"2547c55d-caf1-9e48-a2e4-57d2ce000017\")", 373 | "FeatureId": "LUUID(\"8b7b01da-cc1e-2b8a-bdac-8c8313b13979\")" 374 | }, 375 | "geometry": { 376 | "type": "Point", 377 | "coordinates": [ 378 | 14.70925, 379 | 14.5319 380 | ] 381 | } 382 | }, 383 | { 384 | "type": "Feature", 385 | "properties": { 386 | "_id": "LUUID(\"274d298c-d5ef-9145-8e15-55eafd318512\")", 387 | "FeatureId": "LUUID(\"d4897836-ec58-0407-acc6-0d963ad2a78a\")" 388 | }, 389 | "geometry": { 390 | "type": "Point", 391 | "coordinates": [ 392 | 15.36285, 393 | 15.0044 394 | ] 395 | } 396 | }, 397 | { 398 | "type": "Feature", 399 | "properties": { 400 | "_id": "LUUID(\"5106da4c-a5ae-4b44-8f08-5cb8838cc40c\")", 401 | "FeatureId": "LUUID(\"5668e21f-4e50-2275-73f7-91bb8417792a\")" 402 | }, 403 | "geometry": { 404 | "type": "Point", 405 | "coordinates": [ 406 | 15.36285, 407 | 14.5319 408 | ] 409 | } 410 | }, 411 | { 412 | "type": "Feature", 413 | "properties": { 414 | "_id": "LUUID(\"bf519e12-8bdb-0f46-b97f-632a20c2d653\")", 415 | "FeatureId": "LUUID(\"93897a49-6fee-2a20-413a-809c687b0853\")" 416 | }, 417 | "geometry": { 418 | "type": "Point", 419 | "coordinates": [ 420 | 12.2337, 421 | 10.3677 422 | ] 423 | } 424 | } 425 | ] 426 | } -------------------------------------------------------------------------------- /example/ios/.gitignore: -------------------------------------------------------------------------------- 1 | *.mode1v3 2 | *.mode2v3 3 | *.moved-aside 4 | *.pbxuser 5 | *.perspectivev3 6 | **/*sync/ 7 | .sconsign.dblite 8 | .tags* 9 | **/.vagrant/ 10 | **/DerivedData/ 11 | Icon? 12 | **/Pods/ 13 | **/.symlinks/ 14 | profile 15 | xcuserdata 16 | **/.generated/ 17 | Flutter/App.framework 18 | Flutter/Flutter.framework 19 | Flutter/Flutter.podspec 20 | Flutter/Generated.xcconfig 21 | Flutter/app.flx 22 | Flutter/app.zip 23 | Flutter/flutter_assets/ 24 | Flutter/flutter_export_environment.sh 25 | ServiceDefinitions.json 26 | Runner/GeneratedPluginRegistrant.* 27 | 28 | # Exceptions to above rules. 29 | !default.mode1v3 30 | !default.mode2v3 31 | !default.pbxuser 32 | !default.perspectivev3 33 | -------------------------------------------------------------------------------- /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 | 8.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 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /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 UIKit 2 | import Flutter 3 | 4 | @UIApplicationMain 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /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/caduandrade/vector_map_flutter/34c10c2835b111d23a85d930ae50769c98d117ff/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/caduandrade/vector_map_flutter/34c10c2835b111d23a85d930ae50769c98d117ff/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/caduandrade/vector_map_flutter/34c10c2835b111d23a85d930ae50769c98d117ff/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/caduandrade/vector_map_flutter/34c10c2835b111d23a85d930ae50769c98d117ff/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/caduandrade/vector_map_flutter/34c10c2835b111d23a85d930ae50769c98d117ff/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/caduandrade/vector_map_flutter/34c10c2835b111d23a85d930ae50769c98d117ff/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/caduandrade/vector_map_flutter/34c10c2835b111d23a85d930ae50769c98d117ff/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/caduandrade/vector_map_flutter/34c10c2835b111d23a85d930ae50769c98d117ff/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/caduandrade/vector_map_flutter/34c10c2835b111d23a85d930ae50769c98d117ff/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/caduandrade/vector_map_flutter/34c10c2835b111d23a85d930ae50769c98d117ff/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/caduandrade/vector_map_flutter/34c10c2835b111d23a85d930ae50769c98d117ff/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/caduandrade/vector_map_flutter/34c10c2835b111d23a85d930ae50769c98d117ff/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/caduandrade/vector_map_flutter/34c10c2835b111d23a85d930ae50769c98d117ff/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/caduandrade/vector_map_flutter/34c10c2835b111d23a85d930ae50769c98d117ff/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/caduandrade/vector_map_flutter/34c10c2835b111d23a85d930ae50769c98d117ff/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/caduandrade/vector_map_flutter/34c10c2835b111d23a85d930ae50769c98d117ff/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/caduandrade/vector_map_flutter/34c10c2835b111d23a85d930ae50769c98d117ff/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/caduandrade/vector_map_flutter/34c10c2835b111d23a85d930ae50769c98d117ff/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 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | example 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(FLUTTER_BUILD_NAME) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UIViewControllerBasedStatusBarAppearance 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /example/ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /example/lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter/services.dart' show rootBundle; 3 | import 'package:vector_map/vector_map.dart'; 4 | 5 | void main() { 6 | runApp(ExampleWidget()); 7 | } 8 | 9 | class ExampleWidget extends StatefulWidget { 10 | @override 11 | State createState() => ExampleState(); 12 | } 13 | 14 | class ExampleState extends State { 15 | VectorMapController? _controller; 16 | MapDebugger debugger = MapDebugger(); 17 | 18 | @override 19 | void initState() { 20 | super.initState(); 21 | //String asset = 'assets/south_america.json'; 22 | //String asset = 'assets/rooms.geojson'; 23 | //String asset = 'assets/brazil_counties.json'; 24 | //String asset = 'assets/polygons.json'; 25 | //rootBundle.loadString(asset).then((geoJson) { 26 | _loadDataSources(); 27 | } 28 | 29 | void _loadDataSources() async { 30 | /* 31 | String roomsGeoJson = await rootBundle.loadString('assets/rooms.geojson'); 32 | MapDataSource rooms = await MapDataSource.geoJson(geoJson: roomsGeoJson); 33 | MapLayer roomsLayer = MapLayer(dataSource: rooms, theme: MapTheme(color: Colors.blue)); 34 | 35 | String levelGeoJson = await rootBundle.loadString('assets/level.geojson'); 36 | MapDataSource level = await MapDataSource.geoJson(geoJson: levelGeoJson); 37 | 38 | MapLayer levelLayer = MapLayer( 39 | dataSource: level, 40 | theme: MapTheme(color: Colors.black, contourColor: Colors.white)); 41 | 42 | String workplacesGeoJson = 43 | await rootBundle.loadString('assets/workplaces.geojson'); 44 | MapDataSource workplaces = 45 | await MapDataSource.geoJson(geoJson: workplacesGeoJson); 46 | MapLayer workplacesLayer = MapLayer( 47 | dataSource: workplaces, 48 | theme: MapTheme(color: Colors.white, contourColor: Colors.white)); 49 | */ 50 | String geoJson = await rootBundle.loadString('assets/polygons.json'); 51 | MapDataSource ds = await MapDataSource.geoJson(geoJson: geoJson); 52 | MapLayer layer = MapLayer(dataSource: ds); 53 | 54 | setState(() { 55 | _controller = 56 | VectorMapController(layers: [layer], delayToRefreshResolution: 0); 57 | //_controller= VectorMapController(layers: [roomsLayer, levelLayer, workplacesLayer]); 58 | }); 59 | } 60 | 61 | @override 62 | Widget build(BuildContext context) { 63 | Widget? content; 64 | if (_controller != null) { 65 | VectorMap map = VectorMap( 66 | controller: _controller, 67 | clickListener: (feature) => print(feature.id), 68 | ); 69 | Widget buttons = SingleChildScrollView( 70 | child: Row(children: [ 71 | _buildFitButton(), 72 | SizedBox(width: 8), 73 | _buildModeButton(), 74 | SizedBox(width: 8), 75 | _buildZoomInButton(), 76 | SizedBox(width: 8), 77 | _buildZoomOutButton() 78 | ])); 79 | 80 | Widget buttonsAndMap = Column(children: [ 81 | Padding(child: buttons, padding: EdgeInsets.only(bottom: 8)), 82 | Expanded(child: map) 83 | ]); 84 | 85 | content = buttonsAndMap; 86 | /* 87 | content = Row(children: [ 88 | Expanded(child: buttonsAndMap), 89 | SizedBox( 90 | child: Padding( 91 | child: MapDebuggerWidget(debugger), 92 | padding: EdgeInsets.all(16)), 93 | width: 200) 94 | ]); 95 | 96 | */ 97 | } else { 98 | content = Center(child: Text('Loading...')); 99 | } 100 | 101 | return MaterialApp( 102 | debugShowCheckedModeBanner: false, 103 | theme: ThemeData(scaffoldBackgroundColor: Colors.blue[800]!), 104 | home: Scaffold( 105 | body: SafeArea( 106 | child: Padding(child: content, padding: EdgeInsets.all(8))))); 107 | } 108 | 109 | Widget _buildFitButton() { 110 | return ElevatedButton(child: Text('Fit'), onPressed: _onFit); 111 | } 112 | 113 | void _onFit() { 114 | _controller?.fit(); 115 | } 116 | 117 | Widget _buildModeButton() { 118 | return ElevatedButton(child: Text('Change mode'), onPressed: _onMode); 119 | } 120 | 121 | void _onMode() { 122 | VectorMapMode mode = _controller!.mode == VectorMapMode.autoFit 123 | ? VectorMapMode.panAndZoom 124 | : VectorMapMode.autoFit; 125 | _controller!.mode = mode; 126 | } 127 | 128 | Widget _buildZoomInButton() { 129 | return ElevatedButton(child: Text('Zoom in'), onPressed: _onZoomIn); 130 | } 131 | 132 | void _onZoomIn() { 133 | _controller!.zoomOnCenter(true); 134 | } 135 | 136 | Widget _buildZoomOutButton() { 137 | return ElevatedButton(child: Text('Zoom out'), onPressed: _onZoomOut); 138 | } 139 | 140 | void _onZoomOut() { 141 | _controller!.zoomOnCenter(false); 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /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 | url: "https://pub.dartlang.org" 9 | source: hosted 10 | version: "2.8.2" 11 | boolean_selector: 12 | dependency: transitive 13 | description: 14 | name: boolean_selector 15 | url: "https://pub.dartlang.org" 16 | source: hosted 17 | version: "2.1.0" 18 | characters: 19 | dependency: transitive 20 | description: 21 | name: characters 22 | url: "https://pub.dartlang.org" 23 | source: hosted 24 | version: "1.2.0" 25 | charcode: 26 | dependency: transitive 27 | description: 28 | name: charcode 29 | url: "https://pub.dartlang.org" 30 | source: hosted 31 | version: "1.3.1" 32 | clock: 33 | dependency: transitive 34 | description: 35 | name: clock 36 | url: "https://pub.dartlang.org" 37 | source: hosted 38 | version: "1.1.0" 39 | collection: 40 | dependency: transitive 41 | description: 42 | name: collection 43 | url: "https://pub.dartlang.org" 44 | source: hosted 45 | version: "1.15.0" 46 | fake_async: 47 | dependency: transitive 48 | description: 49 | name: fake_async 50 | url: "https://pub.dartlang.org" 51 | source: hosted 52 | version: "1.2.0" 53 | flutter: 54 | dependency: "direct main" 55 | description: flutter 56 | source: sdk 57 | version: "0.0.0" 58 | flutter_test: 59 | dependency: "direct dev" 60 | description: flutter 61 | source: sdk 62 | version: "0.0.0" 63 | matcher: 64 | dependency: transitive 65 | description: 66 | name: matcher 67 | url: "https://pub.dartlang.org" 68 | source: hosted 69 | version: "0.12.11" 70 | material_color_utilities: 71 | dependency: transitive 72 | description: 73 | name: material_color_utilities 74 | url: "https://pub.dartlang.org" 75 | source: hosted 76 | version: "0.1.3" 77 | meta: 78 | dependency: transitive 79 | description: 80 | name: meta 81 | url: "https://pub.dartlang.org" 82 | source: hosted 83 | version: "1.7.0" 84 | path: 85 | dependency: transitive 86 | description: 87 | name: path 88 | url: "https://pub.dartlang.org" 89 | source: hosted 90 | version: "1.8.0" 91 | sky_engine: 92 | dependency: transitive 93 | description: flutter 94 | source: sdk 95 | version: "0.0.99" 96 | source_span: 97 | dependency: transitive 98 | description: 99 | name: source_span 100 | url: "https://pub.dartlang.org" 101 | source: hosted 102 | version: "1.8.1" 103 | stack_trace: 104 | dependency: transitive 105 | description: 106 | name: stack_trace 107 | url: "https://pub.dartlang.org" 108 | source: hosted 109 | version: "1.10.0" 110 | stream_channel: 111 | dependency: transitive 112 | description: 113 | name: stream_channel 114 | url: "https://pub.dartlang.org" 115 | source: hosted 116 | version: "2.1.0" 117 | string_scanner: 118 | dependency: transitive 119 | description: 120 | name: string_scanner 121 | url: "https://pub.dartlang.org" 122 | source: hosted 123 | version: "1.1.0" 124 | term_glyph: 125 | dependency: transitive 126 | description: 127 | name: term_glyph 128 | url: "https://pub.dartlang.org" 129 | source: hosted 130 | version: "1.2.0" 131 | test_api: 132 | dependency: transitive 133 | description: 134 | name: test_api 135 | url: "https://pub.dartlang.org" 136 | source: hosted 137 | version: "0.4.8" 138 | typed_data: 139 | dependency: transitive 140 | description: 141 | name: typed_data 142 | url: "https://pub.dartlang.org" 143 | source: hosted 144 | version: "1.3.0" 145 | vector_map: 146 | dependency: "direct main" 147 | description: 148 | path: ".." 149 | relative: true 150 | source: path 151 | version: "0.6.1+2" 152 | vector_math: 153 | dependency: transitive 154 | description: 155 | name: vector_math 156 | url: "https://pub.dartlang.org" 157 | source: hosted 158 | version: "2.1.1" 159 | sdks: 160 | dart: ">=2.14.0 <3.0.0" 161 | flutter: ">=1.17.0" 162 | -------------------------------------------------------------------------------- /example/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: example 2 | description: A new Flutter project. 3 | 4 | # The following line prevents the package from being accidentally published to 5 | # pub.dev using `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 | # The following defines the version and build number for your application. 9 | # A version number is three numbers separated by dots, like 1.2.43 10 | # followed by an optional build number separated by a +. 11 | # Both the version and the builder number may be overridden in flutter 12 | # build by specifying --build-name and --build-number, respectively. 13 | # In Android, build-name is used as versionName while build-number used as versionCode. 14 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning 15 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. 16 | # Read more about iOS versioning at 17 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html 18 | version: 1.0.0+1 19 | 20 | environment: 21 | sdk: '>=2.12.0 <3.0.0' 22 | 23 | dependencies: 24 | flutter: 25 | sdk: flutter 26 | vector_map: 27 | path: ../ 28 | 29 | dev_dependencies: 30 | flutter_test: 31 | sdk: flutter 32 | 33 | # For information on the generic Dart part of this file, see the 34 | # following page: https://dart.dev/tools/pub/pubspec 35 | 36 | # The following section is specific to Flutter. 37 | flutter: 38 | 39 | # The following line ensures that the Material Icons font is 40 | # included with your application, so that you can use the icons in 41 | # the material Icons class. 42 | uses-material-design: true 43 | 44 | # To add assets to your application, add an assets section, like this: 45 | assets: 46 | - assets/south_america.json 47 | - assets/brazil_counties.json 48 | - assets/polygons.json 49 | - assets/workplaces.geojson 50 | - assets/rooms.geojson 51 | - assets/level.geojson 52 | 53 | # An image asset can refer to one or more resolution-specific "variants", see 54 | # https://flutter.dev/assets-and-images/#resolution-aware. 55 | 56 | # For details regarding adding assets from package dependencies, see 57 | # https://flutter.dev/assets-and-images/#from-packages 58 | 59 | # To add custom fonts to your application, add a fonts section here, 60 | # in this "flutter" section. Each entry in this list should have a 61 | # "family" key with the font family name, and a "fonts" key with a 62 | # list giving the asset and other descriptors for the font. For 63 | # example: 64 | # fonts: 65 | # - family: Schyler 66 | # fonts: 67 | # - asset: fonts/Schyler-Regular.ttf 68 | # - asset: fonts/Schyler-Italic.ttf 69 | # style: italic 70 | # - family: Trajan Pro 71 | # fonts: 72 | # - asset: fonts/TrajanPro.ttf 73 | # - asset: fonts/TrajanPro_Bold.ttf 74 | # weight: 700 75 | # 76 | # For details regarding fonts from package dependencies, 77 | # see https://flutter.dev/custom-fonts/#from-packages 78 | -------------------------------------------------------------------------------- /example/web/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/caduandrade/vector_map_flutter/34c10c2835b111d23a85d930ae50769c98d117ff/example/web/favicon.png -------------------------------------------------------------------------------- /example/web/icons/Icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/caduandrade/vector_map_flutter/34c10c2835b111d23a85d930ae50769c98d117ff/example/web/icons/Icon-192.png -------------------------------------------------------------------------------- /example/web/icons/Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/caduandrade/vector_map_flutter/34c10c2835b111d23a85d930ae50769c98d117ff/example/web/icons/Icon-512.png -------------------------------------------------------------------------------- /example/web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | example 30 | 31 | 32 | 33 | 36 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /example/web/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example", 3 | "short_name": "example", 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 | } 24 | -------------------------------------------------------------------------------- /lib/src/addon/legend/legend.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/widgets.dart'; 2 | import 'package:vector_map/src/addon/map_addon.dart'; 3 | import 'package:vector_map/src/data/map_layer.dart'; 4 | 5 | /// Abstract legend 6 | /// 7 | /// Allows customize [padding], [margin] and [decoration] 8 | abstract class Legend extends MapAddon { 9 | /// Builds a legend 10 | Legend( 11 | {required this.layer, 12 | EdgeInsetsGeometry? padding, 13 | EdgeInsetsGeometry? margin, 14 | Decoration? decoration}) 15 | : super(padding: padding, decoration: decoration, margin: margin); 16 | final MapLayer layer; 17 | } 18 | -------------------------------------------------------------------------------- /lib/src/addon/map_addon.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/widgets.dart'; 2 | import 'package:vector_map/src/data/map_feature.dart'; 3 | import 'package:vector_map/src/vector_map_api.dart'; 4 | 5 | /// Allows to add components on the [VectorMap] 6 | abstract class MapAddon { 7 | MapAddon({this.padding, this.decoration, this.margin}); 8 | 9 | /// Empty space to inscribe inside the [decoration]. The [MapAddon] widget, if any, is 10 | /// placed inside this padding. 11 | /// 12 | /// This padding is in addition to any padding inherent in the [decoration]; 13 | /// see [Decoration.padding]. 14 | final EdgeInsetsGeometry? padding; 15 | 16 | /// The decoration to paint behind the [MapAddon] widget. 17 | final Decoration? decoration; 18 | 19 | /// Empty space to surround the [decoration] and [MapAddon] widget. 20 | final EdgeInsetsGeometry? margin; 21 | 22 | /// Builds the [Widget] for this addon 23 | Widget buildWidget( 24 | {required BuildContext context, 25 | required VectorMapApi mapApi, 26 | MapFeature? hover}); 27 | } 28 | -------------------------------------------------------------------------------- /lib/src/data/geometries.dart: -------------------------------------------------------------------------------- 1 | import 'dart:collection'; 2 | import 'dart:math' as math; 3 | 4 | import 'package:flutter/rendering.dart'; 5 | import 'package:vector_map/src/data/simplified_path.dart'; 6 | import 'package:vector_map/src/simplifier.dart'; 7 | 8 | /// Abstract map geometry. 9 | mixin MapGeometry { 10 | Rect get bounds; 11 | 12 | int get pointsCount; 13 | } 14 | 15 | /// Point geometry. 16 | class MapPoint extends Offset with MapGeometry { 17 | MapPoint(double x, double y) : super(x, y); 18 | 19 | double get x => dx; 20 | 21 | double get y => dy; 22 | 23 | @override 24 | String toString() { 25 | return 'MapPoint{x: $x, y: $y}'; 26 | } 27 | 28 | @override 29 | Rect get bounds => Rect.fromLTWH(x, y, 0, 0); 30 | 31 | @override 32 | int get pointsCount => 1; 33 | } 34 | 35 | /// Line string geometry. 36 | class MapLineString with MapGeometry { 37 | final UnmodifiableListView points; 38 | final Rect bounds; 39 | 40 | MapLineString._(this.points, this.bounds); 41 | 42 | factory MapLineString.coordinates(List coordinates) { 43 | List points = []; 44 | for (int i = 0; i < coordinates.length; i = i + 2) { 45 | if (i < coordinates.length - 1) { 46 | double x = coordinates[i]; 47 | double y = coordinates[i + 1]; 48 | points.add(MapPoint(x, y)); 49 | } 50 | } 51 | return MapLineString(points); 52 | } 53 | 54 | factory MapLineString(List points) { 55 | //TODO exception for insufficient number of points? 56 | MapPoint first = points.first; 57 | double left = first.dx; 58 | double right = first.dx; 59 | double top = first.dy; 60 | double bottom = first.dy; 61 | 62 | for (int i = 1; i < points.length; i++) { 63 | MapPoint point = points[i]; 64 | left = math.min(point.dx, left); 65 | right = math.max(point.dx, right); 66 | bottom = math.max(point.dy, bottom); 67 | top = math.min(point.dy, top); 68 | } 69 | Rect bounds = Rect.fromLTRB(left, top, right, bottom); 70 | return MapLineString._(UnmodifiableListView(points), bounds); 71 | } 72 | 73 | @override 74 | int get pointsCount => points.length; 75 | 76 | SimplifiedPath toSimplifiedPath( 77 | Matrix4 worldToCanvas, GeometrySimplifier simplifier) { 78 | Path path = Path(); 79 | List simplifiedPoints = 80 | simplifier.simplify(worldToCanvas, points); 81 | for (int i = 0; i < simplifiedPoints.length; i++) { 82 | MapPoint point = simplifiedPoints[i]; 83 | if (i == 0) { 84 | path.moveTo(point.dx, point.dy); 85 | } else { 86 | path.lineTo(point.dx, point.dy); 87 | } 88 | } 89 | return SimplifiedPath(path, simplifiedPoints.length); 90 | } 91 | } 92 | 93 | /// Multi line string geometry. 94 | class MapMultiLineString with MapGeometry { 95 | final UnmodifiableListView linesString; 96 | final Rect bounds; 97 | 98 | MapMultiLineString._(this.linesString, this.bounds); 99 | 100 | factory MapMultiLineString(List linesString) { 101 | Rect bounds = linesString.first.bounds; 102 | for (int i = 1; i < linesString.length; i++) { 103 | bounds = bounds.expandToInclude(linesString[i].bounds); 104 | } 105 | return MapMultiLineString._( 106 | UnmodifiableListView(linesString), bounds); 107 | } 108 | 109 | @override 110 | int get pointsCount => _getPointsCount(); 111 | 112 | /// Gets the count of points. 113 | int _getPointsCount() { 114 | int count = 0; 115 | for (MapLineString line in linesString) { 116 | count += line.pointsCount; 117 | } 118 | return count; 119 | } 120 | } 121 | 122 | /// Line ring geometry. 123 | class MapLinearRing with MapGeometry { 124 | final UnmodifiableListView points; 125 | final Rect bounds; 126 | 127 | MapLinearRing._(this.points, this.bounds); 128 | 129 | factory MapLinearRing.coordinates(List coordinates) { 130 | List points = []; 131 | for (int i = 0; i < coordinates.length; i = i + 2) { 132 | if (i < coordinates.length - 1) { 133 | double x = coordinates[i]; 134 | double y = coordinates[i + 1]; 135 | points.add(MapPoint(x, y)); 136 | } 137 | } 138 | return MapLinearRing(points); 139 | } 140 | 141 | factory MapLinearRing(List points) { 142 | //TODO exception for insufficient number of points? 143 | MapPoint first = points.first; 144 | double left = first.dx; 145 | double right = first.dx; 146 | double top = first.dy; 147 | double bottom = first.dy; 148 | 149 | for (int i = 1; i < points.length; i++) { 150 | MapPoint point = points[i]; 151 | left = math.min(point.dx, left); 152 | right = math.max(point.dx, right); 153 | bottom = math.max(point.dy, bottom); 154 | top = math.min(point.dy, top); 155 | } 156 | Rect bounds = Rect.fromLTRB(left, top, right, bottom); 157 | return MapLinearRing._(UnmodifiableListView(points), bounds); 158 | } 159 | 160 | @override 161 | int get pointsCount => points.length; 162 | 163 | SimplifiedPath toSimplifiedPath( 164 | Matrix4 worldToCanvas, GeometrySimplifier simplifier) { 165 | Path path = Path(); 166 | List simplifiedPoints = 167 | simplifier.simplify(worldToCanvas, points); 168 | for (int i = 0; i < simplifiedPoints.length; i++) { 169 | MapPoint point = simplifiedPoints[i]; 170 | if (i == 0) { 171 | path.moveTo(point.dx, point.dy); 172 | } else { 173 | path.lineTo(point.dx, point.dy); 174 | } 175 | } 176 | path.close(); 177 | return SimplifiedPath(path, simplifiedPoints.length); 178 | } 179 | } 180 | 181 | /// Polygon geometry. 182 | class MapPolygon with MapGeometry { 183 | final MapLinearRing externalRing; 184 | final UnmodifiableListView internalRings; 185 | final Rect bounds; 186 | 187 | MapPolygon._(this.externalRing, this.internalRings, this.bounds); 188 | 189 | factory MapPolygon.coordinates(List coordinates) { 190 | List externalPoints = []; 191 | List internalRings = []; 192 | List points = []; 193 | for (int i = 0; i < coordinates.length; i = i + 2) { 194 | if (i < coordinates.length - 1) { 195 | double x = coordinates[i]; 196 | double y = coordinates[i + 1]; 197 | points.add(MapPoint(x, y)); 198 | if (points.length >= 3) { 199 | if (points.first.x == x && points.first.y == y) { 200 | // closing ring 201 | if (externalPoints.length == 0) { 202 | externalPoints = points; 203 | } else { 204 | internalRings.add(MapLinearRing(points)); 205 | } 206 | points = []; 207 | } 208 | } 209 | } 210 | } 211 | return MapPolygon(MapLinearRing(externalPoints), internalRings); 212 | } 213 | 214 | factory MapPolygon( 215 | MapLinearRing externalRing, List? internalRings) { 216 | Rect bounds = externalRing.bounds; 217 | 218 | List internal = internalRings != null ? internalRings : []; 219 | for (MapLinearRing linearRing in internal) { 220 | bounds = bounds.expandToInclude(linearRing.bounds); 221 | } 222 | return MapPolygon._( 223 | externalRing, UnmodifiableListView(internal), bounds); 224 | } 225 | 226 | @override 227 | int get pointsCount => _getPointsCount(); 228 | 229 | int _getPointsCount() { 230 | int count = externalRing.pointsCount; 231 | for (MapLinearRing ring in internalRings) { 232 | count += ring.pointsCount; 233 | } 234 | return count; 235 | } 236 | 237 | SimplifiedPath toSimplifiedPath( 238 | Matrix4 worldToCanvas, GeometrySimplifier simplifier) { 239 | Path path = Path()..fillType = PathFillType.evenOdd; 240 | 241 | SimplifiedPath simplifiedPath = 242 | externalRing.toSimplifiedPath(worldToCanvas, simplifier); 243 | int pointsCount = simplifiedPath.pointsCount; 244 | path.addPath(simplifiedPath.path, Offset.zero); 245 | for (MapLinearRing ring in internalRings) { 246 | simplifiedPath = ring.toSimplifiedPath(worldToCanvas, simplifier); 247 | pointsCount += simplifiedPath.pointsCount; 248 | path.addPath(simplifiedPath.path, Offset.zero); 249 | } 250 | return SimplifiedPath(path, pointsCount); 251 | } 252 | } 253 | 254 | /// Multi polygon geometry. 255 | class MapMultiPolygon with MapGeometry { 256 | final UnmodifiableListView polygons; 257 | final Rect bounds; 258 | 259 | MapMultiPolygon._(this.polygons, this.bounds); 260 | 261 | factory MapMultiPolygon(List polygons) { 262 | Rect bounds = polygons.first.bounds; 263 | for (int i = 1; i < polygons.length; i++) { 264 | bounds = bounds.expandToInclude(polygons[i].bounds); 265 | } 266 | return MapMultiPolygon._( 267 | UnmodifiableListView(polygons), bounds); 268 | } 269 | 270 | @override 271 | int get pointsCount => _getPointsCount(); 272 | 273 | /// Gets the count of points. 274 | int _getPointsCount() { 275 | int count = 0; 276 | for (MapPolygon polygon in polygons) { 277 | count += polygon.pointsCount; 278 | } 279 | return count; 280 | } 281 | } 282 | -------------------------------------------------------------------------------- /lib/src/data/map_data_source.dart: -------------------------------------------------------------------------------- 1 | import 'dart:collection'; 2 | import 'dart:ui'; 3 | 4 | import 'package:vector_map/src/data/geometries.dart'; 5 | import 'package:vector_map/src/data/map_feature.dart'; 6 | import 'package:vector_map/src/data/property_limits.dart'; 7 | import 'package:vector_map/src/data_reader.dart'; 8 | 9 | /// [VectorMap] data source. 10 | class MapDataSource { 11 | MapDataSource._( 12 | {required this.features, 13 | required this.bounds, 14 | required this.pointsCount, 15 | Map? limits}) 16 | : this._limits = limits; 17 | 18 | final UnmodifiableMapView features; 19 | final Rect? bounds; 20 | final int pointsCount; 21 | final Map? _limits; 22 | 23 | /// Create a [MapDataSource] from a list of [MapFeature]. 24 | static MapDataSource fromFeatures(List features) { 25 | Rect? boundsFromGeometry; 26 | int pointsCount = 0; 27 | if (features.isNotEmpty) { 28 | boundsFromGeometry = features.first.geometry.bounds; 29 | } 30 | Map limits = Map(); 31 | Map featuresMap = Map(); 32 | for (MapFeature feature in features) { 33 | featuresMap[feature.id] = feature; 34 | pointsCount += feature.geometry.pointsCount; 35 | if (boundsFromGeometry == null) { 36 | boundsFromGeometry = feature.geometry.bounds; 37 | } else { 38 | boundsFromGeometry = 39 | boundsFromGeometry.expandToInclude(feature.geometry.bounds); 40 | } 41 | if (feature.properties != null) { 42 | feature.properties!.entries.forEach((entry) { 43 | dynamic value = entry.value; 44 | double? doubleValue; 45 | if (value is int) { 46 | doubleValue = value.toDouble(); 47 | } else if (value is double) { 48 | doubleValue = value; 49 | } 50 | if (doubleValue != null) { 51 | String key = entry.key; 52 | if (limits.containsKey(key)) { 53 | PropertyLimits propertyLimits = limits[key]!; 54 | propertyLimits.expand(doubleValue); 55 | } else { 56 | limits[key] = PropertyLimits(doubleValue); 57 | } 58 | } 59 | }); 60 | } 61 | } 62 | 63 | return MapDataSource._( 64 | features: UnmodifiableMapView(featuresMap), 65 | bounds: boundsFromGeometry, 66 | pointsCount: pointsCount, 67 | limits: limits.isNotEmpty ? limits : null); 68 | } 69 | 70 | /// Loads a [MapDataSource] from GeoJSON. 71 | /// 72 | /// Geometries are always loaded. 73 | /// The [keys] argument defines which properties must be loaded. 74 | /// The [parseToNumber] argument defines which properties will have 75 | /// numeric values in quotes parsed to numbers. 76 | static Future geoJson( 77 | {required String geoJson, 78 | String? labelKey, 79 | List? keys, 80 | List? parseToNumber, 81 | String? colorKey, 82 | ColorValueFormat colorValueFormat = ColorValueFormat.hex}) async { 83 | MapFeatureReader reader = MapFeatureReader( 84 | labelKey: labelKey, 85 | keys: keys != null ? keys.toSet() : null, 86 | parseToNumber: parseToNumber != null ? parseToNumber.toSet() : null, 87 | colorKey: colorKey, 88 | colorValueFormat: colorValueFormat); 89 | 90 | List features = await reader.read(geoJson); 91 | return fromFeatures(features); 92 | } 93 | 94 | /// Loads a [MapDataSource] from geometries. 95 | /// [MapDataSource] features will have no properties. 96 | factory MapDataSource.geometries(List geometries) { 97 | Rect? boundsFromGeometry; 98 | int pointsCount = 0; 99 | Map featuresMap = Map(); 100 | int id = 1; 101 | for (MapGeometry geometry in geometries) { 102 | featuresMap[id] = MapFeature(id: id, geometry: geometry); 103 | pointsCount += geometry.pointsCount; 104 | if (boundsFromGeometry == null) { 105 | boundsFromGeometry = geometry.bounds; 106 | } else { 107 | boundsFromGeometry = 108 | boundsFromGeometry.expandToInclude(geometry.bounds); 109 | } 110 | id++; 111 | } 112 | 113 | return MapDataSource._( 114 | features: UnmodifiableMapView(featuresMap), 115 | bounds: boundsFromGeometry, 116 | pointsCount: pointsCount); 117 | } 118 | 119 | PropertyLimits? getPropertyLimits(String key) { 120 | if (_limits != null && _limits!.containsKey(key)) { 121 | return _limits![key]!; 122 | } 123 | return null; 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /lib/src/data/map_feature.dart: -------------------------------------------------------------------------------- 1 | import 'dart:collection'; 2 | 3 | import 'package:vector_map/src/data/geometries.dart'; 4 | 5 | /// A representation of a real-world object on a map. 6 | class MapFeature { 7 | MapFeature( 8 | {required this.id, 9 | required this.geometry, 10 | Map? properties, 11 | this.label}) 12 | : this.properties = 13 | properties != null ? UnmodifiableMapView(properties) : null; 14 | 15 | final int id; 16 | final String? label; 17 | final UnmodifiableMapView? properties; 18 | final MapGeometry geometry; 19 | 20 | dynamic getValue(String key) { 21 | if (properties != null && properties!.containsKey(key)) { 22 | return properties![key]; 23 | } 24 | return null; 25 | } 26 | 27 | double? getDoubleValue(String key) { 28 | dynamic d = getValue(key); 29 | if (d != null) { 30 | if (d is double) { 31 | return d; 32 | } else if (d is int) { 33 | return d.toDouble(); 34 | } 35 | } 36 | return null; 37 | } 38 | 39 | @override 40 | bool operator ==(Object other) => 41 | identical(this, other) || 42 | other is MapFeature && runtimeType == other.runtimeType && id == other.id; 43 | 44 | @override 45 | int get hashCode => id.hashCode; 46 | } 47 | -------------------------------------------------------------------------------- /lib/src/data/map_layer.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | 3 | import 'package:vector_map/src/data/map_data_source.dart'; 4 | import 'package:vector_map/src/theme/map_highlight_theme.dart'; 5 | import 'package:vector_map/src/theme/map_theme.dart'; 6 | 7 | /// Layer for [VectorMap]. 8 | class MapLayer { 9 | MapLayer( 10 | {int? id, 11 | required this.dataSource, 12 | MapTheme? theme, 13 | this.highlightTheme, 14 | this.name}) 15 | : this.id = id != null ? id : _randomId(), 16 | this.theme = theme != null ? theme : MapTheme(); 17 | 18 | final int id; 19 | final MapDataSource dataSource; 20 | final MapTheme theme; 21 | final MapHighlightTheme? highlightTheme; 22 | final String? name; 23 | 24 | /// Indicates if the hover is drawable, if there is any highlight theme and 25 | /// if it has a set value. 26 | bool get hoverDrawable { 27 | return highlightTheme != null && highlightTheme!.hasValue(); 28 | } 29 | 30 | @override 31 | bool operator ==(Object other) => 32 | identical(this, other) || 33 | other is MapLayer && runtimeType == other.runtimeType && id == other.id; 34 | 35 | @override 36 | int get hashCode => id.hashCode; 37 | 38 | /// Gets a random layer id. 39 | static int _randomId() { 40 | Random random = Random(); 41 | return random.nextInt(9999999); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /lib/src/data/property_limits.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math' as math; 2 | 3 | /// Stores the number limits, max and min, for a given feature property. 4 | class PropertyLimits { 5 | double _max; 6 | double _min; 7 | 8 | PropertyLimits(double value) 9 | : this._max = value, 10 | this._min = value; 11 | 12 | double get max => _max; 13 | 14 | double get min => _min; 15 | 16 | expand(double value) { 17 | _max = math.max(_max, value); 18 | _min = math.min(_min, value); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lib/src/data/simplified_path.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | /// Stores a simplified path generated from the original [MapFeature] geometry. 4 | class SimplifiedPath { 5 | SimplifiedPath(this.path, this.pointsCount); 6 | 7 | final Path path; 8 | final int pointsCount; 9 | } 10 | -------------------------------------------------------------------------------- /lib/src/data_reader.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:vector_map/src/data/geometries.dart'; 4 | import 'package:vector_map/src/data/map_feature.dart'; 5 | import 'package:vector_map/src/error.dart'; 6 | 7 | /// Generic GeoJSON reader. 8 | class _GeoJsonReaderBase { 9 | void _checkKeyOn(Map map, String key) { 10 | if (map.containsKey(key) == false) { 11 | throw VectorMapError.keyNotFound(key); 12 | } 13 | } 14 | 15 | MapGeometry _readGeometry(bool hasParent, Map map) { 16 | _checkKeyOn(map, 'type'); 17 | final type = map['type']; 18 | switch (type) { 19 | //TODO other geometries 20 | case 'Point': 21 | return _readPoint(map); 22 | case 'MultiPoint': 23 | throw UnimplementedError(); 24 | case 'LineString': 25 | return _readLineString(map); 26 | case 'MultiLineString': 27 | return _readMultiLineString(map); 28 | case 'Polygon': 29 | return _readPolygon(map); 30 | case 'MultiPolygon': 31 | return _readMultiPolygon(map); 32 | default: 33 | if (hasParent) { 34 | throw VectorMapError.invalidGeometryType(type); 35 | } else { 36 | throw VectorMapError.invalidType(type); 37 | } 38 | } 39 | } 40 | 41 | MapGeometry _readPoint(Map map) { 42 | _checkKeyOn(map, 'coordinates'); 43 | List coordinates = map['coordinates']; 44 | if (coordinates.length == 2) { 45 | double x = _toDouble(coordinates[0]); 46 | double y = _toDouble(coordinates[1]); 47 | return MapPoint(x, y); 48 | } 49 | 50 | throw VectorMapError( 51 | 'Expected 2 coordinates but received ' + coordinates.length.toString()); 52 | } 53 | 54 | MapGeometry _readLineString(Map map) { 55 | _checkKeyOn(map, 'coordinates'); 56 | List coordinates = map['coordinates']; 57 | List points = []; 58 | for (List xy in coordinates) { 59 | double x = _toDouble(xy[0]); 60 | double y = _toDouble(xy[1]); 61 | points.add(MapPoint(x, y)); 62 | } 63 | return MapLineString(points); 64 | } 65 | 66 | MapGeometry _readMultiLineString(Map map) { 67 | _checkKeyOn(map, 'coordinates'); 68 | List coordinates = map['coordinates']; 69 | List lineString = []; 70 | for (List coords in coordinates) { 71 | List points = []; 72 | for (List xy in coords) { 73 | double x = _toDouble(xy[0]); 74 | double y = _toDouble(xy[1]); 75 | points.add(MapPoint(x, y)); 76 | } 77 | lineString.add(MapLineString(points)); 78 | } 79 | return MapMultiLineString(lineString); 80 | } 81 | 82 | MapGeometry _readPolygon(Map map) { 83 | late MapLinearRing externalRing; 84 | List internalRings = []; 85 | 86 | _checkKeyOn(map, 'coordinates'); 87 | List rings = map['coordinates']; 88 | for (int i = 0; i < rings.length; i++) { 89 | List points = []; 90 | List ring = rings[i]; 91 | for (List xy in ring) { 92 | double x = _toDouble(xy[0]); 93 | double y = _toDouble(xy[1]); 94 | points.add(MapPoint(x, y)); 95 | } 96 | if (i == 0) { 97 | externalRing = MapLinearRing(points); 98 | } else { 99 | internalRings.add(MapLinearRing(points)); 100 | } 101 | } 102 | 103 | return MapPolygon(externalRing, internalRings); 104 | } 105 | 106 | MapGeometry _readMultiPolygon(Map map) { 107 | _checkKeyOn(map, 'coordinates'); 108 | List polygons = map['coordinates']; 109 | 110 | List mapPolygons = []; 111 | for (List rings in polygons) { 112 | late MapLinearRing externalRing; 113 | List internalRings = []; 114 | 115 | for (int i = 0; i < rings.length; i++) { 116 | List points = []; 117 | List ring = rings[i]; 118 | for (List xy in ring) { 119 | double x = _toDouble(xy[0]); 120 | double y = _toDouble(xy[1]); 121 | points.add(MapPoint(x, y)); 122 | } 123 | if (i == 0) { 124 | externalRing = MapLinearRing(points); 125 | } else { 126 | internalRings.add(MapLinearRing(points)); 127 | } 128 | } 129 | MapPolygon polygon = MapPolygon(externalRing, internalRings); 130 | mapPolygons.add(polygon); 131 | } 132 | 133 | return MapMultiPolygon(mapPolygons); 134 | } 135 | 136 | /// Parses a dynamic coordinate to [double]. 137 | double _toDouble(dynamic coordinate) { 138 | if (coordinate is double) { 139 | return coordinate; 140 | } else if (coordinate is int) { 141 | return coordinate.toDouble(); 142 | } 143 | // The coordinate shouldn't be a String but since it is, tries to parse. 144 | return double.parse(coordinate.toString()); 145 | } 146 | } 147 | 148 | enum ColorValueFormat { hex } 149 | 150 | /// Properties read. 151 | class _Properties { 152 | _Properties({this.label, this.values}); 153 | 154 | /// Label value extracted from [labelKey]. 155 | final String? label; 156 | final Map? values; 157 | } 158 | 159 | /// [MapFeature] reader 160 | /// 161 | /// The [keys] argument defines which properties must be loaded. 162 | /// The [parseToNumber] argument defines which properties will have numeric 163 | /// values in quotes parsed to numbers. 164 | class MapFeatureReader extends _GeoJsonReaderBase { 165 | MapFeatureReader( 166 | {this.labelKey, 167 | this.keys, 168 | this.parseToNumber, 169 | this.colorKey, 170 | this.colorValueFormat = ColorValueFormat.hex}); 171 | 172 | final List _list = []; 173 | 174 | final String? labelKey; 175 | final Set? keys; 176 | final Set? parseToNumber; 177 | final String? colorKey; 178 | final ColorValueFormat colorValueFormat; 179 | 180 | Future> read(String geoJson) async { 181 | Map map = json.decode(geoJson); 182 | await _readMap(map); 183 | return _list; 184 | } 185 | 186 | Future _readMap(Map map) async { 187 | _checkKeyOn(map, 'type'); 188 | 189 | final type = map['type']; 190 | 191 | if (type == 'FeatureCollection') { 192 | _checkKeyOn(map, 'features'); 193 | //TODO check if it is a Map? 194 | for (Map featureMap in map['features']) { 195 | _readFeature(featureMap); 196 | } 197 | } else if (type == 'GeometryCollection') { 198 | } else if (type == 'Feature') { 199 | _readFeature(map); 200 | } else { 201 | MapGeometry geometry = _readGeometry(false, map); 202 | _addFeature(geometry: geometry); 203 | } 204 | } 205 | 206 | void _readFeature(Map map) { 207 | _checkKeyOn(map, 'geometry'); 208 | Map geometryMap = map['geometry']; 209 | MapGeometry geometry = _readGeometry(true, geometryMap); 210 | _Properties? properties; 211 | if ((labelKey != null || keys != null || colorKey != null) && 212 | map.containsKey('properties')) { 213 | Map propertiesMap = map['properties']; 214 | properties = _readProperties(propertiesMap); 215 | } 216 | _addFeature(geometry: geometry, properties: properties); 217 | } 218 | 219 | _Properties _readProperties(Map map) { 220 | String? label; 221 | Map? values; 222 | if (labelKey != null && map.containsKey(labelKey)) { 223 | // converting dynamic to String 224 | label = map[labelKey].toString(); 225 | } 226 | if (keys != null) { 227 | if (keys!.isNotEmpty) { 228 | Map valuesTmp = Map(); 229 | for (String key in keys!) { 230 | if (map.containsKey(key)) { 231 | dynamic value = map[key]; 232 | if (parseToNumber != null && 233 | parseToNumber!.contains(key) && 234 | value is String) { 235 | value = double.parse(value); 236 | } 237 | valuesTmp[key] = value; 238 | } 239 | } 240 | if (valuesTmp.isNotEmpty) { 241 | values = valuesTmp; 242 | } 243 | } 244 | } 245 | return _Properties(label: label, values: values); 246 | } 247 | 248 | void _addFeature({required MapGeometry geometry, _Properties? properties}) { 249 | _list.add(MapFeature( 250 | id: _list.length + 1, 251 | geometry: geometry, 252 | properties: properties?.values, 253 | label: properties?.label)); 254 | } 255 | } 256 | 257 | /// GeoJSON geometry reader. 258 | class MapGeometryReader extends _GeoJsonReaderBase { 259 | final List _list = []; 260 | 261 | Future> geoJson(String geoJson) async { 262 | Map map = json.decode(geoJson); 263 | await _readMap(map); 264 | return _list; 265 | } 266 | 267 | Future _readMap(Map map) async { 268 | _checkKeyOn(map, 'type'); 269 | 270 | final type = map['type']; 271 | 272 | if (type == 'FeatureCollection') { 273 | _checkKeyOn(map, 'features'); 274 | //TODO check if it is a Map? 275 | for (Map featureMap in map['features']) { 276 | _readFeature(featureMap); 277 | } 278 | } else if (type == 'GeometryCollection') { 279 | } else if (type == 'Feature') { 280 | _readFeature(map); 281 | } else { 282 | MapGeometry geometry = _readGeometry(false, map); 283 | _list.add(geometry); 284 | } 285 | } 286 | 287 | void _readFeature(Map map) { 288 | _checkKeyOn(map, 'geometry'); 289 | Map geometryMap = map['geometry']; 290 | MapGeometry geometry = _readGeometry(true, geometryMap); 291 | _list.add(geometry); 292 | } 293 | } 294 | -------------------------------------------------------------------------------- /lib/src/debugger.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/widgets.dart'; 2 | import 'package:vector_map/src/data/map_layer.dart'; 3 | import 'package:vector_map/src/drawable/drawable_layer.dart'; 4 | import 'package:vector_map/src/vector_map_mode.dart'; 5 | 6 | class DurationDebugger extends ChangeNotifier { 7 | DurationDebugger(VoidCallback listener) { 8 | addListener(listener); 9 | } 10 | 11 | int _milliseconds = 0; 12 | int get milliseconds => _milliseconds; 13 | 14 | DateTime? _lastStartTime; 15 | 16 | void clear() { 17 | _milliseconds = 0; 18 | _lastStartTime = null; 19 | } 20 | 21 | void open() { 22 | _lastStartTime = DateTime.now(); 23 | } 24 | 25 | closeAndInc() { 26 | if (_lastStartTime != null) { 27 | DateTime end = DateTime.now(); 28 | Duration duration = end.difference(_lastStartTime!); 29 | _milliseconds += duration.inMilliseconds; 30 | _lastStartTime = null; 31 | notifyListeners(); 32 | } 33 | } 34 | } 35 | 36 | class MapDebugger extends ChangeNotifier { 37 | MapDebugger() { 38 | drawableBuildDuration = DurationDebugger(notifyListeners); 39 | bufferBuildDuration = DurationDebugger(notifyListeners); 40 | } 41 | 42 | int _layersCount = 0; 43 | int _chunksCount = 0; 44 | int _featuresCount = 0; 45 | int _originalPointsCount = 0; 46 | int _simplifiedPointsCount = 0; 47 | Offset? _mouseHoverWorld; 48 | Offset? _mouseHoverCanvas; 49 | 50 | late DurationDebugger drawableBuildDuration; 51 | late DurationDebugger bufferBuildDuration; 52 | 53 | String? _mode; 54 | 55 | void updateMode(VectorMapMode mode) { 56 | if (mode == VectorMapMode.autoFit) { 57 | _mode = "auto fit"; 58 | } else if (mode == VectorMapMode.panAndZoom) { 59 | _mode = "pan and zoom"; 60 | } else { 61 | _mode = null; 62 | } 63 | } 64 | 65 | void updateLayers(List drawableLayers, int chunksCount) { 66 | _layersCount = drawableLayers.length; 67 | _chunksCount = chunksCount; 68 | for (DrawableLayer drawableLayer in drawableLayers) { 69 | MapLayer layer = drawableLayer.layer; 70 | _featuresCount += layer.dataSource.features.length; 71 | _originalPointsCount += layer.dataSource.pointsCount; 72 | } 73 | _simplifiedPointsCount = 0; 74 | notifyListeners(); 75 | } 76 | 77 | void updateMouseHover({Offset? worldCoordinate, Offset? locationOnCanvas}) { 78 | this._mouseHoverWorld = worldCoordinate; 79 | this._mouseHoverCanvas = locationOnCanvas; 80 | notifyListeners(); 81 | } 82 | 83 | void updateSimplifiedPointsCount(int simplifiedPointsCount) { 84 | _simplifiedPointsCount = simplifiedPointsCount; 85 | notifyListeners(); 86 | } 87 | } 88 | 89 | class MapDebuggerWidget extends StatefulWidget { 90 | MapDebuggerWidget(this.debugger); 91 | 92 | final MapDebugger? debugger; 93 | 94 | @override 95 | State createState() { 96 | return MapDebuggerState(); 97 | } 98 | } 99 | 100 | class MapDebuggerState extends State { 101 | ScrollController _controller = ScrollController(); 102 | 103 | String formatInt(int value) { 104 | String str = value.toString(); 105 | String fmt = ''; 106 | int indexGroup = 3 - str.length % 3; 107 | if (indexGroup == 3) { 108 | indexGroup = 0; 109 | } 110 | for (int i = 0; i < str.length; i++) { 111 | fmt += str.substring(i, i + 1); 112 | indexGroup++; 113 | if (indexGroup == 3 && i < str.length - 1) { 114 | fmt += ','; 115 | indexGroup = 0; 116 | } 117 | } 118 | return fmt; 119 | } 120 | 121 | @override 122 | Widget build(BuildContext context) { 123 | if (widget.debugger == null) { 124 | return Container(); 125 | } 126 | MapDebugger d = widget.debugger!; 127 | 128 | int drawableBuildDuration = d.drawableBuildDuration.milliseconds; 129 | int bufferBuildDuration = d.bufferBuildDuration.milliseconds; 130 | int multiResolutionDuration = drawableBuildDuration + bufferBuildDuration; 131 | 132 | return SingleChildScrollView( 133 | controller: _controller, 134 | child: Container( 135 | child: Column(children: [ 136 | _title('Quantities'), 137 | _int('Layers: ', d._layersCount), 138 | _int(' • Chunks: ', d._chunksCount), 139 | _int('Features: ', d._featuresCount), 140 | _int('Original points: ', d._originalPointsCount), 141 | _int('Simplified points: ', d._simplifiedPointsCount), 142 | _title('Last durations'), 143 | _milliseconds('Drawables build: ', multiResolutionDuration), 144 | _milliseconds( 145 | ' • Simplified geometries: ', drawableBuildDuration), 146 | _milliseconds(' • Buffers: ', bufferBuildDuration), 147 | _title('Cursor location'), 148 | _offset('Canvas: ', d._mouseHoverCanvas), 149 | _offset('World: ', d._mouseHoverWorld), 150 | _title('Configurations'), 151 | _item('Mode: ', d._mode != null ? d._mode! : '') 152 | ], crossAxisAlignment: CrossAxisAlignment.start), 153 | width: 200, 154 | padding: EdgeInsets.all(8))); 155 | } 156 | 157 | Widget _title(String text) { 158 | return Padding( 159 | padding: EdgeInsets.fromLTRB(0, 12, 0, 12), 160 | child: Text(text, 161 | style: TextStyle(fontWeight: FontWeight.bold, fontSize: 12))); 162 | } 163 | 164 | Widget _milliseconds(String label, int value) { 165 | return _item(label, formatInt(value) + ' ms'); 166 | } 167 | 168 | Widget _int(String label, int value) { 169 | return _item(label, formatInt(value)); 170 | } 171 | 172 | Widget _offset(String label, Offset? offset) { 173 | if (offset == null) { 174 | return _item(label, ''); 175 | } 176 | return _item(label, offset.dx.toString() + ', ' + offset.dy.toString()); 177 | } 178 | 179 | Widget _item(String label, String value) { 180 | return Padding( 181 | padding: EdgeInsets.fromLTRB(0, 4, 0, 0), 182 | child: RichText( 183 | text: new TextSpan( 184 | style: TextStyle(fontSize: 12), 185 | children: [ 186 | new TextSpan(text: label), 187 | new TextSpan( 188 | text: value, 189 | style: new TextStyle(fontWeight: FontWeight.bold)), 190 | ], 191 | ), 192 | )); 193 | } 194 | 195 | @override 196 | void initState() { 197 | super.initState(); 198 | widget.debugger?.addListener(_refresh); 199 | } 200 | 201 | @override 202 | void didUpdateWidget(MapDebuggerWidget oldWidget) { 203 | super.didUpdateWidget(oldWidget); 204 | oldWidget.debugger?.removeListener(_refresh); 205 | widget.debugger?.addListener(_refresh); 206 | } 207 | 208 | @override 209 | void dispose() { 210 | widget.debugger?.removeListener(_refresh); 211 | super.dispose(); 212 | } 213 | 214 | void _refresh() { 215 | // avoid calling setState during build 216 | Future.delayed(Duration.zero, () { 217 | if (mounted) { 218 | setState(() { 219 | // rebuild 220 | }); 221 | } 222 | }); 223 | } 224 | } 225 | -------------------------------------------------------------------------------- /lib/src/draw_utils.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/rendering.dart'; 2 | import 'package:vector_map/src/data/map_data_source.dart'; 3 | import 'package:vector_map/src/data/map_feature.dart'; 4 | import 'package:vector_map/src/data/map_layer.dart'; 5 | import 'package:vector_map/src/drawable/drawable.dart'; 6 | import 'package:vector_map/src/drawable/drawable_feature.dart'; 7 | import 'package:vector_map/src/drawable/drawable_layer.dart'; 8 | import 'package:vector_map/src/drawable/drawable_layer_chunk.dart'; 9 | import 'package:vector_map/src/map_highlight.dart'; 10 | import 'package:vector_map/src/theme/map_theme.dart'; 11 | 12 | /// Draw utils for [VectorMap]. 13 | class DrawUtils { 14 | /// Draws the features on a given canvas. 15 | /// 16 | /// Only features that match [highlightRule] will be drawn. 17 | static void draw( 18 | {required Canvas canvas, 19 | required DrawableLayerChunk chunk, 20 | required MapLayer layer, 21 | required double contourThickness, 22 | required double scale, 23 | required bool antiAlias, 24 | MapHighlight? highlightRule}) { 25 | MapDataSource dataSource = layer.dataSource; 26 | MapTheme theme = layer.theme; 27 | Color? highlightColor = layer.highlightTheme?.color; 28 | 29 | for (int index = 0; index < chunk.length; index++) { 30 | DrawableFeature drawableFeature = chunk.getDrawableFeature(index); 31 | MapFeature feature = drawableFeature.feature; 32 | Drawable? drawable = drawableFeature.drawable; 33 | if (drawable != null && drawable.visible && drawable.hasFill) { 34 | Color color; 35 | if (highlightColor != null && 36 | highlightRule != null && 37 | highlightRule.applies(feature)) { 38 | color = highlightColor; 39 | } else { 40 | color = MapTheme.getThemeOrDefaultColor(dataSource, feature, theme); 41 | } 42 | var paint = Paint() 43 | ..style = PaintingStyle.fill 44 | ..color = color 45 | ..isAntiAlias = antiAlias; 46 | drawable.drawOn(canvas, paint, scale); 47 | } 48 | } 49 | 50 | if (contourThickness > 0) { 51 | DrawUtils.drawContour( 52 | canvas: canvas, 53 | layer: layer, 54 | chunk: chunk, 55 | contourThickness: contourThickness, 56 | scale: scale, 57 | antiAlias: antiAlias, 58 | highlightRule: highlightRule); 59 | } 60 | } 61 | 62 | /// Draws the contour of the features on a given canvas. 63 | /// 64 | /// Only features that match [highlightRule] will be drawn. 65 | static void drawContour( 66 | {required Canvas canvas, 67 | required DrawableLayerChunk chunk, 68 | required MapLayer layer, 69 | required double contourThickness, 70 | required double scale, 71 | required bool antiAlias, 72 | MapHighlight? highlightRule}) { 73 | MapTheme theme = layer.theme; 74 | 75 | late Color contourColor; 76 | if (highlightRule != null && layer.highlightTheme?.contourColor != null) { 77 | contourColor = layer.highlightTheme!.contourColor!; 78 | } else { 79 | contourColor = theme.contourColor != null 80 | ? theme.contourColor! 81 | : MapTheme.defaultContourColor; 82 | } 83 | 84 | var paint = Paint() 85 | ..style = PaintingStyle.stroke 86 | ..color = contourColor 87 | ..strokeWidth = contourThickness / scale 88 | ..isAntiAlias = antiAlias; 89 | 90 | for (int index = 0; index < chunk.length; index++) { 91 | DrawableFeature drawableFeature = chunk.getDrawableFeature(index); 92 | Drawable? drawable = drawableFeature.drawable; 93 | if (drawable != null && drawable.visible) { 94 | if (highlightRule != null) { 95 | MapFeature feature = drawableFeature.feature; 96 | if (highlightRule.applies(feature) == false) { 97 | continue; 98 | } 99 | } 100 | drawable.drawOn(canvas, paint, scale); 101 | } 102 | } 103 | } 104 | 105 | /// Draws the features that match [MapMultiHighlight] on a given canvas. 106 | static void drawHighlight( 107 | {required Canvas canvas, 108 | required DrawableLayer drawableLayer, 109 | required Paint paint, 110 | required double scale, 111 | required bool fillOnly, 112 | required MapHighlight highlight}) { 113 | for (DrawableLayerChunk chunk in drawableLayer.chunks) { 114 | for (int index = 0; index < chunk.length; index++) { 115 | DrawableFeature drawableFeature = chunk.getDrawableFeature(index); 116 | MapFeature feature = drawableFeature.feature; 117 | Drawable? drawable = drawableFeature.drawable; 118 | if (drawable != null && drawable.visible) { 119 | if (fillOnly && drawable.hasFill == false) { 120 | continue; 121 | } 122 | if (highlight.applies(feature)) { 123 | drawable.drawOn(canvas, paint, scale); 124 | } 125 | } 126 | } 127 | } 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /lib/src/drawable/circle_marker.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math' as math; 2 | import 'dart:ui'; 3 | 4 | import 'package:vector_map/src/data/map_data_source.dart'; 5 | import 'package:vector_map/src/data/map_feature.dart'; 6 | import 'package:vector_map/src/data/property_limits.dart'; 7 | import 'package:vector_map/src/drawable/marker.dart'; 8 | import 'package:vector_map/src/error.dart'; 9 | 10 | /// Defines a circle marker to be painted on the map. 11 | class CircleMaker extends Marker { 12 | CircleMaker( 13 | {required Offset offset, 14 | required double radius, 15 | required double scaledRadius}) 16 | : this._bounds = Rect.fromLTWH(offset.dx - scaledRadius, 17 | offset.dy - scaledRadius, scaledRadius * 2, scaledRadius * 2), 18 | this._radius = radius, 19 | super(offset: offset); 20 | 21 | final Rect _bounds; 22 | final double _radius; 23 | 24 | @override 25 | bool contains(Offset offset) { 26 | return _bounds.contains(offset); 27 | } 28 | 29 | @override 30 | void drawMarkerOn(Canvas canvas, Paint paint, Offset offset, double scale) { 31 | canvas.drawCircle(offset, _radius / scale, paint); 32 | } 33 | 34 | @override 35 | Rect getBounds() { 36 | return _bounds; 37 | } 38 | 39 | @override 40 | bool get visible => _radius > 0 ? true : false; 41 | 42 | @override 43 | bool get hasFill => true; 44 | } 45 | 46 | /// A [CircleMaker] builder. 47 | class CircleMakerBuilder { 48 | /// Builds a fixed radius circle marker. The default [radius] value is [5]. 49 | static MarkerBuilder fixed({double radius = 5}) { 50 | return _FixedRadius(radius: math.max(0, radius)); 51 | } 52 | 53 | /// Builds a circle marker by mapping a property value to a radius. 54 | static MarkerBuilder map( 55 | {required String key, required Map radiuses}) { 56 | return _MappedValues(key: key, radiuses: radiuses); 57 | } 58 | 59 | /// Builds a circle marker using property values as radiuses. 60 | /// The type of the values must be numeric. 61 | static MarkerBuilder property({required String key}) { 62 | return _Property(key: key); 63 | } 64 | 65 | /// Builds a circle marker by proportionally mapping property 66 | /// values to defined minimum and maximum values. 67 | static MarkerBuilder proportion( 68 | {required String key, 69 | required double minRadius, 70 | required double maxRadius}) { 71 | if (maxRadius <= minRadius) { 72 | throw VectorMapError('maxRadius must be bigger than minRadius'); 73 | } 74 | return _Proportion(key: key, minRadius: minRadius, maxRadius: maxRadius); 75 | } 76 | } 77 | 78 | /// Fixed radius [CircleMaker] builder. 79 | class _FixedRadius extends MarkerBuilder { 80 | _FixedRadius({required this.radius}); 81 | 82 | final double radius; 83 | 84 | @override 85 | Marker build( 86 | {required MapDataSource dataSource, 87 | required MapFeature feature, 88 | required Offset offset, 89 | required double scale}) { 90 | return CircleMaker( 91 | offset: offset, radius: radius, scaledRadius: radius / scale); 92 | } 93 | } 94 | 95 | class _MappedValues extends MarkerBuilder { 96 | _MappedValues({required this.key, required this.radiuses}); 97 | 98 | final String key; 99 | final Map radiuses; 100 | 101 | @override 102 | Marker build( 103 | {required MapDataSource dataSource, 104 | required MapFeature feature, 105 | required Offset offset, 106 | required double scale}) { 107 | double r = 0; 108 | dynamic value = feature.getValue(key); 109 | if (value != null && radiuses.containsKey(value)) { 110 | r = math.max(0, radiuses[value]!); 111 | } 112 | return CircleMaker(offset: offset, radius: r, scaledRadius: r / scale); 113 | } 114 | } 115 | 116 | class _Property extends MarkerBuilder { 117 | _Property({required this.key}); 118 | 119 | final String key; 120 | 121 | @override 122 | Marker build( 123 | {required MapDataSource dataSource, 124 | required MapFeature feature, 125 | required Offset offset, 126 | required double scale}) { 127 | double r = 0; 128 | dynamic dynamicValue = feature.getValue(key); 129 | if (dynamicValue is int) { 130 | r = math.max(0, dynamicValue.toDouble()); 131 | } else if (dynamicValue is double) { 132 | r = math.max(0, dynamicValue); 133 | } 134 | 135 | return CircleMaker(offset: offset, radius: r, scaledRadius: r / scale); 136 | } 137 | } 138 | 139 | class _Proportion extends MarkerBuilder { 140 | _Proportion( 141 | {required this.key, required this.minRadius, required this.maxRadius}); 142 | 143 | final String key; 144 | final double minRadius; 145 | final double maxRadius; 146 | 147 | @override 148 | Marker build( 149 | {required MapDataSource dataSource, 150 | required MapFeature feature, 151 | required Offset offset, 152 | required double scale}) { 153 | double radius = 0; 154 | 155 | PropertyLimits? propertyLimits = dataSource.getPropertyLimits(key); 156 | if (propertyLimits != null) { 157 | dynamic dynamicValue = feature.getValue(key); 158 | if (dynamicValue is int) { 159 | radius = _radius( 160 | propertyLimits.min, propertyLimits.max, dynamicValue.toDouble()); 161 | } else if (dynamicValue is double) { 162 | radius = _radius(propertyLimits.min, propertyLimits.max, dynamicValue); 163 | } 164 | } 165 | 166 | return CircleMaker( 167 | offset: offset, radius: radius, scaledRadius: radius / scale); 168 | } 169 | 170 | double _radius(double minValue, double maxValue, double dynamicValue) { 171 | double valueRange = maxValue - minValue; 172 | double p = ((dynamicValue - minValue) / valueRange); 173 | return minRadius + ((maxRadius - minRadius) * p); 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /lib/src/drawable/drawable.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | /// Defines how a [MapFeature] should be painted on the map. 4 | abstract class Drawable { 5 | /// Gets the geometry bounds 6 | Rect getBounds(); 7 | 8 | /// Draws this drawable on the canvas. 9 | void drawOn(Canvas canvas, Paint paint, double scale); 10 | 11 | /// Gets the count of points for this drawable. 12 | int get pointsCount; 13 | 14 | /// Checks whether a point is contained in this drawable. 15 | bool contains(Offset offset); 16 | 17 | /// Indicates whether it is visible. 18 | bool get visible; 19 | 20 | /// Indicates whether to draw the fill 21 | bool get hasFill; 22 | } 23 | -------------------------------------------------------------------------------- /lib/src/drawable/drawable_builder.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/rendering.dart'; 2 | import 'package:vector_map/src/data/geometries.dart'; 3 | import 'package:vector_map/src/data/map_data_source.dart'; 4 | import 'package:vector_map/src/data/map_feature.dart'; 5 | import 'package:vector_map/src/data/simplified_path.dart'; 6 | import 'package:vector_map/src/drawable/drawable.dart'; 7 | import 'package:vector_map/src/drawable/drawable_line.dart'; 8 | import 'package:vector_map/src/drawable/drawable_polygon.dart'; 9 | import 'package:vector_map/src/error.dart'; 10 | import 'package:vector_map/src/simplifier.dart'; 11 | import 'package:vector_map/src/theme/map_theme.dart'; 12 | 13 | /// [Drawable] builder. 14 | class DrawableBuilder { 15 | static Drawable build( 16 | {required MapDataSource dataSource, 17 | required MapFeature feature, 18 | required MapTheme theme, 19 | required Matrix4 worldToCanvas, 20 | required double scale, 21 | required GeometrySimplifier simplifier}) { 22 | MapGeometry geometry = feature.geometry; 23 | if (geometry is MapPoint) { 24 | return _point( 25 | dataSource: dataSource, 26 | feature: feature, 27 | point: geometry, 28 | theme: theme, 29 | scale: scale, 30 | simplifier: simplifier); 31 | } else if (geometry is MapLinearRing) { 32 | return _linearRing( 33 | feature: feature, 34 | linearRing: geometry, 35 | theme: theme, 36 | worldToCanvas: worldToCanvas, 37 | simplifier: simplifier); 38 | } else if (geometry is MapLineString) { 39 | return _lineString( 40 | feature: feature, 41 | lineString: geometry, 42 | theme: theme, 43 | worldToCanvas: worldToCanvas, 44 | simplifier: simplifier); 45 | } else if (geometry is MapMultiLineString) { 46 | return _multiLineString( 47 | feature: feature, 48 | multiLineString: geometry, 49 | theme: theme, 50 | worldToCanvas: worldToCanvas, 51 | simplifier: simplifier); 52 | } else if (geometry is MapPolygon) { 53 | return _polygon( 54 | feature: feature, 55 | polygon: geometry, 56 | theme: theme, 57 | worldToCanvas: worldToCanvas, 58 | simplifier: simplifier); 59 | } else if (geometry is MapMultiPolygon) { 60 | return _multiPolygon( 61 | feature: feature, 62 | multiPolygon: geometry, 63 | theme: theme, 64 | worldToCanvas: worldToCanvas, 65 | simplifier: simplifier); 66 | } else { 67 | throw VectorMapError( 68 | 'Unrecognized geometry: ' + geometry.runtimeType.toString()); 69 | } 70 | } 71 | 72 | static Drawable _point( 73 | {required MapDataSource dataSource, 74 | required MapFeature feature, 75 | required MapPoint point, 76 | required MapTheme theme, 77 | required double scale, 78 | required GeometrySimplifier simplifier}) { 79 | return theme.markerBuilder.build( 80 | dataSource: dataSource, 81 | feature: feature, 82 | offset: Offset(point.x, point.y), 83 | scale: scale); 84 | } 85 | 86 | static Drawable _lineString( 87 | {required MapFeature feature, 88 | required MapLineString lineString, 89 | required MapTheme theme, 90 | required Matrix4 worldToCanvas, 91 | required GeometrySimplifier simplifier}) { 92 | SimplifiedPath simplifiedPath = 93 | lineString.toSimplifiedPath(worldToCanvas, simplifier); 94 | return DrawableLine(simplifiedPath.path, simplifiedPath.pointsCount); 95 | } 96 | 97 | static Drawable _multiLineString( 98 | {required MapFeature feature, 99 | required MapMultiLineString multiLineString, 100 | required MapTheme theme, 101 | required Matrix4 worldToCanvas, 102 | required GeometrySimplifier simplifier}) { 103 | Path path = Path(); 104 | int pointsCount = 0; 105 | for (MapLineString lineString in multiLineString.linesString) { 106 | SimplifiedPath simplifiedPath = 107 | lineString.toSimplifiedPath(worldToCanvas, simplifier); 108 | pointsCount += simplifiedPath.pointsCount; 109 | path.addPath(simplifiedPath.path, Offset.zero); 110 | } 111 | return DrawableLine(path, pointsCount); 112 | } 113 | 114 | static Drawable _linearRing( 115 | {required MapFeature feature, 116 | required MapLinearRing linearRing, 117 | required MapTheme theme, 118 | required Matrix4 worldToCanvas, 119 | required GeometrySimplifier simplifier}) { 120 | SimplifiedPath simplifiedPath = 121 | linearRing.toSimplifiedPath(worldToCanvas, simplifier); 122 | return DrawablePolygon(simplifiedPath.path, simplifiedPath.pointsCount); 123 | } 124 | 125 | static Drawable _polygon( 126 | {required MapFeature feature, 127 | required MapPolygon polygon, 128 | required MapTheme theme, 129 | required Matrix4 worldToCanvas, 130 | required GeometrySimplifier simplifier}) { 131 | SimplifiedPath simplifiedPath = 132 | polygon.toSimplifiedPath(worldToCanvas, simplifier); 133 | return DrawablePolygon(simplifiedPath.path, simplifiedPath.pointsCount); 134 | } 135 | 136 | static Drawable _multiPolygon( 137 | {required MapFeature feature, 138 | required MapMultiPolygon multiPolygon, 139 | required MapTheme theme, 140 | required Matrix4 worldToCanvas, 141 | required GeometrySimplifier simplifier}) { 142 | Path path = Path(); 143 | int pointsCount = 0; 144 | for (MapPolygon polygon in multiPolygon.polygons) { 145 | SimplifiedPath simplifiedPath = 146 | polygon.toSimplifiedPath(worldToCanvas, simplifier); 147 | pointsCount += simplifiedPath.pointsCount; 148 | path.addPath(simplifiedPath.path, Offset.zero); 149 | } 150 | return DrawablePolygon(path, pointsCount); 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /lib/src/drawable/drawable_feature.dart: -------------------------------------------------------------------------------- 1 | import 'package:vector_map/src/data/map_feature.dart'; 2 | import 'package:vector_map/src/drawable/drawable.dart'; 3 | 4 | class DrawableFeature { 5 | DrawableFeature(this.feature); 6 | 7 | final MapFeature feature; 8 | Drawable? drawable; 9 | 10 | @override 11 | bool operator ==(Object other) => 12 | identical(this, other) || 13 | other is DrawableFeature && 14 | runtimeType == other.runtimeType && 15 | feature == other.feature; 16 | 17 | @override 18 | int get hashCode => feature.hashCode; 19 | } 20 | -------------------------------------------------------------------------------- /lib/src/drawable/drawable_layer.dart: -------------------------------------------------------------------------------- 1 | import 'dart:collection'; 2 | import 'dart:ui'; 3 | 4 | import 'package:vector_map/src/data/map_feature.dart'; 5 | import 'package:vector_map/src/data/map_layer.dart'; 6 | import 'package:vector_map/src/drawable/drawable_layer_chunk.dart'; 7 | 8 | /// Holds all geometry layers to be paint in the current resolution. 9 | class DrawableLayer { 10 | static const int pointsPerChunk = 35000; 11 | 12 | DrawableLayer._(this.layer, this.chunks); 13 | 14 | factory DrawableLayer(MapLayer layer) { 15 | List chunks = []; 16 | DrawableLayerChunk chunk = DrawableLayerChunk(); 17 | for (MapFeature feature in layer.dataSource.features.values) { 18 | chunk.add(feature); 19 | if (chunk.pointsCount > pointsPerChunk) { 20 | chunks.add(chunk); 21 | chunk = DrawableLayerChunk(); 22 | } 23 | } 24 | if (chunk.pointsCount > 0) { 25 | chunks.add(chunk); 26 | } 27 | return DrawableLayer._(layer, UnmodifiableListView(chunks)); 28 | } 29 | 30 | final MapLayer layer; 31 | final UnmodifiableListView chunks; 32 | 33 | /// Gets the bounds of the layers. Returns [NULL] if the list is empty. 34 | static Rect? boundsOf(List drawableLayers) { 35 | Rect? bounds; 36 | for (DrawableLayer drawableLayer in drawableLayers) { 37 | Rect? layerBounds = drawableLayer.layer.dataSource.bounds; 38 | if (bounds == null) { 39 | bounds = layerBounds; 40 | } else if (layerBounds != null) { 41 | bounds = bounds.expandToInclude(layerBounds); 42 | } 43 | } 44 | return bounds; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /lib/src/drawable/drawable_layer_chunk.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui' as ui; 2 | 3 | import 'package:vector_map/src/data/map_feature.dart'; 4 | import 'package:vector_map/src/drawable/drawable_feature.dart'; 5 | 6 | class DrawableLayerChunk { 7 | final List _drawableFeatures = []; 8 | ui.Image? buffer; 9 | 10 | ui.Rect? _bounds; 11 | ui.Rect? get bounds => _bounds; 12 | 13 | int _pointsCount = 0; 14 | int get pointsCount => _pointsCount; 15 | 16 | int get length => _drawableFeatures.length; 17 | 18 | DrawableFeature getDrawableFeature(int index) { 19 | return _drawableFeatures[index]; 20 | } 21 | 22 | void add(MapFeature feature) { 23 | _drawableFeatures.add(DrawableFeature(feature)); 24 | _pointsCount += feature.geometry.pointsCount; 25 | 26 | if (_bounds == null) { 27 | _bounds = feature.geometry.bounds; 28 | } else { 29 | _bounds = _bounds!.expandToInclude(feature.geometry.bounds); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /lib/src/drawable/drawable_line.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | import 'package:vector_map/src/drawable/drawable_path.dart'; 4 | 5 | /// Defines a line or multi line to be painted on the map. 6 | class DrawableLine extends DrawablePath { 7 | DrawableLine(Path path, int pointsCount) : super(path, pointsCount); 8 | 9 | @override 10 | bool get hasFill => false; 11 | } 12 | -------------------------------------------------------------------------------- /lib/src/drawable/drawable_path.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | import 'package:vector_map/src/drawable/drawable.dart'; 4 | 5 | /// Defines a path to be painted on the map. 6 | abstract class DrawablePath extends Drawable { 7 | DrawablePath(Path path, int pointsCount) 8 | : this._path = path, 9 | this._pointsCount = pointsCount; 10 | 11 | final Path _path; 12 | final int _pointsCount; 13 | 14 | @override 15 | void drawOn(Canvas canvas, Paint paint, double scale) { 16 | canvas.drawPath(_path, paint); 17 | } 18 | 19 | @override 20 | Rect getBounds() { 21 | return _path.getBounds(); 22 | } 23 | 24 | @override 25 | bool contains(Offset offset) { 26 | return _path.contains(offset); 27 | } 28 | 29 | @override 30 | int get pointsCount => _pointsCount; 31 | 32 | @override 33 | bool get visible => true; 34 | } 35 | -------------------------------------------------------------------------------- /lib/src/drawable/drawable_polygon.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | import 'package:vector_map/src/drawable/drawable_path.dart'; 4 | 5 | /// Defines a polygon or multi polygon to be painted on the map. 6 | class DrawablePolygon extends DrawablePath { 7 | DrawablePolygon(Path path, int pointsCount) : super(path, pointsCount); 8 | 9 | @override 10 | bool get hasFill => true; 11 | } 12 | -------------------------------------------------------------------------------- /lib/src/drawable/marker.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | import 'package:vector_map/src/data/map_data_source.dart'; 4 | import 'package:vector_map/src/data/map_feature.dart'; 5 | import 'package:vector_map/src/drawable/drawable.dart'; 6 | 7 | /// [Marker] builder. 8 | abstract class MarkerBuilder { 9 | MarkerBuilder(); 10 | 11 | /// Builds a [Marker] 12 | Marker build( 13 | {required MapDataSource dataSource, 14 | required MapFeature feature, 15 | required Offset offset, 16 | required double scale}); 17 | } 18 | 19 | /// Defines a marker to be painted on the map. 20 | abstract class Marker extends Drawable { 21 | Marker({required this.offset}); 22 | 23 | final Offset offset; 24 | 25 | @override 26 | void drawOn(Canvas canvas, Paint paint, double scale) { 27 | drawMarkerOn(canvas, paint, offset, scale); 28 | } 29 | 30 | @override 31 | int get pointsCount => 1; 32 | 33 | /// Draw this marker on [Canvas] 34 | void drawMarkerOn(Canvas canvas, Paint paint, Offset offset, double scale); 35 | } 36 | -------------------------------------------------------------------------------- /lib/src/error.dart: -------------------------------------------------------------------------------- 1 | /// Generic [VectorMap] error 2 | class VectorMapError extends Error { 3 | final String _message; 4 | 5 | VectorMapError(this._message); 6 | 7 | VectorMapError.keyNotFound(String key) 8 | : this._message = 'Key "$key" not found.'; 9 | 10 | VectorMapError.invalidType(String type) 11 | : this._message = 12 | 'Invalid "$type" type. Must be: FeatureCollection, GeometryCollection, Feature, Point, MultiPoint, LineString, MultiLineString, Polygon or MultiPolygon.'; 13 | 14 | VectorMapError.invalidGeometryType(String type) 15 | : this._message = 16 | 'Invalid geometry "$type" type. Must be: GeometryCollection, Point, MultiPoint, LineString, MultiLineString, Polygon or MultiPolygon.'; 17 | 18 | @override 19 | String toString() { 20 | return 'VectorMapError - $_message'; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lib/src/low_quality_mode.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | /// The low-quality mode can be used during resizing, panning, 4 | /// and zooming to optimize the drawing. 5 | /// 6 | /// Allows you to simplify drawing during these events avoiding freezes. 7 | /// The default [quality] value is 0.3. 8 | class LowQualityMode { 9 | LowQualityMode( 10 | {this.quality = 0.3, 11 | this.strokeColor = Colors.black, 12 | this.fillEnabled = false}) { 13 | if (this.quality <= 0 || this.quality > 1) { 14 | throw ArgumentError( 15 | 'Quality value must be greater than 0 and less than or equal to 1'); 16 | } 17 | } 18 | 19 | /// Defines the quality of the geometries that will be drawn during events. 20 | /// Value 1 represents 100% quality. 21 | final double quality; 22 | 23 | /// Color to paint the edge of geometries. 24 | /// If null, the color defined by the theme will be used. 25 | final Color? strokeColor; 26 | 27 | final bool fillEnabled; 28 | } 29 | -------------------------------------------------------------------------------- /lib/src/map_highlight.dart: -------------------------------------------------------------------------------- 1 | import 'package:vector_map/src/data/map_feature.dart'; 2 | import 'package:vector_map/src/drawable/drawable_feature.dart'; 3 | 4 | /// Base class to define which [MapFeature] should be highlighted. 5 | abstract class MapHighlight { 6 | MapHighlight({required this.layerId}); 7 | 8 | /// Identifier of the layer to be highlighted. 9 | final int layerId; 10 | 11 | /// Identifies whether the rule applies to a given [MapFeature]. 12 | bool applies(MapFeature feature); 13 | 14 | @override 15 | bool operator ==(Object other) => 16 | identical(this, other) || 17 | other is MapHighlight && 18 | runtimeType == other.runtimeType && 19 | layerId == other.layerId; 20 | 21 | @override 22 | int get hashCode => layerId.hashCode; 23 | } 24 | 25 | /// Defines a single [MapFeature] to be highlighted. 26 | class MapSingleHighlight extends MapHighlight { 27 | MapSingleHighlight({required int layerId, this.drawableFeature}) 28 | : super(layerId: layerId); 29 | 30 | final DrawableFeature? drawableFeature; 31 | 32 | @override 33 | bool applies(MapFeature feature) { 34 | return this.drawableFeature?.feature == feature; 35 | } 36 | 37 | @override 38 | bool operator ==(Object other) => 39 | identical(this, other) || 40 | super == other && 41 | other is MapSingleHighlight && 42 | runtimeType == other.runtimeType && 43 | drawableFeature == other.drawableFeature; 44 | 45 | @override 46 | int get hashCode => super.hashCode ^ drawableFeature.hashCode; 47 | } 48 | 49 | /// Rule to find out which [MapFeature] should be highlighted. 50 | class MapGradientHighlight extends MapHighlight { 51 | /// Builds a [MapHighlight] 52 | /// 53 | /// The [rangePerPixel] is the range of value represented by each legend 54 | /// bar pixel, that is, the range between the min and the max values 55 | /// divided by the height of the legend bar. 56 | factory MapGradientHighlight( 57 | {required int layerId, 58 | required String key, 59 | required double value, 60 | required double rangePerPixel, 61 | required double max, 62 | required double min}) { 63 | int comparator = 0; 64 | double r = comparatorPrecisionPixels * rangePerPixel; 65 | if (value > max - r) { 66 | comparator = 1; 67 | } else if (value < min + r) { 68 | comparator = -1; 69 | } 70 | return MapGradientHighlight._( 71 | layerId: layerId, 72 | key: key, 73 | value: value, 74 | rangePerPixel: rangePerPixel, 75 | comparator: comparator); 76 | } 77 | 78 | /// Builds a [MapGradientHighlight] 79 | MapGradientHighlight._( 80 | {required int layerId, 81 | required this.key, 82 | required this.value, 83 | required this.rangePerPixel, 84 | required this.comparator}) 85 | : super(layerId: layerId); 86 | 87 | final String key; 88 | final double value; 89 | final double rangePerPixel; 90 | final int comparator; 91 | 92 | static const int precisionPixels = 3; 93 | static const int comparatorPrecisionPixels = 2 * precisionPixels; 94 | 95 | /// Identifies whether the rule applies to a given [MapFeature]. 96 | @override 97 | bool applies(MapFeature feature) { 98 | double? featureValue = feature.getDoubleValue(key); 99 | if (featureValue != null) { 100 | if (greater()) { 101 | return value < featureValue; 102 | } else if (smaller()) { 103 | return value > featureValue; 104 | } else { 105 | double r = rangePerPixel * precisionPixels; 106 | if (value - r <= featureValue && featureValue <= value + r) { 107 | return true; 108 | } 109 | } 110 | } 111 | return false; 112 | } 113 | 114 | /// Indicates whether to compare with larger values. 115 | bool greater() { 116 | return comparator == 1; 117 | } 118 | 119 | /// Indicates whether to compare with smaller values. 120 | bool smaller() { 121 | return comparator == -1; 122 | } 123 | 124 | String get formattedValue { 125 | if (greater()) { 126 | return '> ' + value.roundToDouble().toString(); 127 | } else if (smaller()) { 128 | return '< ' + value.roundToDouble().toString(); 129 | } 130 | return '≈ ' + value.roundToDouble().toString(); 131 | } 132 | 133 | @override 134 | bool operator ==(Object other) => 135 | identical(this, other) || 136 | super == other && 137 | other is MapGradientHighlight && 138 | runtimeType == other.runtimeType && 139 | key == other.key && 140 | value == other.value && 141 | rangePerPixel == other.rangePerPixel && 142 | comparator == other.comparator; 143 | 144 | @override 145 | int get hashCode => 146 | super.hashCode ^ 147 | key.hashCode ^ 148 | value.hashCode ^ 149 | rangePerPixel.hashCode ^ 150 | comparator.hashCode; 151 | } 152 | -------------------------------------------------------------------------------- /lib/src/map_painter.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter/widgets.dart'; 3 | import 'package:vector_map/src/data/map_data_source.dart'; 4 | import 'package:vector_map/src/data/map_feature.dart'; 5 | import 'package:vector_map/src/data/map_layer.dart'; 6 | import 'package:vector_map/src/draw_utils.dart'; 7 | import 'package:vector_map/src/drawable/drawable.dart'; 8 | import 'package:vector_map/src/drawable/drawable_feature.dart'; 9 | import 'package:vector_map/src/drawable/drawable_layer.dart'; 10 | import 'package:vector_map/src/drawable/drawable_layer_chunk.dart'; 11 | import 'package:vector_map/src/map_highlight.dart'; 12 | import 'package:vector_map/src/theme/map_highlight_theme.dart'; 13 | import 'package:vector_map/src/theme/map_theme.dart'; 14 | import 'package:vector_map/src/vector_map_controller.dart'; 15 | 16 | /// Painter for [VectorMap]. 17 | class MapPainter extends CustomPainter { 18 | MapPainter({required this.controller}); 19 | final VectorMapController controller; 20 | 21 | @override 22 | void paint(Canvas canvas, Size size) { 23 | MapHighlight? highlight = controller.highlight; 24 | 25 | DrawableLayer? overlayContourDrawableLayer; 26 | 27 | // drawing layers 28 | for (int layerIndex = 0; 29 | layerIndex < controller.layersCount; 30 | layerIndex++) { 31 | DrawableLayer drawableLayer = controller.getDrawableLayer(layerIndex); 32 | for (DrawableLayerChunk chunk in drawableLayer.chunks) { 33 | if (controller.drawBuffers && chunk.buffer != null) { 34 | canvas.drawImage(chunk.buffer!, Offset.zero, Paint()); 35 | } else { 36 | // resizing, panning or zooming 37 | canvas.save(); 38 | controller.applyMatrixOn(canvas); 39 | // drawing contour only to be faster 40 | DrawUtils.drawContour( 41 | canvas: canvas, 42 | chunk: chunk, 43 | layer: drawableLayer.layer, 44 | contourThickness: controller.contourThickness, 45 | scale: controller.scale, 46 | antiAlias: false); 47 | canvas.restore(); 48 | } 49 | } 50 | 51 | MapLayer layer = drawableLayer.layer; 52 | 53 | // highlighting 54 | if (highlight != null && 55 | highlight.layerId == layer.id && 56 | layer.highlightTheme != null) { 57 | if (controller.contourThickness > 0 && 58 | layer.highlightTheme!.overlayContour) { 59 | overlayContourDrawableLayer = drawableLayer; 60 | } 61 | 62 | canvas.save(); 63 | controller.applyMatrixOn(canvas); 64 | 65 | if (layer.highlightTheme!.color != null) { 66 | var paint = Paint() 67 | ..style = PaintingStyle.fill 68 | ..color = layer.highlightTheme!.color! 69 | ..isAntiAlias = true; 70 | if (highlight is MapSingleHighlight) { 71 | DrawableFeature? drawableFeature = highlight.drawableFeature; 72 | Drawable? drawable = drawableFeature?.drawable; 73 | if (drawable != null && drawable.visible && drawable.hasFill) { 74 | drawable.drawOn(canvas, paint, controller.scale); 75 | } 76 | } else { 77 | DrawUtils.drawHighlight( 78 | canvas: canvas, 79 | drawableLayer: drawableLayer, 80 | paint: paint, 81 | scale: controller.scale, 82 | fillOnly: true, 83 | highlight: highlight); 84 | } 85 | } 86 | 87 | if (controller.contourThickness > 0 && 88 | layer.highlightTheme!.overlayContour == false) { 89 | _drawHighlightContour(canvas, drawableLayer, controller); 90 | } 91 | 92 | canvas.restore(); 93 | } 94 | } 95 | 96 | // drawing the overlay highlight contour 97 | if (overlayContourDrawableLayer != null) { 98 | canvas.save(); 99 | controller.applyMatrixOn(canvas); 100 | _drawHighlightContour(canvas, overlayContourDrawableLayer, controller); 101 | canvas.restore(); 102 | } 103 | 104 | // drawing labels 105 | for (int layerIndex = 0; 106 | layerIndex < controller.layersCount; 107 | layerIndex++) { 108 | DrawableLayer drawableLayer = controller.getDrawableLayer(layerIndex); 109 | MapLayer layer = drawableLayer.layer; 110 | MapDataSource dataSource = layer.dataSource; 111 | MapTheme theme = layer.theme; 112 | MapHighlightTheme? highlightTheme = layer.highlightTheme; 113 | if (theme.labelVisibility != null || 114 | (highlightTheme != null && highlightTheme.labelVisibility != null)) { 115 | for (DrawableLayerChunk chunk in drawableLayer.chunks) { 116 | for (int index = 0; index < chunk.length; index++) { 117 | DrawableFeature drawableFeature = chunk.getDrawableFeature(index); 118 | MapFeature feature = drawableFeature.feature; 119 | Drawable? drawable = drawableFeature.drawable; 120 | if (drawable != null && drawable.visible && feature.label != null) { 121 | LabelVisibility? labelVisibility; 122 | if (highlight != null && 123 | highlight.layerId == layer.id && 124 | highlight.applies(feature) && 125 | highlightTheme != null && 126 | highlightTheme.labelVisibility != null) { 127 | labelVisibility = highlightTheme.labelVisibility; 128 | } else { 129 | labelVisibility = theme.labelVisibility; 130 | } 131 | if (labelVisibility != null && labelVisibility(feature)) { 132 | LabelStyleBuilder? labelStyleBuilder; 133 | MapHighlightTheme? highlightTheme; 134 | if (highlight != null && highlight.applies(feature)) { 135 | highlightTheme = layer.highlightTheme; 136 | if (highlightTheme != null) { 137 | labelStyleBuilder = highlightTheme.labelStyleBuilder; 138 | } 139 | } 140 | Color featureColor = MapTheme.getFeatureColor( 141 | dataSource, feature, theme, highlightTheme); 142 | if (labelStyleBuilder == null) { 143 | labelStyleBuilder = theme.labelStyleBuilder; 144 | } 145 | _drawLabel( 146 | canvas, feature, drawable, featureColor, labelStyleBuilder); 147 | } 148 | } 149 | } 150 | } 151 | } 152 | } 153 | } 154 | 155 | void _drawHighlightContour(Canvas canvas, DrawableLayer drawableLayer, 156 | VectorMapController controller) { 157 | MapHighlight? highlight = controller.highlight; 158 | Color? color = MapTheme.getContourColor( 159 | drawableLayer.layer.theme, drawableLayer.layer.highlightTheme); 160 | if (color != null) { 161 | var paint = Paint() 162 | ..style = PaintingStyle.stroke 163 | ..color = color 164 | ..strokeWidth = controller.contourThickness / controller.scale 165 | ..isAntiAlias = true; 166 | if (highlight is MapSingleHighlight) { 167 | DrawableFeature? drawableFeature = highlight.drawableFeature; 168 | Drawable? drawable = drawableFeature?.drawable; 169 | if (drawable != null && drawable.visible) { 170 | drawable.drawOn(canvas, paint, controller.scale); 171 | } 172 | } else { 173 | DrawUtils.drawHighlight( 174 | canvas: canvas, 175 | drawableLayer: drawableLayer, 176 | paint: paint, 177 | scale: controller.scale, 178 | fillOnly: false, 179 | highlight: highlight!); 180 | } 181 | } 182 | } 183 | 184 | void _drawLabel(Canvas canvas, MapFeature feature, Drawable drawable, 185 | Color featureColor, LabelStyleBuilder? labelStyleBuilder) { 186 | Color labelColor = _labelColorFrom(featureColor); 187 | 188 | TextStyle? labelStyle; 189 | if (labelStyleBuilder != null) { 190 | labelStyle = labelStyleBuilder(feature, featureColor, labelColor); 191 | } 192 | if (labelStyle == null) { 193 | labelStyle = TextStyle( 194 | color: labelColor, 195 | fontSize: 11, 196 | ); 197 | } 198 | 199 | Rect bounds = MatrixUtils.transformRect( 200 | controller.worldToCanvas, drawable.getBounds()); 201 | _drawText(canvas, bounds.center, feature.label!, labelStyle); 202 | } 203 | 204 | Color _labelColorFrom(Color featureColor) { 205 | final luminance = featureColor.computeLuminance(); 206 | if (luminance > 0.55) { 207 | return const Color(0xFF000000); 208 | } 209 | return const Color(0xFFFFFFFF); 210 | } 211 | 212 | void _drawText( 213 | Canvas canvas, Offset center, String text, TextStyle textStyle) { 214 | TextSpan textSpan = TextSpan( 215 | text: text, 216 | style: textStyle, 217 | ); 218 | TextPainter textPainter = TextPainter( 219 | text: textSpan, 220 | textDirection: TextDirection.ltr, 221 | ); 222 | 223 | textPainter.layout( 224 | minWidth: 0, 225 | ); 226 | 227 | double xCenter = center.dx - (textPainter.width / 2); 228 | double yCenter = center.dy - (textPainter.height / 2); 229 | textPainter.paint(canvas, Offset(xCenter, yCenter)); 230 | } 231 | 232 | @override 233 | bool shouldRepaint(covariant CustomPainter oldDelegate) { 234 | return true; 235 | } 236 | } 237 | -------------------------------------------------------------------------------- /lib/src/simplifier.dart: -------------------------------------------------------------------------------- 1 | import 'dart:typed_data'; 2 | 3 | import 'package:flutter/rendering.dart'; 4 | import 'package:vector_map/src/data/geometries.dart'; 5 | 6 | /// Simplifies geometry by ignoring unnecessary points for viewing 7 | /// on the screen. 8 | abstract class GeometrySimplifier { 9 | GeometrySimplifier(this.tolerance); 10 | 11 | final double tolerance; 12 | 13 | List simplify(Matrix4 worldToCanvas, List points); 14 | 15 | MapPoint transformPoint(Matrix4 transform, MapPoint point) { 16 | final Float64List storage = transform.storage; 17 | final double x = point.x; 18 | final double y = point.y; 19 | 20 | // Directly simulate the transform of the vector (x, y, 0, 1), 21 | // dropping the resulting Z coordinate, and normalizing only 22 | // if needed. 23 | 24 | final double rx = storage[0] * x + storage[4] * y + storage[12]; 25 | final double ry = storage[1] * x + storage[5] * y + storage[13]; 26 | final double rw = storage[3] * x + storage[7] * y + storage[15]; 27 | if (rw == 1.0) { 28 | return MapPoint(rx, ry); 29 | } else { 30 | return MapPoint(rx / rw, ry / rw); 31 | } 32 | } 33 | } 34 | 35 | /// Ignores points that collide on the same physical pixel. 36 | class IntegerSimplifier extends GeometrySimplifier { 37 | IntegerSimplifier({double tolerance = 1}) : super(tolerance); 38 | 39 | @override 40 | List simplify(Matrix4 worldToCanvas, List points) { 41 | List simplifiedPoints = []; 42 | MapPoint? lastMapPoint; 43 | for (MapPoint point in points) { 44 | MapPoint transformedPoint = transformPoint(worldToCanvas, point); 45 | 46 | transformedPoint = MapPoint(transformedPoint.x.truncateToDouble(), 47 | transformedPoint.y.truncateToDouble()); 48 | if (simplifiedPoints.isEmpty || 49 | _accept(lastMapPoint!, transformedPoint)) { 50 | simplifiedPoints.add(point); 51 | lastMapPoint = transformedPoint; 52 | } 53 | } 54 | return simplifiedPoints; 55 | } 56 | 57 | bool _accept(MapPoint p1, MapPoint p2) { 58 | double dx = (p1.x - p2.x).abs(); 59 | if (dx >= tolerance) { 60 | return true; 61 | } 62 | double dy = (p1.y - p2.y).abs(); 63 | return dy >= tolerance; 64 | } 65 | } 66 | 67 | /// Does not apply any simplification. 68 | class NoSimplifier extends GeometrySimplifier { 69 | NoSimplifier() : super(0); 70 | 71 | @override 72 | List simplify(Matrix4 worldToCanvas, List points) { 73 | return points; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /lib/src/theme/map_gradient_theme.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/rendering.dart'; 2 | import 'package:vector_map/src/data/map_data_source.dart'; 3 | import 'package:vector_map/src/data/map_feature.dart'; 4 | import 'package:vector_map/src/data/property_limits.dart'; 5 | import 'package:vector_map/src/drawable/marker.dart'; 6 | import 'package:vector_map/src/error.dart'; 7 | import 'package:vector_map/src/theme/map_theme.dart'; 8 | 9 | /// Theme for gradient colors. 10 | /// 11 | /// The gradient is created given the colors and limit values of the 12 | /// chosen property. 13 | /// The property must have numeric values. 14 | /// If the [min] is set, all smaller values will be displayed with the first 15 | /// gradient color. 16 | /// If the [max] is set, all larger values will be displayed with the last 17 | /// gradient color. 18 | class MapGradientTheme extends MapTheme { 19 | MapGradientTheme( 20 | {Color? color, 21 | Color? contourColor, 22 | LabelVisibility? labelVisibility, 23 | LabelStyleBuilder? labelStyleBuilder, 24 | MarkerBuilder? markerBuilder, 25 | double? min, 26 | double? max, 27 | required this.key, 28 | required this.colors}) 29 | : this._max = max, 30 | this._min = min, 31 | super( 32 | color: color, 33 | contourColor: contourColor, 34 | labelVisibility: labelVisibility, 35 | labelStyleBuilder: labelStyleBuilder, 36 | markerBuilder: markerBuilder) { 37 | if (colors.length < 2) { 38 | throw VectorMapError('At least 2 colors are required for the gradient.'); 39 | } 40 | } 41 | 42 | final double? _min; 43 | final double? _max; 44 | final String key; 45 | final List colors; 46 | 47 | @override 48 | bool hasValue() { 49 | //It is not possible to know in advance, it depends on the property values. 50 | return true; 51 | } 52 | 53 | double? min(MapDataSource dataSource) { 54 | double? min = this._min; 55 | if (min == null) { 56 | PropertyLimits? propertyLimits = dataSource.getPropertyLimits(key); 57 | if (propertyLimits != null) { 58 | min = propertyLimits.min; 59 | } 60 | } 61 | return min; 62 | } 63 | 64 | double? max(MapDataSource dataSource) { 65 | double? max = this._max; 66 | if (max == null) { 67 | PropertyLimits? propertyLimits = dataSource.getPropertyLimits(key); 68 | if (propertyLimits != null) { 69 | max = propertyLimits.max; 70 | } 71 | } 72 | return max; 73 | } 74 | 75 | @override 76 | Color? getColor(MapDataSource dataSource, MapFeature feature) { 77 | double? min = this.min(dataSource); 78 | double? max = this.max(dataSource); 79 | 80 | if (min != null && max != null) { 81 | double? value = feature.getDoubleValue(key); 82 | if (value != null) { 83 | if (value <= min) { 84 | return colors.first; 85 | } 86 | if (value >= max) { 87 | return colors.last; 88 | } 89 | 90 | double size = max - min; 91 | 92 | int stepsCount = colors.length - 1; 93 | double stepSize = size / stepsCount; 94 | int stepIndex = (value - min) ~/ stepSize; 95 | 96 | double currentStepRange = (stepIndex * stepSize) + stepSize; 97 | double positionInStep = value - min - (stepIndex * stepSize); 98 | double t = positionInStep / currentStepRange; 99 | return Color.lerp(colors[stepIndex], colors[stepIndex + 1], t)!; 100 | } 101 | } 102 | return super.getColor(dataSource, feature); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /lib/src/theme/map_highlight_theme.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:vector_map/src/theme/map_theme.dart'; 3 | 4 | /// The theme for highlights. 5 | /// 6 | /// This theme is activated by hover or external components like a legend. 7 | class MapHighlightTheme { 8 | /// Builds a [MapHighlightTheme] 9 | MapHighlightTheme( 10 | {this.color, 11 | this.contourColor, 12 | this.overlayContour = false, 13 | this.labelVisibility, 14 | this.labelStyleBuilder}); 15 | 16 | final Color? color; 17 | final Color? contourColor; 18 | final bool overlayContour; 19 | final LabelVisibility? labelVisibility; 20 | final LabelStyleBuilder? labelStyleBuilder; 21 | 22 | /// Indicates whether the theme has any value set. 23 | bool hasValue() { 24 | return color != null || contourColor != null || labelVisibility != null; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lib/src/theme/map_rule_theme.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/rendering.dart'; 2 | import 'package:vector_map/src/data/map_data_source.dart'; 3 | import 'package:vector_map/src/data/map_feature.dart'; 4 | import 'package:vector_map/src/drawable/marker.dart'; 5 | import 'package:vector_map/src/theme/map_theme.dart'; 6 | 7 | /// Theme for colors by rule. 8 | /// 9 | /// The feature color is obtained from the first rule that returns 10 | /// a non-null color. 11 | /// If all rules return a null color, the default color is used. 12 | class MapRuleTheme extends MapTheme { 13 | MapRuleTheme( 14 | {Color? color, 15 | Color? contourColor, 16 | LabelVisibility? labelVisibility, 17 | LabelStyleBuilder? labelStyleBuilder, 18 | MarkerBuilder? markerBuilder, 19 | required List colorRules}) 20 | : this._colorRules = colorRules, 21 | super( 22 | color: color, 23 | contourColor: contourColor, 24 | labelVisibility: labelVisibility, 25 | labelStyleBuilder: labelStyleBuilder, 26 | markerBuilder: markerBuilder); 27 | 28 | final List _colorRules; 29 | 30 | @override 31 | bool hasValue() { 32 | //It is not possible to know in advance, it depends on the rule. 33 | return true; 34 | } 35 | 36 | @override 37 | Color? getColor(MapDataSource dataSource, MapFeature feature) { 38 | Color? color; 39 | for (ColorRule rule in _colorRules) { 40 | color = rule(feature); 41 | if (color != null) { 42 | break; 43 | } 44 | } 45 | return color != null ? color : super.getColor(dataSource, feature); 46 | } 47 | } 48 | 49 | /// Rule to obtain a color of a feature. 50 | typedef ColorRule = Color? Function(MapFeature feature); 51 | -------------------------------------------------------------------------------- /lib/src/theme/map_theme.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:vector_map/src/data/map_data_source.dart'; 3 | import 'package:vector_map/src/data/map_feature.dart'; 4 | import 'package:vector_map/src/drawable/circle_marker.dart'; 5 | import 'package:vector_map/src/drawable/marker.dart'; 6 | import 'package:vector_map/src/theme/map_highlight_theme.dart'; 7 | 8 | /// The [VectorMap] theme. 9 | class MapTheme { 10 | static const Color defaultColor = Color(0xFFE0E0E0); 11 | static const Color defaultContourColor = Color(0xFF9E9E9E); 12 | 13 | static Color getThemeOrDefaultColor( 14 | MapDataSource dataSource, MapFeature feature, MapTheme theme) { 15 | Color? color = theme.getColor(dataSource, feature); 16 | if (color != null) { 17 | return color; 18 | } 19 | return MapTheme.defaultColor; 20 | } 21 | 22 | /// Gets the feature color. 23 | static Color getFeatureColor(MapDataSource dataSource, MapFeature feature, 24 | MapTheme theme, MapHighlightTheme? highlightTheme) { 25 | Color? color = highlightTheme?.color; 26 | if (color == null) { 27 | color = theme.getColor(dataSource, feature); 28 | } 29 | if (color != null) { 30 | return color; 31 | } 32 | return MapTheme.defaultColor; 33 | } 34 | 35 | /// Gets the feature contour color. 36 | static Color? getContourColor( 37 | MapTheme theme, MapHighlightTheme? highlightTheme) { 38 | Color? color = highlightTheme?.contourColor; 39 | if (color == null) { 40 | color = theme.contourColor; 41 | } 42 | return color; 43 | } 44 | 45 | /// Builds a [VectorMap] 46 | MapTheme( 47 | {Color? color, 48 | this.contourColor, 49 | this.labelVisibility, 50 | this.labelStyleBuilder, 51 | MarkerBuilder? markerBuilder}) 52 | : this._color = color, 53 | this.markerBuilder = 54 | markerBuilder != null ? markerBuilder : CircleMakerBuilder.fixed(); 55 | 56 | final Color? _color; 57 | final Color? contourColor; 58 | final LabelVisibility? labelVisibility; 59 | final LabelStyleBuilder? labelStyleBuilder; 60 | final MarkerBuilder markerBuilder; 61 | 62 | /// Indicates whether the theme has any value set. 63 | bool hasValue() { 64 | return _color != null || contourColor != null || labelVisibility != null; 65 | } 66 | 67 | /// Gets the feature color. 68 | Color? getColor(MapDataSource dataSource, MapFeature feature) { 69 | return _color; 70 | } 71 | } 72 | 73 | /// Defines the visibility of a [MapFeature] 74 | typedef LabelVisibility = bool Function(MapFeature feature); 75 | 76 | /// The label style builder. 77 | typedef LabelStyleBuilder = TextStyle Function( 78 | MapFeature feature, Color featureColor, Color labelColor); 79 | -------------------------------------------------------------------------------- /lib/src/theme/map_value_theme.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/rendering.dart'; 2 | import 'package:vector_map/src/data/map_data_source.dart'; 3 | import 'package:vector_map/src/data/map_feature.dart'; 4 | import 'package:vector_map/src/drawable/marker.dart'; 5 | import 'package:vector_map/src/theme/map_theme.dart'; 6 | 7 | /// Theme for colors by value. 8 | class MapValueTheme extends MapTheme { 9 | MapValueTheme( 10 | {Color? color, 11 | Color? contourColor, 12 | LabelVisibility? labelVisibility, 13 | LabelStyleBuilder? labelStyleBuilder, 14 | MarkerBuilder? markerBuilder, 15 | required this.key, 16 | Map? colors}) 17 | : this._colors = colors, 18 | super( 19 | color: color, 20 | contourColor: contourColor, 21 | labelVisibility: labelVisibility, 22 | labelStyleBuilder: labelStyleBuilder, 23 | markerBuilder: markerBuilder); 24 | 25 | final String key; 26 | final Map? _colors; 27 | 28 | @override 29 | bool hasValue() { 30 | return (_colors != null && _colors!.isNotEmpty) || super.hasValue(); 31 | } 32 | 33 | @override 34 | Color? getColor(MapDataSource dataSource, MapFeature feature) { 35 | if (_colors != null) { 36 | dynamic value = feature.getValue(key); 37 | if (value != null && _colors!.containsKey(value)) { 38 | return _colors![value]!; 39 | } 40 | } 41 | return super.getColor(dataSource, feature); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /lib/src/vector_map.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/gestures.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:vector_map/src/addon/map_addon.dart'; 4 | import 'package:vector_map/src/data/map_feature.dart'; 5 | import 'package:vector_map/src/data/map_layer.dart'; 6 | import 'package:vector_map/src/drawable/drawable.dart'; 7 | import 'package:vector_map/src/drawable/drawable_feature.dart'; 8 | import 'package:vector_map/src/drawable/drawable_layer.dart'; 9 | import 'package:vector_map/src/drawable/drawable_layer_chunk.dart'; 10 | import 'package:vector_map/src/low_quality_mode.dart'; 11 | import 'package:vector_map/src/vector_map_controller.dart'; 12 | import 'package:vector_map/src/map_highlight.dart'; 13 | import 'package:vector_map/src/map_painter.dart'; 14 | import 'package:vector_map/src/vector_map_mode.dart'; 15 | 16 | /// Vector map widget. 17 | class VectorMap extends StatefulWidget { 18 | VectorMap( 19 | {Key? key, 20 | this.controller, 21 | this.color, 22 | this.borderColor = Colors.black54, 23 | this.borderThickness = 1, 24 | this.layersPadding = const EdgeInsets.all(8), 25 | this.hoverRule, 26 | this.hoverListener, 27 | this.clickListener, 28 | this.addons, 29 | this.placeHolder, 30 | this.lowQualityMode}) 31 | : super(key: key); 32 | 33 | final VectorMapController? controller; 34 | final Color? color; 35 | final Color? borderColor; 36 | final double? borderThickness; 37 | final Widget? placeHolder; 38 | final EdgeInsetsGeometry? layersPadding; 39 | final HoverRule? hoverRule; 40 | final HoverListener? hoverListener; 41 | final FeatureClickListener? clickListener; 42 | final List? addons; 43 | final LowQualityMode? lowQualityMode; 44 | 45 | @override 46 | State createState() => _VectorMapState(); 47 | } 48 | 49 | /// Holds the initial mouse location and matrix translate from the pan. 50 | class _PanZoom { 51 | _PanZoom( 52 | {required this.initialMouseLocation, 53 | required this.initialMapScale, 54 | required this.translateX, 55 | required this.translateY}) 56 | : this.lastLocalPosition = initialMouseLocation; 57 | 58 | final double initialMapScale; 59 | final Offset initialMouseLocation; 60 | final translateX; 61 | final translateY; 62 | Offset lastLocalPosition; 63 | bool _rebuildSimplifiedGeometry = false; 64 | bool get rebuildSimplifiedGeometry => _rebuildSimplifiedGeometry; 65 | 66 | double newScale( 67 | {required double currentMapScale, required double mouseScale}) { 68 | if (mouseScale != 1) { 69 | double newScale = initialMapScale * mouseScale; 70 | double delta = (1 - (newScale / currentMapScale)).abs(); 71 | if (delta > 0.05) { 72 | _rebuildSimplifiedGeometry = true; 73 | return newScale; 74 | } 75 | } 76 | return currentMapScale; 77 | } 78 | } 79 | 80 | /// [VectorMap] state. 81 | class _VectorMapState extends State { 82 | VectorMapController _controller = VectorMapController(); 83 | 84 | _PanZoom? _panZoom; 85 | 86 | @override 87 | void initState() { 88 | super.initState(); 89 | if (widget.controller != null) { 90 | _controller = widget.controller!; 91 | } 92 | _controller.addListener(_rebuild); 93 | } 94 | 95 | @override 96 | void didUpdateWidget(covariant VectorMap oldWidget) { 97 | super.didUpdateWidget(oldWidget); 98 | if (widget.controller != null && 99 | widget.controller != oldWidget.controller) { 100 | _controller.removeListener(_rebuild); 101 | _controller = widget.controller!; 102 | _controller.addListener(_rebuild); 103 | } 104 | } 105 | 106 | @override 107 | void dispose() { 108 | _controller.removeListener(_rebuild); 109 | super.dispose(); 110 | } 111 | 112 | void _rebuild() { 113 | setState(() { 114 | // rebuild 115 | }); 116 | } 117 | 118 | bool get _onPanAndZoom => _panZoom != null; 119 | 120 | @override 121 | Widget build(BuildContext context) { 122 | Widget? content; 123 | if (_controller.hasLayer) { 124 | Widget mapCanvas = _buildMapCanvas(); 125 | if (widget.addons != null) { 126 | List children = [LayoutId(id: 0, child: mapCanvas)]; 127 | int count = 1; 128 | for (MapAddon addon in widget.addons!) { 129 | DrawableFeature? hover; 130 | if (_controller.highlight != null && 131 | _controller.highlight is MapSingleHighlight) { 132 | hover = 133 | (_controller.highlight as MapSingleHighlight).drawableFeature; 134 | } 135 | children.add(LayoutId( 136 | id: count, 137 | child: addon.buildWidget( 138 | context: context, 139 | mapApi: _controller, 140 | hover: hover?.feature))); 141 | count++; 142 | } 143 | content = CustomMultiChildLayout( 144 | children: children, delegate: _VectorMapLayoutDelegate(count)); 145 | } else { 146 | content = mapCanvas; 147 | } 148 | } else if (widget.placeHolder != null) { 149 | content = widget.placeHolder; 150 | } 151 | 152 | BoxBorder? border; 153 | if (widget.borderColor != null && 154 | widget.borderThickness != null && 155 | widget.borderThickness! > 0) { 156 | border = Border.all( 157 | color: widget.borderColor!, width: widget.borderThickness!); 158 | } 159 | Decoration? decoration; 160 | if (widget.color != null || border != null) { 161 | decoration = BoxDecoration(color: widget.color, border: border); 162 | } 163 | 164 | return Container(decoration: decoration, child: content); 165 | } 166 | 167 | /// Builds the canvas area 168 | Widget _buildMapCanvas() { 169 | Widget mapCanvas = LayoutBuilder( 170 | builder: (BuildContext context, BoxConstraints constraints) { 171 | if (constraints.maxWidth == 0 || constraints.maxHeight == 0) { 172 | return Container(); 173 | } 174 | Size canvasSize = Size(constraints.maxWidth, constraints.maxHeight); 175 | _controller.setCanvasSize(canvasSize); 176 | 177 | return ClipRect( 178 | child: CustomPaint( 179 | painter: MapPainter(controller: _controller), 180 | child: Container())); 181 | }); 182 | 183 | mapCanvas = MouseRegion( 184 | child: mapCanvas, 185 | onHover: (event) => _onHover( 186 | localPosition: event.localPosition, 187 | canvasToWorld: _controller.canvasToWorld), 188 | onExit: (event) { 189 | if (_controller.highlight != null) { 190 | _updateHover(null); 191 | } 192 | _controller.debugger?.updateMouseHover(); 193 | }, 194 | ); 195 | 196 | mapCanvas = GestureDetector( 197 | child: mapCanvas, 198 | onTapDown: (details) => _onClick( 199 | localPosition: details.localPosition, 200 | canvasToWorld: _controller.canvasToWorld), 201 | onScaleStart: (details) { 202 | if (_controller.mode == VectorMapMode.panAndZoom) { 203 | if (_controller.highlight != null) { 204 | _updateHover(null); 205 | } 206 | _controller.notifyPanZoomMode(start: true); 207 | setState(() { 208 | _panZoom = _PanZoom( 209 | initialMouseLocation: details.localFocalPoint, 210 | initialMapScale: _controller.scale, 211 | translateX: _controller.translateX, 212 | translateY: _controller.translateY); 213 | }); 214 | } 215 | }, 216 | onScaleUpdate: (details) { 217 | if (_panZoom != null) { 218 | if (details.pointerCount == 1) { 219 | // pan only 220 | _panZoom!.lastLocalPosition = details.localFocalPoint; 221 | double diffX = _panZoom!.initialMouseLocation.dx - 222 | details.localFocalPoint.dx; 223 | double diffY = _panZoom!.initialMouseLocation.dy - 224 | details.localFocalPoint.dy; 225 | _controller.translate( 226 | _panZoom!.translateX - diffX, _panZoom!.translateY - diffY); 227 | } else if (details.pointerCount > 1) { 228 | // zoom 229 | double newScale = _panZoom!.newScale( 230 | currentMapScale: _controller.scale, 231 | mouseScale: details.scale); 232 | _controller.zoom(details.localFocalPoint, newScale); 233 | } 234 | } 235 | }, 236 | onScaleEnd: (details) { 237 | if (_panZoom != null) { 238 | _controller.notifyPanZoomMode( 239 | start: false, 240 | rebuildSimplifiedGeometry: _panZoom!.rebuildSimplifiedGeometry); 241 | final Offset localPosition = _panZoom!.lastLocalPosition; 242 | setState(() { 243 | _panZoom = null; 244 | }); 245 | _onHover( 246 | localPosition: localPosition, 247 | canvasToWorld: _controller.canvasToWorld); 248 | } 249 | }); 250 | 251 | mapCanvas = Listener( 252 | child: mapCanvas, 253 | onPointerSignal: (event) { 254 | if (event is PointerScrollEvent && 255 | _controller.mode == VectorMapMode.panAndZoom) { 256 | bool zoomIn = event.scrollDelta.dy < 0; 257 | _controller.zoomOnLocation(event.localPosition, zoomIn); 258 | } 259 | }); 260 | 261 | return Container(child: mapCanvas, padding: widget.layersPadding); 262 | } 263 | 264 | /// Triggered when a pointer tap on the map. 265 | void _onClick( 266 | {required Offset localPosition, required Matrix4 canvasToWorld}) { 267 | if (widget.clickListener != null) { 268 | Offset worldCoordinate = 269 | MatrixUtils.transformPoint(canvasToWorld, localPosition); 270 | MapFeature? feature; 271 | for (int layerIndex = _controller.layersCount - 1; 272 | layerIndex >= 0; 273 | layerIndex--) { 274 | DrawableLayer drawableLayer = _controller.getDrawableLayer(layerIndex); 275 | DrawableFeature? drawableFeature = 276 | _findDrawableFeature(drawableLayer, worldCoordinate); 277 | if (drawableFeature != null) { 278 | feature = drawableFeature.feature; 279 | break; 280 | } 281 | } 282 | if (feature != null) { 283 | widget.clickListener!(feature); 284 | } 285 | } 286 | } 287 | 288 | /// Triggered when a pointer moves over the map. 289 | void _onHover( 290 | {required Offset localPosition, required Matrix4 canvasToWorld}) { 291 | if (_onPanAndZoom) { 292 | return; 293 | } 294 | Offset worldCoordinate = 295 | MatrixUtils.transformPoint(canvasToWorld, localPosition); 296 | 297 | _controller.debugger?.updateMouseHover( 298 | locationOnCanvas: localPosition, worldCoordinate: worldCoordinate); 299 | 300 | MapSingleHighlight? hoverHighlightRule; 301 | for (int layerIndex = _controller.layersCount - 1; 302 | layerIndex >= 0; 303 | layerIndex--) { 304 | DrawableLayer drawableLayer = _controller.getDrawableLayer(layerIndex); 305 | DrawableFeature? drawableFeature = 306 | _findDrawableFeature(drawableLayer, worldCoordinate); 307 | if (drawableFeature != null) { 308 | MapLayer layer = drawableLayer.layer; 309 | hoverHighlightRule = MapSingleHighlight( 310 | layerId: layer.id, drawableFeature: drawableFeature); 311 | break; 312 | } 313 | } 314 | 315 | if (_controller.highlight != hoverHighlightRule) { 316 | _updateHover(hoverHighlightRule); 317 | } 318 | } 319 | 320 | /// Finds the first feature that contains a coordinate. 321 | DrawableFeature? _findDrawableFeature( 322 | DrawableLayer drawableLayer, Offset worldCoordinate) { 323 | for (DrawableLayerChunk chunk in drawableLayer.chunks) { 324 | for (int index = 0; index < chunk.length; index++) { 325 | DrawableFeature drawableFeature = chunk.getDrawableFeature(index); 326 | MapFeature feature = drawableFeature.feature; 327 | if (widget.hoverRule != null && widget.hoverRule!(feature) == false) { 328 | continue; 329 | } 330 | Drawable? drawable = drawableFeature.drawable; 331 | if (drawable != null && drawable.contains(worldCoordinate)) { 332 | return drawableFeature; 333 | } 334 | } 335 | } 336 | return null; 337 | } 338 | 339 | void _updateHover(MapSingleHighlight? hoverHighlightRule) { 340 | if (hoverHighlightRule != null) { 341 | _controller.setHighlight(hoverHighlightRule); 342 | } else { 343 | _controller.clearHighlight(); 344 | } 345 | if (widget.hoverListener != null) { 346 | widget.hoverListener!(hoverHighlightRule?.drawableFeature?.feature); 347 | } 348 | } 349 | } 350 | 351 | /// The [VectorMap] layout. 352 | class _VectorMapLayoutDelegate extends MultiChildLayoutDelegate { 353 | _VectorMapLayoutDelegate(this.count); 354 | 355 | final int count; 356 | 357 | @override 358 | void performLayout(Size size) { 359 | Size childSize = Size.zero; 360 | for (int id = 0; id < count; id++) { 361 | if (hasChild(id)) { 362 | if (id == 0) { 363 | childSize = layoutChild(id, BoxConstraints.tight(size)); 364 | positionChild(id, Offset.zero); 365 | } else { 366 | childSize = layoutChild(id, BoxConstraints.loose(size)); 367 | positionChild( 368 | id, 369 | Offset(size.width - childSize.width, 370 | size.height - childSize.height)); 371 | } 372 | } 373 | } 374 | } 375 | 376 | @override 377 | bool shouldRelayout(covariant MultiChildLayoutDelegate oldDelegate) { 378 | return false; 379 | } 380 | } 381 | 382 | typedef FeatureClickListener = Function(MapFeature feature); 383 | 384 | typedef HoverRule = bool Function(MapFeature feature); 385 | 386 | typedef HoverListener = Function(MapFeature? feature); 387 | -------------------------------------------------------------------------------- /lib/src/vector_map_api.dart: -------------------------------------------------------------------------------- 1 | import 'package:vector_map/src/map_highlight.dart'; 2 | 3 | /// Defines the map API. 4 | /// Through this class, plugins and addons will be able to automate the map. 5 | abstract class VectorMapApi { 6 | /// Removes the current highlight. 7 | void clearHighlight(); 8 | 9 | /// Sets a new highlight on the map. 10 | void setHighlight(MapHighlight newHighlight); 11 | } 12 | -------------------------------------------------------------------------------- /lib/src/vector_map_mode.dart: -------------------------------------------------------------------------------- 1 | /// Indicates in which interaction mode the map is working. 2 | enum VectorMapMode { autoFit, panAndZoom } 3 | -------------------------------------------------------------------------------- /lib/vector_map.dart: -------------------------------------------------------------------------------- 1 | library vector_map; 2 | 3 | export 'src/data_reader.dart'; 4 | export 'src/data/map_data_source.dart'; 5 | export 'src/data/geometries.dart'; 6 | export 'src/data/map_feature.dart'; 7 | export 'src/data/simplified_path.dart'; 8 | export 'src/data/property_limits.dart'; 9 | export 'src/error.dart'; 10 | export 'src/drawable/drawable_builder.dart'; 11 | export 'src/drawable/drawable.dart'; 12 | export 'src/drawable/drawable_feature.dart'; 13 | export 'src/drawable/drawable_path.dart'; 14 | export 'src/drawable/drawable_polygon.dart'; 15 | export 'src/drawable/drawable_line.dart'; 16 | export 'src/drawable/drawable_layer.dart'; 17 | export 'src/drawable/drawable_layer_chunk.dart'; 18 | export 'src/drawable/marker.dart'; 19 | export 'src/drawable/circle_marker.dart'; 20 | export 'src/data/map_layer.dart'; 21 | export 'src/debugger.dart'; 22 | export 'src/addon/map_addon.dart'; 23 | export 'src/addon/legend/legend.dart'; 24 | export 'src/addon/legend/gradient_legend.dart'; 25 | export 'src/simplifier.dart'; 26 | export 'src/map_highlight.dart'; 27 | export 'src/theme/map_theme.dart'; 28 | export 'src/theme/map_value_theme.dart'; 29 | export 'src/theme/map_rule_theme.dart'; 30 | export 'src/theme/map_gradient_theme.dart'; 31 | export 'src/theme/map_highlight_theme.dart'; 32 | export 'src/vector_map_api.dart'; 33 | export 'src/vector_map_mode.dart'; 34 | export 'src/low_quality_mode.dart'; 35 | export 'src/vector_map_controller.dart'; 36 | export 'src/vector_map.dart'; 37 | -------------------------------------------------------------------------------- /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 | url: "https://pub.dartlang.org" 9 | source: hosted 10 | version: "2.8.2" 11 | boolean_selector: 12 | dependency: transitive 13 | description: 14 | name: boolean_selector 15 | url: "https://pub.dartlang.org" 16 | source: hosted 17 | version: "2.1.0" 18 | characters: 19 | dependency: transitive 20 | description: 21 | name: characters 22 | url: "https://pub.dartlang.org" 23 | source: hosted 24 | version: "1.2.0" 25 | charcode: 26 | dependency: transitive 27 | description: 28 | name: charcode 29 | url: "https://pub.dartlang.org" 30 | source: hosted 31 | version: "1.3.1" 32 | clock: 33 | dependency: transitive 34 | description: 35 | name: clock 36 | url: "https://pub.dartlang.org" 37 | source: hosted 38 | version: "1.1.0" 39 | collection: 40 | dependency: transitive 41 | description: 42 | name: collection 43 | url: "https://pub.dartlang.org" 44 | source: hosted 45 | version: "1.15.0" 46 | fake_async: 47 | dependency: transitive 48 | description: 49 | name: fake_async 50 | url: "https://pub.dartlang.org" 51 | source: hosted 52 | version: "1.2.0" 53 | flutter: 54 | dependency: "direct main" 55 | description: flutter 56 | source: sdk 57 | version: "0.0.0" 58 | flutter_test: 59 | dependency: "direct dev" 60 | description: flutter 61 | source: sdk 62 | version: "0.0.0" 63 | matcher: 64 | dependency: transitive 65 | description: 66 | name: matcher 67 | url: "https://pub.dartlang.org" 68 | source: hosted 69 | version: "0.12.11" 70 | material_color_utilities: 71 | dependency: transitive 72 | description: 73 | name: material_color_utilities 74 | url: "https://pub.dartlang.org" 75 | source: hosted 76 | version: "0.1.3" 77 | meta: 78 | dependency: "direct main" 79 | description: 80 | name: meta 81 | url: "https://pub.dartlang.org" 82 | source: hosted 83 | version: "1.7.0" 84 | path: 85 | dependency: transitive 86 | description: 87 | name: path 88 | url: "https://pub.dartlang.org" 89 | source: hosted 90 | version: "1.8.0" 91 | sky_engine: 92 | dependency: transitive 93 | description: flutter 94 | source: sdk 95 | version: "0.0.99" 96 | source_span: 97 | dependency: transitive 98 | description: 99 | name: source_span 100 | url: "https://pub.dartlang.org" 101 | source: hosted 102 | version: "1.8.1" 103 | stack_trace: 104 | dependency: transitive 105 | description: 106 | name: stack_trace 107 | url: "https://pub.dartlang.org" 108 | source: hosted 109 | version: "1.10.0" 110 | stream_channel: 111 | dependency: transitive 112 | description: 113 | name: stream_channel 114 | url: "https://pub.dartlang.org" 115 | source: hosted 116 | version: "2.1.0" 117 | string_scanner: 118 | dependency: transitive 119 | description: 120 | name: string_scanner 121 | url: "https://pub.dartlang.org" 122 | source: hosted 123 | version: "1.1.0" 124 | term_glyph: 125 | dependency: transitive 126 | description: 127 | name: term_glyph 128 | url: "https://pub.dartlang.org" 129 | source: hosted 130 | version: "1.2.0" 131 | test_api: 132 | dependency: transitive 133 | description: 134 | name: test_api 135 | url: "https://pub.dartlang.org" 136 | source: hosted 137 | version: "0.4.8" 138 | typed_data: 139 | dependency: transitive 140 | description: 141 | name: typed_data 142 | url: "https://pub.dartlang.org" 143 | source: hosted 144 | version: "1.3.0" 145 | vector_math: 146 | dependency: transitive 147 | description: 148 | name: vector_math 149 | url: "https://pub.dartlang.org" 150 | source: hosted 151 | version: "2.1.1" 152 | sdks: 153 | dart: ">=2.14.0 <3.0.0" 154 | flutter: ">=1.17.0" 155 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: vector_map 2 | description: Vector map for Flutter. Highly customizable. Compatible with GeoJSON. Map chart. Pure Flutter. 3 | version: 0.7.0 4 | repository: https://github.com/caduandrade/vector_map_flutter 5 | 6 | environment: 7 | sdk: ">=2.12.0 <3.0.0" 8 | flutter: ">=1.17.0" 9 | 10 | dependencies: 11 | flutter: 12 | sdk: flutter 13 | meta: ^1.7.0 14 | 15 | dev_dependencies: 16 | flutter_test: 17 | sdk: flutter 18 | 19 | # For information on the generic Dart part of this file, see the 20 | # following page: https://dart.dev/tools/pub/pubspec 21 | 22 | # The following section is specific to Flutter. 23 | flutter: 24 | # To add assets to your package, add an assets section, like this: 25 | # assets: 26 | # - images/a_dot_ham.jpeg 27 | # 28 | # For details regarding assets in packages, see 29 | # https://flutter.dev/assets-and-images/#from-packages 30 | # 31 | # An image asset can refer to one or more resolution-specific "variants", see 32 | # https://flutter.dev/assets-and-images/#resolution-aware. 33 | 34 | # To add custom fonts to your package, add a fonts section here, 35 | # in this "flutter" section. Each entry in this list should have a 36 | # "family" key with the font family name, and a "fonts" key with a 37 | # list giving the asset and other descriptors for the font. For 38 | # example: 39 | # fonts: 40 | # - family: Schyler 41 | # fonts: 42 | # - asset: fonts/Schyler-Regular.ttf 43 | # - asset: fonts/Schyler-Italic.ttf 44 | # style: italic 45 | # - family: Trajan Pro 46 | # fonts: 47 | # - asset: fonts/TrajanPro.ttf 48 | # - asset: fonts/TrajanPro_Bold.ttf 49 | # weight: 700 50 | # 51 | # For details regarding fonts in packages, see 52 | # https://flutter.dev/custom-fonts/#from-packages 53 | --------------------------------------------------------------------------------