最近根據(jù)公司需求接觸了mxGraph技術(shù),mxGraph 是一個(gè) JS 繪圖組件適用于需要在網(wǎng)頁(yè)中設(shè)計(jì)/編輯 Workflow/BPM 流程圖、圖表、網(wǎng)絡(luò)圖和普通圖形的 Web 應(yīng)用程序框架。
官方文檔:http://jgraph.github.io/mxgraph/javascript/index.html
官方API:http://jgraph.github.io/mxgraph/docs/js-api
GitHub庫(kù):jgraph/mxgraph
一耙考、下載:使用前首先要下載庫(kù)直接在github上拉取項(xiàng)目,以下是項(xiàng)目目錄鲸沮。
javaScript文件夾下的mxClient.js就是我們要用的文件玖详,mxClient.min.js是壓縮后的代碼啦吧,用于打包上線時(shí)引用糠爬。
二叼耙、配置&&引入:
<script type="text/javascript">
mxBasePath = '../src';
</script>
<script type="text/javascript" src="../src/js/mxClient.js"></script>
要定義一個(gè)mxBasePath為存放靜態(tài)資源的路徑。
以<script>標(biāo)簽引入怒坯。
在Vue中引入
npm install mxgraph --save
npm install exports-loader --save
npm install script-loader --save
在項(xiàng)目根目錄新建vue.config.js文件炫狱。配置如下:
const path = require('path');
function resolve(dir) {
return path.join(__dirname, dir);
}
module.exports = {
publicPath: './',
outputDir: 'dist',
lintOnSave: true,
chainWebpack: (config) => {
config.module
.rule('')
.test(/mxClient\.js$/)
.use('exports-loader')
.loader('exports-loader?mxClient,mxGraphModel,mxActor,mxShape,mxEventObject,mxGraph,mxPrintPreview,mxEventSource,mxRectangle,mxVertexHandler,mxMouseEvent,mxGraphView,mxImage,mxGeometry,mxRubberband,mxKeyHandler,mxDragSource,mxGraphModel,mxEvent,mxUtils,mxWindow,mxEvent,mxCodec,mxCell,mxConstants,mxPoint,mxGraphHandler,mxCylinder,mxCellRenderer,mxEvent,mxUndoManager')
.end();
config.resolve.alias
.set('@', resolve('src'))
.set('@assets', resolve('src/assets'));
// 按這種格式.set('', resolve('')) 自己添加
}
};
---------------------
作者:懶牛不愛(ài)梳毛
來(lái)源:CSDN
原文:https://blog.csdn.net/dikentoujing99/article/details/86630652
.Vue
<template>
<div ref="graph_container"></div>
</template>
<script>
import {
mxGraph
} from 'mxgraph/javascript/mxClient';
export default {
name: 'HelloWorld',
props: {
msg: String
},
mounted() {
// Creates the graph inside the given container
var graph = new mxGraph(this.$refs.graph_container);
// Gets the default parent for inserting new cells. This
// is normally the first child of the root (ie. layer 0).
var parent = graph.getDefaultParent();
// Adds cells to the model in a single step
graph.getModel().beginUpdate();
try {
let v1 = graph.insertVertex(parent, null, 'Hello,', 20, 20, 80, 30);
let v2 = graph.insertVertex(parent, null, 'World!', 200, 150, 80, 30);
graph.insertEdge(parent, null, '', v1, v2);
} finally {
// Updates the display
graph.getModel().endUpdate();
}
}
};
</script>
使用到mxGraph的哪個(gè)方法就得把它們import進(jìn)來(lái)。
三剔猿、具體操作
1.mxGraph中有三個(gè)主要的組件:mxGraph视译、mxGraphModel、mxCell归敬。mxGraph是用戶(hù)直接操作的圖酷含,圖的所有狀態(tài)都保存在mxGraphModel中,而圖中的頂點(diǎn)和邊都是用mxCell定義汪茧。
2.當(dāng)用戶(hù)對(duì)mxGraph進(jìn)行操作時(shí)椅亚,所有操作都映射到對(duì)mxGraphModel中保存的狀態(tài)進(jìn)行修改,而mxGraphModel中保存的狀態(tài)也就是mxCell的狀態(tài)舱污。
舉個(gè)最簡(jiǎn)單的??
<html>
<head>
<title>Hello, World! example for mxGraph</title>
<!-- Sets the basepath for the library if not in same directory -->
<script type="text/javascript">
mxBasePath = '../src';
</script>
<!-- Loads and initializes the library -->
<script type="text/javascript" src="../src/js/mxClient.js"></script>
<!-- Example code -->
<script type="text/javascript">
function main(container)
{
// 判斷瀏覽器是否支持
if (!mxClient.isBrowserSupported())
{
// mxUtils報(bào)錯(cuò)提示
mxUtils.error('Browser is not supported!', 200, false);
}
else
{
//去鋸齒效果
mxRectangleShape.prototype.crisp = true;
// 顯示導(dǎo)航線
mxGraphHandler.prototype.guidesEnabled = true;
// Alt鍵禁用導(dǎo)航線
mxGuide.prototype.isEnabledForEvent = function (evt) {
return !mxEvent.isAltDown(evt);
};
// 顯示終點(diǎn)
mxEdgeHandler.prototype.snapToTerminals = false;
// 禁用瀏覽器默認(rèn)的右鍵菜單欄
mxEvent.disableContextMenu(container);
// 在已有容器內(nèi)構(gòu)造一個(gè)graph
var graph = new mxGraph(container);
// 鼠標(biāo)框選
new mxRubberband(graph);
// 在圖形中創(chuàng)建默認(rèn)組件
var parent = graph.getDefaultParent();
// 只可預(yù)覽不可選中拖動(dòng)連接
graph.setEnabled(false);
// 容器大小自適應(yīng)
graph.setResizeContainer(true);
// 動(dòng)態(tài)改變樣式
graph.getView().updateStyle = true;
// 可否重復(fù)連接
graph.setMultigraph(false);
// 禁止改變?cè)卮笮?
graph.setCellsResizable(false);
// 允許連線的目標(biāo)和源是同一元素
graph.setAllowLoops(true);
// 開(kāi)始往module里添加cell
graph.getModel().beginUpdate();
try
{
//new一個(gè)cell 以單元的形式創(chuàng)建一個(gè)節(jié)點(diǎn)
var cell = new mxCell(null, new mxGeometry(100, 200, 100, 100), "一些樣式配置");
cell.vertex = true;
//插入這個(gè)cell
graph.addCell(cell);
var v1 = graph.insertVertex(parent, null, 'Hello,', 20, 20, 80, 30);
var v2 = graph.insertVertex(parent, null, 'World!', 200, 150, 80, 30);
//插入線條設(shè)置連接圖形
var e1 = graph.insertEdge(parent, null, '', v1, v2);
//預(yù)覽時(shí)鼠標(biāo)懸浮到節(jié)點(diǎn)時(shí)呀舔,改變鼠標(biāo)樣式
graph.getCursorForCell = function (cell) {
if (cell != null && cell.value != null && cell.vertex == 1) {
return 'pointer';
}
};
}
finally
{
// 更新事務(wù)結(jié)束
graph.getModel().endUpdate();
}
}
};
</script>
</head>
<!-- Page passes the container for the graph to the program -->
<body onload="main(document.getElementById('graphContainer'))">
<!-- Creates a container for the graph with a grid wallpaper -->
<div id="graphContainer"
style="position:relative;overflow:hidden;width:321px;height:241px;background:url('editors/images/grid.gif');cursor:default;">
</div>
</body>
</html>
1.事物的更新一定要放在 beginUpdate 和 endUpdate 里面。一次 beginUpdate 必須對(duì)應(yīng)一次 endUpdate
2.插入cell有兩種方式:
new mxCell(null, new mxGeometry(100, 200, 100, 100))
和
graph.insertVertex(parent, null, 'Hello,', 20, 20, 80, 30)
insertVertex 做了三件事扩灯,先是設(shè)置幾何信息媚赖,然后創(chuàng)建一個(gè)節(jié)點(diǎn)霜瘪,最后將這個(gè)節(jié)點(diǎn)添加到畫(huà)布。insertEdge 與 insertVertex 類(lèi)似惧磺,中間過(guò)程會(huì)調(diào)用vertex.setEdge(true)
將Cell
標(biāo)記為邊颖对。
幾何信息四個(gè)數(shù)字分別對(duì)應(yīng) X、 Y磨隘、 寬惜互、 高 坐標(biāo)是以graph的左上角為原點(diǎn)。
3.最上面是針對(duì)圖區(qū)域的一些設(shè)置
4.對(duì)插入元素的樣式配置跟在mxCell()最后面的參數(shù)里琳拭,樣式可以有很多,庫(kù)里也提供了一些描验。就不多說(shuō)白嘁,說(shuō)一下自定義樣式。
var style1 = [];
style1[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_IMAGE;
style1[mxConstants.STYLE_IMAGE] = './demoimg/屏幕快照 2019-03-27 下午1.06.15.png';
style1[mxConstants.STYLE_IMAGE_WIDTH] = '48';
style1[mxConstants.STYLE_IMAGE_HEIGHT] = '48';
graph.getStylesheet().putCellStyle('img1', style1);
//插入節(jié)點(diǎn)時(shí)定義樣式
var cell1 = new mxCell(null, new mxGeometry(100, 200, 100, 100), "img1");
5.添加按鈕
document.body.appendChild(mxUtils.button('value', function(evt){}
分裝一個(gè)動(dòng)態(tài)添加不同功能的按鈕的方法
// 創(chuàng)建按鈕
createButton = function (label, fun) {
document.getElementById("btn").appendChild(mxUtils.button(label, fun));
};
buttons = [{
label: "選擇所有",
fun: function (graph) {
return function (evt) {
graph.selectAll();//graph提供了很多的不同方法的API
};
}
},
{
label: "刪除",
fun: function (graph) {
return function (evt) {
var cells = graph.getSelectionCells();
graph.removeCells(cells);
};
}
},
]
//循環(huán)添加所有設(shè)置好功能的按鈕
(function () {
for (var i = 0; i < buttons.length; i++) {
createButton(buttons[i].label, buttons[i].fun(graph));
}
})();
6.讀取Xml
var xml ="<root><mxCell id='2' value='Hello,' vertex='1'><mxGeometry x='20' y='20' width='80' height='30' as='geometry'/></mxCell><mxCell id='3' value='World!' vertex='1'><mxGeometry x='200' y='150' width='80' height='30' as='geometry'/></mxCell><mxCell id='4' value='' edge='1' source='2' target='3'><mxGeometry relative='1' as='geometry'/></mxCell></root>";
var doc = mxUtils.parseXml(xml);
var codec = new mxCodec(doc);
var elt = doc.documentElement.firstChild;
var cells = [];
while (elt != null) {
cells.push(codec.decode(elt));
elt = elt.nextSibling;
}
graph.addCells(cells);
7.建立拖拽關(guān)系(選取拖動(dòng)定點(diǎn)添加)
// 檢查圖形中是否包含對(duì)應(yīng)的elt節(jié)點(diǎn)
function containsElt(graph, elt) {
while (elt != null) {
if (elt == graph.container) {
return true;
}
elt = elt.parentNode;
}
return false;
};
// 返回鼠標(biāo)選中的元素
var graphF = function (evt) {
var x = mxEvent.getClientX(evt);
var y = mxEvent.getClientY(evt);
var elt = document.elementFromPoint(x, y);
for (var i = 0; i < graphs.length; i++) {
if (containsElt(graphs[i], elt)) {
return graphs[i];
}
}
return null;
};
// 在給定的位置插入一個(gè)元素
//mxCell是頂點(diǎn)和邊的單元對(duì)象膘流,mxCell從模型(mxGraph)那里復(fù)制了許多的方法
//它們的主要差別在于絮缅,使用模型的方法會(huì)創(chuàng)建相關(guān)的事件通知以及撤銷(xiāo)方法,使用單元的方法可以發(fā)生改變但不記錄它們
var funct = function (graph, evt, target, x, y) {
var cell = new mxCell('NewCELL', new mxGeometry(0, 0, 120, 40));
cell.vertex = true;
var cells = graph.importCells([cell], x, y, target); //插入元素呼股、位置耕魄、大小
if (cells != null && cells > 0) {
graph.scrollCellToVisible(cells[0]);
graph.setSelectionCells(cells);
}
};
//創(chuàng)建一個(gè)DOM節(jié)點(diǎn),作為拖動(dòng)源
var img = mxUtils.createImage('images/icons48/gear.png');
img.style.width = '48px';
img.style.height = '48px';
img.style.margin = '10px';
document.getElementById("left").appendChild(img);
// 禁用IE瀏覽器中的DnD功能(這是為了跨瀏覽器平臺(tái)而設(shè)計(jì)的彭谁,見(jiàn)下文)
if (mxClient.IS_IE) {
mxEvent.addListener(img, 'dragstart', function (evt) {
evt.returnValue = false;
});
}
// 創(chuàng)建拖動(dòng)源的預(yù)覽
var dragElt = document.createElement('div');
dragElt.style.border = 'dashed black 1px';
dragElt.style.width = '120px';
dragElt.style.height = '40px';
// 在點(diǎn)擊拖動(dòng)源圖標(biāo)時(shí)提供預(yù)覽吸奴。 預(yù)覽是提供的僅僅是拖動(dòng)源的圖片
// 只有拖動(dòng)源到容器內(nèi)時(shí)才會(huì)顯示元素的坐標(biāo)預(yù)覽
var ds = mxUtils.makeDraggable(img, graphF, funct, dragElt, null, null, graph.autoscroll, true);
//從拖動(dòng)源拖動(dòng)時(shí)顯示導(dǎo)航線。
//注意缠局,對(duì)圖形中已存在的元素拖動(dòng)時(shí)顯示導(dǎo)航線不在本方法約束范圍则奥。
ds.isGuidesEnabled = function () {
return graph.graphHandler.guidesEnabled;
};
//從拖動(dòng)源拖動(dòng)元素到圖形以外的區(qū)域時(shí),顯示拖動(dòng)源圖片預(yù)覽
ds.createDragElement = mxDragSource.prototype.createDragElement;
var ds = mxUtils.makeDraggable(img, graphF, funct, dragElt, null, null, graph.autoscroll, true);
makeDraggable的參數(shù)makeDraggable( element, graphF, funct, dragElement, dx, dy, autoscroll, scalePreview, highlightDropTargets, getDropTarget)
詳細(xì)信息請(qǐng)點(diǎn)這里
前人栽樹(shù)狭园,后人乘涼
關(guān)于mxGraph读处,官方API文檔不友好,介紹簡(jiǎn)單不說(shuō)還全是英文的唱矛,官網(wǎng)的Demo倒是不少罚舱,不過(guò)有的拉下來(lái)在自己的環(huán)境下跑會(huì)報(bào)錯(cuò),同時(shí)國(guó)內(nèi)對(duì)于mxGraph技術(shù)的文章真的是少之又少绎谦,學(xué)習(xí)過(guò)程簡(jiǎn)直就是摸著石頭過(guò)河管闷,目前只基本掌握基礎(chǔ)使用部分,文章還會(huì)繼續(xù)更新燥滑。希望可以幫助到有需要的朋友渐北。