Update and match marker style betwen google and osm backend (as much as possible)

This commit is contained in:
Ming Ming 2024-07-23 01:11:34 +08:00
parent 3c94741da3
commit a7ef3b0ed7
4 changed files with 152 additions and 99 deletions

View file

@ -23,6 +23,7 @@ import 'package:nc_photos/exception_event.dart';
import 'package:nc_photos/k.dart' as k; import 'package:nc_photos/k.dart' as k;
import 'package:nc_photos/snack_bar_manager.dart'; import 'package:nc_photos/snack_bar_manager.dart';
import 'package:nc_photos/stream_extension.dart'; import 'package:nc_photos/stream_extension.dart';
import 'package:nc_photos/stream_util.dart';
import 'package:nc_photos/theme.dart'; import 'package:nc_photos/theme.dart';
import 'package:nc_photos/theme/dimension.dart'; import 'package:nc_photos/theme/dimension.dart';
import 'package:nc_photos/widget/collection_browser.dart'; import 'package:nc_photos/widget/collection_browser.dart';

View file

@ -14,16 +14,8 @@ class _DataPoint extends DataPoint {
final int fileId; final int fileId;
} }
class _GoogleMarkerBuilder { class _MarkerBuilder {
_GoogleMarkerBuilder(this.context); _MarkerBuilder(this.context);
Future<BitmapDescriptor> build(List<DataPoint> dataPoints) {
return _getClusterBitmap(
_getMarkerSize(dataPoints.length),
text: _getMarkerCountString(dataPoints.length),
color: _getMarkerColor(dataPoints.length),
);
}
String _getMarkerCountString(int count) { String _getMarkerCountString(int count) {
switch (count) { switch (count) {
@ -40,7 +32,7 @@ class _GoogleMarkerBuilder {
} }
} }
Color _getMarkerColor(int count) { double _getMarkerRatio(int count) {
const step = 1 / 4; const step = 1 / 4;
final double r; final double r;
switch (count) { switch (count) {
@ -55,43 +47,77 @@ class _GoogleMarkerBuilder {
default: default:
r = (count / 10) * step; r = (count / 10) * step;
} }
if (Theme.of(context).brightness == Brightness.light) { return r;
return HSLColor.fromAHSL(
1,
_colorHsl.hue,
r * .7 + .3,
(_colorHsl.lightness - (.1 - r * .1)).clamp(0, 1),
).toColor();
} else {
return HSLColor.fromAHSL(
1,
_colorHsl.hue,
r * .6 + .4,
(_colorHsl.lightness - (.1 - r * .1)).clamp(0, 1),
).toColor();
}
} }
int _getMarkerSize(int count) { final BuildContext context;
const step = 1 / 4;
final double r; late final _minColorHsl =
switch (count) { HSLColor.fromColor(Theme.of(context).colorScheme.primary)
case >= 10000: .withSaturation(
r = 1; Theme.of(context).brightness == Brightness.light ? .9 : .7)
case >= 1000: .withLightness(
r = (count ~/ 1000) / 10 * step + step * 3; Theme.of(context).brightness == Brightness.light ? .4 : .3);
case >= 100: late final _maxColorHsl =
r = (count ~/ 100) / 10 * step + step * 2; HSLColor.fromColor(Theme.of(context).colorScheme.primary)
case >= 10: .withSaturation(
r = (count ~/ 10) / 10 * step + step; Theme.of(context).brightness == Brightness.light ? .9 : .7)
default: .withLightness(
r = (count / 10) * step; Theme.of(context).brightness == Brightness.light ? .3 : .2);
} }
return (r * 85).toInt() + 85;
class _OsmMarkerBuilder extends _MarkerBuilder {
_OsmMarkerBuilder(super.context);
Widget build(List<DataPoint> dataPoints) {
final text = _getMarkerCountString(dataPoints.length);
return _OsmMarker(
size: _getMarkerSize(dataPoints.length),
text: text,
textSize: _getMarkerTextSize(text, dataPoints.length),
color: _getMarkerColor(dataPoints.length),
);
}
double _getMarkerSize(int count) {
final r = _getMarkerRatio(count);
return (r * 28).toInt() + 28;
}
double _getMarkerTextSize(String text, int count) {
final r = _getMarkerRatio(count);
return (r * 3) + 9 - ((text.length / 6) * 1);
}
Color _getMarkerColor(int count) {
final r = _getMarkerRatio(count);
return HSLColor.lerp(_minColorHsl, _maxColorHsl, r)!.toColor();
}
}
class _GoogleMarkerBuilder extends _MarkerBuilder {
_GoogleMarkerBuilder(super.context);
Future<BitmapDescriptor> build(List<DataPoint> dataPoints) {
return _getClusterBitmap(
_getMarkerSize(dataPoints.length),
text: _getMarkerCountString(dataPoints.length),
color: _getMarkerColor(dataPoints.length),
);
}
double _getMarkerSize(int count) {
final r = _getMarkerRatio(count);
return (r * 75).toInt() + 100;
}
Color _getMarkerColor(int count) {
final r = _getMarkerRatio(count);
return HSLColor.lerp(_minColorHsl, _maxColorHsl, r)!.toColor();
} }
Future<BitmapDescriptor> _getClusterBitmap( Future<BitmapDescriptor> _getClusterBitmap(
int size, { double size, {
String? text, String? text,
required Color color, required Color color,
}) async { }) async {
@ -99,9 +125,7 @@ class _GoogleMarkerBuilder {
final Canvas canvas = Canvas(pictureRecorder); final Canvas canvas = Canvas(pictureRecorder);
final fillPaint = Paint()..color = color; final fillPaint = Paint()..color = color;
final outlinePaint = Paint() final outlinePaint = Paint()
..color = Theme.of(context).brightness == Brightness.light ..color = Colors.white.withOpacity(.75)
? Colors.black.withOpacity(.28)
: Colors.white.withOpacity(.6)
..strokeWidth = size / 28 ..strokeWidth = size / 28
..style = PaintingStyle.stroke; ..style = PaintingStyle.stroke;
const shadowPadding = 6.0; const shadowPadding = 6.0;
@ -126,7 +150,7 @@ class _GoogleMarkerBuilder {
text: text, text: text,
style: TextStyle( style: TextStyle(
fontSize: size / 3 - ((text.length / 6) * (size * 0.1)), fontSize: size / 3 - ((text.length / 6) * (size * 0.1)),
color: Theme.of(context).colorScheme.onPrimaryContainer, color: Colors.white.withOpacity(.75),
fontWeight: FontWeight.normal, fontWeight: FontWeight.normal,
), ),
); );
@ -139,15 +163,11 @@ class _GoogleMarkerBuilder {
), ),
); );
} }
final img = await pictureRecorder.endRecording().toImage(size, size); final img =
await pictureRecorder.endRecording().toImage(size.ceil(), size.ceil());
final data = await img.toByteData(format: ImageByteFormat.png) as ByteData; final data = await img.toByteData(format: ImageByteFormat.png) as ByteData;
return BitmapDescriptor.fromBytes(data.buffer.asUint8List()); return BitmapDescriptor.fromBytes(data.buffer.asUint8List());
} }
final BuildContext context;
late final _colorHsl =
HSLColor.fromColor(Theme.of(context).colorScheme.primaryContainer);
} }
enum _DateRangeType { enum _DateRangeType {

View file

@ -26,42 +26,44 @@ class _MapViewState extends State<_MapView> {
builder: (context, state) { builder: (context, state) {
final prevPosition = final prevPosition =
context.read<PrefController>().mapBrowserPrevPositionValue; context.read<PrefController>().mapBrowserPrevPositionValue;
return InteractiveMap( return ValueStreamBuilder<GpsMapProvider>(
providerHint: GpsMapProvider.google, stream: context.bloc.prefController.gpsMapProvider,
initialPosition: prevPosition ?? const MapCoord(0, 0), builder: (context, gpsMapProvider) => InteractiveMap(
initialZoom: prevPosition == null ? 2.5 : 10, providerHint: gpsMapProvider.requireData,
dataPoints: state.data, initialPosition: prevPosition ?? const MapCoord(0, 0),
onClusterTap: (dataPoints) { initialZoom: prevPosition == null ? 2.5 : 10,
final c = Collection( dataPoints: state.data,
name: "", onClusterTap: (dataPoints) {
contentProvider: CollectionAdHocProvider( final c = Collection(
account: context.bloc.account, name: "",
fileIds: dataPoints contentProvider: CollectionAdHocProvider(
.cast<_DataPoint>() account: context.bloc.account,
.map((e) => e.fileId) fileIds: dataPoints
.toList(), .cast<_DataPoint>()
), .map((e) => e.fileId)
); .toList(),
Navigator.of(context).pushNamed( ),
CollectionBrowser.routeName, );
arguments: CollectionBrowserArguments(c), Navigator.of(context).pushNamed(
); CollectionBrowser.routeName,
}, arguments: CollectionBrowserArguments(c),
googleClusterBuilder: (context, dataPoints) => );
_GoogleMarkerBuilder(context).build(dataPoints), },
osmClusterBuilder: (context, dataPoints) => _OsmMarker( googleClusterBuilder: (context, dataPoints) =>
count: dataPoints.length, _GoogleMarkerBuilder(context).build(dataPoints),
osmClusterBuilder: (context, dataPoints) =>
_OsmMarkerBuilder(context).build(dataPoints),
contentPadding: EdgeInsets.only(
top: MediaQuery.of(context).padding.top,
bottom: MediaQuery.of(context).padding.bottom,
),
onMapCreated: (controller) {
_controller = controller;
if (state.initialPoint != null) {
controller.setPosition(state.initialPoint!);
}
},
), ),
contentPadding: EdgeInsets.only(
top: MediaQuery.of(context).padding.top,
bottom: MediaQuery.of(context).padding.bottom,
),
onMapCreated: (controller) {
_controller = controller;
if (state.initialPoint != null) {
controller.setPosition(state.initialPoint!);
}
},
); );
}, },
), ),
@ -73,26 +75,50 @@ class _MapViewState extends State<_MapView> {
class _OsmMarker extends StatelessWidget { class _OsmMarker extends StatelessWidget {
const _OsmMarker({ const _OsmMarker({
required this.count, required this.size,
required this.text,
required this.textSize,
required this.color,
}); });
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return Center(
decoration: BoxDecoration( child: Container(
borderRadius: BorderRadius.circular(20), width: size,
color: Theme.of(context).colorScheme.primary, height: size,
), decoration: BoxDecoration(
child: Center( borderRadius: BorderRadius.circular(size / 2),
child: Text( boxShadow: [
count.toString(), BoxShadow(
style: const TextStyle(color: Colors.white), color: Colors.black.withOpacity(.3),
blurRadius: 2,
offset: const Offset(1, 1),
),
],
border: Border.all(
color: Colors.white.withOpacity(.75),
width: 1.5,
),
color: color,
),
child: Center(
child: Text(
text,
style: TextStyle(
fontSize: textSize,
color: Colors.white.withOpacity(.75),
),
),
), ),
), ),
); );
} }
final int count; final double size;
final String text;
final double textSize;
final Color color;
} }
class _PanelContainer extends StatefulWidget { class _PanelContainer extends StatefulWidget {

View file

@ -73,6 +73,12 @@ class _OsmInteractiveMapState extends State<OsmInteractiveMap> {
context, context,
markers.cast<_OsmDataPoint>().map((e) => e.original).toList(), markers.cast<_OsmDataPoint>().map((e) => e.original).toList(),
), ),
// need to be large enough to contain markers of all size
size: const Size.square(120),
// disable all tap handlers from package
zoomToBoundsOnClick: false,
centerMarkerOnClick: false,
spiderfyCluster: false,
), ),
), ),
Padding( Padding(