Apri
Apri

Reputation: 1515

Flutter draw line with custom pattern in Map

Is it possible to draw a line in Flutter with a complete custom pattern that repeats itself along the line? For example, I want to have this pattern:

enter image description here

So if I draw a straight line, it should like like this:

enter image description here

Now, I don't just want to draw straight lines. I actually want to draw polylines on a map. I am using the flutter_map package. I saw that the PolylineLayer Widget just uses a CustomPainter to draw the lines along the map. The Polilines are not very customizable (they just come with options for a border, dashes, etc). So my idea is to just create another widget that does exactly the same as the PolylineLayer widget, but with my own CustomPainter, that should draw the custom pattern along the path. Ideally I could just create an svg with the pattern and apply it to the path, if that is possible.

Edit

I tried pskinks Answer. It generally works, but it doesn't quite work for a curved line. Here is my code:

@override
void paint(Canvas canvas, Size size) {
    var path = ui.Path();
    final paint = Paint()
    ..strokeWidth = polyline.strokeWidth
    ..strokeCap = polyline.strokeCap
    ..strokeJoin = polyline.strokeJoin
    ..style = PaintingStyle.stroke
    ..shader = ImageShader(
      polyline.image, // this is a ui.Image
      TileMode.repeated,
      TileMode.repeated,
      Matrix4.identity().storage,
    );
    
    final offsets = getOffsets(polyline.points);
    _paintLine(path, offsets);
    canvas.drawPath(path, paint);
}



void _paintLine(ui.Path path, List<Offset> offsets) {
  if (offsets.isEmpty) {
    return;
  }
  path.addPolygon(offsets, false);
}

List<Offset> getOffsets(List<LatLng> points) {
   // Calculate offsets on map
}

Now, the line is drawn, the path is correct, and the line has the pattern of the image. But the direction of the image doesn't follow the line.

The image that I use for the pattern looks like this:

enter image description here

The outcome I expect should look somewhat like this. This is just an example to visualize that the image direction should follow the line. It should be even more curved in reality:

enter image description here

The current outcome looks somewhat like this. I hope it makes the problem clear. The direction does not follow the line:

enter image description here

This is what it actually looks like in my app (to visualize it again):

enter image description here

Edit 2

I to draw each line individually with composeMatrix as mentioned by pskink. The patterns get rotated, but I can't seem to figure out the strokeWidth and translation. The height of my image should stretch exactly across the height of the line. The width of my image should not stretch, instead it should repeat. Here is my code, and below is the current outcome.

@override
void paint(Canvas canvas, Size size) {
    for (final polyline in polylines) {
      final offsets = getOffsets(polyline.points);
      if (offsets.isEmpty) {
        continue;
      }

      final image = _cacheManager.getImageSync(polyline.svgPath);

      final paint = Paint()
        ..strokeWidth = polyline.strokeWidth
        ..strokeCap = polyline.strokeCap
        ..strokeJoin = polyline.strokeJoin
        ..style = PaintingStyle.stroke;

      for (int i = 0; i < offsets.length - 1; i++) {
        final p1 = offsets[i];
        final p2 = offsets[i + 1];
        final angle = (p2 - p1).direction;
        final center = Offset((p1.dx + p2.dx) / 2, (p1.dy + p2.dy) / 2);

        final matrix = composeMatrix(
          anchor: center,
          rotation: angle,
          scale: polyline.strokeWidth / image.height,
          translate: p1,
        );

        final shader = ImageShader(
          image,
          TileMode.repeated,
          TileMode.repeated,
          matrix.storage,
        );

        paint.shader = shader;

        final path = ui.Path()
          ..moveTo(p1.dx, p1.dy)
          ..lineTo(p2.dx, p2.dy);

        canvas.drawPath(path, paint);
      }
    }
  }

  @override
  bool shouldRepaint(covariant SvgPolylinePainter oldDelegate) {
    return oldDelegate.bounds != bounds ||
        oldDelegate.polylines.length != polylines.length ||
        oldDelegate.hash != hash;
  }
}

enter image description here

Upvotes: 0

Views: 260

Answers (0)

Related Questions