Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
esride-jts committed Nov 22, 2024
2 parents 2670881 + 5543416 commit 2d21ae6
Show file tree
Hide file tree
Showing 4 changed files with 135 additions and 40 deletions.
7 changes: 7 additions & 0 deletions native-apps/urban-heat-notifier/urban_heat_notifier/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,13 @@ Use `dart run build_runner build` to run the generator:
dart run build_runner build
```

When modifying the .env file, the generator might not pick up the change. If that happens simply clean the build cache and run the generator again.

```
dart run build_runner clean
dart run build_runner build --delete-conflicting-outputs
```

Step 3 Run the application

```
Expand Down
5 changes: 2 additions & 3 deletions native-apps/urban-heat-notifier/urban_heat_notifier/_.env
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,5 @@ HriFeatureServicePortalItemID=5969b96bfb0340b0abe1ad78dbe8150c
DrinkingWaterFeatureServiceTitle=Drinking Water Feature
DrinkingWaterFeatureServicePortalItemID=bd918e6dd0da42ca9462cfb56214eb6a
PlacesServiceUrl=https://places-api.arcgis.com/arcgis/rest/services/places-service/v1/places/near-point
PlacesSearchRadius=500
PlacesCategoryDiningDrinkingId=13000
PlacesCategoryHealthMedicineId=1500
PlacesSearchRadius=75
PlacesCategoryIds=13000,15000
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@ abstract class Env {
static String placesServiceUrl = _Env.placesServiceUrl;
@EnviedField(varName: 'PlacesSearchRadius', obfuscate: false)
static String placesSearchRadius = _Env.placesSearchRadius;
@EnviedField(varName: 'PlacesCategoryDiningDrinkingId', obfuscate: false)
static String placesCategoryDiningDrinkingId = _Env.placesCategoryDiningDrinkingId;
@EnviedField(varName: 'PlacesCategoryHealthMedicineId', obfuscate: false)
static String placesCategoryHealthMedicineId = _Env.placesCategoryHealthMedicineId;
@EnviedField(varName: 'PlacesCategoryIds', obfuscate: false)
static String placesCategoryIds = _Env.placesCategoryIds;

}
156 changes: 123 additions & 33 deletions native-apps/urban-heat-notifier/urban_heat_notifier/lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:arcgis_maps/arcgis_maps.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'env/env.dart';

Expand Down Expand Up @@ -34,6 +35,7 @@ class _MapScreenState extends State<MapScreen> {
late FeatureLayer _dwFeatureLayer;
bool isButtonVisible = false;
final _geodeticOverlay = GraphicsOverlay();
final _placesOverlay = GraphicsOverlay();

@override
void initState() {
Expand Down Expand Up @@ -143,6 +145,7 @@ class _MapScreenState extends State<MapScreen> {

void onLongPressEnd(Offset screenPoint) async {
if (!isButtonVisible) {
_hriFeatureLayer.isVisible = false;
_geodeticOverlay.graphics.clear();
// Capture the tapped point and convert it to a map point.
final mapPoint = _mapViewController.screenToLocation(screen: screenPoint);
Expand All @@ -151,54 +154,139 @@ class _MapScreenState extends State<MapScreen> {
// Create a geodetic buffer around the tapped point at the specified distance.
final geodeticGeometry = GeometryEngine.bufferGeodetic(
geometry: mapPoint,
distance: 100,
distance: double.parse(Env.placesSearchRadius),
distanceUnit: LinearUnit(unitId: LinearUnitId.meters),
maxDeviation: double.nan,
curveType: GeodeticCurveType.geodesic,
);
// Create and add a graphic to the geodetic overlay.
final geodeticGraphic = Graphic(geometry: geodeticGeometry);
_geodeticOverlay.graphics.add(geodeticGraphic);

final queryParameters = QueryParameters();
queryParameters.geometry = geodeticGeometry;
queryParameters.returnGeometry = false;
showBuffer(geodeticGeometry);
showDrinkingWater(geodeticGeometry);
showPlaces(mapPoint);

ServiceFeatureTable sfTable =
_dwFeatureLayer.featureTable as ServiceFeatureTable;
setState(() {
isButtonVisible = !isButtonVisible;
});
}
}

final queryResult = await sfTable.queryFeatures(
parameters: queryParameters,
void showBuffer(Geometry geodeticGeometry) async {
final geodeticGraphic = Graphic(geometry: geodeticGeometry);
_geodeticOverlay.graphics.add(geodeticGraphic);
}

void showPlaces(Geometry mapPoint) async {
final wgs84MapPoint = GeometryEngine.project(mapPoint,
outputSpatialReference: SpatialReference.wgs84) as ArcGISPoint;

String url = '${Env.placesServiceUrl}'
'?f=json'
'&x=${wgs84MapPoint.x}'
'&y=${wgs84MapPoint.y}'
'&radius=${Env.placesSearchRadius}'
'&categoryIds=${Env.placesCategoryIds}'
'&pageSize=20'
'&icon=png'
'&token=${Env.apikey}';

List<dynamic> allResults = [];
bool hasNextPage = true;

while (hasNextPage) {
final response = await http.get(Uri.parse(url));

if (response.statusCode == 200) {
final String responseBody = response.body;

final Map<String, dynamic> jsonResponse = json.decode(responseBody);
allResults.addAll(jsonResponse['results']);

if (jsonResponse.containsKey('pagination') &&
jsonResponse['pagination'].containsKey('nextUrl')) {
url = jsonResponse['pagination']['nextUrl'];
url += '&token=${Env.apikey}';
print('Next URL: $url'); // Debugging-Ausgabe
} else {
hasNextPage = false;
}
} else {
print('Request failed with status: ${response.statusCode}');
hasNextPage = false;
}
}

List<Graphic> graphics = allResults.map((result) {
double x = result['location']['x'];
double y = result['location']['y'];
ArcGISPoint point = ArcGISPoint(
x: x,
y: y,
spatialReference: SpatialReference.wgs84,
);

var whereClause = '';
ArcGISPoint projectedPoint = GeometryEngine.project(point,
outputSpatialReference: SpatialReference.webMercator) as ArcGISPoint;

for (var feature in queryResult.features()) {
whereClause =
whereClause + 'ObjectId = ${feature.attributes['ObjectId']}';
Map<String, dynamic> attributes = {
'placeId': result['placeId'],
'name': result['name'],
'distance': result['distance'],
'categoryId': result['categories'][0]['categoryId'],
'categoryLabel': result['categories'][0]['label'],
};

if (feature.attributes['ObjectId'] !=
queryResult.features().first.attributes['ObjectId'] &&
feature.attributes['ObjectId'] !=
queryResult.features().last.attributes['objectId']) {
whereClause = whereClause + ' OR ';
}
}
Uri iconUri = Uri.parse(result['icon']['url']);
PictureMarkerSymbol symbol = PictureMarkerSymbol.withUrl(iconUri);
symbol.width = 30;
symbol.height = 30;

_dwFeatureLayer.definitionExpression = whereClause;
await _dwFeatureLayer.retryLoad();
// _dwFeatureLayer.setFeaturesVisible(features: queryResult.features().toList(), visible: false);
_dwFeatureLayer.isVisible = true;
return Graphic(
geometry: projectedPoint,
symbol: symbol,
attributes: attributes,
);
}).toList();

setState(() {
isButtonVisible = !isButtonVisible;
});
_placesOverlay.graphics.addAll(graphics);
}

void showDrinkingWater(Geometry geodeticGeometry) async {
final queryParameters = QueryParameters();
queryParameters.geometry = geodeticGeometry;
queryParameters.returnGeometry = false;

ServiceFeatureTable sfTable =
_dwFeatureLayer.featureTable as ServiceFeatureTable;

final queryResult = await sfTable.queryFeatures(
parameters: queryParameters,
);

var whereClause = '';

for (var feature in queryResult.features()) {
whereClause =
whereClause + 'ObjectId = ${feature.attributes['ObjectId']}';

if (feature.attributes['ObjectId'] !=
queryResult.features().first.attributes['ObjectId'] &&
feature.attributes['ObjectId'] !=
queryResult.features().last.attributes['objectId']) {
whereClause = whereClause + ' OR ';
}
}

_dwFeatureLayer.definitionExpression = whereClause;
await _dwFeatureLayer.retryLoad();
// _dwFeatureLayer.setFeaturesVisible(features: queryResult.features().toList(), visible: false);
_dwFeatureLayer.isVisible = true;
}

void onClearButtenPressed() {
_geodeticOverlay.graphics.clear();
_placesOverlay.graphics.clear();
_dwFeatureLayer.isVisible = false;
_hriFeatureLayer.isVisible = true;
setState(() {
isButtonVisible = !isButtonVisible;
});
Expand Down Expand Up @@ -233,7 +321,7 @@ class _MapScreenState extends State<MapScreen> {
_hriFeatureLayer =
FeatureLayer.withItem(featureServiceItem: portalItem, layerId: 0);
_hriFeatureLayer.definitionExpression = "hri >= 9";
_hriFeatureLayer.opacity = .5;
_hriFeatureLayer.opacity = .4;
map.operationalLayers.add(_hriFeatureLayer);

await _hriFeatureLayer.load();
Expand Down Expand Up @@ -262,15 +350,15 @@ class _MapScreenState extends State<MapScreen> {
color: Colors.grey,
outline: SimpleLineSymbol(
style: SimpleLineSymbolStyle.solid,
color: Colors.black,
width: 2.0,
color: Colors.red,
width: 5.0,
),
),
);
_geodeticOverlay.opacity = 0.2;

_mapViewController.graphicsOverlays.addAll(
[_geodeticOverlay],
[_geodeticOverlay, _placesOverlay],
);

// Set the initial system location data source and auto-pan mode.
Expand Down Expand Up @@ -343,6 +431,8 @@ class _MapScreenState extends State<MapScreen> {
}

void _toggleLayerVisibility(double scale) async {
if (!_placesOverlay.graphics.isEmpty) return;

if (scale <= 10000) {
_hriVectorTiledLayer.isVisible = false;
_hriFeatureLayer.isVisible = true;
Expand Down

0 comments on commit 2d21ae6

Please sign in to comment.