preface

For some interesting drawing skills and knowledge, I will add them to the book “Flutter Drawing Guide – Wonderful Ideas” through “chapters”, on the one hand, to keep the book “up-to-date” and “dynamic”. On the other hand, it is to put some important knowledge to a good home. The source of this article can be seen here. Another piece of good news: IdRAW, the source code for the Flutter Drawing Guide, has been converted to empty safety.


First, understanding of SVG

1. The first

F12 shows that the Nuggets logo is an SVG, which can be downloaded as a file.


When opened, you can see that there are many unknown characters in the logo. One thing is certain: these characters determine the display of the logo. Why and how these characters control the display is not understandable to the first observer.


2. The test

In Android Studio, you can see how an SVG file looks in real time. Here’s a comment on path to show that it’s missing.


Comment out another path, and you can see that another path is missing. So you can see that each path block represents a partial path.


The linear path operator

1. Horizontal and verticalabsolutePath:HV

M0,0 H50 V50 H0

<svg width="50" height="50" viewBox="0 0 50 to 50." " fill="none" xmlns="http://www.w3.org/2000/svg">
    <path d="M0, 0 H50 V50 H0." " fill="#FFFFFF"/>
</svg>
Copy the code

M0,0: moves from the starting point to 0,0. H50 means: move horizontally to 50. V50: move vertically to 50. H0 means: move horizontally to 0. Finally, the path will connect to the starting point,0, and fill=”#FFFFFF” means fill white.


2. Absolute movement:M

The orange area below is the effect of M20,0 H50 V50 H0, where M20,0 indicates that the starting point of the path moves to the (20,0) coordinate.


4. A straight lineabsolutePath:L

The blue area below is the effect of M28,0, L43,0, 12,32, and 25. As long as you know the coordinates of the points, you can splice the points to form a path through the L symbol.


A path can be formed by knowing all the point coordinates of the graph. Multiple paths can be joined together to display the desired pattern, such as the Flutter icon below.

<svg width="50" height="50" viewBox="0 0 50 to 50." " fill="none" xmlns="http://www.w3.org/2000/svg">
    <path d="M0, 0 H50 V50 H0." " fill="#FFFFFF" />
    <path d="M28, 2 L43, 2 12, 32, 4, 25" fill="#3AD0FF" />
    <path d="L30 M16, 36, 44, 48 13 23, 29." " fill="#00559E" />
    <path d="M16, 36 L28, 24, 24 24 42 lancet." " fill="#3AD0FF" />
</svg>
Copy the code


A closer look reveals that this complex character is just a concatenation of the M/H/V/L operators. Notice also that commas and Spaces are interchangeable. Normal SVG files are generated by design software, so they are blank and generally unreadable.

In fact, the most important thing for Flutter drawing is the formation of the Path. Since the Path information is contained in the SVG file, does this mean that we can extract coordinates, generate the Path, and then draw the Flutter? Without further ado, let’s try it out.


3. Convert SVG linear operators to Path objects

1. How to parse SVG paths

The problem now is how to parse the SVG path to the information we need to handle a string, naturally non-regular. Just write a regex and match it.

<path d="M17.5865 17.3955H17.5902L28.5163 8.77432L25.5528 6.39453L17.5902 12.6808H17.5865L17.5828 12.6845L9.62018 6.40201L6.6604 8.78181 L17.5828 L17.5865 17.3992 17.3955 Z" fill="#1E80FF"/>
Copy the code

In the future, we will publish a small volume on regex, which will make it more interesting to know regex by implementing the following regex verification application. Currently, there are only four commands M,H,V, and L in the file. You can use the following command to match the information of each command.


After matching, we can obtain the necessary information, as shown below:


2. Connection with Flutter drawing

The following method forms a Path in a Flutter by parsing an SVG Path. Note that currently there are only four instructions, M,H,V,L, and Z. Other SVG instructions will be improved in the future. The path formed by drawing can be displayed:

Color color = const Color(0xff1E80FF); canvas.drawPath(formPathFromSvgOp(src), paint.. color=color);Copy the code

Path formPathFromSvgOp(String src) {
  Path path = Path();
  RegExp regExp = RegExp(r'[M,H,V,L](((\d+\.\d+)|\d)([ ,])?) +|Z');
  List<RegExpMatch> results = regExp.allMatches(src).toList();
  double lastX = 0;
  double lastY = 0;
  results.forEach((RegExpMatch element) {
    String? op = element.group(0);
    if(op ! =null) {
      if (op.startsWith("M")) {
        List<String> pos = op.substring(1).split(RegExp(r'[, ]'));
        double dx = num.parse(pos[0]).toDouble();
        double dy = num.parse(pos[1]).toDouble();
        path.moveTo(dx, dy);
        lastX = dx;
        lastY = dy;
      }
      if (op.startsWith("L")) {
        List<String> pos = op.substring(1).split(RegExp(r'[, ]'));
        for (int i = 0; i < pos.length; i += 2) {
          double dx = num.parse(pos[i]).toDouble();
          double dy = num.parse(pos[i + 1]).toDouble(); path.lineTo(dx, dy); lastX = dx; lastY = dy; }}if (op.startsWith("H")) {
        print(op.length);
        List<String> pos = op.substring(1).trim().split(RegExp(r'[, ]'));
        for (int i = 0; i < pos.length; i ++) {
          print('${pos[i]}');
          double dx = num.parse(pos[i]).toDouble();
          doubledy = lastY; path.lineTo(dx, dy); lastX = dx; }}if (op.startsWith("V")) {
        List<String> pos = op.substring(1).trim().split(RegExp(r'[, ]'));
        for (int i = 0; i < pos.length; i ++) {
          double dx = lastX;
          double dy = num.parse(pos[i]).toDouble(); path.lineTo(dx, dy); lastY = dy; }}if (op.startsWith("Z")) { path.close(); }}});return path;
}
Copy the code

Just draw the three paths to form the nuggets logo, as shown below:


In this way, the SVG file is divided by path and traversed to form a path. Notice that the text part doesn’t seem to work very well, because it only parses M, H, L, and V. If you look closely, this file also contains the C instruction for forming Bezier curves, which will be explained in the next article. The next chapter will be perfect when we parse C.


3. Color analysis

The color information in each path is also matched by regular expression, as shown below:

Since each SVG path has path information and color information, you can define an SVGPathResult object for maintenance.

class SVGPathResult{
  final Color color;
  final Path path;

  SVGPathResult({required this.color, required this.path});
}
Copy the code

The color parsing logic is as follows:

  SVGPathResult formPathFromSvgOp(String src) {
    Color resultColor = Colors.black;
    RegExp color = RegExp(r'(? < = #) ((. *)? = ") ');
    List<RegExpMatch> colorResult = color.allMatches(src).toList();
    if(colorResult.length>0) {String? colorStr = colorResult[0].group(0);
      if(colorStr! =null) {print(colorStr);
        resultColor = Color(int.parse(colorStr, radix: 16) + 0xFF000000); }}Copy the code

In this way, the SVG of the Flutter icon written earlier can be parsed and colored as follows:


This paper mainly introduces the use of H, V and L absolute linear paths and regular resolution for the formation of Path objects in Flutter. There are some other more important operators in SVG that we will cover and parse in the next article. So don’t assume that this parsing logic will parse any SVG file, there are a lot of details to be worked out. That’s all for this article, thanks for watching