diff --git a/packages/gi-assets-basic/src/components/Toolbar/Component.tsx b/packages/gi-assets-basic/src/components/Toolbar/Component.tsx index da6d0878a..5f4849a47 100644 --- a/packages/gi-assets-basic/src/components/Toolbar/Component.tsx +++ b/packages/gi-assets-basic/src/components/Toolbar/Component.tsx @@ -1,4 +1,4 @@ -import { utils } from '@antv/gi-sdk'; +import { useComponents, useContext, utils } from '@antv/gi-sdk'; import React, { memo } from 'react'; import Toolbar from './Toolbar'; const { getPositionStyles } = utils; @@ -10,30 +10,30 @@ export interface ToolbarProps { assets?: any; placement: string; offset: number[]; + GI_CONTAINER: string[]; } +/** + * 获取根据容器资产配置,获取容器内资产实例 + * + * @param context GISDK 上下文 + * @param containers 容器资产 props.containers + * @returns + */ + const ToolbarContainer: React.FunctionComponent = props => { - const { direction = 'horizontal', components, assets, placement, offset } = props; + const { direction = 'horizontal', placement, offset, GI_CONTAINER } = props; + const { assets, config } = useContext(); + const { components } = useComponents(GI_CONTAINER, config, assets); const positionStyles = getPositionStyles(placement, offset); - const sortedComponents = components.sort((a, b) => a.props?.GI_CONTAINER_INDEX - b.props?.GI_CONTAINER_INDEX); return ( <> - {sortedComponents.map(item => { - if (!item) { - return null; - } - const { props: itemProps, id: itemId } = item; - const asset = assets[itemId]; - if (!asset) { - console.warn(`asset: ${itemId} not found`); - return null; - } - const { component: Component } = asset; + {components.map(item => { return ( - - + + ); })} diff --git a/packages/gi-assets-basic/src/elements/SimpleEdge/registerTransform.ts b/packages/gi-assets-basic/src/elements/SimpleEdge/registerTransform.ts index 4a2d6da3d..6f70b0d44 100644 --- a/packages/gi-assets-basic/src/elements/SimpleEdge/registerTransform.ts +++ b/packages/gi-assets-basic/src/elements/SimpleEdge/registerTransform.ts @@ -214,7 +214,7 @@ const transform = (config: GIEdgeConfig, reset?: boolean) => { }, preStyle, ); - console.log('edge.......', id); + // console.log('edge.......', id); return { source, diff --git a/packages/gi-assets-basic/src/elements/SimpleNode/registerTransform.ts b/packages/gi-assets-basic/src/elements/SimpleNode/registerTransform.ts index 1b2ce9b04..8e7aca223 100644 --- a/packages/gi-assets-basic/src/elements/SimpleNode/registerTransform.ts +++ b/packages/gi-assets-basic/src/elements/SimpleNode/registerTransform.ts @@ -263,7 +263,7 @@ const transform = (nodeConfig: GINodeConfig, reset?: boolean) => { }, }, }; - console.log('keyshape', node.id); + // console.log('keyshape', node.id); return { id: node.id, data: { diff --git a/packages/gi-sdk/src/GISDK.tsx b/packages/gi-sdk/src/GISDK.tsx index af5de114d..64044c258 100644 --- a/packages/gi-sdk/src/GISDK.tsx +++ b/packages/gi-sdk/src/GISDK.tsx @@ -3,56 +3,23 @@ import React, { useEffect, useMemo } from 'react'; import { IntlProvider, useIntl } from 'react-intl'; import { useImmer } from 'use-immer'; import { deepClone } from './components/const'; -import getComponents from './hooks/useComponents'; +import { getComponents } from './hooks/useComponents'; +import useConstant from './hooks/useConstant'; import './index.less'; -import { createUuid } from './process/common'; import { getMapperByCfg } from './process/getMapperByCfg'; import type { GIGraphData, Props, State } from './typing'; -let updateHistoryTimer: number; - -const getComponentsCfg = (componentsCfg, pageLayout) => { - let GICC_LAYOUT = { id: 'EmptyLayout', props: {} }; - let INITIALIZER; - if (pageLayout) GICC_LAYOUT = pageLayout; - componentsCfg.forEach(item => { - if (pageLayout) { - if (item.id === pageLayout.id) { - GICC_LAYOUT = item; - return; - } - } else if (item.type === 'GICC_LAYOUT') { - GICC_LAYOUT = item; - return; - } - if (item.type === 'INITIALIZER' || item.props.GI_INITIALIZER) { - INITIALIZER = item; - return; - } - }); - return { componentsCfg, GICC_LAYOUT, INITIALIZER }; -}; - const GISDK = (props: Props) => { const { children, assets, id, services, locales } = props; - const { language = 'zh-CN', ...localeMessages } = locales || {}; - - /** get gisdk id */ - const GISDK_ID = React.useMemo(() => { - if (!id) { - const defaultId = `${Math.random().toString(36).substr(2)}`; - console.warn(`⚠️: props.id 缺失,默认生成 GISDK_ID : ${defaultId} 用于多实例管理`); - return defaultId; - } - return id; - }, []); - const { components: ComponentAssets, elements: ElementAssets, layouts: LayoutAssets } = assets; + const { language = 'zh-CN', ...localeMessages } = locales || {}; // registerShapes(ElementAssets); // registerLayouts(LayoutAssets); const [state, updateState] = useImmer({ + config: props.config, + layout: props.config.layout.props, data: { nodes: [], edges: [] } as GIGraphData, propertyGraphData: undefined, schemaData: { @@ -62,7 +29,7 @@ const GISDK = (props: Props) => { }, HAS_GRAPH: false, source: { nodes: [], edges: [] } as GIGraphData, - config: props.config, + isLoading: false, isContextReady: false, initialized: false, @@ -76,170 +43,73 @@ const GISDK = (props: Props) => { const { data, HAS_GRAPH, graph, config } = state; /** 计算逻辑 */ const { layout: layoutCfg, components: componentsCfg = [], nodes: nodesCfg, edges: edgesCfg, pageLayout } = config; + const constants = useConstant(id, state, updateState); + const { GISDK_ID } = constants; + /** + * 响应 graph 的变化 + */ const handleGraphInit = ins => { updateState(draft => { draft.graph = ins; draft.HAS_GRAPH = true; }); }; - + /** + * 响应 props.config 变化 + */ useEffect(() => { console.log('gisdk props config change.....'); updateState(draft => { draft.config = props.config; + //@ts-ignore + draft.layout = props.config.layout.props; }); }, [props.config]); - const { GICC_LAYOUT, INITIALIZER, ComponentCfg } = useMemo(() => { - const { GICC_LAYOUT, INITIALIZER, componentsCfg: ComponentCfg } = getComponentsCfg(componentsCfg, pageLayout); - return { - GICC_LAYOUT, - INITIALIZER, - ComponentCfg, - }; - }, [componentsCfg, pageLayout, HAS_GRAPH]); - - const sourceDataMap = useMemo(() => { - const nodes = state.source.nodes.reduce((acc, cur) => { - acc[cur.id] = cur; - return acc; - }, {}); - - const edges = state.source.edges.reduce((acc, cur) => { - acc[cur.id] = cur; - return acc; - }, {}); - - return { - nodes, - edges, - }; - }, [state.source]); - - const stopForceSimulation = () => { - // if (graphinRef.current) { - // const { layout, graph } = graphinRef.current; - // const { instance } = layout; - // if (instance) { - // const { type, simulation } = instance; - // if (type === 'graphin-force') { - // simulation.stop(); - // return; - // } - // } - // const layoutController = graph.get('layoutController'); - // const layoutMethod = layoutController.layoutMethods?.[0]; - // if (layoutMethod?.type === 'force2') { - // layoutMethod.stop(); - // } - // } - }; - const restartForceSimulation = (nodes = []) => { - // if (graphinRef.current) { - // const { layout: graphLayout, graph } = graphinRef.current; - // const { instance } = graphLayout; - // if (instance) { - // const { type, simulation } = instance; - // if (type === 'graphin-force') { - // simulation.restart(nodes, graph); - // return; - // } - // } - // const layoutController = graph.get('layoutController'); - // const layoutMethod = layoutController.layoutMethods?.[0]; - // if (layoutMethod?.type === 'force2') { - // graph.updateLayout({ animate: true, disableTriggerLayout: false }); - // updateState(draft => { - // draft.layout.animate = true; - // }); - // } - // } - }; - - console.log('%c GISDK RENDER....', 'color:rgba(255,87,34,1)', HAS_GRAPH, state.initialized, state); + /** + * 响应 config.components 变化,重新渲染组件 + */ + const { renderComponents, InitializerComponent, InitializerProps, GICC_LAYOUT_COMPONENT, GICC_LAYOUT_PROPS } = + useMemo(() => { + return getComponents(componentsCfg, pageLayout, ComponentAssets); + }, [componentsCfg, pageLayout, HAS_GRAPH]); + /** + * 响应 config.layout 变化,重新布局 + */ const layout = useMemo(() => { return deepClone(layoutCfg.props); }, [layoutCfg]); - const { renderComponents, InitializerComponent, InitializerProps, GICC_LAYOUT_COMPONENT, GICC_LAYOUT_PROPS } = - getComponents({ - config: { pageLayout, components: ComponentCfg }, - initializer: INITIALIZER, - GICC_LAYOUT, - components: ComponentCfg, - GISDK_ID, - propsComponentsCfg: ComponentCfg, - ComponentAssets, - }); - - /** 节点样式映射 */ + /** + * 响应 config.nodes 变化,重新设置节点样式 + */ const nodeMapper = useMemo(() => getMapperByCfg(nodesCfg, ElementAssets), [nodesCfg]); - /** 边样式映射 */ + /** + * 响应 config.edges 变化,重新设置节点样式 + */ const edgeMapper = useMemo(() => getMapperByCfg(edgesCfg, ElementAssets), [edgesCfg]); + /** + * 组装 context value + */ const ContextValue = { ...state, + ...constants, layout, GISDK_ID, - services, - assets, - sourceDataMap, HAS_GRAPH, graph, updateContext: updateState, - updateData: res => { - updateState(draft => { - const newData = res; - draft.data = newData; - draft.source = newData; - draft.layoutCache = false; - }); - }, - updateLayout: res => { - updateState(draft => { - draft.config.layout = res; - draft.layoutCache = false; - }); - }, - updateDataAndLayout: (res, lay) => { - updateState(draft => { - const newData = res; - draft.data = newData; - draft.source = newData; - draft.config.layout = lay; - draft.layoutCache = false; - }); - }, - // 更新历史记录 - updateHistory: param => { - const time = new Date().getTime(); - - const fn = () => { - updateState(draft => { - // @ts-ignore - draft.history = (draft.history || []).concat([ - { - id: createUuid(), - timestamp: time, - ...param, - }, - ]); - }); - }; - // 防止频繁更新导致的重复 updateHistory - // 同时,间隔一定时间再更新到历史栈中,保证画布数据已经更新完成 - if (updateHistoryTimer) window.clearTimeout(updateHistoryTimer); - updateHistoryTimer = window.setTimeout(fn, 500); - }, - stopForceSimulation: stopForceSimulation, - restartForceSimulation: restartForceSimulation, + /** props */ + assets, + services, locales, useIntl, language, }; - + console.log('%c GISDK RENDER....', 'color:rgba(255,87,34,1)', HAS_GRAPH, state.initialized, state); return (
{/* @ts-ignore */} diff --git a/packages/gi-sdk/src/hooks/useComponents.tsx b/packages/gi-sdk/src/hooks/useComponents.tsx index b4d8d17d9..2762f5ecb 100644 --- a/packages/gi-sdk/src/hooks/useComponents.tsx +++ b/packages/gi-sdk/src/hooks/useComponents.tsx @@ -11,17 +11,36 @@ const DEFAULT_GICC_LAYOUT = { }, }; -const useComponents = ({ - config, - initializer, - GICC_LAYOUT, - components, - GISDK_ID, - propsComponentsCfg, - ComponentAssets, -}) => { - const { components: stateComponentsCfg } = config; - const ComponentCfgMap = propsComponentsCfg.concat(stateComponentsCfg).reduce((acc, curr) => { +/** + * 兼容过去几个版本的不规范配置,计算真正的 components 和 container + * @param components + * @param pageLayout + * @returns + */ +const getComponentsCfg = (components, pageLayout) => { + let container = { id: 'EmptyLayout', props: {} }; + let initializer; + + components.forEach(item => { + if (item.type === 'INITIALIZER' || item.props.GI_INITIALIZER) { + initializer = item; + return; + } + if (pageLayout) { + container = pageLayout; + return; + } + if (item.type === 'GICC_LAYOUT') { + container = item; + return; + } + }); + return { components, GICC_LAYOUT: container, initializer }; +}; + +export const getComponents = (components, pageLayout, ComponentAssets) => { + const { GICC_LAYOUT, initializer } = getComponentsCfg(components, pageLayout); + const ComponentCfgMap = components.reduce((acc, curr) => { return { ...acc, [curr.id]: curr, @@ -33,12 +52,12 @@ const useComponents = ({ const { props: InitializerProps } = ComponentCfgMap[initializer.id]; // 默认使用空布局,graph ready 了才使用 config.pageLayout,避免 pageLayout 中的资产在 graph 实例之前调用 graph - const { component: GICC_LAYOUT_COMPONENT } = ComponentAssets[config.pageLayout?.id || GICC_LAYOUT.id] || { + const { component: GICC_LAYOUT_COMPONENT } = ComponentAssets[pageLayout?.id || GICC_LAYOUT.id] || { component: DEFAULT_GICC_LAYOUT.component, }; // 页面布局组件的 props 从 context.config.pageLayout 中读取,统一 pageLayout 读写方式 - const { props: GICC_LAYOUT_PROPS } = config.pageLayout || + const { props: GICC_LAYOUT_PROPS } = pageLayout || ComponentCfgMap[GICC_LAYOUT.id] || { props: DEFAULT_GICC_LAYOUT.props, }; @@ -82,16 +101,7 @@ const useComponents = ({ }; } - return ( - - ); + return ; }); }; @@ -104,11 +114,49 @@ const useComponents = ({ GICC_LAYOUT_PROPS: { ComponentCfgMap, assets: ComponentAssets, - GISDK_ID, ...GICC_LAYOUT_PROPS, }, isPageLayoutReady: true, }; }; -export default useComponents; +/** + * + * @param container ['ZoomIn','ZoomOut'] + * @param config GI 配置文件 + * @param assets GI 资产 + */ +export const useComponents = (container, config, assets) => { + const componentsCfgMap = config.components.reduce((acc, curr) => { + return { + ...acc, + [curr.id]: curr, + }; + }, {}); + const getComponentById = (componentId: string) => { + if (!componentId) { + return null; + } + const asset = assets.components[componentId]; + const assetConfig = componentsCfgMap[componentId]; + if (!asset || !assetConfig) { + console.warn(`asset: ${componentId} not found`); + return null; + } + const { icon } = assetConfig.props?.GIAC_CONTENT || asset.info; + return { + icon, + id: componentId, + info: asset.info, + props: assetConfig.props, + component: asset.component, + }; + }; + + return React.useMemo(() => { + return { + components: container.map(getComponentById).filter(c => c), + componentsCfgMap, + }; + }, [config.components, container]); +}; diff --git a/packages/gi-sdk/src/hooks/useConstant.tsx b/packages/gi-sdk/src/hooks/useConstant.tsx new file mode 100644 index 000000000..fd27bc181 --- /dev/null +++ b/packages/gi-sdk/src/hooks/useConstant.tsx @@ -0,0 +1,129 @@ +import { useMemo } from 'react'; +import { createUuid } from '../process/common'; +let updateHistoryTimer: number; +const useConstant = (id, state, updateState) => { + const stopForceSimulation = () => { + // if (graphinRef.current) { + // const { layout, graph } = graphinRef.current; + // const { instance } = layout; + // if (instance) { + // const { type, simulation } = instance; + // if (type === 'graphin-force') { + // simulation.stop(); + // return; + // } + // } + // const layoutController = graph.get('layoutController'); + // const layoutMethod = layoutController.layoutMethods?.[0]; + // if (layoutMethod?.type === 'force2') { + // layoutMethod.stop(); + // } + // } + }; + const restartForceSimulation = (nodes = []) => { + // if (graphinRef.current) { + // const { layout: graphLayout, graph } = graphinRef.current; + // const { instance } = graphLayout; + // if (instance) { + // const { type, simulation } = instance; + // if (type === 'graphin-force') { + // simulation.restart(nodes, graph); + // return; + // } + // } + // const layoutController = graph.get('layoutController'); + // const layoutMethod = layoutController.layoutMethods?.[0]; + // if (layoutMethod?.type === 'force2') { + // graph.updateLayout({ animate: true, disableTriggerLayout: false }); + // updateState(draft => { + // draft.layout.animate = true; + // }); + // } + // } + }; + const sourceDataMap = useMemo(() => { + const nodes = state.source.nodes.reduce((acc, cur) => { + acc[cur.id] = cur; + return acc; + }, {}); + + const edges = state.source.edges.reduce((acc, cur) => { + acc[cur.id] = cur; + return acc; + }, {}); + + return { + nodes, + edges, + }; + }, [state.source]); + const transform = d => { + console.warn('transform 函数已经废弃,请使用 update config 的方式'); + return d; + }; + const updateData = res => { + updateState(draft => { + const newData = res; + draft.data = newData; + draft.source = newData; + draft.layoutCache = false; + }); + }; + const updateLayout = res => { + updateState(draft => { + draft.config.layout = res; + draft.layoutCache = false; + }); + }; + const updateDataAndLayout = (res, lay) => { + updateState(draft => { + const newData = res; + draft.data = newData; + draft.source = newData; + draft.config.layout = lay; + draft.layoutCache = false; + }); + }; + // 更新历史记录 + const updateHistory = param => { + const time = new Date().getTime(); + const fn = () => { + updateState(draft => { + // @ts-ignore + draft.history = (draft.history || []).concat([ + { + id: createUuid(), + timestamp: time, + ...param, + }, + ]); + }); + }; + // 防止频繁更新导致的重复 updateHistory + // 同时,间隔一定时间再更新到历史栈中,保证画布数据已经更新完成 + if (updateHistoryTimer) window.clearTimeout(updateHistoryTimer); + updateHistoryTimer = window.setTimeout(fn, 500); + }; + /** get gisdk id */ + const GISDK_ID = useMemo(() => { + if (!id) { + const defaultId = `${Math.random().toString(36).substr(2)}`; + console.warn(`⚠️: props.id 缺失,默认生成 GISDK_ID : ${defaultId} 用于多实例管理`); + return defaultId; + } + return id; + }, []); + + return { + stopForceSimulation, + restartForceSimulation, + sourceDataMap, + transform, + updateData, + updateDataAndLayout, + updateHistory, + updateLayout, + GISDK_ID, + }; +}; +export default useConstant; diff --git a/packages/gi-sdk/src/index.tsx b/packages/gi-sdk/src/index.tsx index d461d442d..32b0d17c5 100644 --- a/packages/gi-sdk/src/index.tsx +++ b/packages/gi-sdk/src/index.tsx @@ -21,6 +21,7 @@ export { default as SimpleNode } from './components/SimpleNode'; /** default assets */ export { default as Studio } from './components/Studio'; export { Info } from './constants/info'; +export { useComponents } from './hooks/useComponents'; export { default as useContainer } from './hooks/useContainer'; export { Shortcuts, useShortcuts } from './utils'; export { common }; diff --git a/packages/gi-sdk/src/typing.ts b/packages/gi-sdk/src/typing.ts index 3d9c2d39a..3ab002a49 100644 --- a/packages/gi-sdk/src/typing.ts +++ b/packages/gi-sdk/src/typing.ts @@ -1,7 +1,8 @@ import type { ComboModel as Combo } from '@antv/g6'; -import type { GraphinContextType, GraphinData, IUserEdge, IUserNode } from '@antv/graphin'; +import type { GraphinContextType, GraphinData, IUserEdge, IUserNode, Layout } from '@antv/graphin'; import type { LANGUAGE_KEY_NAME } from './process/locale'; import type { GraphSchemaData, IGraphData } from './process/schema'; + export type { GraphSchemaData }; export interface State< G extends { @@ -21,7 +22,7 @@ export interface State< restartForceSimulation: (nodes?: []) => void; /** graphinsight */ - + layout: Layout; /** 最原始的数据,本地数据或者服务端返回的数据,未经过视觉映射 */ rawData: G; /** 当前画布渲染的数据,经过视觉映射 */ diff --git a/packages/graphin/src/Graphin.tsx b/packages/graphin/src/Graphin.tsx index b90ee5d0a..7afe3aaa3 100644 --- a/packages/graphin/src/Graphin.tsx +++ b/packages/graphin/src/Graphin.tsx @@ -30,7 +30,7 @@ const Graphin: React.FunctionComponent = forwardRef((props, ref) = onInit, node = nodeStyleTransform, edge = edgeStyleTransform, - renderer = 'canvas', + renderer = 'webgl', ...options } = props;