react-native-svg
react-native-svg copied to clipboard
LinearGradient rendering as Black/Transparent
Bug
When rendering some SVGs that use Linear Gradient, the Gradient renders as black on Android, or sometimes transparent on iOS.
Environment info
React native info output:
System:
OS: Linux 4.4 Ubuntu 18.04.1 LTS (Bionic Beaver)
CPU: (12) x64 Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz
Memory: 3.53 GB / 15.86 GB
Shell: 5.4.2 - /usr/bin/zsh
Binaries:
Node: 12.9.1 - ~/.nvm/versions/node/v12.9.1/bin/node
Yarn: 1.22.4 - ~/.yarn/bin/yarn
npm: 6.14.4 - ~/.nvm/versions/node/v12.9.1/bin/npm
npmPackages:
react: ~16.9.0 => 16.9.0
react-native: https://github.com/expo/react-native/archive/sdk-36.0.0.tar.gz => 0.61.4
Library version: 9.13.3 that is bundled with Expo SDK 36
Describe what you expected to happen:
- The SVG should render with Linear Gradients on Android and iOS.
Short, Self Contained, Correct (Compilable), Example
I've put together this Expo Snack that reproduces the issue. The original SVG file is also contained in the assets folder.
https://snack.expo.io/BJer8PCUI
I have also read through issues #1153 and #540. In the first example I have actually been able to use the SVG provided successfully, it does not display the same behavior as my SVG. I have also tried changing the stopColor
prop to a style
prop, but this has no effect.
So I managed to do some digging and I've discovered the problem. LinearGradient
(and perhaps other elements) don't support the xLinkHref
prop, or if they do support it, it does not work correctly.
The vast majority of my example SVG uses the following syntax (generated by SVGR)
<LinearGradient
id='prefix__b'
x1={353.71}
y1={360.14}
x2={360.02}
y2={360.14}
gradientTransform='matrix(-1 0 0 1 528.02 0)'
gradientUnits='userSpaceOnUs'
>
<Stop offset={0} stopColor='#e4c5d5' />
<Stop offset={0.42} stopColor='#e9d3cf' />
<Stop offset={1} stopColor='#efe8ca' />
</LinearGradient>
<LinearGradient id='prefix__g' x1={287.43} y1={352.21} x2={294.44} y2={352.21} xlinkHref='#prefix__b' />
where LinearGradient prefix__g
wants to inherit the properties from LinearGradient prefix__b
and then overriding the X
and Y
coordinates.
I discovered that replacing this inheritance with the values from prefix__b
leads to the correct rendering of the SVG like so:
<LinearGradient
id='prefix__b'
x1={353.71}
y1={360.14}
x2={360.02}
y2={360.14}
gradientTransform='matrix(-1 0 0 1 528.02 0)'
gradientUnits='userSpaceOnUse'
>
<Stop offset={0} stopColor='#e4c5d5' />
<Stop offset={0.42} stopColor='#e9d3cf' />
<Stop offset={1} stopColor='#efe8ca' />
</LinearGradient>
<LinearGradient
id='prefix__g'
x1={287.43}
y1={352.21}
x2={294.44}
y2={352.21}
gradientUnits='userSpaceOnUse'
gradientTransform='matrix(-1 0 0 1 528.02 0)'
>
<Stop offset={0} stopColor='#e4c5d5' />
<Stop offset={0.42} stopColor='#e9d3cf' />
<Stop offset={1} stopColor='#efe8ca' />
</LinearGradient>
Here is a snack that shows the old broken SVG, and the new working SVG. https://snack.expo.io/yTM9VSiR8
Is this something that react-native-svg
intends to support?
Ah, as long as it's defined by the spec, and some ever-green browser supports it, then ideally react-native-svg would support it as well. There's a workaround here: https://github.com/react-native-community/react-native-svg/pull/920
But should probably be implemented on the native side, and closer to the wording of the spec. Would you mind looking into it?
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. You may also mark this issue as a "discussion" and I will leave this open.
the problem still exists at 13.6.0
i I use react-native-svg to render the chart of echarts, the gradient is rendered black or transparent, especially when there is animation.
https://echarts.apache.org/examples/zh/editor.html?c=dataset-encode0
Simplified source code
<svg xmlns="http://www.w3.org/2000/svg" baseProfile="full" width="522" height="782" style="position:absolute;left:0;top:0;user-select:none">
<g clip-path="url(#a)">
<path d="M0 0h20v140H0Z" transform="rotate(-90 483.418 293.582)" fill="url(#b)"/>
<path d="M0 0h20v140H0Z" transform="rotate(-90 483.418 293.582)" fill="url(#c)"/>
</g>
<defs>
<linearGradient gradientUnits="objectBoundingBox" x1="0" y1="0" x2="0" y2="1" id="b">
<stop offset="0%" stop-color="#AAA"/>
<stop offset="50%" stop-color="#AAA"/>
<stop offset="100%" stop-color="#AAA"/>
</linearGradient>
<linearGradient gradientUnits="objectBoundingBox" x1="0" y1="0" x2="0" y2="1" id="c">
<stop offset="0%" stop-color="#65B581"/>
<stop offset="50%" stop-color="#FFCE34"/>
<stop offset="100%" stop-color="#FD665F"/>
</linearGradient>
<clipPath id="a">
<path d="M189.836 774v-14a3 3 0 0 1 3-3h134a3 3 0 0 1 3 3v14a3 3 0 0 1-3 3h-134a3 3 0 0 1-3-3"/>
</clipPath>
</defs>
</svg>
render by webview & react-native-svg & react-native-skia (With transition animation)
- webview ✅
- react-native-svg Transparent/black
- skia ✅
expected | Transparent | black |
---|---|---|
![]() |
![]() |
Does this problem only occur in certain scenarios? Is there a way to avoid it?
Does this problem only occur in certain scenarios? Is there a way to avoid it? @zhiqingchen
您好,我也在考虑RN集成echarts,目前遇到两个问题请教一下: 1 用react-native-skia集成的话,原理和集成微信小程序差不多,CanvasRenderingContext2D您自己实现的吗,可否共享一下?不胜感激 1 如何用这个svg库集成,您是怎么做的呢 十分感谢
@ljianc Our project is still under development, not officially open source.
@ljianc try https://github.com/wuba/wrn-echarts
@ljianc try https://github.com/wuba/wrn-echarts
OK,TKS, Thank you for still remembering this question
I still have the same problem with version 14.1.0
So I managed to do some digging and I've discovered the problem.
LinearGradient
(and perhaps other elements) don't support thexLinkHref
prop, or if they do support it, it does not work correctly.The vast majority of my example SVG uses the following syntax (generated by SVGR)
<LinearGradient id='prefix__b' x1={353.71} y1={360.14} x2={360.02} y2={360.14} gradientTransform='matrix(-1 0 0 1 528.02 0)' gradientUnits='userSpaceOnUs' > <Stop offset={0} stopColor='#e4c5d5' /> <Stop offset={0.42} stopColor='#e9d3cf' /> <Stop offset={1} stopColor='#efe8ca' /> </LinearGradient> <LinearGradient id='prefix__g' x1={287.43} y1={352.21} x2={294.44} y2={352.21} xlinkHref='#prefix__b' />
where LinearGradient
prefix__g
wants to inherit the properties from LinearGradientprefix__b
and then overriding theX
andY
coordinates.I discovered that replacing this inheritance with the values from
prefix__b
leads to the correct rendering of the SVG like so:<LinearGradient id='prefix__b' x1={353.71} y1={360.14} x2={360.02} y2={360.14} gradientTransform='matrix(-1 0 0 1 528.02 0)' gradientUnits='userSpaceOnUse' > <Stop offset={0} stopColor='#e4c5d5' /> <Stop offset={0.42} stopColor='#e9d3cf' /> <Stop offset={1} stopColor='#efe8ca' /> </LinearGradient> <LinearGradient id='prefix__g' x1={287.43} y1={352.21} x2={294.44} y2={352.21} gradientUnits='userSpaceOnUse' gradientTransform='matrix(-1 0 0 1 528.02 0)' > <Stop offset={0} stopColor='#e4c5d5' /> <Stop offset={0.42} stopColor='#e9d3cf' /> <Stop offset={1} stopColor='#efe8ca' /> </LinearGradient>
Here is a snack that shows the old broken SVG, and the new working SVG. snack.expo.io/yTM9VSiR8
Is this something that
react-native-svg
intends to support?
I faced the same problem and this did fix it! Thank you for the suggestion!