4
votes

Utilisation des marqueurs SVG dans le plugin google_maps_flutter Flutter

Est-il possible d'utiliser des chemins SVG pour créer un marqueur avec le plugin google_maps_flutter ? Je sais que vous pouvez utiliser des fichiers .png en utilisant:

icon: BitmapDescriptor.fromAsset("images/myFile.png")

Et les chemins SVG?

Merci


0 commentaires

3 Réponses :


1
votes

vient de consulter la documentation de la classe BitmapDescriptor Vous pouvez essayer la méthode de classe fromAssetImage ()

https://pub.dev/documentation/google_maps_flutter/latest /google_maps_flutter/BitmapDescriptor/fromAssetImage.html


1 commentaires

fromAssetImage () n'accepte pas les fichiers SVG, uniquement les images bitmap.



8
votes

Cela peut être réalisé en utilisant le package flutter_svg .

BitmapDescriptor bitmapDescriptor = await _bitmapDescriptorFromSvgAsset(context, 'assets/images/someimage.svg');
Marker marker = Marker(markerId: MarkerId('someId'), icon: bitmapDescriptor, position: LatLng(someLatitude, someLongitude));

Vous pouvez ensuite utiliser le BitmapDescriptor pour créer un marqueur comme d'habitude:

import 'dart:ui' as ui; // imported as ui to prevent conflict between ui.Image and the Image widget
import 'package:flutter/services.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';

Future<BitmapDescriptor> _bitmapDescriptorFromSvgAsset(BuildContext context, String assetName) async {
    // Read SVG file as String
    String svgString = await DefaultAssetBundle.of(context).loadString(assetName);
    // Create DrawableRoot from SVG String
    DrawableRoot svgDrawableRoot = await svg.fromSvgString(svgString, null);

    // toPicture() and toImage() don't seem to be pixel ratio aware, so we calculate the actual sizes here
    MediaQueryData queryData = MediaQuery.of(context);
    double devicePixelRatio = queryData.devicePixelRatio;
    double width = 32 * devicePixelRatio; // where 32 is your SVG's original width
    double height = 32 * devicePixelRatio; // same thing

    // Convert to ui.Picture
    ui.Picture picture = svgDrawableRoot.toPicture(size: Size(width, height));

    // Convert to ui.Image. toImage() takes width and height as parameters
    // you need to find the best size to suit your needs and take into account the
    // screen DPI
    ui.Image image = await picture.toImage(width, height);
    ByteData bytes = await image.toByteData(format: ui.ImageByteFormat.png);
    return BitmapDescriptor.fromBytes(bytes.buffer.asUint8List());
}


1 commentaires

Solution géniale! Une chose à prendre en compte est que les marqueurs chargés à partir d'octets sont plus lents à travailler (12x plus lentement) même une fois chargés en raison d'une optimisation manquante dans le plugin google_maps_flutter. J'ai créé un problème pour ce problème, github.com/flutter/flutter/issues/41731 n'hésitez pas à le voter;)



1
votes

Voici quelques options:

  • getBitmapDescriptorFromSvgAsset - svg des actifs
  • getBitmapDescriptorFromSvgString - svg sous forme de chaîne de db / remote / peu importe
      final icon = await BitmapDescriptorHelper.getBitmapDescriptorFromSvgAsset(
                                      context, "assets/icons/some_svg_icon.svg");

      final Marker marker = Marker(
        icon: icon,
        ...
      );

de votre classe de widget:

class BitmapDescriptorHelper{
  static Future<BitmapDescriptor> getBitmapDescriptorFromSvgAsset(
      BuildContext context, String svgAssetLink) async {
    final svgImage = await _getSvgImageFromAssets(context, svgAssetLink);
    final sizedSvgImage = await _getSizedSvgImage(svgImage);

    final pngSizedBytes = await sizedSvgImage.toByteData(format: ui.ImageByteFormat.png);
    final unit8List = pngSizedBytes.buffer.asUint8List();
    return BitmapDescriptor.fromBytes(unit8List);
  }

  static Future<BitmapDescriptor> getBitmapDescriptorFromSvgString(String svgString) async {
    final svgImage = await _getSvgImageFromString(svgString);
    final sizedSvgImage = await _getSizedSvgImage(svgImage);

    final pngSizedBytes = await sizedSvgImage.toByteData(format: ui.ImageByteFormat.png);
    final unit8List = pngSizedBytes.buffer.asUint8List();
    return BitmapDescriptor.fromBytes(unit8List);
  }

  static Future<ui.Image> _getSvgImageFromAssets(BuildContext context, String svgAssertLink) async {
    String svgString = await DefaultAssetBundle.of(context).loadString(svgAssertLink);
    DrawableRoot drawableRoot = svg.fromSvgString(svgString, null);
    ui.Picture picture = drawableRoot.toPicture();
    ui.Image image = await picture.toImage(
        drawableRoot.viewport.width.toInt(), drawableRoot.viewport.height.toInt());
    return image;
  }

  static Future<ui.Image> _getSvgImageFromString(String svgString) async {
    DrawableRoot drawableRoot = svg.fromSvgString(svgString, null);
    ui.Picture picture = drawableRoot.toPicture();
    ui.Image image = await picture.toImage(
        drawableRoot.viewport.width.toInt(), drawableRoot.viewport.height.toInt());
    return image;
  }

  static Future<ui.Image> _getSizedSvgImage(ui.Image svgImage) async {
    final size = 50 * ui.window.devicePixelRatio;
    final width = size;
    final height = width;

    final ui.PictureRecorder pictureRecorder = ui.PictureRecorder();
    final Canvas canvas = Canvas(pictureRecorder);
    final Rect svgRect =
        Rect.fromLTRB(0.0, 0.0, svgImage.width.toDouble(), svgImage.height.toDouble());
    final Rect sizedRect = Rect.fromLTRB(0.0, 0.0, width, height); // owr size here
    canvas.drawImageRect(svgImage, svgRect, sizedRect, Paint());
    return await pictureRecorder.endRecording().toImage(width.toInt(), height.toInt());
  }
}

appréciez :)


0 commentaires