Skip to content

Commit 693ec3c

Browse files
committed
Merge branch 'develop' into feat/upgrade-vrender-1-1-3
# Conflicts: # common/config/rush/pnpm-lock.yaml # docs/package.json # packages/openinula-vchart/package.json # packages/react-vchart/package.json # packages/vchart-extension/package.json # packages/vchart-extension/src/charts/3d/arc-3d.ts # packages/vchart/package.json # tools/story-player/package.json
2 parents 8b42103 + 2aeb1cf commit 693ec3c

5 files changed

Lines changed: 335 additions & 2 deletions

File tree

.github/workflows/release.yml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,13 @@ jobs:
342342
with:
343343
path: packages/vchart
344344

345+
- name: BytePack CDN smoke test (release)
346+
if: startsWith(github.ref_name, 'release/')
347+
env:
348+
BYTEPACK_SMOKE_ATTEMPTS: 12
349+
BYTEPACK_SMOKE_DELAY_MS: 30000
350+
run: node --experimental-network-imports common/scripts/bytepack-smoke-test.mjs ${{ steps.package_version_release.outputs.current_version }}
351+
345352
- name: Commit & Push changes (release)
346353
if: startsWith(github.ref_name, 'release/')
347354
run: |
@@ -407,6 +414,13 @@ jobs:
407414
with:
408415
path: packages/vchart
409416

417+
- name: BytePack CDN smoke test (hotfix)
418+
if: startsWith(github.ref_name, 'hotfix/')
419+
env:
420+
BYTEPACK_SMOKE_ATTEMPTS: 12
421+
BYTEPACK_SMOKE_DELAY_MS: 30000
422+
run: node --experimental-network-imports common/scripts/bytepack-smoke-test.mjs ${{ steps.package_version_hotfix.outputs.current_version }}
423+
410424
- name: Commit & Push changes (hotfix)
411425
if: startsWith(github.ref_name, 'hotfix/')
412426
run: |
@@ -444,6 +458,13 @@ jobs:
444458
with:
445459
path: packages/vchart
446460

461+
- name: BytePack CDN smoke test (pre-release)
462+
if: startsWith(github.ref_name, 'pre-release/')
463+
env:
464+
BYTEPACK_SMOKE_ATTEMPTS: 12
465+
BYTEPACK_SMOKE_DELAY_MS: 30000
466+
run: node --experimental-network-imports common/scripts/bytepack-smoke-test.mjs ${{ steps.package_version_prerelease.outputs.current_version }}
467+
447468
- name: Commit & Push changes (pre-release)
448469
if: startsWith(github.ref_name, 'pre-release/')
449470
run: |
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import { createRequire } from 'node:module';
2+
import path from 'node:path';
3+
import { fileURLToPath } from 'node:url';
4+
5+
const version = process.argv[2];
6+
7+
if (!version) {
8+
console.error('Usage: node --experimental-network-imports common/scripts/bytepack-smoke-test.mjs <version>');
9+
process.exit(1);
10+
}
11+
12+
const attempts = Number(process.env.BYTEPACK_SMOKE_ATTEMPTS || 10);
13+
const delayMs = Number(process.env.BYTEPACK_SMOKE_DELAY_MS || 30000);
14+
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..');
15+
const requireFromVChart = createRequire(path.join(repoRoot, 'packages/vchart/package.json'));
16+
const Canvas = requireFromVChart('canvas');
17+
18+
const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
19+
20+
async function runSmoke() {
21+
const vchartModule = await import(`https://bytepack.bytedance.net/@visactor/vchart@${version}`);
22+
const extensionModule = await import(
23+
`https://bytepack.bytedance.net/@visactor/vchart-extension@${version}/esm/charts/pie-3d/chart.js`
24+
);
25+
26+
extensionModule.registerPie3dChart();
27+
28+
const VChart = vchartModule.default ?? vchartModule.VChart;
29+
if (!VChart) {
30+
throw new Error('Unable to resolve VChart constructor from BytePack module.');
31+
}
32+
33+
const chart = new VChart(
34+
{
35+
type: 'pie3d',
36+
width: 240,
37+
height: 240,
38+
data: [
39+
{
40+
id: 'data',
41+
values: [
42+
{ category: 'A', value: 12 },
43+
{ category: 'B', value: 18 }
44+
]
45+
}
46+
],
47+
categoryField: 'category',
48+
valueField: 'value',
49+
outerRadius: 0.72
50+
},
51+
{
52+
mode: 'node',
53+
modeParams: Canvas,
54+
animation: false,
55+
options3d: {
56+
enable: true
57+
}
58+
}
59+
);
60+
61+
chart.renderSync();
62+
chart.release();
63+
}
64+
65+
let lastError;
66+
for (let attempt = 1; attempt <= attempts; attempt++) {
67+
try {
68+
console.log(`BytePack smoke test for @visactor/vchart@${version}, attempt ${attempt}/${attempts}`);
69+
await runSmoke();
70+
console.log(`BytePack smoke test passed for @visactor/vchart@${version}`);
71+
process.exit(0);
72+
} catch (err) {
73+
lastError = err;
74+
console.error(`BytePack smoke test failed on attempt ${attempt}/${attempts}:`);
75+
console.error(err && err.stack ? err.stack : err);
76+
77+
if (attempt < attempts) {
78+
await wait(delayMs);
79+
}
80+
}
81+
}
82+
83+
console.error(`BytePack smoke test failed after ${attempts} attempts.`);
84+
if (lastError) {
85+
console.error(lastError && lastError.stack ? lastError.stack : lastError);
86+
}
87+
process.exit(1);

packages/vchart/__tests__/unit/animation/manual-ticker.test.ts

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import VChart, {
66
type ILineChartSpec,
77
type IMark,
88
type IMarkGraphic,
9+
type IPieChartSpec,
910
type ISeries,
1011
type IWordCloudChartSpec
1112
} from '../../../src';
@@ -218,6 +219,52 @@ const getGraphicDatum = (graphic: AnimatedGraphic) => {
218219

219220
const getStateDatum = (datum: any) => (Array.isArray(datum) ? datum[0] : datum);
220221

222+
const createCustomGroupSpec = (x: number): IBarChartSpec =>
223+
({
224+
type: 'bar',
225+
data: [
226+
{
227+
id: 'data',
228+
values: [{ x: 'A', y: 1 }]
229+
}
230+
],
231+
xField: 'x',
232+
yField: 'y',
233+
animation: true,
234+
customMark: [
235+
{
236+
type: 'group',
237+
name: 'customGroup',
238+
animation: true,
239+
animationUpdate: false,
240+
style: {
241+
x,
242+
y: 20,
243+
width: 40,
244+
height: 30
245+
}
246+
}
247+
]
248+
} as unknown as IBarChartSpec);
249+
250+
const getCustomGroupGraphic = (chart: VChart) => {
251+
const mark = (chart.getChart() as any).getAllMarks().find((m: IMark) => m.name === 'customGroup');
252+
253+
expect(mark).toBeDefined();
254+
if (!mark) {
255+
throw new Error('Expected custom group mark to exist');
256+
}
257+
258+
const group = mark.getGraphics?.()[0] as AnimatedGraphic;
259+
260+
expect(group).toBeDefined();
261+
if (!group) {
262+
throw new Error('Expected custom group graphic to exist');
263+
}
264+
265+
return group;
266+
};
267+
221268
const getBarGraphicByDatum = (chart: VChart, predicate: (datum: any) => boolean) => {
222269
const bar = getBarGraphics(chart).find(graphic => predicate(getGraphicDatum(graphic)));
223270

@@ -308,6 +355,25 @@ const getBarClipPathRects = (chart: VChart) =>
308355

309356
const getBarClipPathGraphics = (chart: VChart) => (getBarMarkProduct(chart).attribute.path ?? []) as AnimatedGraphic[];
310357

358+
const getPieGraphics = (chart: VChart) => {
359+
const model = chart.getChart() as IChart;
360+
const pieSeries = model.getAllSeries().find((series: ISeries) => series.type === 'pie');
361+
362+
expect(pieSeries).toBeDefined();
363+
if (!pieSeries) {
364+
throw new Error('Expected pie series to exist');
365+
}
366+
367+
const pieMark = pieSeries.getMarks().find((mark: IMark) => mark.name === 'pie');
368+
369+
expect(pieMark).toBeDefined();
370+
if (!pieMark) {
371+
throw new Error('Expected pie mark to exist');
372+
}
373+
374+
return pieMark.getGraphics() as AnimatedGraphic[];
375+
};
376+
311377
const clickLegendItem = (chart: VChart, index: number) => {
312378
const legendModel = chart.getComponents().find((component: any) => component.type === 'discreteLegend') as any;
313379
const legendComponent = legendModel?._legendComponent;
@@ -469,6 +535,57 @@ const createSeriesChangeDocBarSpec = (mode: 'grouped' | 'single') => {
469535
} as unknown as IBarChartSpec;
470536
};
471537

538+
const createPieLegendFilterSpec = (): IPieChartSpec =>
539+
({
540+
type: 'pie',
541+
width: 500,
542+
height: 500,
543+
padding: 0,
544+
data: [
545+
{
546+
id: 'id0',
547+
values: [
548+
{ group: '0', value: 455, labelValue: '455', dataIndex: 0, seriesIndex: 0, name: '满意' },
549+
{ group: '0', value: 655, labelValue: '655', dataIndex: 1, seriesIndex: 0, name: '一般' },
550+
{ group: '0', value: 160, labelValue: '160', dataIndex: 2, seriesIndex: 0, name: '差评' }
551+
]
552+
}
553+
],
554+
categoryField: 'dataIndex',
555+
valueField: 'value',
556+
startAngle: -90,
557+
endAngle: -90,
558+
animation: true,
559+
animationAppear: {
560+
duration: APPEAR_DURATION,
561+
easing: 'linear'
562+
},
563+
animationUpdate: false,
564+
animationEnter: false,
565+
animationExit: false,
566+
animationDisappear: false,
567+
legends: {
568+
orient: 'bottom',
569+
position: 'middle',
570+
visible: true,
571+
allowAllCanceled: false,
572+
item: {
573+
visible: true
574+
}
575+
},
576+
pie: {
577+
state: {
578+
hover: {
579+
outerRadius: 1.06
580+
}
581+
},
582+
style: {
583+
cursor: 'pointer',
584+
lineWidth: 2
585+
}
586+
}
587+
} as unknown as IPieChartSpec);
588+
472589
const createLineGrowthSpec = (values: Array<{ time: string; value: number }>) =>
473590
({
474591
type: 'line',
@@ -1282,6 +1399,89 @@ const hasRenderableBarGeometry = (graphic: AnimatedGraphic) => {
12821399
};
12831400

12841401
describe('manual ticker animation regressions', () => {
1402+
it('keeps custom group final attributes after a prevented update animation', () => {
1403+
const { container, dom } = createChartContainer();
1404+
const ticker = createManualTicker();
1405+
const chart = new VChart(createCustomGroupSpec(20), {
1406+
dom,
1407+
ticker,
1408+
animation: true
1409+
});
1410+
1411+
chart.renderSync();
1412+
1413+
try {
1414+
ticker.tickAt(APPEAR_DURATION + 50);
1415+
1416+
chart.updateSpecSync(createCustomGroupSpec(80));
1417+
1418+
const group = getCustomGroupGraphic(chart);
1419+
1420+
expectClose(group.attribute.x, 80);
1421+
expectClose(group.baseAttributes?.x, 80);
1422+
expectClose(getGraphicFinalAttribute(group).x, 80);
1423+
} finally {
1424+
chart.release();
1425+
ticker.release();
1426+
removeDom(container);
1427+
}
1428+
});
1429+
1430+
it('keeps pie arc angles stable after legend filtering and hover state changes', () => {
1431+
const { container, dom } = createChartContainer();
1432+
const ticker = createManualTicker();
1433+
const chart = new VChart(createPieLegendFilterSpec(), {
1434+
dom,
1435+
ticker,
1436+
animation: true
1437+
});
1438+
1439+
chart.renderSync();
1440+
1441+
try {
1442+
ticker.tickAt(APPEAR_DURATION + 50);
1443+
1444+
chart.setLegendSelectedDataByIndex(0, [0, 1]);
1445+
chart.renderSync();
1446+
1447+
const updateStart = ticker.getTime();
1448+
ticker.tickAt(updateStart + UPDATE_DURATION + 50);
1449+
1450+
const secondPie = getPieGraphics(chart).find(graphic => graphic.context.data[0]?.dataIndex === 1);
1451+
const expectedStartAngle = -Math.PI / 2 + (Math.PI * 2 * 455) / (455 + 655);
1452+
const expectedEndAngle = -Math.PI / 2 + Math.PI * 2;
1453+
1454+
expect(secondPie).toBeDefined();
1455+
if (!secondPie) {
1456+
throw new Error('Expected second pie graphic to exist');
1457+
}
1458+
1459+
expectClose(secondPie.attribute.startAngle, expectedStartAngle);
1460+
expectClose(secondPie.attribute.endAngle, expectedEndAngle);
1461+
expectClose(secondPie.baseAttributes?.startAngle, expectedStartAngle);
1462+
expectClose(secondPie.baseAttributes?.endAngle, expectedEndAngle);
1463+
expectClose(getGraphicFinalAttribute(secondPie).startAngle, expectedStartAngle);
1464+
expectClose(getGraphicFinalAttribute(secondPie).endAngle, expectedEndAngle);
1465+
1466+
secondPie.useStates(['hover']);
1467+
expectClose(secondPie.attribute.startAngle, expectedStartAngle);
1468+
expectClose(secondPie.attribute.endAngle, expectedEndAngle);
1469+
1470+
ticker.tickAt(ticker.getTime() + UPDATE_DURATION + 50);
1471+
1472+
expectClose(secondPie.attribute.startAngle, expectedStartAngle);
1473+
expectClose(secondPie.attribute.endAngle, expectedEndAngle);
1474+
expectClose(secondPie.baseAttributes?.startAngle, expectedStartAngle);
1475+
expectClose(secondPie.baseAttributes?.endAngle, expectedEndAngle);
1476+
expectClose(getGraphicFinalAttribute(secondPie).startAngle, expectedStartAngle);
1477+
expectClose(getGraphicFinalAttribute(secondPie).endAngle, expectedEndAngle);
1478+
} finally {
1479+
chart.release();
1480+
ticker.release();
1481+
removeDom(container);
1482+
}
1483+
});
1484+
12851485
it('runs word cloud scaleIn appear from zero scale', () => {
12861486
const { container, dom } = createChartContainer();
12871487
const ticker = createManualTicker();

0 commit comments

Comments
 (0)