gis-model/src/demo/index-gaode.vue

582 lines
16 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<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
let mapp = this.map
console.log("地图地图",this.map)
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)
// })
this.graph.on('blank:mousedown',(e)=>{
this.changeMapDrag(true)
})
//鼠标在空白画布上抬起
this.graph.on('blank:mouseup',(e)=>{
this.changeMapDrag(false)
})
},
//初始化拖拽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>