Reputation: 21
Version mapbox_maps_flutter: ^0.5.1 is being used to render a MapBox in Flutter application
Flutter version 3.16.2
1. First problem
The 1st issue I want to highlight that if I apply my own map style other than by default MapboxStyles.LIGHT
, all clusters
and unClusteredLayer
are below the main map layout and not visible - means that I see them during some milliseconds (before map layout was loaded) and later map just covers them. Even if I use MapboxStyles.DARK
the same problem exists.
2. Second problem Is there any way to combine Markers and Clusters in the way that they know that each other exists on the map?
I render Markers by means of pointAnnotationManager
and render Clusters as per your example file (example).
Both Markers and Clusters are displayed on the screen, but when some points are inside Cluster their markers are still visible.
In example YOU use unclusteredLayer instead of Markers. As for the Cluster I found the way how to style it, however as for the unClusteredLayer
I didn't find any way or example on how to set it as an Image but not a simple circle. Nevertheless, even if I find the way how to set unClusteredLayer
as an Image I didn't find any way to listen to tap on cluster or on unClusteredLayer
.
Please, provide a complete example, that includes both clusters and "custom" markers as an Image where these "custom" markers are not visible inside cluster and the way to listen tap on cluster or unClusteredLayer
.
Here is the my code that is responsible for both Clusters and Markers.
...
void setMarkers(BuildContext context, List<PlaceEntity> places) async {
mapboxMap.annotations.createPointAnnotationManager().then((pointAnnotationManager) async {
var options = <PointAnnotationOptions>[];
for (var i = 0; i < places.length; i++) {
final point = points[i];
final place = places[i];
final widget = IEyeMarker(
place: place,
onDetailsTap: () {},
);
final Uint8List? image = await createImageFromWidget(context, widget);
options.add(
PointAnnotationOptions(
geometry: Point(coordinates: Position(point.lng, point.lat)).toJson(),
image: image,
textField: place.id.toString(),
textColor: 0x00000000,
iconSize: 1,
),
);
}
pointAnnotationManager.createMulti(options);
pointAnnotationManager
.addOnPointAnnotationClickListener(AnnotationClickListener(context: context));
});
List<Map<String, Object>> features = [];
for (var i = 0; i < places.length; i++) {
final point = points[i];
final place = places[i];
features.add({
'type': 'Feature',
'id': place.id,
'properties': {
'point_count_abbreviated': '1',
'cluster_id': place.id,
// 'cluster': true,
// 'point_count': 1
},
'geometry': {
'type': 'Point',
'coordinates': [point.lng, point.lat, 0.0]
}
});
}
final data = {
'type': 'FeatureCollection',
'crs': {
'type': 'name',
'properties': {'name': 'urn:ogc:def:crs:OGC:1.3:CRS84'}
},
'features': features,
};
final layout = {
'type': 'geojson',
'data': data,
'cluster': true,
'clusterMaxZoom': 14,
'clusterRadius': 50,
};
mapboxMap.style.styleSourceExists('places').then((value) async {
if (!value) {
var source = jsonEncode(layout);
mapboxMap.style.addStyleSource('places', source.toString());
}
});
mapboxMap.style.styleLayerExists('clusters').then((value) async {
if (!value) {
var layer = await rootBundle.loadString('assets/cluster/cluster_layer.json');
mapboxMap.style.addStyleLayer(layer, null);
var clusterCountLayer =
await rootBundle.loadString('assets/cluster/cluster_count_layer.json');
mapboxMap.style.addStyleLayer(clusterCountLayer, null);
var unClusteredLayer =
await rootBundle.loadString('assets/cluster/unclustered_point_layer.json');
mapboxMap.style.addStyleLayer(unClusteredLayer, null);
}
});
}
...
final points = [
LatLng(lat: 51.5382123, lng: -0.1882464),
LatLng(lat: 51.4382123, lng: -0.1982464),
LatLng(lat: 51.5090229, lng: -0.2886548),
LatLng(lat: 51.1090229, lng: -0.2786548),
LatLng(lat: 51.5054563, lng: -0.0798412),
LatLng(lat: 51.5090215, lng: -0.1959988),
LatLng(lat: 51.5190215, lng: -0.1859988),
LatLng(lat: 51.5577676, lng: -0.2008447),
];
File "create_image_from_widget.dart":
import 'dart:ui';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
Future<Uint8List?> createImageFromWidget(BuildContext context, Widget widget,
{Duration? wait, Size? logicalSize, Size? imageSize}) async {
final repaintBoundary = RenderRepaintBoundary();
logicalSize ??= View.of(context).physicalSize / View.of(context).devicePixelRatio;
imageSize ??= View.of(context).physicalSize;
assert(logicalSize.aspectRatio == imageSize.aspectRatio,
'logicalSize and imageSize must not be the same');
final renderView = RenderView(
child: RenderPositionedBox(alignment: Alignment.center, child: repaintBoundary),
configuration: ViewConfiguration(
size: logicalSize,
devicePixelRatio: 1,
),
view: View.of(context) //PlatformDispatcher.instance.views.first,
);
final pipelineOwner = PipelineOwner();
final buildOwner = BuildOwner(focusManager: FocusManager());
pipelineOwner.rootNode = renderView;
renderView.prepareInitialFrame();
final rootElement = RenderObjectToWidgetAdapter<RenderBox>(
container: repaintBoundary,
child: Directionality(
textDirection: TextDirection.ltr,
child: widget,
)).attachToRenderTree(buildOwner);
buildOwner.buildScope(rootElement);
if (wait != null) {
await Future.delayed(wait);
}
buildOwner
..buildScope(rootElement)
..finalizeTree();
pipelineOwner
..flushLayout()
..flushCompositingBits()
..flushPaint();
final image = await repaintBoundary.toImage(pixelRatio: imageSize.width / logicalSize.width);
final byteData = await image.toByteData(format: ImageByteFormat.png);
return byteData?.buffer.asUint8List();
}
Just for info here is my flutter doctor result:
Doctor summary (to see all details, run flutter doctor -v):
[!] Flutter (Channel stable, 3.16.2, on macOS 14.2.1 23C71 darwin-arm64, locale ru-RU)
! Warning: `dart` on your path resolves to /opt/homebrew/Cellar/dart-sdk/3.1.5/libexec/bin/dart, which is not inside your current Flutter SDK checkout at /Users/andreifufylev/fvm/versions/3.16.2. Consider
adding /Users/andreifufylev/fvm/versions/3.16.2/bin to the front of your path.
[✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
[✓] Xcode - develop for iOS and macOS (Xcode 15.1)
[✓] Chrome - develop for the web
[✓] Android Studio (version 2023.1)
[✓] IntelliJ IDEA Community Edition (version 2023.2.5)
[✓] VS Code (version 1.85.1)
[✓] Connected device (4 available)
[✓] Network resources
! Doctor found issues in 1 category.
In order to make muself clear I also included the video and screenshots of my problem where rounded boxes with Image inside are my custom Markers converted from Widget
to Uint8List
:
Without my own custom Markers With markers
I expect that custom markers to be not visible/clickable when inside cluster.
Upvotes: 1
Views: 689