-
Notifications
You must be signed in to change notification settings - Fork 605
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat(venn): 初始化韦恩图 * feat(venn): 韦恩图支持 meta 设置 * refactor(venn): 重构韦恩图的color字段 * feat(venn): 韦恩图颜色叠加问题 * docs(venn): 补充韦恩图 demo * feat(venn): 韦恩图抽取一些字段常量 & 增加图例配置 * feat(venn): 韦恩图默认配置项 * feat(venn): 处理下韦恩图布局 padding 等问题 * fix(venn): 修复韦恩图绘制问题,G 对小写 a 绘制会有问题 * feat(venn): 韦恩图 tooltip 设置 * feat(venn): 韦恩图支持 label 展示 * docs(venn): 丰富韦恩图 demo * docs(venn): 丰富韦恩图 tooltip 展示 demo * refactor(venn): 韦恩图布局相关的算法从 js 文件改造为 ts 文件 * test(venn): 添加韦恩图基础单测 * fix(venn): 修复韦恩图布局大小问题 & 添加单测 * chore: 包大小又增加了 * fix(venn): 修复韦恩图单测错误 * test(venn): 补充单测 * refactor(color-blend): 重构韦恩图颜色叠加工具方法 * docs(venn): 韦恩图 demo 移除 appendPadding 设置,内置为默认配置项 * feat(venn): 韦恩图增加 sizeField 和 setsField * test(utils): 补充单测 * test: venn图的基础配置的单测和文档 (#2836) * test: venn图的基础配置的单测和文档 * refactor: 处理lint警告,删除暂无用变量 * test: 补充和修改单测的写法 Co-authored-by: 酥云 <lisuwen.lsw@antgroup.com> * refactor(padding): venn图增加padding配置项 (#2838) * refactor(padding): venn图增加padding配置项 * refactor(padding): 把resolveAllPadding方法抽成公共utils,重新处理venn的padding * refactor(padding): 去掉多余的normalPadding方法 Co-authored-by: 酥云 <lisuwen.lsw@antgroup.com> * refactor(blend): 优化颜色叠加计算 (#2837) * refactor(blend): 优化颜色叠加计算 * test(blend): 补充blend的单测 * refactor: 调整打包限制的大小 * refactor(blend): 删除nameToHex工具,使用color-utils Co-authored-by: 酥云 <lisuwen.lsw@antgroup.com> Co-authored-by: Susan <527971893@qq.com> Co-authored-by: 酥云 <lisuwen.lsw@antgroup.com>
- Loading branch information
1 parent
d1e1a52
commit e2b84c6
Showing
39 changed files
with
3,008 additions
and
30 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
import { Venn } from '../../../../src'; | ||
import { createDiv } from '../../../utils/dom'; | ||
|
||
describe('venn: blendMode', () => { | ||
const plot = new Venn(createDiv(), { | ||
data: [ | ||
{ sets: ['A'], size: 12, label: 'A' }, | ||
{ sets: ['B'], size: 12, label: 'B' }, | ||
{ sets: ['C'], size: 12, label: 'C' }, | ||
{ sets: ['A', 'B'], size: 2, label: 'A&B' }, | ||
{ sets: ['A', 'C'], size: 2, label: 'A&C' }, | ||
{ sets: ['B', 'C'], size: 2, label: 'B&C' }, | ||
], | ||
width: 400, | ||
height: 500, | ||
setsField: 'sets', | ||
sizeField: 'size', | ||
color: ['red', 'lime', 'blue'], | ||
legend: false, | ||
}); | ||
plot.render(); | ||
|
||
it('blendMode: default multiply', () => { | ||
plot.update({ blendMode: 'multiply' }); | ||
|
||
expect(plot.chart.geometries[0].elements[0].getModel().color).toBe('red'); | ||
expect(plot.chart.geometries[0].elements[1].getModel().color).toBe('lime'); | ||
expect(plot.chart.geometries[0].elements[2].getModel().color).toBe('blue'); | ||
expect(plot.chart.geometries[0].elements[3].getModel().color).toBe('rgba(0, 0, 0, 1)'); // 交集元素 | ||
expect(plot.chart.geometries[0].elements[4].getModel().color).toBe('rgba(0, 0, 0, 1)'); | ||
expect(plot.chart.geometries[0].elements[5].getModel().color).toBe('rgba(0, 0, 0, 1)'); | ||
}); | ||
|
||
it('blendMode: normal', () => { | ||
plot.update({ blendMode: 'normal' }); | ||
|
||
expect(plot.chart.geometries[0].elements[0].getModel().color).toBe('red'); | ||
expect(plot.chart.geometries[0].elements[1].getModel().color).toBe('lime'); | ||
expect(plot.chart.geometries[0].elements[2].getModel().color).toBe('blue'); | ||
expect(plot.chart.geometries[0].elements[3].getModel().color).toBe('rgba(255, 0, 0, 1)'); // 交集元素 | ||
expect(plot.chart.geometries[0].elements[4].getModel().color).toBe('rgba(255, 0, 0, 1)'); | ||
expect(plot.chart.geometries[0].elements[5].getModel().color).toBe('rgba(0, 255, 0, 1)'); | ||
}); | ||
|
||
it('blendMode: darken', () => { | ||
plot.update({ blendMode: 'darken' }); | ||
|
||
expect(plot.chart.geometries[0].elements[0].getModel().color).toBe('red'); | ||
expect(plot.chart.geometries[0].elements[1].getModel().color).toBe('lime'); | ||
expect(plot.chart.geometries[0].elements[2].getModel().color).toBe('blue'); | ||
expect(plot.chart.geometries[0].elements[3].getModel().color).toBe('rgba(0, 0, 0, 1)'); // 交集元素 | ||
expect(plot.chart.geometries[0].elements[4].getModel().color).toBe('rgba(0, 0, 0, 1)'); | ||
expect(plot.chart.geometries[0].elements[5].getModel().color).toBe('rgba(0, 0, 0, 1)'); | ||
}); | ||
|
||
it('blendMode: lighten', () => { | ||
plot.update({ blendMode: 'lighten' }); | ||
|
||
expect(plot.chart.geometries[0].elements[0].getModel().color).toBe('red'); | ||
expect(plot.chart.geometries[0].elements[1].getModel().color).toBe('lime'); | ||
expect(plot.chart.geometries[0].elements[2].getModel().color).toBe('blue'); | ||
expect(plot.chart.geometries[0].elements[3].getModel().color).toBe('rgba(255, 255, 0, 1)'); // 交集元素 | ||
expect(plot.chart.geometries[0].elements[4].getModel().color).toBe('rgba(255, 0, 255, 1)'); | ||
expect(plot.chart.geometries[0].elements[5].getModel().color).toBe('rgba(0, 255, 255, 1)'); | ||
}); | ||
|
||
it('blendMode: screen', () => { | ||
plot.update({ blendMode: 'screen' }); | ||
|
||
expect(plot.chart.geometries[0].elements[0].getModel().color).toBe('red'); | ||
expect(plot.chart.geometries[0].elements[1].getModel().color).toBe('lime'); | ||
expect(plot.chart.geometries[0].elements[2].getModel().color).toBe('blue'); | ||
expect(plot.chart.geometries[0].elements[3].getModel().color).toBe('rgba(255, 255, 0, 1)'); // 交集元素 | ||
expect(plot.chart.geometries[0].elements[4].getModel().color).toBe('rgba(255, 0, 255, 1)'); | ||
expect(plot.chart.geometries[0].elements[5].getModel().color).toBe('rgba(0, 255, 255, 1)'); | ||
}); | ||
|
||
it('blendMode: overlay', () => { | ||
plot.update({ blendMode: 'overlay' }); | ||
|
||
expect(plot.chart.geometries[0].elements[0].getModel().color).toBe('red'); | ||
expect(plot.chart.geometries[0].elements[1].getModel().color).toBe('lime'); | ||
expect(plot.chart.geometries[0].elements[2].getModel().color).toBe('blue'); | ||
expect(plot.chart.geometries[0].elements[3].getModel().color).toBe('rgba(0, 255, 0, 1)'); // 交集元素 | ||
expect(plot.chart.geometries[0].elements[4].getModel().color).toBe('rgba(0, 0, 255, 1)'); | ||
expect(plot.chart.geometries[0].elements[5].getModel().color).toBe('rgba(0, 0, 255, 1)'); | ||
}); | ||
|
||
it('blendMode: burn', () => { | ||
plot.update({ blendMode: 'burn' }); | ||
|
||
expect(plot.chart.geometries[0].elements[0].getModel().color).toBe('red'); | ||
expect(plot.chart.geometries[0].elements[1].getModel().color).toBe('lime'); | ||
expect(plot.chart.geometries[0].elements[2].getModel().color).toBe('blue'); | ||
expect(plot.chart.geometries[0].elements[3].getModel().color).toBe('rgba(0, 255, 0, 1)'); // 交集元素 | ||
expect(plot.chart.geometries[0].elements[4].getModel().color).toBe('rgba(0, 0, 255, 1)'); | ||
expect(plot.chart.geometries[0].elements[5].getModel().color).toBe('rgba(0, 0, 255, 1)'); | ||
}); | ||
|
||
it('blendMode: dodge', () => { | ||
plot.update({ blendMode: 'dodge' }); | ||
|
||
expect(plot.chart.geometries[0].elements[0].getModel().color).toBe('red'); | ||
expect(plot.chart.geometries[0].elements[1].getModel().color).toBe('lime'); | ||
expect(plot.chart.geometries[0].elements[2].getModel().color).toBe('blue'); | ||
expect(plot.chart.geometries[0].elements[3].getModel().color).toBe('rgba(255, 255, 0, 1)'); // 交集元素 | ||
expect(plot.chart.geometries[0].elements[4].getModel().color).toBe('rgba(255, 0, 255, 1)'); | ||
expect(plot.chart.geometries[0].elements[5].getModel().color).toBe('rgba(0, 255, 255, 1)'); | ||
}); | ||
|
||
afterAll(() => { | ||
plot.destroy(); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
import { Venn } from '../../../../src'; | ||
import { createDiv } from '../../../utils/dom'; | ||
|
||
describe('venn: color', () => { | ||
const plot = new Venn(createDiv(), { | ||
data: [ | ||
{ sets: ['A'], size: 12, label: 'A' }, | ||
{ sets: ['B'], size: 12, label: 'B' }, | ||
{ sets: ['C'], size: 12, label: 'C' }, | ||
{ sets: ['A', 'B'], size: 2, label: 'A&B' }, | ||
{ sets: ['A', 'C'], size: 2, label: 'A&C' }, | ||
{ sets: ['B', 'C'], size: 2, label: 'B&C' }, | ||
], | ||
width: 400, | ||
height: 500, | ||
setsField: 'sets', | ||
sizeField: 'size', | ||
// default blendMode: 'multiply', | ||
legend: false, | ||
}); | ||
plot.render(); | ||
|
||
it('color: string', () => { | ||
plot.update({ color: 'red' }); | ||
|
||
expect(plot.chart.geometries[0].elements[0].getModel().color).toBe('red'); | ||
expect(plot.chart.geometries[0].elements[1].getModel().color).toBe('red'); | ||
expect(plot.chart.geometries[0].elements[2].getModel().color).toBe('red'); | ||
expect(plot.chart.geometries[0].elements[3].getModel().color).toBe('rgba(255, 0, 0, 1)'); // 交集元素 | ||
expect(plot.chart.geometries[0].elements[4].getModel().color).toBe('rgba(255, 0, 0, 1)'); | ||
expect(plot.chart.geometries[0].elements[5].getModel().color).toBe('rgba(255, 0, 0, 1)'); | ||
}); | ||
|
||
it('color: array', () => { | ||
plot.update({ color: ['red', 'blue', 'yellow'] }); | ||
|
||
expect(plot.chart.geometries[0].elements[0].getModel().color).toBe('red'); | ||
expect(plot.chart.geometries[0].elements[1].getModel().color).toBe('blue'); | ||
expect(plot.chart.geometries[0].elements[2].getModel().color).toBe('yellow'); | ||
expect(plot.chart.geometries[0].elements[3].getModel().color).toBe('rgba(0, 0, 0, 1)'); // 交集元素 | ||
expect(plot.chart.geometries[0].elements[4].getModel().color).toBe('rgba(255, 0, 0, 1)'); | ||
expect(plot.chart.geometries[0].elements[5].getModel().color).toBe('rgba(0, 0, 0, 1)'); | ||
}); | ||
|
||
it('color: callback', () => { | ||
plot.update({ | ||
color: ({ size }) => { | ||
return size > 2 ? 'red' : 'blue'; | ||
}, | ||
}); | ||
|
||
expect(plot.chart.geometries[0].elements[0].getModel().color).toBe('red'); | ||
expect(plot.chart.geometries[0].elements[1].getModel().color).toBe('red'); | ||
expect(plot.chart.geometries[0].elements[2].getModel().color).toBe('red'); | ||
expect(plot.chart.geometries[0].elements[3].getModel().color).toBe('blue'); | ||
expect(plot.chart.geometries[0].elements[4].getModel().color).toBe('blue'); | ||
expect(plot.chart.geometries[0].elements[5].getModel().color).toBe('blue'); | ||
}); | ||
|
||
afterAll(() => { | ||
plot.destroy(); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import { Venn } from '../../../../src'; | ||
import { createDiv } from '../../../utils/dom'; | ||
|
||
describe('venn 异常分支处理', () => { | ||
const plot = new Venn(createDiv(), { | ||
width: 400, | ||
height: 500, | ||
setsField: 'sets', | ||
sizeField: 'size', | ||
data: [], | ||
}); | ||
|
||
it('并集中,出现不存在的集合', () => { | ||
function render() { | ||
plot.changeData([ | ||
{ sets: ['A'], size: 12, label: 'A' }, | ||
{ sets: ['B'], size: 12, label: 'B' }, | ||
{ sets: ['C'], size: 12, label: 'C' }, | ||
{ sets: ['A', 'B'], size: 2, label: 'A&B' }, | ||
{ sets: ['A', 'C'], size: 2, label: 'A&C' }, | ||
{ sets: ['B', 'D'], size: 2, label: 'B&C' }, | ||
{ sets: ['A', 'B', 'C'], size: 300 }, | ||
]); | ||
} | ||
// 下个 pr 再处理 | ||
expect(render).toThrowError(); | ||
}); | ||
|
||
afterAll(() => { | ||
plot.destroy(); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
import { IGroup } from '@antv/g-base'; | ||
import { Venn } from '../../../../src'; | ||
import { DEFAULT_OPTIONS } from '../../../../src/plots/venn/constant'; | ||
import { VennData } from '../../../../src/plots/venn/types'; | ||
import { createDiv } from '../../../utils/dom'; | ||
|
||
describe('venn', () => { | ||
const data1 = [{ sets: ['A'], size: 10, label: 'A' }]; | ||
|
||
const plot = new Venn(createDiv(), { | ||
width: 400, | ||
height: 500, | ||
setsField: 'sets', | ||
sizeField: 'size', | ||
data: data1, | ||
appendPadding: 0, | ||
legend: false, | ||
}); | ||
|
||
it('sets: 1个集合', () => { | ||
plot.render(); | ||
expect(plot.type).toBe('venn'); | ||
// @ts-ignore | ||
expect(plot.getDefaultOptions()).toEqual(Venn.getDefaultOptions()); | ||
|
||
// VennShape 已注册 | ||
const elements = plot.chart.geometries[0].elements; | ||
expect(elements[0].shapeFactory['venn']).toBeDefined(); | ||
|
||
expect(elements.length).toBe(1); | ||
expect((elements[0].getData() as any).size).toBe(10); | ||
// path: [['M', ...], ['A', rx ry 0 1 0 x y], ...] | ||
const path = (elements[0].shape as IGroup).getChildren()[0].attr('path'); | ||
const label = (elements[0].shape as IGroup).getChildren()[1]; | ||
expect(label.get('name')).toBe('venn-label'); | ||
expect(path[0][0]).toBe('M'); | ||
expect(path[1][0]).toBe('A'); | ||
expect(path[2][0]).toBe('A'); | ||
expect((elements[0].getData() as any).radius).toBe(400 / 2); | ||
expect(path[1][1]).toBe(400 / 2); | ||
}); | ||
|
||
it('sets: 2个集合 & changedata', () => { | ||
plot.changeData([ | ||
{ sets: ['A'], size: 10, label: 'A' }, | ||
{ sets: ['B'], size: 10, label: 'B' }, | ||
]); | ||
|
||
const elements = plot.chart.geometries[0].elements; | ||
|
||
expect(elements.length).toBe(2); | ||
expect(elements[0].getModel().size).toBe(1); | ||
expect(elements[1].getModel().size).toBe(1); | ||
// path: [['M', ...], ['A', rx ry 0 1 0 x y], ...] | ||
const path = (elements[0].shape as IGroup).getChildren()[0].attr('path'); | ||
const label = (elements[0].shape as IGroup).getChildren()[1]; | ||
expect(label.get('name')).toBe('venn-label'); | ||
expect(path[0][0]).toBe('M'); | ||
expect(path[1][0]).toBe('A'); | ||
expect(path[2][0]).toBe('A'); | ||
expect(path[1][1]).toBe(400 / 2 / 2); | ||
expect(path[1][6]).toBe(200); | ||
// 居中 | ||
expect(path[1][7]).toBe(500 / 2); | ||
|
||
const path1 = (elements[1].shape as IGroup).getChildren()[0].attr('path'); | ||
expect(path1[1][1]).toBe(400 / 2 / 2); | ||
expect(path1[1][6]).toBe(400); | ||
expect(path1[1][7]).toBe(500 / 2); | ||
}); | ||
|
||
it('sets: 2个集合 & exist intersection', () => { | ||
plot.changeData([ | ||
{ sets: ['A'], size: 10, label: 'A' }, | ||
{ sets: ['B'], size: 10, label: 'B' }, | ||
{ sets: ['A', 'B'], size: 4, label: 'A&B' }, | ||
]); | ||
|
||
const elements = plot.chart.geometries[0].elements; | ||
|
||
expect(elements.length).toBe(3); | ||
// 📒 size 的具体计算逻辑,可以再看下 | ||
expect((elements[0].getData() as any).size).toBe(10); | ||
expect((elements[1].getData() as any).size).toBe(10); | ||
expect((elements[2].getData() as any).size).toBe(4); | ||
// path: [['M', ...], ['A', rx ry 0 1 0 x y], ...] | ||
const path = (elements[0].shape as IGroup).getChildren()[0].attr('path'); | ||
const label = (elements[0].shape as IGroup).getChildren()[1]; | ||
expect(label.get('name')).toBe('venn-label'); | ||
expect(path[0][0]).toBe('M'); | ||
expect(path[1][0]).toBe('A'); | ||
expect(path[2][0]).toBe('A'); | ||
expect(path[1][1]).toBeGreaterThan(400 / 2 / 2); | ||
// 有交集,所以往前进一步 | ||
expect(path[1][6]).toBeGreaterThan(200); | ||
// 居中 | ||
expect(path[1][7]).toBeCloseTo(500 / 2); | ||
|
||
const path1 = (elements[1].shape as IGroup).getChildren()[0].attr('path'); | ||
expect(path1[1][1]).toBeGreaterThan(400 / 2 / 2); | ||
expect(path1[1][6]).toBeLessThan(400); | ||
expect(path1[1][7]).toBeCloseTo(500 / 2); | ||
}); | ||
|
||
it('sets: 3个集合 & exist intersection', () => { | ||
plot.changeData([ | ||
{ sets: ['A'], size: 12, label: 'A' }, | ||
{ sets: ['B'], size: 12, label: 'B' }, | ||
{ sets: ['C'], size: 12, label: 'C' }, | ||
{ sets: ['A', 'B'], size: 2, label: 'A&B' }, | ||
{ sets: ['A', 'C'], size: 2, label: 'A&C' }, | ||
{ sets: ['B', 'C'], size: 2, label: 'B&C' }, | ||
{ sets: ['A', 'B', 'C'], size: 1 }, | ||
]); | ||
|
||
const elements = plot.chart.geometries[0].elements; | ||
|
||
expect(elements.length).toBe(7); | ||
const path = (elements[0].shape as IGroup).getChildren()[0].attr('path'); | ||
|
||
expect(path[0][0]).toBe('M'); | ||
expect(path[1][0]).toBe('A'); | ||
expect(path[2][0]).toBe('A'); | ||
|
||
// 中心点 | ||
expect((elements[6].getData() as any).x).toBeCloseTo(200); | ||
// 元素对齐 | ||
expect(elements[2].getData().x).toBeCloseTo((elements[6].getData() as any).x); | ||
expect(elements[0].getData().y).toBeCloseTo((elements[1].getData() as any).y); | ||
}); | ||
|
||
it('defaultOptions 保持从 constants 中获取', () => { | ||
expect(Venn.getDefaultOptions()).toEqual(DEFAULT_OPTIONS); | ||
}); | ||
|
||
it('韦恩图数据结构类型定义 types & constants', () => { | ||
const vennData: VennData = [{ sets: [], size: 0, path: '', id: '' }]; | ||
expect(vennData).toBeDefined(); | ||
}); | ||
|
||
afterAll(() => { | ||
plot.destroy(); | ||
}); | ||
}); |
Oops, something went wrong.