diff --git a/__tests__/bugs/issue-2906-spec.ts b/__tests__/bugs/issue-2906-spec.ts new file mode 100644 index 0000000000..b7b863124c --- /dev/null +++ b/__tests__/bugs/issue-2906-spec.ts @@ -0,0 +1,28 @@ +import { Venn } from '../../src'; +import { createDiv } from '../utils/dom'; + +describe('#2906', () => { + it('venn plot color callback', () => { + const plot = new Venn(createDiv(), { + setsField: 'sets', + sizeField: 'size', + 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 }, + ], + pointStyle: { fillOpacity: 0.85 }, + color: (datum) => (datum.sets?.length === 1 ? 'blue' : 'red'), + }); + plot.render(); + + const legendController = plot.chart.getController('legend'); + const items = legendController.getComponents()[0].component.get('items'); + expect(items[0].marker.style.fill).toBe('blue'); + expect(items[3].marker.style.fill).toBe('red'); + }); +}); diff --git a/__tests__/unit/plots/venn/color-spec.ts b/__tests__/unit/plots/venn/color-spec.ts index 64e6e6d477..0e6661a8a6 100644 --- a/__tests__/unit/plots/venn/color-spec.ts +++ b/__tests__/unit/plots/venn/color-spec.ts @@ -57,6 +57,29 @@ describe('venn: color', () => { expect(plot.chart.geometries[0].elements[5].getModel().color).toBe('blue'); }); + it('color: callback params', () => { + plot.update({ + theme: { colors10: ['red', 'yellow', 'blue'] }, + color: undefined, + }); + + expect(plot.chart.geometries[0].elements[0].getModel().color).toBe('red'); + expect(plot.chart.geometries[0].elements[1].getModel().color).toBe('yellow'); + expect(plot.chart.geometries[0].elements[2].getModel().color).toBe('blue'); + expect(plot.chart.geometries[0].elements[4].getModel().color).not.toBe('black'); + + plot.update({ + color: (datum, defaultColor) => { + return ['red', 'blue'].indexOf(defaultColor) === -1 ? 'black' : defaultColor; + }, + }); + expect(plot.chart.geometries[0].elements[0].getModel().color).toBe('red'); + expect(plot.chart.geometries[0].elements[1].getModel().color).not.toBe('yellow'); + expect(plot.chart.geometries[0].elements[1].getModel().color).toBe('black'); + expect(plot.chart.geometries[0].elements[2].getModel().color).toBe('blue'); + expect(plot.chart.geometries[0].elements[4].getModel().color).toBe('black'); + }); + afterAll(() => { plot.destroy(); }); diff --git a/docs/api/plots/venn.en.md b/docs/api/plots/venn.en.md index cfe9902037..2e5c1d718a 100644 --- a/docs/api/plots/venn.en.md +++ b/docs/api/plots/venn.en.md @@ -38,7 +38,34 @@ The name of the data field corresponding to the point size map. ### Geometry Style -`markdown:docs/common/color.en.md` +#### color + +**optional** _string | string[] | Function_ + +指定图形元素的颜色。可以指定单色,或者一系列色值,也可以通过回调函数的方法根据对应数值进行设置。(**注意**:韦恩图的 color 系列色值只作用于单个集合上,交集部分通过指定 blendMode 来进行叠加处理。另外,color 回调中,第二个参数代表默认分配的颜色。) + +默认配置:采用 theme 中的色板。演示 [Demo](/zh/examples/more-plots/venn#blend-mode) + +```ts +// 设置单一颜色 +{ + color: '#a8ddb5' +} +// 设置多色 +{ + color: ['#d62728', '#2ca02c', '#000000'], +} +// Function +{ + color: (datum, defaultColor) => { + if(datum.size > 100){ + return 'red'; + } + return defaultColor; + } +} +``` + #### blendMode diff --git a/docs/api/plots/venn.zh.md b/docs/api/plots/venn.zh.md index 1f9ff3f5ab..efdf06b673 100644 --- a/docs/api/plots/venn.zh.md +++ b/docs/api/plots/venn.zh.md @@ -38,8 +38,33 @@ order: 12 ### 图形样式 - -`markdown:docs/common/color.zh.md` +#### color + +**optional** _string | string[] | Function_ + +指定图形元素的颜色。可以指定单色,或者一系列色值,也可以通过回调函数的方法根据对应数值进行设置。(**注意**:韦恩图的 color 系列色值只作用于单个集合上,交集部分通过指定 blendMode 来进行叠加处理。另外,color 回调中,第二个参数代表默认分配的颜色。) + +默认配置:采用 theme 中的色板。演示 [Demo](/zh/examples/more-plots/venn#blend-mode) + +```ts +// 设置单一颜色 +{ + color: '#a8ddb5' +} +// 设置多色 +{ + color: ['#d62728', '#2ca02c', '#000000'], +} +// Function +{ + color: (datum, defaultColor) => { + if(datum.size > 100){ + return 'red'; + } + return defaultColor; + } +} +``` #### blendMode diff --git a/docs/manual/plots/venn.en.md b/docs/manual/plots/venn.en.md new file mode 100644 index 0000000000..7a1908b82a --- /dev/null +++ b/docs/manual/plots/venn.en.md @@ -0,0 +1,6 @@ +--- +title: Venn +order: 30 +--- + +`markdown:docs/manual/plots/venn.zh.md` \ No newline at end of file diff --git a/docs/manual/plots/venn.zh.md b/docs/manual/plots/venn.zh.md new file mode 100644 index 0000000000..963c745122 --- /dev/null +++ b/docs/manual/plots/venn.zh.md @@ -0,0 +1,35 @@ +--- +title: 韦恩图 +order: 30 +--- + + + +## 快速上手 + + + +```ts +import { Venn } from '@antv/g2plot'; + +const plot = new Venn('container', { + 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', +}); +plot.render(); +``` + + + +📊 查看更多示例. + +🎨 韦恩图详细的配置参考 [API 文档](/zh/docs/api/plots/venn)。 diff --git a/examples/more-plots/venn/demo/color.ts b/examples/more-plots/venn/demo/color.ts new file mode 100644 index 0000000000..43d49640c3 --- /dev/null +++ b/examples/more-plots/venn/demo/color.ts @@ -0,0 +1,23 @@ +import { Venn } from '@antv/g2plot'; + +const plot = new Venn('container', { + data: [ + { sets: ['A'], size: 102, 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 }, + color: (datum, defaultColor) => { + if (datum.size > 100) { + return '#FF4500'; + } + return defaultColor; + }, +}); +plot.render(); diff --git a/examples/more-plots/venn/demo/meta.json b/examples/more-plots/venn/demo/meta.json index f1847faf33..774347f9b4 100644 --- a/examples/more-plots/venn/demo/meta.json +++ b/examples/more-plots/venn/demo/meta.json @@ -10,7 +10,6 @@ "zh": "基础韦恩图", "en": "Basic venn plot" }, - "new": true, "screenshot": "https://gw.alipayobjects.com/zos/antfincdn/BJw8fy6uxU/009dd50e-c2a4-48dc-a79a-dc417123889f.png" }, { @@ -19,16 +18,22 @@ "zh": "设置颜色叠加模式", "en": "Color blend mode" }, - "new": true, "screenshot": "https://gw.alipayobjects.com/zos/antfincdn/XZE3uS3Ezm/e18cdf57-f528-4a43-a0a5-b92dba819477.png" }, + { + "filename": "color.ts", + "title": { + "zh": "自定义颜色", + "en": "Custom color" + }, + "screenshot": "https://gw.alipayobjects.com/zos/antfincdn/jonq4FL0vL/7b5db090-a855-4861-806f-5e09c2fdfd97.png" + }, { "filename": "tooltip.ts", "title": { "zh": "格式化 tooltip", "en": "Formatter tooltip" }, - "new": true, "screenshot": "https://gw.alipayobjects.com/zos/antfincdn/BJw8fy6uxU/009dd50e-c2a4-48dc-a79a-dc417123889f.png" }, { @@ -37,7 +42,6 @@ "zh": "设置 label", "en": "Label setting" }, - "new": true, "screenshot": "https://gw.alipayobjects.com/zos/antfincdn/nyPJ6bGZ68/d5e85b5d-70c5-45b5-94aa-9a229e65474c.png" }, { @@ -46,7 +50,6 @@ "zh": "自定义韦恩图", "en": "Customize venn plot" }, - "new": true, "screenshot": "https://gw.alipayobjects.com/zos/antfincdn/T6cgHx5BHB/f2137e3b-5784-4626-a986-109fc8cb5feb.png" }, { @@ -55,8 +58,7 @@ "zh": "韦恩图 - 元素交互", "en": "venn plot - with element action" }, - "new": true, "screenshot": "https://gw.alipayobjects.com/zos/antfincdn/x%24Jxds2L2T/0ff5000b-d23e-49a8-a02a-4eb02d7a8e47.png" } ] -} \ No newline at end of file +} diff --git a/src/plots/venn/adaptor.ts b/src/plots/venn/adaptor.ts index 557653fc11..ecc55ccf05 100644 --- a/src/plots/venn/adaptor.ts +++ b/src/plots/venn/adaptor.ts @@ -24,21 +24,32 @@ import './interaction'; /** 图例默认预留空间 */ export const LEGEND_SPACE = 40; +/** + * 获取 color 映射 + */ +function colorMap(params: Params, data: VennData, colorPalette?: string[]) { + const { chart, options } = params; + const { setsField } = options; + const { colors10, colors20 } = chart.getTheme(); + let palette = colorPalette; + if (!isArray(palette)) { + palette = data.filter((d) => d[setsField].length === 1).length <= 10 ? colors10 : colors20; + } + const colorMap = getColorMap(palette, data, options); + + return (id: string) => colorMap.get(id) || palette[0]; +} + /** * color options 转换 */ function transformColor(params: Params, data: VennData): VennOptions['color'] { - const { chart, options } = params; - const { color, setsField } = options; + const { options } = params; + const { color } = 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[setsField].length === 1).length <= 10 ? colors10 : colors20; - } - const colorMap = getColorMap(colorPalette, data, options); - return (datum: Datum) => colorMap.get(datum[ID_FIELD]) || colorPalette[0]; + const colorPalette = typeof color === 'string' ? [color] : color; + return (datum: Datum) => colorMap(params, data, colorPalette)(datum[ID_FIELD]); } return color; } @@ -132,7 +143,6 @@ function geometry(params: Params): Params { schema: { shape: 'venn', style: pointStyle, - color: transformColor(params, vennData), }, }, }) @@ -141,6 +151,16 @@ function geometry(params: Params): Params { const geometry = ext.geometry as Geometry; geometry.customInfo(customInfo); + const colorOptions = transformColor(params, vennData); + // 韦恩图试点, color 通道只能映射一个字段. 通过外部查找获取 datum + if (typeof colorOptions === 'function') { + geometry.color(ID_FIELD, (id) => { + const datum = vennData.find((d) => d[ID_FIELD] === id); + const defaultColor = colorMap(params, vennData)(id); + return colorOptions(datum, defaultColor); + }); + } + return params; } diff --git a/src/plots/venn/types.ts b/src/plots/venn/types.ts index 35dfba8ab4..c937ac316f 100644 --- a/src/plots/venn/types.ts +++ b/src/plots/venn/types.ts @@ -1,5 +1,5 @@ import { Types } from '@antv/g2'; -import { Options, StyleAttr } from '../../types'; +import { Datum, Options, StyleAttr } from '../../types'; import { ID_FIELD, PATH_FIELD } from './constant'; export type VennData = (Types.Datum & { sets: string[]; [PATH_FIELD]: string; [ID_FIELD]: string })[]; @@ -15,7 +15,7 @@ export interface VennOptions extends Options { // 韦恩图 样式 /** color */ - readonly color?: Options['color']; + readonly color?: string | string[] | ((datum: Datum, defaultColor: string) => string); /** 并集合的颜色混合方式, 可选项: 参考 https://gka.github.io/chroma.js/#chroma-blend, 默认: multiply */ readonly blendMode?: string; /** point 样式 */