Skip to content

feat: Markers with Annotations #248

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

pamtbaau
Copy link
Contributor

As discussed, I've created this PR to discuss the possible implementation of Annotations to Markers.

Summary:

  • In widget-layer.dart:
    • Added class Annotation
      Annotation can have any widget as child, including Gestures.
    • Added List<Annotation> annotations to class Marker
    • Extended build() to create and position Annotations relative to Marker
  • In example widget_layer_interactive_page.dart:
    • Extended Markers with list of Annotations.
    • Set Offset of Annotation to finetune its position relative to Marker
    • Added function Size _calculateTextSize(Text textWidget) to calculate width and height of Text widget needed to horizontally/vertically align with centers of Marker.

Issue:

  • Vertical alignment of Text does not work perfectly for centerLeft and centerRight.

Any feedback/suggestion is welcome.

Copy link

codecov bot commented Mar 21, 2025

Codecov Report

Attention: Patch coverage is 51.85185% with 26 lines in your changes missing coverage. Please review.

Project coverage is 61.98%. Comparing base (1df507b) to head (6727a3c).

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@josxha
Copy link
Owner

josxha commented Apr 9, 2025

Sorry for your long wait for a response @pamtbaau. I finally had time to look at your pull requests in detail. I still think that adding marker annotation is a great idea - so let's try solving the alignment issues.

I recommend to enable the "Show Guidelines" option in the flutter dev tools while working with Markers to see the outlines.
Here I created a simple Marker where the content fits the Marker.size:

Marker(
  point: Position(0, 0),
  size: const Size.square(150),
  child: Container(color: Colors.red, width: 150, height: 150),
),

When we change Marker.child to a Text widget, the text shows up in the top left corner. The light blue line indicates the boundaries of the Positioned widget used by the Marker.

We are now able to align the text for example to the center right side using a Align widget.

Marker(
  point: Position(0, 0),
  size: const Size.square(150),
  child: const Align(
    alignment: Alignment.centerRight,
    child: Text(
      'Marker',
      style: TextStyle(color: Colors.red, fontSize: 20),
    ),
  ),
),

We could use the same for annotations where the Annotation defines the maximum area the child widget has to display its content. However for this to work, we need to define the height and width properties of the used Positioned widget.
Currently, the annotation widgets expands towards one side, even when a centered alignment is selected. The Text widgets where a bit hard to see for me, so I replaced them with colored boxes.


Complete code sample of the screenshot (click to expand)

Alignment.center and Alignment.bottomCenter somehow had some problems when I tried to use them.

import 'package:flutter/material.dart';
import 'package:maplibre/maplibre.dart';

@immutable
class WidgetLayerPage extends StatefulWidget {
  const WidgetLayerPage({super.key});

  static const location = '/widget-layer';

  @override
  State<WidgetLayerPage> createState() => _WidgetLayerPageState();
}

class _WidgetLayerPageState extends State<WidgetLayerPage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Widget Layer')),
      body: MapLibreMap(
        options: MapOptions(initZoom: 3, initCenter: Position(0, 0)),
        children: [
          WidgetLayer(
            markers: [
              Marker(
                point: Position(0, 0),
                size: const Size.square(150),
                child: const _Marker(),
                annotations: const [
                  Annotation(
                    child: _Annotation(),
                    alignment: Alignment.topLeft,
                  ),
                  Annotation(
                    child: _Annotation(),
                    alignment: Alignment.topCenter,
                  ),
                  Annotation(
                    child: _Annotation(),
                    alignment: Alignment.topRight,
                  ),
                  Annotation(
                    child: _Annotation(),
                    alignment: Alignment.centerLeft,
                  ),
                  Annotation(
                    child: Text(
                      'centerLeft',
                      style: TextStyle(
                        color: Colors.purpleAccent,
                        fontSize: 30,
                      ),
                    ),
                    alignment: Alignment.centerLeft,
                  ),
                  // Annotation(
                  //   child: _Annotation(),
                  //   alignment: Alignment.center,
                  // ),
                  Annotation(
                    child: _Annotation(),
                    alignment: Alignment.centerRight,
                  ),
                  Annotation(
                    child: _Annotation(),
                    alignment: Alignment.bottomLeft,
                  ),
                  // Annotation(
                  //   child: _Annotation(),
                  //   alignment: Alignment.bottomCenter,
                  // ),
                  Annotation(
                    child: _Annotation(),
                    alignment: Alignment.bottomRight,
                  ),
                ],
              ),
            ],
          ),
          // display the UI widgets above the widget markers.
          const SourceAttribution(),
        ],
      ),
    );
  }
}

class _Annotation extends StatelessWidget {
  const _Annotation();

  @override
  Widget build(BuildContext context) {
    return Container(color: Colors.purple, width: 20, height: 20);
  }
}

class _Marker extends StatelessWidget {
  const _Marker();

  @override
  Widget build(BuildContext context) {
    return Container(color: Colors.red, width: 150, height: 150);
  }
}

To sum it all up, I'd do the following changes

  • use the width and height parameters of the Positioned widget
  • calculate the Positioned left / top / bottom / right parameter based on Annotation.alignment and the (maximum) width / height of the Annotation.
  • If the user needs to align the widget to the center or something else, he can wrap his content inside a Align widget.

Calculating the used height of the font is a nice idea, but I'm not sure if it would cause some problems, for example if the user increased the size of all texts on the device.

@josxha josxha marked this pull request as draft April 9, 2025 21:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Backlog
Development

Successfully merging this pull request may close these issues.

2 participants