Skip to content

Commit

Permalink
Merge pull request #6 from bmx666/issue-5
Browse files Browse the repository at this point in the history
add support linear and radial gradient
  • Loading branch information
seanghay authored Jul 8, 2023
2 parents 7e0f898 + ed36fa7 commit 72ef47c
Show file tree
Hide file tree
Showing 3 changed files with 162 additions and 1 deletion.
100 changes: 99 additions & 1 deletion src/vector-drawable-svg.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,25 @@ const groupAttrsMap = {
'android:translateY': { transform: 'translateY' },
}

const gradientAttrsMap = {
"android:startX": "x1",
"android:startY": "y1",
"android:endX": "x2",
"android:endY": "y2",
"android:centerX": "cx",
"android:centerY": "cy",
"android:gradientRadius": "r",
}

const gradientItemAttrsMap = {
"android:color": "stop-color",
"android:offset": "offset",
}

const gradientItemAttrsTransforms = {
'android:color': convertHexColor,
}

function parsePath(root, pathNode) {
const svgPath = root.createElement("path");
svgPath.setAttribute("fill", "none");
Expand All @@ -46,10 +65,89 @@ function parsePath(root, pathNode) {
return svgPath;
}

function parseGradient(root, gradientNode) {
const type = gradientNode.getAttribute('android:type');

const svgGradient = function(type) {
switch (type) {
case 'linear':
return root.createElement("linearGradient");
case 'radial':
return root.createElement("radialGradient");
case 'sweep':
throw new Error("Sweep gradient is not compatible by SVG");
default:
throw new Error("invalid gradient type");
}
}(type);

svgGradient.setAttribute('gradientUnits', 'userSpaceOnUse');

Array.from(gradientNode.attributes).forEach((attr) => {
const svgAttrName = gradientAttrsMap[attr.name];
if (svgAttrName) {
const svgAttrValue = attr.value;
svgGradient.setAttribute(svgAttrName, svgAttrValue);
}
});

Array.from(gradientNode.childNodes).forEach(it => {
if (it.tagName === 'item') {
const svgGradientStop = root.createElement('stop');

Array.from(it.attributes).forEach((attr) => {
const svgAttrName = gradientItemAttrsMap[attr.name];
const transformer = gradientItemAttrsTransforms[attr.name];
if (svgAttrName) {
const svgAttrValue = transformer ? transformer(attr.value) : attr.value;
svgGradientStop.setAttribute(svgAttrName, svgAttrValue);
}
});

svgGradient.appendChild(svgGradientStop);
}
});

return svgGradient;
}

function transformNode(node, parent, root, defs) {

if (node.tagName === 'path') {
return parsePath(root, node);
const svgPath = parsePath(root, node);

Array.from(node.childNodes).forEach(it => {
if (it.tagName === 'aapt:attr') {
const attrName = it.getAttribute('name');
switch (attrName) {
case 'android:fillColor':
case 'android:strokeColor':

Array.from(it.childNodes).forEach(childNode => {
if (childNode.tagName === 'gradient') {
const svgGradient = parseGradient(root, childNode);

if (svgGradient) {
const size = defs.childNodes.length;
const gradientId = `gradient_${size}`;

svgGradient.setAttribute('id', gradientId);
defs.appendChild(svgGradient);

const svgAttrName = attributesMap[attrName];
svgPath.setAttribute(svgAttrName, `url(#${gradientId})`);
}
}
});

break;
default:
break;
}
}
});

return svgPath;
}

if (node.tagName === 'group') {
Expand Down
62 changes: 62 additions & 0 deletions tests/drawables/sample-03.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M 0 0 h 12 v 12 h -12 v -12 z">
<aapt:attr name="android:fillColor">
<gradient
android:centerX="6.0"
android:centerY="6.0"
android:gradientRadius="8.0"
android:type="radial">
<item
android:color="#f00"
android:offset="0"/>
<item
android:color="#0f0"
android:offset="0.5"/>
<item
android:color="#00f"
android:offset="1"/>
</gradient>
</aapt:attr>
</path>

<path
android:pathData="M 8 8 h 12 v 12 h -12 v -12 z"
android:strokeWidth="3">
<aapt:attr name="android:fillColor">
<gradient
android:endX="18.0"
android:endY="18.0"
android:startX="10.0"
android:startY="10.0"
android:type="linear">
<item
android:color="#0f0"
android:offset="0"/>
<item
android:color="#00f"
android:offset="1"/>
</gradient>
</aapt:attr>
<aapt:attr name="android:strokeColor">
<gradient
android:endX="18"
android:endY="18"
android:startX="10"
android:startY="10"
android:type="linear">
<item
android:color="#000"
android:offset="0"/>
<item
android:color="#fff"
android:offset="1"/>
</gradient>
</aapt:attr>
</path>
</vector>
1 change: 1 addition & 0 deletions tests/svgs/sample-03.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 72ef47c

Please sign in to comment.