Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use SVG markers in google_maps_flutter Flutter plugin?

I wish to place markers using .svg images as icons. I am using google_maps_flutter library. This worked with .png converted images but I didn't find a way to use .svg files directly.

I am posting here after reading this issue : Using SVG markers in google_maps_flutter Flutter plugin

And trying to use the method fromAssetImage as described in this thread : How to change the icon size of Google Map marker in Flutter?

I hoped that this new version of the library would help solve my issue.

I tried solving it with the following code :

MapWidget class

for (Place place in widget.places) {
          place.toMarker(
            context,
            () => _onPlaceTapped(place),
          ).then(setState((){
            markerSet.add
          }));
      }

Place class

Future<Marker> toMarker(BuildContext context, VoidCallback onTap) async {
    return Marker(
      markerId: MarkerId(id.toString()),
      position: LatLng(lat, lon),
      icon: await category.markerIcon(createLocalImageConfiguration(context)),
      onTap: onTap,
    );

Category class

Future<BitmapDescriptor> markerIcon(ImageConfiguration configuration) async {
    BitmapDescriptor b;
    switch (type) {
      case CategoryType.FirstCategory:
        b = await BitmapDescriptor.fromAssetImage(configuration, 'assets/markers/marker-first.svg');
        break;
      case CategoryType.SecondCategory:
        b = await BitmapDescriptor.fromAssetImage(configuration, 'assets/markers/marker-second.svg');
        break;
      default:
        b = await BitmapDescriptor.fromAssetImage(configuration, 'assets/markers/marker-third.svg');
        break;
    }

    return b;
  }

The images' path is already added to pubspec.yaml if you are wondering.

I expected the default red google markers to be replaced by some custom markers (there should be a small icon image on each custom marker) on the map, however only default markers are shown (not the default in the switch statement, I am speaking of google's default markers).

There is no error message using iOS simulator and google_maps_flutter 0.5.15+1 library version.

like image 929
wenolOaR Avatar asked Jun 05 '19 09:06

wenolOaR


2 Answers

You can find the answer to this question here :

Using SVG markers in google_maps_flutter Flutter plugin

I tried rednuht's answer and it worked like a charm.

EDIT (recap)

The answer requires the use of flutter_svg plugin (^0.13 or 0.14.1 seemed to work for myself).

First, create a function that will give you a BitmapDescriptor from the asset. Make sure the asset is declared in your pubspec file.

import 'dart:ui' as ui;
import 'package:flutter/services.dart';
import 'package:flutter_svg/flutter_svg.dart';


Future<BitmapDescriptor> _bitmapDescriptorFromSvgAsset(BuildContext context, String assetName) async {
    String svgString = await DefaultAssetBundle.of(context).loadString(assetName);
    //Draws string representation of svg to DrawableRoot
    DrawableRoot svgDrawableRoot = await svg.fromSvgString(svgString, null);
    ui.Picture picture = svgDrawableRoot.toPicture();
    ui.Image image = await picture.toImage(26, 37);
    ByteData bytes = await image.toByteData(format: ui.ImageByteFormat.png);
    return BitmapDescriptor.fromBytes(bytes.buffer.asUint8List());
}

I instantiated a Map object at the start of my app so that I could use the BitmapDescriptors without using a lot of async/await calls.

data_model.dart

Map<CategoryType, BitmapDescriptor> descriptors = Map<Category, BitmapDescriptor>();

Future<void> loadBitmapDescriptors(context) async {
    descriptors[CategoryType.FirstCatgory] = await _bitmapDescriptorFromSvgAsset(context, 'assets/markers/marker-first.svg');
    descriptors[CategoryType.SecondCategory] = await _bitmapDescriptorFromSvgAsset(context, 'assets/markers/marker-second.svg');
    descriptors[CategoryType.ThirdCategory] = await _bitmapDescriptorFromSvgAsset(context, 'assets/markers/marker-third.svg');
  }

main.dart

DataModel.of(context).loadBitmapDescriptors(context);

So all I had to do after that was to call it correctly when needed.

Marker marker = Marker(markerId: MarkerId(id.toString()), icon: descriptors[category], position: LatLng(lat, lon));
like image 185
wenolOaR Avatar answered Oct 17 '22 14:10

wenolOaR


I had the same problem and ended with this implementation due to without de devicePixelRatio It was showing pixelated markers.

Future<BitmapDescriptor> getBitmapDescriptorFromSVGAsset(
    BuildContext context,
    String svgAssetLink, {
    Size size = const Size(30, 30),
  }) async {
    String svgString = await DefaultAssetBundle.of(context).loadString(
      svgAssetLink,
    );
    final drawableRoot = await svg.fromSvgString(
      svgString,
      'debug: $svgAssetLink',
    );
    final ratio = ui.window.devicePixelRatio.ceil();
    final width = size.width.ceil() * ratio;
    final height = size.height.ceil() * ratio;
    final picture = drawableRoot.toPicture(
      size: Size(
        width.toDouble(),
        height.toDouble(),
      ),
    );
    final image = await picture.toImage(width, height);
    final byteData = await image.toByteData(format: ui.ImageByteFormat.png);
    final uInt8List = byteData.buffer.asUint8List();
    return BitmapDescriptor.fromBytes(uInt8List);
  }
like image 20
Santiago M Avatar answered Oct 17 '22 15:10

Santiago M