From 3e946d9a2f685470b28fa3bb2527d7b8d7a470ec Mon Sep 17 00:00:00 2001 From: Sebastian Date: Sun, 21 May 2023 22:16:12 +0200 Subject: [PATCH] Remove saveLayers from the public PolygonLayer API and call canvas.saveLayer only when needed based on the polygon properties. (#1519) Co-authored-by: JaffaKetchup --- example/lib/pages/polyline.dart | 39 ++++++++++++++- lib/src/layer/polyline_layer.dart | 81 +++++++++++++++---------------- 2 files changed, 75 insertions(+), 45 deletions(-) diff --git a/example/lib/pages/polyline.dart b/example/lib/pages/polyline.dart index 2f0e4d928..64116f6cd 100644 --- a/example/lib/pages/polyline.dart +++ b/example/lib/pages/polyline.dart @@ -16,15 +16,50 @@ class _PolylinePageState extends State { late Future> polylines; Future> getPolylines() async { - final polyLines = [ + final polyLines = [ Polyline( points: [ LatLng(50.5, -0.09), LatLng(51.3498, -6.2603), LatLng(53.8566, 2.3522), ], - strokeWidth: 50, + strokeWidth: 20, + color: Colors.blue.withOpacity(0.6), + borderStrokeWidth: 20, + borderColor: Colors.red.withOpacity(0.4), + ), + Polyline( + points: [ + LatLng(50.2, -0.08), + LatLng(51.2498, -7.2603), + LatLng(54.8566, 1.3522), + ], + strokeWidth: 20, + color: Colors.black.withOpacity(0.2), + borderStrokeWidth: 20, + borderColor: Colors.white30, + ), + Polyline( + points: [ + LatLng(49.1, -0.06), + LatLng(51.15, -7.4), + LatLng(55.5, 0.8), + ], + strokeWidth: 10, + color: Colors.yellow, + borderStrokeWidth: 10, + borderColor: Colors.blue.withOpacity(0.5), + ), + Polyline( + points: [ + LatLng(48.1, -0.03), + LatLng(50.5, -7.8), + LatLng(56.5, 0.4), + ], + strokeWidth: 10, color: Colors.amber, + borderStrokeWidth: 10, + borderColor: Colors.blue.withOpacity(0.5), ), ]; await Future.delayed(const Duration(seconds: 3)); diff --git a/lib/src/layer/polyline_layer.dart b/lib/src/layer/polyline_layer.dart index a50eb59b4..50b06b3b0 100644 --- a/lib/src/layer/polyline_layer.dart +++ b/lib/src/layer/polyline_layer.dart @@ -1,3 +1,4 @@ +import 'dart:core'; import 'dart:ui' as ui; import 'package:flutter/widgets.dart'; @@ -58,21 +59,12 @@ class PolylineLayer extends StatelessWidget { final bool polylineCulling; - /// {@macro newPolylinePainter.saveLayers} - /// - /// By default, this value is set to `false` to improve performance on - /// layers containing a lot of polylines. - /// - /// You might want to set this to `true` if you get unwanted darker lines - /// where they overlap but, keep in mind that this might reduce the - /// performance of the layer. - final bool saveLayers; - const PolylineLayer({ super.key, this.polylines = const [], this.polylineCulling = false, - this.saveLayers = false, + @Deprecated('No longer needed and will be removed.') + bool saveLayers = false, }); @override @@ -87,7 +79,7 @@ class PolylineLayer extends StatelessWidget { : polylines; return CustomPaint( - painter: PolylinePainter(lines, saveLayers, map), + painter: PolylinePainter(lines, map), size: size, isComplex: true, ); @@ -97,17 +89,10 @@ class PolylineLayer extends StatelessWidget { class PolylinePainter extends CustomPainter { final List polylines; - /// {@template newPolylinePainter.saveLayers} - /// If `true`, the canvas will be updated on every frame by calling the - /// methods [Canvas.saveLayer] and [Canvas.restore]. - /// {@endtemplate} - final bool saveLayers; - final FlutterMapState map; final LatLngBounds bounds; - PolylinePainter(this.polylines, this.saveLayers, this.map) - : bounds = map.bounds; + PolylinePainter(this.polylines, this.map) : bounds = map.bounds; int get hash { _hash ??= Object.hashAll(polylines); @@ -134,26 +119,35 @@ class PolylinePainter extends CustomPainter { var borderPath = ui.Path(); var filterPath = ui.Path(); var paint = Paint(); + bool needsLayerSaving = false; + Paint? borderPaint; Paint? filterPaint; int? lastHash; void drawPaths() { - canvas.drawPath(path, paint); - path = ui.Path(); - paint = Paint(); + final hasBorder = borderPaint != null && filterPaint != null; + if (hasBorder) { + if (needsLayerSaving) { + canvas.saveLayer(rect, Paint()); + } - if (borderPaint != null) { canvas.drawPath(borderPath, borderPaint!); borderPath = ui.Path(); borderPaint = null; - } - if (filterPaint != null) { - canvas.drawPath(filterPath, filterPaint!); - filterPath = ui.Path(); - filterPaint = null; + if (needsLayerSaving) { + canvas.drawPath(filterPath, filterPaint!); + filterPath = ui.Path(); + filterPaint = null; + + canvas.restore(); + } } + + canvas.drawPath(path, paint); + path = ui.Path(); + paint = Paint(); } for (final polyline in polylines) { @@ -163,10 +157,12 @@ class PolylinePainter extends CustomPainter { } final hash = polyline.renderHashCode; - if (lastHash != null && lastHash != hash) { + if (needsLayerSaving || (lastHash != null && lastHash != hash)) { drawPaths(); } lastHash = hash; + needsLayerSaving = polyline.color.opacity < 1.0 || + (polyline.gradientColors?.any((c) => c.opacity < 1.0) ?? false); late final double strokeWidth; if (polyline.useStrokeWidthInMeter) { @@ -200,17 +196,10 @@ class PolylinePainter extends CustomPainter { : paint.color = polyline.color; } - if (polyline.borderColor != null) { - filterPaint = Paint() - ..color = polyline.borderColor!.withAlpha(255) - ..strokeWidth = strokeWidth - ..strokeCap = polyline.strokeCap - ..strokeJoin = polyline.strokeJoin - ..style = isDotted ? PaintingStyle.fill : PaintingStyle.stroke - ..blendMode = BlendMode.dstOut; - } - - if (polyline.borderStrokeWidth > 0.0) { + if (polyline.borderColor != null && polyline.borderStrokeWidth > 0.0) { + // Outlined lines are drawn by drawing a thicker path underneath, then + // stenciling the middle (in case the line fill is transparent), and + // finally drawing the line fill. borderPaint = Paint() ..color = polyline.borderColor ?? const Color(0x00000000) ..strokeWidth = strokeWidth + polyline.borderStrokeWidth @@ -218,12 +207,19 @@ class PolylinePainter extends CustomPainter { ..strokeJoin = polyline.strokeJoin ..style = isDotted ? PaintingStyle.fill : PaintingStyle.stroke ..blendMode = BlendMode.srcOver; + + filterPaint = Paint() + ..color = polyline.borderColor!.withAlpha(255) + ..strokeWidth = strokeWidth + ..strokeCap = polyline.strokeCap + ..strokeJoin = polyline.strokeJoin + ..style = isDotted ? PaintingStyle.fill : PaintingStyle.stroke + ..blendMode = BlendMode.dstOut; } final radius = paint.strokeWidth / 2; final borderRadius = (borderPaint?.strokeWidth ?? 0) / 2; - if (saveLayers) canvas.saveLayer(rect, Paint()); if (isDotted) { final spacing = strokeWidth * 1.5; if (borderPaint != null && filterPaint != null) { @@ -238,7 +234,6 @@ class PolylinePainter extends CustomPainter { } _paintLine(path, offsets); } - if (saveLayers) canvas.restore(); } drawPaths();