Commit 1739d222 authored by 郭铭瑶's avatar 郭铭瑶 🤘

接入接口调试

parent b12ffcdd
This diff is collapsed.
......@@ -7,7 +7,9 @@
"build": "vite build"
},
"dependencies": {
"axios": "^0.21.1",
"d3": "^7.0.0",
"qs": "^6.10.1",
"vue": "^3.0.5"
},
"devDependencies": {
......
const BASE_URL = 'http://pae.omniview.pro/api'
switch (process.env.NODE_ENV) {
case 'production':
break
default:
}
export default {
BASE_URL,
GET_RELATIONS: '/relations',
POST_SUBJECT: '/subject',
POST_NODE: '/node/relation',
DELETE_RELATION: '/node/relation',
GET_NODES: '/node/relations',
DELETE_NODE: '/node/{id}',
}
import axios from 'axios'
import qs from 'qs'
import api from './api'
const Axios = axios.create({
baseURL: api.BASE_URL,
timeout: 15000,
})
Axios.interceptors.request.use(
(config) => {
// 添加token
// config.headers.Authorization = 'token'
return config
},
(error) => {
return Promise.reject(error)
}
)
Axios.interceptors.response.use(
(response) => {
if (response.config.headers.__show_loading) {
// store.commit('SET_LOADING', false)
}
// TODO 返回的数据status判断错误操作等……
return response.data
},
(error) => {
// store.commit('SET_LOADING', false)
return Promise.reject(error)
}
)
/**
* 请求
* @param {String} method [请求方法]
* @param {String} url [请求地址]
* @param {Object} params [请求参数]
* @param {String} contentType [请求头,默认为'application/json;charset=UTF-8']
* @param {Boolean} showLoading [是否显示请求时的loading图,默认为true]
* @param {Object} headers [自定义请求头]
*/
const ajax = ({
method = 'GET',
url,
params = {},
contentType = 'application/json;charset=UTF-8',
showLoading = true,
headers = {},
}) => {
if (!url || typeof url != 'string') {
throw new Error('接口URL不正确')
}
let config = {
method,
url,
headers: {
'X-Requested-With': 'XMLHttpRequest',
'Content-Type': contentType,
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers':
'Authorization,Origin, X-Requested-With, Content-Type, Accept',
'Access-Control-Allow-Methods': '*',
__show_loading: showLoading,
...headers,
},
}
if (method === 'GET') {
config = Object.assign(config, { params })
} else {
if (contentType.toLowerCase().indexOf('x-www-form-urlencoded') >= 0) {
config = Object.assign(config, { data: qs.stringify(params) })
} else {
config = Object.assign(config, { data: params })
}
}
if (showLoading) {
// store.commit('SET_LOADING', true)
}
return Axios(config)
}
export default {
get(args) {
return ajax({ method: 'GET', ...args })
},
post(args) {
// args.contentType = 'application/x-www-form-urlencoded;charset=UTF-8'
return ajax({ method: 'POST', ...args })
},
put(args) {
return ajax({ method: 'PUT', ...args })
},
delete(args) {
return ajax({ method: 'DELETE', ...args })
},
}
import ajax from './axios'
import api from './api'
export { ajax, api }
......@@ -4,7 +4,11 @@
<script>
import RelationGraph from '@/util/useD3.js'
import { nextTick, onMounted, watch, ref } from 'vue'
import { watch, ref } from 'vue'
import branch from '@/assets/images/branch.svg'
import more from '@/assets/images/more.svg'
import add from '@/assets/images/add.svg'
import del from '@/assets/images/delete.svg'
export default {
name: 'D3',
props: {
......@@ -19,24 +23,39 @@ export default {
},
},
},
setup(props) {
emits: ['more', 'add', 'del', 'branch'],
setup(props, ctx) {
let instance = null
const container = ref(null)
onMounted(async () => {
if (!props.data.nodes || !props.data.links) return
await nextTick()
init()
})
const menuData = [
{ icon: branch, action: (d) => ctx.emit('branch', d), title: '分支' },
{ icon: more, action: (d) => ctx.emit('more', d), title: '更多' },
{ icon: add, action: (d) => ctx.emit('add', d), title: '新增' },
{ icon: del, action: (d) => ctx.emit('del', d), title: '删除' },
]
function init() {
if (!container.value) return
if (instance) {
instance.selectAll('*').remove()
} else {
instance = new RelationGraph(container.value, props.data, props.config)
instance.graph.selectAll('*').remove()
}
instance = new RelationGraph(
container.value,
props.data,
props.config,
menuData
)
}
watch(() => props.data, init)
function setKey(key) {
instance.setKey(key)
}
watch(
() => props.data,
() => init(),
{ immediate: true }
)
return {
container,
setKey,
}
},
}
......
<template>
<D3
:data="mockData"
ref="d3Ref"
:data="data"
:config="config"
style="background: #fff; width: 100%; height: 100vh"
@branch="handleBranch"
@add="handleAdd"
/>
<div class="btns">
<button @click="setKey('systemName')">systemName</button>
<button @click="setKey('propertyName')">propertyName</button>
<button @click="setKey('subjectName')">subjectName</button>
</div>
</template>
<script>
import D3 from './d3.vue'
import mockData from '@/util/mock.js'
import { ref } from 'vue'
import { ref, shallowRef } from 'vue'
import { ajax, api } from '@/ajax'
export default {
name: 'Main',
components: { D3 },
setup() {
const d3Ref = ref(null)
const data = ref([])
ajax
.get({
url: api.GET_NODES,
})
.then((res) => {
console.log('nodes:', res)
data.value = res.data.content
})
const config = ref({
config: {
strokeColor: 'skyblue',
},
})
function handleBranch({ nodeId }) {
ajax
.get({
url: api.GET_NODES,
params: { nodeId },
})
.then((res) => {
console.log('nodes:', res)
// data.value = res.data.content
})
}
function handleAdd() {
const { nodes, links } = data.value
data.value = {
nodes: nodes.slice(0, 2),
links: links.slice(0, 2),
}
console.log(data.value)
}
function setKey(key) {
d3Ref.value.setKey(key)
}
return {
data,
mockData,
config,
handleBranch,
handleAdd,
d3Ref,
setKey,
}
},
}
</script>
<style lang="stylus" scoped>
.btns
position fixed
top 10px
left 10px
z-index 100
>button
margin-right 10px
cursor pointer
</style>
......@@ -14,7 +14,7 @@ export default function RadialMenu() {
let radius = 50
let thickness = 20
let iconSize = 16
let animationDuration = 250 // The duration to run animations for
let animationDuration = 150 // The duration to run animations for
// Private Variables
let offsetAngleDeg = -180 / data.length // Initial rotation angle designed to put centre the first segment at the top
......@@ -132,12 +132,13 @@ export default function RadialMenu() {
return control
}
control.curNodeData = null
/**
* Display the menu
* @returns {object} The control
*/
control.show = function (data) {
control.show = function (data, curNodeData) {
control.curNodeData = curNodeData
// Calculate the new offset angle based on the number of data items and
// then rotate the menu to re-centre the first segment
offsetAngleDeg = -180 / data.length
......@@ -198,7 +199,7 @@ export default function RadialMenu() {
}) // store the initial data value for later
.on('click', function (e, d) {
const { action } = d.data
action && action(e, d)
action && action(control.curNodeData)
})
.transition()
.duration(animationDuration)
......@@ -216,9 +217,7 @@ export default function RadialMenu() {
menuSegments
.append('image')
.attr('class', 'menu-icon')
.attr('xlink:href', function (d) {
return d.data.icon
})
.attr('href', (d) => d.data.icon)
.attr('width', iconSize)
.attr('height', iconSize)
.attr('x', function (d) {
......@@ -278,13 +277,14 @@ export default function RadialMenu() {
return arc.innerRadius(innerTween(t)).outerRadius(outerTween(t))(a)
}
})
.selectAll('*')
.remove()
let timer = setTimeout(() => {
segmentLayer.remove()
clearTimeout(timer)
timer = null
}, animationDuration + 100)
}, animationDuration + 50)
return control
}
......
import * as d3 from 'd3'
import RadialMenu from './menu'
import branch from '@/assets/images/branch.svg'
import more from '@/assets/images/more.svg'
import add from '@/assets/images/add.svg'
import del from '@/assets/images/delete.svg'
// import branch from '@/assets/images/branch.svg'
// import more from '@/assets/images/more.svg'
// import add from '@/assets/images/add.svg'
// import del from '@/assets/images/delete.svg'
// 求两点间的距离
function getDis(s, t) {
......@@ -88,18 +88,26 @@ const defaultConfig = {
linkColor: 'gray', // 链接线默认的颜色
strokeColor: 'gray', // 圈圈外围包裹的颜色
strokeWidth: 0, // 圈圈外围包裹的宽度
colorList: {
default: 'skyblue',
System: '#58b2dc',
Property: '#ffb11b',
Subject: '#42b983',
},
}
const menuData = [
{ icon: branch, action: () => console.log('branch') },
{ icon: more, action: () => console.log('more') },
{ icon: add, action: () => console.log('add') },
{ icon: del, action: () => console.log('del') },
]
// const menuData = [
// { icon: branch, action: () => console.log('branch'), title: '分支' },
// { icon: more, action: () => console.log('more'), title: '更多' },
// { icon: add, action: () => console.log('add'), title: '新增' },
// { icon: del, action: () => console.log('del'), title: '删除' },
// ]
let menu = null
export default class RelationGraph {
constructor(selector, data, configs = {}) {
constructor(selector, data, configs = {}, menuData) {
this.menuData = menuData
const mapW = selector.offsetWidth
const mapH = selector.offsetHeight
......@@ -135,13 +143,40 @@ export default class RelationGraph {
this.dependsNode = []
this.dependsLinkAndText = []
// 创建力学模拟器
this.initSimulation()
return this.graph
console.log('init', this.config)
this.init()
}
setKey(key) {
d3.selectAll('.node-text')
.text((d) => (key && d[key]) || d[d.nodeLabel.toLowerCase() + 'Name'])
.call(textWrap, this.config.r * 1.8)
}
update(data) {
this.config = Object.assign({}, this.config, data)
console.log('update', this.config)
this.createSimulation()
d3.selectAll('pattern.circle-bg').data(this.config.nodes)
d3.selectAll('g.circle-wrapper').data(this.config.nodes)
d3.selectAll('g.edge').data(this.config.links)
}
openMenu(self, d) {
menu = new RadialMenu()
.radius(50)
.thickness(40)
.appendTo(self.parentNode)
.show(this.menuData, d)
}
closeMenu() {
if (menu) {
menu.hide()
menu = null
}
}
// 创建力学模拟器
initSimulation() {
const self = this
createSimulation() {
console.log('createSimulation', this.config.nodes)
// 1. 创建一个力学模拟器
this.simulation = d3
.forceSimulation(this.config.nodes)
......@@ -165,6 +200,12 @@ export default class RelationGraph {
.alphaDecay(this.config.alphaDecay)
// 监听事件 ,tick|end ,例如监听 tick 滴答事件
.on('tick', () => this.ticked())
}
init() {
const self = this
this.createSimulation()
// 2.创建svg标签
this.SVG = this.graph
......@@ -181,7 +222,7 @@ export default class RelationGraph {
}
})
)
.on('click', () => menu && menu.hide())
.on('click', () => this.closeMenu())
.on('dblclick.zoom', null) // 取消双击放大
// 3.defs <defs>标签的内容不会显示,只有调用的时候才显示
......@@ -218,17 +259,22 @@ export default class RelationGraph {
.append('rect')
.attr('width', 2 * this.config.r)
.attr('height', 2 * this.config.r)
.attr('fill', (d) => d.color || this.config.nodeColor)
.attr(
'fill',
(d) =>
(d && this.config.colorList[d.nodeLabel || 'default']) ||
this.config.nodeColor
)
this.patterns
.append('text')
.attr('class', 'node-text')
.attr('x', this.config.r)
.attr('y', this.config.r * 0.9) // edit
.attr('y', this.config.r) // edit
.attr('text-anchor', 'middle')
.attr('fill', this.config.fontColor)
.style('font-size', this.config.r / 3.8)
.text((d) => d.name)
.text((d) => d[d.nodeLabel.toLowerCase() + 'Name'])
// 4.放关系图的容器
this.relMap_g = this.SVG.append('g')
......@@ -294,7 +340,7 @@ export default class RelationGraph {
.attr('y', 5)
.attr('text-anchor', 'middle') // <text>文本中轴对齐方式居中 start | middle | end
.style('font-size', 12)
.text((d) => d.relation)
.text((d) => d.name)
const tooltip = d3
.select('body')
......@@ -322,17 +368,17 @@ export default class RelationGraph {
.on('mouseover', function (e, d) {
d3.select(this).attr(
'stroke-width',
self.config.strokeWidth == 0 ? 5 : 1.5 * self.config.strokeWidth
self.config.strokeWidth == 0 ? 3 : 1.5 * self.config.strokeWidth
)
d3.select(this).attr('stroke', d.strokeColor || self.config.strokeColor)
if (self.config.isHighLight) {
self.highlightObject(d)
}
tooltip
.html(d.name)
.style('left', e.pageX + 10 + 'px')
.style('top', e.pageY + 10 + 'px')
.style('opacity', 1)
// tooltip
// .html(d.name)
// .style('left', e.pageX + 10 + 'px')
// .style('top', e.pageY + 10 + 'px')
// .style('opacity', 1)
})
.on('mouseout', function (e, d) {
d3.select(this).attr('stroke-width', self.config.strokeWidth)
......@@ -340,15 +386,15 @@ export default class RelationGraph {
if (self.config.isHighLight) {
self.highlightObject(null)
}
tooltip.style('opacity', 0)
// tooltip.style('opacity', 0)
})
.on('click', function (e, d) {
menu && menu.hide()
menu = new RadialMenu()
.radius(50)
.thickness(40)
.appendTo(this.parentNode)
.show(menuData)
if (menu && menu.curNodeData == d) {
self.closeMenu()
} else {
self.closeMenu()
self.openMenu(this, d)
}
//阻止事件冒泡 阻止事件默认行为
e.stopPropagation ? e.stopPropagation() : (e.cancelBubble = true)
e.preventDefault ? e.preventDefault() : (e.returnValue = false)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment