I have something like this:
CustomPaint(
painter: CurvePainter(),
)
In this class I am doing my painting:
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import './myState.dart';
import './models/mode.dart';
final String rawSvg = '''<svg viewBox="...">...</svg>''';
class CurvePainter extends CustomPainter {
MyState _myState;
DrawableRoot svgRoot;
CurvePainter(MyState myState) {
this._myState = myState;
this.loadAsset();
}
void loadAsset() async {
this.svgRoot = await svg.fromSvgString(rawSvg, rawSvg);// The canvas that is your board.
}
@override
void paint (Canvas canvas, Size size) {
canvas.translate(_myState.translateX, _myState.translateY);
if(this.svgRoot != null){
svgRoot.scaleCanvasToViewBox(canvas, size);
svgRoot.clipCanvasToViewBox(canvas);
// svgRoot.draw(canvas, size);
}
}
Somebody know how to draw a SVG inside paint method? I found this library https://pub.dev/packages/flutter_svg#-readme-tab- . With my code I get error: Unhandled Exception: Bad state: viewBox element must be 4 elements long
I would be nice, if I can scale and rotate the svg inside canvas. But this is optional.
From the README:
import 'package:flutter_svg/flutter_svg.dart';
final String rawSvg = '''<svg viewBox="...">...</svg>''';
final DrawableRoot svgRoot = await svg.fromSvgString(rawSvg, rawSvg);
// If you only want the final Picture output, just use
final Picture picture = svgRoot.toPicture();
// Otherwise, if you want to draw it to a canvas:
// Optional, but probably normally desirable: scale the canvas dimensions to
// the SVG's viewbox
svgRoot.scaleCanvasToViewBox(canvas);
// Optional, but probably normally desireable: ensure the SVG isn't rendered
// outside of the viewbox bounds
svgRoot.clipCanvasToViewBox(canvas);
svgRoot.draw(canvas, size);
Which you could adapt as:
class CurvePainter extends CustomPainter {
CurvePainter(this.svg);
final DrawableRoot svg;
@override
void paint(Canvas canvas, Size size) {
canvas.drawLine(...);
svg.scaleCanvasToViewBox(canvas);
svg.clipCanvasToViewBox(canvas);
svg.draw(canvas, size);
}
}
I'd advise finding some way to get the asynchronous part earlier on in your app, perhaps using a FutureBuilder or a ValueListenableBuilder.
Disclosure: I'm the author/primary maintainer of Flutter SVG.
Ultimately I found drawing SVGs directly in Canvas to be cumbersome. Instead, I copied the SVG paths and transforms to Dart code using path_drawing
and rendered them as Path
s with Canvas.drawPath
. This has the advantage of not even being an asset at all; the SVG data is literally code at this point. And you can convert back to an SVG easily. The process goes a bit like this:
path_drawing: 0.4.1
to pubspec.yaml
, flutter pub get
, in the file you're rendering from import 'package:path_drawing/path_drawing.dart';
.parseSvgPathData
as Path constants. (Path strings look something like M 86.102000,447.45700 L 86.102000,442.75300 .....
)
static final Path complexPathToDraw = parseSvgPathData("path_1").addPath(parseSvgPathData("path_2"));
. <g transform='translate()>
). And drawPath
can only render the Path from the top-left position. So you have to translate to the appropriate position. When rendering, translate the canvas before drawing (1) first to correct for the translations in the SVG, (2) next to scale to the size you want, (3) to go to the position you really want it on the Canvas. Then draw, and restore the Canvas to its untransformed state. But keep in mind, these matrices are added in reverse order to how we logically break it down because linear algebra is stupid.
canvas.save();
canvas.translate(dxToRenderPosition, dyToRenderPosition);
canvas.scale(sxFromSvgSizeToDesiredRenderSize);
canvas.translate(dxFromSvg, dyFromSvg);
canvas.drawPath(complexPathToDraw, Paint());
canvas.restore();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With