Commit b7bcd648 authored by wangqinghua's avatar wangqinghua

login

parent cb5f8692
...@@ -20,16 +20,7 @@ export class FlowTrendComponent implements OnInit { ...@@ -20,16 +20,7 @@ export class FlowTrendComponent implements OnInit {
} }
loadVisTree(treedata) { loadVisTree(treedata) {
const options = {
interaction: {
hover: true,
},
manipulation: {
enabled: true
}
};
const container = this.networkContainer.nativeElement;
this.network = new vis.Network(container, treedata, options);
} }
getTreeData(){ getTreeData(){
......
...@@ -28,20 +28,19 @@ ...@@ -28,20 +28,19 @@
</nz-select> </nz-select>
</div> </div>
<div nz-col nzSpan="12" class="text-right"> <div nz-col nzSpan="12" class="text-right">
<button nz-button nzType="default"><i class="anticon anticon-plus"></i>添加 <button nz-button (click)="addTopo()" nzType="default"><i class="anticon anticon-plus"></i>添加</button>
</button> <button nz-button (click)="editTopo()" nzType="default"><i class="anticon anticon-pause-circle-o"></i>编辑</button>
<button nz-button nzType="default"><i class="anticon anticon-pause-circle-o"></i>编辑</button> <button nz-button (click)="deleteTopo()" nzType="default"><i class="anticon anticon-play-circle-o"></i>删除</button>
<button nz-button nzType="default"><i class="anticon anticon-play-circle-o"></i>删除</button>
<button nz-button nzType="default"><i class="anticon anticon-close-circle"></i>暂停</button>
</div> </div>
</div> </div>
<div class="layui-layout layui-layout-admin"> <div class="layui-layout layui-layout-admin">
<div class="layui-header layui-bg-gray"> <div class="layui-header layui-bg-gray">
<input style="width: 200px;" type="text" [(ngModel)]="name" nz-input placeholder="请输入拓扑图名称">
<!-- 顶部工具栏 --> <!-- 顶部工具栏 -->
<div class="layui-nav layui-layout-right"> <div class="layui-nav layui-layout-right" style="line-height: 60px">
<span aria-hidden="true" title="编辑" onClick="editor.utils.editTopology()">编辑</span> <!--<span aria-hidden="true" title="编辑" onClick="editor.utils.editTopology()">编辑</span>-->
<span aria-hidden="true" title="全屏查看" <span aria-hidden="true" title="全屏查看"
onClick="editor.utils.showInFullScreen(editor.stage.canvas,'RequestFullScreen')"> onClick="editor.utils.showInFullScreen(editor.stage.canvas,'RequestFullScreen')">
全屏查看</span> 全屏查看</span>
...@@ -49,7 +48,7 @@ ...@@ -49,7 +48,7 @@
onClick="editor.utils.showInCenter()">居中显示</span> onClick="editor.utils.showInCenter()">居中显示</span>
<span aria-hidden="true" title="预览" <span aria-hidden="true" title="预览"
onClick="editor.utils.showPic()">预览</span> onClick="editor.utils.showPic()">预览</span>
<span aria-hidden="true" title="保存" (click)="create()">保存</span> <span aria-hidden="true" title="保存" (click)="save()">保存</span>
<span aria-hidden="true" title="复制" <span aria-hidden="true" title="复制"
onClick="editor.utils.cloneSelectedNodes()">复制</span> onClick="editor.utils.cloneSelectedNodes()">复制</span>
<span aria-hidden="true" title="删除" <span aria-hidden="true" title="删除"
...@@ -560,6 +559,7 @@ ...@@ -560,6 +559,7 @@
style="height: 580px;width: 100%;"> style="height: 580px;width: 100%;">
您的浏览器不支持HTML5! 您的浏览器不支持HTML5!
</canvas> </canvas>
<span>{{topoType}}</span>
</div> </div>
</div> </div>
</div> </div>
......
import {AfterViewChecked, Component, ElementRef, OnInit, ViewChild} from '@angular/core'; import {AfterViewChecked, Component, ElementRef, OnInit, ViewChild} from '@angular/core';
import {TopologyService} from '../topology.service'; import {TopologyService} from '../topology.service';
import {NzMessageService} from 'ng-zorro-antd'; import {NzMessageService, NzModalService} from 'ng-zorro-antd';
import {DomSanitizer} from '@angular/platform-browser'; import {DomSanitizer} from '@angular/platform-browser';
import * as $ from 'jquery'; import * as $ from 'jquery';
declare let editor:any;
declare let layui:any; declare let editor: any;
declare let layui: any;
@Component({ @Component({
selector: 'smart-ne-topology', selector: 'smart-ne-topology',
templateUrl: './ne-topology.component.html', templateUrl: './ne-topology.component.html',
styles: [ styles: [
` `
.layui-side-scroll{ .layui-side-scroll {
width: initial; width: initial;
} }
.layui-layout-right{
.layui-layout-right {
color: #666666; color: #666666;
} }
.layui-layout-right span{
.layui-layout-right span {
margin-right: 15px; margin-right: 15px;
cursor: pointer; cursor: pointer;
} }
...@@ -25,91 +28,46 @@ declare let layui:any; ...@@ -25,91 +28,46 @@ declare let layui:any;
] ]
}) })
export class NeTopologyComponent implements OnInit { export class NeTopologyComponent implements OnInit {
@ViewChild('topologyCanvas') topologyCanvas:ElementRef; @ViewChild('topologyCanvas') topologyCanvas: ElementRef;
dataSet; dataSet;
isVisible = false; isVisible = false;
image; image;
topoId; topoId;
name;
topoType = '查看';
constructor(private topologySer: TopologyService, private message: NzMessageService, constructor(private topologySer: TopologyService, private message: NzMessageService,
private sanitizer:DomSanitizer) { private sanitizer: DomSanitizer, private modalSer: NzModalService) {
} }
ngOnInit() { ngOnInit() {
layui.use('element', ()=>{ layui.use('element', () => {
let element = layui.element; let element = layui.element;
}); });
this.loadCanvas(); this.loadCanvas();
this.getList(); this.getList();
} }
loadCanvas(){ //新增拓扑图
// 选择连线方式后的css样式 addTopo() {
$("#link-line").click( ()=> { this.topoType = '新增';
$(this).css("background-color", "darkgray"); editor.utils.clearTopology();
$("#link-foldline-h").css("background-color", "white"); }
$("#link-foldline-v").css("background-color", "white");
$("#link-flexline-h").css("background-color", "white");
$("#link-flexline-v").css("background-color", "white");
$("#link-curveline").css("background-color", "white");
});
$("#link-foldline-h").click(()=> {
$(this).css("background-color", "darkgray");
$("#link-line").css("background-color", "white");
$("#link-foldline-v").css("background-color", "white");
$("#link-flexline-h").css("background-color", "white");
$("#link-flexline-v").css("background-color", "white");
$("#link-curveline").css("background-color", "white");
});
$("#link-foldline-v").click(()=> {
$(this).css("background-color", "darkgray");
$("#link-line").css("background-color", "white");
$("#link-foldline-h").css("background-color", "white");
$("#link-flexline-h").css("background-color", "white");
$("#link-flexline-v").css("background-color", "white");
$("#link-curveline").css("background-color", "white");
});
$("#link-flexline-h").click(()=> {
$(this).css("background-color", "darkgray");
$("#link-line").css("background-color", "white");
$("#link-foldline-h").css("background-color", "white");
$("#link-foldline-v").css("background-color", "white");
$("#link-flexline-v").css("background-color", "white");
$("#link-curveline").css("background-color", "white");
});
$("#link-flexline-v").click(()=> {
$(this).css("background-color", "darkgray");
$("#link-line").css("background-color", "white");
$("#link-foldline-h").css("background-color", "white");
$("#link-foldline-v").css("background-color", "white");
$("#link-flexline-h").css("background-color", "white");
$("#link-curveline").css("background-color", "white");
});
$("#link-curveline").click(()=> {
$(this).css("background-color", "darkgray");
$("#link-line").css("background-color", "white");
$("#link-foldline-h").css("background-color", "white");
$("#link-foldline-v").css("background-color", "white");
$("#link-flexline-h").css("background-color", "white");
$("#link-flexline-v").css("background-color", "white");
});
// 节点树中每个节点的拖放动作定义给拓扑图编辑器 //编辑拓扑图
let nodes = $("[topo-div-type='topo-node']"); editTopo() {
let nodeLength = nodes.length; if(!this.topoId){
console.log(nodes); this.message.info("请选择需要编辑的拓扑图")
for (let i = 0; i < nodeLength; i++) { return false;
let text = $(nodes[i]).find("span").eq(0).text();
editor.drag(nodes[i], document.getElementById('topology-canvas'), text);
} }
editor.loadTopology( '', "img/backimg1.png"); this.topoType = '编辑';
editor.utils.editTopology();
} }
//获取列表 //获取列表
getList() { getList() {
this.topologySer.findAll({}).subscribe( this.topologySer.findAll().subscribe(
(res) => { (res) => {
if (res.errCode == 10000) { if (res.errCode == 10000) {
this.dataSet = res.data; this.dataSet = res.data;
...@@ -120,29 +78,165 @@ export class NeTopologyComponent implements OnInit { ...@@ -120,29 +78,165 @@ export class NeTopologyComponent implements OnInit {
); );
} }
save() {
if (this.topoType == '新增') {
this.create();
} else {
this.update();
}
}
//创建 //创建
create(){ create() {
let data = editor.saveTopology(); if (!this.name) {
console.log(data); this.message.info('请输入拓扑图名称');
this.topologySer.create(data).subscribe( return false;
(res)=>{ }
let data = {
} name: this.name,
) json: editor.saveTopology()
};
this.topologySer.create(data).subscribe(
(res) => {
if (res.errCode == 10000) {
this.message.info('创建成功');
this.getList();
} else {
this.message.info(res.errMsg);
}
}
);
}
//编辑
update() {
if (!this.name) {
this.message.info('请输入拓扑图名称');
return false;
}
let data = {
id: this.topoId,
name: this.name,
json: editor.saveTopology()
};
this.topologySer.update(data).subscribe(
(res) => {
if (res.errCode == 10000) {
this.message.info('编辑成功');
this.getList();
} else {
this.message.info(res.errMsg);
}
}
);
} }
//查询单个 //查询单个
getDetail(id){ getDetail(id) {
editor.utils.clearTopology();
this.topologySer.findItem(id).subscribe( this.topologySer.findItem(id).subscribe(
(res)=>{ (res) => {
if (res.errCode == 10000) {
let json = JSON.parse(res.data.json);
this.name = res.data.name;
this.topoId = res.data.id;
editor.loadTopologyByJson(json, 'img/backimg.png');
}
}
);
}
//删除拓扑图
deleteTopo() {
if(!this.topoId){
this.message.info("请选择需要删除的拓扑图")
return false;
}
this.modalSer.confirm({
nzTitle: '删除',
nzContent: '<b style="color: red;">确认删除该拓扑图吗?</b>',
nzOkText: '确定',
nzOkType: 'danger',
nzOnOk: () => {
this.topologySer.delete(this.topoId).subscribe(
(res) => {
if (res.errCode == 10000) {
this.topoId = null;
this.message.info('删除成功');
this.getList();
} else {
this.message.info(res.errMsg);
}
}
);
},
nzCancelText: '取消',
nzOnCancel: () => console.log('Cancel')
} }
) );
} }
//load
loadCanvas() {
// 选择连线方式后的css样式
$('#link-line').click(() => {
$(this).css('background-color', 'darkgray');
$('#link-foldline-h').css('background-color', 'white');
$('#link-foldline-v').css('background-color', 'white');
$('#link-flexline-h').css('background-color', 'white');
$('#link-flexline-v').css('background-color', 'white');
$('#link-curveline').css('background-color', 'white');
});
$('#link-foldline-h').click(() => {
$(this).css('background-color', 'darkgray');
$('#link-line').css('background-color', 'white');
$('#link-foldline-v').css('background-color', 'white');
$('#link-flexline-h').css('background-color', 'white');
$('#link-flexline-v').css('background-color', 'white');
$('#link-curveline').css('background-color', 'white');
});
$('#link-foldline-v').click(() => {
$(this).css('background-color', 'darkgray');
$('#link-line').css('background-color', 'white');
$('#link-foldline-h').css('background-color', 'white');
$('#link-flexline-h').css('background-color', 'white');
$('#link-flexline-v').css('background-color', 'white');
$('#link-curveline').css('background-color', 'white');
});
$('#link-flexline-h').click(() => {
$(this).css('background-color', 'darkgray');
$('#link-line').css('background-color', 'white');
$('#link-foldline-h').css('background-color', 'white');
$('#link-foldline-v').css('background-color', 'white');
$('#link-flexline-v').css('background-color', 'white');
$('#link-curveline').css('background-color', 'white');
});
$('#link-flexline-v').click(() => {
$(this).css('background-color', 'darkgray');
$('#link-line').css('background-color', 'white');
$('#link-foldline-h').css('background-color', 'white');
$('#link-foldline-v').css('background-color', 'white');
$('#link-flexline-h').css('background-color', 'white');
$('#link-curveline').css('background-color', 'white');
});
$('#link-curveline').click(() => {
$(this).css('background-color', 'darkgray');
$('#link-line').css('background-color', 'white');
$('#link-foldline-h').css('background-color', 'white');
$('#link-foldline-v').css('background-color', 'white');
$('#link-flexline-h').css('background-color', 'white');
$('#link-flexline-v').css('background-color', 'white');
});
handleOk() { // 节点树中每个节点的拖放动作定义给拓扑图编辑器
this.isVisible = false; let nodes = $('[topo-div-type=\'topo-node\']');
this.image = null; let nodeLength = nodes.length;
for (let i = 0; i < nodeLength; i++) {
let text = $(nodes[i]).find('span').eq(0).text();
editor.drag(nodes[i], document.getElementById('topology-canvas'), text);
}
editor.loadTopology('', 'img/backimg.png');
} }
} }
...@@ -10,28 +10,28 @@ export class TopologyService { ...@@ -10,28 +10,28 @@ export class TopologyService {
} }
//查询所有拓扑图 //查询所有拓扑图
findAll(data): Observable<any> { findAll(): Observable<any> {
return this.http.post(SERVER_API_URL + '/sysmap/findAll',data); return this.http.get(SERVER_API_URL + '/sysmapJson/findAll');
} }
//根据拓扑图ID查询背景图 //根据拓扑图ID查询
findItem(params): Observable<any> { findItem(params): Observable<any> {
return this.http.get(SERVER_API_URL + '/sysmap/find/' + params); return this.http.get(SERVER_API_URL + '/sysmapJson/find/' + params);
} }
//创建拓扑图 //创建拓扑图
create(data): Observable<any> { create(data): Observable<any> {
return this.http.post(SERVER_API_URL + '/sysmap/create' , data); return this.http.post(SERVER_API_URL + '/sysmapJson/create' , data);
} }
//修改拓扑图 //修改拓扑图
update(data): Observable<any> { update(data): Observable<any> {
return this.http.put(SERVER_API_URL + '/sysmap/update' , data); return this.http.put(SERVER_API_URL + '/sysmapJson/update' , data);
} }
//删除拓扑图 //删除拓扑图
delete(params): Observable<any> { delete(params): Observable<any> {
return this.http.get(SERVER_API_URL + '/sysmap/delete/' + params); return this.http.get(SERVER_API_URL + '/sysmapJson/delete/' + params);
} }
......
...@@ -7,19 +7,21 @@ ...@@ -7,19 +7,21 @@
/** /**
* 提供拓扑图面板相关操作的函数集,编辑器继承其全部功能 * 提供拓扑图面板相关操作的函数集,编辑器继承其全部功能
*/ */
function TopologyPanel() {} function TopologyPanel() {
}
/** /**
* 保存序列化的拓扑图JSON数据到服务器 * 保存序列化的拓扑图JSON数据到服务器
*/ */
TopologyPanel.prototype.saveTopology = function (url) { TopologyPanel.prototype.saveTopology = function (url) {
editor.mainMenu.hide() editor.mainMenu.hide()
let self = this
// 保存container状态 // 保存container状态
var containers = editor.utils.getContainers() let containers = editor.utils.getContainers()
for (var c = 0; c < containers.length; c++) { for (let c = 0; c < containers.length; c++) {
var temp = [] let temp = []
var nodes = containers[c].childs let nodes = containers[c].childs
for (var n = 0; n < nodes.length; n++) { for (let n = 0; n < nodes.length; n++) {
if (nodes[n] instanceof JTopo.Node) { if (nodes[n] instanceof JTopo.Node) {
temp.push(nodes[n].nodeId) temp.push(nodes[n].nodeId)
} }
...@@ -27,30 +29,10 @@ TopologyPanel.prototype.saveTopology = function (url) { ...@@ -27,30 +29,10 @@ TopologyPanel.prototype.saveTopology = function (url) {
containers[c].childNodes = temp.join(',') containers[c].childNodes = temp.join(',')
} }
// 获取json // 获取json
var topologyJSON = editor.stage.toJson(); let topologyJSON = editor.stage.toJson();
console.log(topologyJSON); console.log(topologyJSON);
return topologyJSON; return topologyJSON;
// 保存拓扑图数据 // 保存拓扑图数据
// $.ajax({
// type: 'POST',
// url: url,
// async: false,
// data: JSON.stringify({'topology_json': topologyJSON}),
// contentType: 'application/json',
// dataType: 'json',
// error: function () {
// // alert('服务器异常,请稍后重试..')
// },
// success: function (response) {
// // 错误处理
// if (response.code !== 200) {
// console.error(response.msg)
// } else {
// editor.stageMode = 'normal'; // 只读模式
// self.replaceStage(url) // 重新加载
// }
// }
// })
} }
/** /**
...@@ -66,23 +48,11 @@ TopologyPanel.prototype.resetTopology = function (url) { ...@@ -66,23 +48,11 @@ TopologyPanel.prototype.resetTopology = function (url) {
* @param topologyGuid 拓扑 表记录ID * @param topologyGuid 拓扑 表记录ID
* @param backImg 拓扑图的背景图片 * @param backImg 拓扑图的背景图片
*/ */
TopologyPanel.prototype.loadTopology = function (url, topologyGuid, backImg) { TopologyPanel.prototype.loadTopology = function (response, topologyGuid, backImg) {
$.ajax({
type: 'GET',
url: url,
async: false,
contentType: 'application/json',
dataType: 'json',
error: function () {
// alert('服务器异常,请稍后重试..')
},
success: function (response) {
// 错误处理 // 错误处理
if (response.code !== 200) { if (!response) {
console.error(response.msg)
} else if (response.code === 200 && $.isEmptyObject(response.data.topology_json)) {
// 拓扑不存在,创建一个空白的拓扑图 // 拓扑不存在,创建一个空白的拓扑图
var initTopologyJson = { let initTopologyJson = {
'version': '0.4.8', 'version': '0.4.8',
'wheelZoom': 0.95, 'wheelZoom': 0.95,
'width': 972, 'width': 972,
...@@ -103,11 +73,8 @@ TopologyPanel.prototype.loadTopology = function (url, topologyGuid, backImg) { ...@@ -103,11 +73,8 @@ TopologyPanel.prototype.loadTopology = function (url, topologyGuid, backImg) {
editor.init(topologyGuid, backImg, initTopologyJson, '') editor.init(topologyGuid, backImg, initTopologyJson, '')
} else { } else {
// 拓扑存在,渲染拓扑图 // 拓扑存在,渲染拓扑图
var topologyJson = response.data.topology_json editor.init(topologyGuid, backImg, response, '')
editor.init(topologyGuid, backImg, topologyJson, '')
} }
}
})
} }
/** /**
...@@ -123,7 +90,7 @@ TopologyPanel.prototype.loadTopologyByJson = function (topologyJson, backImg) { ...@@ -123,7 +90,7 @@ TopologyPanel.prototype.loadTopologyByJson = function (topologyJson, backImg) {
} }
} catch (e) { } catch (e) {
console.error(e) console.error(e)
var initTopologyJson = { let initTopologyJson = {
'version': '0.4.8', 'version': '0.4.8',
'wheelZoom': 0.95, 'wheelZoom': 0.95,
'width': 972, 'width': 972,
...@@ -249,12 +216,12 @@ TopologyEditor.prototype = new TopologyPanel() ...@@ -249,12 +216,12 @@ TopologyEditor.prototype = new TopologyPanel()
* 菜单初始化 * 菜单初始化
*/ */
TopologyEditor.prototype.initMenus = function () { TopologyEditor.prototype.initMenus = function () {
var self = this let self = this
// 右键菜单事件处理(右键一级菜单) // 右键菜单事件处理(右键一级菜单)
self.nodeMenu.on('click', function (event) { self.nodeMenu.on('click', function (event) {
// 菜单文字对应事件 // 菜单文字对应事件
var text = $.trim($(event.target).text()) let text = $.trim($(event.target).text())
if (text === '删除节点(Delete)') { if (text === '删除节点(Delete)') {
editor.utils.deleteSelectedNodes() editor.utils.deleteSelectedNodes()
} else if (text === '复制节点(Shift+C)') { } else if (text === '复制节点(Shift+C)') {
...@@ -294,8 +261,8 @@ TopologyEditor.prototype.initMenus = function () { ...@@ -294,8 +261,8 @@ TopologyEditor.prototype.initMenus = function () {
self.nodeMenu.on('mouseover', function (event) { self.nodeMenu.on('mouseover', function (event) {
// 菜单文字 // 菜单文字
var text = $.trim($(event.target).text()) let text = $.trim($(event.target).text())
var menuX = parseInt(this.style.left) + $(document.getElementById('change-node-text-pos')).width() let menuX = parseInt(this.style.left) + $(document.getElementById('change-node-text-pos')).width()
// 边界判断 // 边界判断
if (menuX + self.nodeTextPosMenu.width() * 2 >= self.stage.width) { if (menuX + self.nodeTextPosMenu.width() * 2 >= self.stage.width) {
menuX -= (self.nodeTextPosMenu.width() + self.nodeMenu.width()) menuX -= (self.nodeTextPosMenu.width() + self.nodeMenu.width())
...@@ -321,7 +288,7 @@ TopologyEditor.prototype.initMenus = function () { ...@@ -321,7 +288,7 @@ TopologyEditor.prototype.initMenus = function () {
// 修改节点文字位置菜单 // 修改节点文字位置菜单
self.nodeTextPosMenu.on('click', function (event) { self.nodeTextPosMenu.on('click', function (event) {
// 菜单文字 // 菜单文字
var text = $.trim($(event.target).text()) let text = $.trim($(event.target).text())
if (self.currentNode && self.currentNode instanceof JTopo.Node) { if (self.currentNode && self.currentNode instanceof JTopo.Node) {
self.utils.saveNodeInitState() self.utils.saveNodeInitState()
switch (text) { switch (text) {
...@@ -370,7 +337,7 @@ TopologyEditor.prototype.initMenus = function () { ...@@ -370,7 +337,7 @@ TopologyEditor.prototype.initMenus = function () {
self.lineMenu.on('click', function (event) { self.lineMenu.on('click', function (event) {
// 关闭菜单 // 关闭菜单
$(this).hide() $(this).hide()
var text = $.trim($(event.target).text()) let text = $.trim($(event.target).text())
switch (text) { switch (text) {
case '连线设置': case '连线设置':
// alert('连线设置') // alert('连线设置')
...@@ -391,18 +358,18 @@ TopologyEditor.prototype.initMenus = function () { ...@@ -391,18 +358,18 @@ TopologyEditor.prototype.initMenus = function () {
// 节点分组菜单 // 节点分组菜单
self.groupMangeMenu.on('click', function (event) { self.groupMangeMenu.on('click', function (event) {
$(this).hide() $(this).hide()
var text = $.trim($(event.target).text()) let text = $.trim($(event.target).text())
if (text === '新建分组') { if (text === '新建分组') {
self.utils.toMerge() self.utils.toMerge()
} }
}) })
// 对齐 // 对齐
self.groupAlignMenu.on('click', function (event) { self.groupAlignMenu.on('click', function (event) {
var currNode = self.currentNode let currNode = self.currentNode
var selectedNodes = self.utils.getSelectedNodes() let selectedNodes = self.utils.getSelectedNodes()
if (!currNode || !selectedNodes || selectedNodes.length === 0) return if (!currNode || !selectedNodes || selectedNodes.length === 0) return
$(this).hide() $(this).hide()
var text = $.trim($(event.target).text()) let text = $.trim($(event.target).text())
selectedNodes.forEach(function (n) { selectedNodes.forEach(function (n) {
if (n.nodeId === currNode.nodeId) return true if (n.nodeId === currNode.nodeId) return true
if (text === '水平对齐') { if (text === '水平对齐') {
...@@ -415,10 +382,10 @@ TopologyEditor.prototype.initMenus = function () { ...@@ -415,10 +382,10 @@ TopologyEditor.prototype.initMenus = function () {
}) })
}) })
self.groupMangeMenu.on('mouseover', function (event) { self.groupMangeMenu.on('mouseover', function (event) {
var text = $.trim($(event.target).text()) let text = $.trim($(event.target).text())
if (text === '对齐方式') { if (text === '对齐方式') {
// 节点对齐 // 节点对齐
var menuX = parseInt(this.style.left) + $(document.getElementById('align-group')).width() let menuX = parseInt(this.style.left) + $(document.getElementById('align-group')).width()
if (menuX + self.alignGroup.width() * 2 >= self.stage.width) { if (menuX + self.alignGroup.width() * 2 >= self.stage.width) {
menuX -= (self.alignGroup.width() + self.groupMangeMenu.width()) menuX -= (self.alignGroup.width() + self.groupMangeMenu.width())
} }
...@@ -432,12 +399,12 @@ TopologyEditor.prototype.initMenus = function () { ...@@ -432,12 +399,12 @@ TopologyEditor.prototype.initMenus = function () {
}) })
// 容器管理菜单 // 容器管理菜单
self.containerMangeMenu.on('click', function (event) { self.containerMangeMenu.on('click', function (event) {
var cNode = editor.currentNode let cNode = editor.currentNode
if (!(cNode instanceof JTopo.Container)) { if (!(cNode instanceof JTopo.Container)) {
return return
} }
$(this).hide() $(this).hide()
var text = $.trim($(event.target).text()) let text = $.trim($(event.target).text())
if (text === '拆分') { if (text === '拆分') {
self.utils.toSplit() self.utils.toSplit()
self.utils.deleteNode(cNode) self.utils.deleteNode(cNode)
...@@ -448,7 +415,7 @@ TopologyEditor.prototype.initMenus = function () { ...@@ -448,7 +415,7 @@ TopologyEditor.prototype.initMenus = function () {
self.layoutMenu.on('click', function (event) { self.layoutMenu.on('click', function (event) {
editor.currentNode.layout = {} editor.currentNode.layout = {}
$('div[id$=\'-menu\']').hide() $('div[id$=\'-menu\']').hide()
var text = $.trim($(event.target).text()) let text = $.trim($(event.target).text())
if (text === '取消布局') { if (text === '取消布局') {
editor.currentNode.layout.on = false editor.currentNode.layout.on = false
} else if (text === '分组布局') { } else if (text === '分组布局') {
...@@ -489,7 +456,7 @@ TopologyEditor.prototype.replaceStage = function (url) { ...@@ -489,7 +456,7 @@ TopologyEditor.prototype.replaceStage = function (url) {
if (response.code !== 200) { if (response.code !== 200) {
console.error(response.msg) console.error(response.msg)
} else { } else {
var topologyJson = response.data.topology_json let topologyJson = response.data.topology_json
JTopo.replaceStageWithJson(topologyJson) JTopo.replaceStageWithJson(topologyJson)
if (editor.stage && editor.scene && editor.scene.childs && editor.scene.childs.length > 0) { if (editor.stage && editor.scene && editor.scene.childs && editor.scene.childs.length > 0) {
editor.stage.centerAndZoom() editor.stage.centerAndZoom()
...@@ -506,12 +473,13 @@ TopologyEditor.prototype.replaceStage = function (url) { ...@@ -506,12 +473,13 @@ TopologyEditor.prototype.replaceStage = function (url) {
*/ */
TopologyEditor.prototype.init = function (topologyGuid, backImg, topologyJson) { TopologyEditor.prototype.init = function (topologyGuid, backImg, topologyJson) {
if (!topologyJson) { if (!topologyJson) {
alert('加载拓扑编辑器失败!') // alert('加载拓扑编辑器失败!')
return return
} }
console.log(topologyJson);
this.topologyGuid = topologyGuid this.topologyGuid = topologyGuid
// 创建jTopo舞台屏幕对象 // 创建jTopo舞台屏幕对象
var canvas = document.getElementById('topology-canvas') let canvas = document.getElementById('topology-canvas')
canvas.width = $('#topology-body').width() canvas.width = $('#topology-body').width()
canvas.height = $('#topology-body').height() canvas.height = $('#topology-body').height()
// 加载空白的编辑器 // 加载空白的编辑器
...@@ -519,6 +487,7 @@ TopologyEditor.prototype.init = function (topologyGuid, backImg, topologyJson) { ...@@ -519,6 +487,7 @@ TopologyEditor.prototype.init = function (topologyGuid, backImg, topologyJson) {
this.stage = new JTopo.Stage(canvas) // 定义舞台对象 this.stage = new JTopo.Stage(canvas) // 定义舞台对象
this.scene = new JTopo.Scene(this.stage) // 定义场景对象 this.scene = new JTopo.Scene(this.stage) // 定义场景对象
} else { } else {
console.log(topologyJson);
this.stage = JTopo.createStageFromJson(topologyJson, canvas) // 根据保存好的jsonStr(拓扑结构)创建舞台对象 this.stage = JTopo.createStageFromJson(topologyJson, canvas) // 根据保存好的jsonStr(拓扑结构)创建舞台对象
this.scene = this.stage.childs[0] // 场景对象列表,childs是舞台的属性 this.scene = this.stage.childs[0] // 场景对象列表,childs是舞台的属性
} }
...@@ -537,10 +506,12 @@ TopologyEditor.prototype.init = function (topologyGuid, backImg, topologyJson) { ...@@ -537,10 +506,12 @@ TopologyEditor.prototype.init = function (topologyGuid, backImg, topologyJson) {
this.tempNodeZ.setSize(1, 1) this.tempNodeZ.setSize(1, 1)
this.beginNode = null this.beginNode = null
this.link = null this.link = null
var self = this let self = this
// 模拟告警 // 模拟告警
editor.utils.getAllNodes()[0].alarm = "告警"; if(editor.utils.getAllNodes().length > 0){
editor.utils.getAllNodes()[0].alarm = "告警";
}
// 初始化菜单 // 初始化菜单
...@@ -553,8 +524,8 @@ TopologyEditor.prototype.init = function (topologyGuid, backImg, topologyJson) { ...@@ -553,8 +524,8 @@ TopologyEditor.prototype.init = function (topologyGuid, backImg, topologyJson) {
if (event.target != null && event.target instanceof JTopo.Node && event.target.nodeTooltip && editor.stageMode !== 'edit') { if (event.target != null && event.target instanceof JTopo.Node && event.target.nodeTooltip && editor.stageMode !== 'edit') {
$('.node-tooltip span').html(event.target.nodeTooltip) $('.node-tooltip span').html(event.target.nodeTooltip)
// 记录鼠标触发位置在canvas中的相对位置 // 记录鼠标触发位置在canvas中的相对位置
var menuY = event.layerY ? event.layerY : event.offsetY let menuY = event.layerY ? event.layerY : event.offsetY
var menuX = event.layerX ? event.layerX : event.offsetX let menuX = event.layerX ? event.layerX : event.offsetX
// 判断边界出是否能完整显示弹出菜单 // 判断边界出是否能完整显示弹出菜单
if (menuX + $('.node-tooltip').width() >= self.stage.width) { if (menuX + $('.node-tooltip').width() >= self.stage.width) {
menuX -= $('.node-tooltip').width() menuX -= $('.node-tooltip').width()
...@@ -573,8 +544,8 @@ TopologyEditor.prototype.init = function (topologyGuid, backImg, topologyJson) { ...@@ -573,8 +544,8 @@ TopologyEditor.prototype.init = function (topologyGuid, backImg, topologyJson) {
} else if (event.target != null && event.target instanceof JTopo.Link && event.target.linkTooltip && editor.stageMode !== 'edit') { } else if (event.target != null && event.target instanceof JTopo.Link && event.target.linkTooltip && editor.stageMode !== 'edit') {
$('.link-tooltip span').html(event.target.linkTooltip) $('.link-tooltip span').html(event.target.linkTooltip)
// 记录鼠标触发位置在canvas中的相对位置 // 记录鼠标触发位置在canvas中的相对位置
var menuY = event.layerY ? event.layerY : event.offsetY let menuY = event.layerY ? event.layerY : event.offsetY
var menuX = event.layerX ? event.layerX : event.offsetX let menuX = event.layerX ? event.layerX : event.offsetX
// 判断边界出是否能完整显示弹出菜单 // 判断边界出是否能完整显示弹出菜单
if (menuX + $('.link-tooltip').width() >= self.stage.width) { if (menuX + $('.link-tooltip').width() >= self.stage.width) {
menuX -= $('.link-tooltip').width() menuX -= $('.link-tooltip').width()
...@@ -596,7 +567,7 @@ TopologyEditor.prototype.init = function (topologyGuid, backImg, topologyJson) { ...@@ -596,7 +567,7 @@ TopologyEditor.prototype.init = function (topologyGuid, backImg, topologyJson) {
// 鼠标离开事件 // 鼠标离开事件
this.scene.mouseout(function (event) { this.scene.mouseout(function (event) {
var timeSpan = Timer.pause() let timeSpan = Timer.pause()
// 消抖 // 消抖
if (timeSpan > 100) { if (timeSpan > 100) {
$('.node-tooltip').css('display', 'none') $('.node-tooltip').css('display', 'none')
...@@ -651,7 +622,7 @@ TopologyEditor.prototype.init = function (topologyGuid, backImg, topologyJson) { ...@@ -651,7 +622,7 @@ TopologyEditor.prototype.init = function (topologyGuid, backImg, topologyJson) {
content: $("#node-dialog"), content: $("#node-dialog"),
btn: ["应用", "删除", "取消"], btn: ["应用", "删除", "取消"],
yes: function(index, layero){ yes: function(index, layero){
var param = getParam("node-form"); let param = getParam("node-form");
self.currentNode.text = param.text; self.currentNode.text = param.text;
self.currentNode.textPosition = param.textPosition; self.currentNode.textPosition = param.textPosition;
self.currentNode.setLocation(param.x, param.y); self.currentNode.setLocation(param.x, param.y);
...@@ -668,7 +639,7 @@ TopologyEditor.prototype.init = function (topologyGuid, backImg, topologyJson) { ...@@ -668,7 +639,7 @@ TopologyEditor.prototype.init = function (topologyGuid, backImg, topologyJson) {
content: $("#link-dialog"), content: $("#link-dialog"),
btn: ["应用", "删除", "取消"], btn: ["应用", "删除", "取消"],
yes: function(index, layero){ yes: function(index, layero){
var param = getParam("link-form"); let param = getParam("link-form");
self.currentNode.text = param.text; self.currentNode.text = param.text;
self.currentNode.textPosition = param.textPosition; self.currentNode.textPosition = param.textPosition;
self.currentNode.setLocation(param.x, param.y); self.currentNode.setLocation(param.x, param.y);
...@@ -701,14 +672,14 @@ TopologyEditor.prototype.init = function (topologyGuid, backImg, topologyJson) { ...@@ -701,14 +672,14 @@ TopologyEditor.prototype.init = function (topologyGuid, backImg, topologyJson) {
} }
if (event.button === 2) { // 右键菜单 if (event.button === 2) { // 右键菜单
$('div[id$=\'-menu\']').hide() $('div[id$=\'-menu\']').hide()
var menuY = event.layerY ? event.layerY : event.offsetY let menuY = event.layerY ? event.layerY : event.offsetY
var menuX = event.layerX ? event.layerX : event.offsetX let menuX = event.layerX ? event.layerX : event.offsetX
// 记录鼠标触发位置在canvas中的相对位置 // 记录鼠标触发位置在canvas中的相对位置
self.xInCanvas = menuX self.xInCanvas = menuX
self.yInCanvas = menuY self.yInCanvas = menuY
if (event.target) { if (event.target) {
if (event.target instanceof JTopo.Node) { // 处理节点右键菜单事件 if (event.target instanceof JTopo.Node) { // 处理节点右键菜单事件
var selectedNodes = self.utils.getSelectedNodes() let selectedNodes = self.utils.getSelectedNodes()
// 如果是节点多选状态弹出分组菜单 // 如果是节点多选状态弹出分组菜单
if (selectedNodes && selectedNodes.length > 1) { if (selectedNodes && selectedNodes.length > 1) {
// 判断边界出是否能完整显示弹出菜单 // 判断边界出是否能完整显示弹出菜单
...@@ -794,7 +765,7 @@ TopologyEditor.prototype.init = function (topologyGuid, backImg, topologyJson) { ...@@ -794,7 +765,7 @@ TopologyEditor.prototype.init = function (topologyGuid, backImg, topologyJson) {
self.tempNodeZ.setLocation(event.x, event.y) self.tempNodeZ.setLocation(event.x, event.y)
} else if (event.target && event.target instanceof JTopo.Node && self.beginNode !== event.target) { } else if (event.target && event.target instanceof JTopo.Node && self.beginNode !== event.target) {
// 在终点节点处松开鼠标,则建立连线 // 在终点节点处松开鼠标,则建立连线
var endNode = event.target let endNode = event.target
// 判断两个节点是否有循环引用 // 判断两个节点是否有循环引用
/** ***************** 我这里允许循环引用 ************************* /** ***************** 我这里允许循环引用 *************************
for (var el = 0; el < endNode.outLinks.length; el++) { for (var el = 0; el < endNode.outLinks.length; el++) {
...@@ -819,7 +790,7 @@ TopologyEditor.prototype.init = function (topologyGuid, backImg, topologyJson) { ...@@ -819,7 +790,7 @@ TopologyEditor.prototype.init = function (topologyGuid, backImg, topologyJson) {
} }
} }
*****************************************************************/ *****************************************************************/
var link let link
if (self.lineType === 'line') { if (self.lineType === 'line') {
link = new JTopo.Link(self.beginNode, endNode) link = new JTopo.Link(self.beginNode, endNode)
link.lineType = 'line' link.lineType = 'line'
...@@ -1003,49 +974,51 @@ TopologyEditor.prototype.init = function (topologyGuid, backImg, topologyJson) { ...@@ -1003,49 +974,51 @@ TopologyEditor.prototype.init = function (topologyGuid, backImg, topologyJson) {
*/ */
TopologyEditor.prototype.drag = function (modeDiv, drawArea, text) { TopologyEditor.prototype.drag = function (modeDiv, drawArea, text) {
if (!text) text = '' if (!text) text = ''
var self = this let self = this
// 拖拽开始,携带必要的参数 // 拖拽开始,携带必要的参数
modeDiv.ondragstart = function (event) { modeDiv.ondragstart = function (event) {
event = event || window.event event = event || window.event
var dragSrc = this let dragSrc = this
console.log(dragSrc); let backImg = $(dragSrc).find('img').eq(0).attr('data-src')
var backImg = $(dragSrc).find('img').eq(0).attr('data-src');
backImg = backImg.substring(backImg.lastIndexOf('/') + 1) backImg = backImg.substring(backImg.lastIndexOf('/') + 1)
var nodeType = $(this).attr('topo-nodetype') let nodeType = $(this).attr('topo-nodetype')
try { try {
// IE只允许KEY为text和URL // IE只允许KEY为text和URL
event.dataTransfer.setData('text', backImg + ';' + text + ';' + nodeType) event.dataTransfer.setData('text', backImg + ';' + text + ';' + nodeType)
} catch (ex) { } catch (ex) {
console.log(ex) console.log(ex)
} }
}
//
modeDiv.ondrop = function (event) {
event.preventDefault();
event.stopPropagation();
return false
} }
//
// 阻止默认事件 // 阻止默认事件
drawArea.ondragover = function (event) { drawArea.ondragover = function (event) {
event.preventDefault(); event.preventDefault()
// event.stopPropagation()
return false return false
} }
// 创建节点 // 创建节点
drawArea.ondrop = function (event) { drawArea.ondrop = function (event) {
event.preventDefault()
// 只读模式 // 只读模式
if (editor.stageMode === "normal") { if (editor.stageMode === "normal") {
return; return;
} }
event = event || window.event event = event || window.event
var data = event.dataTransfer.getData('text') let data = event.dataTransfer.getData('text')
var img, text, nodeType let img, text, nodeType
if (data) { if (data) {
var datas = data.split(';') let datas = data.split(';')
if (datas && datas.length === 3) { if (datas && datas.length === 3) {
img = datas[0] img = datas[0]
text = datas[1] text = datas[1]
nodeType = datas[2] nodeType = datas[2]
var node = new JTopo.Node() let node = new JTopo.Node()
node.fontColor = self.config.nodeFontColor node.fontColor = self.config.nodeFontColor
// 节点坐标 // 节点坐标
node.setBound((event.layerX ? event.layerX : event.offsetX) - self.scene.translateX - self.config.nodeDefaultWidth / 2, (event.layerY ? event.layerY : event.offsetY) - self.scene.translateY - self.config.nodeDefaultHeight / 2, self.config.nodeDefaultWidth, self.config.nodeDefaultHeight) node.setBound((event.layerX ? event.layerX : event.offsetX) - self.scene.translateX - self.config.nodeDefaultWidth / 2, (event.layerY ? event.layerY : event.offsetY) - self.scene.translateY - self.config.nodeDefaultHeight / 2, self.config.nodeDefaultWidth, self.config.nodeDefaultHeight)
...@@ -1089,7 +1062,7 @@ editor.utils = { ...@@ -1089,7 +1062,7 @@ editor.utils = {
if (!text) { if (!text) {
text = "图片"; // 默认标签 text = "图片"; // 默认标签
} }
var node = new JTopo.Node() let node = new JTopo.Node()
node.fontColor = editor.config.nodeFontColor node.fontColor = editor.config.nodeFontColor
// 节点坐标 // 节点坐标
node.setBound(20, 20, 50, 50) node.setBound(20, 20, 50, 50)
...@@ -1120,8 +1093,8 @@ editor.utils = { ...@@ -1120,8 +1093,8 @@ editor.utils = {
}, },
// 获取所有选择的节点实例 // 获取所有选择的节点实例
getSelectedNodes: function () { getSelectedNodes: function () {
var selectedNodes = [] let selectedNodes = []
var nodes = editor.scene.selectedElements let nodes = editor.scene.selectedElements
nodes.forEach(function (n) { nodes.forEach(function (n) {
if (n.elementType === 'node') { if (n.elementType === 'node') {
selectedNodes.push(n) selectedNodes.push(n)
...@@ -1131,9 +1104,9 @@ editor.utils = { ...@@ -1131,9 +1104,9 @@ editor.utils = {
}, },
// 节点分组合并 // 节点分组合并
toMerge: function () { toMerge: function () {
var selectedNodes = this.getSelectedNodes() let selectedNodes = this.getSelectedNodes()
// 不指定布局的时候,容器的布局为自动(容器边界随元素变化) // 不指定布局的时候,容器的布局为自动(容器边界随元素变化)
var container = new JTopo.Container() let container = new JTopo.Container()
container.textPosition = 'Top_Center' container.textPosition = 'Top_Center'
container.fontColor = editor.config.nodeFontColor container.fontColor = editor.config.nodeFontColor
container.borderColor = editor.config.nodeBorderColor container.borderColor = editor.config.nodeBorderColor
...@@ -1178,10 +1151,10 @@ editor.utils = { ...@@ -1178,10 +1151,10 @@ editor.utils = {
if (editor.stageMode !== 'edit') { if (editor.stageMode !== 'edit') {
return false return false
} }
var self = this let self = this
var nodes = editor.scene.selectedElements let nodes = editor.scene.selectedElements
if (nodes && nodes.length > 0) { if (nodes && nodes.length > 0) {
for (var i = 0; i < nodes.length; i++) { for (let i = 0; i < nodes.length; i++) {
self.deleteNode(nodes[i]) self.deleteNode(nodes[i])
} }
} }
...@@ -1237,7 +1210,7 @@ editor.utils = { ...@@ -1237,7 +1210,7 @@ editor.utils = {
// 复制节点 // 复制节点
cloneNode: function (n) { cloneNode: function (n) {
if (n instanceof JTopo.Node) { if (n instanceof JTopo.Node) {
var newNode = new JTopo.Node() let newNode = new JTopo.Node()
n.serializedProperties.forEach(function (i) { n.serializedProperties.forEach(function (i) {
// 只复制虚拟机的模板属性 // 只复制虚拟机的模板属性
// if (i == "templateId" && n.dataType != "VM") return true; // if (i == "templateId" && n.dataType != "VM") return true;
...@@ -1264,8 +1237,8 @@ editor.utils = { ...@@ -1264,8 +1237,8 @@ editor.utils = {
}, },
// 复制选择的节点 // 复制选择的节点
cloneSelectedNodes: function () { cloneSelectedNodes: function () {
var self = this let self = this
var nodes = editor.scene.selectedElements let nodes = editor.scene.selectedElements
nodes.forEach(function (n) { nodes.forEach(function (n) {
if (n.elementType === 'node') { if (n.elementType === 'node') {
self.cloneNode(n) self.cloneNode(n)
...@@ -1274,7 +1247,7 @@ editor.utils = { ...@@ -1274,7 +1247,7 @@ editor.utils = {
}, },
// 全屏显示 // 全屏显示
showInFullScreen: function (element, method) { showInFullScreen: function (element, method) {
var usablePrefixMethod; let usablePrefixMethod;
['webkit', 'moz', 'ms', 'o', ''].forEach(function (prefix) { ['webkit', 'moz', 'ms', 'o', ''].forEach(function (prefix) {
if (usablePrefixMethod) { if (usablePrefixMethod) {
return return
...@@ -1283,7 +1256,7 @@ editor.utils = { ...@@ -1283,7 +1256,7 @@ editor.utils = {
// 无前缀,方法首字母小写 // 无前缀,方法首字母小写
// method = method.slice(0, 1).toLowerCase() + method.slice(1) // method = method.slice(0, 1).toLowerCase() + method.slice(1)
} }
var typePrefixMethod = typeof element[prefix + method] let typePrefixMethod = typeof element[prefix + method]
if (typePrefixMethod + '' !== 'undefined') { if (typePrefixMethod + '' !== 'undefined') {
if (typePrefixMethod === 'function') { if (typePrefixMethod === 'function') {
usablePrefixMethod = element[prefix + method]() usablePrefixMethod = element[prefix + method]()
...@@ -1301,7 +1274,7 @@ editor.utils = { ...@@ -1301,7 +1274,7 @@ editor.utils = {
}, },
// 获取所有的容器对象 // 获取所有的容器对象
getContainers: function () { getContainers: function () {
var containers = [] let containers = []
editor.stage.childs.forEach(function (s) { editor.stage.childs.forEach(function (s) {
s.childs.forEach(function (n) { s.childs.forEach(function (n) {
if (n.elementType === 'container') { if (n.elementType === 'container') {
...@@ -1313,7 +1286,7 @@ editor.utils = { ...@@ -1313,7 +1286,7 @@ editor.utils = {
}, },
// 根据指定的key返回节点实例 // 根据指定的key返回节点实例
getNodeByKey: function (key, value) { getNodeByKey: function (key, value) {
var node = null let node = null
editor.stage.childs.forEach(function (s) { editor.stage.childs.forEach(function (s) {
s.childs.forEach(function (n) { s.childs.forEach(function (n) {
if (n.elementType === 'node' && n[key] === value) { if (n.elementType === 'node' && n[key] === value) {
...@@ -1330,7 +1303,7 @@ editor.utils = { ...@@ -1330,7 +1303,7 @@ editor.utils = {
return return
} }
--editor.currentNode.currStep --editor.currentNode.currStep
for (var p in editor.currentNode) { for (let p in editor.currentNode) {
if (p !== 'currStep') { if (p !== 'currStep') {
editor.currentNode[p] = (editor.currentNode.historyStack[editor.currentNode.currStep])[p] editor.currentNode[p] = (editor.currentNode.historyStack[editor.currentNode.currStep])[p]
} }
...@@ -1343,7 +1316,7 @@ editor.utils = { ...@@ -1343,7 +1316,7 @@ editor.utils = {
return return
} }
editor.currentNode.currStep++ editor.currentNode.currStep++
for (var q in editor.currentNode) { for (let q in editor.currentNode) {
if (q !== 'currStep') { if (q !== 'currStep') {
editor.currentNode[q] = (editor.currentNode.historyStack[editor.currentNode.currStep])[q] editor.currentNode[q] = (editor.currentNode.historyStack[editor.currentNode.currStep])[q]
} }
...@@ -1370,12 +1343,12 @@ editor.utils = { ...@@ -1370,12 +1343,12 @@ editor.utils = {
if (!text) return if (!text) return
// var self = this // var self = this
text = text.trim() text = text.trim()
var nodes = editor.stage.find('node[text="' + text + '"]') let nodes = editor.stage.find('node[text="' + text + '"]')
if (nodes.length > 0) { if (nodes.length > 0) {
var node = nodes[0] let node = nodes[0]
this.unSelectAllNodeExcept(node) this.unSelectAllNodeExcept(node)
node.selected = true node.selected = true
var location = node.getCenterLocation() let location = node.getCenterLocation()
// 查询到的节点居中显示 // 查询到的节点居中显示
editor.stage.setCenter(location.x, location.y) editor.stage.setCenter(location.x, location.y)
......
This source diff could not be displayed because it is too large. You can view the blob instead.
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