Skip to content

Commit

Permalink
feat: add hit detection to Polylines (fleaflet#1728)
Browse files Browse the repository at this point in the history
Co-authored-by: Luka S <github@jaffaketchup.dev>
  • Loading branch information
ignatz and JaffaKetchup authored Dec 15, 2023
1 parent e7170da commit b94de88
Show file tree
Hide file tree
Showing 2 changed files with 405 additions and 103 deletions.
253 changes: 188 additions & 65 deletions example/lib/pages/polyline.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,96 @@ class PolylinePage extends StatefulWidget {
}

class _PolylinePageState extends State<PolylinePage> {
final PolylineHitNotifier hitNotifier = ValueNotifier(null);

final polylines = <Polyline, ({String title, String subtitle})>{
Polyline(
points: [
const LatLng(51.5, -0.09),
const LatLng(53.3498, -6.2603),
const LatLng(48.8566, 2.3522),
],
strokeWidth: 8,
color: const Color(0xFF60399E),
): (
title: 'Elizabeth Line',
subtitle: 'Nothing really special here...',
),
Polyline(
points: [
const LatLng(48.5, -3.09),
const LatLng(47.3498, -9.2603),
const LatLng(43.8566, -1.3522),
],
strokeWidth: 16000,
color: Colors.pink,
useStrokeWidthInMeter: true,
): (
title: 'Pink Line',
subtitle: 'Fixed radius in meters instead of pixels',
),
Polyline(
points: [
const LatLng(55.5, -0.09),
const LatLng(54.3498, -6.2603),
const LatLng(52.8566, 2.3522),
],
strokeWidth: 4,
gradientColors: [
const Color(0xffE40203),
const Color(0xffFEED00),
const Color(0xff007E2D),
],
): (
title: 'Traffic Light Line',
subtitle: 'Fancy gradient instead of a solid color',
),
Polyline(
points: [
const LatLng(50.5, -0.09),
const LatLng(51.3498, 6.2603),
const LatLng(53.8566, 2.3522),
],
strokeWidth: 20,
color: Colors.blue.withOpacity(0.6),
borderStrokeWidth: 20,
borderColor: Colors.red.withOpacity(0.4),
): (
title: 'BlueRed Line',
subtitle: 'Solid translucent color fill, with different color outline',
),
Polyline(
points: [
const LatLng(50.2, -0.08),
const LatLng(51.2498, -10.2603),
const LatLng(54.8566, -9.3522),
],
strokeWidth: 20,
color: Colors.black.withOpacity(0.2),
borderStrokeWidth: 20,
borderColor: Colors.white30,
): (
title: 'BlackWhite Line',
subtitle: 'Solid translucent color fill, with different color outline',
),
Polyline(
points: [
const LatLng(49.1, -0.06),
const LatLng(52.15, -1.4),
const LatLng(55.5, 0.8),
],
strokeWidth: 10,
color: Colors.yellow,
borderStrokeWidth: 10,
borderColor: Colors.blue.withOpacity(0.5),
): (
title: 'YellowBlue Line',
subtitle: 'Solid translucent color fill, with different color outline',
),
};

List<Polyline>? hoverLines;

@override
Widget build(BuildContext context) {
return Scaffold(
Expand All @@ -26,78 +116,111 @@ class _PolylinePageState extends State<PolylinePage> {
),
children: [
openStreetMapTileLayer,
PolylineLayer(
polylines: [
Polyline(
points: [
const LatLng(51.5, -0.09),
const LatLng(53.3498, -6.2603),
const LatLng(48.8566, 2.3522),
],
strokeWidth: 4,
color: Colors.purple,
),
Polyline(
points: [
const LatLng(55.5, -0.09),
const LatLng(54.3498, -6.2603),
const LatLng(52.8566, 2.3522),
],
strokeWidth: 4,
gradientColors: [
const Color(0xffE40203),
const Color(0xffFEED00),
const Color(0xff007E2D),
],
),
Polyline(
points: [
const LatLng(50.5, -0.09),
const LatLng(51.3498, 6.2603),
const LatLng(53.8566, 2.3522),
],
strokeWidth: 20,
color: Colors.blue.withOpacity(0.6),
borderStrokeWidth: 20,
borderColor: Colors.red.withOpacity(0.4),
MouseRegion(
hitTestBehavior: HitTestBehavior.deferToChild,
cursor: SystemMouseCursors.click,
onHover: (_) {
if (hitNotifier.value == null) return;

final lines = hitNotifier.value!.lines
.where((e) => polylines.containsKey(e))
.map(
(e) => Polyline(
points: e.points,
strokeWidth: e.strokeWidth + e.borderStrokeWidth,
color: Colors.transparent,
borderStrokeWidth: 15,
borderColor: Colors.green,
useStrokeWidthInMeter: e.useStrokeWidthInMeter,
),
)
.toList();
setState(() => hoverLines = lines);
},

/// Clear hovered lines when touched lines modal appears
onExit: (_) => setState(() => hoverLines = null),
child: GestureDetector(
onTap: () => _openTouchedLinesModal(
'Tapped',
hitNotifier.value!.lines,
hitNotifier.value!.point,
),
Polyline(
points: [
const LatLng(50.2, -0.08),
const LatLng(51.2498, -10.2603),
const LatLng(54.8566, -9.3522),
],
strokeWidth: 20,
color: Colors.black.withOpacity(0.2),
borderStrokeWidth: 20,
borderColor: Colors.white30,
onLongPress: () => _openTouchedLinesModal(
'Long pressed',
hitNotifier.value!.lines,
hitNotifier.value!.point,
),
Polyline(
points: [
const LatLng(49.1, -0.06),
const LatLng(52.15, -1.4),
const LatLng(55.5, 0.8),
],
strokeWidth: 10,
color: Colors.yellow,
borderStrokeWidth: 10,
borderColor: Colors.blue.withOpacity(0.5),
onSecondaryTap: () => _openTouchedLinesModal(
'Secondary tapped',
hitNotifier.value!.lines,
hitNotifier.value!.point,
),
Polyline(
points: [
const LatLng(48.1, -0.03),
const LatLng(50.5, -7.8),
const LatLng(56.5, 0.4),
],
strokeWidth: 10,
color: Colors.amber,
borderStrokeWidth: 10,
borderColor: Colors.blue.withOpacity(0.5),
child: PolylineLayer(
hitNotifier: hitNotifier,
polylines: polylines.keys.followedBy(hoverLines ?? []).toList(),
),
],
),
),
],
),
);
}

void _openTouchedLinesModal(
String eventType,
List<Polyline> tappedLines,
LatLng coords,
) {
tappedLines.removeWhere((e) => !polylines.containsKey(e));

showModalBottomSheet<void>(
context: context,
builder: (context) => Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Tapped Polyline(s)',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
Text(
'$eventType at point: (${coords.latitude.toStringAsFixed(6)}, ${coords.longitude.toStringAsFixed(6)})',
),
const SizedBox(height: 8),
Expanded(
child: ListView.builder(
itemBuilder: (context, index) {
final tappedLineData = polylines[tappedLines[index]]!;
return ListTile(
leading: index == 0
? const Icon(Icons.vertical_align_top)
: index == tappedLines.length - 1
? const Icon(Icons.vertical_align_bottom)
: const SizedBox.shrink(),
title: Text(tappedLineData.title),
subtitle: Text(tappedLineData.subtitle),
dense: true,
);
},
itemCount: tappedLines.length,
),
),
const SizedBox(height: 8),
Align(
alignment: Alignment.bottomCenter,
child: SizedBox(
width: double.infinity,
child: OutlinedButton(
onPressed: () => Navigator.pop(context),
child: const Text('Close'),
),
),
),
],
),
),
);
}
}
Loading

0 comments on commit b94de88

Please sign in to comment.