From cf25de6e6200aa49702e9ae7b84319381409bb35 Mon Sep 17 00:00:00 2001 From: Tarek Tolba Date: Wed, 28 May 2025 10:12:55 +0300 Subject: [PATCH 1/5] Basemap styles cleanup --- .../arcgis_map_sdk_android/Parsing.kt | 149 +++++----- .../arcgis_map_sdk_ios/ArcgisMapView.swift | 105 ++++--- .../arcgis_map_sdk_ios/GraphicsParser.swift | 2 +- .../lib/src/models/basemap.dart | 65 ++--- .../lib/src/model_extension.dart | 65 +++-- .../xcshareddata/xcschemes/Runner.xcscheme | 2 +- example/lib/basemap_style_example_page.dart | 268 ++++++++++++++++++ example/lib/main.dart | 21 +- example/lib/pointer_interceptor_web.dart | 27 ++ example/pubspec.lock | 24 +- 10 files changed, 524 insertions(+), 204 deletions(-) create mode 100644 example/lib/basemap_style_example_page.dart create mode 100644 example/lib/pointer_interceptor_web.dart diff --git a/arcgis_map_sdk_android/android/src/main/kotlin/dev/fluttercommunity/arcgis_map_sdk_android/Parsing.kt b/arcgis_map_sdk_android/android/src/main/kotlin/dev/fluttercommunity/arcgis_map_sdk_android/Parsing.kt index 80181c74..a5762ac7 100644 --- a/arcgis_map_sdk_android/android/src/main/kotlin/dev/fluttercommunity/arcgis_map_sdk_android/Parsing.kt +++ b/arcgis_map_sdk_android/android/src/main/kotlin/dev/fluttercommunity/arcgis_map_sdk_android/Parsing.kt @@ -178,90 +178,73 @@ fun parseAnimationCurve(value: String): AnimationCurve { } } -fun BasemapStyle.getJsonValue(): String? { - return when (this) { - BasemapStyle.ArcGISImagery -> "arcgisImagery" - BasemapStyle.ArcGISImageryStandard -> "arcgisImageryStandard" - BasemapStyle.ArcGISImageryLabels -> "arcgisImageryLabels" - BasemapStyle.ArcGISLightGray -> "arcgisLightGray" - BasemapStyle.ArcGISLightGray -> null - BasemapStyle.ArcGISLightGrayLabels -> null - BasemapStyle.ArcGISDarkGray -> "arcgisDarkGray" - BasemapStyle.ArcGISDarkGrayBase -> null - BasemapStyle.ArcGISDarkGrayLabels -> null - BasemapStyle.ArcGISNavigation -> "arcgisNavigation" - BasemapStyle.ArcGISNavigationNight -> "arcgisNavigationNight" - BasemapStyle.ArcGISStreets -> "arcgisStreets" - BasemapStyle.ArcGISStreetsNight -> "arcgisStreetsNight" - BasemapStyle.OsmStreetsRelief -> "arcgisStreetsRelief" - BasemapStyle.ArcGISTopographic -> "arcgisTopographic" - BasemapStyle.ArcGISOceans -> "arcgisOceans" - BasemapStyle.ArcGISOceansBase -> null - BasemapStyle.ArcGISOceansLabels -> null - BasemapStyle.ArcGISTerrain -> "arcgisTerrain" - BasemapStyle.ArcGISTerrainBase -> null - BasemapStyle.ArcGISTerrainDetail -> null - BasemapStyle.ArcGISCommunity -> "arcgisCommunity" - BasemapStyle.ArcGISChartedTerritory -> "arcgisChartedTerritory" - BasemapStyle.ArcGISColoredPencil -> "arcgisColoredPencil" - BasemapStyle.ArcGISNova -> "arcgisNova" - BasemapStyle.ArcGISModernAntique -> "arcgisModernAntique" - BasemapStyle.ArcGISMidcentury -> "arcgisMidcentury" - BasemapStyle.ArcGISNewspaper -> "arcgisNewspaper" - BasemapStyle.ArcGISHillshadeLight -> "arcgisHillshadeLight" - BasemapStyle.ArcGISHillshadeDark -> "arcgisHillshadeDark" - BasemapStyle.ArcGISStreetsReliefBase -> null - BasemapStyle.ArcGISTopographicBase -> null - BasemapStyle.ArcGISChartedTerritoryBase -> null - BasemapStyle.ArcGISModernAntiqueBase -> null - BasemapStyle.OsmStandard -> "osmStandard" - BasemapStyle.OsmStandardRelief -> "osmStandardRelief" - BasemapStyle.OsmStandardReliefBase -> null - BasemapStyle.OsmStreets -> "osmStreets" - BasemapStyle.OsmStreetsRelief -> "osmStreetsRelief" - BasemapStyle.OsmStreetsReliefBase -> null - BasemapStyle.OsmLightGray -> "osmLightGray" - BasemapStyle.OsmLightGrayBase -> null - BasemapStyle.OsmLightGrayLabels -> null - BasemapStyle.OsmDarkGray -> "osmDarkGray" - BasemapStyle.OsmDarkGrayBase -> null - BasemapStyle.OsmDarkGrayLabels -> null - BasemapStyle.OsmHybrid -> "hybrid" - else -> null - } +private val basemapStyleMapping = mapOf( + BasemapStyle.ArcGISImagery to "arcgisImagery", + BasemapStyle.ArcGISImageryStandard to "arcgisImageryStandard", + BasemapStyle.ArcGISImageryLabels to "arcgisImageryLabels", + BasemapStyle.ArcGISLightGray to "arcgisLightGray", + BasemapStyle.ArcGISLightGrayBase to "arcgisLightGrayBase", + BasemapStyle.ArcGISLightGrayLabels to "arcgisLightGrayLabels", + BasemapStyle.ArcGISDarkGray to "arcgisDarkGray", + BasemapStyle.ArcGISDarkGrayBase to "arcgisDarkGrayBase", + BasemapStyle.ArcGISDarkGrayLabels to "arcgisDarkGrayLabels", + BasemapStyle.ArcGISNavigation to "arcgisNavigation", + BasemapStyle.ArcGISNavigationNight to "arcgisNavigationNight", + BasemapStyle.ArcGISStreets to "arcgisStreets", + BasemapStyle.ArcGISStreetsRelief to "arcgisStreetsRelief", + BasemapStyle.ArcGISStreetsReliefBase to "arcgisStreetsReliefBase", + BasemapStyle.ArcGISStreetsNight to "arcgisStreetsNight", + BasemapStyle.ArcGISTopographic to "arcgisTopographic", + BasemapStyle.ArcGISTopographicBase to "arcgisTopographicBase", + BasemapStyle.ArcGISOceans to "arcgisOceans", + BasemapStyle.ArcGISOceansBase to "arcgisOceansBase", + BasemapStyle.ArcGISOceansLabels to "arcgisOceansLabels", + BasemapStyle.ArcGISTerrain to "arcgisTerrain", + BasemapStyle.ArcGISTerrainBase to "arcgisTerrainBase", + BasemapStyle.ArcGISTerrainDetail to "arcgisTerrainDetail", + BasemapStyle.ArcGISCommunity to "arcgisCommunity", + BasemapStyle.ArcGISChartedTerritory to "arcgisChartedTerritory", + BasemapStyle.ArcGISChartedTerritoryBase to "arcgisChartedTerritoryBase", + BasemapStyle.ArcGISColoredPencil to "arcgisColoredPencil", + BasemapStyle.ArcGISNova to "arcgisNova", + BasemapStyle.ArcGISModernAntique to "arcgisModernAntique", + BasemapStyle.ArcGISModernAntiqueBase to "arcgisModernAntiqueBase", + BasemapStyle.ArcGISMidcentury to "arcgisMidcentury", + BasemapStyle.ArcGISNewspaper to "arcgisNewspaper", + BasemapStyle.ArcGISHillshadeLight to "arcgisHillshadeLight", + BasemapStyle.ArcGISHillshadeDark to "arcgisHillshadeDark", + BasemapStyle.ArcGISOutdoor to "arcgisOutdoor", + BasemapStyle.ArcGISHumanGeography to "arcgisHumanGeography", + BasemapStyle.ArcGISHumanGeographyBase to "arcgisHumanGeographyBase", + BasemapStyle.ArcGISHumanGeographyDetail to "arcgisHumanGeographyDetail", + BasemapStyle.ArcGISHumanGeographyLabels to "arcgisHumanGeographyLabels", + BasemapStyle.ArcGISHumanGeographyDark to "arcgisHumanGeographyDark", + BasemapStyle.ArcGISHumanGeographyDarkBase to "arcgisHumanGeographyDarkBase", + BasemapStyle.ArcGISHumanGeographyDarkDetail to "arcgisHumanGeographyDarkDetail", + BasemapStyle.ArcGISHumanGeographyDarkLabels to "arcgisHumanGeographyDarkLabels", + BasemapStyle.OsmStandard to "osmStandard", + BasemapStyle.OsmStandardRelief to "osmStandardRelief", + BasemapStyle.OsmStandardReliefBase to "osmStandardReliefBase", + BasemapStyle.OsmStreets to "osmStreets", + BasemapStyle.OsmStreetsRelief to "osmStreetsRelief", + BasemapStyle.OsmStreetsReliefBase to "osmStreetsReliefBase", + BasemapStyle.OsmLightGray to "osmLightGray", + BasemapStyle.OsmLightGrayBase to "osmLightGrayBase", + BasemapStyle.OsmLightGrayLabels to "osmLightGrayLabels", + BasemapStyle.OsmDarkGray to "osmDarkGray", + BasemapStyle.OsmDarkGrayBase to "osmDarkGrayBase", + BasemapStyle.OsmDarkGrayLabels to "osmDarkGrayLabels", + BasemapStyle.OsmBlueprint to "osmBlueprint", + BasemapStyle.OsmHybrid to "osmHybrid", + BasemapStyle.OsmHybridDetail to "osmHybridDetail", + BasemapStyle.OsmNavigation to "osmNavigation", + BasemapStyle.OsmNavigationDark to "osmNavigationDark" +) + +fun BasemapStyle.getJsonValue(): String { + return basemapStyleMapping[this]!! } fun parseBasemapStyle(value: String): BasemapStyle? { - return when (value) { - "arcgisImagery" -> BasemapStyle.ArcGISImagery - "arcgisImageryStandard" -> BasemapStyle.ArcGISImageryStandard - "arcgisImageryLabels" -> BasemapStyle.ArcGISImageryLabels - "arcgisLightGray" -> BasemapStyle.ArcGISLightGray - "arcgisDarkGray" -> BasemapStyle.ArcGISDarkGray - "arcgisNavigation" -> BasemapStyle.ArcGISNavigation - "arcgisNavigationNight" -> BasemapStyle.ArcGISNavigationNight - "arcgisStreets" -> BasemapStyle.ArcGISStreets - "arcgisStreetsNight" -> BasemapStyle.ArcGISStreetsNight - "arcgisStreetsRelief" -> BasemapStyle.OsmStreetsRelief - "arcgisTopographic" -> BasemapStyle.ArcGISTopographic - "arcgisOceans" -> BasemapStyle.ArcGISOceans - "arcgisTerrain" -> BasemapStyle.ArcGISTerrain - "arcgisCommunity" -> BasemapStyle.ArcGISCommunity - "arcgisChartedTerritory" -> BasemapStyle.ArcGISChartedTerritory - "arcgisColoredPencil" -> BasemapStyle.ArcGISColoredPencil - "arcgisNova" -> BasemapStyle.ArcGISNova - "arcgisModernAntique" -> BasemapStyle.ArcGISModernAntique - "arcgisMidcentury" -> BasemapStyle.ArcGISMidcentury - "arcgisNewspaper" -> BasemapStyle.ArcGISNewspaper - "arcgisHillshadeLight" -> BasemapStyle.ArcGISHillshadeLight - "arcgisHillshadeDark" -> BasemapStyle.ArcGISHillshadeDark - "osmStandard" -> BasemapStyle.OsmStandard - "osmStandardRelief" -> BasemapStyle.OsmStandardRelief - "osmStreets" -> BasemapStyle.OsmStreets - "osmStreetsRelief" -> BasemapStyle.OsmStreetsRelief - "osmLightGray" -> BasemapStyle.OsmLightGray - "osmDarkGray" -> BasemapStyle.OsmDarkGray - "hybrid" -> BasemapStyle.OsmHybrid - else -> null - } + return basemapStyleMapping.entries.firstOrNull { it.value == value }?.key } diff --git a/arcgis_map_sdk_ios/ios/arcgis_map_sdk_ios/Sources/arcgis_map_sdk_ios/ArcgisMapView.swift b/arcgis_map_sdk_ios/ios/arcgis_map_sdk_ios/Sources/arcgis_map_sdk_ios/ArcgisMapView.swift index 2d36eedb..3f2f9ed9 100644 --- a/arcgis_map_sdk_ios/ios/arcgis_map_sdk_ios/Sources/arcgis_map_sdk_ios/ArcgisMapView.swift +++ b/arcgis_map_sdk_ios/ios/arcgis_map_sdk_ios/Sources/arcgis_map_sdk_ios/ArcgisMapView.swift @@ -615,7 +615,9 @@ extension Basemap.Style: CaseIterable { .arcGISStreets, .arcGISStreetsNight, .arcGISStreetsRelief, + .arcGISStreetsReliefBase, .arcGISTopographic, + .arcGISTopographicBase, .arcGISOceans, .arcGISOceansBase, .arcGISOceansLabels, @@ -624,29 +626,41 @@ extension Basemap.Style: CaseIterable { .arcGISTerrainDetail, .arcGISCommunity, .arcGISChartedTerritory, + .arcGISChartedTerritoryBase, .arcGISColoredPencil, .arcGISNova, .arcGISModernAntique, + .arcGISModernAntiqueBase, .arcGISMidcentury, .arcGISNewspaper, .arcGISHillshadeLight, .arcGISHillshadeDark, - .arcGISStreetsReliefBase, - .arcGISTopographicBase, - .arcGISChartedTerritoryBase, - .arcGISModernAntiqueBase, + .arcGISOutdoor, + .arcGISHumanGeography, + .arcGISHumanGeographyBase, + .arcGISHumanGeographyDetail, + .arcGISHumanGeographyLabels, + .arcGISHumanGeographyDark, + .arcGISHumanGeographyDarkBase, + .arcGISHumanGeographyDarkDetail, + .arcGISHumanGeographyDarkLabels, .osmStandard, .osmStandardRelief, .osmStandardReliefBase, .osmStreets, .osmStreetsRelief, + .osmStreetsReliefBase, .osmLightGray, .osmLightGrayBase, .osmLightGrayLabels, .osmDarkGray, .osmDarkGrayBase, .osmDarkGrayLabels, - .osmStreetsReliefBase + .osmBlueprint, + .osmHybrid, + .osmHybridDetail, + .osmNavigation, + .osmNavigationDark, ] } } @@ -663,49 +677,57 @@ extension Basemap.Style { case .arcGISLightGray: return "arcgisLightGray" case .arcGISLightGrayBase: - return "arcgisDarkGray" + return "arcgisLightGrayBase" case .arcGISLightGrayLabels: - return nil + return "arcgisLightGrayLabels" case .arcGISDarkGray: - return nil + return "arcgisDarkGray" case .arcGISDarkGrayBase: - return nil + return "arcgisDarkGrayBase" case .arcGISDarkGrayLabels: - return nil + return "arcgisDarkGrayLabels" case .arcGISNavigation: return "arcgisNavigation" case .arcGISNavigationNight: return "arcgisNavigationNight" case .arcGISStreets: return "arcgisStreets" - case .arcGISStreetsNight: - return "arcgisStreetsNight" case .arcGISStreetsRelief: return "arcgisStreetsRelief" + case .arcGISStreetsReliefBase: + return "arcgisStreetsReliefBase" + case .arcGISStreetsNight: + return "arcgisStreetsNight" case .arcGISTopographic: return "arcgisTopographic" + case .arcGISTopographicBase: + return "arcgisTopographicBase" case .arcGISOceans: return "arcgisOceans" case .arcGISOceansBase: - return nil + return "arcgisOceansBase" case .arcGISOceansLabels: - return nil + return "arcgisOceansLabels" case .arcGISTerrain: return "arcgisTerrain" case .arcGISTerrainBase: - return nil + return "arcgisTerrainBase" case .arcGISTerrainDetail: - return nil + return "arcgisTerrainDetail" case .arcGISCommunity: return "arcgisCommunity" case .arcGISChartedTerritory: return "arcgisChartedTerritory" + case .arcGISChartedTerritoryBase: + return "arcgisChartedTerritoryBase" case .arcGISColoredPencil: return "arcgisColoredPencil" case .arcGISNova: return "arcgisNova" case .arcGISModernAntique: return "arcgisModernAntique" + case .arcGISModernAntiqueBase: + return "arcgisModernAntiqueBase" case .arcGISMidcentury: return "arcgisMidcentury" case .arcGISNewspaper: @@ -714,14 +736,24 @@ extension Basemap.Style { return "arcgisHillshadeLight" case .arcGISHillshadeDark: return "arcgisHillshadeDark" - case .arcGISStreetsReliefBase: - return nil - case .arcGISTopographicBase: - return nil - case .arcGISChartedTerritoryBase: - return nil - case .arcGISModernAntiqueBase: - return nil + case .arcGISOutdoor: + return "arcgisOutdoor" + case .arcGISHumanGeography: + return "arcgisHumanGeography" + case .arcGISHumanGeographyBase: + return "arcgisHumanGeographyBase" + case .arcGISHumanGeographyDetail: + return "arcgisHumanGeographyDetail" + case .arcGISHumanGeographyLabels: + return "arcgisHumanGeographyLabels" + case .arcGISHumanGeographyDark: + return "arcgisHumanGeographyDark" + case .arcGISHumanGeographyDarkBase: + return "arcgisHumanGeographyDarkBase" + case .arcGISHumanGeographyDarkDetail: + return "arcgisHumanGeographyDarkDetail" + case .arcGISHumanGeographyDarkLabels: + return "arcgisHumanGeographyDarkLabels" case .osmStandard: return "osmStandard" case .osmStandardRelief: @@ -732,22 +764,31 @@ extension Basemap.Style { return "osmStreets" case .osmStreetsRelief: return "osmStreetsRelief" + case .osmStreetsReliefBase: + return "osmStreetsReliefBase" case .osmLightGray: return "osmLightGray" case .osmLightGrayBase: - return nil + return "osmLightGrayBase" case .osmLightGrayLabels: - return nil + return "osmLightGrayLabels" case .osmDarkGray: return "osmDarkGray" case .osmDarkGrayBase: - return nil + return "osmDarkGrayBase" case .osmDarkGrayLabels: - return nil - case .osmStreetsReliefBase: - return nil - @unknown default: - return nil + return "osmDarkGrayLabels" + case .osmBlueprint: + return "osmBlueprint" + case .osmHybrid: + return "osmHybrid" + case .osmHybridDetail: + return "osmHybridDetail" + case .osmNavigation: + return "osmNavigation" + case .osmNavigationDark: + return "osmNavigationDark" + } } } diff --git a/arcgis_map_sdk_ios/ios/arcgis_map_sdk_ios/Sources/arcgis_map_sdk_ios/GraphicsParser.swift b/arcgis_map_sdk_ios/ios/arcgis_map_sdk_ios/Sources/arcgis_map_sdk_ios/GraphicsParser.swift index 04cf4dc2..3217c088 100644 --- a/arcgis_map_sdk_ios/ios/arcgis_map_sdk_ios/Sources/arcgis_map_sdk_ios/GraphicsParser.swift +++ b/arcgis_map_sdk_ios/ios/arcgis_map_sdk_ios/Sources/arcgis_map_sdk_ios/GraphicsParser.swift @@ -98,7 +98,7 @@ class GraphicsParser { case "simple-marker": return parseSimpleMarkerSymbol(dictionary) case "picture-marker": - return parsePictureMarkerSymbol(dictionary) + return try parsePictureMarkerSymbol(dictionary) case "simple-fill": return parseSimpleFillMarkerSymbol(dictionary) case "simple-line": diff --git a/arcgis_map_sdk_platform_interface/lib/src/models/basemap.dart b/arcgis_map_sdk_platform_interface/lib/src/models/basemap.dart index 35ec6623..5f3de3d4 100644 --- a/arcgis_map_sdk_platform_interface/lib/src/models/basemap.dart +++ b/arcgis_map_sdk_platform_interface/lib/src/models/basemap.dart @@ -3,59 +3,60 @@ enum BaseMap { arcgisImageryStandard, arcgisImageryLabels, arcgisLightGray, + arcgisLightGrayBase, + arcgisLightGrayLabels, arcgisDarkGray, + arcgisDarkGrayBase, + arcgisDarkGrayLabels, arcgisNavigation, arcgisNavigationNight, - arcgisOutdoor, arcgisStreets, arcgisStreetsNight, arcgisStreetsRelief, + arcgisStreetsReliefBase, arcgisTopographic, arcgisTopographicBase, arcgisOceans, arcgisOceansBase, arcgisOceansLabels, - osmStandard, - osmStandardRelief, - osmStandardReliefBase, - osmNavigation, - osmNavigationDark, - osmStreetsReliefBase, - osmHybrid, - osmStreets, - osmDarkGrayBase, + arcgisTerrain, arcgisTerrainBase, arcgisTerrainDetail, - osmStreetsRelief, - osmLightGray, - osmDarkGray, - arcgisTerrain, arcgisCommunity, arcgisChartedTerritory, arcgisChartedTerritoryBase, - arcgisStreetsReliefBase, arcgisColoredPencil, arcgisNova, arcgisModernAntique, + arcgisModernAntiqueBase, arcgisMidcentury, arcgisNewspaper, arcgisHillshadeLight, arcgisHillshadeDark, - nationalGepgraphic, - streetsNavigationVector, - darkGrayVector, - grayVector, - topo, - gray, - darkGray, - terrain, - hybrid, - streets, - oceans, - osm, - satellite, - topoVector, - streetsNightVector, - streetsVector, - streetsReliefVector, + arcgisOutdoor, + arcgisHumanGeography, + arcgisHumanGeographyBase, + arcgisHumanGeographyDetail, + arcgisHumanGeographyLabels, + arcgisHumanGeographyDark, + arcgisHumanGeographyDarkBase, + arcgisHumanGeographyDarkDetail, + arcgisHumanGeographyDarkLabels, + osmStandard, + osmStandardRelief, + osmStandardReliefBase, + osmStreets, + osmStreetsRelief, + osmStreetsReliefBase, + osmLightGray, + osmLightGrayBase, + osmLightGrayLabels, + osmDarkGray, + osmDarkGrayBase, + osmDarkGrayLabels, + osmBlueprint, + osmHybrid, + osmHybridDetail, + osmNavigation, + osmNavigationDark, } diff --git a/arcgis_map_sdk_web/lib/src/model_extension.dart b/arcgis_map_sdk_web/lib/src/model_extension.dart index 32e3aa7e..b2175ba4 100644 --- a/arcgis_map_sdk_web/lib/src/model_extension.dart +++ b/arcgis_map_sdk_web/lib/src/model_extension.dart @@ -195,31 +195,22 @@ extension BaseMapExt on BaseMap { BaseMap.arcgisImageryStandard: 'arcgis/imagery/standard', BaseMap.arcgisImageryLabels: 'arcgis/imagery/labels', BaseMap.arcgisLightGray: 'arcgis/light-gray', + BaseMap.arcgisLightGrayBase: 'arcgis/light-gray/base', + BaseMap.arcgisLightGrayLabels: 'arcgis/light-gray/labels', BaseMap.arcgisDarkGray: 'arcgis/dark-gray', + BaseMap.arcgisDarkGrayBase: 'arcgis/dark-gray/base', + BaseMap.arcgisDarkGrayLabels: 'arcgis/dark-gray/labels', BaseMap.arcgisNavigation: 'arcgis/navigation', BaseMap.arcgisNavigationNight: 'arcgis/navigation-night', BaseMap.arcgisStreets: 'arcgis/streets', - BaseMap.arcgisStreetsNight: 'arcgis/streets-night', BaseMap.arcgisStreetsRelief: 'arcgis/streets-relief', BaseMap.arcgisStreetsReliefBase: 'arcgis/streets-relief-base', - BaseMap.arcgisOutdoor: 'arcgis/outdoor', + BaseMap.arcgisStreetsNight: 'arcgis/streets-night', BaseMap.arcgisTopographic: 'arcgis/topographic', BaseMap.arcgisTopographicBase: 'arcgis/topographic/base', BaseMap.arcgisOceans: 'arcgis/oceans', BaseMap.arcgisOceansBase: 'arcgis/oceans/base', BaseMap.arcgisOceansLabels: 'arcgis/oceans/labels', - BaseMap.osmStandard: 'osm/standard', - BaseMap.osmStandardRelief: 'osm/standard-relief', - BaseMap.osmStandardReliefBase: 'osm/standard-relief/base', - BaseMap.osmNavigation: 'osm/navigation', - BaseMap.osmNavigationDark: 'osm/navigation-dark', - BaseMap.osmStreets: 'osm/streets', - BaseMap.osmStreetsRelief: 'osm/streets-relief', - BaseMap.osmStreetsReliefBase: 'osm/streets-relief/base', - BaseMap.osmLightGray: 'osm/light-gray', - BaseMap.osmHybrid: 'osm/hybrid', - BaseMap.osmDarkGray: 'osm/dark-gray', - BaseMap.osmDarkGrayBase: 'osm/dark-gray/base', BaseMap.arcgisTerrain: 'arcgis/terrain', BaseMap.arcgisTerrainBase: 'arcgis/terrain/base', BaseMap.arcgisTerrainDetail: 'arcgis/terrain/detail', @@ -229,27 +220,39 @@ extension BaseMapExt on BaseMap { BaseMap.arcgisColoredPencil: 'arcgis/colored-pencil', BaseMap.arcgisNova: 'arcgis/nova', BaseMap.arcgisModernAntique: 'arcgis-modern-antique', + BaseMap.arcgisModernAntiqueBase: 'arcgis-modern-antique-base', BaseMap.arcgisMidcentury: 'arcgis/midcentury', BaseMap.arcgisNewspaper: 'arcgis/newspaper', BaseMap.arcgisHillshadeLight: 'arcgis/hillshade-light', BaseMap.arcgisHillshadeDark: 'arcgis/hillshade-dark', - BaseMap.nationalGepgraphic: 'national-geographic', - BaseMap.streetsNavigationVector: 'streets-navigation-vector', - BaseMap.darkGrayVector: 'dark-gray-vector', - BaseMap.grayVector: 'gray-vector', - BaseMap.topo: 'topo', - BaseMap.gray: 'gray', - BaseMap.darkGray: 'dark-gray', - BaseMap.terrain: 'terrain', - BaseMap.hybrid: 'hybrid', - BaseMap.streets: 'streets', - BaseMap.oceans: 'oceans', - BaseMap.osm: 'osm', - BaseMap.satellite: 'satellite', - BaseMap.topoVector: 'topo-vector', - BaseMap.streetsNightVector: 'streets-night-vector', - BaseMap.streetsVector: 'streets-vector', - BaseMap.streetsReliefVector: 'streets-relief-vector', + BaseMap.arcgisOutdoor: 'arcgis/outdoor', + BaseMap.arcgisHumanGeography: 'arcgis/human-geography', + BaseMap.arcgisHumanGeographyBase: 'arcgis/human-geography/base', + BaseMap.arcgisHumanGeographyDetail: 'arcgis/human-geography/detail', + BaseMap.arcgisHumanGeographyLabels: 'arcgis/human-geography-labels', + BaseMap.arcgisHumanGeographyDark: 'arcgis/human-geography-dark', + BaseMap.arcgisHumanGeographyDarkBase: 'arcgis/human-geography-dark/base', + BaseMap.arcgisHumanGeographyDarkDetail: + 'arcgis/human-geography-dark/detail', + BaseMap.arcgisHumanGeographyDarkLabels: + 'arcgis/human-geography-dark-labels', + BaseMap.osmStandard: 'osm/standard', + BaseMap.osmStandardRelief: 'osm/standard-relief', + BaseMap.osmStandardReliefBase: 'osm/standard-relief/base', + BaseMap.osmStreets: 'osm/streets', + BaseMap.osmStreetsRelief: 'osm/streets-relief', + BaseMap.osmStreetsReliefBase: 'osm/streets-relief/base', + BaseMap.osmLightGray: 'osm/light-gray', + BaseMap.osmLightGrayBase: 'osm/light-gray/base', + BaseMap.osmLightGrayLabels: 'osm/light-gray/labels', + BaseMap.osmDarkGray: 'osm/dark-gray', + BaseMap.osmDarkGrayBase: 'osm/dark-gray/base', + BaseMap.osmDarkGrayLabels: 'osm/dark-gray/labels', + BaseMap.osmBlueprint: 'osm/blueprint', + BaseMap.osmHybrid: 'osm/hybrid', + BaseMap.osmHybridDetail: 'osm/hybrid-detail', + BaseMap.osmNavigation: 'osm/navigation', + BaseMap.osmNavigationDark: 'osm/navigation-dark', }; String get value => values[this]!; diff --git a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 128d5765..4ef8712a 100644 --- a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,7 +1,7 @@ + version = "1.7"> diff --git a/example/lib/basemap_style_example_page.dart b/example/lib/basemap_style_example_page.dart new file mode 100644 index 00000000..decaa020 --- /dev/null +++ b/example/lib/basemap_style_example_page.dart @@ -0,0 +1,268 @@ +import 'dart:async'; + +import 'package:arcgis_example/main.dart'; +import 'package:arcgis_example/map_elements.dart'; +import 'package:arcgis_example/pointer_interceptor_web.dart'; +import 'package:arcgis_map_sdk/arcgis_map_sdk.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; + +/// Example 3D SceneLayer page. +class BasemapStyleExamplePage extends StatefulWidget { + const BasemapStyleExamplePage({super.key}); + + @override + State createState() => + _BasemapStyleExamplePageState(); +} + +class _BasemapStyleExamplePageState extends State { + /// null when executed on a platform that's not supported yet + ArcgisMapController? _controller; + BaseMap selectedBasemap = BaseMap.values.first; + bool show3dMap = false; + bool isBasemapMenuOpened = false; + final initialCenter = const LatLng(51.16, 10.45); + final tappedHQ = const LatLng(48.1234963, 11.5910182); + + VoidCallback? _removeStatusListener; + + final _scaffoldKey = GlobalKey(); + + @override + void dispose() { + _removeStatusListener?.call(); + + super.dispose(); + } + + Future _onMapCreated(ArcgisMapController controller) async { + _controller = controller; + + _removeStatusListener = + _controller!.addStatusChangeListener(_onMapStatusChanged); + + // TODO: Remove when mobile implementation is complete + if (kIsWeb) { + // Create basic 3D Layer with elevation and 3D buildings + await _createSceneLayer(); + } + } + + Future _createSceneLayer() async { + final layer = await _controller?.addSceneLayer( + layerId: '3D Buildings', + options: SceneLayerOptions( + symbol: mesh3d, + ), + url: + 'https://basemaps3d.arcgis.com/arcgis/rest/services/OpenStreetMap3D_Buildings_v1/SceneServer', + ); + return layer; + } + + @override + Widget build(BuildContext context) { + return Scaffold( + // appBar: AppBar(), + key: _scaffoldKey, + body: GestureDetector( + onTap: () { + setState(() { + isBasemapMenuOpened = false; + }); + }, + child: Stack( + children: [ + ArcgisMap( + mapStyle: show3dMap ? MapStyle.threeD : MapStyle.twoD, + apiKey: arcGisApiKey, + basemap: BaseMap.osmDarkGray, + ground: show3dMap ? Ground.worldElevation : null, + showLabelsBeneathGraphics: true, + initialCenter: initialCenter, + zoom: 8, + rotationEnabled: true, + onMapCreated: _onMapCreated, + defaultUiList: [ + DefaultWidget( + viewType: DefaultWidgetType.compass, + position: WidgetPosition.topRight, + ), + ], + ), + Positioned( + top: MediaQuery.paddingOf(context).top + 8, + left: 8, + child: BackButton( + color: Colors.black, + style: ButtonStyle( + backgroundColor: WidgetStatePropertyAll(Colors.grey)), + ), + ), + Positioned( + bottom: 40, + right: 0, + left: 0, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + FloatingActionButton( + heroTag: "zoom-in-button", + onPressed: () { + _controller?.zoomIn( + lodFactor: 1, + animationOptions: AnimationOptions( + duration: 1000, + animationCurve: AnimationCurve.easeIn, + ), + ); + }, + backgroundColor: Colors.grey, + child: const Icon(Icons.add), + ), + FloatingActionButton( + heroTag: "zoom-out-button", + onPressed: () { + _controller?.zoomOut( + lodFactor: 1, + animationOptions: AnimationOptions( + duration: 1000, + animationCurve: AnimationCurve.easeIn, + ), + ); + }, + backgroundColor: Colors.grey, + child: const Icon(Icons.remove), + ), + FloatingActionButton( + heroTag: "move-camera-button", + backgroundColor: Colors.red, + child: const Icon(Icons.place_outlined), + onPressed: () { + _controller?.moveCamera( + point: tappedHQ, + zoomLevel: 8.0, + threeDHeading: 30, + threeDTilt: 60, + animationOptions: AnimationOptions( + duration: 1500, + animationCurve: AnimationCurve.easeIn, + ), + ); + }, + ), + if (kIsWeb) + FloatingActionButton( + heroTag: "3d-map-button", + onPressed: () { + setState(() { + show3dMap = !show3dMap; + _controller?.switchMapStyle( + show3dMap ? MapStyle.threeD : MapStyle.twoD, + ); + }); + }, + backgroundColor: show3dMap ? Colors.red : Colors.blue, + child: Text(show3dMap ? '3D' : '2D'), + ), + ], + ), + SizedBox(height: 8), + Center( + child: ElevatedButton( + style: ButtonStyle( + shape: WidgetStatePropertyAll( + RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8)), + ), + ), + onPressed: () { + showModalBottomSheet( + context: context, + builder: (context) { + return PointerInterceptorWeb( + child: ListView.separated( + padding: EdgeInsets.only( + top: 8, + bottom: + MediaQuery.paddingOf(context).bottom + + 8), + itemCount: BaseMap.values.length, + separatorBuilder: (_, __) => Padding( + padding: const EdgeInsets.symmetric( + horizontal: 20), + child: Divider( + height: 1, + ), + ), + itemBuilder: (context, int i) { + final basemap = BaseMap.values[i]; + return ListTile( + dense: true, + onTap: () { + Navigator.pop(context); + setState(() { + selectedBasemap = basemap; + }); + + _controller! + .toggleBaseMap(baseMap: basemap); + }, + title: Text( + basemap.name, + style: TextStyle( + color: Theme.of(context) + .buttonTheme + .colorScheme! + .onPrimaryContainer, + ), + ), + ); + }, + ), + ); + }); + }, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + selectedBasemap.name, + style: TextStyle( + decoration: TextDecoration.underline, + fontSize: 15, + ), + ), + SizedBox(width: 8), + Icon( + Icons.keyboard_arrow_down, + size: 22, + ) + ], + ), + ), + ), + ], + ), + ), + ], + ), + ), + ); + } + + void _onMapStatusChanged(MapStatus status) { + final scaffoldContext = _scaffoldKey.currentContext; + if (scaffoldContext == null) return; + + ScaffoldMessenger.of(scaffoldContext).showSnackBar( + SnackBar( + content: Text('Map status changed to: $status'), + duration: const Duration(seconds: 1), + ), + ); + } +} diff --git a/example/lib/main.dart b/example/lib/main.dart index 589e0588..9276959e 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'dart:core'; +import 'package:arcgis_example/basemap_style_example_page.dart'; import 'package:arcgis_example/export_image_example_page.dart'; import 'package:arcgis_example/location_indicator_example_page.dart'; import 'package:arcgis_example/map_elements.dart'; @@ -72,7 +73,6 @@ class _ExampleMapState extends State { final Map _hoveredPolygons = {}; bool show3dMap = false; - bool _baseMapToggled = false; final initialCenter = const LatLng(51.16, 10.45); final tappedHQ = const LatLng(48.1234963, 11.5910182); var _isInteractionEnabled = true; @@ -525,17 +525,8 @@ class _ExampleMapState extends State { child: const Text("Location indicator example"), ), ElevatedButton( - onPressed: () { - setState(() { - _baseMapToggled = !_baseMapToggled; - _controller?.toggleBaseMap( - baseMap: _baseMapToggled - ? BaseMap.hybrid - : BaseMap.osmDarkGray, - ); - }); - }, - child: const Text("Toggle BaseMap"), + onPressed: _routeToBasemapStyleExamplePage, + child: const Text("Basemap example"), ), ElevatedButton( onPressed: () { @@ -785,6 +776,12 @@ class _ExampleMapState extends State { ); } + void _routeToBasemapStyleExamplePage() { + Navigator.of(context).push( + MaterialPageRoute(builder: (_) => BasemapStyleExamplePage()), + ); + } + void _onMapStatusChanged(MapStatus status) { final scaffoldContext = _scaffoldKey.currentContext; if (scaffoldContext == null) return; diff --git a/example/lib/pointer_interceptor_web.dart b/example/lib/pointer_interceptor_web.dart new file mode 100644 index 00000000..db065b87 --- /dev/null +++ b/example/lib/pointer_interceptor_web.dart @@ -0,0 +1,27 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; + +/// A [Widget] that blocks touch and scroll events from being intercepted by underlying PlatformViews. +/// Useful for preserving interaction with overlay widgets like dialogs or bottom sheets when placed over a map +class PointerInterceptorWeb extends StatelessWidget { + final Widget child; + + const PointerInterceptorWeb({super.key, required this.child}); + + @override + Widget build(BuildContext context) { + if (!kIsWeb) return child; + return Stack( + alignment: Alignment.center, + children: [ + Positioned.fill( + child: HtmlElementView.fromTagName( + tagName: 'div', + isVisible: false, + ), + ), + child, + ], + ); + } +} diff --git a/example/pubspec.lock b/example/pubspec.lock index c5df2cf6..7b5b015e 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -47,10 +47,10 @@ packages: dependency: transitive description: name: async - sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" + sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63 url: "https://pub.dev" source: hosted - version: "2.13.0" + version: "2.12.0" boolean_selector: dependency: transitive description: @@ -103,10 +103,10 @@ packages: dependency: transitive description: name: fake_async - sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" + sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc" url: "https://pub.dev" source: hosted - version: "1.3.3" + version: "1.3.2" fixnum: dependency: transitive description: @@ -206,26 +206,26 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "8dcda04c3fc16c14f48a7bb586d4be1f0d1572731b6d81d51772ef47c02081e0" + sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec url: "https://pub.dev" source: hosted - version: "11.0.1" + version: "10.0.8" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" + sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 url: "https://pub.dev" source: hosted - version: "3.0.10" + version: "3.0.9" leak_tracker_testing: dependency: transitive description: name: leak_tracker_testing - sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "3.0.1" lint: dependency: "direct dev" description: @@ -363,10 +363,10 @@ packages: dependency: transitive description: name: vm_service - sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02 + sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14" url: "https://pub.dev" source: hosted - version: "15.0.0" + version: "14.3.1" web: dependency: transitive description: From 4d5535b11617f7bb5ae27728529fa8571d7f4344 Mon Sep 17 00:00:00 2001 From: Tarek Tolba Date: Wed, 28 May 2025 10:58:55 +0300 Subject: [PATCH 2/5] Basemap styles cleanup --- .../arcgis_map_sdk_android/Parsing.kt | 190 ++++++++++++------ example/lib/basemap_style_example_page.dart | 1 - 2 files changed, 125 insertions(+), 66 deletions(-) diff --git a/arcgis_map_sdk_android/android/src/main/kotlin/dev/fluttercommunity/arcgis_map_sdk_android/Parsing.kt b/arcgis_map_sdk_android/android/src/main/kotlin/dev/fluttercommunity/arcgis_map_sdk_android/Parsing.kt index a5762ac7..bdb634db 100644 --- a/arcgis_map_sdk_android/android/src/main/kotlin/dev/fluttercommunity/arcgis_map_sdk_android/Parsing.kt +++ b/arcgis_map_sdk_android/android/src/main/kotlin/dev/fluttercommunity/arcgis_map_sdk_android/Parsing.kt @@ -178,73 +178,133 @@ fun parseAnimationCurve(value: String): AnimationCurve { } } -private val basemapStyleMapping = mapOf( - BasemapStyle.ArcGISImagery to "arcgisImagery", - BasemapStyle.ArcGISImageryStandard to "arcgisImageryStandard", - BasemapStyle.ArcGISImageryLabels to "arcgisImageryLabels", - BasemapStyle.ArcGISLightGray to "arcgisLightGray", - BasemapStyle.ArcGISLightGrayBase to "arcgisLightGrayBase", - BasemapStyle.ArcGISLightGrayLabels to "arcgisLightGrayLabels", - BasemapStyle.ArcGISDarkGray to "arcgisDarkGray", - BasemapStyle.ArcGISDarkGrayBase to "arcgisDarkGrayBase", - BasemapStyle.ArcGISDarkGrayLabels to "arcgisDarkGrayLabels", - BasemapStyle.ArcGISNavigation to "arcgisNavigation", - BasemapStyle.ArcGISNavigationNight to "arcgisNavigationNight", - BasemapStyle.ArcGISStreets to "arcgisStreets", - BasemapStyle.ArcGISStreetsRelief to "arcgisStreetsRelief", - BasemapStyle.ArcGISStreetsReliefBase to "arcgisStreetsReliefBase", - BasemapStyle.ArcGISStreetsNight to "arcgisStreetsNight", - BasemapStyle.ArcGISTopographic to "arcgisTopographic", - BasemapStyle.ArcGISTopographicBase to "arcgisTopographicBase", - BasemapStyle.ArcGISOceans to "arcgisOceans", - BasemapStyle.ArcGISOceansBase to "arcgisOceansBase", - BasemapStyle.ArcGISOceansLabels to "arcgisOceansLabels", - BasemapStyle.ArcGISTerrain to "arcgisTerrain", - BasemapStyle.ArcGISTerrainBase to "arcgisTerrainBase", - BasemapStyle.ArcGISTerrainDetail to "arcgisTerrainDetail", - BasemapStyle.ArcGISCommunity to "arcgisCommunity", - BasemapStyle.ArcGISChartedTerritory to "arcgisChartedTerritory", - BasemapStyle.ArcGISChartedTerritoryBase to "arcgisChartedTerritoryBase", - BasemapStyle.ArcGISColoredPencil to "arcgisColoredPencil", - BasemapStyle.ArcGISNova to "arcgisNova", - BasemapStyle.ArcGISModernAntique to "arcgisModernAntique", - BasemapStyle.ArcGISModernAntiqueBase to "arcgisModernAntiqueBase", - BasemapStyle.ArcGISMidcentury to "arcgisMidcentury", - BasemapStyle.ArcGISNewspaper to "arcgisNewspaper", - BasemapStyle.ArcGISHillshadeLight to "arcgisHillshadeLight", - BasemapStyle.ArcGISHillshadeDark to "arcgisHillshadeDark", - BasemapStyle.ArcGISOutdoor to "arcgisOutdoor", - BasemapStyle.ArcGISHumanGeography to "arcgisHumanGeography", - BasemapStyle.ArcGISHumanGeographyBase to "arcgisHumanGeographyBase", - BasemapStyle.ArcGISHumanGeographyDetail to "arcgisHumanGeographyDetail", - BasemapStyle.ArcGISHumanGeographyLabels to "arcgisHumanGeographyLabels", - BasemapStyle.ArcGISHumanGeographyDark to "arcgisHumanGeographyDark", - BasemapStyle.ArcGISHumanGeographyDarkBase to "arcgisHumanGeographyDarkBase", - BasemapStyle.ArcGISHumanGeographyDarkDetail to "arcgisHumanGeographyDarkDetail", - BasemapStyle.ArcGISHumanGeographyDarkLabels to "arcgisHumanGeographyDarkLabels", - BasemapStyle.OsmStandard to "osmStandard", - BasemapStyle.OsmStandardRelief to "osmStandardRelief", - BasemapStyle.OsmStandardReliefBase to "osmStandardReliefBase", - BasemapStyle.OsmStreets to "osmStreets", - BasemapStyle.OsmStreetsRelief to "osmStreetsRelief", - BasemapStyle.OsmStreetsReliefBase to "osmStreetsReliefBase", - BasemapStyle.OsmLightGray to "osmLightGray", - BasemapStyle.OsmLightGrayBase to "osmLightGrayBase", - BasemapStyle.OsmLightGrayLabels to "osmLightGrayLabels", - BasemapStyle.OsmDarkGray to "osmDarkGray", - BasemapStyle.OsmDarkGrayBase to "osmDarkGrayBase", - BasemapStyle.OsmDarkGrayLabels to "osmDarkGrayLabels", - BasemapStyle.OsmBlueprint to "osmBlueprint", - BasemapStyle.OsmHybrid to "osmHybrid", - BasemapStyle.OsmHybridDetail to "osmHybridDetail", - BasemapStyle.OsmNavigation to "osmNavigation", - BasemapStyle.OsmNavigationDark to "osmNavigationDark" -) - fun BasemapStyle.getJsonValue(): String { - return basemapStyleMapping[this]!! + return when (this) { + BasemapStyle.ArcGISImagery -> "arcgisImagery" + BasemapStyle.ArcGISImageryStandard -> "arcgisImageryStandard" + BasemapStyle.ArcGISImageryLabels -> "arcgisImageryLabels" + BasemapStyle.ArcGISLightGray -> "arcgisLightGray" + BasemapStyle.ArcGISLightGrayBase -> "arcgisLightGrayBase" + BasemapStyle.ArcGISLightGrayLabels -> "arcgisLightGrayLabels" + BasemapStyle.ArcGISDarkGray -> "arcgisDarkGray" + BasemapStyle.ArcGISDarkGrayBase -> "arcgisDarkGrayBase" + BasemapStyle.ArcGISDarkGrayLabels -> "arcgisDarkGrayLabels" + BasemapStyle.ArcGISNavigation -> "arcgisNavigation" + BasemapStyle.ArcGISNavigationNight -> "arcgisNavigationNight" + BasemapStyle.ArcGISStreets -> "arcgisStreets" + BasemapStyle.ArcGISStreetsRelief -> "arcgisStreetsRelief" + BasemapStyle.ArcGISStreetsReliefBase -> "arcgisStreetsReliefBase" + BasemapStyle.ArcGISStreetsNight -> "arcgisStreetsNight" + BasemapStyle.ArcGISTopographic -> "arcgisTopographic" + BasemapStyle.ArcGISTopographicBase -> "arcgisTopographicBase" + BasemapStyle.ArcGISOceans -> "arcgisOceans" + BasemapStyle.ArcGISOceansBase -> "arcgisOceansBase" + BasemapStyle.ArcGISOceansLabels -> "arcgisOceansLabels" + BasemapStyle.ArcGISTerrain -> "arcgisTerrain" + BasemapStyle.ArcGISTerrainBase -> "arcgisTerrainBase" + BasemapStyle.ArcGISTerrainDetail -> "arcgisTerrainDetail" + BasemapStyle.ArcGISCommunity -> "arcgisCommunity" + BasemapStyle.ArcGISChartedTerritory -> "arcgisChartedTerritory" + BasemapStyle.ArcGISChartedTerritoryBase -> "arcgisChartedTerritoryBase" + BasemapStyle.ArcGISColoredPencil -> "arcgisColoredPencil" + BasemapStyle.ArcGISNova -> "arcgisNova" + BasemapStyle.ArcGISModernAntique -> "arcgisModernAntique" + BasemapStyle.ArcGISModernAntiqueBase -> "arcgisModernAntiqueBase" + BasemapStyle.ArcGISMidcentury -> "arcgisMidcentury" + BasemapStyle.ArcGISNewspaper -> "arcgisNewspaper" + BasemapStyle.ArcGISHillshadeLight -> "arcgisHillshadeLight" + BasemapStyle.ArcGISHillshadeDark -> "arcgisHillshadeDark" + BasemapStyle.ArcGISOutdoor -> "arcgisOutdoor" + BasemapStyle.ArcGISHumanGeography -> "arcgisHumanGeography" + BasemapStyle.ArcGISHumanGeographyBase -> "arcgisHumanGeographyBase" + BasemapStyle.ArcGISHumanGeographyDetail -> "arcgisHumanGeographyDetail" + BasemapStyle.ArcGISHumanGeographyLabels -> "arcgisHumanGeographyLabels" + BasemapStyle.ArcGISHumanGeographyDark -> "arcgisHumanGeographyDark" + BasemapStyle.ArcGISHumanGeographyDarkBase -> "arcgisHumanGeographyDarkBase" + BasemapStyle.ArcGISHumanGeographyDarkDetail -> "arcgisHumanGeographyDarkDetail" + BasemapStyle.ArcGISHumanGeographyDarkLabels -> "arcgisHumanGeographyDarkLabels" + BasemapStyle.OsmStandard -> "osmStandard" + BasemapStyle.OsmStandardRelief -> "osmStandardRelief" + BasemapStyle.OsmStandardReliefBase -> "osmStandardReliefBase" + BasemapStyle.OsmStreets -> "osmStreets" + BasemapStyle.OsmStreetsRelief -> "osmStreetsRelief" + BasemapStyle.OsmStreetsReliefBase -> "osmStreetsReliefBase" + BasemapStyle.OsmLightGray -> "osmLightGray" + BasemapStyle.OsmLightGrayBase -> "osmLightGrayBase" + BasemapStyle.OsmLightGrayLabels -> "osmLightGrayLabels" + BasemapStyle.OsmDarkGray -> "osmDarkGray" + BasemapStyle.OsmDarkGrayBase -> "osmDarkGrayBase" + BasemapStyle.OsmDarkGrayLabels -> "osmDarkGrayLabels" + BasemapStyle.OsmBlueprint -> "osmBlueprint" + BasemapStyle.OsmHybrid -> "osmHybrid" + BasemapStyle.OsmHybridDetail -> "osmHybridDetail" + BasemapStyle.OsmNavigation -> "osmNavigation" + BasemapStyle.OsmNavigationDark -> "osmNavigationDark" + } } fun parseBasemapStyle(value: String): BasemapStyle? { - return basemapStyleMapping.entries.firstOrNull { it.value == value }?.key + return when (value) { + "arcgisImagery" -> BasemapStyle.ArcGISImagery + "arcgisImageryStandard" -> BasemapStyle.ArcGISImageryStandard + "arcgisImageryLabels" -> BasemapStyle.ArcGISImageryLabels + "arcgisLightGray" -> BasemapStyle.ArcGISLightGray + "arcgisLightGrayBase" -> BasemapStyle.ArcGISLightGrayBase + "arcgisLightGrayLabels" -> BasemapStyle.ArcGISLightGrayLabels + "arcgisDarkGray" -> BasemapStyle.ArcGISDarkGray + "arcgisDarkGrayBase" -> BasemapStyle.ArcGISDarkGrayBase + "arcgisDarkGrayLabels" -> BasemapStyle.ArcGISDarkGrayLabels + "arcgisNavigation" -> BasemapStyle.ArcGISNavigation + "arcgisNavigationNight" -> BasemapStyle.ArcGISNavigationNight + "arcgisStreets" -> BasemapStyle.ArcGISStreets + "arcgisStreetsRelief" -> BasemapStyle.ArcGISStreetsRelief + "arcgisStreetsReliefBase" -> BasemapStyle.ArcGISStreetsReliefBase + "arcgisStreetsNight" -> BasemapStyle.ArcGISStreetsNight + "arcgisTopographic" -> BasemapStyle.ArcGISTopographic + "arcgisTopographicBase" -> BasemapStyle.ArcGISTopographicBase + "arcgisOceans" -> BasemapStyle.ArcGISOceans + "arcgisOceansBase" -> BasemapStyle.ArcGISOceansBase + "arcgisOceansLabels" -> BasemapStyle.ArcGISOceansLabels + "arcgisTerrain" -> BasemapStyle.ArcGISTerrain + "arcgisTerrainBase" -> BasemapStyle.ArcGISTerrainBase + "arcgisTerrainDetail" -> BasemapStyle.ArcGISTerrainDetail + "arcgisCommunity" -> BasemapStyle.ArcGISCommunity + "arcgisChartedTerritory" -> BasemapStyle.ArcGISChartedTerritory + "arcgisChartedTerritoryBase" -> BasemapStyle.ArcGISChartedTerritoryBase + "arcgisColoredPencil" -> BasemapStyle.ArcGISColoredPencil + "arcgisNova" -> BasemapStyle.ArcGISNova + "arcgisModernAntique" -> BasemapStyle.ArcGISModernAntique + "arcgisModernAntiqueBase" -> BasemapStyle.ArcGISModernAntiqueBase + "arcgisMidcentury" -> BasemapStyle.ArcGISMidcentury + "arcgisNewspaper" -> BasemapStyle.ArcGISNewspaper + "arcgisHillshadeLight" -> BasemapStyle.ArcGISHillshadeLight + "arcgisHillshadeDark" -> BasemapStyle.ArcGISHillshadeDark + "arcgisOutdoor" -> BasemapStyle.ArcGISOutdoor + "arcgisHumanGeography" -> BasemapStyle.ArcGISHumanGeography + "arcgisHumanGeographyBase" -> BasemapStyle.ArcGISHumanGeographyBase + "arcgisHumanGeographyDetail" -> BasemapStyle.ArcGISHumanGeographyDetail + "arcgisHumanGeographyLabels" -> BasemapStyle.ArcGISHumanGeographyLabels + "arcgisHumanGeographyDark" -> BasemapStyle.ArcGISHumanGeographyDark + "arcgisHumanGeographyDarkBase" -> BasemapStyle.ArcGISHumanGeographyDarkBase + "arcgisHumanGeographyDarkDetail" -> BasemapStyle.ArcGISHumanGeographyDarkDetail + "arcgisHumanGeographyDarkLabels" -> BasemapStyle.ArcGISHumanGeographyDarkLabels + "osmStandard" -> BasemapStyle.OsmStandard + "osmStandardRelief" -> BasemapStyle.OsmStandardRelief + "osmStandardReliefBase" -> BasemapStyle.OsmStandardReliefBase + "osmStreets" -> BasemapStyle.OsmStreets + "osmStreetsRelief" -> BasemapStyle.OsmStreetsRelief + "osmStreetsReliefBase" -> BasemapStyle.OsmStreetsReliefBase + "osmLightGray" -> BasemapStyle.OsmLightGray + "osmLightGrayBase" -> BasemapStyle.OsmLightGrayBase + "osmLightGrayLabels" -> BasemapStyle.OsmLightGrayLabels + "osmDarkGray" -> BasemapStyle.OsmDarkGray + "osmDarkGrayBase" -> BasemapStyle.OsmDarkGrayBase + "osmDarkGrayLabels" -> BasemapStyle.OsmDarkGrayLabels + "osmBlueprint" -> BasemapStyle.OsmBlueprint + "osmHybrid" -> BasemapStyle.OsmHybrid + "osmHybridDetail" -> BasemapStyle.OsmHybridDetail + "osmNavigation" -> BasemapStyle.OsmNavigation + "osmNavigationDark" -> BasemapStyle.OsmNavigationDark + else -> null + } } diff --git a/example/lib/basemap_style_example_page.dart b/example/lib/basemap_style_example_page.dart index decaa020..af65f023 100644 --- a/example/lib/basemap_style_example_page.dart +++ b/example/lib/basemap_style_example_page.dart @@ -7,7 +7,6 @@ import 'package:arcgis_map_sdk/arcgis_map_sdk.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -/// Example 3D SceneLayer page. class BasemapStyleExamplePage extends StatefulWidget { const BasemapStyleExamplePage({super.key}); From f403fcfc45324b8e1ce2b551a3907377f95c539a Mon Sep 17 00:00:00 2001 From: Tarek Tolba Date: Wed, 28 May 2025 16:41:08 +0300 Subject: [PATCH 3/5] Example app cleanup --- example/lib/basemap_style_example_page.dart | 335 ++++---- example/lib/draw_on_map_example_page.dart | 589 ++++++++++++++ example/lib/main.dart | 815 ++++++-------------- 3 files changed, 995 insertions(+), 744 deletions(-) create mode 100644 example/lib/draw_on_map_example_page.dart diff --git a/example/lib/basemap_style_example_page.dart b/example/lib/basemap_style_example_page.dart index af65f023..c46842f4 100644 --- a/example/lib/basemap_style_example_page.dart +++ b/example/lib/basemap_style_example_page.dart @@ -20,7 +20,6 @@ class _BasemapStyleExamplePageState extends State { ArcgisMapController? _controller; BaseMap selectedBasemap = BaseMap.values.first; bool show3dMap = false; - bool isBasemapMenuOpened = false; final initialCenter = const LatLng(51.16, 10.45); final tappedHQ = const LatLng(48.1234963, 11.5910182); @@ -63,192 +62,184 @@ class _BasemapStyleExamplePageState extends State { @override Widget build(BuildContext context) { return Scaffold( - // appBar: AppBar(), key: _scaffoldKey, - body: GestureDetector( - onTap: () { - setState(() { - isBasemapMenuOpened = false; - }); - }, - child: Stack( - children: [ - ArcgisMap( - mapStyle: show3dMap ? MapStyle.threeD : MapStyle.twoD, - apiKey: arcGisApiKey, - basemap: BaseMap.osmDarkGray, - ground: show3dMap ? Ground.worldElevation : null, - showLabelsBeneathGraphics: true, - initialCenter: initialCenter, - zoom: 8, - rotationEnabled: true, - onMapCreated: _onMapCreated, - defaultUiList: [ - DefaultWidget( - viewType: DefaultWidgetType.compass, - position: WidgetPosition.topRight, - ), - ], - ), - Positioned( - top: MediaQuery.paddingOf(context).top + 8, - left: 8, - child: BackButton( - color: Colors.black, - style: ButtonStyle( - backgroundColor: WidgetStatePropertyAll(Colors.grey)), + body: Stack( + children: [ + ArcgisMap( + mapStyle: show3dMap ? MapStyle.threeD : MapStyle.twoD, + apiKey: arcGisApiKey, + basemap: BaseMap.osmDarkGray, + ground: show3dMap ? Ground.worldElevation : null, + showLabelsBeneathGraphics: true, + initialCenter: initialCenter, + zoom: 8, + rotationEnabled: true, + onMapCreated: _onMapCreated, + defaultUiList: [ + DefaultWidget( + viewType: DefaultWidgetType.compass, + position: WidgetPosition.topRight, ), + ], + ), + Positioned( + top: MediaQuery.paddingOf(context).top + 8, + left: 8, + child: BackButton( + color: Colors.black, + style: ButtonStyle( + backgroundColor: WidgetStatePropertyAll(Colors.grey)), ), - Positioned( - bottom: 40, - right: 0, - left: 0, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - FloatingActionButton( - heroTag: "zoom-in-button", - onPressed: () { - _controller?.zoomIn( - lodFactor: 1, - animationOptions: AnimationOptions( - duration: 1000, - animationCurve: AnimationCurve.easeIn, - ), - ); - }, - backgroundColor: Colors.grey, - child: const Icon(Icons.add), - ), - FloatingActionButton( - heroTag: "zoom-out-button", - onPressed: () { - _controller?.zoomOut( - lodFactor: 1, - animationOptions: AnimationOptions( - duration: 1000, - animationCurve: AnimationCurve.easeIn, - ), - ); - }, - backgroundColor: Colors.grey, - child: const Icon(Icons.remove), - ), + ), + Positioned( + bottom: 40, + right: 0, + left: 0, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + FloatingActionButton( + heroTag: "zoom-in-button", + onPressed: () { + _controller?.zoomIn( + lodFactor: 1, + animationOptions: AnimationOptions( + duration: 1000, + animationCurve: AnimationCurve.easeIn, + ), + ); + }, + backgroundColor: Colors.grey, + child: const Icon(Icons.add), + ), + FloatingActionButton( + heroTag: "zoom-out-button", + onPressed: () { + _controller?.zoomOut( + lodFactor: 1, + animationOptions: AnimationOptions( + duration: 1000, + animationCurve: AnimationCurve.easeIn, + ), + ); + }, + backgroundColor: Colors.grey, + child: const Icon(Icons.remove), + ), + FloatingActionButton( + heroTag: "move-camera-button", + backgroundColor: Colors.red, + child: const Icon(Icons.place_outlined), + onPressed: () { + _controller?.moveCamera( + point: tappedHQ, + zoomLevel: 8.0, + threeDHeading: 30, + threeDTilt: 60, + animationOptions: AnimationOptions( + duration: 1500, + animationCurve: AnimationCurve.easeIn, + ), + ); + }, + ), + if (kIsWeb) FloatingActionButton( - heroTag: "move-camera-button", - backgroundColor: Colors.red, - child: const Icon(Icons.place_outlined), + heroTag: "3d-map-button", onPressed: () { - _controller?.moveCamera( - point: tappedHQ, - zoomLevel: 8.0, - threeDHeading: 30, - threeDTilt: 60, - animationOptions: AnimationOptions( - duration: 1500, - animationCurve: AnimationCurve.easeIn, - ), - ); + setState(() { + show3dMap = !show3dMap; + _controller?.switchMapStyle( + show3dMap ? MapStyle.threeD : MapStyle.twoD, + ); + }); }, + backgroundColor: show3dMap ? Colors.red : Colors.blue, + child: Text(show3dMap ? '3D' : '2D'), ), - if (kIsWeb) - FloatingActionButton( - heroTag: "3d-map-button", - onPressed: () { - setState(() { - show3dMap = !show3dMap; - _controller?.switchMapStyle( - show3dMap ? MapStyle.threeD : MapStyle.twoD, - ); - }); - }, - backgroundColor: show3dMap ? Colors.red : Colors.blue, - child: Text(show3dMap ? '3D' : '2D'), - ), - ], - ), - SizedBox(height: 8), - Center( - child: ElevatedButton( - style: ButtonStyle( - shape: WidgetStatePropertyAll( - RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8)), - ), + ], + ), + SizedBox(height: 8), + Center( + child: ElevatedButton( + style: ButtonStyle( + shape: WidgetStatePropertyAll( + RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8)), ), - onPressed: () { - showModalBottomSheet( - context: context, - builder: (context) { - return PointerInterceptorWeb( - child: ListView.separated( - padding: EdgeInsets.only( - top: 8, - bottom: - MediaQuery.paddingOf(context).bottom + - 8), - itemCount: BaseMap.values.length, - separatorBuilder: (_, __) => Padding( - padding: const EdgeInsets.symmetric( - horizontal: 20), - child: Divider( - height: 1, - ), + ), + onPressed: () { + showModalBottomSheet( + context: context, + builder: (context) { + return PointerInterceptorWeb( + child: ListView.separated( + padding: EdgeInsets.only( + top: 8, + bottom: + MediaQuery.paddingOf(context).bottom + + 8), + itemCount: BaseMap.values.length, + separatorBuilder: (_, __) => Padding( + padding: const EdgeInsets.symmetric( + horizontal: 20), + child: Divider( + height: 1, ), - itemBuilder: (context, int i) { - final basemap = BaseMap.values[i]; - return ListTile( - dense: true, - onTap: () { - Navigator.pop(context); - setState(() { - selectedBasemap = basemap; - }); + ), + itemBuilder: (context, int i) { + final basemap = BaseMap.values[i]; + return ListTile( + dense: true, + onTap: () { + Navigator.pop(context); + setState(() { + selectedBasemap = basemap; + }); - _controller! - .toggleBaseMap(baseMap: basemap); - }, - title: Text( - basemap.name, - style: TextStyle( - color: Theme.of(context) - .buttonTheme - .colorScheme! - .onPrimaryContainer, - ), + _controller! + .toggleBaseMap(baseMap: basemap); + }, + title: Text( + basemap.name, + style: TextStyle( + color: Theme.of(context) + .buttonTheme + .colorScheme! + .onPrimaryContainer, ), - ); - }, - ), - ); - }); - }, - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - selectedBasemap.name, - style: TextStyle( - decoration: TextDecoration.underline, - fontSize: 15, - ), + ), + ); + }, + ), + ); + }); + }, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + selectedBasemap.name, + style: TextStyle( + decoration: TextDecoration.underline, + fontSize: 15, ), - SizedBox(width: 8), - Icon( - Icons.keyboard_arrow_down, - size: 22, - ) - ], - ), + ), + SizedBox(width: 8), + Icon( + Icons.keyboard_arrow_down, + size: 22, + ) + ], ), ), - ], - ), + ), + ], ), - ], - ), + ), + ], ), ); } diff --git a/example/lib/draw_on_map_example_page.dart b/example/lib/draw_on_map_example_page.dart new file mode 100644 index 00000000..1d23e2ec --- /dev/null +++ b/example/lib/draw_on_map_example_page.dart @@ -0,0 +1,589 @@ +import 'dart:async'; + +import 'package:arcgis_example/main.dart'; +import 'package:arcgis_example/map_elements.dart'; +import 'package:arcgis_example/pointer_interceptor_web.dart'; +import 'package:arcgis_map_sdk/arcgis_map_sdk.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; + +class DrawOnMapExamplePage extends StatefulWidget { + const DrawOnMapExamplePage({super.key}); + + @override + State createState() => _DrawOnMapExamplePageState(); +} + +class _DrawOnMapExamplePageState extends State { + static const String _pinId1 = '123'; + final LatLng _firstPinCoordinates = const LatLng(52.9, 13.2); + static const String _pinId2 = '456'; + final LatLng _secondPinCoordinates = const LatLng(51, 11); + static const String _pinFeatureId = '789'; + final LatLng _pinFeatureCoordinates = const LatLng(50.945, 6.965); + static const String _pinLayerId = 'PinLayer'; + static const String _featureLayerId = 'FeatureLayer'; + static const String _polygon1 = 'polygon1'; + static const String _polygon2 = 'polygon2'; + static const String _polyLayerId = 'PolygonLayer'; + static const String _lineLayerId = 'LinesGraphics'; + + /// null when executed on a platform that's not supported yet + ArcgisMapController? _controller; + bool show3dMap = false; + final initialCenter = const LatLng(51.16, 10.45); + final tappedHQ = const LatLng(48.1234963, 11.5910182); + + VoidCallback? _removeStatusListener; + + final _scaffoldKey = GlobalKey(); + + bool _isFirstPinInView = false; + bool _isSecondPinInView = false; + bool _isFeatureInView = false; + + bool _subscribedToGraphicsInView = false; + + final Map _hoveredPolygons = {}; + StreamSubscription? _isGraphicHoveredSubscription; + StreamSubscription>? _graphicsInViewSubscription; + + final _markerSymbol = PictureMarkerSymbol( + assetUri: 'assets/navPointer.png', + width: 56, + height: 56, + ); + + @override + void dispose() { + _isGraphicHoveredSubscription?.cancel(); + _graphicsInViewSubscription?.cancel(); + _removeStatusListener?.call(); + super.dispose(); + } + + Future _onMapCreated(ArcgisMapController controller) async { + _controller = controller; + + _removeStatusListener = + _controller!.addStatusChangeListener(_onMapStatusChanged); + + // TODO: Remove when mobile implementation is complete + if (kIsWeb) { + _controller?.onClickListener().listen((Attributes? attributes) { + if (attributes == null || !mounted) return; + final snackBar = SnackBar( + content: + Text('Attributes Id after on Click: ${attributes.data['name']}'), + ); + ScaffoldMessenger.of(context) + ..hideCurrentSnackBar() + ..showSnackBar(snackBar); + }); + + // Create GraphicsLayer with Polygons + await _createGraphicLayer( + layerId: _polyLayerId, + elevationMode: ElevationMode.onTheGround, + ); + + await _createFeatureLayer( + layerId: _featureLayerId, + ); + + // Create GraphicsLayer with Lines + await _createGraphicLayer( + layerId: _lineLayerId, + elevationMode: ElevationMode.onTheGround, + ); + + // Create GraphicsLayer with 3D Pins + await _createGraphicLayer(layerId: _pinLayerId); + + // Subscribe to hover events to change the mouse cursor + _isGraphicHoveredSubscription = + _controller?.isGraphicHoveredStream().listen((bool isHovered) { + _setMouseCursor(isHovered); + }); + } + + _connectTwoPinsWithPolyline( + id: 'connecting-polyline-01', + name: 'Connecting polyline', + start: _firstPinCoordinates, + end: _secondPinCoordinates, + ); + + // Add Polygons to the PolyLayer + _addPolygon( + layerId: _polyLayerId, + graphic: PolygonGraphic( + rings: firstPolygon, + symbol: orangeFillSymbol, + attributes: Attributes({'id': _polygon1, 'name': 'First Polygon'}), + onHover: (isHovered) { + isHovered + ? _updateGraphicSymbol( + layerId: _polyLayerId, + graphicId: _polygon1, + symbol: highlightedOrangeFillSymbol, + ) + : _updateGraphicSymbol( + layerId: _polyLayerId, + graphicId: _polygon1, + symbol: orangeFillSymbol, + ); + if (_hoveredPolygons[_polygon1] == isHovered) return; + _hoveredPolygons[_polygon1] = isHovered; + }, + ), + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + key: _scaffoldKey, + floatingActionButton: FloatingActionButton(onPressed: _showBottomSheet,child: Icon(Icons.draw),), + body: Stack( + children: [ + ArcgisMap( + mapStyle: show3dMap ? MapStyle.threeD : MapStyle.twoD, + apiKey: arcGisApiKey, + basemap: BaseMap.osmDarkGray, + ground: show3dMap ? Ground.worldElevation : null, + showLabelsBeneathGraphics: true, + initialCenter: initialCenter, + zoom: 8, + rotationEnabled: true, + onMapCreated: _onMapCreated, + defaultUiList: [ + DefaultWidget( + viewType: DefaultWidgetType.compass, + position: WidgetPosition.topRight, + ), + ], + ), + Positioned( + top: MediaQuery.paddingOf(context).top + 8, + left: 8, + child: BackButton( + color: Colors.black, + style: ButtonStyle( + backgroundColor: WidgetStatePropertyAll(Colors.grey)), + ), + ), + Positioned( + bottom: 40, + right: 0, + left: 0, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + FloatingActionButton( + heroTag: "zoom-in-button", + onPressed: () { + _controller?.zoomIn( + lodFactor: 1, + animationOptions: AnimationOptions( + duration: 1000, + animationCurve: AnimationCurve.easeIn, + ), + ); + }, + backgroundColor: Colors.grey, + child: const Icon(Icons.add), + ), + FloatingActionButton( + heroTag: "zoom-out-button", + onPressed: () { + _controller?.zoomOut( + lodFactor: 1, + animationOptions: AnimationOptions( + duration: 1000, + animationCurve: AnimationCurve.easeIn, + ), + ); + }, + backgroundColor: Colors.grey, + child: const Icon(Icons.remove), + ), + FloatingActionButton( + heroTag: "move-camera-button", + backgroundColor: Colors.red, + child: const Icon(Icons.place_outlined), + onPressed: () { + _controller?.moveCamera( + point: tappedHQ, + zoomLevel: 8.0, + threeDHeading: 30, + threeDTilt: 60, + animationOptions: AnimationOptions( + duration: 1500, + animationCurve: AnimationCurve.easeIn, + ), + ); + }, + ), + if (kIsWeb) + FloatingActionButton( + heroTag: "3d-map-button", + onPressed: () { + setState(() { + show3dMap = !show3dMap; + _controller?.switchMapStyle( + show3dMap ? MapStyle.threeD : MapStyle.twoD, + ); + }); + }, + backgroundColor: show3dMap ? Colors.red : Colors.blue, + child: Text(show3dMap ? '3D' : '2D'), + ), + ], + ), + ], + ), + ), + ], + ), + ); + } + + void _onMapStatusChanged(MapStatus status) { + final scaffoldContext = _scaffoldKey.currentContext; + if (scaffoldContext == null) return; + + ScaffoldMessenger.of(scaffoldContext).showSnackBar( + SnackBar( + content: Text('Map status changed to: $status'), + duration: const Duration(seconds: 1), + ), + ); + } + + void _setMouseCursor(bool isHovered) { + _controller?.setMouseCursor( + isHovered ? SystemMouseCursors.click : SystemMouseCursors.basic, + ); + } + + void _addPin({ + required String layerId, + required String objectId, + required LatLng location, + }) { + _controller?.addGraphic( + layerId: layerId, + graphic: PointGraphic( + longitude: location.longitude, + latitude: location.latitude, + height: 20, + attributes: Attributes({ + 'id': objectId, + 'name': objectId, + 'family': 'Pins', + }), + symbol: _markerSymbol, + ), + ); + } + + void _updateGraphicSymbol({ + required String layerId, + required String graphicId, + required Symbol symbol, + }) { + _controller?.updateGraphicSymbol( + layerId: layerId, + symbol: symbol, + graphicId: graphicId, + ); + } + + void _subscribeToGraphicsInView() { + _graphicsInViewSubscription?.cancel(); + _graphicsInViewSubscription = _controller + ?.visibleGraphics() + .listen((List visibleGraphicsIds) { + visibleGraphicsIds.forEach(debugPrint); + }); + setState(() { + _subscribedToGraphicsInView = true; + }); + } + + void _unSubscribeToGraphicsInView() { + _graphicsInViewSubscription?.cancel(); + setState(() { + _subscribedToGraphicsInView = false; + }); + } + + Future _createGraphicLayer({ + required String layerId, + ElevationMode elevationMode = ElevationMode.relativeToScene, + }) async { + final layer = await _controller?.addGraphicsLayer( + layerId: layerId, + options: GraphicsLayerOptions( + fields: [ + Field(name: 'oid', type: 'oid'), + Field(name: 'id', type: 'string'), + Field(name: 'family', type: 'string'), + Field(name: 'name', type: 'string'), + ], + featureReduction: FeatureReductionCluster().toJson(), + elevationMode: elevationMode, + ), + ); + return layer; + } + + void _removeGraphic({ + required String layerId, + required String objectId, + }) { + _controller?.removeGraphic(layerId: layerId, objectId: objectId); + } + + Future _createFeatureLayer({ + required String layerId, + }) async { + final layer = await _controller?.addFeatureLayer( + layerId: layerId, + options: FeatureLayerOptions( + fields: [ + Field(name: 'oid', type: 'oid'), + Field(name: 'id', type: 'string'), + Field(name: 'family', type: 'string'), + Field(name: 'name', type: 'string'), + ], + symbol: _markerSymbol, + ), + ); + return layer; + } + + void _makePolylineVisible({required List points}) { + _controller?.moveCameraToPoints( + points: points, + padding: 30, + ); + } + + void _addPolygon({ + required String layerId, + required PolygonGraphic graphic, + }) { + _controller?.addGraphic( + layerId: layerId, + graphic: graphic, + ); + } + + void _connectTwoPinsWithPolyline({ + required String id, + required String name, + required LatLng start, + required LatLng end, + }) { + _controller?.addGraphic( + layerId: _lineLayerId, + graphic: PolylineGraphic( + paths: [ + [ + [start.longitude, start.latitude, 10.0], + [end.longitude, end.latitude, 10.0], + ] + ], + symbol: const SimpleLineSymbol( + color: Colors.purple, + style: PolylineStyle.shortDashDotDot, + width: 3, + marker: LineSymbolMarker( + color: Colors.green, + colorOpacity: 1, + style: MarkerStyle.circle, + ), + ), + attributes: Attributes({'id': id, 'name': name}), + ), + ); + } + + void _showBottomSheet() { + showModalBottomSheet( + context: context, + builder: (context) { + return PointerInterceptorWeb( + child: ListView( + padding: EdgeInsets.only( + top: 16, + bottom: MediaQuery.paddingOf(context).bottom + 8, + right: 16, + left: 16), + children: [ + _buildAction( + onPressed: () { + if (_isFirstPinInView) { + _removeGraphic( + layerId: _pinLayerId, + objectId: _pinId1, + ); + setState(() { + _isFirstPinInView = false; + }); + } else { + _addPin( + layerId: _pinLayerId, + objectId: _pinId1, + location: _firstPinCoordinates, + ); + setState(() { + _isFirstPinInView = true; + }); + } + }, + text: + _isFirstPinInView ? 'Remove first Pin' : 'Add first Pin', + ), + _buildAction( + onPressed: () { + if (_isSecondPinInView) { + _removeGraphic( + layerId: _pinLayerId, + objectId: _pinId2, + ); + setState(() { + _isSecondPinInView = false; + }); + } else { + _addPin( + layerId: _pinLayerId, + objectId: _pinId2, + location: _secondPinCoordinates, + ); + setState(() { + _isSecondPinInView = true; + }); + } + }, + text: _isSecondPinInView + ? 'Remove second Pin' + : 'Add second Pin', + ), + _buildAction( + onPressed: () { + if (_isFeatureInView) { + _removeGraphic( + layerId: _featureLayerId, + objectId: _pinFeatureId, + ); + setState(() { + _isFeatureInView = false; + }); + } else { + _addPin( + layerId: _featureLayerId, + objectId: _pinFeatureId, + location: _pinFeatureCoordinates, + ); + _controller?.moveCamera( + point: _pinFeatureCoordinates, + zoomLevel: 15, + ); + setState(() { + _isFeatureInView = true; + }); + } + }, + text: _isFeatureInView + ? 'Remove FeatureLayer Pin' + : 'Add FeatureLayer Pin', + ), + if (kIsWeb) + _buildAction( + onPressed: () { + if (_subscribedToGraphicsInView) { + _unSubscribeToGraphicsInView(); + } else { + _subscribeToGraphicsInView(); + } + }, + text: _subscribedToGraphicsInView + ? "Stop printing Graphics" + : "Start printing Graphics", + ), + if (kIsWeb) + _buildAction( + onPressed: () { + final graphicIdsInView = + _controller?.getVisibleGraphicIds(); + graphicIdsInView?.forEach(debugPrint); + }, + text: "Print visible Graphics", + ), + _buildAction( + onPressed: () { + _addPolygon( + layerId: _polyLayerId, + graphic: PolygonGraphic( + rings: secondPolygon, + symbol: redFillSymbol, + attributes: Attributes({ + 'id': _polygon2, + 'name': 'Second Polygon', + }), + onHover: (isHovered) { + isHovered + ? _updateGraphicSymbol( + layerId: _polyLayerId, + graphicId: _polygon2, + symbol: highlightedRedFillSymbol, + ) + : _updateGraphicSymbol( + layerId: _polyLayerId, + graphicId: _polygon2, + symbol: redFillSymbol, + ); + if (_hoveredPolygons[_polygon2] == isHovered) { + return; + } + _hoveredPolygons[_polygon2] = isHovered; + }, + ), + ); + }, + text: 'Add red polygon', + ), + _buildAction( + onPressed: () => _removeGraphic( + layerId: _polyLayerId, + objectId: _polygon2, + ), + text: 'Remove red polygon', + ), + _buildAction( + onPressed: () => _makePolylineVisible( + points: [_firstPinCoordinates, _secondPinCoordinates], + ), + text: 'Zoom to polyline', + ), + ], + ), + ); + }); + } + + Widget _buildAction({required VoidCallback onPressed, required String text}) { + return ListTile( + onTap: () { + Navigator.pop(context); + onPressed(); + }, + title: Text(text,style: TextStyle(color: Colors.deepPurple),), + ); + } +} diff --git a/example/lib/main.dart b/example/lib/main.dart index 9276959e..859a2907 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'dart:core'; import 'package:arcgis_example/basemap_style_example_page.dart'; +import 'package:arcgis_example/draw_on_map_example_page.dart'; import 'package:arcgis_example/export_image_example_page.dart'; import 'package:arcgis_example/location_indicator_example_page.dart'; import 'package:arcgis_example/map_elements.dart'; @@ -40,37 +41,18 @@ class ExampleMap extends StatefulWidget { } class _ExampleMapState extends State { - static const String _pinId1 = '123'; - final LatLng _firstPinCoordinates = const LatLng(52.9, 13.2); - static const String _pinId2 = '456'; - final LatLng _secondPinCoordinates = const LatLng(51, 11); - static const String _pinFeatureId = '789'; - final LatLng _pinFeatureCoordinates = const LatLng(50.945, 6.965); - static const String _pinLayerId = 'PinLayer'; - static const String _featureLayerId = 'FeatureLayer'; - static const String _polygon1 = 'polygon1'; - static const String _polygon2 = 'polygon2'; - static const String _polyLayerId = 'PolygonLayer'; - static const String _lineLayerId = 'LinesGraphics'; - /// null when executed on a platform that's not supported yet ArcgisMapController? _controller; StreamSubscription? _boundingBoxSubscription; StreamSubscription? _centerPositionSubscription; - StreamSubscription>? _graphicsInViewSubscription; StreamSubscription? _attributionTextSubscription; StreamSubscription? _zoomSubscription; - StreamSubscription? _isGraphicHoveredSubscription; String _attributionText = ''; bool _subscribedToBounds = false; - bool _isFirstPinInView = false; - bool _isSecondPinInView = false; - bool _isFeatureInView = false; + bool _subscribedToCenterPosition = false; - bool _subscribedToGraphicsInView = false; bool _subscribedToZoom = false; - final Map _hoveredPolygons = {}; bool show3dMap = false; final initialCenter = const LatLng(51.16, 10.45); @@ -85,10 +67,8 @@ class _ExampleMapState extends State { void dispose() { _boundingBoxSubscription?.cancel(); _centerPositionSubscription?.cancel(); - _graphicsInViewSubscription?.cancel(); _attributionTextSubscription?.cancel(); _zoomSubscription?.cancel(); - _isGraphicHoveredSubscription?.cancel(); _removeStatusListener?.call(); super.dispose(); @@ -122,82 +102,7 @@ class _ExampleMapState extends State { // Create basic 3D Layer with elevation and 3D buildings await _createSceneLayer(); - - // Create GraphicsLayer with Polygons - await _createGraphicLayer( - layerId: _polyLayerId, - elevationMode: ElevationMode.onTheGround, - ); - - await _createFeatureLayer( - layerId: _featureLayerId, - ); - - // Create GraphicsLayer with Lines - await _createGraphicLayer( - layerId: _lineLayerId, - elevationMode: ElevationMode.onTheGround, - ); - - // Create GraphicsLayer with 3D Pins - await _createGraphicLayer(layerId: _pinLayerId); - - // Subscribe to hover events to change the mouse cursor - _isGraphicHoveredSubscription = - _controller?.isGraphicHoveredStream().listen((bool isHovered) { - _setMouseCursor(isHovered); - }); } - - _connectTwoPinsWithPolyline( - id: 'connecting-polyline-01', - name: 'Connecting polyline', - start: _firstPinCoordinates, - end: _secondPinCoordinates, - ); - - // Add Polygons to the PolyLayer - _addPolygon( - layerId: _polyLayerId, - graphic: PolygonGraphic( - rings: firstPolygon, - symbol: orangeFillSymbol, - attributes: Attributes({'id': _polygon1, 'name': 'First Polygon'}), - onHover: (isHovered) { - isHovered - ? _updateGraphicSymbol( - layerId: _polyLayerId, - graphicId: _polygon1, - symbol: highlightedOrangeFillSymbol, - ) - : _updateGraphicSymbol( - layerId: _polyLayerId, - graphicId: _polygon1, - symbol: orangeFillSymbol, - ); - if (_hoveredPolygons[_polygon1] == isHovered) return; - _hoveredPolygons[_polygon1] = isHovered; - }, - ), - ); - } - - void _updateGraphicSymbol({ - required String layerId, - required String graphicId, - required Symbol symbol, - }) { - _controller?.updateGraphicSymbol( - layerId: layerId, - symbol: symbol, - graphicId: graphicId, - ); - } - - void _setMouseCursor(bool isHovered) { - _controller?.setMouseCursor( - isHovered ? SystemMouseCursors.click : SystemMouseCursors.basic, - ); } void _subscribeToBounds() { @@ -222,25 +127,6 @@ class _ExampleMapState extends State { }); } - void _subscribeToGraphicsInView() { - _graphicsInViewSubscription?.cancel(); - _graphicsInViewSubscription = _controller - ?.visibleGraphics() - .listen((List visibleGraphicsIds) { - visibleGraphicsIds.forEach(debugPrint); - }); - setState(() { - _subscribedToGraphicsInView = true; - }); - } - - void _unSubscribeToGraphicsInView() { - _graphicsInViewSubscription?.cancel(); - setState(() { - _subscribedToGraphicsInView = false; - }); - } - void _subscribeToPos() { _centerPositionSubscription?.cancel(); _centerPositionSubscription = @@ -276,27 +162,6 @@ class _ExampleMapState extends State { }); } - void _addPin({ - required String layerId, - required String objectId, - required LatLng location, - }) { - _controller?.addGraphic( - layerId: layerId, - graphic: PointGraphic( - longitude: location.longitude, - latitude: location.latitude, - height: 20, - attributes: Attributes({ - 'id': objectId, - 'name': objectId, - 'family': 'Pins', - }), - symbol: _markerSymbol, - ), - ); - } - Future _createSceneLayer() async { final layer = await _controller?.addSceneLayer( layerId: '3D Buildings', @@ -309,444 +174,221 @@ class _ExampleMapState extends State { return layer; } - Future _createGraphicLayer({ - required String layerId, - ElevationMode elevationMode = ElevationMode.relativeToScene, - }) async { - final layer = await _controller?.addGraphicsLayer( - layerId: layerId, - options: GraphicsLayerOptions( - fields: [ - Field(name: 'oid', type: 'oid'), - Field(name: 'id', type: 'string'), - Field(name: 'family', type: 'string'), - Field(name: 'name', type: 'string'), - ], - featureReduction: FeatureReductionCluster().toJson(), - elevationMode: elevationMode, - ), - ); - return layer; - } - - void _removeGraphic({ - required String layerId, - required String objectId, - }) { - _controller?.removeGraphic(layerId: layerId, objectId: objectId); - } - - Future _createFeatureLayer({ - required String layerId, - }) async { - final layer = await _controller?.addFeatureLayer( - layerId: layerId, - options: FeatureLayerOptions( - fields: [ - Field(name: 'oid', type: 'oid'), - Field(name: 'id', type: 'string'), - Field(name: 'family', type: 'string'), - Field(name: 'name', type: 'string'), - ], - symbol: _markerSymbol, - ), - ); - return layer; - } - - void _makePolylineVisible({required List points}) { - _controller?.moveCameraToPoints( - points: points, - padding: 30, - ); - } - - void _addPolygon({ - required String layerId, - required PolygonGraphic graphic, - }) { - _controller?.addGraphic( - layerId: layerId, - graphic: graphic, - ); - } - - void _connectTwoPinsWithPolyline({ - required String id, - required String name, - required LatLng start, - required LatLng end, - }) { - _controller?.addGraphic( - layerId: _lineLayerId, - graphic: PolylineGraphic( - paths: [ - [ - [start.longitude, start.latitude, 10.0], - [end.longitude, end.latitude, 10.0], - ] - ], - symbol: const SimpleLineSymbol( - color: Colors.purple, - style: PolylineStyle.shortDashDotDot, - width: 3, - marker: LineSymbolMarker( - color: Colors.green, - colorOpacity: 1, - style: MarkerStyle.circle, - ), - ), - attributes: Attributes({'id': id, 'name': name}), - ), - ); - } - @override Widget build(BuildContext context) { + final isLargeScreen = MediaQuery.sizeOf(context).width > 800; return Scaffold( key: _scaffoldKey, - body: Stack( + drawer: isLargeScreen + ? null + : NavigationDrawer(children: _buildTiles(context)), + body: Row( children: [ - ArcgisMap( - mapStyle: show3dMap ? MapStyle.threeD : MapStyle.twoD, - apiKey: arcGisApiKey, - basemap: BaseMap.osmDarkGray, - ground: show3dMap ? Ground.worldElevation : null, - showLabelsBeneathGraphics: true, - initialCenter: initialCenter, - zoom: 8, - rotationEnabled: true, - onMapCreated: _onMapCreated, - defaultUiList: [ - DefaultWidget( - viewType: DefaultWidgetType.compass, - position: WidgetPosition.topRight, - ), - ], + SizedBox( + width: 250, + child: ListView( + children: _buildTiles(context), + ), ), - Positioned( - bottom: 40, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, + Expanded( + child: Stack( children: [ - SizedBox( - width: MediaQuery.of(context).size.width, - child: Wrap( - crossAxisAlignment: WrapCrossAlignment.center, + ArcgisMap( + mapStyle: show3dMap ? MapStyle.threeD : MapStyle.twoD, + apiKey: arcGisApiKey, + basemap: BaseMap.osmDarkGray, + ground: show3dMap ? Ground.worldElevation : null, + showLabelsBeneathGraphics: true, + initialCenter: initialCenter, + zoom: 8, + rotationEnabled: true, + onMapCreated: _onMapCreated, + defaultUiList: [ + DefaultWidget( + viewType: DefaultWidgetType.compass, + position: WidgetPosition.topRight, + ), + ], + ), + Positioned( + bottom: 40, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ - Row( - children: [ - FloatingActionButton( - heroTag: "zoom-in-button", - onPressed: () { - _controller?.zoomIn( - lodFactor: 1, - animationOptions: AnimationOptions( - duration: 1000, - animationCurve: AnimationCurve.easeIn, + SizedBox( + width: MediaQuery.of(context).size.width, + child: Wrap( + crossAxisAlignment: WrapCrossAlignment.center, + children: [ + Row( + children: [ + FloatingActionButton( + onPressed: () { + _controller?.zoomIn( + lodFactor: 1, + animationOptions: AnimationOptions( + duration: 1000, + animationCurve: AnimationCurve.easeIn, + ), + ); + }, + backgroundColor: Colors.grey, + child: const Icon(Icons.add), ), - ); - }, - backgroundColor: Colors.grey, - child: const Icon(Icons.add), - ), - FloatingActionButton( - heroTag: "zoom-out-button", - onPressed: () { - _controller?.zoomOut( - lodFactor: 1, - animationOptions: AnimationOptions( - duration: 1000, - animationCurve: AnimationCurve.easeIn, + FloatingActionButton( + onPressed: () { + _controller?.zoomOut( + lodFactor: 1, + animationOptions: AnimationOptions( + duration: 1000, + animationCurve: AnimationCurve.easeIn, + ), + ); + }, + backgroundColor: Colors.grey, + child: const Icon(Icons.remove), ), - ); - }, - backgroundColor: Colors.grey, - child: const Icon(Icons.remove), - ), - FloatingActionButton( - heroTag: "move-camera-button", - backgroundColor: Colors.red, - child: const Icon(Icons.place_outlined), - onPressed: () { - _controller?.moveCamera( - point: tappedHQ, - zoomLevel: 8.0, - threeDHeading: 30, - threeDTilt: 60, - animationOptions: AnimationOptions( - duration: 1500, - animationCurve: AnimationCurve.easeIn, + FloatingActionButton( + backgroundColor: Colors.red, + child: const Icon(Icons.place_outlined), + onPressed: () { + _controller?.moveCamera( + point: tappedHQ, + zoomLevel: 8.0, + threeDHeading: 30, + threeDTilt: 60, + animationOptions: AnimationOptions( + duration: 1500, + animationCurve: AnimationCurve.easeIn, + ), + ); + }, ), - ); - }, - ), - if (kIsWeb) - FloatingActionButton( - heroTag: "3d-map-button", + if (kIsWeb) + FloatingActionButton( + heroTag: "3d-map-button", + onPressed: () { + setState(() { + show3dMap = !show3dMap; + _controller?.switchMapStyle( + show3dMap + ? MapStyle.threeD + : MapStyle.twoD, + ); + }); + }, + backgroundColor: + show3dMap ? Colors.red : Colors.blue, + child: Text(show3dMap ? '3D' : '2D'), + ), + ], + ), + ElevatedButton( onPressed: () { + _controller?.setInteraction( + isEnabled: !_isInteractionEnabled, + ); + setState(() { - show3dMap = !show3dMap; - _controller?.switchMapStyle( - show3dMap ? MapStyle.threeD : MapStyle.twoD, - ); + _isInteractionEnabled = + !_isInteractionEnabled; }); }, - backgroundColor: - show3dMap ? Colors.red : Colors.blue, - child: Text(show3dMap ? '3D' : '2D'), + child: Text( + "${_isInteractionEnabled ? "Disable" : "Enable"} Interaction", + ), ), - ], - ), - ElevatedButton( - onPressed: () { - _controller?.setInteraction( - isEnabled: !_isInteractionEnabled, - ); - - setState(() { - _isInteractionEnabled = !_isInteractionEnabled; - }); - }, - child: Text( - "${_isInteractionEnabled ? "Disable" : "Enable"} Interaction", - ), - ), - ElevatedButton( - onPressed: _routeToVectorLayerMap, - child: const Text("Show Vector layer example"), - ), - ElevatedButton( - onPressed: _routeToExportImageExample, - child: const Text("Show export image example"), - ), - ElevatedButton( - onPressed: _routeToLocationIndicatorExample, - child: const Text("Location indicator example"), - ), - ElevatedButton( - onPressed: _routeToBasemapStyleExamplePage, - child: const Text("Basemap example"), - ), - ElevatedButton( - onPressed: () { - _controller?.addViewPadding( - padding: const ViewPadding(right: 300), - ); - }, - child: const Text("Add 300 right"), - ), - ElevatedButton( - onPressed: () { - _controller?.addViewPadding( - padding: const ViewPadding(left: 300), - ); - }, - child: const Text("Add 300 left"), - ), - ElevatedButton( - onPressed: () { - if (_isFirstPinInView) { - _removeGraphic( - layerId: _pinLayerId, - objectId: _pinId1, - ); - setState(() { - _isFirstPinInView = false; - }); - } else { - _addPin( - layerId: _pinLayerId, - objectId: _pinId1, - location: _firstPinCoordinates, - ); - setState(() { - _isFirstPinInView = true; - }); - } - }, - child: _isFirstPinInView - ? const Text('Remove first Pin') - : const Text('Add first Pin'), - ), - ElevatedButton( - onPressed: () { - if (_isSecondPinInView) { - _removeGraphic( - layerId: _pinLayerId, - objectId: _pinId2, - ); - setState(() { - _isSecondPinInView = false; - }); - } else { - _addPin( - layerId: _pinLayerId, - objectId: _pinId2, - location: _secondPinCoordinates, - ); - setState(() { - _isSecondPinInView = true; - }); - } - }, - child: _isSecondPinInView - ? const Text('Remove second Pin') - : const Text('Add second Pin'), - ), - ElevatedButton( - onPressed: () { - if (_isFeatureInView) { - _removeGraphic( - layerId: _featureLayerId, - objectId: _pinFeatureId, - ); - setState(() { - _isFeatureInView = false; - }); - } else { - _addPin( - layerId: _featureLayerId, - objectId: _pinFeatureId, - location: _pinFeatureCoordinates, - ); - _controller?.moveCamera( - point: _pinFeatureCoordinates, - zoomLevel: 15, - ); - setState(() { - _isFeatureInView = true; - }); - } - }, - child: _isFeatureInView - ? const Text('Remove FeatureLayer Pin') - : const Text('Add FeatureLayer Pin'), - ), - ElevatedButton( - onPressed: () { - if (_subscribedToZoom) { - _unsubscribeFromZoom(); - } else { - _subscribeToZoom(); - } - }, - child: _subscribedToZoom - ? const Text('Stop zoom') - : const Text('Sub to zoom'), - ), - ElevatedButton( - onPressed: () { - if (_subscribedToCenterPosition) { - _unsubscribeFromPos(); - } else { - _subscribeToPos(); - } - }, - child: _subscribedToCenterPosition - ? const Text("Stop pos") - : const Text("Sub to pos"), - ), - if (kIsWeb) - ElevatedButton( - onPressed: () { - if (_subscribedToBounds) { - _unsubscribeFromBounds(); - } else { - _subscribeToBounds(); - } - }, - child: _subscribedToBounds - ? const Text("Stop bounds") - : const Text("Sub to bounds"), - ), - if (kIsWeb) - ElevatedButton( - onPressed: () { - if (_subscribedToGraphicsInView) { - _unSubscribeToGraphicsInView(); - } else { - _subscribeToGraphicsInView(); - } - }, - child: _subscribedToGraphicsInView - ? const Text("Stop printing Graphics") - : const Text("Start printing Graphics"), - ), - if (kIsWeb) - ElevatedButton( - onPressed: () { - final graphicIdsInView = - _controller?.getVisibleGraphicIds(); - graphicIdsInView?.forEach(debugPrint); - }, - child: const Text("Print visible Graphics"), - ), - ElevatedButton( - onPressed: () { - _addPolygon( - layerId: _polyLayerId, - graphic: PolygonGraphic( - rings: secondPolygon, - symbol: redFillSymbol, - attributes: Attributes({ - 'id': _polygon2, - 'name': 'Second Polygon', - }), - onHover: (isHovered) { - isHovered - ? _updateGraphicSymbol( - layerId: _polyLayerId, - graphicId: _polygon2, - symbol: highlightedRedFillSymbol, - ) - : _updateGraphicSymbol( - layerId: _polyLayerId, - graphicId: _polygon2, - symbol: redFillSymbol, - ); - if (_hoveredPolygons[_polygon2] == isHovered) { - return; + ElevatedButton( + onPressed: () { + _controller?.addViewPadding( + padding: const ViewPadding(right: 300), + ); + }, + child: const Text("Add 300 right"), + ), + ElevatedButton( + onPressed: () { + _controller?.addViewPadding( + padding: const ViewPadding(left: 300), + ); + }, + child: const Text("Add 300 left"), + ), + ElevatedButton( + onPressed: () { + if (_subscribedToZoom) { + _unsubscribeFromZoom(); + } else { + _subscribeToZoom(); } - _hoveredPolygons[_polygon2] = isHovered; }, + child: _subscribedToZoom + ? const Text('Stop zoom') + : const Text('Sub to zoom'), ), - ); - }, - child: const Text('Add red polygon'), - ), - ElevatedButton( - onPressed: () => _removeGraphic( - layerId: _polyLayerId, - objectId: _polygon2, + ElevatedButton( + onPressed: () { + if (_subscribedToCenterPosition) { + _unsubscribeFromPos(); + } else { + _subscribeToPos(); + } + }, + child: _subscribedToCenterPosition + ? const Text("Stop pos") + : const Text("Sub to pos"), + ), + if (kIsWeb) + ElevatedButton( + onPressed: () { + if (_subscribedToBounds) { + _unsubscribeFromBounds(); + } else { + _subscribeToBounds(); + } + }, + child: _subscribedToBounds + ? const Text("Stop bounds") + : const Text("Sub to bounds"), + ), + ElevatedButton( + onPressed: () => _controller?.retryLoad(), + child: const Text('Reload map'), + ), + ], ), - child: const Text('Remove red polygon'), ), - ElevatedButton( - onPressed: () => _controller?.retryLoad(), - child: const Text('Reload map'), - ), - ElevatedButton( - onPressed: () => _makePolylineVisible( - points: [_firstPinCoordinates, _secondPinCoordinates], - ), - child: const Text('Zoom to polyline'), + Row( + children: [ + const Text( + 'Powered by Esri', + style: TextStyle(color: Colors.white), + ), + Text( + _attributionText, + style: const TextStyle(color: Colors.white), + ), + ], ), ], ), ), - Row( - children: [ - const Text( - 'Powered by Esri', - style: TextStyle(color: Colors.white), - ), - Text( - _attributionText, - style: const TextStyle(color: Colors.white), + if (!isLargeScreen) + Positioned( + top: 8 + MediaQuery.paddingOf(context).top, + left: 8, + child: IconButton( + onPressed: () { + _scaffoldKey.currentState!.openDrawer(); + }, + color: Colors.black, + style: ButtonStyle( + backgroundColor: WidgetStatePropertyAll( + Colors.grey.withValues(alpha: 0.5)), + ), + icon: Icon(Icons.menu), ), - ], - ), + ) ], ), ), @@ -764,24 +406,6 @@ class _ExampleMapState extends State { // height: 56, // ); - final _markerSymbol = PictureMarkerSymbol( - assetUri: 'assets/navPointer.png', - width: 56, - height: 56, - ); - - void _routeToVectorLayerMap() { - Navigator.of(context).push( - MaterialPageRoute(builder: (_) => const VectorLayerExamplePage()), - ); - } - - void _routeToBasemapStyleExamplePage() { - Navigator.of(context).push( - MaterialPageRoute(builder: (_) => BasemapStyleExamplePage()), - ); - } - void _onMapStatusChanged(MapStatus status) { final scaffoldContext = _scaffoldKey.currentContext; if (scaffoldContext == null) return; @@ -794,15 +418,62 @@ class _ExampleMapState extends State { ); } - void _routeToLocationIndicatorExample() { - Navigator.of(context).push( - MaterialPageRoute(builder: (_) => const LocationIndicatorExamplePage()), + List _buildTiles(BuildContext context) { + return [ + _buildTile( + title: "Vector Layer Example", + onTap: () { + _navigateTo(context, VectorLayerExamplePage()); + }, + ), + _buildTile( + title: "Export Image Example", + onTap: () { + _navigateTo(context, ExportImageExamplePage()); + }, + ), + _buildTile( + title: "Location Indicator Example", + onTap: () { + _navigateTo(context, LocationIndicatorExamplePage()); + }, + ), + _buildTile( + title: "Basemap Style Example", + onTap: () { + _navigateTo(context, BasemapStyleExamplePage()); + }, + ), + _buildTile( + title: "Draw on map Example", + onTap: () { + _navigateTo(context, DrawOnMapExamplePage()); + }, + ), + ]; + } + + Widget _buildTile({ + required String title, + required VoidCallback onTap, + }) { + return Column( + children: [ + ListTile( + onTap: onTap, + title: Text( + title, + style: TextStyle(fontSize: 14, color: Colors.deepPurple), + ), + ), + Divider(height: 1), + ], ); } - void _routeToExportImageExample() { + void _navigateTo(BuildContext context, Widget page) { Navigator.of(context).push( - MaterialPageRoute(builder: (_) => const ExportImageExamplePage()), + MaterialPageRoute(builder: (_) => page), ); } } From e51fc28ef74be0a51524d69a369bfb011d072ec0 Mon Sep 17 00:00:00 2001 From: Tarek Tolba Date: Wed, 28 May 2025 18:04:15 +0300 Subject: [PATCH 4/5] Formatting --- example/lib/draw_on_map_example_page.dart | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/example/lib/draw_on_map_example_page.dart b/example/lib/draw_on_map_example_page.dart index 1d23e2ec..b04f9b93 100644 --- a/example/lib/draw_on_map_example_page.dart +++ b/example/lib/draw_on_map_example_page.dart @@ -144,7 +144,10 @@ class _DrawOnMapExamplePageState extends State { Widget build(BuildContext context) { return Scaffold( key: _scaffoldKey, - floatingActionButton: FloatingActionButton(onPressed: _showBottomSheet,child: Icon(Icons.draw),), + floatingActionButton: FloatingActionButton( + onPressed: _showBottomSheet, + child: Icon(Icons.draw), + ), body: Stack( children: [ ArcgisMap( @@ -583,7 +586,10 @@ class _DrawOnMapExamplePageState extends State { Navigator.pop(context); onPressed(); }, - title: Text(text,style: TextStyle(color: Colors.deepPurple),), + title: Text( + text, + style: TextStyle(color: Colors.deepPurple), + ), ); } } From d3ff16c0700b70c779a97917dd5986e8ea037792 Mon Sep 17 00:00:00 2001 From: Tarek Tolba Date: Wed, 28 May 2025 18:15:39 +0300 Subject: [PATCH 5/5] Update navigation drawer --- example/lib/main.dart | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index 859a2907..19d6fe53 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -184,12 +184,13 @@ class _ExampleMapState extends State { : NavigationDrawer(children: _buildTiles(context)), body: Row( children: [ - SizedBox( - width: 250, - child: ListView( - children: _buildTiles(context), + if (isLargeScreen) + SizedBox( + width: 250, + child: ListView( + children: _buildTiles(context), + ), ), - ), Expanded( child: Stack( children: [ @@ -426,18 +427,20 @@ class _ExampleMapState extends State { _navigateTo(context, VectorLayerExamplePage()); }, ), - _buildTile( - title: "Export Image Example", - onTap: () { - _navigateTo(context, ExportImageExamplePage()); - }, - ), - _buildTile( - title: "Location Indicator Example", - onTap: () { - _navigateTo(context, LocationIndicatorExamplePage()); - }, - ), + if (!kIsWeb) + _buildTile( + title: "Export Image Example", + onTap: () { + _navigateTo(context, ExportImageExamplePage()); + }, + ), + if (!kIsWeb) + _buildTile( + title: "Location Indicator Example", + onTap: () { + _navigateTo(context, LocationIndicatorExamplePage()); + }, + ), _buildTile( title: "Basemap Style Example", onTap: () {