flutter_map icon indicating copy to clipboard operation
flutter_map copied to clipboard

[BUG] Changing CRS Does Not Rebuild Other Children

Open yang6626 opened this issue 1 year ago • 12 comments

What is the bug?

hi there

flutter_map: 2.0.0

in my case, i have 2 diffenert crs epsg4490 and epsg3857 , let's say we set it as 4490 in the first time and has a polyline on map. when i press a button to switch crs to 3857, the polyline disappear untill i move the map.

What is the expected behaviour?

the polyline still there when change crs.

How can we reproduce this issue?

FlutterMap(
              mapController: _mapController,
              options: MapOptions(
                  crs: _currentMapIndex == 0 ? epsg4490 : const Epsg3857(),
                  center: LatLng(23.388149672864074, 116.7156679026907),
                  interactiveFlags:
                      InteractiveFlag.all & ~InteractiveFlag.rotate,
                  zoom: 14,
                  minZoom: 0,
                  maxZoom: 22),
              children: [
                ..._buildBaseMap(),
                PolylineLayerWidget(
                    options: PolylineLayerOptions(polylines: [
                  Polyline(strokeWidth: 4, color: Colors.red, points: [
                    LatLng(23.3884495, 116.7191143),
                    LatLng(23.3806962, 116.7124767),
                    LatLng(23.3799523, 116.7246074),
                    LatLng(23.3716553, 116.7208881),
                  ])
                ])),
                Positioned(
                  bottom: 20,
                  left: 20,
                  child: TextButton(
                    onPressed: () {
                      _currentMapIndex = _currentMapIndex == 0 ? 1 : 0;
                      setState(() {});
                    },
                    child: const Text("切换"),
                  ),
                )
              ],
            )

Do you have a potential solution?

No response

Can you provide any other information?

No response

Platforms Affected

Android, iOS

Severity

Erroneous: Prevents normal functioning and causes errors in the console

Frequency

Consistently: Always occurs at the same time and location

Requirements

  • [X] I agree to follow this project's Code of Conduct
  • [X] My Flutter/Dart installation is unaltered, and flutter doctor finds no relevant issues
  • [X] I am using the latest stable version of this package
  • [X] I have checked the FAQs section on the documentation website
  • [X] I have checked for similar issues which may be duplicates

yang6626 avatar Jul 29 '22 07:07 yang6626

Hi there, and thanks for your report.

This might be because the PolylineLayerWidget will not rebuild unless it is needs to, like all other Flutter widgets. To do this, you'll need to change the state of a property inside the widget.

May I suggest using a variable for the strokeWidth, and when you change the CRS, set the state of that variable to 3, then back to 4.

Let me know what happens!

JaffaKetchup avatar Jul 29 '22 14:07 JaffaKetchup

@JaffaKetchup sorry for being late;
i change the storkwidth when i press the switch button, polyline still not been rebuilded untill i move the map

yang6626 avatar Aug 01 '22 02:08 yang6626

You could probably just call mapController move with a 0.00001 different value instead of setState or something I would imagine (I feel like we should be able to force a mapController move, whatever, but it does for the moment have a check if it's not moved, not to do anything).

ibrierley avatar Aug 01 '22 08:08 ibrierley

@ibrierley's suggestion will probably work, but I'm not sure that's fixing the underlying issue? If that's good enough for you, then that's great, if not, can you post your code from my suggestion.

JaffaKetchup avatar Aug 01 '22 08:08 JaffaKetchup

@ibrierley yes, i has tried this way at the first time but no luck;

yang6626 avatar Aug 01 '22 08:08 yang6626

Hmm that is strange. Can you post your code from your attempt at my suggestion please?

JaffaKetchup avatar Aug 01 '22 08:08 JaffaKetchup

@JaffaKetchup here is my code

FlutterMap(
              mapController: _mapController,
              options: MapOptions(
                  crs: _currentMapIndex == 0 ? epsg4490 : const Epsg3857(),
                  center: LatLng(23.388149672864074, 116.7156679026907),
                  interactiveFlags:
                      InteractiveFlag.all & ~InteractiveFlag.rotate,
                  zoom: 14,
                  minZoom: 0,
                  maxZoom: 22),
              children: [
                ..._buildBaseMap(),
                PolylineLayerWidget(
                    options: PolylineLayerOptions(polylines: [
                  Polyline(
                      strokeWidth: _strokeWidth,
                      color: Colors.red,
                      points: [
                        LatLng(23.3884495, 116.7191143),
                        LatLng(23.3806962, 116.7124767),
                        LatLng(23.3799523, 116.7246074),
                        LatLng(23.3716553, 116.7208881),
                      ])
                ])),
                Positioned(
                  bottom: 20,
                  left: 20,
                  child: TextButton(
                    onPressed: () {
                      _currentMapIndex = _currentMapIndex == 0 ? 1 : 0;
                      _strokeWidth = _currentMapIndex == 0 ? 6.0 : 3.0;
                      // _mapController.move(
                      //     LatLng(_mapController.center.latitude + 0.001,
                      //         _mapController.center.longitude + 0.001),
                      //     _mapController.zoom);
                      setState(() {});
                    },
                    child: const Text("切换"),
                  ),
                )
              ],
            )

flutter_map

yang6626 avatar Aug 01 '22 08:08 yang6626

Ok I see. Using the IDE tools, can you get your map to a situation where the polylines aren't showing, then manually use the hot reload button. What happens? Can you try this with none of our suggestions, my suggestion, and @ibrierley's suggestion.

JaffaKetchup avatar Aug 01 '22 08:08 JaffaKetchup

@JaffaKetchup the same when press hot reload button image

yang6626 avatar Aug 01 '22 08:08 yang6626

Can you paste a minimal example others can run (i.e _baseBuildMap etc is all missing)

ibrierley avatar Aug 01 '22 08:08 ibrierley

@ibrierley https://github.com/yang6626/flutter_map_crs.git

yang6626 avatar Aug 01 '22 09:08 yang6626

#1333

using setState should now build all children correctly and may fix this issue as long as you setState the entire map when switching which looks like what you are doing

mootw avatar Aug 03 '22 07:08 mootw

Hi @MooNag, i had tried 3.0.0-beta.1 and the polyline still not shown when i changing the crs untill i move the map.

yang6626 avatar Aug 15 '22 03:08 yang6626

Out of interest, what happens if you call setState on the widget flutter_map is in ?

ibrierley avatar Aug 15 '22 17:08 ibrierley

Out of interest, what happens if you call setState on the widget flutter_map is in ?

hi @ibrierley here is the example https://github.com/yang6626/flutter_map_crs.git, could you help to look at it. thanks a lot.

yang6626 avatar Aug 16 '22 03:08 yang6626

Interesting, and good spot.

I'm a bit baffled on this one. I can see the polyline rebuild paint get called each time (and interestingly paint gets called several tiles, even without any tilelayers, but that may well be normal). But yes, indeed it doesn't display, even with a setState, but a move does make it appear, so can confirm the issue.

Looking at the flutter inspector all looks ok, and interestingly if you remove the tileLayers it doesn't display either. Can't figure if I'm missing something obvious, but it's something we should certainly understand before 3.0

ibrierley avatar Aug 16 '22 13:08 ibrierley

Looks a bit like map.getOffsetFromOrigin(point) gets strange y values before the move...so maybe its something like an old pixelOrigin being used in these circumstances...

I note if I do _pixelOrigin = getNewPixelOrigin(_center); inside getOffsetFromOrigin it fixes the issue...however, thats likely just papering over the issue of at what times that should get reset ?

ibrierley avatar Aug 16 '22 14:08 ibrierley

Thinking out loud about this a bit more, I'm wondering if we should have a kind of "reset()" method... eg

Eg a soft reset _pixelBounds = getPixelBounds(zoom); _bounds = _calculateBounds();

Full reset (basically call those things that are in initState()) ?

ibrierley avatar Aug 16 '22 16:08 ibrierley

I have a fix for this issue. I wasn't updating pixel origin in setState of the map. It did get updated with the layout builder through updateSizeAndRotation, which (only gets called when the layout changes? I tested and it does fix the layer when I rotate the device).

I added the update to pixel origin to build of the map and the issue is now fixed. I think a recalculate method might make sense.

mootw avatar Aug 16 '22 16:08 mootw

Maybe a reset stream, like is available on the TileLayer would be good, for the sake of consistency?

JaffaKetchup avatar Aug 16 '22 16:08 JaffaKetchup

Um not so much a reset stream, just inside of flutter map have a function with all of the values that need to update when the state of the map changes (setState, move, rotate, etc) and call that function whenever the values need to be updated. This way if new values are added or changed it only needs to happen in one spot.

mootw avatar Aug 16 '22 16:08 mootw

Ah, sorry, I misunderstood the context. Yeah, this makes sense - reducing spaghetti and duplication is always a good idea!

JaffaKetchup avatar Aug 16 '22 16:08 JaffaKetchup

@ibrierley @MooNag @JaffaKetchup guys, i have try it from @MooNag 's version and it works great. thanks all of you.

yang6626 avatar Aug 17 '22 02:08 yang6626