Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Android rendering artefact not working correctly #2418

Open
MorneBitcube opened this issue May 9, 2024 · 3 comments
Open

Android rendering artefact not working correctly #2418

MorneBitcube opened this issue May 9, 2024 · 3 comments
Labels
bug Something isn't working

Comments

@MorneBitcube
Copy link

Description

I'm using a custom component to render an SVG path with rounded caps. It works fine on iOS. But on Android, it causes a weird render artefact. See image below

1715247013733

1715247090433

This only occurs when 4 or more SVGs in separate canvases are stacked on top of each other

Version

1.2.0

Steps to reproduce

  • Add the given code to react-native code base and build the app on Android.

Snack, code example, screenshot, or link to a repository

  • The ring component
import * as React from "react"
import { useEffect } from "react"
import { observer } from "mobx-react-lite"
import { Easing, useSharedValue, withDelay, withTiming } from "react-native-reanimated"
import { Canvas, Color, Path, Skia } from "@shopify/react-native-skia"
import { View } from "react-native"

export type RingSizePreset = keyof typeof $sizePresets

export interface RingProgressProps {
  progress: number
  size: RingSizePreset
  color: Color
  canvasSize: number
}

function degToRad(degrees: number): number {
  return degrees * (Math.PI / 180)
}

export const RingProgress = observer(function RingProgress(props: RingProgressProps) {
  const { progress, size, color, canvasSize } = props

  const { width, startAngleDeg, endAngleDeg } = $sizePresets[size]

  const progressValue = useSharedValue(0)
  useEffect(() => {
    progressValue.value = withDelay(
      100,
      withTiming(progress, { duration: 700, easing: Easing.elastic(1) }),
    )
  }, [progress])

  const strokeWidth = 25
  const center = canvasSize / 2
  const r = (width + canvasSize - strokeWidth * 2) / 2
  const startAngle = degToRad(startAngleDeg)
  const endAngle = degToRad(endAngleDeg)

  const x1 = center - r * Math.cos(endAngle)
  const y1 = -r * Math.sin(endAngle) + center
  const x2 = center - r * Math.cos(startAngle)
  const y2 = -r * Math.sin(startAngle) + center

  const backgroundPath = `M ${x1} ${y1} A ${r} ${r} 0 1 0 ${x2} ${y2}`
  const foregroundPath = `M ${x2} ${y2} A ${r} ${r} 0 1 1 ${x1} ${y1}`

  const skiaBackgroundPath = Skia.Path.MakeFromSVGString(backgroundPath)
  const skiaForegroundPath = Skia.Path.MakeFromSVGString(foregroundPath)

  if (!skiaBackgroundPath || !skiaForegroundPath) {
    return <View />
  }
  return (
    <Canvas
      style={{
        width: canvasSize,
        height: canvasSize,
        position: "absolute",
      }}
    >
      <Path
        path={skiaBackgroundPath}
        strokeCap={"round"}
        strokeWidth={strokeWidth}
        style={"stroke"}
        color={color}
        opacity={0.1}
      />

      <Path
        path={skiaForegroundPath}
        strokeCap={"round"}
        strokeWidth={strokeWidth}
        start={0}
        end={progressValue}
        style={"stroke"}
        color={color}
      />
    </Canvas>
  )
})

const $sizePresets = {
  extraSmall: {
    width: -180,
    startAngleDeg: -70,
    endAngleDeg: 250,
  },
  small: {
    width: -120,
    startAngleDeg: -72,
    endAngleDeg: 252,
  },
medium: { width: -60, startAngleDeg: -74, endAngleDeg: 254 },
  large: { width: 0, startAngleDeg: -76, endAngleDeg: 256 },
}

  • Implement the component for use
 export const ProgressRings = () => {

const dataList = [
  { 
    id: 1,
    progress: 0,
    name: "FirstRing",
   size: 'extraSmall',
   color: 'blue'
  },
  {
    id: 2,
    progress: 0.5,
    name: "SecondRing",
    size: 'small',
    color: 'red'
  },
  {
    id: 3,
    progress: 0.5,
    name: "Third",
    size: 'medium',
    color: 'red'
  },
  {
    id: 4,
    progress: 0.5,
    name: "Fourth",
    size: 'large',
    color: 'red'
  },
]

  const $canvasContainer: ViewStyle = {
    width: 400,
    height: 400,
    alignItems: "center",
    justifyContent: "center",
  }

  return (
    <View style={$canvasContainer}>
      {dataList.map((item) => (
        <RingProgress
          color={item.color}
          size={item.size}
          progress={item.progress}
          canvasSize={400}
          key={item.id}
        />
      ))}
    </View>
  )
})
@MorneBitcube MorneBitcube added the bug Something isn't working label May 9, 2024
@wcandillon
Copy link
Collaborator

wcandillon commented May 9, 2024 via email

@MorneBitcube
Copy link
Author

@wcandillon As requested here is a single file
rings.tsx.zip

@MorneBitcube
Copy link
Author

@wcandillon have you managed to reproduce this issue yet? I have tried to fix this on my side but was not successful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants