diff --git a/__tests__/data/circle-packing.ts b/__tests__/data/circle-packing.ts new file mode 100644 index 0000000000..131d728c1f --- /dev/null +++ b/__tests__/data/circle-packing.ts @@ -0,0 +1,131 @@ +export const DATA = { + name: 'root', + children: [ + { + name: 'Drama', + value: 1046790, + }, + { + name: 'Comedy', + value: 1039358, + }, + { + name: 'Documentary', + value: 461880, + }, + { + name: 'News', + value: 308136, + }, + { + name: 'Talk-Show', + value: 270578, + }, + { + name: 'Action', + value: 226334, + }, + { + name: 'Animation', + value: 197342, + }, + { + name: 'Reality-TV', + value: 189739, + }, + { + name: 'Crime', + value: 175272, + }, + { + name: 'Family', + value: 150621, + }, + { + name: 'Short', + value: 138255, + }, + { + name: 'Adventure', + value: 121216, + }, + { + name: 'Game-Show', + value: 119912, + }, + { + name: 'Music', + value: 102488, + }, + { + name: 'Adult', + value: 90157, + }, + { + name: 'Biography', + value: 59307, + }, + { + name: 'Sport', + value: 58999, + }, + { + name: 'Romance', + value: 52776, + }, + { + name: 'Horror', + value: 50800, + }, + { + name: 'Fantasy', + value: 22614, + }, + { + name: 'Sci-Fi', + value: 22026, + }, + { + name: 'Thriller', + value: 19706, + }, + { + name: 'Mystery', + value: 18274, + }, + { + name: 'History', + value: 16108, + }, + { + name: 'Western', + value: 12535, + }, + { + name: 'Musical', + value: 12240, + }, + { + name: 'War', + value: 1992, + }, + { + name: 'Film-Noir', + value: 12240 + 1992 + 1992, + children: [ + { + name: 'Musical', + value: 12240, + }, + { + name: 'War', + value: 1992, + }, + { + name: 'Film', + value: 1992, + }, + ], + }, + ], +}; diff --git a/__tests__/unit/plots/circle-packing/index-spec.ts b/__tests__/unit/plots/circle-packing/index-spec.ts new file mode 100644 index 0000000000..5e2e8733b3 --- /dev/null +++ b/__tests__/unit/plots/circle-packing/index-spec.ts @@ -0,0 +1,130 @@ +import { CirclePacking } from '../../../../src'; +import { createDiv } from '../../../utils/dom'; +import { DATA } from '../../../data/circle-packing'; +import { DEFAULT_OPTIONS } from '../../../../src/plots/circle-packing/constant'; + +describe('Circle-Packing', () => { + const div = createDiv(); + const diameter = 500; + const plot = new CirclePacking(div, { + width: diameter, + height: diameter, + autoFit: false, + data: DATA, + sizeField: 'r', + size: ({ r }) => r * diameter, + legend: false, + hierarchyConfig: { + sort: (a, b) => b.depth - a.depth, + }, + }); + plot.render(); + + it('default', () => { + expect(plot.type).toBe('circle-packing'); + // @ts-ignore + expect(plot.getDefaultOptions()).toBe(CirclePacking.getDefaultOptions()); + + const geometry = plot.chart.geometries[0]; + expect(geometry.type).toBe('point'); + + const positionFields = geometry.getAttribute('position').getFields(); + expect(geometry.elements.length).toBe(geometry.data.length); + expect(positionFields).toHaveLength(2); + expect(positionFields).toEqual(['x', 'y']); + }); + + it('color', () => { + plot.update({ color: ['red', 'green', 'blue'] }); + + const geometry = plot.chart.geometries[0]; + const elements = geometry.elements; + expect(elements.length).toBe(plot.chart.getData().length); + + // 绘图数据 + expect(elements[0].getModel().color).toBe('red'); + expect(elements[1].getModel().color).toBe('green'); + expect(elements[7].getModel().color).toBe('green'); + expect(elements[14].getModel().color).toBe('blue' /** 15 % 3 === 0 */); + }); + + it('style', () => { + plot.update({ pointStyle: { fill: 'red', fillOpacity: 1 } }); + + const geometry = plot.chart.geometries[0]; + let elements = geometry.elements; + expect(elements.length).toBe(plot.chart.getData().length); + + // 绘图数据 + expect(elements[0].shape.attr('fillOpacity')).toBe(1); + expect(elements[1].shape.attr('fillOpacity')).toBe(1); + expect(elements[1].shape.attr('fill')).toBe('red'); + expect(elements[7].shape.attr('fillOpacity')).toBe(1); + expect(elements[13].shape.attr('fillOpacity')).toBe(1); + expect(elements[14].shape.attr('fillOpacity')).toBe(1); + + // callback + plot.update({ + rawFields: ['depth'], + pointStyle: ({ depth }) => ({ + fill: 'red', + fillOpacity: depth > 1 ? 1 : 0.5, + stroke: 'green', + lineWidth: depth, + }), + }); + elements = plot.chart.geometries[0].elements; + // 绘图数据 + expect(elements[0].shape.attr('fillOpacity')).toBe(0.5); + expect(elements[0].shape.attr('stroke')).toBe('green'); + + expect(elements[0].shape.attr('fillOpacity')).toBe(0.5); + expect(elements[elements.length - 1].shape.attr('fillOpacity')).toBe(1); + + expect(elements[0].shape.attr('lineWidth')).toBe(0); + expect(elements[1].shape.attr('lineWidth')).toBe(1); + expect(elements[elements.length - 1].shape.attr('lineWidth')).toBe(2); + }); + + it('label', () => { + let geometry = plot.chart.geometries[0]; + let labelGroup = plot.chart.geometries[0].labelsContainer.getChildren()[0]; + expect(typeof plot.chart.geometries[0].labelOption).toBe('object'); + // @ts-ignore + expect(labelGroup.getChildByIndex(0).attr('text')).toBe(DATA.name); + // @ts-ignore + expect(plot.chart.geometries[0].labelsContainer.getChildren()[1].getChildByIndex(0).attr('text')).toBe( + DATA.children[0].name + ); + + plot.update({ label: { fields: ['value'] } }); + labelGroup = plot.chart.geometries[0].labelsContainer.getChildren()[0]; + const filterData = plot.chart.getData(); + // @ts-ignore + expect(labelGroup.getChildByIndex(0).attr('text')).toBe(`${filterData[0].value}`); + + // meta + plot.update({ meta: { value: { formatter: (v) => v + '%' } } }); + labelGroup = plot.chart.geometries[0].labelsContainer.getChildren()[0]; + // @ts-ignore + expect(labelGroup.getChildByIndex(0).attr('text')).toBe(`${filterData[0].value}%`); + + // formatter + plot.update({ label: { formatter: () => 'xxx' } }); + geometry = plot.chart.geometries[0]; + // @ts-ignore + expect(geometry.labelsContainer.getChildren()[0].getChildByIndex(0).attr('text')).toBe('xxx'); + + // 关闭 + plot.update({ label: false }); + expect(plot.chart.geometries[0].labelOption).toBe(false); + }); + + it('defaultOptions 保持从 constants 中获取', () => { + expect(CirclePacking.getDefaultOptions()).toEqual(DEFAULT_OPTIONS); + }); + + afterAll(() => { + plot.destroy(); + }); +});