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
3 Réponses :
vient de consulter la documentation de la classe BitmapDescriptor Vous pouvez essayer la méthode de classe fromAssetImage ()
fromAssetImage () n'accepte pas les fichiers SVG, uniquement les images bitmap.
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()); }
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;)
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 :)