271 lines
7.0 KiB
Vue
271 lines
7.0 KiB
Vue
<style>
|
|
.info-div {
|
|
width: 100%;
|
|
position: absolute;
|
|
bottom: 0;
|
|
left: 0;
|
|
}
|
|
</style>
|
|
<template>
|
|
<v-app>
|
|
<v-app-bar
|
|
app
|
|
color="primary"
|
|
dark
|
|
dense
|
|
>
|
|
<v-app-bar-nav-icon>
|
|
<v-avatar size="20">
|
|
<img
|
|
src="/favicon.ico"
|
|
alt="veypi"
|
|
>
|
|
</v-avatar>
|
|
</v-app-bar-nav-icon>
|
|
<v-toolbar-title>
|
|
{{ $store.state.algorithms[$store.state.algorithm].text }}
|
|
</v-toolbar-title>
|
|
<v-spacer></v-spacer>
|
|
<v-text-field
|
|
v-model="search"
|
|
append-icon="mdi-magnify"
|
|
label="Search"
|
|
single-line
|
|
hide-details
|
|
></v-text-field>
|
|
<v-icon class="mr-5" @click="info=!info">mdi-information</v-icon>
|
|
<v-icon class="mr-5" @click="sync">mdi-autorenew</v-icon>
|
|
<v-btn color="warning" class="mr-5" v-if="$store.state.algorithm===0" @click="$refs.core.lay2()">计算</v-btn>
|
|
<v-icon @click="dialog=!dialog">mdi-cog</v-icon>
|
|
</v-app-bar>
|
|
<v-main>
|
|
<v-system-bar>
|
|
<v-row class="text-center">
|
|
<v-col>边数: {{ $store.state.edgesNum }}</v-col>
|
|
<v-col>节点数: {{ $store.state.nodesNum }}</v-col>
|
|
</v-row>
|
|
</v-system-bar>
|
|
<router-view ref="core" style="height: 100%;width: 100%"></router-view>
|
|
</v-main>
|
|
<div class="info-div" v-if="info">
|
|
<v-data-table
|
|
class="mx-auto"
|
|
:headers="headers"
|
|
:items="nodeList"
|
|
:search="search"
|
|
disable-sort
|
|
dense
|
|
height="300px"
|
|
style="background: rgba(0,0,0,0.2);"
|
|
>
|
|
<template v-slot:item.x="{ item }">
|
|
{{ item.x.toFixed(2) }}
|
|
</template>
|
|
<template v-slot:item.y="{ item }">
|
|
{{ item.y.toFixed(2) }}
|
|
</template>
|
|
<template v-slot:item.act="{ item }">
|
|
<v-btn v-if="item.color === freeC " color="warning" @click="lock(item)">固定</v-btn>
|
|
<v-btn v-else color="primary" @click="unlock(item)">解除</v-btn>
|
|
</template>
|
|
</v-data-table>
|
|
</div>
|
|
<v-dialog
|
|
v-model="dialog"
|
|
transition="dialog-bottom-transition"
|
|
max-width="600"
|
|
>
|
|
<v-card>
|
|
<v-system-bar
|
|
color="success"
|
|
dark
|
|
>
|
|
设置
|
|
</v-system-bar>
|
|
<v-card-text class="mt-10">
|
|
<v-form>
|
|
<v-select v-model="$store.state.algorithm" :items="$store.state.algorithms" label="算法"></v-select>
|
|
<v-slider
|
|
label="节点数量"
|
|
class="mt-10"
|
|
v-model="$store.state.nodesNum"
|
|
thumb-label="always"
|
|
:max="$store.state.algorithm ? 100: 10"
|
|
:min="5"
|
|
></v-slider>
|
|
<v-slider
|
|
:max="$store.state.nodesNum * 5"
|
|
:min="$store.state.nodesNum * (1 + $store.state.algorithm) - 1" label="边数量" class="mt-10"
|
|
v-model="$store.state.edgesNum" thumb-label="always"></v-slider>
|
|
</v-form>
|
|
</v-card-text>
|
|
</v-card>
|
|
</v-dialog>
|
|
</v-app>
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
import Vue from 'vue'
|
|
|
|
function uniform2NormalDistribution() {
|
|
let sum = 0.0
|
|
for (let i = 0; i < 12; i++) {
|
|
sum = sum + Math.random(1)
|
|
}
|
|
return sum - 6.0
|
|
}
|
|
|
|
function getNumberInNormalDistribution(mean, stdDev) {
|
|
return mean + (uniform2NormalDistribution() * stdDev)
|
|
}
|
|
|
|
export default Vue.extend({
|
|
name: 'App',
|
|
|
|
components: {},
|
|
|
|
data: () => ({
|
|
freeC: '#5cf43d',
|
|
search: '',
|
|
headers: [
|
|
{
|
|
text: '节点id',
|
|
align: 'start',
|
|
width: '60px',
|
|
value: 'id'
|
|
},
|
|
{text: 'x', value: 'x', width: 60},
|
|
{text: 'y', value: 'y', width: 60},
|
|
{text: 'act', value: 'act'}
|
|
],
|
|
dialog: false,
|
|
info: false
|
|
//
|
|
}),
|
|
computed: {
|
|
nodeList() {
|
|
return Object.keys(this.$store.state.nodes).map(v => {
|
|
return this.$store.state.nodes[v]
|
|
})
|
|
}
|
|
},
|
|
methods: {
|
|
lock(n) {
|
|
n.color = 'red'
|
|
n.fx = n.x
|
|
n.fy = n.y
|
|
const graph = this.$refs.core.graph
|
|
graph.updateItem(n.id, {color: n.color})
|
|
},
|
|
unlock(n) {
|
|
n.color = this.freeC
|
|
n.fx = null
|
|
n.fy = null
|
|
this.$refs.core.graph.updateItem(n.id, {color: n.color})
|
|
},
|
|
sync() {
|
|
const edges = {}
|
|
const nodes = {}
|
|
for (let i = 0; i < this.$store.state.nodesNum; i++) {
|
|
nodes['n' + i] = {
|
|
label: 'n' + i,
|
|
id: 'n' + i,
|
|
// 随机布局
|
|
color: this.freeC,
|
|
x: i * Math.random() * 100,
|
|
y: i * Math.random() * 100,
|
|
size: Math.floor(Math.random() * 20) + 5
|
|
}
|
|
}
|
|
// nodes.n0.color = 'red'
|
|
// nodes.n0.fx = 100
|
|
// nodes.n0.fy = 175
|
|
// nodes.n0.x = 100
|
|
// nodes.n0.y = 175
|
|
// nodes.n1.color = 'red'
|
|
// nodes.n1.fx = 200
|
|
// nodes.n1.fy = 225
|
|
// nodes.n1.x = 200
|
|
// nodes.n1.y = 225
|
|
// edges['0-2'] = {
|
|
// id: '0-2',
|
|
// source: 'n0',
|
|
// target: 'n2',
|
|
// value: 1
|
|
// }
|
|
// edges['2-3'] = {
|
|
// id: '2-3',
|
|
// source: 'n2',
|
|
// target: 'n3',
|
|
// value: 1
|
|
// }
|
|
// edges['3-4'] = {
|
|
// id: '3-4',
|
|
// source: 'n3',
|
|
// target: 'n4',
|
|
// value: 1
|
|
// }
|
|
// edges['4-1'] = {
|
|
// id: '4-1',
|
|
// source: 'n4',
|
|
// target: 'n1',
|
|
// value: 1
|
|
// }
|
|
let iter = 1
|
|
for (let i = 0; i < this.$store.state.nodesNum; i++) {
|
|
if (Object.keys(edges).length >= this.$store.state.edgesNum) {
|
|
this.$store.state.edges = edges
|
|
this.$store.state.nodes = nodes
|
|
this.$refs.core.loaddata()
|
|
return
|
|
}
|
|
let j = i
|
|
while (i === j) {
|
|
j = Math.floor(Math.random() * this.$store.state.nodesNum)
|
|
}
|
|
let ni = i
|
|
if (i > j) {
|
|
ni = j
|
|
j = i
|
|
}
|
|
const v = Math.abs(Math.floor(getNumberInNormalDistribution(4, 20)))
|
|
edges[ni + '-' + j] = {
|
|
id: ni + '-' + j,
|
|
source: 'n' + ni,
|
|
target: 'n' + j,
|
|
value: v
|
|
}
|
|
}
|
|
while (iter < 10) {
|
|
iter = iter + 1
|
|
for (let i = 0; i < this.$store.state.nodesNum; i++) {
|
|
for (let j = i + 1; j < this.$store.state.nodesNum; j++) {
|
|
// const v = Math.floor(Math.random() * 10)
|
|
const v = Math.floor(getNumberInNormalDistribution(4, 20))
|
|
if (v > 0) {
|
|
const id = i + '-' + j
|
|
edges[id] = {
|
|
id: id,
|
|
source: 'n' + i,
|
|
target: 'n' + j,
|
|
value: v
|
|
// label: v
|
|
}
|
|
if (Object.keys(edges).length >= this.$store.state.edgesNum) {
|
|
this.$store.state.edges = edges
|
|
this.$store.state.nodes = nodes
|
|
this.$refs.core.loaddata()
|
|
return
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
mounted() {
|
|
this.sync()
|
|
}
|
|
})
|
|
</script>
|