aves/plugins/aves_map/lib/src/marker/image.dart
Thibault Deckers f10abcd670 format review
2024-05-20 15:20:13 +02:00

171 lines
5.6 KiB
Dart

import 'package:aves_map/aves_map.dart';
import 'package:aves_map/src/marker/arrow_painter.dart';
import 'package:collection/collection.dart';
import 'package:custom_rounded_rectangle_border/custom_rounded_rectangle_border.dart';
import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:intl/intl.dart' as intl;
import 'package:latlong2/latlong.dart';
class ImageMarker extends StatelessWidget {
final int? count;
final intl.NumberFormat countFormatter;
final bool drawArrow;
final Widget Function(double extent) buildThumbnailImage;
static const double outerBorderRadiusDim = 8;
static const outerBorderWidth = MapThemeData.markerOuterBorderWidth;
static const innerBorderWidth = MapThemeData.markerInnerBorderWidth;
static const extent = MapThemeData.markerImageExtent;
static const arrowSize = MapThemeData.markerArrowSize;
static const outerBorderRadius = BorderRadius.all(Radius.circular(outerBorderRadiusDim));
static const innerRadius = Radius.circular(outerBorderRadiusDim - outerBorderWidth);
static const innerBorderRadius = BorderRadius.all(innerRadius);
ImageMarker({
super.key,
required this.count,
required String locale,
this.drawArrow = true,
required this.buildThumbnailImage,
}) : countFormatter = intl.NumberFormat.decimalPattern(locale);
@override
Widget build(BuildContext context) {
Widget child = buildThumbnailImage(extent);
// need to be sized for the Google map marker generator
child = SizedBox(
width: extent,
height: extent,
child: child,
);
final theme = Theme.of(context);
final isDark = theme.brightness == Brightness.dark;
final outerBorderColor = MapThemeData.markerThemedOuterBorderColor(isDark);
final innerBorderColor = MapThemeData.markerThemedInnerBorderColor(isDark);
final outerDecoration = BoxDecoration(
border: Border.fromBorderSide(BorderSide(
color: outerBorderColor,
width: outerBorderWidth,
)),
borderRadius: outerBorderRadius,
);
final innerDecoration = BoxDecoration(
border: Border.fromBorderSide(BorderSide(
color: innerBorderColor,
width: innerBorderWidth,
)),
borderRadius: innerBorderRadius,
);
child = DecoratedBox(
decoration: innerDecoration,
position: DecorationPosition.foreground,
child: ClipRRect(
borderRadius: innerBorderRadius,
child: child,
),
);
if (count != null) {
final borderSide = BorderSide(
color: innerBorderColor,
width: innerBorderWidth,
);
child = Stack(
children: [
child,
Container(
padding: const EdgeInsets.symmetric(vertical: 0, horizontal: 2),
decoration: ShapeDecoration(
color: theme.colorScheme.primary,
shape: Directionality.of(context) == TextDirection.rtl
? CustomRoundedRectangleBorder(
leftSide: borderSide,
rightSide: borderSide,
topSide: borderSide,
bottomSide: borderSide,
topRightCornerSide: borderSide,
bottomLeftCornerSide: borderSide,
borderRadius: const BorderRadius.only(
topRight: innerRadius,
bottomLeft: innerRadius,
),
)
: CustomRoundedRectangleBorder(
leftSide: borderSide,
rightSide: borderSide,
topSide: borderSide,
bottomSide: borderSide,
topLeftCornerSide: borderSide,
bottomRightCornerSide: borderSide,
borderRadius: const BorderRadius.only(
topLeft: innerRadius,
bottomRight: innerRadius,
),
),
),
child: Text(
countFormatter.format(count),
style: TextStyle(
fontSize: 12,
color: theme.colorScheme.onPrimary,
),
),
),
],
);
}
child = Container(
decoration: outerDecoration,
child: child,
);
if (drawArrow) {
child = CustomPaint(
foregroundPainter: MarkerArrowPainter(
color: innerBorderColor,
outlineColor: outerBorderColor,
outlineWidth: outerBorderWidth,
size: arrowSize,
),
child: Padding(
padding: EdgeInsets.only(bottom: arrowSize.height),
child: child,
),
);
}
return child;
}
static const _crs = Epsg3857();
static GeoEntry<T>? markerMatch<T>(LatLng position, double zoom, Set<GeoEntry<T>> markers) {
final pressPoint = _crs.latLngToPoint(position, zoom);
final pressOffset = Offset(pressPoint.x.toDouble(), pressPoint.y.toDouble());
const double markerWidth = extent;
const double markerHeight = extent;
return markers.firstWhereOrNull((marker) {
final latitude = marker.latitude;
final longitude = marker.longitude;
if (latitude == null || longitude == null) return false;
final markerAnchorPoint = _crs.latLngToPoint(LatLng(latitude, longitude), zoom);
final bottom = markerAnchorPoint.y.toDouble();
final top = bottom - markerHeight;
final left = markerAnchorPoint.x.toDouble() - markerWidth / 2;
final right = left + markerWidth;
final markerRect = Rect.fromLTRB(left, top, right, bottom);
return markerRect.contains(pressOffset);
});
}
}