fleaflet / flutter_map

A versatile mapping package for Flutter. Simple and easy to learn, yet completely customizable and configurable, it's the best choice for mapping in your Flutter app.
https://pub.dev/packages/flutter_map
BSD 3-Clause "New" or "Revised" License
2.75k stars 860 forks source link

[Help] Is it possible to implement this ? #778

Closed RomanJos closed 3 years ago

RomanJos commented 3 years ago

Hello I'm a writing an app to track my employees in the agriculture, for that I need them to enter the job and the greenhouses they are gonna working in. I did most of the app, however I need them to select the greenhouses by clicking on them like this : image

A overlay with rounded corners on each greenhousees (I only did 8 in the design and the edges look kinda off but you get the point)

image

when clicking on one

As far as I know I could implement this with polygons but I'll loose the rounded corners and I will need to pin the exact 4 LatLng of every greenhouses which is a bit tedious, so my question is do you think is it possible to achieve this ? and if yes is there any better solution instead of cutting each greenhouses individually ? They are espaced of like 1 or 2 meters each so espacing each boxes by how many distance a meters is in latitude could be a solution

rorystephenson commented 3 years ago

It's definitely possible.

Have a look at implementing a custom layer. You can most likely work off the polygon layer as a base and customise it to suit you. You just want to be able to express different shapes and draw them.

If you have a fairly limited number of greenhouses and you don't need to be able to change them often I'd just hard-code them.

RomanJos commented 3 years ago

Hello, thank you for your reply, by custom layer do you mean like creating overlay tiles dynamically ? that could be a solution but I have no idea how to do it, I also thought you were meaning to use a marker but markers have a size by pixels and not LatLng so this couldn't work. Do you have some example or just explain a little bit more on that ?

ibrierley commented 3 years ago

I'm assuming he means do a custom layer using a canvas and custom painter, like polyline/polygon use.

There you can use a path and commands like arcTo/clubTo etc. Have a read through https://medium.com/flutter-community/paths-in-flutter-a-visual-guide-6c906464dcd0

RomanJos commented 3 years ago

Thank you, that make sense, In the absolute, I don't know if I need to use a customPainter since I can achieve the same thing easily using Container, unless you mean creating every greenhouse in one CustomPainter to gain performance etc. In both case the challenge is to place it on the map, I experimented with OverlayImage and I discovered this :

final zoomScale =
        map.getZoomScale(map.zoom, map.zoom); // TODO replace with 1?
    final pixelOrigin = map.getPixelOrigin();
    final upperLeftPixel =
        map.project(overlayImage.bounds.northWest).multiplyBy(zoomScale) -
            pixelOrigin;
    final bottomRightPixel =
        map.project(overlayImage.bounds.southEast).multiplyBy(zoomScale) -
            pixelOrigin;
    return Positioned(
      left: upperLeftPixel.x.toDouble(),
      top: upperLeftPixel.y.toDouble(),
      width: (bottomRightPixel.x - upperLeftPixel.x).toDouble(),
      height: (bottomRightPixel.y - upperLeftPixel.y).toDouble(),

I didn't understood anything, I tried to navigate inside the library to know what map.project() do and I got even more confused lol I've never been good at math so its kinda hard

The layout of our exploitation look like this : image As you can see they are divided by area, my plan is to use a customPainter that draw x number of rounded rectangle separated by x distance so then I can use the same calculation of OverlayImage and fit the customPainter in the bounds. To animate the opacity when the user select one I could either rebuild every custom painters or wrap them all in an opacity widget and draw another CustomPainter on top of the area in which the greenhouse is selected with only the selected in color, the others completly transparent, this way I believe I could gain more performance and the opacity could get animated.

But there is two problem with this method, first it doesn't feel good and second, the areas have a bit of orientation : image And I didn't saw any implementation in OverlayImage so I'll need to take a bigger bounds and apply the rotation to the whole custom painter.

Do you guys have any better idea ?

rorystephenson commented 3 years ago

To be clearer I meant adding a custom layer via a plugin. I wrote a plugin for having popups for markers and the popup is a Widget. Here you can see where I add the widget to the map: https://github.com/rorystephenson/flutter_map_marker_popup/blob/697c38df46916e2c77d74db54f3b7a94fc76f909/lib/src/popup_marker_layer.dart#L67-L74.

Note that in my example I always add the popup to the map since there is only one. You can see that for the markers, they are only added if they are inside the visible bounds: https://github.com/rorystephenson/flutter_map_marker_popup/blob/697c38df46916e2c77d74db54f3b7a94fc76f909/lib/src/popup_marker_layer.dart#L35-L46 . This makes a big different in performance if you have a lot of things to show on the map.

RomanJos commented 3 years ago

Hello, just to keep you updated, I didin't achieved what I wanted with your library because it was just too difficult for me to read your code and try to figure out how plugins are implemented and should behave, especially in some part where I needed to understand the coordinate system with pi and stuff like this lol. I instead downloaded the google maps tiles and merged it into a big png to display it inside a stack with my greenhouses overlay using InteractiveViewer. To generate the greenhouses layout i did everything in adobe xD and exported it to svg to then, using a python script, convert it to a Map to then retrieve the information and draw them like @ibrierley suggested

It look like this : Possible to implement this - Solution

and here is the code :

InteractiveViewer(
    transformationController: controller,
    maxScale: 10,
    minScale: 0.01,
    constrained: false,
    child: RepaintBoundary(
      child: Stack(
        children: [
          Image(
            filterQuality: FilterQuality.medium,
            image: AssetImage('assets/images/L\'oustalet.jpg'),
          ),
          //Instead of Opacity because it lag on zoom
          Positioned.fill(
              child: GestureDetector(
                  onTapUp: (details) => widget.greenhouseID.value = Dico.locateGreenhouse(details),
                  child: Container(color: Coolors.backfloor.withAlpha(150)))),
          ValueListenableBuilder(
            valueListenable: widget.greenhouseID,
            builder: (context, value, child) => ValueListenableBuilder(
                valueListenable: Notifiers.color,
                builder: (context, value, child) => CustomPaint(
                      painter: GreenhousesLayout(
                          [if (widget.greenhouseID.value != "") widget.greenhouseID.value], value),
                    )),
          ),
        ],
      ),
    ))

Thank you for your effort nonetheless !