Skip to content
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
2 changes: 1 addition & 1 deletion src/double-axes/demos/DoubleAxes.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ Basic.args = {
showCrosshairs: false,
shared: true,
render: (options: any) => {
return <InfoCard {...options} title="用户量" data={options?.data} />;
return <InfoCard {...options} title="用户量" data={options?.data} forwardKey={null} />;
},
},
column: {
Expand Down
16 changes: 13 additions & 3 deletions src/info-card/InfoCardBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,15 @@ const InfoCardBox = (props: InfoCardProps) => {
fixedItems = fixedItems.map((item: any) => {
const legend = legendObject.getLegend(item.name);
item.type = legend?.type || config?.type;
const shapeConfig = getShapeConfig(config, item.type);
const [, yField] = getAxisFields(shapeConfig.position);
let shapeConfig = getShapeConfig(config, item.type);

// 双y轴折线图(line + line2):两条折线分布在不同 y 轴上,
// 需要根据 item 所属的颜色字段判断它属于 line 还是 line2,从而读取对应的 y 轴字段
const line2Cfg = (config as ChartConfig)?.line2;
if (line2Cfg && item?.data?.[line2Cfg.color] === item.name) {
shapeConfig = line2Cfg;
}
const [, yField] = getAxisFields(shapeConfig.position);
item.xField = shapeConfig.color;
item.yField = yField;
return item;
Expand All @@ -89,7 +95,11 @@ const InfoCardBox = (props: InfoCardProps) => {
if (!item) {
return {} as InfoCardData;
}
const [legend, color] = getInfoCardStyles(options, config, item, legendObject, nameKey);
let [legend, color] = getInfoCardStyles(options, config, item, legendObject, nameKey);
const line2Cfg = (config as ChartConfig)?.line2;
if (line2Cfg && item?.data?.[line2Cfg.color] === item.name) {
[legend, color] = getInfoCardStyles(options, { ...config, line: line2Cfg }, item, legendObject, nameKey);
}
// Set color for trigger item, it will change the point color when mouseover the column bar
item.color = color;
const itemData = item.data;
Expand Down
5 changes: 5 additions & 0 deletions src/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,11 @@ export interface LineConfig extends ChartConfig {
* 用来创建折线图的配置
*/
line: Shape;
/**
* 第二组折线配置,用于双y轴折线图。
* 配置后会渲染到右侧的第二个 y 轴,与 line 共享 x 轴。
*/
line2?: Shape;
}

export interface GaugeConfig extends ChartConfig {
Expand Down
45 changes: 44 additions & 1 deletion src/line/demos/Line.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ComponentStory } from '@storybook/react';
import Line from '../Line';
import { dataWithOneLine, dataWithMenu, dataWithOnelineDate, contrastData, dataWithSplit } from './data';
import { dataWithOneLine, dataWithMenu, dataWithOnelineDate, contrastData, dataWithSplit,dataWithDualAxis } from './data';
import Card from '../../demos/card';
import Docs from './Line.mdx';
import { colors } from '../../theme';
Expand Down Expand Up @@ -110,6 +110,49 @@ const BaiscLineArgs = {
BaiscLine.storyName = '基础折线图';
BaiscLine.args = { ...BaiscLineArgs };

const DualAxisTemplate: ComponentStory<typeof Line> = (args) => (
<Card>
<Line {...args} />
</Card>
);

export const DualAxisLine = DualAxisTemplate.bind({});
const DualAxisLineArgs = {
legends: [
'指标1',
'指标2',
],
data: dataWithDualAxis,
config: {
chart: {
autoFit: true,
height: 300,
},
axises: [['value2', { grid: null }]],
scale: {
value: { nice: true, min: 0 },
value2: { nice: true, min: 0 },
},
tooltip: {
showCrosshairs: false,
shared: false,
render: (options: any) => {
return <InfoCard {...options} data={options?.data} forwardKey={null} />;
},
},
line: {
position: 'tm*value',
color: 'type1',
},
line2: {
position: 'tm*value2',
color: 'type2',
},
},
};
DualAxisLine.storyName = '双y轴折线图';
DualAxisLine.args = { ...DualAxisLineArgs };

export const MultiLine = Template.bind({});
const MultiLineArgs = {
legends: [
Expand Down
11 changes: 11 additions & 0 deletions src/line/demos/data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1245,3 +1245,14 @@ export const contrastData = [
// NxDLPLD7_name: '访问的总次数(上周)',
// },
];

export const dataWithDualAxis = [
{ type1: '指标1',type2: '指标2', tm: '06/04 周五', value: 10900, value2: 10 },
{ type1: '指标1',type2: '指标2', tm: '06/05 周六', value: 7200, value2: 72 },
{ type1: '指标1',type2: '指标2', tm: '06/06 周日', value: 13900, value2: 13 },
{ type1: '指标1',type2: '指标2', tm: '06/07 周一', value: 11100, value2: 11 },
{ type1: '指标1',type2: '指标2', tm: '06/08 周二', value: 6500, value2: 65 },
{ type1: '指标1',type2: '指标2', tm: '06/09 周三', value: 4800, value2: 48 },
{ type1: '指标1',type2: '指标2', tm: '06/10 周四', value: 8123, value2: 81 },
{ type1: '指标1',type2: '指标2', tm: '06/11 周五', value: 9865, value2: 98 },
]
72 changes: 55 additions & 17 deletions src/line/framework.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,26 +110,58 @@ export class LineBase extends BaseChart {
return line;
};

/**
* 渲染双y轴折线图:
* line 与 line2 两条折线渲染在同一个 view 上(与双轴图 DoubleAxes 保持一致),
* 以便 shared tooltip 能同时收集到两条折线的数据;line2 对应的 y 轴放在右侧形成双 y 轴。
*/
dualAxisRender = (chart: Chart, options: ChartOptions, config: ChartConfig) => {
const lineCfg = getShapeConfig(config, ChartType.LINE);
const line2Cfg = ((config as ChartConfig) || { line2: undefined }).line2 as Shape;
const [, yField2] = getAxisFields(line2Cfg.position as string);

// 双y轴折线图:line 与 line2 两条折线保持在同一个 view 上渲染,
// 这样 G2 的 shared tooltip 才能同时收集到两条折线的数据(与双轴图 DoubleAxes 保持一致)。
this.lineShape(chart, options, lineCfg);
this.lineShape(chart, options, line2Cfg);

// 将 line2 对应的 y 轴放到右侧,形成双 y 轴
if (yField2) {
chart.axis(yField2, { position: 'right', grid: null });
}

return chart;
};

update = (data: Datum[]) => {
const hasDualAxis = !!((this.config as ChartConfig) || { line2: undefined }).line2;
const lineCfg = getShapeConfig(this.config, ChartType.LINE);
const [xField, yField] = getAxisFields(lineCfg.position);
const [maxValue, dataMapping] = this.getDataByColor(lineCfg.color, xField, yField, data);
this.setMax(yField, maxValue, this.config as ChartConfig);

const legends = this.options?.legends || {};
const viewCount = 0;
this.contrastViewQueue(dataMapping, legends)(
(updatedData) => {
const view = this.views?.[viewCount];
view?.changeData(updatedData);
view?.render(true);
},
/* istanbul ignore next */
(updatedData: LooseObject[]) => {
this.finalView?.changeData(updatedData);
this.finalView?.render(true);
}
);
if (hasDualAxis) {
const line2Cfg = ((this.config as ChartConfig) || { line2: undefined }).line2 as Shape;
const [, yField2] = getAxisFields(line2Cfg.position as string);
this.setMax(yField2, maxValue, this.config as ChartConfig);

// 双轴场景:两条折线在同一 view 上,数据变更时直接更新实例数据后重绘即可
this.instance?.changeData(data);
} else {
const legends = this.options?.legends || {};
const viewCount = 0;
this.contrastViewQueue(dataMapping, legends)(
(updatedData) => {
const view = this.views?.[viewCount];
view?.changeData(updatedData);
view?.render(true);
},
/* istanbul ignore next */
(updatedData: LooseObject[]) => {
this.finalView?.changeData(updatedData);
this.finalView?.render(true);
}
);
}
this.annotations();
this.instance?.render(true);
};
Expand All @@ -146,11 +178,17 @@ export class Line extends LineBase {
}
this.instance = renderChart(options, config);
try {
const lineConfig = getShapeConfig(config, 'line');
this.lineShape(this.instance, options, lineConfig);
const hasDualAxis = !!((config as ChartConfig) || { line2: undefined }).line2;
if (hasDualAxis) {
this.dualAxisRender(this.instance, options, config);
} else {
const lineConfig = getShapeConfig(config, 'line');
this.lineShape(this.instance, options, lineConfig);
}

this.annotations();

// fetchTooltip(this.instance, config);
this.instance.render();
// Sometimes, chart will render wrong axis labels, render again will be fine.
// this.instance.render(true);
Expand Down
Loading