Skip to content

Commit

Permalink
feat(legend): 图例支持回调设置 marker (#3448)
Browse files Browse the repository at this point in the history
* feat(legend): 图例支持回调设置 marker

* docs(legend): 添加图例 marker 设置文档
  • Loading branch information
visiky authored May 31, 2021
1 parent 572570d commit ed3047e
Show file tree
Hide file tree
Showing 11 changed files with 263 additions and 21 deletions.
30 changes: 19 additions & 11 deletions docs/api/general/legend.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,10 @@ _legendOption_ 配置如下:

适用于 <tag color="green" text="分类图例">分类图例</tag>,对图例分页器进行主题样式设置。_LegendPageNavigatorCfg_ 配置如下:

| 参数名 | 类型 | 默认值 | 描述 |
| ------ | --------------------- | ------ | -------------- |
| marker | _PageNavigatorMarker_ | - | 分页器指示箭头配置项 |
| text | _PageNavigatorText_ | - | 分页器指示文本配置项 |
| 参数名 | 类型 | 默认值 | 描述 |
| ------ | --------------------- | ------ | -------------------- |
| marker | _PageNavigatorMarker_ | - | 分页器指示箭头配置项 |
| text | _PageNavigatorText_ | - | 分页器指示文本配置项 |

示例:

Expand Down Expand Up @@ -122,11 +122,11 @@ pageNavigator: {
```ts
chart.legend('type', {
selected: {
'分类一': true,
'分类二': false,
'分类三': false,
}
})
分类一: true,
分类二: false,
分类三: false,
},
});
```

<playground path='interaction/component/demo/legend-focus.ts' rid='legend-selected'></playground>
Expand Down Expand Up @@ -212,12 +212,20 @@ chart.legend('type', {

### legendOption.marker

<description> _MarkerCfg_ **optional** </description>
<description> _MarkerCfg | MarkerCfgCallback_ **optional** </description>

适用于 <tag color="green" text="分类图例">分类图例</tag>,图例项的 marker 图标的配置
适用于 <tag color="green" text="分类图例">分类图例</tag>,图例项的 marker 图标配置,也支持通过回调的方式设置

`markdown:docs/common/marker-cfg.md`

```sign
type LegendItem = { name: string; value: string; } & MarkerCfg;
type MarkerCfgCallback = (name: string, index: number, item: LegendItem) => MarkerCfg;
```

<playground path="component/legend/demo/marker-callback.ts" rid="legend-marker-callback"></playground>

### legendOption.min

<description> _number_ **optional** </description>
Expand Down
1 change: 1 addition & 0 deletions examples/component/legend/API.en.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
`markdown:docs/common/api..md`
1 change: 1 addition & 0 deletions examples/component/legend/API.zh.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
`markdown:docs/common/api.zh.md`
55 changes: 55 additions & 0 deletions examples/component/legend/demo/custom-items.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { Chart } from '@antv/g2';

const data = [
{ name: 'London', 月份: 'Jan.', 月均降雨量: 18.9 },
{ name: 'London', 月份: 'Feb.', 月均降雨量: 28.8 },
{ name: 'London', 月份: 'Mar.', 月均降雨量: 39.3 },
{ name: 'London', 月份: 'Apr.', 月均降雨量: 81.4 },
{ name: 'London', 月份: 'May', 月均降雨量: 47 },
{ name: 'London', 月份: 'Jun.', 月均降雨量: 20.3 },
{ name: 'London', 月份: 'Jul.', 月均降雨量: 24 },
{ name: 'London', 月份: 'Aug.', 月均降雨量: 35.6 },
{ name: 'Berlin', 月份: 'Jan.', 月均降雨量: 12.4 },
{ name: 'Berlin', 月份: 'Feb.', 月均降雨量: 23.2 },
{ name: 'Berlin', 月份: 'Mar.', 月均降雨量: 34.5 },
{ name: 'Berlin', 月份: 'Apr.', 月均降雨量: 99.7 },
{ name: 'Berlin', 月份: 'May', 月均降雨量: 52.6 },
{ name: 'Berlin', 月份: 'Jun.', 月均降雨量: 35.5 },
{ name: 'Berlin', 月份: 'Jul.', 月均降雨量: 37.4 },
{ name: 'Berlin', 月份: 'Aug.', 月均降雨量: 42.4 },
];

const chart = new Chart({
container: 'container',
autoFit: true,
height: 500,
});

chart.data(data);
chart.scale('月均降雨量', {
nice: true,
});
chart.tooltip({
shared: true,
showMarkers: false,
});
chart.legend({
custom: true,
items: [
{
name: '城市 1',
id: 'city-1',
marker: { symbol: 'triangle', style: { r: 4, fill: 'red' } },
},
{
name: '城市 2',
id: 'city-2',
},
],
});

chart.interval().position('月份*月均降雨量').color('name').adjust('stack');

chart.interaction('active-region');

chart.render();
52 changes: 52 additions & 0 deletions examples/component/legend/demo/marker-callback.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { Chart } from '@antv/g2';

const data = [
{ name: 'London', 月份: 'Jan.', 月均降雨量: 18.9 },
{ name: 'London', 月份: 'Feb.', 月均降雨量: 28.8 },
{ name: 'London', 月份: 'Mar.', 月均降雨量: 39.3 },
{ name: 'London', 月份: 'Apr.', 月均降雨量: 81.4 },
{ name: 'London', 月份: 'May', 月均降雨量: 47 },
{ name: 'London', 月份: 'Jun.', 月均降雨量: 20.3 },
{ name: 'London', 月份: 'Jul.', 月均降雨量: 24 },
{ name: 'London', 月份: 'Aug.', 月均降雨量: 35.6 },
{ name: 'Berlin', 月份: 'Jan.', 月均降雨量: 12.4 },
{ name: 'Berlin', 月份: 'Feb.', 月均降雨量: 23.2 },
{ name: 'Berlin', 月份: 'Mar.', 月均降雨量: 34.5 },
{ name: 'Berlin', 月份: 'Apr.', 月均降雨量: 99.7 },
{ name: 'Berlin', 月份: 'May', 月均降雨量: 52.6 },
{ name: 'Berlin', 月份: 'Jun.', 月均降雨量: 35.5 },
{ name: 'Berlin', 月份: 'Jul.', 月均降雨量: 37.4 },
{ name: 'Berlin', 月份: 'Aug.', 月均降雨量: 42.4 },
];

const chart = new Chart({
container: 'container',
autoFit: true,
height: 500,
});

chart.data(data);
chart.scale('月均降雨量', {
nice: true,
});
chart.tooltip({
shared: true,
showMarkers: false,
});
chart.legend({
marker: (name, index, item) => {
return {
symbol: index === 0 ? 'circle' : 'diamond',
style: {
fill: index === 0 ? 'purple' : 'green',
stroke: '#363636',
lineWidth: 1,
},
};
},
});

chart.interval().position('月份*月均降雨量').color('name').adjust('stack');
chart.interaction('active-region');

chart.render();
24 changes: 24 additions & 0 deletions examples/component/legend/demo/meta.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"title": {
"zh": "中文分类",
"en": "Category"
},
"demos": [
{
"filename": "marker-callback.ts",
"title": {
"zh": "通过回调设置 legend marker",
"en": "Legend marker with callback"
},
"screenshot": "https://gw.alipayobjects.com/zos/antfincdn/XYbSi6Ztbo/f5bd6aff-61fa-41ff-ab3b-8de9be14d053.png"
},
{
"filename": "custom-items.ts",
"title": {
"zh": "自定义图例 items",
"en": "Custom legend items"
},
"screenshot": "https://gw.alipayobjects.com/zos/antfincdn/PgYlI9hB3Z/c50fffd5-5db0-49f2-ba16-ee3f523905bc.png"
}
]
}
4 changes: 4 additions & 0 deletions examples/component/legend/index.en.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
title: Legend
order: 4
---
4 changes: 4 additions & 0 deletions examples/component/legend/index.zh.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
title: 图例
order: 4
---
2 changes: 1 addition & 1 deletion src/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1032,7 +1032,7 @@ export interface LegendCfg {
/**
* **分类图例适用**,图例项的 marker 图标的配置。
*/
marker?: MarkerCfg;
marker?: MarkerCfg | ((name: string, index: number, item: { name: string; value: string } & MarkerCfg) => MarkerCfg);
/**
* **适用于分类图例**,当图例项过多时是否进行分页。
*/
Expand Down
28 changes: 19 additions & 9 deletions src/util/legend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import View from '../chart/view';
import { DIRECTION } from '../constant';
import { Attribute, ShapeAttrs, Tick } from '../dependents';
import Geometry from '../geometry/base';
import { LegendItem, MarkerCfg } from '../interface';
import { LegendCfg, LegendItem, MarkerCfg } from '../interface';
import { getMappingValue } from './attr';
import { omit } from './helper';
import { MarkerSymbols } from './marker';
Expand Down Expand Up @@ -74,15 +74,15 @@ type ComponentLegendItem = Omit<LegendItem, 'marker'> & {
* @param geometry
* @param attr
* @param themeMarker
* @param userMarker
* @param markerCfg
* @returns legend items
*/
export function getLegendItems(
view: View,
geometry: Geometry,
attr: Attribute,
themeMarker: object,
userMarker
userMarker: LegendCfg['marker'],
): ComponentLegendItem[] {
const scale = attr.getScale(attr.type);
if (scale.isCategory) {
Expand All @@ -92,7 +92,7 @@ export function getLegendItems(
const defaultColor = view.getTheme().defaultColor;
const isInPolar = geometry.coordinate.isPolar;

return scale.getTicks().map((tick: Tick) => {
return scale.getTicks().map((tick: Tick, index: number) => {
const { text, value: scaleValue } = tick;
const name = text;
const value = scale.invert(scaleValue);
Expand All @@ -112,12 +112,18 @@ export function getLegendItems(
color,
isInPolar,
});

let markerCfg = userMarker;
if (isFunction(markerCfg)) {
markerCfg = markerCfg(name, index, { name, value, ...deepMix({}, themeMarker, marker) })
}

// the marker configure order should be ensure
marker = deepMix({}, themeMarker, marker, omit({ ...userMarker }, ['style']));
marker = deepMix({}, themeMarker, marker, omit({ ...markerCfg }, ['style']));
adpatorMarkerStyle(marker, color);
if (userMarker && userMarker.style) {
if (markerCfg && markerCfg.style) {
// handle user's style settings
marker.style = handleUserMarkerStyle(marker.style, userMarker.style);
marker.style = handleUserMarkerStyle(marker.style, markerCfg.style);
}
setMarkerSymbol(marker);

Expand All @@ -137,8 +143,12 @@ export function getLegendItems(
*/
export function getCustomLegendItems(themeMarker: object, userMarker: object, customItems: LegendItem[]) {
// 如果有自定义的 item,那么就直接使用,并合并主题的 marker 配置
return customItems.map((item: LegendItem) => {
const marker = deepMix({}, themeMarker, userMarker, item.marker);
return customItems.map((item: LegendItem, index: number) => {
let markerCfg = userMarker;
if (isFunction(markerCfg)) {
markerCfg = markerCfg(item.name, index, deepMix({}, themeMarker, item))
}
const marker = deepMix({}, themeMarker, markerCfg, item.marker);
setMarkerSymbol(marker);

item.marker = marker;
Expand Down
83 changes: 83 additions & 0 deletions tests/unit/component/legend-category-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,89 @@ describe('Legend category navigation', () => {

expect(navigation).toBeUndefined();
});

it('legend marker with callback', () => {
chart.legend('clarity', {
position: 'right',
flipPage: true,
marker: {
symbol: 'square',
style: { fill: 'red' },
},
});
chart.render();

let legends = chart.getComponents().filter((co) => co.type === COMPONENT_TYPE.LEGEND);
let items = legends[0].component.get('items');
expect(items[0].marker.symbol).toBe('square');
expect(items[0].marker.style.fill).toBe('red');

chart.legend('clarity', {
position: 'right',
flipPage: true,
marker: (text, index, item) => {
return {
symbol: index === 0 ? 'triangle' : 'diamond',
style: { fill: 'red', stroke: index === 1 ? 'red' : undefined },
};
},
});
chart.render();

legends = chart.getComponents().filter((co) => co.type === COMPONENT_TYPE.LEGEND);
items = legends[0].component.get('items');
expect(items[0].marker.symbol).toBe('triangle');
expect(items[1].marker.symbol).toBe('diamond');
expect(items[0].marker.style.fill).toBe('red');
expect(items[1].marker.style.stroke).toBe('red');

chart.legend('clarity', {
marker: {
symbol: 'circle',
style: { fill: 'lightgreen' },
},
});
chart.render();

legends = chart.getComponents().filter((co) => co.type === COMPONENT_TYPE.LEGEND);
items = legends[0].component.get('items');
expect(items[0].marker.symbol).toBe('circle');
expect(items[1].marker.symbol).toBe('circle');
expect(items[0].marker.style.fill).toBe('lightgreen');
});

it('custom legend items, and marker with callback', () => {
chart.legend('clarity', {
marker: (text, index, item) => {
return {
symbol: index === 0 ? 'square' : 'diamond',
style: { fill: 'red', stroke: index === 0 ? 'red' : undefined },
};
},
custom: true,
items: [
{
name: '城市 1',
value: 'city-1',
marker: { symbol: 'triangle', style: { r: 4, fill: 'blue' } },
},
{
name: '城市 2',
value: 'city-2',
},
],
});
chart.render();

const legends = chart.getComponents().filter((co) => co.type === COMPONENT_TYPE.LEGEND);
const items = legends[0].component.get('items');
expect(items[0].marker.symbol).toBe('triangle');
// 继承默认的 symbol 设置
expect(items[1].marker.symbol).toBe('diamond');
expect(items[0].marker.style.fill).toBe('blue');
// 继承默认的 symbol 设置
expect(items[1].marker.style.stroke).toBeUndefined();
});
});

describe('Legend Category Vertical', () => {
Expand Down

0 comments on commit ed3047e

Please sign in to comment.