From a2442fa51534a5be45d6d5465ce623a84cf6e62a Mon Sep 17 00:00:00 2001 From: "yelinlei.yll" Date: Fri, 17 Nov 2023 21:20:34 +0800 Subject: [PATCH 1/2] feat: add venn plots --- packages/plots/src/components/index.ts | 5 ++ packages/plots/src/components/venn/index.tsx | 10 ++++ packages/plots/src/core/index.ts | 4 ++ packages/plots/src/core/plots/venn/adaptor.ts | 58 +++++++++++++++++++ packages/plots/src/core/plots/venn/index.ts | 40 +++++++++++++ packages/plots/src/core/plots/venn/type.ts | 8 +++ site/examples/statistics/venn/demo/basic.js | 35 +++++++++++ .../statistics/venn/demo/custom-color.js | 42 ++++++++++++++ site/examples/statistics/venn/demo/custom.js | 48 +++++++++++++++ .../statistics/venn/demo/interaction.js | 49 ++++++++++++++++ site/examples/statistics/venn/demo/label.js | 28 +++++++++ site/examples/statistics/venn/demo/meta.json | 48 +++++++++++++++ site/examples/statistics/venn/index.en.md | 4 ++ site/examples/statistics/venn/index.zh.md | 6 ++ 14 files changed, 385 insertions(+) create mode 100644 packages/plots/src/components/venn/index.tsx create mode 100644 packages/plots/src/core/plots/venn/adaptor.ts create mode 100644 packages/plots/src/core/plots/venn/index.ts create mode 100644 packages/plots/src/core/plots/venn/type.ts create mode 100644 site/examples/statistics/venn/demo/basic.js create mode 100644 site/examples/statistics/venn/demo/custom-color.js create mode 100644 site/examples/statistics/venn/demo/custom.js create mode 100644 site/examples/statistics/venn/demo/interaction.js create mode 100644 site/examples/statistics/venn/demo/label.js create mode 100644 site/examples/statistics/venn/demo/meta.json create mode 100644 site/examples/statistics/venn/index.en.md create mode 100644 site/examples/statistics/venn/index.zh.md diff --git a/packages/plots/src/components/index.ts b/packages/plots/src/components/index.ts index 1044a9f7d..2b8b30c8d 100644 --- a/packages/plots/src/components/index.ts +++ b/packages/plots/src/components/index.ts @@ -22,6 +22,8 @@ import WordCloud from './wordCloud'; import Treemap from './treemap'; import Violin from './violin'; import BidirectionalBar from './bidirectional-bar'; +import Venn from './venn'; + export type { AreaConfig } from './area'; export type { BarConfig } from './bar'; @@ -46,6 +48,8 @@ export type { WordCloudConfig } from './wordCloud'; export type { TreemapConfig } from './treemap'; export type { ViolinConfig } from './violin'; export type { BidirectionalBarConfig } from './bidirectional-bar'; +export type { VennConfig } from './venn'; + export { Base, @@ -72,4 +76,5 @@ export { Treemap, Violin, BidirectionalBar, + Venn }; diff --git a/packages/plots/src/components/venn/index.tsx b/packages/plots/src/components/venn/index.tsx new file mode 100644 index 000000000..3bf2e9e04 --- /dev/null +++ b/packages/plots/src/components/venn/index.tsx @@ -0,0 +1,10 @@ +import React from 'react'; +import { VennOptions } from '../../core'; +import { CommonConfig } from '../../interface'; +import { BaseChart } from '../base'; + +export type VennConfig = CommonConfig; + +const VennChart = (props: VennConfig) => ; + +export default VennChart; diff --git a/packages/plots/src/core/index.ts b/packages/plots/src/core/index.ts index 514ce3f7e..2ad3037b5 100644 --- a/packages/plots/src/core/index.ts +++ b/packages/plots/src/core/index.ts @@ -26,6 +26,8 @@ export type { WordCloudOptions } from './plots/wordCloud'; export type { TreemapOptions } from './plots/treemap'; export type { ViolinOptions } from './plots/violin'; export type { BidirectionalBarOptions } from './plots/bidirectional-bar'; +export type { VennOptions } from './plots/venn'; + export * from './types'; import { Base } from './plots/base'; @@ -56,6 +58,7 @@ import { WordCloud } from './plots/wordCloud'; import { Treemap } from './plots/treemap'; import { Violin } from './plots/violin'; import { BidirectionalBar } from './plots/bidirectional-bar'; +import { Venn } from './plots/venn'; export const Plots = { Base, @@ -86,4 +89,5 @@ export const Plots = { Treemap, Violin, BidirectionalBar, + Venn, }; diff --git a/packages/plots/src/core/plots/venn/adaptor.ts b/packages/plots/src/core/plots/venn/adaptor.ts new file mode 100644 index 000000000..680799573 --- /dev/null +++ b/packages/plots/src/core/plots/venn/adaptor.ts @@ -0,0 +1,58 @@ +import { flow, isArray, omit, remove, set, transformOptions } from '../../utils'; +import type { Adaptor } from '../../types'; +import { DefaultTransformKey, type VennOptions } from './type'; + +type Params = Adaptor; + +/** + * @param chart + * @param options + */ +export function adaptor(params: Params) { + /** + * 图表差异化处理 + */ + const init = (params: Params) => { + const { options } = params; + const { data, setsField, sizeField } = options; + if (isArray(data)) { + set(options, 'data', { + type: 'inline', + value: data, + transform: [ + { + type: 'venn', + sets: setsField, + size: sizeField, + as: [DefaultTransformKey.color, DefaultTransformKey.d], + }, + ], + }); + set(options, 'colorField', setsField); + set(options.children[0].encode, 'd', sizeField); + } + set(params, 'options', omit(options, ['sizeField', 'setsField'])); + return params; + }; + + const style = (params: Params) => { + const { options } = params; + const { pointStyle, style } = options; + set(options, 'style', { ...style, ...pointStyle }); + set(params, 'options', omit(options, ['pointStyle'])); + return params; + }; + + const transformColorRange = (params: Params) => { + const { options } = params; + const { color } = options; + if (color) { + set(options, 'scale', { + color: { range: color }, + }); + } + return params; + }; + + return flow(init, style, transformColorRange, transformOptions)(params); +} diff --git a/packages/plots/src/core/plots/venn/index.ts b/packages/plots/src/core/plots/venn/index.ts new file mode 100644 index 000000000..62c75dbd3 --- /dev/null +++ b/packages/plots/src/core/plots/venn/index.ts @@ -0,0 +1,40 @@ +import { Plot } from '../../base'; +import type { Adaptor } from '../../types'; +import { adaptor } from './adaptor'; +import { DefaultTransformKey, VennOptions } from './type'; + +export type { VennOptions }; + +export class Venn extends Plot { + /** 图表类型 */ + public type = 'venn'; + + /** + * 获取 韦恩图 默认配置项 + * 供外部使用 + */ + static getDefaultOptions(): Partial { + return { + type: 'view', + children: [{ type: 'path' }], + legend: { + color: { itemMarker: 'circle' }, + }, + encode: { color: DefaultTransformKey.color, d: DefaultTransformKey.d }, + }; + } + + /** + * 获取 韦恩图 默认配置 + */ + protected getDefaultOptions() { + return Venn.getDefaultOptions(); + } + + /** + * 韦恩图适配器 + */ + protected getSchemaAdaptor(): (params: Adaptor) => void { + return adaptor; + } +} diff --git a/packages/plots/src/core/plots/venn/type.ts b/packages/plots/src/core/plots/venn/type.ts new file mode 100644 index 000000000..002c6a72d --- /dev/null +++ b/packages/plots/src/core/plots/venn/type.ts @@ -0,0 +1,8 @@ +import type { BaseOptions, Options } from '../../types/common'; + +export type VennOptions = Options & BaseOptions; + +export enum DefaultTransformKey { + color = 'key', + d = 'path', +} diff --git a/site/examples/statistics/venn/demo/basic.js b/site/examples/statistics/venn/demo/basic.js new file mode 100644 index 000000000..2c0f8ce0c --- /dev/null +++ b/site/examples/statistics/venn/demo/basic.js @@ -0,0 +1,35 @@ +import { Venn } from '@ant-design/plots'; +import React from 'react'; +import ReactDOM from 'react-dom'; + +const DemoVenn = () => { + const config = { + 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' }, + { sets: ['A', 'B', 'C'], size: 1 }, + ], + setsField: 'sets', + sizeField: 'size', + pointStyle: { fillOpacity: 0.85 }, + label: { + position: 'inside', + text: (d) => d.label || '', + }, + tooltip: { + title: false, + items: [ + (d) => { + return { name: d.key, value: d.size }; + }, + ], + }, + }; + return ; +}; + +ReactDOM.render(, document.getElementById('container')); diff --git a/site/examples/statistics/venn/demo/custom-color.js b/site/examples/statistics/venn/demo/custom-color.js new file mode 100644 index 000000000..9bf3dc6cb --- /dev/null +++ b/site/examples/statistics/venn/demo/custom-color.js @@ -0,0 +1,42 @@ +import { Venn } from '@ant-design/plots'; +import React from 'react'; +import ReactDOM from 'react-dom'; + +const DemoVenn = () => { + const config = { + 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' }, + { sets: ['A', 'B', 'C'], size: 1 }, + ], + setsField: 'sets', + sizeField: 'size', + pointStyle: { fillOpacity: 0.85 }, + label: { + position: 'inside', + text: (d) => d.label || '', + }, + tooltip: { + title: false, + items: [ + (d) => { + return { name: d.key, value: d.size }; + }, + ], + }, + style: { + fill: (datum, index, data) => { + console.log(data) + const { size } = datum; + if (size <= 2) return '#f4bb51'; + }, + }, + }; + return ; +}; + +ReactDOM.render(, document.getElementById('container')); diff --git a/site/examples/statistics/venn/demo/custom.js b/site/examples/statistics/venn/demo/custom.js new file mode 100644 index 000000000..2a7d9536c --- /dev/null +++ b/site/examples/statistics/venn/demo/custom.js @@ -0,0 +1,48 @@ +import { Venn } from '@ant-design/plots'; +import React from 'react'; +import ReactDOM from 'react-dom'; + +const DemoVenn = () => { + const config = { + data: { + type: 'fetch', + value: 'https://gw.alipayobjects.com/os/bmw-prod/c4c17fe9-0a93-4255-bc1e-1ff84966d24a.json', + transform: [ + { + type: 'venn', + sets: 'sets', + size: 'size', + as: ['key', 'path'], + }, + ], + }, + setsField: 'sets', + sizeField: 'size', + pointStyle: { fillOpacity: 0.85 }, + color: ['#9DF5CA', '#61DDAA', '#42C090'], + label: { + position:'inside', + style: { + lineHeight: 20, + }, + text: (datum) => { + return `${datum.size}`; + }, + }, + interaction: { + tooltip: { + // render 回调方法返回一个innerHTML 或者 DOM + render: (event, { title, items }) => { + console.log(event, { title, items }); + return `
+

title:${title}

+
    ${items.map((d) => `
  • ${d.name} ${d.value}
  • `)}
+
`; + }, + }, + }, + }; + return ; +}; + +ReactDOM.render(, document.getElementById('container')); diff --git a/site/examples/statistics/venn/demo/interaction.js b/site/examples/statistics/venn/demo/interaction.js new file mode 100644 index 000000000..bf38b9105 --- /dev/null +++ b/site/examples/statistics/venn/demo/interaction.js @@ -0,0 +1,49 @@ +import { Venn } from '@ant-design/plots'; +import React from 'react'; +import ReactDOM from 'react-dom'; + +const DemoVenn = () => { + const config = { + 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' }, + { sets: ['A', 'B', 'C'], size: 1 }, + ], + setsField: 'sets', + sizeField: 'size', + pointStyle: { fillOpacity: 0.85 }, + label: { + position: 'inside', + text: (d) => d.label || '', + }, + tooltip: { + title: false, + items: [ + (d) => { + return { name: d.key, value: d.size }; + }, + ], + }, + state: { + active: { + fillOpacity: 0.8, + stroke: 'red', + lineWidth: 1, + }, + inactive: { + fillOpacity: 0.2, + lineWidth: 0, + }, + }, + interaction: { + elementHighlight: true, + }, + }; + return ; +}; + +ReactDOM.render(, document.getElementById('container')); diff --git a/site/examples/statistics/venn/demo/label.js b/site/examples/statistics/venn/demo/label.js new file mode 100644 index 000000000..26cb37958 --- /dev/null +++ b/site/examples/statistics/venn/demo/label.js @@ -0,0 +1,28 @@ +import { Venn } from '@ant-design/plots'; +import React from 'react'; +import ReactDOM from 'react-dom'; + +const DemoVenn = () => { + const config = { + 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' }, + { sets: ['A', 'B', 'C'], size: 1 }, + ], + setsField: 'sets', + sizeField: 'size', + pointStyle: { fillOpacity: 0.85 }, + label: { + position: 'inside', + text: (d) => d.label || '', + transform: [{ type: 'contrastReverse' }], + } + }; + return ; +}; + +ReactDOM.render(, document.getElementById('container')); diff --git a/site/examples/statistics/venn/demo/meta.json b/site/examples/statistics/venn/demo/meta.json new file mode 100644 index 000000000..4c2eff801 --- /dev/null +++ b/site/examples/statistics/venn/demo/meta.json @@ -0,0 +1,48 @@ +{ + "title": { + "zh": "中文分类", + "en": "Category" + }, + "demos": [ + { + "filename": "basic.js", + "title": { + "zh": "基础韦恩图", + "en": "Basic venn plot" + }, + "screenshot": "https://gw.alipayobjects.com/zos/antfincdn/BJw8fy6uxU/009dd50e-c2a4-48dc-a79a-dc417123889f.png" + }, + { + "filename": "custom-color.js", + "title": { + "zh": "自定义颜色", + "en": "Custom color" + }, + "screenshot": "https://mdn.alipayobjects.com/huamei_lwk8lu/afts/img/A*zLutTqj3As0AAAAAAAAAAAAADma_AQ/original" + }, + { + "filename": "label.js", + "title": { + "zh": "设置label", + "en": "Label setting" + }, + "screenshot": "https://gw.alipayobjects.com/zos/antfincdn/BJw8fy6uxU/009dd50e-c2a4-48dc-a79a-dc417123889f.png" + }, + { + "filename": "custom.js", + "title": { + "zh": "自定义韦恩图", + "en": "Customize venn plot" + }, + "screenshot": "https://gw.alipayobjects.com/zos/antfincdn/T6cgHx5BHB/f2137e3b-5784-4626-a986-109fc8cb5feb.png" + }, + { + "filename": "interaction.js", + "title": { + "zh": "韦恩图-元素交互", + "en": "venn plot - with element action" + }, + "screenshot": "https://gw.alipayobjects.com/zos/antfincdn/BJw8fy6uxU/009dd50e-c2a4-48dc-a79a-dc417123889f.png" + } + ] +} diff --git a/site/examples/statistics/venn/index.en.md b/site/examples/statistics/venn/index.en.md new file mode 100644 index 000000000..811ec7aab --- /dev/null +++ b/site/examples/statistics/venn/index.en.md @@ -0,0 +1,4 @@ +--- +title: Venn +order: 3 +--- diff --git a/site/examples/statistics/venn/index.zh.md b/site/examples/statistics/venn/index.zh.md new file mode 100644 index 000000000..584b58f51 --- /dev/null +++ b/site/examples/statistics/venn/index.zh.md @@ -0,0 +1,6 @@ +--- +title: 韦恩图 +order: 3 +--- + + From 6a452e3c41aaaa36f5eed7bf8386a2d6d9a75f3b Mon Sep 17 00:00:00 2001 From: "yelinlei.yll" Date: Mon, 20 Nov 2023 15:21:05 +0800 Subject: [PATCH 2/2] =?UTF-8?q?feat:=20=E8=B0=83=E6=95=B4=E5=85=A5?= =?UTF-8?q?=E5=8F=82=E5=BD=A2=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/plots/src/core/plots/venn/adaptor.ts | 23 ++----------------- site/examples/statistics/venn/demo/basic.js | 2 +- .../statistics/venn/demo/custom-color.js | 4 ++-- site/examples/statistics/venn/demo/custom.js | 11 +++++---- .../statistics/venn/demo/interaction.js | 2 +- site/examples/statistics/venn/demo/label.js | 2 +- 6 files changed, 14 insertions(+), 30 deletions(-) diff --git a/packages/plots/src/core/plots/venn/adaptor.ts b/packages/plots/src/core/plots/venn/adaptor.ts index 680799573..2c07cbb3b 100644 --- a/packages/plots/src/core/plots/venn/adaptor.ts +++ b/packages/plots/src/core/plots/venn/adaptor.ts @@ -29,30 +29,11 @@ export function adaptor(params: Params) { ], }); set(options, 'colorField', setsField); - set(options.children[0].encode, 'd', sizeField); + set(options, ['children', '0', 'encode', 'd'], DefaultTransformKey.d); } set(params, 'options', omit(options, ['sizeField', 'setsField'])); return params; }; - const style = (params: Params) => { - const { options } = params; - const { pointStyle, style } = options; - set(options, 'style', { ...style, ...pointStyle }); - set(params, 'options', omit(options, ['pointStyle'])); - return params; - }; - - const transformColorRange = (params: Params) => { - const { options } = params; - const { color } = options; - if (color) { - set(options, 'scale', { - color: { range: color }, - }); - } - return params; - }; - - return flow(init, style, transformColorRange, transformOptions)(params); + return flow(init, transformOptions)(params); } diff --git a/site/examples/statistics/venn/demo/basic.js b/site/examples/statistics/venn/demo/basic.js index 2c0f8ce0c..8ecc54e14 100644 --- a/site/examples/statistics/venn/demo/basic.js +++ b/site/examples/statistics/venn/demo/basic.js @@ -15,7 +15,7 @@ const DemoVenn = () => { ], setsField: 'sets', sizeField: 'size', - pointStyle: { fillOpacity: 0.85 }, + style: { fillOpacity: 0.85 }, label: { position: 'inside', text: (d) => d.label || '', diff --git a/site/examples/statistics/venn/demo/custom-color.js b/site/examples/statistics/venn/demo/custom-color.js index 9bf3dc6cb..ad08273c1 100644 --- a/site/examples/statistics/venn/demo/custom-color.js +++ b/site/examples/statistics/venn/demo/custom-color.js @@ -15,7 +15,6 @@ const DemoVenn = () => { ], setsField: 'sets', sizeField: 'size', - pointStyle: { fillOpacity: 0.85 }, label: { position: 'inside', text: (d) => d.label || '', @@ -29,8 +28,9 @@ const DemoVenn = () => { ], }, style: { + fillOpacity: 0.85, fill: (datum, index, data) => { - console.log(data) + console.log(data); const { size } = datum; if (size <= 2) return '#f4bb51'; }, diff --git a/site/examples/statistics/venn/demo/custom.js b/site/examples/statistics/venn/demo/custom.js index 2a7d9536c..3c26ec335 100644 --- a/site/examples/statistics/venn/demo/custom.js +++ b/site/examples/statistics/venn/demo/custom.js @@ -18,10 +18,14 @@ const DemoVenn = () => { }, setsField: 'sets', sizeField: 'size', - pointStyle: { fillOpacity: 0.85 }, - color: ['#9DF5CA', '#61DDAA', '#42C090'], + style: { fillOpacity: 0.85 }, + scale: { + color: { + range: ['#9DF5CA', '#61DDAA', '#42C090'], + }, + }, label: { - position:'inside', + position: 'inside', style: { lineHeight: 20, }, @@ -33,7 +37,6 @@ const DemoVenn = () => { tooltip: { // render 回调方法返回一个innerHTML 或者 DOM render: (event, { title, items }) => { - console.log(event, { title, items }); return `

title:${title}

    ${items.map((d) => `
  • ${d.name} ${d.value}
  • `)}
diff --git a/site/examples/statistics/venn/demo/interaction.js b/site/examples/statistics/venn/demo/interaction.js index bf38b9105..3561aecda 100644 --- a/site/examples/statistics/venn/demo/interaction.js +++ b/site/examples/statistics/venn/demo/interaction.js @@ -15,7 +15,7 @@ const DemoVenn = () => { ], setsField: 'sets', sizeField: 'size', - pointStyle: { fillOpacity: 0.85 }, + style: { fillOpacity: 0.85 }, label: { position: 'inside', text: (d) => d.label || '', diff --git a/site/examples/statistics/venn/demo/label.js b/site/examples/statistics/venn/demo/label.js index 26cb37958..ba7b1f106 100644 --- a/site/examples/statistics/venn/demo/label.js +++ b/site/examples/statistics/venn/demo/label.js @@ -15,7 +15,7 @@ const DemoVenn = () => { ], setsField: 'sets', sizeField: 'size', - pointStyle: { fillOpacity: 0.85 }, + style: { fillOpacity: 0.85 }, label: { position: 'inside', text: (d) => d.label || '',