androidreact-nativesvgreact-native-svg

react-native-svg - Marker / Line markerEnd doesn't work on Android


Simply trying to draw an arrow line using the following code

import * as React from 'react';
import { Text, View, StyleSheet } from 'react-native';
import Svg, { Defs, Line, Marker, Path } from "react-native-svg";

export default function App() {
  return (
     <Svg>
        <Defs>
          <Marker
            id="arrow"
            refX={0}
            refY={3}
            markerWidth="6"
            markerHeight="6"
            orient="auto"
          >
            <Path d="M 0 0 L 6 3 L 0 6 z" fill={"red"} stroke={"red"} strokeWidth="2" />
          </Marker>
        </Defs>
        <Line
          x1={80}
          y1={80}
          x2={220}
          y2={220}
          stroke={"green"}
          strokeWidth="2"
          markerEnd="url(#arrow)"
        />
      </Svg>
  );
}

The above code draws a line with an arrow fine on iOS but doesn't work on Android at all, it draws a simple line in Android without the markerEnd.

Is this is a bug, or I am doing anything wrong?

Live example here https://snack.expo.dev/@vedexpo/d2ed3c which clearly shows it doesn't work on Android.

Thanks.


Solution

  • Thanks, @sandarshnaroju for the trick I was looking for, however, it works with the fixed values only. Here is my solution where I am drawing the arrowhead dynamically, which might help anyone looking for a similar solution.

    import React, { Component } from 'react';
    import Svg, { Line, Polygon } from 'react-native-svg';
    
    export default class App extends Component {
    
    drawHead=(x0, y0, x1, y1, h, w)=> {
        var L = Math.sqrt(Math.pow((x0 - x1), 2) + Math.pow((y0 - y1), 2));
    
        //first base point coordinates
        var base_x0 = x1 + (w / 2) * (y1 - y0) / L;
        var base_y0 = y1 + (w / 2) * (x0 - x1) / L;
    
        //second base point coordinates
        var base_x1 = x1 - (w / 2) * (y1 - y0) / L;
        var base_y1 = y1 - (w / 2) * (x0 - x1) / L;
    
        var dx = 0;
        var dy = 0;
        var head_x = 0;
        var head_y = 0;
    
        if (x1 == x0) {
          dx = 0;
          dy = h;
          if (y1 < y0) {
           dy = -h;
          }
        } else if (y1 == y0) {
          dx = h;
          dy = 0;
          if (x1 < x0) {
            dx = -h;
          }
        } else {
          if (x1 < x0) {
             h = -h;
          }
        var slope = (y1 - y0) / (x1 - x0);
        dx = h / Math.sqrt(1 + Math.pow(slope, 2));
        dy = dx * slope;
    }
    
    //head_points
    head_x = x1 + dx;
    head_y = y1 + dy;
    
    return `${base_x0},${base_y0} ${base_x1},${base_y1} ${head_x},${head_y}`;
    }
    
      render(){
          var x1=50
          var y1=80
          var x2=150
          var y2=30
    
          var arrowPoints = this.drawHead(x1,y1,x2,y2,8,10)
    
          return (
            <Svg width={300} height={300}>
              <Line
                x1={x1}
                y1={y1}
                x2={x2}
                y2={y2}
                stroke={'green'}
                strokeWidth="2"
                markerEnd="url(#arrow)"
              />
              <Polygon
                points={arrowPoints}
                fill="green"
              />
            </Svg>
          );
      }
    }
    

    See here live

    Hope it helps someone.

    Cheers.