Skip to content

Commit 722386f

Browse files
authored
Merge pull request #1929 from VisActor/feat/gradient-percent
feat: linear-gradient support ignore percent, closed #1926
2 parents b60e695 + 22c29d1 commit 722386f

File tree

5 files changed

+99
-21
lines changed

5 files changed

+99
-21
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"changes": [
3+
{
4+
"packageName": "@visactor/vrender-core",
5+
"comment": "feat: linear-gradient support ignore percent, closed #1926",
6+
"type": "none"
7+
}
8+
],
9+
"packageName": "@visactor/vrender-core"
10+
}

packages/vrender-core/src/common/color-utils.ts

Lines changed: 57 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,60 @@ export class GradientParser {
371371
}
372372
return c;
373373
}
374+
static processColorStops(
375+
colorStops: Array<{ value: string; length?: { value: string } }>
376+
): { color: string; offset: number }[] {
377+
if (!colorStops || colorStops.length === 0) {
378+
return [];
379+
}
380+
381+
const anyStopHasLength = colorStops.some((item: any) => item.length);
382+
383+
if (anyStopHasLength) {
384+
const stops = colorStops.map((item: any) => ({
385+
color: item.value,
386+
offset: item.length ? parseFloat(item.length.value) / 100 : -1
387+
}));
388+
389+
// If first color stop has no position, it defaults to 0%
390+
if (stops[0].offset < 0) {
391+
stops[0].offset = 0;
392+
}
393+
394+
// If last color stop has no position, it defaults to 100%
395+
if (stops[stops.length - 1].offset < 0) {
396+
stops[stops.length - 1].offset = 1;
397+
}
398+
399+
// If a color stop in between has no position, its position is the average of the preceding and succeeding color stops with positions.
400+
for (let i = 1; i < stops.length - 1; i++) {
401+
if (stops[i].offset < 0) {
402+
const prevWithOffsetIdx = i - 1;
403+
let nextWithOffsetIdx = i + 1;
404+
while (nextWithOffsetIdx < stops.length && stops[nextWithOffsetIdx].offset < 0) {
405+
nextWithOffsetIdx++;
406+
}
407+
408+
const startOffset = stops[prevWithOffsetIdx].offset;
409+
const endOffset = stops[nextWithOffsetIdx].offset;
410+
const unspecCount = nextWithOffsetIdx - prevWithOffsetIdx;
411+
412+
for (let j = 1; j < unspecCount; j++) {
413+
stops[prevWithOffsetIdx + j].offset = startOffset + ((endOffset - startOffset) * j) / unspecCount;
414+
}
415+
i = nextWithOffsetIdx - 1;
416+
}
417+
}
418+
return stops;
419+
}
420+
return colorStops.map((item: any, index: number) => {
421+
const offset = colorStops.length > 1 ? index / (colorStops.length - 1) : 0;
422+
return {
423+
color: item.value,
424+
offset
425+
};
426+
});
427+
}
374428
private static ParseConic(datum: any): IConicalGradient {
375429
const { orientation, colorStops = [] } = datum;
376430
const halfPi = pi / 2;
@@ -381,12 +435,7 @@ export class GradientParser {
381435
y: 0.5,
382436
startAngle: sa,
383437
endAngle: sa + pi2,
384-
stops: colorStops.map((item: any) => {
385-
return {
386-
color: item.value,
387-
offset: parseFloat(item.length.value) / 100
388-
};
389-
})
438+
stops: GradientParser.processColorStops(colorStops)
390439
};
391440
}
392441
private static ParseRadial(datum: any): IRadialGradient {
@@ -399,12 +448,7 @@ export class GradientParser {
399448
y1: 0.5,
400449
r0: 0,
401450
r1: 1,
402-
stops: colorStops.map((item: any) => {
403-
return {
404-
color: item.value,
405-
offset: parseFloat(item.length.value) / 100
406-
};
407-
})
451+
stops: GradientParser.processColorStops(colorStops)
408452
};
409453
}
410454
private static ParseLinear(datum: any): ILinearGradient {
@@ -448,12 +492,7 @@ export class GradientParser {
448492
y0,
449493
x1,
450494
y1,
451-
stops: colorStops.map((item: any) => {
452-
return {
453-
color: item.value,
454-
offset: parseFloat(item.length.value) / 100
455-
};
456-
})
495+
stops: GradientParser.processColorStops(colorStops)
457496
};
458497
}
459498
}

packages/vrender-core/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export * from './factory';
2121

2222
/* export common */
2323
export * from './common/text';
24+
export * from './common/color-utils';
2425
export * from './common/bezier-utils';
2526
export * from './common/bounds-context';
2627
export * from './common/seg-context';

packages/vrender/__tests__/browser/src/pages/rect.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { createStage, container, createRect, IGraphic, createGroup, createSymbol } from '@visactor/vrender';
22
import { roughModule } from '@visactor/vrender-kits';
33

4-
container.load(roughModule);
4+
// container.load(roughModule);
55
export const page = () => {
66
const graphics: IGraphic[] = [];
77
// graphics.push(
@@ -78,8 +78,8 @@ export const page = () => {
7878
stroke: 'red',
7979
// scaleCenter: ['50%', '50%'],
8080
// _debug_bounds: true,
81-
fill: 'conic-gradient(from 90deg, rgba(5,0,255,1) 16%, rgba(0,255,10,1) 41%, rgba(9,9,121,1) 53%, rgba(0,212,255,1) 100%)',
82-
// fill: 'linear-gradient(90deg, #215F97 0%, #FF948F 100%)',
81+
// fill: 'conic-gradient(from 90deg, rgba(5,0,255,1) 16%, rgba(0,255,10,1) 41%, rgba(9,9,121,1) 53%, rgba(0,212,255,1) 100%)',
82+
fill: 'linear-gradient(90deg, #215F97, #FF948F)',
8383
// cornerRadius: [5, 10, 15, 20],
8484
lineWidth: 5,
8585
anchor: ['50%', '50%'],
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { GradientParser } from '../../src/index';
2+
3+
it('gradient-color', () => {
4+
expect(GradientParser.processColorStops([{ value: 'rgb(100, 0, 0)' }, { value: 'rgb(0, 100, 0)' }])).toEqual([
5+
{ color: 'rgb(100, 0, 0)', offset: 0 },
6+
{ color: 'rgb(0, 100, 0)', offset: 1 }
7+
]);
8+
expect(
9+
GradientParser.processColorStops([
10+
{ value: 'rgb(100, 0, 0)', length: { value: '0' } },
11+
{ value: 'rgb(0, 100, 0)', length: { value: '100' } }
12+
])
13+
).toEqual([
14+
{ color: 'rgb(100, 0, 0)', offset: 0 },
15+
{ color: 'rgb(0, 100, 0)', offset: 1 }
16+
]);
17+
expect(
18+
GradientParser.processColorStops([
19+
{ value: 'rgb(100, 0, 0)', length: { value: '0' } },
20+
{ value: 'rgb(0, 0, 100)', length: { value: '30' } },
21+
{ value: 'rgb(0, 100, 0)', length: { value: '100' } }
22+
])
23+
).toEqual([
24+
{ color: 'rgb(100, 0, 0)', offset: 0 },
25+
{ color: 'rgb(0, 0, 100)', offset: 0.3 },
26+
{ color: 'rgb(0, 100, 0)', offset: 1 }
27+
]);
28+
});

0 commit comments

Comments
 (0)