From 7cae2827c70cc8cdeb28f4ca768b92cfdaab74f4 Mon Sep 17 00:00:00 2001 From: Ming Ming Date: Sat, 13 Jul 2024 21:12:18 +0800 Subject: [PATCH] Update cluster marker style in map browser --- app/lib/widget/map_browser.dart | 1 + app/lib/widget/map_browser/view.dart | 93 +++++++++++++++++++++++++--- 2 files changed, 87 insertions(+), 7 deletions(-) diff --git a/app/lib/widget/map_browser.dart b/app/lib/widget/map_browser.dart index 5f9ccf2c..0b035afc 100644 --- a/app/lib/widget/map_browser.dart +++ b/app/lib/widget/map_browser.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'dart:ui'; import 'package:copy_with/copy_with.dart'; +import 'package:flex_seed_scheme/flex_seed_scheme.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; diff --git a/app/lib/widget/map_browser/view.dart b/app/lib/widget/map_browser/view.dart index b2b85938..6929c7b1 100644 --- a/app/lib/widget/map_browser/view.dart +++ b/app/lib/widget/map_browser/view.dart @@ -56,27 +56,41 @@ class _MapViewState extends State<_MapView> { Future _getClusterBitmap( int size, { String? text, + required Color color, }) async { final PictureRecorder pictureRecorder = PictureRecorder(); final Canvas canvas = Canvas(pictureRecorder); - final Paint paint1 = Paint()..color = Theme.of(context).colorScheme.primary; + final Paint paint1 = Paint()..color = color; - canvas.drawCircle(Offset(size / 2, size / 2), size / 2.0, paint1); + const shadowPadding = 6.0; + const shadowPaddingHalf = shadowPadding / 2; + final shadowPath = Path() + ..addOval( + Rect.fromLTWH(0, 0, size - shadowPadding, size - shadowPadding)); + canvas.drawShadow(shadowPath, Colors.black, 1, false); + canvas.drawCircle( + Offset(size / 2 - shadowPaddingHalf, size / 2 - shadowPaddingHalf), + size / 2 - shadowPaddingHalf, + paint1, + ); if (text != null) { TextPainter painter = TextPainter(textDirection: TextDirection.ltr); painter.text = TextSpan( text: text, style: TextStyle( - fontSize: size / 3, - color: Theme.of(context).colorScheme.onPrimary, + fontSize: size / 3.5, + color: Theme.of(context).colorScheme.onPrimaryContainer, fontWeight: FontWeight.normal, ), ); painter.layout(); painter.paint( canvas, - Offset(size / 2 - painter.width / 2, size / 2 - painter.height / 2), + Offset( + size / 2 - painter.width / 2 - shadowPaddingHalf, + size / 2 - painter.height / 2 - shadowPaddingHalf, + ), ); } @@ -86,6 +100,63 @@ class _MapViewState extends State<_MapView> { return BitmapDescriptor.fromBytes(data.buffer.asUint8List()); } + String _getMarkerCountString(int count) { + switch (count) { + case >= 10000: + return "10000+"; + case >= 1000: + return "${count ~/ 1000 * 1000}+"; + case >= 100: + return "${count ~/ 100 * 100}+"; + case >= 10: + return "${count ~/ 10 * 10}+"; + default: + return count.toString(); + } + } + + Color _getMarkerColor(int count) { + const step = 1 / 4; + final double r; + switch (count) { + case >= 10000: + r = 1; + case >= 1000: + r = (count ~/ 1000) / 10 * step + step * 3; + case >= 100: + r = (count ~/ 100) / 10 * step + step * 2; + case >= 10: + r = (count ~/ 10) / 10 * step + step; + default: + r = (count / 10) * step; + } + if (Theme.of(context).brightness == Brightness.light) { + final tone = (r * 30 + 65).toInt(); + return Color(_colorTonalPalette.get(tone)); + } else { + final tone = (60 - r * 30).toInt(); + return Color(_colorTonalPalette.get(tone)); + } + } + + int _getMarkerSize(int count) { + const step = 1 / 4; + final double r; + switch (count) { + case >= 10000: + r = 1; + case >= 1000: + r = (count ~/ 1000) / 10 * step + step * 3; + case >= 100: + r = (count ~/ 100) / 10 * step + step * 2; + case >= 10: + r = (count ~/ 10) / 10 * step + step; + default: + r = (count / 10) * step; + } + return (r * 50).toInt() + 90; + } + late final _clusterManager = ClusterManager<_DataPoint>( const [], (markers) { @@ -109,9 +180,17 @@ class _MapViewState extends State<_MapView> { arguments: CollectionBrowserArguments(c), ); }, - icon: await _getClusterBitmap(cluster.isMultiple ? 125 : 50, - text: cluster.isMultiple ? cluster.count.toString() : null), + icon: await _getClusterBitmap( + _getMarkerSize(cluster.count * 1), + text: _getMarkerCountString(cluster.count * 1), + color: _getMarkerColor(cluster.count * 1), + ), ), ); GoogleMapController? _mapController; + + late final _colorTonalPalette = () { + final hct = Hct.fromInt(Theme.of(context).colorScheme.primary.value); + return FlexTonalPalette.of(hct.hue, hct.chroma); + }(); }