1.新增高德自定义图层解决方案:遗留问题:鼠标点击地图后会吸附到地图上,操作滚轮可取消吸附

2.新增gojs+leaflet解决方案:研究进度:案例简单结合,如采用该方案需要深度学习gojs和leaflet,将两者进行深度融合
This commit is contained in:
wangzijun 2022-08-02 14:02:47 +08:00
parent 9fc0b40cd6
commit e4024064d1
8 changed files with 2095 additions and 4 deletions

View File

@ -8,14 +8,16 @@
"lint": "vue-cli-service lint" "lint": "vue-cli-service lint"
}, },
"dependencies": { "dependencies": {
"@amap/amap-jsapi-loader": "^1.0.1",
"@antv/x6": "^1.32.3-beta.1", "@antv/x6": "^1.32.3-beta.1",
"@antv/x6-vue-shape": "^1.4.0", "@antv/x6-vue-shape": "^1.4.0",
"@vue/composition-api": "^1.6.3", "@vue/composition-api": "^1.6.3",
"core-js": "^3.6.5", "core-js": "^3.6.5",
"element-ui": "^2.15.9", "element-ui": "^2.15.9",
"gojs": "^2.2.14",
"vue": "^2.6.11", "vue": "^2.6.11",
"vue-json-viewer": "^2.2.22", "vue-baidu-map": "^0.21.22",
"vue-baidu-map": "^0.21.22" "vue-json-viewer": "^2.2.22"
}, },
"devDependencies": { "devDependencies": {
"@vue/cli-plugin-babel": "~4.5.13", "@vue/cli-plugin-babel": "~4.5.13",

View File

@ -5,6 +5,8 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0"> <meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico"> <link rel="icon" href="<%= BASE_URL %>favicon.ico">
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.8.0/dist/leaflet.css">
<script src="https://unpkg.com/leaflet@1.8.0/dist/leaflet.js"></script>
<title><%= htmlWebpackPlugin.options.title %></title> <title><%= htmlWebpackPlugin.options.title %></title>
</head> </head>
<body> <body>

View File

@ -1,15 +1,21 @@
<template> <template>
<div id="app"> <div id="app">
<index-stencil></index-stencil> <!-- <index-stencil></index-stencil> -->
<!-- <index-gaode></index-gaode> -->
<index-gojs></index-gojs>
</div> </div>
</template> </template>
<script> <script>
import indexStencil from "./demo/index-stencil.vue"; import indexStencil from "./demo/index-stencil.vue";
import indexGaode from "./demo/index-gaode.vue";
import indexGojs from "./gojsDemo/index-gojs.vue";
export default { export default {
name: 'App', name: 'App',
components: { components: {
indexStencil indexStencil,
indexGaode,
indexGojs
} }
} }
</script> </script>

572
src/demo/index-gaode.vue Normal file
View File

@ -0,0 +1,572 @@
<template>
<div>
<div class="tools-bar">
<el-popover
placement="bottom"
width="200"
class="el-po"
trigger="click">
<div ref="stencilContainer" class="x6-stencil"></div>
<i class="el-icon-s-operation opt-btn" slot="reference" ></i>
</el-popover>
</div>
<div class="content" :style="{ height: contentHeight }">
<!-- <div ref="stencilContainer" class="x6-stencil"></div> -->
<div class="middle-box">
<div
ref="container"
class="x6-content"
:style="{ height: contentHeight }"
></div>
<div
id="map-container"
class="mp-view"
:style="{ height: contentHeight }"
></div>
</div>
</div>
</div>
</template>
<script>
import { Graph, Shape, Addon,Path } from '@antv/x6';
const { Stencil } = Addon
const { Rect, Circle } = Shape
import AMapLoader from '@amap/amap-jsapi-loader';
export default {
data() {
return {
contentHeight:'0px', //x6
mapHeight: "200px", //
center: {lng: 0, lat: 0},//
zoom: 3,//
graph:undefined,//x6
stencil:undefined,//x6
projection:undefined,//projection
map:null,//
data : {
//
nodes: [
{
id: 'node1', // String
x: 0, // Number x
y: 0, // Number y
width: 80, // Number width
height: 40, // Number height
label: 'hello', // String
},
{
id: 'node2', // String
x: 160, // Number x
y: 180, // Number y
width: 80, // Number width
height: 40, // Number height
label: 'world', // String
},
],
//
edges: [
{
source: 'node1', // String id
target: 'node2', // String id
},
],
}
}
},
mounted () {
this.init()
this.initCell()
this.initGraph();
this.initStencil()
this.initGaodeMap()
},
methods:{
onRender() {
//
//
const container = this.$refs.container
const ports = container.querySelectorAll(
'.x6-port-body',
)
//
this.graph.getNodes().forEach((node)=>{
let mapPoint = node.store.data.mapPoint
//
var lnglat = new AMap.LngLat(mapPoint.lng,mapPoint.lat);
var pixel = this.map.lngLatToContainer(lnglat);
node.position(pixel.round().x,pixel.round().y)
})
},
init() {
this.contentHeight = document.documentElement.clientHeight -45 + "px";
this.mapHeight = document.documentElement.clientHeight -45 + "px";
},
//
initCell(){
//
const ports = {
groups: {
top: {
position: 'top',
attrs: {
circle: {
r: 4,
magnet: true,
stroke: '#5F95FF',
strokeWidth: 1,
fill: '#fff',
style: {
visibility: 'hidden',
},
},
},
},
right: {
position: 'right',
attrs: {
circle: {
r: 4,
magnet: true,
stroke: '#5F95FF',
strokeWidth: 1,
fill: '#fff',
style: {
visibility: 'hidden',
},
},
},
},
bottom: {
position: 'bottom',
attrs: {
circle: {
r: 4,
magnet: true,
stroke: '#5F95FF',
strokeWidth: 1,
fill: '#fff',
style: {
visibility: 'hidden',
},
},
},
},
left: {
position: 'left',
attrs: {
circle: {
r: 4,
magnet: true,
stroke: '#5F95FF',
strokeWidth: 1,
fill: '#fff',
style: {
visibility: 'hidden',
},
},
},
},
},
items: [
{
group: 'top',
},
{
group: 'right',
},
{
group: 'bottom',
},
{
group: 'left',
},
],
}
//
Graph.registerNode(
'custom-rect',
{
inherit: 'rect',
width: 66,
height: 36,
attrs: {
body: {
strokeWidth: 1,
stroke: '#5F95FF',
fill: '#EFF4FF',
},
text: {
fontSize: 12,
fill: '#262626',
},
},
ports: { ...ports },
},
true,
)
},
//
initGaodeMap(){
AMapLoader.load({
key:'5cebc9186d74c44afbfee1e178a89782',
version:'2.0',
plugins:['']
}).then((AMap)=>{
this.map = new AMap.Map("map-container",{
zoom:5,//
center:[105.602725,37.076636],//
})
//var x6Dom = document.createElement('container');
var x6Dom = this.$refs.container
var x6 = document.getElementsByClassName("x6-graph-svg")[1];
console.log("x6Dom",this.$refs.container)
//
var customLayer = new AMap.CustomLayer(x6Dom, {
zIndex: 12,
zooms: [3, 18], // []
dragEnable: true
});
customLayer.render = this.onRender;
this.map.add(customLayer)
}).catch(e=>{
console.log(e)
})
},
//
initGraph(){
console.log("x6图层",this.$refs.container)
let mapZoom = this.zoom
this.graph = new Graph({
container: this.$refs.container,
background: {//
color: 'transport', //
},
grid: {//
size: 10, // 10px
visible: true, //
},
// panning: {//
// enabled: true, //
// modifiers: 'shift', //
// },
// mousewheel: {//
// enabled: true,
// modifiers: ['ctrl'],
// guard(e){//
// return true
// }
// },
snapline: true,//线
selecting: {///
enabled: true,///
rubberband: true,//
showNodeSelectionBox: true,//
},
resizing:true,//
highlighting: {//
//
magnetAdsorbed: {
name: 'stroke',
args: {
attrs: {
//fill: '#5F95FF',
stroke: '#5F95FF',
},
},
},
//
embedding: {
name: 'stroke',
args: {
padding: -1,
attrs: {
stroke: '#73d13d',
},
},
},
},
connecting:{//线
//20
snap: {
radius: 20,
},
allowBlank:false,//
allowNode:false,//
allowEdge:false,//
anchor: 'center',// anchor
connectionPoint: 'anchor',//
router: {// vertices
name: 'manhattan',
args: {
padding: 1,
},
},
connector: {//
name: 'rounded',
args: {
radius: 8,
},
},
createEdge() {//
return new Shape.Edge({
attrs: {
line: {
//stroke: '#A2B1C3',
stroke: 'green',
strokeWidth: 3,
targetMarker: {
name: 'block',
width: 12,
height: 8,
},
},
},
zIndex: 20,
})
},
validateConnection({ targetMagnet }) {//
return !!targetMagnet
},
},
//
embedding:{
enabled:true,//
findParent(node){// findParent
const bbox = node.node.getBBox()
return this.getNodes().filter((node) => {
// data.parent true
const data = node.getData()
if (data && data.canBeParent) {
const targetBBox = node.getBBox()
return bbox.isIntersectWithRect(targetBBox)
}
return false
})
}
},
//
translating: {
restrict(view) {
if(view){
const cell = view.cell
if (cell.isNode()) {
const parent = cell.getParent()
if (parent) {
return parent.getBBox()
}
}
}
return null
},
},
});
//this.graph.fromJSON(this.data)
//
//
this.graph.on('node:mouseenter', ( e ) => {
const container = this.$refs.container
const ports = container.querySelectorAll(
'.x6-port-body',
)
this.showPorts(ports, true)
this.showNodeTool(e.node,true)
//
this.changeMapDrag(false)
})
//
this.graph.on('node:mouseleave', ( e) => {
const container = this.$refs.container
const ports = container.querySelectorAll(
'.x6-port-body',
)
this.showPorts(ports, false)
this.showNodeTool(e.node,false)
//
this.changeMapDrag(true)
})
//线线
this.graph.on('edge:mouseenter',(e)=>{
this.showEdgeTool(e.edge,true)
})
//线线
this.graph.on('edge:mouseleave',(e)=>{
this.showEdgeTool(e.edge,false)
})
//
this.graph.on('node:change:parent', ({ node }) => {
node.attr({
body:{
stroke: 'none',
fill: '#47C769',
},
label: {
text: '节点-过程',
},
})
})
//
this.graph.on('node:added',(args)=>{
//
this.pixelToPoint(args.node,args.node.store.data.position)
})
//
this.graph.on('node:change:position',(args)=>{
//
this.pixelToPoint(args.node,args.current)
})
//
// this.graph.on('translate', ({ tx, ty }) => {
// console.log("tx",tx)
// //console.log("ty",ty)
// this.mapScrollBy(tx,ty)
// })
},
//Stencil
initStencil(){
this.stencil = new Stencil({
target: this.graph,//
stencilGraphWidth: 200,//
stencilGraphHeight: 80,//
groups: [
{
name: 'group1',//
title: '元素',//
collapsable: false,// true
},
],
})
//Stencil
this.$refs.stencilContainer.appendChild(this.stencil.container)
//
const process = this.graph.createNode({
shape: 'custom-rect',
label: '过程',
zIndex: 10,
attrs: {
body: {
stroke: 'none',
fill: '#3199FF',
},
},
})
const node = this.graph.createNode({
shape: 'custom-rect',
label: '节点',
zIndex: 1,
data: {
canBeParent: true,
},
})
//
this.stencil.load([process,node], 'group1')
},
///
showPorts(ports,show){
ports.forEach(port => {
port.style.visibility = show?'visible' : 'hidden'
});
},
///
showNodeTool(node,show){
if(show){
node.addTools({
name: 'button-remove',
args: {
x: '100%',
y: 0,
offset: { x: -3, y: 3 },
},
})
}else{
node.removeTools()
}
},
//线/
showEdgeTool(edge,show){
if(show){
edge.addTools({
name: 'button-remove',
args: { distance: -40 },
})
}else{
edge.removeTools()
}
},
//
pixelToPoint(node,position){
let ePoint = this.map.containerToLngLat(new AMap.Pixel(position.x, position.y))
//node
node.store.data.mapPoint = ePoint
console.log("新位置数据",node)
},
//
mapScrollBy(tx,ty){
this.projection.panBy(tx,ty)
},
///
changeMapDrag(canDrag){
this.map.setStatus({
dragEnable:canDrag
})
}
}
}
</script>
<style lang="scss" scoped>
.tools-bar{
height: 45px;
line-height: 45px;
background: #fff;
display: flex;
.opt-btn{
margin-top: 4px;
font-size: 35px;
}
}
.content {
display: flex;
.x6-stencil{
width: 250px;
}
.middle-box{
width: 100%;
position: relative;
.x6-content {
width: 100%;
position: absolute;
z-index: 1;
}
.mp-view{
width: 100%;
position:absolute;
z-index: 2;
}
}
}
.el-popover{
height: 500px;
overflow: auto;
}
</style>
<style>
.el-popover{
height: 120px;
overflow: auto;
}
</style>

View File

@ -0,0 +1,580 @@
<!--
* @FilePath src/views/dashboard/components/FlowChart/index.vue
* @Created Bay<baizhanying@autobio.com.cn> 2021-11-10 14:23:50
* @Modified Bay<baizhanying@autobio.com.cn> 2021-11-10 18:11:22
* @Description https://github.com/NorthwoodsSoftware/GoJS/blob/master/samples/flowchart.html
-->
<template>
<div id="diagram-contanier">
<div id="diagram-tool">
<slot>
<el-button type="primary" @click="save">保存</el-button>
<el-button @click="load">加载</el-button>
</slot>
</div>
<div id="diagram-wrap">
<div id="diagram-palette" ref="palette" />
<!-- <div id="diagram" ref="diagram" /> -->
<!-- <div>
<div id="diagram" ref="diagram" />
</div> -->
<div id="map"
class="mapDiagram leaflet-container leaflet-touch leaflet-retina leaflet-fade-anim leaflet-touch-zoom leaflet-grab leaflet-touch-drag"
tabindex="0"
style="position: relative;width:100%">
<div style="height:100%" id="diagram" ref="diagram" />
</div>
<!-- <div id="diagram" ref="diagram" /> -->
</div>
</div>
</template>
<script>
import go from "gojs";
const $ = go.GraphObject.make;
export default {
name: "Index",
data() {
return {
diagram: null,
palette: null,
textStyle: {
font: "bold 9pt Lato, Helvetica, Arial, sans-serif",
stroke: "#F8F8F8",
},
chart: {
class: "GraphLinksModel",
linkFromPortIdProperty: "fromPort",
linkToPortIdProperty: "toPort",
nodeDataArray: [
{
category: "Start",
text: "开始",
key: -1,
loc: "-107.94070280440474 -309.08209495195183",
},
{ text: "流程", key: -2, loc: "-107.68839591351332 -189.421875" },
{
category: "Conditional",
text: "逻辑判断",
key: -3,
loc: "-107.84415803147851 -72.68596298078074",
},
{
category: "End",
text: "结束",
key: -4,
loc: "-109.21840230579596 76.632035837822",
},
],
linkDataArray: [
{
from: -2,
to: -3,
fromPort: "B",
toPort: "T",
points: [
-107.68839591351332,
-169.421875,
-107.68839591351332,
-159.421875,
-107.68839591351332,
-131.05391899039037,
-107.84415803147851,
-131.05391899039037,
-107.84415803147851,
-102.68596298078074,
-107.84415803147851,
-92.68596298078074,
],
},
{
from: -1,
to: -2,
fromPort: "B",
toPort: "T",
points: [
-107.94070280440474,
-289.08209495195183,
-107.94070280440474,
-279.08209495195183,
-107.94070280440474,
-249.25198497597592,
-107.68839591351332,
-249.25198497597592,
-107.68839591351332,
-219.421875,
-107.68839591351332,
-209.421875,
],
},
{
from: -3,
to: -4,
fromPort: "B",
toPort: "T",
visible: true,
points: [
-107.84415803147851,
-52.685962980780744,
-107.84415803147851,
-42.685962980780744,
-107.84415803147851,
1.9730364285206292,
-109.21840230579596,
1.9730364285206292,
-109.21840230579596,
46.632035837822,
-109.21840230579596,
56.632035837822,
],
text: "是",
},
{
from: -3,
to: -2,
fromPort: "R",
toPort: "T",
visible: true,
points: [
-47.844158031478514,
-72.68596298078074,
-37.844158031478514,
-72.68596298078074,
-37.844158031478514,
-240.921875,
-107.68839591351332,
-240.921875,
-107.68839591351332,
-219.421875,
-107.68839591351332,
-209.421875,
],
text: "否",
},
],
},
//
defaultZoom:6,
defaultOrigin:[50.02185841773444, 0.15380859375],
myLeafletMap:undefined,
myUpdatingGoJS:false,
};
},
mounted() {
const showLinkLabel = (e) => {
var label = e.subject.findObject("LABEL");
if (label !== null)
label.visible = e.subject.fromNode.data.category === "Conditional";
};
this.diagram = $(go.Diagram, this.$refs["diagram"], {
LinkDrawn: showLinkLabel, // this DiagramEvent listener is defined below
LinkRelinked: showLinkLabel,
"undoManager.isEnabled": true, // enable undo & redo
});
this.setLinkTemplate();
this.createPattle();
// linkFromPortIdProperty , link
this.diagram.model.linkFromPortIdProperty = "fromPort"; // portIds
this.diagram.model.linkToPortIdProperty = "toPort";
this.diagram.toolManager.linkingTool.temporaryLink.routing =
go.Link.Orthogonal;
this.diagram.toolManager.relinkingTool.temporaryLink.routing =
go.Link.Orthogonal;
//this.initLeaflet()
},
methods: {
//
initLeaflet(){
let myLeafletMap = this.myLeafletMap
myLeafletMap = L.map("map", {}).setView(this.defaultOrigin, this.defaultZoom);
L.tileLayer("https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token={accessToken}", {
attribution: '&copy; <a href="https://www.mapbox.com/about/maps/">Mapbox</a> &copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>',
maxZoom: 18,
minZoom: 2,
tileSize: 512,
zoomOffset: -1,
id: "mapbox/streets-v11",
accessToken: "pk.eyJ1IjoiZ29qcyIsImEiOiJjaXppcnNkbDgwMzQ3MnFsNDFnY2phb2QwIn0.7AuVKrWdxQnJxa_W7qC3-w"
}).addTo(myLeafletMap);
// myLeafletMap.on("zoomend", updateNodes);
// myLeafletMap.on("move", updatePosition);
// myLeafletMap.on("moveend", updatePosition);
},
// updateNodes() { // called when zoom level has changed
// this.myUpdatingGoJS = true;
// myDiagram.commit(diag => {
// diag.nodes.each(n => n.updateTargetBindings("latlong")); // without virtualization this can be slow if there are many nodes
// }, null);
// myUpdatingGoJS = false;
// },
save() {
console.log(this.diagram.model.toJson());
},
load() {
this.diagram.model = go.Model.fromJson(this.chart);
},
createPattle() {
this.diagram.nodeTemplateMap.add(
"", // the default category
$(
go.Node,
"Table",
this.nodeStyle(),
// the main object is a Panel that surrounds a TextBlock with a rectangular Shape
$(
go.Panel,
"Auto",
$(
go.Shape,
"RoundedRectangle",
{
desiredSize: new go.Size(120, 40),
fill: "#006266",
strokeWidth: 0,
},
new go.Binding("figure", "figure"),
new go.Binding("fill", "color")
),
$(
go.TextBlock,
this.textStyle,
{
margin: 8,
maxSize: new go.Size(160, NaN),
wrap: go.TextBlock.WrapFit,
editable: true,
},
new go.Binding("text").makeTwoWay()
),
{
// define a context menu for each node
contextMenu: $(
"ContextMenu", // that has one button
$(
"ContextMenuButton",
{
"ButtonBorder.fill": "white",
_buttonFillOver: "skyblue",
},
$(go.TextBlock, "change color"),
{ click: this.changeColor }
)
// more ContextMenuButtons would go here
), // end Adornment
}
),
// four named ports, one on each side:
this.makePort("T", go.Spot.Top, go.Spot.Top, false, true),
this.makePort("L", go.Spot.Left, go.Spot.Left, true, true),
this.makePort("R", go.Spot.Right, go.Spot.Right, true, true),
this.makePort("B", go.Spot.Bottom, go.Spot.Bottom, true, false)
)
);
this.diagram.nodeTemplateMap.add(
"Conditional",
$(
go.Node,
"Table",
this.nodeStyle(),
// the main object is a Panel that surrounds a TextBlock with a rectangular Shape
$(
go.Panel,
"Auto",
$(
go.Shape,
"Diamond",
{
desiredSize: new go.Size(120, 40),
fill: "#F79F1F",
strokeWidth: 0,
},
new go.Binding("figure", "figure")
),
$(
go.TextBlock,
this.textStyle,
{
margin: 8,
maxSize: new go.Size(160, NaN),
wrap: go.TextBlock.WrapFit,
editable: true,
},
new go.Binding("text").makeTwoWay()
)
),
// four named ports, one on each side:
this.makePort("T", go.Spot.Top, go.Spot.Top, false, true),
this.makePort("L", go.Spot.Left, go.Spot.Left, true, true),
this.makePort("R", go.Spot.Right, go.Spot.Right, true, true),
this.makePort("B", go.Spot.Bottom, go.Spot.Bottom, true, false)
)
);
this.diagram.nodeTemplateMap.add(
"Start",
$(
go.Node,
"Table",
this.nodeStyle(),
$(
go.Panel,
"Spot",
$(go.Shape, "Ellipse", {
desiredSize: new go.Size(120, 40),
fill: "#009432",
strokeWidth: 0,
}),
$(go.TextBlock, "Start", this.textStyle, new go.Binding("text"))
),
// , 线()
// this.makePort('L', go.Spot.Left, go.Spot.Left, true, false),
// this.makePort('R', go.Spot.Right, go.Spot.Right, true, false),
this.makePort("B", go.Spot.Bottom, go.Spot.Bottom, true, false)
)
);
this.diagram.nodeTemplateMap.add(
"End",
$(
go.Node,
"Table",
this.nodeStyle(),
$(
go.Panel,
"Spot",
$(go.Shape, "Ellipse", {
desiredSize: new go.Size(120, 40),
fill: "#EA2027",
strokeWidth: 0,
}),
$(go.TextBlock, "End", this.textStyle, new go.Binding("text"))
),
// , 线()
this.makePort("T", go.Spot.Top, go.Spot.Top, false, true)
// this.makePort('L', go.Spot.Left, go.Spot.Left, false, true),
// this.makePort('R', go.Spot.Right, go.Spot.Right, false, true)
)
);
this.palette = $(
go.Palette,
this.$refs["palette"], // must name or refer to the DIV HTML element
{
// Instead of the default animation, use a custom fade-down
allowZoom: false,
"animationManager.initialAnimationStyle": go.AnimationManager.None,
InitialAnimationStarting: this.animateFadeDown, // Instead, animate with this function
nodeTemplateMap: this.diagram.nodeTemplateMap, // share the templates used by myDiagram
model: new go.GraphLinksModel([
// specify the contents of the Palette
{ category: "Start", text: "开始" },
{ text: "流程" },
{ category: "Conditional", text: "逻辑判断" },
{ category: "End", text: "结束" },
]),
}
);
},
changeColor(e, obj) {
this.diagram.commit((d) => {
// get the context menu that holds the button that was clicked
var contextmenu = obj.part;
// get the node data to which the Node is data bound
var nodedata = contextmenu.data;
// compute the next color for the node
var newcolor = "lightblue";
switch (nodedata.color) {
case "lightblue":
newcolor = "lightgreen";
break;
case "lightgreen":
newcolor = "lightyellow";
break;
case "lightyellow":
newcolor = "orange";
break;
case "orange":
newcolor = "lightblue";
break;
}
// modify the node data
// this evaluates data Bindings and records changes in the UndoManager
d.model.set(nodedata, "color", newcolor);
}, "changed color");
},
// link
setLinkTemplate() {
this.diagram.linkTemplate = $(
go.Link, // the whole link panel
{
routing: go.Link.AvoidsNodes, // link 穿
curve: go.Link.JumpOver, // 线
corner: 5, // 线
toShortLength: 4,
relinkableFrom: true,
relinkableTo: true,
reshapable: true,
// resegmentable: true,
// mouse-overs subtly highlight links:
mouseEnter: function (e, link) {
link.findObject("HIGHLIGHT").stroke = "rgba(30,144,255,0.2)";
},
mouseLeave: function (e, link) {
link.findObject("HIGHLIGHT").stroke = "transparent";
},
selectionAdorned: false,
},
new go.Binding("points").makeTwoWay(),
$(
go.Shape, // the highlight shape, normally transparent
{
isPanelMain: true,
strokeWidth: 8,
stroke: "transparent",
name: "HIGHLIGHT",
}
),
$(
go.Shape, // the link path shape
{ isPanelMain: true, stroke: "gray", strokeWidth: 2 },
new go.Binding("stroke", "isSelected", function (sel) {
return sel ? "dodgerblue" : "gray";
}).ofObject()
),
$(
go.Shape, // the arrowhead
{ toArrow: "standard", strokeWidth: 0, fill: "gray" }
),
$(
go.Panel,
"Auto", // the link label, normally not visible
{
visible: false,
name: "LABEL",
segmentIndex: 2,
segmentFraction: 0.5,
},
new go.Binding("visible", "visible").makeTwoWay(),
$(
go.Shape,
"RoundedRectangle", // the label shape
{ fill: "#F8F8F8", strokeWidth: 0 }
),
$(
go.TextBlock,
"是", // the label
{
textAlign: "center",
font: "8pt helvetica, arial, sans-serif",
stroke: "#333333",
editable: true,
},
new go.Binding("text").makeTwoWay()
)
)
);
},
nodeStyle() {
return [
new go.Binding("location", "loc", go.Point.parse).makeTwoWay(
go.Point.stringify
),
{ locationSpot: go.Spot.Center },
];
},
// , 线
makePort(name, align, spot, output, input) {
var horizontal =
align.equals(go.Spot.Top) || align.equals(go.Spot.Bottom);
// the port is basically just a transparent rectangle that stretches along the side of the node,
// and becomes colored when the mouse passes over it
return $(go.Shape, {
fill: "transparent", // changed to a color in the mouseEnter event handler
strokeWidth: 0, // no stroke
width: horizontal ? NaN : 8, // if not stretching horizontally, just 8 wide
height: !horizontal ? NaN : 8, // if not stretching vertically, just 8 tall
alignment: align, // align the port on the main Shape
stretch: horizontal
? go.GraphObject.Horizontal
: go.GraphObject.Vertical,
portId: name, // declare this object to be a "port"
fromSpot: spot, // declare where links may connect at this port
fromLinkable: output, // declare whether the user may draw links from here
toSpot: spot, // declare where links may connect at this port
toLinkable: input, // declare whether the user may draw links to here
cursor: "pointer", // show a different cursor to indicate potential link point
mouseEnter: function (e, port) {
// the PORT argument will be this Shape
if (!e.diagram.isReadOnly) port.fill = "rgba(255,0,255,0.5)";
},
mouseLeave: function (e, port) {
port.fill = "transparent";
},
});
},
animateFadeDown(e) {
var diagram = e.diagram;
var animation = new go.Animation();
animation.isViewportUnconstrained = true; // So Diagram positioning rules let the animation start off-screen
animation.easing = go.Animation.EaseOutExpo;
animation.duration = 900;
// Fade "down", in other words, fade in from above
animation.add(
diagram,
"position",
diagram.position.copy().offset(0, 200),
diagram.position
);
animation.add(diagram, "opacity", 0, 1);
animation.start();
},
},
};
</script>
<style lang="scss" scoped>
#diagram-contanier {
height: 100%;
display: flex;
flex-direction: column;
border: 1px solid #eee;
#diagram-tool {
width: 100%;
height: 40px;
line-height: 40px;
background-color: #dfdfdf;
display: flex;
align-items: center;
justify-content: flex-end;
padding-right: 20px;
}
#diagram-wrap {
flex-grow: 1;
height: 100%;
display: flex;
#diagram-palette {
flex: 0 0 140px;
height: 100%;
// border-right: 1px solid #dfdfdf;
background-color: #eee;
}
#diagram {
width: 100%;
flex-grow: 1;
}
::v-deep canvas {
outline: none;
}
}
}
</style>

View File

@ -0,0 +1,711 @@
<!--
* @FilePath src/views/dashboard/components/FlowChart/index.vue
* @Created Bay<baizhanying@autobio.com.cn> 2021-11-10 14:23:50
* @Modified Bay<baizhanying@autobio.com.cn> 2021-11-10 18:11:22
* @Description https://github.com/NorthwoodsSoftware/GoJS/blob/master/samples/flowchart.html
-->
<template>
<div id="diagram-contanier">
<div id="diagram-tool">
<slot>
<!-- <el-button type="primary" @click="save">保存</el-button> -->
<!-- <el-button @click="load">加载</el-button> -->
</slot>
</div>
<div id="diagram-wrap">
<div id="diagram-palette" ref="palette" />
<div id="map"
class="mapDiagram leaflet-container leaflet-touch leaflet-retina leaflet-fade-anim leaflet-touch-zoom leaflet-grab leaflet-touch-drag"
tabindex="0"
style="position: relative;">
<div id="diagram"
class="mapDiagram"
style="position: relative; -webkit-tap-highlight-color: rgba(255, 255, 255, 0); cursor: default;z-index: 701;">
</div>
</div>
</div>
</div>
</template>
<script>
import go from "gojs";
const $ = go.GraphObject.make;
export default {
name: "Index",
data() {
return {
diagram: null,
palette: null,
textStyle: {
font: "bold 9pt Lato, Helvetica, Arial, sans-serif",
stroke: "#F8F8F8",
},
chart: {
class: "GraphLinksModel",
linkFromPortIdProperty: "fromPort",
linkToPortIdProperty: "toPort",
nodeDataArray: [
{
category: "Start",
text: "开始",
key: -1,
loc: "-107.94070280440474 -309.08209495195183",
},
{ text: "流程", key: -2, loc: "-107.68839591351332 -189.421875" },
{
category: "Conditional",
text: "逻辑判断",
key: -3,
loc: "-107.84415803147851 -72.68596298078074",
},
{
category: "End",
text: "结束",
key: -4,
loc: "-109.21840230579596 76.632035837822",
},
],
linkDataArray: [
{
from: -2,
to: -3,
fromPort: "B",
toPort: "T",
points: [
-107.68839591351332,
-169.421875,
-107.68839591351332,
-159.421875,
-107.68839591351332,
-131.05391899039037,
-107.84415803147851,
-131.05391899039037,
-107.84415803147851,
-102.68596298078074,
-107.84415803147851,
-92.68596298078074,
],
},
{
from: -1,
to: -2,
fromPort: "B",
toPort: "T",
points: [
-107.94070280440474,
-289.08209495195183,
-107.94070280440474,
-279.08209495195183,
-107.94070280440474,
-249.25198497597592,
-107.68839591351332,
-249.25198497597592,
-107.68839591351332,
-219.421875,
-107.68839591351332,
-209.421875,
],
},
{
from: -3,
to: -4,
fromPort: "B",
toPort: "T",
visible: true,
points: [
-107.84415803147851,
-52.685962980780744,
-107.84415803147851,
-42.685962980780744,
-107.84415803147851,
1.9730364285206292,
-109.21840230579596,
1.9730364285206292,
-109.21840230579596,
46.632035837822,
-109.21840230579596,
56.632035837822,
],
text: "是",
},
{
from: -3,
to: -2,
fromPort: "R",
toPort: "T",
visible: true,
points: [
-47.844158031478514,
-72.68596298078074,
-37.844158031478514,
-72.68596298078074,
-37.844158031478514,
-240.921875,
-107.68839591351332,
-240.921875,
-107.68839591351332,
-219.421875,
-107.68839591351332,
-209.421875,
],
text: "否",
},
],
},
//
defaultZoom:6,
defaultOrigin:[50.02185841773444, 0.15380859375],
myLeafletMap:undefined,
myUpdatingGoJS:false,
//goJs
diagram:undefined,
};
},
created(){
},
mounted() {
this.init()
},
methods: {
init(){
//
this.initLeaflet()
//GoJS
this.initGoJs()
this.initTemplate()
this.initManager()
this.initData()
//
//this.setLinkTemplate();
this.createPattle()
},
//
initLeaflet(){
this.myLeafletMap = L.map("map", {}).setView(this.defaultOrigin, this.defaultZoom);
L.tileLayer("https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token={accessToken}", {
attribution: '&copy; <a href="https://www.mapbox.com/about/maps/">Mapbox</a> &copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>',
maxZoom: 18,
minZoom: 2,
tileSize: 512,
zoomOffset: -1,
id: "mapbox/streets-v11",
accessToken: "pk.eyJ1IjoiZ29qcyIsImEiOiJjaXppcnNkbDgwMzQ3MnFsNDFnY2phb2QwIn0.7AuVKrWdxQnJxa_W7qC3-w"
}).addTo(this.myLeafletMap);
this.myLeafletMap.on("zoomend", this.updateNodes);
this.myLeafletMap.on("move", this.updatePosition);
this.myLeafletMap.on("moveend", this.updatePosition);
},
updateNodes() { // called when zoom level has changed
this.myUpdatingGoJS = true;
this.diagram.commit(diag => {
diag.nodes.each(n => n.updateTargetBindings("latlong")); // without virtualization this can be slow if there are many nodes
}, null);
this.myUpdatingGoJS = false;
},
updatePosition() { // called when map has been panned (i.e. top-left corner is at a different latlong)
console.log("地图",this.myLeafletMap)
const mapb = this.myLeafletMap.getBounds();
const pos = this.myLeafletMap.project([mapb.getNorth(), mapb.getWest()], this.myLeafletMap.getZoom());
this.diagram.position = new go.Point(pos.x, pos.y);
},
initGoJs(){
this.diagram = $(go.Diagram, "diagram",{
"InitialLayoutCompleted": e => this.updatePosition(),
"dragSelectingTool.isEnabled": false,
"animationManager.isEnabled": false,
scrollMode: go.Diagram.InfiniteScroll,
allowZoom: false,
allowHorizontalScroll: false,
allowVerticalScroll: false,
hasHorizontalScrollbar: false,
hasVerticalScrollbar: false,
padding: 0,
defaultCursor: "default",
"toolManager.hoverDelay": 100, // how quickly tooltips are shown
"undoManager.isEnabled": true,
"ModelChanged": e => {
if (e.change === go.ChangedEvent.Transaction &&(e.propertyName === "FinishedUndo" || e.propertyName === "FinishedRedo")) {
setTimeout(() => this.updateNodes());
}
},
});
},
initTemplate(){
const toolTipTemplate =
$("ToolTip", $(go.TextBlock, { margin: 4 },
new go.Binding("text", "", d => d.key + "\nlocation: [" + d.latlong.join(", ") + "]"))
);
this.diagram.nodeTemplate =
$(go.Node, "Auto",
{ toolTip: toolTipTemplate, locationSpot: go.Spot.Center, cursor: "pointer" },
$(go.Shape, "Circle",
{
fill: "rgba(0, 255, 0, .4)", stroke: "#082D47", strokeWidth: 1,
width: 7, height: 7
}),
// A two-way data binding with an Array of latitude,longitude numbers.
// We have to explicitly avoid updating the source data Array
// when myUpdatingGoJS is true; otherwise there would be accumulating errors.
new go.Binding("location", "latlong", data => {
const pos = this.myLeafletMap.project(data, this.myLeafletMap.getZoom());
return new go.Point(pos.x, pos.y);
}).makeTwoWay((pt, data) => {
if (myUpdatingGoJS) {
return data.latlong; // no-op
} else {
const ll = this.myLeafletMap.unproject(L.point(pt.x, pt.y), this.myLeafletMap.getZoom());
return [ll.lat, ll.lng];
}
})
);
this.diagram.linkTemplate =
$(go.Link,
{ layerName: "Background", curve: go.Link.Bezier, curviness: 5 },
$(go.Shape, { strokeWidth: 3, stroke: "rgba(100,100,255,.7)" })
);
},
initManager(){
let leaflet = this.myLeafletMap
this.diagram.toolManager.draggingTool.doActivate = function() {
leaflet.dragging.disable();
go.DraggingTool.prototype.doActivate.call(this);
}
this.diagram.toolManager.draggingTool.doDeactivate = function() {
leaflet.dragging.enable();
go.DraggingTool.prototype.doDeactivate.call(this);
}
},
initData(){
this.diagram.model = new go.GraphLinksModel(
[
// France
{ key: "Paris", latlong: [48.876569, 2.359017] },
{ key: "Brest", latlong: [48.387778, -4.479921] },
{ key: "Rennes", latlong: [48.103375, -1.672809] },
{ key: "Le Mans", latlong: [47.995562, 0.192413] },
{ key: "Nantes", latlong: [47.217579, -1.541839] },
{ key: "Tours", latlong: [47.388502, 0.694500] },
{ key: "Le Havre", latlong: [49.492755, 0.125278] },
{ key: "Rouen", latlong: [49.449031, 1.094128] },
{ key: "Lille", latlong: [50.636379, 3.070620] },
// Belgium
{ key: "Brussels", latlong: [50.836271, 4.333963] },
{ key: "Antwerp", latlong: [51.217495, 4.421204] },
{ key: "Liege", latlong: [50.624168, 5.566008] },
// UK
{ key: "London", latlong: [51.531132, -0.125132] },
{ key: "Bristol", latlong: [51.449541, -2.581118] },
{ key: "Birmingham", latlong: [52.477405, -1.898494] },
{ key: "Liverpool", latlong: [53.408396, -2.978809] },
{ key: "Manchester", latlong: [53.476346, -2.229651] },
{ key: "Leeds", latlong: [53.795480, -1.548345] },
{ key: "Glasgow", latlong: [55.863287, -4.250989] },
],
[
{ from: "Brest", to: "Rennes" },
{ from: "Rennes", to: "Le Mans" },
{ from: "Nantes", to: "Le Mans" },
{ from: "Le Mans", to: "Paris" },
{ from: "Tours", to: "Paris" },
{ from: "Le Havre", to: "Rouen" },
{ from: "Rouen", to: "Paris" },
{ from: "Lille", to: "Paris" },
{ from: "London", to: "Lille" },
{ from: "Lille", to: "Brussels" },
{ from: "Brussels", to: "Antwerp" },
{ from: "Brussels", to: "Liege" },
{ from: "Bristol", to: "London" },
{ from: "Birmingham", to: "London" },
{ from: "Leeds", to: "London" },
{ from: "Liverpool", to: "Birmingham" },
{ from: "Manchester", to: "Liverpool" },
{ from: "Manchester", to: "Leeds" },
{ from: "Glasgow", to: "Manchester" },
{ from: "Glasgow", to: "Leeds" }
]);
},
createPattle() {
this.diagram.nodeTemplateMap.add(
"", // the default category
$(
go.Node,
"Table",
this.nodeStyle(),
// the main object is a Panel that surrounds a TextBlock with a rectangular Shape
$(
go.Panel,
"Auto",
$(
go.Shape,
"RoundedRectangle",
{
desiredSize: new go.Size(120, 40),
fill: "#006266",
strokeWidth: 0,
},
new go.Binding("figure", "figure"),
new go.Binding("fill", "color")
),
$(
go.TextBlock,
this.textStyle,
{
margin: 8,
maxSize: new go.Size(160, NaN),
wrap: go.TextBlock.WrapFit,
editable: true,
},
new go.Binding("text").makeTwoWay()
),
{
// define a context menu for each node
contextMenu: $(
"ContextMenu", // that has one button
$(
"ContextMenuButton",
{
"ButtonBorder.fill": "white",
_buttonFillOver: "skyblue",
},
$(go.TextBlock, "change color"),
{ click: this.changeColor }
)
// more ContextMenuButtons would go here
), // end Adornment
}
),
// four named ports, one on each side:
this.makePort("T", go.Spot.Top, go.Spot.Top, false, true),
this.makePort("L", go.Spot.Left, go.Spot.Left, true, true),
this.makePort("R", go.Spot.Right, go.Spot.Right, true, true),
this.makePort("B", go.Spot.Bottom, go.Spot.Bottom, true, false)
)
);
this.diagram.nodeTemplateMap.add(
"Conditional",
$(
go.Node,
"Table",
this.nodeStyle(),
// the main object is a Panel that surrounds a TextBlock with a rectangular Shape
$(
go.Panel,
"Auto",
$(
go.Shape,
"Diamond",
{
desiredSize: new go.Size(120, 40),
fill: "#F79F1F",
strokeWidth: 0,
},
new go.Binding("figure", "figure")
),
$(
go.TextBlock,
this.textStyle,
{
margin: 8,
maxSize: new go.Size(160, NaN),
wrap: go.TextBlock.WrapFit,
editable: true,
},
new go.Binding("text").makeTwoWay()
)
),
// four named ports, one on each side:
this.makePort("T", go.Spot.Top, go.Spot.Top, false, true),
this.makePort("L", go.Spot.Left, go.Spot.Left, true, true),
this.makePort("R", go.Spot.Right, go.Spot.Right, true, true),
this.makePort("B", go.Spot.Bottom, go.Spot.Bottom, true, false)
)
);
this.diagram.nodeTemplateMap.add(
"Start",
$(
go.Node,
"Table",
this.nodeStyle(),
$(
go.Panel,
"Spot",
$(go.Shape, "Ellipse", {
desiredSize: new go.Size(120, 40),
fill: "#009432",
strokeWidth: 0,
}),
$(go.TextBlock, "Start", this.textStyle, new go.Binding("text"))
),
// , 线()
// this.makePort('L', go.Spot.Left, go.Spot.Left, true, false),
// this.makePort('R', go.Spot.Right, go.Spot.Right, true, false),
this.makePort("B", go.Spot.Bottom, go.Spot.Bottom, true, false)
)
);
this.diagram.nodeTemplateMap.add(
"End",
$(
go.Node,
"Table",
this.nodeStyle(),
$(
go.Panel,
"Spot",
$(go.Shape, "Ellipse", {
desiredSize: new go.Size(120, 40),
fill: "#EA2027",
strokeWidth: 0,
}),
$(go.TextBlock, "End", this.textStyle, new go.Binding("text"))
),
// , 线()
this.makePort("T", go.Spot.Top, go.Spot.Top, false, true)
// this.makePort('L', go.Spot.Left, go.Spot.Left, false, true),
// this.makePort('R', go.Spot.Right, go.Spot.Right, false, true)
)
);
this.palette = $(
go.Palette,
this.$refs["palette"], // must name or refer to the DIV HTML element
{
// Instead of the default animation, use a custom fade-down
allowZoom: false,
"animationManager.initialAnimationStyle": go.AnimationManager.None,
InitialAnimationStarting: this.animateFadeDown, // Instead, animate with this function
nodeTemplateMap: this.diagram.nodeTemplateMap, // share the templates used by myDiagram
model: new go.GraphLinksModel([
// specify the contents of the Palette
{ category: "Start", text: "开始" },
{ text: "流程" },
{ category: "Conditional", text: "逻辑判断" },
{ category: "End", text: "结束" },
]),
}
);
},
changeColor(e, obj) {
this.diagram.commit((d) => {
// get the context menu that holds the button that was clicked
var contextmenu = obj.part;
// get the node data to which the Node is data bound
var nodedata = contextmenu.data;
// compute the next color for the node
var newcolor = "lightblue";
switch (nodedata.color) {
case "lightblue":
newcolor = "lightgreen";
break;
case "lightgreen":
newcolor = "lightyellow";
break;
case "lightyellow":
newcolor = "orange";
break;
case "orange":
newcolor = "lightblue";
break;
}
// modify the node data
// this evaluates data Bindings and records changes in the UndoManager
d.model.set(nodedata, "color", newcolor);
}, "changed color");
},
// link
setLinkTemplate() {
this.diagram.linkTemplate = $(
go.Link, // the whole link panel
{
routing: go.Link.AvoidsNodes, // link 穿
curve: go.Link.JumpOver, // 线
corner: 5, // 线
toShortLength: 4,
relinkableFrom: true,
relinkableTo: true,
reshapable: true,
// resegmentable: true,
// mouse-overs subtly highlight links:
mouseEnter: function (e, link) {
link.findObject("HIGHLIGHT").stroke = "rgba(30,144,255,0.2)";
},
mouseLeave: function (e, link) {
link.findObject("HIGHLIGHT").stroke = "transparent";
},
selectionAdorned: false,
},
new go.Binding("points").makeTwoWay(),
$(
go.Shape, // the highlight shape, normally transparent
{
isPanelMain: true,
strokeWidth: 8,
stroke: "transparent",
name: "HIGHLIGHT",
}
),
$(
go.Shape, // the link path shape
{ isPanelMain: true, stroke: "gray", strokeWidth: 2 },
new go.Binding("stroke", "isSelected", function (sel) {
return sel ? "dodgerblue" : "gray";
}).ofObject()
),
$(
go.Shape, // the arrowhead
{ toArrow: "standard", strokeWidth: 0, fill: "gray" }
),
$(
go.Panel,
"Auto", // the link label, normally not visible
{
visible: false,
name: "LABEL",
segmentIndex: 2,
segmentFraction: 0.5,
},
new go.Binding("visible", "visible").makeTwoWay(),
$(
go.Shape,
"RoundedRectangle", // the label shape
{ fill: "#F8F8F8", strokeWidth: 0 }
),
$(
go.TextBlock,
"是", // the label
{
textAlign: "center",
font: "8pt helvetica, arial, sans-serif",
stroke: "#333333",
editable: true,
},
new go.Binding("text").makeTwoWay()
)
)
);
},
nodeStyle() {
return [
new go.Binding("location", "loc", go.Point.parse).makeTwoWay(
go.Point.stringify
),
{ locationSpot: go.Spot.Center },
];
},
// , 线
makePort(name, align, spot, output, input) {
var horizontal =
align.equals(go.Spot.Top) || align.equals(go.Spot.Bottom);
// the port is basically just a transparent rectangle that stretches along the side of the node,
// and becomes colored when the mouse passes over it
return $(go.Shape, {
fill: "transparent", // changed to a color in the mouseEnter event handler
strokeWidth: 0, // no stroke
width: horizontal ? NaN : 8, // if not stretching horizontally, just 8 wide
height: !horizontal ? NaN : 8, // if not stretching vertically, just 8 tall
alignment: align, // align the port on the main Shape
stretch: horizontal
? go.GraphObject.Horizontal
: go.GraphObject.Vertical,
portId: name, // declare this object to be a "port"
fromSpot: spot, // declare where links may connect at this port
fromLinkable: output, // declare whether the user may draw links from here
toSpot: spot, // declare where links may connect at this port
toLinkable: input, // declare whether the user may draw links to here
cursor: "pointer", // show a different cursor to indicate potential link point
mouseEnter: function (e, port) {
// the PORT argument will be this Shape
if (!e.diagram.isReadOnly) port.fill = "rgba(255,0,255,0.5)";
},
mouseLeave: function (e, port) {
port.fill = "transparent";
},
});
},
animateFadeDown(e) {
var diagram = e.diagram;
var animation = new go.Animation();
animation.isViewportUnconstrained = true; // So Diagram positioning rules let the animation start off-screen
animation.easing = go.Animation.EaseOutExpo;
animation.duration = 900;
// Fade "down", in other words, fade in from above
animation.add(
diagram,
"position",
diagram.position.copy().offset(0, 200),
diagram.position
);
animation.add(diagram, "opacity", 0, 1);
animation.start();
},
},
};
</script>
<style lang="scss" scoped>
.myDiagramDiv {
z-index: 701;
}
.mapDiagram {
border: solid 1px black;
width: 100%;
height: 100%;
}
#diagram-contanier {
height: 100%;
display: flex;
flex-direction: column;
border: 1px solid #eee;
#diagram-tool {
width: 100%;
height: 40px;
line-height: 40px;
background-color: #dfdfdf;
display: flex;
align-items: center;
justify-content: flex-end;
padding-right: 20px;
}
#diagram-wrap {
flex-grow: 1;
height: 100%;
display: flex;
#diagram-palette {
flex: 0 0 140px;
height: 100%;
// border-right: 1px solid #dfdfdf;
background-color: #eee;
}
#diagram {
width: 100%;
flex-grow: 1;
}
::v-deep canvas {
outline: none;
}
}
}
</style>

View File

@ -0,0 +1,199 @@
<!--
* @FilePath src/views/gantt/components/GanttChart/index.vue
* @Created Bay<baizhanying@autobio.com.cn> 2021-11-11 11:12:27
* @Modified Bay<baizhanying@autobio.com.cn> 2021-11-11 14:12:06
* @Description
-->
<template>
<div id="map"
class="mapDiagram leaflet-container leaflet-touch leaflet-retina leaflet-fade-anim leaflet-touch-zoom leaflet-grab leaflet-touch-drag"
tabindex="0"
style="position: relative;">
<!-- <div id="myDiagramDiv"
class="mapDiagram"
style="position: relative; -webkit-tap-highlight-color: rgba(255, 255, 255, 0); cursor: default;">
</div> -->
<div id="diagram" ref="diagram" />
</div>
</template>
<script>
import go from "gojs";
const $ = go.GraphObject.make;
export default {
name: "GanttChart",
data() {
return {
diagram: null,
};
},
mounted() {
this.diagram = $(
go.Diagram,
this.$refs["diagram"], // Diagram refers to its DIV HTML element by id
{
_widthFactor: 1, // a scale for the nodes' positions and widths
isReadOnly: true, // deny the user permission to alter the diagram or zoom in or out
allowZoom: false, //
allowSelect: false, //
allowHorizontalScroll: false, //
allowVerticalScroll: false, //
"grid.visible": true, //
"grid.gridCellSize": new go.Size(30, 150), //
}
);
this.createNodeTemplates();
this.crateLinkTemplate();
this.diagram.model = new go.GraphLinksModel(
[
// node data
{ key: "a", color: "coral", width: 120, loc: new go.Point(0, 40) },
{ key: "b", color: "turquoise", width: 160, loc: new go.Point(0, 60) },
{ key: "c", color: "coral", width: 150, loc: new go.Point(120, 80) },
{
key: "d",
color: "turquoise",
width: 190,
loc: new go.Point(120, 100),
},
{ key: "e", color: "coral", width: 150, loc: new go.Point(270, 120) },
{
key: "f",
color: "turquoise",
width: 130,
loc: new go.Point(310, 140),
},
{ key: "g", color: "coral", width: 155, loc: new go.Point(420, 160) },
{ key: "begin", category: "start", loc: new go.Point(-15, 20) },
{ key: "end", category: "end", loc: new go.Point(575, 180) },
],
[
// link data
{ from: "begin", to: "a" },
{ from: "begin", to: "b" },
{ from: "a", to: "c" },
{ from: "a", to: "d" },
{ from: "b", to: "e" },
{ from: "c", to: "e" },
{ from: "d", to: "f" },
{ from: "e", to: "g" },
{ from: "f", to: "end" },
{ from: "g", to: "end" },
]
);
const dateScale = $(
go.Part,
"Graduated",
{
graduatedTickUnit: 1,
graduatedMin: 0,
graduatedMax: 3,
pickable: false,
location: new go.Point(0, 0),
},
$(go.Shape, {
name: "line",
strokeWidth: 0,
geometryString: "M0 0 H" + 450,
}),
$(go.TextBlock, {
name: "labels",
font: "10pt sans-serif",
alignmentFocus: new go.Spot(0, 0, -3, -3),
graduatedFunction: function (v) {
var d = new Date(2017, 6, 23);
d.setDate(d.getDate() + v * 7);
// format date output to string
var options = { month: "short", day: "2-digit" };
return d.toLocaleDateString("en-US", options);
},
})
);
this.diagram.add(dateScale);
},
methods: {
createNodeTemplates() {
// create the template for the standard nodes
this.diagram.nodeTemplateMap.add(
"",
$(
go.Node,
"Auto",
// links come from the right and go to the left side of the top of the node
{ fromSpot: go.Spot.Right, toSpot: new go.Spot(0.001, 0, 11, 0) },
$(
go.Shape,
"Rectangle",
{ height: 15 },
new go.Binding("fill", "color"),
new go.Binding("width", "width")
),
$(
go.TextBlock,
{ margin: 2, alignment: go.Spot.Left },
new go.Binding("text", "key")
),
// using a function in the Binding allows the value to
// change when Diagram.updateAllTargetBindings is called
new go.Binding("location", "loc", function (l) {
return new go.Point(l.x, l.y);
})
)
);
// create the template for the start node
this.diagram.nodeTemplateMap.add(
"start",
$(
go.Node,
{ fromSpot: go.Spot.Right, toSpot: go.Spot.Top, selectable: false },
$(go.Shape, "Diamond", { height: 15, width: 15 }),
// make the location of the start node is not scalable
new go.Binding("location", "loc")
)
);
// create the template for the end node
this.diagram.nodeTemplateMap.add(
"end",
$(
go.Node,
{ fromSpot: go.Spot.Right, toSpot: go.Spot.Top, selectable: false },
$(go.Shape, "Diamond", { height: 15, width: 15 }),
// make the location of the end node (with location.x < 0) scalable
new go.Binding("location", "loc", function (l) {
if (l.x >= 0) return new go.Point(l.x, l.y);
else return l;
})
)
);
},
crateLinkTemplate() {
this.diagram.linkTemplate = $(
go.Link,
{
routing: go.Link.Orthogonal,
corner: 3,
toShortLength: 2,
selectable: false,
},
$(go.Shape, { strokeWidth: 2 }),
$(go.Shape, { toArrow: "OpenTriangle" })
);
},
},
};
</script>
<style lang="scss" scoped>
#diagram {
width: 100%;
height: 100%;
::v-deep canvas {
outline: none;
}
}
</style>

View File

@ -0,0 +1,19 @@
<template>
<div id="app">
<FlowChart />
<!-- <GanttChart /> -->
</div>
</template>
<script>
import FlowChart from "./components/FlowChart";
import GanttChart from "./components/GanttChart";
export default {
name: "App",
components: {
FlowChart,
GanttChart,
},
};
</script>