|
@@ -1,263 +1,101 @@
|
|
|
<template>
|
|
|
- <div>
|
|
|
- <div id="chart" style="width: 1000px; height: 700px"></div>
|
|
|
- <button v-show="selectedNode" @click="addLeftNode">添加左节点</button>
|
|
|
- <button v-show="selectedNode" @click="addRightNode">添加右节点</button>
|
|
|
- <button v-show="selectedNode" @click="deleteNode">删除该节点</button>
|
|
|
- <button v-show="selectedNode" @click="updateNode">修改该节点</button>
|
|
|
-
|
|
|
- <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
|
|
|
- <el-form ref="form" :model="form" :rules="rules" label-width="80px">
|
|
|
- <el-form-item label="检查点" prop="startId">
|
|
|
- <el-select
|
|
|
- v-model="form.id"
|
|
|
- placeholder="请选择检查点"
|
|
|
- value-key="id"
|
|
|
- filterable
|
|
|
- >
|
|
|
- <el-option
|
|
|
- v-for="item in pointList"
|
|
|
- :key="item.id"
|
|
|
- :label="item.check_piont"
|
|
|
- :value="item.id"
|
|
|
- >
|
|
|
- </el-option>
|
|
|
- </el-select>
|
|
|
- </el-form-item>
|
|
|
- </el-form>
|
|
|
- <div slot="footer" class="dialog-footer">
|
|
|
- <el-button type="primary" @click="submitForm">确 定</el-button>
|
|
|
- <el-button @click="cancel">取 消</el-button>
|
|
|
- </div>
|
|
|
- </el-dialog>
|
|
|
- </div>
|
|
|
+ <div class="app-container" ref="svgContainer"></div>
|
|
|
</template>
|
|
|
|
|
|
-
|
|
|
-
|
|
|
<script>
|
|
|
-import echarts from "echarts";
|
|
|
-import { getPointOption } from "@/api/suport/piont";
|
|
|
+import * as d3 from 'd3';
|
|
|
|
|
|
export default {
|
|
|
- data() {
|
|
|
- return {
|
|
|
- chartInstance: null,
|
|
|
- selectedNode: null,
|
|
|
- treeData: [
|
|
|
- // 初始节点
|
|
|
- {
|
|
|
- name: "Root",
|
|
|
- value: null,
|
|
|
- children: [],
|
|
|
- borderColor: {
|
|
|
- color: "#ccc"
|
|
|
- }
|
|
|
- },
|
|
|
- ],
|
|
|
- title: "",
|
|
|
- open: false,
|
|
|
- form: {},
|
|
|
- rules: {},
|
|
|
- pointList: [],
|
|
|
- ecode:'',
|
|
|
- };
|
|
|
- },
|
|
|
-
|
|
|
- created() {
|
|
|
- this.getPointOption();
|
|
|
- },
|
|
|
-
|
|
|
mounted() {
|
|
|
- this.chartInstance = echarts.init(document.getElementById("chart"));
|
|
|
- this.chartInstance.on("click", this.selectNode); // 监听点击事件
|
|
|
- this.renderChart();
|
|
|
- this.levelOrder();
|
|
|
- },
|
|
|
- beforeDestroy() {
|
|
|
- this.chartInstance.off("click", this.selectNode); // 移除监听事件
|
|
|
- },
|
|
|
- methods: {
|
|
|
- renderChart() {
|
|
|
- const option = {
|
|
|
- // ECharts配置项
|
|
|
- tooltip: {
|
|
|
- trigger: "item",
|
|
|
- triggerOn: "mousemove",
|
|
|
- },
|
|
|
- series: [
|
|
|
- {
|
|
|
- type: "tree",
|
|
|
- data: this.treeData,
|
|
|
- left: "2%",
|
|
|
- right: "2%",
|
|
|
- top: "8%",
|
|
|
- bottom: "20%",
|
|
|
- symbol: "emptyCircle",
|
|
|
- orient: "vertical",
|
|
|
- symbolSize: 30,
|
|
|
- itemStyle: {
|
|
|
- color: null,
|
|
|
- },
|
|
|
- expandAndCollapse: false,
|
|
|
- label: {
|
|
|
- position: "bottom",
|
|
|
- rotate: 0,
|
|
|
- verticalAlign: "middle",
|
|
|
- align: "center",
|
|
|
- fontSize: 15,
|
|
|
- distance: 10,
|
|
|
- },
|
|
|
- animationDurationUpdate: 750,
|
|
|
- initialTreeDepth: 10,
|
|
|
- },
|
|
|
- ],
|
|
|
- };
|
|
|
-
|
|
|
- this.chartInstance.setOption(option);
|
|
|
- },
|
|
|
-
|
|
|
- reset() {
|
|
|
- this.form = {
|
|
|
- id: null,
|
|
|
- code: null,
|
|
|
- checkPiont: null,
|
|
|
- createBy: null,
|
|
|
- createTime: null,
|
|
|
- updateBy: null,
|
|
|
- updateTime: null,
|
|
|
- };
|
|
|
- this.resetForm("form");
|
|
|
- },
|
|
|
-
|
|
|
- selectNode(params) {
|
|
|
- if (params.data && params.data.name) {
|
|
|
- this.selectedNode = params.data;
|
|
|
+ const svgContainer = this.$refs.svgContainer;
|
|
|
+ const width = svgContainer.clientWidth;
|
|
|
+ const height = svgContainer.clientHeight;
|
|
|
+
|
|
|
+ const links = [
|
|
|
+ { source: "A", target: "B", value: 1 },
|
|
|
+ { source: "A", target: "C", value: 2 },
|
|
|
+ { source: "B", target: "C", value: 3 },
|
|
|
+ { source: "B", target: "D", value: 4 },
|
|
|
+ { source: "C", target: "D", value: 5 },
|
|
|
+ ];
|
|
|
+
|
|
|
+ const nodes = [
|
|
|
+ { id: "A", x: 100, y: 100 },
|
|
|
+ { id: "B", x: 200, y: 100 },
|
|
|
+ { id: "C", x: 150, y: 200 },
|
|
|
+ { id: "D", x: 250, y: 200 },
|
|
|
+ ];
|
|
|
+
|
|
|
+ const svg = d3.select(svgContainer).append("svg")
|
|
|
+ .attr("width", width)
|
|
|
+ .attr("height", height);
|
|
|
+
|
|
|
+ const link = svg.selectAll("line")
|
|
|
+ .data(links)
|
|
|
+ .join("line")
|
|
|
+ .attr("stroke", "black")
|
|
|
+ .attr("stroke-width", d => d.value);
|
|
|
+
|
|
|
+ const node = svg.selectAll("circle")
|
|
|
+ .data(nodes)
|
|
|
+ .join("circle")
|
|
|
+ .attr("r", 20)
|
|
|
+ .attr("fill", "red")
|
|
|
+ .call(drag(simulation));
|
|
|
+
|
|
|
+ const label = svg.selectAll("text")
|
|
|
+ .data(nodes)
|
|
|
+ .join("text")
|
|
|
+ .text(d => d.id)
|
|
|
+ .attr("x", d => d.x)
|
|
|
+ .attr("y", d => d.y);
|
|
|
+
|
|
|
+ const simulation = d3.forceSimulation(nodes)
|
|
|
+ .force("link", d3.forceLink(links).id(d => d.id))
|
|
|
+ .force("charge", d3.forceManyBody())
|
|
|
+ .force("center", d3.forceCenter(width / 2, height / 2));
|
|
|
+
|
|
|
+ simulation.on("tick", () => {
|
|
|
+ link
|
|
|
+ .attr("x1", d => d.source.x)
|
|
|
+ .attr("y1", d => d.source.y)
|
|
|
+ .attr("x2", d => d.target.x)
|
|
|
+ .attr("y2", d => d.target.y);
|
|
|
+
|
|
|
+ node
|
|
|
+ .attr("cx", d => d.x)
|
|
|
+ .attr("cy", d => d.y);
|
|
|
+
|
|
|
+ label
|
|
|
+ .attr("x", d => d.x)
|
|
|
+ .attr("y", d => d.y - 25);
|
|
|
+ });
|
|
|
+
|
|
|
+ function drag(simulation) {
|
|
|
+
|
|
|
+ function dragstarted(event) {
|
|
|
+ if (!event.active) simulation.alphaTarget(0.3).restart();
|
|
|
+ event.subject.fx = event.subject.x;
|
|
|
+ event.subject.fy = event.subject.y;
|
|
|
}
|
|
|
- },
|
|
|
|
|
|
- addLeftNode() {
|
|
|
- const newNode = { name: "Left Node", value: null, children: [], itemStyle: {borderColor: "#FF0000"} };
|
|
|
- this.selectedNode.children.unshift(newNode);
|
|
|
- this.treeData = this.chartInstance.getOption().series[0].data;
|
|
|
- this.chartInstance.clear();
|
|
|
- this.renderChart();
|
|
|
- this.levelOrder();
|
|
|
- },
|
|
|
- addRightNode() {
|
|
|
- const newNode = { name: "Right Node", value: null, children: [],itemStyle: {borderColor: "#0000FF"} };
|
|
|
- this.selectedNode.children.push(newNode);
|
|
|
- this.treeData = this.chartInstance.getOption().series[0].data;
|
|
|
- this.chartInstance.clear();
|
|
|
- this.renderChart();
|
|
|
- this.levelOrder();
|
|
|
- },
|
|
|
- deleteNode() {
|
|
|
- this.treeData = this.chartInstance.getOption().series[0].data;
|
|
|
- const parentNode = this.findParentNode(this.treeData, this.selectedNode);
|
|
|
- if (parentNode) {
|
|
|
- const index = parentNode.children.indexOf(this.selectedNode);
|
|
|
- parentNode.children.splice(index, 1);
|
|
|
- this.chartInstance.clear();
|
|
|
- this.renderChart();
|
|
|
- this.levelOrder();
|
|
|
- this.selectedNode = null;
|
|
|
- }
|
|
|
- },
|
|
|
- findParentNode(tree, targetNode) {
|
|
|
- for (const node of tree) {
|
|
|
- for (const child of node.children) {
|
|
|
- if (child.name === targetNode.name) {
|
|
|
- return node;
|
|
|
- }
|
|
|
- }
|
|
|
- if (node.children.length > 0) {
|
|
|
- const parentNode = this.findParentNode(node.children, targetNode);
|
|
|
- if (parentNode) {
|
|
|
- return parentNode;
|
|
|
- }
|
|
|
- }
|
|
|
+ function dragged(event) {
|
|
|
+ event.subject.fx = event.x;
|
|
|
+ event.subject.fy = event.y;
|
|
|
}
|
|
|
- return null;
|
|
|
- },
|
|
|
|
|
|
- updateNode() {
|
|
|
- this.reset();
|
|
|
- this.form.id = this.selectedNode.value;
|
|
|
- this.open = true;
|
|
|
- this.title = "修改检查点";
|
|
|
- },
|
|
|
-
|
|
|
- /** 提交按钮 */
|
|
|
- submitForm() {
|
|
|
- this.selectedNode.value = this.form.id;
|
|
|
- for (const point of this.pointList) {
|
|
|
- if (point.id === this.form.id) {
|
|
|
- this.selectedNode.name = point.check_piont;
|
|
|
- break;
|
|
|
- }
|
|
|
+ function dragended(event) {
|
|
|
+ if (!event.active) simulation.alphaTarget(0);
|
|
|
+ event.subject.fx = null;
|
|
|
+ event.subject.fy = null;
|
|
|
}
|
|
|
- this.open = false;
|
|
|
- this.treeData = this.chartInstance.getOption().series[0].data;
|
|
|
- this.chartInstance.clear();
|
|
|
- this.renderChart();
|
|
|
- this.levelOrder();
|
|
|
- },
|
|
|
-
|
|
|
- // 取消按钮
|
|
|
- cancel() {
|
|
|
- this.open = false;
|
|
|
- this.reset();
|
|
|
- },
|
|
|
-
|
|
|
- getPointOption() {
|
|
|
- getPointOption().then((resp) => {
|
|
|
- this.pointList = resp.data;
|
|
|
- console.info(resp);
|
|
|
- });
|
|
|
- },
|
|
|
|
|
|
- levelOrder() {
|
|
|
- const ret = [];
|
|
|
- if (!this.treeData) {
|
|
|
- return ret;
|
|
|
- }
|
|
|
- const q = [];
|
|
|
- q.push(this.treeData[0]);
|
|
|
- while (q.length !== 0) {
|
|
|
- const currentLevelSize = q.length;
|
|
|
- const nullNode = { name: "", value: 0, children: [],itemStyle: {} };
|
|
|
- for (let i = 1; i <= currentLevelSize; ++i) {
|
|
|
- const node = q.shift();
|
|
|
- ret.push(node.value);
|
|
|
- let n = node.children.length;
|
|
|
- if (n == 0 && node.value != 0) {
|
|
|
- q.push(nullNode);
|
|
|
- q.push(nullNode);
|
|
|
- }
|
|
|
- else if (n == 1) {
|
|
|
- if (node.children[0].itemStyle.borderColor == "#FF0000"){
|
|
|
- q.push(node.children[0]);
|
|
|
- q.push(nullNode);
|
|
|
- }
|
|
|
- else {
|
|
|
- q.push(nullNode);
|
|
|
- q.push(node.children[0]);
|
|
|
- }
|
|
|
- }
|
|
|
- else if (n == 2) {
|
|
|
- q.push(node.children[0]);
|
|
|
- q.push(node.children[1]);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- let n = ret.length;
|
|
|
- while (ret[n-1] === 0) {
|
|
|
- ret.pop();
|
|
|
- n--;
|
|
|
- }
|
|
|
- this.$emit('flowEncode', ret.join(','));
|
|
|
- },
|
|
|
- },
|
|
|
-};
|
|
|
+ return d3.drag()
|
|
|
+ .on("start", dragstarted)
|
|
|
+ .on("drag",
|
|
|
+ dragged)
|
|
|
+ .on("end", dragended);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
</script>
|