Browse Source

feat: lerna + rollup + babel + typescript 配置

添加 npm 生命周期 prepublishOnly
master
suanmei 5 years ago
committed by 拾邑
parent
commit
22eebb6827
  1. 8
      .babelrc
  2. 16
      .editorconfig
  3. 2
      .env
  4. 3
      .eslintrc
  5. 54
      .eslintrc.js
  6. 28
      .gitignore
  7. 4
      .prettierignore
  8. 8
      .prettierrc
  9. 37
      .umirc.ts
  10. 21
      LICENSE
  11. 6
      lerna.json
  12. 12650
      package-lock.json
  13. 85
      package.json
  14. 3
      packages/core/.babelrc
  15. 2
      packages/core/.npmignore
  16. 11
      packages/core/README.md
  17. 89
      packages/core/package-lock.json
  18. 45
      packages/core/package.json
  19. 6
      packages/core/rollup.config.js
  20. 6
      packages/core/scripts/prepublishOnly.js
  21. 7
      packages/core/src/index.tsx
  22. 7
      packages/core/tsconfig.json
  23. 34
      rollup.config.js
  24. 22
      scripts/prepublish.js
  25. 7
      src/global.css
  26. 398
      src/pages/flowchart/data.ts
  27. 171
      src/pages/flowchart/index.less
  28. 71
      src/pages/flowchart/index.tsx
  29. 70
      src/pages/flowchart/settings/execute.tsx
  30. 138
      src/pages/flowchart/settings/index.tsx
  31. 58
      src/pages/flowchart/settings/state.tsx
  32. 112
      src/pages/flowchart/sidebar.tsx
  33. 250
      src/pages/flowchart/toolbar.tsx
  34. 185
      src/pages/flowchart/util.ts
  35. 6
      src/pages/index.tsx
  36. 44
      src/util.ts
  37. 28
      tsconfig.json
  38. 25
      tslint.json
  39. 1
      typings.d.ts

8
.babelrc

@ -0,0 +1,8 @@
{
"presets": ["@babel/preset-env", "@babel/preset-react", "@babel/typescript"],
"plugins": [
"@babel/proposal-class-properties",
"@babel/proposal-object-rest-spread",
"@babel/plugin-transform-runtime"
]
}

16
.editorconfig

@ -1,16 +0,0 @@
# http://editorconfig.org
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
[Makefile]
indent_style = tab

2
.env

@ -1,2 +0,0 @@
BROWSER=none
ESLINT=1

3
.eslintrc

@ -1,3 +0,0 @@
{
"extends": "eslint-config-umi"
}

54
.eslintrc.js

@ -0,0 +1,54 @@
module.exports = {
extends: [
'airbnb',
'airbnb/hooks',
'plugin:import/typescript',
'plugin:unicorn/recommended',
'prettier',
'prettier/react',
],
plugins: ['prettier', 'unicorn'],
env: {
node: true,
browser: true,
},
rules: {
'import/no-extraneous-dependencies': ['error', { peerDependencies: true }],
'prettier/prettier': 'error',
// 修复 tsx 文件引用 tsx 文件报错的问题
'react/jsx-filename-extension': ['error', { extensions: ['.ts', '.tsx'] }],
'unicorn/prevent-abbreviations': 'off',
'unicorn/filename-case': [
'off',
{
case: 'pascalCase',
ignore: [/prepublish/i],
},
],
},
overrides: [
{
files: ['*.ts', '*.tsx'],
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint'],
extends: [
'plugin:@typescript-eslint/eslint-recommended',
'plugin:@typescript-eslint/recommended',
'prettier/@typescript-eslint',
],
rules: {
'@typescript-eslint/no-explicit-any': 'off',
'no-param-reassign': 'off',
'import/extensions': [
// airbnb 配置导致 tsx 文件引用一直报错
'error',
'ignorePackages',
{
ts: 'never',
tsx: 'never',
},
],
},
},
],
};

28
.gitignore

@ -1,18 +1,12 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/npm-debug.log*
/yarn-error.log
/yarn.lock
/package-lock.json
# production
/dist
# misc
.DS_Store
# umi
.umi
.umi-production
.vscode
.eslintcache
.size-snapshot.json
npm-debug.log
yarn-error.log
lerna-debug.log
node_modules
coverage
lib
es
dist

4
.prettierignore

@ -0,0 +1,4 @@
.cache
package.json
package-lock.json
public

8
.prettierrc

@ -0,0 +1,8 @@
{
"endOfLine": "lf",
"semi": true,
"singleQuote": true,
"tabWidth": 2,
"printWidth": 100,
"trailingComma": "es5"
}

37
.umirc.ts

@ -1,37 +0,0 @@
import { IConfig } from 'umi-types'
// ref: https://umijs.org/config/
const config: IConfig = {
treeShaking: true,
disableCSSModules: true,
plugins: [
// ref: https://umijs.org/plugin/umi-plugin-react.html
[
'umi-plugin-react',
{
antd: true,
dva: false,
dynamicImport: false,
title: 'iMove',
dll: false,
routes: {
exclude: [/components\//],
},
},
],
],
extraBabelPlugins: [
[
'import',
{
libraryName: '@antv/x6-components',
libraryDirectory: 'es',
transformToDefaultImport: false,
style: true,
},
],
],
}
export default config

21
LICENSE

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020 拾邑
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

6
lerna.json

@ -0,0 +1,6 @@
{
"packages": [
"packages/*"
],
"version": "0.1.5"
}

12650
package-lock.json

File diff suppressed because it is too large

85
package.json

@ -1,57 +1,44 @@
{
"name": "root",
"private": true,
"name": "@antv/x6-example-features",
"version": "0.2.3",
"scripts": {
"start": "umi dev",
"build": "umi build",
"lint": "yarn lint:ts",
"lint:ts": "tslint -c tslint.json -p tsconfig.json --fix",
"precommit": "lint-staged"
},
"dependencies": {
"@antv/x6": "^0.3.0",
"@antv/x6-components": "^0.2.0",
"@antv/x6-react-shape": "^0.2.0",
"antd": "^3.19.5",
"classnames": "^2.2.6",
"react": "^16.12.0",
"react-dom": "^16.8.6"
"lint-eslint": "eslint --cache --ext .js,.jsx,.ts,.tsx ./packages/**/src",
"check-types": "tsc --noEmit",
"lint": "npm run lint-eslint & npm run check-types"
},
"devDependencies": {
"@types/classnames": "^2.2.10",
"@types/jest": "^23.3.12",
"@types/react": "^16.7.18",
"@types/react-dom": "^16.0.11",
"@types/react-test-renderer": "^16.0.3",
"babel-eslint": "^9.0.0",
"babel-plugin-import": "^1.13.0",
"eslint": "^5.4.0",
"eslint-config-umi": "^1.4.0",
"eslint-plugin-flowtype": "^2.50.0",
"eslint-plugin-import": "^2.14.0",
"eslint-plugin-jsx-a11y": "^5.1.1",
"eslint-plugin-react": "^7.11.1",
"lint-staged": "^7.2.2",
"react-test-renderer": "^16.7.0",
"tslint": "^5.12.0",
"tslint-eslint-rules": "^5.4.0",
"tslint-react": "^3.6.0",
"umi": "^2.9.0",
"umi-plugin-react": "^1.8.0",
"umi-types": "^0.3.0"
"@babel/core": "^7.9.0",
"@babel/plugin-external-helpers": "^7.8.3",
"@babel/plugin-proposal-class-properties": "^7.8.3",
"@babel/plugin-proposal-object-rest-spread": "^7.9.5",
"@babel/plugin-transform-runtime": "^7.9.0",
"@babel/preset-env": "^7.9.5",
"@babel/preset-react": "^7.9.4",
"@babel/preset-typescript": "^7.9.0",
"@svgr/rollup": "^5.3.1",
"@typescript-eslint/eslint-plugin": "^2.29.0",
"@typescript-eslint/parser": "^2.29.0",
"eslint": "^6.8.0",
"eslint-config-airbnb": "^18.1.0",
"eslint-config-prettier": "^6.10.1",
"eslint-plugin-import": "^2.20.2",
"eslint-plugin-jsx-a11y": "^6.2.3",
"eslint-plugin-prettier": "^3.1.3",
"eslint-plugin-react": "^7.19.0",
"eslint-plugin-react-hooks": "^3.0.0",
"eslint-plugin-unicorn": "^18.0.1",
"lerna": "^3.20.2",
"prettier": "^2.0.4",
"rollup": "^2.6.1",
"rollup-plugin-babel": "^4.4.0",
"rollup-plugin-commonjs": "^10.1.0",
"rollup-plugin-node-resolve": "^5.2.0",
"rollup-plugin-size-snapshot": "^0.11.0",
"rollup-plugin-strip": "^1.2.2",
"rollup-plugin-url": "^3.0.1",
"typescript": "^3.8.3"
},
"lint-staged": {
"./src/**/*.{ts,tsx}": [
"tslint -c tslint.json -p ./tsconfig.json --fix",
"git add"
],
"*.{js,jsx}": [
"eslint --fix",
"git add"
]
},
"engines": {
"node": ">=8.0.0"
"dependencies": {
"ora": "^4.0.3"
}
}

3
packages/core/.babelrc

@ -0,0 +1,3 @@
{
"extends": "../../.babelrc"
}

2
packages/core/.npmignore

@ -0,0 +1,2 @@
node_modules
src

11
packages/core/README.md

@ -0,0 +1,11 @@
# `core`
> TODO: description
## Usage
```
const core = require('core');
// TODO: DEMONSTRATE API
```

89
packages/core/package-lock.json

@ -0,0 +1,89 @@
{
"name": "@imove/core",
"version": "0.1.5",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@types/prop-types": {
"version": "15.7.3",
"resolved": "https://registry.npm.taobao.org/@types/prop-types/download/@types/prop-types-15.7.3.tgz",
"integrity": "sha1-KrDV2i5YFflLC51LldHl8kOrLKc=",
"dev": true
},
"@types/react": {
"version": "16.9.34",
"resolved": "https://registry.npm.taobao.org/@types/react/download/@types/react-16.9.34.tgz?cache=0&sync_timestamp=1586464409519&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Freact%2Fdownload%2F%40types%2Freact-16.9.34.tgz",
"integrity": "sha1-99XjMcRo9Tr/7ReopNSIzUTqk0k=",
"dev": true,
"requires": {
"@types/prop-types": "*",
"csstype": "^2.2.0"
}
},
"csstype": {
"version": "2.6.10",
"resolved": "https://registry.npm.taobao.org/csstype/download/csstype-2.6.10.tgz?cache=0&sync_timestamp=1586935655811&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcsstype%2Fdownload%2Fcsstype-2.6.10.tgz",
"integrity": "sha1-5jr1DmbXwmbttrMpCc/Qqr4Dkos=",
"dev": true
},
"fsevents": {
"version": "2.1.2",
"resolved": "https://registry.npm.taobao.org/fsevents/download/fsevents-2.1.2.tgz",
"integrity": "sha1-TAofs0vGjlQ7S4Kp7Dkr+9qECAU=",
"dev": true,
"optional": true
},
"js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npm.taobao.org/js-tokens/download/js-tokens-4.0.0.tgz",
"integrity": "sha1-GSA/tZmR35jjoocFDUZHzerzJJk="
},
"loose-envify": {
"version": "1.4.0",
"resolved": "https://registry.npm.taobao.org/loose-envify/download/loose-envify-1.4.0.tgz",
"integrity": "sha1-ce5R+nvkyuwaY4OffmgtgTLTDK8=",
"requires": {
"js-tokens": "^3.0.0 || ^4.0.0"
}
},
"object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npm.taobao.org/object-assign/download/object-assign-4.1.1.tgz",
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
},
"prop-types": {
"version": "15.7.2",
"resolved": "https://registry.npm.taobao.org/prop-types/download/prop-types-15.7.2.tgz",
"integrity": "sha1-UsQedbjIfnK52TYOAga5ncv/psU=",
"requires": {
"loose-envify": "^1.4.0",
"object-assign": "^4.1.1",
"react-is": "^16.8.1"
}
},
"react": {
"version": "16.13.1",
"resolved": "https://registry.npm.taobao.org/react/download/react-16.13.1.tgz?cache=0&sync_timestamp=1586484496963&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Freact%2Fdownload%2Freact-16.13.1.tgz",
"integrity": "sha1-LoGIIvGpdDEiwGPWQQ2FweOv5I4=",
"requires": {
"loose-envify": "^1.1.0",
"object-assign": "^4.1.1",
"prop-types": "^15.6.2"
}
},
"react-is": {
"version": "16.13.1",
"resolved": "https://registry.npm.taobao.org/react-is/download/react-is-16.13.1.tgz?cache=0&sync_timestamp=1586484576689&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Freact-is%2Fdownload%2Freact-is-16.13.1.tgz",
"integrity": "sha1-eJcppNw23imZ3BVt1sHZwYzqVqQ="
},
"rollup": {
"version": "2.6.1",
"resolved": "https://registry.npm.taobao.org/rollup/download/rollup-2.6.1.tgz",
"integrity": "sha1-g1TmfKp7i/JMJIjZ4vZNor5i7r4=",
"dev": true,
"requires": {
"fsevents": "~2.1.2"
}
}
}
}

45
packages/core/package.json

@ -0,0 +1,45 @@
{
"name": "@imove/core",
"version": "0.1.5",
"description": "流程编排",
"keywords": [
"imove",
"x6",
"flowchart"
],
"author": "suanmei <mr_suanmei@163.com>",
"homepage": "https://github.com/suanmei/iMove#readme",
"license": "MIT",
"main": "lib/core.js",
"directories": {
"lib": "lib",
"test": "__tests__"
},
"files": [
"lib"
],
"publishConfig": {
"access": "public",
"registry": "http://registry.npmjs.org/"
},
"repository": {
"type": "git",
"url": "git+https://github.com/suanmei/iMove.git"
},
"scripts": {
"prepublishOnly": "node scripts/prepublishOnly.js",
"declare-type": "tsc --emitDeclarationOnly",
"build": "rollup -c & npm run declare-type"
},
"bugs": {
"url": "https://github.com/suanmei/iMove/issues"
},
"devDependencies": {
"@types/react": "^16.9.34",
"rollup": "^2.6.1"
},
"peerDependencies": {
"react": "^16.13.1"
},
"gitHead": "9fafd8c5390fa001e7b661ccccfaf65f636d721a"
}

6
packages/core/rollup.config.js

@ -0,0 +1,6 @@
import rollupBaseConfig from '../../rollup.config';
import pkg from './package.json';
export default Object.assign(rollupBaseConfig, {
external: Object.keys(pkg.peerDependencies),
});

6
packages/core/scripts/prepublishOnly.js

@ -0,0 +1,6 @@
#!/usr/bin/env node
const path = require('path');
const prePublish = require('../../../scripts/prepublish');
prePublish('@imove/core', path.join(__dirname, '../'));

7
packages/core/src/index.tsx

@ -0,0 +1,7 @@
import * as React from 'react';
const Core = (): JSX.Element => {
return <div>2</div>;
};
export default Core;

7
packages/core/tsconfig.json

@ -0,0 +1,7 @@
{
"extends": "../../tsconfig",
"compilerOptions": {
"outDir": "lib/types"
},
"include": ["./src"]
}

34
rollup.config.js

@ -0,0 +1,34 @@
import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import babel from 'rollup-plugin-babel';
import url from 'rollup-plugin-url';
import svgr from '@svgr/rollup';
import strip from 'rollup-plugin-strip';
import { sizeSnapshot } from 'rollup-plugin-size-snapshot';
const input = './src/index.tsx';
const extensions = ['.js', '.jsx', '.ts', '.tsx'];
export default {
input,
output: {
file: 'lib/index.js',
format: 'cjs',
sourcemap: true,
},
plugins: [
resolve({ extensions }),
commonjs(),
babel({
extensions,
exclude: 'node_modules/**',
runtimeHelpers: true,
}),
url({
limit: 10 * 1024,
}),
svgr(),
strip({ debugger: true }),
sizeSnapshot(),
],
};

22
scripts/prepublish.js

@ -0,0 +1,22 @@
#!/usr/bin/env node
const childProcess = require('child_process');
const ora = require('ora');
const timeout = 1000 * 60 * 2;
const buildCommand = `npm run build`;
function prePublish(packageAlias, packagePath) {
const spinner = ora(`Building "${packageAlias}" library`).start();
try {
childProcess.execSync(buildCommand, { timeout, cwd: packagePath });
} catch (error) {
spinner.fail(`Could not finish building "${packageAlias}" library`);
process.exit();
}
spinner.succeed(`Finished building "${packageAlias}" library`);
}
module.exports = prePublish;

7
src/global.css

@ -1,7 +0,0 @@
html, body, #root {
height: 100%;
}
body {
margin: 0;
}

398
src/pages/flowchart/data.ts

@ -1,398 +0,0 @@
export interface DataItem {
width: number;
height: number;
data: {
type: string;
title: string;
icon?: string;
};
}
const items: DataItem[] = [
{
width: 56,
height: 56,
data: {
type: "start",
title: "开始"
}
},
{
width: 56,
height: 56,
data: {
type: "end",
title: "结束"
}
},
{
width: 72,
height: 72,
data: {
type: "status",
title: "状态节点"
}
},
{
width: 128,
height: 48,
data: {
type: "execute",
title: "执行节点",
icon:
'<svg viewBox="0 0 1024 1024" focusable="false" width="1em" height="1em" fill="currentColor" aria-hidden="true"><path d="M825.8 498L538.4 249.9c-10.7-9.2-26.4-.9-26.4 14v496.3c0 14.9 15.7 23.2 26.4 14L825.8 526c8.3-7.2 8.3-20.8 0-28zm-320 0L218.4 249.9c-10.7-9.2-26.4-.9-26.4 14v496.3c0 14.9 15.7 23.2 26.4 14L505.8 526c4.1-3.6 6.2-8.8 6.2-14 0-5.2-2.1-10.4-6.2-14z"></path></svg>'
}
},
{
width: 148,
height: 48,
data: {
type: "cond",
title: "条件节点",
icon:
'<svg viewBox="64 64 896 896" focusable="false" width="1em" height="1em" fill="currentColor" aria-hidden="true"><path d="M752 100c-61.8 0-112 50.2-112 112 0 47.7 29.9 88.5 72 104.6v27.6L512 601.4 312 344.2v-27.6c42.1-16.1 72-56.9 72-104.6 0-61.8-50.2-112-112-112s-112 50.2-112 112c0 50.6 33.8 93.5 80 107.3v34.4c0 9.7 3.3 19.3 9.3 27L476 672.3v33.6c-44.2 15-76 56.9-76 106.1 0 61.8 50.2 112 112 112s112-50.2 112-112c0-49.2-31.8-91-76-106.1v-33.6l226.7-291.6c6-7.7 9.3-17.3 9.3-27v-34.4c46.2-13.8 80-56.7 80-107.3 0-61.8-50.2-112-112-112zM224 212a48.01 48.01 0 0 1 96 0 48.01 48.01 0 0 1-96 0zm336 600a48.01 48.01 0 0 1-96 0 48.01 48.01 0 0 1 96 0zm192-552a48.01 48.01 0 0 1 0-96 48.01 48.01 0 0 1 0 96z"></path></svg>'
}
}
];
const map: { [key: string]: DataItem } = {};
items.forEach(item => {
map[item.data.type] = item;
});
export const data = { items, map };
export function isCircle(item: DataItem) {
return item.data.type === "start" || item.data.type === "end";
}
export function isGroup(type: string) {
return type === "combine" || type === "group";
}
export function isFunc(type: string) {
return type === "approvement" || type === "execute";
}
export const mockGraphData = {
nodes: [
{
id: "cell-2",
data: {
type: "start",
title: "开始"
},
shape: "html",
resizable: false,
perimeter: "ellipse",
visible: true,
x: -200,
y: -292,
width: 56,
height: 56,
relative: false,
translateControlPoints: true
},
{
id: "cell-3",
data: {
type: "status",
title: "idle",
serviceType: "none"
},
shape: "html",
resizable: true,
perimeter: "rectangle",
visible: true,
x: -208,
y: -200,
width: 72,
height: 72,
relative: false,
translateControlPoints: true
},
{
id: "cell-4",
data: {
type: "status",
title: "loading",
serviceType: "invoke",
api: "douban.api"
},
shape: "html",
resizable: true,
perimeter: "rectangle",
visible: true,
x: -208,
y: -70,
width: 72,
height: 72,
relative: false,
translateControlPoints: true
},
{
id: "cell-5",
data: {
type: "execute",
title: "reject",
icon:
'<svg viewBox="0 0 1024 1024" focusable="false" width="1em" height="1em" fill="currentColor" aria-hidden="true"><path d="M825.8 498L538.4 249.9c-10.7-9.2-26.4-.9-26.4 14v496.3c0 14.9 15.7 23.2 26.4 14L825.8 526c8.3-7.2 8.3-20.8 0-28zm-320 0L218.4 249.9c-10.7-9.2-26.4-.9-26.4 14v496.3c0 14.9 15.7 23.2 26.4 14L505.8 526c4.1-3.6 6.2-8.8 6.2-14 0-5.2-2.1-10.4-6.2-14z"></path></svg>'
},
shape: "html",
resizable: true,
perimeter: "rectangle",
visible: true,
x: -370,
y: 60,
width: 128,
height: 48,
relative: false,
translateControlPoints: true
},
{
id: "cell-6",
data: {
type: "execute",
title: "resolve",
icon:
'<svg viewBox="0 0 1024 1024" focusable="false" width="1em" height="1em" fill="currentColor" aria-hidden="true"><path d="M825.8 498L538.4 249.9c-10.7-9.2-26.4-.9-26.4 14v496.3c0 14.9 15.7 23.2 26.4 14L825.8 526c8.3-7.2 8.3-20.8 0-28zm-320 0L218.4 249.9c-10.7-9.2-26.4-.9-26.4 14v496.3c0 14.9 15.7 23.2 26.4 14L505.8 526c4.1-3.6 6.2-8.8 6.2-14 0-5.2-2.1-10.4-6.2-14z"></path></svg>',
action: "empty",
contextKey: "file",
contextValue: "result.a"
},
shape: "html",
resizable: true,
perimeter: "rectangle",
visible: true,
x: -100,
y: 60,
width: 128,
height: 48,
relative: false,
translateControlPoints: true
},
{
id: "cell-7",
data: {
type: "status",
title: "fail"
},
shape: "html",
resizable: true,
perimeter: "rectangle",
visible: true,
x: -342,
y: 190,
width: 72,
height: 72,
relative: false,
translateControlPoints: true
},
{
id: "cell-9",
data: {
type: "status",
title: "success"
},
shape: "html",
resizable: true,
perimeter: "rectangle",
visible: true,
x: -72,
y: 190,
width: 72,
height: 72,
relative: false,
translateControlPoints: true
}
],
edges: [
{
id: "cell-10",
data: null,
align: "center",
verticalAlign: "middle",
fontColor: "rgba(0, 0, 0, 1)",
shape: "connector",
endArrow: "classic",
stroke: "#888",
edge: "elbow",
elbow: "vertical",
labelBackgroundColor: "#f8f9fa",
rounded: true,
movable: false,
sourceAnchorX: "0.5",
sourceAnchorY: "1",
targetAnchorX: "0.5",
targetAnchorY: "0",
sourceAnchorDx: "0",
targetAnchorDx: "0",
targetAnchorDy: "0",
visible: true,
x: 0,
y: 0,
width: 0,
height: 0,
relative: true,
translateControlPoints: true,
source: "cell-2",
target: "cell-3"
},
{
id: "cell-11",
data: null,
align: "center",
verticalAlign: "middle",
fontColor: "rgba(0, 0, 0, 1)",
shape: "connector",
endArrow: "classic",
stroke: "#888",
edge: "elbow",
elbow: "vertical",
labelBackgroundColor: "#f8f9fa",
rounded: true,
movable: false,
sourceAnchorX: "0.5",
sourceAnchorY: "1",
targetAnchorX: "0.5",
targetAnchorY: "0",
sourceAnchorDx: "0",
targetAnchorDx: "0",
targetAnchorDy: "0",
visible: true,
x: 0,
y: 0,
width: 0,
height: 0,
relative: true,
translateControlPoints: true,
source: "cell-3",
target: "cell-4"
},
{
id: "cell-12",
data: null,
align: "center",
verticalAlign: "middle",
fontColor: "rgba(0, 0, 0, 1)",
shape: "connector",
endArrow: "classic",
stroke: "#888",
edge: "elbow",
elbow: "vertical",
labelBackgroundColor: "#f8f9fa",
rounded: true,
movable: false,
sourceAnchorX: "0.5",
sourceAnchorY: "1",
targetAnchorX: "0.5",
targetAnchorY: "0",
sourceAnchorDx: "0",
targetAnchorDx: "0",
targetAnchorDy: "0",
visible: true,
x: 0,
y: 0,
width: 0,
height: 0,
relative: true,
translateControlPoints: true,
source: "cell-4",
target: "cell-5"
},
{
id: "cell-13",
data: null,
align: "center",
verticalAlign: "middle",
fontColor: "rgba(0, 0, 0, 1)",
shape: "connector",
endArrow: "classic",
stroke: "#888",
edge: "elbow",
elbow: "vertical",
labelBackgroundColor: "#f8f9fa",
rounded: true,
movable: false,
sourceAnchorX: "0.5",
sourceAnchorY: "1",
targetAnchorX: "0.5",
targetAnchorY: "0",
sourceAnchorDx: "0",
targetAnchorDx: "0",
targetAnchorDy: "0",
visible: true,
x: 0,
y: 0,
width: 0,
height: 0,
relative: true,
translateControlPoints: true,
source: "cell-4",
target: "cell-6"
},
{
id: "cell-14",
data: null,
align: "center",
verticalAlign: "middle",
fontColor: "rgba(0, 0, 0, 1)",
shape: "connector",
endArrow: "classic",
stroke: "#888",
edge: "elbow",
elbow: "vertical",
labelBackgroundColor: "#f8f9fa",
rounded: true,
movable: false,
sourceAnchorX: "0.5",
sourceAnchorY: "1",
targetAnchorX: "0.5",
targetAnchorY: "0",
sourceAnchorDx: "0",
targetAnchorDx: "0",
targetAnchorDy: "0",
visible: true,
x: 0,
y: 0,
width: 0,
height: 0,
relative: true,
translateControlPoints: true,
source: "cell-5",
target: "cell-7"
},
{
id: "cell-15",
data: null,
align: "center",
verticalAlign: "middle",
fontColor: "rgba(0, 0, 0, 1)",
shape: "connector",
endArrow: "classic",
stroke: "#888",
edge: "elbow",
elbow: "vertical",
labelBackgroundColor: "#f8f9fa",
rounded: true,
movable: false,
sourceAnchorX: "0.5",
sourceAnchorY: "1",
targetAnchorX: "0.5",
targetAnchorY: "0",
sourceAnchorDx: "0",
targetAnchorDx: "0",
targetAnchorDy: "0",
visible: true,
x: 0,
y: 0,
width: 0,
height: 0,
relative: true,
translateControlPoints: true,
source: "cell-6",
target: "cell-9"
}
]
};

171
src/pages/flowchart/index.less

@ -1,171 +0,0 @@
body {
overflow: hidden;
}
.flowchart-wrap {
width: 100%;
height: 100%;
overflow: hidden;
}
.flowchart-main {
display: flex;
flex-direction: column;
width: 100%;
height: 100%;
overflow: hidden;
}
.flowchart-toolbar {
height: 41;
border-bottom: 1px solid #e9e9e9;
background-color: #fbfbfb;
padding: 4px 8px;
}
.flowchart-graph {
flex: 1;
overflow: hidden;
.graph {
box-shadow: none;
}
}
.flowchart-sidebar,
.flowchart-format {
background-color: #fbfbfb;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
}
.flowchart-sidebar {
border-right: 1px solid #e9e9e9;
}
.flowchart-format {
border-left: 1px solid #e9e9e9;
}
.flowchart-sidebar-title {
height: 41px;
text-align: center;
border-bottom: 1px solid #e9e9e9;
font-weight: bold;
line-height: 40px;
font-size: 16px;
}
.flowchart-sidebar-content {
flex: 1;
padding: 8px 16px;
}
.x6-node {
foreignobject {
filter: drop-shadow(2px 4px 4px rgba(80, 80, 80, 0.15));
overflow: visible;
> div {
overflow: visible !important;
}
}
}
.flowchart-node-wrap {
overflow: hidden;
margin: 16px auto;
cursor: move;
&.start,
&.end {
border-radius: 100%;
}
}
.flowchart-node {
font-family: 'PingFangSC-Regular', 'PingFang SC';
font-size: 14px;
font-weight: 400;
display: flex;
align-items: center;
width: 100%;
height: 100%;
color: rgba(0, 0, 0, 0.85);
border: 1px solid #e9e9e9;
text-align: center;
// box-shadow: 0 0 0 1px rgba(34, 36, 38, 0.15);
background: #ffffff;
user-select: none;
border-radius: 4px;
&.is-gruop {
align-items: flex-start;
.icon {
margin-left: 8px;
margin-top: 8px;
}
}
.anticon {
font-size: 16px;
margin-left: 16px;
}
.icon {
font-size: 16px;
margin-left: 16px;
font-style: normal;
line-height: 0;
display: inline-block;
text-align: center;
vertical-align: -0.125em;
text-transform: none;
color: #666666;
text-rendering: optimizelegibility;
-webkit-font-smoothing: antialiased;
}
span {
width: 100%;
}
&.start,
&.end {
border-radius: 100%;
justify-content: center;
.text {
margin-left: 0;
}
}
&.end {
border-color: #b0b0b0;
background: #cccccc;
}
}
.ping {
animation: ping 0.8s ease-in-out infinite both;
transform-origin: 50% 50%;
}
@keyframes ping {
0% {
transform: scale(0.2);
opacity: 0.8;
}
80% {
transform: scale(1.2);
opacity: 0;
}
100% {
transform: scale(2.2);
opacity: 0;
}
}

71
src/pages/flowchart/index.tsx

@ -1,71 +0,0 @@
import React from 'react'
import { SplitBox } from '@antv/x6-components'
import { Graph, DomEvent } from '@antv/x6'
import { Sidebar } from './sidebar'
import { GraphToolbar } from './toolbar'
import { createGraph } from './util'
import { Setting } from './settings'
import './index.less'
export default class FlowChart extends React.Component<{}, FlowChart.State> {
private graph: Graph
private container: HTMLDivElement
componentDidMount() {
DomEvent.disableContextMenu(this.container)
this.graph = createGraph(this.container)
this.graph.center()
this.setState({ inited: true })
}
refContainer = (container: HTMLDivElement) => {
this.container = container
}
render() {
return (
<div className="flowchart-wrap">
<SplitBox
split="vertical"
minSize={200}
maxSize={-320}
defaultSize={240}
primary="first"
>
<div className="flowchart-sidebar">
<div className="flowchart-sidebar-title">iMove</div>
<div className="flowchart-sidebar-title"></div>
<div className="flowchart-sidebar-content">
{this.graph && this.state.inited && (
<Sidebar graph={this.graph} />
)}
</div>
</div>
<SplitBox
split="vertical"
minSize={200}
maxSize={-320}
defaultSize={240}
primary="second"
>
<div className="flowchart-main">
<div className="flowchart-toolbar">
{this.graph && <GraphToolbar graph={this.graph} />}
</div>
<div className="flowchart-graph">
<div className="graph" ref={this.refContainer} tabIndex={-1} />
</div>
</div>
{this.graph && this.state.inited && <Setting graph={this.graph} />}
</SplitBox>
</SplitBox>
</div>
)
}
}
export namespace FlowChart {
export interface State {
inited: boolean
}
}

70
src/pages/flowchart/settings/execute.tsx

@ -1,70 +0,0 @@
import * as React from "react";
import { Select, Input } from "antd";
const { Option } = Select;
class ExecuteSetting extends React.Component<
ExecuteSetting.Props,
ExecuteSetting.State
> {
render() {
return (
<div className="execute-setting">
<label>
<div></div>
<Select
defaultValue={this.props.data.title}
style={{ width: 120 }}
onChange={this.props.onTitleChange}
>
<Option value="empty">empty</Option>
<Option value="resolve">resolve</Option>
<Option value="reject">reject</Option>
</Select>
</label>
<label>
<div>action</div>
<Select
defaultValue={this.props.data.action}
style={{ width: 120 }}
onChange={this.props.onActionChange}
>
<Option value="empty">context赋值</Option>
</Select>
</label>
<label>
<div><b>context key</b></div>
<Input
defaultValue={this.props.data.contextKey}
type="text"
allowClear={true}
onBlur={this.props.onKeyChange}
/>
</label>
<label>
<div><b>value path</b></div>
<Input
defaultValue={this.props.data.contextValue}
type="text"
allowClear={true}
onBlur={this.props.onValueChange}
/>
</label>
</div>
);
}
}
export default ExecuteSetting;
export namespace ExecuteSetting {
export interface Props {
data: any;
onTitleChange: (e: any) => void;
onActionChange: (action: string) => void;
onKeyChange: (e: any) => void;
onValueChange: (e: any) => void;
}
export interface State {}
}

138
src/pages/flowchart/settings/index.tsx

@ -1,138 +0,0 @@
import React from "react";
import { Graph, Cell } from "@antv/x6";
import StateSetting from "./state";
import ExecuteSetting from "./execute";
export class Setting extends React.Component<Setting.Props, Setting.State> {
constructor(props: Setting.Props) {
super(props);
this.state = this.getNextState(props);
props.graph.on("selection:changed", () => {
this.setState(this.getNextState());
});
}
getNextState(props: Setting.Props = this.props) {
return {
selectedCells: props.graph.getSelectedCells()
};
}
onStatusTitleChange = (e: any) => {
const value = e.target.value;
if (value && value.trim()) {
const cell = this.state.selectedCells[0];
const data = cell.data;
this.props.graph.setCellData(cell, {
...data,
title: value.trim()
});
}
};
onExcuteTitleChange = (title: string) => {
const cell = this.state.selectedCells[0];
const data = cell.data;
this.props.graph.setCellData(cell, {
...data,
title
});
};
onSerTypeChange = (serviceType: string) => {
const cell = this.state.selectedCells[0];
const data = cell.data;
this.props.graph.setCellData(cell, {
...data,
serviceType
});
};
onActionChange = (action: string) => {
const cell = this.state.selectedCells[0];
const data = cell.data;
this.props.graph.setCellData(cell, {
...data,
action
});
};
onApiChange = (e: any) => {
const value = e.target.value;
if (value && value.trim()) {
const cell = this.state.selectedCells[0];
const data = cell.data;
this.props.graph.setCellData(cell, {
...data,
api: value.trim()
});
}
};
onKeyChange = (e: any) => {
const value = e.target.value;
if (value && value.trim()) {
const cell = this.state.selectedCells[0];
const data = cell.data;
this.props.graph.setCellData(cell, {
...data,
contextKey: value.trim()
});
}
};
onValueChange = (e: any) => {
const value = e.target.value;
if (value && value.trim()) {
const cell = this.state.selectedCells[0];
const data = cell.data;
this.props.graph.setCellData(cell, {
...data,
contextValue: value.trim()
});
}
};
render() {
if (this.state.selectedCells.length === 1) {
const cell = this.state.selectedCells[0];
const data = cell.data;
return (
<div className="flowchart-format">
<div className="flowchart-sidebar-title"></div>
<div className="flowchart-sidebar-content">
{data && data.type === "status" && (
<StateSetting
data={data}
onTitleChange={this.onStatusTitleChange}
onApiChange={this.onApiChange}
onSerTypeChange={this.onSerTypeChange}
/>
)}
{data && data.type === "execute" && (
<ExecuteSetting
data={data}
onTitleChange={this.onExcuteTitleChange}
onActionChange={this.onActionChange}
onKeyChange={this.onKeyChange}
onValueChange={this.onValueChange}
/>
)}
</div>
</div>
);
}
return null;
}
}
export namespace Setting {
export interface Props {
graph: Graph;
}
export interface State {
selectedCells: Cell[];
}
}

58
src/pages/flowchart/settings/state.tsx

@ -1,58 +0,0 @@
import * as React from "react";
import { Input, Select } from "antd";
const { Option } = Select;
class StateSetting extends React.Component<
StateSetting.Props,
StateSetting.State
> {
render() {
return (
<div>
<label>
<div></div>
<Input
defaultValue={this.props.data.title}
type="text"
allowClear={true}
onBlur={this.props.onTitleChange}
/>
</label>
<label>
<div></div>
<Select
defaultValue={this.props.data.serviceType}
style={{ width: 120 }}
onChange={this.props.onSerTypeChange}
>
<Option value="none">none</Option>
<Option value="invoke">invoke</Option>
</Select>
</label>
<label>
<div>api</div>
<Input
defaultValue={this.props.data.api}
type="text"
allowClear={true}
onBlur={this.props.onApiChange}
/>
</label>
</div>
);
}
}
export default StateSetting;
export namespace StateSetting {
export interface Props {
data: any;
onTitleChange: (e: any) => void;
onApiChange: (e: any) => void;
onSerTypeChange: (serviceType: string) => void;
}
export interface State {}
}

112
src/pages/flowchart/sidebar.tsx

@ -1,112 +0,0 @@
import React from "react";
import classNames from "classnames";
import { Icon } from "@antv/x6-components";
import { Graph, Dnd } from "@antv/x6";
import { data, DataItem, isGroup } from "./data";
import { addNode } from "./util";
export class Sidebar extends React.Component<Sidebar.Props> {
private container: HTMLDivElement;
refContainer = (container: HTMLDivElement) => {
this.container = container;
};
componentDidMount() {
this.container.childNodes.forEach((elem: HTMLElement) => {
const type = elem.getAttribute("data-type") || "";
const itemData = data.map[type];
const dnd = new Dnd<DataItem>(elem, {
data: itemData,
getGraph: () => this.props.graph,
getTargetCell: ({ graph, graphX, graphY }) => {
const cell = graph.getCellAt(graphX, graphY);
if (cell != null && cell.data != null && isGroup(cell.data.type)) {
return cell;
}
return null;
},
createDragElement: ({ element }) => {
const elem = document.createElement("div") as HTMLDivElement;
const w = element.offsetWidth;
const h = element.offsetHeight;
elem.style.width = `${w}px`;
elem.style.height = `${h}px`;
elem.style.border = "1px dashed #000";
elem.style.cursor = "move";
return elem;
},
createPreviewElement: ({ graph, element }) => {
const elem = document.createElement("div") as HTMLDivElement;
const w = element.offsetWidth;
const h = element.offsetHeight;
const s = graph.view.scale;
elem.style.width = `${w * s}px`;
elem.style.height = `${h * s}px`;
elem.style.border = "1px dashed #000";
elem.style.cursor = "move";
return elem;
}
});
dnd.on("dragPrepare", ({ dragElement }) => {
dragElement.style.margin = "0";
});
dnd.on("drop", ({ data, graph, targetCell, targetPosition }) => {
if (data != null) {
const group = isGroup(data.data.type);
const parent = targetCell || undefined;
let x = targetPosition.x;
let y = targetPosition.y;
// relative parent position
if (parent != null) {
const geom = parent.getGeometry()!;
x -= geom.bounds.x;
y -= geom.bounds.y;
}
const cell = addNode(
graph,
data,
x,
y,
group ? 200 : null,
group ? 160 : null,
null,
parent
);
graph.unSelectCells(graph.getSelectedCells()).selectCell(cell);
}
});
});
}
render() {
return (
<div className="flowchart-source-nodes" ref={this.refContainer}>
{data.items.map(({ data, width, height }) => (
<div
key={data.type}
data-type={data.type}
style={{ width, height }}
className={classNames("flowchart-node-wrap", data.type)}
>
<div className={classNames("flowchart-node", data.type)}>
{data.icon && <Icon type={data.icon} svg={true} />}
<span className="text">{data.title}</span>
</div>
</div>
))}
</div>
);
}
}
export namespace Sidebar {
export interface Props {
graph: Graph;
}
}

250
src/pages/flowchart/toolbar.tsx

@ -1,250 +0,0 @@
import React from "react";
import { Toolbar, Menu } from "@antv/x6-components";
import { Graph, UndoManager } from "@antv/x6";
export class GraphToolbar extends React.Component<
GraphToolbar.Props,
GraphToolbar.State
> {
private graph: Graph;
private undoManager: UndoManager;
private commands: GraphToolbar.Command[][];
constructor(props: GraphToolbar.Props) {
super(props);
this.graph = props.graph;
this.undoManager = UndoManager.create(props.graph);
this.commands = [
[
{
name: "zoomIn",
icon: "zoom-in",
tooltip: "放大",
handler: () => {
let scale = this.graph.view.scale;
if (scale >= 8) {
scale += 8;
} else if (scale >= 4) {
scale += 4;
} else if (scale >= 2) {
scale += 1;
} else if (scale >= 1.5) {
scale += 0.5;
} else if (scale >= 1) {
scale += 0.25;
} else if (scale >= 0.7) {
scale += 0.15;
} else if (scale >= 0.4) {
scale += 0.1;
} else if (scale >= 0.15) {
scale += 0.05;
} else if (scale >= 0.01) {
scale += 0.01;
}
this.graph.zoomTo(scale);
}
},
{
name: "zoomOut",
icon: "zoom-out",
tooltip: "缩小",
handler: () => {
let scale = this.graph.view.scale;
if (scale <= 0.15) {
scale -= 0.01;
} else if (scale <= 0.4) {
scale -= 0.05;
} else if (scale <= 0.7) {
scale -= 0.1;
} else if (scale <= 1) {
scale -= 0.15;
} else if (scale <= 1.5) {
scale -= 0.25;
} else if (scale <= 2) {
scale -= 0.5;
} else if (scale <= 4) {
scale -= 1;
} else if (scale <= 8) {
scale -= 4;
} else if (scale <= 16) {
scale -= 8;
}
this.graph.zoomTo(scale);
}
}
],
[
{
name: "undo",
icon: "undo",
tooltip: "撤销",
shortcut: "Cmd + Z",
handler: () => this.undoManager.undo()
},
{
name: "redo",
icon: "redo",
tooltip: "重做",
shortcut: "Cmd + Shift + Z",
handler: () => this.undoManager.redo()
}
],
[
{
name: "delete",
icon: "delete",
tooltip: "删除",
shortcut: "Delete",
handler: () => this.graph.deleteCells()
},
{
name: "save",
icon: "save",
tooltip: "保存",
shortcut: "Cmd + S",
handler: () => {
const graphData = this.graph.toJSON();
console.log(JSON.stringify(graphData));
}
}
]
];
this.commands.forEach(items =>
items.forEach(item => {
if (item.shortcut) {
if (item.shortcut === "Delete") {
this.graph.bindKey(["del", "backspace"], item.handler);
} else {
this.graph.bindKey(item.shortcut, item.handler);
}
}
})
);
this.graph.on("selection:changed", this.updateState);
this.graph.view.on("scale", this.updateState);
this.graph.view.on("scaleAndTranslate", this.updateState);
this.graph.model.on("change", this.updateState);
this.undoManager.on("undo", this.updateState);
this.undoManager.on("redo", this.updateState);
this.state = this.getNextState();
}
updateState = () => {
this.setState(this.getNextState());
};
getNextState() {
return {
zoomIn: this.graph.view.scale === this.graph.maxScale,
zoomOut: this.graph.view.scale === this.graph.minScale,
undo: !this.undoManager.canUndo(),
redo: !this.undoManager.canRedo(),
delete: this.graph.getSelectedCells().length <= 0
};
}
resetZoom = () => {
if (this.graph.view.scale !== 1) {
this.graph.zoomTo(1);
}
};
onClick = (name: string) => {
if (name === "resetView") {
this.graph.zoomTo(1);
this.graph.center();
} else if (name === "fitWindow") {
this.graph.fit(8);
// this.graph.center()
} else if (
name === "25" ||
name === "50" ||
name === "75" ||
name === "100" ||
name === "125" ||
name === "150" ||
name === "200" ||
name === "400"
) {
const scale = parseInt(name, 10) / 100;
this.graph.zoomTo(scale);
}
};
renderZoomDropdown() {
const MenuItem = Menu.Item;
return (
<Menu hasIcon={false}>
<MenuItem name="25">25%</MenuItem>
<MenuItem name="50">50%</MenuItem>
<MenuItem name="75">75%</MenuItem>
<MenuItem name="100">100%</MenuItem>
<MenuItem name="125">125%</MenuItem>
<MenuItem name="150">150%</MenuItem>
<MenuItem name="200">200%</MenuItem>
<MenuItem name="400">400%</MenuItem>
</Menu>
);
}
render() {
const Item = Toolbar.Item;
const Group = Toolbar.Group;
return (
<Toolbar onClick={this.onClick} hoverEffect={true} align="left">
<Item dropdown={this.renderZoomDropdown()}>
{(this.graph.view.scale * 100).toFixed(0)}%
</Item>
<Group>
<Item name="resetView" tooltip="重置视口" icon="retweet" />
<Item name="fitWindow" tooltip="适应窗口" icon="fullscreen" />
</Group>
{this.commands.map(items => (
<Group key={items.map(i => i.name).join("-")}>
{items.map(item => (
<Item
key={item.name}
name={item.name}
icon={item.icon}
tooltip={
item.shortcut
? `${item.tooltip}(${item.shortcut})`
: item.tooltip
}
disabled={(this.state as any)[item.name] as boolean}
onClick={item.handler}
/>
))}
</Group>
))}
</Toolbar>
);
}
}
export namespace GraphToolbar {
export interface Props {
graph: Graph;
}
export interface State {
zoomIn: boolean;
zoomOut: boolean;
redo: boolean;
undo: boolean;
delete: boolean;
}
export interface Command {
name: string;
icon: string;
tooltip: string;
shortcut?: string;
handler: () => void;
}
}

185
src/pages/flowchart/util.ts

@ -1,185 +0,0 @@
import { Cell, Graph, Style } from "@antv/x6";
import { DataItem, isCircle, isGroup, mockGraphData } from "./data";
export function createGraph(container: HTMLDivElement) {
return new Graph(container, {
rotate: false,
resize: true,
folding: false,
infinite: true, // 无限大画布
// pageVisible: true,
// pageBreak: {
// enabled: true,
// dsahed: true,
// stroke: '#c0c0c0',
// },
// pageFormat: {
// width: 800,
// height: 960,
// },
// mouseWheel: true,
rubberband: true,
allowLoops: true,
backgroundColor: "#f8f9fa",
grid: {
type: "dot",
color: "#bcbcbc"
},
guide: {
enabled: true,
dashed: true,
stroke: "#ff5500"
},
connection: {
enabled: true,
hotspotable: false,
livePreview: true,
createEdge(options) {
const style = options.style;
fixEdgeStyle(style, style);
return this.createEdge(options);
}
},
connectionPreview: {
stroke: "#1890ff"
},
connectionHighlight: {},
allowDanglingEdges: false,
keyboard: {
enabled: true,
global: false,
escape: true
},
selectionPreview: {
dashed: false,
strokeWidth: 2
},
nodeStyle: {
fill: "rgba(0, 0, 0, 0)",
stroke: "none",
label: false,
editable: false
},
edgeStyle: {
edge: "elbow",
elbow: "vertical",
labelBackgroundColor: "#f8f9fa",
rounded: true,
movable: false
},
dropEnabled: true,
dropTargetHighlight: {
stroke: "#87d068",
opacity: 1
},
anchor: {
inductiveSize: 24
},
// anchorTip: {
// enabled: true,
// opacity: 1,
// className: 'ping',
// },
anchorHighlight: {
strokeWidth: 16
},
isValidDropTarget(target) {
if (target && target.data) {
return isGroup(target.data.type);
}
},
isLabelMovable() {
return false;
},
shouldRedrawOnDataChange() {
return true;
},
getAnchors(cell) {
if (cell != null && this.model.isNode(cell)) {
const type = cell.data.type;
if (type === "start") {
return [[0.5, 1]];
}
if (isGroup(type)) {
return [
[0.25, 0],
[0.5, 0],
[0.75, 0],
[0, 0.25],
[0, 0.5],
[0, 0.75],
[1, 0.25],
[1, 0.5],
[1, 0.75],
[0.25, 1],
[0.5, 1],
[0.75, 1]
];
}
return [[0.5, 0], [0, 0.5], [1, 0.5], [0.5, 1]];
}
return null;
},
getHtml(cell) {
const data = cell.data;
const group = isGroup(data.type);
return `
<div class="flowchart-node${group ? " is-gruop" : ""} ${data.type}">
${data.icon ? `<i class="icon">${data.icon}</i>` : ""}
${group ? "" : `<span class="text">${data.title}</span>`}
</div>
`;
}
});
}
export function addNode(
graph: Graph,
item: DataItem,
x: number,
y: number,
width?: number | null,
height?: number | null,
title?: string | null,
parent?: Cell
) {
const data = { ...item.data };
if (title) {
data.title = title;
}
return graph.addNode({
x,
y,
data,
parent,
width: width || item.width,
height: height || item.height,
shape: "html",
resizable: !isCircle(item),
perimeter: isCircle(item) ? "ellipse" : "rectangle"
});
}
function fixEdgeStyle(raw: Style, result: Style) {
if (raw.targetAnchorX === 1 || raw.targetAnchorX === 0) {
result.elbow = "horizontal";
}
}
export function addEdge(graph: Graph, options: any) {
const style: Style = {};
fixEdgeStyle(options, style);
graph.addEdge({ ...options, style });
}
// export function graph2flow(graphJson: any) {
// const { nodes, edges } = mockGraphData;
// nodes.forEach()
// }

6
src/pages/index.tsx

@ -1,6 +0,0 @@
import React from "react";
import FlowChart from "./flowchart";
export default function() {
return <FlowChart />;
}

44
src/util.ts

@ -1,44 +0,0 @@
export function randomColor() {
var letters = '0123456789ABCDEF';
var color = '#';
for (var i = 0; i < 6; i += 1) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
}
export function invertColor(hex: string, bw: boolean) {
if (hex.indexOf('#') === 0) {
hex = hex.slice(1);
}
// convert 3-digit hex to 6-digits.
if (hex.length === 3) {
hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];
}
if (hex.length !== 6) {
throw new Error('Invalid HEX color.');
}
const r = parseInt(hex.slice(0, 2), 16);
const g = parseInt(hex.slice(2, 4), 16);
const b = parseInt(hex.slice(4, 6), 16);
if (bw) {
// http://stackoverflow.com/a/3943023/112731
return r * 0.299 + g * 0.587 + b * 0.114 > 186 ? '#000000' : '#FFFFFF';
}
// invert color components
const rr = (255 - r).toString(16);
const gg = (255 - g).toString(16);
const bb = (255 - b).toString(16);
// pad each with zeros and return
return '#' + padZero(rr) + padZero(gg) + padZero(bb);
}
function padZero(str: string, len: number = 2) {
var zeros = new Array(len).join('0');
return (zeros + str).slice(-len);
}

28
tsconfig.json

@ -1,25 +1,15 @@
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"moduleResolution": "node",
/* Basic Options */
"target": "es5",
"lib": ["dom", "esnext"],
"module": "commonjs",
"allowJs": false,
"jsx": "react",
"baseUrl": ".",
"importHelpers": true,
"sourceMap": true,
"esModuleInterop": true,
"noImplicitAny": true,
"noEmitOnError": true,
"noUnusedLocals": true,
"strictNullChecks": true,
"resolveJsonModule": true,
"declaration": true,
"types": [],
"strict": true,
"experimentalDecorators": true,
"strictPropertyInitialization": false,
"allowSyntheticDefaultImports": true,
"paths": {
"@/*": [
"src/*"
]
}
"skipLibCheck": true
}
}

25
tslint.json

@ -1,25 +0,0 @@
{
"extends": ["tslint-react", "tslint-eslint-rules"],
"rules": {
"semicolon": [true, "never"],
"quotemark": [true, "single", "jsx-double"],
"trailing-comma": [
true,
{
"singleline": "never",
"multiline": {
"objects": "always",
"arrays": "always",
"functions": "always",
"typeLiterals": "ignore"
},
"esSpecCompliant": true
}
],
"no-construct": true,
"no-debugger": true,
"no-reference": true,
"jsx-no-multiline-js": false,
"jsx-no-lambda": false
}
}

1
typings.d.ts

@ -1 +0,0 @@
declare module '*.less'
Loading…
Cancel
Save