初始化代码

This commit is contained in:
20932067@zju.edu.cn 2021-05-16 20:57:07 +08:00
commit 8da1996605
22 changed files with 14070 additions and 0 deletions

23
.gitignore vendored Normal file
View File

@ -0,0 +1,23 @@
.DS_Store
node_modules
/dist
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

24
README.md Normal file
View File

@ -0,0 +1,24 @@
# clay-top-test
## Project setup
```
npm install
```
### Compiles and hot-reloads for development
```
npm run serve
```
### Compiles and minifies for production
```
npm run build
```
### Lints and fixes files
```
npm run lint
```
### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/).

5
babel.config.js Normal file
View File

@ -0,0 +1,5 @@
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
]
}

12741
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

45
package.json Normal file
View File

@ -0,0 +1,45 @@
{
"name": "clay-top-test",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
"@antv/g6": "^4.2.7",
"core-js": "^3.6.5",
"vue": "^3.0.0",
"vue-router": "^4.0.0-0"
},
"devDependencies": {
"@vue/cli-plugin-babel": "~4.5.0",
"@vue/cli-plugin-eslint": "~4.5.0",
"@vue/cli-plugin-router": "^4.5.13",
"@vue/cli-service": "~4.5.0",
"@vue/compiler-sfc": "^3.0.0",
"babel-eslint": "^10.1.0",
"eslint": "^6.7.2",
"eslint-plugin-vue": "^7.0.0"
},
"eslintConfig": {
"root": true,
"env": {
"node": true
},
"extends": [
"plugin:vue/vue3-essential",
"eslint:recommended"
],
"parserOptions": {
"parser": "babel-eslint"
},
"rules": {}
},
"browserslist": [
"> 1%",
"last 2 versions",
"not dead"
]
}

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

17
public/index.html Normal file
View File

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>

25
src/App.vue Normal file
View File

@ -0,0 +1,25 @@
<template>
<!-- <div id="nav">-->
<!-- <router-link to="/">Home</router-link> |-->
<!-- <router-link to="/about">About</router-link>-->
<!-- </div>-->
<!-- <router-view/>-->
<Index/>
<div id="container"/>
</template>
<script>
import Index from './views/Index'
export default {
name: 'App',
components: {
Index
},
}
</script>
<style scoped>
</style>

BIN
src/assets/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

View File

@ -0,0 +1,58 @@
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<p>
For a guide and recipes on how to configure / customize this project,<br>
check out the
<a href="https://cli.vuejs.org" target="_blank" rel="noopener">vue-cli documentation</a>.
</p>
<h3>Installed CLI Plugins</h3>
<ul>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel" target="_blank" rel="noopener">babel</a></li>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint" target="_blank" rel="noopener">eslint</a></li>
</ul>
<h3>Essential Links</h3>
<ul>
<li><a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a></li>
<li><a href="https://forum.vuejs.org" target="_blank" rel="noopener">Forum</a></li>
<li><a href="https://chat.vuejs.org" target="_blank" rel="noopener">Community Chat</a></li>
<li><a href="https://twitter.com/vuejs" target="_blank" rel="noopener">Twitter</a></li>
<li><a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a></li>
</ul>
<h3>Ecosystem</h3>
<ul>
<li><a href="https://router.vuejs.org" target="_blank" rel="noopener">vue-router</a></li>
<li><a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a></li>
<li><a href="https://github.com/vuejs/vue-devtools#vue-devtools" target="_blank" rel="noopener">vue-devtools</a></li>
<li><a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener">vue-loader</a></li>
<li><a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">awesome-vue</a></li>
</ul>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
props: {
msg: String
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>

5
src/main.js Normal file
View File

@ -0,0 +1,5 @@
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
createApp(App).use(router).mount('#app')

25
src/router/index.js Normal file
View File

@ -0,0 +1,25 @@
import { createRouter, createWebHashHistory } from 'vue-router'
// import Home from '../views/Home.vue'
const routes = [
// {
// path: '/',
// name: 'Home',
// component: Home
// },
// {
// path: '/about',
// name: 'About',
// // route level code-splitting
// // this generates a separate chunk (about.[hash].js) for this route
// // which is lazy-loaded when the route is visited.
// component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
// }
]
const router = createRouter({
history: createWebHashHistory(),
routes
})
export default router

225
src/views/Index.vue Normal file
View File

@ -0,0 +1,225 @@
<template>
<div id="container"/>
</template>
<script>
import {renderMap} from "@/views/create";
import G6 from "@antv/g6";
//,线,
import Behavior from './behavior'
import Edge from './edge'
import Node from './node'
Behavior.register(G6)
Edge.register(G6)
Node.register(G6)
// import initGraph from "@/views/graph";
export default {
name: "Index",
data(){
return{
graphConfig:{
container: 'container',
defaultNode: {
size: [300, 400],
type: 'dice-er-box',
color: '#5B8FF9',
style: {
fill: '#9EC9FF',
lineWidth: 3,
},
labelCfg: {
style: {
fill: 'black',
fontSize: 20,
},
},
},
//edge
defaultEdge: {
type: 'dice-er-edge',
style: {
stroke: '#e2e2e2',
lineWidth: 4,
endArrow: true,
},
},
modes: {
default: ['dice-er-scroll', 'drag-node', 'drag-canvas'],
},
layout: {
type: 'dagre',
rankdir: 'LR',
align: 'UL',
controlPoints: true,
nodesepFunc: () => 0.2,
ranksepFunc: () => 0.5,
},
animate: true,
},
graphData: {
nodes: [
{
id: "info",
label: "Employee",
attrs: [
{
key: "id",
type: "number(6)"
},
{
key: "key",
type: "varchar(255)"
},
{
key: "gender",
type: "enum(M, F)"
},
{
key: "birthday",
type: "date"
},
{
key: "hometown",
type: "varchar(255)"
},
{
key: "country",
type: "varchar(255)"
},
{
key: "nation",
type: "varchar(255)"
},
{
key: "jobId",
type: "number(3)",
relation: [
{
key: "id",
nodeId: "job"
}
]
},
{
key: "phone",
type: "varchar(255)"
},
{
key: "deptId",
type: "number(6)",
relation: [
{
key: "id",
nodeId: "dept"
}
]
},
{
key: "startTime",
type: "date"
},
{
key: "leaveTime",
type: "date"
}
]
},
{
id: "job",
label: "Job",
attrs: [
{
key: "id",
type: "number(3)"
},
{
key: "title",
type: "varchar(255)"
},
{
key: "level",
type: "number(3)"
}
]
},
{
id: "dept",
label: "Department",
attrs: [
{
key: "id",
type: "number(6)"
},
{
key: "title",
type: "varchar(255)"
},
{
key: "desc",
type: "text"
},
{
key: "parent",
type: "number(6)",
relation: [
{
key: "id",
nodeId: "dept"
}
]
},
{
key: "manager",
type: "number(6)"
}
]
}
],
edges: [
{
source: "info",
target: "job",
sourceKey: "jobId",
targetKey: "id"
},
{
source: "info",
target: "dept",
sourceKey: "deptId",
targetKey: "id"
},
{
source: "dept",
target: "dept",
sourceKey: "parent",
targetKey: "id"
}
]
}
}
},
mounted() {
this.initTopo()
},
methods:{
initTopo(){
const container = document.getElementById('container');
const width = container.scrollWidth;
const height = (container.scrollHeight || 800) - 20;
const graph = new G6.Graph({
...this.graphConfig,
width,
height,
})
renderMap(graph,this.graphData)
}
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,125 @@
/**
* @author: clay
* @data: 2021/5/14 23:20
* @email: clay@hchyun.com
* @description: node
*/
const isInBBox = (point, bbox) => {
const {
x,
y
} = point;
const {
minX,
minY,
maxX,
maxY
} = bbox;
return x < maxX && x > minX && y > minY && y < maxY;
};
export default {
name: 'dice-er-scroll',
options: {
getDefaultCfg() {
return {
multiple: true,
};
},
getEvents() {
return {
itemHeight: 50,
wheel: "scroll",
click: "click",
"node:mousemove": "moves",
};
},
scroll(e) {
console.log(454)
e.preventDefault();
const {
graph
} = this;
const nodes = graph.getNodes().filter((n) => {
const bbox = n.getBBox();
return isInBBox(graph.getPointByClient(e.clientX, e.clientY), bbox);
});
if (nodes) {
nodes.forEach((node) => {
const model = node.getModel();
if (model.attrs.length < 9) {
return;
}
const idx = model.startIndex || 0;
let startX = model.startX || 0.5;
let startIndex = idx + e.deltaY * 0.02;
startX -= e.deltaX;
if (startIndex < 0) {
startIndex = 0;
}
if (startX > 0) {
startX = 0;
}
if (startIndex > model.attrs.length - 1) {
startIndex = model.attrs.length - 1;
}
graph.update(node, {
startIndex,
startX,
});
});
}
},
click(e) {
console.log(789)
const {
graph
} = this;
const {
// eslint-disable-next-line no-unused-vars
y
} = e;
const item = e.item;
const shape = e.shape;
if (!item) {
return;
}
// eslint-disable-next-line no-unused-vars
const model = item.getModel();
if (shape.get("name") === "collapse") {
graph.updateItem(item, {
collapsed: true,
size: [300, 50],
});
setTimeout(() => graph.layout(), 100);
} else if (shape.get("name") === "expand") {
graph.updateItem(item, {
collapsed: false,
size: [300, 500],
});
setTimeout(() => graph.layout(), 100);
}
},
moves(e) {
const name = e.shape.get("name");
console.log(name)
const item = e.item;
console.log(name)
if (name && name.startsWith("item")) {
this.graph.updateItem(item, {
selectedIndex: Number(name.split("-")[1]),
});
} else {
this.graph.updateItem(item, {
selectedIndex: NaN,
});
}
},
}
}

View File

@ -0,0 +1,18 @@
/**
* @author: clay
* @data: 2021/5/14 23:19
* @email: clay@hchyun.com
* @description: node
*/
import diceErScroll from './dice-er-scroll'
const obj={
diceErScroll
}
export default {
obj,
register(G6) {
Object.values(obj).map(item => {
G6.registerBehavior(item.name,item.options)
})
}
}

15
src/views/config/edge.js Normal file
View File

@ -0,0 +1,15 @@
/**
* @author: clay
* @data: 2021/5/14 23:58
* @email: clay@hchyun.com
* @description: node
*/
export default {
type: 'dice-er-edge',
style: {
stroke: '#e2e2e2',
lineWidth: 4,
endArrow: true,
}
}

151
src/views/create/index.js Normal file
View File

@ -0,0 +1,151 @@
/**
* @author: clay
* @data: 2021/5/14 23:06
* @email: clay@hchyun.com
* @description: node
*/
export function renderMap(graph,graphData){
// const rawData = [
// {
// "id": "info",
// "label": "Employee",
// "attrs": [{
// "key": "id",
// "type": "number(6)"
// },
// {
// "key": "key",
// "type": "varchar(255)"
// },
// {
// "key": "gender",
// "type": "enum(M, F)"
// },
// {
// "key": "birthday",
// "type": "date"
// },
// {
// "key": "hometown",
// "type": "varchar(255)"
// },
// {
// "key": "country",
// "type": "varchar(255)"
// },
// {
// "key": "nation",
// "type": "varchar(255)"
// },
// {
// "key": "jobId",
// "type": "number(3)",
// "relation": [{
// "key": "id",
// "nodeId": "job"
// }]
// },
// {
// "key": "phone",
// "type": "varchar(255)"
// },
// {
// "key": "deptId",
// "type": "number(6)",
// "relation": [{
// "key": "id",
// "nodeId": "dept"
// }]
// },
// {
// "key": "startTime",
// "type": "date"
// },
// {
// "key": "leaveTime",
// "type": "date"
// }
// ]
// },
// {
// "id": "job",
// "label": "Job",
// "attrs": [{
// "key": "id",
// "type": "number(3)"
// },
// {
// "key": "title",
// "type": "varchar(255)"
// },
// {
// "key": "level",
// "type": "number(3)"
// }
// ]
// },
// {
// "id": "dept",
// "label": "Department",
// "attrs": [{
// "key": "id",
// "type": "number(6)"
// },
// {
// "key": "title",
// "type": "varchar(255)"
// },
// {
// "key": "desc",
// "type": "text"
// },
// {
// "key": "parent",
// "type": "number(6)",
// "relation": [{
// "key": "id",
// "nodeId": "dept"
// }]
// },
// {
// "key": "manager",
// "type": "number(6)"
// }
// ]
// }
// ]
//
// const dataTransform = (data) => {
// const nodes = [];
// const edges = [];
//
// data.map((node) => {
// nodes.push({
// ...node
// });
// if (node.attrs) {
// node.attrs.forEach((attr) => {
// if (attr.relation) {
// attr.relation.forEach((relation) => {
// edges.push({
// source: node.id,
// target: relation.nodeId,
// sourceKey: attr.key,
// targetKey: relation.key,
// label: relation.label,
// });
// });
// }
//
// });
// }
// });
//
// return {
// nodes,
// edges,
// };
// }
graph.data(graphData);
graph.render();
}

View File

@ -0,0 +1,130 @@
/**
* @author: clay
* @data: 2021/5/14 23:46
* @email: clay@hchyun.com
* @description: node
*/
import {Util} from '@antv/g6'
export default {
name: 'dice-er-edge',
options: {
draw(cfg, group) {
//todo 画线
// console.log("cfg",cfg,"group",group)
const edge = group.cfg.item;
const sourceNode = edge.getSource().getModel();
const targetNode = edge.getTarget().getModel();
const sourceIndex = sourceNode.attrs.findIndex(
(e) => e.key === cfg.sourceKey
);
const sourceStartIndex = sourceNode.startIndex || 0;
let sourceY = 15;
if (!sourceNode.collapsed && sourceIndex > sourceStartIndex - 1) {
sourceY = 30 + (sourceIndex - sourceStartIndex + 0.5) * 30;
sourceY = Math.min(sourceY, 300);
}
const targetIndex = targetNode.attrs.findIndex(
(e) => e.key === cfg.targetKey
);
const targetStartIndex = targetNode.startIndex || 0;
let targetY = 15;
if (!targetNode.collapsed && targetIndex > targetStartIndex - 1) {
targetY = (targetIndex - targetStartIndex + 0.5) * 30 + 30;
targetY = Math.min(targetY, 300);
}
const startPoint = {
...cfg.startPoint
};
const endPoint = {
...cfg.endPoint
};
startPoint.y = startPoint.y + sourceY;
endPoint.y = endPoint.y + targetY;
let shape;
if (sourceNode.id !== targetNode.id) {
shape = group.addShape("path", {
attrs: {
stroke: "#5B8FF9",
path: [
["M", startPoint.x, startPoint.y],
[
"C",
endPoint.x / 3 + (2 / 3) * startPoint.x,
startPoint.y,
endPoint.x / 3 + (2 / 3) * startPoint.x,
endPoint.y,
endPoint.x,
endPoint.y,
],
],
endArrow: true,
},
name: "path-shape",
});
} else if (!sourceNode.collapsed) {
let gap = Math.abs((startPoint.y - endPoint.y) / 3);
if (startPoint["index"] === 1) {
gap = -gap;
}
shape = group.addShape("path", {
attrs: {
stroke: "#5B8FF9",
path: [
["M", startPoint.x, startPoint.y],
[
"C",
startPoint.x - gap,
startPoint.y,
startPoint.x - gap,
endPoint.y,
startPoint.x,
endPoint.y,
],
],
endArrow: true,
},
name: "path-shape",
});
}
return shape;
},
afterDraw(cfg, group) {
// eslint-disable-next-line no-unused-vars
const labelCfg = cfg.labelCfg || {};
const edge = group.cfg.item;
const sourceNode = edge.getSource().getModel();
const targetNode = edge.getTarget().getModel();
if (sourceNode.collapsed && targetNode.collapsed) {
return;
}
const path = group.find(
(element) => element.get("name") === "path-shape"
);
const labelStyle = Util.getLabelPosition(path, 0.5, 0, 0, true);
const label = group.addShape("text", {
attrs: {
...labelStyle,
text: cfg.label || '',
fill: "#000",
textAlign: "center",
stroke: "#fff",
lineWidth: 1,
},
});
label.rotateAtStart(labelStyle.rotate);
},
}
}

20
src/views/edge/index.js Normal file
View File

@ -0,0 +1,20 @@
/**
* @author: clay
* @data: 2021/5/14 23:49
* @email: clay@hchyun.com
* @description: node
*/
import diceErEdge from './dice-er-edge'
const obj = {
diceErEdge
}
export default {
obj,
register(G6) {
Object.values(obj).map(item =>{
G6.registerEdge(item.name,item.options)
})
}
}

139
src/views/graph/index.js Normal file
View File

@ -0,0 +1,139 @@
/**
* @author: clay
* @data: 2021/5/15 0:01
* @email: clay@hchyun.com
* @description: node
*/
import * as d3 from 'd3-force/dist/d3-force'
import {renderMap} from '../create'
const initGraph = {
commonGraph:function(G6,options){
var graphData = options.graphData
const graph = new G6.Graph({
container:options.container,
defaultNode: {
size: [300, 400],
type: 'dice-er-box',
color: '#5B8FF9',
style: {
fill: '#9EC9FF',
lineWidth: 3,
},
labelCfg: {
style: {
fill: 'black',
fontSize: 20,
},
},
},
//设置edge默认属性
defaultEdge: {
type: 'dice-er-edge',
style: {
stroke: '#e2e2e2',
lineWidth: 4,
endArrow: true,
},
},
modes: {
default: ['dice-er-scroll', 'drag-node', 'drag-canvas'],
},
layout: {
type: 'dagre',
rankdir: 'LR',
align: 'UL',
controlPoints: true,
nodesepFunc: () => 0.2,
ranksepFunc: () => 0.5,
},
animate: true,
})
// 将 read 方法分解成 data() 和 render 方法,便于整个生命周期的管理
renderMap(graph,graphData)
return graph;
},
/**
* 力导布局
* @param G6
* @param options
* @returns {*}
*/
forceLayoutGraph: function(resolve, G6, options) {
let graphData = options.graphData
// let themeStyle = theme.defaultStyle // todo...先使用默认主题,后期可能增加其它风格的主体
// 生成G6实例
let graph = new G6.Graph({
container: options.container,
width: options.width,
height: options.height,
// nodeStateStyles: themeStyle.nodeStyle,
// edgeStateStyles: themeStyle.edgeStyle
})
// 初始化力导布局
let simulation = d3
.forceSimulation()
.force(
'link',
d3
.forceLink()
.id(function(d) {
return d.id
})
.distance(linkDistance)
.strength(0.5)
)
.force('charge', d3.forceManyBody().strength(-500).distanceMax(500).distanceMin(100))
.force('center', d3.forceCenter(options.width / 2, options.height / 2))
// 定义节点数据
simulation.nodes(graphData.nodes).on('tick', ticked)
// 定义连线数据
let edges = []
for (let i = 0; i < graphData.edges.length; i++) {
edges.push({
id: graphData.edges[i].id,
source: graphData.edges[i].source,
target: graphData.edges[i].target
})
}
simulation.force('link').links(edges)
graph.data(graphData)
graph.render()
// eslint-disable-next-line no-unused-vars
function linkDistance(d) {
return 150
}
function ticked() {
// protect: planA: 移除事件监听器 planB: 手动停止力模拟
if (graph.destroyed) {
// simulation.nodes(graphData.nodes).on('tick', null)
simulation.stop()
return
}
if (!graph.get('data')) {
// 若是第一次渲染,定义数据,渲染
graph.data(graphData)
graph.render()
} else {
// 后续渲染,直接刷新所有点和边的位置
graph.refreshPositions()
}
}
// 控制时间: 只布局10秒
let t = setTimeout(function() {
simulation.stop()
resolve(graph)
}, 10000)
// 判断force-layout结束
simulation.on('end', () => {
clearTimeout(t)
resolve(graph)
})
}
}
export default initGraph

View File

@ -0,0 +1,259 @@
/**
* @author: clay
* @data: 2021/5/15 0:16
* @email: clay@hchyun.com
* @description: node
*/
const itemHeight = 30;
export default {
name: 'dice-er-box',
options: {
draw(cfg, group) {
const width = 250;
const height = 316;
const itemCount = 10;
const boxStyle = {
stroke: "#096DD9",
radius: 4,
};
const {
attrs = [],
startIndex = 0,
selectedIndex,
collapsed,
icon,
} = cfg;
const list = attrs;
const afterList = list.slice(
Math.floor(startIndex),
Math.floor(startIndex + itemCount - 1)
);
const offsetY = (0.5 - (startIndex % 1)) * itemHeight + 30;
group.addShape("rect", {
attrs: {
fill: boxStyle.stroke,
height: 30,
width,
radius: [boxStyle.radius, boxStyle.radius, 0, 0],
},
draggable: true,
});
let fontLeft = 12;
if (icon && icon.show !== false) {
group.addShape("image", {
attrs: {
x: 8,
y: 8,
height: 16,
width: 16,
...icon,
},
});
fontLeft += 18;
}
group.addShape("text", {
attrs: {
y: 22,
x: fontLeft,
fill: "#fff",
text: cfg.label,
fontSize: 12,
fontWeight: 500,
},
});
group.addShape("rect", {
attrs: {
x: 0,
y: collapsed ? 30 : 300,
height: 15,
width,
fill: "#eee",
radius: [0, 0, boxStyle.radius, boxStyle.radius],
cursor: "pointer",
},
name: collapsed ? "expand" : "collapse",
});
group.addShape("text", {
attrs: {
x: width / 2 - 6,
y: (collapsed ? 30 : 300) + 12,
text: collapsed ? "+" : "-",
width,
fill: "#000",
radius: [0, 0, boxStyle.radius, boxStyle.radius],
cursor: "pointer",
},
name: collapsed ? "expand" : "collapse",
});
const keyshape = group.addShape("rect", {
attrs: {
x: 0,
y: 0,
width,
height: collapsed ? 45 : height,
...boxStyle,
},
draggable: true,
});
if (collapsed) {
return keyshape;
}
const listContainer = group.addGroup({});
listContainer.setClip({
type: "rect",
attrs: {
x: -8,
y: 30,
width: width + 16,
height: 300 - 30,
},
});
listContainer.addShape({
type: "rect",
attrs: {
x: 1,
y: 30,
width: width - 2,
height: 300 - 30,
fill: "#fff",
},
draggable: true,
});
if (list.length > itemCount) {
const barStyle = {
width: 4,
padding: 0,
boxStyle: {
stroke: "#00000022",
},
innerStyle: {
fill: "#00000022",
},
};
listContainer.addShape("rect", {
attrs: {
y: 30,
x: width - barStyle.padding - barStyle.width,
width: barStyle.width,
height: height - 30,
...barStyle.boxStyle,
},
});
const indexHeight =
afterList.length > itemCount ?
(afterList.length / list.length) * height :
10;
listContainer.addShape("rect", {
attrs: {
y: 30 +
barStyle.padding +
(startIndex / list.length) * (height - 30),
x: width - barStyle.padding - barStyle.width,
width: barStyle.width,
height: Math.min(height, indexHeight),
...barStyle.innerStyle,
},
});
}
if (afterList) {
afterList.forEach((e, i) => {
const isSelected =
Math.floor(startIndex) + i === Number(selectedIndex);
let {
key = "", type
} = e;
if (type) {
key += " - " + type;
}
const label = key.length > 26 ? key.slice(0, 24) + "..." : key;
listContainer.addShape("rect", {
attrs: {
x: 1,
y: i * itemHeight - itemHeight / 2 + offsetY,
width: width - 4,
height: itemHeight,
radius: 2,
lineWidth: 1,
cursor: "pointer",
},
name: `item-${Math.floor(startIndex) + i}-content`,
draggable: true,
});
if (!cfg.hideDot) {
listContainer.addShape("circle", {
attrs: {
x: 0,
y: i * itemHeight + offsetY,
r: 3,
stroke: boxStyle.stroke,
fill: "white",
radius: 2,
lineWidth: 1,
cursor: "pointer",
},
});
listContainer.addShape("circle", {
attrs: {
x: width,
y: i * itemHeight + offsetY,
r: 3,
stroke: boxStyle.stroke,
fill: "white",
radius: 2,
lineWidth: 1,
cursor: "pointer",
},
});
}
listContainer.addShape("text", {
attrs: {
x: 12,
y: i * itemHeight + offsetY + 6,
text: label,
fontSize: 12,
fill: "#000",
fontFamily: "Avenir,-apple-system,BlinkMacSystemFont,Segoe UI,PingFang SC,Hiragino Sans GB,Microsoft YaHei,Helvetica Neue,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol",
full: e,
fontWeight: isSelected ? 500 : 100,
cursor: "pointer",
},
name: `item-${Math.floor(startIndex) + i}`,
});
});
}
// console.log(keyshape);
return keyshape;
},
getAnchorPoints() {
return [
[0, 0],
[1, 0],
];
},
}
}

20
src/views/node/index.js Normal file
View File

@ -0,0 +1,20 @@
/**
* @author: clay
* @data: 2021/5/15 0:18
* @email: clay@hchyun.com
* @description: node
*/
import diceErBox from './dice-er-box'
const node = {
diceErBox
}
export default {
node,
register(G6) {
Object.values(node).map(item => {
G6.registerNode(item.name,item.options)
})
}
}