Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(components):add Legend Component
- Loading branch information
1 parent
b3aa9ad
commit d578d91
Showing
4 changed files
with
288 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
import { GraphinContext } from '@antv/graphin/dist'; | ||
import React from 'react'; | ||
import './index.less'; | ||
|
||
export interface LegendOption { | ||
/** 标签 */ | ||
label: string; | ||
/** 颜色 */ | ||
color: string; | ||
/** 值 */ | ||
value: string; | ||
/** 是否选中 */ | ||
checked?: boolean; | ||
} | ||
export interface LegendProps { | ||
options: LegendOption[]; | ||
style?: React.CSSProperties; | ||
onChange?: (checked: LegendOption, newOptions: LegendOption[], props: any) => any; // eslint-disable-line | ||
} | ||
|
||
const LegendNode: React.FunctionComponent<LegendProps> = (props) => { | ||
const { | ||
legend, | ||
// apis, | ||
graph, | ||
} = React.useContext(GraphinContext); | ||
// 依然存在两个legend,graphin.context只是一个全局对象 | ||
const { onChange = () => {}, style } = props; | ||
|
||
const { options: defaultOptions, dataMap } = legend.node; | ||
|
||
const [state, setState] = React.useState({ | ||
options: defaultOptions, | ||
}); | ||
|
||
const { options } = state; | ||
|
||
const handleClick = (option: LegendOption) => { | ||
const checkedValue = { ...option, checked: !option.checked }; | ||
const result = options.map((c) => { | ||
const matched = c.value === option.value; | ||
return matched ? checkedValue : c; | ||
}); | ||
setState({ | ||
options: result, | ||
}); | ||
const nodes = dataMap.get(checkedValue.value); | ||
|
||
/** highlight */ | ||
// const nodesId = nodes.map((c) => c.id); | ||
// apis.highlightNodeById(nodesId); | ||
|
||
nodes.forEach((node) => { | ||
graph.setItemState(node.id, 'active', checkedValue.checked); | ||
graph.setItemState(node.id, 'inactice', !checkedValue.checked); | ||
}); | ||
|
||
/** 给用户的回调函数 */ | ||
onChange(checkedValue, result, props); | ||
}; | ||
|
||
return ( | ||
<ul className="graphin-components-legend-content" style={style}> | ||
{options.map((option: LegendOption) => { | ||
const { label, checked, color } = option; | ||
return ( | ||
<li // eslint-disable-line jsx-a11y/no-noninteractive-element-interactions | ||
key={option.value} | ||
className="item" | ||
onClick={() => { | ||
handleClick(option); | ||
}} | ||
onKeyDown={() => { | ||
handleClick(option); | ||
}} | ||
> | ||
<span className="dot" style={{ background: checked ? color : '#ddd' }} /> | ||
<span className="label" style={{ color: checked ? '#000000d9' : '#ddd' }}> | ||
{label} | ||
</span> | ||
</li> | ||
); | ||
})} | ||
</ul> | ||
); | ||
}; | ||
|
||
export default LegendNode; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
ul.graphin-components-legend-content { | ||
display: block; | ||
position: relative; | ||
margin: 0px; | ||
padding: 0px; | ||
li.item { | ||
display: inline-block; | ||
vertical-align: top; | ||
margin: 5px 10px; | ||
cursor: pointer; | ||
& > .dot { | ||
width: 10px; | ||
height: 10px; | ||
border-radius: 50%; | ||
display: inline-block; | ||
} | ||
& > .label { | ||
padding: 0px 5px; | ||
font-size: 12px; | ||
display: inline-block; | ||
vertical-align: baseline; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,175 @@ | ||
import React from 'react'; | ||
import { | ||
GraphinContext, | ||
Graph, | ||
GraphData, | ||
TreeGraphData, | ||
NodeConfig, | ||
EdgeConfig, | ||
GraphinContextType, | ||
} from '@antv/graphin'; | ||
import Node from './Node'; | ||
|
||
export interface LegendProps { | ||
/** 绑定的类型 */ | ||
bindType: 'node' | 'edge'; | ||
/** | ||
* @description 分类映射的Key值 | ||
*/ | ||
sortKey: string; | ||
/** | ||
* @description 颜色映射的Key值 | ||
* @default "style.fill" | ||
*/ | ||
colorKey?: string; | ||
} | ||
export interface OptionType { | ||
/** 颜色 */ | ||
color: string; | ||
/** 值 */ | ||
value: string | number; | ||
/** 标签 */ | ||
label: string; | ||
/** 是否选中 */ | ||
checked: boolean; | ||
} | ||
|
||
const getEnumValue = (keyString: string, data) => { | ||
const keyArray = keyString.split('.'); | ||
const enumValue = keyArray.reduce((acc: {}, curr) => { | ||
return acc[curr] || {}; | ||
}, data) as string; | ||
return enumValue; | ||
}; | ||
|
||
const calculate = ({ | ||
bindType, | ||
sortKey, | ||
graph, | ||
colorKey, | ||
}: { | ||
bindType: LegendProps['bindType']; | ||
sortKey: LegendProps['sortKey']; | ||
graph: Graph; | ||
colorKey: string; | ||
}) => { | ||
const data = graph.save(); | ||
const treeData = data as TreeGraphData; | ||
const graphData = data as GraphData; | ||
const nodeMapByMapKey: Map<string | number, NodeConfig[]> = new Map(); | ||
const edgeMapByMapKey: Map<string | number, EdgeConfig[]> = new Map(); | ||
/** 暂时不支持treeGraph的legend */ | ||
if (treeData.children) { | ||
console.error('not support tree graph'); | ||
return { | ||
dataMap: new Map(), | ||
options: {}, | ||
}; | ||
} | ||
|
||
const { nodes = [], edges = [] } = graphData; | ||
|
||
if (bindType === 'node') { | ||
nodes.forEach((node) => { | ||
/** 得到枚举值 */ | ||
const enumValue = getEnumValue(sortKey, node); | ||
/** 按照枚举值重新将节点存放 */ | ||
const current = nodeMapByMapKey.get(enumValue); | ||
if (current) { | ||
nodeMapByMapKey.set(enumValue, [...current, node]); | ||
} else { | ||
nodeMapByMapKey.set(enumValue, [node]); | ||
} | ||
}); | ||
/** 计算legend.content 的 options */ | ||
const keys = [...nodeMapByMapKey.keys()]; | ||
const options = keys.map((key) => { | ||
const node = (nodeMapByMapKey.get(key) || [{}])[0]; | ||
const color = getEnumValue(colorKey, node); | ||
return { | ||
/** 颜色 */ | ||
color, | ||
/** 值 */ | ||
value: key, | ||
/** 标签 */ | ||
label: key, | ||
/** 是否选中 */ | ||
checked: true, | ||
}; | ||
}); | ||
return { | ||
dataMap: nodeMapByMapKey, | ||
options, | ||
}; | ||
} | ||
// if (bindType === 'edge') { | ||
edges.forEach((edge) => { | ||
/** 得到枚举值 */ | ||
const enumValue = getEnumValue(sortKey, edge); | ||
|
||
const current = edgeMapByMapKey.get(enumValue); | ||
if (current) { | ||
edgeMapByMapKey.set(enumValue, [...current, edge]); | ||
} else { | ||
edgeMapByMapKey.set(enumValue, [edge]); | ||
} | ||
}); | ||
/** 计算legend.content 的 options */ | ||
const keys = [...edgeMapByMapKey.keys()]; | ||
const options = keys.map((key) => { | ||
const edge = (edgeMapByMapKey.get(key) || [{}])[0]; | ||
const color = getEnumValue(colorKey, edge); | ||
return { | ||
/** 颜色 */ | ||
color, | ||
/** 值 */ | ||
value: key, | ||
/** 标签 */ | ||
label: key, | ||
/** 是否选中 */ | ||
checked: true, | ||
}; | ||
}); | ||
|
||
return { dataMap: edgeMapByMapKey, options }; | ||
}; | ||
export interface LegendContextType extends GraphinContextType { | ||
legend: { | ||
node?: { | ||
bindType: string; | ||
sortKey: string; | ||
colorKey: string; | ||
dataMap: Map<string, NodeConfig[]>; | ||
options: OptionType[]; | ||
}; | ||
edge?: { | ||
bindType: string; | ||
sortKey: string; | ||
colorKey: string; | ||
dataMap: Map<string, EdgeConfig[]>; | ||
options: OptionType[]; | ||
}; | ||
}; | ||
} | ||
const Legend: React.FunctionComponent<LegendProps> & { Node: typeof Node } = (props) => { | ||
const graphin = React.useContext<GraphinContextType>(GraphinContext); | ||
const { graph } = graphin; | ||
const { bindType, sortKey, children, colorKey = 'style.fill' } = props; | ||
const { dataMap, options } = calculate({ bindType, sortKey, graph, colorKey }); | ||
|
||
graphin.legend = { | ||
...graphin.legend, | ||
// 一个Graphin组件下,最多仅有2个Legend组件:node和edge | ||
[bindType]: { | ||
bindType, | ||
sortKey, | ||
colorKey, | ||
dataMap, | ||
options, | ||
}, | ||
}; | ||
return <div className="graphin-components-legend">{children}</div>; | ||
}; | ||
|
||
Legend.Node = Node; | ||
export default Legend; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters