Skip to content

Commit

Permalink
feat(venn): 韦恩图增加 sizeField 和 setsField
Browse files Browse the repository at this point in the history
  • Loading branch information
visiky committed Sep 6, 2021
1 parent a89873a commit 1583648
Show file tree
Hide file tree
Showing 9 changed files with 38 additions and 50 deletions.
2 changes: 2 additions & 0 deletions examples/more-plots/venn/demo/basic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ const plot = new Venn('container', {
{ sets: ['B', 'C'], size: 2, label: 'B&C' },
{ sets: ['A', 'B', 'C'], size: 1 },
],
setsField: 'sets',
sizeField: 'size',
pointStyle: { fillOpacity: 0.85 },
});
plot.render();
2 changes: 2 additions & 0 deletions examples/more-plots/venn/demo/blend-mode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ const plot = new Venn('container', {
{ sets: ['B', 'C'], size: 2, label: 'B&C' },
{ sets: ['A', 'B', 'C'], size: 1 },
],
setsField: 'sets',
sizeField: 'size',
// more blendMode to see: https://gka.github.io/chroma.js/#chroma-blend
blendMode: 'overlay',
pointStyle: { fillOpacity: 0.85 },
Expand Down
3 changes: 2 additions & 1 deletion examples/more-plots/venn/demo/customize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ fetch('https://gw.alipayobjects.com/os/antfincdn/yzC3ZiBbhM/venn-data.json')
const sum = data.reduce((a, b) => a + b.size, 0);
const toPercent = (p) => `${(p * 100).toFixed(2)}%`;
const plot = new Venn('container', {
appendPadding: [10, 20, 40, 20],
setsField: 'sets',
sizeField: 'size',
data,
pointStyle: { fillOpacity: 0.85 },
color: ['#9DF5CA', '#61DDAA', '#42C090'],
Expand Down
2 changes: 2 additions & 0 deletions examples/more-plots/venn/demo/label.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ const plot = new Venn('container', {
{ sets: ['B', 'C'], size: 2, label: 'B&C' },
{ sets: ['A', 'B', 'C'], size: 1, label: 'A&B&C' },
],
setsField: 'sets',
sizeField: 'size',
pointStyle: { fillOpacity: 0.85 },
label: {
offsetY: 7,
Expand Down
2 changes: 2 additions & 0 deletions examples/more-plots/venn/demo/tooltip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ const plot = new Venn('container', {
{ sets: ['B', 'C'], size: 2, label: 'B&C' },
{ sets: ['A', 'B', 'C'], size: 1, label: 'A&B&C' },
],
setsField: 'sets',
sizeField: 'size',
pointStyle: { fillOpacity: 0.85 },
tooltip: {
fields: ['label', 'size'],
Expand Down
35 changes: 10 additions & 25 deletions src/plots/venn/adaptor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { deepAssign, flow, getAdjustAppendPadding, normalPadding } from '../../u
import { Datum } from '../../types';
import { getColorMap, layoutVennData } from './utils';
import { CustomInfo, VennData, VennOptions } from './types';
import { ID_FIELD, SETS_FIELD, SIZE_FIELD, RAW_FIELDS } from './constant';
import { ID_FIELD } from './constant';
import './shape';

/** 图例默认预留空间 */
Expand All @@ -18,33 +18,20 @@ export const LEGEND_SPACE = 40;
*/
function transformColor(params: Params<VennOptions>, data: VennData): VennOptions['color'] {
const { chart, options } = params;
const { color, blendMode = 'multiply' } = options;
const { color, blendMode = 'multiply', setsField } = options;

if (typeof color !== 'function') {
let colorPalette = typeof color === 'string' ? [color] : color;
if (!isArray(colorPalette)) {
const { colors10, colors20 } = chart.getTheme();
colorPalette = data.filter((d) => d[SETS_FIELD].length === 1).length <= 10 ? colors10 : colors20;
colorPalette = data.filter((d) => d[setsField].length === 1).length <= 10 ? colors10 : colors20;
}
const colorMap = getColorMap(colorPalette, [...data], blendMode);
const colorMap = getColorMap(colorPalette, data, options);
return (datum: Datum) => colorMap.get(datum[ID_FIELD]) || colorPalette[0];
}
return color;
}

/**
* 处理默认配置项
*/
function defaultOptions(params: Params<VennOptions>): Params<VennOptions> {
const { options } = params;
const { data } = options;
// 进行排序,mutable。避免 图形元素遮挡
data.sort((a, b) => a[SETS_FIELD].length - b[SETS_FIELD].length);

// todo 可以在这里处理下非法数据输入,避免直接 crash
return params;
}

/**
* 处理 padding
*/
Expand All @@ -69,7 +56,7 @@ function padding(params: Params<VennOptions>): Params<VennOptions> {
*/
function geometry(params: Params<VennOptions>): Params<VennOptions> {
const { chart, options } = params;
const { data, pointStyle, label } = options;
const { data, pointStyle, label, setsField, sizeField } = options;

// 获取容器大小
const [t, r, b, l] = normalPadding(chart.appendPadding);
Expand All @@ -78,17 +65,17 @@ function geometry(params: Params<VennOptions>): Params<VennOptions> {
// coordinateBBox + appendPadding = viewBBox, 不需要再计算 appendPadding 部分,因此直接使用 viewBBox
const { width, height } = chart.viewBBox;

const vennData: VennData = layoutVennData(data, width - (r + l), height - (t + b), 0);
const vennData: VennData = layoutVennData(options, width - (r + l), height - (t + b), 0);
chart.data(vennData);

const { ext } = schemaGeometry(
deepAssign({}, params, {
options: {
xField: 'x',
yField: 'y',
sizeField: SIZE_FIELD,
sizeField: sizeField,
seriesField: ID_FIELD,
rawFields: RAW_FIELDS,
rawFields: [setsField, sizeField],
// 不使用 G2 的label,直接在自定义 shape 中实现
label: false,
schema: {
Expand All @@ -112,11 +99,11 @@ function geometry(params: Params<VennOptions>): Params<VennOptions> {
*/
export function legend(params: Params<VennOptions>): Params<VennOptions> {
const { chart, options } = params;
const { legend } = options;
const { legend, sizeField } = options;

chart.legend(ID_FIELD, legend);
// 强制不开启 连续图例
chart.legend(SIZE_FIELD, false);
chart.legend(sizeField, false);

return params;
}
Expand All @@ -140,8 +127,6 @@ export function axis(params: Params<VennOptions>): Params<VennOptions> {
export function adaptor(params: Params<VennOptions>) {
// flow 的方式处理所有的配置到 G2 API
return flow(
// 先处理默认配置项,再处理主题
defaultOptions,
padding,
theme,
geometry,
Expand Down
5 changes: 0 additions & 5 deletions src/plots/venn/constant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,8 @@ import { VennOptions } from './types';

// 一些字段常量定义,需要在文档初告知用户
export const ID_FIELD = 'id';
export const SETS_FIELD = 'sets';
export const SIZE_FIELD = 'size';
export const PATH_FIELD = 'path';

/** 源数据字段 */
export const RAW_FIELDS = ['sets', 'size'];

/**
* 韦恩图 默认配置项
*/
Expand Down
7 changes: 3 additions & 4 deletions src/plots/venn/types.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import { Types } from '@antv/g2';
import { Options, StyleAttr } from '../../types';
import { ID_FIELD, PATH_FIELD, SETS_FIELD, SIZE_FIELD } from './constant';
import { ID_FIELD, PATH_FIELD } from './constant';

export type VennDatum = Types.Datum & { [SETS_FIELD]: string[]; [SIZE_FIELD]: number };
export type VennData = (VennDatum & { [PATH_FIELD]: string; [ID_FIELD]: string })[];
export type VennData = (Types.Datum & { sets: string[]; [PATH_FIELD]: string; [ID_FIELD]: string })[];

/** 配置类型定义 */
export interface VennOptions extends Options {
/** 韦恩图 数据 */
readonly data: VennDatum[];
readonly data: Types.Datum[];
/** 集合字段 */
readonly setsField: string;
/** 大小字段 */
Expand Down
30 changes: 15 additions & 15 deletions src/plots/venn/utils.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { assign, clone, memoize } from '@antv/util';
import { assign, memoize } from '@antv/util';
import { blend } from '../../utils/color/blend';
import { venn, scaleSolution } from './layout/layout';
import { circlePath, intersectionAreaPath, computeTextCentres } from './layout/diagram';
import { ID_FIELD, PATH_FIELD, SETS_FIELD } from './constant';
import { ID_FIELD, PATH_FIELD } from './constant';
import { VennData, VennOptions } from './types';

/**
Expand All @@ -12,17 +12,16 @@ import { VennData, VennOptions } from './types';
* @returns Map<string, string>
*/
export const getColorMap = memoize(
(colorPalette: string[], data: VennData, blendMode: string) => {
(colorPalette: string[], data: VennData, options: VennOptions) => {
const { blendMode, setsField } = options;
const colorMap = new Map<string /** id */, string /** color */>();
const colorPaletteLen = colorPalette.length;
// 排序,mutable
data.sort((a, b) => a[SETS_FIELD].length - b[SETS_FIELD].length);
data.forEach((d, idx) => {
if (d[SETS_FIELD].length === 1) {
if (d[setsField].length === 1) {
colorMap.set(d[ID_FIELD], colorPalette[(idx + colorPaletteLen) % colorPaletteLen]);
} else {
/** 一般都是可以获取到颜色的,如果不正确 就是输入了非法数据 */
const colorArr = d[SETS_FIELD].map((id) => colorMap.get(id));
const colorArr = d[setsField].map((id) => colorMap.get(id));
colorMap.set(
d[ID_FIELD],
colorArr.slice(1).reduce((a, b) => blend(a, b, blendMode), colorArr[0])
Expand All @@ -44,18 +43,19 @@ export const getColorMap = memoize(
* @param padding
* @returns 韦恩图数据
*/
export function layoutVennData(
data: VennOptions['data'],
width: number,
height: number,
padding: number = 0
): VennData {
const vennData: VennData = clone(data);
export function layoutVennData(options: VennOptions, width: number, height: number, padding: number = 0): VennData {
const { data, setsField, sizeField } = options;

const vennData: VennData = data.map((d) => ({ ...d, sets: d[setsField] || [], size: d[sizeField] }));
// 1. 进行排序,避免图形元素遮挡
vennData.sort((a, b) => a.sets.length - b.sets.length);
// todo 2. 可以在这里处理下非法数据输入,避免直接 crash

const solution = venn(vennData);
const circles = scaleSolution(solution, width, height, padding);
const textCenters = computeTextCentres(circles, vennData);
vennData.forEach((row) => {
const sets = row[SETS_FIELD];
const sets = row.sets;
const id = sets.join(',');
row[ID_FIELD] = id;
if (sets.length === 1) {
Expand Down

0 comments on commit 1583648

Please sign in to comment.