Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(legend): 图例支持回调设置 marker #3448

Merged
merged 2 commits into from
May 31, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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