diff --git a/README.md b/README.md index 321be88..183a8aa 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,20 @@ - Supports exporting chart as a picture or pdf document - Supports pan and zoom - Allows user to customize the internal structure for every node +- Allows user to fetch nodes from server and add to chart(lazyload) + +## Chart Node + +```js +type node = { + id: string + isLeaf?: boolean + defaultExpanded?: boolean + children: node[] +``` + +you can add other fields to the model. + ## Props @@ -103,6 +117,12 @@ + + + + + +
0.5 User can zoom the chart at different scales(0.5~7).
loadDatafunctionThis function takes the node as an argument and returns a Promise. Promise should return a list of child nodes in resolve: (node) => Promise< node[] >
diff --git a/package.json b/package.json index d9a5e47..a497ea5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@dabeng/react-orgchart", - "version": "1.0.0", + "version": "1.1.0", "main": "./dist/ChartContainer.js", "files": [ "dist", @@ -76,4 +76,4 @@ "last 1 safari version" ] } -} +} \ No newline at end of file diff --git a/src/App.js b/src/App.js index 2178be0..1847a18 100644 --- a/src/App.js +++ b/src/App.js @@ -8,6 +8,7 @@ import ExportChart from "./export-chart/export-chart"; import DragDropChart from "./drag-drop-chart/drag-drop-chart"; import EditChart from "./edit-chart/edit-chart"; import EditNode from "./edit-node/edit-node"; +import lazyloadChart from "./lazyload/lazyload-chart"; import "./App.css"; const App = () => { @@ -19,6 +20,7 @@ const App = () => { Deault Chart Pan & Zoom Chart Custom Node Chart + LazyLoad Chart Export Chart Drap & Drop Chart Edit Chart @@ -29,6 +31,7 @@ const App = () => { + diff --git a/src/components/ChartContainer.js b/src/components/ChartContainer.js index 44d8947..cf2d0e8 100644 --- a/src/components/ChartContainer.js +++ b/src/components/ChartContainer.js @@ -26,7 +26,8 @@ const propTypes = { collapsible: PropTypes.bool, multipleSelect: PropTypes.bool, onClickNode: PropTypes.func, - onClickChart: PropTypes.func + onClickChart: PropTypes.func, + loadData: PropTypes.func }; const defaultProps = { @@ -56,14 +57,15 @@ const ChartContainer = forwardRef( collapsible, multipleSelect, onClickNode, - onClickChart + onClickChart, + loadData }, ref ) => { + const container = useRef(); const chart = useRef(); const downloadButton = useRef(); - const [startX, setStartX] = useState(0); const [startY, setStartY] = useState(0); const [transform, setTransform] = useState(""); @@ -74,8 +76,12 @@ const ChartContainer = forwardRef( const [download, setDownload] = useState(""); const attachRel = (data, flags) => { - data.relationship = - flags + (data.children && data.children.length > 0 ? 1 : 0); + if (data.isLeaf === undefined) { + data.isLeaf = true; + } + + data.relationship = flags + ((data.children && !!data.children.length) || !data.isLeaf ? 1 : 0); + if (data.children) { data.children.forEach(function(item) { attachRel(item, "1" + (data.children.length > 1 ? 1 : 0)); @@ -84,11 +90,17 @@ const ChartContainer = forwardRef( return data; }; - const [ds, setDS] = useState(datasource); useEffect(() => { setDS(datasource); }, [datasource]); + const [ds, setDS] = useState(datasource); + + const onLoadData = async (datasource, children) => { + await dsDigger.updateNode({ ...datasource, children }); + setDS({ ...dsDigger.ds }); + }; + const dsDigger = new JSONDigger(datasource, "id", "children"); const clickChartHandler = event => { @@ -212,12 +224,12 @@ const ChartContainer = forwardRef( orientation: "landscape", unit: "px", format: [canvasWidth, canvasHeight] - }) + }) : new jsPDF({ orientation: "portrait", unit: "px", format: [canvasHeight, canvasWidth] - }); + }); doc.addImage(canvas.toDataURL("image/jpeg", 1.0), "JPEG", 0, 0); doc.save(exportFilename + ".pdf"); }; @@ -291,7 +303,7 @@ const ChartContainer = forwardRef( "isAncestorsCollapsed" ); }); - } + }, })); return ( @@ -318,6 +330,8 @@ const ChartContainer = forwardRef( multipleSelect={multipleSelect} changeHierarchy={changeHierarchy} onClickNode={onClickNode} + loadData={loadData} + onLoadData={onLoadData} /> diff --git a/src/components/ChartNode.css b/src/components/ChartNode.css index 470fac8..bf4a5c8 100644 --- a/src/components/ChartNode.css +++ b/src/components/ChartNode.css @@ -1,4 +1,3 @@ - .orgchart ul { padding-left: 0; text-align: center; diff --git a/src/components/ChartNode.js b/src/components/ChartNode.js index a2f1a47..23bc42b 100644 --- a/src/components/ChartNode.js +++ b/src/components/ChartNode.js @@ -10,7 +10,9 @@ const propTypes = { collapsible: PropTypes.bool, multipleSelect: PropTypes.bool, changeHierarchy: PropTypes.func, - onClickNode: PropTypes.func + onClickNode: PropTypes.func, + loadData: PropTypes.func, + onLoadData: PropTypes.func, }; const defaultProps = { @@ -26,14 +28,15 @@ const ChartNode = ({ collapsible, multipleSelect, changeHierarchy, - onClickNode + onClickNode, + loadData, + onLoadData }) => { const node = useRef(); - - const [isChildrenCollapsed, setIsChildrenCollapsed] = useState(false); + const [isChildrenCollapsed, setIsChildrenCollapsed] = useState(!datasource.defaultExpanded); const [topEdgeExpanded, setTopEdgeExpanded] = useState(); const [rightEdgeExpanded, setRightEdgeExpanded] = useState(); - const [bottomEdgeExpanded, setBottomEdgeExpanded] = useState(); + const [bottomEdgeExpanded, setBottomEdgeExpanded] = useState(datasource.defaultExpanded); const [leftEdgeExpanded, setLeftEdgeExpanded] = useState(); const [allowedDrop, setAllowedDrop] = useState(false); const [selected, setSelected] = useState(false); @@ -148,10 +151,21 @@ const ChartNode = ({ toggleAncestors(e.target.closest("li")); }; - const bottomEdgeClickHandler = e => { + const addChildrenHandler = children => { + onLoadData(datasource, children); + setIsChildrenCollapsed(false); + setBottomEdgeExpanded(true); + }; + + const bottomEdgeClickHandler = async e => { e.stopPropagation(); - setIsChildrenCollapsed(!isChildrenCollapsed); - setBottomEdgeExpanded(!bottomEdgeExpanded); + if (loadData && !!!datasource.children) { + const children = await loadData(datasource); + addChildrenHandler(children); + } else { + setIsChildrenCollapsed(!isChildrenCollapsed); + setBottomEdgeExpanded(!bottomEdgeExpanded); + } }; const toggleSiblings = actionNode => { @@ -235,6 +249,11 @@ const ChartNode = ({ ); }; + const setCollapse = collapse => { + setIsChildrenCollapsed(collapse); + setBottomEdgeExpanded(!collapse); + }; + return (
  • {NodeTemplate ? ( - + ) : ( - <> -
    - {datasource.relationship && - datasource.relationship.charAt(2) === "1" && ( - - )} - {datasource.name} -
    -
    {datasource.title}
    - - )} + <> +
    + {datasource.relationship && + datasource.relationship.charAt(2) === "1" && ( + + )} + {datasource.name} +
    +
    {datasource.title}
    + + )} {collapsible && datasource.relationship && datasource.relationship.charAt(0) === "1" && ( )} @@ -283,23 +305,23 @@ const ChartNode = ({ datasource.relationship.charAt(1) === "1" && ( <> @@ -308,13 +330,13 @@ const ChartNode = ({ datasource.relationship && datasource.relationship.charAt(2) === "1" && ( )} @@ -332,6 +354,8 @@ const ChartNode = ({ multipleSelect={multipleSelect} changeHierarchy={changeHierarchy} onClickNode={onClickNode} + loadData={loadData} + onLoadData={onLoadData} /> ))} diff --git a/src/custom-node-chart/custom-node-chart.js b/src/custom-node-chart/custom-node-chart.js index db9d16f..eb4d415 100644 --- a/src/custom-node-chart/custom-node-chart.js +++ b/src/custom-node-chart/custom-node-chart.js @@ -6,7 +6,7 @@ const CustomNodeChart = () => { const ds = { id: "n1", name: "Lao Lao", - title: "general manager", + title: "general manager", children: [ { id: "n2", name: "Bo Miao", title: "department manager" }, { @@ -40,4 +40,4 @@ const CustomNodeChart = () => { return ; }; -export default CustomNodeChart; +export default CustomNodeChart; \ No newline at end of file diff --git a/src/custom-node-chart/my-node.js b/src/custom-node-chart/my-node.js index 7e5ab52..c619704 100644 --- a/src/custom-node-chart/my-node.js +++ b/src/custom-node-chart/my-node.js @@ -21,4 +21,4 @@ const MyNode = ({ nodeData }) => { MyNode.propTypes = propTypes; -export default MyNode; +export default MyNode; \ No newline at end of file diff --git a/src/lazyload/custom-node.css b/src/lazyload/custom-node.css new file mode 100644 index 0000000..e8cfb4c --- /dev/null +++ b/src/lazyload/custom-node.css @@ -0,0 +1,36 @@ +.orgchart.lazyload-chart { + background-image: linear-gradient( + 90deg, + rgba(33, 90, 136, 0.15) 10%, + rgba(0, 0, 0, 0) 10% + ), + linear-gradient(rgba(33, 90, 136, 0.15) 10%, rgba(0, 0, 0, 0) 10%) !important; +} + +.orgchart.lazyload-chart > ul > li > ul li::before { + border-top-color: #F7C374; +} + +.orgchart.lazyload-chart > ul > li > ul li .oc-node::before, +.orgchart.lazyload-chart ul li .oc-node:not(:only-child)::after { + background-color: #F7C374; +} + +.orgchart.lazyload-chart .oc-node .position { + box-sizing: border-box; + background-color: #F7C374; + color: #fff; + width: 130px; + height: 65px; + padding: 2px; +} + +.orgchart.lazyload-chart .oc-node .fullname { + box-sizing: border-box; + color: #215a88; + background-color: #fff; + width: 130px; + height: 65px; + padding: 2px; + border: 1px solid#F7C374; +} diff --git a/src/lazyload/custom-node.js b/src/lazyload/custom-node.js new file mode 100644 index 0000000..3cb8704 --- /dev/null +++ b/src/lazyload/custom-node.js @@ -0,0 +1,21 @@ +import React from "react"; +import PropTypes from "prop-types"; +import "./custom-node.css"; + +const propTypes = { + nodeData: PropTypes.object.isRequired, +}; + +const MyNode = ({ nodeData, addChildren, setCollapse}) => { + + return ( +
    +
    {nodeData.title}
    +
    {nodeData.name}
    +
    + ); +}; + +MyNode.propTypes = propTypes; + +export default MyNode; diff --git a/src/lazyload/lazyload-chart.js b/src/lazyload/lazyload-chart.js new file mode 100644 index 0000000..9062f67 --- /dev/null +++ b/src/lazyload/lazyload-chart.js @@ -0,0 +1,29 @@ +import React from "react"; +import OrganizationChart from "../components/ChartContainer"; +import MyNode from "./custom-node"; + +export const loadDataAsync = (node) => { + return new Promise((resolve, reject) => { + resolve([ + { id: "n2", name: "Bo Miao", title: "department manager" }, + { + id: "n3", + name: "Su Miao", + title: "department manager", + } + ]) + }) +} + +const lazyloadChart = () => { + const ds = { + id: "n1", + name: "Lao Lao", + title: "general manager", + }; + + + return ; +}; + +export default lazyloadChart;