diff --git a/package.json b/package.json index 2ec542988..be6fe01dc 100644 --- a/package.json +++ b/package.json @@ -4,8 +4,9 @@ "pnpm": "^8" }, "scripts": { - "preinstall": "npx only-allow pnpm && npm run check-gitmodules", - "check-gitmodules": "test -d packages/graphin/.git || git clone -b v3 https://github.com/antvis/Graphin.git packages/graphin", + "preinstall": "npx only-allow pnpm && npm run add-gitmodule-graphin", + "add-gitmodule-graphin": "test -d packages/graphin/.git || git clone -b v3 https://github.com/antvis/Graphin.git packages/graphin", + "setup:tugraph-db": "node scripts/setupProject.js https://github.com/TuGraph-family/gi-assets-tugraph-db.git packages/gi-assets-tugraph-db", "build:all:es": "turbo run build:es", "build:all:umd": "turbo run build:umd --no-cache", "start": "cd packages/gi-site && npm run start", diff --git a/packages/gi-sdk/docs/Testing.md b/packages/gi-sdk/docs/Testing.md index 0c55de1fc..99d5aabc4 100644 --- a/packages/gi-sdk/docs/Testing.md +++ b/packages/gi-sdk/docs/Testing.md @@ -1,14 +1,102 @@ --- -title: 本地测试 +title: 组件测试 order: 1 group: - path: /quick-start - title: 快速开始 - order: 3 + path: /gi-sdk + title: GISDK + order: 0 nav: title: GISDK path: /sdk order: 1 --- -GISDK_TESTING 介绍 +`@antv/gi-sdk` 提供了 `GISDK_TEST` 组件,用于组件的本地测试,而无需在 G6VP 站点中研发。相比 GISDK 而言,它不用写繁琐的 Config 配置,而是通过资产包的 `registerMeta` 信息自动生成初始化配置,再配合「Setting」的按钮,可视化调整配置,模拟资产在 G6VP 产品中的表现。如下图所示 + +```jsx +import * as React from 'react'; +import { GISDK_TEST } from '@antv/gi-sdk'; +import * as Assets from '@antv/gi-assets-basic'; + +const services = [ + { + id: `GI/PropertiesPanel`, + service: params => { + const { data } = params; + return new Promise(resolve => { + return resolve(data); + }); + }, + }, +]; + +const App = () => { + return ( +
+ +
+ ); +}; + +export default App; +``` + +## 详细解析 + +组件拥有 3 个属性,`assets`和 `services` 和 GISDK 的属性保持一致。`activeAssets` 用于告知需要哪些激活的资产,这对于资产的单独测试很有帮助。 + +| 属性 | 类型 | 描述 | +| -------------- | ------------------------- | ---------- | +| `assets` | `GIAssets` | 资产包 | +| `activeAssets` | `{id:string;type:string}` | 激活的资产 | +| `services` | `string` | 资产服务 | + +如代码所示 + +```jsx | pure +import * as React from 'react'; +import { GISDK_TEST } from '@antv/gi-sdk'; +import * as Assets from '@antv/gi-assets-basic'; + +const services = [ + { + id: `GI/PropertiesPanel`, + service: params => { + const { data } = params; + return new Promise(resolve => { + return resolve(data); + }); + }, + }, +]; + +const App = () => { + return ( +
+ +
+ ); +}; + +export default App; +``` diff --git a/packages/gi-sdk/docs/demos/gi-export.tsx b/packages/gi-sdk/docs/demos/gi-export.tsx new file mode 100644 index 000000000..7214552a1 --- /dev/null +++ b/packages/gi-sdk/docs/demos/gi-export.tsx @@ -0,0 +1,188 @@ +import * as BaiscAssets from '@antv/gi-assets-basic'; +import GISDK from '@antv/gi-sdk'; +import * as React from 'react'; +import { data, edgesCfg as defaultEdgesCfg, nodesCfg as defaultNodesCfg, schemaData } from '../demos/const'; +import type { GIComponentAssets, GIService } from './typing'; + +const defaultServices: GIService[] = [ + { + name: '初始化查询', + method: 'GET', + id: 'GI/GI_SERVICE_INTIAL_GRAPH', + service: async () => { + return new Promise(resolve => { + resolve(data); + }); + }, + }, + { + name: '查询图模型', + method: 'GET', + id: 'GI/GI_SERVICE_SCHEMA', + service: async () => { + return new Promise(resolve => { + resolve(schemaData); + }); + }, + }, +]; + +const appendAssets = assets => { + return { + ...assets, + components: { + ...assets.components, + ...BaiscAssets.components, + }, + }; +}; +const calcProps = props => { + const { + activeAssets: activeAssetsInfo, + + nodes = defaultNodesCfg, + edges = defaultEdgesCfg, + } = props; + const services = [...(props.services || []), ...defaultServices]; + const activeAssetsKey = activeAssetsInfo.map(item => item.id); + const assets = appendAssets(props.assets); + /** 得到资产的运行时配置 */ + const CMPS_CONFIG = getComponentsByAssets( + assets.components as GIComponentAssets, + { nodes: [], edges: [] }, + services, + //@ts-ignore + {}, + { nodes: [], edges: [] }, + 'GI', + ); + + /** 根据清单,拆分不同类型的资产 */ + const KEYS_LAYOUT: string[] = []; + const KEYS_ELEMENTS: string[] = []; + const KEYS_COMPONENTS: string[] = []; + + const KEYS_GICC_LAYOUT: string[] = []; //布局容器 + const KEYS_GICC_MENU: string[] = []; //右键菜单容器 + const KEYS_GICC: string[] = []; //内容容器 + + const KEYS_GIAC_CONTENT: string[] = []; //内容原子资产 + const KEYS_GIAC_MENU: string[] = []; //菜单原子资产 + const KEYS_GIAC: string[] = []; //原子资产 + + activeAssetsInfo.forEach(item => { + const { type, id } = item; + if (type === 'NODE' || type === 'EDGE') { + KEYS_ELEMENTS.push(id); + return; + } + if (type === 'LAYOUT') { + KEYS_LAYOUT.push(id); + return; + } + /** 剩下的都是分析组件 */ + KEYS_COMPONENTS.push(id); + + if (type === 'GICC_LAYOUT') { + KEYS_GICC_LAYOUT.push(id); + } + if (type === 'GICC_MENU') { + KEYS_GICC_MENU.push(id); + } + if (type === 'GICC') { + KEYS_GICC.push(id); + } + if (type === 'GIAC') { + KEYS_GIAC.push(id); + } + if (type === 'GIAC_MENU') { + KEYS_GIAC_MENU.push(id); + } + if (type === 'GIAC_CONTENT') { + KEYS_GIAC_CONTENT.push(id); + } + }); + + const activeAssetsKeys = { + /** 追加默认必须存在的资产,防止用户漏选而导致运行报错 */ + components: [ + ...new Set([ + ...KEYS_COMPONENTS, + 'MetaConfig', + 'Initializer', + 'CanvasSetting', + 'SegmentedLayout', + 'Toolbar', + 'ContextMenu', + ]), + ], + + layouts: [...new Set([...KEYS_LAYOUT, 'Force'])], + elements: [...new Set([...KEYS_ELEMENTS, 'SimpleNode', 'SimpleEdge'])], + }; + + let GICC_LAYOUT; // 容器资产的配置详情 + const components: any[] = []; + CMPS_CONFIG.forEach(c => { + if (!c) return; + const item = { + id: c.id, + mame: c.name, + info: c.info, + props: c.props, + }; + if (item && activeAssetsKeys.components.indexOf(item.id) !== -1) { + components.push(item); + const { type } = item.info; + if (type === 'GICC_LAYOUT') GICC_LAYOUT = item; + } + }); + + try { + // 手动集成「布局容器」「画布容器」的原子资产 + GICC_LAYOUT.props.containers[0].GI_CONTAINER = KEYS_GIAC_CONTENT; + components.forEach(item => { + if (item.id === 'ContextMenu') { + item.props.GI_CONTAINER = KEYS_GIAC_MENU; + } + if (item.id === 'Toolbar') { + item.props.GI_CONTAINER = KEYS_GIAC; + } + if (item.id === 'MetaConfig') { + item.props = { activeIds: activeAssetsKey }; + } + }); + } catch (error) { + console.log(error); + } + + return { + config: { + components, + layout: { + // id: activeAssetsKeys.layouts[0], + id: 'Force2', + props: { + type: 'force', + presetLayout: {}, + }, + }, + nodes: nodes, + edges: edges, + pageLayout: GICC_LAYOUT, + }, + assets, + services, + }; +}; +const GISDK_TEST: React.FunctionComponent = props => { + const { config, assets, services } = calcProps(props); + + return ( +
+ +
+ ); +}; + +export default GISDK_TEST; diff --git a/packages/gi-sdk/docs/demos/gi-sdk.tsx b/packages/gi-sdk/docs/demos/gi-sdk.tsx index 2a453b91e..05bb5cd8c 100644 --- a/packages/gi-sdk/docs/demos/gi-sdk.tsx +++ b/packages/gi-sdk/docs/demos/gi-sdk.tsx @@ -194,7 +194,7 @@ const config: GIConfig = { type: 'INITIALIZER', name: '初始化器', props: { - serviceId: 'GI/GI_SERVICE_INTIAL_GRAPH_1', + serviceId: 'GI/GI_SERVICE_INTIAL_GRAPH', schemaServiceId: 'GI/GI_SERVICE_SCHEMA', GI_INITIALIZER: true, aggregate: false, diff --git a/packages/gi-sdk/docs/gi-sdk.md b/packages/gi-sdk/docs/gi-sdk.md index 2ad0ded60..6e5a20b7a 100644 --- a/packages/gi-sdk/docs/gi-sdk.md +++ b/packages/gi-sdk/docs/gi-sdk.md @@ -1,26 +1,258 @@ --- -title: 基本介绍 +title: 快速开始 order: 1 group: - path: /quick-start - title: 快速开始 - order: 3 + path: /gi-sdk + title: GISDK + order: 0 nav: title: GISDK path: /sdk order: 1 --- +## 定义 + +GISDK 是构建 G6VP 产品的技术底座,它由 Graphin 组件封装而成,旨在通过一份配置文件,渲染出一个图分析应用。 + ## 使用场景 -GISDK 是构建 G6VP 产品的技术底座,它由 Graphin 组件封装而成,旨在通过提供统一的配置文件`config`,资产包`assets`,配合开放多源的服务`services` 即可渲染出一个图分析应用。 +当用户在 G6VP 产品上完成图数据的可视化与分析,希望进一步集成到自己的业务系统中,就需要使用产品提供的「导出 SDK」功能。 -大多数情况下,用户在 G6VP 产品上选择数据源,配置分析参数,导出代码即可得到这么一个可运行的 GISDK,无缝嵌入到自己的应用中。如下图所示 +该功能会将整个画布的参数导出成一份 JSON 文件 `GI_EXPORT_FILES`,然后通过 `@antv/gi-sdk` 提供的 GISDK 组件,以 React 组件的形式原生运行。 - +```jsx | pure +import GISDK from '@antv/gi-sdk'; +//从 GI 站点上导出的配置 +import { assets, config, services } from './GI_EXPORT_FILES'; + +const GraphApp = () => { + return ; +}; + +export default GraphApp; +``` -但是在少部分情况下,我们需要脱离 G6VP 产品,直接以「写代码」的方式集成。如下图所示: +我们可以看出,GISDK 仅接受 4 个参数 + +| Prop Name | Type | Description | Required | +| ---------- | ---------- | -------------------------------------------- | -------- | +| `id` | `string` | 唯一标识:用于管理多实例。 | Yes | +| `config` | `GIConfig` | 配置表:定义节点、边和组件的具体属性。 | Yes | +| `assets` | `GIAssets` | 资产池:包含节点、边、布局和组件的定义。 | Yes | +| `services` | `Array` | 服务池:定义了数据获取和其他交互逻辑的函数。 | Yes | + +下面,我们将脱离 G6VP 产品,完全构造一个符合上述组件规范的 GISDK DEMO + +## DEMO -## 属性解释 +## 代码解析 + +在上述的案例中,我们将整个图分析应用划分成 3 部分 + +- assets:资产池,集合了应用渲染所需的 React 组件 +- config:配置表:每个资产配置的集合,id 用来匹配组件,props 用于运行时参数 +- services:数据池:组件需要数据获取或者其他数据交互 + +## Assets 资产池!一切都是组件! + +如上述案例所示,assets 的数据结构定义如下,这恰好对应了 assets 的三种类型 + +```jsx | pure +const assets = { + components, //分析资产 + elements, //元素资产 + layouts, //元素资产 +}; +``` + +我们先重点来看 `assets.components` ,以计数器资产为例,是由 `info` `registerMeta` 和 `component` 三部分组成的。 + +```jsx | pure +const CounterAsset = { + component: Counter, + info: { + name: '计数器', + id: 'Counter', + type: 'AUTO', + category: 'workbook', + }, + registerMeta: () => ({}), +}; +``` + +- `component` 是普通的 React 组件,组件内可以通过 `@antv/gi-sdk` 提供的 `useContext`方法,获得 GISDK 提供的全局状态 +- `registerMeta` 用于 `component` 组件属性 props 的可视化表达, 采用 [Formily](https://www.yuque.com/r/goto?url=https%3A%2F%2Fantd.formilyjs.org%2Fzh-CN%2Fcomponents) 表单库。 +- `info` 是元信息,用于组件的更多信息描述,可以用于 G6VP 站点的上层消费 + +| 属性 | 类型 | 描述 | +| --------------- | --------------- | ---------- | +| `id` | `string` | 资产 ID | +| `name` | `string` | 资产名称 | +| `cover` | `string` | 资产缩略图 | +| `type` | `AssetType` | 资产类型 | +| `icon` | `string` | 资产 ID | +| `category` | `AssetCategory` | 资产分类 | +| `desc` | `string` | 资产描述 | +| `[key: string]` | `any` | 额外的属性 | + +整个 info 元信息中,`id` 和 `type` 是必选的, `id` 默认需要「组件名」「组件文件夹名」保持一致,`type` 决定了资产的运行时渲染逻辑 + +| AssetType | 名称 | 描述 | +| -------------- | ---------------- | ---------------------------------------------------------------------------------- | +| `AUTO` | 自加载组件 | 拥有独立的 UI 和交互,例如 CanvasSetting | +| `INITIALIZER` | 初始化组件 | 全局唯一,用于初始化 例如 Initializer | +| `GICC_LAYOUT` | 布局容器组件 | 全局唯一,用于页面布局 例如 SegmentContainer | +| `GIAC` | 原子组件 | 没有自己的 UI 和交互,都是由容器组件决定的,例如 ZoomIn | +| `GIAC_CONTENT` | 原子组件(内容) | 有自己的 UI 和交互,但是不能决定自己展示在什么位置,什么时候触发,例如 FilterPanel | +| `GIAC_MENU` | 原子组件(菜单) | 和 GIAC_CONTENT 类似,但是只能集成在 Menu 容器中 ,例如 RemoveNodeWithMenu | +| `GICC` | 容器组件 | 提供了容器功能,可以集成 GIAC_CONTENT 也可以集成 GIAC 原子资产。例如 Toolbar | +| `GICC_MENU` | 容器组件(菜单) | 提供了容器功能,可以集成 GIAC_MENU 原子资产。 例如 ContextMenu | +| `NODE` | 节点组件 | | +| `EDGE` | 边组件 | | +| `LAYOUT` | 布局算法 | | + +## Config 配置表!id 用来匹配组件,props 用于运行时参数 + +`config` 配置表的结构基本上都是`{id:"",props:{}}`,其核心是 SDK 运行时, `id` 用于从资产池中找寻需要运行的资产实例,`props`用于给组件外部传参,(因此 layout 和 pageLayout 其实设计得不是很合理,至少来说是不太一致,后续需要修改) + +```jsx | pure +const config = { + nodes: [{ id: 'SimpleNode', props: {} }], + edges: [{ id: 'SimpleEdge', props: {} }], + components: [ + { id: 'Counter', props: {} }, + { id: 'Initializer', props: {} }, + ], + layout: { + id: 'Force', + props: {}, + }, + pageLayout: {}, +}; +``` + +| 属性 | 类型 | 描述 | +| ------------ | -------------------------- | ---------------- | +| `layout` | `GILayoutConfig` | 图的布局配置 | +| `components` | `Array` | 组件配置数组 | +| `nodes` | `Array` | 节点配置数组 | +| `edges` | `Array` | 边配置数组 | +| `pageLayout` | `GIComponentConfig` | 页面布局组件配置 | + +| GIComponentConfig | 类型 | 描述 | +| ----------------- | ----------- | ------------------ | +| `id` | `string` | 组件配置的唯一标识 | +| `name` | `string` | 组件的名称,可选 | +| `type` | `AssetType` | 资产类型 | +| `props` | `Object` | 组件的属性配置 | + +对于节点和边这类元素资产,我们在`id`和`props`的基础上,增加了`expressions`和`logic`两个关键字段,用于条件渲染,如下述代码所示,`nodes[1]`的逻辑将会先执行,当`id eql account_7 ` 时候,将执行配置`nodes[1].props` + +```jsx | pure + + const nodes= [ + { + id: 'SimpleNode', + props: { + size: 26, + color: 'red', + label: [], + }, + name: '官方节点', + expressions: [], + logic: true, + groupName: '默认样式', + }, + { + id: 'SimpleNode', + expressions: [ + { + name: 'id', + operator: 'eql', + value: 'account_7', + }, + ], + props: { + size: 26, + color: '#3056E3', + label: ['id'], + }, + name: '官方节点', + logic: true, + groupName: 'Account_7 TYPE', + }, + ], + +``` + +| GINodeConfig / GIEdgeConfig | 类型 | 描述 | +| --------------------------- | --------- | ------------------------ | +| `id` | `string` | 节点配置的唯一标识 | +| `name` | `string` | 节点的名称,可选 | +| `props` | `Object` | 节点的属性配置 | +| `expressions` | `Array` | 表达式数组,用于条件渲染 | +| `logic` | `boolean` | 逻辑标识 | +| `groupName` | `string` | 分组名称 | +| `default` | `boolean` | 是否为默认设置 | + +## Services 服务池!接口别写死,从服务池中匹配捞数据 + +以上述代码的 `Initializer` 初始化器为例,在组件的运行中,需要查询初始图数据和图模型数据。 对于不同的数据源,比如图数据库,图计算引擎,设置是本地 CSV 文件,数据查询的方式可能不一样,通常做法,我们会这么做 + +```jsx | pure + +``` + +GI 的设计是这样的,组件的 `props` 设计仅用于静态数据配置,它由 `registerMeta` 产生。对于用户交互,系统交互产生的动态数据,则需要在封装在组件内部,对外仅暴露服务 ID,这样既可以形成接口规范,也有利于服务实现的复写,这对于多引擎的场景下,非常有帮助。如下图所示,不同数据引擎封装了一组资产定义的服务接口,就能够轻松对接上 + +![Alt text](./image-2.png) + +```jsx | pure + +const services: GIService[] = [ + { + name: '初始化查询', + method: 'GET', + id: 'GI/GI_SERVICE_INTIAL_GRAPH', + service: async () => { + return new Promise(resolve => { + resolve(data); + }); + }, + }, + { + name: '查询图模型', + method: 'GET', + id: 'GI/GI_SERVICE_SCHEMA', + service: async () => { + return new Promise(resolve => { + resolve(schemaData); + }); + }, + }, +]; + +const Initializer = props => { + const { services, updateContext } = useContext(); + const { serviceId, schemaServiceId } = props; + useEffect(() => { + let initialService = services.find(s => s.id === serviceId) as GIService; + let schemaService = services.find(s => s.id === schemaServiceId) as GIService; + + Promise.all([schemaService.service(), initialService.service()]).then(([schemaData, graphData]) => { + console.log('Initializer', Initializer); + updateContext(draft => { + draft.data = graphData; + draft.schemaData = schemaData; + draft.initialized = true; + }); + }); + }, []); + return null; +}; + + +``` diff --git a/packages/gi-sdk/docs/image-1.png b/packages/gi-sdk/docs/image-1.png new file mode 100644 index 000000000..a57bcb8d0 Binary files /dev/null and b/packages/gi-sdk/docs/image-1.png differ diff --git a/packages/gi-sdk/docs/image-2.png b/packages/gi-sdk/docs/image-2.png new file mode 100644 index 000000000..5fa6e2102 Binary files /dev/null and b/packages/gi-sdk/docs/image-2.png differ diff --git a/packages/gi-sdk/docs/registerContext.md b/packages/gi-sdk/docs/registerContext.md new file mode 100644 index 000000000..0d44140ac --- /dev/null +++ b/packages/gi-sdk/docs/registerContext.md @@ -0,0 +1,66 @@ +--- +title: registerContext +order: 2 +group: + path: /api + title: API + order: 3 +nav: + title: GISDK + path: /sdk + order: 1 +--- + +以内置的 `Canvas` 画布组件为例,它包含了 `apis` 等 6 个变量,`registerContext` 允许子组件将自己的变量注册到全局的 `context` 中,(准确讲叫 ObserveStore 更合理些),从而使得使用它的组件触发重绘 + +```jsx | pure +import Graphin from '@antv/graphin'; +import deepClone from 'lodash-es/cloneDeep'; +import React, { useMemo } from 'react'; +import { registerContext, useContext } from './Context'; + +const initialCanvasStore = { + apis: {}, + HAS_GRAPH: false, + data: { + nodes: [], + edges: [], + }, + source: { + nodes: [], + edges: [], + }, + schemaData: { + nodes: [], + edges: [], + }, + renderer: 'canvas', //'webgl-3d', +}; +registerContext(initialCanvasStore); +interface CanvasProps {} + +const Canvas: React.FunctionComponent = props => { + const { context, updateContext, assets, id, updateGraph } = useContext(); + const { data, nodes, edges, layout, renderer } = context; + return ( + + ); +}; + +export default Canvas; + + +``` diff --git a/packages/gi-sdk/docs/typing.md b/packages/gi-sdk/docs/typing.md new file mode 100644 index 000000000..7051ffb9b --- /dev/null +++ b/packages/gi-sdk/docs/typing.md @@ -0,0 +1,87 @@ +--- +title: 类型参考 +order: 1 +group: + path: /gi-sdk + title: GISDK + order: 0 +nav: + title: GISDK + path: /sdk + order: 1 +--- + +## AssetInfo + +| 属性 | 类型 | 描述 | +| --------------- | --------------- | ---------- | +| `id` | `string` | 资产 ID | +| `name` | `string` | 资产名称 | +| `cover` | `string` | 资产缩略图 | +| `type` | `AssetType` | 资产类型 | +| `icon` | `string` | 资产 ID | +| `category` | `AssetCategory` | 资产分类 | +| `desc` | `string` | 资产描述 | +| `[key: string]` | `any` | 额外的属性 | + +整个 info 元信息中,`id` 和 `type` 是必选的, `id` 默认需要「组件名」「组件文件夹名」保持一致,`type` 决定了资产的运行时渲染逻辑 + +| AssetType | 描述 | +| -------------------- | ---------------------- | +| `AUTO` | 自加载组件 initializer | +| `INITIALIZER` | 初始化组件 | +| `GICC` | 容器组件,可以多选 | +| `GICC_LAYOUT` | 布局容器组件, 只能单选 | +| `GICC_MENU` | 容器组件(菜单) | +| `GIAC` | 原子组件 | +| `GIAC_CONTENT` | 原子组件(内容) | +| `GIAC_MENU` | 原子组件(菜单) | +| `NODE` | 节点 | +| `EDGE` | 边 | +| `LAYOUT` | 布局算法 | +| `GI_CONTAINER` | 兼容旧版本 | +| `GI_CONTAINER_INDEX` | 兼容旧版本 | + +| AssetCategory | 描述 | +| ---------------------- | -------- | +| `container-components` | 容器组件 | +| `canvas-interaction` | 画布交互 | +| `elements-interaction` | 元素交互 | +| `data-analysis` | 数据分析 | +| `data-query` | 数据查询 | +| `system-interaction` | 系统交互 | +| `styling-analysis` | 样式分析 | +| `algorithm-analysis` | 算法分析 | +| `workbook` | 工作簿 | + +## Config 配置表!id 用来匹配组件,props 用于运行时参数 + +| 属性 | 类型 | 描述 | +| ------------ | -------------------------- | ---------------- | +| `layout` | `GILayoutConfig` | 图的布局配置 | +| `components` | `Array` | 组件配置数组 | +| `nodes` | `Array` | 节点配置数组 | +| `edges` | `Array` | 边配置数组 | +| `pageLayout` | `GIComponentConfig` | 页面布局组件配置 | + +| GIComponentConfig | 类型 | 描述 | +| ----------------- | ----------- | ------------------ | +| `id` | `string` | 组件配置的唯一标识 | +| `name` | `string` | 组件的名称,可选 | +| `type` | `AssetType` | 资产类型 | +| `props` | `Object` | 组件的属性配置 | + +| GINodeConfig / GIEdgeConfig | 类型 | 描述 | +| --------------------------- | --------- | ------------------------ | +| `id` | `string` | 节点配置的唯一标识 | +| `name` | `string` | 节点的名称,可选 | +| `props` | `Object` | 节点的属性配置 | +| `expressions` | `Array` | 表达式数组,用于条件渲染 | +| `logic` | `boolean` | 逻辑标识 | +| `groupName` | `string` | 分组名称 | +| `default` | `boolean` | 是否为默认设置 | + +| GILayoutConfig | 类型 | 描述 | +| -------------- | -------------- | ------------------ | +| `id` | `string` | 布局配置的唯一标识 | +| `props` | `LayoutConfig` | 布局的属性配置 | diff --git a/packages/gi-sdk/docs/updateContext.md b/packages/gi-sdk/docs/updateContext.md new file mode 100644 index 000000000..d7c37b685 --- /dev/null +++ b/packages/gi-sdk/docs/updateContext.md @@ -0,0 +1,41 @@ +--- +title: updateContext +order: 1 +group: + path: /api + title: API + order: 3 +nav: + title: GISDK + path: /sdk + order: 1 +--- + +`updateContext` 可以更新全局 `context` + +```jsx | pure +import React from 'react'; +import { useContext } from '@antv/gi-sdk'; + +const MyComponent = () => { + const { context, updateContext } = useContext(); + + useEffect(() => { + updateContext(preStore => { + // 更新数据 + preStore.data = { nodes: [], edges: [] }; + // 更新布局 + preStore.layout = { + id: 'Force', + props: {}, + }; + }); + // 更新loading + updateContext(preStore => { + preStore.isLoading = true; + }); + }, []); + + return null; +}; +``` diff --git a/packages/gi-sdk/docs/useContext.md b/packages/gi-sdk/docs/useContext.md new file mode 100644 index 000000000..8d56cb00c --- /dev/null +++ b/packages/gi-sdk/docs/useContext.md @@ -0,0 +1,55 @@ +--- +title: useContext +order: 0 +group: + path: /api + title: API + order: 3 +nav: + title: GISDK + path: /sdk + order: 1 +--- + +`useContext` 是 GISDK 提供的一个重要方法,它基于 React 的 useContext 和 valtio 库实现。核心用法如下 + +```jsx | pure +import React from 'react'; +import { useContext } from '@antv/gi-sdk'; + +const MyComponent = () => { + const { + context, // 包含画布状态的快照 + assets, // 资产信息 + services, // 服务数组 + GISDK_ID, // 画布的唯一标识 + id, // 同 GISDK_ID + graph, // IGraph 图形实例 + updateContext, // 函数,用于更新画布的状态 + updateGraph, // 函数,用于更新 IGraph 实例 + } = useContext(); +}; +``` + +其中,`context` 包含下述这么多变量,这些变量都是 `valtio` 的 `proxy` 对象,这就意味着,只有当你的组件中,消费到这些变量的时候,它才触发重绘 + +| Key | Type | Description | +| ----------------- | --------------------- | ------------------------------------------------ | +| `apis` | `any` | 存储与画布相关的 API 方法。 | +| `renderer` | `string` | 指示使用的渲染器类型。 | +| `HAS_GRAPH` | `boolean` | 指示是否已经加载了图形。 | +| `GISDK_ID` | `string` | 画布的唯一标识。 | +| `isLoading` | `boolean` | 指示画布是否正在加载数据。 | +| `data` | `GraphinData` | 存储图形的数据,包括节点和边。 | +| `source` | `GraphinData` | 存储原始图形数据。 | +| `schemaData` | `GraphSchemaData` | 存储图形的模式数据。 | +| `largeGraphLimit` | `number` | 定义大图模式的节点数限制。 | +| `largeGraphData` | `GraphinData` | 用于大图模式下的图形数据。 | +| `largeGraphMode` | `boolean` | 指示是否启用大图模式。 | +| `nodes` | `GINodeConfig[]` | 数组存储节点配置。 `props.config.nodes` | +| `edges` | `GIEdgeConfig[]` | 数组存储边配置。 `props.config.edges` | +| `layout` | `GILayoutConfig` | 存储图形布局配置。 `props.config.layout` | +| `components` | `GIComponentConfig[]` | 数组存储组件配置。 `props.config.components` | +| `pageLayout` | `any` | 用于存储页面布局配置。 `props.config.pageLayout` | +| `initialized` | `boolean` | 指示画布是否已初始化。 | +| `prepare` | `boolean` | 可能用于指示预备状态或前置条件。 | diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index a3c55cd7b..de38107ec 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -2,5 +2,3 @@ packages: # all packages in subdirs of packages/ and components/ - 'packages/**' - '!packages/gi-cli/templates' - - '!packages/gi-assets-tugraph-db' - - '!packages/gi-assets-xlab' diff --git a/scripts/setupProject.js b/scripts/setupProject.js new file mode 100644 index 000000000..fa02b4c4e --- /dev/null +++ b/scripts/setupProject.js @@ -0,0 +1,118 @@ +const fs = require('fs'); +const path = require('path'); +const { exec } = require('child_process'); + +// 从命令行参数获取 repoUrl 和 cloneDir +const [, , repoUrl, cloneDirPath] = process.argv; + +const cloneDir = path.join(__dirname, '../', cloneDirPath); +const packageJsonPath = path.join(__dirname, '../', `${cloneDirPath}/package.json`); +const siteJsonPath = path.join(__dirname, '../', 'packages/gi-site/package.json'); + +function cloneRepository() { + if (fs.existsSync(cloneDir)) { + console.log('目录已存在,跳过克隆操作。'); + return; + } + + exec(`git clone ${repoUrl} ${cloneDir}`, (err, stdout, stderr) => { + if (err) { + console.error('克隆仓库时出错:', err); + return; + } + console.log('仓库克隆成功。'); + }); +} + +function updatePackageJson() { + if (!fs.existsSync(packageJsonPath)) { + console.log('package.json 文件不存在,跳过更新操作。'); + return; + } + let pkgName; + + /** update asset package.json */ + fs.readFile(packageJsonPath, 'utf8', (err, data) => { + if (err) { + console.error('读取文件时出错:', err); + return; + } + + let packageJson; + + try { + packageJson = JSON.parse(data); + } catch (jsonErr) { + console.error('解析 JSON 时出错:', jsonErr); + return; + } + + const dependencies = packageJson.dependencies; + pkgName = packageJson.name; + let updated = false; + if (dependencies) { + if (dependencies['@antv/gi-sdk']) { + dependencies['@antv/gi-sdk'] = 'workspace:*'; + updated = true; + } + if (dependencies['@antv/graphin']) { + dependencies['@antv/graphin'] = 'workspace:*'; + updated = true; + } + } + + if (updated) { + fs.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2), 'utf8', writeErr => { + if (writeErr) { + console.error('写入文件时出错:', writeErr); + return; + } + console.log(`${pkgName} package.json 已更新。`); + }); + } else { + console.log(`无需更新 ${pkgName} package.json。`); + } + + updateSite(pkgName); + }); +} +/** update asset site.json */ +function updateSite(pkgName) { + fs.readFile(siteJsonPath, 'utf8', (err, data) => { + if (err) { + console.error('读取文件时出错:', err); + return; + } + let packageJson; + try { + packageJson = JSON.parse(data); + } catch (jsonErr) { + console.error('解析 JSON 时出错:', jsonErr); + return; + } + const dependencies = packageJson.dependencies; + + let updated = false; + + if (!dependencies[pkgName]) { + dependencies[pkgName] = 'workspace:*'; + updated = true; + } + + if (updated) { + fs.writeFile(siteJsonPath, JSON.stringify(packageJson, null, 2), 'utf8', writeErr => { + if (writeErr) { + console.error('写入文件时出错:', writeErr); + return; + } + console.log('site package.json 已更新。'); + }); + } else { + console.log('无需更新 site package.json。'); + } + }); +} + +// 执行脚本 +cloneRepository(); +updatePackageJson();