Skip to content

Commit

Permalink
✨ feat: support rad angle line-gradient #96
Browse files Browse the repository at this point in the history
  • Loading branch information
arvinxx committed Sep 13, 2021
1 parent 1626b8f commit 9860090
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 32 deletions.
15 changes: 15 additions & 0 deletions src/models/Style/Style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,21 @@ class Style extends BaseStyle {
const from = { x: 0.5, y: 0 };
const to = { x: 0.5, y: 1 };

// 处理带 rad 弧度的对象
if (angle.includes('rad')) {
const rad = parseFloat(angle.split('rad')[0]);
from.x = 0;
from.y = 0;

// 获取自然数 0 (-0 -> 0)
const getNaturalZero = (num: number) => (Math.abs(num) === 0 ? 0 : num);

const x = Math.round(Math.cos(rad) * 100) / 100;
const y = Math.round(Math.sin(rad) * 100) / 100;

to.x = getNaturalZero(x);
to.y = getNaturalZero(y);
}
// Learn math or find someone smarter to figure this out correctly
switch (angle) {
case 'to top':
Expand Down
8 changes: 6 additions & 2 deletions src/utils/background.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,13 @@ export const parseLinearGradient = (value: string) => {
};
}
if (parts.length > 2) {
// 如果 parts 的第一个对象 不包含 deg to
// 如果 parts 的第一个对象 不包含 deg to 或者 rad
// 那就意味着全部都是 stops
if (!parts[0].includes('deg') && !parts[0].includes('to')) {
if (
!parts[0].includes('deg') &&
!parts[0].includes('to') &&
!parts[0].includes('rad')
) {
return { angle: '180deg', stops: parts };
}

Expand Down
9 changes: 9 additions & 0 deletions tests/__tests__/parser/html/shape.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
.linear-gradient {
background-image: linear-gradient(red, yellow, blue);
}
.linear-gradient-angle {
background-image: linear-gradient(1.5708rad, red, yellow, blue);
}

.radial-gradient {
background-image: radial-gradient(red, yellow, blue);
Expand All @@ -26,6 +29,12 @@
style="width: 200px; height: 200px"
></div>

<div
id="linear-gradient-angle"
class="linear-gradient-angle"
style="width: 200px; height: 200px"
></div>

<div
id="linear-gradient"
class="linear-gradient"
Expand Down
80 changes: 50 additions & 30 deletions tests/__tests__/parser/shape.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,23 +165,56 @@ describe('parseToShape', () => {
expect(shadow4?.offsetX).toBe(2);
expect(shadow4?.color.blue).toBe(1);
});
it('background-image 正常解析', async () => {
const node = document.getElementById('background-image') as HTMLDivElement;
const rectangle = (await parseToShape(node)) as Rectangle;

expect(rectangle.class).toBe('rectangle');
const fill = rectangle.style.fills[0];
expect(fill.type).toBe(4);

expect(fill.image?.url).toBe(
'https://gw.alipayobjects.com/zos/rmsportal/mZBWtboYbnMkTBaRIuWQ.png',
);

expect(rectangle.frame.width).toBe(200);
expect(rectangle.frame.height).toBe(200);
expect(fill.image?.base64).toBe(
'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',
);
describe('background-image 正常解析', () => {
it('普通图片正常', async () => {
const node = document.getElementById(
'background-image',
) as HTMLDivElement;
const rectangle = (await parseToShape(node)) as Rectangle;

expect(rectangle.class).toBe('rectangle');
const fill = rectangle.style.fills[0];
expect(fill.type).toBe(4);

expect(fill.image?.url).toBe(
'https://gw.alipayobjects.com/zos/rmsportal/mZBWtboYbnMkTBaRIuWQ.png',
);

expect(rectangle.frame.width).toBe(200);
expect(rectangle.frame.height).toBe(200);
expect(fill.image?.base64).toBe(
'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',
);
});
it('linear-gradient 正常解析', async () => {
const node = document.getElementById('linear-gradient') as HTMLDivElement;
const rectangle = (await parseToShape(node)) as Rectangle;

expect(rectangle.class).toBe('rectangle');
const fill = rectangle.style.fills[0];

expect(fill.type).toBe(1);

expect(rectangle.frame.width).toBe(200);
expect(rectangle.frame.height).toBe(200);
expect(fill.gradient?.stops.length).toBe(3);
});
it('linear-gradient 如果有角度也可以正常解析', async () => {
const node = document.getElementById(
'linear-gradient-angle',
) as HTMLDivElement;
const rectangle = (await parseToShape(node)) as Rectangle;

expect(rectangle.class).toBe('rectangle');
const fill = rectangle.style.fills[0];

expect(fill.type).toBe(1);

expect(rectangle.frame.width).toBe(200);
expect(rectangle.frame.height).toBe(200);
expect(fill.gradient?.from).toEqual({ x: 0, y: 0 });
expect(fill.gradient?.to).toEqual({ x: 0, y: 1 });
});
});
it('clip-background-image 正常解析', async () => {
const node = document.getElementById(
Expand Down Expand Up @@ -214,19 +247,6 @@ describe('parseToShape', () => {
'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',
);
});
it('linear-gradient 正常解析', async () => {
const node = document.getElementById('linear-gradient') as HTMLDivElement;
const rectangle = (await parseToShape(node)) as Rectangle;

expect(rectangle.class).toBe('rectangle');
const fill = rectangle.style.fills[0];

expect(fill.type).toBe(1);

expect(rectangle.frame.width).toBe(200);
expect(rectangle.frame.height).toBe(200);
expect(fill.gradient?.stops.length).toBe(3);
});
it('radial-gradient 暂不支持解析', async () => {
const node = document.getElementById('radial-gradient') as HTMLDivElement;
const rectangle = (await parseToShape(node)) as Rectangle;
Expand Down
15 changes: 15 additions & 0 deletions tests/__tests__/utils/background.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,13 @@ describe('parseBackgroundImage', () => {
const result = parseBackgroundImageType(str) as BackgroundImageType;
expect(result.type).toStrictEqual('LinearGradient');
});
it('解析 angle 三种颜色', () => {
const str = 'linear-gradient(1.5708rad, red, yellow, blue)';
const result = parseBackgroundImageType(str) as BackgroundImageType;
expect(result.type).toStrictEqual('LinearGradient');
expect(result.value.angle).toStrictEqual('1.5708rad');
expect(result.value.stops.length).toEqual(3);
});
});
});

Expand Down Expand Up @@ -194,6 +201,14 @@ describe('parseLinearGradient', () => {
angle: '90deg',
});
});
it('解析 angle 类型的方向', () => {
const str = '1.5708rad, red, blue';
const result = parseLinearGradient(str);
expect(result).toStrictEqual({
stops: ['red', 'blue'],
angle: '1.5708rad',
});
});
it('解析三种颜色', () => {
const str = 'red, yellow, blue';
const result = parseLinearGradient(str);
Expand Down

0 comments on commit 9860090

Please sign in to comment.